gh_UserManager/apps/web/components/ui/reveal.tsx
bermooda-company 54d5891edf user
2026-08-23 23:59:14 +03:30

64 lines
1.4 KiB
TypeScript

"use client";
import { useEffect, useRef, useState } from "react";
import { cn } from "@/lib/utils";
export function Reveal({
children,
className,
delay = 0,
y = 16,
}: {
children: React.ReactNode;
className?: string;
delay?: number;
y?: number;
}) {
const ref = useRef<HTMLDivElement>(null);
const [visible, setVisible] = useState(false);
useEffect(() => {
const el = ref.current;
if (!el) return;
const io = new IntersectionObserver(
([e]) => {
if (e.isIntersecting) {
setVisible(true);
io.unobserve(e.target);
}
},
{ threshold: 0.15 }
);
io.observe(el);
return () => io.disconnect();
}, []);
return (
<div
ref={ref}
className={cn("will-change-transform", className)}
style={{
opacity: visible ? 1 : 0,
transform: visible ? "translateY(0)" : `translateY(${y}px)`,
transition: `opacity 600ms cubic-bezier(0.16,1,0.3,1) ${delay}ms, transform 600ms cubic-bezier(0.16,1,0.3,1) ${delay}ms`,
}}
>
{children}
</div>
);
}
export function Stagger({ children, stagger = 80 }: { children: React.ReactNode; stagger?: number }) {
return (
<>
{Array.isArray(children)
? (children as React.ReactNode[]).map((c, i) => (
<Reveal key={i} delay={i * stagger} y={14}>
{c}
</Reveal>
))
: children}
</>
);
}