62 lines
1.3 KiB
TypeScript
62 lines
1.3 KiB
TypeScript
"use client"
|
|
|
|
import { type HTMLAttributes, useEffect, useRef, useState } from "react"
|
|
import { cn } from "@/lib/utils"
|
|
|
|
type SectionRevealProps = HTMLAttributes<HTMLDivElement> & {
|
|
delay?: number
|
|
}
|
|
|
|
export function SectionReveal({
|
|
children,
|
|
className,
|
|
delay = 0,
|
|
style,
|
|
...props
|
|
}: SectionRevealProps) {
|
|
const ref = useRef<HTMLDivElement | null>(null)
|
|
const [visible, setVisible] = useState(false)
|
|
|
|
useEffect(() => {
|
|
const node = ref.current
|
|
|
|
if (!node) {
|
|
return
|
|
}
|
|
|
|
const observer = new IntersectionObserver(
|
|
([entry]) => {
|
|
if (entry.isIntersecting) {
|
|
setVisible(true)
|
|
observer.disconnect()
|
|
}
|
|
},
|
|
{
|
|
threshold: 0.18,
|
|
rootMargin: "0px 0px -10% 0px",
|
|
}
|
|
)
|
|
|
|
observer.observe(node)
|
|
|
|
return () => observer.disconnect()
|
|
}, [])
|
|
|
|
return (
|
|
<div
|
|
ref={ref}
|
|
{...props}
|
|
className={cn(
|
|
"motion-safe:transition-[opacity,transform,filter] motion-safe:duration-[1200ms] motion-safe:[transition-timing-function:cubic-bezier(0.22,1,0.36,1)] motion-safe:will-change-transform",
|
|
visible
|
|
? "opacity-100 translate-y-0 scale-100 blur-0"
|
|
: "opacity-0 translate-y-10 scale-[0.985] blur-[10px]",
|
|
className
|
|
)}
|
|
style={{ ...style, transitionDelay: `${delay}ms` }}
|
|
>
|
|
{children}
|
|
</div>
|
|
)
|
|
}
|