38 lines
1.0 KiB
TypeScript
38 lines
1.0 KiB
TypeScript
import { useEffect, useRef } from 'react'
|
|
import { usePrefersReducedMotion } from './usePrefersReducedMotion'
|
|
|
|
/** Reveal children with `.reveal` when the root enters the viewport. */
|
|
export function useReveal<T extends HTMLElement>() {
|
|
const ref = useRef<T | null>(null)
|
|
const reduced = usePrefersReducedMotion()
|
|
|
|
useEffect(() => {
|
|
const root = ref.current
|
|
if (!root) return
|
|
|
|
if (reduced) {
|
|
root.classList.add('is-visible')
|
|
root.querySelectorAll('.reveal').forEach((el) => el.classList.add('is-visible'))
|
|
return
|
|
}
|
|
|
|
const targets = [root, ...root.querySelectorAll<HTMLElement>('.reveal')]
|
|
|
|
const io = new IntersectionObserver(
|
|
(entries) => {
|
|
for (const entry of entries) {
|
|
if (!entry.isIntersecting) continue
|
|
entry.target.classList.add('is-visible')
|
|
io.unobserve(entry.target)
|
|
}
|
|
},
|
|
{ threshold: 0.12, rootMargin: '0px 0px -6% 0px' },
|
|
)
|
|
|
|
for (const el of targets) io.observe(el)
|
|
return () => io.disconnect()
|
|
}, [reduced])
|
|
|
|
return ref
|
|
}
|