85 lines
3.2 KiB
JavaScript
85 lines
3.2 KiB
JavaScript
import { resize } from '../resize/index.mjs';
|
|
import { createScrollInfo } from './info.mjs';
|
|
import { createOnScrollHandler } from './on-scroll-handler.mjs';
|
|
import { frame, cancelFrame, frameData } from '../../../frameloop/frame.mjs';
|
|
|
|
const scrollListeners = new WeakMap();
|
|
const resizeListeners = new WeakMap();
|
|
const onScrollHandlers = new WeakMap();
|
|
const getEventTarget = (element) => element === document.documentElement ? window : element;
|
|
function scrollInfo(onScroll, { container = document.documentElement, ...options } = {}) {
|
|
let containerHandlers = onScrollHandlers.get(container);
|
|
/**
|
|
* Get the onScroll handlers for this container.
|
|
* If one isn't found, create a new one.
|
|
*/
|
|
if (!containerHandlers) {
|
|
containerHandlers = new Set();
|
|
onScrollHandlers.set(container, containerHandlers);
|
|
}
|
|
/**
|
|
* Create a new onScroll handler for the provided callback.
|
|
*/
|
|
const info = createScrollInfo();
|
|
const containerHandler = createOnScrollHandler(container, onScroll, info, options);
|
|
containerHandlers.add(containerHandler);
|
|
/**
|
|
* Check if there's a scroll event listener for this container.
|
|
* If not, create one.
|
|
*/
|
|
if (!scrollListeners.has(container)) {
|
|
const measureAll = () => {
|
|
for (const handler of containerHandlers)
|
|
handler.measure();
|
|
};
|
|
const updateAll = () => {
|
|
for (const handler of containerHandlers) {
|
|
handler.update(frameData.timestamp);
|
|
}
|
|
};
|
|
const notifyAll = () => {
|
|
for (const handler of containerHandlers)
|
|
handler.notify();
|
|
};
|
|
const listener = () => {
|
|
frame.read(measureAll, false, true);
|
|
frame.read(updateAll, false, true);
|
|
frame.update(notifyAll, false, true);
|
|
};
|
|
scrollListeners.set(container, listener);
|
|
const target = getEventTarget(container);
|
|
window.addEventListener("resize", listener, { passive: true });
|
|
if (container !== document.documentElement) {
|
|
resizeListeners.set(container, resize(container, listener));
|
|
}
|
|
target.addEventListener("scroll", listener, { passive: true });
|
|
}
|
|
const listener = scrollListeners.get(container);
|
|
frame.read(listener, false, true);
|
|
return () => {
|
|
var _a;
|
|
cancelFrame(listener);
|
|
/**
|
|
* Check if we even have any handlers for this container.
|
|
*/
|
|
const currentHandlers = onScrollHandlers.get(container);
|
|
if (!currentHandlers)
|
|
return;
|
|
currentHandlers.delete(containerHandler);
|
|
if (currentHandlers.size)
|
|
return;
|
|
/**
|
|
* If no more handlers, remove the scroll listener too.
|
|
*/
|
|
const scrollListener = scrollListeners.get(container);
|
|
scrollListeners.delete(container);
|
|
if (scrollListener) {
|
|
getEventTarget(container).removeEventListener("scroll", scrollListener);
|
|
(_a = resizeListeners.get(container)) === null || _a === void 0 ? void 0 : _a();
|
|
window.removeEventListener("resize", scrollListener);
|
|
}
|
|
};
|
|
}
|
|
|
|
export { scrollInfo };
|