keyboard: Tab cycles the surface's text fields, forward-only (keyboard 3 of 4)

Plain Tab now navigates instead of being pure dead weight: the global
handler dispatches lh:kbd-cycle-fields and each composer-bearing
surface answers with its own chain, gathered from live DOM at event
time (the docks mount and unmount — refs would go stale):

- chat: reading-thinking → the active dock's field → the composer,
  visual order, wrap; Tab from anywhere else focuses the first live
  field (navigate in)
- new-session + home: the composer is the whole chain — Tab navigates
  into it

Shift+Tab is untouched (the thinking-level cycle keeps it — owner
ruling); the quiz dock's rows↔thinking Tab claim stops propagation at
document level, so a claimed Tab never reaches the dispatch — no
double act.

1427 tests, tsc, lint, build green.
This commit is contained in:
amosblomqvist
2026-10-07 00:04:03 +03:00
parent 9007e6eb7a
commit 94470815ab
5 changed files with 75 additions and 1 deletions
+7
View File
@@ -65,6 +65,13 @@ export function KeyboardShortcuts() {
if (e.key === "Tab") {
e.preventDefault();
if (e.shiftKey) window.dispatchEvent(new CustomEvent("lh:kbd-cycle-thinking"));
// Plain Tab cycles the active surface's text fields (owner,
// keyboard round 2026-10-06) — forward-only, wrapping; each
// composer-bearing page answers with its own chain. The quiz
// dock's rows↔thinking claim stops propagation at document
// level, so a claimed Tab never reaches this dispatch.
else if (!e.metaKey && !e.ctrlKey && !e.altKey)
window.dispatchEvent(new CustomEvent("lh:kbd-cycle-fields"));
return;
}