{ "$schema": "迭代点子库,status: open=待做 / done=已完成;按数组顺序取第一条 open 执行", "items": [ { "id": "b01", "title": "新增 tooltip 组件", "motivation": "皮肤包 16 组件缺少悬浮提示,表单与工具栏场景常用;可复用自绘弹层与微动画既有模式", "acceptance": "packages/skin/ui 新增 tooltip.ts:content/message 简单 API,hover/focus 触发,延迟约 150ms 出场,带出入场微动画与 prefers-reduced-motion 兜底,只消费 --ua-* 令牌;导出并注册进 ua.manifest.json,文档站 props 表与 llms-full.txt 同步更新;npm run check 全绿", "status": "done", "notes": "API 定为 tooltip(props, trigger) 包裹式;delay 默认 150ms,Esc 立即收起,气泡 pointer-events:none 防抖,aria-describedby + role=tooltip 保证读屏可读;demo 新增 sec-tooltip 区块。顺带修复 ua style 对 https:// 的误判(先剥离字面量再定位 //)" }, { "id": "b02", "title": "新增 toast 消息提示组件", "motivation": "alert 是常驻块级元素,缺少轻量转瞬即逝的全局反馈;操作成功/失败场景刚需", "acceptance": "新增 toast.ts:toast.success/error/warning/info 四个工厂函数,入参 {message, duration?},默认 3s 自动消失,右上角堆叠,语义色复用四档 variant,出入场微动画 + prefers-reduced-motion 兜底;导出、manifest、文档、llms-full.txt 同步;npm run check 全绿", "status": "done", "notes": "对外暴露 toast.info/success/warning/error(message, duration?) 四工厂 + showToast(props) 完整入参版;全局堆叠容器懒创建,role=status 无障碍;退场用 transitionend 移除并带 320ms 兜底(覆盖 reduced-motion 下 transition 不触发的情况);样式复用 alert 语义色 color-mix 模式,reduced-motion 列表已补 .ua-toast;demo 新增 sec-toast 区块" }, { "id": "b03", "title": "新增 skeleton 骨架屏组件", "motivation": "异步加载占位是数据表格与卡片的标配,配合 dataTable 空状态形成完整加载体验", "acceptance": "新增 skeleton.ts:skeleton({variant: 'text'|'rect'|'circle', rows?}),呼吸/扫光微动画 + prefers-reduced-motion 静态化,只消费 --ua-* 令牌;导出、manifest、文档、llms-full.txt 同步;demo 页加一节演示;npm run check 全绿", "status": "done", "notes": "skeleton({variant, rows}):text(多行,末行缩短)/ rect / circle 三形状,扫光动画(::after 位移 + 渐变),reduced-motion 下静态灰块(动画列表已补 .ua-skeleton 与 ::after);demo 新增 sec-skeleton 卡片组合演示" }, { "id": "b04", "title": "新增独立 pagination 分页器组件并与 dataTable 演示联动", "motivation": "table-core 已有 pagination 插件,但皮肤包没有独立分页器;dataTable 演示也未展示分页联动", "acceptance": "新增 pagination.ts:受控 API {page, pageSize, total, onChange},页码过多时折叠省略号,键盘可达,禁用态完整;demo 页 dataTable 一节增加分页联动演示;导出、manifest、文档、llms-full.txt 同步;npm run check 全绿", "status": "done", "notes": "pagination(props):page 信号双向绑定(受控),≤7 页全展开、更多时首尾 + 当前页 ±1 折叠省略号(renderList 重建),原生 button 键盘可达,aria-current / aria-label 完整,首末页禁用 ‹ ›;dataTable 新增可选 page 信号桥接(双向同步 + 越界钳制,防无效派发);demo sec-table 新增 pageSize 3 × 24 行的联动卡片" }, { "id": "b05", "title": "文档站演示区由 manifest 驱动自动生成", "motivation": "目前 apps/docs/index.html 手写 props 表与演示,每加组件都要人肉同步;由 manifest 单一来源驱动可消除重复维护", "acceptance": "ua CLI 新增 docs-gen 逻辑:读取各组件 ua.manifest.json 中的 components 参数表,自动生成 props 表 HTML 片段注入文档站模板;生成结果与现有手写版信息量对齐(props 名/类型/默认值/说明);npm run check 全绿且文档站可正常打开", "status": "done", "notes": "核查确认 props 表/示例/步骤/演示 iframe 早已由 ua docs 从 manifest docs.components 单一来源驱动;真正的缺口是信息量不含默认值——本轮 CLI propsTable 新增「默认值」列(props 条目可选 df 字段,缺省渲染 —),llms-full.txt 参数行同步追加「默认 x」标注;16 处可机读默认值从描述文案提取进 df;check 全绿 + 文档站结构完整性校验通过" }, { "id": "c01", "title": "button / checkbox / switch 补 disabled 禁用态", "motivation": "三个基础交互组件缺禁用能力,表单只读/权限控制场景刚需", "acceptance": "ButtonProps / CheckboxProps / SwitchProps 新增可选 disabled(boolean | Signal):静态布尔与信号绑定都支持,禁用时事件不触发、置灰 + not-allowed 光标;demo 表单区加静态禁用与信号联动示例;manifest/文档/llms-full.txt 同步;npm run check 全绿", "status": "done", "notes": "零新增辅助代码:复用 frame h() 对 false/undefined 移除属性、Signal 函数走响应式绑定的既有语义,disabled 透传即可;CSS 补通用禁用态(opacity 0.45 + not-allowed,开关轨道同级置灰);demo 用同一 locked 信号绑定 switch 的 checked 与 checkbox 的 disabled 展示联动" }, { "id": "c02", "title": "textField / textarea 补 disabled 禁用态", "motivation": "输入类组件与 c01 的交互组件对齐,表单只读场景闭环", "acceptance": "TextFieldProps / TextareaProps 新增可选 disabled(boolean | Signal),禁用时不响应输入、置灰 + not-allowed 光标;demo 禁用示例区补一个信号绑定输入框;manifest/文档/llms-full.txt 同步;npm run check 全绿", "status": "done", "notes": "与 c01 同模式:disabled 透传 h() 即得布尔/信号双支持;禁用态 CSS 追加 .ua-input / .ua-textarea;demo 复用 locked 信号联动开关与输入框" }, { "id": "d01", "title": "新增下拉菜单 menu 组件", "motivation": "工具栏/行操作场景缺省可折叠的动作集合,select 只能选值不能派发动作;可复用自绘弹层与微动画既有模式", "acceptance": "packages/skin/ui 新增 menu.ts:触发器 + 自绘弹层,items 支持 disabled / danger / divider,点条目 / 点外部 / Esc 关闭,↑↓ 环形导航(禁用项跳过),Enter/Space 选中,Esc 收起后焦点回触发器;只消费 --ua-* 令牌并带 prefers-reduced-motion 兜底;导出 + manifest + 文档 + llms-full.txt + demo 同步;npm run check 全绿", "status": "done", "notes": "API menu({ label, items, variant, align, onSelect });MenuItem = { value, label, disabled?, danger?, divider? };弹层 ua-open 同时挂在根与弹层(根管箭头旋转、弹层管出入场),危险条目取 danger 色;键盘 ↑↓ 环形导航 + Esc 回焦触发器;demo 新增 sec-menu 双示例(含禁用/危险/分隔线与右对齐)" }, { "id": "d02", "title": "select / radioGroup 补 disabled,修复 select 箭头旋转失效", "motivation": "c01/c02 已覆盖 button/checkbox/switch/输入类,选择类仍缺禁用;同时发现 select 的 .ua-select.ua-open 选择器永不命中(ua-open 只挂在弹层),展开时箭头不旋转", "acceptance": "SelectProps / RadioGroupProps 新增可选 disabled(boolean | Signal);禁用时 select 触发器置灰且不展开弹层,radioGroup 整组置灰不可选;select 箭头在展开时旋转 180°;demo 加信号禁用与静态禁用示例;manifest/文档/llms-full.txt 同步;npm run check 全绿", "status": "done", "notes": "disabled 仍走 h() 透传(原生 button/input 拦截交互)零辅助代码;select 根节点补 class 函数加 ua-open,箭头旋转选择器命中;CSS 通用禁用态列表并入 .ua-select-trigger 与 .ua-radio,另加 :has() 让单选行整行弱化、禁用触发器 hover 不改边框色" }, { "id": "d03", "title": "新增折叠面板 accordion 组件", "motivation": "长表单/设置页需要分区收起,皮肤包无折叠容器;grid 行高过渡可零测量实现展开动画", "acceptance": "新增 accordion.ts:items(value/title/content/disabled)+ 单开(手风琴)与 multiple 多开,active 信号可选受控,标题为原生 button(aria-expanded/controls + region 关联),内容区 0fr→1fr 过渡且 reduced-motion 静态化;导出 / manifest / 文档 / llms-full.txt / demo 同步;npm run check 全绿", "status": "done", "notes": "contents 走 appendChild 既有语义,字符串/DOM/响应式函数通吃;未传 active 时内部 signal 持有展开集合,受控模式只认 active 单开;CSS 用 grid-template-rows 0fr→1fr 过渡免测量,reduced-motion 列表补 ua-acc-*;demo 新增 sec-accordion(多开 + 禁用面板)" }, { "id": "d04", "title": "dataTable 接加载态(骨架行 + 交互禁用)", "motivation": "异步取数时表格直接闪空状态,缺少 loading 反馈;skeleton 已就位但未与表格打通", "acceptance": "DataTableProps 新增 loading?: boolean | Signal;为真时表体渲染骨架行(行数随 pageSize,列数含选择列)、筛选输入与上下页按钮禁用、容器 aria-busy=true;demo 加开关演示;manifest/文档/llms-full.txt 同步;npm run check 全绿", "status": "done", "notes": "busy() 读取器兼顾布尔与信号(信号在 renderList 内调用可被依赖收集);骨架行数量 Math.min(pageSize,6) 防过长;加载态优先于数据判断,避免闪出旧行;disabled 仍走 props 透传,零新增辅助组件" }, { "id": "d05", "title": "新增面包屑 breadcrumb 组件", "motivation": "多层级页面的位置指示缺失;顺带补齐导航类组件的语义结构(nav/ol/li + aria-current)", "acceptance": "新增 breadcrumb.ts:nav + ol 语义结构,末项自动为当前页(不可点、aria-current=page),条目有 href 渲染 、无 href 渲染 button 走 onNavigate,分隔符可配;只消费 --ua-* 令牌;导出 / manifest / 文档 / llms-full.txt / demo 同步;npm run check 全绿", "status": "done", "notes": "API breadcrumb({ items: {label, href?}[], separator?, onNavigate? });分隔符 aria-hidden;reduced-motion 列表补 .ua-crumb-link;demo 新增 sec-breadcrumb('›' 分隔 + toast 反馈跳转);首轮 style 门禁拦下多行 /*** 注释(检查器只认紧邻单行块),已改单行" }, { "id": "d06", "title": "门禁新增 ua verify:清单 ↔ 文档 ↔ 演示锚点一致性校验", "motivation": "新增组件靠人工同步 manifest/docs/demo,易漏(本轮已出现 badge/alert/spinner 手把手只有 2 步);把不变量机器化,防回归", "acceptance": "CLI 新增 verify 子命令:docs.components 的 id 唯一且 api.exports 有 `${id}(` 或以 `${id}.` 开头条目、props 条目必备 n/t/d、steps ≥3、example 必填、demo 锚点必须存在于 apps/demo/main.ts;纳入 npm run check 链条;AGENTS.md 同步;npm run check 全绿", "status": "done", "notes": "锚点校验改看演示源码而非打包产物(demo.html 是 esbuild 产物,锚点在运行时生成);顺带补齐 badge/alert/spinner 的第 3 条手把手(说明与 button/skeleton 的分工);check 链变为 build→style→typecheck→smoke→index→verify" }, { "id": "d07", "title": "新增可交互气泡卡片 popover 组件", "motivation": "tooltip 只做纯展示(pointer-events:none),筛选面板/快捷操作需要可点击的浮层;与 tooltip 形成展示/交互分工", "acceptance": "新增 popover.ts:popover(props, trigger) 包裹式,默认点击开合,trigger:'hover' 走延迟出场,点外部 / Esc 收起(Esc 回焦触发器),content 支持任意 DOM 且内部点击不误关,onOpenChange 回调;aria-haspopup/aria-expanded 正确;只消费 --ua-* 令牌 + reduced-motion 兜底;导出 / manifest / 文档 / llms-full.txt / demo 同步;npm run check 全绿", "status": "done", "notes": "触发器 click 内 stopPropagation,避免刚开就被 document 的外部点击关掉;aria-expanded 用 effect 写回(setAttribute 不吃函数值);弹层点击已阻止冒泡;demo 新增 sec-popover(含 checkbox+button 的筛选面板与 hover 触发示例)" }, { "id": "d08", "title": "演示页加侧边目录与滚动高亮", "motivation": "演示页已 14 个区块,长页滚动找区块靠手滑;目录同时给文档站 iframe 外的直接访问提供导航", "acceptance": "demo 页改为 shell 双栏布局(左 sticky 目录 + 右内容),目录项挂载后从 .sec 自动反推(不手写清单),IntersectionObserver 高亮当前区块,窄屏(≤820px)隐藏目录,reduced-motion 下关平滑滚动;npm run check 全绿、demo 可正常构建", "status": "done", "notes": "目录由 buildToc 在 mount 后扫描 section.sec 生成(id + h2 文案),新增区块自动入目录无需维护;rootMargin -10%/-80% 让高亮更跟手;.page 去掉 max-width 由 .shell 统一控宽 1160" }, { "id": "d09", "title": "新增滑块 slider 组件", "motivation": "设置类场景(音量/阈值/预算)需要范围输入,皮肤包只有文本类输入;原生 range 自带键盘与触屏,接入成本低", "acceptance": "新增 slider.ts:value 信号双向绑定(拖动写回 + 外部赋值同步),min/max/step 可配,disabled 支持布尔或信号,showValue 可关,onChange 回调;样式只消费 --ua-* 令牌(accent-color)且带聚焦光环与禁用态;导出 / manifest / 文档 / llms-full.txt / demo 同步;npm run check 全绿", "status": "done", "notes": "组件不持有数值,一律委托调用方信号;effect 内等值不重写 input.value,避免拖动过程被打断;轨道配色用 accent-color 令牌化,无需自绘 thumb;demo 新增 sec-slider(音量 step 5 + 与 locked 信号联动的禁用滑块)" }, { "id": "d10", "title": "toast 补手动关闭与同屏堆叠上限", "motivation": "自动消失前用户无法提前关掉(如已看清错误),且连续触发会无限堆叠淹没页面", "acceptance": "ToastProps 新增 closable(显示 × 立即退场);同屏最多 4 条,超出挤掉最早一条;退场逻辑抽为内部 dismiss() 供自动/手动共用;is-closable 才接收指针事件,其余保持 pointer-events:none;manifest/文档/llms-full.txt/demo 同步;npm run check 全绿", "status": "done", "notes": "dismiss() 统一 transitionend + 320ms 双保险;超限用 firstElementChild.remove() 立即腾位(不走动画,保证硬上限);demo sec-toast 增加「可关闭」按钮演示 showToast({closable:true})" }, { "id": "d11", "title": "modal 补 size 档位与 footer 操作区", "motivation": "弹窗内容宽窄差异大(确认框 vs 表单),底部操作按钮只能塞进 body 导致分割线语义缺失", "acceptance": "ModalProps 新增 size?: 'sm'|'md'|'lg'(340/420/640)与 footer?: unknown;footer 渲染右对齐操作区带上分割线;缺省行为与旧版一致;manifest/文档/llms-full.txt/demo 同步;npm run check 全绿", "status": "done", "notes": "宽度档位用 .ua-modal-sm/lg 覆盖基准 md,基础宽 min(420px,90vw) 不动;footer 仅在传入时渲染(null 分支不进 DOM);demo 的弹窗改为 size:'lg' + 取消/确定 footer 按钮" }, { "id": "d12", "title": "新增可关闭标签 tag 组件", "motivation": "badge 纯展示无法移除,筛选条件/已选关键字需要带 × 的标签;补齐 badge 的交互版", "acceptance": "新增 tag.ts:label + variant 五档 + closable/onClose;closable 时渲染带 aria-label 的 × 按钮;只消费 --ua-* 令牌;导出 / manifest / 文档 / llms-full.txt / demo 同步;npm run check 全绿", "status": "done", "notes": "组件无状态:onClose 只通知,节点由调用方按信号重渲染移除(与 form/formItem 返回句柄、dataTable 委托内核的哲学一致);demo 用 signal + renderList 演示真实删除链路,另有四档语义色静态展示" }, { "id": "d13", "title": "dataTable 列定义支持对齐与单元格格式化", "motivation": "皮肤层只能 String() 原始值,数字列无法右对齐、年龄/金额无法加单位;内核不关心展示,字段应留在皮肤层", "acceptance": "新增皮肤层 TableColumn extends ColumnDef,追加 align?: left|center|right 与 format?: (value,row)=>string;DataTableProps.columns 改用它;表头与单元格共用对齐类;format 走 textContent 天然免注入;demo 表格演示年龄右对齐+单位、城市居中;manifest/文档/llms-full.txt 同步;npm run check 全绿", "status": "done", "notes": "严格分层:内核 ColumnDef 不动,展示字段只在 skin 的 TableColumn 上扩展(extends 而非改核心);对齐类同时作用于 th(取代原 class 函数,合并 ua-sortable);demo 首表展示 align:right + format(v=>`${v} 岁`)、城市居中" }, { "id": "d14", "title": "新增抽屉 drawer 组件", "motivation": "详情查看/编辑需要不打断主视图的侧滑容器,modal 是强打断确认;移动端尤其常用", "acceptance": "新增 drawer.ts:open 信号驱动,placement 左右、width 可调(窄屏 92vw 上限)、footer 操作区、遮罩 / × / Esc 关闭、打开聚焦首个可交互元素;只消费 --ua-* 令牌 + reduced-motion 兜底;导出 / manifest / 文档 / llms-full.txt / demo 同步;npm run check 全绿", "status": "done", "notes": "遮罩开合用 opacity+visibility(与 tooltip/popover 同模式),面板靠 transform:translateX 滑入;width 走 inline style(调用方数据驱动的表现值不进 CSS);demo 新增 sec-drawer(订单详情 + footer 关闭 + tag/badge 组合)" }, { "id": "d15", "title": "CLI 包补 ua.manifest.json 并修正文档里的过期组件数", "motivation": "工具链自身不在注册表里,Agent 无法通过 MCP/llms 发现 ua 的 6 个子命令;AGENTS.md 与 ARCHITECTURE.md 仍写 17 个组件(实际 27)", "acceptance": "packages/tools/cli/ua.manifest.json(type: tooling)描述 index/list/info/docs/style/verify/mcp 七个子命令与约定,索引包数变 5;AGENTS.md 与 ARCHITECTURE.md 的组件数改成 27;llms.txt / llms-full.txt 重新生成且 CLI 段落可读;npm run check 全绿", "status": "done", "notes": "tooling 类型在 ORDER 表外,排序自然落到末尾(??9 兜底),无需改 CLI 排序逻辑;CLI 清单 docs.components 留空,故不参与 verify 的组件级校验;顺带确认 docs 生成对无组件包不报错" }, { "id": "d16", "title": "dataTable 落地内核已定义的列宽 width", "motivation": "table-core 的 ColumnDef 声明了 width?: number | 'flex',但皮肤层从未消费,列宽完全靠浏览器猜;契约与实现脱节", "acceptance": "dataTable 渲染 colgroup:数字 width 落成固定像素 ,'flex' 或不设交给自适应,选择列固定 44px;demo 表格演示 name 160 / age 100 / city flex;manifest 列定义说明与手把手同步;npm run check 全绿", "status": "done", "notes": "用 colgroup 而非逐 th 设宽,保证表头与表体一致且不入侵单元格渲染;未开 table-layout:fixed(nowrap 内容会被裁),宽高仍由内容兜底;pinned 固定列仍未消费(多列 sticky 偏移需测量),留作后续条目" }, { "id": "d17", "title": "表单错误态覆盖包裹式控件并修正校验时机事件", "motivation": "① 现有 blur 不冒泡,checkbox/select/radioGroup 这类包裹式控件失焦永远不校验;② ua-invalid 只加在控件根,自绘 select 的边框在内部触发器上,视觉上无错误提示;③ 缺 aria-invalid,读屏感知不到", "acceptance": "formItem 用 focusout 取代 blur、补 change(select/checkbox 变更即校验);错误态同时落到控件根与内部原生控件,并同步 aria-invalid;CSS 覆盖 .ua-invalid 后代 .ua-input/.ua-textarea/.ua-select-trigger/.ua-radio/.ua-slider-input;demo 表单加必填 select 演示;manifest/文档/llms-full.txt 同步;npm run check 全绿", "status": "done", "notes": "marked() 统一收集控件根 + 内部 input/textarea/select/.ua-select-trigger 两处落点;.ua-invalid 后代选择器让包裹式控件描红,无需组件各自改签名(低侵入);demo formlab 新增城市必填 select,提交结果显示城市" }, { "id": "d18", "title": "把「皮肤包禁止硬编码颜色」做成 ua verify 门禁", "motivation": "AGENTS.md 写着皮肤禁硬编码颜色,但一直靠自觉;ui.css 实际残留 5 处 #fff(按钮/徽标/开关滑块),暗色下对比也不理想", "acceptance": "checkSkinCss():skin-dom 类型包里所有 .css 出现 #hex 字面量即报错并指出文件行号;5 处 #fff 改为 var(--ua-color-bg)(信号色底上的反色,暗色自动翻转);负向测试(临时加 .ua-tmp{color:#fff})能拦下,移除后回归全绿;AGENTS.md 门禁说明同步;npm run check 全绿", "status": "done", "notes": "rgba(...) 未禁:仅用于阴影与遮罩透明度叠加,不承载品牌色,禁掉会逼出更难读的写法(已在函数注释写明边界);实现上先随 python 写文件把正则转义搞坏两次,改用编辑工具直写并做负向验证确认门禁真实生效" }, { "id": "d19", "title": "dataTable 选中态受控(selected 信号)", "motivation": "选中集只在内核里,外部拿不到也无法预设,批量操作/清空选择只能靠内部工具栏;与 page 受控桥接形成对称能力", "acceptance": "DataTableProps 新增 selected?: Signal,与内核选择双向同步(内容比较避免来回派发,外部数组拷贝保护内核);demo 首表传 picked 信号,展示已选计数与「清空选择」按钮;manifest/文档/llms-full.txt 同步;npm run check 全绿", "status": "done", "notes": "复用 page 桥接的同一套思路:两个 effect 各管一向,sameKeys 内容比较收敛;内部写回拷贝 [...internal],防外部改动内核数组;demo 需 import type { RowKey } 才能对齐 Signal 的逆变" }, { "id": "d20", "title": "progress 支持不确定态(未知时长加载)", "motivation": "请求时长未知时只能硬编造一个假百分比,或用 spinner 但失去条状形态;不确定态是进度条的标准形态", "acceptance": "ProgressProps.value 改为可选;缺省时渲染不确定态(35% 填充块 1.2s 往复)、不显示百分比、role=progressbar + aria-label=进行中;定量态补 aria-valuemin/max/now;reduced-motion 静态化;demo 加不确定态示例;manifest/文档/llms-full.txt 同步;npm run check 全绿", "status": "done", "notes": "以「不传 value」作为不确定态的开关,不新增布尔参数(少一个可矛盾的状态);定量态的 aria-valuenow 用函数属性随信号更新;reduced-motion 下靠既有 .ua-progress-fill 规则把动画归零,退化为静态 35% 条" }, { "id": "d21", "title": "无障碍收尾:× 按钮 aria-label、spinner/skeleton 语义、tablist 标签", "motivation": "审计发现 modal 的 × 按钮无 aria-label(读屏只念「×」)、spinner 无 role=status(不播报加载)、skeleton 未 aria-hidden(占位文本被读出来)、tablist 缺 aria-label 与 aria-disabled", "acceptance": "modal 关闭按钮补 type/aria-label、spinner 补 role=status + aria-label、skeleton 全形态 aria-hidden、tabs 的 tablist 补 aria-label 且禁用页签标 aria-disabled;manifest conventions 记录无障碍基线;npm run check 全绿", "status": "done", "notes": "纯属性级修复,不动结构与样式;tabIndex 漫游(仅激活页签可 Tab)此前已实现,本次只补语义;分页器审计后无需改动(已有 nav aria-label、页码 aria-current、‹› aria-label)" }, { "id": "d22", "title": "新增头像 avatar 组件", "motivation": "用户列表/评论区需要头像位,缺 component 只能手拼 img + 圆角;首字占位是缺图时的标准兜底", "acceptance": "新增 avatar.ts:name 必填(alt / title / 首字来源),src 可选(有则图片、无则首字占位),size 可调,variant 四档语义底色;只消费 --ua-* 令牌;导出 / manifest / 文档 / llms-full.txt / demo 同步;npm run check 全绿", "status": "done", "notes": "首字占位对中文取首字、英文大写,空名兜底 ?;flex:none 保证不被挤压;首次跑 verify 被自身新门禁拦下(声明 sec-avatar 但 demo 缺区块),补独立区块后通过——门禁有效性再次得到验证" }, { "id": "d23", "title": "alert 补标题行与可关闭,并补 role=alert", "motivation": "常驻提示无法消除(错误已处理完仍占版面),且只有单层正文放不下「结论 + 详情」;role=alert 缺失导致读屏不播报", "acceptance": "AlertProps 新增 title? / closable? / onClose?;关闭时先退场(opacity+上移,200ms)再从 DOM 移除;容器 role=alert;只消费 --ua-* 令牌;demo 新增 sec-alert 展示无标题与可关闭带标题两种;manifest/文档/llms-full.txt 同步;npm run check 全绿", "status": "done", "notes": "与 toast 的分工保持:alert 常驻在页面流里、toast 全局浮动;关闭后由调用方自行决定是否重新渲染;body/title/message 三层结构让 flex 布局能把 × 对齐到首行;对现有 alert({message}) 调用完全兼容" }, { "id": "d24", "title": "重写 README 并把组件清单纳入 verify 防漂移", "motivation": "README 只有标题一行,新人/Agent 从仓库首页拿不到任何信息;而文档里的组件数此前已经漂移过(17 vs 27)", "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 字体避免等宽字跳脱整体排版" }, { "id": "d26", "title": "select 键盘导航:↑↓ 环形移动、Home/End 跳转、Esc 回焦触发器", "status": "done" }, { "id": "d27", "title": "modal 焦点陷阱:Tab/Shift+Tab 回绕、role=dialog/aria-modal、关闭归还焦点", "status": "done" }, { "id": "d28", "title": "drawer 焦点陷阱:Tab/Shift+Tab 回绕、关闭归还焦点(对齐 modal)", "status": "done" }, { "id": "d29", "title": "menu 补 Home/End 跳转,与 select 键盘导航对称", "status": "done" }, { "id": "e01", "title": "新增 inputNumber 数字输入组件", "motivation": "数量、份数等离散数值输入是表单常见场景,纯 textField 缺少步进语义;加减按钮 + 键盘调节可复用既有 button 与信号双向绑定模式", "acceptance": "packages/skin/ui 新增 inputNumber.ts:−/+ 按钮 + 输入框三段式,value 信号双向绑定,min/max/step 超界自动夹取,键盘 ↑↓ 调节,非法输入回滚,disabled 支持布尔或信号;只消费 --ua-* 令牌;导出、manifest、文档、llms-full.txt 同步;demo 加一节演示;npm run check 全绿", "status": "done", "notes": "inputNumber(props):−/+ 复用 ghost button(自带微动画与 disabled 透传),输入框 inputmode=decimal,change 时 parseFloat 解析、非法回滚当前值;↑↓ 步进并 preventDefault;clamp 统一夹取 min/max(缺省 ±Infinity);aria-label 三件套 + role=group;CSS 步进按钮收窄、tabular-nums;demo 新增 sec-inputnumber(与禁用态实例共用 qty 信号);manifest/docs/llms-full/README 同步为 29 组件" }, { "id": "e02", "title": "新增 stepper 步骤条组件", "motivation": "下单、注册等多步流程需要进度指示与回跳,现有导航类组件(tabs/breadcrumb/pagination)都不覆盖分步语义;纯展示 + 可选点击回跳,改动范围可控", "acceptance": "packages/skin/ui 新增 stepper.ts:stepper({steps, active, clickable?, onChange?}),done/current/upcoming 三态视觉,clickable 时已完成步骤可点回跳并写回 active 信号,aria-current=step;只消费 --ua-* 令牌;导出、manifest、文档、llms-full.txt、README 清单同步;demo 加一节演示;npm run check 全绿", "status": "done", "notes": "stepper(props):active 信号变化整条重渲染(effect 首跑赋值 + replaceWith,条目少开销可忽略);done 显示 ✓、current 光环聚焦、upcoming 弱化,aria-current=step;clickable 时已完成步骤渲染为 button 回跳写回信号;连接线用 .ua-step + .ua-step::before 横向短线;demo 新增 sec-stepper(上一步/下一步按钮 computed 禁用联动);README 同步 30 组件" }, { "id": "e03", "title": "新增 rate 评分组件", "motivation": "评价、打分场景常用,现有组件无覆盖;星标交互可完整复用信号双向绑定与微动画审美约定,单文件可控", "acceptance": "packages/skin/ui 新增 rate.ts:rate({value, max?, disabled?, onChange?}),max 缺省 5,hover 预览移出还原,键盘 ←→/↑↓ 调节,aria 星标语义;只消费 --ua-* 令牌;导出、manifest、文档、llms-full.txt、README 清单同步;demo 加一节演示;npm run check 全绿", "status": "done", "notes": "rate(props):hover 预览用组件内局部 hover 信号(容器 mouseleave 归零),shown = hover || value 决定点亮数;value/hover 变化整条重渲染(与 stepper 同款 effect + replaceWith 模式);键盘 →/↑ 加分 ←/↓ 减分并 clamp [1,max];role=slider + aria-valuenow;选中色取 --ua-color-warning 金黄;demo 新增 sec-rate(可交互 + 只读两实例共用 score 信号);README 同步 31 组件" }, { "id": "e04", "title": "新增 empty 空状态组件", "motivation": "列表、表格、搜索无结果时需要统一的占位提示,dataTable 内置空态样式但独立场景(卡片、面板、筛选结果)没有可复用组件", "acceptance": "packages/skin/ui 新增 empty.ts:empty({title?, description?, action?}),居中排版,action 为可选 DOM 操作区(常见放按钮);只消费 --ua-* 令牌;导出、manifest、文档、llms-full.txt、README 清单同步;demo 加一节演示;npm run check 全绿", "status": "done", "notes": "empty(props):纯静态组件(无信号),role=status 由读屏播报;装饰符号 ⌀ 弱化为边框色且 aria-hidden;min-height 120px 撑留白(令牌只到 space-4);demo 新增 sec-empty(信号切换有数据/无结果对比,内容用响应式函数渲染);README 同步 32 组件" }, { "id": "e05", "title": "新增 divider 分隔线组件", "motivation": "表单分组、卡片内区块、工具栏之间需要统一分隔语义,目前只有 menu 内部私有分隔线,独立场景无组件可用", "acceptance": "packages/skin/ui 新增 divider.ts:divider({label?, vertical?, dashed?}),水平/垂直两种方向,可带居中文案标签;只消费 --ua-* 令牌;导出、manifest、文档、llms-full.txt、README 清单同步;demo 加一节演示;npm run check 全绿", "status": "done", "notes": "divider(props):水平线用 ::before/::after 双线夹 label 居中文案;vertical 单线(伪元素清空,dashed 走 border-left);dashed 水平线 border-top 替代背景色;role=separator + aria-label;demo 新增 sec-divider(文案线/虚线/工具栏竖线三种用法);README 同步 33 组件" }, { "id": "f01", "title": "组件数漂移治理:AGENTS/ARCHITECTURE 数字纳入 verify 门禁", "motivation": "组件数第三次漂移(AGENTS.md 与 ARCHITECTURE.md 仍写 27,实际 33),ua verify 只锁 README 区块锁不住散文数字", "acceptance": "ua verify 新增规则:扫描 AGENTS.md 与 ARCHITECTURE.md 中的「NN 个组件」模式数字,与 manifest docs.components 长度比对不一致即报错;当前两处 27 改为 33;npm run check 全绿", "status": "done", "notes": "来源:2026-10-23 第二次冷启动审计应修 #1" }, { "id": "f02", "title": "check 链描述同步:AGENTS.md 与 ITERATION.md 补 verify 第六步", "motivation": "AGENTS.md:10 与 ITERATION.md:31 写 5 步,package.json 实为 6 步(含 verify),文档与实际门禁不一致", "acceptance": "两处描述改为 build → style → typecheck → smoke → index → verify 六步;npm run check 全绿", "status": "done", "notes": "来源:审计应修 #2" }, { "id": "f03", "title": "新增 ua lint-iterations 门禁:留痕格式机器校验", "motivation": "iterations.log 41 行中 36 行违规(time 字段混用、UTC 时间戳、缺 commit),靠人工反复修补,规范缺机器校验", "acceptance": "ua 新增 lint-iterations 子命令:校验每行 JSON 字段恰为 {ts,id,result,commit,summary}、ts 为本地 +08:00 ISO 且可用 Date 解析、commit 为 7-40 位哈希或 aborted 时允许为空、result 枚举 done/aborted;并入 npm run check;历史 36 条违规行按规范修复(ts 以对应 git 提交的 author date 本地时区回填,commit 补哈希);npm run check 全绿", "status": "done", "notes": "来源:审计应修 #3;历史行修复用 git log --format=%cI 按条目 id 关联提交时间回填" }, { "id": "f04", "title": "commit-lint 收严:chore/docs 等强制 scope,杜绝无 scope 放行", "motivation": "COMMITTING.md 规定 () 格式,但 chore:、docs: 无 scope 被 lint 放行,历史还有 17 条 iter: 缺 scope", "acceptance": "commit-lint 规则收严为:除 Merge 外所有 type 必须带 scope(scope 允许 cli/skin/core/backlog/留痕等枚举或条目 id);反向用例 chore: xxx / docs: xxx / iter: xxx 必须被拒;正例全部通过;npm run check 全绿", "status": "done", "notes": "来源:审计应修 #4;历史 iter 缺 scope 的提交不回改(已发布历史不动),只管增量" }, { "id": "f05", "title": "ua index 幂等化:generatedAt 仅内容变化时更新", "motivation": "ua index 每次重写 .ua/index.json 的 generatedAt,npm run check 必然弄脏工作区,与「提交前 check」工作流冲突", "acceptance": "index 命令改为:若除 generatedAt 外内容与现有文件一致则不写入(或 generatedAt 改为内容哈希派生);连续两次 npm run check 后 git status 必须干净", "status": "done", "notes": "来源:审计应修 #5" }, { "id": "f06", "title": "pnpm-lock.yaml 入库 + 目录树补全", "motivation": "lockfile 缺失导致依赖树不可复现;ARCHITECTURE.md 目录树缺 scripts/、COMMITTING.md、ITERATION.md、.ua/ 清单等条目,新代理接手有盲区", "acceptance": "pnpm-lock.yaml 提交入库;ARCHITECTURE.md 目录树补 scripts/(gitea.mjs/gitea-api.mjs 一句话说明)、COMMITTING.md、ITERATION.md、.ua/backlog.json、.ua/iterations.log、pnpm-workspace.yaml;npm run check 全绿", "status": "done", "notes": "来源:审计应修 #6 + 建议 #7" }, { "id": "g01", "title": "ua docs 幂等化:llms-full.txt 时间戳不弄脏工作区", "motivation": "llms-full.txt 头部含 generatedAt,每次 ua docs 重写必然弄脏工作区,与 index 幂等化(f05)同类问题", "acceptance": "内容与现有文件仅时间戳之差时不写入;npm run docs 连跑两次 git status 干净", "status": "done", "notes": "自补:延续 f05 方案" }, { "id": "g02", "title": "新增 image 图片组件(缩略图 + 点击预览)", "motivation": "皮肤包缺常规媒体组件,img 缩略图 + 遮罩预览是常规表单/详情页刚需", "acceptance": "image({src, alt, width?}) 返回缩略图,点击开遮罩大图(Esc/点击遮罩关闭,reduced-motion 兜底);manifest/docs/llms-full/README/demo 同步;npm run check 全绿", "status": "done", "notes": "自补:组件补充方向" }, { "id": "g03", "title": "textField/textarea/inputNumber 补 prefix/suffix 附加内容槽", "motivation": "搜索框放大镜、金额单位等前后缀是输入组件高频需求,目前只能外部拼装", "acceptance": "三个输入组件新增 prefix/suffix(string|HTMLElement),渲染为输入框内侧前后附加块;manifest 参数表与 llms-full 同步;npm run check 全绿", "status": "done", "notes": "自补:可用性细节方向" }, { "id": "g04", "title": "dataTable 筛选框用 prefix 放搜索图标", "motivation": "g03 落地了 prefix 附加块,dataTable 工具栏筛选框是最佳实战落点,同时验证包装不影响事件冒泡", "acceptance": "dataTable 筛选输入框带 🔍 prefix;筛选功能回归正常(smoke 不变绿转红);npm run check 全绿", "status": "done", "notes": "自补:g03 实战验证" }, { "id": "g05", "title": "ua verify 增加 llms-full.txt 生成同步校验", "motivation": "llms-full.txt 是手工触发 ua docs 生成的产物,改 manifest 后忘记跑 docs 会产生文档漂移,目前无门禁", "acceptance": "verify 内联重渲染 Agent 文档(时间戳归一化)与根目录 llms-full.txt 比对,不一致即报错提示 npm run docs;npm run check 全绿", "status": "done", "notes": "自补:工具链防漂移方向" }, { "id": "g06", "title": "组件数门禁扩展 README 计数文本", "motivation": "f01 的计数漂移校验只覆盖 AGENTS/ARCHITECTURE,README 的「N 个 DOM 组件」文本仍可漂移", "acceptance": "checkCountDocs 扫描列表加入 README.md,漂移即 verify 失败;npm run check 全绿", "status": "done", "notes": "自补:f01 收尾" }, { "id": "g07", "title": "新增 timeline 时间线组件", "motivation": "皮肤包缺少按时间顺序展示事件流的组件,日志 / 审批流 / 版本记录场景常用;只需轴线 + 语义色节点,可复用既有令牌与微动画模式", "acceptance": "新增 packages/skin/ui/src/timeline.ts:items(title/content/time/variant) + mode(left|right) + pending 尾部节点,节点色只走 --ua-* 令牌,入场淡入带 prefers-reduced-motion 兜底;导出 + manifest props 表与 steps + demo sec-timeline + README 与文档同步;npm run check 全绿", "status": "done", "notes": "API 定为 items(title/content/time/variant) + mode(left|right) + pending 尾部虚节点;节点语义色走 --ua-* 令牌,0.18s 入场淡入 + 虚线脉冲动画,prefers-reduced-motion 全部关停;demo 新增 sec-timeline(按钮切换 pending);组件数 34→35 三处计数与 README 清单同步" }, { "id": "g08", "title": "新增 segmented 分段控制器组件", "motivation": "tabs 是页签语义(下划线 + 面板),视图 / 单位切换需要紧凑的胶囊分段控件;与 radioGroup 的差别是不承载表单语义", "acceptance": "新增 src/segmented.ts:options / value(信号双向) / size(sm|md) / disabled,滑块指示条随选中平移,←→ 键盘导航 + roving tabindex,选中态低视觉比重;导出 + manifest + demo sec-segmented + 文档同步;npm run check 全绿", "status": "done", "notes": "API 为 options + value(必传信号) + size + disabled(布尔|信号) + onChange;滑块几何由 getBoundingClientRect 实测(减去容器 clientLeft 边框),挂载后 rAF 二次测量;←→ 环形导航 + 漫游 tabindex;整组禁用用 is-disabled 类 + 逐按钮 disabled;demo sec-segmented 用两个实例共用 range 信号演示联动" }, { "id": "g09", "title": "新增 descriptions 描述列表组件", "motivation": "详情页与抽屉里高频需要 label:value 两列布局,目前只能借用 form 或手写 DOM;需要列数自适应与 bordered 两种形态", "acceptance": "新增 src/descriptions.ts:items(label/value/span) + column(1-4,窄屏自动降列) + bordered + size;label 走 text-muted 令牌,值支持任意 DOM;导出 + manifest + demo sec-descriptions + 文档同步;npm run check 全绿", "status": "done", "notes": "API 为 items(label/value/span) + column(1-4) + bordered + size + title;列数通过 CSS 变量 --ua-desc-col 注入,样式表在 ≤640px 覆盖为单列;span 在 min(span, column) 处截断防越界;标题为可选外层 wrap;demo sec-descriptions 展示纯网格(含 tag 值与 span 占两列)与 bordered 小尺寸两种形态" }, { "id": "g10", "title": "新增 statistic 统计数值组件", "motivation": "看板需要大号数值 + 单位 + 环比趋势,现在只能手写;数值变化时的滚动动画能强化数据反馈", "acceptance": "新增 src/statistic.ts:title / value(Signal) / precision / prefix / suffix / trend(up|down),值变化用 rAF 从旧值滚到新值(约 400ms),prefers-reduced-motion 直接落终值,涨红跌绿;导出 + manifest + demo sec-statistic + 文档同步;npm run check 全绿", "status": "done", "notes": "API 为 title + value(信号) + precision + prefix + suffix + trend;滚动用 rAF 逐帧改文本(400ms easeOutCubic),新目标先 cancelAnimationFrame 打断,收尾强制对齐终值防浮点残差;matchMedia prefers-reduced-motion 直落终值;trend 按 A 股涨红跌绿;demo sec-statistic 用随机涨跌按钮演示双向滚动" }, { "id": "g11", "title": "浮层定位空间不足时自动翻转", "motivation": "popover / tooltip / select / menu 固定按 placement 定位,视口底部会溢出被裁切,缺少统一 flip 判定", "acceptance": "新增 src/position.ts:flip(trigger, panel, preferred) 依据 getBoundingClientRect 与视口高度决定是否上下翻转,四个浮层组件接入;导出 + 文档说明 + demo 覆盖说明;npm run check 全绿", "status": "done", "notes": "自补:既有组件可用性细节" }, { "id": "g12", "title": "verify 增加 backlog 与 iterations.log 交叉校验", "motivation": "lint-iterations 只校验行格式,无法发现『条目置 done 但无留痕』或『留痕指向不存在的条目』", "acceptance": "ua.js 新增交叉校验并挂进 cmdVerify:每条 done 条目必须在 iterations.log 有 result=done 记录,每条日志 id 必须在 backlog 存在;人为注入违规时 verify 退出码 1;npm run check 全绿", "status": "done", "notes": "cmdVerify 增加 checkIterations:done 条目必须有 done 留痕、留痕 id 必须存在于 backlog;行格式仍归 lint-iterations;实测注入幽灵 id zz99 后 verify 报 1 violation 退出码 1,还原后复绿;AGENTS.md 门禁说明同步补一句" }, { "id": "g13", "title": "新增 ua changelog 生成 CHANGELOG.md", "motivation": "迭代提交已有规范前缀,但没有面向人的变更汇总,qa/stable 的提交史对使用者不可读", "acceptance": "ua.js 新增 cmdChangelog:解析 git log 按 iter / feat / fix / chore 分组生成 CHANGELOG.md,带 --check 幂等模式(无变化不写盘、退出码 0);挂进 package.json scripts;npm run check 全绿", "status": "done", "notes": "cmdChangelog 解析 git log -n 400(%h\\t%s),按 iter/feat/fix/docs/chore|refactor|test|build|ci 五组 + 其他兜底分组渲染,输出不含时间戳故可幂等比对;--check 只校验不写盘、无变化 skip 不写;package.json 挂 changelog 与 changelog:check 两个脚本;不进 check 链(生成内容依赖提交史,提交后天然落后一步)" }, { "id": "g14", "title": "演示站侧边目录支持关键字过滤", "motivation": "组件增至 35 个后侧边目录变长,定位区块只能靠滚动", "acceptance": "apps/demo/main.ts 的 buildToc 前置搜索框,输入按标题子串过滤目录链接(无匹配给空态提示),Esc 清空;不破坏 IntersectionObserver 高亮;npm run check 全绿", "status": "done", "notes": "buildToc 顶部加 type=search 输入框,input 事件按标题子串小写匹配过滤(hidden 属性 + .toc-link[hidden] 覆盖 display:block),无匹配显示 .toc-empty 空态,Esc 清空后恢复全量;IntersectionObserver 高亮逻辑未改动;样式写在 apps/demo/build.mjs 模板内" }, { "id": "g15", "title": "toast 悬停暂停自动关闭", "motivation": "toast 到点即消失,用户来不及读完长文案;悬停暂停是主流反馈组件的常规可用性细节", "acceptance": "showToast 悬停时暂停倒计时、移出后按剩余时长继续;duration 语义不变;manifest 与 demo 说明同步;npm run check 全绿", "status": "done", "notes": "自补:既有组件可用性细节" }, { "id": "g16", "title": "image 加载失败占位", "motivation": "图片地址失效时显示破图图标,观感差且无提示;需要统一的失败占位兜底", "acceptance": "img 加载失败自动替换为虚线占位块,fallback 可自定义文案;样式只消费 --ua-* 令牌;manifest/demo 同步;npm run check 全绿", "status": "done", "notes": "自补:既有组件可用性细节" }, { "id": "g17", "title": "select 键入字母快跳选项", "motivation": "选项多时纯方向键逐个移动太慢,主流下拉都支持键入首字母循环跳转", "acceptance": "select 展开时键入可打印字符循环聚焦 label 前缀匹配项(不区分大小写),1 秒无输入重置缓冲;既有 ↑↓/Home/End 行为不变;npm run check 全绿", "status": "done", "notes": "自补:既有组件可用性细节" }, { "id": "g18", "title": "textField 可清空按钮", "motivation": "长文本输入后逐字删除太慢,主流输入框都提供 clearable 一键清空", "acceptance": "clearable 开启后有值时显示清空按钮,点击清空并同步信号与 onInput;空值自动隐藏;npm run check 全绿", "status": "done", "notes": "自补:既有组件可用性细节" }, { "id": "g19", "title": "textarea 字数统计", "motivation": "多行输入常配字数上限,用户需要 n/limit 实时反馈而不是提交后才报错", "acceptance": "maxCount 传入后 textarea 设原生 maxlength 并在下方附加块显示实时计数,与外部写回同步;npm run check 全绿", "status": "done", "notes": "自补:既有组件可用性细节" }, { "id": "g20", "title": "inputNumber 长按连发步进", "motivation": "大步长调节时反复点按钮太累,主流数字输入都支持长按持续步进", "acceptance": "按住 −/+ 按钮 400ms 后每 100ms 连续步进,松开或移出即停;单击行为不变;npm run check 全绿", "status": "done", "notes": "自补:既有组件可用性细节" }, { "id": "g21", "title": "pagination 跳页输入框", "motivation": "页数多时逐页点击太慢,主流分页器都提供直接跳页入口", "acceptance": "jumpable 开启且总页数 > 1 时末尾显示页码输入 + 总页数,回车跳转并钳制合法范围;npm run check 全绿", "status": "done", "notes": "自补:既有组件可用性细节" }, { "id": "g22", "title": "menu 键入字母快跳菜单项", "motivation": "菜单项多时方向键逐个移动太慢,与 select 的键入快跳对齐保持组件族一致性", "acceptance": "menu 展开时键入可打印字符循环聚焦 label 前缀匹配项(忽略大小写),1s 无输入重置;既有导航不变;npm run check 全绿", "status": "done", "notes": "自补:既有组件可用性细节" }, { "id": "g23", "title": "tabs 键盘 Home/End 跳转", "motivation": "页签多时方向键逐个移动太慢,与 select/menu 的 Home/End 行为对齐", "acceptance": "tabs 聚焦时 Home 跳首个可用页签、End 跳末个可用页签并激活;方向键行为不变;npm run check 全绿", "status": "done", "notes": "自补:既有组件可用性细节;Home/End 直达首末启用页签,方向键环形逻辑不变" }, { "id": "g24", "title": "新增 list 列表组件", "motivation": "皮肤包缺通用列表容器,审批/消息/搜索结果等场景只能手写 div 拼装,样式与令牌脱节", "acceptance": "list({ items, header, footer, bordered, emptyText, onItemClick }) 渲染条目 avatar/title/description/extra;空数组回落 empty;组件数 38→39 三处计数同步;npm run check 全绿", "status": "done", "notes": "自补:组件补充;items 为空回落 empty,onItemClick 让条目可点击" }, { "id": "g25", "title": "令牌查询能力:ua tokens + MCP get_tokens", "motivation": "Agent 与人都得翻 tokens.json 才知道有哪些 --ua-* 变量,容易凭记忆写错名;llms-full 里还把 textMuted 当成变量名(实际是 text-muted)", "acceptance": "ua tokens 列出全部令牌(颜色带暗色值)、--json 输出数组;MCP 新增 get_tokens 工具;llms-full 令牌名统一 kebab-case;npm run check 全绿", "status": "done", "notes": "自补:工具链改进;CLI 与 MCP 共用 loadTokenList 单一来源" }, { "id": "g26", "title": "verify 增加令牌引用校验", "motivation": "皮肤样式表写错令牌名(如 --ua-color-textt)不会报错、静默失效;#hex 门禁只管硬编码,管不到拼错变量", "acceptance": "var(--ua-*) 必须是 tokens.css 已定义或组件自设变量,否则 verify 失败;ua tokens / llms-full 令牌清单统一取 tokens.css(补全字号与复合间距);npm run check 全绿", "status": "done", "notes": "自补:门禁改进;负向测试 var(--ua-color-textt) 已被拦截" }, { "id": "g27", "title": "弹层 Esc 栈:多弹层只关最上层", "motivation": "modal 与 drawer 各自往 document 挂 keydown,叠加打开时一次 Esc 会把所有弹层全关;实例销毁也不摘监听", "acceptance": "modal/drawer 共用 overlay.ts 的 Esc 栈,后开先关;栈空自动摘全局监听;npm run check 全绿", "status": "done", "notes": "自补:既有组件可用性细节;去掉两处各自挂的 document keydown" }, { "id": "g28", "title": "Esc 逐层关闭:浮层阻止冒泡", "motivation": "弹窗内的 select/menu/popover 展开时按 Esc,会先收下拉再冒泡到 document 的 Esc 栈,导致弹窗一起被关——一次 Esc 关两层", "acceptance": "menu/select/popover/tooltip/image 的 Esc 处理各自 stopPropagation,只关本层;演示页在弹窗内放下拉可复现逐层关闭;npm run check 全绿", "status": "done", "notes": "自补:既有组件可用性细节;演示页弹窗内加下拉可复现" }, { "id": "g29", "title": "新增 carousel 轮播组件", "motivation": "组件库缺轮播,首页 banner/图片墙只能外部引库,样式与令牌体系脱节", "acceptance": "carousel({ items, index, autoplay, height, label, onChange }) 横排位移 + 指示点/箭头/←→ 键切换 + 悬停暂停 + 环形回绕;组件数 39→40 三处计数同步;npm run check 全绿", "status": "done", "notes": "自补:组件补充;index 信号可外部受控,内部信号兜底" }, { "id": "g30", "title": "check 链并入 demo 构建 + 产物锚点校验", "motivation": "npm run check 不重建 apps/demo/dist/demo.html,改了演示页门禁照样全绿,文档站 iframe 拿到的是旧产物;verify 只查 main.ts 源码锚点,查不到产物缺块", "acceptance": "check 链为 build → demo → style → typecheck → smoke → index → verify → lint-iterations;verify 校验产物含全部 sec-* 锚点(负向删除锚点即失败);文档四处链路描述同步;npm run check 全绿", "status": "done", "notes": "自补:门禁改进;文档四处链路描述同步" }, { "id": "g31", "title": "新增 tree 树形组件", "motivation": "文件树/组织架构/权限勾选等场景缺组件,只能手写嵌套 DOM,展开态与键盘可达性都要重造", "acceptance": "tree({ nodes, expanded, selected, defaultExpandAll, onSelect }) 递归渲染 + 箭头展开收起 + 点选 + Enter/→/← 键盘 + 禁用不响应;组件数 40→41 三处计数同步;npm run check 全绿", "status": "done", "notes": "自补:组件补充;selected/expanded 信号均可外部受控" }, { "id": "g32", "title": "tree 补 ↑↓/Home/End 行间导航", "motivation": "tree 只支持 Enter/→/←,无法用键盘在节点间移动焦点,键盘用户仍得靠鼠标找行", "acceptance": "↑↓ 在当前可见节点间移动、Home/End 到首末行,只改焦点不改选中,收起分支的子节点不参与遍历;npm run check 全绿", "status": "done", "notes": "自补:既有组件可用性细节;NodeList 需 Array.from 展开(downlevel 迭代)" }, { "id": "g33", "title": "新增 upload 文件选择组件", "motivation": "表单里选附件只能裸写 input[type=file],样式脱节、无拖拽、无已选清单,也没有统一的 onChange 出口", "acceptance": "upload({ accept, multiple, hint, disabled, onChange }) 支持点击/拖拽/键盘选择、清单逐个移除、同名同大小去重、disabled 全禁;组件数 41→42 三处计数同步;npm run check 全绿", "status": "done", "notes": "自补:组件补充;不内置上传请求,onChange 回传副本" }, { "id": "g34", "title": "ua info 支持组件 id 查询", "motivation": "ua info 只认包名,Agent 按组件名查(如 ua info list / MCP get_component(list))直接 not found,只能翻整包清单;输出还是原始 JSON,抄参数得自己解析", "acceptance": "ua info <组件id> 输出 props 表 + 步骤 + 示例,ua info <包名> 出摘要且 --json 保留原始清单;MCP get_component 支持组件 id(返回 package + component);npm run check 全绿", "status": "open", "notes": "自补:文档与 Agent 查询体验" } ] }