From 6b8c6498769a3716fc34b83384bdf9d3cb2d944c Mon Sep 17 00:00:00 2001 From: Yuichiro Utsumi <81412151+utsumi-fj@users.noreply.github.com> Date: Wed, 26 Nov 2025 23:39:29 +0900 Subject: [PATCH] fix: prevent auto-scrolling from stopping in chat (#28690) Signed-off-by: Yuichiro Utsumi Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- web/app/components/base/chat/chat/index.tsx | 40 +++++++++++++++------ 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/web/app/components/base/chat/chat/index.tsx b/web/app/components/base/chat/chat/index.tsx index a362f4dc99..51b5df4f32 100644 --- a/web/app/components/base/chat/chat/index.tsx +++ b/web/app/components/base/chat/chat/index.tsx @@ -128,10 +128,17 @@ const Chat: FC = ({ const chatFooterRef = useRef(null) const chatFooterInnerRef = useRef(null) const userScrolledRef = useRef(false) + const isAutoScrollingRef = useRef(false) const handleScrollToBottom = useCallback(() => { - if (chatList.length > 1 && chatContainerRef.current && !userScrolledRef.current) + if (chatList.length > 1 && chatContainerRef.current && !userScrolledRef.current) { + isAutoScrollingRef.current = true chatContainerRef.current.scrollTop = chatContainerRef.current.scrollHeight + + requestAnimationFrame(() => { + isAutoScrollingRef.current = false + }) + } }, [chatList.length]) const handleWindowResize = useCallback(() => { @@ -198,18 +205,31 @@ const Chat: FC = ({ }, [handleScrollToBottom]) useEffect(() => { - const chatContainer = chatContainerRef.current - if (chatContainer) { - const setUserScrolled = () => { - // eslint-disable-next-line sonarjs/no-gratuitous-expressions - if (chatContainer) // its in event callback, chatContainer may be null - userScrolledRef.current = chatContainer.scrollHeight - chatContainer.scrollTop > chatContainer.clientHeight - } - chatContainer.addEventListener('scroll', setUserScrolled) - return () => chatContainer.removeEventListener('scroll', setUserScrolled) + const setUserScrolled = () => { + const container = chatContainerRef.current + if (!container) return + + if (isAutoScrollingRef.current) return + + const distanceToBottom = container.scrollHeight - container.clientHeight - container.scrollTop + const SCROLL_UP_THRESHOLD = 100 + + userScrolledRef.current = distanceToBottom > SCROLL_UP_THRESHOLD } + + const container = chatContainerRef.current + if (!container) return + + container.addEventListener('scroll', setUserScrolled) + return () => container.removeEventListener('scroll', setUserScrolled) }, []) + // Reset user scroll state when a new chat starts (length <= 1) + useEffect(() => { + if (chatList.length <= 1) + userScrolledRef.current = false + }, [chatList.length]) + useEffect(() => { if (!sidebarCollapseState) setTimeout(() => handleWindowResize(), 200)