feat(chat): migrate history list to @tanstack/react-virtual with deterministic mobile history loading
- Replace virtua with @tanstack/react-virtual for chat history on all surfaces: bottom anchoring (anchorTo: end), key-stable prepend preservation, and native iOS touch/momentum deferral live in the core - Patch virtual-core to clamp the render range to real scroll bounds during transient adjustments - Rows render in normal flow inside a translated wrapper so sticky user headers keep working; measurement snapshots cached per session - Pre-write container height in scrollToFn so the browser cannot clamp anchor corrections to the stale height; hold the prepend anchor for up to 180 frames on mobile while fresh rows settle (cancelled by user input; desktop relies on core anchoring alone) - Adaptive row-size estimate from per-session measured averages; disable reveal fade-in for virtualized history rows - Mobile loads older history only through an explicit localized top button: no scroll-position trigger and no post-mount background prepend, so every insert happens from a resting state; a quiet-window hold defers any stray prepend commit while a touch gesture is active - Desktop/VS Code keep the seamless scroll-up trigger and progressive background prepend
This commit is contained in:
@@ -503,11 +503,15 @@ export function useSync() {
|
||||
shouldLoadMessages ? loadMessages(sessionID, { isStale }) : Promise.resolve(),
|
||||
])
|
||||
|
||||
// Progressive mount on desktop: after the initial page resolves, if the
|
||||
// session isn't stale and the server indicated more messages, dispatch a
|
||||
// second fetch to prepend older history. Mobile avoids this background
|
||||
// prepend because adding rows after first paint on a narrow viewport can
|
||||
// visibly shift the timeline; user scroll still loads older history.
|
||||
// Progressive mount (desktop/VS Code): after the initial page
|
||||
// resolves, if the session isn't stale and the server indicated more
|
||||
// messages, dispatch a second fetch to prepend older history — it
|
||||
// gives the scroll container headroom so the scroll-up trigger fires
|
||||
// seamlessly. Mobile deliberately opts out: it has no scroll-position
|
||||
// trigger at all — ALL older history loads happen through the
|
||||
// explicit "load older" button at the top, so every prepend lands
|
||||
// from a resting state the user initiated. (The initial page itself,
|
||||
// including the turn-boundary extension, is unaffected.)
|
||||
if (!isStale() && !isMobileSurfaceRuntime()) {
|
||||
const currentMeta = getMetaFor(sessionID)
|
||||
if (currentMeta.cursor && !currentMeta.complete) {
|
||||
|
||||
Reference in New Issue
Block a user