-
Notifications
You must be signed in to change notification settings - Fork 11
/
useRect.ts
68 lines (56 loc) · 1.47 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
58
59
60
61
62
63
64
65
66
67
68
// Ref: https://codesandbox.io/s/userect-hook-1y5t7
import { useCallback, useLayoutEffect, useState } from 'react';
import { useElement } from './useElement';
import ResizeObserver from 'resize-observer-polyfill';
export interface RectResult {
bottom: number;
height: number;
left: number;
right: number;
top: number;
width: number;
}
const nullResult: RectResult = {
bottom: 0,
height: 0,
left: 0,
right: 0,
top: 0,
width: 0
};
function getRect<T extends HTMLElement | SVGElement>( element?: T ): RectResult {
if ( element ) {
return element.getBoundingClientRect();
} else {
return nullResult;
}
}
export function useRect<T extends HTMLElement | SVGElement>(
ref: React.RefObject<T>
): RectResult {
const element = useElement( ref );
const [ rect, setRect ] = useState<RectResult>( nullResult );
const handleResize = useCallback(
() => {
if ( !element ) { return; }
setRect( getRect( element ) ); // Update client rect
},
[ element ]
);
useLayoutEffect(
() => {
if ( !element ) { return; }
handleResize();
const resizeObserver = new ResizeObserver( handleResize );
resizeObserver.observe( element );
window.addEventListener( 'resize', handleResize );
return () => {
if ( !resizeObserver ) { return; }
resizeObserver.disconnect();
window.removeEventListener( 'resize', handleResize );
};
},
[ element, handleResize ]
);
return rect;
}