"use client" import { type RefObject, useEffect, useState, useRef, useCallback } from "react" import { useThrottledCallback } from "./external" const TOP_THRESHOLD = 150 export const useScrollDirection = ({ delay = 150, el, }: { delay?: number el?: RefObject } = {}) => { const [isTopOfPage, setIsTopOfPage] = useState(true) const [isBottomOfPage, setIsBottomOfPage] = useState(false) const [scrollDirection, setScrollDirection] = useState<"up" | "down">() const lastScrollY = useRef(0) const setScrollDirectionDown = useThrottledCallback( () => { setScrollDirection("down") }, delay, { leading: false }, ) const handleScroll = useCallback(() => { const scrollEl = el?.current ?? window const currentScrollY = scrollEl instanceof Window ? scrollEl.scrollY : scrollEl.scrollTop const isTop = currentScrollY <= TOP_THRESHOLD const isBottom = scrollEl instanceof Window ? window.innerHeight + window.scrollY >= document.documentElement.scrollHeight : scrollEl.scrollHeight - scrollEl.scrollTop <= scrollEl.clientHeight + 1 setIsTopOfPage(isTop) setIsBottomOfPage(isBottom) if (currentScrollY > lastScrollY.current) { setScrollDirectionDown() } else if (currentScrollY < lastScrollY.current) { // Immediately cancel any pending "down" updates setScrollDirectionDown.cancel() setScrollDirection("up") } lastScrollY.current = currentScrollY }, [el, setScrollDirectionDown]) useEffect(() => { const scrollEl = el?.current ?? window scrollEl.addEventListener("scroll", handleScroll) return () => { scrollEl.removeEventListener("scroll", handleScroll) // Clean up any pending debounced calls setScrollDirectionDown.cancel() } }, [handleScroll, el, setScrollDirectionDown]) return { isTopOfPage, isBottomOfPage, scrollDirection } }