From a81dc52d775befc41358950b925f0eba9b78c081 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Sun, 14 Sep 2025 16:20:50 +0000 Subject: [PATCH] fix: preserve scroll position when reading LLM output - Added userHasScrolledUpRef to track when user manually scrolls up - Modified wheel event handler to detect scroll direction - Only re-enable auto-scroll when user explicitly scrolls down to bottom - Prevent auto-scroll from re-enabling when reaching bottom passively - Reset scroll state when starting new tasks Fixes #7974 --- webview-ui/src/components/chat/ChatView.tsx | 35 ++++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index d358c68f1c..62dcad6af8 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -188,6 +188,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction>() const scrollContainerRef = useRef(null) const disableAutoScrollRef = useRef(false) + const userHasScrolledUpRef = useRef(false) const [showScrollToBottom, setShowScrollToBottom] = useState(false) const [isAtBottom, setIsAtBottom] = useState(false) const lastTtsRef = useRef("") @@ -477,6 +478,9 @@ const ChatViewComponent: React.ForwardRefRenderFunction { @@ -508,6 +512,7 @@ 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 < 0) { + // User scrolled up - disable auto-scroll and mark that user has scrolled up + disableAutoScrollRef.current = true + userHasScrolledUpRef.current = true + } else if (wheelEvent.deltaY > 0 && isAtBottom) { + // User scrolled down while at bottom - re-enable auto-scroll + // This indicates intentional scrolling to bottom to resume following output + disableAutoScrollRef.current = false + userHasScrolledUpRef.current = false + } } - } - }, []) + }, + [isAtBottom], + ) useEvent("wheel", handleWheel, window, { passive: true }) // passive improves scrolling performance @@ -1880,7 +1895,9 @@ const ChatViewComponent: React.ForwardRefRenderFunction { setIsAtBottom(isAtBottom) - if (isAtBottom) { + // Only re-enable auto-scroll if user hasn't manually scrolled up + // When user manually scrolls to bottom, the wheel handler will re-enable it + if (isAtBottom && !userHasScrolledUpRef.current) { disableAutoScrollRef.current = false } setShowScrollToBottom(disableAutoScrollRef.current && !isAtBottom) @@ -1905,7 +1922,9 @@ const ChatViewComponent: React.ForwardRefRenderFunction { scrollToBottomSmooth() + // User explicitly clicked to scroll to bottom - re-enable auto-scroll disableAutoScrollRef.current = false + userHasScrolledUpRef.current = false }}>