agentcss 0.0.0-stage → 0.11.3

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 +3138 -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 +497 -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 +311 -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,265 @@
1
+ (function () {
2
+ 'use strict';
3
+
4
+ var NS = 'http://www.w3.org/2000/svg';
5
+ var instances = [];
6
+
7
+ function toArray(x) { return Array.prototype.slice.call(x); }
8
+ function el(name, attrs) {
9
+ var n = document.createElementNS(NS, name);
10
+ if (attrs) for (var k in attrs) if (attrs.hasOwnProperty(k)) n.setAttribute(k, attrs[k]);
11
+ return n;
12
+ }
13
+ function num(v, d) { var n = parseFloat(v); return isNaN(n) ? d : n; }
14
+
15
+ function parsePoints(spark) {
16
+ var raw = spark.getAttribute('data-spark') || '';
17
+ if (!raw.trim()) return [];
18
+ var parts = raw.split(',');
19
+ var out = [];
20
+ for (var i = 0; i < parts.length; i++) {
21
+ var t = parts[i].trim();
22
+
23
+ if (t === '' || t === '-' || t === 'null' || t === 'NaN') {
24
+ out.push(null);
25
+ continue;
26
+ }
27
+ var v = parseFloat(t);
28
+ out.push(isNaN(v) ? null : v);
29
+ }
30
+ return out;
31
+ }
32
+
33
+ function readOpts(spark) {
34
+ return {
35
+ type: spark.getAttribute('data-spark-type') || 'line',
36
+ height: num(spark.getAttribute('data-spark-height'), 32),
37
+ color: spark.getAttribute('data-spark-color') || 'var(--accent)',
38
+ fill: (spark.getAttribute('data-spark-fill') || 'yes') !== 'no',
39
+ last: (spark.getAttribute('data-spark-last') || 'no') === 'yes',
40
+ animate: (spark.getAttribute('data-spark-animate') || 'yes') !== 'no',
41
+ };
42
+ }
43
+
44
+ function scale(points, w, h, pad) {
45
+
46
+ var vals = [];
47
+ for (var k = 0; k < points.length; k++) {
48
+ if (points[k] !== null) vals.push(points[k]);
49
+ }
50
+ if (!vals.length) return null;
51
+ var min = Math.min.apply(null, vals);
52
+ var max = Math.max.apply(null, vals);
53
+
54
+ if (max === min) { max = min + 1; min = min - 1; }
55
+ var span = max - min;
56
+ var n = points.length;
57
+ var xs = [], ys = [];
58
+ for (var i = 0; i < n; i++) {
59
+ xs.push(n === 1 ? w / 2 : pad + (w - pad * 2) * (i / (n - 1)));
60
+
61
+ ys.push(points[i] === null ? null
62
+ : h - pad - (h - pad * 2) * ((points[i] - min) / span));
63
+ }
64
+ return { xs: xs, ys: ys, min: min, max: max };
65
+ }
66
+
67
+ function supportsReducedMotion() {
68
+ return typeof window.matchMedia === 'function' &&
69
+ window.matchMedia('(prefers-reduced-motion: reduce)').matches;
70
+ }
71
+
72
+ function draw(spark) {
73
+ var pts = parsePoints(spark);
74
+
75
+ var wQuick = Math.round(spark.getBoundingClientRect().width);
76
+ var sigQuick = wQuick + '|' + (spark.getAttribute('data-spark') || '');
77
+ var isFirstQuick = spark.__sparkSig === undefined;
78
+ if (!isFirstQuick && spark.__sparkSig === sigQuick && spark.firstChild) {
79
+ return;
80
+ }
81
+
82
+ var old = spark.firstChild;
83
+ while (old) { var n = old.nextSibling; spark.removeChild(old); old = n; }
84
+ if (pts.length < 2) return;
85
+
86
+ var o = readOpts(spark);
87
+
88
+ var w = Math.round(spark.getBoundingClientRect().width)
89
+ || spark.clientWidth
90
+ || num(spark.getAttribute('data-spark-width'), 120);
91
+ var h = o.height;
92
+
93
+ spark.__sparkSig = sigQuick;
94
+
95
+ spark.style.setProperty('--spark-h', h + 'px');
96
+
97
+ var LAST_R = 2.5;
98
+ var LAST_BAR = 3;
99
+
100
+ var pad = o.last ? (LAST_R + 1.5) : 1;
101
+ var s = scale(pts, w, h, pad);
102
+
103
+ if (!s) return;
104
+ if (s.xs.length < 2) return;
105
+
106
+ var svg = el('svg', {
107
+ width: '100%', height: h,
108
+ viewBox: '0 0 ' + w + ' ' + h,
109
+
110
+ 'aria-hidden': 'true',
111
+ focusable: 'false',
112
+ });
113
+
114
+ var segs = [], cur = [];
115
+ for (var i = 0; i < s.xs.length; i++) {
116
+ if (s.ys[i] === null) {
117
+ if (cur.length) segs.push(cur);
118
+ cur = [];
119
+ } else {
120
+ cur.push(i);
121
+ }
122
+ }
123
+ if (cur.length) segs.push(cur);
124
+
125
+ var total = 0;
126
+ for (var q = 0; q < segs.length; q++) total += segs[q].length;
127
+ if (total < 2) { spark.appendChild(svg); return; }
128
+
129
+ function pathOf(seg) {
130
+ var d = 'M' + s.xs[seg[0]].toFixed(1) + ' ' + s.ys[seg[0]].toFixed(1);
131
+ for (var t = 1; t < seg.length; t++) {
132
+ d += 'L' + s.xs[seg[t]].toFixed(1) + ' ' + s.ys[seg[t]].toFixed(1);
133
+ }
134
+ return d;
135
+ }
136
+
137
+ if (o.type === 'area' && o.fill) {
138
+ var base = h - pad;
139
+ for (var g = 0; g < segs.length; g++) {
140
+ var sg = segs[g];
141
+ if (sg.length < 2) continue;
142
+ var ad = pathOf(sg) +
143
+ 'L'+ s.xs[sg[sg.length - 1]].toFixed(1) + ' ' + base +
144
+ 'L'+ s.xs[sg[0]].toFixed(1) + ' ' + base + 'Z';
145
+ var ap = el('path', { d: ad, 'class': 'spark-area', 'fill-opacity': '0.14' });
146
+ ap.style.setProperty('--spark-c', o.color);
147
+ svg.appendChild(ap);
148
+ }
149
+ }
150
+
151
+ if (o.type === 'bar') {
152
+ var bw = Math.max(1, (w - pad * 2) / pts.length - 1);
153
+ for (var j = 0; j < s.xs.length; j++) {
154
+
155
+ if (s.ys[j] === null) continue;
156
+ var bh = h - pad - s.ys[j];
157
+ var rc = el('rect', {
158
+ x: (s.xs[j] - bw / 2).toFixed(1), y: s.ys[j].toFixed(1),
159
+ width: bw.toFixed(1), height: Math.max(0, bh).toFixed(1),
160
+ 'class': 'spark-bar',
161
+ 'fill-opacity': j === s.xs.length - 1 ? '1' : '0.72',
162
+ });
163
+ rc.style.setProperty('--spark-c', o.color);
164
+ svg.appendChild(rc);
165
+ }
166
+ } else {
167
+ for (var m = 0; m < segs.length; m++) {
168
+ var seg = segs[m];
169
+ if (seg.length === 1) {
170
+
171
+ var dc = el('circle', {
172
+ cx: s.xs[seg[0]].toFixed(1), cy: s.ys[seg[0]].toFixed(1), r: '1.5',
173
+ 'class': 'spark-dot',
174
+ });
175
+ dc.style.setProperty('--spark-c', o.color);
176
+ svg.appendChild(dc);
177
+ continue;
178
+ }
179
+
180
+ var path = el('path', {
181
+ d: pathOf(seg),
182
+ 'class': 'spark-line',
183
+ 'stroke-width': '1.5',
184
+ 'stroke-linecap': 'round', 'stroke-linejoin': 'round',
185
+ 'vector-effect': 'non-scaling-stroke',
186
+ });
187
+ path.style.setProperty('--spark-c', o.color);
188
+
189
+ if (o.animate && !supportsReducedMotion() && isFirstQuick) {
190
+
191
+ path.classList.add('spark-anim');
192
+ }
193
+ svg.appendChild(path);
194
+ }
195
+ }
196
+
197
+ var li = s.xs.length - 1;
198
+ if (o.last && s.ys[li] !== null) {
199
+ var lc = el('circle', {
200
+ cx: s.xs[li].toFixed(1), cy: s.ys[li].toFixed(1), r: String(LAST_R),
201
+ 'class': 'spark-dot',
202
+ });
203
+ lc.style.setProperty('--spark-c', o.color);
204
+ svg.appendChild(lc);
205
+ }
206
+
207
+ spark.appendChild(svg);
208
+ }
209
+
210
+ var Chart = {
211
+ draw: draw,
212
+ emit: function (spark) { draw(spark); },
213
+
214
+ update: function (root) {
215
+ var list = (root || document).querySelectorAll('.sparkline[data-spark]');
216
+ for (var i = 0; i < list.length; i++) draw(list[i]);
217
+ },
218
+ };
219
+ window.Chart = Chart;
220
+
221
+ function init() { Chart.update(); }
222
+
223
+ if (typeof window.ResizeObserver === 'function') {
224
+ var ro = new window.ResizeObserver(function (entries) {
225
+ for (var i = 0; i < entries.length; i++) {
226
+ var el = entries[i].target;
227
+ if (el && el.className && el.className.indexOf('sparkline') > -1) {
228
+ draw(el);
229
+ }
230
+ }
231
+ });
232
+
233
+ function observeAll() {
234
+ var list = document.querySelectorAll('.sparkline[data-spark]');
235
+ for (var i = 0; i < list.length; i++) {
236
+ try { ro.observe(list[i]); } catch (e) { }
237
+ }
238
+ }
239
+ if (document.readyState === 'loading') {
240
+ document.addEventListener('DOMContentLoaded', observeAll);
241
+ } else {
242
+ observeAll();
243
+ }
244
+
245
+ Chart.observe = function (el) {
246
+ if (el) { try { ro.observe(el); } catch (e) { } }
247
+ else observeAll();
248
+ };
249
+ } else {
250
+
251
+ window.addEventListener('resize', function () { Chart.update(); });
252
+ }
253
+
254
+ if (document.readyState === 'loading') {
255
+ document.addEventListener('DOMContentLoaded', init);
256
+ } else {
257
+ init();
258
+ }
259
+
260
+ var t = null;
261
+ window.addEventListener('resize', function () {
262
+ if (t) clearTimeout(t);
263
+ t = setTimeout(function () { Chart.update(); }, 150);
264
+ });
265
+ })();
package/dist/COSTS.md ADDED
@@ -0,0 +1,56 @@
1
+ # 采纳成本表
2
+
3
+ > 这个文件由 `05-audit/dist-cost-gate.py` **生成**,不要手改(改了门禁会红)。
4
+ > 数字口径:**dist 里的 min 产物,gzip 9 级**。
5
+
6
+ ## 一、为什么单独算这一笔
7
+
8
+ 采用一个组件要付三笔钱:`tokens`(必付)+ 组件 CSS + 组件 JS(可选)。
9
+
10
+ 实测两笔账,一笔不省:
11
+
12
+ - `tokens` 源码版 gzip **18.1 KB** → min 版 **2.6 KB**(省 85%)——
13
+ 源码多的那部分**全是注释**(全库 CSS 有 66% 是注释,字节口径),而注释是给我们的,不是给使用者浏览器的。
14
+ - tokens 的 min 版 2.6 KB **比任何一个组件自己都贵** ⇒
15
+ "只用一个组件"的真实起步价就是它。不公开这张表,等于让人盲买。
16
+
17
+ ## 二、明码标价
18
+
19
+ | 档 | 组件 | tokens(必付) | CSS | JS | **合计** | 源码版合计 | 差 |
20
+ |---|---|---:|---:|---:|---:|---:|---:|
21
+ | primitive | `badge` | 2.6 KB | 0.5 KB | — | **3.1 KB** | 20.8 KB | −17.7 KB |
22
+ | primitive | `button` | 2.6 KB | 1.0 KB | — | **3.6 KB** | 24.3 KB | −20.7 KB |
23
+ | primitive | `card` | 2.6 KB | 0.9 KB | — | **3.6 KB** | 21.6 KB | −18.0 KB |
24
+ | primitive | `choice` | 2.6 KB | 1.1 KB | — | **3.7 KB** | 23.5 KB | −19.7 KB |
25
+ | primitive | `combobox` | 2.6 KB | 1.0 KB | 5.4 KB | **9.0 KB** | 27.7 KB | −18.8 KB |
26
+ | primitive | `date-range` | 2.6 KB | 0.8 KB | 2.5 KB | **6.0 KB** | 24.5 KB | −18.6 KB |
27
+ | primitive | `input` | 2.6 KB | 1.0 KB | — | **3.6 KB** | 21.7 KB | −18.0 KB |
28
+ | primitive | `popover` | 2.6 KB | 0.8 KB | 2.1 KB | **5.6 KB** | 25.6 KB | −20.0 KB |
29
+ | primitive | `progress` | 2.6 KB | 0.7 KB | — | **3.3 KB** | 20.9 KB | −17.6 KB |
30
+ | primitive | `select` | 2.6 KB | 0.8 KB | 3.5 KB | **6.9 KB** | 27.9 KB | −20.9 KB |
31
+ | primitive | `separator` | 2.6 KB | 0.2 KB | — | **2.9 KB** | 19.3 KB | −16.5 KB |
32
+ | primitive | `skeleton` | 2.6 KB | 0.5 KB | — | **3.1 KB** | 19.5 KB | −16.4 KB |
33
+ | primitive | `switch` | 2.6 KB | 0.8 KB | — | **3.4 KB** | 25.2 KB | −21.8 KB |
34
+ | pattern | `accordion` | 2.6 KB | 1.3 KB | 1.7 KB | **5.7 KB** | 31.9 KB | −26.2 KB |
35
+ | pattern | `content` | 2.6 KB | 1.0 KB | — | **3.6 KB** | 22.6 KB | −19.0 KB |
36
+ | pattern | `drawer` | 2.6 KB | 0.8 KB | 2.0 KB | **5.4 KB** | 23.4 KB | −18.1 KB |
37
+ | pattern | `dropdown` | 2.6 KB | 0.8 KB | 2.9 KB | **6.3 KB** | 26.3 KB | −20.0 KB |
38
+ | pattern | `form-validation` | 2.6 KB | 0.8 KB | — | **3.4 KB** | 22.6 KB | −19.2 KB |
39
+ | pattern | `list` | 2.6 KB | 0.6 KB | — | **3.2 KB** | 20.5 KB | −17.2 KB |
40
+ | pattern | `nav` | 2.6 KB | 1.2 KB | 2.6 KB | **6.5 KB** | 29.2 KB | −22.8 KB |
41
+ | pattern | `overlay` | 2.6 KB | 1.1 KB | 2.8 KB | **6.6 KB** | 32.0 KB | −25.4 KB |
42
+ | pattern | `pagination` | 2.6 KB | 0.8 KB | 2.6 KB | **6.0 KB** | 28.3 KB | −22.4 KB |
43
+ | pattern | `reveal` | 2.6 KB | 0.3 KB | 1.1 KB | **4.1 KB** | 22.5 KB | −18.4 KB |
44
+ | pattern | `states` | 2.6 KB | 0.8 KB | — | **3.5 KB** | 22.1 KB | −18.6 KB |
45
+ | pattern | `tabs` | 2.6 KB | 0.7 KB | 2.0 KB | **5.3 KB** | 25.0 KB | −19.7 KB |
46
+ | pattern | `tooltip` | 2.6 KB | 0.5 KB | 1.9 KB | **5.0 KB** | 24.7 KB | −19.7 KB |
47
+ | pattern | `tree` | 2.6 KB | 0.6 KB | 2.9 KB | **6.2 KB** | 25.7 KB | −19.5 KB |
48
+
49
+ ## 三、全库
50
+
51
+ - 全部组件都用上(min,含 tokens 一份):**60.0 KB**
52
+ - 源码版(带注释)全库 gzip:288.4 KB
53
+
54
+ > ⚠️ 源码版那个数字**不是**要付的钱:它包含我们的注释(全库 CSS 有 66% 是注释,字节口径)。
55
+ > 它的用途只有一个 —— 让人看清"dist 到底省了多少"。
56
+
@@ -0,0 +1,197 @@
1
+ # AI 编辑契约
2
+
3
+ > **这份文件是给「正在修改本库或其使用者页面」的人与 AI 看的操作边界。**
4
+ > 不是风格指南,是**硬约束**。违反其中任何一条,库里的门禁会红。
5
+
6
+ ---
7
+
8
+ ## 为什么需要这份文件
9
+
10
+ 一次真实事故:用本库做 14 页 PPT,AI 反复局部修改后整体崩坏,
11
+ 人工修复 1.5 小时仍未收口。
12
+
13
+ 复盘结论:**问题不在模型不够聪明,而在系统没有划定修改边界。**
14
+ 库约束了「浏览器里怎么表现」,但没有约束「CSS 能写在哪」——
15
+ 于是模型可以随手写 `a { color: blue }`,把宿主全站链接改掉。
16
+
17
+ ⇒ 本库能做的不是「保证 AI 不犯错」,是**让 AI 犯的错有上限**。
18
+
19
+ ---
20
+
21
+ ## 一、七条硬约束
22
+
23
+ | # | 规则 | 为什么 | 门禁 |
24
+ |---|---|---|---|
25
+ | 1 | **不得写裸标签选择器**(`a {}` `h1 {}` `button {}`) | 作用域是整个文档 ⇒ 会改掉宿主页面所有同名元素 | `bleed-gate.py` |
26
+ | 2 | **不得新增裸颜色 / 裸间距** | 一旦绕过令牌,暗色模式立刻失效 | `hardcode-gate.py` |
27
+ | 3 | **不得修改 `tokens.css`**(除非任务明确要求改令牌) | 它是全库配色/字号/间距的源头,改它=改整个项目 | `impact-report.py` |
28
+ | 4 | **不得新增页面级 override 链**(`.page-3 h1 {...}` 叠加) | 局部改动必须对全局无副作用 | `bleed-gate.py` + 视觉回归 |
29
+ | 5 | **组件改动必须重跑该组件的视觉基线** | 行为契约抓不到「样式被改坏」 | `shot-baseline.py` |
30
+ | 6 | **组件不得自己造 DOM 事件**(`new CustomEvent` / `createEvent`) | 老 WebView 没有 `CustomEvent` 构造函数 ⇒ 在**用户交互路径上**抛异常,本地测不出来。唯一入口是 `flEmit` | `emit-check.js` 判据 ⑨ |
31
+ | 7 | **不得在注释/示例里写不存在的 API**(含 `data-on-*` 这种"属性当回调") | 用法示例会被照抄;`pg.on(...)` 这种从来没实现过的写法 ⇒ 运行时 `is not a function`。HTML 属性里放不出函数,`data-on-*` 物理上只能是死代码 | `api-form-gate.py` 判据 5 · `emit-check.js` 判据 ⑩ |
32
+
33
+ > 第 6 条为什么值得单独列:它不是风格问题。
34
+ > 自己写 `new CustomEvent(...)` 在 Chrome 里**一切正常**,
35
+ > 只在真机上表现为"点了没反应",而且控制台不一定有线索。
36
+ > ⇒ 这类"本地全绿、真机崩"的改动,正是这份契约要挡的东西。
37
+ >
38
+ > 第 7 条是同一类:**本地全绿、别人照抄就崩**。
39
+ > 本库已经有过两次这种事故(`is-*` 状态类、pagination 的 `pg.on`),
40
+ > 它们的共同点是"说有、实现里没有",而没有任何门禁在比对这两者。
41
+
42
+ ---
43
+
44
+ ## 二、修改之前先看影响范围
45
+
46
+ ```bash
47
+ python3 05-audit/impact-report.py # 我刚改了哪些文件
48
+ python3 05-audit/impact-report.py --staged # 只看暂存区
49
+ ```
50
+
51
+ 它会明确告诉你:
52
+
53
+ ```
54
+ 🔴 全局影响(必须全量回归)
55
+ 01-tokens/tokens.css 令牌层:全库配色/间距/字号的源头
56
+ ⇒ 必须通过:bleed contrast dark-cont visual
57
+
58
+ 🟡 局部影响(只需检查这些)
59
+ 03-patterns/content/content.css 组件样式:仅该组件的页面
60
+ ⇒ 需要重跑视觉回归:03-patterns/content/demo.html
61
+ ```
62
+
63
+ **不要凭感觉决定要不要跑回归。** 这条命令就是为此存在的。
64
+
65
+ ---
66
+
67
+ ## 三、局部修改的标准动作
68
+
69
+ 以「改第 3 页的标题」为例:
70
+
71
+ ```bash
72
+ # 1. 先看范围
73
+ python3 05-audit/impact-report.py
74
+
75
+ # 2. 只改该页面的文件,不要碰共享层
76
+
77
+ # 3. 只跑相关的门禁
78
+ MODE=fast bash 05-audit/check-all.sh
79
+ python3 05-audit/shot-baseline.py --check # 视觉基线
80
+
81
+ # 4. 确认没波及别处
82
+ python3 05-audit/impact-report.py # 应当仍然全是局部
83
+ ```
84
+
85
+ ❌ 反面做法(事故里的实际路径):
86
+
87
+ ```css
88
+ /* 为了修第 3 页 */
89
+ h1 { font-size: 31px } /* 改一个,14 页全变 */
90
+ .slide-3 h1 { font-size: 31px } /* 于是开始堆页面级 override */
91
+ .slide-4 h1 { font-size: 32px } /* ……一路滑向灾难 */
92
+ ```
93
+
94
+ ⇒ **正确的修法是改组件,不是改页面。**
95
+ 如果你发现自己在写 `.slide-N xxx`,停下来 —— 那是信号。
96
+
97
+ ---
98
+
99
+ ## 四、布局应该用组件,不是自由发挥
100
+
101
+ 本库提供的是**组件**,不是自由布局。
102
+ 要表达「两栏」「卡片网格」,用现有组件组合,不要自己写宽度。
103
+
104
+ ```html
105
+ <!--✅ 用组件组合 -->
106
+ <div class="card"><div class="card__body">…</div></div>
107
+
108
+ <!--❌ 自己发明布局:magic number 谁都维护不了 -->
109
+ <div style="width: 612px; margin-left: 37px; transform: translateX(19px)">
110
+ ```
111
+
112
+ **理由**:magic number 无法被门禁检查,也无法在暗色模式下自适应。
113
+ 本库现有的令牌与组件已经覆盖常见场景;找不到合适的场景时,
114
+ **加一个组件**比在页面里调数值更省事。
115
+
116
+ ---
117
+
118
+ ## 五、什么时候该停下来问
119
+
120
+ 以下情况不要自行决定,停下来确认:
121
+
122
+ - 需要修改 `01-tokens/tokens.css`(影响全局)
123
+ - 需要绕过某个门禁(说明门禁要么错了、要么设计要改)
124
+ - 一个组件要加第三种视觉变体(先确认能不能用现有变体组合)
125
+ - 某个问题「改A 坏了,改 B 也坏了」(可能是耦合,需要先查依赖)
126
+
127
+ ---
128
+
129
+ ## 六、这套约束的边界(诚实说明)
130
+
131
+ **本库做不到的事**:
132
+
133
+ - ❌ 约束使用者在**自己项目**里写的 CSS —— 那些文件不在本库仓库里
134
+ - ❌ 替代人工设计判断 —— 布局是否「好看」不是机械判据
135
+ - ❌ 保证任何模型不犯错 —— 只能保证它犯的错**有上限、有据可查**
136
+
137
+ **为什么还要做**:因为「有上限」和「没上限」在真实工作量上是天壤之别。
138
+ 事故里 1.5 小时修不完,恰恰是因为错误**没有边界**。
139
+
140
+ ---
141
+
142
+ ## 六·五、这份文档的层次
143
+
144
+ ⚠️ 本节上面的内容是 **Guidance**(建议)。它可以整份推翻,不动门禁。
145
+
146
+ 真正不能被推翻的是另外两层:
147
+
148
+ | 层 | 在哪 | 怎么改 |
149
+ |---|---|---|
150
+ | **不变式**(客观事实) | `INVARIANT.md` | 改不了,除非物理定律变了 |
151
+ | **契约**(约定) | `ai/*.json` + `API.md` | 发个版本就能改 |
152
+ | **建议**(这里) | `GUIDANCE.md` + 本文件 | 随时可整份作废 |
153
+
154
+ 为什么分三层:**约束如果只有一层,今天的约束就是明天的天花板。**
155
+ 模型变强、做法变化时,放宽的是建议层,不变式一个字都不用动。
156
+
157
+ ⇒ 如果你在写自动化工具,请读 `ai/` 下的机器可读契约,而不是解析这份散文。
158
+
159
+ ## 七、给 AI 的极简版(贴进 system prompt 即可)
160
+
161
+ ```
162
+ 遵守以下编辑边界:
163
+ 1. 不写裸标签选择器(a{} h1{} button{})——一律挂组件根类
164
+ 2. 不新增裸颜色与裸间距——用 tokens
165
+ 3. 不改 01-tokens/tokens.css,除非任务明确要求改令牌
166
+ 4. 不写 .page-N .xxx 这类页面级 override 链
167
+ 5. 改组件样式后必须重跑该组件的视觉基线
168
+ 6. 改之前先跑 impact-report.py 看影响范围
169
+ 7. 状态一律写 data-state 属性,不写状态类名(见 API.md 迁移表)
170
+ 发现自己在写页面级 override ⇒ 停下来,改组件
171
+ ```
172
+
173
+ 机器的版本在这里(**优先用它**,不用解析上面的散文):
174
+
175
+ - `ai/components.json` / `ai/tokens.json` —— 组件与令牌的结构化事实
176
+ - `ai/validate.js` + `node ai/cli.js check <文件>` —— 零依赖校验
177
+ - `ai/profiles.json` —— 三档严格程度;`strict` 只允许 `stable` 组件
178
+ - `ai/capabilities.json` —— 按**能力**协商可用操作,不按模型名分支
179
+ - `ai/behaviors.json` —— **行为覆盖矩阵**:哪些组件必须有哪种微行为
180
+ (状态:`core` 已收编 / `manual` 手写未收编 / `gap` 应做未做 / `n/a` 不适用)
181
+ ⇒ **不登记就红**,不许靠省略跳过;`manual` 与 `gap` 的数量有棘轮,只能降不能升
182
+ - **`maturity`(成熟度)是算出来的,不是拍的** —— 每个组件有一个
183
+ `maturity`(`alpha` / `beta` / `stable`)和一份 `maturityReasons`。
184
+ 四条判据:有 `demo.html` · 有专属门禁 · 状态全在 `data-*` 属性上(I-8)
185
+ · **行为零欠账**(矩阵里没有 `manual` / `gap`)。
186
+ ⇒ 手写把某个组件改成 `stable` 而它还欠着账,门禁会红(`05-audit/maturity-gate.py`)。
187
+ ⇒ ⚠️ `strict` 档位只放行 `stable`:欠着账的组件在 `strict` 下**不可用**,
188
+ 这是有意的 —— 要用就切 `standard`,并接受它们可能还有手写副本。
189
+ - `ai/deprecations.json` —— **废弃登记册**:库里曾经有 / 现在有但将来要删的公开名字
190
+ (令牌名 / 类名)。移除公开名字是破坏性变更,必须走流程:
191
+ 登记(`deprecatedIn`)→ **跨至少一个次版本**的迁移窗口 → 到 `removeIn` 才允许删。
192
+ 判据双向看住(`05-audit/deprecation-gate.py`):到期没删红、提前删也红。
193
+ ⇒ `ai/surface.baseline.json` 是公开面基线,**只增不减** —— 否则"先删代码再更新基线"
194
+ 就能把未登记的移除洗白。
195
+
196
+ ⚠️ 诚实边界:我们没有 codemod、也没有运行时告警,所以这个"窗口"只是**版本号承诺**,
197
+ 不是技术阻断。要真的拦截,得自己在 CI 里加 lint。
@@ -0,0 +1,127 @@
1
+ # 待办与判定台账(BACKLOG)
2
+
3
+ > 这份文件只回答三个问题:
4
+ > **① 那些"好想法"哪些已经落地、由什么守着;② 哪些裁定不做、什么条件下重开;
5
+ > ③ 哪些是环境边界(不是待办,别再当 TODO 挂着)。**
6
+ >
7
+ > 它的存在理由:这些结论原本散在四份报告里(交付报告 / huxx 借鉴评审 /
8
+ > 合并评审 / 交接单),要翻完才知道还剩什么。于是同一件事被反复讨论、
9
+ > 已被判"不做"的又被重新提出来做一遍。
10
+ >
11
+ > ⚠️ **本文件不写会变的数字**(门禁数、自检数、组件数)。要给数字,
12
+ > 就跑对应的门禁看它的输出 —— 数字只有运行时一个出处(I-7)。
13
+
14
+ ---
15
+
16
+ ## 一、已落地(每一项都有门禁守着,不是"写过")
17
+
18
+ | 能力 | 落点 | 守着它的判据 |
19
+ |---|---|---|
20
+ | 入场动效(六方向、位移 ≤8px、默认不接管、只播一次) | `03-patterns/reveal/` | `reveal-contract.js`(10 条)+ `motion.py --reduced-audit` |
21
+ | 减少动效三档(位移必停 / 真实进度必留 / 颜色压到 `--dur-fast`) | `01-tokens/` 令牌层一条覆盖规则 | `motion.py`(三向核对,非文件计数) |
22
+ | 详情页三变体(full / partial / null 同构) | `04-recipes/detail-page/` | `detail-page-contract.py`(标签序列逐项比对 + 视觉覆盖) |
23
+ | 无数据是一等状态(不隐藏、不拿 0 冒充、必须给理由、版面不塌) | 同上 `null.html` | `no-data-gate.py` |
24
+ | 新页面必须进视觉基线(防"新配方无人看管") | `05-audit/visual-coverage-gate.py` | 自身 `--selftest` + 反向控制 |
25
+ | 视觉基线防"改注释也算变更" | `shot-baseline.py` 的 `css_fingerprint()` | 剥注释/去空行后再哈希 |
26
+ | 包内闭包 + 消费者侧解析 | `pack-closure.js` / `entry-resolve.js` | `pack-closure` / `pkg-resolve`(判"消费者真去解析") |
27
+ | 自动初始化写成契约(每个全局逐个写明 是 / 条件 / 否) | `API.md`「自动初始化」+ 源码 `@autoinit` 标记 | `autoinit-gate.py`(三条判据,双向) |
28
+ | 门禁自己也要有牙(反向控制被真的跑到) | `behavior-reverse.sh` + `selftest-all.py` | `selftest-all`(元门禁)+ `selftest-all-rev` |
29
+ | 文档事实与仓库一致(组件数 / 门禁数 / stable·beta) | `05-audit/doc-facts-gate.py` | 自身 `--selftest` |
30
+ | 真机能力矩阵(每一行都是 VERIFIED) | `docs/LAYER-BASELINE.md` | `webview-probe-gate.py`(清单与源码双向) |
31
+
32
+ ---
33
+
34
+ ## 二、本轮(autoinit 契约那一轮)做的事
35
+
36
+ | 事 | 性质 | 证据 |
37
+ |---|---|---|
38
+ | `selftest-all` 自备 `:8000`(canary 字节比对 + 退出时关掉) | **修真实缺陷**:fast 档无服务 ⇒ 一条自检假红,红的原因与检查内容无关 | `python 05-audit/selftest-all.py` → 全部通过 |
39
+ | 判定抽成 `verdict()` + 判据 ④「跑不起来 ≠ 通过」 | 新增牙:`RC=0` 但输出说跑不起来,判红 | 自带 `--selftest` 样本 |
40
+ | `dead-class-gate --selftest` 接进 `behavior-reverse.sh` | 补 P2 欠账:它有自检但**从没被跑过** | `behavior-reverse.sh` |
41
+ | 自动初始化契约 + `autoinit-gate` | 把 P3 的误判转成真闭环:**不改行为**,只补文档与判据 | 每个破坏样本都判对 |
42
+ | `CONTRIBUTING` 两处过时数字 | 一处被 `doc-facts` 抓到,一处(散文标题 `159 道`)判据够不着 ⇒ 改成不写数字 | `doc-facts-gate` 绿 |
43
+ | `ERRORS.md` E56 / E57 | 判据前提要自己造;注释不写会变的数量 | 台账 |
44
+
45
+ ---
46
+
47
+ ## 三、裁定不做(附重开条件)
48
+
49
+ | 事项 | 为什么不做 | 什么条件下重开 |
50
+ |---|---|---|
51
+ | **T4 全局事件总线** | 没有第二个消费者(图表不订阅主题切换)。为一个假想消费者加全局单例,是把"零依赖"换成"零依赖但有隐含全局状态" | 出现**第二个真实消费者**(例如表格排序要通知图表重绘),且实现 ≤30 行 |
52
+ | **View Transitions** | 真机基线含 **Chromium 97**(百度浏览器),而它要 111+。收益是"更好看"不是"更能用" | 有 Chromium 97–111 区间的实测基线,且能给出降级路径 |
53
+ | **装饰层兄弟门禁**(`deco-sibling`) | 库里只有 **1 个**装饰层节点(`.detail-hero__deco`),且它已经做对了(`pointer-events:none` + `aria-hidden` + 空 div)。门禁判据只能靠 `deco` 这个**命名约定**触发 —— 第二个人把那层叫 `.hero__glow` 就漏了。**靠命名的守卫是弱判据**,不如不建 | 出现第 2 个装饰层,且命名不统一 ⇒ 改成**形态判据**(绝对定位 + 覆盖父容器 + 无文本/无交互子树),不再看名字 |
54
+ | **滚动位置还原**(S5) | 实测三组 A/B/C 全部 `1600 → 1600`:桌面 Chromium 后退走 **bfcache** 整页恢复,脚本那段根本不需要跑。按"无法实测不合并"回退,没有留死代码 | 有**不走 bfcache** 的目标(旧 WebView),或页面返回后必然重渲染 |
55
+ | **给 9 个 create-only 组件加自动初始化**(P3 的 A 方案) | 自动初始化拿不到 `options` ⇒ 给一个"看起来能用、行为不对"的默认实例,比不初始化更坏;且会与用户手写的 `create` **双初始化**(双重事件、泄漏) | 组件出现"零配置也能正确工作"的形态(例如全部改由 `data-*` 驱动),且能给出去重机制 |
56
+ | **把散文里的数字也纳入 doc-facts** | 实测全库 6 处「NNN 道」,其中 4 处是**历史事故记录**(本来就是旧数字,改了才是篡改)。扩宽正则只会误伤历史叙述 —— 判据咬错人比不咬更坏 | 文档里出现"当前值"与"历史值"可区分的写法约定(例如统一 `@fact:` 标记),再据标记判 |
57
+
58
+ ---
59
+
60
+ ## 四、环境边界(不是待办,别再挂 TODO)
61
+
62
+ 这三件事**代码侧已经就绪或已到边界**,缺的是外部条件。写在这里是为了
63
+ 下次不再重新讨论一遍"要不要做""是不是没做"。
64
+
65
+ ### 4.1 真机覆盖:只到现有矩阵,不再扩
66
+
67
+ | 已有(全部 VERIFIED) | 缺口 |
68
+ |---|---|
69
+ | iPhone Safari / iPad Safari / iPad 微信 / iPad 企微 / Android 微信(XWEB 146)/ Android 百度浏览器(Chromium 97) | Android **系统浏览器 / 其它 App 内置内核**(抖音、小红书、支付宝…) |
70
+
71
+ **为什么不再扩**:国内环境下拿不到稳定的 Android 系统浏览器与 Google 组件,
72
+ 云真机又要实名与费用;使用者能提供的机器已经全部采过。
73
+
74
+ **在现有条件下已经做到了什么(这些不需要新设备)**:
75
+
76
+ 1. **语法下限**:`es5-gate.py` 保证库代码不会用到 Chromium 97 不认识的语法。
77
+ 2. **特性探测而非 UA 猜测**:`@layer` 不可用时整层回退(`LAYER-BASELINE.md` 已记录
78
+ Chromium 97 **不支持 `@layer`** 这条阻塞项,并按"每一行都通过才无条件切"处理)。
79
+ 3. **能力探针页可复用**:`10-review/webview/capability-probe.html` 是自包含的,
80
+ 任何人用手机自带浏览器打开就能采一行;采集结果按 `LAYER-BASELINE.md`
81
+ 的表头填(必须写清**从哪个入口**打开)。
82
+ 4. **不虚构结论**:没有实测的内核一律标 `UNVERIFIED`,不写成"应该没问题"。
83
+
84
+ ### 4.2 npm 发布
85
+
86
+ 代码与发布脚本已就绪(`05-audit/publish.sh`,`.npmrc` 钉官方源)。
87
+ 缺的是账号 + 2FA 的人工动作。**注意历史坑**(`ERRORS.md` E55):
88
+ publish 返回 0 之后 registry 可能仍显示旧占位,**不要据此删包**。
89
+
90
+ ### 4.3 W13 真模型跑批
91
+
92
+ 工具链封闭(记录 v2 / 八条判据 / `models/reference.json` 必须 10/10),
93
+ **记录数 0 ⇒ UNVERIFIED**。缺的是模型 API 访问权。现有结论("一次生成半分到
94
+ 一毛钱,瓶颈是轮次不是 token")来自人工实测,不是跑批。
95
+
96
+ ---
97
+
98
+ ## 五、如果还要往前推,按性价比排序
99
+
100
+ | 顺序 | 事项 | 为什么值得 | 前置 |
101
+ |---|---|---|---|
102
+ | 1 | **把 `docs/ROADMAP.md` 的评分表按真值重写** | 它现在还写着「运行时描述符比对待做(W3)」「npm ci + WebKit 待做(W7)」「事实门禁待做(W4)」,而这三项**实测都已完成**(`api-form-gate` 消费 `global-api-probe`;CI 有 `npm ci` + nightly webkit 矩阵;`doc-facts-gate` 在跑)。过时的路线图会让下一个人重做一遍 | 无 |
103
+ | 2 | 真机矩阵补一行(任何人的手机自带浏览器) | 成本 5 分钟,直接减少一个 `UNVERIFIED` | 一台能扫二维码的手机 |
104
+ | 3 | 把 `capability-probe` 的采集流程写成一页 SOP | 现在采集格式只写在表格里,靠人猜 | 无 |
105
+ | 4 | 次要:`ERRORS.md` 按"触发面"重新索引 | 查"我是不是又要犯某条"很不方便 | 无 |
106
+
107
+ ---
108
+
109
+ ## 六、怎么复查这份台账
110
+
111
+ ```bash
112
+ cd <仓库根>
113
+
114
+ # ① 已落地的东西还在不在(全量,约 10 分钟)
115
+ MODE=full bash 05-audit/check-all.sh
116
+
117
+ # ② 判据有没有牙(含本轮新增的 autoinit / selftest-all / dead-class)
118
+ python 05-audit/selftest-all.py
119
+ bash 05-audit/behavior-reverse.sh
120
+
121
+ # ③ 文档说的和仓库是不是一回事
122
+ python 05-audit/doc-facts-gate.py
123
+ python 05-audit/autoinit-gate.py
124
+ ```
125
+
126
+ **判定纪律**:本文件里说"已落地"的条目,如果哪天门禁红了,以门禁为准 ——
127
+ 台账只是索引,不是证据。