fix(#552): release stick-to-bottom on any upward user scroll
The chat viewport previously only released stick-to-bottom when the user scrolled up AND was already more than 200px from the bottom. While reading near the end of a streaming response, any upward scroll inside the bottom 200px did nothing — the ResizeObserver then yanked the viewport back to the bottom on the next streaming chunk, producing the 'can't scroll up' tug-of-war reported in #552. Fix: any user-initiated upward scroll releases stick-to-bottom immediately. Re-stick only when the user has stopped scrolling up AND is at the bottom (<=NEAR_BOTTOM_THRESHOLD). Applied symmetrically in ChatContainerRoot (handleScroll) and in chat-message-list's handleUserScroll mirror.
This commit is contained in:
@@ -48,13 +48,21 @@ function ChatContainerRoot({
|
|||||||
if (!element) return
|
if (!element) return
|
||||||
|
|
||||||
const handleScroll = () => {
|
const handleScroll = () => {
|
||||||
// Track stick-to-bottom internally based on actual scroll position
|
// Track stick-to-bottom internally based on actual scroll position.
|
||||||
|
// Bug #552: previously we only released stick-to-bottom when the user
|
||||||
|
// both scrolled up AND was already >200px from bottom. That meant any
|
||||||
|
// upward scroll within the bottom 200px did nothing — and during heavy
|
||||||
|
// streaming the ResizeObserver immediately yanked the viewport back to
|
||||||
|
// the bottom on the next content growth, producing the "can't scroll up"
|
||||||
|
// tug-of-war. Fix: ANY user-initiated upward scroll releases stick. Only
|
||||||
|
// re-stick when the user has stopped scrolling up AND is right at the
|
||||||
|
// bottom (≤NEAR_BOTTOM_THRESHOLD).
|
||||||
const distFromBottom =
|
const distFromBottom =
|
||||||
element.scrollHeight - element.scrollTop - element.clientHeight
|
element.scrollHeight - element.scrollTop - element.clientHeight
|
||||||
const wasScrollingUp = element.scrollTop < lastScrollTopRef.current - 5
|
const wasScrollingUp = element.scrollTop < lastScrollTopRef.current - 5
|
||||||
lastScrollTopRef.current = element.scrollTop
|
lastScrollTopRef.current = element.scrollTop
|
||||||
|
|
||||||
if (wasScrollingUp && distFromBottom > NEAR_BOTTOM_THRESHOLD) {
|
if (wasScrollingUp) {
|
||||||
stickToBottomRef.current = false
|
stickToBottomRef.current = false
|
||||||
} else if (distFromBottom <= NEAR_BOTTOM_THRESHOLD) {
|
} else if (distFromBottom <= NEAR_BOTTOM_THRESHOLD) {
|
||||||
stickToBottomRef.current = true
|
stickToBottomRef.current = true
|
||||||
|
|||||||
@@ -722,7 +722,11 @@ function ChatMessageListComponent({
|
|||||||
const wasScrollingUp = metrics.scrollTop < lastScrollTopRef.current - 5
|
const wasScrollingUp = metrics.scrollTop < lastScrollTopRef.current - 5
|
||||||
lastScrollTopRef.current = metrics.scrollTop
|
lastScrollTopRef.current = metrics.scrollTop
|
||||||
|
|
||||||
if (wasScrollingUp && !nearBottom) {
|
// Bug #552: any user-initiated upward scroll releases stick-to-bottom
|
||||||
|
// (previously required >200px from bottom, which let streaming yank the
|
||||||
|
// viewport back down during near-bottom reading). Re-stick only when the
|
||||||
|
// user lands back at the bottom.
|
||||||
|
if (wasScrollingUp) {
|
||||||
stickToBottomRef.current = false
|
stickToBottomRef.current = false
|
||||||
isNearBottomRef.current = false
|
isNearBottomRef.current = false
|
||||||
} else if (nearBottom) {
|
} else if (nearBottom) {
|
||||||
|
|||||||
Reference in New Issue
Block a user