agentcss 0.25.6 → 0.27.0

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 (81) hide show
  1. package/01-tokens/README.md +1 -1
  2. package/01-tokens/behavior/labels.js +44 -0
  3. package/01-tokens/responsive-demo.html +1 -1
  4. package/01-tokens/tokens.core.css +1 -1
  5. package/01-tokens/tokens.css +2 -2
  6. package/02-primitives/combobox/combobox.js +26 -3
  7. package/02-primitives/date-range/date-range.js +28 -6
  8. package/02-primitives/popover/popover.js +22 -2
  9. package/02-primitives/select/select.js +23 -2
  10. package/02-primitives/timeline/demo.html +1 -1
  11. package/02-primitives/upload/upload.js +50 -17
  12. package/03-patterns/content/content.css +13 -1
  13. package/03-patterns/content/demo.html +1 -1
  14. package/03-patterns/drawer/demo.html +1 -1
  15. package/03-patterns/drawer/drawer.js +44 -6
  16. package/03-patterns/dropdown/dropdown.js +21 -1
  17. package/03-patterns/overlay/overlay.css +1 -1
  18. package/03-patterns/overlay/overlay.js +39 -2
  19. package/03-patterns/pagination/pagination.js +37 -10
  20. package/03-patterns/states/states.css +1 -1
  21. package/03-patterns/tooltip/tooltip.js +17 -2
  22. package/03-patterns/tree/tree.js +21 -1
  23. package/04-recipes/analysis-report/demo.html +1 -1
  24. package/04-recipes/app-shell/README.md +1 -1
  25. package/04-recipes/app-shell/demo.html +1 -1
  26. package/04-recipes/data-showcase/demo.html +2 -2
  27. package/04-recipes/longform/content.html +993 -78
  28. package/04-recipes/longform/longform.html +3 -3
  29. package/04-recipes/report/demo.html +3 -3
  30. package/04-recipes/table/README.md +23 -1
  31. package/04-recipes/table/demo.html +7 -7
  32. package/09-assets/bar/bar.css +1 -1
  33. package/09-assets/bar/bar.js +28 -4
  34. package/09-assets/model-viewer/model-viewer.js +45 -13
  35. package/09-assets/scientific-plot/demo.html +6 -6
  36. package/AGENTS.md +3 -1
  37. package/API.md +32 -0
  38. package/CHANGELOG.md +174 -5
  39. package/CONTRIBUTING.md +44 -3
  40. package/README.md +19 -0
  41. package/README.zh-CN.md +18 -0
  42. package/SECURITY.md +16 -4
  43. package/START-HERE.md +25 -18
  44. package/ai/START-HERE.md +40 -6
  45. package/ai/check-html.js +658 -0
  46. package/ai/cli.js +557 -67
  47. package/ai/components.json +9 -4
  48. package/ai/pdf.js +52 -10
  49. package/ai/recipes.json +86 -0
  50. package/ai/scaffold.js +195 -0
  51. package/ai/shot.js +345 -0
  52. package/ai/validate.js +65 -6
  53. package/dist/01-tokens/behavior/labels.js +11 -0
  54. package/dist/02-primitives/combobox/combobox.js +25 -3
  55. package/dist/02-primitives/date-range/date-range.js +26 -5
  56. package/dist/02-primitives/popover/popover.js +14 -1
  57. package/dist/02-primitives/select/select.js +22 -2
  58. package/dist/02-primitives/upload/upload.js +47 -17
  59. package/dist/03-patterns/content/content.css +1 -1
  60. package/dist/03-patterns/drawer/drawer.js +32 -4
  61. package/dist/03-patterns/dropdown/dropdown.js +20 -1
  62. package/dist/03-patterns/overlay/overlay.js +25 -1
  63. package/dist/03-patterns/pagination/pagination.js +34 -10
  64. package/dist/03-patterns/tooltip/tooltip.js +14 -2
  65. package/dist/03-patterns/tree/tree.js +20 -1
  66. package/dist/09-assets/bar/bar.js +23 -4
  67. package/dist/09-assets/model-viewer/model-viewer.js +38 -12
  68. package/dist/COSTS.md +20 -20
  69. package/docs/ACCESSIBILITY.md +3 -3
  70. package/docs/ARCHITECTURE.md +116 -0
  71. package/docs/L10N.md +92 -0
  72. package/docs/LAYER-BASELINE.md +2 -2
  73. package/docs/PRINT.md +3 -3
  74. package/docs/RELEASE-PROCESS.md +59 -3
  75. package/docs/STABILITY.md +1 -1
  76. package/docs/VERIFY-RELEASE.md +24 -2
  77. package/index.html +3 -3
  78. package/llms-full.txt +18 -4
  79. package/llms.txt +26 -5
  80. package/package.json +4 -2
  81. package/types/index.d.ts +218 -13
@@ -10,8 +10,9 @@
10
10
  demo 可以用现代语法(跑在用户浏览器上),库代码不行。
11
11
 
12
12
  API:
13
- Overlay.toast({ title, desc, variant, duration })
13
+ Overlay.toast({ title, desc, variant, duration, maxVisible, labels })
14
14
  Overlay.dialog({ title, desc, actions, danger, initialFocus })
15
+ labels: 读屏文案覆盖(默认中文,不传时行为不变)
15
16
  → 返回 { el, close }
16
17
  ========================================================================= */
17
18
  (function (global) {
@@ -265,8 +266,36 @@
265
266
  warning: 'toast--warning'
266
267
  };
267
268
 
269
+ /* 读屏文案的**默认值**与合并规则(F2 / 0.26.0)。
270
+ 🔴 只覆盖"会被读屏念出来或用户看得见"的文案;`throw new Error(...)`
271
+ 这类是给调用方看的开发期信息,不在这里 —— 它们不经过 UI。
272
+ 值可以是字符串,也可以是函数(动态文案,如 `第 N 页`)。
273
+ 不传 `labels` 时行为与之前**逐字相同**(默认中文)。 */
274
+ var DEFAULT_LABELS = {
275
+ closeToast: '关闭提示'
276
+ };
277
+
278
+ /* ==== BEHAVIOR INJECT BEGIN: labels ==== */
279
+ var flLabels = function (defaults, src) {
280
+ src = src || {};
281
+ var out = {};
282
+ var k;
283
+ for (k in defaults) {
284
+ if (Object.prototype.hasOwnProperty.call(defaults, k)) {
285
+ out[k] = (src[k] === undefined || src[k] === null) ? defaults[k] : src[k];
286
+ }
287
+ }
288
+ return out;
289
+ };
290
+ /* ==== BEHAVIOR INJECT END: labels ==== */
291
+ /* 同屏最多几条 toast。超了就把**最旧的**直接摘掉 ——
292
+ 否则 20 条并发提示会把屏幕铺满,且最后一条永远读不到。
293
+ 0 / 负数表示不限制(调用方自己负责)。 */
294
+ var TOAST_LIMIT = 4;
295
+
268
296
  function toast(opts) {
269
297
  opts = opts || {};
298
+ var L = flLabels(DEFAULT_LABELS, opts && opts.labels);
270
299
 
271
300
  var region = document.querySelector('.toast-region');
272
301
  if (!region) {
@@ -314,7 +343,7 @@
314
343
  var closeBtn = document.createElement('button');
315
344
  closeBtn.className = 'toast__close';
316
345
  closeBtn.type = 'button';
317
- closeBtn.setAttribute('aria-label', '关闭提示');
346
+ closeBtn.setAttribute('aria-label', L.closeToast);
318
347
  closeBtn.textContent = '×';
319
348
  el.appendChild(closeBtn);
320
349
 
@@ -331,6 +360,14 @@
331
360
  }
332
361
 
333
362
  closeBtn.addEventListener('click', close);
363
+ /* 同屏上限:先摘最旧的,再挂新的。
364
+ 🔴 摘的时候**不走 close()** —— 它带 220ms 退场动画,
365
+ 动画期间节点仍在 DOM 里,children.length 不减 ⇒ 这里会空转。
366
+ 被摘掉的那条已经在屏幕外了,动画没有意义。 */
367
+ var max = (opts.maxVisible === undefined) ? TOAST_LIMIT : opts.maxVisible;
368
+ while (max > 0 && region.children.length >= max) {
369
+ region.removeChild(region.firstChild);
370
+ }
334
371
  region.appendChild(el);
335
372
 
336
373
  var timerId = auto > 0 ? setTimeout(close, auto) : null;
@@ -137,12 +137,39 @@
137
137
 
138
138
  /* ---------------------------------------------------------------------- */
139
139
 
140
- function Pagination(node) {
140
+ /* 读屏文案默认值(F2 / 0.26.0)。值是字符串或函数;
141
+ 不传 `labels` 时输出与之前逐字相同。 */
142
+ var DEFAULT_LABELS = {
143
+ nav: '分页',
144
+ prev: '上一页',
145
+ next: '下一页',
146
+ page: function (p, isCurrent) {
147
+ return '第 ' + p + ' 页' + (isCurrent ? '(当前页)' : '');
148
+ },
149
+ status: function (page, pages) { return '第 ' + page + ' 页 / 共 ' + pages + ' 页'; },
150
+ live: function (page, pages) { return '第 ' + page + ' 页,共 ' + pages + ' 页'; }
151
+ };
152
+
153
+ /* ==== BEHAVIOR INJECT BEGIN: labels ==== */
154
+ var flLabels = function (defaults, src) {
155
+ src = src || {};
156
+ var out = {};
157
+ var k;
158
+ for (k in defaults) {
159
+ if (Object.prototype.hasOwnProperty.call(defaults, k)) {
160
+ out[k] = (src[k] === undefined || src[k] === null) ? defaults[k] : src[k];
161
+ }
162
+ }
163
+ return out;
164
+ };
165
+ /* ==== BEHAVIOR INJECT END: labels ==== */
166
+ function Pagination(node, opts) {
141
167
  this.node = node;
168
+ this.labels = flLabels(DEFAULT_LABELS, opts && opts.labels);
142
169
  this.total = Math.max(1, parseInt(node.getAttribute('data-total') || '1', 10));
143
170
  this.size = Math.max(1, parseInt(node.getAttribute('data-page-size') || '20', 10));
144
171
  this.page = Math.max(1, parseInt(node.getAttribute('data-page') || '1', 10));
145
- this.label = node.getAttribute('aria-label') || '分页';
172
+ this.label = node.getAttribute('aria-label') || this.labels.nav;
146
173
  this.pages = Math.max(1, Math.ceil(this.total / this.size));
147
174
  this.onChange = null;
148
175
 
@@ -301,7 +328,7 @@
301
328
  /** ⭐ 播报(依据第 2 条:改 textContent,不换元素) */
302
329
  Pagination.prototype.announce = function () {
303
330
  if (!this.liveNode) return;
304
- this.liveNode.textContent = '第 ' + this.page + ' 页,共 ' + this.pages + ' 页';
331
+ this.liveNode.textContent = this.labels.live(this.page, this.pages);
305
332
  };
306
333
 
307
334
  Pagination.prototype.render = function () {
@@ -309,6 +336,7 @@
309
336
  var L = this.listNode;
310
337
  while (L.firstChild) L.removeChild(L.firstChild);
311
338
  var self = this;
339
+ var T = this.labels;
312
340
 
313
341
  function addBtn(text, ariaLabel, goto, disabled) {
314
342
  var li = el('li', 'pagination__item');
@@ -325,7 +353,7 @@
325
353
  }
326
354
 
327
355
  /* --- 上一页 / 首页 --- */
328
- addBtn('‹', '上一页', 'prev', self.page <= 1);
356
+ addBtn('‹', T.prev, 'prev', self.page <= 1);
329
357
  /* --- 页码 --- */
330
358
  var win = pageWindow(self.page, self.pages, SLOTS);
331
359
  for (var i = 0; i < win.length; i++) {
@@ -347,7 +375,7 @@
347
375
  var b2 = el('button', 'pagination__link', String(p));
348
376
  b2.type = 'button';
349
377
  b2.setAttribute('data-goto', String(p));
350
- b2.setAttribute('aria-label', '第 ' + p + ' 页' + (isCur ? '(当前页)' : ''));
378
+ b2.setAttribute('aria-label', T.page(p, isCur));
351
379
  if (isCur) {
352
380
  b2.setAttribute('aria-current', 'page');
353
381
  b2.setAttribute('aria-disabled', 'true');
@@ -356,22 +384,21 @@
356
384
  L.appendChild(li2);
357
385
  }
358
386
  /* --- 下一页 / 末页 --- */
359
- addBtn('›', '下一页', 'next', self.page >= self.pages);
387
+ addBtn('›', T.next, 'next', self.page >= self.pages);
360
388
 
361
389
  /* --- 可见状态("第 2 页 / 共 12 页") --- */
362
390
  if (this.statusNode) {
363
- this.statusNode.textContent =
364
- '第 ' + self.page + ' 页 / 共 ' + self.pages + ' 页';
391
+ this.statusNode.textContent = T.status(self.page, self.pages);
365
392
  }
366
393
  };
367
394
 
368
395
  /* ---------------------------------------------------------------------- */
369
396
  var API = {
370
397
  /** 创建一个分页实例(返回实例以便绑定 onChange) */
371
- create: function (node) {
398
+ create: function (node, opts) {
372
399
  if (!node) return null;
373
400
  if (node.__pg) return node.__pg;
374
- node.__pg = new Pagination(node);
401
+ node.__pg = new Pagination(node, opts);
375
402
  return node.__pg;
376
403
  },
377
404
  /** 页面内所有 [data-pagination] */
@@ -137,7 +137,7 @@
137
137
  ⇒ 减少动态效果的用户照样看到闪烁的微光;
138
138
  · 与 `02-primitives/skeleton/skeleton.css` 同特异性 ⇒ 谁后加载谁定生死。
139
139
 
140
- 即"要不要尊重减少动态效果"取决于 CSS 顺序。与 E254 同类。
140
+ 即"要不要尊重减少动态效果"取决于 CSS 顺序。与同类。
141
141
  ⚠️ 这里与 skeleton.css 是**两份实现**(已登记在 css-ownership.json),
142
142
  修的时候两边都要看。 */
143
143
  @media (prefers-reduced-motion: no-preference) {
@@ -125,6 +125,21 @@ var flDismissable = function (opts) {
125
125
 
126
126
  var uid = 0;
127
127
 
128
+ /* 读屏文案默认值(F2 / 0.26.0)。
129
+ 本组件是 `attach(el, text)` 形式、没有逐实例 opts,
130
+ 所以文案用**模块级**设置:`Tooltip.setLabels({ region: 'Tooltip' })`。 */
131
+ var LABELS = { region: '组件提示' };
132
+
133
+ function setLabels(patch) {
134
+ if (!patch) return;
135
+ for (var k in LABELS) {
136
+ if (Object.prototype.hasOwnProperty.call(LABELS, k)
137
+ && patch[k] !== undefined && patch[k] !== null) {
138
+ LABELS[k] = patch[k];
139
+ }
140
+ }
141
+ }
142
+
128
143
  function ensureStyle() {
129
144
  if (document.getElementById('tooltip-css')) return;
130
145
  /* 说明:样式由页面通过 <link> 引入;这里只做"有没有"的提示,
@@ -149,7 +164,7 @@ var flDismissable = function (opts) {
149
164
  而在读屏用户"到达"它之前它通常是空的
150
165
  ⇒ 光靠内容拿不到名字 ⇒ 必须显式给 aria-label。
151
166
  label 用通用措辞,具体内容由 aria-live 负责播报。 */
152
- r.setAttribute('aria-label', '组件提示');
167
+ r.setAttribute('aria-label', LABELS.region);
153
168
  r.style.cssText =
154
169
  'position:absolute;width:1px;height:1px;padding:0;margin:-1px;' +
155
170
  'overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0';
@@ -280,5 +295,5 @@ var flDismissable = function (opts) {
280
295
  el.setAttribute('data-tooltip', text);
281
296
  }
282
297
 
283
- global.Tooltip = { attach: attach };
298
+ global.Tooltip = { attach: attach, setLabels: setLabels };
284
299
  })(typeof window !== 'undefined' ? window : globalThis);
@@ -231,11 +231,31 @@
231
231
  var uid = 0;
232
232
 
233
233
  function create(root, opt) {
234
+ /* 读屏文案默认值(F2 / 0.26.0)。不传 `labels` 时输出逐字不变。 */
235
+ var DEFAULT_LABELS = {
236
+ tree: '树形视图'
237
+ };
238
+
239
+ /* ==== BEHAVIOR INJECT BEGIN: labels ==== */
240
+ var flLabels = function (defaults, src) {
241
+ src = src || {};
242
+ var out = {};
243
+ var k;
244
+ for (k in defaults) {
245
+ if (Object.prototype.hasOwnProperty.call(defaults, k)) {
246
+ out[k] = (src[k] === undefined || src[k] === null) ? defaults[k] : src[k];
247
+ }
248
+ }
249
+ return out;
250
+ };
251
+ /* ==== BEHAVIOR INJECT END: labels ==== */
252
+ var L = flLabels(DEFAULT_LABELS, opt && opt.labels);
253
+
234
254
  opt = opt || {};
235
255
  root.classList.add('tree');
236
256
  if (!root.getAttribute('role')) root.setAttribute('role', 'tree');
237
257
  if (!root.getAttribute('aria-label') && !root.getAttribute('aria-labelledby')) {
238
- root.setAttribute('aria-label', opt.label || '树形视图');
258
+ root.setAttribute('aria-label', opt.label || L.tree);
239
259
  }
240
260
 
241
261
  /* ---------- 初始化结构 ---------- */
@@ -98,7 +98,7 @@
98
98
  每组成 2 个平行样,取算术平均。
99
99
  </p>
100
100
 
101
- <pre class="report__code">电解液 1 M LiPF6 in EC:EMC:DMC = 3:5:2 (v/v) + 2 wt% VC
101
+ <pre class="report__code" tabindex="0">电解液 1 M LiPF6 in EC:EMC:DMC = 3:5:2 (v/v) + 2 wt% VC
102
102
  截止电压 3.0 – 4.4 V (vs. Li/Li+)
103
103
  倍率 0.5C 充电 / 1.0C 放电
104
104
  温度 25 ± 1 °C
@@ -243,7 +243,7 @@ rail 下硬塞一个 `.shell__side-label` 会被 CSS 藏掉(兜底,防止它
243
243
 
244
244
  - **❌ 侧栏 `position: fixed` + 主区 `margin-inline-start`** —— 看起来能用,但侧栏被摘出
245
245
  grid 流,主区宽度靠**手抄的数字**维持(改侧栏宽就要改两处);`inset-inline-start`
246
- 与 `margin-inline-start` 只要有一处漏改,RTL 下侧栏跑到右边、主区仍在右边留白。**
246
+ 与 `margin-inline-start` 只要有一处漏改,RTL 下侧栏跑到右边、主区仍在右边留白。
247
247
 
248
248
  正确的做法见上面「侧栏为什么是 `sticky` 而不是 `fixed`」。
249
249
 
@@ -48,7 +48,7 @@
48
48
 
49
49
  <h1>应用外壳 · app-shell</h1>
50
50
  <p class="lede">工具型页面的骨架:左边一列常驻导航、上面一条工具栏、右边是主区。
51
- 它存在的理由不是"少写几个 div",而是**两个每个人都会踩的坑** —— 见下面两节。</p>
51
+ 它存在的理由不是"少写几个 div",而是<strong>两个每个人都会踩的坑</strong> —— 见下面两节。</p>
52
52
 
53
53
  <h2>1 · 标准三段式</h2>
54
54
  <div class="demo">
@@ -112,7 +112,7 @@
112
112
  多级表头用 <code>scope</code> 标明层级。
113
113
  </p>
114
114
 
115
- <div class="table table--academic">
115
+ <div class="table table--academic" tabindex="0" role="region" aria-label="三种干燥工艺的成品性能对比(可横向滚动)">
116
116
  <table>
117
117
  <caption class="table__cap">表 1 · 三种干燥工艺的成品性能对比(示例数据)</caption>
118
118
  <thead>
@@ -157,7 +157,7 @@
157
157
  不能用同一个数字格式化函数打发。<strong>本表不推断显著性,也不计算统计量。</strong>
158
158
  </p>
159
159
 
160
- <div class="table table--stats">
160
+ <div class="table table--stats" tabindex="0" role="region" aria-label="干燥工艺对含水率的影响(可横向滚动)">
161
161
  <table>
162
162
  <caption class="table__cap">表 2 · 干燥工艺对含水率的影响(OLS 估计,示例数据,n = 60)</caption>
163
163
  <thead>