web: dir autocomplete is hard to dismiss — fix focus and key handling #60

Closed
opened 2026-08-23 19:28:22 +01:00 by naps62-yolo · 2 comments
Collaborator

web/src/dirAutocomplete.ts is hard to get out of once it opens — the popup keeps focus and there is no obvious way to dismiss it without losing what was typed. It stays as the escape hatch behind the project list, so it has to behave.

  • Escape closes the popup and returns focus to the input, leaving the typed value intact. It must not propagate: in a draft pane, an Escape that bubbles should not also discard the draft.
  • Tab commits the highlighted entry and moves to the next field; with nothing highlighted it just moves on.
  • Arrow keys move the highlight, Enter commits it.
  • Clicking outside, or the input losing focus, dismisses the popup.
  • The popup does not reopen on its own after being dismissed until the operator types again.

The { once: true } keydown listener the modal used for Escape is not the pattern to copy — it unregisters after the first key of any kind, so Escape silently stops working once anything is typed. The draft pane's own key handling should not repeat that.

Depends on: #57

`web/src/dirAutocomplete.ts` is hard to get out of once it opens — the popup keeps focus and there is no obvious way to dismiss it without losing what was typed. It stays as the escape hatch behind the project list, so it has to behave. - `Escape` closes the popup and returns focus to the input, leaving the typed value intact. It must not propagate: in a draft pane, an `Escape` that bubbles should not also discard the draft. - `Tab` commits the highlighted entry and moves to the next field; with nothing highlighted it just moves on. - Arrow keys move the highlight, `Enter` commits it. - Clicking outside, or the input losing focus, dismisses the popup. - The popup does not reopen on its own after being dismissed until the operator types again. The `{ once: true }` `keydown` listener the modal used for `Escape` is not the pattern to copy — it unregisters after the first key of any kind, so `Escape` silently stops working once anything is typed. The draft pane's own key handling should not repeat that. Depends on: #57
naps62-yolo added this to the Spawn v2 milestone 2026-08-23 19:28:22 +01:00
naps62-yolo added the area/webtype/fixdifficulty/easy labels 2026-08-23 19:28:22 +01:00
naps62-yolo added a new dependency 2026-08-23 19:29:56 +01:00
naps62-yolo added a new dependency 2026-08-23 19:29:56 +01:00
Author
Collaborator

Out of scope finding: the legacy spawn modal (web/src/spawn.ts:59) still registers its window Escape handler with { once: true }, so it unregisters after the first keydown of any kind — after one keystroke anywhere, Escape no longer closes the modal. Same pattern this issue flags; worth fixing (or deleting the modal) if it is still reachable now that draft panes exist.

Out of scope finding: the legacy spawn modal (`web/src/spawn.ts:59`) still registers its window Escape handler with `{ once: true }`, so it unregisters after the first keydown of any kind — after one keystroke anywhere, Escape no longer closes the modal. Same pattern this issue flags; worth fixing (or deleting the modal) if it is still reachable now that draft panes exist.
Author
Collaborator

Integrated into blitz/spawn-v2.

Escape now stops propagating so it dismisses the popup without discarding the draft, Tab commits the highlight, blur and outside clicks dismiss, and a dismissed popup stays closed until the next keystroke.

The worker pulled in happy-dom as a dev dependency to test this at the DOM level — the web suite had no DOM environment before. Kept: it is test-only and these behaviours are not testable without it.

Verified on the integration branch: typecheck clean, 60 tests across 9 files.

Integrated into `blitz/spawn-v2`. Escape now stops propagating so it dismisses the popup without discarding the draft, Tab commits the highlight, blur and outside clicks dismiss, and a dismissed popup stays closed until the next keystroke. The worker pulled in `happy-dom` as a dev dependency to test this at the DOM level — the web suite had no DOM environment before. Kept: it is test-only and these behaviours are not testable without it. Verified on the integration branch: typecheck clean, 60 tests across 9 files.
This repo is archived. You cannot comment on issues.
1 Participants
Due Date
No due date set.
Reference: naps62/maestro#60