From 6f8af789180a63eae5692bbeec3ab908c9c12092 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Fri, 8 Aug 2025 16:16:17 +0000 Subject: [PATCH] fix: improve chat window scroll behavior when user scrolls back to bottom - Re-enable auto-scroll when user scrolls down while at bottom - Increase atBottomThreshold from 10px to 50px for more forgiving detection - Auto-scroll on new messages if user is at bottom, even if auto-scroll is disabled - Handle row height changes better when user is at bottom This fixes the issue where the chat window would jump randomly and miss messages when the user scrolled up and then back down during API calls. Fixes #6852 --- webview-ui/src/components/chat/ChatView.tsx | 47 +++++++++++++++------ 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index 9b8c96dea1..3ecf39dfa6 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -1377,20 +1377,31 @@ const ChatViewComponent: React.ForwardRefRenderFunction { + // Only auto-scroll if we're supposed to be following the conversation if (!disableAutoScrollRef.current) { if (isTaller) { scrollToBottomSmooth() } else { setTimeout(() => scrollToBottomAuto(), 0) } + } else if (isAtBottom) { + // If auto-scroll is disabled but we're at the bottom, + // the user likely wants to follow along, so scroll anyway + if (isTaller) { + scrollToBottomSmooth() + } else { + setTimeout(() => scrollToBottomAuto(), 0) + } } }, - [scrollToBottomSmooth, scrollToBottomAuto], + [scrollToBottomSmooth, scrollToBottomAuto, isAtBottom], ) useEffect(() => { let timer: ReturnType | undefined - if (!disableAutoScrollRef.current) { + // Auto-scroll on new messages if auto-scroll is enabled OR if we're at the bottom + // This ensures we follow the conversation when the user is actively reading at the bottom + if (!disableAutoScrollRef.current || isAtBottom) { timer = setTimeout(() => scrollToBottomSmooth(), 50) } return () => { @@ -1398,18 +1409,27 @@ const ChatViewComponent: React.ForwardRefRenderFunction { - const wheelEvent = event as WheelEvent + const handleWheel = useCallback( + (event: Event) => { + const wheelEvent = event as WheelEvent - if (wheelEvent.deltaY && wheelEvent.deltaY < 0) { - if (scrollContainerRef.current?.contains(wheelEvent.target as Node)) { - // User scrolled up - disableAutoScrollRef.current = true + if (wheelEvent.deltaY) { + if (scrollContainerRef.current?.contains(wheelEvent.target as Node)) { + if (wheelEvent.deltaY < 0) { + // User scrolled up - disable auto-scroll + disableAutoScrollRef.current = true + } else if (wheelEvent.deltaY > 0 && isAtBottom) { + // User scrolled down and we're at bottom - re-enable auto-scroll + // This helps when user scrolls down to catch up with messages + disableAutoScrollRef.current = false + } + } } - } - }, []) + }, + [isAtBottom], + ) useEvent("wheel", handleWheel, window, { passive: true }) // passive improves scrolling performance @@ -1876,11 +1896,14 @@ const ChatViewComponent: React.ForwardRefRenderFunction { setIsAtBottom(isAtBottom) if (isAtBottom) { + // Re-enable auto-scroll when we reach the bottom disableAutoScrollRef.current = false } + // Show scroll-to-bottom button only when auto-scroll is disabled and not at bottom setShowScrollToBottom(disableAutoScrollRef.current && !isAtBottom) }} - atBottomThreshold={10} + // Increase threshold to be more forgiving about what counts as "at bottom" + atBottomThreshold={50} initialTopMostItemIndex={groupedMessages.length - 1} />