UNPKG

shelving

Version:

Toolkit for using data in JavaScript.

41 lines (38 loc) 1.69 kB
import { type RefObject, useEffect, useRef } from "react"; import type { Callback } from "../../util/function.js"; import type { Nullish } from "../../util/null.js"; /** * Fires a callback when an element enters the visible scrolling area on the client. * - Checks that is the last element in its parent. * - Finds the closest parent above this that scrolls (e.g. `.page`, customisable with `selector` param), then fires the callbacks appropriately. */ export function useScrollIntersect<T extends HTMLElement>(onEnter?: Nullish<Callback>, onLeave?: Nullish<Callback>): RefObject<T | null> { const ref = useRef<T | null>(null); useEffect(() => { const el = ref.current; if (el) { const observer = new IntersectionObserver( ([entry]) => { if (entry) { if (entry.isIntersecting) onEnter?.(); if (!entry.isIntersecting) onLeave?.(); } }, { threshold: [1] }, ); observer.observe(el); return () => observer.disconnect(); } }, [onEnter, onLeave]); return ref; } /** Go through a list of `IntersectionObserverEntry` (from `IntersectionObserver`) and return the index of the one with the highest `intersectionRatio` */ export function getMostVisibleObserverEntry(entries: IntersectionObserverEntry[]): IntersectionObserverEntry | undefined { return entries.reduce<IntersectionObserverEntry | undefined>(_reduceMostVisibleObserverEntry, undefined); } function _reduceMostVisibleObserverEntry( mostVisible: IntersectionObserverEntry | undefined, current: IntersectionObserverEntry, ): IntersectionObserverEntry | undefined { return mostVisible && mostVisible.intersectionRatio > current.intersectionRatio ? mostVisible : current; }