Skip to content

Board selection, keyboard and focus fixes - #1944

Merged
BarganConstantin merged 7 commits into
developmentfrom
fix/board-keyboard
Oct 5, 2026
Merged

BarganConstantin merged 7 commits into
developmentfrom
fix/board-keyboard

Conversation

@BarganConstantin

Copy link
Copy Markdown
Owner

What changes

  • A selected card draws its ring. React Flow's own selected prop is never true on a canvas whose nodes are controlled, so .agent-node.selected and its far-zoom twin matched nothing and a selected card looked like every other card. The frame now marks selected cards' wrappers with rf-selected and the ring is drawn from that: the session-hue outline and lift up close, the face's ring at a distance, and the highlight colour in a forced-colours theme (where the lift that tells selection from focus is dropped).
  • Closing a docked panel from the keyboard keeps focus on the page. The × of Usage, This machine, Claude accounts and the detail panel, and the session list's ‹, left focus on <body>. Focus now goes to the topbar button that opens the panel, and for the detail panel to the card it was about (or the canvas if that card is not drawn). A mouse press still leaves focus where it was, so Space keeps pausing the stream.
  • Delete works after selecting a card through a button. A session row, a session's name or the ribbon kept focus after the click, and that button kept Delete because only single characters were handed back to the deck (After any mouse click on a topbar or panel button, every single-key shortcut is dead until Esc, with no visible cue #851). Delete now goes back with the letters; the button keeps Space and Enter, and a button reached by Tab keeps every key as before.
  • ? closes the shortcuts sheet it opened from the keyboard. The sheet gives its × focus on opening, which kept the key. ? now closes the sheet whatever in it has focus, except a text field, and the auto-repeat of the press that opened it does not shut it again.
  • The shortcuts sheet names Delete's real way back. It said "Undo brings it back"; there is no Undo. It now says the session list (L) brings it back, as the detail panel's Remove button does.
  • A held shortcut acts once. Holding Space flipped pause about thirty times a second, and T, L, D and U flickered the same way. Repeats are ignored for every shortcut but J and K, which keep stepping while held.
  • Tab walks the cards in board order. The cards were handed to React Flow, and so to Tab, in the order their agents were first heard of, so a session's late subagents came after other sessions. They now go down each column of sessions and then across, and inside a session the root and then each rank of subagents from the top.

Verification

  • npm run typecheck clean.
  • Full suite: 904 files, 11788 tests passed (exit 0), and the touched tests again after rebasing on development.
  • New regression tests, each run first against the unfixed code and failing for the reason above:
    • card-selection-ring.test.ts (no class on a selected card's wrapper, no rule drawing the ring from one)
    • panel-close-focus.test.ts (no hand-off existed)
    • delete-after-button-select.test.ts (Delete never reached the removal with a mouse-focused button)
    • key-sheet-question-toggle.test.ts (the second ? left the sheet open)
    • held-shortcut-repeat.test.ts (togglePause ran six times for one held Space)
    • key-help-delete-way-back.test.ts (the row promised Undo)
    • canvas-tab-order.test.ts (arrival order: A, B, A's subagents)
    • The keydown tests drive the real handler through a small harness (deck-keys-harness.ts) rather than reading its text.
  • Repointed text pins where the code they quote changed: card-focus-ring-869, canvas-keyboard, topbar-interaction, left-column-824, toggle-state, machine-panel-escape, details-on-select-814.
  • Browser, on an isolated deck with a 28-session fixture, dark and light, keyboard only where it applies:
    • Selected card: session-hue 2px ring and lift on click, on J, and on both cards of a Shift+Enter multi-selection in one session; the ring on the far-zoom face after F; Highlight in forced colours (dark and light) up close and at a distance.
    • Enter on each panel's close: focus lands on Toggle usage panel, Toggle machine detail, Toggle session list, Toggle accounts panel, and the selected card for the detail panel. A mouse click on the usage × leaves focus on the page, and Space then pauses instead of reopening the panel.
    • Clicking a session row and pressing Delete removes the card ("… removed from the board.", "Bring back 1 removed card").
    • ? then ? closes the sheet; a held ? leaves it open; the Delete row reads the new text.
    • Ten keydowns of a held Space pause once; a held T switches the theme once.
    • Tab across the canvas visits every session's cards together (no session split); focus stays on the focused card through an R re-layout that reorders the DOM.

React Flow's own selected prop is never true on a canvas whose nodes are controlled, so the ring the sheet draws for a selected card matched nothing. The frame now marks selected cards' wrappers itself and the ring, its far-zoom twin and a forced-colours highlight are drawn from that mark.
Selecting a card from a session row, a session's name or the ribbon leaves focus on the button the mouse pressed, and that button kept Delete because only single characters were handed back to the deck. Delete now goes back with the letters, so it removes the selected card; the button keeps Space and Enter, and a button reached by Tab keeps every key as before.
Opening the sheet gives its × focus by program, so the button was not one the mouse had pressed and kept every key, and the handler returned before the exception that lets ? close the sheet. ? now closes the sheet whatever in it has focus, except a text field, and the auto-repeat of the press that opened it does not shut it again.
No shortcut read the key's auto-repeat, so holding Space flipped pause and resume about thirty times a second and left the stream in whichever state the key came up on, and T, L, D and U flickered the theme and the panels the same way. Repeats are now ignored for every shortcut but J and K, which keep stepping through the board while held; a repeated Space is still cancelled.
…s sheet

The sheet said Undo brings a removed card back, but the banner that carried Undo is gone and nothing offers one. The row now names the session list (L), which is the real way back and what the detail panel's Remove button already says.
React Flow renders the cards, and Tab visits them, in the order the frame hands them over, which was the order their agents were first heard of. A subagent spawned after another session started landed after that session, so Tab jumped from one session into the next and back for the rest of its subagents. The frame now hands them over down each column of sessions and then across, and inside a session the root and then each rank of subagents from the top.
…it away

Closing Usage, This machine, Claude accounts, the detail panel or the session list with its own × or ‹ from the keyboard left focus on the page body, so the next Tab started again at the skip link and a screen reader said nothing. Focus now goes to the topbar button that opens the panel, and for the detail panel to the card it was about, or the canvas when that card is not drawn. A mouse press still leaves focus where it was, so Space keeps pausing the stream instead of reopening the panel.
@BarganConstantin
BarganConstantin merged commit 74b53ac into development Oct 5, 2026
10 checks passed
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