diff --git a/DESIGN/04-interactions.md b/DESIGN/04-interactions.md index a453c36..da1063f 100644 --- a/DESIGN/04-interactions.md +++ b/DESIGN/04-interactions.md @@ -37,6 +37,7 @@ Selection, drag & drop, keyboard, clipboard, search. This is where the old app s - **Arrows**: spatial card navigation (nearest card in the direction, across interior grid columns and lanes); with a lane selected, ←/→ move lane selection; ⇧-arrow extends; selection scrolls into view; all grammar keys inert while a title editor is focused, and menu dispatch narrows to the text domain (focused-editor rule below). - **⌥-arrows jump**: ⌥↑/⌥↓ to the current lane's first/last card; ⌥←/⌥→ to the first/last lane. - **Return** on a selected lane: creates a card at its bottom, editor focused; Return commits and re-selects the lane (next Return = next card); ⌘↩ commits and opens the card window. Abandoned placeholders (Escape, empty commit, click-away) are discarded — creating-then-abandoning never leaves an empty card behind (untitled cards exist only when made deliberately, e.g. by an external writer or by clearing an existing title). The placeholder is store-transient overlay state — the named exception to 02-architecture.md's one-way flow; nothing exists on disk until the title commits. +- **Inline rename tracks its target by UUID, and vanishing discards it** (the placeholder and card-window kin rules — 02-architecture.md — applied to the third inline editor): a foreign *move* mid-rename is invisible — the editor follows the UUID and the commit writes the title wherever the card now lives; a target that is tombstoned, deleted, or gone at commit time discards the editor and its keystrokes silently (a liveness flip is a vanish; nothing is ever written into a vanished folder, and no partial `index.md` can resurrect deleted data). A write that fails *after* a valid commit is the ordinary one-shot write-failure banner. VoiceOver announces the vanished target per 10-accessibility.md's recovery rule. - **Return** on a sole selected **card**: inline rename. Return disambiguates on card selection — sole card = rename, lane = create (above) — and is **inert on a multi-card selection**; a lane's rename path is Board ▸ Rename. **Escape** steps outward one layer per press: abandons an open editor; else clears search, returning focus to the board (Search below); else **clears the selection** — the keyboard deselect. - **Focused editor = text domain** (settled): while an inline title editor — rename or the new-card placeholder — is focused, board-scoped menu commands (Delete, New Card, Paste, Move, Style, …) disable via menu validation; text-domain chords route to the field as standard text ops — ⌘Z/⇧⌘Z are the editor's text undo (06-history-undo.md ▸ Undo routing), ⌘X/⌘C/⌘V/⌘A act on the text. The one board-command carve-out is **Open Card ⌘↩**, which stays enabled to commit the edit — placeholder or rename — and open the card window. Exits are otherwise unchanged: Return commits, Escape abandons; click-away splits by editor kind — a **rename commits** (focus loss = commit, matching the card window's title field in 05-card-window.md and the branch-switch parenthetical in 06-history-undo.md), while the **placeholder discards** per its rule above, the deliberate exception because nothing exists on disk yet. - **⌫** on a live selection: delete (tombstone) — the plain-key synonym for File ▸ Delete ⌘⌫ (see The map). Grammar, not a menu item: giving it a menu home would require a second "Delete"-titled item, which would collide for title-matched remapping (Configurable bindings). Inert while a title editor is focused, like every grammar key. @@ -81,7 +82,7 @@ Custom shortcuts are **system-native, with no in-app remapping UI**: macOS's App ## Search - Search field invoked with ⌘F (the board toolbar's sole default item; removed from the toolbar, ⌘F surfaces it transiently — 03-board-ui.md ▸ Toolbar; in the **card window**, Edit ▸ Find is find-in-text instead — 05-card-window.md), live filter: cards whose title *and* body both miss the query animate out; case/diacritic-insensitive substring. Scope is **title + body only** (settled) — attachment filenames are not searched. -- The filter is the single source of truth for "what's on the board": layout, drop zones, marquee, ranges, arrow nav, and lane count badges all read it. Hidden cards leave the selection; creating a card clears the search. Escape clears, then returns focus to the board. +- The filter is the single source of truth for "what's on the board": layout, drop zones, marquee, ranges, arrow nav, and lane count badges all read it. Hidden cards leave the selection; creating a card clears the search — creation's carve-out exists because a brand-new card must not be born invisible. **Rename deliberately gets no carve-out**: a rename committed during an active search re-runs the predicate like any edit — a title that stops matching animates the card out and drops it from the selection, exactly as an agent's edit would; the filter stays a pure predicate with one exception, not two. Escape clears, then returns focus to the board. - **Dispatch while the search field is focused** (settled): the field is a *control*, not a content editor — the focused-editor lockdown (Grammar above) does not apply. Text-domain keys route to the field: ⌘A/⌘X/⌘C/⌘V act on the query, plain ⌫ edits the query and never reaches the board, horizontal arrows move the caret. Board menu commands stay enabled and act on the board selection exactly as when the field is unfocused — ⌘N included (creating a card clears the search, above) — and the Delete pair stays unambiguous by construction: plain ⌫ is query editing, ⌘⌫ is File ▸ Delete on the selection. ## Changes from Kanban