UNPKG

@intility/bifrost-react

Version:

React library for Intility's design system, Bifrost.

42 lines (41 loc) 1.8 kB
"use client"; import { useEffect, useState } from "react"; import closestElement, { isEverScrollable } from "../utils/closestElement.js"; /** * Listens to scroll event and reports which direction (`'up'` or `'down'`) the user is scrolling, * or `'none'` if not scrolled yet. * @param options Optional options object, with `threshold` and `elementRef` * @returns `'none'` if not scrolled yet, otherwise `'up'` or `'down'` */ export default function useScrollDirection({ threshold = 50, elementRef } = {}) { // inspired by https://stackoverflow.com/a/62497293/833146 const [scrollDir, setScrollDir] = useState("none"); useEffect(()=>{ // find closest element that can become scrollable. defaults to document.documentElement const scrollableElement = closestElement(isEverScrollable, elementRef?.current); let lastScrollY = scrollableElement.scrollTop; let ticking = false; const updateScrollDir = ()=>{ const scrollY = scrollableElement.scrollTop; if (Math.abs(scrollY - lastScrollY) < threshold) { ticking = false; return; } setScrollDir(scrollY > lastScrollY ? "down" : "up"); lastScrollY = scrollY > 0 ? scrollY : 0; ticking = false; }; const onScroll = ()=>{ if (!ticking) { requestAnimationFrame(updateScrollDir); ticking = true; } }; let eventTarget = scrollableElement; if (scrollableElement === document.documentElement) { eventTarget = document; } eventTarget.addEventListener("scroll", onScroll); return ()=>eventTarget.removeEventListener("scroll", onScroll); }, []); return scrollDir; }