@stapel/tokens-antd 0.3.0 → 0.4.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.
package/README.md CHANGED
@@ -1,15 +1,18 @@
1
1
  # @stapel/tokens-antd
2
2
 
3
- The Ant Design leg of the **token bridge** (frontend-guidelines §2.4; owner
4
- decision §38 T3). It projects `@stapel/tokens` L2 core tokens onto an Ant Design
5
- `ConfigProvider` theme — so integrating a `@stapel/*-react` pair's default skin
6
- already carries the user's theme, light and dark.
3
+ The Ant Design leg of the **token bridge** (§68; frontend-guidelines §2.4;
4
+ owner decision §38 T3). It projects `@stapel/tokens`' neutral colour roles
5
+ onto an Ant Design `ConfigProvider` theme — so integrating a
6
+ `@stapel/*-react` pair's default skin already carries the user's theme,
7
+ light and dark.
7
8
 
8
- There is exactly **one** L2 design-system role mapping table, and it lives in
9
- `@stapel/tokens` (`bridgeColorRoles` + the radius/font-size roles). This package
10
- only renames those neutral roles to antd's flat token field names and picks the
11
- `light`/`dark` half it holds no colour decisions of its own, so it and
12
- `@stapel/tokens-mui` cannot drift.
9
+ The §68 neutral role dictionary IS the bridge vocabulary a role name
10
+ (`brand`, `surface-raised`, `text-muted`, …) is both the CSS var suffix
11
+ (`--stapel-brand`) and the exact key this package reads off `@stapel/tokens`'
12
+ `colors` object. There is no separate role→role indirection table (the old
13
+ `bridgeColorRoles` map is gone) — this package only renames roles to antd's
14
+ flat token field names and picks the `light`/`dark` half; it holds no colour
15
+ decisions of its own, so it and `@stapel/tokens-mui` cannot drift.
13
16
 
14
17
  ## Usage
15
18
 
@@ -34,20 +37,28 @@ import { toAntdThemeConfig } from "@stapel/tokens-antd";
34
37
  </ConfigProvider>;
35
38
  ```
36
39
 
37
- ## The mapping (frontend-guidelines §2.4)
38
-
39
- | `@stapel/tokens` role | L2 core token | antd `theme.token` |
40
- | --- | --- | --- |
41
- | `brand` | `accent` | `colorPrimary` |
42
- | `success` | `text-positive` | `colorSuccess` |
43
- | `warning` | `text-warning` | `colorWarning` |
44
- | `danger` | `text-negative` | `colorError` |
45
- | `info` | `text-info` | `colorInfo` |
46
- | `bgContainer` | `upperground-primary` | `colorBgContainer` / `colorBgElevated` |
47
- | `bgLayout` | `background-primary` | `colorBgLayout` |
48
- | `textPrimary` | `text-primary` | `colorText` |
49
- | `link` | `text-brand` | `colorLink` |
50
- | radius `md` | — | `borderRadius` |
51
- | font-size `md` | | `fontSize` |
40
+ ## The mapping (§68; frontend-guidelines §2.4)
41
+
42
+ | `@stapel/tokens` role | antd `theme.token` |
43
+ | --- | --- |
44
+ | `brand` | `colorPrimary` |
45
+ | `success` / `warning` / `error` / `info` | `colorSuccess` / `colorWarning` / `colorError` / `colorInfo` |
46
+ | `text` | `colorText` |
47
+ | `text-muted` | `colorTextSecondary` |
48
+ | `text-subtle` | `colorTextTertiary` |
49
+ | `surface` | `colorBgLayout` |
50
+ | `surface-raised` | `colorBgContainer` |
51
+ | `surface-overlay` | `colorBgElevated` |
52
+ | `border` | `colorBorder` |
53
+ | `border-subtle` | `colorBorderSecondary` |
54
+ | `link` / `link-hover` | `colorLink` / `colorLinkHover` |
55
+ | radius `md` | `borderRadius` |
56
+ | font-size `md` | `fontSize` |
57
+
58
+ Every field above is resolved by reading the host's **live**
59
+ `--stapel-<role>` CSS custom property off `document.documentElement` at call
60
+ time (falling back to the compiled-in default only with no DOM — SSR/tests) —
61
+ so a host's customized brand colour flows through even to antd's seed-token
62
+ colour derivation (hover/active shades), not just its own light/dark mode.
52
63
 
53
64
  `antd` is a peer dependency — the consuming app brings its own copy.
package/dist/index.d.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  import type { ThemeConfig } from "antd";
2
- /** Light or dark — the half of every L2 core token's `{light,dark}` pair. */
2
+ /** Light or dark — the half of every role's `{light,dark}` pair. */
3
3
  export type ThemeMode = "light" | "dark";
4
4
  /** The flat antd token map (`ThemeConfig["token"]`), never undefined. */
5
5
  export type AntdThemeToken = NonNullable<ThemeConfig["token"]>;
6
6
  /**
7
- * `@stapel/tokens` L2 → antd `theme.token` (frontend-guidelines §2.4 table).
8
- * Pure: same `mode` in, same object out; reads no globals.
7
+ * `@stapel/tokens` §68 roles → antd `theme.token` (frontend-guidelines §2.4
8
+ * table). Pure: same `mode` in, same object out; reads no globals besides the
9
+ * live CSS custom properties documented on {@link readLiveCssVar}.
9
10
  */
10
11
  export declare function toAntdTheme(mode: ThemeMode): AntdThemeToken;
11
12
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,MAAM,CAAC;AAaxC,6EAA6E;AAC7E,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;AA8CzC,yEAAyE;AACzE,MAAM,MAAM,cAAc,GAAG,WAAW,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;AAE/D;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS,GAAG,cAAc,CAoB3D;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,GAAG,WAAW,CAM9D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,MAAM,CAAC;AAYxC,oEAAoE;AACpE,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;AA6CzC,yEAAyE;AACzE,MAAM,MAAM,cAAc,GAAG,WAAW,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;AAE/D;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS,GAAG,cAAc,CAqB3D;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,GAAG,WAAW,CAM9D"}
package/dist/index.js CHANGED
@@ -1,11 +1,14 @@
1
1
  /**
2
- * `@stapel/tokens-antd` — the Ant Design leg of the token bridge
3
- * (frontend-guidelines §2.4, owner decision §38 T3). It translates the ONE
4
- * neutral role table in `@stapel/tokens` (`bridgeColorRoles` + the radius/
5
- * font-size roles) into Ant Design's flat `ConfigProvider` theme token. The
6
- * L2 role decision is NOT duplicated here this file only renames roles to
7
- * antd field names and picks the light/dark half, so it and `@stapel/tokens-mui`
8
- * cannot drift.
2
+ * `@stapel/tokens-antd` — the Ant Design leg of the token bridge (§68;
3
+ * frontend-guidelines §2.4, owner decision §38 T3). It translates the ONE
4
+ * neutral colour-role dictionary in `@stapel/tokens` (§68 `surface`,
5
+ * `brand`, `text-muted`, `success-bg`, …) straight into Ant Design's flat
6
+ * `ConfigProvider` theme token: a role name IS the antd mapping's input, no
7
+ * separate role→role indirection table (that table `bridgeColorRoles`
8
+ * is gone; §68 Ф1 "алиас-слой совместимости не делать"). The mapping table
9
+ * below (role → antd field) is the ONE place this decision lives; both this
10
+ * file and `@stapel/tokens-mui` read the same `colors` object so they cannot
11
+ * silently diverge on what a role visually means.
9
12
  *
10
13
  * ```tsx
11
14
  * import { toAntdTheme } from "@stapel/tokens-antd";
@@ -21,23 +24,23 @@
21
24
  * and spread it directly: `<ConfigProvider theme={toAntdThemeConfig(mode)}>`.
22
25
  */
23
26
  import { theme as antdTheme } from "antd";
24
- import { bridgeColorRoles, bridgeFontSizeRole, bridgeRadiusRole, colors, cssVar, fontFamily, fontSize, radii, } from "@stapel/tokens";
27
+ import { bridgeFontSizeRole, bridgeRadiusRole, colors, cssVar, fontFamily, fontSize, radii, } from "@stapel/tokens";
25
28
  /**
26
29
  * Resolve a neutral colour role to a real hex for `mode` (owner audit
27
30
  * 2026-07-17, §54 theme-bridge root cause): a host that customizes its OWN
28
31
  * brand colour does so exactly as `@stapel/tokens`' README prescribes — copy
29
32
  * `theme.default.json` to `stapel.theme.json`, edit the `ramps`, run
30
- * `pnpm gen:tokens` — which regenerates THAT HOST's `tokens.css` custom
31
- * properties (`--stapel-color-<role>`). It does NOT and CANNOT change this
32
- * published package's own compiled-in `colors` object — that snapshot is
33
- * frozen at `@stapel/tokens`' OWN publish time to `@stapel/tokens`' OWN
34
- * default theme, forever, regardless of what any host does. Feeding `colors`
35
- * straight into antd's `ConfigProvider` (the previous implementation) is why
36
- * every default skin rendered Stapel's stock brand colour instead of the
37
- * host's, no matter how correctly the host had customized its tokens: the
33
+ * `stapel-tokens` (`pnpm gen:tokens`) — which regenerates THAT HOST's
34
+ * `tokens.css` custom properties (`--stapel-<role>`). It does NOT and CANNOT
35
+ * change this published package's own compiled-in `colors` object — that
36
+ * snapshot is frozen at `@stapel/tokens`' OWN publish time to `@stapel/tokens`'
37
+ * OWN default theme, forever, regardless of what any host does. Feeding
38
+ * `colors` straight into antd's `ConfigProvider` (the previous implementation)
39
+ * is why every default skin rendered Stapel's stock brand colour instead of
40
+ * the host's, no matter how correctly the host had customized its tokens: the
38
41
  * bridge was never wired to read them.
39
42
  *
40
- * The fix reads the LIVE `--stapel-color-<role>` custom property off
43
+ * The fix reads the LIVE `--stapel-<role>` custom property off
41
44
  * `document.documentElement` at call time — the exact value the host's own
42
45
  * (re)generated `tokens.css` sets, already resolved through whichever
43
46
  * `data-theme` is active — and falls back to the static default only where
@@ -49,42 +52,43 @@ import { bridgeColorRoles, bridgeFontSizeRole, bridgeRadiusRole, colors, cssVar,
49
52
  function readLiveCssVar(name, fallback) {
50
53
  if (typeof document === "undefined")
51
54
  return fallback;
52
- // `getPropertyValue` wants the BARE custom-property name (`--stapel-color-x`);
53
- // `cssVar()` deliberately returns the `var(--stapel-color-x)` wrapper for
55
+ // `getPropertyValue` wants the BARE custom-property name (`--stapel-x`);
56
+ // `cssVar()` deliberately returns the `var(--stapel-x)` wrapper for
54
57
  // embedding in a CSS value, which `getPropertyValue` would never match —
55
58
  // stripped back off here rather than duplicating the `--stapel-` prefix.
56
- const propertyName = cssVar(`color-${name}`).slice("var(".length, -1);
59
+ const propertyName = cssVar(name).slice("var(".length, -1);
57
60
  const value = getComputedStyle(document.documentElement)
58
61
  .getPropertyValue(propertyName)
59
62
  .trim();
60
63
  return value.length > 0 ? value : fallback;
61
64
  }
62
- /** Resolve a neutral colour role to its hex for `mode` via the shared table,
63
- * preferring the host's live CSS custom property over the compiled-in default. */
65
+ /** Resolve a §68 colour role to its hex for `mode`, preferring the host's
66
+ * live CSS custom property over the compiled-in default. */
64
67
  function role(name, mode) {
65
- const token = bridgeColorRoles[name];
66
- return readLiveCssVar(token, colors[token][mode]);
68
+ return readLiveCssVar(name, colors[name][mode]);
67
69
  }
68
70
  /**
69
- * `@stapel/tokens` L2 → antd `theme.token` (frontend-guidelines §2.4 table).
70
- * Pure: same `mode` in, same object out; reads no globals.
71
+ * `@stapel/tokens` §68 roles → antd `theme.token` (frontend-guidelines §2.4
72
+ * table). Pure: same `mode` in, same object out; reads no globals besides the
73
+ * live CSS custom properties documented on {@link readLiveCssVar}.
71
74
  */
72
75
  export function toAntdTheme(mode) {
73
76
  return {
74
77
  colorPrimary: role("brand", mode),
75
78
  colorLink: role("link", mode),
76
- colorLinkHover: role("brandHover", mode),
79
+ colorLinkHover: role("link-hover", mode),
77
80
  colorSuccess: role("success", mode),
78
81
  colorWarning: role("warning", mode),
79
- colorError: role("danger", mode),
82
+ colorError: role("error", mode),
80
83
  colorInfo: role("info", mode),
81
- colorText: role("textPrimary", mode),
82
- colorTextSecondary: role("textSecondary", mode),
83
- colorBgContainer: role("bgContainer", mode),
84
- colorBgLayout: role("bgLayout", mode),
85
- colorBgElevated: role("bgContainer", mode),
84
+ colorText: role("text", mode),
85
+ colorTextSecondary: role("text-muted", mode),
86
+ colorTextTertiary: role("text-subtle", mode),
87
+ colorBgLayout: role("surface", mode),
88
+ colorBgContainer: role("surface-raised", mode),
89
+ colorBgElevated: role("surface-overlay", mode),
86
90
  colorBorder: role("border", mode),
87
- colorBorderSecondary: role("borderSecondary", mode),
91
+ colorBorderSecondary: role("border-subtle", mode),
88
92
  borderRadius: radii[bridgeRadiusRole],
89
93
  fontSize: fontSize[bridgeFontSizeRole].fontSize,
90
94
  fontFamily: fontFamily.sans,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAE1C,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,MAAM,EACN,MAAM,EACN,UAAU,EACV,QAAQ,EACR,KAAK,GACN,MAAM,gBAAgB,CAAC;AAMxB;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,SAAS,cAAc,CAAC,IAAmB,EAAE,QAAgB;IAC3D,IAAI,OAAO,QAAQ,KAAK,WAAW;QAAE,OAAO,QAAQ,CAAC;IACrD,+EAA+E;IAC/E,0EAA0E;IAC1E,yEAAyE;IACzE,yEAAyE;IACzE,MAAM,YAAY,GAAG,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;IACtE,MAAM,KAAK,GAAG,gBAAgB,CAAC,QAAQ,CAAC,eAAe,CAAC;SACrD,gBAAgB,CAAC,YAAY,CAAC;SAC9B,IAAI,EAAE,CAAC;IACV,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC7C,CAAC;AAED;kFACkF;AAClF,SAAS,IAAI,CAAC,IAAqB,EAAE,IAAe;IAClD,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACrC,OAAO,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACpD,CAAC;AAKD;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,IAAe;IACzC,OAAO;QACL,YAAY,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC;QACjC,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;QAC7B,cAAc,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC;QACxC,YAAY,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC;QACnC,YAAY,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC;QACnC,UAAU,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC;QAChC,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;QAC7B,SAAS,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC;QACpC,kBAAkB,EAAE,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC;QAC/C,gBAAgB,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC;QAC3C,aAAa,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC;QACrC,eAAe,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC;QAC1C,WAAW,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC;QACjC,oBAAoB,EAAE,IAAI,CAAC,iBAAiB,EAAE,IAAI,CAAC;QACnD,YAAY,EAAE,KAAK,CAAC,gBAAgB,CAAC;QACrC,QAAQ,EAAE,QAAQ,CAAC,kBAAkB,CAAC,CAAC,QAAQ;QAC/C,UAAU,EAAE,UAAU,CAAC,IAAI;KAC5B,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAe;IAC/C,OAAO;QACL,SAAS,EACP,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,gBAAgB;QACxE,KAAK,EAAE,WAAW,CAAC,IAAI,CAAC;KACzB,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAE1C,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,MAAM,EACN,MAAM,EACN,UAAU,EACV,QAAQ,EACR,KAAK,GACN,MAAM,gBAAgB,CAAC;AAMxB;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,SAAS,cAAc,CAAC,IAAmB,EAAE,QAAgB;IAC3D,IAAI,OAAO,QAAQ,KAAK,WAAW;QAAE,OAAO,QAAQ,CAAC;IACrD,yEAAyE;IACzE,oEAAoE;IACpE,yEAAyE;IACzE,yEAAyE;IACzE,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;IAC3D,MAAM,KAAK,GAAG,gBAAgB,CAAC,QAAQ,CAAC,eAAe,CAAC;SACrD,gBAAgB,CAAC,YAAY,CAAC;SAC9B,IAAI,EAAE,CAAC;IACV,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC7C,CAAC;AAED;4DAC4D;AAC5D,SAAS,IAAI,CAAC,IAAmB,EAAE,IAAe;IAChD,OAAO,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAClD,CAAC;AAKD;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,IAAe;IACzC,OAAO;QACL,YAAY,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC;QACjC,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;QAC7B,cAAc,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC;QACxC,YAAY,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC;QACnC,YAAY,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC;QACnC,UAAU,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC;QAC/B,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;QAC7B,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;QAC7B,kBAAkB,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC;QAC5C,iBAAiB,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC;QAC5C,aAAa,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC;QACpC,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC;QAC9C,eAAe,EAAE,IAAI,CAAC,iBAAiB,EAAE,IAAI,CAAC;QAC9C,WAAW,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC;QACjC,oBAAoB,EAAE,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC;QACjD,YAAY,EAAE,KAAK,CAAC,gBAAgB,CAAC;QACrC,QAAQ,EAAE,QAAQ,CAAC,kBAAkB,CAAC,CAAC,QAAQ;QAC/C,UAAU,EAAE,UAAU,CAAC,IAAI;KAC5B,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAe;IAC/C,OAAO;QACL,SAAS,EACP,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,gBAAgB;QACxE,KAAK,EAAE,WAAW,CAAC,IAAI,CAAC;KACzB,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stapel/tokens-antd",
3
- "version": "0.3.0",
4
- "description": "Token bridge (frontend-guidelines §2.4, §38 T3): projects @stapel/tokens L2 core tokens onto an Ant Design ConfigProvider theme. `toAntdTheme(mode)` → theme.token; `toAntdThemeConfig(mode)` → the full ThemeConfig (algorithm + token). Pure functions, one mapping table shared with @stapel/tokens-mui. Not components.",
3
+ "version": "0.4.0",
4
+ "description": "Token bridge (§68 neutral colour-role dictionary; frontend-guidelines §2.4, §38 T3): projects @stapel/tokens' roles (surface, brand, text-muted, success-bg, ...) onto an Ant Design ConfigProvider theme. `toAntdTheme(mode)` → theme.token; `toAntdThemeConfig(mode)` → the full ThemeConfig (algorithm + token). Pure functions reading the same `colors` object as @stapel/tokens-mui, so they cannot diverge. Not components.",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -35,7 +35,7 @@
35
35
  "antd": ">=5.20.0 <7"
36
36
  },
37
37
  "dependencies": {
38
- "@stapel/tokens": "^0.4.0"
38
+ "@stapel/tokens": "^0.5.0"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@size-limit/preset-small-lib": "^11.2.0",
package/src/index.ts CHANGED
@@ -1,11 +1,14 @@
1
1
  /**
2
- * `@stapel/tokens-antd` — the Ant Design leg of the token bridge
3
- * (frontend-guidelines §2.4, owner decision §38 T3). It translates the ONE
4
- * neutral role table in `@stapel/tokens` (`bridgeColorRoles` + the radius/
5
- * font-size roles) into Ant Design's flat `ConfigProvider` theme token. The
6
- * L2 role decision is NOT duplicated here this file only renames roles to
7
- * antd field names and picks the light/dark half, so it and `@stapel/tokens-mui`
8
- * cannot drift.
2
+ * `@stapel/tokens-antd` — the Ant Design leg of the token bridge (§68;
3
+ * frontend-guidelines §2.4, owner decision §38 T3). It translates the ONE
4
+ * neutral colour-role dictionary in `@stapel/tokens` (§68 `surface`,
5
+ * `brand`, `text-muted`, `success-bg`, …) straight into Ant Design's flat
6
+ * `ConfigProvider` theme token: a role name IS the antd mapping's input, no
7
+ * separate role→role indirection table (that table `bridgeColorRoles`
8
+ * is gone; §68 Ф1 "алиас-слой совместимости не делать"). The mapping table
9
+ * below (role → antd field) is the ONE place this decision lives; both this
10
+ * file and `@stapel/tokens-mui` read the same `colors` object so they cannot
11
+ * silently diverge on what a role visually means.
9
12
  *
10
13
  * ```tsx
11
14
  * import { toAntdTheme } from "@stapel/tokens-antd";
@@ -23,7 +26,6 @@
23
26
  import { theme as antdTheme } from "antd";
24
27
  import type { ThemeConfig } from "antd";
25
28
  import {
26
- bridgeColorRoles,
27
29
  bridgeFontSizeRole,
28
30
  bridgeRadiusRole,
29
31
  colors,
@@ -32,9 +34,9 @@ import {
32
34
  fontSize,
33
35
  radii,
34
36
  } from "@stapel/tokens";
35
- import type { BridgeColorRole, CoreTokenName } from "@stapel/tokens";
37
+ import type { CoreTokenName } from "@stapel/tokens";
36
38
 
37
- /** Light or dark — the half of every L2 core token's `{light,dark}` pair. */
39
+ /** Light or dark — the half of every role's `{light,dark}` pair. */
38
40
  export type ThemeMode = "light" | "dark";
39
41
 
40
42
  /**
@@ -42,17 +44,17 @@ export type ThemeMode = "light" | "dark";
42
44
  * 2026-07-17, §54 theme-bridge root cause): a host that customizes its OWN
43
45
  * brand colour does so exactly as `@stapel/tokens`' README prescribes — copy
44
46
  * `theme.default.json` to `stapel.theme.json`, edit the `ramps`, run
45
- * `pnpm gen:tokens` — which regenerates THAT HOST's `tokens.css` custom
46
- * properties (`--stapel-color-<role>`). It does NOT and CANNOT change this
47
- * published package's own compiled-in `colors` object — that snapshot is
48
- * frozen at `@stapel/tokens`' OWN publish time to `@stapel/tokens`' OWN
49
- * default theme, forever, regardless of what any host does. Feeding `colors`
50
- * straight into antd's `ConfigProvider` (the previous implementation) is why
51
- * every default skin rendered Stapel's stock brand colour instead of the
52
- * host's, no matter how correctly the host had customized its tokens: the
47
+ * `stapel-tokens` (`pnpm gen:tokens`) — which regenerates THAT HOST's
48
+ * `tokens.css` custom properties (`--stapel-<role>`). It does NOT and CANNOT
49
+ * change this published package's own compiled-in `colors` object — that
50
+ * snapshot is frozen at `@stapel/tokens`' OWN publish time to `@stapel/tokens`'
51
+ * OWN default theme, forever, regardless of what any host does. Feeding
52
+ * `colors` straight into antd's `ConfigProvider` (the previous implementation)
53
+ * is why every default skin rendered Stapel's stock brand colour instead of
54
+ * the host's, no matter how correctly the host had customized its tokens: the
53
55
  * bridge was never wired to read them.
54
56
  *
55
- * The fix reads the LIVE `--stapel-color-<role>` custom property off
57
+ * The fix reads the LIVE `--stapel-<role>` custom property off
56
58
  * `document.documentElement` at call time — the exact value the host's own
57
59
  * (re)generated `tokens.css` sets, already resolved through whichever
58
60
  * `data-theme` is active — and falls back to the static default only where
@@ -63,47 +65,48 @@ export type ThemeMode = "light" | "dark";
63
65
  */
64
66
  function readLiveCssVar(name: CoreTokenName, fallback: string): string {
65
67
  if (typeof document === "undefined") return fallback;
66
- // `getPropertyValue` wants the BARE custom-property name (`--stapel-color-x`);
67
- // `cssVar()` deliberately returns the `var(--stapel-color-x)` wrapper for
68
+ // `getPropertyValue` wants the BARE custom-property name (`--stapel-x`);
69
+ // `cssVar()` deliberately returns the `var(--stapel-x)` wrapper for
68
70
  // embedding in a CSS value, which `getPropertyValue` would never match —
69
71
  // stripped back off here rather than duplicating the `--stapel-` prefix.
70
- const propertyName = cssVar(`color-${name}`).slice("var(".length, -1);
72
+ const propertyName = cssVar(name).slice("var(".length, -1);
71
73
  const value = getComputedStyle(document.documentElement)
72
74
  .getPropertyValue(propertyName)
73
75
  .trim();
74
76
  return value.length > 0 ? value : fallback;
75
77
  }
76
78
 
77
- /** Resolve a neutral colour role to its hex for `mode` via the shared table,
78
- * preferring the host's live CSS custom property over the compiled-in default. */
79
- function role(name: BridgeColorRole, mode: ThemeMode): string {
80
- const token = bridgeColorRoles[name];
81
- return readLiveCssVar(token, colors[token][mode]);
79
+ /** Resolve a §68 colour role to its hex for `mode`, preferring the host's
80
+ * live CSS custom property over the compiled-in default. */
81
+ function role(name: CoreTokenName, mode: ThemeMode): string {
82
+ return readLiveCssVar(name, colors[name][mode]);
82
83
  }
83
84
 
84
85
  /** The flat antd token map (`ThemeConfig["token"]`), never undefined. */
85
86
  export type AntdThemeToken = NonNullable<ThemeConfig["token"]>;
86
87
 
87
88
  /**
88
- * `@stapel/tokens` L2 → antd `theme.token` (frontend-guidelines §2.4 table).
89
- * Pure: same `mode` in, same object out; reads no globals.
89
+ * `@stapel/tokens` §68 roles → antd `theme.token` (frontend-guidelines §2.4
90
+ * table). Pure: same `mode` in, same object out; reads no globals besides the
91
+ * live CSS custom properties documented on {@link readLiveCssVar}.
90
92
  */
91
93
  export function toAntdTheme(mode: ThemeMode): AntdThemeToken {
92
94
  return {
93
95
  colorPrimary: role("brand", mode),
94
96
  colorLink: role("link", mode),
95
- colorLinkHover: role("brandHover", mode),
97
+ colorLinkHover: role("link-hover", mode),
96
98
  colorSuccess: role("success", mode),
97
99
  colorWarning: role("warning", mode),
98
- colorError: role("danger", mode),
100
+ colorError: role("error", mode),
99
101
  colorInfo: role("info", mode),
100
- colorText: role("textPrimary", mode),
101
- colorTextSecondary: role("textSecondary", mode),
102
- colorBgContainer: role("bgContainer", mode),
103
- colorBgLayout: role("bgLayout", mode),
104
- colorBgElevated: role("bgContainer", mode),
102
+ colorText: role("text", mode),
103
+ colorTextSecondary: role("text-muted", mode),
104
+ colorTextTertiary: role("text-subtle", mode),
105
+ colorBgLayout: role("surface", mode),
106
+ colorBgContainer: role("surface-raised", mode),
107
+ colorBgElevated: role("surface-overlay", mode),
105
108
  colorBorder: role("border", mode),
106
- colorBorderSecondary: role("borderSecondary", mode),
109
+ colorBorderSecondary: role("border-subtle", mode),
107
110
  borderRadius: radii[bridgeRadiusRole],
108
111
  fontSize: fontSize[bridgeFontSizeRole].fontSize,
109
112
  fontFamily: fontFamily.sans,