Conversation
Keep the first-open visibility gate, but stop treating the sticky library's near-bottom lock as flush-to-bottom readiness. End restore may keep correcting to the real DOM bottom until reveal; after reveal, observers still cannot re-arm follow. Model: grok-4.6
Model: grok-4.6
Skip geometry-observer stopScroll only for the first end restore. An unrestored offset restore must still release a near-bottom relock so a content shrink cannot pull the cached reading position to the end. Model: grok-4.6
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 / pressure
Opening a Chat Session could leave the conversation pane permanently black while the message DOM was fully present. The first-open viewport stays
visibility: hiddenuntilinitialScrollRestored. That flag never flipped when the ready check treateduse-stick-to-bottom's ~70px near-bottom lock as "flush with the last row", and compared descendantgetBoundingClientRectagainst a scroller that is itselfvisibility: hiddenwithcontain: strict. The group-toggle follow-lock fix then stopped observers from correcting to the real bottom until a commit snapshot said the reader was already following — with no settle timer allowed, the pane stayed hidden.Summary
Keep the visibility gate. Ready now uses restore intent and viewport distance from the DOM bottom, not the library lock or last-row boxes. Until reveal, an end restore may keep writing the real bottom; a reader who already followed and escaped is not pulled back. After reveal, observers still cannot re-arm follow.
Visual explanation
sequenceDiagram participant View as SessionChatStreamView participant Hook as useStickyScroll participant Ready as isInitialScrollLayoutReady View->>View: visibility hidden until initialScrollRestored Hook->>Hook: apply cached end or offset alt end restore and lock never held Hook->>Hook: keep scrollToRealBottom from observers else reader already followed then escaped Hook->>Hook: do not pull to end end Hook->>Ready: following = restore intent is end Ready-->>Hook: destination row measured and distanceFromBottom <= 2 Hook-->>View: initialScrollRestored View->>View: visibility visibleBefore / after
visibility: hiddenwhen the 2px last-row flush fails or observersstopScroll()during first end-restoreTest plan
pnpm --filter @lody/components exec vitest run tests/use-sticky-scroll.test.ts tests/sticky-scroll-virtua.test.tsx— 32 passed, including last-row box 50px off still reveals at DOM bottom, near-bottom offset restore without a 2px flush, unmeasured destination stays hidden, and escaped readers are not re-armed on collapsee2e/scripts/capture-conversation-open-flicker.mjs) was not re-measuredRelated issue
Same-repository maintainer branch; no intake Issue.