refactor(#289 review): extract useScrollRestoreOnSwap so the test guards real code (F2)
The prior test guarded a verbatim MIRROR of the two scroll-restore useLayoutEffect blocks — the reviewer proved removing '&& editor' from the real page-editor.tsx left the test green (a copy, not the original). Extract the wiring into an exported useScrollRestoreOnSwap(pageId, editor, showStatic) hook (the two effects verbatim + useScrollPosition inside; F1 budget logic untouched), call it once from page-editor.tsx (replacing the removed useScrollPosition call + both effects), and rewrite the test to render the REAL hook — deleting the mirror and the false 'regresses in lockstep' comment (F2-doc). Non-vacuity proven: removing '&& editor' from the real hook reddens the guard test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,6 @@ import "@/features/editor/styles/index.css";
|
||||
import React, {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useLayoutEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
@@ -79,7 +78,7 @@ import { PageEditMode } from "@/features/user/types/user.types.ts";
|
||||
import { jwtDecode } from "jwt-decode";
|
||||
import { searchSpotlight } from "@/features/search/constants.ts";
|
||||
import { useEditorScroll } from "./hooks/use-editor-scroll";
|
||||
import { useScrollPosition } from "./hooks/use-scroll-position";
|
||||
import { useScrollRestoreOnSwap } from "./hooks/use-scroll-position";
|
||||
import { EditorLinkMenu } from "@/features/editor/components/link/link-menu";
|
||||
import ColumnsMenu from "@/features/editor/components/columns/columns-menu.tsx";
|
||||
import { TransclusionLookupProvider } from "@/features/editor/components/transclusion/transclusion-lookup-context";
|
||||
@@ -144,7 +143,6 @@ export default function PageEditor({
|
||||
[isComponentMounted],
|
||||
);
|
||||
const { handleScrollTo } = useEditorScroll({ canScroll });
|
||||
const { restoreScrollPosition } = useScrollPosition(pageId);
|
||||
// Providers only created once per pageId
|
||||
const providersRef = useRef<{
|
||||
local: IndexeddbPersistence;
|
||||
@@ -483,19 +481,10 @@ export default function PageEditor({
|
||||
}
|
||||
}, [yjsConnectionStatus, isSynced]);
|
||||
|
||||
// Restore as early as the static (cached) content is laid out, before paint,
|
||||
// so the reader's position is applied without a visible jump. Aborts itself if
|
||||
// the reader has already started scrolling (handled inside the hook).
|
||||
useLayoutEffect(() => {
|
||||
restoreScrollPosition();
|
||||
}, [restoreScrollPosition]);
|
||||
|
||||
// Re-assert once after the static -> live editor swap in case the swap reset
|
||||
// the window scroll. Idempotent: a no-op when the position is already correct,
|
||||
// and a no-op after the reader has interacted.
|
||||
useLayoutEffect(() => {
|
||||
if (!showStatic && editor) restoreScrollPosition();
|
||||
}, [showStatic, editor, restoreScrollPosition]);
|
||||
// Restore the reader's scroll position across the static -> live editor swap.
|
||||
// The wiring (early pre-paint restore + post-swap re-assert) lives in the hook
|
||||
// so its triggers/guard are directly unit-testable.
|
||||
useScrollRestoreOnSwap(pageId, editor, showStatic);
|
||||
|
||||
return (
|
||||
<TransclusionLookupProvider>
|
||||
|
||||
Reference in New Issue
Block a user