feat(canvas): keyboard-accessible node drag via Arrow keys
Closes canvas audit item: MEDIUM keyboard-accessible node drag. - Arrow keys move the selected node by 10px per press; Shift+Arrow moves by 50px. Position is persisted to the backend via savePosition. - The modal-dialog guard (same pattern as ? shortcut) prevents Arrow keys from moving nodes when a modal like KeyboardShortcutsDialog is open — dialogs own their own arrow semantics. - All shortcuts guarded by the inInput check so Arrow keys still work for text navigation inside inputs/textareas. Changes: - canvas.ts: new moveNode(dx, dy) store action — updates position directly without the grow-parents pass that onNodesChange runs on every drag tick (avoids edge-chase flicker). - useKeyboardShortcuts.ts: Arrow key handler added. - canvas.test.ts: new moveNode unit tests (position update, no-op, savePosition call). - useKeyboardShortcuts.test.tsx: new integration tests for all keyboard shortcuts including the new Arrow key handlers. - canvas-audit-items.md: Keyboard Shortcuts section upgraded to ✅, drag item marked done. - canvas-events.test.ts: fix pre-existing double-}); syntax error. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -72,10 +72,12 @@ canvas/src/
|
||||
- **Minimap:** Not present (MiniMap mocked as null in tests)
|
||||
- **Status:** Basic keyboard support via viewport shortcuts
|
||||
|
||||
### Keyboard Shortcuts ⚠️ PARTIAL
|
||||
- Exists in `useKeyboardShortcuts.ts` but no `aria-describedby` on trigger buttons
|
||||
- No dedicated keyboard shortcut help dialog
|
||||
- **Gap:** Users can't discover shortcuts visually
|
||||
### Keyboard Shortcuts ✅ (strong)
|
||||
- All shortcuts in `useKeyboardShortcuts.ts` with `inInput` guard ✅
|
||||
- Global `?` shortcut opens `KeyboardShortcutsDialog` (PR #175) ✅
|
||||
- Dialog: portal-based, aria-modal, focus trap, Escape close ✅
|
||||
- Arrow keys move selected node 10px (50px with Shift) — keyboard node drag (this PR) ✅
|
||||
- Hierarchy navigation (Enter/Shift+Enter), z-order (Cmd+]/[), zoom-to-team (Z) ✅
|
||||
|
||||
### Focus Management ✅ (strong)
|
||||
- Skip link → `#canvas-main` ✅
|
||||
@@ -83,9 +85,9 @@ canvas/src/
|
||||
- Focus trap in modals via Radix ✅
|
||||
- Focus ring: `focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950`
|
||||
|
||||
### Accessibility Tree ⚠️ PARTIAL
|
||||
### Accessibility Tree ✅
|
||||
- Canvas is in accessibility tree (React Flow DOM nodes)
|
||||
- Node state changes not announced to screen readers (no `aria-live` region)
|
||||
- Node state changes announced via `aria-live="polite"` region (PR #172) ✅
|
||||
- Context menus announced via `role="menu"` ✅
|
||||
|
||||
### Context Menus ✅ (strong)
|
||||
@@ -109,7 +111,7 @@ canvas/src/
|
||||
|----------|------|-------|--------|
|
||||
| ~~HIGH~~ | ~~Screen reader announcements for canvas state changes~~ | ~~Canvas.tsx, canvas-events.ts, canvas.ts~~ | ✅ Done — PR #172 |
|
||||
| MEDIUM | Keyboard shortcut help dialog | useKeyboardShortcuts.ts | ✅ Done (PR #175) |
|
||||
| MEDIUM | Keyboard-accessible node drag | WorkspaceNode.tsx, useDragHandlers.ts | Not started |
|
||||
| MEDIUM | Keyboard-accessible node drag | WorkspaceNode.tsx, useDragHandlers.ts | ✅ Done (this PR) |
|
||||
| LOW | Edge anchor keyboard accessibility | A2AEdge.tsx | Not started |
|
||||
| LOW | Node resize keyboard accessibility | WorkspaceNode.tsx (NodeResizer) | Not started |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user