From 9bc20cf89474653c96bf424809a7dd8b64c3c463 Mon Sep 17 00:00:00 2001 From: Dash <125997726+dashhuang@users.noreply.github.com> Date: Mon, 24 Aug 2026 08:16:51 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix(desktop):=20=E9=80=89=E5=AE=8C=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E5=90=8E=E6=8A=8A=E7=84=A6=E7=82=B9=E9=80=81=E5=9B=9E?= =?UTF-8?q?=E8=BE=93=E5=85=A5=E6=A1=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新建任务页选完模型后,选择器卸掉会把焦点掉到 body,必须再点一次才能接着打字。composer 工具条现在在选择器关闭后把焦点送回输入框,并阻止 pill mousedown 抢焦。 Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com> --- .../__tests__/composerMorphScope.test.ts | 9 ++ .../renderer/__tests__/morphPopover.test.tsx | 115 ++++++++++++++++++ .../components/new-chat/ChatInput.tsx | 6 +- .../components/new-chat/ModelSelector.tsx | 10 ++ .../renderer/components/ui/morph-popover.tsx | 40 ++++-- 5 files changed, 166 insertions(+), 14 deletions(-) diff --git a/apps/desktop/src/renderer/__tests__/composerMorphScope.test.ts b/apps/desktop/src/renderer/__tests__/composerMorphScope.test.ts index a39d52b5f3..294c3333d0 100644 --- a/apps/desktop/src/renderer/__tests__/composerMorphScope.test.ts +++ b/apps/desktop/src/renderer/__tests__/composerMorphScope.test.ts @@ -32,6 +32,15 @@ describe('composer morph scope', () => { expect(modelSelector).toContain('{trigger}'); }); + it('composer 选完模型后把焦点送回输入框;设置页不传 restoreFocusTarget', () => { + expect(chatInput).toContain('restoreFocusTarget={composerSuggestionFocusTarget}'); + expect(modelSelector).toContain('restoreFocusTarget?: () => HTMLElement | null'); + expect(modelSelector).toContain('onMouseDown={morphEnabled ? (event) => event.preventDefault() : undefined}'); + expect(settingsModel).not.toContain('restoreFocusTarget'); + expect(subagentModel).not.toContain('restoreFocusTarget'); + expect(createWorker).not.toContain('restoreFocusTarget'); + }); + it('PermissionSelector / ExtraDirsButton 仅 composer 使用,恒走脱身上浮 morph(无 opt-in、无 Radix 回退)', () => { expect(permissionSelector).not.toContain('useMorphPopover'); expect(extraDirsButton).not.toContain('useMorphPopover'); diff --git a/apps/desktop/src/renderer/__tests__/morphPopover.test.tsx b/apps/desktop/src/renderer/__tests__/morphPopover.test.tsx index 483e3f76e3..75b9941651 100644 --- a/apps/desktop/src/renderer/__tests__/morphPopover.test.tsx +++ b/apps/desktop/src/renderer/__tests__/morphPopover.test.tsx @@ -7,6 +7,7 @@ * 故本文件按新语义重写(取代旧 ghost/left-定位/focus-first-action/scroll-close 契约): * - 打开聚焦 [data-morph-autofocus] → 首个 input → 面板容器(不抢焦到首个按钮,§14.2) * - 关闭仅键盘(Esc)归还 trigger 焦点;鼠标关闭(选项/outside)不回焦(防误弹 trigger tooltip) + * - 传了 restoreFocusTarget 时,关完回该目标(选完模型立刻能接着打字);其它控件已接走则不抢 * - outside pointerdown 关闭,但嵌套 Radix portal(data-radix-popper-content-wrapper)内不算 outside * - trigger chip 全程可见(不隐藏),再点即关(toggle) * - 无 ghost 幽灵层 @@ -227,6 +228,120 @@ describe('MorphPopover interaction contract', () => { expect(document.activeElement).not.toBe(trigger); }); + it('restoreFocusTarget:鼠标选完后把焦点送回指定输入,而不是 trigger 或 body', async () => { + function RestoreHomeHarness() { + const [open, setOpen] = useState(false); + const composerRef = useRef(null); + return ( + <> +