fix(thread): stop ChatThread snapping to top on prompt submit#3083
Merged
Conversation
Stable row keys keep the optimistic user bubble's DOM element across the echoed-prompt swap and a lone tool marker's element across tool-group collapse, so quill's message scroller never sees a count-neutral childList mutation (its re-anchor fallback scrolls to the first never-handled anchor, i.e. the first user message in the conversation). New prompts now anchor to the viewport top explicitly via scrollToMessage, since the engine's implicit anchor path can't fire while the footer is a scroller-content child. Generated-By: PostHog Code Task-Id: c30ae5a8-6f18-4a44-882e-a1b29ea84154
|
React Doctor found no issues in the changed files. 🎉 Reviewed by React Doctor for commit |
Contributor
|
Reviews (1): Last reviewed commit: "fix(thread): stop ChatThread snapping to..." | Re-trigger Greptile |
Generated-By: PostHog Code Task-Id: c30ae5a8-6f18-4a44-882e-a1b29ea84154
The scroller only auto-follows in following-bottom mode, which it re-enters solely within 8px of the exact bottom. With the thread's bottom padding the view is rarely that close, and any stray trackpad wheel drops out of follow mode permanently. Scroll to end on every user submit (which also re-engages follow mode for the streaming reply) and widen the edge threshold to 100px so near-bottom counts as at-bottom for recapture. Generated-By: PostHog Code Task-Id: c30ae5a8-6f18-4a44-882e-a1b29ea84154
There was a problem hiding this comment.
No showstoppers — this is a focused, self-contained UI scroll-behavior fix with no data model, API contract, or business logic changes. The tool_group id simplification is safe (no key collision), the new ScrollToEndOnSubmit component uses correct React patterns, and the wider scroll threshold is a reasonable UX improvement.
…n it The engine guards each autoscroll with a 180ms grace window; a big streamed block can jank past it, so the engine sees content below the fold while not autoscrolling and demotes itself to free-scrolling mid-reply. Arm a pin on submit that re-issues scrollToEnd whenever content slips below the fold, disarmed by user scroll intent. Generated-By: PostHog Code Task-Id: c30ae5a8-6f18-4a44-882e-a1b29ea84154
New commits pushed (delta classified non_trivial_delta) — stamphog approval dismissed; re-review running automatically.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
In the new ChatThread view (behind
useNewChatThread):Root causes
The snap. quill's message scroller reacts to childList mutations on the scroller content by comparing direct-child counts. When a prompt is sent, the optimistic user bubble (
optimistic-…id) is swapped for the echoed real prompt (turn-…-userid) in a single React commit — a mutation where the child count doesn't change. In that case the engine falls into a re-anchor branch that scans all rows from the top for the firstdata-scroll-anchorelement it hasn't scrolled to before. Historical user messages never qualify as handled, so it scrolls to the first user message in the conversation. A second trigger of the same branch: a lone tool marker collapsing into atool_grouprow (1 row → 1 row, key change) mid-response.Unreliable following. The engine only auto-follows in
following-bottommode, which it re-enters solely withinscrollEdgeThreshold(default 8px) of the exact bottom — with the thread's bottom padding the view is rarely that close, and any stray trackpad wheel exits follow mode. Additionally, each engine autoscroll is guarded by a 180ms grace window; a large streamed block (heavy markdown render) can jank past it, making the engine observe "content below the fold while not autoscrolling" and demote itself tofree-scrollingmid-reply.Fix
All in
ChatThread.tsx:user-turn-N) instead ofitem.id, so the optimistic→real swap reuses the same DOM element and the buggy re-anchor branch never fires.tool_groupid, so a lone marker growing into a group keeps its key/element.ThreadAutoFollow: pin the view to the bottom from prompt submit until the user scrolls away — scroll to end on submit (which also re-engages the engine'sfollowing-bottom), and while armed re-issuescrollToEndwhenever content slips below the fold, recapturing follow after stream bursts. User scroll intent (wheel/touch/pointer/keys) disarms.scrollEdgeThresholdto 100px so near-bottom counts as at-bottom for the engine's own follow-mode recapture.Follow-up: the underlying count-neutral re-anchor bug should also be fixed upstream in
@posthog/quill's message scroller.Created with PostHog Code