Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | import { useCallback, useEffect, useRef, useState } from "react"; const SCROLL_THRESHOLD = 80; export function useAutoScroll( changeKey: unknown, options?: { followOnChange?: boolean; }, ) { const containerRef = useRef<HTMLDivElement>(null); const [showNewMessages, setShowNewMessages] = useState(false); const userScrolledRef = useRef(false); const rafRef = useRef<number>(0); const followOnChange = options?.followOnChange ?? true; const handleScroll = useCallback(() => { const el = containerRef.current; if (!el) return; const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight < SCROLL_THRESHOLD; userScrolledRef.current = !atBottom; if (atBottom) { setShowNewMessages(false); } }, []); useEffect(() => { const el = containerRef.current; if (!el) return; el.addEventListener("scroll", handleScroll, { passive: true }); return () => el.removeEventListener("scroll", handleScroll); }, [handleScroll]); useEffect(() => { const el = containerRef.current; if (!el) return; if (!followOnChange) return; if (!userScrolledRef.current) { cancelAnimationFrame(rafRef.current); rafRef.current = requestAnimationFrame(() => { el.scrollTo({ top: el.scrollHeight, behavior: "instant" }); }); } else { // eslint-disable-next-line react-hooks/set-state-in-effect -- badge visibility should change with the message batch that triggered this effect, not one frame later. setShowNewMessages(true); } }, [changeKey, followOnChange]); useEffect(() => { return () => { cancelAnimationFrame(rafRef.current); }; }, []); const scrollToBottom = useCallback(() => { const el = containerRef.current; if (!el) return; el.scrollTo({ top: el.scrollHeight, behavior: "smooth" }); userScrolledRef.current = false; setShowNewMessages(false); }, []); return { containerRef, showNewMessages, setShowNewMessages, scrollToBottom, userScrolledRef }; } |