From f35d635d9774f53c172b12ced9f49f0230f9d424 Mon Sep 17 00:00:00 2001 From: hhhjin Date: Sun, 12 Apr 2026 19:14:54 +0900 Subject: [PATCH 1/2] refactor: extract editor activation restore --- apps/desktop/src/components/editor/editor.tsx | 32 +++--- .../restore-selection-on-activate.test.ts | 98 +++++++++++++++++++ .../utils/restore-selection-on-activate.ts | 40 ++++++++ 3 files changed, 152 insertions(+), 18 deletions(-) create mode 100644 apps/desktop/src/components/editor/utils/restore-selection-on-activate.test.ts create mode 100644 apps/desktop/src/components/editor/utils/restore-selection-on-activate.ts diff --git a/apps/desktop/src/components/editor/editor.tsx b/apps/desktop/src/components/editor/editor.tsx index f21d6e63..362d641e 100644 --- a/apps/desktop/src/components/editor/editor.tsx +++ b/apps/desktop/src/components/editor/editor.tsx @@ -34,6 +34,7 @@ import { restoreHistorySelection, toTabHistorySelection, } from "./utils/history-restore-utils" +import { restoreSelectionOnEditorActivate } from "./utils/restore-selection-on-activate" export function Editor({ destroyOnClose }: { destroyOnClose?: boolean }) { const { @@ -366,34 +367,29 @@ function EditorContent({ return } - const pathDidChange = lastPathRef.current !== path - lastPathRef.current = path const isAliasSwitch = previous.active && previous.tabId !== null && previous.tabId !== activeTabId && previous.path === path if (isAliasSwitch) { + lastPathRef.current = path return } + const pathDidChange = lastPathRef.current !== path + lastPathRef.current = path const timeoutId = window.setTimeout(() => { - const pendingRestore = consumeTabPendingHistorySelectionRestore( - activeTabId, - path, - ) - if (pendingRestore.found) { - restoreHistorySelection(editor, pendingRestore.selection) - return - } - - // Keep the current selection when only the backing file path changes. - if (pathDidChange) { - return - } - - focusEditorAtDefaultSelection(editor) - editor.tf.focus() + restoreSelectionOnEditorActivate({ + editor, + pathDidChange, + pendingRestore: consumeTabPendingHistorySelectionRestore( + activeTabId, + path, + ), + restoreHistorySelection, + focusEditorAtDefaultSelection, + }) }, 0) return () => { diff --git a/apps/desktop/src/components/editor/utils/restore-selection-on-activate.test.ts b/apps/desktop/src/components/editor/utils/restore-selection-on-activate.test.ts new file mode 100644 index 00000000..93e96341 --- /dev/null +++ b/apps/desktop/src/components/editor/utils/restore-selection-on-activate.test.ts @@ -0,0 +1,98 @@ +import { describe, expect, it, vi } from "vitest" +import { restoreSelectionOnEditorActivate } from "./restore-selection-on-activate" + +describe("restoreSelectionOnEditorActivate", () => { + it("restores pending selection and keeps focus behavior delegated", () => { + const focus = vi.fn() + const select = vi.fn() + const restoreHistorySelection = vi.fn() + const focusEditorAtDefaultSelection = vi.fn() + const editor = { + children: [], + api: { + isVoid: vi.fn(), + }, + tf: { + focus, + select, + }, + } + + restoreSelectionOnEditorActivate({ + editor, + pathDidChange: false, + pendingRestore: { + found: true, + selection: { + anchor: { path: [0, 0], offset: 0 }, + focus: { path: [0, 0], offset: 4 }, + }, + }, + restoreHistorySelection, + focusEditorAtDefaultSelection, + }) + + expect(restoreHistorySelection).toHaveBeenCalledOnce() + expect(focusEditorAtDefaultSelection).not.toHaveBeenCalled() + expect(focus).not.toHaveBeenCalled() + }) + + it("keeps the current selection when only the backing path changes", () => { + const restoreHistorySelection = vi.fn() + const focusEditorAtDefaultSelection = vi.fn() + + restoreSelectionOnEditorActivate({ + editor: { + children: [], + api: { + isVoid: vi.fn(), + }, + tf: { + focus: vi.fn(), + select: vi.fn(), + }, + }, + pathDidChange: true, + pendingRestore: { + found: false, + selection: null, + }, + restoreHistorySelection, + focusEditorAtDefaultSelection, + }) + + expect(restoreHistorySelection).not.toHaveBeenCalled() + expect(focusEditorAtDefaultSelection).not.toHaveBeenCalled() + }) + + it("prepares the default selection without forcing focus on normal note open", () => { + const focus = vi.fn() + const select = vi.fn() + const restoreHistorySelection = vi.fn() + const focusEditorAtDefaultSelection = vi.fn() + + restoreSelectionOnEditorActivate({ + editor: { + children: [], + api: { + isVoid: vi.fn(), + }, + tf: { + focus, + select, + }, + }, + pathDidChange: false, + pendingRestore: { + found: false, + selection: null, + }, + restoreHistorySelection, + focusEditorAtDefaultSelection, + }) + + expect(restoreHistorySelection).not.toHaveBeenCalled() + expect(focusEditorAtDefaultSelection).toHaveBeenCalledOnce() + expect(focus).not.toHaveBeenCalled() + }) +}) diff --git a/apps/desktop/src/components/editor/utils/restore-selection-on-activate.ts b/apps/desktop/src/components/editor/utils/restore-selection-on-activate.ts new file mode 100644 index 00000000..1c9f9db1 --- /dev/null +++ b/apps/desktop/src/components/editor/utils/restore-selection-on-activate.ts @@ -0,0 +1,40 @@ +import type { PendingHistorySelectionRestoreResult } from "@/store" + +type HistoryRestoreEditor = { + children: unknown[] + api: { + isVoid(element: unknown): boolean + } + tf: { + select(...args: [unknown, ...unknown[]]): void + focus(): void + } +} + +type RestoreSelectionOnEditorActivateOptions = { + editor: HistoryRestoreEditor + pathDidChange: boolean + pendingRestore: PendingHistorySelectionRestoreResult + restoreHistorySelection: typeof import("./history-restore-utils").restoreHistorySelection + focusEditorAtDefaultSelection: typeof import("./history-restore-utils").focusEditorAtDefaultSelection +} + +export function restoreSelectionOnEditorActivate({ + editor, + pathDidChange, + pendingRestore, + restoreHistorySelection, + focusEditorAtDefaultSelection, +}: RestoreSelectionOnEditorActivateOptions): void { + if (pendingRestore.found) { + restoreHistorySelection(editor, pendingRestore.selection) + return + } + + // Keep the current selection when only the backing file path changes. + if (pathDidChange) { + return + } + + focusEditorAtDefaultSelection(editor) +} From 78eedd53bae862b3b3e8d254b641ac9574f92481 Mon Sep 17 00:00:00 2001 From: hhhjin Date: Sun, 12 Apr 2026 19:18:01 +0900 Subject: [PATCH 2/2] test: fix restore selection pending restore typing --- .../editor/utils/restore-selection-on-activate.test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/desktop/src/components/editor/utils/restore-selection-on-activate.test.ts b/apps/desktop/src/components/editor/utils/restore-selection-on-activate.test.ts index 93e96341..454ca7a7 100644 --- a/apps/desktop/src/components/editor/utils/restore-selection-on-activate.test.ts +++ b/apps/desktop/src/components/editor/utils/restore-selection-on-activate.test.ts @@ -55,7 +55,6 @@ describe("restoreSelectionOnEditorActivate", () => { pathDidChange: true, pendingRestore: { found: false, - selection: null, }, restoreHistorySelection, focusEditorAtDefaultSelection, @@ -85,7 +84,6 @@ describe("restoreSelectionOnEditorActivate", () => { pathDidChange: false, pendingRestore: { found: false, - selection: null, }, restoreHistorySelection, focusEditorAtDefaultSelection,