import { useCallback, useEffect, useMemo, useRef, useState } from "react"; type ObserverRect = Omit; const defaultState: ObserverRect = { x: 0, y: 0, width: 0, height: 0, top: 0, left: 0, bottom: 0, right: 0, }; const browser = typeof window !== "undefined"; export function useResizeObserver() { const frameID = useRef(0); const ref = useRef(null); const [rect, setRect] = useState(defaultState); const observer = useMemo( () => browser ? new ResizeObserver((entries: any) => { const entry = entries[0]; if (entry) { cancelAnimationFrame(frameID.current); frameID.current = requestAnimationFrame(() => { if (ref.current) { setRect(entry.contentRect); } }); } }) : null, [], ); const measure = useCallback(() => { const rect = ref.current?.getBoundingClientRect(); if (rect) { setRect(rect); } return rect; }, []); useEffect(() => { if (!observer) return; if (ref.current) { observer.observe(ref.current); } return () => { observer.disconnect(); if (frameID.current) { cancelAnimationFrame(frameID.current); } }; }, [observer]); return [ref, rect, measure] as const; } export function useElementSize() { const [ref, { width, height }] = useResizeObserver(); return { ref, width, height }; }