import { useEffect, useRef, useState } from "react"; // How many pixels from the bottom of the container to enable auto-scroll const ACTIVATION_THRESHOLD = 50; // Minimum pixels of scroll-up movement required to disable auto-scroll const MIN_SCROLL_UP_THRESHOLD = 10; export function useAutoScroll(dependencies: React.DependencyList) { const containerRef = useRef(null); const previousScrollTop = useRef(null); const [shouldAutoScroll, setShouldAutoScroll] = useState(true); const scrollToBottom = () => { if (containerRef.current) { containerRef.current.scrollTop = containerRef.current.scrollHeight; } }; const handleScroll = () => { if (containerRef.current) { const { scrollTop, scrollHeight, clientHeight } = containerRef.current; const distanceFromBottom = Math.abs( scrollHeight - scrollTop - clientHeight ); const isScrollingUp = previousScrollTop.current ? scrollTop < previousScrollTop.current : false; const scrollUpDistance = previousScrollTop.current ? previousScrollTop.current - scrollTop : 0; const isDeliberateScrollUp = isScrollingUp && scrollUpDistance > MIN_SCROLL_UP_THRESHOLD; if (isDeliberateScrollUp) { setShouldAutoScroll(false); } else { const isScrolledToBottom = distanceFromBottom < ACTIVATION_THRESHOLD; setShouldAutoScroll(isScrolledToBottom); } previousScrollTop.current = scrollTop; } }; const handleTouchStart = () => { setShouldAutoScroll(false); }; useEffect(() => { if (containerRef.current) { previousScrollTop.current = containerRef.current.scrollTop; } }, []); useEffect(() => { if (shouldAutoScroll) { scrollToBottom(); } // eslint-disable-next-line react-hooks/exhaustive-deps }, dependencies); return { containerRef, scrollToBottom, handleScroll, shouldAutoScroll, handleTouchStart, }; }