'use client'; import * as React from 'react'; type 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 || 0; let extra = 0; if (options.includeParentBox && el.parentElement) { const cs = getComputedStyle(el.parentElement); const paddingY = (parseFloat(cs.paddingTop || '0') || 0) + (parseFloat(cs.paddingBottom || '0') || 0); const borderY = (parseFloat(cs.borderTopWidth || '0') || 0) + (parseFloat(cs.borderBottomWidth || '0') || 0); const isBorderBox = cs.boxSizing === 'border-box'; if (isBorderBox) { extra += paddingY + borderY; } } if (options.includeSelfBox) { const cs = getComputedStyle(el); const paddingY = (parseFloat(cs.paddingTop || '0') || 0) + (parseFloat(cs.paddingBottom || '0') || 0); const borderY = (parseFloat(cs.borderTopWidth || '0') || 0) + (parseFloat(cs.borderBottomWidth || '0') || 0); const isBorderBox = cs.boxSizing === 'border-box'; if (isBorderBox) { extra += paddingY + borderY; } } const dpr = typeof window !== 'undefined' ? window.devicePixelRatio || 1 : 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; }; // eslint-disable-next-line react-hooks/exhaustive-deps }, deps); React.useLayoutEffect(() => { if (height === 0) { const next = measure(); if (next !== 0) setHeight(next); } }, [height, measure]); return { ref, height } as const; }