agentcss 0.11.16 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/01-tokens/README.md +54 -3
- package/01-tokens/market.css +48 -0
- package/01-tokens/tokens.css +66 -0
- package/02-primitives/delta/README.md +92 -0
- package/02-primitives/delta/delta.css +113 -0
- package/02-primitives/delta/demo.html +162 -0
- package/02-primitives/metric/README.md +93 -0
- package/02-primitives/metric/demo.html +176 -0
- package/02-primitives/metric/metric.css +157 -0
- package/03-patterns/overlay/overlay.js +10 -4
- package/04-recipes/table/README.md +45 -7
- package/04-recipes/table/demo.html +92 -5
- package/04-recipes/tierA-tokens.css +12 -6
- package/API.md +15 -0
- package/CHANGELOG.md +295 -0
- package/CONTRIBUTING.md +54 -2
- package/README.zh-CN.md +8 -6
- package/START-HERE.md +3 -1
- package/ai/START-HERE.md +1 -1
- package/ai/cli.js +149 -0
- package/ai/components.json +96 -5
- package/ai/components.meta.json +8 -0
- package/ai/tokens.audience.json +3 -2
- package/ai/tokens.json +21 -2
- package/ai/tokens.tree.json +20 -2
- package/dist/01-tokens/market.css +1 -0
- package/dist/01-tokens/tokens.css +1 -1
- package/dist/02-primitives/delta/delta.css +1 -0
- package/dist/02-primitives/metric/metric.css +1 -0
- package/dist/04-recipes/tierA-tokens.css +1 -1
- package/dist/COSTS.md +35 -33
- package/docs/A11Y-MANUAL-PROTOCOL.md +8 -0
- package/docs/ACCESSIBILITY.md +5 -5
- package/docs/CONVENTIONS.md +36 -2
- package/index.html +4 -2
- package/package.json +1 -1
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
/* ============================================================================
|
|
2
|
-
|
|
2
|
+
精简档:内联用令牌(单文件 / 无构建项目)
|
|
3
3
|
============================================================================
|
|
4
4
|
本文件由 `python 05-audit/make-tiersnippet.py` 从 01-tokens/tokens.css
|
|
5
5
|
**自动抽取**,请不要手改 —— 改源头,然后重新生成。
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
"精简档只需复制 tokens.css 的 [核心] 段",
|
|
9
|
-
但**那个区块从来不存在**。复用的人照着做只会找不到。
|
|
10
|
-
这个文件就是那个"核心",真的、能复制、能用。
|
|
7
|
+
用法:整段复制进 `<style>`,零外链、零构建。
|
|
11
8
|
|
|
12
|
-
|
|
9
|
+
它只含**中间层语义令牌**(L1 原语已内联成具体值),所以体积小、能直接改;
|
|
10
|
+
但它**不含** `market.css` 的涨跌口径切换 —— 需要国际口径时见
|
|
11
|
+
`01-tokens/README.md` 的「涨跌口径」一节。
|
|
12
|
+
|
|
13
|
+
体积:浅色 104 个令牌 + 暗色 35 个,零外链零构建。
|
|
13
14
|
--------------------------------------------------------------------- */
|
|
14
15
|
|
|
15
16
|
:root {
|
|
@@ -68,6 +69,9 @@
|
|
|
68
69
|
--warning-bg: #fbf1dd;
|
|
69
70
|
--info-bg: #e8f1f8;
|
|
70
71
|
|
|
72
|
+
--dir-up: #c0392b;
|
|
73
|
+
--dir-down: #2f6b3a;
|
|
74
|
+
|
|
71
75
|
--accent: #1b4d8f;
|
|
72
76
|
--switch-on: #1b4d8f;
|
|
73
77
|
--accent-hover: #163a6d;
|
|
@@ -169,6 +173,8 @@
|
|
|
169
173
|
--danger-bg: #341D1A;
|
|
170
174
|
--success: #6FAA7A;
|
|
171
175
|
--success-bg: #16241A;
|
|
176
|
+
--dir-up: #E07A6E;
|
|
177
|
+
--dir-down: #6FAA7A;
|
|
172
178
|
--warning: #C99A3F;
|
|
173
179
|
|
|
174
180
|
--warning-bg: #242A31;
|
package/API.md
CHANGED
|
@@ -329,9 +329,24 @@ python3 05-audit/prefix-build.py --prefix fl
|
|
|
329
329
|
| `--border-decor` | ✅ | 分隔线 |
|
|
330
330
|
| `--shadow-1` / `--shadow-2` | ✅ | 阴影 |
|
|
331
331
|
| `--dur` / `--ease-out` | ✅ | 动效 |
|
|
332
|
+
| `--dir-up` / `--dir-down` | ✅ | 涨跌方向色(**方向 ≠ 好恶**:默认红涨绿跌,`[data-market="intl"]` 整体对调) |
|
|
332
333
|
|
|
333
334
|
新增令牌算**小版本变更**;移除或改默认值算**破坏性变更**。
|
|
334
335
|
|
|
336
|
+
### 口径切换:`[data-market]`
|
|
337
|
+
|
|
338
|
+
涨跌配色是**全局约定**,不是组件参数:
|
|
339
|
+
|
|
340
|
+
| 写法 | 效果 |
|
|
341
|
+
|---|---|
|
|
342
|
+
| 不写 | A 股口径:涨 = 红、跌 = 绿 |
|
|
343
|
+
| `<html data-market="intl">` | 国际口径:涨 = 绿、跌 = 红 |
|
|
344
|
+
| `<section data-market="intl">` | 只切这一块 |
|
|
345
|
+
|
|
346
|
+
实现方式是**换令牌的指向**(`--dir-up` 永远表示"涨"),组件 CSS 里没有任何分支
|
|
347
|
+
—— 与暗色同一手法。`05-audit/delta-check.js` 在浏览器里读 computed color,
|
|
348
|
+
四种组合(两种口径 × 明暗)各判一遍,并断言 `intl` 是**完整互换**而不是只改一边。
|
|
349
|
+
|
|
335
350
|
---
|
|
336
351
|
|
|
337
352
|
## 无障碍保证
|
package/CHANGELOG.md
CHANGED
|
@@ -16,6 +16,301 @@
|
|
|
16
16
|
|
|
17
17
|
(无)
|
|
18
18
|
|
|
19
|
+
## [0.13.1] - 2026-10-30
|
|
20
|
+
|
|
21
|
+
**补录 Linux 三套视觉基线。0.13.0 的 tag 因这处过期未通过发布门禁,包没有发出去
|
|
22
|
+
—— npm 上不存在 0.13.0。本版本内容 = 0.13.0 + 基线对齐。**
|
|
23
|
+
|
|
24
|
+
0.12.1 改了 `04-recipes/table/demo.html`(新增第 6 节两栏对照,页面高度
|
|
25
|
+
`4540` → `5653`),当时只重录了 Windows 的三套基线。Linux 三套仍指向旧代码,
|
|
26
|
+
而**基线与指纹戳是按平台分集的** —— 本机的 `visual-stamp` 只核本平台,
|
|
27
|
+
于是「212 道全绿」在这件事上的保证范围**仅限 Windows**,Linux 那三套要到
|
|
28
|
+
CI 上才暴露。
|
|
29
|
+
|
|
30
|
+
重录后逐张核对:三套各**只有** `04-recipes_table.png` 变化(418 KB → 556 KB),
|
|
31
|
+
其余 `43 / 43 / 14` 张**逐字节相同**。这同时证明渲染环境没有漂移,
|
|
32
|
+
变化只来自表格页新增的那一节。
|
|
33
|
+
|
|
34
|
+
`CONTRIBUTING.md` 补了基线纪律:改 demo 的**结构**(页面高度会变)⇒
|
|
35
|
+
所有已有平台的基线都要重录,不只本机;Linux 那套走
|
|
36
|
+
Actions → release → Run workflow → 勾 `shoot_baseline`,
|
|
37
|
+
**不要**在本机 `--record`(那录的是 Windows 的渲染,等于污染基准)。
|
|
38
|
+
|
|
39
|
+
## [0.13.0] - 2026-10-30
|
|
40
|
+
|
|
41
|
+
**门禁体系从「两态」变成「三态」,并补上四道真能红的门禁。
|
|
42
|
+
`SKIP` 从此是一个独立的、不计入通过了的结果 —— 在此之前,
|
|
43
|
+
「我没跑」只能靠 `return 0` 表达,于是它被显示成 PASS。**
|
|
44
|
+
|
|
45
|
+
组件 CSS 产物本轮只动了一处注释,所以对**使用者**而言这是个空版本;
|
|
46
|
+
真正的变化在「你怎么知道它是对的」这条链上。
|
|
47
|
+
|
|
48
|
+
### 新增能力
|
|
49
|
+
|
|
50
|
+
- **`node ai/cli.js assets`** —— 列出**全部**可复用资产(49 项),
|
|
51
|
+
不再只覆盖「有独立 CSS 的组件目录」。此前 `longform`(单文件长文示例页)、
|
|
52
|
+
`data-showcase`、`echarts-adapter`、`01-tokens/page.css`(页面骨架)、
|
|
53
|
+
`01-tokens/behavior/`(三个共享微行为核)对机器不可见 ——
|
|
54
|
+
而 AI 不知道有 `page.css` 就会自己写布局,不知道有 `behavior/` 就会重写
|
|
55
|
+
「Esc 关闭 + 焦点归还」。清单**从目录扫描生成**,不维护第二份手工列表。
|
|
56
|
+
- **`benchmark/REAL-PAGE-TASKS.md`** —— P01–P10 十个页面级生成任务,
|
|
57
|
+
每个给出「需求 → 必须用到的库能力 → 自动判据 → 参考结果」,配 A/B 对照协议、
|
|
58
|
+
记录格式与统计口径。定位是**效果验证**,与既有的 T01–T10(契约层)分开报告。
|
|
59
|
+
- **`benchmark/score-page.js`** —— 对**任意** HTML 打分的 5 条静态判据。
|
|
60
|
+
既有的 `a11y-ax` / `responsive-check` / `zoom-reflow` 页面清单是内置页常量,
|
|
61
|
+
指不到新生成的文件 ⇒ 不能拿它们给生成页打分,这是另写一个的原因。
|
|
62
|
+
库类覆盖率阈值 `0.6` 是拿参考页实测 `0.696` 校准的,反向控制 3 条全绿。
|
|
63
|
+
|
|
64
|
+
### 修掉的真缺陷
|
|
65
|
+
|
|
66
|
+
- **门禁跑完不退出(必然死锁)** `check-all.sh` 的主等待是裸 `wait`,
|
|
67
|
+
而它会等**本 shell 起的全部子进程** —— 包括脚本自己启动的静态服务,
|
|
68
|
+
那个服务永不退出 ⇒ 208 道跑完后进程无限挂起,只能人工 kill。
|
|
69
|
+
实测复现:`sleep 30 & wait` 超时 `124`;加 `disown` 后 **0.076 秒**返回。
|
|
70
|
+
⇒ 起服务后 `disown`。
|
|
71
|
+
- **临时目录只增不减(21.2 GB)** `FL_TMPDIR` 只 `mkdir -p`、从不清理;
|
|
72
|
+
更隐蔽的是第 565 行的 `trap ... EXIT` **覆盖**了第 171 行的清理 trap
|
|
73
|
+
(bash 的 trap 是替换,不是追加)⇒ 浏览器 profile 一个都删不掉。
|
|
74
|
+
⇒ 合并成唯一出口,并且只清理本脚本自己设的默认目录(用户显式指定的不碰)。
|
|
75
|
+
清理时另揪出 8 个孤儿 headless 浏览器仍占着 profile 目录。
|
|
76
|
+
- **两道门禁把「没跑」说成「通过」** `engine-gate` 在可用引擎 < 2 时 `return 0`;
|
|
77
|
+
`benchmark --check-records` 把参考解法数成「模型记录」。两者都被汇总显示为 PASS。
|
|
78
|
+
⇒ `check-all.sh` 引入第三态 **`rc=3` = 未判定**,单独计数;
|
|
79
|
+
有未判定项时**不再打印「已执行的全部通过」**这种容易被读成全绿的措辞。
|
|
80
|
+
(没用 `2`:已有 9 道门禁用 `exit(2)` 表示「参数错 / 前置不满足」,
|
|
81
|
+
把 2 定义成跳过会把这些真错误静默吞掉。)
|
|
82
|
+
- **资产发现的三处遗漏**(详见上节「新增能力」的 `ai assets` 条目)。
|
|
83
|
+
|
|
84
|
+
### 新增门禁(4 道,均带反向控制)
|
|
85
|
+
|
|
86
|
+
| 门禁 | 它守什么 | 反向控制 |
|
|
87
|
+
|---|---|---|
|
|
88
|
+
| `assets-catalog` | 磁盘目录 / 契约 / CLI 三方对账 | 注入空目录 ⇒ 红;`_` 前缀目录 ⇒ 不算资产 |
|
|
89
|
+
| `zero-dep` | 「零第三方运行时依赖」这条对外承诺 | 往 `dependencies` 注入 `lodash` ⇒ 红 |
|
|
90
|
+
| `pattern-behavior` | **组件有没有真的接上行为核**(13 条) | 关掉遮罩关闭 / 不归还焦点 ⇒ 红 |
|
|
91
|
+
| `benchmark-score` | 评分器自身的判据合成 | 3 条破坏样本 ⇒ 红 |
|
|
92
|
+
|
|
93
|
+
`zero-dep` 值得单说:README 第一句就是「零依赖」,而此前**没有任何门禁读
|
|
94
|
+
`dependencies`**。注入 `lodash` 后 `doc-facts` / `dist:check` / `npm test`
|
|
95
|
+
**三道全部 RC=0** —— 核心承诺被违反时全库不会发现。
|
|
96
|
+
|
|
97
|
+
`pattern-behavior` 与既有的 `dismissable-check` / `focus-return-check` 分工不同:
|
|
98
|
+
后者测**核本身**(把核注入空白页直接调),前者测**接线**(通过组件真实 API
|
|
99
|
+
开一个抽屉,验焦点是否进入、Esc 是否只关最内层、点遮罩是否符合该组件自己的语义)。
|
|
100
|
+
|
|
101
|
+
### 文档对齐
|
|
102
|
+
|
|
103
|
+
- `CONTRIBUTING.md`:补「全量为什么**不**在 CI 上跑」的完整理由与责任边界;
|
|
104
|
+
补 `rc=3` 三态表;补「失败时先读 `internal/tmp/selftest-fail-*.log`」。
|
|
105
|
+
- `docs/A11Y-MANUAL-PROTOCOL.md`:结果表补 `accordion` / `drawer` / `dropdown`
|
|
106
|
+
三行 —— 三个 beta 组件此前一个都不在表内,而「beta 升 stable」的判据之一
|
|
107
|
+
就是行为零欠账,人工读屏是唯一的用户侧证据。**状态仍写「未执行」**:
|
|
108
|
+
加行不等于做过。
|
|
109
|
+
|
|
110
|
+
### 未改(诚实登记)
|
|
111
|
+
|
|
112
|
+
- **真实模型跑批仍是 0 条**。`benchmark --check-records` 现在会显示 **SKIP**,
|
|
113
|
+
这不是故障,是它在说「还没有真实记录」。转述时不要把它说成通过。
|
|
114
|
+
- **人工读屏仍未执行**:需要一台装读屏软件的机器与人耳,已在协议里标 `NOT_TESTED`。
|
|
115
|
+
- 一处**等价突变体**:`overlay.js` 里删除 `stopPropagation` 抓不到红。实测
|
|
116
|
+
`outer.contains(inner) === false`(两个 backdrop 是兄弟节点),拦不拦行为一样。
|
|
117
|
+
保留该行(未来若改成真嵌套就必需),但注释已改为说明**真实机制**,
|
|
118
|
+
而不是原先那句把假设写成事实的「不拦会一次关两层」。
|
|
119
|
+
|
|
120
|
+
## [0.12.1] - 2026-10-29
|
|
121
|
+
|
|
122
|
+
**把 `table` 与 `delta` 接上:市场涨跌以 `delta` 嵌进单元格,
|
|
123
|
+
表格不再需要第四组颜色类;顺带修掉「零值被印成正号」。**
|
|
124
|
+
|
|
125
|
+
这是 0.12.0 留下的那条自认缺口(`table/README.md` 原话:「目前**没有解**」)。
|
|
126
|
+
解法不是当初列的两个候选(加 `num--up/down` 或 `data-polarity`),而是第三条:
|
|
127
|
+
**方向是独立语义,所以它继续待在独立原子里,表格只负责对齐。**
|
|
128
|
+
|
|
129
|
+
### 修掉的真缺陷
|
|
130
|
+
|
|
131
|
+
- **E145 · 零值被印成正号** `format: 'signed-percent'` 的正号由类名触发,
|
|
132
|
+
而旧实现判的是 `v < 0` ⇒ `v === 0` 掉进 else 得到 `num--pos`,渲染成「**+0.0%**」——
|
|
133
|
+
一个没变化的数被念成"涨了"。四舍五入处同样复现:`0.0004` 在 1 位精度下也印成「+0.0%」。
|
|
134
|
+
⇒ 改成「先算打印值,再按它定符号」,与 `delta--flat` 同一个契约。
|
|
135
|
+
(**不是门禁发现的** —— 门禁只验它写了判据的东西。这条是有人顺着 demo 源码
|
|
136
|
+
读下来才看见的,记在这里提醒自己:判据的边界就是视野的边界。)
|
|
137
|
+
|
|
138
|
+
### 本轮流程上踩的坑(详见 `internal/ERRORS.md` E146–E148)
|
|
139
|
+
|
|
140
|
+
- **E146** 新判据 F7 的豁免条件第一版用 `or` 连接「版本号」与「过去时语汇」,
|
|
141
|
+
结果 `docs/ACCESSIBILITY.md` 表格行里的 WCAG 编号「**4.1.2**」被当成版本号
|
|
142
|
+
⇒ 整行豁免 ⇒ **判据对它自己最该管的那一行完全失效**。破坏实验才发现。
|
|
143
|
+
- **E147** 同一份文档的「适用版本 `0.11.9`」与「38 个 demo 页」跨了三个版本没人改。
|
|
144
|
+
这类数字只有加了 F7/F8 才第一次被机器看见。
|
|
145
|
+
- **E148** 我在本文件初稿里写了一条**没发生过的缺陷**("table demo 写了 `data-market`
|
|
146
|
+
却没引 `market.css`")。核对 `git show HEAD:` 发现改前那个 demo 里 `data-market`
|
|
147
|
+
出现 **0 次** —— 是我把"我要新增的东西"误记成"原来就有的漏洞"。已删。
|
|
148
|
+
|
|
149
|
+
### 新增
|
|
150
|
+
|
|
151
|
+
- `04-recipes/table/demo.html` 第 6 节:**同一张表里的两种方向语义**。
|
|
152
|
+
两块数据逐字相同,只有外层 `data-market` 不同 —— 会计列一个字不变,市场列整体翻转。
|
|
153
|
+
零值那一行两边都不带符号。
|
|
154
|
+
- `table-check.js` 三条判据(该门禁的专属判据 14 → 17 条):
|
|
155
|
+
- ⑫ 符号与打印值同号(**且要求页面上真的存在零值样本**,删掉零值行不能算通过)
|
|
156
|
+
- ⑬ 市场涨跌用 `delta` + `table.css` 不许出现 `num--up/down` + intl 只翻市场列
|
|
157
|
+
- ⑭ 393px 下单元格内的 `delta` 不溢出(量几何,不看声明)
|
|
158
|
+
三次破坏实验确认判别力:退回旧符号逻辑 ⇒ ⑫ 红;给 `table.css` 加 `num--up` ⇒ ⑬ 红;
|
|
159
|
+
把 intl 块改成 cn ⇒ ⑬ 红。
|
|
160
|
+
- `doc-facts-gate` 新增 F7:文档里的「全部 N 个 demo 页」必须等于磁盘份数。
|
|
161
|
+
它第一次跑就抓到 `CONTRIBUTING.md` 的旧数字,也抓到本门禁自己的一处设计错误
|
|
162
|
+
(拿 WCAG 编号「4.1.2」当版本号 ⇒ 整行被豁免 ⇒ 判据对目标文件完全失效)。
|
|
163
|
+
- `doc-facts-gate` 新增 F8:「无障碍声明适用版本」必须等于 `VERSION`。
|
|
164
|
+
|
|
165
|
+
### 文档对齐
|
|
166
|
+
|
|
167
|
+
- `docs/ACCESSIBILITY.md`:适用版本 `0.11.9` → `0.12.1`;
|
|
168
|
+
覆盖数 38 → **40**(a11y-ax)/ 39(axe)/ 40(zoom-reflow)——
|
|
169
|
+
三个工具各自口径不同,原先把它们写成同一个 38 是错的。
|
|
170
|
+
- `04-recipes/table/README.md`:「未来没有解」改写为解法与取舍,并补零值规则。
|
|
171
|
+
|
|
172
|
+
### 未改(诚实登记)
|
|
173
|
+
|
|
174
|
+
- `axe` 的 991 条规则通过数、`zoom-reflow` 的 3 条 AA 硬项结果都是上一轮实测值,
|
|
175
|
+
本版没有重跑这两个工具(只重跑了 `a11y-ax`)。数字沿用,但**不声称本轮复核过**。
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## [0.12.0] - 2026-10-29
|
|
180
|
+
|
|
181
|
+
**新增两个组件:`delta`(变化量)与 `metric`(指标块)。这是「数值展示层」的第一批。**
|
|
182
|
+
|
|
183
|
+
起因是一条量出来的空白:拿「做一张 A 股财报分析页」当尺子逐段量现有 35 个组件,
|
|
184
|
+
**KPI 数字行那一整段是空的** —— 全库没有 `metric` / `statistic` / `kpi`,
|
|
185
|
+
`.stat__*` 只是 `table--stats` 预设下的统计单元格(标准误、p 值)。
|
|
186
|
+
|
|
187
|
+
更具体的一处:`table` 的 `num--pos` / `num--neg` 是**会计约定**(正 = 绿、负数即红字),
|
|
188
|
+
而 A 股涨跌幅是**市场约定**(涨 = 红)。两者塞进同一列会打架 ——
|
|
189
|
+
这条此前登记在 `04-recipes/table/README.md` 的「已知未统一」里,列了两个候选解法
|
|
190
|
+
(给 `table` 加 `num--up/down`,或加 `data-polarity`),**都说明没解**。
|
|
191
|
+
|
|
192
|
+
这一版走第三条路:涨跌不该由 `table` 的颜色类承担,而该由一个**独立原子**承担。
|
|
193
|
+
`delta` 自带市场语义、自带符号,放进任何单元格都不会被 `num--pos/neg` 命中;
|
|
194
|
+
`table` 一行不用改,会计约定保持不动。
|
|
195
|
+
|
|
196
|
+
### ① 方向色独立成令牌:`--dir-up` / `--dir-down`
|
|
197
|
+
|
|
198
|
+
不复用 `--danger` / `--success`。这两组读起来都是红绿,但它们是两件事:
|
|
199
|
+
|
|
200
|
+
| 令牌 | 语义 | 例子 |
|
|
201
|
+
|---|---|---|
|
|
202
|
+
| `--danger` / `--success` | **评价**(错了 / 成了) | 已停牌、审计失败 |
|
|
203
|
+
| `--dir-up` / `--dir-down` | **事实**(涨了 / 跌了) | 同比 +12.4% |
|
|
204
|
+
|
|
205
|
+
一句就够说明为什么不能共用:「研发费用同比 +38%」是**涨**,但那是成本失控。
|
|
206
|
+
用 `--danger` 渲染它,颜色说着“错了”,语义说着“涨了”,读者收到矛盾信号。
|
|
207
|
+
|
|
208
|
+
当前取值与 `--danger`/`--success` 相同(这是巧,不是同一件事),但允许将来单独调
|
|
209
|
+
—— 金融终端普遍用比 `--danger` 更饱和的红。
|
|
210
|
+
|
|
211
|
+
实测对比度(`contrast.py`,四组底各算一遍):
|
|
212
|
+
浅色红 4.89–5.44 / 绿 5.75–5.96;暗色红 5.60–6.15 / 绿 6.01–6.60,全部 AA。
|
|
213
|
+
|
|
214
|
+
### ② 口径可整体切换:`[data-market="intl"]`
|
|
215
|
+
|
|
216
|
+
默认 A 股(红涨绿跌)。给任意祖先加 `data-market="intl"` 切成国际口径。
|
|
217
|
+
实现与暗色同构:`--dir-up` 永远表示“涨”,切换只改**令牌的指向**,
|
|
218
|
+
组件 CSS 里没有任何分支 —— 两栏 HTML 逐字相同,只差那个属性。
|
|
219
|
+
|
|
220
|
+
交换规则放在**独立可选文件** `01-tokens/market.css`:引它才有国际口径,
|
|
221
|
+
不引就永远是 A 股口径、`data-market` 被完全忽略。核心令牌不放条件规则
|
|
222
|
+
(原因见下面 E137 —— 那会让五六个工具静默读错)。
|
|
223
|
+
|
|
224
|
+
### ③ `metric`:缺数是一等状态
|
|
225
|
+
|
|
226
|
+
`metric--null` + 值写 `—`(U+2014)+ 脚下说明原因。三条禁止都进了判据:
|
|
227
|
+
不填 0(`0.00` 是“现金流为零”这个具体结论)、不留空、不用 `opacity` 压淡
|
|
228
|
+
(`--text-tertiary` 的 5.33:1 已是地板)。
|
|
229
|
+
|
|
230
|
+
单位独立成槽位(`metric__unit`),不拼进值字符串 —— 与 `table__unit` 同一理由。
|
|
231
|
+
|
|
232
|
+
### 过程中踩到并修掉的五个真缺陷
|
|
233
|
+
|
|
234
|
+
- **E134**:我在 `:root { }` 里写了一个 `[data-market]` 规则块。`theme-sync.py`
|
|
235
|
+
按「声明序列」解析这个块,遇到嵌套规则把选择器切碎,生成了一段
|
|
236
|
+
`where([data-market="intl"]) { … }` —— 无效 CSS,且第二条声明丢失。
|
|
237
|
+
CSS 的 `:root` 只能装声明。(`theme-sync` 本身没坏,是我喂了它不认识的形状。)
|
|
238
|
+
- **E135**:口径交换写成了 `:where([data-market="intl"])`,想把特异性压到 0。
|
|
239
|
+
**实测完全不生效** —— `:where()` 是 0,`:root` 是 (0,1,0),两者都匹配 `<html>`,
|
|
240
|
+
`:root` 赢。压得越低越抢不过。改成 `:root[data-market="intl"]`,并**挪到两个主题
|
|
241
|
+
属性段之后**(它们由 `theme-sync` 生成,会连 L2 一起重声明,同权重下靠顺序定胜负)。
|
|
242
|
+
- **E136**:`delta-check` 的「红涨」判据第一版写的是 `up === --danger`。
|
|
243
|
+
这是**假判据**:把整个色板对调(danger 改成绿)之后它照样绿,因为两边一起变了。
|
|
244
|
+
「红涨」说的是颜色本身,只能判**色相**(红区 ≤20° 或 ≥345°,绿区 90–165°)。
|
|
245
|
+
- **E137**:口径交换规则最初写在 `tokens.css` 末尾,直接污染了工具链。
|
|
246
|
+
`05-audit/_css.py` 的 `declared_tokens()` 是**纯词法**的 —— 遍历所有 `--x: y;`,
|
|
247
|
+
后者覆盖前者,**不看选择器**。于是它把「条件性交换」当成默认值叠上去:
|
|
248
|
+
`contrast.py` 报告里「暗色 涨」显示成绿色,`token-tree-gate` 报「浏览器解析到了
|
|
249
|
+
`--dir-down`,导出里没有」,`gen-ai-contract --check` 报看似随机的错位 ——
|
|
250
|
+
而浏览器里的值一直是对的。**门禁冤枉代码比漏判更难查。**
|
|
251
|
+
修法:交换规则移到独立可选文件 `01-tokens/market.css`,`tokens.css` 只留说明注释。
|
|
252
|
+
- **E138**:E137 的修法又带出一个新缺陷 —— 把规则挪到 `market.css` 之后,
|
|
253
|
+
`delta` 的 demo **没跟着引新文件**,那一栏「国际口径」静默显示成 A 股配色:
|
|
254
|
+
页面在说谎,而所有门禁都是绿的(CSS 不报错,`data-market` 属性也照样存在,
|
|
255
|
+
只是没东西接它)。修法:demo 补引用,并给 `delta-check` 加判据 ⑧ ——
|
|
256
|
+
用了 `data-market` 的页面必须引 `market.css` 且排在 `tokens.css` 之后,
|
|
257
|
+
92 个页面全扫描(破坏实验确认删掉引用会红)。
|
|
258
|
+
|
|
259
|
+
### 全量门禁又抓出六个(E139–E144)
|
|
260
|
+
|
|
261
|
+
本地单项验证绿了不等于全量绿 —— 这一轮全量门禁(208 项)第二次跑才发现:
|
|
262
|
+
|
|
263
|
+
- **E139**:`tierA-tokens.css`(精简档)漂了两轮没人管。文件本身有 `--check`,
|
|
264
|
+
但它**连 `--dir-*` 都没有**(用户写 `var(--dir-up)` 会拿到未定义令牌),
|
|
265
|
+
文档里「浅色 102 + 暗色 33」也停在旧值。⇒ 重抽文件 + `doc-facts-gate` 加 F6,
|
|
266
|
+
把「浅色 N + 暗色 M」变成可核对的判据。
|
|
267
|
+
- **E140**:两个新门禁起名 `dir-gate` / `metric-gate`,而成熟度探测器要求
|
|
268
|
+
文件名含 `check`/`contract`/`geometry` ⇒ 「有没有专属门禁」判 False,
|
|
269
|
+
两个组件被判成 `alpha`。⇒ 改名 `delta-check.js` / `metric-check.js`,
|
|
270
|
+
重新生成契约(**stable 33 / beta 4**)。
|
|
271
|
+
- **E141**:脚本删块加注释时漏了 `*/`,`tokens.css` 后半段(含字体栈)
|
|
272
|
+
被整段注释吞掉;而**视觉基线是在那之后录的**。⇒ 补闭合、先跑语法级判据再录基线。
|
|
273
|
+
- **E142**:库里早有 `.num` / `.num-lg`(`typography.css`),我又在两个组件里
|
|
274
|
+
各写了一遍 `font-variant-numeric`。⇒ 不是加豁免,而是**删掉**:
|
|
275
|
+
两个原子都用 `--mono`,等宽字族天然对齐,那条声明是无效动作。
|
|
276
|
+
- **E143**:`metric` 的值写了 `white-space: nowrap`,单位是它的子元素 ⇒
|
|
277
|
+
RTL 下阿语膨胀后顶破视口 212px。⇒ 值改 flex + `overflow-wrap: anywhere`,
|
|
278
|
+
单位 `min-width: 0`。
|
|
279
|
+
- **E144**:精简档生成器的头注释里写着内部协作用语,
|
|
280
|
+
随包发布 ⇒ `leak-scan` 报「过程痕迹」。⇒ 改生成器文案(产物注释只写给使用者看)。
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
`delta` 的 `+` / `−` 由 CSS `::before` 生成,所以它们**不在** `textContent` 里。
|
|
285
|
+
实测(Chromium + CDP 可访问性树):元素的可访问名字只有 `3.21%`,**不含符号**;
|
|
286
|
+
但符号作为**独立的 StaticText 节点**存在,读屏会按顺序念「加」「3.21%」。
|
|
287
|
+
|
|
288
|
+
也就是说「符号对读屏可用」是成立的 —— 但成立在一个很容易被改坏的机制上:
|
|
289
|
+
换成空串、换成背景图、或让伪元素 `visibility: hidden`,视觉上可能仍有符号,
|
|
290
|
+
可访问性树里就没了,而颜色对读屏毫无意义。
|
|
291
|
+
|
|
292
|
+
⇒ `delta-check` 加了判据 ⑦:直接数十字树里的 `+` / `−` 节点。
|
|
293
|
+
破坏实验(给 `::before` 加 `visibility: hidden`)确认它会红。
|
|
294
|
+
|
|
295
|
+
### 门禁 204 → 208
|
|
296
|
+
|
|
297
|
+
新增 `dir-color` / `dir-color-rev` / `metric` / `metric-rev`。
|
|
298
|
+
两道主门禁都要起浏览器,自检不需要(纯判据)。
|
|
299
|
+
三个新组件页全部纳入视觉基线(明/暗/RTL 各三张)与无障碍树快照(38 → 40 页)。
|
|
300
|
+
|
|
301
|
+
CSS 体积预算 125 → **132 KB**(剥注释后口径):两个新组件 + `market.css` 的
|
|
302
|
+
真实规则合计 +2.1 KB(127.1 KB 实测)。**这是有意增长,不是放宽**——
|
|
303
|
+
涨的是规则,不是注释;单文件上限仍是 24 KB(最大 `tokens.css` 14.4 KB)。
|
|
304
|
+
|
|
305
|
+
### 已知边界
|
|
306
|
+
|
|
307
|
+
- `delta` 的方向**不由数值推断**(没有 JS)。类名写错就颜色错且不报错 ——
|
|
308
|
+
这是有意的:本库不带运行时,读数值意味着把格式化逻辑也拉进来。
|
|
309
|
+
- `metric` 不做数值格式化(千分位、小数位、单位换算归数据侧)。
|
|
310
|
+
- 真机读屏(NVDA / VoiceOver)仍是 0 条记录,`docs/A11Y-MANUAL-PROTOCOL.md` 表格还是空的。
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
19
314
|
## [0.11.16] - 2026-10-29
|
|
20
315
|
|
|
21
316
|
**这一版没有新组件,补的是两处「说了但没做到」。**
|
package/CONTRIBUTING.md
CHANGED
|
@@ -8,10 +8,48 @@ npm run gate # 全量:含浏览器类
|
|
|
8
8
|
npm run gate:fast # 只跑静态层,不用装浏览器
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
全量是 **
|
|
12
|
-
0.11.15 起默认 4
|
|
11
|
+
全量是 **212 道门禁**(4 路并发实测约 9 分钟 / 退出码 0;单道耗时累加 1691 秒,
|
|
12
|
+
组件层要起浏览器,还要逐张比 96 张视觉截图。0.11.15 起默认 4 路并发)。
|
|
13
13
|
只想确认没改坏静态契约的话用 `gate:fast`,几秒到几分钟。
|
|
14
14
|
|
|
15
|
+
### 全量为什么**不**在 CI 上跑(这不是缺口,是结论)
|
|
16
|
+
|
|
17
|
+
`.github/workflows/gate.yml` 分三层:`quick`(`MODE=fast`,静态 + 视觉)、
|
|
18
|
+
`contract`(API 契约,需 Chromium)、`browsers`(nightly,三引擎矩阵)。
|
|
19
|
+
**没有任何一处是 `MODE=full`**,而且不该有 —— 实测在 Linux runner 上跑全量会
|
|
20
|
+
FAIL 10+ 道(字体渲染不同 ⇒ 视觉 diff 必然不一致;路径/编码不同 ⇒ 体积类误报;
|
|
21
|
+
shallow clone ⇒ 依赖 git 状态的判据语义不同;浏览器版本不同 ⇒ 截图基线不匹配)。
|
|
22
|
+
|
|
23
|
+
**一个长期红的 CI 比没有 CI 更糟**:大家会习惯性忽略它,真正的新问题也一起被忽略。
|
|
24
|
+
所以边界是:
|
|
25
|
+
|
|
26
|
+
- **CI 负责**:跨平台可靠的那部分(静态契约、类型、API 形态、单引擎行为)
|
|
27
|
+
- **发版人负责**:发版前在**本机目标平台**跑一次 `bash 05-audit/check-all.sh`
|
|
28
|
+
|
|
29
|
+
`browsers` job 已覆盖三引擎的组件行为契约,但它**不替代**本机全量:
|
|
30
|
+
它不跑视觉基线(基线按平台分集)、不跑 RTL/响应式/无障碍全量。
|
|
31
|
+
|
|
32
|
+
### 失败时先读哪里
|
|
33
|
+
|
|
34
|
+
`selftest-all` 报红时,除屏幕上那 4 行摘要,**完整子输出会落盘**到
|
|
35
|
+
`internal/tmp/selftest-fail-<脚本名>.log`(`internal/` 已被忽略,不进仓库)。
|
|
36
|
+
不可复现的红最需要这个 —— 摘要往往不够定位。
|
|
37
|
+
|
|
38
|
+
只想验一条反向控制时,用 `SKIP_SELFTESTS="a.py,b.py" python3 05-audit/selftest-all.py`
|
|
39
|
+
(列表里没写到的都会跑;被跳过的会在末尾逐条列出理由)。
|
|
40
|
+
|
|
41
|
+
### 门禁退出码的三种含义(写新门禁必读)
|
|
42
|
+
|
|
43
|
+
| rc | 含义 | 汇总里显示 | 计入失败 |
|
|
44
|
+
|---|---|---|---|
|
|
45
|
+
| `0` | 通过 | `PASS` | 否 |
|
|
46
|
+
| `1` | 失败 | `FAIL`,并原样打印门禁自己的话 | 是 |
|
|
47
|
+
| `3` | **跳过 / 未判定**(环境不具备、数据为空,但本身无错) | `SKIP`,末尾单独数「未判定 N 道」 | 否 |
|
|
48
|
+
|
|
49
|
+
**`2` 不是跳过**:已有 9 个门禁用它表示「参数错 / 前置条件不满足」,往 2 上加语义会把真错误
|
|
50
|
+
静默降级成跳过。**更不要 `return 0` 冒充跳过**——`rc=0` 天然等于通过,那正是假绿
|
|
51
|
+
(见 `internal/ERRORS.md` 的 E152 / E153)。有未判定项时,汇总**不会**打印「全部通过」。
|
|
52
|
+
|
|
15
53
|
环境依赖只有一套(Node + Chromium),缺了对应的门禁会**跳过**(跳过不算通过):
|
|
16
54
|
|
|
17
55
|
| 依赖 | 少了会怎样 | 装法 |
|
|
@@ -44,6 +82,20 @@ python 05-audit/shot-baseline.py --check --dir rtl # 视觉基线(13 页)
|
|
|
44
82
|
不各抄一份 apt 清单)。字体版本升级会让 CI 红而本机绿 —— 确认是字体变化,
|
|
45
83
|
就重录 Linux 那套;这也是"基线锚在渲染环境上"的固有代价。
|
|
46
84
|
|
|
85
|
+
**改了 demo 的结构 ⇒ 所有已有平台的基线都要重录,不只是你本机那套。**
|
|
86
|
+
|
|
87
|
+
基线连同 `_stamp.json` 是**按平台分集**的:你重录 Windows 那套,
|
|
88
|
+
本机的 `visual-stamp` 立刻绿;而 Linux 那套的戳仍指向旧 head,
|
|
89
|
+
它在 CI 上红,**本机全量永远看不见**。判据很简单:**页面高度会不会变**——
|
|
90
|
+
增删章节、改布局、改示例数据条数都会变;改文案、改注释不会。
|
|
91
|
+
`visual` 报「尺寸变了 (393, 4540) → (393, 5653)」就是该重录的信号,
|
|
92
|
+
不是"轻微像素差",别当噪音忽略。
|
|
93
|
+
|
|
94
|
+
Linux 那套**不要**在本机 `--record`(录出来的是 Windows 的渲染,等于污染基准)。
|
|
95
|
+
正确通道是 Actions → release → Run workflow → 勾 `shoot_baseline`:
|
|
96
|
+
它在 ubuntu + `ci-fonts.sh` 的同一套环境里录,产物只出 artifact、不落库、不发布。
|
|
97
|
+
下载 `baseline-Linux` 覆盖 `10-review/shots/_baseline-linux*`,**逐张看过**再提交。
|
|
98
|
+
|
|
47
99
|
**加新组件时请注意**:若它含有 **方向性字形**(箭头、指示符)、
|
|
48
100
|
**左右不对称的槽位/边框/滑入方向**、或**顺序有语义**(上一页/下一页、首列),
|
|
49
101
|
就必须把它的 demo 加进 `shot-baseline.py` 的 `RTL_PAGES`。
|
package/README.zh-CN.md
CHANGED
|
@@ -83,9 +83,9 @@ npm install github:owain323/frontend-lib
|
|
|
83
83
|
|
|
84
84
|
## 组件一览
|
|
85
85
|
|
|
86
|
-
共 **
|
|
86
|
+
共 **37** 个(stable 33 / beta 4)。每个组件目录下有 `README.md`(为什么这么做)和 `demo.html`(能直接抄的结构)。
|
|
87
87
|
|
|
88
|
-
### primitives · 基础件(
|
|
88
|
+
### primitives · 基础件(15)
|
|
89
89
|
|
|
90
90
|
| 组件 | 根类名 | 用途 |
|
|
91
91
|
|---|---|---|
|
|
@@ -95,7 +95,9 @@ npm install github:owain323/frontend-lib
|
|
|
95
95
|
| `choice` | `choice` | 单选/多选/原生 select 外观的统一控件 |
|
|
96
96
|
| `combobox` | `combo` | 可搜索 + 可多选标签的输入控件 |
|
|
97
97
|
| `date-range` | `drange` | 日期区间选择,含预设快捷范围 |
|
|
98
|
+
| `delta` | `delta` | 变化量:涨跌方向 + 符号,**只描述方向不判断好坏** |
|
|
98
99
|
| `input` | `field` | 文本输入及其标签/帮助/错误三件套 |
|
|
100
|
+
| `metric` | `metric` | 指标块:一个标签 + 一个值 + 一句上下文,缺数是一等状态 |
|
|
99
101
|
| `popover` | `popover` | 锚定到触发元素的浮层 |
|
|
100
102
|
| `progress` | `progress` | 进度条与进度环 |
|
|
101
103
|
| `select` | `select` | 自定义下拉选择(非原生) |
|
|
@@ -181,8 +183,8 @@ dist/01-tokens/tokens.css ← 拷这个
|
|
|
181
183
|
01-tokens/tokens.css ← 源码(带 31.6 KB 注释),用于阅读
|
|
182
184
|
```
|
|
183
185
|
|
|
184
|
-
- **别拷源码目录**除非你要读它:全库 CSS 有
|
|
185
|
-
|
|
186
|
+
- **别拷源码目录**除非你要读它:全库 CSS 有 67% 是注释(字节口径;字符口径会低报 12 个百分点),`page.css` 一个文件
|
|
187
|
+
17.5 KB 里 15.1 KB 是注释。
|
|
186
188
|
- **JS 也拷 `dist/`**:那一份去了注释但没压缩(理由见「体积」一节)。
|
|
187
189
|
|
|
188
190
|
---
|
|
@@ -249,10 +251,10 @@ dist/01-tokens/tokens.css ← 拷这个
|
|
|
249
251
|
## 体积:默认给你的已经是干净产物
|
|
250
252
|
|
|
251
253
|
源码目录(`01-tokens/` `02-primitives/` …)里的 CSS **带着全部注释** —— 实测全库 CSS
|
|
252
|
-
有 **
|
|
254
|
+
有 **67% 是注释**(399.3 KB 原始里 267.8 KB),`page.css` 单个就有 86%。
|
|
253
255
|
|
|
254
256
|
那些注释是写给你看的取舍理由(为什么这么定、踩过什么坑),不是写给你浏览器看的。
|
|
255
|
-
**注释让你看代码时处处撞墙,构建工具还会把
|
|
257
|
+
**注释让你看代码时处处撞墙,构建工具还会把 67% 的字节原样传下去。**
|
|
256
258
|
|
|
257
259
|
⇒ 所以 `import 'agentcss/tokens.css'` **默认给你去注释后的产物**,
|
|
258
260
|
源码版放在 `agentcss/src/*`:
|
package/START-HERE.md
CHANGED
|
@@ -54,12 +54,14 @@
|
|
|
54
54
|
| 分页 | `03-patterns/pagination/pagination.css` | 195 | **必需 401** (`pagination.js`) | 数据多到要翻页就要 |
|
|
55
55
|
| 树形 | `03-patterns/tree/tree.css` | 122 | **必需 464** (`tree.js`) | 层级数据(文件 / 组织 / 分类)要展开就要 |
|
|
56
56
|
| 侧边抽屉(beta) | `03-patterns/drawer/drawer.css` | 129 | **必需 258** (`drawer.js`) | 要从侧边滑出面板就要 |
|
|
57
|
-
| 弹窗 / 吐司(beta) | `03-patterns/overlay/overlay.css` | 319 | **必需
|
|
57
|
+
| 弹窗 / 吐司(beta) | `03-patterns/overlay/overlay.css` | 319 | **必需 569** (`overlay.js`) | 需要弹层(吐司 / 模态)就要 |
|
|
58
58
|
| 状态(空 / 加载 / 错 / 成功) | `03-patterns/states/states.css` | 252 | — | **凡是会异步取数就要** |
|
|
59
59
|
| 表单校验 | `03-patterns/form-validation/form-validation.css` | 263 | — | 提交前要校验就要 |
|
|
60
60
|
| 列表增删 | `03-patterns/list/list.css` | 162 | 可选 201 (`flip.js`,FLIP 增删动画,纯增强) | 列表会动态增删就要 |
|
|
61
61
|
| 导航 / 目录 | `03-patterns/nav/nav.css` | 314 | **必需 433** (`nav.js`) · 可选 111 (`toc.js`,自动生成目录,纯增强) | 顶部要导航,或长文要目录就要 |
|
|
62
62
|
| 长文排版 | `03-patterns/content/content.css` | 286 | — | 写文档 / 长文就要 |
|
|
63
|
+
| delta | `02-primitives/delta/delta.css` | 113 | — | |
|
|
64
|
+
| metric | `02-primitives/metric/metric.css` | 157 | — | |
|
|
63
65
|
| reveal | `03-patterns/reveal/reveal.css` | 93 | 可选 175 (`reveal.js`,入场动效,纯增强;没有它内容直接可见) | |
|
|
64
66
|
| analysis-report | `04-recipes/analysis-report/analysis-report.css` | 187 | — | |
|
|
65
67
|
| detail-page | `04-recipes/detail-page/detail-page.css` | 190 | — | |
|
package/ai/START-HERE.md
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
> 它的值直接从 `ai/components.json` 与目录实际内容读出来 —— **不信上面的说法,信这个**。
|
|
31
31
|
|
|
32
32
|
<!-- ==== AI-INVENTORY-BEGIN ==== -->
|
|
33
|
-
- 组件 **
|
|
33
|
+
- 组件 **37** 个(`beta` 4 · `stable` 33)
|
|
34
34
|
- `04-recipes/`(页面级示例):`analysis-report`(组合型研究报告:正文 + 辅助栏并排,窄屏退回单栏) · `data-showcase`(四种数据表达方式对照:我到底该用哪个) · `detail-page`(实体详情页骨架:字段齐全 / 部分缺失 / 无数据,三态同构(DOM 不变)) · `longform`(单栏长文排版与阅读节奏) · `report`(报告版式系统 v1:共享基础 + 三种版式取舍(杂志 / 科研技术 / 金融研究)) · `table`(专业数据表格:列级格式与单位,三种用途预设)
|
|
35
35
|
- `09-assets/`(图表与可视化):`bar`(柱状图,含图表规范的裁剪铁律) · `echarts-adapter`(把令牌喂给 ECharts,按需引入;本库不含 ECharts) · `model-viewer`(惰性加载的 3D 模型查看器) · `scientific-plot`(二维科学绘图:坐标轴 / 误差棒 / 置信区间带 / 对数轴) · `sparkline`(迷你趋势线,没有坐标轴的走势提示)
|
|
36
36
|
<!-- ==== AI-INVENTORY-END ==== -->
|