Commit Graph
23 Commits
Author SHA1 Message Date
liukx0205 9827bcfb37 Merge master into fix/focus-ring-brand-primary 2026-09-24 15:38:51 +08:00
liukx0205 4f1a1289f5 fix(client): use blue focus rings in light and dark themes 2026-09-24 12:24:47 +08:00
liukx0205 e71fa92030 Merge master into fix/focus-ring-brand-primary 2026-09-24 12:05:19 +08:00
liukx0205 bf4d264368 Merge master into feat/unify-code-highlight-languages 2026-09-24 11:58:08 +08:00
liukx0205 caa4b8feca fix: highlight CSV without changing the default spreadsheet preview 2026-09-23 21:09:42 +08:00
liukx0205 5e13010b90 test(web): document suite-level browser setup and bound the reconnect polls 2026-09-20 14:54:27 +08:00
liukx0205 b882e7fc20 docs(session): record the client-local engagement memory limits 2026-09-20 14:54:27 +08:00
liukx0205 d8480db9f0 refactor(web): read engagement retention from one identity set
Address review: retention now has a single definition (retainedIds) shared by
the list-refresh sweep and the single-id prune, an already-engaged identity
skips the redundant row mutation, and the ledger documents why Host-asserted
running is recorded before any holder exists while the client-local acceptance
callback requires one.
2026-09-20 14:54:20 +08:00
liukx0205 4bff618b17 docs(web): note the metadata hint applied over the engagement rule 2026-09-20 14:44:25 +08:00
liukx0205 ae58d210eb docs(web): scope the second projection store to a discarded store 2026-09-20 14:44:01 +08:00
liukx0205 7aa2d4b5cc docs(web): note the retained subagent catalog on session removal 2026-09-20 14:44:01 +08:00
liukx0205 e3f0d3fb6e fix(web): preserve session engagement across blank list refreshes 2026-09-20 14:43:46 +08:00
liukx0205 cccfdb6040 Merge origin/master into feat/composer-selection-keyboard 2026-09-15 19:42:37 +08:00
liukx0205 21a785902b fix(client): keep a launcher-opened menu open through its own focus track
Opening the trigger menu from the launcher button has to put the keyboard in
the editor for the arrows to drive it, and Lexical's focus restores its
selection a tick later — a track the controller read as an empty draft and
answered by closing the menu the gesture had just opened. A launcher-opened
menu now survives that single follow-up track; typing, picking, Escape or a
pointer press still takes over.

The access-confirmation golden follows the panel's new highlight: it parks on
the row the options mark as the current value rather than the top row.
2026-09-15 14:39:21 +08:00
liukx0205 afbe3a4b1d refactor(client): compute the menu's keyboard region once per key 2026-09-15 14:22:03 +08:00
liukx0205 b263581e92 fix(client): answer the review bot's findings on the keyboard hand-offs
- The model seat decides before consuming: a focused control that is not a row
  (a retry button) keeps the browser's traversal, and Tab enters the list only
  from the trigger.
- A launcher-opened menu is a fresh intent, so the dismissal that closed the
  same token earlier no longer silences it.
- Comments and JSDoc now match the implementation: the near-end entry resumes
  from the walk's last index, Shift+Tab leaves whenever the menu is open, and
  the anchor hand-back names the control that opened the menu.
- The e2e focus assertions all go through `expect.poll`.
- Regression coverage for a rowless pane (the trigger keeps the keyboard) and
  for a focused retry keeping its Tab, in the seat and the popup shell.
- The PR records the two public-surface changes (`SessionInput.focus()` in,
  `bindComposerFocus` out) and the row-fill focus decision.
2026-09-15 14:21:00 +08:00
liukx0205 5c3081eeaa fix(client): tighten the keyboard hand-offs, and drop the dialog Escape layering
Review follow-ups on the hand-offs this branch added:

- Menu gives the keyboard back to the control that opened it (an anchor may
  wrap several, as a split button does), falls back to a disabled-free anchor
  button, leaves a Tab it cannot use to the browser, and no longer moves focus
  while the owner keeps the list open.
- The model seat settles only real rows with Tab and keeps the keyboard on its
  trigger when a pane's rows are disabled or absent.
- The popup shell leaves Tab to the browser when nothing can be settled (the
  error strip's retry button stays reachable), and a dismissal caused by a
  stale catalog returns the keyboard like the other paths.
- A frozen-tier track is the submit gesture's own bookkeeping and no longer
  re-arms a menu the user dismissed.
- The launcher reuses the shared caret-preserving focus helper; the option
  contract records that `active` is the row an accept gesture confirms; the
  conversation README documents the composer's key and focus behavior.

The dialog/menu Escape layering this branch also carried is out of scope here
and has been removed again.
2026-09-15 14:16:14 +08:00
liukx0205 3065f9cc27 docs(client): drop a reverted implementation from the note's evidence list 2026-09-15 13:59:38 +08:00
liukx0205 4fc515cb68 fix(client): keep the ring on the triggers and off the menu rows
The two split the other way around: the composer's triggers keep the focus
ring their design gives them (a 2px `--dsw-alias-border-l3` ring), while a
walked menu row shows the hover fill alone, without the browser's default
outline doubling it.
2026-09-15 13:55:50 +08:00
liukx0205 449a4610d7 fix(client): keep the browser ring on the focused menu row
The menu family was the only place that suppressed the browser's default focus
ring. It keeps that ring now, like the app's other controls, on top of the
hover fill a walked row already carried.
2026-09-15 13:52:49 +08:00
liukx0205 4b8a47a198 docs(client): record the SessionInput focus addition in the note 2026-09-15 13:38:56 +08:00
liukx0205 f46b025fd5 feat(client): give the shared menu family its keyboard model
Arrow navigation was bound to `autoFocus`, so the dropdowns that open with the
keyboard on their trigger — the composer's permission seat, the settings
pickers, the workspace and preset chips — had no walk at all, and a walk that
read its position from `document.activeElement` alternated between the first
and last row as soon as a row refused focus. The walk now works either way and
resumes from the index it last focused.

The keyboard returns to the anchor on Escape and on a selection — unless the
owner moved it itself, as a presented file card does for its preview button —
and the focused row wears the hover fill instead of the browser's ring. An open
menu takes the first Escape from the dialog it sits in.

The composer's trigger menu keeps its own Tab, which settles or drills the
highlighted candidate; Escape and Shift+Tab leave it without settling, and a
dismissed menu stays dismissed until its query changes. Opening it from the
launcher button returns the keyboard to the editor first, since the menu is a
combobox over that editor.
2026-09-15 13:35:27 +08:00
liukx0205 c47a469aec feat(client): accept and leave with Enter, Tab, and Escape in the composer
The popup select panel and the model seat hold focus while open, and their Tab
fell through to the browser's traversal, leaving an open surface that only a
pointer press clears. Both now settle on Enter or Tab, leave on Escape or
Shift+Tab, walk with the arrows, and park on the value in use: the panel's
highlight on the row its options mark current, the seat's drilled pane on its
checked row, with the keyboard handed back to the cell that drilled in when the
pane is left.

Dismissal rides the conversation's own focus(), so the caret returns where the
draft left it instead of at the start.
2026-09-15 13:35:04 +08:00