agentcss 0.0.0-stage → 0.11.2

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.
Files changed (274) hide show
  1. package/01-tokens/README.md +236 -0
  2. package/01-tokens/behavior/dismissable.js +132 -0
  3. package/01-tokens/behavior/emit.js +76 -0
  4. package/01-tokens/behavior/focus-return.js +81 -0
  5. package/01-tokens/behavior/roving.js +152 -0
  6. package/01-tokens/behavior/typeahead.js +124 -0
  7. package/01-tokens/focus-ring-demo.html +133 -0
  8. package/01-tokens/focus-ring.css +102 -0
  9. package/01-tokens/page.css +244 -0
  10. package/01-tokens/polyfill.js +116 -0
  11. package/01-tokens/responsive-demo.html +171 -0
  12. package/01-tokens/scrollbar-demo.html +194 -0
  13. package/01-tokens/scrollbar.css +179 -0
  14. package/01-tokens/theme-toggle.js +103 -0
  15. package/01-tokens/tokens.css +972 -0
  16. package/01-tokens/typography.css +156 -0
  17. package/02-primitives/badge/README.md +71 -0
  18. package/02-primitives/badge/badge.css +141 -0
  19. package/02-primitives/badge/demo.html +101 -0
  20. package/02-primitives/button/README.md +99 -0
  21. package/02-primitives/button/button.css +353 -0
  22. package/02-primitives/button/demo.html +200 -0
  23. package/02-primitives/card/README.md +145 -0
  24. package/02-primitives/card/card.css +246 -0
  25. package/02-primitives/card/demo.html +170 -0
  26. package/02-primitives/choice/README.md +161 -0
  27. package/02-primitives/choice/choice.css +395 -0
  28. package/02-primitives/choice/demo.html +277 -0
  29. package/02-primitives/combobox/README.md +79 -0
  30. package/02-primitives/combobox/combobox.css +223 -0
  31. package/02-primitives/combobox/combobox.js +485 -0
  32. package/02-primitives/combobox/demo.html +109 -0
  33. package/02-primitives/date-range/README.md +100 -0
  34. package/02-primitives/date-range/date-range.css +206 -0
  35. package/02-primitives/date-range/date-range.js +301 -0
  36. package/02-primitives/date-range/demo.html +104 -0
  37. package/02-primitives/input/README.md +170 -0
  38. package/02-primitives/input/demo.html +246 -0
  39. package/02-primitives/input/input.css +239 -0
  40. package/02-primitives/popover/README.md +80 -0
  41. package/02-primitives/popover/demo.html +150 -0
  42. package/02-primitives/popover/popover.css +187 -0
  43. package/02-primitives/popover/popover.js +331 -0
  44. package/02-primitives/progress/README.md +82 -0
  45. package/02-primitives/progress/demo.html +154 -0
  46. package/02-primitives/progress/progress.css +172 -0
  47. package/02-primitives/select/README.md +95 -0
  48. package/02-primitives/select/demo.html +121 -0
  49. package/02-primitives/select/select.css +151 -0
  50. package/02-primitives/select/select.js +549 -0
  51. package/02-primitives/separator/README.md +63 -0
  52. package/02-primitives/separator/demo.html +84 -0
  53. package/02-primitives/separator/separator.css +73 -0
  54. package/02-primitives/skeleton/README.md +69 -0
  55. package/02-primitives/skeleton/demo.html +110 -0
  56. package/02-primitives/skeleton/skeleton.css +96 -0
  57. package/02-primitives/switch/README.md +65 -0
  58. package/02-primitives/switch/demo.html +115 -0
  59. package/02-primitives/switch/switch.css +370 -0
  60. package/03-patterns/accordion/README.md +121 -0
  61. package/03-patterns/accordion/accordion.css +453 -0
  62. package/03-patterns/accordion/accordion.js +369 -0
  63. package/03-patterns/accordion/demo.html +223 -0
  64. package/03-patterns/content/README.md +103 -0
  65. package/03-patterns/content/content.css +286 -0
  66. package/03-patterns/content/demo.html +88 -0
  67. package/03-patterns/drawer/README.md +79 -0
  68. package/03-patterns/drawer/demo.html +101 -0
  69. package/03-patterns/drawer/drawer.css +129 -0
  70. package/03-patterns/drawer/drawer.js +258 -0
  71. package/03-patterns/dropdown/README.md +78 -0
  72. package/03-patterns/dropdown/demo.html +101 -0
  73. package/03-patterns/dropdown/dropdown.css +135 -0
  74. package/03-patterns/dropdown/dropdown.js +451 -0
  75. package/03-patterns/form-validation/README.md +147 -0
  76. package/03-patterns/form-validation/demo.html +280 -0
  77. package/03-patterns/form-validation/form-validation.css +263 -0
  78. package/03-patterns/list/README.md +150 -0
  79. package/03-patterns/list/demo.html +225 -0
  80. package/03-patterns/list/flip.js +201 -0
  81. package/03-patterns/list/list.css +162 -0
  82. package/03-patterns/nav/README.md +225 -0
  83. package/03-patterns/nav/demo.html +131 -0
  84. package/03-patterns/nav/nav.css +314 -0
  85. package/03-patterns/nav/nav.js +430 -0
  86. package/03-patterns/nav/toc.js +111 -0
  87. package/03-patterns/overlay/README.md +196 -0
  88. package/03-patterns/overlay/demo.html +241 -0
  89. package/03-patterns/overlay/overlay.css +319 -0
  90. package/03-patterns/overlay/overlay.js +563 -0
  91. package/03-patterns/pagination/README.md +114 -0
  92. package/03-patterns/pagination/demo.html +165 -0
  93. package/03-patterns/pagination/pagination.css +195 -0
  94. package/03-patterns/pagination/pagination.js +395 -0
  95. package/03-patterns/reveal/README.md +91 -0
  96. package/03-patterns/reveal/demo.html +106 -0
  97. package/03-patterns/reveal/reveal.css +93 -0
  98. package/03-patterns/reveal/reveal.js +172 -0
  99. package/03-patterns/states/README.md +141 -0
  100. package/03-patterns/states/demo.html +240 -0
  101. package/03-patterns/states/states.css +252 -0
  102. package/03-patterns/tabs/README.md +84 -0
  103. package/03-patterns/tabs/demo.html +139 -0
  104. package/03-patterns/tabs/tabs.css +172 -0
  105. package/03-patterns/tabs/tabs.js +307 -0
  106. package/03-patterns/tooltip/README.md +96 -0
  107. package/03-patterns/tooltip/demo.html +78 -0
  108. package/03-patterns/tooltip/tooltip.css +89 -0
  109. package/03-patterns/tooltip/tooltip.js +288 -0
  110. package/03-patterns/tree/README.md +94 -0
  111. package/03-patterns/tree/demo.html +138 -0
  112. package/03-patterns/tree/tree.css +113 -0
  113. package/03-patterns/tree/tree.js +456 -0
  114. package/04-recipes/analysis-report/README.md +80 -0
  115. package/04-recipes/analysis-report/analysis-report.css +187 -0
  116. package/04-recipes/analysis-report/demo.html +274 -0
  117. package/04-recipes/data-showcase/README.md +45 -0
  118. package/04-recipes/data-showcase/demo.html +247 -0
  119. package/04-recipes/detail-page/README.md +93 -0
  120. package/04-recipes/detail-page/demo.html +55 -0
  121. package/04-recipes/detail-page/detail-page.css +190 -0
  122. package/04-recipes/detail-page/full.html +60 -0
  123. package/04-recipes/detail-page/null.html +60 -0
  124. package/04-recipes/detail-page/partial.html +60 -0
  125. package/04-recipes/detail-page/verify-skeleton.py +19 -0
  126. package/04-recipes/longform/README.md +93 -0
  127. package/04-recipes/longform/agc-memory.svg +4 -0
  128. package/04-recipes/longform/content.html +610 -0
  129. package/04-recipes/longform/content.md +51 -0
  130. package/04-recipes/longform/longform.html +627 -0
  131. package/04-recipes/report/README.md +176 -0
  132. package/04-recipes/report/demo.html +355 -0
  133. package/04-recipes/report/report.css +364 -0
  134. package/04-recipes/table/README.md +103 -0
  135. package/04-recipes/table/demo.html +455 -0
  136. package/04-recipes/table/table.css +372 -0
  137. package/04-recipes/tierA-tokens.css +189 -0
  138. package/09-assets/README.md +74 -0
  139. package/09-assets/bar/README.md +94 -0
  140. package/09-assets/bar/bar.css +166 -0
  141. package/09-assets/bar/bar.js +320 -0
  142. package/09-assets/bar/demo.html +176 -0
  143. package/09-assets/echarts-adapter/demo.html +192 -0
  144. package/09-assets/echarts-adapter/echarts-adapter.js +277 -0
  145. package/09-assets/model-viewer/README.md +155 -0
  146. package/09-assets/model-viewer/demo.html +105 -0
  147. package/09-assets/model-viewer/model-viewer.css +143 -0
  148. package/09-assets/model-viewer/model-viewer.js +423 -0
  149. package/09-assets/scientific-plot/README.md +94 -0
  150. package/09-assets/scientific-plot/demo.html +252 -0
  151. package/09-assets/scientific-plot/scientific-plot.css +141 -0
  152. package/09-assets/scientific-plot/scientific-plot.js +610 -0
  153. package/09-assets/sparkline/README.md +153 -0
  154. package/09-assets/sparkline/demo.html +163 -0
  155. package/09-assets/sparkline/sparkline.css +158 -0
  156. package/09-assets/sparkline/sparkline.js +508 -0
  157. package/API.md +332 -0
  158. package/CHANGELOG.md +3116 -0
  159. package/CODE_OF_CONDUCT.md +64 -0
  160. package/CONTRIBUTING.md +89 -0
  161. package/ERRORS.md +1658 -0
  162. package/LICENSE +21 -0
  163. package/README.md +491 -2
  164. package/SECURITY.md +72 -0
  165. package/START-HERE.md +164 -0
  166. package/SUPPORT.md +109 -0
  167. package/adapters/presentation/README.md +113 -0
  168. package/adapters/presentation/check.js +101 -0
  169. package/adapters/presentation/deck.schema.json +74 -0
  170. package/adapters/presentation/to-doc.js +138 -0
  171. package/ai/START-HERE.md +104 -0
  172. package/ai/behaviors.json +380 -0
  173. package/ai/behaviors.schema.json +61 -0
  174. package/ai/capabilities.json +56 -0
  175. package/ai/cli.js +387 -0
  176. package/ai/components.json +1944 -0
  177. package/ai/components.meta.json +168 -0
  178. package/ai/components.schema.json +220 -0
  179. package/ai/contract.schema.json +147 -0
  180. package/ai/deprecations.json +55 -0
  181. package/ai/deprecations.schema.json +85 -0
  182. package/ai/motion-policy.json +22 -0
  183. package/ai/patch.js +323 -0
  184. package/ai/patch.schema.json +63 -0
  185. package/ai/profiles.json +92 -0
  186. package/ai/tokens.audience.json +55 -0
  187. package/ai/tokens.audience.schema.json +73 -0
  188. package/ai/tokens.json +762 -0
  189. package/ai/tokens.schema.json +58 -0
  190. package/ai/tokens.tree.json +752 -0
  191. package/ai/tokens.tree.schema.json +56 -0
  192. package/ai/validate.js +383 -0
  193. package/dist/01-tokens/behavior/dismissable.js +60 -0
  194. package/dist/01-tokens/behavior/emit.js +21 -0
  195. package/dist/01-tokens/behavior/focus-return.js +31 -0
  196. package/dist/01-tokens/behavior/roving.js +77 -0
  197. package/dist/01-tokens/behavior/typeahead.js +61 -0
  198. package/dist/01-tokens/focus-ring.css +1 -0
  199. package/dist/01-tokens/page.css +1 -0
  200. package/dist/01-tokens/polyfill.js +78 -0
  201. package/dist/01-tokens/scrollbar.css +1 -0
  202. package/dist/01-tokens/theme-toggle.js +61 -0
  203. package/dist/01-tokens/tokens.css +1 -0
  204. package/dist/01-tokens/typography.css +1 -0
  205. package/dist/02-primitives/badge/badge.css +1 -0
  206. package/dist/02-primitives/button/button.css +1 -0
  207. package/dist/02-primitives/card/card.css +1 -0
  208. package/dist/02-primitives/choice/choice.css +1 -0
  209. package/dist/02-primitives/combobox/combobox.css +1 -0
  210. package/dist/02-primitives/combobox/combobox.js +439 -0
  211. package/dist/02-primitives/date-range/date-range.css +1 -0
  212. package/dist/02-primitives/date-range/date-range.js +267 -0
  213. package/dist/02-primitives/input/input.css +1 -0
  214. package/dist/02-primitives/popover/popover.css +1 -0
  215. package/dist/02-primitives/popover/popover.js +257 -0
  216. package/dist/02-primitives/progress/progress.css +1 -0
  217. package/dist/02-primitives/select/select.css +1 -0
  218. package/dist/02-primitives/select/select.js +449 -0
  219. package/dist/02-primitives/separator/separator.css +1 -0
  220. package/dist/02-primitives/skeleton/skeleton.css +1 -0
  221. package/dist/02-primitives/switch/switch.css +1 -0
  222. package/dist/03-patterns/accordion/accordion.css +1 -0
  223. package/dist/03-patterns/accordion/accordion.js +219 -0
  224. package/dist/03-patterns/content/content.css +1 -0
  225. package/dist/03-patterns/drawer/drawer.css +1 -0
  226. package/dist/03-patterns/drawer/drawer.js +229 -0
  227. package/dist/03-patterns/dropdown/dropdown.css +1 -0
  228. package/dist/03-patterns/dropdown/dropdown.js +365 -0
  229. package/dist/03-patterns/form-validation/form-validation.css +1 -0
  230. package/dist/03-patterns/list/flip.js +117 -0
  231. package/dist/03-patterns/list/list.css +1 -0
  232. package/dist/03-patterns/nav/nav.css +1 -0
  233. package/dist/03-patterns/nav/nav.js +322 -0
  234. package/dist/03-patterns/nav/toc.js +76 -0
  235. package/dist/03-patterns/overlay/overlay.css +1 -0
  236. package/dist/03-patterns/overlay/overlay.js +398 -0
  237. package/dist/03-patterns/pagination/pagination.css +1 -0
  238. package/dist/03-patterns/pagination/pagination.js +273 -0
  239. package/dist/03-patterns/reveal/reveal.css +1 -0
  240. package/dist/03-patterns/reveal/reveal.js +138 -0
  241. package/dist/03-patterns/states/states.css +1 -0
  242. package/dist/03-patterns/tabs/tabs.css +1 -0
  243. package/dist/03-patterns/tabs/tabs.js +242 -0
  244. package/dist/03-patterns/tooltip/tooltip.css +1 -0
  245. package/dist/03-patterns/tooltip/tooltip.js +213 -0
  246. package/dist/03-patterns/tree/tree.css +1 -0
  247. package/dist/03-patterns/tree/tree.js +383 -0
  248. package/dist/04-recipes/analysis-report/analysis-report.css +1 -0
  249. package/dist/04-recipes/detail-page/detail-page.css +1 -0
  250. package/dist/04-recipes/report/report.css +1 -0
  251. package/dist/04-recipes/table/table.css +1 -0
  252. package/dist/04-recipes/tierA-tokens.css +1 -0
  253. package/dist/09-assets/bar/bar.css +1 -0
  254. package/dist/09-assets/bar/bar.js +222 -0
  255. package/dist/09-assets/echarts-adapter/echarts-adapter.js +185 -0
  256. package/dist/09-assets/model-viewer/model-viewer.css +1 -0
  257. package/dist/09-assets/model-viewer/model-viewer.js +320 -0
  258. package/dist/09-assets/scientific-plot/scientific-plot.css +1 -0
  259. package/dist/09-assets/scientific-plot/scientific-plot.js +568 -0
  260. package/dist/09-assets/sparkline/sparkline.css +1 -0
  261. package/dist/09-assets/sparkline/sparkline.js +265 -0
  262. package/dist/COSTS.md +56 -0
  263. package/docs/AI-CONTRACT.md +197 -0
  264. package/docs/BACKLOG.md +127 -0
  265. package/docs/BENCHMARK.md +252 -0
  266. package/docs/GUIDANCE.md +154 -0
  267. package/docs/INVARIANT.md +372 -0
  268. package/docs/LAYER-BASELINE.md +158 -0
  269. package/docs/RELEASING.md +275 -0
  270. package/docs/RFC-THEME-SCOPE.md +141 -0
  271. package/docs/ROADMAP.md +182 -0
  272. package/index.html +82 -0
  273. package/package.json +107 -4
  274. package/types/index.d.ts +310 -0
@@ -0,0 +1,156 @@
1
+ /* ============================================================================
2
+ frontend-lib / 01-tokens / typography.css
3
+ 排版辅助类(跨组件共享)
4
+
5
+ 依赖:无(只用 tokens.css 里的变量)
6
+ 版本:A ✅ / B ✅ / C ✅
7
+
8
+ 🔴 建立。此前 8 个 demo 各自在内联 <style> 里**重复定义**
9
+ .small / .note / .lead 等,全库没有一个共同出处 ——
10
+ 改一处就要改八处,漏一处就样式不一致(这次就被 refs.py 当场抓到)。
11
+ ========================================================================= */
12
+
13
+ /* ============================================================================
14
+ 页面级默认值
15
+ ============================================================================
16
+ 🔴 补(暗色模式首次生效后暴露的真问题):
17
+ 此前 tokens.css 与 typography.css 都**没有给 body 设 color / background**
18
+ ⇒ 暗色下所有页面继承**浏览器默认黑**(rgb(0,0,0))
19
+ ⇒ 实测 19 个 demo 页面的 h1 是「黑字 on #14171A」,对比度 1.17:1(几乎看不见)
20
+ ⇒ 页面底色与文字色的默认值属于**排版层**职责,故放在 typography.css。
21
+ ⚠️ 加在文件**头部**:此前我加在末尾,结果末尾的说明注释没闭合,
22
+ 规则被当成注释吞掉(CSSOM 里查不到)—— 又一次同类问题。
23
+ ============================================================================ */
24
+ body {
25
+ color: var(--text-primary);
26
+ background: var(--paper);
27
+ }
28
+
29
+ /* 辅助文字:说明、注释、元信息 */
30
+ .small {
31
+ font-size: var(--fs-xs);
32
+ color: var(--text-secondary);
33
+ line-height: 1.7;
34
+ }
35
+
36
+ /* 更弱一档:几乎不抢眼,用在页脚、版权行 */
37
+ .small--faint { color: var(--text-tertiary); }
38
+
39
+ /* 导语:紧跟标题的一段话,比正文略大、略淡 */
40
+ .lead {
41
+ font-size: var(--fs-md);
42
+ color: var(--text-secondary);
43
+ line-height: 1.6;
44
+ }
45
+
46
+ /* 说明块:补充/解释,不是警告,更不是错误。要"注意"用 .note--warn。
47
+ 🔴 0.4.2 底色 --warning-bg → --surface-sunken:实测 21 页用 .note,
48
+ 20 页当灰底说明块手写同一个值,只有 1 页用 warning ⇒ 取众数。 */
49
+ .note {
50
+ /* 🔴 去掉 `border-left: 3px solid`。
51
+ 评审意见"很蠢的左边侧边阴影" —— 说得对:
52
+ ① 它是**纯装饰**,不传达信息(颜色已经表达了)
53
+ ② 3px 竖条在浅底上形成一条硬边,视觉噪声比信息量大
54
+ ③ 满库 13 处同款,一眼就能看出"模板感" —— 这正是 AI 味的来源。
55
+ 真实产品(GitHub callout / Vercel / Stripe)都是**纯底色 + 圆角**,没有竖条。 */
56
+ background: var(--surface-sunken);
57
+ color: var(--text-secondary);
58
+ padding: var(--sp-3) var(--sp-4);
59
+ border-radius: var(--r-sm);
60
+ font-size: var(--fs-sm);
61
+ line-height: 1.6;
62
+ /* 众数写法是 `margin: 0 0 var(--sp-4)`(9 页)。
63
+ 上下都要留出呼吸,但它是**紧跟上下文的补充**,不是独立章节,
64
+ 所以下边距给 --sp-4、上边距为 0(由上一个块的 margin 负责)。 */
65
+ margin: 0 0 var(--sp-4);
66
+ }
67
+
68
+ /* 注意块:同样一块,但要"提醒"而不是"补充" —— 唯一差别是底色。 */
69
+ .note--warn {
70
+ background: var(--warning-bg);
71
+ }
72
+
73
+ /* 分隔线:比 border 轻,用于段落之间 */
74
+ .rule {
75
+ border: 0;
76
+ border-top: 1px solid var(--border-decor);
77
+ margin: var(--sp-6) 0;
78
+ }
79
+
80
+ /* 代码片段(行内)—— 与 content.css 的 .prose > code 呼应 */
81
+ code {
82
+ font-family: var(--mono);
83
+ }
84
+
85
+ /* ============================================================================
86
+ 反模式
87
+ =========================================================================
88
+ 1. 在每个 demo 的内联 <style> 里重复定义 .small / .note
89
+ 八处重复,改一处漏一处。不如引这一个文件。
90
+ 2. 用 .note 装错误消息
91
+ 它是"注意"不是"错误",颜色与语义都不对。错误用 .field__error。
92
+ 3. 在这里加组件专有样式
93
+ 这是 tokens 层,只放跨组件通用的东西。
94
+ ========================================================================= */
95
+
96
+ /* ============================================================================
97
+ 数字排印:`.num`
98
+ ============================================================================
99
+ 🔴 建立。之前的情况是「每个组件自己写一遍」:
100
+ `list.css` 有 `tabular-nums`、longform 用自造的 `.num`、
101
+ 而 states 的数据行(26,831 条记录)根本没处理。
102
+ ⇒ 同一个库里三套做法,且**只有一处**是真规则。
103
+
104
+ 为什么必须等宽(实测):
105
+ Windows 的 Segoe UI 里 `1` `8` `0` 本来就等宽(都 10.33px @14px),
106
+ **但逗号只有 4.25px** ⇒ `12,345,678` 仍然会歪。
107
+ 也就是说:**不能依赖系统字体的默认**,
108
+ 不同系统(macOS SF / Linux DejaVu)连数字本身都不一定等宽。
109
+ 必须显式声明。
110
+
111
+ 为什么不做成全局 `* { font-variant-numeric: tabular-nums }`:
112
+ 比例数字在正文里更好看("第 3 步"不该被拉宽)。
113
+ ⇒ **只在"需要成列比较"的地方用**,这是排版判断,不是全局开关。
114
+
115
+ 用法:
116
+ <td class="num">26,831</td> 表格、金额、指标
117
+ <span class="num">+2.41%</span> 涨跌幅
118
+ ------------------------------------------------------------------------ */
119
+ .num {
120
+ font-variant-numeric: tabular-nums;
121
+ /* 🔴 负数与小数点也要等宽,否则 "-1.2%" 和 "12.3%" 仍然对不齐 */
122
+ font-feature-settings: "tnum" 1;
123
+ }
124
+
125
+ /* 指标块的数字:更大的、更"技术"的一档。
126
+ 金融看板的标志性元素 —— 数字本身成为视觉主体,而不是正文的一部分。 */
127
+ .num-lg {
128
+ font-variant-numeric: tabular-nums;
129
+ font-feature-settings: "tnum" 1;
130
+ font-weight: 500;
131
+ letter-spacing: -0.01em; /* 大字号收紧一点,数字块更整齐 */
132
+ }
133
+
134
+ /* ==========================================================================
135
+ 🔴 补:`.lede`(导语/引言段)
136
+
137
+ ⭐ 为什么补它(refs 门禁抓到):
138
+ 全库有 **6 个 demo** 都在用 `class="lede"`(导语段),
139
+ 但**从来没有定义过** ⇒ 属于「静默失效」——
140
+ 浏览器不报错、页面照常显示,只是这一段**根本没生效**。
141
+ 这类问题只能靠门禁抓,肉眼完全看不出来。
142
+
143
+ 用途:标题下面那段摘要性文字。要比正文大一号、行距更松,
144
+ 但**不能大到抢标题的视觉重量**(标题才是层级入口)。
145
+
146
+ ⚠️ 全部走令牌,不写死值 —— 换主题/换字号版本时自动跟随。
147
+ ========================================================================== */
148
+ .lede {
149
+ /* 🔴 0.4.2:--fs-lg → --fs-md。前者与 h2 同档,导语抢了小节标题的层级。 */
150
+ font-size: var(--fs-md);
151
+ line-height: 1.65;
152
+ color: var(--text-secondary);
153
+ /* 众数是 --sp-6(6 页);--measure-lede 取代各页手写的 60ch / 62ch。 */
154
+ margin: 0 0 var(--sp-6);
155
+ max-width: var(--measure-lede);
156
+ }
@@ -0,0 +1,71 @@
1
+ # badge · 状态标记
2
+
3
+ 承载**一个短状态词**("已披露""已停牌""审计中")。
4
+
5
+ ## 类
6
+
7
+ | 类 | 作用 |
8
+ |---|---|
9
+ | `.badge` | 基础(不带变体时是中性色)|
10
+ | `.badge--neutral` | 中性:草稿 / 归档 / 草稿态 |
11
+ | `.badge--success` | 成功 / 已披露 |
12
+ | `.badge--warning` | 警告 / 审计中 |
13
+ | `.badge--danger` | 危险 / 已停牌 |
14
+ | `.badge--info` | 信息 / 待复核 |
15
+ | `.badge--lg` | 较大一档(13px)|
16
+ | `.badge--clickable` | 可点 —— **必须配合 `<button>` 或 `<a>`** |
17
+
18
+ ## 用法
19
+
20
+ ```html
21
+ <!-- 不可点(默认) -->
22
+ <span class="badge badge--success">已披露</span>
23
+
24
+ <!-- 可点:语义由元素承担,样式照抄 .badge -->
25
+ <button class="badge badge--info badge--clickable">待复核</button>
26
+ ```
27
+
28
+ ## 三条硬规矩
29
+
30
+ **1. 不可点就别用 button。** 要能点必须用 `<button>` 或 `<a>` ——
31
+ `div + onclick` 对读屏是「没有角色的按钮」:读不出能点,键盘也 Tab 不到。
32
+
33
+ **2. 一定要有文字。** WCAG 1.4.1 要求不能只靠颜色区分。
34
+ 本组件的颜色是**冗余线索**,不是唯一编码 —— 去掉颜色也必须能读懂。
35
+
36
+ **3. 不要数字角标。** badge 是"状态词",不是"数字气泡"。
37
+
38
+ ## 为什么是「淡底 + 深字」
39
+
40
+ 小字号(11–12px)在饱和底上白字对比度普遍不够。本库五组实测:
41
+
42
+ | 变体 | 浅色 | 暗色 |
43
+ |---|---|---|
44
+ | `--neutral` | 6.76 | 10.59 |
45
+ | `--success` | 5.58 | 5.92 |
46
+ | `--danger` | 4.82 | 5.37 |
47
+ | `--warning` | 5.29 | 6.05 |
48
+ | `--info` | 6.01 | 5.25 |
49
+
50
+ **全部 ≥ 4.5** ⇒ 不需要为 badge 单独调一套色(省一次决策,也少一套漂移风险)。
51
+
52
+ **反例的真实数字**:暗色下白字在 `--success` 上只有 **2.72:1**(浅色是 6.39 达标)——
53
+ **看浅色时完全发现不了这个失效**。这就是为什么每组都要两套都算。
54
+
55
+ ## 两档尺寸
56
+
57
+ 出现第三档说明信息密度没规划好 —— 与 `card` 的判断标准一致。
58
+
59
+ ## 强制高对比模式
60
+
61
+ `@media (forced-colors: active)` 下边框改用 `currentColor` ——
62
+ **靠边框保住边界,不靠底色**。这一段本机无法验证(需系统级开关)。
63
+
64
+ ## 尺寸
65
+
66
+ 高度 24px(默认)· 字号 12px —— 达 WCAG 2.2 的 24×24 最小目标。
67
+
68
+ ## 验证
69
+
70
+ - `component-contrast.py`:5 组字/底组合两套配色全过
71
+ - `a11y-scan`:本 demo axe 0 违规 / 16 条通过
@@ -0,0 +1,141 @@
1
+ /* ============================================================================
2
+ Badge — 状态标记
3
+ ============================================================================
4
+ 为什么用「淡底 + 深字」而不是「饱和底 + 白字」
5
+ ----------------------------------------------------
6
+ 饱和底(如 --success #2f6b3a)+ 白字在**小字号**下对比度普遍不够 ——
7
+ 本库正文门槛是 4.5:1,而 badge 只有 11–12px,更严格才对。
8
+
9
+ 实测(本库令牌,两套配色):
10
+ success 浅 5.58 · 暗 5.92
11
+ danger 浅 4.82 · 暗 5.37
12
+ warning 浅 5.29 · 暗 6.05
13
+ info 浅 6.01 · 暗 5.25
14
+ neutral 浅 6.76 · 暗 10.59
15
+ ⇒ 全部 ≥ 4.5,不需要为 badge 单独调色。
16
+
17
+ 为什么可以只用颜色
18
+ ----------------
19
+ 🔴 **不行。** WCAG 1.4.1(不能只靠颜色)要求形状或文字参与区分。
20
+ 本组件的做法:**badge 一律带文字**("已停牌"/"审计中"),
21
+ 颜色只是**冗余线索**,不是唯一线索。
22
+ ⇒ 这是"可选的辅助",不是"唯一的编码"。
23
+
24
+ 不用它承载什么信息
25
+ ------------------
26
+ ❌ 不用 badge 装数字角标(那是另一类设计,且数字变化读屏未必会念)
27
+ ❌ 不用 badge 装可点击的东西(那是 button,见下)
28
+ ========================================================================= */
29
+
30
+ .badge {
31
+ display: inline-flex;
32
+ align-items: center;
33
+ gap: var(--sp-1);
34
+ padding: 2px var(--sp-2);
35
+ border: 1px solid transparent;
36
+ border-radius: var(--r-sm);
37
+ font-size: var(--fs-xs);
38
+ line-height: 1.5; /* 不用行高单位:11px 字号下 1.5em 会虚 */
39
+ white-space: nowrap;
40
+ vertical-align: baseline;
41
+ align-self: flex-start; /* flex 容器里不被 stretch 拉满(实测 54→355px) */
42
+ /* 🔴 不可点 ⇒ cursor 默认、不要 transition 假装能点 */
43
+ }
44
+
45
+ /* 中性(默认)—— 数量最多的一档,别让它显得像"缺省" */
46
+ .badge--neutral {
47
+ background: var(--surface-sunken);
48
+ border-color: var(--border-decor);
49
+ color: var(--text-secondary);
50
+ }
51
+
52
+ .badge--success {
53
+ background: var(--success-bg);
54
+ border-color: var(--success-bg); /* 同色底 ⇒ 边框不产生额外对比 */
55
+ color: var(--success);
56
+ }
57
+
58
+ .badge--danger {
59
+ background: var(--danger-bg);
60
+ border-color: var(--danger-bg);
61
+ color: var(--danger);
62
+ }
63
+
64
+ .badge--warning {
65
+ background: var(--warning-bg);
66
+ border-color: var(--warning-bg);
67
+ color: var(--warning);
68
+ }
69
+
70
+ .badge--info {
71
+ background: var(--info-bg);
72
+ border-color: var(--info-bg);
73
+ color: var(--info);
74
+ }
75
+
76
+ /* ---------------------------------------------------------------- 可点版
77
+ 🔴 当 badge **需要可点**时(比如点标签跳到筛选结果),
78
+ 语义必须是 button/a —— div + onClick 对读屏是"没有角色的按钮"。
79
+
80
+ 给 .badge--clickable 时**必须**同时在 HTML 上写正确的元素与键盘支持。
81
+ 本类只负责**看起来可点**(hover/focus 反馈),
82
+ 焦点环用 :focus-visible(键盘才出现,鼠标点击不出现 —— 与本库 button 一致)。
83
+ ---------------------------------------------------------------- */
84
+
85
+ .badge--clickable {
86
+ cursor: pointer;
87
+ transition: background var(--dur-fast) var(--ease-out);
88
+ }
89
+
90
+ /* 🔴 两处修正:
91
+ ① 加 @media (hover) 门控 —— 触屏上"点一下"会先点亮 hover 再 click,
92
+ 于是保持"被悬停"的颜色不褪(hover-gate 抓到的)。
93
+ ② **不用 `filter: brightness(0.97)`** —— states 门禁把它列为反模式,
94
+ 理由成立:brightness 是**整体乘亮**,换主题时效果完全不同
95
+ (浅色下几乎看不出,暗色下明显压暗)⇒ 颜色跟着主题漂。
96
+ ⇒ 改成显式换边框色,行为可预测。 */
97
+ @media (hover: hover) and (pointer: fine) {
98
+ .badge--neutral.badge--clickable:hover { border-color: var(--text-tertiary); }
99
+ .badge--success.badge--clickable:hover { border-color: var(--success); }
100
+ .badge--warning.badge--clickable:hover { border-color: var(--warning); }
101
+ .badge--danger.badge--clickable:hover { border-color: var(--danger); }
102
+ .badge--info.badge--clickable:hover { border-color: var(--info); }
103
+ }
104
+
105
+ /* 强制高对比模式(Windows)—— 淡底会被系统强制色覆盖,
106
+ 这时靠边框保住边界,而不是靠底色。 */
107
+ @media (forced-colors: active) {
108
+ .badge {
109
+ border-color: currentColor; /* 强制色下边框取文字色 */
110
+ }
111
+ }
112
+
113
+ /* ---------------------------------------------------------------- 尺寸
114
+ 两档够了。badge 出现三档说明信息密度没规划好
115
+ (与 card 的判断标准一致)。 */
116
+ .badge--lg {
117
+ font-size: var(--fs-sm);
118
+ padding: var(--sp-1) var(--sp-3);
119
+ }
120
+
121
+ /* ============================================================================
122
+ 实心态变体
123
+ ============================================================================
124
+ 🔴 新增(暗色门禁抓出来的):
125
+ demo 原来用**行内 style** 写 `background: var(--success); color: #fff`
126
+ ⇒ 暗色下 --success 变浅(#6FAA7A),白字压上去只有 2.72:1
127
+ ⇒ 行内 style 还会**绕过 tokens 门禁**(门禁只扫 CSS 文件)
128
+
129
+ ⇒ 正确做法:把"实心底 + 白字"做成**变体类**,让暗色令牌能接管。
130
+ 白字写在 `--text-on-*` 上(暗色下会变深色),而不是写死 #fff。
131
+ ============================================================================ */
132
+ .badge--solid-success { background: var(--success); color: var(--text-on-solid); }
133
+ .badge--solid-danger { background: var(--danger); color: var(--text-on-solid); }
134
+ .badge--solid-warning { background: var(--warning); color: var(--text-on-solid); }
135
+
136
+ /* 🔴 暗色下:--success / --danger 都**变浅**了(为的是在深底上更醒目)
137
+ ⇒ 白字压上去只有 2.72:1 ⇒ 实心态在暗色下必须换成**深字**。
138
+ ⚠️ 这不是"暗色就该反色",而是 WCAG 的硬要求:
139
+ 浅底必须配深字,否则对比度不够。 */
140
+ /* 原有 `@media (prefers-color-scheme: dark)` 块已删:它的内容与上面三行
141
+ 逐字相同(`--text-on-solid` 令牌化后暗色自己会变深),是死代码。 */
@@ -0,0 +1,101 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <link rel="icon" href="data:,">
7
+ <title>badge · 状态标记</title>
8
+ <link rel="stylesheet" href="../../01-tokens/tokens.css">
9
+ <link rel="stylesheet" href="../../01-tokens/typography.css">
10
+ <link rel="stylesheet" href="../../01-tokens/page.css">
11
+ <link rel="stylesheet" href="../../02-primitives/button/button.css">
12
+ <link rel="stylesheet" href="../../02-primitives/badge/badge.css">
13
+ <style>
14
+ .row { display: flex; gap: var(--sp-2); flex-wrap: wrap; align-items: center;
15
+ padding: var(--sp-4) 0; }
16
+ </style>
17
+ </head>
18
+ <body class="page page">
19
+ <main class="wrap">
20
+ <h1>badge · 状态标记</h1>
21
+ <p class="lede">
22
+ badge 承载<strong>一个短状态词</strong>("已停牌""审计中")。
23
+ 它<strong>不可点</strong> —— 要能点请用 <code>&lt;button class="badge badge--clickable"&gt;</code>
24
+ 或 <code>&lt;a&gt;</code>,语义由元素本身承担。
25
+ </p>
26
+
27
+ <h2 class="rule-top">五个变体</h2>
28
+ <div class="row">
29
+ <span class="badge badge--neutral">草稿</span>
30
+ <span class="badge badge--success">已披露</span>
31
+ <span class="badge badge--warning">审计中</span>
32
+ <span class="badge badge--danger">已停牌</span>
33
+ <span class="badge badge--info">待复核</span>
34
+ </div>
35
+ <p class="small">
36
+ 为什么是「淡底 + 深字」而不是「饱和底 + 白字」?因为 badge 只有 11–12px,
37
+ 小字号在饱和底上对比度普遍不够。本库五组实测 4.82–6.76(浅色)· 5.25–10.59(暗色),
38
+ 全部 ≥ 4.5,<strong>不需要为 badge 单独调一套色</strong>。
39
+ </p>
40
+
41
+ <h2 class="rule-top">用在真实语境里</h2>
42
+ <div class="row">
43
+ <span class="small">600519</span>
44
+ <span class="badge badge--success">已披露</span>
45
+ <span class="small">000001</span>
46
+ <span class="badge badge--danger">已停牌</span>
47
+ <span class="small">688981</span>
48
+ <span class="badge badge--warning">审计中</span>
49
+ </div>
50
+ <p class="small">
51
+ 每一枚都<strong>自带文字</strong>(WCAG 1.4.1:不能只靠颜色区分)——
52
+ 去掉颜色也能读懂,颜色只是冗余线索。
53
+ </p>
54
+
55
+ <h2 class="rule-top">两档尺寸</h2>
56
+ <div class="row">
57
+ <span class="badge badge--neutral">默认 11px</span>
58
+ <span class="badge badge--neutral badge--lg">较大 13px</span>
59
+ </div>
60
+ <p class="small">
61
+ 只有两档。出现第三档说明信息密度没规划好
62
+ (与 <code>card</code> 的判断标准一致)。
63
+ </p>
64
+
65
+ <h2 class="rule-top">反例</h2>
66
+ <div class="box bad">
67
+ <h3>反例:饱和底 + 白字</h3>
68
+ <div class="row">
69
+ <span class="badge badge--solid-success">已披露</span>
70
+ <span class="badge badge--solid-danger">已停牌</span>
71
+ <span class="badge badge--solid-warning">>审计中</span>
72
+ </div>
73
+ <p class="small">
74
+ 看起来"更醒目",但白字在小字号饱和底上<strong>对比度普遍不足</strong>。
75
+ 实测(<code>contrast.py</code>):暗色下白字在 <code>--success</code> 上只有
76
+ <strong>2.72:1</strong>,远低于 4.5;浅色下是 6.39 达标 ——
77
+ 也就是说<strong>这套写法在暗色下会直接失效</strong>,而看浅色时完全发现不了。
78
+ 并且全页面只有这三个色块时,视觉噪声远大于信息量。
79
+ </p>
80
+ </div>
81
+
82
+ <div class="box bad">
83
+ <h3>反例:用 badge 装可点的东西</h3>
84
+ <p class="small">
85
+ <code>&lt;div class="badge badge--info" onclick="..."&gt;待复核&lt;/div&gt;</code>
86
+ —— div 加 onclick 对读屏是<strong>「没有角色的按钮」</strong>:
87
+ 读不出来它是能点的,键盘也 Tab 不到。
88
+ 要能点就用 <code>&lt;button&gt;</code> 或 <code>&lt;a&gt;</code>,样式照抄 <code>.badge</code>。
89
+ </p>
90
+ </div>
91
+
92
+ <h2 class="rule-top">强制高对比模式</h2>
93
+ <p class="small">
94
+ Windows 的高对比模式会覆盖底色。本组件在
95
+ <code>@media (forced-colors: active)</code> 下把边框换成
96
+ <code>currentColor</code> —— <strong>靠边框保住边界,不靠底色</strong>。
97
+ 这一段无法在本机验证(需要系统级开关)。
98
+ </p>
99
+ </main>
100
+ </body>
101
+ </html>
@@ -0,0 +1,99 @@
1
+ # button
2
+
3
+ | 字段 | 内容 |
4
+ |---|---|
5
+ | **来源** | 原创(依据 WCAG 2.1 + 实测诊断) |
6
+ | **实测** | 对比度见下,全部由 `05-audit/contrast.py` 得出;44px 依据 WCAG 2.5.5 |
7
+ | **适用** | 精简档 / B / C,纯 CSS,可整段复制 |
8
+ | **依赖** | `01-tokens/tokens.css` + `01-tokens/typography.css`(`.note` 提示框) + `01-tokens/page.css`(页面骨架:`.wrap` / `.lede` / `.note`) |
9
+
10
+ ---
11
+
12
+ ## 七态清单(按钮取的是这七个,不是九个)
13
+
14
+ | # | 状态 | 实现 | 不做会怎样 |
15
+ |---|---|---|---|
16
+ | 1 | default | `.btn--primary` | — |
17
+ | 2 | hover | `:hover` + `--accent-hover` | 用户不知道能点 |
18
+ | 3 | active | `:active` 下沉 1px | 点了没反馈 |
19
+ | 4 | **focus-visible** | `:focus-visible` 2px outline | **键盘用户彻底迷失** |
20
+ | 5 | **disabled** | `:disabled` 明确色值(不用 opacity) | **点了没反应,以为坏了** |
21
+ | 6 | **loading** | `[aria-busy]` + `pointer-events:none` | **重复提交** |
22
+ | 7 | success | `data-state="success"`(约 1.2s) | 不知道成没成 |
23
+
24
+ 🔴 实测动机:某项目 的按钮**只有 default + hover 两态**,`:disabled` 0 处。
25
+ 用户不会抱怨"你缺 disabled 态",只会觉得"这个按钮点了没反应,是不是坏了"。
26
+
27
+ ---
28
+
29
+ ## 用法
30
+
31
+ ```html
32
+ <button class="btn btn--md btn--primary">提交</button>
33
+
34
+ <!-- loading:宽度不变,防重复点击 -->
35
+ <button class="btn btn--md btn--primary" aria-busy="true">
36
+ <span class="btn__label">提交</span>
37
+ <span class="btn__spinner"></span>
38
+ </button>
39
+
40
+ <!-- 图标按钮必须带 aria-label -->
41
+ <button class="btn btn--icon btn--ghost" aria-label="关闭">
42
+ <svg ...></svg>
43
+ </button>
44
+ ```
45
+
46
+ 变体:`primary` / `secondary` / `ghost` / `danger`
47
+ 尺寸:`sm`(32) / `md`(44) / `lg`(52)
48
+
49
+ ---
50
+
51
+ ## 🔴 最关键的一个判断:`disabled` 还是 `aria-disabled`
52
+
53
+ 这两个不是同义词,选错会直接伤到键盘用户。
54
+
55
+ | | `disabled` 属性 | `aria-disabled="true"` |
56
+ |---|---|---|
57
+ | Tab 能聚焦 | ❌ 不能,从 tab 顺序移除 | ✅ 能 |
58
+ | 屏幕阅读器 | 直接跳过,用户不知道有这个按钮 | 读到"不可用" |
59
+ | 适用 | **永久**不可用(权限不足、功能下线) | **暂时**不可用(表单没填完) |
60
+
61
+ **表单提交按钮应该用 `aria-disabled`**。理由:用户 Tab 到它,才知道"哦,还差点什么";
62
+ 用 `disabled` 的话他永远找不到这个按钮,也不知道为什么提交不了。
63
+
64
+ 两个都不要的情况:**别用视觉上的"灰掉"来假装禁用**。灰了但还能点,是欺骗。
65
+
66
+ ---
67
+
68
+ ## 反例 —— 什么时候不该用
69
+
70
+ - ❌ **一个视图里出现两个 `primary`** —— 有两个就等于没有重点。其余全降为 secondary/ghost。
71
+ - ❌ **`danger` 做成和 `primary` 一样大** —— 破坏性动作不该被引导去点。
72
+ - ❌ **普通操作加 `success` 态** —— 只有不可逆动作(提交、支付)需要确认反馈,其余是噪音。
73
+ - ❌ **桌面端用 `btn--block`** —— 全宽按钮把视觉动线压成一条竖线。它是移动端方案。
74
+ - ❌ **`ghost` 用在主路径上** —— ghost 的语义是"我不建议你点这个",不是"这个比较淡"。
75
+
76
+ ---
77
+
78
+ ## 两个容易被跳过的细节
79
+
80
+ **1. loading 时宽度不能变**
81
+
82
+ 常见做法是把文字换成 spinner,结果按钮缩窄 → 整行布局跳动。
83
+ 解法:文字 `visibility: hidden` 保留占位,spinner 绝对定位居中。
84
+
85
+ **2. spinner 要豁免 `prefers-reduced-motion`**
86
+
87
+ 全局兜底会把动画压到 0.01ms,spinner 就停了 —— 用户会以为页面卡死。
88
+ WCAG 的 reduced-motion 针对**大幅位移**(前庭功能障碍),
89
+ 小幅度原地旋转不属于此类。**放慢但保留,不要停。**
90
+
91
+ 这是"照抄规范"和"理解规范"的区别。
92
+
93
+ ---
94
+
95
+ ## 已记录的废弃写法
96
+
97
+ 详见 `button.css` 末尾。要点:
98
+ `filter: brightness()` 当 hover / `transition: all` / `opacity` 当 disabled /
99
+ loading 换文字 / hover 用 `scale()`。