36 lines
1023 B
TypeScript
36 lines
1023 B
TypeScript
"use client";
|
|
|
|
import { useLayoutEffect } from "react";
|
|
|
|
type Mode = "scroll" | "offset";
|
|
|
|
export function useHeightVar(
|
|
ref: React.RefObject<HTMLElement | null>,
|
|
cssVarName: string,
|
|
mode: Mode = "scroll",
|
|
trigger?: unknown,
|
|
targetRef?: React.RefObject<HTMLElement | null>,
|
|
) {
|
|
useLayoutEffect(() => {
|
|
const el = ref.current;
|
|
if (!el) return;
|
|
const target = targetRef?.current ?? el;
|
|
|
|
const measure = () => {
|
|
const h = mode === "scroll" ? el.scrollHeight : el.offsetHeight;
|
|
|
|
target.style.setProperty(cssVarName, `${h}px`);
|
|
};
|
|
|
|
measure();
|
|
|
|
// Observe el (the unclipped content), not target: if target is the
|
|
// element whose max-height is being CSS-transitioned, observing it
|
|
// directly re-triggers measure() on every layout step of the
|
|
// transition, fighting the animation (visible as stutter in Firefox).
|
|
const ro = new ResizeObserver(measure);
|
|
ro.observe(el);
|
|
|
|
return () => ro.disconnect();
|
|
}, [ref, targetRef, cssVarName, mode, trigger]);
|
|
} |