Skip to content

Commit 3b99234

Browse files
committed
fix(file-viewer): prevent false re-engage when spacer restoration triggers onScroll
1 parent 62ecc74 commit 3b99234

1 file changed

Lines changed: 11 additions & 1 deletion

File tree

apps/sim/hooks/use-scroll-anchor.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ export function useScrollAnchor(isStreaming: boolean, content?: string) {
3636
const stickyRef = useRef(false)
3737
// Tracks the user's last intentional position; updated only on genuine user events, never programmatic ones.
3838
const intendedScrollTopRef = useRef(0)
39+
// Mirrors the spacer's current minHeight so onScroll can check it without a layout read.
40+
// Re-engagement is blocked while the spacer is active: the spacer inflates scrollHeight to
41+
// exactly targetScrollTop + clientHeight, so distanceFromBottom = 0 after restoration —
42+
// which would otherwise falsely trigger the re-engage branch and clear the spacer.
43+
const spacerHeightRef = useRef(0)
3944

4045
const scrollToBottom = useCallback(() => {
4146
const el = containerRef.current
@@ -59,7 +64,10 @@ export function useScrollAnchor(isStreaming: boolean, content?: string) {
5964
if (hasUserScrolledRef.current) {
6065
intendedScrollTopRef.current = el.scrollTop
6166
const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight
62-
if (distanceFromBottom <= NEAR_BOTTOM_THRESHOLD) {
67+
// Only re-engage when the spacer is not active. While the spacer is inflated,
68+
// distanceFromBottom reads 0 after programmatic scroll restoration — that is
69+
// artificial proximity, not the user genuinely reaching the document bottom.
70+
if (distanceFromBottom <= NEAR_BOTTOM_THRESHOLD && spacerHeightRef.current === 0) {
6371
hasUserScrolledRef.current = false
6472
stickyRef.current = true
6573
}
@@ -132,6 +140,7 @@ export function useScrollAnchor(isStreaming: boolean, content?: string) {
132140
if (!el) return
133141

134142
if (!hasUserScrolledRef.current || !isStreaming) {
143+
spacerHeightRef.current = 0
135144
if (spacer) spacer.style.minHeight = '0'
136145
return
137146
}
@@ -148,6 +157,7 @@ export function useScrollAnchor(isStreaming: boolean, content?: string) {
148157
prevSpacerHeight
149158
)
150159

160+
spacerHeightRef.current = shortage
151161
if (spacer) spacer.style.minHeight = `${shortage}px`
152162
if (el.scrollTop < targetScrollTop) el.scrollTop = targetScrollTop
153163
}, [content, isStreaming])

0 commit comments

Comments
 (0)