import { useMotionValue, useSpring } from "motion/react";
import { useEffect, useRef } from "react";
export function useSmartHeader(headerPx = 64, snapDelay = 120) {
const yRaw = useMotionValue(0); // 0 = fully shown
const y = useSpring(yRaw, { stiffness: 400, damping: 40 });
const lastY = useRef(0);
const snapTimer = useRef<NodeJS.Timeout | null>(null);
useEffect(() => {
const onScroll = () => {
const cur = window.scrollY;
/* Always show at top, even if the user scrolled up slowly to the top */
if (cur <= 50) {
yRaw.set(0); // fully visible
lastY.current = 0;
return;
}
const delta = cur - lastY.current;
lastY.current = cur;
// move header opposite to scroll direction, clamped
const next = Math.max(Math.min(yRaw.get() - delta, 0), -headerPx);
yRaw.set(next);
if (snapTimer.current !== null) {
clearTimeout(snapTimer.current);
}
snapTimer.current = setTimeout(() => {
const pos = yRaw.get();
yRaw.set(pos < -headerPx / 2 ? -headerPx : 0); // snap
}, snapDelay);
};
window.addEventListener("scroll", onScroll, { passive: true });
return () => window.removeEventListener("scroll", onScroll);
}, [headerPx, snapDelay, yRaw]);
return y; // spring-smoothed motion value
}