import { hookUtils } from "@local-logic/core/utils"; import { useLayoutEffect, useMemo, useState } from "react"; export type UseMeasureRect = Pick< DOMRectReadOnly, "x" | "y" | "top" | "left" | "right" | "bottom" | "height" | "width" >; export type UseMeasureRef = ( element: E ) => void; export type UseMeasureResult = [ UseMeasureRef, UseMeasureRect, E | null ]; const defaultState: UseMeasureRect = { x: 0, y: 0, width: 0, height: 0, top: 0, left: 0, bottom: 0, right: 0, }; const useMeasure = < E extends HTMLElement = HTMLElement >(): UseMeasureResult => { const isSSR = hookUtils.useIsSSR(); const [element, ref] = useState(null); const [rect, setRect] = useState(defaultState); const observer = useMemo( () => !isSSR ? new window.ResizeObserver((entries) => { if (entries[0]) { const { x, y, width, height, top, left, bottom, right } = entries[0].contentRect; setRect({ x, y, width, height, top, left, bottom, right }); } }) : undefined, [isSSR] ); useLayoutEffect(() => { if (!element || isSSR) return undefined; observer?.observe(element); return () => { observer?.disconnect(); }; }, [element, isSSR]); return [ref, rect, element]; }; export default useMeasure;