@skdx/tokens 0.26.0 → 0.28.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 (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +77 -57
  3. package/dist/themes/AntDark.d.cts +3 -7
  4. package/dist/themes/AntDark.d.ts +3 -7
  5. package/dist/themes/ChakraDark.d.cts +3 -7
  6. package/dist/themes/ChakraDark.d.ts +3 -7
  7. package/dist/themes/DefaultTheme.d.cts +1 -2
  8. package/dist/themes/DefaultTheme.d.ts +1 -2
  9. package/dist/themes/DraculaLight.d.cts +1 -9
  10. package/dist/themes/DraculaLight.d.ts +1 -9
  11. package/dist/themes/EverforestDark.d.cts +1 -2
  12. package/dist/themes/EverforestDark.d.ts +1 -2
  13. package/dist/themes/EverforestLight.d.cts +4 -8
  14. package/dist/themes/EverforestLight.d.ts +4 -8
  15. package/dist/themes/FluentDark.d.cts +2 -6
  16. package/dist/themes/FluentDark.d.ts +2 -6
  17. package/dist/themes/GruvboxLight.d.cts +1 -2
  18. package/dist/themes/GruvboxLight.d.ts +1 -2
  19. package/dist/themes/MaterialBrand.d.cts +1 -1
  20. package/dist/themes/MaterialBrand.d.ts +1 -1
  21. package/dist/themes/MaterialDark.d.cts +3 -7
  22. package/dist/themes/MaterialDark.d.ts +3 -7
  23. package/dist/themes/MidnightBrand.d.cts +2 -5
  24. package/dist/themes/MidnightBrand.d.ts +2 -5
  25. package/dist/themes/MidnightLight.d.cts +2 -5
  26. package/dist/themes/MidnightLight.d.ts +2 -5
  27. package/dist/themes/NordLight.d.cts +1 -2
  28. package/dist/themes/NordLight.d.ts +1 -2
  29. package/dist/themes/OneLight.d.cts +4 -8
  30. package/dist/themes/OneLight.d.ts +4 -8
  31. package/dist/themes/PrimerDark.d.cts +0 -1
  32. package/dist/themes/PrimerDark.d.ts +0 -1
  33. package/dist/themes/RosePineDawn.d.cts +4 -8
  34. package/dist/themes/RosePineDawn.d.ts +4 -8
  35. package/dist/themes/SkandaDark.d.cts +3 -7
  36. package/dist/themes/SkandaDark.d.ts +3 -7
  37. package/dist/themes/SynthwaveLight.d.cts +3 -7
  38. package/dist/themes/SynthwaveLight.d.ts +3 -7
  39. package/dist/themes/brands.d.cts +7 -14
  40. package/dist/themes/brands.d.ts +7 -14
  41. package/dist/themes/createBrandTheme.d.cts +13 -21
  42. package/dist/themes/createBrandTheme.d.ts +13 -21
  43. package/dist/utils/aliases.d.cts +22 -92
  44. package/dist/utils/aliases.d.ts +22 -92
  45. package/dist/utils/contrast.d.cts +2 -17
  46. package/dist/utils/contrast.d.ts +2 -17
  47. package/dist/utils/cssVars.d.cts +7 -29
  48. package/dist/utils/cssVars.d.ts +7 -29
  49. package/dist/utils/foundation.d.cts +47 -143
  50. package/dist/utils/foundation.d.ts +47 -143
  51. package/dist/utils/mode.d.cts +31 -43
  52. package/dist/utils/mode.d.ts +31 -43
  53. package/dist/utils/theme.d.cts +83 -240
  54. package/dist/utils/theme.d.ts +83 -240
  55. package/dist/utils/toCss.d.cts +18 -57
  56. package/dist/utils/toCss.d.ts +18 -57
  57. package/package.json +1 -1
@@ -1,121 +1,51 @@
1
1
  /**
2
- * The semantic alias layer: the vocabulary component skins are allowed to name.
2
+ * The semantic alias layer: `var()` indirection for component skins.
3
3
  *
4
- * Why this file exists
5
- * -------------------
6
- * `@skdx/skins` is forbidden from containing a colour literal every colour
7
- * it declares must resolve through a token. But the surface a theme actually
8
- * defines is small: five ramps (`primary`, `neutral`, `success`, `warning`,
9
- * `danger`) and ten `semantic` entries. A button skin needs more than that. It
10
- * needs to say "the background of a pressed primary action" and "the border of
11
- * an invalid field", and neither exists as a theme-authored token.
4
+ * Aliases point at ramp steps and semantic entries themes already define. A
5
+ * theme redeclaring `--skdx-color-primary-600` makes every alias pointing
6
+ * there re-resolve, so adding a theme costs one line per alias, not 38.
12
7
  *
13
- * The naive fix is to add those names to `SemanticColors` and set them in all
14
- * 38 themes. That is 38 files edited per alias added, and every one of those
15
- * edits is a chance for a theme to drift out of step with the others.
8
+ * Aliases are emitted at `:root`, below theme declarations in the cascade,
9
+ * letting a theme override an alias when the derivation is mode-dependent.
10
+ * {@link darkColorAliases} uses this escape hatch for aliases that put ink
11
+ * directly on the page and need opposite ends of the ramp in dark mode.
16
12
  *
17
- * This layer takes the other option: aliases are **pure `var()` indirection**,
18
- * declared once at `:root`, pointing at ramp steps and semantic entries the
19
- * themes already define. No alias holds a colour — it holds the *name of* a
20
- * colour. So when `[data-skdx-theme="nord-dark"]` redeclares
21
- * `--skdx-color-primary-600` at its own higher-specificity selector, every alias
22
- * pointing at that step re-resolves to Nord's value automatically. Adding a
23
- * theme costs nothing here, and adding an alias costs one line rather than 38.
24
- *
25
- * This is also why the aliases are emitted at `:root` rather than inside each
26
- * theme block: they must sit *below* the theme declarations in the cascade so a
27
- * theme can still override an alias outright when the derivation is wrong for
28
- * it. {@link darkColorAliases} is exactly that escape hatch in use: a ramp runs
29
- * light-to-dark in every theme, so the aliases that put ink directly on the
30
- * page need the opposite end in dark mode.
31
- *
32
- * Choosing the ramp step
33
- * ----------------------
34
- * A dark theme's ramp is authored for dark — `NordDark`'s `primary-600` is
35
- * already a step that works as a filled background on a dark surface, the same
36
- * way `DefaultTheme`'s is on a light one. So a single step choice per alias is
37
- * correct in both modes for the *filled* aliases. It does not hold for aliases
38
- * that put ink or a wash directly on the page — see {@link darkColorAliases},
39
- * which was written after measuring 22 of 38 themes failing WCAG contrast.
40
- *
41
- * @see docs/architecture/skin-token-map.md for the per-property mapping table.
13
+ * @see packages/skins/README.md for how a skin consumes these aliases.
42
14
  */
43
15
  /**
44
- * Every alias, as `[name, value]` pairs where `value` is always a `var()`
45
- * reference never a literal. Grouped by the question a skin author asks.
46
- *
47
- * Kept as data rather than a hand-written CSS string so
48
- * `aliases.test.ts` can assert the no-literal rule mechanically over the whole
49
- * set, which is the only thing standing between this file and the exact class
50
- * of drift the skins package's Stylelint rule exists to prevent.
16
+ * Alias entries as `[name, value]` pairs, where `value` is always a `var()` reference.
17
+ * Kept as data so `aliases.test.ts` can assert the no-literal rule.
51
18
  */
52
19
  export declare const colorAliases: ReadonlyArray<readonly [string, string]>;
53
20
  /**
54
- * The aliases a dark theme re-points, and what it re-points them to.
55
- *
56
- * Why this exists
57
- * ---------------
58
- * The base table above picks one ramp step per alias and claims that is correct
59
- * in both modes. For most aliases it is: a theme authors its ramp for its own
60
- * mode, so `primary-600` is a usable filled background whichever way the page
61
- * faces.
62
- *
63
- * It is *not* true for the aliases that put ink directly on the page. A ramp
64
- * runs light at 50 to dark at 950 in every theme, dark ones included — that is
65
- * what makes a ramp a ramp. So `--skdx-color-text-danger: danger-700` is dark
66
- * red: correct on a white page, and nearly invisible on a charcoal one. The
67
- * same applies to every "wash + dark ink" status pairing, and to the neutral
68
- * fills (`surface-sunken`, `track`, `skeleton`) that assume the page is lighter
69
- * than they are.
70
- *
71
- * Measured before writing this: 22 of the 38 themes had at least one contrast
72
- * failure, every one of them a dark theme, and every failure in this list.
73
- * Input text sat at 1.07:1 and the tooltip at 1.00:1.
74
- *
75
- * The fix uses the escape hatch the base table was designed around — a theme
76
- * may override an alias, because `[data-skdx-theme="…"]` outranks `:root`. These
77
- * overrides are emitted automatically for every theme whose `mode` is `'dark'`,
78
- * so the cost stays "one line per alias" rather than "one edit per theme", and
79
- * a new dark theme is correct the day it lands without anyone remembering this
80
- * file exists.
81
- *
82
- * Steps mirror around the middle of the ramp: 700 → 300, 800 → 200, 50 → 950.
83
- * That keeps the light and dark treatments the same *distance* from their
84
- * background rather than merely both legible.
21
+ * Dark-mode alias overrides. Base table picks one ramp step per alias; it fails
22
+ * for aliases putting ink directly on the page (ramp runs 50–950 in all themes,
23
+ * so dark-page inks become invisible). These overrides automatically emit for
24
+ * themes where `mode` is `'dark'`. Steps mirror around ramp center: 700 → 300,
25
+ * keeping equal distance from background.
85
26
  */
86
27
  export declare const darkColorAliases: ReadonlyArray<readonly [string, string]>;
87
28
  /**
88
- * Renders {@link darkColorAliases} at `selector`, for a theme whose mode is dark.
89
- *
90
- * @param selector - The theme's own selector, e.g. `'[data-skdx-theme="nord-dark"]'`.
29
+ * Renders {@link darkColorAliases} at the theme selector.
30
+ * @param selector - Theme selector, e.g. `'[data-skdx-theme="nord-dark"]'`.
91
31
  * @public
92
32
  */
93
33
  export declare function darkAliasesToCss(selector: string): string;
94
34
  /**
95
- * Renders {@link colorAliases} as a `:root` rule block.
96
- *
97
- * Emitted *after* `foundationToCss()` and *before* the theme blocks in
98
- * `@skdx/tokens/css`. Order matters in one direction only: an alias must be
99
- * able to be overridden by a theme, and `:root` loses to
100
- * `[data-skdx-theme="…"]` on specificity regardless of source order, so the
101
- * position here is for readability rather than correctness.
102
- *
103
- * @returns A CSS string, e.g. `':root {\n --skdx-color-action-primary-bg: var(--skdx-color-primary-600);\n …\n}\n'`.
35
+ * Renders {@link colorAliases} as a `:root` rule block. `:root` always loses
36
+ * to `[data-skdx-theme="…"]` on specificity.
104
37
  *
38
+ * @returns CSS string; emitted after `foundationToCss()` and before theme blocks.
105
39
  * @example
106
40
  * ```ts
107
41
  * import { foundationToCss, aliasesToCss } from '@skdx/tokens';
108
- *
109
42
  * fs.writeFileSync('tokens.css', foundationToCss() + aliasesToCss());
110
43
  * ```
111
- *
112
44
  * @public
113
45
  */
114
46
  export declare function aliasesToCss(): string;
115
47
  /**
116
- * {@link colorAliases} as a plain object, for consumers applying tokens through
117
- * JS rather than a stylesheet (the alias counterpart to `themeToCssVars`).
118
- *
48
+ * {@link colorAliases} as a plain object for JS consumers (counterpart to `themeToCssVars`).
119
49
  * @public
120
50
  */
121
51
  export declare function aliasesToCssVars(): Record<string, string>;
@@ -3,25 +3,10 @@
3
3
  * colors, per the standard formula (https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio).
4
4
  * Returns a value from 1 (no contrast) to 21 (black on white).
5
5
  *
6
- * **Throws on anything that is not a hex color.** This used to coerce silently:
7
- * `hex.replace('#','')` then `Number.parseInt(full, 16)` yields `NaN` for
8
- * `rgb(0 0 0 / 0.45)`, and `(NaN >> 16) & 255` is `0`, so a translucent value
9
- * was measured as opaque black. `ant-daybreak`'s `textMuted` scored a perfect
10
- * 21:1 while rendering at 3.36:1 — a live AA failure passing as a perfect
11
- * score, which is worse than no guard at all.
12
- *
13
- * Throwing rather than compositing is deliberate. Compositing would need a
14
- * backdrop this function does not have and cannot infer, and it would let the
15
- * next translucent value into the theme set silently. Rejecting forces every
16
- * theme to state its colors as measurable values, which makes the whole set
17
- * auditable by construction instead of by vigilance.
18
- *
19
- * `#rgba` and `#rrggbbaa` are rejected too: an alpha channel is exactly the
20
- * thing that needs a backdrop, and the luminance math below would read those
21
- * extra digits as colour.
6
+ * **Throws on anything that is not a hex color.** Compositing would need
7
+ * a backdrop this function does not have; rejecting forces measurable values.
22
8
  *
23
9
  * @throws {TypeError} if either argument is not `#rgb` or `#rrggbb`
24
- *
25
10
  * @public
26
11
  */
27
12
  export declare function contrastRatio(hexA: string, hexB: string): number;
@@ -3,25 +3,10 @@
3
3
  * colors, per the standard formula (https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio).
4
4
  * Returns a value from 1 (no contrast) to 21 (black on white).
5
5
  *
6
- * **Throws on anything that is not a hex color.** This used to coerce silently:
7
- * `hex.replace('#','')` then `Number.parseInt(full, 16)` yields `NaN` for
8
- * `rgb(0 0 0 / 0.45)`, and `(NaN >> 16) & 255` is `0`, so a translucent value
9
- * was measured as opaque black. `ant-daybreak`'s `textMuted` scored a perfect
10
- * 21:1 while rendering at 3.36:1 — a live AA failure passing as a perfect
11
- * score, which is worse than no guard at all.
12
- *
13
- * Throwing rather than compositing is deliberate. Compositing would need a
14
- * backdrop this function does not have and cannot infer, and it would let the
15
- * next translucent value into the theme set silently. Rejecting forces every
16
- * theme to state its colors as measurable values, which makes the whole set
17
- * auditable by construction instead of by vigilance.
18
- *
19
- * `#rgba` and `#rrggbbaa` are rejected too: an alpha channel is exactly the
20
- * thing that needs a backdrop, and the luminance math below would read those
21
- * extra digits as colour.
6
+ * **Throws on anything that is not a hex color.** Compositing would need
7
+ * a backdrop this function does not have; rejecting forces measurable values.
22
8
  *
23
9
  * @throws {TypeError} if either argument is not `#rgb` or `#rrggbb`
24
- *
25
10
  * @public
26
11
  */
27
12
  export declare function contrastRatio(hexA: string, hexB: string): number;
@@ -1,37 +1,15 @@
1
- /**
2
- * The one place `--skdx-*` custom property *names* are derived from token
3
- * object keys.
4
- *
5
- * Both halves of the token system emit CSS variables — `themeToCssVars` for
6
- * the per-theme colors, `foundationToCssVars` for everything shared — and they
7
- * have to agree byte-for-byte, because a consumer writing
8
- * `var(--skdx-font-size-md)` cannot tell (and should not care) which half
9
- * declared it. Two copies of this naming logic would drift the first time
10
- * someone added a camelCase token, and the failure mode is silent: the
11
- * variable simply never resolves.
12
- *
13
- * @internal
14
- */
15
- /** A token group and the `--skdx-<prefix>-…` namespace its keys render under. @internal */
1
+ /** Token group and its `--skdx-<prefix>-…` namespace. @internal */
16
2
  export type CssVarSection = [prefix: string, tokens: Record<string, unknown> | undefined];
17
3
  /**
18
- * Flattens token groups into a `{ '--skdx-…': value }` map.
19
- *
20
- * A section whose tokens are `undefined` contributes nothing — that is how an
21
- * optional group (a theme's `typography` or `motion`) opts out without the caller
22
- * needing a conditional.
23
- *
24
- * @internal
4
+ * Flatten token groups into `{ '--skdx-…': value }` map. Undefined sections
5
+ * contribute nothing (optional groups opt out without caller conditional). @internal
25
6
  */
26
7
  export declare function sectionsToCssVars(sections: CssVarSection[]): Record<string, string>;
27
- /** Renders a var map as the indented declaration lines of a CSS rule block. @internal */
8
+ /** Render vars as indented CSS declarations. @internal */
28
9
  export declare function varsToDeclarations(vars: Record<string, string>, indent?: string): string;
29
10
  /**
30
- * The `--skdx-motion-*` variables that a `prefers-reduced-motion: reduce` block
31
- * has to zero: every duration *and* every stagger. A stagger is a delay, so
32
- * zeroing the durations without zeroing it would leave a still page that still
33
- * arrives late.
34
- *
35
- * @internal
11
+ * Motion variables to zero in `prefers-reduced-motion: reduce`: durations
12
+ * and staggers (staggers are delays; zeroing one without the other leaves
13
+ * late arrival). @internal
36
14
  */
37
15
  export declare function reducedMotionVarNames(vars: Record<string, string>): string[];
@@ -1,37 +1,15 @@
1
- /**
2
- * The one place `--skdx-*` custom property *names* are derived from token
3
- * object keys.
4
- *
5
- * Both halves of the token system emit CSS variables — `themeToCssVars` for
6
- * the per-theme colors, `foundationToCssVars` for everything shared — and they
7
- * have to agree byte-for-byte, because a consumer writing
8
- * `var(--skdx-font-size-md)` cannot tell (and should not care) which half
9
- * declared it. Two copies of this naming logic would drift the first time
10
- * someone added a camelCase token, and the failure mode is silent: the
11
- * variable simply never resolves.
12
- *
13
- * @internal
14
- */
15
- /** A token group and the `--skdx-<prefix>-…` namespace its keys render under. @internal */
1
+ /** Token group and its `--skdx-<prefix>-…` namespace. @internal */
16
2
  export type CssVarSection = [prefix: string, tokens: Record<string, unknown> | undefined];
17
3
  /**
18
- * Flattens token groups into a `{ '--skdx-…': value }` map.
19
- *
20
- * A section whose tokens are `undefined` contributes nothing — that is how an
21
- * optional group (a theme's `typography` or `motion`) opts out without the caller
22
- * needing a conditional.
23
- *
24
- * @internal
4
+ * Flatten token groups into `{ '--skdx-…': value }` map. Undefined sections
5
+ * contribute nothing (optional groups opt out without caller conditional). @internal
25
6
  */
26
7
  export declare function sectionsToCssVars(sections: CssVarSection[]): Record<string, string>;
27
- /** Renders a var map as the indented declaration lines of a CSS rule block. @internal */
8
+ /** Render vars as indented CSS declarations. @internal */
28
9
  export declare function varsToDeclarations(vars: Record<string, string>, indent?: string): string;
29
10
  /**
30
- * The `--skdx-motion-*` variables that a `prefers-reduced-motion: reduce` block
31
- * has to zero: every duration *and* every stagger. A stagger is a delay, so
32
- * zeroing the durations without zeroing it would leave a still page that still
33
- * arrives late.
34
- *
35
- * @internal
11
+ * Motion variables to zero in `prefers-reduced-motion: reduce`: durations
12
+ * and staggers (staggers are delays; zeroing one without the other leaves
13
+ * late arrival). @internal
36
14
  */
37
15
  export declare function reducedMotionVarNames(vars: Record<string, string>): string[];
@@ -1,79 +1,42 @@
1
1
  import { type ThemeControls, type ThemeControlsCoarse, type ThemeMotion, type ThemeRadii, type ThemeShadows, type ThemeSpace, type ThemeTypography } from './theme.cjs';
2
2
  /**
3
- * The type system: one font stack, one scale, one set of weights,
4
- * line-heights and tracking steps, shared by every theme.
5
- *
6
- * A theme picks colors. It does not get to resize the type scale, because a
7
- * layout that reflows when you switch brand is a layout that was never
8
- * designed — it was designed once, against one scale, and every other brand
9
- * was hoping. The two font *stacks* are the only part a theme can override,
10
- * and only through {@link ThemeTypographyDeviation}, because impersonating a
11
- * design language means impersonating its typeface.
12
- *
3
+ * The type system: one font stack, scale, weight set, line-heights and
4
+ * tracking steps, shared by every theme. Only the font stacks are
5
+ * per-theme overridable, via {@link ThemeTypographyDeviation}.
13
6
  * @public
14
7
  */
15
8
  export declare const typography: ThemeTypography;
16
9
  /**
17
- * The spacing scale — a 4px base with the usual gaps (no `7`, no `9`) so the
18
- * steps stay memorable rather than exhaustive. Structural: gap and padding are
19
- * rhythm, and rhythm is a property of the design system, not of the brand
20
- * painted on top of it.
21
- *
10
+ * The spacing scale — a 4px base, structural rather than per-brand: gap and
11
+ * padding are rhythm, a property of the system, not the brand on top of it.
22
12
  * @public
23
13
  */
24
14
  export declare const space: ThemeSpace;
25
15
  /**
26
- * The corner-radius scale. Shared for the same reason {@link space} is: a
27
- * component's silhouette is part of the system's shape language, and a brand
28
- * that rounds its corners differently is a different component library
29
- * wearing the same class names.
30
- *
16
+ * The corner-radius scale, structural like {@link space}: a component's
17
+ * silhouette is part of the system's shape language, not the brand's.
31
18
  * @public
32
19
  */
33
20
  export declare const radii: ThemeRadii;
34
21
  /**
35
22
  * The elevation scale — geometry only. Every value defers its color to
36
23
  * `var(--skdx-shadow-color)` and scales its alpha by
37
- * `var(--skdx-shadow-strength)`, both of which a theme supplies (see
38
- * {@link ThemeShadowColor}).
39
- *
40
- * This split is the whole reason shadows can be shared at all. A shadow is one
41
- * CSS string that welds geometry to a color, so before this every theme
42
- * restated `0 4px 6px -1px` purely to be able to change `rgb(…)` at the end of
43
- * it — 38 copies of the same three offsets, and no way to tell a deliberate
44
- * elevation change from a color change.
45
- *
46
- * The base alphas below are the original `skanda-light` values, so a theme
47
- * with `strength: '1'` renders exactly what it did before the split.
48
- * Substitution is lazy: these live at `:root`, but `var(--skdx-shadow-color)`
49
- * resolves against the element the shadow is finally *used* on, so the active
50
- * `[data-skdx-theme]` block wins. `calc()` is legal in the alpha slot, and an
51
- * alpha above 1 clamps rather than erroring — which is what keeps a
52
- * high-strength dark theme from being a footgun.
53
- *
24
+ * `var(--skdx-shadow-strength)`, both supplied by a theme (see
25
+ * {@link ThemeShadowColor}), so 38 themes share one set of offsets instead of
26
+ * each restating them to vary only the color.
54
27
  * @public
55
28
  */
56
29
  export declare const shadows: ThemeShadows;
57
30
  /**
58
- * The shared animation timing re-exported from {@link defaultMotion}, which
59
- * remains the single source so that `themeToCssVars` can keep merging it under
60
- * a theme's {@link Theme.motion} without importing this module.
61
- *
62
- * See {@link ThemeMotion} for why motion is theme-invariant.
63
- *
31
+ * The shared animation timing, re-exported from {@link defaultMotion}. See
32
+ * {@link ThemeMotion} for why motion is theme-invariant.
64
33
  * @public
65
34
  */
66
35
  export declare const motion: Required<ThemeMotion>;
67
36
  /**
68
37
  * A structural stacking-order scale for overlay-class UI (dropdowns, sticky
69
- * headers, dialog/popover backdrops, floating content, toasts). Unlike the
70
- * rest of the token system, z-index isn't a per-brand visual choice every
71
- * theme should stack the same way — so it's exported once here rather than
72
- * duplicated into all 38 {@link Theme} objects. Consumers building an app
73
- * with multiple concurrent overlay types (e.g. a `Select` opened from inside
74
- * a `Dialog`, with a `Toast` on top of both) should coordinate their own
75
- * z-indices against this scale instead of picking ad hoc numbers per
76
- * component.
38
+ * headers, dialog/popover backdrops, floating content, toasts) every theme
39
+ * stacks the same way, so it's exported once rather than duplicated per theme.
77
40
  *
78
41
  * @example
79
42
  * ```css
@@ -88,27 +51,20 @@ export declare const zIndex: {
88
51
  readonly base: 0;
89
52
  readonly dropdown: 10;
90
53
  readonly sticky: 20;
91
- /** The scrim behind a modal surface. */
54
+ /** Scrim behind modal. */
92
55
  readonly overlay: 30;
93
- /** The modal surface itself — above its own scrim, below any popover opened from inside it. */
56
+ /** Modal surface; above scrim, below popovers opened from inside. */
94
57
  readonly modal: 35;
95
58
  readonly popover: 40;
96
59
  readonly toast: 50;
97
- /**
98
- * Escape hatch for the one thing that must sit above everything, e.g. a
99
- * debug overlay or an "app is offline" banner. Deliberately far above
100
- * `toast` so app code never has to guess a bigger number.
101
- */
60
+ /** Escape hatch for the one thing that must sit above everything, e.g. a debug overlay. */
102
61
  readonly max: 9999;
103
62
  };
104
63
  /** The shape of the {@link zIndex} scale — a map of named stacking layers (`sticky`, `overlay`, `popover`, `toast`, …) to their numeric `z-index`. @public */
105
64
  export type ZIndexScale = typeof zIndex;
106
65
  /**
107
- * Structural focus-ring geometry (width/offset) the *color* half of the
108
- * focus-ring contract is themed per brand ({@link SemanticColors.focusRing}),
109
- * but the ring's thickness and offset are a layout constant every theme
110
- * should share, so they live here rather than being repeated as identical
111
- * values across all 38 bundled themes.
66
+ * Structural focus-ring geometry (width/offset). The ring's *color* is themed
67
+ * per brand ({@link SemanticColors.focusRing}); thickness/offset are shared.
112
68
  *
113
69
  * @example
114
70
  * ```css
@@ -124,30 +80,17 @@ export declare const focusRing: {
124
80
  readonly width: "2px";
125
81
  readonly offset: "2px";
126
82
  /**
127
- * The offset a *clipping* container hands down to its children.
128
- *
129
- * An outline is painted outward from the border edge and is clipped by an
130
- * ancestor's `overflow` exactly like any other overflowing paint — which
131
- * sliced the ring off inside every control group that rounds its corners by
132
- * clipping. Because `outline-offset` is read from a custom property, such a
133
- * container sets this on itself and every descendant ring moves *inside* the
134
- * border box, where nothing can reach it. One declaration per clipping
135
- * container, no per-part focus rules.
136
- *
137
- * Negative by exactly the ring width, which lands it flush against the
138
- * inside of the edge rather than floating in from it.
83
+ * Offset for clipping containers; moves ring inside border-box so overflow
84
+ * doesn't clip. Negative ring width, flush inside edge.
139
85
  */
140
86
  readonly offsetInset: "calc(-1 * var(--skdx-focus-ring-width))";
141
87
  };
142
88
  /** The shape of the {@link focusRing} geometry — the structural `width`/`offset` of the focus ring (its color is themed separately). @public */
143
89
  export type FocusRingScale = typeof focusRing;
144
90
  /**
145
- * Border thicknesses. Structural for the same reason {@link focusRing}'s
146
- * geometry is: a brand changes border *color* (see
147
- * {@link SemanticColors.border}), not how many pixels thick a hairline is.
148
- * Three steps only — a hairline, an emphasis weight (focus/selected/invalid
149
- * outlines drawn without the focus ring), and a heavy weight for deliberate
150
- * structural rules. There is no `0`: that's `border: none`, not a token.
91
+ * Border thicknesses, structural like {@link focusRing}: a brand changes
92
+ * border *color* ({@link SemanticColors.border}), not hairline width. No `0`
93
+ * step that's `border: none`, not a token.
151
94
  *
152
95
  * @example
153
96
  * ```css
@@ -165,37 +108,25 @@ export declare const borderWidth: {
165
108
  /** The shape of the {@link borderWidth} scale — `thin`/`thick`/`thicker` border thicknesses. @public */
166
109
  export type BorderWidthScale = typeof borderWidth;
167
110
  /**
168
- * The shared control geometry — heights, paddings, icon boxes, row heights and
169
- * overlay insets. See {@link ThemeControls} for why this is structural rather
170
- * than per-brand, and for the retuning escape hatch.
171
- *
172
- * The ladder is an even 6px step (30/36/42) and every rung sits inside the
173
- * range the two reference libraries surveyed occupy. Several values are
174
- * `var()` references rather than lengths on purpose: a control's inline
175
- * padding *is* a step of {@link space}, and restating `0.75rem` here would let
176
- * the two drift. The exceptions are the four numbers that are deliberately off
177
- * a scale — `padding.sm` (10px), `height.compact` (32px), `item.gap` (2px) and
178
- * `target.min` (24px) — each documented where it is declared.
179
- *
111
+ * The shared control geometry — heights, paddings, icon boxes, row heights
112
+ * and overlay insets. See {@link ThemeControls} for why this is structural
113
+ * rather than per-brand, and for the retuning escape hatch. Values are
114
+ * `var()` references where they equal a {@link space} step, so the two can't
115
+ * drift; the few off-scale exceptions are documented where declared.
180
116
  * @public
181
117
  */
182
118
  export declare const controls: ThemeControls;
183
119
  /**
184
- * What a coarse pointer overrides. Emitted by {@link foundationToCss} as a
185
- * `@media (pointer: coarse)` block; see {@link ThemeControlsCoarse} for why
120
+ * What a coarse pointer overrides, emitted as a `@media (pointer: coarse)`
121
+ * block by {@link foundationToCss}; see {@link ThemeControlsCoarse} for why
186
122
  * only hit sizes are listed.
187
- *
188
123
  * @public
189
124
  */
190
125
  export declare const controlsCoarse: ThemeControlsCoarse;
191
126
  /**
192
- * The two opacities the system actually has an opinion about. Deliberately
193
- * *not* a 0–100 ramp: an arbitrary ramp invents decisions nobody made, while
194
- * these two are real, repeated cross-component choices — how faded a disabled
195
- * control is, and how much a modal scrim dims the page behind it.
196
- *
197
- * Scrim *color* is themed ({@link SemanticColors.overlay}); this is the
198
- * structural strength of the dim, so every brand's scrim occludes equally.
127
+ * The two opacities the system has an opinion about — disabled fade and
128
+ * modal scrim dim not an arbitrary 0–100 ramp. Scrim *color* is themed
129
+ * ({@link SemanticColors.overlay}); this is the structural dim strength.
199
130
  *
200
131
  * @example
201
132
  * ```css
@@ -212,16 +143,9 @@ export declare const opacity: {
212
143
  /** The shape of the {@link opacity} scale — the `disabled` and `scrim` opacities. @public */
213
144
  export type OpacityScale = typeof opacity;
214
145
  /**
215
- * Viewport widths, in pixels, as **TypeScript exports only** — deliberately
216
- * not emitted as CSS custom properties by {@link foundationToCss}. A custom
217
- * property cannot be used in a `@media` query's condition (`@media (min-width:
218
- * var(--x))` is invalid CSS), so a `--skdx-breakpoint-*` variable would be a
219
- * token that looks usable and isn't. Consume these from JS/TS, or from a
220
- * build step that inlines the number into your own media queries.
221
- *
222
- * The components themselves are headless and ship no responsive behavior;
223
- * this exists so consumers building a styled layer on top don't have to
224
- * invent their own set.
146
+ * Viewport widths, in pixels, as **TypeScript exports only** — not emitted as
147
+ * CSS custom properties, since `@media (min-width: var(--x))` is invalid CSS.
148
+ * Consume from JS/TS or inline into your own media queries.
225
149
  *
226
150
  * @example
227
151
  * ```ts
@@ -242,51 +166,31 @@ export declare const breakpoints: {
242
166
  export type BreakpointScale = typeof breakpoints;
243
167
  /**
244
168
  * Flattens every shared token into a map of CSS custom property names to
245
- * values — the foundation's counterpart to `themeToCssVars`. Together the two
246
- * maps are the complete `--skdx-*` surface, and they never overlap.
247
- *
248
- * {@link breakpoints} is not included — see its docs for why a breakpoint
249
- * can't be a CSS custom property.
169
+ * values — the foundation's counterpart to `themeToCssVars`. Together they
170
+ * are the complete `--skdx-*` surface, and never overlap. {@link breakpoints}
171
+ * is excluded, since a breakpoint can't be a CSS custom property.
250
172
  *
251
173
  * @returns A plain object keyed by CSS custom property name (e.g. `'--skdx-space-4'`), unprefixed by any selector.
252
- *
253
174
  * @public
254
175
  */
255
176
  export declare function foundationToCssVars(): Record<string, string>;
256
177
  /**
257
178
  * The control metrics a coarse pointer overrides, as a var map — the
258
179
  * `@media (pointer: coarse)` counterpart to {@link foundationToCssVars}.
259
- *
260
- * Exported because `@skdx/skins` renders its own no-tokens fallback copy of
261
- * both blocks from these functions rather than restating the values, which is
262
- * the only thing that keeps the two in step.
263
- *
180
+ * Exported so `@skdx/skins` can render its fallback copy from these
181
+ * functions instead of restating the values.
264
182
  * @public
265
183
  */
266
184
  export declare function coarsePointerToCssVars(): Record<string, string>;
267
185
  /**
268
186
  * Renders every shared token as a `:root`-scoped `--skdx-*` rule block — the
269
187
  * theme-invariant counterpart to {@link themeToCss}. **Inject this exactly
270
- * once**, then inject `themeToCss(theme)` per theme alongside it. Without it
271
- * the type scale, spacing, radii, shadow geometry and motion are simply
272
- * absent, because no theme declares them any more.
273
- *
274
- * Followed by a `@media (prefers-reduced-motion: reduce)` block that
275
- * re-declares every `--skdx-motion-duration-*` and `--skdx-motion-stagger-*` as
276
- * `0ms`. Components are headless and animate nothing themselves, so honoring
277
- * the preference has to happen where the durations are *defined* rather than
278
- * where they're used — this way a consumer who writes `transition-duration:
279
- * var(--skdx-motion-duration-normal)` gets WCAG 2.3.3 behavior for free instead
280
- * of having to remember the media query at every call site. The easing curve
281
- * is left alone: it's a shape, not a duration, and is inert at `0ms`. A theme
282
- * that retunes motion via `ThemeMotionDeviation` emits its own copy of this
283
- * block, so the guarantee survives the escape hatch.
188
+ * once**, then `themeToCss(theme)` per theme alongside it.
284
189
  *
285
- * Then a `@media (pointer: coarse)` block re-declaring the hit sizes from
286
- * {@link controlsCoarse}, for the same reason: the preference has to be honored
287
- * where the metric is *defined*, so a consumer who writes
288
- * `block-size: var(--skdx-control-height-md)` gets a touch-sized control without
289
- * having to remember the query.
190
+ * Also emits a `@media (prefers-reduced-motion: reduce)` block zeroing every
191
+ * motion duration/stagger at the definition site (WCAG 2.3.3 for free at every
192
+ * call site, no per-consumer media query), and a `@media (pointer: coarse)`
193
+ * block re-declaring the hit sizes from {@link controlsCoarse} the same way.
290
194
  *
291
195
  * @example
292
196
  * ```ts