2615 lines
230 KiB
JSON
2615 lines
230 KiB
JSON
{
|
||
"$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:// 的误判(先剥离字面量再定位 //)",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"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 区块",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"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 卡片组合演示",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"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 行的联动卡片",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"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 全绿 + 文档站结构完整性校验通过",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "c01",
|
||
"title": "button / checkbox / switch 补 disabled 禁用态",
|
||
"motivation": "三个基础交互组件缺禁用能力,表单只读/权限控制场景刚需",
|
||
"acceptance": "ButtonProps / CheckboxProps / SwitchProps 新增可选 disabled(boolean | Signal<boolean>):静态布尔与信号绑定都支持,禁用时事件不触发、置灰 + 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 展示联动",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "c02",
|
||
"title": "textField / textarea 补 disabled 禁用态",
|
||
"motivation": "输入类组件与 c01 的交互组件对齐,表单只读场景闭环",
|
||
"acceptance": "TextFieldProps / TextareaProps 新增可选 disabled(boolean | Signal<boolean>),禁用时不响应输入、置灰 + not-allowed 光标;demo 禁用示例区补一个信号绑定输入框;manifest/文档/llms-full.txt 同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "与 c01 同模式:disabled 透传 h() 即得布尔/信号双支持;禁用态 CSS 追加 .ua-input / .ua-textarea;demo 复用 locked 信号联动开关与输入框",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"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 双示例(含禁用/危险/分隔线与右对齐)",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"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<boolean>);禁用时 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 不改边框色",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"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<string[]> 持有展开集合,受控模式只认 active 单开;CSS 用 grid-template-rows 0fr→1fr 过渡免测量,reduced-motion 列表补 ua-acc-*;demo 新增 sec-accordion(多开 + 禁用面板)",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "d04",
|
||
"title": "dataTable 接加载态(骨架行 + 交互禁用)",
|
||
"motivation": "异步取数时表格直接闪空状态,缺少 loading 反馈;skeleton 已就位但未与表格打通",
|
||
"acceptance": "DataTableProps 新增 loading?: boolean | Signal<boolean>;为真时表体渲染骨架行(行数随 pageSize,列数含选择列)、筛选输入与上下页按钮禁用、容器 aria-busy=true;demo 加开关演示;manifest/文档/llms-full.txt 同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "busy() 读取器兼顾布尔与信号(信号在 renderList 内调用可被依赖收集);骨架行数量 Math.min(pageSize,6) 防过长;加载态优先于数据判断,避免闪出旧行;disabled 仍走 props 透传,零新增辅助组件",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "d05",
|
||
"title": "新增面包屑 breadcrumb 组件",
|
||
"motivation": "多层级页面的位置指示缺失;顺带补齐导航类组件的语义结构(nav/ol/li + aria-current)",
|
||
"acceptance": "新增 breadcrumb.ts:nav + ol 语义结构,末项自动为当前页(不可点、aria-current=page),条目有 href 渲染 <a>、无 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 门禁拦下多行 /*** 注释(检查器只认紧邻单行块),已改单行",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"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",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"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 触发示例)",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"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",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"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 信号联动的禁用滑块)",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"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})",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"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 按钮",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"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<string[]> + renderList 演示真实删除链路,另有四档语义色静态展示",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "d13",
|
||
"title": "dataTable 列定义支持对齐与单元格格式化",
|
||
"motivation": "皮肤层只能 String() 原始值,数字列无法右对齐、年龄/金额无法加单位;内核不关心展示,字段应留在皮肤层",
|
||
"acceptance": "新增皮肤层 TableColumn<T> extends ColumnDef<T>,追加 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} 岁`)、城市居中",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"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 组合)",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"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 生成对无组件包不报错",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "d16",
|
||
"title": "dataTable 落地内核已定义的列宽 width",
|
||
"motivation": "table-core 的 ColumnDef 声明了 width?: number | 'flex',但皮肤层从未消费,列宽完全靠浏览器猜;契约与实现脱节",
|
||
"acceptance": "dataTable 渲染 colgroup:数字 width 落成固定像素 <col>,'flex' 或不设交给自适应,选择列固定 44px;demo 表格演示 name 160 / age 100 / city flex;manifest 列定义说明与手把手同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "用 colgroup 而非逐 th 设宽,保证表头与表体一致且不入侵单元格渲染;未开 table-layout:fixed(nowrap 内容会被裁),宽高仍由内容兜底;pinned 固定列仍未消费(多列 sticky 偏移需测量),留作后续条目",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"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,提交结果显示城市",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"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 写文件把正则转义搞坏两次,改用编辑工具直写并做负向验证确认门禁真实生效",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "d19",
|
||
"title": "dataTable 选中态受控(selected 信号)",
|
||
"motivation": "选中集只在内核里,外部拿不到也无法预设,批量操作/清空选择只能靠内部工具栏;与 page 受控桥接形成对称能力",
|
||
"acceptance": "DataTableProps 新增 selected?: Signal<RowKey[]>,与内核选择双向同步(内容比较避免来回派发,外部数组拷贝保护内核);demo 首表传 picked 信号,展示已选计数与「清空选择」按钮;manifest/文档/llms-full.txt 同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "复用 page 桥接的同一套思路:两个 effect 各管一向,sameKeys 内容比较收敛;内部写回拷贝 [...internal],防外部改动内核数组;demo 需 import type { RowKey } 才能对齐 Signal 的逆变",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"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% 条",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"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)",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"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 缺区块),补独立区块后通过——门禁有效性再次得到验证",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"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}) 调用完全兼容",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "d24",
|
||
"title": "重写 README 并把组件清单纳入 verify 防漂移",
|
||
"motivation": "README 只有标题一行,新人/Agent 从仓库首页拿不到任何信息;而文档里的组件数此前已经漂移过(17 vs 27)",
|
||
"acceptance": "README 覆盖定位 / 快速开始 / 28 组件清单 / 目录表 / 三道门禁 / Agent 接入 / 分支流水线;新增 <!-- ua:components --> 标记区块,ua verify 校验区块 id 集合与全部清单 docs.components 完全一致(缺/多都报);负向测试(删 avatar)能拦下;AGENTS.md 同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "不做自动写入(避免工具偷偷改文档),只做一致性校验:新增组件时 verify 报「README 组件区块缺少 xxx」,由人补一行;标记区块用 · 分隔便于人读与机器切分",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"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 字体避免等宽字跳脱整体排版",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "d26",
|
||
"title": "select 键盘导航:↑↓ 环形移动、Home/End 跳转、Esc 回焦触发器",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "d27",
|
||
"title": "modal 焦点陷阱:Tab/Shift+Tab 回绕、role=dialog/aria-modal、关闭归还焦点",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "d28",
|
||
"title": "drawer 焦点陷阱:Tab/Shift+Tab 回绕、关闭归还焦点(对齐 modal)",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "d29",
|
||
"title": "menu 补 Home/End 跳转,与 select 键盘导航对称",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"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 组件",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"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 组件",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"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 组件",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"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 组件",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"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 组件",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"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",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"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",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"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 关联提交时间回填",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "f04",
|
||
"title": "commit-lint 收严:chore/docs 等强制 scope,杜绝无 scope 放行",
|
||
"motivation": "COMMITTING.md 规定 <type>(<scope>) 格式,但 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 的提交不回改(已发布历史不动),只管增量",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"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",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"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",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"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 方案",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"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": "自补:组件补充方向",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g03",
|
||
"title": "textField/textarea/inputNumber 补 prefix/suffix 附加内容槽",
|
||
"motivation": "搜索框放大镜、金额单位等前后缀是输入组件高频需求,目前只能外部拼装",
|
||
"acceptance": "三个输入组件新增 prefix/suffix(string|HTMLElement),渲染为输入框内侧前后附加块;manifest 参数表与 llms-full 同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:可用性细节方向",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g04",
|
||
"title": "dataTable 筛选框用 prefix 放搜索图标",
|
||
"motivation": "g03 落地了 prefix 附加块,dataTable 工具栏筛选框是最佳实战落点,同时验证包装不影响事件冒泡",
|
||
"acceptance": "dataTable 筛选输入框带 🔍 prefix;筛选功能回归正常(smoke 不变绿转红);npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:g03 实战验证",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"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": "自补:工具链防漂移方向",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g06",
|
||
"title": "组件数门禁扩展 README 计数文本",
|
||
"motivation": "f01 的计数漂移校验只覆盖 AGENTS/ARCHITECTURE,README 的「N 个 DOM 组件」文本仍可漂移",
|
||
"acceptance": "checkCountDocs 扫描列表加入 README.md,漂移即 verify 失败;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:f01 收尾",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"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 清单同步",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"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 信号演示联动",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"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 小尺寸两种形态",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g10",
|
||
"title": "新增 statistic 统计数值组件",
|
||
"motivation": "看板需要大号数值 + 单位 + 环比趋势,现在只能手写;数值变化时的滚动动画能强化数据反馈",
|
||
"acceptance": "新增 src/statistic.ts:title / value(Signal<number>) / 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 用随机涨跌按钮演示双向滚动",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"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": "自补:既有组件可用性细节",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"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 门禁说明同步补一句",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"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 链(生成内容依赖提交史,提交后天然落后一步)",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"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 模板内",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g15",
|
||
"title": "toast 悬停暂停自动关闭",
|
||
"motivation": "toast 到点即消失,用户来不及读完长文案;悬停暂停是主流反馈组件的常规可用性细节",
|
||
"acceptance": "showToast 悬停时暂停倒计时、移出后按剩余时长继续;duration 语义不变;manifest 与 demo 说明同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:既有组件可用性细节",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g16",
|
||
"title": "image 加载失败占位",
|
||
"motivation": "图片地址失效时显示破图图标,观感差且无提示;需要统一的失败占位兜底",
|
||
"acceptance": "img 加载失败自动替换为虚线占位块,fallback 可自定义文案;样式只消费 --ua-* 令牌;manifest/demo 同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:既有组件可用性细节",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g17",
|
||
"title": "select 键入字母快跳选项",
|
||
"motivation": "选项多时纯方向键逐个移动太慢,主流下拉都支持键入首字母循环跳转",
|
||
"acceptance": "select 展开时键入可打印字符循环聚焦 label 前缀匹配项(不区分大小写),1 秒无输入重置缓冲;既有 ↑↓/Home/End 行为不变;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:既有组件可用性细节",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g18",
|
||
"title": "textField 可清空按钮",
|
||
"motivation": "长文本输入后逐字删除太慢,主流输入框都提供 clearable 一键清空",
|
||
"acceptance": "clearable 开启后有值时显示清空按钮,点击清空并同步信号与 onInput;空值自动隐藏;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:既有组件可用性细节",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g19",
|
||
"title": "textarea 字数统计",
|
||
"motivation": "多行输入常配字数上限,用户需要 n/limit 实时反馈而不是提交后才报错",
|
||
"acceptance": "maxCount 传入后 textarea 设原生 maxlength 并在下方附加块显示实时计数,与外部写回同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:既有组件可用性细节",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g20",
|
||
"title": "inputNumber 长按连发步进",
|
||
"motivation": "大步长调节时反复点按钮太累,主流数字输入都支持长按持续步进",
|
||
"acceptance": "按住 −/+ 按钮 400ms 后每 100ms 连续步进,松开或移出即停;单击行为不变;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:既有组件可用性细节",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g21",
|
||
"title": "pagination 跳页输入框",
|
||
"motivation": "页数多时逐页点击太慢,主流分页器都提供直接跳页入口",
|
||
"acceptance": "jumpable 开启且总页数 > 1 时末尾显示页码输入 + 总页数,回车跳转并钳制合法范围;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:既有组件可用性细节",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g22",
|
||
"title": "menu 键入字母快跳菜单项",
|
||
"motivation": "菜单项多时方向键逐个移动太慢,与 select 的键入快跳对齐保持组件族一致性",
|
||
"acceptance": "menu 展开时键入可打印字符循环聚焦 label 前缀匹配项(忽略大小写),1s 无输入重置;既有导航不变;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:既有组件可用性细节",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g23",
|
||
"title": "tabs 键盘 Home/End 跳转",
|
||
"motivation": "页签多时方向键逐个移动太慢,与 select/menu 的 Home/End 行为对齐",
|
||
"acceptance": "tabs 聚焦时 Home 跳首个可用页签、End 跳末个可用页签并激活;方向键行为不变;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:既有组件可用性细节;Home/End 直达首末启用页签,方向键环形逻辑不变",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"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 让条目可点击",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"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 单一来源",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"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) 已被拦截",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g27",
|
||
"title": "弹层 Esc 栈:多弹层只关最上层",
|
||
"motivation": "modal 与 drawer 各自往 document 挂 keydown,叠加打开时一次 Esc 会把所有弹层全关;实例销毁也不摘监听",
|
||
"acceptance": "modal/drawer 共用 overlay.ts 的 Esc 栈,后开先关;栈空自动摘全局监听;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:既有组件可用性细节;去掉两处各自挂的 document keydown",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"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": "自补:既有组件可用性细节;演示页弹窗内加下拉可复现",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g29",
|
||
"title": "新增 carousel 轮播组件",
|
||
"motivation": "组件库缺轮播,首页 banner/图片墙只能外部引库,样式与令牌体系脱节",
|
||
"acceptance": "carousel({ items, index, autoplay, height, label, onChange }) 横排位移 + 指示点/箭头/←→ 键切换 + 悬停暂停 + 环形回绕;组件数 39→40 三处计数同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:组件补充;index 信号可外部受控,内部信号兜底",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"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": "自补:门禁改进;文档四处链路描述同步",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g31",
|
||
"title": "新增 tree 树形组件",
|
||
"motivation": "文件树/组织架构/权限勾选等场景缺组件,只能手写嵌套 DOM,展开态与键盘可达性都要重造",
|
||
"acceptance": "tree({ nodes, expanded, selected, defaultExpandAll, onSelect }) 递归渲染 + 箭头展开收起 + 点选 + Enter/→/← 键盘 + 禁用不响应;组件数 40→41 三处计数同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:组件补充;selected/expanded 信号均可外部受控",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g32",
|
||
"title": "tree 补 ↑↓/Home/End 行间导航",
|
||
"motivation": "tree 只支持 Enter/→/←,无法用键盘在节点间移动焦点,键盘用户仍得靠鼠标找行",
|
||
"acceptance": "↑↓ 在当前可见节点间移动、Home/End 到首末行,只改焦点不改选中,收起分支的子节点不参与遍历;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:既有组件可用性细节;NodeList 需 Array.from 展开(downlevel 迭代)",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"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 回传副本",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"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": "done",
|
||
"notes": "自补:Agent 查询体验;--json 保留原始清单",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g35",
|
||
"title": "新增 notification 通知卡片",
|
||
"motivation": "toast 是右上角轻量瞬时提示,装不下「标题 + 描述 + 操作按钮 + 需读完」的通知场景,业务侧只能自己写浮层",
|
||
"acceptance": "notification({ title, description, variant, duration, closable, action }) 右下角堆叠(与 toast 分区)、超出 3 条挤掉最早、返回 { el, close }、duration 0 常驻;组件数 42→43 三处计数同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:组件补充;与 toast 分区避免视觉冲突",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g36",
|
||
"title": "新增 result 结果页组件",
|
||
"motivation": "提交成功/校验失败/权限不足这类终态页每次手写图标+标题+按钮,语义色和留白都不统一",
|
||
"acceptance": "result({ status, title, description, extra }) 四档语义色 + 居中终态布局 + role=\"status\";组件数 43→44 三处计数同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:组件补充",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g37",
|
||
"title": "llms-full 增加组合配方章节",
|
||
"motivation": "清单只能描述单组件参数,Agent 拼多组件(表单+校验+提交反馈、表格+分页+批量、危险操作确认)时没有权威范例,容易各写一套",
|
||
"acceptance": "packages/tools/cli/recipes.md 作为唯一来源,ua docs 时追加到 llms-full.txt 末尾;缺少文件时不报错;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:Agent 文档;配方文件缺失时静默跳过",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g38",
|
||
"title": "select 支持 searchable 搜索",
|
||
"motivation": "选项超过十个时只能靠键入首字母快跳,看不到筛掉的候选;业务常自己再包一层搜索框,交互割裂",
|
||
"acceptance": "select({ searchable: true }) 弹层顶部带搜索框,打开即聚焦、实时包含匹配、无命中显示「无匹配选项」,↑↓/Home/End 只在可见项间移动;README 分组行补齐新组件;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:既有组件可用性细节",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g39",
|
||
"title": "统一键盘焦点可见性 + 可访问性约定入文档",
|
||
"motivation": "多数组件为自绘样式写了 outline:none,只有 14 处补了 focus-visible 光环,漏掉的组件键盘 Tab 过去完全看不出焦点在哪",
|
||
"acceptance": "ui.css 顶部统一 [class^=ua-]:focus-visible 描边兜底(不引入硬编码色);README 增「可访问性约定」章节;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:a11y;避免组件各自 outline:none 丢失焦点指示",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g40",
|
||
"title": "修表单双提交:button 显式 type + Enter 提交",
|
||
"motivation": "button() 不写 type,放进 <form> 里默认是 submit:点提交会先跑 click 回调再触发原生 submit(onSubmit 触发两次),点「重置」还会顺带提交表单",
|
||
"acceptance": "ButtonProps 增 type(缺省 button);form 内提交按钮用 submit、重置用 button;单行输入框 Enter 等同提交且 textarea 不受影响;文档同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:缺陷修复;textarea 保留换行语义",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g41",
|
||
"title": "verify 校验 README 分组行",
|
||
"motivation": "README「分组:」行是第二份组件清单,新增组件只改 ua:components 区块时分组行会静默过期(本轮之前已漏 6 个组件)",
|
||
"acceptance": "verify 解析分组行并比对清单集合,漏写/多写均报错(formItem 作为别名放行);负向删除 tree 即失败;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:门禁改进;把手工维护的第二份清单纳入自动校验",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g42",
|
||
"title": "pagination 支持每页条数切换",
|
||
"motivation": "分页器只能固定 pageSize,列表页要改条数得业务另做下拉并自算总页数;且每次翻页都在重建跳页输入框",
|
||
"acceptance": "pagination({ pageSizes, onPageSizeChange }) 渲染条数切换器、切换后回第 1 页并按新条数重算总页数;跳页区只创建一次;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:组件补充;新增 sec-pagination 演示区块",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g43",
|
||
"title": "select/menu/popover/image 的 Esc 接入统一弹层栈",
|
||
"motivation": "四个弹层组件各自监听 document 的 Esc:多层叠加(如 popover 内再开 image 预览)时一次 Esc 全部关闭,与 modal/drawer 的 pushOverlay 栈行为不一致",
|
||
"acceptance": "四个组件展开期入 Esc 栈、收起即释放;多层叠加时 Esc 后进先出逐层关闭;焦点归还触发器;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:一致性修复;复用 overlay.ts 的 pushOverlay 栈",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g44",
|
||
"title": "accordion 标题行方向键导航",
|
||
"motivation": "标题是原生 button 只有 Enter/Space,行间移动要靠 Tab 逐个跳,与 tabs/tree 的 ↑↓/Home/End 键盘约定不一致",
|
||
"acceptance": "↑↓ 在标题行间环形移动、Home/End 首尾直达,均跳过禁用行;焦点不在标题行不拦截;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:可达性对齐;复用环形回绕取模模式",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g45",
|
||
"title": "modal/drawer/image 打开时锁定背景滚动",
|
||
"motivation": "模态弹层开着时背景页面仍可滚动,长页面里滚动会带着遮罩底下内容跑;非模态弹层(select/menu/popover/tooltip)不受影响",
|
||
"acceptance": "overlay.ts 新增 lockScroll 引用计数:嵌套叠加只由最后一层还原 body;modal/drawer/image 预览接入,关闭即解锁;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:缺陷修复;引用计数避免多层同开时提前解锁",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g46",
|
||
"title": "新增 transfer 穿梭框组件",
|
||
"motivation": "组件库缺常规的双栏搬运组件:批量选择/授权/字段启用这类场景,调用方目前只能用两个 list + 手写搬运逻辑,勾选态与全选三态都要重复实现",
|
||
"acceptance": "新增 transfer(两栏由 dataSource 按 targetKeys 派生、逐栏搜索、全选含半选、禁用条目不参与、信号双向绑定);manifest/docs/demo/README/计数同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:组件补充;归属只存 key,搬运只改 targetKeys,不删条目",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g47",
|
||
"title": "新增 cascader 级联选择组件",
|
||
"motivation": "省市区、组织层级这类逐级下钻的选择场景目前只能靠多级 select 拼接,调用方得自己维护中间态与列联动",
|
||
"acceptance": "新增 cascader(多列联动、悬停下钻、点击提交、changeOnSelect、全键盘、Esc 入栈);manifest/docs/demo/README/计数同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:组件补充;浏览路径与已提交路径分离,避免悬停污染受控值",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g48",
|
||
"title": "新增 splitter 可拖拽分栏容器",
|
||
"motivation": "仪表盘/IDE 式布局需要可调整比例的分栏,库内没有任何布局基础件,调用方只能自己写拖拽与边界夹逼",
|
||
"acceptance": "新增 splitter(指针拖拽、键盘微调、双击复位、min 夹逼、sizes 信号受控、横纵两向);manifest/docs/demo/README/计数同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:布局基础件;两栏之和恒定,只改相邻一对",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g49",
|
||
"title": "新增 autoComplete 自动补全组件",
|
||
"motivation": "搜索式输入(组件名、城市、标签)目前只能用 select 的 searchable 近似,无法做到「边打边联想 + Enter 取首项」的输入法式体验",
|
||
"acceptance": "新增 autoComplete(输入即过滤、↑↓ 环形高亮、Enter 选中、Esc 入栈、options 函数式远程联想、空态提示);manifest/docs/demo/README/计数同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:组件补充;mousedown+preventDefault 保住输入框焦点",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g50",
|
||
"title": "新增 datePicker 日期选择组件",
|
||
"motivation": "表单体系里日期只能填文本,缺一个受控的单月网格选择器;min/max 约束与键盘逐日导航是排期/账期场景的刚需",
|
||
"acceptance": "新增 datePicker(单月网格、翻月、今天、min/max 闭区间、←→↑↓/PageUp/PageDown/Enter、Esc 入栈、value 信号);manifest/docs/demo/README/计数同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:表单组件补缺;跨月自动翻页,漫游 tabindex 只有焦点日可 Tab 进入",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g51",
|
||
"title": "新增 backTop 返回顶部按钮",
|
||
"motivation": "长文档/长表格页面缺少回顶入口,用户只能拖滚动条;进度环还能给出「还剩多少没看」的定位感",
|
||
"acceptance": "新增 backTop(阈值浮现、滚动进度环、平滑回顶且尊重 reduced-motion、支持内滚容器 target);manifest/docs/demo/README/计数同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:组件补充;进度环用 conic-gradient 内联写角度,不引入新令牌",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g52",
|
||
"title": "新增 colorPicker 颜色选择组件",
|
||
"motivation": "主题定制、标签配色等场景只能填十六进制文本框;缺省色板应直接消费 --ua-* 令牌,才能天然支持暗色切换",
|
||
"acceptance": "新增 colorPicker(预设色板 + 原生取色器 + 手输 CSS 颜色串、值信号、Esc 入栈、触发器实时预览);manifest/docs/demo/README/计数同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:组件补充;预设缺省为令牌色而非硬编码 hex",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g53",
|
||
"title": "新增 tour 引导漫游组件",
|
||
"motivation": "新用户首次进入复杂页面缺少分步指引;库内已有 overlay/position 能力,聚光挖洞式引导是最自然的组合产物",
|
||
"acceptance": "新增 tour(返回 {el,start,close} 句柄、按选择器聚光、卡片自动选方位、滚动重算、末步完成/跳过区分回调、Esc 入栈、焦点归还);manifest/docs/demo/README/计数同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:组件补充;聚光用超大 box-shadow 挖洞,省掉独立遮罩层",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g54",
|
||
"title": "新增 watermark 水印组件",
|
||
"motivation": "内部系统的防截图外传诉求没有落地件;水印颜色必须能跟随暗色主题,所以要从 --ua-* 令牌解析出实色再喂给 canvas",
|
||
"acceptance": "新增 watermark(props, ...children)(canvas 平铺单元、令牌色解析、多行/旋转/间距可配、覆盖层 pointer-events:none);manifest/docs/demo/README/计数同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:组件补充;canvas 不认 CSS 变量,先 getComputedStyle 解析",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g55",
|
||
"title": "新增 checkboxGroup 多选组组件",
|
||
"motivation": "权限勾选、标签多选这类场景只有单个 checkbox,调用方要自己拼数组、自己算全选与半选、自己处理「最多选 N 项」",
|
||
"acceptance": "新增 checkboxGroup(数组信号、min/max 禁用边界、checkAll 半选、纵横向、整组禁用);manifest/docs/demo/README/计数同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:表单组件补缺;边界用禁用表达,不抛错不静默回滚",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g56",
|
||
"title": "ua style 增加单文件 200 行门禁",
|
||
"motivation": "CODING.md 写明「单文件尽量 < 200 行」,但一直是人工约定;随着组件数涨到 54,靠人盯不住,应把这条规范变成可执行门禁",
|
||
"acceptance": "cmdStyle 增加 sizeCheckFile:只约束分层包 src 内实现文件、types.ts 与 index.ts 豁免;正向全绿、负向(造 210 行文件)退出码 1;AGENTS/CODING/README 同步该门禁说明;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:工具链改进;只约束包内实现文件,cli 自身与 demo 单文件不受限",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g57",
|
||
"title": "form 校验支持异步规则(validator 返回 Promise)",
|
||
"motivation": "邀请码占用、用户名唯一性这类校验必须打后端;原来 validator 只接受同步返回值,调用方只能绕过 form 自己写提交拦截",
|
||
"acceptance": "FormRule.validator 允许返回 Promise;formItem 返回 validateAsync 并按轮次丢弃过期结论;form 提交逐项 await、期间禁用提交按钮、有错聚焦首错;同步 validate 行为不变;demo 增异步字段;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:既有组件增强;同步路径不被 Promise 拖慢,异步路径防乱序覆盖",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g58",
|
||
"title": "新增 affix 固钉组件",
|
||
"motivation": "文档站目录、工具栏、筛选条都需要「滚过就贴顶」;直接用 position:sticky 常受父级 overflow 影响,需要占位 + fixed 的可靠实现",
|
||
"acceptance": "新增 affix(props, ...children)(阈值固定、外层等高占位不塌陷、宽度横向随容器自适应、支持内滚容器 target);manifest/docs/demo/README/计数同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:组件补充;固定态只在状态切换时重写样式,滚动中仅刷新宽度",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g59",
|
||
"title": "verify 检测 README 组件清单重复项",
|
||
"motivation": "README 区块与分组行原来用 Set 去重后比对,同一组件写两遍也能通过;重复项会让「组件数」与分组导航对不上,属于纯文档漂移",
|
||
"acceptance": "checkReadme 保留原始顺序并检测重复:区块重复、分组行重复(整词计数,避开 formItem 命中 form)都报错;正负向验证通过;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:工具链改进;分组行按整词边界计数,formItem 不被 form 误伤",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g60",
|
||
"title": "新增 multiSelect 多选下拉组件",
|
||
"motivation": "select 只支持单选,标签多选场景只能退回 checkboxGroup(占空间)或自拼 popover;需要一个「标签式回显 + 可搜索 + 连续多选」的标准控件",
|
||
"acceptance": "新增 multiSelect(标签回显与删除、搜索过滤、点选不收起、max 禁用边界、↑↓/Enter/Esc、受控信号);manifest/docs/demo/README/计数同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:组件补充;输入框常驻不重建,避免重绘丢焦点",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g61",
|
||
"title": "tree 支持勾选多选与父子级联",
|
||
"motivation": "权限树、菜单授权这类场景必须多选;原来只有单选 selected,调用方只能自己拿 DOM 拼一套勾选逻辑",
|
||
"acceptance": "TreeProps 增加 multi/checked/onCheck;勾父选子、子全选回勾父、部分勾选半选、禁用项不参与级联;勾选不触发选中,多选下 Enter/空格切换勾选;manifest/docs/demo 同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:既有组件增强;key→节点/父节点索引在建树时一次建立",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g62",
|
||
"title": "verify 校验 demo 实际调用每个组件",
|
||
"motivation": "原来只校验 section 锚点存在,理论上可以保留锚点却删掉组件调用——文档声称「有演示」而实际没渲染",
|
||
"acceptance": "verify 对每个 docs.components 条目要求 apps/demo/main.ts 出现 id( 或 id.(兼容 toast.info 这类命名空间调用);正负向验证通过;AGENTS 同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:门禁改进;当前 56 个组件全部通过该规则",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g63",
|
||
"title": "card 支持标题操作区、底部操作区与悬停态",
|
||
"motivation": "card 只有 title + children,业务里最常要的「标题右侧操作 / 底部主次按钮 / 可点击卡片」都得在外部再包一层",
|
||
"acceptance": "CardProps 增加 extra / footer / bordered / hoverable;标题行改 flex 头、标题下边距移到头部(视觉不变);demo/manifest 同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:既有组件增强;不改内部结构,只在有 title/extra 时才输出头部",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g64",
|
||
"title": "刷新 CHANGELOG 并说明刷新时机",
|
||
"motivation": "CHANGELOG 停在 g14,之后 40+ 条迭代都没进日志;同时没人说明它为何不在 check 链里(它包含提交自身,天然自指)",
|
||
"acceptance": "npm run changelog 重新生成到最新;AGENTS 增加「变更日志」段说明生成方式与「不进 check」的原因;README 脚本清单补 changelog;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:文档完善;changelog:check 只能用于发版前确认漂移,不能作为提交门禁",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g65",
|
||
"title": "verify 校验文档 props 落到实现,并补齐漏记字段",
|
||
"motivation": "文档 props 表与实现参数是两处手写,改了参数名忘改文档时 check 全绿但 Agent 读到的是幽灵字段;反向也有漏记(image.fallback、textField.clearable、textarea.maxCount、pagination.jumpable 都没进文档)",
|
||
"acceptance": "ua verify 新增「每个文档 props 名必须在组件实现源码里出现」校验(按同名文件优先、export function 兜底定位实现);补齐四处漏记字段;负向造幽灵字段能命中报错;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:门禁增强;说明性条目(...children、带括号注记)按非标识符跳过,避免误报",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g66",
|
||
"title": "verify 反向校验入参接口字段均已登记文档",
|
||
"motivation": "上一轮只挡了「文档有、实现无」的幽灵字段;反方向(types.ts 加了字段但文档没写)仍会漏,Agent 读文档就会少一个可用参数",
|
||
"acceptance": "ua verify 解析 src/types.ts 的 <组件>Props 字段并与文档 props 表双向比对;清单支持 propsType 覆盖接口名、false 表示无入参;补齐 form.onReset 漏记;负向注入 ghostField 能命中报错;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:门禁增强;接口名默认取 PascalCase(组件 id)+Props,switchButton/dataTable 用 propsType 覆盖",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g67",
|
||
"title": "tag 支持 checkable 筛选片",
|
||
"motivation": "筛选场景只能用 closable 标签表达「已选」,表达不了「未选可点」;且删掉再重建节点会丢焦点",
|
||
"acceptance": "TagProps 增加 checkable/checked/onChange;渲染为 button + aria-pressed,effect 同步 class 不整块重渲染;选中态低视觉比重(accent 10% 底 + 55% 边框),hover 上浮、按压回缩、focus-visible 光环并带 reduced-motion 兜底;文档与演示补齐;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:组件增强;checkable 与 closable 互斥(同时传以 checkable 为准),checked 不传则内部自持",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g68",
|
||
"title": "alert 增加语义图标与通栏形态",
|
||
"motivation": "提示条只有文字,语义强度全靠颜色(色弱不可辨);顶部通知也做不出通栏效果,得靠调用方套壳改样式",
|
||
"acceptance": "AlertProps 增加 banner/showIcon/icon;图标纯装饰 aria-hidden 不干扰读屏播报;is-banner 去圆角、只留下边框、通栏 padding;文档 props 与手把手补齐;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:组件增强;图标用字符而非外部图标集,避免引入依赖,颜色走 currentColor 跟随语义档",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g69",
|
||
"title": "修正单击排序的升降序循环与 getPageInfo 陈旧快照",
|
||
"motivation": "补冒烟时发现两处真 bug:非 multi 的 toggleSort 每轮先清空规则,导致同一列永远停在 asc(点了变不回去);getPageInfo 只在 derive 里赋值,没先取可见行时返回陈旧/默认快照",
|
||
"acceptance": "toggleSort 保留本列既有方向再循环 asc → desc → 取消(multi 保留全部列);getPageInfo 内部先跑一次带 memo 的派生;冒烟补三条不变量(快照即时性、selection 跨筛选保留、三次点击回无序);npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:核心正确性;state.pagination.page 保留调用方意图、仅视图钳制,这条既有语义未改",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g70",
|
||
"title": "冒烟补多列排序、页大小与 reset 重置断言",
|
||
"motivation": "冒烟只覆盖单列排序与越界钳制;multi 排序的规则优先级、setPageSize 回第 1 页、reset 回默认态都没有回归网,改动 patchState 时容易静默破功",
|
||
"acceptance": "smoke 新增三条不变量:multi 双列规则生成且按规则序生效(city 升序 + 同城 age 升序)、setPageSize 回第 1 页、reset 清空排序筛选并把分页回 1/20;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:回归网;断言数 9 → 16",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g71",
|
||
"title": "数据表表头补 aria-sort 三态播报",
|
||
"motivation": "排序态只有 ↑ / ↓ / ↕ 视觉箭头,读屏用户听不出当前按哪列排、什么方向;这是可排序表最基本的一条 a11y 约束",
|
||
"acceptance": "可排序 th 用 effect 同步 aria-sort(ascending / descending / none),与箭头同源;文档手把手补一条;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:无障碍;非 sortable 列不写 aria-sort,避免读屏误报",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g72",
|
||
"title": "文档站搜索框与结果区补无障碍语义",
|
||
"motivation": "生成的文档站搜索框没有可访问名(读屏只报「编辑框」),搜索后也没有结果数播报,键盘/读屏用户拿不到反馈",
|
||
"acceptance": "input 改 type=search + aria-label;nav 加 aria-label;新增 sr-only 的 role=status 区域,render 时播报「匹配 N 个包」与「无匹配结果」;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:无障碍(文档站产物本身)",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g73",
|
||
"title": "表格分页区补导航语义与页码播报",
|
||
"motivation": "底栏只是一排按钮,读屏不知道那是分页;页码/行数变化也没有播报,筛选后用户不知道结果变了",
|
||
"acceptance": "分页容器加 role=navigation + aria-label;页码行数文本改 role=status aria-live=polite;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:无障碍;live region 只在文本变化时播报,翻页/筛选都会触发",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g74",
|
||
"title": "弹窗与抽屉补 aria-labelledby 标题关联",
|
||
"motivation": "role=dialog 但没挂可访问名,读屏只会念「对话框」,用户不知道是哪个弹窗;标题元素本身也没有 id,无法被引用",
|
||
"acceptance": "modal/drawer 用模块级序号生成唯一标题 id 并挂 aria-labelledby,多实例不撞号;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:无障碍;drawer 的 aria-hidden 与 open 同步逻辑未动",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g75",
|
||
"title": "评分组件键盘可达性与焦点保持",
|
||
"motivation": "role=slider 却不可聚焦(div 无 tabindex),keydown 只挂在首帧节点上且整体重渲染会替换节点——方向键实际按一下就失效,读屏也听不到键盘操作",
|
||
"acceptance": "整组 tabindex=0 可聚焦,keydown 每轮渲染重挂,重渲染后焦点归还并继续连按;补 focus-visible 光环;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:无障碍;重渲染策略保持不变(星标少,开销可忽略)",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g76",
|
||
"title": "文字头像补 role=img 使名称可播报",
|
||
"motivation": "无 src 的文字头像只是带 aria-label 的 span,普通元素上的 aria-label 不保证被读屏当名称读出来,等于没有可访问名",
|
||
"acceptance": "文字头像容器补 role=img,与有 src 时的 img alt 语义对齐;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:无障碍;title 仍保留供鼠标悬浮提示",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g77",
|
||
"title": "刷新 CHANGELOG 至最新提交",
|
||
"motivation": "g64 之后又落了 12 次提交,changelog:check 已经报漂移;CHANGELOG 停在旧版本等于给读者过期信息",
|
||
"acceptance": "npm run changelog 重新生成(226 提交),changelog:check 不再报漂移;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:发版前刷新步骤,按 g64 约定的方式执行",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g78",
|
||
"title": "新增 space 间距容器组件",
|
||
"motivation": "库里 56 个组件都在各自实现里写 margin/gap,「一排按钮统一间距」「工具栏两端撑开」这类布局诉求没有承载物,演示页与业务方只能重复拼 style",
|
||
"acceptance": "新增 space(props, ...children):direction / size(sm|md|lg 走令牌,数字按像素)/ align / justify / wrap / block;manifest 参数表 + 手把手步骤 + api.exports 登记;demo 有 sec-space 区块真实调用;README 计数与分组同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:布局基础件缺失;间距一律走 --ua-space-* 令牌,几何用内联 style 不进皮肤样式表",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g79",
|
||
"title": "数据表可排序表头补键盘可达与列作用域",
|
||
"motivation": "表头只绑了 onClick,键盘用户聚焦不到、也按不出来——README 声称「关键交互都有键盘等价」,表格排序是唯一漏网的;th 还缺 scope=col,读屏无法把列标题与数据格关联",
|
||
"acceptance": "可排序 th 进 Tab 序(tabindex=0,不可排序的不抢焦点),Enter/空格 触发与点击相同的 toggleSort(空格不滚页),补 scope=col;悬停/聚焦视觉沿用既有 ua-sortable 与全局 focus-visible;dataTable 仍 ≤ 200 行;npm run check 全绿",
|
||
"notes": "自补:无障碍;排序入口收敛为单个 toggle 闭包,鼠标与键盘同源,不改核心签名",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g80",
|
||
"title": "通知悬停/聚焦暂停自动关闭计时",
|
||
"motivation": "duration 一设定就是定时器到点即退场,鼠标悬停正在读的卡片照样消失(WCAG 2.2.1「计时可调」);通知恰恰是长篇描述,读到一半被收走比不自动关更烦",
|
||
"acceptance": "pointerenter / focusin 暂停并扣减已流逝时间,pointerleave / focusout 按剩余毫秒续计;duration 为 0 时行为不变;关闭仍先清计时器;文档与演示描述同步;npm run check 全绿",
|
||
"notes": "自补:无障碍;不改签名,remaining 时间在组件内折算",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g81",
|
||
"title": "树形组件改用 roving tabindex",
|
||
"motivation": "每行都写死 tabindex=0,键盘用户从树里穿过去要按 N 次 Tab(20 个节点就是 20 次),违反 WAI-ARIA 树模式「整棵树一个 Tab 停点、行间用方向键」的要求",
|
||
"acceptance": "只有当前行 tabindex=0 其余 -1;焦点落到哪行停点就跟到哪行(focusin 同步),下次 Tab 直接回到该行;↑↓/Home/End 移动后停点随焦点迁移;初始停点为首个未禁用根节点;tree ≤ 200 行;npm run check 全绿",
|
||
"notes": "自补:无障碍;keyOf 抽出复用,去掉 keydown 里的内联查找",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g82",
|
||
"title": "文件选择补类型/体积/数量校验与拒收提示",
|
||
"motivation": "accept 只设到原生 input 上,拖拽进来的文件完全绕过校验;也没有体积与数量上限,超限只能靠调用方在 onChange 里事后过滤,用户看不到为什么文件没进清单(静默丢弃)",
|
||
"acceptance": "新增 maxSize(字节)/ maxCount(多选上限)两个可选参数;accept 支持 .ext / type/subtype / type/* 且对拖拽同样生效;被拒文件不进清单并在 role=status 提示行写明原因(类型不符 / 超上限 / 数量已满);不改onChange 语义;文档与演示同步;npm run check 全绿",
|
||
"notes": "自补:可用性;校验入口收敛到 add(),点选与拖拽共用同一条路径",
|
||
"status": "done",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g83",
|
||
"title": "开关改用 switch 语义并补可访问名兜底",
|
||
"motivation": "开关底层是 input type=checkbox,读屏一律播报成「复选框」,与视觉上的开关语义不符;不留 label 时更是完全没有可访问名(只有一个匿名复选框)",
|
||
"acceptance": "input 补 role=switch(选中态沿用原生 checked 映射);新增可选 ariaLabel,缺省取 label,纯图标开关也有可访问名;文档 props 与演示(无文案开关实例)同步;npm run check 全绿",
|
||
"notes": "自补:无障碍;沿用原生 checkbox 的 Space 切换行为,不重造键盘交互",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g84",
|
||
"title": "数据表定宽列支持拖拽调宽",
|
||
"motivation": "列宽只能在定义时写死,长内容把列撑开就再也调不回去;表格库缺这个基本操作,用户只能改代码重发版",
|
||
"acceptance": "width 为数字的列在表头右缘出现手柄:拖动实时改对应 <col> 宽度(下限 56px,拖出表头仍跟手),聚焦手柄后 ← → 每次 ±8px,双击复位到声明宽度;拖拽/双击不触发排序;拖拽期间全局禁选文本;样式走令牌且有 reduced-motion 兜底;dataTable ≤ 200 行;npm run check 全绿",
|
||
"notes": "自补:可用性;拖拽与键盘共用 apply 单一写宽入口,逻辑拆到 columnResize.ts 免撑大 dataTable",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g85",
|
||
"title": "进度条补可访问名与语义色",
|
||
"motivation": "定量态只有 aria-valuenow,没有名称——读屏只念「50%」,不知道是什么在 50%;且除 accent/success 外没有失败告警色,同步失败也只能显示成一片蓝",
|
||
"acceptance": "新增 label(可访问名,不确定态缺省「进行中」兜底)与 variant(default/success/warning/danger);语义色规则置于 .ua-done 之后同特异性胜出,满格不回退 success;样式只消费 --ua-* 令牌;文档 props/steps 与演示同步;npm run check 全绿",
|
||
"notes": "自补:无障碍 + 视觉语义;CSS 层用特异性解决 variant 与满格 success 的冲突,不加 JS 分支",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g86",
|
||
"title": "弹层外部点击监听改为按需挂载",
|
||
"motivation": "8 个弹层(select / multiSelect / cascader / datePicker / colorPicker / autoComplete / menu / popover)在构造时就在 document 上挂一个永不移除的 click 监听:组件从页面移除后监听仍常驻(SPA 里实例越多越积压),且各写一份重复逻辑;popover 里还残留一个空的 keydown 监听",
|
||
"acceptance": "overlay 新增 bindOutside(root, isOpen, close):仅展开期间挂全局 click、收起即摘,内部点击直接返回;8 个弹层全部改用它并删掉各自的重复实现;popover 删掉空 keydown,点弹层内部不再误关;npm run check 全绿",
|
||
"notes": "自补:稳健性 + 去重;展开动作本身也是 click,靠 root.contains 卫语句避免刚开就被关",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g87",
|
||
"title": "轮播补焦点暂停与轮播语义",
|
||
"motivation": "自动播放只在 pointerenter 暂停——键盘用户没有 hover,Tab 进轮播后幻灯片照样自己换页,正在读的内容被抽走(WCAG 2.2.2);区域与幻灯片也只有笼统的 aria-label,读屏不知道这是轮播的第几张",
|
||
"acceptance": "焦点进入(focusin)与移出(focusout)同样暂停自动播放,两者都不在才前进;区域补 aria-roledescription=轮播,每张补 aria-roledescription=幻灯片 且标签为「第 x 张,共 n 张」;演示描述同步;npm run check 全绿",
|
||
"notes": "自补:无障碍;hover 与 focus 分开计数,避免一个 pointerleave 就误解除暂停",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g88",
|
||
"title": "数据表支持导出 CSV",
|
||
"motivation": "表格能筛能排却导不出来,用户只能截图或手抄;导出还必须导「筛选+排序后的全量行」而不是当前页,但内核只有 getVisibleRows()(已分页裁剪),UI 层拿不到全量派生行",
|
||
"acceptance": "内核 getVisibleRows(paged=false) 跳过 pagination 阶段并新增 getAllRows(),派生上下文带 paged 标记(缺省分页),分页快照不受影响;dataTable 新增 exportable / exportName,工具栏按钮导出筛选+排序后的全量行、单元格走 format;CSV 带 BOM + CRLF、逗号引号换行正确转义;冒烟补 4 条不变量;npm run check 全绿",
|
||
"notes": "自补:功能缺口;核心只加可选参数与一个实例方法,不动既有签名",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g89",
|
||
"title": "演示产物启用保守压缩",
|
||
"motivation": "demo.html 单文件 278 KB,其中 JS 近 190 KB 全是未压缩的空白与冗余括号;演示页是给别人点开看的产物,体积直接影响加载体验,而全量 minify 会把标识符改短、不利于现场排查",
|
||
"acceptance": "esbuild 开启 minifyWhitespace + minifySyntax(保留标识符),产物仍可读;demo.html 由 278 KB 降到 205 KB(JS 190 KB → 120 KB);产物语法可被 node --check 通过,sec-space / ua-col-grip 等新增内容仍在;npm run check 全绿",
|
||
"notes": "自补:构建改进;刻意不用全量 minify,平衡体积与可读性",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g90",
|
||
"title": "刷新 CHANGELOG 至最新提交",
|
||
"motivation": "g89 之后又累积了十余次迭代提交,changelog:check 已报漂移;CHANGELOG 停在旧版本等于给读者过期信息",
|
||
"acceptance": "npm run changelog 重新生成(253 提交),changelog:check 不再报漂移(提交本条后按既有约定会再差一条,属正常);npm run check 全绿",
|
||
"notes": "自补:发版前刷新步骤,按 g64/g77 的既定方式执行",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g91",
|
||
"title": "表单字段补辅助说明 hint",
|
||
"motivation": "formItem 只有 label 与错误位,没有「格式提示」的位置:调用方只能把说明塞进 placeholder 或标签里,一报错提示就被替换得无处可看,用户不知道正确格式是什么",
|
||
"acceptance": "FormItemProps 新增可选 hint,渲染在控件下方;校验失败时 hint 让位(hidden)只留错误文案,校验通过自动恢复;样式走令牌;文档参数表(formItem 前缀)与演示同步;npm run check 全绿",
|
||
"notes": "自补:表单可用性;不改 formItem 返回句柄与 form 聚合逻辑",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g92",
|
||
"title": "徽标支持数字角标与纯红点",
|
||
"motivation": "badge 只能塞一段文字,做「未读 5 条」「99+」「有更新的小红点」时得自己拼 span + 手写样式,红色点还会硬编码颜色绕过令牌",
|
||
"acceptance": "BadgeProps 新增 count / max / dot,label 改为可选;count 超过 max(缺省 99)显示 N+,负数归零;dot 渲染 8px 圆点并以 role=img + label 作可访问名;新增样式只消费 --ua-* 令牌;文档与演示(三种形态)同步;npm run check 全绿",
|
||
"notes": "自补:组件能力补齐;保持纯展示、无内部状态",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g93",
|
||
"title": "树形组件支持按标签搜索",
|
||
"motivation": "节点一多(如目录树、组织架构)就只能靠展开逐层找;tree 只有展开/收起与方向键,没有任何过滤入口,几十个节点等于不可用",
|
||
"acceptance": "TreeProps 新增 searchable:顶部搜索框按标签包含匹配(大小写不敏感),命中节点连同父链保留、命中枝临时强制展开,不命中整枝隐藏且不参与 ↑↓ 遍历(visibleRows 改判 [hidden]);搜索框放在 role=tree 之外避免语义混淆;文档与演示同步;tree ≤ 200 行;npm run check 全绿",
|
||
"notes": "自补:可用性;搜索只改视图显隐,不回写 expanded 信号,退出搜索即恢复用户原有展开态",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g94",
|
||
"title": "补充数据表联动导出配方",
|
||
"motivation": "本轮新增的受控 page 联动、列宽拖拽、CSV 导出三个能力只有单组件参数表,没有「怎么拼在一起」的指导;配方文件停在第 4 条,Agent 与新人拼表格联动时仍要自己试",
|
||
"acceptance": "recipes.md 新增「配方 5:数据表 + 独立分页器 + 导出」,覆盖同一 page 信号双绑、exportable 导全量行与当页的区别、拖拽只对数字列宽生效、rowKey 记账;npm run docs 后 llms-full.txt 出现该配方;npm run check 全绿",
|
||
"notes": "自补:文档完善;只写用法不碰实现,配方随 docs 注入 llms-full",
|
||
"status": "done",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g95",
|
||
"title": "统计数值支持倒计时模式",
|
||
"motivation": "活动剩余时间这类需求只能调用方自己 setInterval 改信号再塞进 statistic,还得自己管停表;组件本身只认一个数值信号,秒级刷新没有落脚点",
|
||
"acceptance": "StatisticProps 新增 countdown(目标时间戳毫秒),传了即每秒显示 DD 天 HH:MM:SS(不足一天省天数),value 转为可选;到点或组件被移除后自动 clearInterval,不留常驻定时器;倒计时不走滚动动画;文档与演示同步;npm run check 全绿",
|
||
"notes": "自补:功能补齐;停表条件放在 tick 内自检 isConnected,无需额外卸载钩子",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g96",
|
||
"title": "抽屉支持上下滑出方位",
|
||
"motivation": "drawer 的 placement 只有 left/right,移动端最常见的「底部弹层」只能拿 modal 或者自己写 fixed 容器凑,既丢了焦点陷阱与 Esc 栈,样式也不统一",
|
||
"acceptance": "placement 扩到 'left' | 'right' | 'top' | 'bottom';上下滑出时 width 语义变为高度、横向自动铺满(max-width 放开),入场位移走 translateY,四条方位共用同一套遮罩/焦点陷阱/Esc 栈;文档与演示(底部抽屉实例)同步;npm run check 全绿",
|
||
"notes": "自补:组件能力补齐;只加 CSS 分支与一个三元表达尺寸,逻辑零改动",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g97",
|
||
"title": "本轮收尾刷新变更日志",
|
||
"motivation": "g90 之后又落了 19 次迭代提交(space 组件、列宽拖拽、CSV 导出、树搜索、抽屉四向等),CHANGELOG 已明显落后",
|
||
"acceptance": "npm run changelog 重新生成(267 提交),changelog:check 一致(提交本条后按约定再差一条);npm run check 全绿",
|
||
"notes": "自补:发版前刷新步骤,收尾统一执行",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g98",
|
||
"title": "弹窗与抽屉补遮罩关闭开关",
|
||
"motivation": "modal/drawer 点遮罩必关,表单类弹窗填到一半误触就丢内容;调用方没有任何开关能保留 × 与 Esc 的同时禁掉遮罩关闭",
|
||
"acceptance": "ModalProps / DrawerProps 新增 closeOnOverlay(缺省 true);传 false 时点遮罩不关闭,× 与 Esc 行为不变;文档参数表与演示(防误关弹窗实例)同步;npm run check 全绿",
|
||
"notes": "自补:可用性;遮罩点击处理改成显式卫语句,语义比一长串 && 更清楚",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g99",
|
||
"title": "加载指示器补可定制播报文案",
|
||
"motivation": "spinner 的 aria-label 写死「加载中」,页面里同时有三处加载时读屏念三次一样的话,用户不知道在等什么;组件没有出口让调用方说明加载对象",
|
||
"acceptance": "SpinnerProps 新增可选 label,缺省仍是「加载中」(不传即旧行为);role=status 保持不变;文档参数与手把手步骤、演示(带 label 的实例)同步;npm run check 全绿",
|
||
"notes": "自补:无障碍;纯透传一个可选参数,行为向后兼容",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g100",
|
||
"title": "收尾刷新变更日志",
|
||
"motivation": "g97 之后又落了 6 次提交(抽屉四向、遮罩关闭开关、加载播报等),changelog:check 已报漂移",
|
||
"acceptance": "npm run changelog 重新生成(273 提交),changelog:check 一致;npm run check 全绿",
|
||
"notes": "自补:发版前刷新步骤;本条为本次唤起第 22 轮收尾",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g101",
|
||
"title": "新增锚点导航组件 anchor",
|
||
"motivation": "文档页、设置页、长表单都需要「侧边跳转 + 滚动高亮」,现在库里没有任何可复用件:demo 的侧栏目录 (buildToc) 是手写 IntersectionObserver + 类名切换,偏移量、hash 回写、禁用项、减少动效各写各的,调用方要复制一遍才用得上",
|
||
"acceptance": "新增 anchor(props)(packages/skin/ui/src/anchor.ts,< 200 行):items/href/title/disabled、offset 偏移量、container 内滚容器、onChange 回调;滚动按目标位置高亮并同步 aria-current,点击平滑定位 + replaceState 回写 hash,prefers-reduced-motion 下瞬移;types/manifest/index/ui.css/demo/README/AGENTS/ARCHITECTURE 同步,npm run check 全绿",
|
||
"notes": "自补:组件补充;样式全走令牌,选出态维持低视觉比重(accent 10% 底色 + 左侧 2px 指示条)",
|
||
"status": "done",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g102",
|
||
"title": "焦点陷阱下沉为共享助手,图片预览接上",
|
||
"motivation": "modal 与 drawer 各自复制了一份 25 行的 Tab 焦点陷阱(focusables + keydown 环形回绕),改一处漏一处;image 的全屏预览层是 role=dialog aria-modal,却完全没有焦点陷阱也没把焦点移进去,键盘用户 Tab 一下就穿到背后的页面",
|
||
"acceptance": "overlay.ts 新增 trapFocus(box, isOpen):Tab / Shift+Tab 首尾环形,有无可用焦点与焦点在容器外的两种情况都拦回;modal / drawer 删掉本地实现改为调用(行为不变);image 预览层补 tabindex=-1 + 打开即聚焦 + 全程锁焦点;npm run check 全绿",
|
||
"notes": "自补:一致性与无障碍;陷阱实现单一来源,后续新增模态层直接复用",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g103",
|
||
"title": "表格空状态区分「没数据」与「被筛掉」",
|
||
"motivation": "dataTable 不论有没有筛选词,0 行时一律显示「暂无匹配数据」:数据本身就空的时候提示「匹配」让人以为筛选还在生效,而筛选筛空的时候又不给任何出口,用户只能手动删掉输入框里的字才发现原来有数据",
|
||
"acceptance": "有筛选词时显示「没有符合「关键词」的行」并给「清除筛选」按钮(一次性清空关键字信号与内核筛选、回第 1 页);无筛选词时显示「暂无数据」且不出现按钮;关键字用受控信号持有,与筛选框同源;每行文件仍 ≤ 200 行;npm run check 全绿",
|
||
"notes": "自补:可用性;空状态行抽到 tableEmpty.ts,dataTable 顺手把 api 类型别名下沉到 types.ts 才没破 200 行",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g104",
|
||
"title": "留痕校验回查提交是否真实存在",
|
||
"motivation": "iterations.log 目前只校验字段格式:commit 随便写个哈希、或复制粘贴时抄错一位,门禁照样全绿。留痕是「这条迭代真的落过」的唯一凭证,凭证本身不可验证等于没校验",
|
||
"acceptance": "ua lint-iterations 额外做双向核对:每行 commit 必须能在 git 历史里按前缀命中,且该提交主题以 iter(<id>) 开头(兼容早期无 scope 的 iter: <id>);伪造 / 抄错的哈希报违规并退出码 1;非 git 环境(打包分发)自动跳过该维度;ITERATION.md 留痕章节写明该校验;npm run check 全绿",
|
||
"notes": "自补:门禁工具链;一次 git log 建索引,150 行留痕不额外起进程",
|
||
"status": "done",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g105",
|
||
"title": "标签页支持可关闭页签",
|
||
"motivation": "多开详情页 / 编辑器类界面需要「关掉这个页签」,tabs 只有 label + disabled,调用方得自己在页签头外面挂按钮,关闭按钮的 hover 显现、指示条宽度、键盘等价全得重写一遍",
|
||
"acceptance": "TabItem 新增 closable(缺省不可关),渲染 × 关闭按钮(aria-label=关闭 <label>),点击或页签聚焦后按 Delete 触发 onClose(value);指示条改为量外壳宽度,可关闭页签的高亮能盖住 ×;触摸设备(hover: none)常显 ×;表单化入参不变(closable 在项上),文档参数表/手把手/示例与演示(三张可关订单页签,关完显示空态)同步;npm run check 全绿",
|
||
"notes": "自补:组件可用性;关闭只回调不改数据,符合受控约定",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g106",
|
||
"title": "滚动监听改为卸载自清理",
|
||
"motivation": "affix / backTop / anchor / tour 四个组件都是「挂 window 或容器的 scroll+resize 监听,从不摘」:单页应用里每次进页面重建组件就多一根监听,旧闭包连同旧 DOM 一起被 window 拽住,切十次页面就十份空转的 sync 在滚动时跑",
|
||
"acceptance": "新增 watch.ts 的 watchViewport(root, host, handler):滚动 / 缩放时若 root 已脱离文档就一次性摘掉两个监听并停止回调,否则转交 handler 并首帧同步一次;四个组件改用该助手,行为与原来一致(首帧同步保留);npm run check 全绿",
|
||
"notes": "自补:一致性与泄漏治理;一处实现四处复用,后续新增长期监听组件照抄",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g107",
|
||
"title": "新增二次确认气泡 popconfirm",
|
||
"motivation": "删除 / 发布这类危险操作只有两条路:直接执行(误点就没了)或弹 modal(打断视线、还要再找一次按钮)。中间档位「就地确认」缺失,而 popover 的 open 状态是组件私有的,调用方连编程收起都做不到,没法自己拼",
|
||
"acceptance": "PopoverProps 新增受控 open 信号(不传行为不变);新增 popconfirm(props, trigger):title/description/confirmText/cancelText/variant/placement/onConfirm/onCancel/open,确定先收起再回调,取消 / 点外部 / Esc 走 onCancel,展开即聚焦「取消」;组件 58→59,manifest/docs/README/AGENTS/ARCHITECTURE/demo 同步;npm run check 全绿",
|
||
"notes": "自补:组件补充;复用 popover + button,不重复实现定位与 Esc 栈",
|
||
"status": "done",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g108",
|
||
"title": "表单提交失败给汇总条与回调",
|
||
"motivation": "提交失败时只把焦点扔到第一处错误:视觉上用户得自己数还有几处红框,读屏用户更是只听到某个输入框的 aria-invalid,完全不知道总共有几项要改;调用方也拿不到「这次失败了几项」做埋点或顶部提示",
|
||
"acceptance": "form 提交时统计不通字段数,顶部渲染 role=alert 的汇总条「有 N 项需要修改,已定位到第一处」(通过则隐藏);FormProps 新增 onError(count) 与 errorSummary(缺省 true,传 false 不插节点);文档参数表与演示说明同步;npm run check 全绿",
|
||
"notes": "自补:无障碍与可用性;汇总条与逐项红框同源,均由一次提交的校验结果推导",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g109",
|
||
"title": "提示气泡支持触摸屏点按",
|
||
"motivation": "tooltip 只挂 pointerenter / pointerleave:触摸屏上按下会触发 enter(延迟 150ms 出),抬手立刻触发 leave 收起 —— 等于气泡刚出来就被手指带走,用户根本没机会读;移动端等于该组件不可用",
|
||
"acceptance": "触摸指针(pointerType=touch)不走 hover 分支,改为按下即出场、抬手后延迟 1.2s 收起;鼠标与键盘路径行为不变;re-enter 时清掉上一轮的延迟收起计时;文档手把手与 api 说明补触摸语义;npm run check 全绿",
|
||
"notes": "自补:可用性;只在原文件加两个分支与一个计时器,未改签名",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g110",
|
||
"title": "下拉选择支持清空",
|
||
"motivation": "筛选项一旦选中就回不到「未选」:城市、负责人这类可选筛选的下拉没有清空出口,用户只能刷新页面或换一个值。textField 早有 clearable,select 一直没有对应能力",
|
||
"acceptance": "SelectProps 新增 clearable(缺省 false):有值时触发器右缘出现 ×,点它把值写成空串并回调 onChange('');收起态按 Delete / Backspace 等价清空;按钮不进 Tab 序、无值自动隐藏;文档参数表 / 手把手 / api 说明与演示(城市下拉开启清空)同步;npm run check 全绿",
|
||
"notes": "自补:可用性;复用既有 value 信号与 onChange,不新增状态",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g111",
|
||
"title": "面包屑支持超长路径折叠",
|
||
"motivation": "七层路径(首页/控制台/订单管理/华东区/2026 Q4/待发货/订单 #1024)在窄容器里会把末项当前页挤到换行甚至省略号之后,而当前页恰恰是最该看清的;breadcrumb 没有任何收窄手段",
|
||
"acceptance": "BreadcrumbProps 新增 maxItems:超出时渲染「首项 + … + 末 Math.max(2, maxItems-1) 项」,折叠按钮 aria-label 报出被折叠条数、点一下原地展开全部;展开后不再折叠,末项始终是当前页;文档参数表 / 手把手 / 演示(七层路径 maxItems=4)同步;npm run check 全绿",
|
||
"notes": "自补:可用性;渲染走 effect + replaceChildren,不重建整个 nav",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g112",
|
||
"title": "消息提示支持撤销类操作按钮",
|
||
"motivation": "「已删除 3 条记录」这种提示最常见的下一步就是撤销,现在只能干看着它 3 秒后消失,要撤销得自己去列表里找回来;toast 只有 closable 一个交互出口",
|
||
"acceptance": "ToastProps 新增 actionLabel 与 onAction:传了文案才渲染操作按钮(accent 色、hover 下划线、focus-visible 有环),点后先收起再回调;带操作按钮的 toast 接收指针事件(原来只有 closable 才接收),悬停暂停逻辑不变;文档参数表 / 手把手 / api 说明与演示(「带撤销」按钮,5s)同步;npm run check 全绿",
|
||
"notes": "自补:可用性;沿用现有 dismiss,不新增公开 API",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g113",
|
||
"title": "吸顶容器支持贴底固定",
|
||
"motivation": "底部操作条(保存 / 取消 / 合计金额)是长表单与详情页的刚需,affix 只会贴顶:调用方得自己监听滚动改 position,或者干脆让操作条跟着内容滚走,用户翻到表单底部才发现按钮在屏幕外",
|
||
"acceptance": "AffixProps 新增 position(top 缺省 / bottom):贴底时占位容器底边越过「视口底 - offset」才固定,内联边距写 bottom 并清空 top,取消固定时两边都还原;贴顶行为不变;文档参数表 / 手把手 / api 说明同步;npm run check 全绿",
|
||
"notes": "自补:组件可用性;只在 sync 里加一条判定与一个样式分支",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g114",
|
||
"title": "收尾刷新变更日志",
|
||
"motivation": "g100 之后又落了 26 次提交(锚点导航、焦点陷阱下沉、留痕真实性校验、可关闭页签、二次确认气泡、表单汇总条、下拉清空、面包屑折叠、toast 撤销、贴底固钉等),changelog:check 已报漂移",
|
||
"acceptance": "npm run changelog 重新生成(301 提交),changelog:check 与提交史一致;npm run check 全绿",
|
||
"notes": "自补:发版前刷新步骤;本条为本次唤起收尾轮",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g115",
|
||
"title": "新增月历组件 calendar",
|
||
"motivation": "排期表、值班表、日程页需要「整月网格一直看得见」,datePicker 只能弹层选一天且收起来就没了;调用方要自己算月初留白、当月天数、今天与选中的标记,还要补键盘漫游,一写就是一百多行重复逻辑",
|
||
"acceptance": "新增 calendar(props)(< 200 行):value/month 信号、marker 每日标记(文案同时进 aria-label)、onSelect / onMonthChange;月初留白与天数计算抽到 dateKit.ts,datePicker 改为共用同一份(消除两处日期工具);组件 59→60,types/index/css/manifest/docs/README/AGENTS/ARCHITECTURE/demo 同步;npm run check 全绿",
|
||
"notes": "自补:组件补充 + 派生语义单一来源(日期工具下沉 dateKit)",
|
||
"status": "done",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g116",
|
||
"title": "抽屉支持非模态模式",
|
||
"motivation": "「一边看列表一边改右侧详情」是后台最常见的交互,但 drawer 只有模态一档:打开就盖一层遮罩、锁住背景滚动、把焦点困在面板里,主视图彻底不可用;调用方只能拿 fixed 的 div 自己拼一个假抽屉",
|
||
"acceptance": "DrawerProps 新增 modal(缺省 true):false 时遮罩透明且 pointer-events: none、面板自身可交互并带阴影、不锁背景滚动、不启用 Tab 焦点陷阱、aria-modal=false、点外部不算关闭(× 与 Esc 仍可用);文档参数表 / 手把手与演示(非模态检查器)同步;npm run check 全绿",
|
||
"notes": "自补:组件可用性;沿用现有遮罩节点加一个 is-plain 分支,不新增 DOM 结构",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g117",
|
||
"title": "指示条与滑块跟随尺寸重算",
|
||
"motivation": "tabs 的滑动指示条与 segmented 的滑块都只在「激活项变化」和挂载后一帧各量一次:窗口缩放、侧栏展开收起、字体调大之后,指示条宽度就停在旧值上,明显错位;这类「布局变了但没重算」的问题用户只会觉得组件坏了一半",
|
||
"acceptance": "watch.ts 新增 trackSize(root, handler):用 ResizeObserver 观察根节点尺寸,变化即回调,节点脱离文档时自查并断开(无 ResizeObserver 的环境回落成 window resize);tabs / segmented 接入,指示条与滑块在容器变宽变窄后保持对齐;npm run check 全绿",
|
||
"notes": "自补:正确性;与 watchViewport 同一处收口,后续布局敏感组件照抄",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g118",
|
||
"title": "收尾再刷变更日志",
|
||
"motivation": "g114 之后又落了 4 次提交(新增 calendar 月历、抽屉非模态、trackSize 尺寸重算等),changelog:check 再次报漂移",
|
||
"acceptance": "npm run changelog 重新生成(309 提交),与提交史一致;npm run check 全绿",
|
||
"notes": "自补:发版前刷新步骤;本次唤起收尾轮",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g119",
|
||
"title": "空状态支持自定义图标",
|
||
"motivation": "empty 的图标位写死成 ⌀,业务方几乎都会换成自己的插图(搜索无结果用放大镜、空订单用纸箱);现在只能在外面再包一层插画 div,既影响居中节奏又和组件内置图标同屏",
|
||
"acceptance": "EmptyProps 新增 icon(unknown):字符串或图标 DOM 直接进图标位,缺省仍是 ⌀;图标位保持 aria-hidden,语义由 title / description 承担;文档参数表 / 手把手与演示(搜索无结果换成 🔍)同步;npm run check 全绿",
|
||
"notes": "自补:可用性;一个可选参数透传,行为向后兼容",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g120",
|
||
"title": "AGENTS.md 补新增组件落点清单",
|
||
"motivation": "本轮 20 次迭代里,每加一个组件都要现推一遍「要改哪些文件」:types / index / css / manifest 两处 / demo / README 三处 / AGENTS / ARCHITECTURE / docs,漏一处就靠 verify 报错来提醒,返工成本高;接手的 Agent 也没有一份照单打勾的清单",
|
||
"acceptance": "AGENTS.md「贡献新组件」章节补一张 10 行的落点表(每个落点写清具体动作与门禁原因),并说明改既有组件入参同样要走 manifest / docs 三步;npm run check 全绿",
|
||
"notes": "自补:Agent 文档完善;把本轮踩到的同步点固化成清单",
|
||
"status": "done",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g121",
|
||
"title": "textField 补 maxCount 字数统计",
|
||
"motivation": "textarea 早有 maxCount(原生上限 + 实时 n/limit),textField 却没有:昵称、标题、单行备注这类短字段同样需要限长,调用方只能自己拼计数节点贴在输入框外,样式与位置各写各的",
|
||
"acceptance": "TextFieldProps 新增 maxCount(缺省不渲染):传了即设原生 maxlength 拦截超限输入,输入框内侧附加组显示实时 n/上限(数字等宽不抖);与 clearable 共存时同组并排;文档参数表 / api 说明 / 手把手与 llms-full.txt 同步;npm run check 全绿",
|
||
"notes": "自补:输入类一致性;计数与清空共用后置附加组,零新增布局容器;首轮 verify 曾报 llms-full 漂移,重跑 npm run docs 后恢复(docs 需在 index 之后跑)",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g122",
|
||
"title": "评分组件支持 allowHalf 半星",
|
||
"motivation": "评分只有整数档:商品 4.5 星、服务 3.5 分这类半档表达不了,调用方只能取整或自己换别的组件;点星也只能选整颗,左半区白白浪费",
|
||
"acceptance": "RateProps 新增 allowHalf(缺省整数):点击星标左半区记 0.5 分、右半区整颗,键盘步进同为 0.5(值按 0.5 量化夹取),悬停位置实时预览半格填充(左半亮右半灭走渐变裁字),value 信号可写入 x.5;文档参数表 / api 说明 / 手把手与 llms-full.txt 同步;npm run check 全绿",
|
||
"notes": "自补:组件能力补齐;命中值与键盘步进共用 0.5 量化,不改信号语义",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g123",
|
||
"title": "收尾刷新变更日志",
|
||
"motivation": "g118 之后又落了 10 次提交(textField 字数统计、rate 半星等),changelog:check 已报漂移",
|
||
"acceptance": "npm run changelog 重新生成(319 提交),changelog:check 一致(提交本条后按约定再差一条,属正常);npm run check 全绿",
|
||
"notes": "自补:发版前刷新步骤;本次唤起收尾轮",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g124",
|
||
"title": "checkbox 补 indeterminate 半选态",
|
||
"motivation": "全选/子项联动只能表达「全勾」与「全不勾」:部分选中时全选框没有任何视觉区分,dataTable 内部的全选三态也是包私有实现,独立 checkbox 场景(树形勾选、批量列选择)用不上",
|
||
"acceptance": "CheckboxProps 新增 indeterminate(布尔或信号):同步到原生 input.indeterminate 属性,accent-color 自动渲染横杠,读屏播报 mixed;不改变 checked 值与点击语义(点一下即回全选);文档参数表 / api 说明 / 手把手与 llms-full.txt 同步;npm run check 全绿",
|
||
"notes": "自补:组件能力补齐;零新增 CSS(accent-color 原生覆盖 :indeterminate)",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g125",
|
||
"title": "开关补 loading 加载态",
|
||
"motivation": "开关切换常伴随后端写入(改配置、提交设置):请求在途时用户可以连续拨动,最后一次点击覆盖前面的状态,业务方只能自己在 onChange 里加标志位手动锁",
|
||
"acceptance": "SwitchProps 新增 loading(布尔或信号):加载中锁定交互(disabled 同值语义)、滑块换成转圈(reduced-motion 静态化为实心环)、input 挂 aria-busy;与 disabled 同时生效且不双写竞争;文档参数表 / api 说明 / 手把手与 llms-full.txt 同步;npm run check 全绿",
|
||
"notes": "自补:组件能力补齐;loading 接管时 disabled 不再走 h() 绑定,单一 effect 写入避免竞争",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g126",
|
||
"title": "数字输入补 precision 小数位",
|
||
"motivation": "金额、比例、权重这类小数场景:step 0.1 步进会累积出 0.30000000000000004 这样的浮点尾差直接写进信号,显示位数也无法约束,调用方只能自己在 onChange 里 toFixed 再写回",
|
||
"acceptance": "InputNumberProps 新增 precision(缺省不处理):写回与显示都按 toFixed(p) 归一(写回量化 + 输入框定长显示),步进浮点尾差消除;min/max 夹取语义不变;文档参数表 / api 说明 / 手把手与 llms-full.txt 同步;npm run check 全绿",
|
||
"notes": "自补:组件能力补齐;量化收敛在 emit/sync 单点,不改夹取与连发逻辑",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g127",
|
||
"title": "补充长表单编辑页组合配方",
|
||
"motivation": "affix 贴底、form 汇总条、hint、maxCount、saving 三处锁定这些能力都是本轮及此前几轮陆续落地的,但「长表单编辑页怎么拼」没有一篇端到端指导,Agent 与新人仍要自己试错组合",
|
||
"acceptance": "recipes.md 新增「配方 6:长表单编辑页(吸底操作条 + 提交锁定)」:affix position bottom 固定操作条、form 聚合校验与汇总条、同一 saving 信号锁按钮/开关/请求出口、maxCount 与 rules max 同源约束;npm run docs 后 llms-full.txt 出现该配方;npm run check 全绿",
|
||
"notes": "自补:文档完善;只写用法不碰实现,配方随 docs 注入 llms-full",
|
||
"status": "done",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g128",
|
||
"title": "收尾刷新变更日志",
|
||
"motivation": "g123 之后又落了 10 次提交(rate 半星、checkbox 半选、开关 loading、precision、配方 6 等),changelog:check 已报漂移",
|
||
"acceptance": "npm run changelog 重新生成(329 提交),changelog:check 一致(提交本条后按约定再差一条,属正常);npm run check 全绿",
|
||
"notes": "自补:发版前刷新步骤;本次唤起收尾轮,顺带提交 g127 漏带的 llms-full.txt",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g129",
|
||
"title": "新增排版文本组件 typography",
|
||
"motivation": "文档类页面(详情、说明、条款)目前只能手搓 h/p + 内联样式,标题层级、语义色、多行省略、复制都没有统一入口",
|
||
"acceptance": "typography 支持 variant(title/text/paragraph) + level + type + 装饰位(strong/underline/delete/mark/code) + align + ellipsis 多行截断 + copyable;标题出语义 h1-h5;样式只消费 --ua-*;manifest/docs/README/demo/llms-full 同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:组件补充方向",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g130",
|
||
"title": "新增栅格容器 grid",
|
||
"motivation": "页面骨架只能靠 space 与手写 flex,24 栅格、列间距、响应式断点缺失,示例页布局各写一套",
|
||
"acceptance": "grid 支持 columns 固定列数与 min 走 auto-fit 自适应列宽、gutter 统一列间距、align 交叉轴对齐、dense 紧凑填充;窄屏自动降为单列;样式只消费 --ua-*;manifest/docs/README/demo/llms-full 同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:组件补充方向(原设想 row/col 24 栅格,实施改为单容器 grid —— auto-fit 已覆盖响应式,跨列需求交给子项自身宽度,少一层抽象)",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g131",
|
||
"title": "新增悬浮操作按钮 floatButton",
|
||
"motivation": "backTop 只能回顶,页面里「新建 / 帮助 / 客服」这类常驻悬浮入口没有统一件,各处自己 fixed 定位",
|
||
"acceptance": "floatButton 固定右下角,支持 icon/label/tooltip/badge/点击回调与 position 偏移,键盘可达;样式只消费 --ua-*;文档与演示同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:组件补充方向",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g132",
|
||
"title": "@提及输入补 mentions 组件",
|
||
"motivation": "评论 / 协作场景要 @ 选人,目前只能 textarea + 自己接 autoComplete,光标定位与插入逻辑重复实现",
|
||
"acceptance": "mentions 在 @ 触发后按光标位置弹候选,↑↓/Enter/Tab 选择、Esc 关闭,选中插入文本并回调 onSelect;受控 value 信号;样式只消费 --ua-*;文档与演示同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:组件补充方向",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g133",
|
||
"title": "树形选择补 treeSelect 组件",
|
||
"motivation": "tree 与 select 都在,但「可搜索的层级下拉选择」缺位,级联选择 cascader 不适配任意深度懒加载场景",
|
||
"acceptance": "treeSelect 点击开弹层、支持搜索过滤、单选/多选、父子联动、清空,弹层沿用 overlay 的 Esc 栈与外部点击收起;样式只消费 --ua-*;文档与演示同步;npm run check 全绿",
|
||
"status": "done",
|
||
"notes": "自补:组件补充方向",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g134",
|
||
"title": "组件计数自动同步 ua sync-counts",
|
||
"motivation": "新增组件要手改 README 标题 / README 包说明 / AGENTS / ARCHITECTURE 四处数字,本轮四次新增每次都靠人工替换;且 README 标题「共 N 个」此前不在 verify 正则里,漏改不报错",
|
||
"acceptance": "新增 ua sync-counts(幂等,无变化不写盘)把三份文档的「N 个组件 / N 个 DOM 组件 / 共 N 个」统一改写为清单实际数量;verify 的计数正则覆盖 README 标题形态并提示修法;npm run check 全绿",
|
||
"notes": "自补:构建/门禁工具链改进(实测把 README 标题改成 61 后 verify 能报行号,sync-counts 一键修回)",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g135",
|
||
"title": "表单支持多列布局 columns",
|
||
"motivation": "字段多的编辑页只能一列往下堆,长表单要滚很久;页面里已有 grid,form 却没用上,调用方只能自己拆成多个 form(校验被割裂)",
|
||
"acceptance": "form 新增 columns(1/2/3),>1 时字段走 grid 铺列、窄屏自动单列、按钮区始终整行;单向依赖(form 复用 grid);manifest props/steps 与 demo 同步;npm run check 全绿",
|
||
"notes": "自补:既有组件可用性细节",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g136",
|
||
"title": "新增链接组件 link",
|
||
"motivation": "页面里的 a 标签各写各的样式:站外链接普遍漏 rel=noopener、没有 ↗ 提示,读屏也不知道开了新窗口;禁用态要么当纯文本要么还能点",
|
||
"acceptance": "link 支持 href/label/target/external/muted/disabled/onClick,站外自动补 ↗ 与 rel 并播报新窗口,禁用去 href 保留 aria-disabled;样式只消费 --ua-*;文档与演示同步;npm run check 全绿",
|
||
"notes": "自补:组件补充方向",
|
||
"status": "done",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g137",
|
||
"title": "演示页补暗色主题开关",
|
||
"motivation": "tokens 里有 [data-theme=dark] 整套令牌,但演示页从未切换过:暗色令牌长期无人验证,页面自有 --page-* 变量也只跟系统偏好、不跟显式主题",
|
||
"acceptance": "演示页头部提供暗色主题开关(写 html[data-theme],localStorage 记忆,初值跟随系统);--page-* 变量响应 data-theme,媒体查询只在未显式指定时生效;npm run check 全绿",
|
||
"notes": "自补:演示页完善",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g138",
|
||
"title": "日期选择支持区间模式",
|
||
"motivation": "筛选条件几乎都要「起止日期」,datePicker 只有单日:调用方只能并排放两个选择器,用户看不出选了什么区间,也拿不到排序保证",
|
||
"acceptance": "datePicker 新增 range/end/onRangeChange:首点定起点不收弹层、次点定终点并排序,区间内部有底色;文档 props/steps 与演示同步;npm run check 全绿",
|
||
"notes": "自补:既有组件可用性细节",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g139",
|
||
"title": "提示气泡支持左右方位",
|
||
"motivation": "tooltip 只有上下两向:竖排工具栏、贴右边的内容只能硬翻,left/right 全靠调用方自己补样式;position.ts 的 flip 也只认上下",
|
||
"acceptance": "position 新增 flipSide(四向判定,水平按宽度算左右空间),tooltip placement 支持 left/right 并复用自动翻转;CSS 四向定位 + 出场位移分离;文档 props/steps 与演示同步;npm run check 全绿",
|
||
"notes": "自补:既有组件可用性细节",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g140",
|
||
"title": "表格支持整行点击",
|
||
"motivation": "「点行进详情」是表格最常用交互,dataTable 只能把跳转塞进某一列的按钮:点击区域小、键盘不可达,行本身对读屏也只是文本",
|
||
"acceptance": "dataTable 新增 onRowClick:传了则该行 tabindex=0 并响应点击 / Enter / 空格,未传时行为与现在完全一致(不进 Tab 序列);文档 props/steps 与演示同步;单文件仍 ≤200 行;npm run check 全绿",
|
||
"notes": "自补:既有组件可用性细节(行数恰好压到 200 行上限,靠合并注释行达标)",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g141",
|
||
"title": "通知支持四角停靠",
|
||
"motivation": "notification 只能堆在右下角,与抽屉 / 悬浮按钮抢位置;页面里已有 toast 占右上,通知没有别处可去",
|
||
"acceptance": "notification 新增 placement(四个角),每角独立容器与 3 条上限,顶部角落新通知贴边出现、旧的往下让;文档 props/steps 与演示同步;npm run check 全绿",
|
||
"notes": "自补:既有组件可用性细节",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g142",
|
||
"title": "间距容器支持分隔符 split",
|
||
"motivation": "「A · B · C」这类一行多段信息(筛选摘要、面包屑式路径)只能手写 span 分隔符再逐个调 margin,gap 与分隔符混用后间距不均,读屏还会念出「·」",
|
||
"acceptance": "space 新增 split:仅在 2 个以上子元素间插入分隔符,分隔符 aria-hidden、弱化色、不可选中;文档与演示同步;npm run check 全绿",
|
||
"notes": "自补:既有组件可用性细节",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g143",
|
||
"title": "页签栏支持右侧操作区 extra",
|
||
"motivation": "「新建 / 设置」这类页签级操作只能塞进页签数组或浮在页签栏外,垂直不对齐、分隔线断掉;调用方还得自己包一层 flex",
|
||
"acceptance": "tabs 新增 extra:与页签同一行、共用一条分隔线,不传时 DOM 结构不变(纯增量);文档 props/steps 与演示同步;npm run check 全绿",
|
||
"notes": "自补:既有组件可用性细节",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g144",
|
||
"title": "新增头像组组件 avatarGroup",
|
||
"motivation": "协作列表 / 评论头部要展示参与人,并排 avatar 占横向空间且没有「还有 N 人」的表达;调用方各自用 margin 叠放,切口与层级都不一致",
|
||
"acceptance": "avatarGroup 支持 items(name/src/variant)、max 折叠为 +N、size 与 avatar 对齐;整组 title 列全部姓名、+N 有可访问名;样式只消费 --ua-*;文档与演示同步;npm run check 全绿",
|
||
"notes": "自补:组件补充方向",
|
||
"status": "done",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g145",
|
||
"title": "滑块支持刻度标注 marks",
|
||
"motivation": "0-100 的滑块看不出档位含义,用户只能看右侧数字猜;调用方要在轨道下标 0/50/100 得自己量宽度算百分比",
|
||
"acceptance": "slider 新增 marks(value/label),按 min-max 换算百分比绝对定位、随宽度自适应;轨道包一层不影响右侧数值;刻度 aria-hidden;文档与演示同步;npm run check 全绿",
|
||
"notes": "自补:既有组件可用性细节",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g146",
|
||
"title": "进度条支持环形形态",
|
||
"motivation": "看板与上传卡片普遍要环形进度,progress 只有线性条:调用方只能自带 SVG 并对齐语义色与百分比文字",
|
||
"acceptance": "progress 新增 type=line|circle,环形走 createElementNS 的 SVG 双圆 + dashoffset,中间显示百分比、aria-label 拼名称与数值,variant 换弧色;linear 行为不变;文档与演示同步;npm run check 全绿",
|
||
"notes": "自补:既有组件可用性细节(坑:h() 用 createElement 造不出可渲染 SVG,必须 createElementNS)",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g147",
|
||
"title": "补三条组合配方(筛选栏/评论/详情页)",
|
||
"motivation": "本轮新增的 treeSelect、datePicker range、mentions、avatarGroup、typography、grid 只有参数表,Agent 拿到组件却不知道该怎么拼;recipes.md 还停在 6 条",
|
||
"acceptance": "recipes.md 补配方 7-9(筛选栏、评论输入、详情页排版),只消费对外 API,随 npm run docs 进入 llms-full.txt;npm run check 全绿",
|
||
"notes": "自补:Agent 文档完善",
|
||
"status": "done",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g148",
|
||
"title": "MCP 暴露组合配方检索(list_recipes / get_recipe)",
|
||
"motivation": "recipes.md 已有 9 条跨组件配方,但只写在文档里:Agent 通过 MCP 只能查单组件参数,拿不到「怎么拼」,容易各自造轮子或漏掉约定。",
|
||
"acceptance": "ua mcp 新增 list_recipes(id/title/components)与 get_recipe(骨架代码 + 要点 + 用到的组件)两个工具;配方解析复用 recipes.md 单一来源;verify 增加配方结构校验(编号连续、每条有代码块与要点、有通用约定段);AGENTS/README/CLI 清单文档同步。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g149",
|
||
"title": "CLI 补 ua search(关键词找组件 + 拼错给相近 id)",
|
||
"motivation": "组件已达 67 个,只有 ua list 全量平铺与 ua info 精确查询:不记得 id 时只能肉眼扫列表,拼错则只回一句 not found。",
|
||
"acceptance": "ua search <关键词> 按 id/标题/props 名/步骤匹配并排序输出,支持 --json;ua info 与 search 未命中时给出编辑距离 ≤3 的相近 id;usage 与 CLI 清单 steps、README、AGENTS 同步。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g150",
|
||
"title": "ua info 反查组件出现在哪些配方",
|
||
"motivation": "配方与组件是两套入口:查完 props 往往还要自己判断「这组件平时和谁一起用」,而 recipes.md 里已有答案却没接上。",
|
||
"acceptance": "ua info <组件id> 末尾列出包含该组件的配方 id 与标题(无命中不追加空行);--json 输出增加 recipes 字段;MCP get_component 组件级返回同步带 recipes。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g151",
|
||
"title": "verify 校验 MCP 工具清单三处一致",
|
||
"motivation": "MCP 工具从 4 个扩到 6 个时,README/AGENTS/CLI 清单靠手改;漏一处就会让 Agent 读到过期的工具名,而 verify 当时不管这块。",
|
||
"acceptance": "MCP_TOOL_NAMES 为单一来源,cmdMcp 启动时自证注册表与之一致;verify 检查 README/AGENTS/CLI 清单逐个写出工具名,缺失即报错并指出漏了哪个(已负向实测)。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g152",
|
||
"title": "ua list 增加组件全览模式",
|
||
"motivation": "ua list 只列 5 个包,67 个组件的 id 只能靠 ua search 猜关键词去找;没关键词时缺少「一次扫全量」的入口。",
|
||
"acceptance": "ua list 每行带上组件数;ua list --components 按包分组列出 id / 标题 / 演示锚点并给出总数与后续命令提示,原有无参输出保持可用。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g153",
|
||
"title": "ua search 支持多关键词与脚本退出码",
|
||
"motivation": "单一关键词只能粗筛:想找「日期区间」时搜日期会连 calendar/timeline 一起返回;且未命中仍退 0,脚本里判断不了。",
|
||
"acceptance": "ua search a b 取各词命中的最弱档做 AND 过滤仍保持 id>标题>props>步骤 的排序;未命中输出相近建议并 exit 1;无参数打印用法。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g154",
|
||
"title": "MCP search_components 补组件级命中",
|
||
"motivation": "原实现只在包级字段(name/description/tags/api.exports)里搜,命中后只返回包:Agent 搜「日期」得到 @ui-arch/ui,还得再猜组件 id。",
|
||
"acceptance": "返回 { packages, components } 两级结构,components 按 id/标题/props 名命中并带 package 字段;空 query 与无命中都抛明确错误;工具描述同步。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g155",
|
||
"title": "llms.txt 补配方目录 + 修正 MCP 工具清单描述",
|
||
"motivation": "Agent 常只读 llms.txt 速览,但速览里完全没有配方入口;同时 cli 包导出描述里只写了 3 个 MCP 工具,与实际的 6 个不符。",
|
||
"acceptance": "ua index 在 llms.txt 末尾输出配方目录(id / 标题 / 要点数)并指明三种取法;cli 清单的 mcp 导出描述与 MCP_TOOL_NAMES 一致。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g156",
|
||
"title": "ua tokens 支持按名字过滤",
|
||
"motivation": "21 个令牌全表打印后再肉眼找某一个,写样式时反复查多行;缺令牌名拼错也不报错。",
|
||
"acceptance": "ua tokens <子串> 只列匹配项并在末尾标注匹配词,--json 同步过滤;无匹配时给出总数并以 1 退出。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g157",
|
||
"title": "补配方 10:暗色主题切换",
|
||
"motivation": "令牌层早就支持 [data-theme=dark],但配方里没有任何一条说清「怎么切、初值怎么定、原生控件为何仍是白底」,实践只能靠翻令牌表猜。",
|
||
"acceptance": "recipes.md 新增配方 10(切 data-theme + 同步 color-scheme + 初值先读 localStorage),verify 的配方结构校验通过,llms-full 与 MCP get_recipe 10 可取到骨架。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g158",
|
||
"title": "日期选择支持快捷区间预设",
|
||
"motivation": "仪表盘类界面里「最近 7 天 / 最近 30 天」是高频刚需,现在调用方只能在弹层外自己摆按钮再算日期区间,算完还得手写 value/end 两个信号,重复且易错。",
|
||
"acceptance": "datePicker 新增 presets 入参(仅区间模式渲染):每项支持 days 相对今天或 from/to 绝对日期,点击即写入 value/end、按 min/max 钳制并收起;演示页区间示例带三档预设;manifest props 表与步骤、llms-full 同步;npm run check 全绿。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g159",
|
||
"title": "多选下拉支持标签折叠",
|
||
"motivation": "multiSelect 的 max 放开后标签会把输入区挤到换行,窄栏(筛选栏 / 表单侧栏)里选中五六个就撑破布局,调用方只能自己截断数组、却因此拿不到真实值。",
|
||
"acceptance": "multiSelect 新增 maxTagCount:前 N 枚标签照常渲染与删除,其余折成虚线「+N」(title 给全量、点击展开弹层,含 aria-label);演示页加一枚预置 3 项的折叠实例;manifest props 表与步骤、llms-full 同步;npm run check 全绿。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g160",
|
||
"title": "滑块支持双滑块区间",
|
||
"motivation": "价格 / 数值区间筛选是电商与报表的基本控件,此前只能拼两个单值 slider,视觉上两条独立轨道、还得自己保证下限不超过上限,调用方到处写同样的 clamp。",
|
||
"acceptance": "slider 新增 range / end / onRangeChange:两条原生 range 叠轨、只有拇指可命中,强调色画出已选段,越界自动压平保证 low ≤ high,右侧显示「低 ~ 高」;单值路径不变;manifest props 表与步骤、llms-full 同步;npm run check 全绿。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g161",
|
||
"title": "通知支持同 key 原地更新",
|
||
"motivation": "异步任务(上传/导出/同步)要把一条通知从 0% 刷到 100%,此前只能再调一次 notification,结果右上角堆出三条互不相干的卡,MAX_STACK=3 还会把别的通知挤掉。",
|
||
"acceptance": "notification 新增 key 入参:同 key 二次调用原地改标题 / 描述 / 语义色并返回同一句柄;句柄新增 update(partial),close 时释放 key 登记;演示页加三拍进度演示;manifest props 表与步骤、llms-full 同步;npm run check 全绿。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g162",
|
||
"title": "门禁补暗色令牌齐全校验",
|
||
"motivation": "暗色主题此前只靠人眼看:新增一个 --ua-color-* 忘了在 [data-theme='dark'] 里给值,暗色下就静默沿用亮色(如白底深字条突然发白),没有任何机制拦。",
|
||
"acceptance": "verify 新增两项校验:每个 --ua-color-* 必须在暗色块有覆盖值;暗色块里的变量必须先在 :root 定义过(防改名漏改);ua tokens 对缺暗色的颜色令牌追加「缺暗色」标注;AGENTS.md 门禁说明同步;npm run check 全绿,且临时抽掉一条暗色值时 verify 确实报错。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g163",
|
||
"title": "留痕校验补编号与时间线约束",
|
||
"motivation": "上一实例曾把新条目误插到旧条目后面,把一条 done 写成两条,还出现过手写时间戳——这些都是「结构错但内容看起来对」的漂移,verify 当时完全看不出来。",
|
||
"acceptance": "verify 新增:backlog id 不重复、g 编号严格递增、同一 id 只能有一条 done 留痕、留痕 ts 必须带 +08:00、时间线不回退、不落在未来(5 分钟容差);AGENTS.md 与 verify 成功文案同步;负向注入(复制条目 + 手写无偏移时间戳)四类错误全部报出,复原后全绿。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g164",
|
||
"title": "描述列表支持竖排与标题操作区",
|
||
"motivation": "详情页右侧窄栏里,字段名横排会把值挤成两三行断字;标题行想放个「刷新 / 更新时间」也没位置——只能在外面另拼一个 flex 头。",
|
||
"acceptance": "descriptions 新增 layout(vertical 把字段名挪到值上方,bordered 时自动去掉标签分隔线与底纹)与 extra(标题行右侧内容);演示页加竖排 + 操作区实例;manifest props 表与步骤、llms-full 同步;npm run check 全绿。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g165",
|
||
"title": "步骤条支持竖向排列",
|
||
"motivation": "审批流 / 物流轨迹在侧栏里只能横排,三步以上就被挤成两行、连接线错位;调用方只能退回自己拼时间线,丢了 done/current 三态语义。",
|
||
"acceptance": "stepper 新增 direction:vertical 时圆点成一列、连接线走圆点下方、末步不画线、已完成段用主色;演示页加独立信号的竖向实例;manifest props 表与步骤、llms-full 同步;npm run check 全绿。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g166",
|
||
"title": "下拉选项支持分组标题",
|
||
"motivation": "技术栈 / 部门 / 城市这类长候选集只能平铺,用户得一行行扫;分组要么拆成多个 select,要么在 label 里塞「【前端】Vue」这类假标题。",
|
||
"acceptance": "OptionItem 与 CheckOption 新增 group:select 在组首插灰色小标题(段间分隔线)、整组过滤无命中时标题隐藏;multiSelect 候选同步支持且小标题不占键盘下标;演示页加分组下拉实例;manifest 的 options 描述与步骤、llms-full 同步;npm run check 全绿。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g167",
|
||
"title": "弹窗支持内置页脚与异步确认",
|
||
"motivation": "「取消 + 确定」这两个按钮几乎每个确认框都要手拼一遍,异步提交时还得自己管「处理中」禁用与成功后收窗,各处写法不一。",
|
||
"acceptance": "modal 新增 confirmText / cancelText / onConfirm:不传 footer 时渲染内置按钮组(footer 仍优先),onConfirm 返回 Promise 时按钮禁用并显示「处理中…」,成功自动收窗、失败保持打开;演示页把确认弹窗改成异步确认;manifest props 表与步骤、llms-full 同步;npm run check 全绿。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g168",
|
||
"title": "补配方 11:数据看板筛选区",
|
||
"motivation": "本轮补的区间滑块、日期预设、分组下拉都是筛选区零件,但配方里没有一条把它们拼起来;Agent 拿到零件也不知道该用 computed 派生查询而不是各存一份状态。",
|
||
"acceptance": "recipes.md 新增配方 11(grid 三列放 slider/datePicker/select + dataTable),要点写清「信号单一来源」「区间控件自带 clamp」「group/presets 的取舍」;verify 配方结构校验通过;llms-full.txt 与 MCP get_recipe 可取到。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g169",
|
||
"title": "表单字段支持跨列",
|
||
"motivation": "columns: 2 的表单里,多行备注 / 地址这类字段只能各占一格,看上去被压成半宽;想整宽只能把 form 拆成两个再手拼,校验聚合也就断了。",
|
||
"acceptance": "formItem 新增 span:字段在栅格里占 N 列;grid 窄屏单列时用 !important 忽略跨列,避免撑出横向滚动;演示页两列表单加整宽备注;manifest 的 formItem 参数表与步骤、llms-full 同步;npm run check 全绿。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g170",
|
||
"title": "分页器支持极简模式与单页隐藏",
|
||
"motivation": "表格工具栏里放完整页码会占掉半行;只有一页时又留一个灰掉的「1」占位,两种场景都只能靠调用方自己条件渲染。",
|
||
"acceptance": "pagination 新增 simple(只留前后箭头 + 「当前 / 总页」文字,带 aria-live)与 hideOnSinglePage(单页整块 hidden);演示页各加一例;manifest props 表与步骤、llms-full 同步;npm run check 全绿。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g171",
|
||
"title": "刷新 CHANGELOG 与配方目录",
|
||
"motivation": "CHANGELOG 由提交史生成、不进 check(它包含每个提交自身,提交后必然差一条),只能作为发版前刷新;本轮 14 次迭代后已落后 30 余条,llms.txt 的配方目录也漏了配方 11。",
|
||
"acceptance": "npm run changelog 重生成到当前提交史(400 提交);llms.txt 补配方 11 目录行并在此后随 docs 归档;CHANGELOG 内容与 git log 一致(npm run changelog:check 通过)。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g172",
|
||
"title": "列表命令支持 JSON 输出",
|
||
"motivation": "ua info 早就有 --json,但 ua list 只能打印文本,脚本与 Agent 想拿「包 + 组件 id」清单只能抓 stdout 再正则,容易随文案变化失效。",
|
||
"acceptance": "ua list --json 输出 {name, version, type, description, components[]} 数组,--components 仍逐组件展开;CLI 清单 exports 与 AGENTS.md 的用法行同步;npm run check 全绿(含 lint-iterations)。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g173",
|
||
"title": "上传图片显示缩略图",
|
||
"motivation": "选完图片只看到文件名,用户没法确认选的是哪张——上传头像 / 凭证照这类场景必须点开本地文件核对,体验很别扭。",
|
||
"acceptance": "upload 对 image/* 文件渲染 28px 缩略图(object-fit: cover),对象 URL 按 File 缓存、文件离场即 revoke;非图片保持文件名 + 体积;manifest 步骤、llms-full 同步;npm run check 全绿。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g174",
|
||
"title": "时间线支持双侧交替",
|
||
"motivation": "里程碑 / 项目历程这类内容用单侧时间线时,长正文会把右侧挤成一条窄柱;做左右交替得自己包两层栅格,pending 虚节点还容易错位。",
|
||
"acceptance": "timeline 的 mode 增加 alternate:轴线居中、条目按奇偶分列左右、圆点贴中线、窄屏自动退回单侧(pending 虚节点参与交替计数);演示页加里程碑实例;manifest 参数类型与步骤、llms-full 同步;npm run check 全绿。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g175",
|
||
"title": "确认气泡支持异步确认",
|
||
"motivation": "删除 / 归档的行内操作基本都要打后端,但 popconfirm 的 onConfirm 是同步签名:点确定立刻收起,请求失败时气泡已经没了,用户只能看到一条报错、得重新点开。",
|
||
"acceptance": "popconfirm 的 onConfirm 返回 Promise 时:气泡保持展开、确认按钮变「处理中…」并禁用,resolve 后收起、reject 后复原可重试;类型放宽为 () => unknown(普通回调仍先收起再执行),modal 的 onConfirm 同步放宽;演示页加异步归档实例;manifest、llms-full 同步;npm run check 全绿。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g176",
|
||
"title": "ua search 覆盖参数说明并标出命中字段",
|
||
"motivation": "Agent 找组件时给的往往是需求词(如「处理中」「省略号」「归档」),这些词只出现在参数说明或步骤里;原实现只拼参数名,说明文字搜不到,明明有组件却回 no match,Agent 只能改用 list 全量翻。",
|
||
"acceptance": "search 按 id / 标题 / 参数名 / 参数说明 / 步骤五层打分排序,命中非 id 标题时行尾标出命中字段(如「← 参数说明含『处理中』」),--json 附带 matched;MCP search_components 复用同一字段表,工具描述与 AGENTS.md、tools manifest 同步;npm run check 全绿。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g177",
|
||
"title": "补 ua recipes 子命令,配方不再只能靠 MCP 取",
|
||
"motivation": "组合配方(跨组件拼装骨架)原本只有 MCP 的 list_recipes / get_recipe 能读,没注册 MCP 或纯 CLI 场景下 Agent 只能翻 recipes.md 原文;另外 CLI 与 MCP 各写了一份「配方里用到哪些组件」的抽取逻辑,口径容易漂移。",
|
||
"acceptance": "ua recipes 列出编号/标题/用到的组件,ua recipes <编号> 打印骨架代码与要点,--json 给脚本用;MCP 复用同一抽取函数;AGENTS.md 与 packages/tools/cli/ua.manifest.json 同步;npm run check 全绿。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g178",
|
||
"title": "verify 兜住「认不出组件」的配方",
|
||
"motivation": "配方骨架里的组件名如果拼错(如 cascader 写成 cascaderSelect),结构校验全都过——代码块在、要点在、编号连续,但 ua recipes 会把组件列成空表,Agent 拿到的是一份「没有依赖」的骨架,排查成本高。",
|
||
"acceptance": "ua verify 对每条配方检查代码块+正文是否至少认出一个已注册组件 id,认不出直接报错并指名配方编号与标题;负向自检(临时插一条用未注册组件名的配方)确认会拦;AGENTS.md 门禁说明同步;npm run check 全绿。",
|
||
"notes": "",
|
||
"status": "done",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g179",
|
||
"title": "弹层阴影语义化:剩余字面阴影归入 elevation 四档",
|
||
"motivation": "阴影已收敛出四档令牌,但仍有主题色投影(color-mix text/accent)与状态色环以字面值散落在弹层、气泡、选中态里,同名层级在不同组件用不同数值,观感不齐且改不动。",
|
||
"acceptance": "ui.css 中 box-shadow 的 px 字面值全部归入 --ua-shadow-1..4 或语义色环(无主题色投影字面值);`ua audit:visual --json` 的 shadow-literal 计数相对 .ua/visual-baseline.json 至少减少 8 处并写入新基线;在 packages/skin/ui/ua.manifest.json 的 docs.intro 写明「下拉=shadow-2 / 浮层=shadow-3 / 弹窗=shadow-4 / 通知=shadow-4」对照表;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "主题色投影新增 shadow-accent / shadow-accent-strong 两档令牌(含暗色),文本系投影按「下拉=2 / 浮层=3 / 最高层=4」归档;shadow-literal 17→9(减 8 处),新基线 27 处已写入;manifest intro 补阴影对照表",
|
||
"domain": "visual"
|
||
},
|
||
{
|
||
"id": "g180",
|
||
"title": "内距令牌化:padding / gap 字面值降到基线以下",
|
||
"motivation": "间距只有 4/8/12/16 四档令牌,实际却大量写 6px/10px 这类中间值,同一类容器内距不统一,改密度只能全仓替换。",
|
||
"acceptance": "packages/design/tokens/tokens.css 补齐内距档位(新增 6px/10px 两档或把它们归并到既有档并在注释说明),tokens.json 同步;visual-rules 增加 space-literal 类(padding/gap/margin 的 px 字面值),迁移脚本同步规则并幂等;该类计数写入新基线且比首次统计少 30 处以上;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "新增半步内距档 space-05/15/25/35(2/6/10/14px,tokens.css+json 同步);visual-rules 新增 space-literal 第六类(迁移脚本与审计共用同一张表、幂等);首次统计 160 处,迁移 121 处后余 13 处,新基线 40 处",
|
||
"domain": "visual"
|
||
},
|
||
{
|
||
"id": "g181",
|
||
"title": "表单控件高度统一接入 control-h 三档",
|
||
"motivation": "控件高度令牌 --ua-control-h-sm/md/lg 已就位,但 button/textField/select/inputNumber 仍各自写死高度,同一行并排时高度不一致,也挡住「略放大提高可点面积」的落地。",
|
||
"acceptance": "ui.css 中 .ua-btn / .ua-input / .ua-select / .ua-input-number 的高度声明全部引用 var(--ua-control-h-*);visual-rules 增加 control-h-literal 类且计数为 0;apps/demo/main.ts 中存在一行并排的三档高度演示(sec 锚点内真实调用四个组件);npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "四个控件载体(ua-btn/ua-input/ua-select-trigger/ua-input-number-field)统一 height 走 control-h 三档;button/textField/select/inputNumber 新增 size 入参(sm/md/lg,is-sm/is-lg 类);步进器按钮 height:auto 豁免;control-h-literal 第七类规则(28/34/40px 保留给控件档位)计数 0;28px×5 与 40px×2 字面值归档位令牌;demo sec-inputnumber 加四组件三档并排行",
|
||
"domain": "visual"
|
||
},
|
||
{
|
||
"id": "g182",
|
||
"title": "暗色主题阴影与焦点环适配",
|
||
"motivation": "暗色块只覆盖颜色,弹层阴影沿用亮色主题的低透明度黑投影,暗底上几乎看不出层级;焦点环在暗色下对比也不足。",
|
||
"acceptance": "[data-theme='dark'] 覆盖 --ua-shadow-1..4(更高黑度)与 --ua-focus-ring 两个槽位;ua verify 增加一条校验:暗色块缺 shadow / focus 覆盖即报错;ua tokens 输出的暗色列能看到这 6 个令牌的暗色值;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "暗色块补 --ua-focus-ring / --ua-focus-ring-inset(透明度上调补对比),shadow-1..4 与 accent 两档人类上游已备;verify 暗色齐全校验扩展到 --ua-shadow-* / --ua-focus-* 前缀(负向自检删除 shadow-1 暗色覆盖已被拦);ua tokens 暗色列可见全部 6 个令牌的暗色值;tokens.json focus 组补 light/dark 结构",
|
||
"domain": "visual"
|
||
},
|
||
{
|
||
"id": "g183",
|
||
"title": "字重与行高统一到三档令牌",
|
||
"motivation": "标题、正文、辅助文字的字重与行高全靠各组件手写,同一层级的标题在不同弹窗里字重不同,多行文本行距忽松忽紧。",
|
||
"acceptance": "visual-rules 增加 weight-literal 与 leading-literal 两类(font-weight / line-height 的字面值),迁移脚本把字面值改为 --ua-weight-* / --ua-leading-*;两类计数归零并写入新基线;标题/正文/辅助三档在注释里写明归属;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "visual-rules 新增 weight-literal / leading-literal 两类(第八、九类);字重映射 400/500/600/700 → normal/medium/semibold/bold(补 bold 档),行高 unitless 就近收敛到 none/tight/normal(补 none 档,px 行高按图形对齐豁免);两类 36+36 处全部归零并写新基线 40 处;tokens.css 注释标明标题/正文/辅助三档归属",
|
||
"domain": "visual"
|
||
},
|
||
{
|
||
"id": "g184",
|
||
"title": "层级令牌落地:z-index 字面值归零",
|
||
"motivation": "--ua-z-dropdown/sticky/overlay/modal/toast 五档已定义但无人使用,实际仍是各组件写 100/1000/9999,弹层互相盖住的问题只能靠试数值解决。",
|
||
"acceptance": "visual-rules 增加 z-literal 类;迁移脚本把 ui.css 中全部 z-index 字面值替换为 var(--ua-z-*);该类计数为 0 并写入新基线;ua tokens 能看到五档层级;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "z-literal 第十类规则(组件内 z:1/2 微排序豁免,同 1px 边框惯例);按选择器把 20 处全局浮层字面值归入五档:下拉/气泡类 20/30/40→dropdown,fab→dropdown,toast/notice 宿主→toast,affix/backtop→sticky,tour/模态抽屉遮罩→overlay,image 遮罩→modal;迁移脚本对下拉类 20/30/40 提供幂等自动迁移;计数归零并写新基线 40 处",
|
||
"domain": "visual"
|
||
},
|
||
{
|
||
"id": "g185",
|
||
"title": "边框细节统一到 subtle 与基础色",
|
||
"motivation": "分割线、输入框、卡片边框混用基础边框色与更深的黑边,1px 线在不同组件上粗细观感不一,密集表格里分割线过重。",
|
||
"acceptance": "分割线改用 --ua-border-subtle、输入框与卡片边框用 --ua-color-border,ui.css 中不再出现硬编码黑边(rgba(0,0,0,…) 作为边框值);visual-rules 增加 border-literal 类且计数为 0;表格与输入框在 demo 中肉眼无粗细跳变;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "border-literal 第十一类规则(border/border-color 色值字面量,纯黑 rgba 边可幂等迁移到基础边框色);19 处 1px 分割线统一改走 --ua-border-subtle(表格行线、卡片页脚、弹窗/抽屉页头页脚、列表项、选项卡底边、折叠面板与步骤条连接线、分隔线组件),组件轮廓仍用 --ua-color-border;border-literal 计数 0 并写新基线 40 处;顺带修正 manifest 里「五类/十组」陈旧表述",
|
||
"domain": "visual"
|
||
},
|
||
{
|
||
"id": "g186",
|
||
"title": "视觉回归抽查清单:六个代表组件的可勾选验收项",
|
||
"motivation": "视觉类改动只能靠人眼抽查,每次凭记忆看一遍,漏看是常态;把六个高频组件的观感要点固化成清单,后续视觉条目可直接复用。",
|
||
"acceptance": "在 ITERATION.md 或 packages/skin/ui/ua.manifest.json 增加《视觉回归抽查清单》,button / textField / select / modal / dataTable / toast 六个组件各 ≥3 条可勾选要点(合计 ≥18 条);清单条目必须覆盖边框、阴影、过渡、焦点环、暗色五项;ua verify 校验清单存在且 18 条要点齐全;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "清单落在 ITERATION.md《视觉回归抽查清单》:六个代表组件共 26 条可勾选要点(button 5 / textField 4 / select 4 / modal 5 / dataTable 4 / toast 4),每条带【边框/阴影/过渡/焦点环/暗色】维度标签;ua verify 新增 checkVisualChecklist(章节存在 + 六段齐全 + 每段 ≥3 + 合计 ≥18 + 五维度全覆盖 + 维度标签合法性),负向自检确认删段/降标签/条目不足都会报错;AGENTS.md 与 cli manifest 同步该职责",
|
||
"domain": "visual"
|
||
},
|
||
{
|
||
"id": "g187",
|
||
"title": "新增虚拟列表组件 virtualList",
|
||
"motivation": "长列表(万级流水、日志、消息流)用 list 全量渲染必然卡死,DOM 数量随数据线性增长是性能悬崖;组件库有 list 但没有虚拟化,调用方只能各写各的滚动窗口逻辑。(自补选题;g179–g186 已被人工视觉域条目占用,本条顺延取号)",
|
||
"acceptance": "新增 virtualList(固定行高、只渲染可视窗口 + overscan 缓冲条、rAF 合帧滚动重建、scrollTo 句柄越界钳制),10 处落点齐全(实现/类型/导出/样式/manifest/demo/README/计数/文档),万行 demo 常驻 DOM 只有窗口行数;npm run check 全绿。",
|
||
"notes": "自补:组件补充;rebase 到人工新推的视觉令牌/审计门禁上游后门禁全绿",
|
||
"status": "done"
|
||
},
|
||
{
|
||
"id": "g188",
|
||
"title": "新增命令面板组件 commandPalette(⌘K 唤起)",
|
||
"motivation": "68 个组件里缺「全局命令入口」这类高频交互:菜单要逐级点、autoComplete 只能选值不能执行动作,Agent 与键盘用户都没有一个「输入即缩小、回车就执行」的入口。",
|
||
"acceptance": "新增 commandPalette:open 信号驱动显隐、items 支持 group/hint/keywords 三层过滤、↑↓ 环形选择 + Home/End + 回车执行、Esc 走弹层栈只关最上层、开关均归还焦点、⌘K/Ctrl+K 可开关;样式只消费 --ua-* 令牌,禁止新增硬编码阴影/时长/字号;demo 新增可交互区块;npm run check 全绿且 audit:visual 计数不涨。",
|
||
"status": "done",
|
||
"notes": "新增 packages/skin/ui/src/commandPalette.ts(148 行)+ types 三接口 + ui.css 13 条规则(全令牌,含 prefers-reduced-motion 兜底);过滤看 label/hint/keywords 三层,高亮只切 class 不重建列表(aria-activedescendant 供读屏);Esc 复用 overlay 栈、滚动锁复用 lockScroll;demo 新增 sec-cmdk(按钮 + ⌘K 双入口);README 清单与「浮层」分组、ARCHITECTURE/AGENTS 组件数随 sync-counts 同步到 69;audit:visual 仍 40 处"
|
||
},
|
||
{
|
||
"id": "g189",
|
||
"title": "补配方 12:命令面板(⌘K 全局操作入口)",
|
||
"motivation": "commandPalette 刚入库,但「id 分发 / keywords 兜拼音 / onSelect 里开二次确认 / 多实例 hotkey 冲突」这些坑只有实现者知道;配方是 Agent 与新人复用组件的入口,缺一条就会各写一遍。",
|
||
"acceptance": "packages/tools/cli/recipes.md 增加配方 12(编号连续、含代码块与要点),代码块至少认出一个已注册组件 id;ua recipes 12 能取到骨架与要点;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "配方 12「命令面板(⌘K 全局操作入口)」:id 做分发键、label 只显示;keywords 塞拼音别名;同组连续才合并;二次确认交给 modal/popconfirm 而非面板内叠层;一页只留一个 hotkey;items 快照需重建。ua recipes 12 识别 commandPalette / modal / popconfirm / toast 四组件"
|
||
},
|
||
{
|
||
"id": "g190",
|
||
"title": "字号字面值归零:补展示档与相对缩放档",
|
||
"motivation": "五档主轴只覆盖到 18px,剩下 5 处 22/26/34px 与大号字符图标、代码片段 0.92em、行内图标 0.85em 无令牌可用,只能写字面值;字号门禁因此长期停在 5 处,谁也不敢动。",
|
||
"acceptance": "tokens 增加 --ua-font-size-3xl/4xl/5xl(22/26/34px 展示档)与 --ua-font-size-scale-md/sm(0.92em/0.85em 相对缩放档),visual-rules 映射表同步;迁移后 font-size-literal 计数为 0 并写入新基线;ua tokens 能看到五个新令牌;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "字号令牌从 6 档扩到 11 档:3xl 22px(评分星等字符图形)/ 4xl 26px(统计主数值)/ 5xl 34px(空状态大图标)/ scale-md 0.92em(代码片段)/ scale-sm 0.85em(行内小图标,随文字缩放不建绝对档);迁移脚本按表幂等替换 5 处,font-size-literal 5→0,总计数 40→35 已写基线"
|
||
},
|
||
{
|
||
"id": "g191",
|
||
"title": "焦点环变体归零:补语义色环 / 光晕 / 选中环四档",
|
||
"motivation": "焦令牌只有强调色两档,评分星(警告色)、校验失败(错误色外扩环)、时间线脉冲(5px 4% 光晕)、色板选中(实色 2px)四处只能自绘,audit 的 focus-ring-variant 长期停在 4 处,也意味着语义色焦点在暗底上没有统一的可调点。",
|
||
"acceptance": "tokens 增加 --ua-focus-ring-warning / -danger / -pulse / -selected 四档(亮暗各一套,暗色块必须有覆盖),tokens.json 同步;ui.css 四处自绘环改走令牌;focus-ring-variant 计数为 0,总计数 35→27 并写入新基线;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "四档语义环:warning 25%(评分星)/ danger 18%(校验失败外扩)/ pulse 5px 4%(时间线呼吸光晕,暗色加倍 8%)/ selected 实色 2px(色板选中);暗色块四个都给了覆盖,verify 暗色齐全校验通过;替换后 focus-ring-variant 4→0,同时这 4 条不再计入 shadow-literal,总计数 35→27"
|
||
},
|
||
{
|
||
"id": "g192",
|
||
"title": "动效时长字面值归零:补更慢档与循环四档",
|
||
"motivation": "三档交互时长上限 0.25s,转圈 0.7/0.8s、扫光 1.4s、脉冲 1.6s、条纹 0.6s、进度条 0.35s 全部无处可归,只能写字面值;duration-literal 一直卡在 9 处,加载动画的节奏也没法统一调。",
|
||
"acceptance": "tokens 增加 --ua-duration-slower(0.35s 交互)与 --ua-duration-loop-fast/mid/slow/long(0.6/0.8/1.2/1.6s 循环),tokens.json 同步;visual-rules 增加循环档映射(仅在 animation + infinite 时启用)并扩展交互档到四档;duration-literal 计数为 0,总计数 27→18 并写新基线;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "交互时长三档→四档(新增 slower 0.35s,收 0.3/0.32/0.35 三处大跨度形变);循环四档 0.6/0.8/1.2/1.6s,0.7 与 0.8 并到中档、1.2 与 1.4 并到慢档;迁移脚本按「animation + infinite」判定走循环表,避免把交互过渡误归循环档;9 处全部归零,总计数 27→18"
|
||
},
|
||
{
|
||
"id": "g193",
|
||
"title": "阴影字面值归零:补描边族与断口令牌",
|
||
"motivation": "shadow-literal 剩下 5 处都不是投影,而是「用 box-shadow 画线」:粘性表头底部细线、日历今天的内框、色板/头像组的底色断口。它们没有令牌可用,只能写字面值,也让投影类目混进了非投影值。",
|
||
"acceptance": "tokens 增加描边族 --ua-shadow-hairline / inset-border / inset-accent 与断口 --ua-shadow-gap(亮暗各一套,暗色块必须有覆盖),tokens.json 同步;ui.css 五处改走令牌;shadow-literal 计数为 0,总计数 18→13 并写新基线;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "四档描边族:hairline(inset 0 -1px 0 border-subtle,用阴影画线不占高度)/ inset-border(1px 细内框)/ inset-accent(强调内框标今天)/ gap(0 0 0 2px bg 底色断口,头像组与角标各一处);暗色四档全部覆盖;shadow-literal 5→0,总计数 18→13,剩空间类 13 处"
|
||
},
|
||
{
|
||
"id": "g194",
|
||
"title": "审计 json 输出每类命中明细(行号 / 属性 / 值 / 提示)",
|
||
"motivation": "ua audit:visual --json 只给计数,排查「哪一行踩了规则」必须临时手写 node -e 调 scanSource —— 本轮迭代里这件事就重复了三次;Agent 与 CI 都拿不到可定位信息,棘轮报红时仍要人工全表搜索。",
|
||
"acceptance": "audit:visual --json 在 counts / baseline 之外增加 hits:每个类目一组 { line, prop, value, hint },空类目给空数组;人读模式与退出码不变;cli manifest 的 api 描述同步;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "--json 增加 hits(11 个类目齐全,空类目为空数组),每项含 line / prop / value / hint;实测 space-literal 13 条可定位到具体行与值;人读输出与棘轮退出码未改动,manifest 描述同步后 docs 已重生成"
|
||
},
|
||
{
|
||
"id": "g195",
|
||
"title": "内距字面值归零:视觉基线清零(11 类全 0)",
|
||
"motivation": "space-literal 剩 13 处,全部是「梯子里没有的零碎值」:3/5/7px 微调、13px 连接线对齐、22px 树缩进、28px 空态留白。它们让基线永远停在 13,也让「视觉零漂移」这个目标永远达不成。",
|
||
"acceptance": "tokens 补 --ua-space-6(24px 大面积留白)与 --ua-space-indent(22px 层级缩进);13 处按就近收敛或换用新令牌;space-literal 归零、总计数 13→0 并写入零基线;audit:visual 在零基线下能拦住任何新增字面值(负向自检);npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "13 处全部归位:3px 间隙→space-1(4)、5px 微距→space-15(6)、7px 页签→space-15(6)、13px 连接线→space-35(14,与圆点中心对齐)、28px 空态留白→新增 space-6(24)、22px 树缩进→新增 space-indent(22);合计 0 处,基线写为全 0(11 类),负向自检插一条 rgba 投影即报红并指出工作区未提交改动"
|
||
},
|
||
{
|
||
"id": "g196",
|
||
"title": "中性色阶地基:表面/文字/遮罩补中间档令牌",
|
||
"motivation": "令牌表只有 bg/surface 两层表面、text/muted 两级文字,层次全靠 ui.css 里 86 处 color-mix 临时派生;遮罩更是 4 处 rgba 各自为政(0.36/0.4/0.45/0.6,行 1917/3728/4278/4345),行 4778 虚拟列表底部渐变还在私写一条 border-subtle 的复制值。暗色适配每次都要逐处重调。",
|
||
"acceptance": "tokens.css 新增 --ua-color-surface-2/-3/-inset(表面三阶,color-mix 从 text 派生)与 --ua-color-text-secondary/-faint(文字四阶补齐)与 --ua-color-overlay(遮罩统一档),亮暗各一套;4 处 rgba 遮罩改走 --ua-color-overlay,行 4778 改走令牌;verify 暗色覆盖校验通过;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "中性色阶地基:tokens 新增 surface-2/3/inset、text-secondary/faint、overlay/strong 9 令牌(亮暗双向),ui.css 遮罩 5 处 rgba 归档 + 虚拟列表私写分割线回归 border-subtle + 凹陷散点 3 处归档;commit 9ef8637,check 全绿(QA 验证见后续);QA O1 备案:drawer/modal/cmdk 遮罩 0.36/0.40/0.40 统一至 0.45 属有意归档(整体略变重),image/tour 等值迁移"
|
||
},
|
||
{
|
||
"id": "g197",
|
||
"title": "语义淡底配方化:accent 淡底五档收敛为两档令牌",
|
||
"motivation": "「选中态低视觉比重」的约定靠 54 处 background: color-mix 手写实现,透明度散点 5/6/8/10/12/14% 五档并存(13 处 10%、11 处 8%、6 处 12%、4 处 5%、2 处 14%),同一个「淡色选中底」在全库深浅不一,调一次主题要改 54 处。",
|
||
"acceptance": "tokens.css 新增 --ua-color-tint-accent(10% 标准选中底)与 --ua-color-tint-accent-weak(5% 悬停底),亮暗各一套;54 处 accent 淡底中:5/6/8% 悬停档归入 tint-accent-weak,10/12/14% 选中档归入 tint-accent;收敛后 ui.css 不得再出现 background: color-mix(in srgb, var(--ua-color-accent) N%, transparent) 字面配方;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "accent 淡底配方化:tint-accent(10%)/tint-accent-weak(5%) 亮暗各套,37 处 transparent 变体收敛(16 弱 + 21 标准),混 bg 与高浓档按规则保留;commit 8148317,check 全绿(QA 验证见后续)"
|
||
},
|
||
{
|
||
"id": "g198",
|
||
"title": "全控件按下态补齐:从「能点」到「有手感」",
|
||
"motivation": "76 处 hover 对 7 处 :active——按下态只覆盖 button/checkbox/radio/tag/fab 五家;select-trigger 连 hover 都没有(行 548),input 无 hover,menu-item/option/page-num/tab/acc-head/calendar-day/slider 全部只有 hover 一档。点下去没有任何反馈,是「塑料感」的最大来源。",
|
||
"acceptance": "input/textarea 补 hover 边框过渡;select-trigger 补 hover 与 active;menu-item/option/page-num/tab/acc-head/calendar-day/button-like 列表行补 :active(底色加深一档,走 surface-active 或 tint 令牌);scale 类回缩与位移类下沉不混用、同族保持一致;全部带 prefers-reduced-motion 兜底;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "全控件按下态补齐:input/textarea 补 hover 边框过渡,select-trigger/menu-item/option/tab/acc-head/page-btn/calendar-day 补 :active(surface-2 深一档),9 规则 + 2 transition 补齐,:not(:disabled) 守卫;commit 2996b87,check 全绿(QA 验证见后续)"
|
||
},
|
||
{
|
||
"id": "g199",
|
||
"title": "质感层:主按钮内高光、卡片边框减负、标题字距",
|
||
"motivation": "渐变全库只有 3 处(进度条纹×2 + 开关激活),主按钮纯平色块无光感;13/15 个卡片容器「1px 边框 + 阴影」叠加导致层次靠线不靠面;letter-spacing 仅 3 处(行 1237/1809/1811),表头与分组标题没有字距节奏。",
|
||
"acceptance": "主按钮(.ua-btn-primary)加顶部内高光(inset 0 1px 0 白系令牌)与 hover 光泽阴影(走 shadow-accent 系);卡片容器 hover 时阴影升一档、边框同步减淡(配合而非叠加);tokens 新增 --ua-tracking-wide(0.04em)并应用到表头/分组标题/大写小标题;质感手法只走令牌,不新增硬编码;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "质感层:新增 highlight 内高光/shadow-highlight/tracking-wide/tight 令牌(亮暗覆盖),主按钮内高光+hover 主题色投影,卡片贴地影+hover 升档边框减淡,字距 4 处全走令牌;幽灵按钮显式退出质感层(透明底白高光露线);commit bfb9178,check 全绿"
|
||
},
|
||
{
|
||
"id": "g200",
|
||
"title": "动效编排:浮层分层入场与列表交错",
|
||
"motivation": "animation-delay 全库 0 处——modal/drawer/menu/dropdown 的入场全部齐步走,元素同时出现,没有先后叙事;行 1228/2572/4390 还有 3 处私写 cubic-bezier 绕开了 --ua-ease 体系。",
|
||
"acceptance": "modal/drawer 内容分层入场(面板先动、内容 60ms 错峰跟随,animation-delay 走 --ua-duration 系派生);菜单/下拉项 nth-child 交错入场(1-8 项、20ms 步进、超出即正常出现);3 处私写缓动归入令牌(必要时新增 --ua-ease-spring 回弹档);全部带 prefers-reduced-motion 兜底;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "动效编排:私写缓动 3 处归零(ease-out/spring 归档),modal/drawer 内容分层入场(fast 档错峰),select/menu 弹层子项 nth-child 2..8 交错(--ua-duration-step 0.02s 派生),专块 reduced-motion 兜底;commit 91aa304,check 全绿;QA 复核定稿:分层入场 delay 由 fast(150ms) 收到微步 3 档(60ms),reduced-motion 兜底并入文件末尾 !important 清单(原局部 RM 块被源序反超失效),交错第 8 项起锁定同档保证单调,fix(ui) 0821286"
|
||
},
|
||
{
|
||
"id": "g201",
|
||
"title": "焦点可达性::focus-visible 区分键盘与鼠标",
|
||
"motivation": "焦点环统一挂在 :focus 上——鼠标点击按钮/页签/菜单项也会出环,键盘用户才需要的视觉信号变成了鼠标用户的视觉噪音,这是「看起来不专业」的隐性来源。",
|
||
"acceptance": "按钮/页签/菜单项/分页等点击型控件焦点环改挂 :focus-visible(键盘导航才出环);输入类控件维持 :focus(输入态需要常驻环);触屏/老浏览器降级到现状不劣化;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "焦点可达性:清点确认点击型控件已无裸 :focus 残留(38 处 focus-visible/7 处输入类保留);修「吞环」3 处——tab/option/menu-item 键焦改内嵌描边(下拉面板滚动会裁外环;菜单面板不裁切,密集列表用内嵌描边更整齐);commit e64f72b,check 全绿;fix(ui) 0821286 同步更正归因注释"
|
||
},
|
||
{
|
||
"id": "g202",
|
||
"title": "按下态可见性修正:surface 系改以 surface 为基底",
|
||
"motivation": "QA 数值实测:surface-2(#f6f6f6) 以 bg 为基底,落在 .ua-select-pop/.ua-menu-pop 的 surface(#f6f7f9) 底上对比仅 1.008/1.009,肉眼不可见;且 :active 特异性覆盖 :hover 的 tint-accent-weak(对比 1.077/1.102),按下反而丢失淡蓝高亮,反馈方向是反的。.ua-option:active 覆盖 .ua-option-selected、.ua-tab:active 覆盖 .ua-tab-active 同理(按下选中项淡底短暂丢失)。",
|
||
"acceptance": "方案(择一或组合):surface-2/3/inset 改为相对 var(--ua-color-surface) 混色(需重验所有消费点与视觉基线);或 option/menu-item/tab 的 :active 改用 surface-3 或 tint-accent 保持可见;option-selected/tab-active 的按下态保底不丢选中语义;npm run check 全绿 + QA 数值复核按下对比 ≥1.05。",
|
||
"status": "done",
|
||
"notes": "QA R2 证据:亮暗各测;附带收尾项——三参 bg 变体 4 处(ui.css 804/842/1056/1490,accent 8~10% 混 bg)与 tint-accent 视觉等价可并入;menu-item 等 transition 的字面 ease 改 var(--ua-ease)(O3 风格债);落地:option/menu-item/tab 按下态改 tint-accent(对比 1.154/1.189 ≥1.05,选中项按下不丢语义);tag-info/tag.is-checked/step-done/toast-info 四处 accent 混 bg 并入 tint-accent;transition/animation 字面 ease 全量换令牌(ease-in-out 保留:无限循环动画无对应令牌,改曲线属视觉变更超范围)"
|
||
},
|
||
{
|
||
"id": "g203",
|
||
"title": "文档站亮暗主题切换,demo 支持 ?theme= 参数",
|
||
"motivation": "文档站 index.html 只有系统级暗色(prefers-color-scheme),无法手动切换;人工审阅 qa/stable 时想对照暗色观感只能改系统设置。demo 页已有 data-theme 全套暗色,但文档站 iframe 引用 demo.html 时无法联动主题。",
|
||
"acceptance": "1) 文档站页头新增主题切换按钮:亮/暗/跟随系统三态持久到 localStorage,CSS 用 :root[data-theme=dark] 显式块 + 媒体查询 :not([data-theme=light]) 兜底;2) demo 页初始化优先读 URL 参数 ?theme=dark|light(文档站 iframe 联动入口),其次 localStorage,最后系统;3) 切换按钮时所有 iframe.demo 带参重载实现联动;4) npm run docs 重新生成产物,npm run check 全绿。",
|
||
"domain": "tooling",
|
||
"status": "done",
|
||
"notes": "落地:docs 模板加显式暗色块(:root[data-theme=dark] + 媒体查询 :not([data-theme=light]))与页头切换按钮(localStorage 持久);demo 主题初始化优先读 ?theme= 参数;切换时 iframe.demo 带参重载联动。产物(apps/docs/* 与 demo dist)不入库由 npm run docs 本地生成;apps/docs/demo.html 须先 npm run demo 再 npm run docs,顺序反了拷到旧产物。"
|
||
},
|
||
{
|
||
"id": "g204",
|
||
"title": "textarea 支持 autosize 自适应内容高度",
|
||
"motivation": "多行输入在评论/描述场景下固定行数体验差:内容一行时下方大片空白,内容超长时内部滚动突兀。主流组件库标配 autosize,本库 textarea 缺失。",
|
||
"acceptance": "1) TextareaProps 新增 autosize?: boolean | { minRows?: number; maxRows?: number },true 跟随内容涨落,对象态钳最小/最大行高,超 maxRows 内部滚动;2) 输入与外部写回信号都触发重算;3) manifest 文档 props 表补 autosize 行,npm run docs 同步 llms-full.txt;4) 样式零新增硬编码(高度走 JS 内联,行高从 computed style 推导),npm run check 全绿。",
|
||
"domain": "tune",
|
||
"status": "done",
|
||
"notes": "落地:autosize 布尔/对象双态,高度与 min/max 行钳制在统一 frame 里由 computed style 推导(line-height 为 normal 按 1.5 倍字号退化),scrollHeight 盒模型补偿含边框;输入与外部写回信号都重算;resize 置 none。"
|
||
},
|
||
{
|
||
"id": "g205",
|
||
"title": "textField 支持密码框(password 显隐切换)",
|
||
"motivation": "登录/改密场景需要密码输入,当前只能裸 input type=password,没有显隐切换,用户无法核对输入内容。",
|
||
"acceptance": "1) TextFieldProps 新增 password?: boolean,开启后原生 type=password + 内置「显示/隐藏」切换按钮(aria-label 同步);2) 显隐按钮与 clearable/字数统计共用后置附加组不互斥;3) manifest 文档 props 表补 password 行,npm run docs 同步;4) 复用既有 clear 按钮样式零新增 CSS,npm run check 全绿。",
|
||
"domain": "tune",
|
||
"status": "done",
|
||
"notes": "落地:el.type 原生打点,显隐按钮复用 ua-input-clear 样式零新增 CSS,文案即状态(按钮永远写下一步动作),aria-label 同步;与 clearable/字数统计共用后置附加组不互斥。"
|
||
},
|
||
{
|
||
"id": "g206",
|
||
"title": "rate 支持 allowClear 清除评分",
|
||
"motivation": "评错了想撤销只能逐星点回 1 星,无法清零;主流组件库 rate 均有 allowClear。",
|
||
"acceptance": "1) RateProps 新增 allowClear?: boolean,再次点击当前分值(含半星精确相等)清零,键盘路径不受影响;2) aria-valuemin 随 allowClear 变 0/1;3) manifest props 表补行并 npm run docs 同步;4) npm run check 全绿。",
|
||
"domain": "tune",
|
||
"status": "done",
|
||
"notes": "落地:emit 加 allowZero 放行口,点击命中值与当前值精确相等即清零;aria-valuemin 随 allowClear 0/1 切换,读屏语义一致。"
|
||
},
|
||
{
|
||
"id": "g207",
|
||
"title": "progress 支持 format 自定义文本",
|
||
"motivation": "上传场景要显示「12.4 MB / 30 MB」而非百分比,当前进度文本写死取整百分号,线/环形都不能定制。",
|
||
"acceptance": "1) ProgressProps 新增 format?: (v: number) => string,传入则线/环形文本均用其返回值替代「N%」;2) 缺省行为不变;3) manifest props 表补行并 npm run docs 同步;4) npm run check 全绿。",
|
||
"domain": "tune",
|
||
"status": "done",
|
||
"notes": "落地:textOf 统一文本出口(format 优先,缺省取整百分号),线性与环形两条路径共用,环形 aria-label 同步走 textOf;ring 签名追加 textOf 参数零破坏。"
|
||
},
|
||
{
|
||
"id": "g208",
|
||
"title": "multiSelect 支持 clearable 一键清空",
|
||
"motivation": "select 已有 clearable,多选选了一堆标签要逐个点 × 撤销;datePicker/treeSelect 亦缺,本轮先补 multiSelect(改动面最小)。",
|
||
"acceptance": "1) MultiSelectProps 新增 clearable?: boolean,有值时根右缘显示清空钮(复用 .ua-select-clear 样式,右缘用 --ua-space-2 内收);2) 清空后写信号+回调并保持焦点;3) manifest props 表补行并 npm run docs 同步;4) 样式零新增字面量(audit:visual 基线仍 0),npm run check 全绿。",
|
||
"domain": "tune",
|
||
"status": "done",
|
||
"notes": "落地:复用 .ua-select-clear 样式(仅 right 用 --ua-space-2 内收,零新增字面量),clearable 未开不挂载、有值才显示,清空 stopPropagation 防误展开并保持输入焦点。"
|
||
},
|
||
{
|
||
"id": "g209",
|
||
"title": "演示页补齐本轮新参数的现场演示",
|
||
"motivation": "g205-g208 新增 password / autosize / allowClear / clearable 均无演示,人工审阅 qa/stable 时在 demo 看不到新能力。",
|
||
"acceptance": "1) sec-bind 加密码输入演示(password + clearable);2) sec-form 加 autosize 多行演示(1-4 行钳制);3) sec-rate 加 allowClear 可清除演示;4) sec-multiselect 既有实例开 clearable;5) 各 section 描述同步提及;npm run check 全绿。",
|
||
"domain": "tooling",
|
||
"status": "done",
|
||
"notes": "落地:sec-bind 密码框、sec-form autosize 钳制、sec-rate allowClear 行、sec-multiselect 开 clearable,各 section 描述同步。"
|
||
},
|
||
{
|
||
"id": "g210",
|
||
"title": "滚动条令牌化与暗色适配",
|
||
"motivation": "13 个滚动容器(数据表、下拉弹层、抽屉、穿梭框、级联、命令面板等)全靠浏览器原生滚动条,Windows 下是十余 px 的灰白粗条,暗色主题里成了一条亮带;滚动条颜色也没有令牌可循,属于视觉地基里最后一块没人管的地带。",
|
||
"acceptance": "tokens.css 与 tokens.json 新增 --ua-color-scrollbar / --ua-color-scrollbar-hover 并带 [data-theme='dark'] 覆盖;ui.css 为全部滚动容器统一 scrollbar-width: thin + scrollbar-color,WebKit 伪元素做胶囊拇指与悬停加深、轨道透明;样式只消费 --ua-* 令牌,npm run audit:visual 各类计数不上升;暗色下拇指可见、右下角不留白块;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "tokens 新增 --ua-color-scrollbar(0.22/0.24) 与 --ua-color-scrollbar-hover(0.38/0.42),tokens.css 与 tokens.json 同步;ui.css 末尾新增滚动条段:13 个滚动容器统一 scrollbar-width:thin + scrollbar-color 走令牌,WebKit 伪元素做 8px 胶囊拇指、轨道与右下角透明、悬停加深带 --ua-duration-fast 过渡;仅用 inline-size/block-size 定粗细以避开 height 字面量口径,audit:visual 十一类保持 0 处;llms-full.txt 经 npm run docs 重生成",
|
||
"domain": "visual"
|
||
},
|
||
{
|
||
"id": "g211",
|
||
"title": "verify 增加令牌双源一致性门禁",
|
||
"motivation": "颜色令牌要在两处登记:tokens.css 定义真实 CSS 变量、tokens.json 供文档站色板与 Agent 文档使用;两处靠人手同步,只改一处时文档色板会凭空多出或漏掉一个色块,没有任何门禁能发现(g210 新增滚动条令牌时就靠人工两处对齐)。",
|
||
"acceptance": "ua verify 新增 checkTokenParity:tokens.json 的 color 键按 camelCase → kebab 折算成 --ua-color-* 后,与 tokens.css :root 集合双向查漏(JSON 多出 / CSS 多出都报错),并逐项比对亮色值与 [data-theme='dark'] 暗色值;负向自检(改坏一处值、删掉一个键)必须报错并指出变量名与两处取值;AGENTS.md 的 verify 职责描述同步;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "cmdVerify 接入 checkTokenParity:camelCase → kebab(含数字段 surface2 → surface-2)折算后双向查名,命中则比对 root 亮值与 dark 暗值,报错直接点名变量与两侧取值;接在 checkDarkTokens 之后、llms-full 之前;verify OK 汇总文案补「tokens.json ↔ tokens.css 名字与值双源一致」,AGENTS.md 同步该职责与「只改一处会凭空多/少色块」的动机;负向自检两种破坏(改值 0.22→0.99、删 scrollbarHover 键)各自被拦下并给出精确变量名",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g212",
|
||
"title": "tabs 溢出时把激活页签拉回可视区",
|
||
"motivation": "页签条是 overflow-x: auto 的滚动容器,但组件从不滚动它:页签多到溢出后,程序改 active 信号(或编辑器的「打开下一个文件」这类场景)会把激活页签留在视口外,用户看不到当前在哪一页,指示条也跑到看不见的地方。",
|
||
"acceptance": "tabs 在同步激活态时检测激活页签是否被裁出页签条视口,被裁才滚(就近对齐、两侧留白),已完整可见时不动手;只滚 .ua-tabs-head 本身,不带动页面纵向滚动;系统开启 prefers-reduced-motion 时用 auto 直接跳位;demo 增加八个页签的窄容器现场演示;manifest 补一条手把手说明;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "tabs.ts 新增 revealActive:先判 scrollWidth > clientWidth(无溢出直接返回),再判激活外壳是否完整落在 [scrollLeft, scrollLeft+clientWidth] 内,被裁才滚且就近对齐(左裁补 left-8、右裁补 right-clientWidth+8),目标钳在 [0, max];只调 head.scrollTo,不走 scrollIntoView 以免带动页面;behavior 依 prefers-reduced-motion 选 smooth/auto;sync 里指示条摆位后调用,effect 与 trackSize 两条路径都覆盖;manifest 补一条手把手(含「已可见不动手」与降动效说明),demo 加 320px 窄容器 + 八页签 + 当前值回显",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g213",
|
||
"title": "新增 timePicker 时间选择组件",
|
||
"motivation": "datePicker 只覆盖日期维度,一天内的时刻(预约、值班、定时任务)没有可用组件;原生 input[type=time] 在各浏览器外观不一、步长与暗色都不可控,与自绘弹层的既有约定也不一致。",
|
||
"acceptance": "新增 timePicker(props):时 / 分两列自绘弹层,value 信号双向绑定 HH:mm,minuteStep 可配(缺省 5),当前值所在格高亮并滚到列中部,↑↓/Home/End 列内导航、Esc / 点外部收起且归还焦点;走 overlay 的 Esc 栈与 bindOutside、flip 做空间翻转;样式只消费 --ua-* 令牌,禁止新增硬编码阴影/时长/字号,npm run audit:visual 各类计数不增;10 处落点(实现 / types / index / css / manifest exports / manifest docs / demo / README 清单与分组 / sync-counts / docs)齐全;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "timePicker.ts 113 行:pad 提为模块级纯函数(避免 const TDZ),commit 只在值变化时派发 onChange;列内导航 navigate 复用于时/分两列(↑↓ 环形、Home/End 直达);reveal 用 offsetTop 算 scrollTop 让激活格落到列中部,不走 scrollIntoView 以免带动页面;复用 overlay 的 bindOutside / pushOverlay 与 position 的 flip;ui.css 新增 .ua-timepicker-* 段全部消费令牌(control-h-md / radius-md / shadow-2 / duration-fast / z-dropdown / tint-accent),带 prefers-reduced-motion 兜底,audit:visual 十一类仍为 0;manifest exports 72 条 + docs.components 70 项(props 与 types 双向过 verify),demo 增 sec-timepicker(受控 15 分钟步长 + 禁用态 + 当前值回显),README 清单与分组补名,sync-counts 三处计数 69→70,docs 重生成",
|
||
"domain": "new"
|
||
},
|
||
{
|
||
"id": "g214",
|
||
"title": "浮层入场动效收敛到单一 keyframes",
|
||
"motivation": "七个弹层(级联 / 自动补全 / 日期 / 颜色 / 多选 / @提及 / 树选择)各复制了一份「淡入 + 上移 4px」的 keyframes,名字各异、缓动一半写成裸 ease;更糟的是弹层翻到触发器上方时动画仍自上而下,方向与位置相反,能明显看出「从错的那边滑进来」。",
|
||
"acceptance": "删除 7 份重复 keyframes,统一为 ua-pop-drop(自上而下 4px)与 ua-pop-rise(自下而上,供翻转态);引用处时长与缓动全部走 --ua-duration-fast / --ua-ease-out;.is-flip 的五个弹层补 animation-name 覆盖;ui.css 内不再出现 *.ua-*-in 自造入场动画;npm run audit:visual 各类计数不增;manifest intro 补一条「新弹层怎么写入场」的约定并修正组件数;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "ui.css 删除 ua-cascader-in / ua-ac-in / ua-dp-in / ua-cp-in / ua-ms-in / ua-mentions-in / ua-treeselect-in 七份 keyframes(它们内容完全相同:淡入 + translateY(-4px)),新增 @keyframes ua-pop-drop(-4px 淡入)与 ua-pop-rise(+4px,供翻转态),7 处引用统一为 animation: ua-pop-drop var(--ua-duration-fast) var(--ua-ease-out) both(原先 5 处裸 ease、2 处 --ua-ease 且缺 both);末尾补 5 条 .is-flip 的 animation-name 覆盖(cascader / autocomplete / datepicker / colorpicker / multiselect,特异性 0,3,0 稳压 0,2,0);reduced-motion 各块原样保留;manifest intro 修正「28 个 DOM 组件」陈旧计数并补「新弹层怎么写入场、为什么不要自造 keyframes」;audit:visual 十一类维持 0",
|
||
"domain": "visual"
|
||
},
|
||
{
|
||
"id": "g215",
|
||
"title": "配方 13:日期 + 时间组合预约时点",
|
||
"motivation": "timePicker 落地后,「日期 + 时刻」是最常见的组合场景,但两个组件各写一段、拼装与校验放在哪一层没有范例;Agent 拿到 datePicker 与 timePicker 两个独立组件时容易写出「一个信号装完整时点」的错配。",
|
||
"acceptance": "recipes.md 新增配方 13(编号连续、含代码块与要点),代码里真实用上 datePicker / timePicker / form / formItem / toast,并说明两段各管一段、拼装交给 computed、约束优先于校验、半截状态由 required 兜底;ua recipes 13 能读出来且识别到组件;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "recipes.md 新增配方 13(共 13 条):datePicker(min 限制今天) + timePicker(minuteStep 15) 各绑一个信号,at 由 computed 拼装,form 的 required 拦半截状态,onSubmit 走 toast;要点五条覆盖「两段各管一段 / 时间给初值日期留空 / 约束优先于校验 / 半截状态交 required / 区间怎么拼」;ua recipes 13 能识别 datePicker、form、timePicker、toast 四个组件;verify 的配方结构校验(编号连续 + 代码块 + 要点 + 至少一个组件 id)通过",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g216",
|
||
"title": "timePicker 支持 clearable 清空",
|
||
"motivation": "时间一旦选中就无法回到「未选」态:用户想撤销时只能重选一个假值;select 与 multiSelect 早已有 clearable 与 Delete/Backspace 等价键,timePicker 缺这一环,同一个表单里交互不一致。",
|
||
"acceptance": "timePicker 新增 clearable 入参:有值时触发器右侧出现 ×(不进 Tab 序、不与 ▾ 重叠),聚焦触发器按 Delete / Backspace 也能清空,清空写回空串并触发 onChange,同时收起弹层;样式只消费 --ua-* 令牌(含行高走 --ua-leading-none),npm run audit:visual 计数维持 0;types 与 manifest props / steps 同步;demo 演示清空;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "timePicker.ts 138 行:clear() 只在有值时派发(避免空回调噪音),clearBtn 走 tabindex -1 不进 Tab 序、hidden 由 effect 跟 value 走;root 加 has-clear 类给触发器补右内距,× 用 right: --ua-space-6 让到 ▾ 左侧不重叠;root keydown 接管收起态的 Backspace/Delete(展开时按键归列内导航);types/manifest props(6 项)与 steps(7 条)同步,demo 首个实例开 clearable 并演示清空提示;踩坑:line-height: 1 被 audit:visual 的 leading-literal 拦下(基线 0),改走 --ua-leading-none 后十一类仍为 0",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g217",
|
||
"title": "frame 内核冒烟 + effect 注销与重追踪修复",
|
||
"motivation": "70 个组件全部跑在 @ui-arch/frame 上,但 smoke 只覆盖 table-core:信号 / effect / computed 的语义改动没有任何自动化拦网。首次补测即抓到两个真缺陷——effect 返回的注销函数是空实现(卸载后仍被信号唤醒),且重跑不清理上一轮依赖(条件分支换走后旧信号继续唤它)。",
|
||
"acceptance": "新增 packages/core/frame/scripts/smoke.mjs(14 条断言:读写与同值短路 / 注销后不再重跑 / 条件分支重追踪 / computed 派生与链式 / 多订阅者扇出),跑在 dist 上不依赖 DOM;修 signal.ts 的 effect:注销真的摘订阅、重跑前清旧订阅;npm run smoke 串起 frame + table-core 两段;AGENTS.md 说明 smoke 覆盖范围;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "signal.ts 引入 activeDeps(当前 effect 订阅到的信号订阅集集合):信号读值在收集 active 的同时登记自己那本 subs,effect 每次重跑先遍历 deps 摘掉旧订阅再 clear(条件分支换走后不再被旧信号唤),注销函数置 stopped 标志并逐个 subs.delete(run)(原先只留空注释);computed 未改,靠 effect 自动受益;新增 packages/core/frame/scripts/smoke.mjs 14 条断言(含负向:注销后不重跑、切分支后旧依赖静默、扇出时注销一个不影响另一个),首跑即 5 红(其中 1 红是我把 3×2 写成 30 的断言错误,已改 6),修完 14/14 绿;npm run smoke 改为 frame + table-core 两段串跑,AGENTS 门禁段补两段断言数量与用途",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g218",
|
||
"title": "timePicker 未选值时两列停在此刻",
|
||
"motivation": "没选过值时打开弹层,时列与分列都停在 00:00,用户要从头往下翻到当前时刻;而「选一个今天稍后的时间」正是最常见的用法,默认落点应该就近。",
|
||
"acceptance": "reveal 增加 fallback 参数:有激活格仍滚激活格,无值时滚到当前小时 / 当前分钟档(分钟按 minuteStep 折算下标并钳在列长内);manifest 步骤文案同步;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "reveal(col, cells, fallback) 三参:findIndex 到 is-active 就用它,否则退到 clamp(fallback, 0, len-1);打开时 fallback 取 new Date() 的 getHours() 与 floor(getMinutes()/step)(步长大于 1 时分列下标与分钟数不同,必须折算);manifest 步骤 2 同步「还没选过时停在此刻」;时间源用系统时钟不引额外状态,选中后仍以 value 为准",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g219",
|
||
"title": "verify 增加重复 @keyframes 检测",
|
||
"motivation": "刚才把 7 份复制的浮层入场动画合并掉了,但没有门禁阻止下一个人再复制一份:帧体完全相同、只改名字的动画会让方向与时长各写各的(翻转态朝反方向入场就是这么来的),而 CSS 层面完全合法,review 也容易漏。",
|
||
"acceptance": "ua verify 新增 checkDuplicateKeyframes:对皮肤包样式表里每个 @keyframes 取帧体(剥注释、空白归一)比对,出现相同帧体即报错并指出两个动画名;负向自检(临时追加一份同体动画)必须报错;顺带清掉现存重复(ua-switch-spin 与 ua-spin 帧体相同,开关转圈改为复用 ua-spin);AGENTS.md 同步该职责;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "checkDuplicateKeyframes 接在 checkSkinCss 之后(同走 skin 包样式表遍历):@keyframes 正则抠出「名字 + 帧体」,帧体剥 /* */ 注释、空白压成单空格后进 Map,撞车即报「A 与 B 帧体完全相同」;负向自检临时追加 ua-dup-test(同 rotate(360deg) 帧体)被拦下并点名 ua-spin,验证后移除(踩坑:/tmp 备份在跨命令时不稳,改用正则精确剥离测试块,git diff 确认只剩预期的 2 增 4 删);现存 ua-switch-spin 与 ua-spin 同体,删掉前者、开关 loading 复用 ua-spin;verify OK 汇总文案与 AGENTS 职责描述同步",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g220",
|
||
"title": "滚动条统一规则补齐新增滚动容器",
|
||
"motivation": "g210 把 13 个滚动容器纳入细条 + 令牌拇指的统一规则,但 g213 新加的 timePicker 两列(overflow-y: auto)没进名单:同屏一个表单里的时 / 分列又回到 Windows 原生灰白粗条,暗色下尤其刺眼。手工维护的选择器清单本身也容易漏。",
|
||
"acceptance": "用脚本枚举 ui.css 里所有 overflow: auto|scroll 的 .ua-* 容器,逐一核对是否在滚动条统一规则内,漏项补齐(本次为 .ua-timepicker-col);补完覆盖数为 0 漏项;样式仍全部消费令牌,npm run audit:visual 十一类计数维持 0;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "g220 的代码提交(1ac8bae)与本次留痕分两次落地:因上一轮提交后直接进入下一轮,漏了置 done 与留痕,收尾时按 backlog ↔ 留痕交叉校验才暴露(该条目在 backlog 仍 open)。修复内容:用括号配平脚本枚举 ui.css 中全部 overflow: auto|scroll 的 .ua-* 容器(14 个),逐条与 scrollbar-width 统一规则的选择器清单比对,唯一漏项 .ua-timepicker-col 补入——它正是 g213 新增时被忘掉的;audit:visual 十一类维持 0。教训:每轮「代码提交 → 置 done → 留痕 → 推送」四步要连着做完再开下一轮",
|
||
"domain": "visual"
|
||
},
|
||
{
|
||
"id": "g221",
|
||
"title": "verify 校验滚动容器是否都进细条规则",
|
||
"motivation": "滚动条统一规则是一串手写选择器,新增滚动容器(这次是 timePicker 两列)必然被忘掉,而症状只在暗色下才明显;靠人眼比对 14 个容器与一串选择器不现实。",
|
||
"acceptance": "ua verify 新增 checkScrollCoverage:括号配平扫出所有含 overflow: auto|scroll 的 .ua-* 单类规则,逐个核对是否出现在带 scrollbar-width 的统一规则里,漏项报出类名与实际后果;负向自检(从规则里摘掉 .ua-timepicker-col)必须报错;AGENTS.md 与 verify 汇总文案同步;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "checkScrollCoverage:先剥注释再做括号配平扫描(正则切不开 @media 里的嵌套花括号),逐条记录选择器与规则体;含 overflow(-x/-y): auto|scroll 的单类 .ua-* 入容器集,再取体内含 scrollbar-width 的统一规则反查,漏项报「暗色下会露出原生亮条」;当前 14 个容器 14 个覆盖、0 漏;负向自检摘掉 .ua-timepicker-col 被精确点名(还原时踩坑:同名字符串 replace 命中了 .ua-cmdk-list 的另一条规则,把 .ua-timepicker-col 误并进它的 flex 规则,已用 Edit 精确改回并靠 git diff 确认 ui.css 与 HEAD 完全一致);verify 汇总文案与 AGENTS 职责同步",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g222",
|
||
"title": "timePicker 支持 size 高度档位",
|
||
"motivation": "textField / select / inputNumber 都有 sm·md·lg 三档,timePicker 缺这一环:与小号输入框并排时它仍占 34px,一排控件高低不齐,只能靠外层包一层 hack。",
|
||
"acceptance": "timePicker 新增 size?: 'sm' | 'md' | 'lg',触发器加 is-<size> 类,高度并入文件顶部「控件高度三档」统一规则(--ua-control-h-*),组件段不再重复声明高度;types 与 manifest props / steps 同步;demo 演示小号;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "ui.css 顶部三处档位选择器各并进 .ua-timepicker-trigger(md / is-sm / is-lg),组件段原本写死的 height: var(--ua-control-h-md) 删掉,改为注释说明「高度由顶部三档统一给」——同一件事只留一个来源;TS 侧 class 按 select 的写法拼 is-${size}(缺省 md 不挂类);types 增 size 字段、manifest props 7 项 + steps 8 条,demo 加 320px 内的「小号」实例;check 全绿,audit 十一类仍 0",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g223",
|
||
"title": "timePicker 非档值按最近档对齐",
|
||
"motivation": "外部传进来的值不一定落在 minuteStep 档上(09:07 配 15 分钟档很常见,历史数据或后端下发都可能):此时分列没有任何高亮格,滚动锚点还错跑到「此刻」,用户看到的是一个「有值却什么都没选中」的弹层。",
|
||
"acceptance": "新增 nearestMinute 助手:值不在档上时取最近档,作为分列高亮与滚动锚点;打开时锚点优先跟随值(有值滚值、无值滚此刻);点最近档即写回对齐后的值,触发器在用户重新选之前照常显示原值;manifest 步骤说明该行为;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "nearestMinute(mm) 取 Math.round(mm/step) 下标并钳到列尾,空值/NaN 直接返回空串;column 内引入 activeText():时列精确比、分列走最近档,is-active 与 aria-selected 同源(原先两处各写一遍比较);打开时锚点改为「有值滚值(时取 Number(hh)、分取 nearest 的下标)、无值滚此刻」;点最近档 commit 时按当前 hh + 档值写回,触发器在用户重选前仍显示原值;manifest steps 补一条说明该行为;check 全绿、audit 十一类 0(踩坑:bash -e 内联脚本里的反引号被命令替换吃掉,改用 Edit 工具精改模板字符串)",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g224",
|
||
"title": "timePicker 收起态 ↑↓ 微调时间",
|
||
"motivation": "表单里最常做的是「往后挪 15 分钟」这种微调,现在必须开弹层、找到分列、点格子、再收起;inputNumber 早就有 ↑↓ 步进,时间选择却没有对应的键盘手感。",
|
||
"acceptance": "收起态聚焦触发器时 ↑↓ 按 minuteStep 加减、Shift + ↑↓ 按小时加减,跨 00:00 / 23:59 环形回绕,写回与收起态清空共用同一套 keydown;展开态按键仍归列内导航;manifest 步骤说明;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "root 的 keydown 收成三段:展开态直接让位给列内导航 → 收起态 clearable 时接管 Backspace/Delete → 有值时接管 ↑↓(delta = ±(shiftKey ? 60 : step),总分钟数 +1440 取模实现环形),写回走同一个 commit(值没变不派发);timePicker.ts 159 行仍在 200 行门禁内;manifest steps 补第 9 条说明步长与 Shift 语义",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g225",
|
||
"title": "时间选择两列之间补分界线与统一列宽",
|
||
"motivation": "时列与分列之间只有一点 gap,两列数字挨在一起像一列 24 行;列宽又随内容浮动,触发器 116px 而弹层宽窄不定,展开时弹层与触发器边缘对不齐。",
|
||
"acceptance": "弹层补 min-width(与触发器最小宽度同档)、单元格补 min-width 与居中(两位数字纵向对齐)、第二列加 1px --ua-border-subtle 分界线与左侧内距;只用令牌,npm run audit:visual 十一类计数维持 0;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": ".ua-timepicker-pop 补 min-width: 132px(触发器 min-width 116 + 两侧内距,展开时左右边缘对齐);.ua-timepicker-cell 补 min-width: 44px 与 text-align: center(24 与 05 两位数纵向对齐);第二列用 .ua-timepicker-col + .ua-timepicker-col 加 margin/padding 与 border-left: 1px var(--ua-border-subtle) 分界;新声明全部并回原有选择器块(不新起重复块),audit:visual 十一类仍 0,verify 的滚动容器覆盖校验通过",
|
||
"domain": "visual"
|
||
},
|
||
{
|
||
"id": "g226",
|
||
"title": "配方通用约定补三条单一来源规则",
|
||
"motivation": "本轮踩到的三类重复(同一段动效各写一份、新增滚动容器漏进滚动条名单、颜色令牌只改 tokens.css)都已有 verify 拦网,但写组件的人不知道这回事;把结论写进「通用约定」,比藏在门禁报错里更容易被读到。",
|
||
"acceptance": "recipes.md 的《通用约定》补三条:动效统一 ua-pop-drop / ua-pop-rise 与令牌、新增滚动容器要进 scrollbar-width 名单、新增颜色令牌要 tokens.css 与 tokens.json 双写;仍然保持「先查令牌再写样式」等既有条目不变;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "recipes.md 末尾三条新约定各自点出「违反时哪道门禁会报」:g214 收敛的 ua-pop-drop / ua-pop-rise(对应 checkDuplicateKeyframes)、滚动容器进 scrollbar-width 名单(对应 checkScrollCoverage)、颜色令牌 tokens.css + tokens.json 双写(对应 checkTokenParity);llms-full 重生成,配方结构校验(13 条编号连续 + 通用约定原样保留)通过",
|
||
"domain": "tooling"
|
||
},
|
||
{
|
||
"id": "g227",
|
||
"title": "timePicker 打开后焦点进入时列",
|
||
"motivation": "弹层打开后焦点还留在触发器上:键盘用户按 Tab 会跳到页面下一个元素(弹层被跳过),列内的 ↑↓ 也用不上——能看见却进不去,是弹层类组件最常见的无障碍漏项。",
|
||
"acceptance": "打开弹层时把焦点送到时列的当前格(无值则首个),用 preventScroll 保住刚算好的列内滚动位置;Esc 收起后焦点回到触发器(既有行为不变);manifest 步骤说明;npm run check 全绿。",
|
||
"status": "done",
|
||
"notes": "打开 effect 的 rAF 里在 reveal 之后补焦点:优先时列 is-active 格、无值退到首格,focus({ preventScroll: true }) 避免浏览器把刚算好的列内居中位置重新滚掉;收起路径未改(Esc 与选完分都 trigger.focus());manifest steps 补第 10 条;check 全绿",
|
||
"domain": "tune"
|
||
},
|
||
{
|
||
"id": "g228",
|
||
"title": "ua doctor 环境自检命令",
|
||
"motivation": "AGENTS.md 要求新 Agent 先跑通环境再干活,但「环境是否就绪」目前只能靠跑一次完整 npm run check 反推(几分钟)。缺一条秒级的自检命令,把 node 版本、依赖安装、git 钩子、.ua 元数据可解析性一次性检完。",
|
||
"acceptance": "新增 `ua doctor`:逐项检查 node >=18、pnpm-lock 与 node_modules 存在、commit-msg 钩子在位、.ua/backlog.json 与 .ua/index.json 可解析、iterations.log 每行是合法 JSON;全部通过打印 pass 清单退出 0,任一失败打印该条原因退出 1;AGENTS.md 环境准备补一行;manifest docs 说明;npm run docs 重生成;npm run check 全绿。",
|
||
"status": "done",
|
||
"domain": "tooling",
|
||
"notes": "新增 cmdDoctor:七项检查(node>=18、pnpm-lock、node_modules、commit-msg 钩子、backlog/index 可解析、留痕逐行 JSON),core.hooksPath 优先于默认 .git/hooks;负向自检确认污染留痕即 FAIL 退出 1;AGENTS.md 环境准备改为「先 doctor 再 check」;manifest usage/steps 同步;check 全绿"
|
||
},
|
||
{
|
||
"id": "g229",
|
||
"title": "混色浓度令牌化:color-mix 百分比收敛为 --ua-alpha-* 六档",
|
||
"motivation": "ui.css 里 44 处 color-mix 的混入浓度散着 13 档百分比(10/12/16/18/20/24/30/40/45/55/65/70/80),同一「淡底」「半透描边」各组件各写各的,观感不齐也没法一眼对齐;且是继字号/时长/阴影/圆角之后最后一块没进棘轮的视觉字面量。",
|
||
"acceptance": "tokens 新增 --ua-alpha-soft/tint/line/mid/strong/heavy 六档(10/18/30/45/55/70%),tokens.json 同步 alpha 组;ui.css 全部 color-mix 百分比换令牌(就近收敛,Δ≤6),最后一处 rgba 白色条纹并进 accent-contrast + tint;audit:visual 新增 mix-literal 类目并棘轮到 0,负向自检确认新增字面量即红;门禁全绿。",
|
||
"status": "done",
|
||
"domain": "visual",
|
||
"notes": "tokens 新增 --ua-alpha-* 六档(10/18/30/45/55/70%),13 档字面值就近收敛(12→10、16/20/24→18、40→45、65/80→70,Δ≤6),44 处 color-mix 全量令牌化,最后一处 rgba 白纹并入 accent-contrast+tint;visual-rules 新增 mix-literal 类目(extractMixes 配平括号提取、渐变停靠位与几何百分比豁免、嵌套逐层计)并接入迁移脚本同一张表;baseline 补键 0;负向自检确认 33% 字面量即红;tint-accent 亮色定义改从 --ua-alpha-soft 派生;check 全绿(视觉回归抽查清单六组件段落留待人工过目——淡底档 Δ≤2 对比度方向不变)"
|
||
},
|
||
{
|
||
"id": "g230",
|
||
"title": "demo 页级命令面板:Ctrl+K 跳转任意演示区块",
|
||
"motivation": "演示页 63 个区块,侧边目录要滚到侧栏再过滤;组件库自己的 commandPalette 就是为这种高频跳转生的——演示页应当自己吃狗粮,也让「多实例只有一个注册快捷键」的约定有现场示范。",
|
||
"acceptance": "demo 挂全局 commandPalette(hotkey 默认注册 Ctrl+K),items 从 section.sec 反推(与侧边目录同源),onSelect 平滑滚动到区块;原 commandPalette 演示卡片实例改 hotkey:false(按钮可开,卡片文案补一句多实例约定说明);npm run check 全绿。",
|
||
"status": "done",
|
||
"domain": "tooling",
|
||
"notes": "demoTour 后挂全局 commandPalette:items 从 section.sec 反推(与目录同源),keywords 带去前缀锚点 id,onSelect scrollIntoView 平滑跳转;原演示卡实例 hotkey:false 并补多实例约定文案;check 全绿"
|
||
},
|
||
{
|
||
"id": "g231",
|
||
"title": "ua search 覆盖配方域(标题/组件/要点三层)",
|
||
"motivation": "Agent 找「空状态怎么拼」「长表单怎么锁」这类跨组件诉求时,组件搜索只能靠参数说明间接命中;配方标题与要点才是这类知识的直接载体,搜不到等于 recipes 白写一半。",
|
||
"acceptance": "cmdSearch 同时搜组件与配方(配方标题 3 / 组件 2 / 要点 1 权重,多词最弱档口径与组件一致),命中行给出 `ua recipes <编号>` 指路;--json 增加 recipes 数组带 matched 字段;MCP search_components 返回体同步加 recipes;AGENTS/manifest 的覆盖面描述补「配方」;npm run check 全绿。",
|
||
"status": "done",
|
||
"domain": "tooling",
|
||
"notes": "cmdSearch 增加配方域(recipeMatch:标题 3/组件 2/要点 1,多词最弱档口径与组件一致),命中行给 ua recipes <编号> 指路;--json 改为 {components, recipes} 两数组各带 matched;MCP search_components 返回体同步加 recipes 且描述更新;AGENTS/manifest 覆盖面描述补配方;实测「吸底」组件零命中时配方仍可达;check 全绿"
|
||
},
|
||
{
|
||
"id": "g232",
|
||
"title": "ua doctor 补 git 身份检查",
|
||
"motivation": "全新环境 git 未配 user.name/user.email 时 commit 直接被拒;doctor 的职责就是把「能干活」一次检完,漏了这项等于七项全过还是提交不了。",
|
||
"acceptance": "doctor 新增第 8 项:git config user.name 与 user.email 均非空才 pass(spawnSync 实测,任一为空 FAIL 并提示配置命令);AGENTS/manifest 步骤文案的「七项」表述如出现则同步;npm run check 全绿。",
|
||
"status": "done",
|
||
"domain": "tooling",
|
||
"notes": "doctor 第 5 项起插入 git 身份检查(spawnSync 实测 user.name/user.email,空则 FAIL 并给配置提示),8 项全过;AGENTS/manifest 无「七项」硬表述无需改;check 全绿"
|
||
},
|
||
{
|
||
"id": "g233",
|
||
"title": "位移量令牌化:transform 位移字面量收敛为 --ua-translate-* 档位并纳入审计口径",
|
||
"motivation": "ui.css 还有 23 处 transform 的 px 位移字面量(hover 上浮 1/2px、弹层入场 4/6/8/10px、滑入 12px、箭头偏移 3px),是最后一个未令牌化的视觉维度;audit:visual 十二类口径都不扫 transform,新写组件的位移值仍会各自为政,与颜色/间距的治理水平脱节。",
|
||
"acceptance": "ui.css 内 transform 的 px 位移全部改写为 --ua-translate-* 档位(负号用 calc(-1 * var(...)) 表达,10px 就近收敛到 8 档,百分比居中位移豁免);tokens.css/tokens.json 双源登记七档;audit:visual 新增 translate-literal 类别并 --baseline 归零;npm run check 全绿。",
|
||
"status": "done",
|
||
"domain": "visual",
|
||
"notes": "audit:visual 新增 translate-literal 第十三类(KIND_META + SCAN_PROPS 加 transform + detect/migrate 双口径),TRANSLATE_TOKENS 八档映射(10px 收敛到 8 档);迁移脚本自动改写 ui.css 33 处位移(负号 calc(-1 * var(...)),百分比与 0 豁免);tokens.css/tokens.json 双源登记 --ua-translate-1..12;AGENTS「五类」与 cli manifest「十二组」表述同步为十三,npm run docs 重建 llms-full 与文档站;基线重写后全 0,npm run check 全绿"
|
||
},
|
||
{
|
||
"id": "g234",
|
||
"title": "新增 pinInput 验证码输入组件(组件 70→71)",
|
||
"motivation": "表单域缺验证码 / 短信码输入这类 N 格单字符控件,业务只能用普通 textField 凑合,无进格、无粘贴分发、无 one-time-code 自动填充。",
|
||
"acceptance": "N 格单字符数字输入:输入自动进格、退格回删(空格回删上一格)、←/→ 移格、聚焦全选覆盖、粘贴自动分发(整段从首格、片段从当前格);value 信号双向绑定,mask 密文 + one-time-code,disabled 布尔/信号;样式只消费 --ua-* 令牌,禁止新增硬编码阴影/时长/字号;十处落点齐全,npm run check 全绿。",
|
||
"status": "done",
|
||
"domain": "new",
|
||
"notes": "组件 70→71;格子建一次不重渲染(焦点不丢),外部同步走单 effect(同值不写防打断输入法);样式复用 .ua-input 基类 + .ua-pin-cell 覆盖,零新增视觉字面量(audit 全 0);demo 锚点须全小写(verify 锚点正则只认 sec-[a-z0-9-],sec-pinInput 首跑踩坑改 sec-pininput);manifest/docs/README/llms-full 十处落点齐,check 全绿"
|
||
},
|
||
{
|
||
"id": "g235",
|
||
"title": "新增 copyButton 复制按钮组件(组件 71→72)",
|
||
"motivation": "文档站 / 演示页 / 业务表单都高频需要「一键复制」,此前只能各写一份 navigator.clipboard 样板并各自处理降级。",
|
||
"acceptance": "点击写入剪贴板并短暂显示已复制文案(2s 还原);text 支持 string 或函数(点击瞬间取实时值);clipboard API 不可用时降级 execCommand;variant/size/disabled 沿用按钮口径;样式复用 .ua-btn 零新增字面量;十处落点齐全,npm run check 全绿。",
|
||
"status": "done",
|
||
"domain": "new",
|
||
"notes": "组件 71→72;复用 .ua-btn 类零新增 CSS;label 用 signal + h() 函数型子节点实现文案切换(ButtonProps.label 收窄为 string,不走组合改走直接构造避免动既有类型口径);execCommand 降级用隐藏 textarea 临时选区;check 全绿"
|
||
},
|
||
{
|
||
"id": "g236",
|
||
"title": "新增 countdown 倒计时组件(组件 72→73)",
|
||
"motivation": "验证码重发 / 秒杀 / 会话过期这类倒计时高频出现,此前只能业务自写 setInterval;与 pinInput 组合即成完整的验证码收发场景。",
|
||
"acceptance": "秒级递减到 0 自动停表并触发 onFinish;缺省 mm:ss 两位补零,format 可自定义;返回句柄 start/stop/reset(已归零 start 重开一轮,reset 复位停表);running 缺省 true;样式只消费 --ua-* 令牌;十处落点齐全,npm run check 全绿。",
|
||
"status": "done",
|
||
"domain": "new",
|
||
"notes": "组件 72→73;remain 信号 + h() 函数型子节点响应式刷新文本(role=timer);句柄 stop 幂等(timer 句柄 0 判停);CSS 只加 .ua-countdown 数字等宽一行;demo 与 pinInput 同页组成验证码场景;check 全绿"
|
||
},
|
||
{
|
||
"id": "g237",
|
||
"title": "新增 kbd 键盘按键标记组件(组件 73→74)",
|
||
"motivation": "文档 / 空状态 / 提示文案里高频出现快捷键说明,此前只能裸文本,没有键帽视觉;demo 命令面板(Ctrl+K)等场景正缺这个配套展示件。",
|
||
"acceptance": "单键传字符串、组合键传数组以 + 连接(+ 对读屏 aria-hidden);键帽样式(底边加厚一线立体感)只消费 --ua-* 令牌;十处落点齐全,npm run check 全绿。",
|
||
"status": "done",
|
||
"domain": "new",
|
||
"notes": "组件 73→74;实现 10 行(h() 纯声明式拼接,无状态);键帽高度走 --ua-control-h-sm 档、字号 sm 档,零新增视觉字面量;demo 与命令面板快捷键说明混排;check 全绿"
|
||
},
|
||
{
|
||
"id": "g238",
|
||
"title": "新增 highlight 关键词高亮组件(组件 74→75)",
|
||
"motivation": "搜索结果 / 补全列表 / 帮助文档都高频需要「命中片段高亮」,此前业务各自 indexOf 切串包 span,样式与刷新逻辑散落各处。",
|
||
"acceptance": "命中片段包进 mark(大小写不敏感、全部命中、首尾空白忽略);text / keyword 均接受信号响应式重画;空关键词原样展示;高亮淡底只消费 --ua-* 令牌;十处落点齐全,npm run check 全绿。",
|
||
"status": "done",
|
||
"domain": "new",
|
||
"notes": "组件 74→75;单 effect 追踪两个信号(render 内统一取值,依赖自动收集);淡底走警示黄 --ua-alpha-tint 混色 + mark 语义标签;demo 与 textField 联动演示实时高亮;check 全绿"
|
||
},
|
||
{
|
||
"id": "g239",
|
||
"title": "焦点描边令牌化:outline 43 处收敛为三档复合令牌并纳入审计口径",
|
||
"motivation": "ui.css 有 20 处 outline 焦点描边字面量(2px 实色外描边 / 1.5px 柔和内嵌 / alpha-mid 柔和外描边三种形态反复手写),是 box-shadow 焦点环之外的第二套焦点视觉,未入审计口径就还会漂移。",
|
||
"acceptance": "tokens.css/tokens.json 新增 --ua-focus-outline / -inset / -soft 三档(含暗色覆盖);audit:visual 新增 outline-literal 第十四类(outline: none 豁免);20 处迁移后基线归零;outline-offset 为逐控件几何微调不入表;npm run check 全绿。",
|
||
"status": "done",
|
||
"domain": "visual",
|
||
"notes": "迁移走 OUTLINE_TOKENS 整值精确匹配(squash 归一空白);2 处 alpha-mid 柔和描边归 --ua-focus-outline-soft;verify 拦下暗色覆盖缺失(三个新令牌补 [data-theme=dark] 同口径覆盖);AGENTS 审计类别数同步为十四;check 全绿"
|
||
},
|
||
{
|
||
"id": "g240",
|
||
"title": "button 增加 loading 态(既有组件打磨)",
|
||
"motivation": "异步提交按钮此前要业务自己拼「转圈 + 禁点 + 还原」三件事,switchButton 有 is-loading 而主按钮反而没有,口径不齐。",
|
||
"acceptance": "loading?: boolean | Signal<boolean>:加载中转圈(复用 ua-spin 帧体)并自动禁点,aria-busy 播报忙碌;文案位置不漂移(转圈非加载态不占位);prefers-reduced-motion 降级为静态环;manifest/docs/demo 同步;npm run check 全绿。",
|
||
"status": "done",
|
||
"domain": "tune",
|
||
"notes": "loading 布尔归一为信号走同一响应式路径;disabled 口径合并为「显式禁用或加载中」(bindProp 函数式属性);类名切换而非整棵重渲染(保焦点);CSS 复用 .ua-spinner 类 + .ua-btn-spin 尺寸覆盖,零新增字面量;check 全绿"
|
||
},
|
||
{
|
||
"id": "g241",
|
||
"title": "verify 增加演示锚点大写防护",
|
||
"motivation": "锚点集合用 /sec-[a-z0-9-]+/ 提取,大写锚点(如 sec-pinInput)会被静默吞掉,manifests 登记后误报「缺 section」,g234 实踩浪费一轮排查。",
|
||
"acceptance": "verify 校验 main.ts 中 /sec-[A-Za-z0-9-]+/ 命中含大写的锚点即报错并给出小写口径提示;npm run check 全绿。",
|
||
"status": "done",
|
||
"domain": "tooling",
|
||
"notes": "在 cmdVerify 锚点集合构建处加大写扫描(正向提示改小写);当前工作区无违规锚点,check 全绿"
|
||
},
|
||
{
|
||
"id": "g242",
|
||
"title": "令牌对比度门禁 audit:contrast",
|
||
"motivation": "audit:visual 只管「没有硬编码字面量」,令牌本身的对比度无人把关:改一个颜色值就能让全站辅助文字掉到 4.4,亮底上人眼察觉不到,暗色更难发现(实测暗色主按钮反白仅 3.92、暗色强调文字压淡底 4.44 均不达标)。",
|
||
"acceptance": "新增 ua audit:contrast:解析 tokens.css 亮暗两套变量(含 var() 与 color-mix 求值、半透明底先压到页面底),16 组文字×底色配对按 WCAG 公式算比值,低于阈值(正文 7 / 常规 4.5 / 禁用 2.6)退出码 1,--json 出逐对明细;不达标的三条配对通过修令牌达标;npm run check 全绿。",
|
||
"status": "done",
|
||
"domain": "visual",
|
||
"notes": "亮色 text-muted #6b7280→#676d78(凹陷底 4.39→4.72)、暗色 accent #378add→#4a9aeb(反白 3.92→4.77、强调文字压淡底 4.44→5.26),16 对全绿最低 4.58;接入 check 尾步 + AGENTS/README/ITERATION/CLI 清单同步"
|
||
},
|
||
{
|
||
"id": "g243",
|
||
"title": "文档站与演示页外壳配色从令牌派生",
|
||
"motivation": "两处外壳 chrome 各自手写十六进制(文档站 --bg/--accent、演示页 --page-*),改暗色 accent 后页面外壳仍留着旧蓝,与组件色各显示一种;这类漂移手写清单永远追不上令牌。",
|
||
"acceptance": "新增 packages/tools/cli/lib/shell-palette.mjs 作为唯一派生点(缺键退回内置默认,tokens.json 缺失不炸),文档站 renderDocs 与 apps/demo/build.mjs 都改为调用它;构建产物里的 --accent/--muted/--page-* 必须等于 tokens.json 对应值,源码不再出现外壳手写色值;npm run check 全绿。",
|
||
"status": "done",
|
||
"domain": "tooling",
|
||
"notes": "产物核对:docs --accent 亮 #185fa5 / 暗 #4a9aeb,demo --page-muted 亮 #676d78 / 暗 #888780,两处产物 378add 残留归零(tokens.css 注释里的旧值描述一并洗掉,避免 grep 误判)"
|
||
},
|
||
{
|
||
"id": "g244",
|
||
"title": "新增 inputTag 标签输入(组件 76)",
|
||
"motivation": "筛选条件、收件人、技能标签这类「输一串值」的输入只能靠 callers 自己拿 textField + tag 手拼,成标签 / 去重 / 退格删末个 / 满额禁输四件事每处各写一遍。",
|
||
"acceptance": "新增 inputTag:回车或逗号成标签、chip 可删、空框退格删末个、失焦自动入列,value 信号双向绑定,max 满额禁输、maxLength 截断、allowDuplicate 可开;样式只复用 .ua-input-group / .ua-tag,禁止新增硬编码阴影 / 时长 / 字号(audit:visual 保持 0);manifest + demo + README + 计数 + llms-full 全同步,npm run check 全绿。",
|
||
"status": "done",
|
||
"domain": "new",
|
||
"notes": "组件 75→76;样式仅 4 条排布规则(flex 换行 / 内距 / 收缩 / 溢出换行),全部走 --ua-space-* 与 --ua-control-h-md;单文件 78 行"
|
||
},
|
||
{
|
||
"id": "g245",
|
||
"title": "高对比偏好令牌 + 对比度门禁升到四套主题",
|
||
"motivation": "系统「提高对比度」偏好下组件毫无变化:边框仍是 0.15 透明黑、辅助文字仍是浅灰,低视力用户开了开关等于没开;而对比度门禁只验常规两套主题,覆盖不到这条路径。",
|
||
"acceptance": "tokens.css 末尾(媒体查询需后置胜出)加 @media (prefers-contrast: more):亮/暗两态分别加深 border / 滚动条、把 text-muted 升到次级档、text-faint 升到原辅助档,只改已有变量不新增名字(verify 双源核对保持一一对应);audit:contrast 解析该媒体块,把配对表在亮/暗 × 常规/高对比四套主题下各算一遍,附 --json 明细;npm run check 全绿。",
|
||
"status": "done",
|
||
"domain": "visual",
|
||
"notes": "高对比下辅助文字 4.85→7.49(亮)/4.72→8.71(暗)、三级文字 2.64→4.83,四套主题 16 对全绿;负向自检(把 text-faint 调亮)确认新主题会被判不达标"
|
||
},
|
||
{
|
||
"id": "g246",
|
||
"title": "ua info 支持 --md 输出 Markdown 片段",
|
||
"motivation": "Agent 或人要把单个组件的参数表贴进文档 / issue / 回复时,只能从文本版参数表里手抄对齐空格,抄完还要重新排表格;清单数据本来就在手里。",
|
||
"acceptance": "ua info <组件id> --md 输出标题 + 参数表 + 用法步骤 + 示例代码块,类型里的竖线自动转义(联合类型不截断表格),尾部保留「出现在配方」指路;文本版与 --json 输出不变,用法串与 AGENTS/清单文档同步;npm run check 全绿。",
|
||
"status": "done",
|
||
"domain": "tooling",
|
||
"notes": "与文本版共用 formatComponent 的数据源,只多一个渲染函数;select 的 'a'|'b' 联合类型已实测转义为 \\| 不破表"
|
||
}
|
||
]
|
||
}
|