fix(virtual-core): clamp tracked scrollOffset at 0 in end-anchor compensation#1230
Conversation
…ensation With anchorTo: 'end' and element scrolling, measurement compensation (applyScrollAdjustment) and the setOptions edge-key re-anchor wrote the tracked scrollOffset without clamping to the reachable range. When items measured smaller than their estimates and the content was shorter than the viewport, the offset went negative with no scroll event ever able to correct it (an unscrollable element emits none), permanently skewing getDistanceFromEnd()/isAtEnd() and wedging _flushIosDeferredIfReady so iOS deferred measurement corrections never flushed. Clamp only the lower bound: upper-bound overflow is transiently legitimate mid-prepend while the consumer's sizer catches up, but a negative element offset is invalid unconditionally. Fixes TanStack#1229 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthrough
ChangesEnd-anchor offset correction
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
packages/virtual-core/tests/index.test.tsParsing error: "parserOptions.project" has been provided for 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 3f963ae
☁️ Nx Cloud last updated this comment at |
Fixes #1229
Problem
With
anchorTo: 'end'and element scrolling, the trackedscrollOffsetwas written without clamping to the element's reachable range in two places:applyScrollAdjustment()— the eagerthis.scrollOffset += this.scrollAdjustmentswritesetOptions()edge-key re-anchor block —this.scrollOffset = anchorItem.start + anchorOffsetWhen items measure smaller than their estimates and the content is shorter than the viewport, the end-anchor compensation applies a negative delta. The DOM
scrollTopwrite is clamped to 0 by the browser, but the tracked offset keeps the negative value — and since an unscrollable element never fires a scroll event, nothing ever corrects it. For the lifetime of the instance:getDistanceFromEnd()reports a constant phantom distance andisAtEnd()stays false, so anything steeringscrollToEnd()toward convergence spins forever_flushIosDeferredIfReady()early-returns whilegetScrollOffset() < 0(the rubber-band guard), so on iOS WebKit deferred measurement corrections stay queued forever and items freeze at their estimated positionsFix
Clamp only the lower bound in both writes. Upper-bound overflow is deliberately left alone — it is transiently legitimate mid-prepend while the consumer's sizer catches up, but a negative element offset is invalid unconditionally.
Tests
Two regression tests reproducing the issue's minimal conditions (unscrollable element,
anchorTo: 'end', estimates larger than measured sizes). Both fail onmain(tracked offset lands at a stable-10, exactly as reported) and pass with the clamps.🤖 Generated with Claude Code
Summary by CodeRabbit
Bug Fixes
Tests