"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}
);
}