Line data Source code
1 : import * as React from 'react';
2 : import useResizeObserverRaw from '@react-hook/resize-observer';
3 1 : const useResizeObserver = useResizeObserverRaw as unknown as (target: React.RefObject<HTMLElement | null> | null, callback: (entry: ResizeObserverEntry) => void) => void;
4 :
5 : export interface ObservedSize {
6 : width: number;
7 : height: number;
8 : }
9 :
10 1 : export const OBSERVED_SIZE = React.createContext<ObservedSize | null>(null);
11 : export const useObservedSize = () => React.useContext(OBSERVED_SIZE)!;
12 :
13 : /// Keep the previous size if the dimensions did not change.
14 : /// Resize observers report a new rect object for every observation.
15 1 : function keepSameSize(prev: ObservedSize | null, next: ObservedSize | null): ObservedSize | null {
16 1 : if (prev !== null && next !== null && prev.width === next.width && prev.height === next.height) {
17 1 : return prev;
18 : }
19 1 : return next;
20 1 : }
21 :
22 1 : export const observeSize = (target: React.RefObject<HTMLElement | null>, enabled: boolean = true): ObservedSize | null => {
23 1 : const [size, setSize] = React.useState<ObservedSize | null>(null);
24 1 : React.useLayoutEffect(() => {
25 1 : const next = target.current?.getBoundingClientRect() ?? null;
26 1 : setSize(prev => keepSameSize(prev, next));
27 1 : }, [target.current]);
28 1 : useResizeObserver(enabled ? target : null, (entry: ResizeObserverEntry) => {
29 1 : setSize(prev => keepSameSize(prev, entry.contentRect));
30 1 : });
31 1 : return size;
32 1 : };
33 :
34 : interface ObserverProps {
35 : children: React.ReactElement;
36 : disableWidth?: boolean;
37 : disableHeight?: boolean;
38 : }
39 :
40 : export const SizeObserver: React.FC<ObserverProps> = (props: ObserverProps) => {
41 : const target = React.useRef(null);
42 : const size = observeSize(target);
43 : return (
44 : <div
45 : ref={target}
46 : style={{ width: props.disableWidth ? 'auto' : '100%', height: props.disableHeight ? 'auto' : '100%' }}
47 : >
48 : <OBSERVED_SIZE.Provider value={size}>{props.children}</OBSERVED_SIZE.Provider>
49 : </div>
50 : );
51 : };
|