From a578916fa1311b6626c302b4b9dc6c61e0258054 Mon Sep 17 00:00:00 2001 From: Melody Ruch <396921921@qq.com> Date: Fri, 14 Aug 2026 17:47:14 +0800 Subject: [PATCH] fix(editor): preserve scroll after closing DDL dialog --- .../src/components/objects/DdlViewDialog.vue | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/apps/desktop/src/components/objects/DdlViewDialog.vue b/apps/desktop/src/components/objects/DdlViewDialog.vue index c478be2604..6ed4d5caf9 100644 --- a/apps/desktop/src/components/objects/DdlViewDialog.vue +++ b/apps/desktop/src/components/objects/DdlViewDialog.vue @@ -51,6 +51,10 @@ const ddlEditorContainer = ref(); const ddlSearchPanelRef = ref>(); const ddlEditorView = shallowRef(null); +// The CodeMirror editor (if any) that was focused when this dialog opened, so focus can be +// restored to it on close. Not a ref: read/written outside of render, never needs reactivity. +let editorRootToRestoreFocus: HTMLElement | null = null; + async function loadDdl(force = false) { ddlError.value = ""; ddlLoading.value = true; @@ -81,12 +85,34 @@ watch( () => props.open, async (open) => { if (!open) return; + const active = document.activeElement; + editorRootToRestoreFocus = active instanceof HTMLElement ? active.closest(".cm-editor") : null; ddlContent.value = ""; await loadDdl(); }, { immediate: true }, ); +/** + * Restores focus through CodeMirror's own `EditorView.focus()` instead of the browser default. + * + * Radix's default close-auto-focus calls the plain DOM `.focus()` on whatever was focused before + * the dialog opened. In WebKit (the desktop app's webview on macOS), refocusing a contenteditable + * this way resets its caret to the very start of the document; CodeMirror then treats that as a + * real selection change and scrolls to follow it, snapping a long query editor to the top (#6067). + * `EditorView.focus()` avoids this by suppressing its own selection observer while it restores the + * DOM selection to match its actual (unmoved) internal state. + */ +function onDdlDialogCloseAutoFocus(event: Event) { + const target = editorRootToRestoreFocus; + editorRootToRestoreFocus = null; + if (!target || !target.isConnected) return; + event.preventDefault(); + void import("@codemirror/view").then(({ EditorView }) => { + EditorView.findFromDOM(target)?.focus(); + }); +} + /** * Creates a lightweight read-only CodeMirror editor inside the dialog. * @@ -198,7 +224,7 @@ function onClose() {