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