From dab2a0f9340e489fa32ee429e007f4eca30240ee Mon Sep 17 00:00:00 2001 From: Edwin Date: Fri, 21 Aug 2026 10:13:42 -0700 Subject: [PATCH 1/3] fix(webui): let Tab focus the Playbook selection menu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Selecting text in the web Playbook editor pops up the selection action menu, but the editor's keydown handler gave Tab exactly one job: insert an indent. With a selection live, `document.execCommand("insertText")` *replaces* it — so Tab both failed to reach the menu and destroyed the very text the menu was offering to act on. The TUI has settled this contract over #1240/#1285/#1286/#1289 and spec 0196 records it. This mirrors that end state rather than inventing a web one: - Bare Tab moves focus into a visible menu; the document is untouched. - Once focused, Tab/S-Tab and the arrows walk the rows, Enter runs the focused one (Shift: in a fork), C-g cancels selection and menu together. - Escape peels the menu off but keeps the selection, so the next Tab reaches the editor and nests every list line the selection spans (S-Tab un-nests). A second Escape then cancels the region — two stages, as in the TUI. - C-o still focuses the menu, and can reopen one Escape dismissed. Menu focus is real focus: the rows are `role="menuitem"` buttons that the browser reports as `document.activeElement`, not a painted highlight. Two details the round trip needs — the editor's `blur` handler disarms the mark, and a blurred contenteditable does not reliably keep a readable Range — so both are parked on focus and restored when focus comes back, leaving the region extendable and Escape's second stage with something to cancel. Tab with no selection still inserts a tab stop, and nothing outside the Playbook editor changes. Spec 0196 previously scoped itself to the TUI and listed web menu focus as a non-goal; it now states the contract for any client that shows the menu. Verified against a real Chrome over CDP with trusted key events, for both a pointer drag and a C-Space region. The new web_smoke coverage asserts `activeElement` moves into the menu and `playbookSerialize()` is unchanged; reverting the Tab branch fails it with `text: "- item"` — the original bug. --- crates/daemon/assets/index.html | 251 +++++++++++++++++- crates/e2e/tests/web_smoke.rs | 207 +++++++++++++++ ...196-playbook-selection-menu-focus-model.md | 38 ++- 3 files changed, 481 insertions(+), 15 deletions(-) diff --git a/crates/daemon/assets/index.html b/crates/daemon/assets/index.html index 90e11893..cbb02acc 100644 --- a/crates/daemon/assets/index.html +++ b/crates/daemon/assets/index.html @@ -4107,8 +4107,12 @@ aria-label="playbook markdown">
-