From c59ab2f058b58ef09ae8ece879f49c165252c652 Mon Sep 17 00:00:00 2001 From: Leo Vasanko Date: Wed, 26 Aug 2026 02:29:33 +0000 Subject: [PATCH] Fix editor-page scroll syncing issues. --- frontend/src/PageEditor.vue | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/frontend/src/PageEditor.vue b/frontend/src/PageEditor.vue index a8dfba1..e859429 100644 --- a/frontend/src/PageEditor.vue +++ b/frontend/src/PageEditor.vue @@ -312,10 +312,14 @@ function onEditorShown() { // directions apply instantly (never smooth — a smooth window scroll feeds // its intermediate positions back into the editor and fights the user's // scrolling) and coalesce to one update per frame. Loops are broken two -// ways: a one-frame driver flag, and a 1px tolerance so the scroll events -// caused by our own writes are no-ops. When the panel's height changes -// mid-scroll (its top tracks the banner), the page is the driver: the -// editor is re-matched to the page's position, never vice versa. +// ways: a driver flag held until one frame AFTER the write (the scroll +// event a programmatic write dispatches arrives asynchronously — clearing +// the flag in the writing frame would let the echo through and the two +// directions would chase each other, which showed up as random jumping +// whenever layout shifted the proportional targets mid-scroll), and a 1px +// tolerance so residual rounding is a no-op. When the panel's height +// changes mid-scroll (its top tracks the banner), the page is the driver: +// the editor is re-matched to the page's position, never vice versa. function syncWindowToEditor() { if (syncingScroll || !view) return syncingScroll = true @@ -325,7 +329,7 @@ function syncWindowToEditor() { const pct = max > 0 ? scroller.scrollTop / max : 0 const y = pct * Math.max(0, document.documentElement.scrollHeight - innerHeight) if (Math.abs(scrollY - y) > 1) scrollTo({ top: y, behavior: 'instant' }) - syncingScroll = false + requestAnimationFrame(() => { syncingScroll = false }) }) } @@ -338,7 +342,7 @@ function syncEditorToWindow() { const pct = pageMax > 0 ? scrollY / pageMax : 0 const top = pct * Math.max(0, scroller.scrollHeight - scroller.clientHeight) if (Math.abs(scroller.scrollTop - top) > 1) scroller.scrollTop = top - syncingScroll = false + requestAnimationFrame(() => { syncingScroll = false }) }) }