obsize
Version:
🧐 Element size observer based on ResizeObserver
62 lines (55 loc) • 1.42 kB
text/typescript
import { nanoid } from "nanoid";
type ObserverItem = { key: string; once: boolean; fn: ObserverHandler };
type ObserverHandler = () => void;
type RemoveObserverHandler = () => void;
const map = new Map();
const obs = new ResizeObserver((entries) => {
entries.forEach((entry) => {
const { target } = entry;
const fns = map.get(target);
if (fns?.length) {
const newFns = [];
fns.forEach((item: ObserverItem) => {
const { fn, once } = item;
fn();
if (!once) {
newFns.push(item);
}
});
map.set(target, newFns);
}
});
});
function observe(
element: HTMLElement,
fn: ObserverHandler,
options = { once: false }
): RemoveObserverHandler {
const isElementObserver = map.has(element);
const elementFns = isElementObserver ? map.get(element) : [];
const key = nanoid();
const { once } = options;
elementFns.push({ key, once, fn });
if (!isElementObserver) {
obs.observe(element);
map.set(element, elementFns);
}
return () => {
if (map.has(element)) {
const fns = map.get(element).filter((item: ObserverItem) => {
return item.key !== key;
});
if (fns.length === 0) {
map.delete(element);
obs.unobserve(element);
} else {
map.set(element, fns);
}
}
};
}
function clear() {
map.clear();
obs.disconnect();
}
export { observe, clear };