tianji/src/client/hooks/useResizeObserver.ts

71 lines
1.5 KiB
TypeScript

/**
* Copy from https://github.com/mantinedev/mantine/blob/master/packages/@mantine/hooks/src/use-resize-observer/use-resize-observer.ts
*/
import { useRef, useState, useMemo, useEffect } from 'react';
type ObserverRect = Omit<DOMRectReadOnly, 'toJSON'>;
const defaultState: ObserverRect = {
x: 0,
y: 0,
width: 0,
height: 0,
top: 0,
left: 0,
bottom: 0,
right: 0,
};
export function useResizeObserver<T extends HTMLElement = any>(
options?: ResizeObserverOptions
) {
const frameID = useRef(0);
const ref = useRef<T>(null);
const [rect, setRect] = useState<ObserverRect>(defaultState);
const observer = useMemo(
() =>
typeof window !== 'undefined'
? new ResizeObserver((entries: any) => {
const entry = entries[0];
if (entry) {
cancelAnimationFrame(frameID.current);
frameID.current = requestAnimationFrame(() => {
if (ref.current) {
setRect(entry.contentRect);
}
});
}
})
: null,
[]
);
useEffect(() => {
if (ref.current) {
observer?.observe(ref.current, options);
}
return () => {
observer?.disconnect();
if (frameID.current) {
cancelAnimationFrame(frameID.current);
}
};
}, [ref.current]);
return [ref, rect] as const;
}
export function useElementSize<T extends HTMLElement = any>(
options?: ResizeObserverOptions
) {
const [ref, { width, height }] = useResizeObserver<T>(options);
return { ref, width, height };
}