File size: 1,416 Bytes
7312c42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import { useEffect, useState, type RefObject } from 'react'

export const DEFAULT_LAZY_INTERSECTION_DELAY_MS = 180
const DEFAULT_INTERSECTION_OBSERVER_INIT: IntersectionObserverInit = { threshold: 0 }

interface UseDelayedIntersectionOptions {
  delayMs?: number
  observerInit?: IntersectionObserverInit
}

export function useDelayedIntersection<T extends Element>(
  ref: RefObject<T | null>,
  {
    delayMs = DEFAULT_LAZY_INTERSECTION_DELAY_MS,
    observerInit = DEFAULT_INTERSECTION_OBSERVER_INIT,
  }: UseDelayedIntersectionOptions = {},
): boolean {
  const [intersected, setIntersected] = useState(false)

  useEffect(() => {
    if (intersected) return

    const element = ref.current
    if (!element) return

    if (typeof IntersectionObserver === 'undefined') {
      setIntersected(true)
      return
    }

    let timer: ReturnType<typeof setTimeout> | undefined
    const observer = new IntersectionObserver(([entry]) => {
      if (entry.isIntersecting) {
        timer ??= setTimeout(() => {
          setIntersected(true)
          observer.disconnect()
        }, delayMs)
        return
      }

      if (timer) {
        clearTimeout(timer)
        timer = undefined
      }
    }, observerInit)

    observer.observe(element)

    return () => {
      if (timer) clearTimeout(timer)
      observer.disconnect()
    }
  }, [delayMs, intersected, observerInit, ref])

  return intersected
}