import { type RefObject, useEffect, useState } from "react" interface UseScrollToTopProps { threshold: number /** * Direct element reference. Use this when the element is conditionally * rendered or when you need to reference a parent element via state. * Takes precedence over elementRef if both are provided. */ element?: HTMLElement | null /** * Ref to the element. Use this when you have a direct ref attachment * to the scrollable element. */ elementRef?: RefObject refScrollable?: boolean } export function useScrollToTop({ threshold, element, elementRef, refScrollable, }: UseScrollToTopProps) { const [showBackToTop, setShowBackToTop] = useState(false) useEffect(() => { const targetElement = element ?? elementRef?.current const scrollTarget = refScrollable && targetElement ? targetElement : window function handleScroll() { const currentElement = element ?? elementRef?.current let position = window.scrollY if (currentElement) { position = refScrollable ? currentElement.scrollTop : currentElement.getBoundingClientRect().top * -1 } setShowBackToTop(position > threshold) } scrollTarget.addEventListener("scroll", handleScroll, { passive: true }) return () => scrollTarget.removeEventListener("scroll", handleScroll) }, [threshold, element, elementRef, refScrollable]) function scrollToTop() { const targetElement = element ?? elementRef?.current if (targetElement) { if (refScrollable) { targetElement.scrollTo({ top: 0, behavior: "smooth" }) } else { window.scrollTo({ top: targetElement.offsetTop, behavior: "smooth" }) } } else { window.scrollTo({ top: 0, behavior: "smooth" }) } } return { showBackToTop, scrollToTop } }