Repository navigation
chore(sync): merge upstream TanStack/virtual main (RIG-9206) - #13
Open
rigel-mintaka wants to merge 47 commits into
Open
rigel-mintaka wants to merge 47 commits into
rigel-mintaka wants to merge 47 commits into
Conversation
…n in-flight scrollToIndex lands (TanStack#1305)
…ead-back to reconcile (TanStack#1309)
… gestures cannot leave touch state stuck (TanStack#1314)
…roll element's window (TanStack#1320)
… the scroll state (TanStack#1324) Finishes TanStack#1307 on top of TanStack#1319's hold: the step-5 command stalls, iOS 27 commands issued mid-fling (wait for the fling; a drag, second flick or tap cancels, read from scroll events since iOS sends no touch events for a touch on a fling), and the behaviour-neutral scroll-state refactor (P1–P4). Device checks on iOS 27/26.5, desktop Safari, Chromium and Firefox; e2e for the command-retire cases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…TanStack#1325) Moves the iOS touch gesture state out of the Virtualizer into an internal IosGesture class. The late-fling window is now a gesture phase. A waiting command keeps its fling samples. One fix: a scroll-element change no longer carries over a pending late-fling window. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… clamp (TanStack#1329) * fix(virtual-core): keep an instant scroll command through a transient clamp Rows measured before an instant scrollToEnd() reports back can shrink the sizer below the written position and then grow it again in the same task. The browser clamps the write to the smaller max, and the scroll event reports that position: neither the write target nor the current max, so it was classified as external and the command was retired short of the end. resizeItem now follows the scroll max while a command's instant write is unreported (element max read once, then each delta, no measurement rebuild), and classifyScrollEvent reads an event between the lowest max and the target as clampedReadBack, so reconcile retargets to the end. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(virtual-core): count a pre-shrunk max and rewrite after a transient clamp Review follow-ups for the transient-clamp read-back: - The element max read at the first resize after the write counts toward `lowestMax`: the sizer can already be below the target when that resize arrives. - After such a clamp, an index or end command moves `lastTargetOffset` to the clamped position, so reconcile writes the target again even when the layout came back to the same end. Only for a clamp below the element's current max; the clamp at the current max (TanStack#1310) is unchanged. - The max is followed only while `_awaitingCommandReadBack()` holds (not under an iOS dragging finger) and only with one lane, where a row's delta is the total's. Scroll-trace snapshots are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(virtual-core): match a transient clamp to a max the layout took A clamped read-back below the element's current max was accepted anywhere between the lowest tracked max and the target, so a user scroll that landed in that range before the read-back kept the command. The browser clamps to a max the sizer actually had, so `pendingWrite` now keeps each tracked max below the target (`lowMaxes`) and the classifier requires the offset to be within the read-back tolerance of one of them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(virtual-core): record a transient max below zero at 0 A row that shrinks the tracked max below zero leaves the element clamped at 0, not at the negative value, so a read-back at 0 after the sizer grew back matched no recorded max and retired the command. `lowMaxes` now records the reachable value (the element's 0, which is the hold in layout coordinates); the raw max still carries the next delta. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…TanStack#1331) * docs(examples): rebuild the React chat example as a ChatGPT-style layout Replace the debug toolbar with a sidebar (new chat, chat history) and a message pane with a composer. Data comes from an in-memory mock API through TanStack Query: chats via useQuery, messages via useInfiniteQuery with older pages prepended, and sends via useMutation. Assistant replies are generated and streamed word by word into the query cache, so the example needs no server or API key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(examples): fix clipped sidebar rows and small icons in the chat example The chat list rows shrank below their text height once the list overflowed, which cut off the text and the selected-row highlight on phones. Keep them at their natural height, and replace the text-glyph icons with 20px SVG icons in 40px buttons. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(examples): jump to the end after a send in the chat example The empty assistant reply is added in the same render as the user message, so the last message was never the user's and scrollToEnd() never ran. Watch the latest user message instead, and skip the first render. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(examples): hide the jump button when the chat opens at the end React's onScroll runs before the virtualizer reads the scroll event, so isAtEnd() there saw the previous position and the button stayed visible after the list landed at the end. Update the at-end state in the virtualizer's onChange instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(examples): simplify the chat example - Seed 5 chats instead of 25, and generate replies from one sentence bank (no lists or code blocks), so the mock API and rendering are shorter. - Add the streamed reply with its first words, which removes the typing indicator and fixes an empty reply left behind by an early Stop. - Scroll to the end in one layout effect keyed on the latest user message, replacing the initial-scroll state, the seen-message ref and the history-load timer. - Let the composer grow with field-sizing: content instead of JavaScript. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(examples): add prompt hints to the empty chat Show three prompts under the composer when no chat is open. A tap sends the prompt as the first message, so a new chat and a streamed reply start in one step. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(examples): link the chat blog post and add icons to the prompt hints - Answer "How do I virtualize a chat list?" with a fixed reply that links Tanner Linsley's "Chat UIs Are Lists Until They Aren't", and render links in assistant messages. - Add a colored Feather icon to each prompt hint. - Rename the seeded "Plan a weekend in Kraków" chat to Rzeszów. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(examples): keep the chat opened while a send is in flight The send selects its chat when it finishes, about 100 ms later. Opening another chat in that time was undone. Select the sent-to chat only when the selection has not changed since the send started. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(examples): load older messages after a direct jump to the top The scroll handler returned early when isAtEnd() was true. React's onScroll runs before the virtualizer reads the event, so after one jump from the end to the top it still saw the old position, skipped the load and did not record scrollTop. Drop the check: scrolling up near the top already gates the load. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…on Android too (TanStack#1347) Chrome on Android carries a fling on from a programmatic write, so a scrollToIndex / scrollToOffset / scrollToEnd issued mid-fling was written and then overshot (Pixel 6, Android 16, Chrome 156: ~3,200px past the target, 3 runs of 3). iOS 27 already stops the fling before such a command (TanStack#1332); this does it everywhere a write does not end the fling, which is everywhere but iOS 26 and earlier. - IosGesture opens the post-touch tail on every platform. Corrections are still deferred through it on iOS only; `_canWriteScroll` and `_awaitingCommandReadBack` keep their isIOSWebKit() gates. - `_startScroll` stops the fling when momentumOverridesWrites(): !isIOSWebKit() || iosMomentumOverridesWrites(). - `_stopMomentum` puts the overflow back in the same task when hiding it changed the element's cross-axis client size: a classic scrollbar (a touchscreen laptop) would vanish and reflow the content for two frames. The command then waits for the tail, as without a style. The web trace snapshots move for seeds with touch steps: a command inside a drag's tail now goes through the stop, which in the simulator (no style) falls back to the tail, as on ios27.
…he end of the list (TanStack#1351)
…rt in a shared scroll element (TanStack#1372)
Co-authored-by: Matt Wilkinson <matt@rigel.build>
🚀 Changeset Version Preview1 package(s) bumped directly, 8 bumped as dependents. 🟩 Patch bumps
|
Collaborator
Author
Review round 1One low, accepted: the CHANGELOG keeps upstream @TanStack entries. That drift predates this merge, and editing upstream entries would cause conflicts on every sync. The conflict resolution adds and drops nothing beyond the fork fields. The fork workflows and hk.pkl are unchanged. All-clear at bd52bbf. The gate ran over SSH on mattpc-wsl. |
rigel-mintaka
marked this pull request as ready for review
November 12, 2026 09:00
This branch has not been deployed
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.
🎯 Changes
Merge upstream TanStack/virtual main into the RigelBuild fork to keep its upstream baseline current. This merge had one conflict in
packages/solid-virtual/package.json; we kept@rigelbuild/solid-virtualat3.0.0-rc.0and retained the publicpublishConfigrequired by the fork's release workflow.✅ Checklist
main.🚀 Release Impact
This sync preserves the existing published package identity and public publish configuration. It does not change the release path.
Refs RIG-9206
Co-authored-by: Matt Wilkinson matt@rigel.build