import type { UIMessage } from "ai"; import { useCallback, useEffect, useState } from "react"; const NEAR_BOTTOM_THRESHOLD = 80; interface UseChatScrollOptions { messages: UIMessage[]; scrollRef: React.RefObject; status: string; } export function useChatScroll({ messages, scrollRef, status }: UseChatScrollOptions) { const [isAtBottom, setIsAtBottom] = useState(true); const isStreaming = status === "streaming"; const checkNearBottom = useCallback(() => { const el = scrollRef.current; if (!el) return true; return el.scrollHeight - el.scrollTop - el.clientHeight < NEAR_BOTTOM_THRESHOLD; }, [scrollRef]); useEffect(() => { const el = scrollRef.current; if (!el) return; setIsAtBottom(checkNearBottom()); const handleScroll = () => { setIsAtBottom(checkNearBottom()); }; el.addEventListener("scroll", handleScroll, { passive: true }); return () => el.removeEventListener("scroll", handleScroll); }, [scrollRef, checkNearBottom]); useEffect(() => { const el = scrollRef.current; if (!el || !isAtBottom) return; el.scrollTo({ behavior: isStreaming ? "instant" : "smooth", top: el.scrollHeight, }); }, [messages, isStreaming, isAtBottom, scrollRef]); const scrollToBottom = useCallback(() => { const el = scrollRef.current; if (!el) return; el.scrollTo({ behavior: "smooth", top: el.scrollHeight }); setIsAtBottom(true); }, [scrollRef]); return { isAtBottom, scrollToBottom }; }