Skip to content

Give the web suggestion deck the keyboard once it is opened - #1197

Merged
edwin-zvs merged 3 commits into
mainfrom
webui-deck-keyboard
Aug 4, 2026
Merged

Give the web suggestion deck the keyboard once it is opened#1197
edwin-zvs merged 3 commits into
mainfrom
webui-deck-keyboard

Conversation

@edwin-zvs

Copy link
Copy Markdown
Contributor

What

In the web UI, after C-x . (or clicking the orb), typing now searches your prompt history — the same gesture the TUI deck has always had. Arrows walk the matches, Enter takes one, Escape or C-g gives the keyboard back.

Before this, the deck was mouse-only: chips carried tabindex="-1", every render path force-restored the caret, and the only key it listened for was Escape. Letters typed after the chord went into the terminal, and the history stack — up to 50 verbatim prompts — could only be searched by eye and scrollbar.

The rule this follows

"Focus stays in the terminal" is untouched, and deliberately so. DOM focus never moves. The deck routes keys while the caret stays in xterm or the composer, which is why handing the keyboard back is a no-op rather than a restore, and why chips keep tabindex="-1". What changed is only that opening the deck deliberately — the chord, or the orb — is treated as an unambiguous request to work with suggestions, so the open deck claims plain keystrokes until dismissed.

Keys deliberately not claimed:

  • Meta/Alt, and every Ctrl key except C-g / C-n / C-p. So C-x chords keep working while the deck is open, including C-x . to toggle it shut.
  • Escape, which the overlay stack already unwinds innermost-first.
  • anything typed while a chord is half-entered — that chord owns the next key.

Narrow layouts keep the old behavior: a phone's composer and virtual keyboard are the point of that layout, and diverting characters out of a half-written message would cost more than the recall saves.

Behavior

Key Effect
any printable types into the history search, from whichever surface is showing
Backspace trims the search, then leaves the surface, then closes
C-p C-n walk the rows
Enter / run the highlighted row's own action (a history pick stages for review, per spec 0109)
back to the fan
Esc / C-g dismiss

The fuzzy scorer is a port of the TUI's, checked against the same fixtures, so recall ranks identically in both clients: exact, prefix, substring, then a subsequence that decays with match span, ties newest-first.

Tests

web_keymap_suggestion_deck_takes_the_keyboard_once_opened drives real key events through a browser and asserts the keystrokes are actually consumed (dispatchEvent returning false is the difference between "the deck took it" and "it fell through to the terminal"), that the caret never moves, that C-g and Escape both release, that reopening starts a clean search, and that a narrow viewport leaves typing to the composer.

Full workspace suite green.

Spec

Spec 0109 previously described type-ahead as TUI-only and said of the web UI only that it "follows the same on-demand rule". Amended with the keyboard-ownership decision, the focus invariant it must not disturb, and the narrow-layout exception.

The web deck was mouse-only: chips carried tabindex="-1", every render
path force-restored the caret, and the sole key it listened for was
Escape. So after `C-x .` the letters you typed went straight into the
terminal, and the history stack — up to 50 verbatim prompts — could only
be searched by eye and scrollbar. The TUI deck has had fuzzy type-ahead
on its History row since it shipped.

Opening the deck deliberately (the chord, or the orb) is an unambiguous
request to work with suggestions, so from that point the open deck routes
keys until it is dismissed. Typing a printable character from any surface
lands in the history type-ahead; arrows / C-n / C-p walk the rows; Enter
runs the highlighted row's own action; Escape or C-g dismisses.

The standing focus rule is untouched, and deliberately so: DOM focus
never moves. The deck routes keys while the caret stays in xterm or the
composer, which is why handing the keyboard back is a no-op rather than a
restore, and why chips keep tabindex="-1". Only plain keys are claimed —
Meta/Alt and every Ctrl key except C-g/C-n/C-p fall through, so `C-x`
chords still work while the deck is open, including `C-x .` to toggle it
shut. Narrow layouts keep the old behavior: a phone's composer and
virtual keyboard are the point of that layout, and diverting characters
out of a half-written message would cost more than the recall saves.

The scorer is a port of the TUI's, verified against the same fixtures, so
recall ranks identically in both clients: exact, prefix, substring, then
a subsequence that decays with match span, ties newest-first.
@edwin-zvs

Copy link
Copy Markdown
Contributor Author

Both frames are e2e artifacts from web_keymap_suggestion_deck_takes_the_keyboard_once_opened, so they are exactly what the test asserts on.

Typing filters history. C-x ., then c,o,m,m,i,t — the query line appears under the header and 3 prompts narrow to 1. None of those characters reached the terminal.

history search

Arrow keys walk the matches. The keyboard cursor is a tinted row with a left edge marker — readable without a pointer, and without a focus ring, since focus is still in the terminal behind the deck.

keyboard cursor

The .pr-media/ commit is removed in the next push; refs/pull keeps the blobs alive so these links stay good.

@edwin-zvs
edwin-zvs merged commit b1b8170 into main Aug 4, 2026
1 check passed
@edwin-zvs
edwin-zvs deleted the webui-deck-keyboard branch August 4, 2026 01:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant