-
Notifications
You must be signed in to change notification settings - Fork 2
/
useRect.ts
57 lines (47 loc) · 1.43 KB
/
useRect.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
import { useState, useEffect, useCallback, RefObject } from "react";
import {
animationFrameScheduler,
fromEvent,
merge as observableMerge,
} from "rxjs";
import { observeOn, debounceTime } from "rxjs/operators";
export interface IRect {
top: number;
left: number;
width: number;
height: number;
}
export const getRect = (targetElm: Element, relatedElm: Element): IRect => {
const targetRect = targetElm.getBoundingClientRect();
const relatedRect = relatedElm.getBoundingClientRect();
return {
top: (targetRect.top || 0) - relatedRect.top,
left: (targetRect.left || 0) - relatedRect.left,
width: targetRect.width || 0,
height: targetRect.height || 0,
};
};
export const useRect = (
elmRef: RefObject<Element | null>,
): [IRect, () => void] => {
const [rect, setRect] = useState({ left: 0, top: 0, width: 0, height: 0 });
const refreshRect = useCallback(() => {
if (elmRef.current) {
setRect(getRect(elmRef.current, document.body));
}
}, []);
useEffect(() => {
refreshRect();
}, []);
useEffect(() => {
const resize$ = fromEvent(globalThis, "resize");
const orientationchange$ = fromEvent(globalThis, "orientationchange");
const sub = observableMerge(resize$, orientationchange$)
.pipe(observeOn(animationFrameScheduler), debounceTime(200))
.subscribe(refreshRect);
return () => {
sub.unsubscribe();
};
}, []);
return [rect, refreshRect];
};