From 030f17947a56e30f4ad81d79efc9976532641edc Mon Sep 17 00:00:00 2001 From: deathemperor Date: Thu, 24 Sep 2026 18:43:38 +0700 Subject: [PATCH] fix(web): typing with the composer unfocused reaches the composer again The chat header's actions menu stays mounted while closed (#12453), and type-to-focus plus the right panel launcher's letter shortcuts bail on any [data-slot="menu-popup"] in the document, so both were dead on every thread. Qualify each popup slot with :is([data-open],[data-ending-style]), as the dialog entries already are. With that fixed, the first redirected key ended up after the next one: focusAt focused the bare DOM node, the browser put the caret at the start, and setTextSelection to the selection ProseMirror already stored was a no-op. editor.view.focus() writes the stored selection to the DOM. Fixes #13403 Co-Authored-By: Claude Opus 5.5 (1M context) --- apps/web/src/components/ChatView.tsx | 10 +++++----- .../components/ComposerPromptEditorTiptap.tsx | 5 ++++- apps/web/src/components/RightPanelTabs.tsx | 16 ++++++++-------- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index 9af410f5722e..7cf7532deb71 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -649,11 +649,11 @@ const TYPE_TO_FOCUS_FLOATING_LAYER_SELECTOR = [ '[data-slot="dialog-popup"]:is([data-open],[data-ending-style])', '[data-slot="sheet-popup"]:is([data-open],[data-ending-style])', '[data-slot="sidebar"][data-mobile="true"]:is([data-open],[data-ending-style])', - '[data-slot="menu-popup"]', - '[data-slot="select-popup"]', - '[data-slot="popover-popup"]', - '[data-slot="combobox-popup"]', - '[data-slot="autocomplete-popup"]', + '[data-slot="menu-popup"]:is([data-open],[data-ending-style])', + '[data-slot="select-popup"]:is([data-open],[data-ending-style])', + '[data-slot="popover-popup"]:is([data-open],[data-ending-style])', + '[data-slot="combobox-popup"]:is([data-open],[data-ending-style])', + '[data-slot="autocomplete-popup"]:is([data-open],[data-ending-style])', ].join(","); type EnvironmentUnavailableState = { diff --git a/apps/web/src/components/ComposerPromptEditorTiptap.tsx b/apps/web/src/components/ComposerPromptEditorTiptap.tsx index 50305ffdbef0..09bc35379017 100644 --- a/apps/web/src/components/ComposerPromptEditorTiptap.tsx +++ b/apps/web/src/components/ComposerPromptEditorTiptap.tsx @@ -1096,7 +1096,10 @@ function ComposerPromptEditorTiptapInner(props: ComposerPromptEditorProps) { const focusAt = useCallback( (nextCursor: number) => { if (!editor) return; - editor.view.dom.focus({ preventScroll: true }); + // view.focus() also writes the stored selection to the DOM. A bare DOM + // focus leaves the caret at the start when the controlled update already + // stored the target selection, so the setTextSelection below is a no-op. + editor.view.focus(); // A newer prompt is waiting to be applied (a chip was just inserted // through the store). Reporting the editor's stale text now would // overwrite that prompt; the pending rewrite places the caret instead. diff --git a/apps/web/src/components/RightPanelTabs.tsx b/apps/web/src/components/RightPanelTabs.tsx index 33a1c9b05c3a..96a7da92008d 100644 --- a/apps/web/src/components/RightPanelTabs.tsx +++ b/apps/web/src/components/RightPanelTabs.tsx @@ -166,14 +166,14 @@ const SURFACE_DISABLED_REASONS = { /** Overlays that must win over the launcher's letter shortcuts. */ const LAUNCHER_SHORTCUT_BLOCKING_LAYERS = [ - '[data-slot="dialog-popup"]', - '[data-slot="alert-dialog-popup"]', - '[data-slot="command-dialog-popup"]', - '[data-slot="menu-popup"]', - '[data-slot="select-popup"]', - '[data-slot="popover-popup"]', - '[data-slot="combobox-popup"]', - '[data-slot="autocomplete-popup"]', + '[data-slot="dialog-popup"]:is([data-open],[data-ending-style])', + '[data-slot="alert-dialog-popup"]:is([data-open],[data-ending-style])', + '[data-slot="command-dialog-popup"]:is([data-open],[data-ending-style])', + '[data-slot="menu-popup"]:is([data-open],[data-ending-style])', + '[data-slot="select-popup"]:is([data-open],[data-ending-style])', + '[data-slot="popover-popup"]:is([data-open],[data-ending-style])', + '[data-slot="combobox-popup"]:is([data-open],[data-ending-style])', + '[data-slot="autocomplete-popup"]:is([data-open],[data-ending-style])', ].join(","); /** One-line unavailability hints for the empty-state rows. */