Skip to content

Commit 0c3a8ba

Browse files
committed
fix: improve auto-scroll behavior during API activities and streaming
- Keep auto-scroll enabled during streaming unless user explicitly scrolls up - Prevent disabling auto-scroll when expanding rows during streaming - Improve scroll-to-bottom logic to handle API activities better - Fix issue where scrollbar jumps up during long conversations Fixes #6987
1 parent 12d1959 commit 0c3a8ba

File tree

1 file changed

+41
-30
lines changed

1 file changed

+41
-30
lines changed

webview-ui/src/components/chat/ChatView.tsx

Lines changed: 41 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -465,26 +465,6 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
465465
}
466466
}, [])
467467

468-
useEffect(() => {
469-
const prev = prevExpandedRowsRef.current
470-
let wasAnyRowExpandedByUser = false
471-
if (prev) {
472-
// Check if any row transitioned from false/undefined to true
473-
for (const [tsKey, isExpanded] of Object.entries(expandedRows)) {
474-
const ts = Number(tsKey)
475-
if (isExpanded && !(prev[ts] ?? false)) {
476-
wasAnyRowExpandedByUser = true
477-
break
478-
}
479-
}
480-
}
481-
482-
if (wasAnyRowExpandedByUser) {
483-
disableAutoScrollRef.current = true
484-
}
485-
prevExpandedRowsRef.current = expandedRows // Store current state for next comparison
486-
}, [expandedRows])
487-
488468
const isStreaming = useMemo(() => {
489469
// Checking clineAsk isn't enough since messages effect may be called
490470
// again for a tool for example, set clineAsk to its value, and if the
@@ -529,6 +509,27 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
529509
return false
530510
}, [modifiedMessages, clineAsk, enableButtons, primaryButtonText])
531511

512+
useEffect(() => {
513+
const prev = prevExpandedRowsRef.current
514+
let wasAnyRowExpandedByUser = false
515+
if (prev) {
516+
// Check if any row transitioned from false/undefined to true
517+
for (const [tsKey, isExpanded] of Object.entries(expandedRows)) {
518+
const ts = Number(tsKey)
519+
if (isExpanded && !(prev[ts] ?? false)) {
520+
wasAnyRowExpandedByUser = true
521+
break
522+
}
523+
}
524+
}
525+
526+
// Don't disable auto-scroll during streaming even if rows are expanded
527+
if (wasAnyRowExpandedByUser && !isStreaming) {
528+
disableAutoScrollRef.current = true
529+
}
530+
prevExpandedRowsRef.current = expandedRows // Store current state for next comparison
531+
}, [expandedRows, isStreaming])
532+
532533
const markFollowUpAsAnswered = useCallback(() => {
533534
const lastFollowUpMessage = messagesRef.current.findLast((msg: ClineMessage) => msg.ask === "followup")
534535
if (lastFollowUpMessage) {
@@ -1390,26 +1391,32 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
13901391

13911392
useEffect(() => {
13921393
let timer: ReturnType<typeof setTimeout> | undefined
1393-
if (!disableAutoScrollRef.current) {
1394+
// Always scroll to bottom during streaming unless user explicitly scrolled up
1395+
if (!disableAutoScrollRef.current || isStreaming) {
13941396
timer = setTimeout(() => scrollToBottomSmooth(), 50)
13951397
}
13961398
return () => {
13971399
if (timer) {
13981400
clearTimeout(timer)
13991401
}
14001402
}
1401-
}, [groupedMessages.length, scrollToBottomSmooth])
1403+
}, [groupedMessages.length, scrollToBottomSmooth, isStreaming])
14021404

1403-
const handleWheel = useCallback((event: Event) => {
1404-
const wheelEvent = event as WheelEvent
1405+
const handleWheel = useCallback(
1406+
(event: Event) => {
1407+
const wheelEvent = event as WheelEvent
14051408

1406-
if (wheelEvent.deltaY && wheelEvent.deltaY < 0) {
1407-
if (scrollContainerRef.current?.contains(wheelEvent.target as Node)) {
1408-
// User scrolled up
1409-
disableAutoScrollRef.current = true
1409+
if (wheelEvent.deltaY && wheelEvent.deltaY < 0) {
1410+
if (scrollContainerRef.current?.contains(wheelEvent.target as Node)) {
1411+
// User scrolled up - but don't disable during streaming if we're near bottom
1412+
if (!isStreaming || !isAtBottom) {
1413+
disableAutoScrollRef.current = true
1414+
}
1415+
}
14101416
}
1411-
}
1412-
}, [])
1417+
},
1418+
[isStreaming, isAtBottom],
1419+
)
14131420

14141421
useEvent("wheel", handleWheel, window, { passive: true }) // passive improves scrolling performance
14151422

@@ -1878,6 +1885,10 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
18781885
if (isAtBottom) {
18791886
disableAutoScrollRef.current = false
18801887
}
1888+
// During streaming, always keep auto-scroll enabled unless user explicitly scrolled
1889+
if (isStreaming && isAtBottom) {
1890+
disableAutoScrollRef.current = false
1891+
}
18811892
setShowScrollToBottom(disableAutoScrollRef.current && !isAtBottom)
18821893
}}
18831894
atBottomThreshold={10}

0 commit comments

Comments
 (0)