fix(web): stop zero-height measurements from desyncing virtualized lists - #943
Open
sheepbox8646 wants to merge 1 commit into
Open
fix(web): stop zero-height measurements from desyncing virtualized lists#943sheepbox8646 wants to merge 1 commit into
sheepbox8646 wants to merge 1 commit into
Conversation
Rows in measured-row virtualizers (sidebar Recents, model pickers) can be (re)measured while they cannot be laid out — their pane is display:none behind a v-show'd sidebar view, or the node was just detached by a window shift. Those measurements report height 0, and recording them poisons the virtualizer twice over: the spacer collapses, and the later 0-to-real re-measure runs scroll compensation on an element whose scrollTop cannot move, walking the virtualizer's internal offset away from the element's real scrollTop one row at a time. Recents then opens with a dead gap at the top and only the oldest sessions visible until a real scroll event resyncs it. Add measureVirtualRow, a shared measureElement guard that treats a zero-height measurement as "unmeasurable right now" and keeps the last known row size, and wire it into the three measured-row virtualizers. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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
The sidebar Recents list would randomly open with a dead gap below the header and only the oldest sessions visible — newly created sessions seemed to disappear. A re-login (full reload) fixed it temporarily; it later came back. Reproduced deterministically on a dev bot's initial load.
Root cause
Rows in measured-row virtualizers can be (re)measured while they cannot be laid out — their pane is
display:nonebehind av-show'd sidebar view, or the node was just detached by a virtualizer window shift. Those measurements report height 0 and get written into@tanstack/vue-virtual'sitemSizeCache.That poisons the virtualizer twice over:
applyScrollAdjustmentassumes theelement.scrollTo()landed and bumps the internal offset anyway, one row height at a time (observed +36px × 18 rows → internal offset 648 while the real scrollTop stayed 0).The virtualizer then renders its window mid-list: a dead gap at the top where the newest sessions belong, only the tail rows painted. Any real scroll event resyncs it, which is why the bug looked random and self-healing.
Fix
Add
measureVirtualRow(apps/web/src/utils/virtual-row-measure.ts), a sharedmeasureElementguard: a zero-height measurement means "unmeasurable right now", so keep the last known size (or the estimate) instead of recording 0. Wired into the three measured-row virtualizers:components/sidebar/recents.vue(the reported list)components/searchable-select-popover/index.vuepages/bots/components/model-options.vueVerification
/bot/helloreproduced on first load (first rendered row index 14 at translateY 288, six 0-height cache entries, +36 adjustment cascade in the scroll log); after the fix, row 0 renders at y=0, full scrollHeight restored, and scroll-to-bottom / panel switch away+back / bot switch while the pane is hidden all stay clean.measureVirtualRow; existing sidebar + chat-list suites pass (139 tests);vue-tsc, ESLint, and the UI contract guard are clean.🤖 Generated with Claude Code