fix(app): prevent scrollend position rollback

Discard virtualizer measurement corrections suppressed during an active user gesture instead of replaying stale offsets at scrollend. Preserve post-scroll live anchoring and add unit plus Electron coverage for ordinary scrolling without updates.
This commit is contained in:
tommy0103
2026-07-15 02:19:55 +08:00
parent 82d9fbf657
commit 5294d76f07
6 changed files with 69 additions and 30 deletions
@@ -1,13 +1,8 @@
export function createSessionTimelineScrollPolicy({ isUserScrolling, writeScroll }) {
let explicitDepth = 0;
let deferredAdjustment = 0;
let deferredInstance = null;
function scrollToFn(offset, options = {}, instance) {
if (explicitDepth === 0 && isUserScrolling()) {
const adjustment = Number(options.adjustments);
if (Number.isFinite(adjustment)) deferredAdjustment += adjustment;
deferredInstance = instance;
return;
}
writeScroll(offset, options, instance);
@@ -22,19 +17,8 @@ export function createSessionTimelineScrollPolicy({ isUserScrolling, writeScroll
}
}
function flushDeferredAdjustment(instance = deferredInstance) {
if (isUserScrolling() || deferredAdjustment === 0 || !instance?.scrollElement) return false;
const adjustment = deferredAdjustment;
deferredAdjustment = 0;
deferredInstance = null;
const offset = Number(instance.scrollElement.scrollTop) || 0;
writeScroll(offset, { behavior: 'auto', adjustments: adjustment }, instance);
return true;
}
return {
scrollToFn,
runExplicit,
flushDeferredAdjustment,
};
}
@@ -133,10 +133,6 @@ export function useSessionTimelineViewport({
tailFollowReady.value = true;
}
function settleUserScroll() {
return scrollPolicy.flushDeferredAdjustment(virtualizer.value);
}
return {
virtualRows,
totalSize,
@@ -145,7 +141,6 @@ export function useSessionTimelineViewport({
scrollToIndex,
scrollToEnd,
isFollowingTail,
settleUserScroll,
resetForInitialSnapshot,
completeInitialSnapshot,
};
@@ -63,7 +63,6 @@ const liveReloadCoordinator = createSessionLiveReloadCoordinator({
});
function handleUserScrollEnd() {
timelineViewport.settleUserScroll();
if (active.value) void liveReloadCoordinator.flush();
}