Skip to content

Agent Skill Preload 选择器缺少键盘、Escape 与焦点管理 #243

Description

@suntianc

来源

2026-07-28 对 b1630e5^...HEAD 的 Standards review。相关重构:#236

问题

SkillPreloadSection.tsx 将候选列表实现为手写绝对定位浮层,每个候选项使用:

<div role="button" onClick={...}>

但没有 tabIndex、键盘事件、Escape 关闭、焦点进入/返回或浮层碰撞管理。结果是鼠标用户可以添加/移除预载 Skill,键盘用户无法可靠聚焦和选择候选项。

这违反 DESIGN.md

  • Select / Combobox / Menu 使用 Radix 或现有可访问原语;
  • 禁止裸 div onClick
  • Menu / Popover 正确管理 focus、Escape 和焦点返回。

该行为在 #236 前已存在,但拆分后的新组件继续固化了问题,因此单独修复,不混入纯重构票。

目标行为

  • 触发按钮可用 Enter/Space 打开选择器。
  • 打开后焦点进入搜索框或首个候选项。
  • 候选项使用语义化 button、checkbox item 或现有可访问组件,不使用裸 div onClick
  • Enter/Space 切换选中状态;屏幕阅读器能感知名称和 checked/selected 状态。
  • Escape 关闭最上层浮层并把焦点还给触发按钮。
  • 点击外部关闭;关闭时沿用现有逻辑清空搜索词。
  • 浮层进行窗口碰撞处理,不因靠近边缘而越界。
  • 鼠标多选、搜索、已选列表删除和保存 payload 行为不变。

实现约束

  • 优先复用 src/renderer/src/components/ui/ 中现有 Radix 封装;若现有 primitive 组合足够,不新增组件库。
  • 保持 SkillPreloadSection props 与 AgentEditDialog 保存契约不变。
  • 保持现有设计 token、密度和视觉层级;不引入新颜色、阴影体系或装饰性动画。
  • 搜索输入和候选项必须有可访问名称;Tooltip 不作为唯一 label。

测试

使用 Testing Library 按用户行为验证:

  1. 键盘打开并聚焦搜索/候选区域;
  2. Enter/Space 选择和取消一个 Skill;
  3. 选中状态可通过 role + checked/selected 查询;
  4. Escape 关闭并恢复触发器焦点;
  5. 点击外部关闭并清空搜索;
  6. 搜索过滤与无结果状态;
  7. 鼠标点击和最终保存 payload 不回归。

不要依赖内部 DOM 层级或 CSS selector。

验收标准

  • 候选列表无裸 div role="button"
  • 全流程可仅用键盘完成。
  • Escape、焦点进入与焦点返回符合 DESIGN.md。
  • 现有 AgentEditDialog 行为与 props 不变。
  • 相关 renderer 测试、pnpm run typecheckpnpm run build 通过。

非目标

  • 不重新设计 AgentEditDialog 信息架构。
  • 不修改 Skill preload 的领域规则或持久化格式。
  • 不调整 MCP、Tool Scope 等其他字段分组。

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2规范 / 坏味道 / 测试缺口bugSomething isn't workingready-for-agentFully specified, ready for an AFK agent

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions