iter(g272): 视觉抽查清单扩到十一个组件

This commit is contained in:
HIsheR
2026-10-26 22:58:03 +08:00
parent 2c08c11645
commit b6c2afbd97
3 changed files with 37 additions and 6 deletions
+1 -1
View File
@@ -29,7 +29,7 @@
**门禁一条龙**:`npm run check` = build + demo + style + typecheck + smoke + index + verify + lint-iterations + audit:visual + audit:contrast + audit:motion,提交前必过。其中 `smoke` 是两段内核断言:`@ui-arch/frame` 14 条(信号读写与同值短路、effect 注销与条件分支重追踪、computed 链式派生、多订阅者扇出)+ `@ui-arch/table-core` 31 条(排序 / 筛选 / 分页 / 选择的派生管线 + setRows 换源与失效行剔除 + 越界页码回写);改内核语义前先跑它,别靠组件 demo 肉眼验。`ua audit:visual` 统计皮肤包里十四类硬编码视觉字面量(字号 / 动效时长 / 阴影 / 圆角 / 焦点环 / 内距 / 控件高度 / 字重 / 行高 / 层级 / 边框色 / 混色浓度 / transform 位移 / 焦点描边)并与 `.ua/visual-baseline.json` 做棘轮:任一类超过基线即退出码 1 并指出疑似引入的提交;迁移脚本 `npm run visual:migrate` 可把字面量幂等改写成令牌。`ua audit:contrast` 走另一条线:把令牌里 18 组「前景色 × 底色」配对(正文/次级/辅助文字 × 页面底/表面/凹陷底、强调色与其反白、语义三色、禁用态豁免档、焦点描边 × 页面底/表面)按 WCAG 公式算成对比度(支持 `color-mix` 与 `var()` 求值,半透明底先压到页面底色上),亮 / 暗 × 常规 / 高对比四套主题各算一遍,低于阈值(正文 7 / 常规 4.5 / 禁用 2.6 / 非文本 3)即退出码 1;`--json` 出逐对明细,`--list` 只列配对表。改任一颜色令牌后它会立刻告诉你「改完谁读不清了」,不必等人工目测暗色。`ua audit:motion` 守的是动效面,两类必查:① 带 `infinite` 的动画是否在 `prefers-reduced-motion: reduce` 块里被 `animation: none` 关掉——循环动画是前庭敏感用户的硬伤,漏一条整页就在抖(它抓出过转圈与不确定态进度两处漏网);② 悬停 / 按压的位移(`translate`)是否在减少动效下归零——位移最容易诱发前庭不适,且只提供手感、不表达状态(一条 `ua-` 类通配的 `transform: none !important` 兜住全站 14 处,新增组件不用各自补)。`ua verify` 校验清单 ↔ 文档 ↔ 演示一致(docs.components 的 id 必须在 api.exports 有对应条目、props 必须带 n/t/d、每个文档字段名必须在组件实现源码里真实出现(改名后忘改文档会直接报错)、反向也校验 `src/types.ts` 里 `<组件>Props`(可用清单的 `propsType` 覆盖接口名,`false` 表示无入参)每个字段都在文档 props 表登记(新加字段忘了写文档会报错)、demo 锚点必须在 `apps/demo/main.ts` 中存在,且该组件必须被 demo 真实调用 `id(` / `id.`),反向也查孤儿演示(demo 里用 section() 定义的每个区块都必须被某个组件的 demo 字段认领,加了区块忘登记会直接报错),检查皮肤包样式表无硬编码颜色(`#hex` 一律禁止,必须走 `--ua-*` 令牌)与令牌引用有效(`var(--ua-*)` 必须是 tokens.css 已定义或组件自设的变量)、核对每个 `--ua-color-*` 都在 `[data-theme='dark']` 里有覆盖值且暗色块没有凭空多出的变量名(新增颜色令牌漏写暗色值直接报错)、核对 `tokens.json` 的 `color` 键与 tokens.css 的 `--ua-color-*` 同名同值(名字按 camelCase → kebab 折算,亮色值与暗色值都比,双向查漏——只改一处时文档色板会凭空多/少一个令牌,过去只能靠人眼发现)、核对 `@keyframes` 没有「帧体完全相同但名字不同」的复制粘贴(同一段动效只该有一份声明,改名复制会让方向 / 时长各写各的,翻转态就出现过「朝反方向入场」),核对 README 的 `<!-- ua:components -->` 区块与「分组:」行都覆盖清单组件集合(漏写/多写/重复都报错),并交叉校验 backlog 的 done 条目与 `.ua/iterations.log` 的 done 留痕一一对应(另外查 backlog id 不重复、g 编号严格递增、同一 id 只有一条 done 留痕,且留痕 ts 带 +08:00、时间线不回退、不落在未来——都是过去手工插条目/手写时间戳踩过的坑);配方还要求编号连续、每条都有代码块与要点,且代码块里至少认出一个已注册组件 id(拼错组件名时 `ua recipes` 会把它列成空组件表)。
`ua verify` 另外校验 `ITERATION.md` 的《视觉回归抽查清单》:button / textField / select / modal / dataTable / toast 六段各 ≥3 条可勾选要点、每条维度标签必须落在边框 / 阴影 / 过渡 / 焦点环 / 暗色五类内、合计 ≥18 条且五维度全覆盖——视觉类条目收尾前照单过一遍,改清单时别把条目删漏。
`ua verify` 另外校验 `ITERATION.md` 的《视觉回归抽查清单》:button / textField / select / modal / dataTable / toast / layout / jsonViewer / diffView / codeBlock / signaturePad 十一段各 ≥3 条可勾选要点、每条维度标签必须落在边框 / 阴影 / 过渡 / 焦点环 / 暗色五类内、合计 ≥33 条(下限由段数 × 3 推导,加抽查位不必手改)且五维度全覆盖——视觉类条目收尾前照单过一遍,改清单时别把条目删漏。
**变更日志**:`CHANGELOG.md` 由 git 提交史生成(`npm run changelog`),**不进 `npm run check`**——它包含每个提交自身,提交后必然与历史差一条,只能作为「发版前刷新」步骤;`npm run changelog:check` 用于确认是否漂移。
+32 -1
View File
@@ -66,7 +66,7 @@ qa/probe ──门禁通过──▶ qa/stable ──人工审阅──▶ main
## 视觉回归抽查清单(人工,视觉类条目收尾时逐条过)
视觉改动只能靠人眼验收,凭记忆看一遍必然漏项。本节把六个高频组件的观感要点固化成可勾选项,视觉类条目(`domain === "visual"`)提交前照单过一遍,勾不上的就是没做完。
视觉改动只能靠人眼验收,凭记忆看一遍必然漏项。本节把十一个代表组件(六个高频 + 容器 / 数据展示 / 表单录入各类一件)的观感要点固化成可勾选项,视觉类条目(`domain === "visual"`)提交前照单过一遍,勾不上的就是没做完。
- **格式约定**:三条横线以下是清单本体,每个组件一个 `### <组件id>` 段,每条以 `- [ ] 【维度】` 开头;维度取值固定五类:`边框` / `阴影` / `过渡` / `焦点环` / `暗色`。
- **门禁口径**:`ua verify` 校验本节存在、六个组件齐全、每个组件 ≥3 条、合计 ≥18 条、五个维度全覆盖;条目改写或删漏直接报错。
@@ -118,6 +118,37 @@ qa/probe ──门禁通过──▶ qa/stable ──人工审阅──▶ main
- [ ] 【过渡】进场 / 出场各一次,堆叠时其余条目平滑让位,不出现跳位
- [ ] 【暗色】四种语义色(info / success / warning / error)在暗底上图标与文字都不糊
### layout
- [ ] 【边框】页头细线与侧栏描边各只一道,两者交汇处不出现双线加深
- [ ] 【过渡】侧栏折叠展开展收干净,内容区不出现横向抖动或文字重排闪烁
- [ ] 【暗色】暗色下页头、侧栏、内容区三层表面能分出层次,不糊成同一块灰
### jsonViewer
- [ ] 【边框】嵌套层级的左侧竖线与容器外框同色同粗细,深三层不显重
- [ ] 【过渡】展开 / 收起即时切换,箭头旋转不与行高变化打架(不推动下方内容跳动)
- [ ] 【暗色】四种叶子类型(字符串 / 数字 / 布尔 / null)在凹陷底色上都能分辨,不互相撞色
- [ ] 【焦点环】Tab 到折叠开关时环贴住整行左缘,不被容器 overflow 裁掉
### diffView
- [ ] 【边框】统计条下沿与差异区之间只一条细线,与代码块头部观感一致
- [ ] 【过渡】滚动长差异时行底色不渗出双行号列,行号列保持静止
- [ ] 【暗色】增行为绿、删行为红的底色在暗底上仍可辨,文字对比不被底色吃掉
### codeBlock
- [ ] 【边框】头部与代码区之间一条细线,悬停整行提亮不出界、不盖住行号
- [ ] 【过渡】悬停提亮瞬时完成,连续快速移动不留下残影行
- [ ] 【暗色】行号(faint)与代码正文在凹陷底上对比都够,行号不糊到底色里
### signaturePad
- [ ] 【边框】画布与底部工具条之间一条细线,四角圆角裁切笔迹不溢出
- [ ] 【过渡】「清空」在未落笔时变为不可点,禁用态与可用态能一眼分清
- [ ] 【暗色】暗色下笔迹(走 text 令牌)在画布表面上清晰可见,不发灰
## 人工介入点
- 审阅 `qa/stable` 的提交,确认质量后合入 `main`(PR 或本地 merge 后推送)。
+4 -4
View File
@@ -1509,12 +1509,12 @@ function checkPropsDoc(pkg, comps) {
return issues;
}
/*** 视觉回归抽查清单校验:ITERATION.md 的清单必须六个高频组件齐全、每条带合法维度标签、条目数达标 ***/
/*** 视觉回归抽查清单校验:ITERATION.md 的清单必须十一个代表组件齐全、每条带合法维度标签、条目数达标 ***/
function checkVisualChecklist() {
const DIMS = ['边框', '阴影', '过渡', '焦点环', '暗色']; // 五个必覆盖维度
const REQUIRED = ['button', 'textField', 'select', 'modal', 'dataTable', 'toast']; // 六个代表组件
const REQUIRED = ['button', 'textField', 'select', 'modal', 'dataTable', 'toast', 'layout', 'jsonViewer', 'diffView', 'codeBlock', 'signaturePad']; // 十一个代表组件:先六个高频,再加「容器 / 数据展示 / 表单录入」三类新组件的抽查位
const MIN_PER_GROUP = 3; // 每个组件至少三条可勾选要点
const MIN_TOTAL = 18; // 清单总条目下限
const MIN_TOTAL = REQUIRED.length * MIN_PER_GROUP; // 总条目下限由组件数推导:加抽查位不用再手改这个数
const file = path.join(ROOT, 'ITERATION.md');
if (!fs.existsSync(file)) return ['视觉回归抽查清单:找不到 ITERATION.md'];
const lines = fs.readFileSync(file, 'utf8').replace(/\r\n/g, '\n').split('\n');
@@ -1629,7 +1629,7 @@ function cmdVerify() {
console.error(`${issues.length} violation(s)`);
process.exit(1);
}
console.log('verify OK (manifest ↔ docs ↔ demo 一致,文档 props ↔ 入参接口双向一致,皮肤无硬编码颜色与未定义令牌、暗色令牌齐全、tokens.json ↔ tokens.css 名字与值双源一致、@keyframes 无复制粘贴的重复帧、滚动容器全在细条规则内,README 组件清单与分组同步,backlog ↔ 留痕一致(编号严格递增、无重复 id、留痕时间线单调且带 +08:00),组合配方结构完整,MCP 工具清单三处一致,视觉回归抽查清单六组件 × 五维度齐全)');
console.log('verify OK (manifest ↔ docs ↔ demo 一致,文档 props ↔ 入参接口双向一致,皮肤无硬编码颜色与未定义令牌、暗色令牌齐全、tokens.json ↔ tokens.css 名字与值双源一致、@keyframes 无复制粘贴的重复帧、滚动容器全在细条规则内,README 组件清单与分组同步,backlog ↔ 留痕一致(编号严格递增、无重复 id、留痕时间线单调且带 +08:00),组合配方结构完整,MCP 工具清单三处一致,视觉回归抽查清单十一组件 × 五维度齐全)');
}
/*** 校验 git 提交信息是否符合 COMMITTING.md 规范(参数为 message 文件路径或直接 message 文本),违规退出码 1 ***/