Cleanup - unused files / unused exports / duplicate exports
[ProtonMail-WebClient.git] / applications / calendar / src / app / hooks / observeRect.ts
blobe40fab4dab0fddea192bbc63b031c86c6e16bf75
1 export interface Rect {
2     width: number;
3     height: number;
4     top: number;
5     right: number;
6     bottom: number;
7     left: number;
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();
17 let rafId = 0;
19 const run = () => {
20     observedNodes.forEach((state) => {
21         if (state.hasRectChanged) {
22             state.callbacks.forEach((cb: Callback) => cb(state.rect));
23             state.hasRectChanged = false;
24         }
25     });
27     setTimeout(() => {
28         observedNodes.forEach((state, node) => {
29             const newRect = node.getBoundingClientRect();
30             if (rectChanged(newRect, state.rect)) {
31                 state.hasRectChanged = true;
32                 state.rect = newRect;
33             }
34         });
35     }, 0);
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);
45         callbacks.push(cb);
46         if (rect && !hasRectChanged) {
47             cb(rect);
48         }
49     } else {
50         observedNodes.set(node, {
51             rect: undefined,
52             hasRectChanged: false,
53             callbacks: [cb],
54         });
55     }
56     if (wasEmpty) {
57         run();
58     }
60     return () => {
61         const state = observedNodes.get(node);
62         if (!state) {
63             return;
64         }
65         const index = state.callbacks.indexOf(cb);
66         if (index >= 0) {
67             state.callbacks.splice(index, 1);
68         }
69         if (!state.callbacks.length) {
70             observedNodes.delete(node);
71         }
72         if (!observedNodes.size) {
73             cancelAnimationFrame(rafId);
74         }
75     };