Repository navigation
Conversation
…ead-back to reconcile After a scrollToIndex/scrollToEnd/reconcile write, `scrollOffset` keeps the old position until the scroll event reads the write back, and the rows on screen are still the ones rendered for it. A resize in that window was compensated against the old position: scrolling up with scrollToIndex could jump back to the old position plus the delta, and reconcile (target unchanged) never rewrote it until the 5s safety valve. Track the offset of the last non-smooth write until its read-back. While a scroll state is active and `scrollOffset` doesn't reflect that write yet, skip resize compensation: reconcileScroll retargets from fresh measurements on the next frame. Compensation writes and the prepend anchor sync update `scrollOffset` eagerly, so they are unaffected. scrollBy builds on the written offset, so a scrollBy right after a scroll command adds to its target. Classifying those resizes against the written offset instead was tried and regressed the chat examples: during scrollToEnd the rows at the old position were compensated, the end target kept moving, and a user scroll could no longer interrupt the never-landed pin. Adds tests/ios-differential.test.ts, which runs scripted event sequences on an iOS and a non-iOS virtualizer and checks they settle at the same offset without needing the safety valve (TanStack#1307). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…efore it lands The scroll handler only treated a scroll event as the user leaving an index scroll once reconcile had seen the target reached. A target that keeps moving while rows are measured (or, on iOS, a write ignored under a finger) never "reaches" it, so the state stayed alive after the user scrolled away and the next measurement that moved the target wrote them back to it. A non-smooth write lands at once, so a scroll event that isn't the read-back of our own write is the user's even before the target is reached. A write the browser reads back short of what we wrote because the scroll max shrank reports the max, where the fresh target also clamps, so it keeps reconciling as before (TanStack#1294); clamped compensation writes stay covered by `_clampedAdjustment`. Smooth scrolls are unchanged: their animation events look like a user's, so they still yield only after reaching the target. That is decided by a new `startedSmooth` flag rather than `behavior`, which reconcile switches to 'auto' for the final approach while WebKit can still deliver animation events. Removes `.fails` from the two TanStack#1308 pull-back tests, and makes the TanStack#1294 "keeps an index scroll active before reaching its target" test model the max shrinking before the read-back. Refs TanStack#1307 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: 2b7ac8b The changes in this PR will be included in the next version bump. This PR includes changesets to release 9 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
View your CI Pipeline Execution ↗ for commit 2b7ac8b
☁️ Nx Cloud last updated this comment at |
|
Reviewed the last commit at 2b7ac8b. The fix works in real browsers, I found no regression, and it also removes a flake in the Chromium chat spec. The fix, in real browsers. Plain-DOM list on
It fixes the
The first one is the No landing regression. The 34,200 uninterrupted index scrolls from my #1309 comment land identically on #1309 and on this PR. The only difference is that 54 runs that sat off-target until the 5s safety valve on #1309 now retire at the next scroll-rest event, at the same position. Mutation check. Checking Two questions, neither a blocker as far as I could measure:
WebKit |
🎯 Changes
The scroll handler treated a scroll event as the user leaving an index scroll only after reconcile had seen the target reached. When the target keeps moving while rows are measured (or, on iOS, when a write is ignored under a finger) the scroll never "reaches" it, so the state stays alive after the user scrolls away, and the next measurement that moves the target writes them back to it. Reproduced on desktop and on iOS in #1307; pinned by two
test.failsin #1308._clampedAdjustment.startedSmoothrather thanbehavior, because WebKit can deliver animation events after reconcile's switch to'auto'.Evidence
scrollToIndexswitched to'auto'near the end, then a late animation eventbehavior)virtual-core: 233 passed + 5 expected failures (remaining iOS scroll-correction deferral: per-row record, iOS 27 momentum, and index-scroll exits #1307 iOS cases). Mutation check: every part of the condition is covered.cached-measurements,smooth-scroll,smooth-prepend,scrollin Chromium, Firefox and WebKit: all pass. WebKit A/B against the parent, 4 runs each interleaved: 0 vs 0 failures (checkingbehaviorinstead ofstartedSmoothgave 8 failures).pnpm run test:prgreen.Merge Danger
Door: two-way. One condition in the scroll handler plus a flag set where scroll commands start.
Blast Radius: non-smooth
scrollToIndex/scrollToEndwhile they haven't been seen to land. A user scroll (wheel inertia included) now ends them immediately instead of being pulled back by the next measurement, which matches nativescrollIntoView. A non-user event in that window that is neither our read-back nor at the target would now end the scroll too; a differential sweep over 98 scenarios (align, lanes, gap, paddings, scroll paddings,scrollMargin, horizontal, window scroller, custom adjust predicate,anchorTo: 'end', rAF-deferred ResizeObserver, iOS) found none.Known and unchanged: a prepend (
anchorTo: 'end') committing before an index write's read-back still loses the scroll (onmainit was stranded, then pulled back later). Tracked with the other shared stalls in #1307.✅ Checklist
pnpm run test:pr.🚀 Release Impact
🤖 Generated with Claude Code