agency-web/app/components/Reveal.tsx

54 lines
1.2 KiB
TypeScript

"use client";
import { useEffect, useRef, type ReactNode } from "react";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);
/**
* Reveal — generic on-scroll entrance with personality (slide + soft clip),
* not a plain fade-up. With `stagger`, animates direct children in sequence.
* Respects reduced-motion (content shown immediately).
*/
export default function Reveal({
children,
className = "",
stagger = 0,
y = 44,
}: {
children: ReactNode;
className?: string;
stagger?: number;
y?: number;
}) {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
const el = ref.current;
if (!el) return;
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
const targets = stagger > 0 ? Array.from(el.children) : [el];
const ctx = gsap.context(() => {
gsap.from(targets, {
y,
opacity: 0,
filter: "blur(8px)",
duration: 1.05,
ease: "power3.out",
stagger,
scrollTrigger: { trigger: el, start: "top 85%" },
});
}, el);
return () => ctx.revert();
}, [stagger, y]);
return (
<div ref={ref} className={className}>
{children}
</div>
);
}