"use client"; import * as React from "react"; interface AutoHeightOptions { includeParentBox?: boolean; includeSelfBox?: boolean; } export function useAutoHeight( deps: React.DependencyList = [], options: AutoHeightOptions = { includeParentBox: true, includeSelfBox: false, }, ) { const ref = React.useRef(null); const roRef = React.useRef(null); const [height, setHeight] = React.useState(0); const measure = React.useCallback(() => { const el = ref.current; if (!el) return 0; const base = el.getBoundingClientRect().height; let extra = 0; if (options.includeParentBox && el.parentElement) { const cs = getComputedStyle(el.parentElement); const paddingY = parseFloat(cs.paddingTop) + parseFloat(cs.paddingBottom); const borderY = parseFloat(cs.borderTopWidth) + parseFloat(cs.borderBottomWidth); const isBorderBox = cs.boxSizing === "border-box"; if (isBorderBox) { extra += paddingY + borderY; } } if (options.includeSelfBox) { const cs = getComputedStyle(el); const paddingY = parseFloat(cs.paddingTop) + parseFloat(cs.paddingBottom); const borderY = parseFloat(cs.borderTopWidth) + parseFloat(cs.borderBottomWidth); const isBorderBox = cs.boxSizing === "border-box"; if (isBorderBox) { extra += paddingY + borderY; } } const dpr = typeof window !== "undefined" ? window.devicePixelRatio : 1; const total = Math.ceil((base + extra) * dpr) / dpr; return total; }, [options.includeParentBox, options.includeSelfBox]); React.useLayoutEffect(() => { const el = ref.current; if (!el) return; setHeight(measure()); if (roRef.current) { roRef.current.disconnect(); roRef.current = null; } const ro = new ResizeObserver(() => { const next = measure(); requestAnimationFrame(() => { setHeight(next); }); }); ro.observe(el); if (options.includeParentBox && el.parentElement) { ro.observe(el.parentElement); } roRef.current = ro; return () => { ro.disconnect(); roRef.current = null; }; }, [...deps, measure, options.includeParentBox]); React.useLayoutEffect(() => { if (height === 0) { const next = measure(); if (next !== 0) setHeight(next); } }, [height, measure]); return { ref, height } as const; }