-
-
Notifications
You must be signed in to change notification settings - Fork 210
/
sizeObserverPlugin.ts
97 lines (86 loc) · 3.29 KB
/
sizeObserverPlugin.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import {
createDOM,
appendChildren,
getOffsetSize,
addEventListener,
addClass,
equalWH,
cAF,
rAF,
stopPropagation,
bind,
scrollElementTo,
strWidth,
strHeight,
setStyles,
} from '~/support';
import {
classNameSizeObserverListenerScroll,
classNameSizeObserverListenerItem,
classNameSizeObserverListenerItemFinal,
} from '~/classnames';
import type { StaticPlugin } from '../plugins';
export const sizeObserverPluginName = '__osSizeObserverPlugin';
export const SizeObserverPlugin = /* @__PURE__ */ (() => ({
[sizeObserverPluginName]: {
static:
() =>
(
listenerElement: HTMLElement,
onSizeChangedCallback: (appear: boolean) => any,
observeAppearChange: boolean | null | undefined
): [appearCallback: () => void, offFns: (() => any)[]] => {
const scrollAmount = 3333333;
const scrollEventName = 'scroll';
const observerElementChildren = createDOM(
`<div class="${classNameSizeObserverListenerItem}" dir="ltr"><div class="${classNameSizeObserverListenerItem}"><div class="${classNameSizeObserverListenerItemFinal}"></div></div><div class="${classNameSizeObserverListenerItem}"><div class="${classNameSizeObserverListenerItemFinal}" style="width: 200%; height: 200%"></div></div></div>`
);
const observerElementChildrenRoot = observerElementChildren[0] as HTMLElement;
const shrinkElement = observerElementChildrenRoot.lastChild as HTMLElement;
const expandElement = observerElementChildrenRoot.firstChild as HTMLElement;
const expandElementChild = expandElement?.firstChild as HTMLElement;
let cacheSize = getOffsetSize(observerElementChildrenRoot);
let currSize = cacheSize;
let isDirty = false;
let rAFId: number;
const reset = () => {
scrollElementTo(expandElement, scrollAmount);
scrollElementTo(shrinkElement, scrollAmount);
};
const onResized = (appear?: unknown) => {
rAFId = 0;
if (isDirty) {
cacheSize = currSize;
onSizeChangedCallback(appear === true);
}
};
const onScroll = (scrollEvent?: Event | false) => {
currSize = getOffsetSize(observerElementChildrenRoot);
isDirty = !scrollEvent || !equalWH(currSize, cacheSize);
if (scrollEvent) {
stopPropagation(scrollEvent);
if (isDirty && !rAFId) {
cAF!(rAFId);
rAFId = rAF!(onResized);
}
} else {
onResized(scrollEvent === false);
}
reset();
};
const destroyFns = [
appendChildren(listenerElement, observerElementChildren),
addEventListener(expandElement, scrollEventName, onScroll),
addEventListener(shrinkElement, scrollEventName, onScroll),
];
addClass(listenerElement, classNameSizeObserverListenerScroll);
// lets assume that the divs will never be that large and a constant value is enough
setStyles(expandElementChild, {
[strWidth]: scrollAmount,
[strHeight]: scrollAmount,
});
rAF!(reset);
return [observeAppearChange ? bind(onScroll, false) : reset, destroyFns];
},
},
}))() satisfies StaticPlugin<typeof sizeObserverPluginName>;