From 6a5e6623fe3c1305b7279cb564ae8f4edb0c7ac0 Mon Sep 17 00:00:00 2001 From: ui-arch-bot Date: Fri, 23 Oct 2026 17:06:17 +0800 Subject: [PATCH] =?UTF-8?q?iter:=20d25=20menu=20=E6=9D=A1=E7=9B=AE?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=BF=AB=E6=8D=B7=E9=94=AE=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .ua/backlog.json | 8 ++++++++ .ua/index.json | 5 +++-- .ua/iterations.log | 1 + apps/demo/main.ts | 4 ++-- llms-full.txt | 9 +++++---- packages/skin/ui/src/menu.ts | 3 ++- packages/skin/ui/src/types.ts | 1 + packages/skin/ui/ua.manifest.json | 3 ++- packages/skin/ui/ui.css | 19 ++++++++++++++++++- 9 files changed, 42 insertions(+), 11 deletions(-) diff --git a/.ua/backlog.json b/.ua/backlog.json index b2ef55e..f272eb7 100644 --- a/.ua/backlog.json +++ b/.ua/backlog.json @@ -248,6 +248,14 @@ "acceptance": "README 覆盖定位 / 快速开始 / 28 组件清单 / 目录表 / 三道门禁 / Agent 接入 / 分支流水线;新增 标记区块,ua verify 校验区块 id 集合与全部清单 docs.components 完全一致(缺/多都报);负向测试(删 avatar)能拦下;AGENTS.md 同步;npm run check 全绿", "status": "done", "notes": "不做自动写入(避免工具偷偷改文档),只做一致性校验:新增组件时 verify 报「README 组件区块缺少 xxx」,由人补一行;标记区块用 · 分隔便于人读与机器切分" + }, + { + "id": "d25", + "title": "menu 条目支持快捷键提示", + "motivation": "菜单里展示快捷键是桌面级体验的标配;缺字段时调用方只能把快捷键拼进 label,文案与对齐都失控", + "acceptance": "MenuItem 新增 shortcut?: string;条目改为 flex 两端对齐,label 单行省略,右侧 kbd 灰字提示(不绑定按键);demo 文件操作菜单加 F2 / ⌘D;manifest/文档/llms-full.txt 同步;npm run check 全绿", + "status": "done", + "notes": "明确边界:快捷键只做展示,实际按键仍需调用方全局监听(组件不做全局键盘陷阱);两端对齐让长文案截断而快捷键始终可见;kbd 用 inherit 字体避免等宽字跳脱整体排版" } ] } diff --git a/.ua/index.json b/.ua/index.json index 127dd57..dffe5c2 100644 --- a/.ua/index.json +++ b/.ua/index.json @@ -1,6 +1,6 @@ { "$schema": "ui-arch-registry-index/0.1", - "generatedAt": "2026-10-23T09:05:40.038Z", + "generatedAt": "2026-10-23T09:06:10.925Z", "repoRoot": ".", "packages": [ { @@ -517,7 +517,7 @@ "n": "items", "t": "MenuItem[]", "r": 1, - "d": "菜单条目:{ value, label, disabled?, danger?, divider? }" + "d": "菜单条目:{ value, label, disabled?, danger?, divider?, shortcut? }" }, { "n": "variant", @@ -543,6 +543,7 @@ "准备 items 数组:value 是回调标识、label 是展示文案,插一条 { divider: true } 即可分出条目组", "传 label 决定触发器文案;默认 ghost 轻量样式,主操作用 variant: 'primary'", "点触发器展开弹层,点条目收起并触发 onSelect;点外部或按 Esc 也会收起(Esc 后焦点回到触发器)", + "条目要给快捷键提示时传 shortcut(如 '⌘K'):右侧灰字展示,组件不绑定按键,实际快捷键由调用方在全局监听", "键盘:Tab 聚焦触发器,↑↓ 展开并在可用条目间环形移动,Enter / Space 选中;disabled 项自动跳过", "靠右对齐避免溢出时传 align: 'end';危险操作给条目加 danger: true" ] diff --git a/.ua/iterations.log b/.ua/iterations.log index 346c29f..2de4aa5 100644 --- a/.ua/iterations.log +++ b/.ua/iterations.log @@ -29,3 +29,4 @@ {"time": "2026-10-23T17:03:49+08:00", "id": "d22", "result": "done", "summary": "新增头像 avatar(src 图片 / 首字占位 + size + 四档语义底色),demo 独立 sec-avatar;中途被 verify 的 demo 锚点检查拦下已补;check 全绿"} {"time": "2026-10-23T17:04:27+08:00", "id": "d23", "result": "done", "summary": "alert 新增 title / closable / onClose 与 role=alert,关闭走 200ms 退场后摘除;demo 独立 sec-alert;manifest/llms 同步,check 全绿"} {"time": "2026-10-23T17:05:46+08:00", "id": "d24", "result": "done", "summary": "重写 README(定位/快速开始/28 组件/目录/门禁/Agent 接入/流水线),组件清单做成标记区块并由 ua verify 校验防漂移;负向测试通过,check 全绿"} +{"time": "2026-10-23T17:06:17+08:00", "id": "d25", "result": "done", "summary": "menu 条目新增 shortcut 快捷键提示(右侧 kbd 灰字,两端对齐 + 单行省略,不绑按键);demo/manifest/llms 同步,check 全绿"} diff --git a/apps/demo/main.ts b/apps/demo/main.ts index 8c8055c..8083d6b 100644 --- a/apps/demo/main.ts +++ b/apps/demo/main.ts @@ -337,8 +337,8 @@ const content = h( menu({ label: '文件操作', items: [ - { value: 'rename', label: '重命名' }, - { value: 'copy', label: '创建副本' }, + { value: 'rename', label: '重命名', shortcut: 'F2' }, + { value: 'copy', label: '创建副本', shortcut: '⌘D' }, { value: 'archive', label: '归档', disabled: true }, { divider: true, value: '', label: '' }, { value: 'delete', label: '删除', danger: true }, diff --git a/llms-full.txt b/llms-full.txt index 771e072..c59cbfc 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -1,6 +1,6 @@ # @ui-arch 组件库 Agent 文档(无图形版) -> 自动生成于 2026-10-23T09:05:40.038Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。 +> 自动生成于 2026-10-23T09:06:10.925Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。 > 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。 ## 快速上手 @@ -224,7 +224,7 @@ const city = signal(''); select({ options: [{ value: 'bj', label: '北京' }], v 参数: - label(必填):string —— 触发器文案 -- items(必填):MenuItem[] —— 菜单条目:{ value, label, disabled?, danger?, divider? } +- items(必填):MenuItem[] —— 菜单条目:{ value, label, disabled?, danger?, divider?, shortcut? } - variant(默认 ghost):'primary' | 'ghost' —— 触发器视觉强度;缺省 ghost - align(默认 start):'start' | 'end' —— 弹层对齐方向;缺省 start(与触发器左对齐) - onSelect(回调):(value: string) => void —— 选中回调,禁用项不触发 @@ -240,8 +240,9 @@ menu({ label: '操作', items: [{ value: 'edit', label: '编辑' }, { value: 'de 1. 准备 items 数组:value 是回调标识、label 是展示文案,插一条 { divider: true } 即可分出条目组 2. 传 label 决定触发器文案;默认 ghost 轻量样式,主操作用 variant: 'primary' 3. 点触发器展开弹层,点条目收起并触发 onSelect;点外部或按 Esc 也会收起(Esc 后焦点回到触发器) -4. 键盘:Tab 聚焦触发器,↑↓ 展开并在可用条目间环形移动,Enter / Space 选中;disabled 项自动跳过 -5. 靠右对齐避免溢出时传 align: 'end';危险操作给条目加 danger: true +4. 条目要给快捷键提示时传 shortcut(如 '⌘K'):右侧灰字展示,组件不绑定按键,实际快捷键由调用方在全局监听 +5. 键盘:Tab 聚焦触发器,↑↓ 展开并在可用条目间环形移动,Enter / Space 选中;disabled 项自动跳过 +6. 靠右对齐避免溢出时传 align: 'end';危险操作给条目加 danger: true 现场演示:apps/docs/demo.html#sec-menu diff --git a/packages/skin/ui/src/menu.ts b/packages/skin/ui/src/menu.ts index c80fd2a..4568873 100644 --- a/packages/skin/ui/src/menu.ts +++ b/packages/skin/ui/src/menu.ts @@ -24,7 +24,8 @@ export function menu(props: MenuProps): HTMLElement { disabled: item.disabled ? true : undefined, onClick: () => pick(item), }, - item.label, + h('span', { class: 'ua-menu-label' }, item.label), + item.shortcut ? h('kbd', { class: 'ua-menu-key' }, item.shortcut) : null, // 快捷键只做提示,不拦截按键 ) as HTMLButtonElement; if (!item.disabled) focusables.push(btn); // 禁用项不参与导航 return btn; diff --git a/packages/skin/ui/src/types.ts b/packages/skin/ui/src/types.ts index 50430d7..29aab78 100644 --- a/packages/skin/ui/src/types.ts +++ b/packages/skin/ui/src/types.ts @@ -103,6 +103,7 @@ export interface MenuItem { label: string; // 条目文案 disabled?: boolean; // 禁用该条目:置灰且不参与键盘导航 danger?: boolean; // 危险操作条目:文案取 danger 语义色 + shortcut?: string; // 右侧快捷键提示(仅展示,不绑定按键),如 '⌘K' divider?: boolean; // 该条目渲染为分隔线(忽略 value / label) } diff --git a/packages/skin/ui/ua.manifest.json b/packages/skin/ui/ua.manifest.json index fe12354..3db9bc9 100644 --- a/packages/skin/ui/ua.manifest.json +++ b/packages/skin/ui/ua.manifest.json @@ -388,7 +388,7 @@ "n": "items", "t": "MenuItem[]", "r": 1, - "d": "菜单条目:{ value, label, disabled?, danger?, divider? }" + "d": "菜单条目:{ value, label, disabled?, danger?, divider?, shortcut? }" }, { "n": "variant", @@ -414,6 +414,7 @@ "准备 items 数组:value 是回调标识、label 是展示文案,插一条 { divider: true } 即可分出条目组", "传 label 决定触发器文案;默认 ghost 轻量样式,主操作用 variant: 'primary'", "点触发器展开弹层,点条目收起并触发 onSelect;点外部或按 Esc 也会收起(Esc 后焦点回到触发器)", + "条目要给快捷键提示时传 shortcut(如 '⌘K'):右侧灰字展示,组件不绑定按键,实际快捷键由调用方在全局监听", "键盘:Tab 聚焦触发器,↑↓ 展开并在可用条目间环形移动,Enter / Space 选中;disabled 项自动跳过", "靠右对齐避免溢出时传 align: 'end';危险操作给条目加 danger: true" ] diff --git a/packages/skin/ui/ui.css b/packages/skin/ui/ui.css index d0e2b67..52627e2 100644 --- a/packages/skin/ui/ui.css +++ b/packages/skin/ui/ui.css @@ -360,8 +360,11 @@ visibility: visible; } .ua-menu-item { - display: block; + display: flex; width: 100%; + align-items: center; + justify-content: space-between; + gap: var(--ua-space-4); text-align: left; padding: 6px 10px; border: none; @@ -381,6 +384,20 @@ .ua-menu-item.is-danger:hover:not(:disabled) { background: color-mix(in srgb, var(--ua-color-danger) 10%, transparent); } +.ua-menu-label { + flex: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.ua-menu-key { + flex: none; + color: var(--ua-color-text-muted); + font-family: inherit; + font-size: var(--ua-font-size-sm); + opacity: 0.8; +} .ua-menu-item:disabled { opacity: 0.45; cursor: not-allowed;