Skip to content

feat(console-ui): global shortcuts, help dialog & overlay stack (#4) - #6

Open
wuxs wants to merge 2 commits into
mainfrom
issue-4-global-shortcuts
Open

feat(console-ui): global shortcuts, help dialog & overlay stack (#4)#6
wuxs wants to merge 2 commits into
mainfrom
issue-4-global-shortcuts

Conversation

@wuxs

@wuxs wuxs commented Jul 26, 2026

Copy link
Copy Markdown
Collaborator

概述

实现 Issue #4:为 Console UI 增加统一、可发现、可测试的全局快捷键系统。

  • 快捷键注册表 (src/shortcuts/shortcuts.js):单一数据源,稳定 id/action/category;平台感知 modifier(mac ⌘/Option、其他 Ctrl/Alt);基于 KeyboardEvent.code 匹配。
  • 默认键位:?Ctrl|⌘+/(帮助)、Ctrl|⌘+Alt+D/M/F/W(显示桌面/最小化/最大化/关闭)、Alt+1..9(按 Dock 顺序聚焦)。
  • 事件规则:编辑上下文(input/textarea/select/contenteditable/role=textbox/.xterm/data-shortcut-scope)禁用;event.repeat 忽略;仅命中且 enabled 时 preventDefault()
  • Overlay 层级 (src/overlays/OverlayProvider.jsx):分层 Escape 只关最顶层 dismissible 层;焦点陷阱/初始焦点/关闭恢复;modal 层把背景 inert+aria-hidden 并锁滚动(引用计数支持嵌套);取代各组件全局 keydown。
  • 帮助面板 (ShortcutHelpDialog.jsx):role=dialog/aria-modal,按 通用/导航/窗口 分组,从同一注册表渲染平台 modifier;?Ctrl|⌘+/ 打开。
  • 弹层迁移:AuthModal、AuditLog 详情 Drawer、AppMgmtDrawer 确认层迁到共享 overlay stack。
  • S0 共享测试基础:Vitest + jsdom + Testing Library + user-event + Playwright;新增 test:unit/test:e2e 脚本与 eslint test globals。

门禁(基于 origin/main 5ca8107)

结果
npm run build
npm run test:unit ✅ 3 文件 21 测试全过
npm run lint ✅ 改动文件 37→36(净减 1);7 个新增文件零 lint

Playwright e2e(e2e/shortcuts.spec.js)与多平台 modifier 人工复核留待 review 阶段补充。

关联

Closes #4

🤖 Generated with Claude Code

Issue #4 — unified, testable keyboard interaction for the console UI.

Shortcut system (src/shortcuts):
- Single-source registry with stable id/action/category, platform-aware
  modifiers (Cmd/Option on mac, Ctrl/Alt elsewhere) and code-based matching
- Default bindings: ? and Ctrl|Cmd+/ (help), Ctrl|Cmd+Alt+D/M/F/W
  (show desktop / minimize / maximize / close), Alt+1..9 (focus dock app)
- Disabled in editable contexts (input/textarea/select/contenteditable/
  role=textbox/.xterm/data-shortcut-scope); key repeat ignored;
  preventDefault only on a matched, enabled action

Overlay stack (src/overlays/OverlayProvider):
- Layered Escape closes only the top dismissible layer
- Focus trap, initial focus, focus restore on close, backdrop dismiss
- Modal layers set background inert + aria-hidden and lock body scroll
  (ref-counted for nesting); replaces per-component global keydown listeners

Help dialog (src/components/ShortcutHelpDialog): role=dialog/aria-modal,
opens via ? or Ctrl|Cmd+/, grouped by category, renders platform-correct
modifiers from the same registry.

Migrations: AuthModal, AuditLog detail drawer and AppMgmtDrawer confirmation
layers now ride the shared overlay stack.

Shared test base (S0): Vitest + jsdom + Testing Library + user-event +
Playwright; adds test:unit/test:e2e scripts and eslint test globals.

Closes #4

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@wuxs

wuxs commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator Author

已补充 Android 平板外接物理键盘兼容修复(commit cec05f5):

  • 有效 KeyboardEvent.code 优先;为空或 Unidentified 时回退到声明的 key
  • ? 按字符语义兼容不同键盘布局
  • 全局监听改为 window capture phase
  • 忽略 composition / keyCode=229
  • 移除整个 AppShell 的快捷键屏蔽,仅保留终端/编辑器等独占键盘区域

验证:

  • npm run test:unit -- --run src/shortcuts/shortcuts.test.js src/shortcuts/useGlobalShortcuts.test.jsx:2 文件、26 测试通过
  • npm run build:通过
  • make build-all:通过
  • 已部署到 192.168.1.2:9092,服务 active,HTTP 200,启动版本 cec05f5

已知限制:跨域 iframe 内按键仍无法冒泡到父页面;Android 外接键盘真实键位需在设备端复验。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(console-ui): 添加全局快捷键与快捷键帮助面板

1 participant