keyboard: the one-Esc law — a surfaced layer claims at the document level (keyboard 4 of 4)

Owner ruling (keyboard round 2026-10-06): Esc (or any key) does ONE
action, on the topmost active layer. The plan-open-while-dictating
double-act was the symptom: the plan popup listened at WINDOW level
with no claim, and same-node window listeners all fire — the global
chain (registered first) cancelled the dictation while the plan's own
listener closed the plan. One Esc, two actions.

The law (now the house pattern, documented at the chain):
- field-level handlers claim at their element (focus in a field: the
  field's action) — unchanged, already correct
- every SURFACED layer claims at the DOCUMENT level with preventDefault
  + stopPropagation — document fires before the window chain, so the
  chain stays silent under any surface
- the window chain is the bottom-up fallback: dictation (a live capture,
  NOT a surface — it survives the Esc that closes a plan or overlay),
  then abort (escAbortTarget layers its own targets)

Converted to the claim: plan popup, session overlay, chain table,
settings dialog, setup dialog, the delete/abort dialogs (window-level
stopPropagation was never enough — same-node listeners all fire), and
the stats popover. Popovers (popover-dismiss), menus, model picker, and
the sidebar context menu already claimed correctly.

1427 tests, tsc, lint, build green.
This commit is contained in:
amosblomqvist
2026-10-07 00:08:49 +03:00
parent 94470815ab
commit e523bea670
10 changed files with 89 additions and 27 deletions
+7 -1
View File
@@ -58,7 +58,13 @@ export function StatsBar({
if (barRef.current && !barRef.current.contains(e.target as Node)) setOpen(false);
};
const onKeyDown = (e: KeyboardEvent) => {
if (e.key === "Escape") setOpen(false);
if (e.key === "Escape") {
// THE ONE-ESC LAW (keyboard round 2026-10-06): claim — the
// window chain must not also act under this popover.
e.preventDefault();
e.stopPropagation();
setOpen(false);
}
};
document.addEventListener("pointerdown", onPointerDown);
document.addEventListener("keydown", onKeyDown);