"use client"; /** * In-view reveal. Fades + lifts content when it scrolls into view (once). * - Motion `whileInView` with a viewport margin so it triggers slightly early. * - `stagger` cascades direct children via Motion variants. * - Honors prefers-reduced-motion (renders fully visible, no transform). */ import { motion, type Variants } from "motion/react"; import { useReducedMotion } from "motion/react"; type Props = { children: React.ReactNode; className?: string; delay?: number; y?: number; stagger?: number; as?: "div" | "section" | "ul" | "ol" | "li" | "p" | "figure" | "header"; }; export default function Reveal({ children, className, delay = 0, y = 26, stagger, as = "div", }: Props) { const reduce = useReducedMotion(); const MotionTag = motion[as] as typeof motion.div; if (stagger) { const parent: Variants = { hidden: {}, show: { transition: { staggerChildren: reduce ? 0 : stagger, delayChildren: delay } }, }; return ( {children} ); } return ( {children} ); } /** A child item that participates in a parent . */ export function RevealItem({ children, className, y = 22, as = "div", }: { children: React.ReactNode; className?: string; y?: number; as?: "div" | "li" | "p"; }) { const reduce = useReducedMotion(); const MotionTag = motion[as] as typeof motion.div; const item: Variants = { hidden: reduce ? { opacity: 1 } : { opacity: 0, y }, show: { opacity: 1, y: 0, transition: { duration: 0.65, ease: [0.16, 1, 0.3, 1] } }, }; return ( {children} ); }