ultisuite-client/components/landing/landing-reveal.tsx
R3D347HR4Y 303b2b1074
Some checks are pending
E2E / Playwright e2e (push) Waiting to run
wow
2026-06-11 01:22:40 +02:00

55 lines
1.4 KiB
TypeScript

"use client"
import { useEffect, useRef, useState, type ReactNode } from "react"
import { cn } from "@/lib/utils"
interface LandingRevealProps {
children: ReactNode
className?: string
/** Délai (s) appliqué à la transition — pour le stagger. */
delay?: number
as?: "div" | "section" | "li" | "span"
}
/** Révèle son contenu à l'entrée dans le viewport (une seule fois). */
export function LandingReveal({
children,
className,
delay = 0,
as: Tag = "div",
}: LandingRevealProps) {
const ref = useRef<HTMLElement | null>(null)
const [revealed, setRevealed] = useState(false)
useEffect(() => {
const node = ref.current
if (!node || revealed) return
if (typeof IntersectionObserver === "undefined") {
setRevealed(true)
return
}
const observer = new IntersectionObserver(
(entries) => {
if (entries.some((entry) => entry.isIntersecting)) {
setRevealed(true)
observer.disconnect()
}
},
{ threshold: 0.12, rootMargin: "0px 0px -36px 0px" }
)
observer.observe(node)
return () => observer.disconnect()
}, [revealed])
return (
<Tag
ref={ref as never}
className={cn("landing-reveal", className)}
data-revealed={revealed}
style={delay ? ({ "--reveal-delay": `${delay}s` } as React.CSSProperties) : undefined}
>
{children}
</Tag>
)
}