agency-web/app/components/Reveal.tsx

49 lines
1.1 KiB
TypeScript

"use client";
import { useEffect, useRef } from "react";
/**
* Lightweight scroll reveal via IntersectionObserver (no GSAP dependency
* so it works even before the smooth-scroll module mounts). Adds .is-in.
* CSS already shows content under reduced motion.
*/
export default function Reveal({
children,
as: Tag = "div",
className = "",
delay = 0,
}: {
children: React.ReactNode;
as?: keyof React.JSX.IntrinsicElements;
className?: string;
delay?: number;
}) {
const ref = useRef<HTMLElement>(null);
useEffect(() => {
const el = ref.current;
if (!el) return;
const io = new IntersectionObserver(
([e]) => {
if (e.isIntersecting) {
el.classList.add("is-in");
io.disconnect();
}
},
{ threshold: 0.15, rootMargin: "0px 0px -8% 0px" }
);
io.observe(el);
return () => io.disconnect();
}, []);
const Comp = Tag as React.ElementType;
return (
<Comp
ref={ref}
className={`reveal ${className}`}
style={{ transitionDelay: `${delay}ms` }}
>
{children}
</Comp>
);
}