fix(cmux-next): no focus ring after clicking away from a menu

Merged
TE
18d ago
+236-2

Summary

After opening a composer menu with the mouse (Reasoning, Computer, any ui/Menu) and clicking away, the chip kept a focus ring. Base UI returned focus to the trigger, and WebKit drew that programmatic focus as keyboard focus because a menu row had just been focused by script. #21395 (in the current nightly) made the rings keyboard-only in CSS but did not cover this return.

MenuPopup now passes a default finalFocus. A pointer close (a press outside, or a mouse pick) puts focus back where it was when the menu opened, normally the prompt, else on the trigger with focusVisible: false. Keyboard closes still return to the trigger with its ring, Escape included. Base UI 1.8 reports the interaction that opened the menu as the close type, so the popup also records whether a key was pressed in it. If focus has already moved outside the popup when Base UI asks (it asks after the close fade), for example into another chip's picker opened by the same press, it stays there. A menu opened through the controlled open prop records its opener too. Menus with an explicit finalFocus, and submenus, are unchanged.

Testing

  • test/menu-pointer-close-focus.test.ts (new, Chromium and WebKit): a press outside the open Reasoning or Computer menu leaves no ring; a mouse pick returns focus to the prompt with no chip ring; Escape after a mouse open still puts a ringed focus on the chip; pressing Model while the Reasoning menu is open keeps the model picker open with focus inside it (probed green in WebKit and Chromium). Committed before the fix. Red/green from a headless WebKit probe on the New Tab gallery stage: after a click away, the chip matched :focus-visible with a drawn outline before and drew none after; Escape still left the chip focused and :focus-visible. The suite itself was not run locally (cosmic-gray load ~300 timed out Vite warm-up); CI's browser lane runs it.
  • bunx tsc --noEmit, vp fmt --check and vp lint clean.

Changelog

Fixed: Clicking away from a composer menu no longer leaves a focus ring on its chip

Proof

Headless WebKit on the gallery stage agent-pane.new-tab / reasoning-chip, dark, 2x.

ring after click away

🤖 Generated with Claude Code