"use client"; import { type CSSProperties, type ReactNode, useEffect, useRef, useState } from "react"; type Props = { children: ReactNode; className?: string; delay?: number; stagger?: boolean; variant?: "up" | "left" | "right"; }; export default function Reveal({ children, className = "", delay = 0, stagger = false, variant = "up", }: Props) { const ref = useRef(null); const [shown, setShown] = useState(false); useEffect(() => { const el = ref.current; if (!el) return undefined; const reveal = () => setShown(true); if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) { reveal(); return undefined; } const observer = new IntersectionObserver( ([entry]) => { if (entry.isIntersecting) { reveal(); observer.disconnect(); } }, { threshold: 0.16, rootMargin: "0px 0px -10% 0px" }, ); observer.observe(el); return () => observer.disconnect(); }, []); const classes = [ "reveal", `reveal--${variant}`, stagger ? "stagger" : "", shown ? "is-in" : "", className, ] .filter(Boolean) .join(" "); return (
{children}
); }