agentcss 0.25.3 → 0.25.4

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/CHANGELOG.md CHANGED
@@ -16,6 +16,60 @@
16
16
 
17
17
  (无)
18
18
 
19
+ ## [0.25.4] - 2026-11-03
20
+
21
+ **修订版:把「类型里看不见的那 8 个全局」补上,并让这件事以后有人管。
22
+ 不改组件行为、不改类名、不改令牌值。**
23
+
24
+ ### 修复:8 个挂在 `window` 上的对象没有类型(E297)
25
+
26
+ 源码里有 **24 个** `window.X =` / `global.X =`,`types/index.d.ts` 只声明了 **16 个**:
27
+
28
+ | 缺的 | 后果 |
29
+ |---|---|
30
+ | `Theme` / `Chart` / `ChartAdapter` / `ModelViewer` | TS 项目里 `window.Theme.set('dark')` 直接报"属性不存在" |
31
+ | `Bar` / `ScientificPlot` / `ShellNav` | 同上(审计报告没点到这三个) |
32
+ | `Upload` | 最刺眼:`esm/upload.mjs` **存在**,运行时能 import,类型里却看不见 |
33
+
34
+ 用户遇到这种情况只有两条路:`(window as any)` 或 `@ts-expect-error` —— **两条都绕开了类型系统**,
35
+ 而这个库最反对的就是绕过契约。
36
+
37
+ 修法:把 8 个对象的真实形状补进 `FrontendLibGlobal`(形状是逐个读源码确认的,
38
+ 不是照抄 README);只有 `Upload` 加了具名导出 `export declare const Upload`,
39
+ 因为只有它在 `esm/` 里有包装模块。声明一个运行时取不到的具名导出,
40
+ 正是本库最反对的「幻觉 API」。
41
+
42
+ ### 更正:一句替门禁吹牛的注释
43
+
44
+ `types/index.d.ts` 里原来写着「behavior-api 门禁核对源码 / esm 入口 / **本文件声明**
45
+ 三者集合相等」。核实:`behavior-api-gate.js` 里**一次都没出现** `index.d.ts`,
46
+ 它只比源码与 `esm/`。`check-all.sh` 里对同一道门禁的描述也有同样的问题。
47
+
48
+ ⇒ 两处都改成实话,并补上真正做这件事的门禁(下一条)。
49
+ **注释替门禁承诺了它没做的事,比没有门禁更危险** —— 你会以为有人在看。
50
+
51
+ ### 新增门禁:类型与运行时必须对齐
52
+
53
+ `05-audit/types-globals-gate.py`,三条判据:
54
+
55
+ 1. 源码里每个 `window.X =` / `global.X =`(排除 `==` / `===`)都必须在
56
+ `FrontendLibGlobal` 里有声明;
57
+ 2. 反过来,每条声明都必须能在源码里找到赋值 ⇒ 防「幻觉类型」;
58
+ 3. 每个 `export declare const X` 必须有 `esm/<kebab>.mjs` ⇒ 防「幻觉导出」。
59
+
60
+ 反向控制五项:新增一个没声明的全局 / 删掉 `Theme` 的声明 / 声明一个源码里没有的成员 /
61
+ 声明一个没有 esm 的具名导出 / 真实仓库必须全绿。
62
+
63
+ ### 修复:`--schema=behaviors` 不可用(E298)
64
+
65
+ `ai/behaviors.schema.json` 一直都在,`ai/cli.js` 的 `SCHEMAS` 映射里却没有 `behaviors`
66
+ ⇒ `node ai/cli.js validate ai/behaviors.json --schema=behaviors` 报「未知 schema」。
67
+
68
+ 后果是这份契约**没有任何工具能校验**:`behaviors.json` 是稳定性承诺里的微行为矩阵,
69
+ 写错了只能靠人看。补一行映射即可,已验证能通过也能报错。
70
+
71
+ ---
72
+
19
73
  ## [0.25.3] - 2026-11-03
20
74
 
21
75
  **修订版:修掉四个「照着文档写会直接失败」的入口问题,并补上三层规范里缺失的那一层。
package/CONTRIBUTING.md CHANGED
@@ -29,7 +29,7 @@ npm run gate # 全量:含浏览器类
29
29
  npm run gate:fast # 只跑静态层,不用装浏览器
30
30
  ```
31
31
 
32
- 全量是 **234 道门禁**(默认 `min(核数, 6)` 路并发,实测 583 秒 / 退出码 0;
32
+ 全量是 **235 道门禁**(默认 `min(核数, 6)` 路并发,实测 583 秒 / 退出码 0;
33
33
  单道耗时累加 1658 秒,并发效率约 2.8×。组件层要起浏览器,还要逐张比 **109 张**视觉截图 ——
34
34
  47 浅色 + 47 暗色 + 15 RTL,按平台分集,只比本平台那套)。
35
35
  只想确认没改坏静态契约的话用 `gate:fast`,几秒到几分钟。
package/ai/cli.js CHANGED
@@ -151,7 +151,11 @@ var SCHEMAS = {
151
151
  tokensAudience: 'tokens.audience.schema.json',
152
152
  tokensTree: 'tokens.tree.schema.json',
153
153
  deprecations: 'deprecations.schema.json',
154
- patch: 'patch.schema.json'
154
+ patch: 'patch.schema.json',
155
+ /* behaviors 是稳定性承诺里的核心契约(微行为矩阵),
156
+ 它的 schema 文件一直都在,但这里漏登记 ⇒ `--schema=behaviors` 报
157
+ "未知 schema",等于这份契约**没有任何工具能校验**(E298)。 */
158
+ behaviors: 'behaviors.schema.json'
155
159
  };
156
160
 
157
161
  function cmdValidate(args) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
3
  "generatedBy": "05-audit/gen-ai-contract.py",
4
- "libraryVersion": "0.25.3",
4
+ "libraryVersion": "0.25.4",
5
5
  "$comment": "机器可读的组件契约。slots = BEM 元素名(在本库里元素名就是插槽名),states.enum = 组件会在 DOM 上写出的 data-* 取值,states.legacyClass = 仍未收敛到 data 属性的历史状态类(INVARIANT I-8 未达标)。printPolicy = 这个组件在纸上会发生什么(空数组 = 原样保留);pagination = 内容是否被分页裁过(server 不许与 expand 同时出现,否则展开的只是当前一页)。",
6
6
  "maturityCriteria": {
7
7
  "alpha": "缺 demo.html 或缺 05-audit 下的专属门禁 ⇒ 还没被机器验证过,不要用",
@@ -5,7 +5,7 @@
5
5
 
6
6
  | 项目 | 值 |
7
7
  |---|---|
8
- | 声明适用版本 | agentcss `0.25.3` |
8
+ | 声明适用版本 | agentcss `0.25.4` |
9
9
  | 声明日期 | 2026-11-03 |
10
10
  | 复核节奏 | 每次发版前重跑(`npm run gate` 内含全部证据) |
11
11
  | 范围 | 本库交付的 CSS / JS、全部 `demo.html`(组件页 + 图表页 + 组合页)、以及文档站生成的页面 |
package/index.html CHANGED
@@ -97,7 +97,7 @@ li a:active { background: var(--surface-sunken); }
97
97
  </p>
98
98
  </main>
99
99
  <footer class="wrap">
100
- <p class="note">0.25.3 · 零第三方运行时依赖</p>
100
+ <p class="note">0.25.4 · 零第三方运行时依赖</p>
101
101
  </footer>
102
102
  </body>
103
103
  </html>
package/llms-full.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  # agentcss — full reference (one file)
2
2
 
3
- > Generated from `ai/components.json` + `ai/pitfalls*.json` + `ai/behaviors.json` at version **0.25.3**.
3
+ > Generated from `ai/components.json` + `ai/pitfalls*.json` + `ai/behaviors.json` at version **0.25.4**.
4
4
  > Do not edit by hand: run `python 05-audit/gen-llms.py` (freshness is gated).
5
5
  > Short version: `llms.txt`. Machine contract: `ai/*.json`.
6
6
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentcss",
3
- "version": "0.25.3",
3
+ "version": "0.25.4",
4
4
  "description": "移动 Web 组件库:CSS + 可选行为脚本,零第三方运行时依赖。样式用 bundler 引入,交互行为用 script 标签引入。",
5
5
  "keywords": [
6
6
  "css",
package/types/index.d.ts CHANGED
@@ -390,6 +390,114 @@ export interface FlipApi {
390
390
  remove(container: HTMLElement, el: HTMLElement, done?: () => void): void;
391
391
  }
392
392
 
393
+ /* ============================================================================
394
+ * 资产 / 主题:`01-tokens/`、`09-assets/`、`04-recipes/` 的公开对象
395
+ *
396
+ * 🔴 为什么单列一段(0.25.2 的缺陷,0.25.3 补):这 8 个对象都挂在 window 上,
397
+ * 但本文件里一个都没有 ⇒ `window.Theme.set('dark')` 在 TS 项目里直接报
398
+ * "属性不存在",用户只能写 `(window as any).Theme` —— 等于绕过类型系统。
399
+ * 其中 `Upload` 更明显:`esm/upload.mjs` 是**存在**的,运行时能 import,
400
+ * 类型里却看不见。
401
+ *
402
+ * ⚠️ 本文件从前在这里写过一句「behavior-api 门禁核对源码 / esm 入口 /
403
+ * 本文件声明三者集合相等」—— 那句话**不成立**:那道门禁只比源码与 esm/,
404
+ * 从不读本文件(0.25.3 核实过)。现在由 `05-audit/types-globals-gate.py` 判:
405
+ * 源码里每个 `window.X =` / `global.X =` 都必须在这里有声明,
406
+ * 反过来每条声明也必须有源码依据。
407
+ *
408
+ * 为什么这 7 个不给 `export declare const`:`esm/` 里没有它们的包装模块
409
+ * (只有 16 个行为脚本 + upload)。声明一个运行时取不到的具名导出,
410
+ * 正是本库最反对的「幻觉 API」。它们只能走 `window.X`。
411
+ * ========================================================================== */
412
+ export type ThemeMode = 'light' | 'dark' | 'auto';
413
+
414
+ export interface ThemeApi {
415
+ /** 读当前**模式**(不是"现在是深还是浅"):auto 也算一种模式 */
416
+ get(): ThemeMode;
417
+ /** 当前实际渲染是不是深色(auto 模式下由系统决定) */
418
+ isDark(): boolean;
419
+ set(mode: ThemeMode): void;
420
+ toggle(): void;
421
+ /** 三态循环:auto → light → dark → auto */
422
+ cycle(): void;
423
+ }
424
+
425
+ export interface ChartApi {
426
+ draw(el: Element): void;
427
+ /** `draw` 的语义别名:数据变了,重画一次 */
428
+ emit(el: Element): void;
429
+ /** 画一个区域里所有 `.sparkline[data-spark]` */
430
+ update(root?: ParentNode): void;
431
+ /** ⚠️ 只有浏览器支持 ResizeObserver 时才存在(老 WebView 里是 undefined) */
432
+ observe?(el?: Element): void;
433
+ }
434
+
435
+ export interface ChartAdapterPalette {
436
+ accent: string;
437
+ danger: string;
438
+ success: string;
439
+ warn: string;
440
+ info: string;
441
+ [key: string]: string;
442
+ }
443
+
444
+ export interface ChartAdapterApi {
445
+ /** 读某个作用域下的 CSS 变量值(`ctx` 决定用哪套主题) */
446
+ cssVar(name: string, fallback?: string, ctx?: Element): string;
447
+ palette(ctx?: Element): ChartAdapterPalette;
448
+ seriesColors(n: number, p: ChartAdapterPalette): string[];
449
+ /** 生成 ECharts 主题对象;`name` 形如 `fe-light` / `fe-dark` */
450
+ theme(name: string, p?: ChartAdapterPalette | null, ctx?: Element): object;
451
+ themeName(ctx?: Element): string;
452
+ defaults(option?: object, ctx?: Element): object;
453
+ create(dom: HTMLElement, opt?: object): unknown;
454
+ /** 主题切换后重设;主题名变了会重建实例(ECharts 的主题在 init 时绑定) */
455
+ refresh(inst: unknown): unknown;
456
+ }
457
+
458
+ export interface ModelViewerInstance {
459
+ build(): void;
460
+ makeIdle(): void;
461
+ fail(msg?: string): void;
462
+ status(text: string): void;
463
+ load(): void;
464
+ boot(): void;
465
+ initScene(): void;
466
+ }
467
+
468
+ export interface BarApi {
469
+ draw(opt: {
470
+ host: HTMLElement;
471
+ /** 🔴 必填:本库铁律三,量程不得自动适配(漏了会抛错,不会悄悄自适应) */
472
+ max: number;
473
+ series?: unknown[];
474
+ height?: number;
475
+ mode?: 'group' | 'stack';
476
+ }): void;
477
+ }
478
+
479
+ export interface ScientificPlotApi {
480
+ render(el: Element, spec?: object): void;
481
+ /** 判据 / 单测用的真值入口;不承诺稳定,改版可能变 */
482
+ __internals: object;
483
+ }
484
+
485
+ export interface ShellNavInstance {
486
+ /** 已开着就直接返回现有句柄(重复点不该叠两层遮罩) */
487
+ open(): unknown;
488
+ close(): void;
489
+ destroy(): void;
490
+ }
491
+
492
+ export interface UploadInstance {
493
+ /** 收下一批文件(拖放入口,也是公开 API) */
494
+ add(incoming: FileList | File[], dirCount?: number): void;
495
+ render(): void;
496
+ setState(state: string): void;
497
+ setProgress(index: number, pct: number): void;
498
+ removeAt(index: number): void;
499
+ }
500
+
393
501
  /* ============================================================================
394
502
  * 全局命名空间(组件脚本是 IIFE,挂到 window)
395
503
  * ========================================================================== */
@@ -412,6 +520,18 @@ export interface FrontendLibGlobal {
412
520
  Toc: TocApi;
413
521
  Reveal: RevealApi;
414
522
  FLIP: FlipApi;
523
+ /* ---- 资产 / 主题(没有 esm 入口,只能走 window.X) ---- */
524
+ Theme: ThemeApi;
525
+ Chart: ChartApi;
526
+ ChartAdapter: ChartAdapterApi;
527
+ /** construct 形态:`new window.ModelViewer(node)` */
528
+ ModelViewer: new (node: HTMLElement) => ModelViewerInstance;
529
+ Bar: BarApi;
530
+ ScientificPlot: ScientificPlotApi;
531
+ /** construct 形态:`new window.ShellNav(root, opts)` */
532
+ ShellNav: new (root: HTMLElement, opts?: object) => ShellNavInstance;
533
+ /** construct 形态:`new window.Upload(root, opts)` */
534
+ Upload: new (root: HTMLElement, opts?: object) => UploadInstance;
415
535
  }
416
536
 
417
537
  declare global {
@@ -426,7 +546,8 @@ export declare const Dropdown: FrontendLibGlobal['Dropdown'];
426
546
  export declare const Tree: FrontendLibGlobal['Tree'];
427
547
  /* 与 `global.X = …` 一一对应(16 个行为脚本全部覆盖)。
428
548
  证据:`esm/` 下的 16 个 .mjs 由 `05-audit/gen-esm.py` 从源码生成,
429
- `behavior-api` 门禁核对「源码导出 / esm 入口 / 本文件声明」三者集合相等。 */
549
+ `behavior-api` 门禁核对「源码导出 ↔ esm 入口」两者集合相等
550
+ (⚠️ 它**不读本文件**;本文件的声明由 `types-globals-gate.py` 判)。 */
430
551
  export declare const Accordion: FrontendLibGlobal['Accordion'];
431
552
  export declare const Tabs: FrontendLibGlobal['Tabs'];
432
553
  export declare const Nav: FrontendLibGlobal['Nav'];
@@ -437,4 +558,7 @@ export declare const Tooltip: TooltipApi;
437
558
  export declare const Popover: PopoverApi;
438
559
  export declare const Toc: TocApi;
439
560
  export declare const Reveal: RevealApi;
440
- export declare const FLIP: FlipApi;
561
+ export declare const FLIP: FlipApi;
562
+ /* Upload 有 esm 入口(`esm/upload.mjs`)⇒ 可以具名导出;
563
+ 其余 7 个资产/主题对象没有包装模块,只在 FrontendLibGlobal 里声明。 */
564
+ export declare const Upload: FrontendLibGlobal['Upload'];