Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ Paths are relative to `docs/design/`, `docs/spec/`, `docs/guides/`, and `skills/
| Dict navigation + polish | dict-navigation | dict-navigation, dict-polish | — | — |
| DD browse lens: spotlight grid (entity + flow-node cards, hover/pin spotlight; solid FK predicate lines + dashed cross-domain data-flow lines; hover-reveal labels; off-screen chips; facing-edge anchoring; focus/isolate mode for scale) | dd-spotlight-grid | dd-spotlight-grid | — | — |
| Graph viewer FAB UX | viewer-fab-ux | viewer-fab-ux | — | — |
| Keyboard navigation shortcuts (g/d/f view switch, l DG layout, b DD lens, `/` or `Cmd`/`Ctrl`+`k` search-focus; pure resolver + global hook; editable/modifier guards, `Cmd`/`Ctrl`+`k` resolved in the same pre-editable slot as the zoom chords) | keyboard-nav-shortcuts | keyboard-nav-shortcuts | commands | — |
| Keyboard navigation shortcuts (g/d/f view switch, l DG layout, b DD lens, `/` or `Cmd`/`Ctrl`+`k` search-focus, arrow-key canvas pan on graph/flow — 5px per keydown, 25px with Shift, viewport-movement `{type:'pan',dx,dy}` action routed to `panBy(dx,dy)` on both view handles, dict/editable/ctrl-meta-alt → null; pure resolver + global hook; editable/modifier guards, `Cmd`/`Ctrl`+`k` resolved in the same pre-editable slot as the zoom chords, arrows in the same post-editable/pre-modifier slot as `?` since Shift is their step multiplier) | keyboard-nav-shortcuts | keyboard-nav-shortcuts | commands | — |
| Help overlay (view-aware orientation modal — "what am I looking at?"; `HelpModal` on the shared `Modal`, switched on `ViewName`; concise term→desc rows: Graph = entity types + layouts + Shift lineage + key-inherited vs surrogate; Dict = lenses + spotlight + Shift lineage + search/focus; Flow = DFD symbols + drill-down/inspect; per-view Keyboard section; footnote to Legend on Graph/Flow. Opened by a top-bar `?` button left of the theme toggle AND the `?` key — `resolveShortcut` returns `{type:'help'}`, resolved after the editable guard but before the bare-key modifier guard since `?` needs Shift, gated off ctrl/meta/alt; `useKeyboardShortcuts` `onHelp`; editable guard keeps `?` inert while typing. Distinct from the symbol `LegendModal`. Tests: `test-shortcuts.ts` T16 + `test/checks/test-help-overlay.ts` Playwright) | help-overlay | help-overlay, keyboard-nav-shortcuts | commands | — |
| Graph and Flows search (dim-don't-filter title-first matching with a per-bar body-text toggle; Graph: `search-match`/`search-dim` cytoscape classes, `n of N` count readout, Enter cycles ascending-id matches wrapping via `navigateToEntity`, survives hover/lineage/relayout/SSE refresh; Flows: `searchFlowDiagrams` walks every non-synthetic diagram incl. sub-DFDs, results dropdown grouped by diagram navigates via `selectDiagramById`, in-diagram dim keys off suffix-stripped base token; `/` focuses the active view's search bar (Dictionary via `DictionaryViewHandle.focusSearch()`, unchanged otherwise); bundle-only, no model/layout-store/hash/export-payload writes) | graph-flow-search | graph-flow-search | commands | — |
| Graph node position persistence (drag-to-save, reset) | graph-position-persistence | graph-position-persistence | — | — |
Expand Down
3 changes: 2 additions & 1 deletion docs/guides/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,9 @@ The app responds to single-key shortcuts while no text field is focused and no m
| `b` | Toggle dictionary lens (read ↔ browse) — Dictionary view |
| `/` or `Cmd`/`Ctrl` + `K` | Focus the search bar — Graph, Dictionary, Flows |
| `?` | Open the help overlay for the current view |
| `←` `→` `↑` `↓` | Scroll the canvas 10px — Graph and Flows views; hold `Shift` for 50px |

Shortcuts are ignored while typing in a search box or any other input, and when a modifier key is held. `?` is the one exception to the modifier rule — it needs Shift to type, so Shift does not suppress it (but it is still ignored while typing in a field). `Cmd`/`Ctrl` + `K` is a second exception: like the zoom chords below, it focuses search even while a text field is already focused elsewhere.
Shortcuts are ignored while typing in a search box or any other input, and when a modifier key is held. `?` is the one exception to the modifier rule — it needs Shift to type, so Shift does not suppress it (but it is still ignored while typing in a field). `Cmd`/`Ctrl` + `K` is a second exception: like the zoom chords below, it focuses search even while a text field is already focused elsewhere. The arrow keys are a third: `Shift` selects their faster stride instead of suppressing them, and holding an arrow scrolls continuously. Arrows keep their normal meaning while typing in a field, and `Cmd`/`Ctrl`/`Alt` arrow chords are left to the OS and browser.


### Help overlay
Expand Down
6 changes: 6 additions & 0 deletions docs/spec/help-overlay.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,9 @@ primitive, view-switched on `ViewName`, with static term→description content;
**What changed:** the Graph and Flows "How to explore" sections each gained a Search row (Graph: term matching, body-text toggle, Enter cycling; Flows: cross-diagram results grouped by diagram, in-diagram dimming). Every view's Keyboard section now lists `/` — focus that view's search input.

**Why:** the graph-flow-search feature (`docs/spec/graph-flow-search.md`, SC8) adds search bars to Graph, Dictionary, and Flows with a shared `/` focus shortcut; the help overlay must describe what a first-time viewer sees, including the new search affordance.

### 2026-07-14 — Arrow-key pan row added to the Keyboard section

**What changed:** the Graph and Flows Keyboard sections gained a `← ↑ ↓ →` row ("Scroll the canvas; hold Shift to scroll faster"), added inside the existing graph/flow-only block next to the zoom chord row.

**Why:** arrow-key canvas panning shipped in the shortcut resolver (`docs/spec/keyboard-nav-shortcuts.md`, 2026-07-14 arrow-key entry); the overlay lists the keys that work on each view.
35 changes: 35 additions & 0 deletions docs/spec/keyboard-nav-shortcuts.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,26 @@ Suppressed in editable context (typing a literal `?` in the search box never
opens the overlay). The overlay content/component is owned by
`docs/spec/help-overlay.md`; this resolver owns only the key binding.

**Arrow-key panning** — resolved in the same slot as `?` (after the editable
guard, before the bare-key modifier guard), because Shift is the step
multiplier here, not a suppressor:

| Key | Action | Active when |
|-----|--------|-------------|
| `←` `→` `↑` `↓` | `{ type: 'pan', dx, dy }` — pan the active canvas by `PAN_STEP` (10) screen px in the arrow's direction; `PAN_STEP_FAST` (50) with Shift held | `view === 'graph'` or `view === 'flow'`, not while typing |

`(dx, dy)` is the direction the **viewport** moves; consumers slide their
content the opposite way (`GraphViewHandle.panBy` → `cy.panBy({ x: -dx, y: -dy })`;
`FlowsViewHandle.panBy` → the flow SVG's registered zoom/pan control, which
converts screen px to viewBox units with the same mapping as the pointer
drag-pan). The action fires on every `keydown`, so OS auto-repeat gives
continuous scrolling while a key is held. Gated off `ctrl`/`meta`/`alt`
(OS text/history chords like `Cmd`+`←` pass through), suppressed in editable
context (the text cursor keeps moving in inputs), and `null` on the dict view
(the Dictionary is a native scroll container — hijacking arrows would break
page scroll). `PAN_STEP`/`PAN_STEP_FAST` are exported constants in
`src/app/logic/shortcuts.ts`.

## Success criteria

- [ ] `resolveShortcut(event, view, editable)` is a pure function in `src/app/logic/shortcuts.ts`, no DOM/React imports, exporting a `ShortcutAction` discriminated union.
Expand All @@ -87,6 +107,7 @@ opens the overlay). The overlay content/component is owned by
- [ ] Touched source files (`App.tsx`, `DictionaryView.tsx`, `FabMenu.tsx`, new `logic/shortcuts.ts`, new `hooks/useKeyboardShortcuts.ts`) introduce **zero** new `tsc --noEmit` errors vs. the baseline (`tmp/baseline-typecheck.log`; these files start at 0).
- [ ] CLAUDE.md feature map gets a "Keyboard navigation shortcuts" row; a brief mention added to the relevant user guide (`docs/guides/commands.md` or controls guide).
- [ ] `Cmd`/`Ctrl` + `k` resolves to `{ type: 'search' }` in the same pre-editable-guard slot as the zoom chords (gated on `ctrl`/`meta`, not `alt`/`shift`), so it focuses the active view's search input even while a text field is already focused elsewhere; `test-shortcuts.ts` covers Cmd+k/Ctrl+k → search, editable-bypass, alt/shift → null, and bare `k` (no modifier) → null.
- [ ] Arrow keys resolve to `{ type: 'pan', dx, dy }` on graph/flow per the keymap (10px, 50px with Shift; dict → null; editable → null; ctrl/meta/alt → null); both view handles expose `panBy(dx, dy)` and the shell routes to the active canvas. `test-shortcuts.ts` covers the resolver rows (T25–T29); `test-keyboard-shortcuts.ts` proves in the browser that ArrowRight moves `cy.pan()` by exactly −10px, Shift steps 50px, the flow SVG inner translate moves opposite the viewport with a 5× Shift ratio, and arrows stay inert while a search input is focused.

## Approaches

Expand Down Expand Up @@ -152,3 +173,17 @@ real-browser Playwright check, per the project's "test the actual runtime" lesso
**What changed:** `resolveShortcut` now also returns `{ type: 'search' }` for `Cmd`/`Ctrl` + `k`, resolved in the same pre-editable-guard slot as the zoom chords (gated on `ctrl`/`meta`, not `alt`/`shift`) — so it focuses the active view's search input even while typing elsewhere, unlike bare `/` which stays suppressed in editable context. The section formerly titled "Modifier-gated zoom" is now "Modifier-gated zoom + search" to reflect the added row. `test-shortcuts.ts` covers Cmd+k/Ctrl+k → search, editable-bypass, alt/shift → null, and bare `k` (no modifier) → null.

**Why:** user feedback on the live graph-flow-search branch (`docs/spec/graph-flow-search.md` CP5, SC8) — `Cmd`/`Ctrl`+`K` is the conventional "focus search" chord in modern web apps and users expect it to work regardless of where focus currently is.

### 2026-07-14 — Arrow-key canvas panning

**What changed:** `resolveShortcut` now returns `{ type: 'pan', dx, dy }` for the arrow keys on the graph and flow views — `PAN_STEP` (5) screen px per keydown, `PAN_STEP_FAST` (25) with Shift, resolved in the same post-editable/pre-modifier-guard slot as `?` since Shift is the step multiplier rather than a suppressor; ctrl/meta/alt chords and the dict view fall through to null. The body gained an "Arrow-key panning" keymap section. `useKeyboardShortcuts` carries an `onPan(dx, dy)` callback; the shell routes it to a new `panBy(dx, dy)` on `GraphViewHandle` (→ `cy.panBy` negated) and `FlowsViewHandle` (→ the flow SVG's registered zoom/pan control, screen-px→viewBox conversion shared with the pointer drag-pan). `test-shortcuts.ts` T25–T29 cover the resolver; `test-keyboard-shortcuts.ts` tests 5–7 prove the browser behavior on both canvases plus the editable guard.

**Why:** user request — the DG and DFD canvases were mouse-only for scrolling; arrow keys with keydown auto-repeat give continuous keyboard scrolling, and Shift gives a faster stride.

### 2026-07-14 — Pan step values raised to 10px / 50px

**What changed:** `PAN_STEP`/`PAN_STEP_FAST` changed from 5/25 to 10/50 screen px; the keymap table, the affected success criterion, and every doc/test wording that named the old values were updated to match (the shift-fast-to-bare ratio stays 5×, unaffected).

**Why:** user feedback on the live branch — the original 5px step felt too slow for practical scrolling.

**Superseded:** the "Arrow-key canvas panning" entry above introduced the feature at 5px/25px; that entry is left as-is as the historical record of that commit.
Loading
Loading