1 export interface Rect {
10 type Callback = (rect: Rect) => void;
12 const props = ['width', 'height', 'top', 'right', 'bottom', 'left'];
14 const rectChanged = (a: any = {}, b: any = {}) => props.some((prop) => a[prop] !== b[prop]);
16 const observedNodes = new Map();
20 observedNodes.forEach((state) => {
21 if (state.hasRectChanged) {
22 state.callbacks.forEach((cb: Callback) => cb(state.rect));
23 state.hasRectChanged = false;
28 observedNodes.forEach((state, node) => {
29 const newRect = node.getBoundingClientRect();
30 if (rectChanged(newRect, state.rect)) {
31 state.hasRectChanged = true;
37 rafId = requestAnimationFrame(run);
40 export default (node: HTMLElement, cb: Callback) => {
41 const wasEmpty = observedNodes.size === 0;
43 if (observedNodes.has(node)) {
44 const { callbacks, rect, hasRectChanged } = observedNodes.get(node);
46 if (rect && !hasRectChanged) {
50 observedNodes.set(node, {
52 hasRectChanged: false,
61 const state = observedNodes.get(node);
65 const index = state.callbacks.indexOf(cb);
67 state.callbacks.splice(index, 1);
69 if (!state.callbacks.length) {
70 observedNodes.delete(node);
72 if (!observedNodes.size) {
73 cancelAnimationFrame(rafId);