iter(g340): verify 固化 toast live 门禁
This commit is contained in:
@@ -3446,6 +3446,15 @@
|
|||||||
"acceptance": "四方向各有一个与气泡同色的 45° 菱形箭头,全部用 --ua-* 令牌与百分比定位,audit:visual 棘轮零新增字面量",
|
"acceptance": "四方向各有一个与气泡同色的 45° 菱形箭头,全部用 --ua-* 令牌与百分比定位,audit:visual 棘轮零新增字面量",
|
||||||
"status": "done",
|
"status": "done",
|
||||||
"notes": ""
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "g340",
|
||||||
|
"domain": "tooling",
|
||||||
|
"title": "verify 固化 toast live 区域门禁",
|
||||||
|
"motivation": "g338 手工补的 aria-live / role=alert 没有门禁守护,回退成纯视觉 toast 不会被发现",
|
||||||
|
"acceptance": "verify 新增检查:skin 包 toast.ts 必须含 aria-live 容器与 alert 抢占播报,删掉任一处即红",
|
||||||
|
"status": "open",
|
||||||
|
"notes": ""
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1656,6 +1656,20 @@ function checkAriaNames(pkgs) {
|
|||||||
return issues;
|
return issues;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*** 校验 toast 的 live 区域:动态插入的通知读屏听不到容器外的变化,缺 aria-live / alert 抢占等于哑巴播报 ***/
|
||||||
|
function checkToastLive(pkgs) {
|
||||||
|
const issues = [];
|
||||||
|
for (const pkg of pkgs) {
|
||||||
|
if (pkg.type !== 'skin-dom') continue;
|
||||||
|
const toastPath = path.join(ROOT, pkg.dir, 'src', 'toast.ts');
|
||||||
|
if (!fs.existsSync(toastPath)) continue;
|
||||||
|
const src = fs.readFileSync(toastPath, 'utf8');
|
||||||
|
if (!/aria-live/.test(src)) issues.push(`${pkg.name}/src/toast.ts 缺 aria-live 容器:toast 是动态插入 DOM 的,没有 live 区域读屏用户感知不到通知出现`);
|
||||||
|
if (!/role: props\.variant === 'danger' \? 'alert' : 'status'/.test(src)) issues.push(`${pkg.name}/src/toast.ts 缺 alert 抢占播报:error 级别必须用 role=alert 打断读屏,其余才降级 polite`);
|
||||||
|
}
|
||||||
|
return issues;
|
||||||
|
}
|
||||||
|
|
||||||
/*** 校验同义词表:目标 id 必须真实存在(改名后残留会让回退指到空气),同一个词不得归两组(歧义会让结果随表序漂移) ***/
|
/*** 校验同义词表:目标 id 必须真实存在(改名后残留会让回退指到空气),同一个词不得归两组(歧义会让结果随表序漂移) ***/
|
||||||
function checkSynonyms(ids) {
|
function checkSynonyms(ids) {
|
||||||
const issues = [];
|
const issues = [];
|
||||||
@@ -1737,6 +1751,7 @@ function cmdVerify() {
|
|||||||
issues.push(...checkCountDocs(skinTotal));
|
issues.push(...checkCountDocs(skinTotal));
|
||||||
issues.push(...checkReadme(pkgs));
|
issues.push(...checkReadme(pkgs));
|
||||||
issues.push(...checkAriaNames(pkgs)); // 输入控件必须有可访问名
|
issues.push(...checkAriaNames(pkgs)); // 输入控件必须有可访问名
|
||||||
|
issues.push(...checkToastLive(pkgs)); // toast 必须有 live 区域与 alert 抢占
|
||||||
issues.push(...checkSynonyms(new Set(pkgs.flatMap((p) => (p.docs?.components ?? []).map((c) => c.id))))); // 同义词表指向的组件必须真实存在
|
issues.push(...checkSynonyms(new Set(pkgs.flatMap((p) => (p.docs?.components ?? []).map((c) => c.id))))); // 同义词表指向的组件必须真实存在
|
||||||
checkDarkTokens(issues);
|
checkDarkTokens(issues);
|
||||||
checkTokenParity(issues);
|
checkTokenParity(issues);
|
||||||
@@ -1749,7 +1764,7 @@ function cmdVerify() {
|
|||||||
console.error(`${issues.length} violation(s)`);
|
console.error(`${issues.length} violation(s)`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
console.log('verify OK (manifest ↔ docs ↔ demo 一致,文档 props ↔ 入参接口双向一致,皮肤无硬编码颜色与未定义令牌、暗色令牌齐全、tokens.json ↔ tokens.css 名字与值双源一致、@keyframes 无复制粘贴的重复帧、滚动容器全在细条规则内,README 组件清单与分组同步,backlog ↔ 留痕双向一致(编号严格递增、无重复 id、留痕时间线单调且带 +08:00,每个 iter 提交都有留痕),组合配方结构完整,MCP 工具清单三处一致,搜索同义词表目标存在且无歧义,combobox / slider / range 控件都有可访问名,视觉回归抽查清单十八组件 × 五维度齐全)');
|
console.log('verify OK (manifest ↔ docs ↔ demo 一致,文档 props ↔ 入参接口双向一致,皮肤无硬编码颜色与未定义令牌、暗色令牌齐全、tokens.json ↔ tokens.css 名字与值双源一致、@keyframes 无复制粘贴的重复帧、滚动容器全在细条规则内,README 组件清单与分组同步,backlog ↔ 留痕双向一致(编号严格递增、无重复 id、留痕时间线单调且带 +08:00,每个 iter 提交都有留痕),组合配方结构完整,MCP 工具清单三处一致,搜索同义词表目标存在且无歧义,combobox / slider / range 控件都有可访问名,toast 有 live 区域与 alert 抢占播报,视觉回归抽查清单十八组件 × 五维度齐全)');
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** 校验 git 提交信息是否符合 COMMITTING.md 规范(参数为 message 文件路径或直接 message 文本),违规退出码 1 ***/
|
/*** 校验 git 提交信息是否符合 COMMITTING.md 规范(参数为 message 文件路径或直接 message 文本),违规退出码 1 ***/
|
||||||
|
|||||||
Reference in New Issue
Block a user