@ttoss/fsl-theme 1.1.13 → 1.1.15

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 (91) hide show
  1. package/dist/Types-BiBa17RL.d.cts +1427 -0
  2. package/dist/Types-BiBa17RL.d.mts +1427 -0
  3. package/dist/baseBundle-DxvXyhGa.mjs +17 -0
  4. package/dist/baseBundle-iEFf5nqT.cjs +22 -0
  5. package/dist/{esm/chunk-SE5Z52RE.js → createTheme-BLNYztZU.mjs} +76 -172
  6. package/dist/createTheme-Cv6RP9D6.cjs +1825 -0
  7. package/dist/css.cjs +48 -0
  8. package/dist/{css.d.ts → css.d.cts} +67 -63
  9. package/dist/css.d.mts +168 -0
  10. package/dist/css.mjs +42 -0
  11. package/dist/dataviz/index.cjs +45 -0
  12. package/dist/dataviz/{index.d.ts → index.d.cts} +9 -5
  13. package/dist/dataviz/index.d.mts +66 -0
  14. package/dist/dataviz/index.mjs +39 -0
  15. package/dist/dtcg.cjs +115 -0
  16. package/dist/{dtcg.d.ts → dtcg.d.cts} +9 -7
  17. package/dist/dtcg.d.mts +51 -0
  18. package/dist/dtcg.mjs +112 -0
  19. package/dist/helpers-4p4-QVt_.cjs +258 -0
  20. package/dist/helpers-CaswNJMy.mjs +211 -0
  21. package/dist/{index.d.ts → index-CsIjfw86.d.cts} +42 -34
  22. package/dist/index-nJrjI0BA.d.mts +94 -0
  23. package/dist/index.cjs +16 -0
  24. package/dist/index.d.cts +6 -0
  25. package/dist/index.d.mts +6 -0
  26. package/dist/index.mjs +7 -0
  27. package/dist/{react.d.ts → react-CGa6FlNL.d.cts} +130 -106
  28. package/dist/react-DnKxR2gK.d.mts +370 -0
  29. package/dist/react-EUwpdvY7.cjs +481 -0
  30. package/dist/react.cjs +12 -0
  31. package/dist/react.d.cts +4 -0
  32. package/dist/react.d.mts +4 -0
  33. package/dist/react.mjs +412 -0
  34. package/dist/runtime-entry.cjs +9 -0
  35. package/dist/runtime-entry.d.cts +3 -0
  36. package/dist/runtime-entry.d.mts +3 -0
  37. package/dist/runtime-entry.mjs +3 -0
  38. package/dist/{runtime-entry.d.ts → ssrScript-BVysxDws.d.cts} +26 -23
  39. package/dist/ssrScript-BVysxDws.d.mts +98 -0
  40. package/dist/ssrScript-CRfrN8Pm.cjs +202 -0
  41. package/dist/ssrScript-D3kGPQpi.mjs +179 -0
  42. package/dist/themes/bruttal.cjs +75 -0
  43. package/dist/themes/bruttal.d.cts +3 -0
  44. package/dist/themes/bruttal.d.mts +3 -0
  45. package/dist/themes/bruttal.mjs +72 -0
  46. package/dist/themes/corporate.cjs +34 -0
  47. package/dist/themes/corporate.d.cts +3 -0
  48. package/dist/themes/corporate.d.mts +3 -0
  49. package/dist/{esm/chunk-TPMN75JM.js → themes/corporate.mjs} +7 -5
  50. package/dist/themes/oca.cjs +34 -0
  51. package/dist/themes/oca.d.cts +3 -0
  52. package/dist/themes/oca.d.mts +3 -0
  53. package/dist/{esm/chunk-DU4QDQUC.js → themes/oca.mjs} +7 -5
  54. package/dist/themes/ventures.cjs +34 -0
  55. package/dist/themes/ventures.d.cts +3 -0
  56. package/dist/themes/ventures.d.mts +3 -0
  57. package/dist/{esm/chunk-BXKVVQEP.js → themes/ventures.mjs} +7 -5
  58. package/dist/toCssVars-CYZCe-on.mjs +286 -0
  59. package/dist/toCssVars-DudHKvt2.cjs +297 -0
  60. package/dist/{esm/chunk-4Q4P3JBB.js → tokenRegistry-DjgSN3oU.mjs} +23 -20
  61. package/dist/tokenRegistry-OhaJ9sPJ.cjs +199 -0
  62. package/dist/vars.cjs +127 -0
  63. package/dist/{vars.d.ts → vars.d.cts} +8 -7
  64. package/dist/vars.d.mts +128 -0
  65. package/dist/vars.mjs +123 -0
  66. package/dist/withDataviz-B4pVsOwV.cjs +192 -0
  67. package/dist/{esm/chunk-FBVUI2PK.js → withDataviz-DY5s7R51.mjs} +40 -12
  68. package/package.json +20 -20
  69. package/dist/Types-6tR0_2Ss.d.ts +0 -1452
  70. package/dist/esm/chunk-5PWPAQMC.js +0 -9
  71. package/dist/esm/chunk-HRNXVRS3.js +0 -54
  72. package/dist/esm/chunk-IJGA42O6.js +0 -141
  73. package/dist/esm/chunk-PQPQNZ73.js +0 -262
  74. package/dist/esm/chunk-UMRQ4OTX.js +0 -11
  75. package/dist/esm/chunk-VL6EGE6Z.js +0 -222
  76. package/dist/esm/chunk-WVQSTQD5.js +0 -192
  77. package/dist/esm/css.js +0 -6
  78. package/dist/esm/dataviz/index.js +0 -19
  79. package/dist/esm/dtcg.js +0 -65
  80. package/dist/esm/index.js +0 -10
  81. package/dist/esm/react.js +0 -8
  82. package/dist/esm/runtime-entry.js +0 -4
  83. package/dist/esm/themes/bruttal.js +0 -6
  84. package/dist/esm/themes/corporate.js +0 -6
  85. package/dist/esm/themes/oca.js +0 -6
  86. package/dist/esm/themes/ventures.js +0 -6
  87. package/dist/esm/vars.js +0 -28
  88. package/dist/themes/bruttal.d.ts +0 -5
  89. package/dist/themes/corporate.d.ts +0 -5
  90. package/dist/themes/oca.d.ts +0 -5
  91. package/dist/themes/ventures.d.ts +0 -5
@@ -0,0 +1,34 @@
1
+ /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
+ Object.defineProperty(exports, Symbol.toStringTag, {
3
+ value: 'Module'
4
+ });
5
+ const require_createTheme = require('../createTheme-Cv6RP9D6.cjs');
6
+ const require_withDataviz = require('../withDataviz-B4pVsOwV.cjs');
7
+
8
+ //#region src/themes/ventures.ts
9
+ const bundle = require_createTheme.createTheme({
10
+ overrides: {
11
+ core: {
12
+ colors: {
13
+ brand: {
14
+ 50: "#EEF1F8",
15
+ 100: "#CDD5EA",
16
+ 200: "#9BAED5",
17
+ 300: "#6887BF",
18
+ 400: "#3A61A8",
19
+ 500: "#1A3D8F",
20
+ 600: "#142E6E",
21
+ 700: "#0E2050",
22
+ 800: "#081333",
23
+ 900: "#03091A"
24
+ }
25
+ }
26
+ },
27
+ semantic: {}
28
+ },
29
+ alternate: void 0
30
+ });
31
+ const ventures = require_withDataviz.withDataviz(bundle);
32
+
33
+ //#endregion
34
+ exports.ventures = ventures;
@@ -0,0 +1,3 @@
1
+
2
+ import { t as ventures } from "../index-CsIjfw86.cjs";
3
+ export { ventures };
@@ -0,0 +1,3 @@
1
+
2
+ import { t as ventures } from "../index-nJrjI0BA.mjs";
3
+ export { ventures };
@@ -1,9 +1,9 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- import { withDataviz } from "./chunk-FBVUI2PK.js";
3
- import { createTheme } from "./chunk-SE5Z52RE.js";
2
+ import { n as createTheme } from "../createTheme-BLNYztZU.mjs";
3
+ import { t as withDataviz } from "../withDataviz-DY5s7R51.mjs";
4
4
 
5
- // src/themes/ventures.ts
6
- var bundle = createTheme({
5
+ //#region src/themes/ventures.ts
6
+ const bundle = createTheme({
7
7
  overrides: {
8
8
  core: {
9
9
  colors: {
@@ -25,5 +25,7 @@ var bundle = createTheme({
25
25
  },
26
26
  alternate: void 0
27
27
  });
28
- var ventures = withDataviz(bundle);
28
+ const ventures = withDataviz(bundle);
29
+
30
+ //#endregion
29
31
  export { ventures };
@@ -0,0 +1,286 @@
1
+ /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
+ import { a as flattenTheme, i as flattenObject, n as SAFE_ID_RE, r as deepMerge, t as COMPOUND_REF_RE } from "./helpers-CaswNJMy.mjs";
3
+ import { t as CSS_PATH_PREFIXES } from "./tokenRegistry-DjgSN3oU.mjs";
4
+
5
+ //#region src/roots/toCssVars.ts
6
+ /**
7
+ * Convert a full token path to a CSS custom property name.
8
+ *
9
+ * `core.colors.brand.500` → `--tt-core-colors-brand-500`
10
+ * `semantic.colors.action.primary.background.default` → `--tt-colors-action-primary-background-default`
11
+ */
12
+ const toCssVarName = tokenPath => {
13
+ for (const [prefix, cssPrefix] of CSS_PATH_PREFIXES) if (tokenPath.startsWith(prefix)) return `${cssPrefix}${tokenPath.slice(prefix.length).replace(/\./g, "-")}`;
14
+ return `--tt-${tokenPath.replace(/\./g, "-")}`;
15
+ };
16
+ /**
17
+ * Replace all embedded `{token.path}` refs inside a raw string with `var(--tt-...)` references.
18
+ *
19
+ * Handles compound semantic values like:
20
+ * `clamp({core.spacing.4}, {core.spacing.6}, {core.spacing.12})`
21
+ * → `clamp(var(--tt-core-spacing-4), var(--tt-core-spacing-6), var(--tt-core-spacing-12))`
22
+ */
23
+ const inlineRefsToVars = value => {
24
+ return value.replace(COMPOUND_REF_RE, (_match, path) => {
25
+ return `var(${toCssVarName(path)})`;
26
+ });
27
+ };
28
+ /**
29
+ * Build a flat CSS custom properties record from a ThemeTokens.
30
+ *
31
+ * Core tokens get raw values. Semantic tokens get `var()` references
32
+ * to preserve the cascade relationship at runtime.
33
+ */
34
+ const buildCssVars = theme => {
35
+ const vars = {};
36
+ const {
37
+ core: coreFlat,
38
+ semantic: semanticFlat
39
+ } = flattenTheme(theme);
40
+ for (const [path, value] of Object.entries(coreFlat)) vars[toCssVarName(path)] = value;
41
+ for (const [path, value] of Object.entries(semanticFlat)) {
42
+ const varName = toCssVarName(path);
43
+ if (typeof value === "string" && value.includes("{")) vars[varName] = inlineRefsToVars(value);else vars[varName] = value;
44
+ }
45
+ return vars;
46
+ };
47
+ const sanitizeId = value => {
48
+ if (!SAFE_ID_RE.test(value)) throw new Error(`Invalid themeId "${value}". Only alphanumeric characters, hyphens, and underscores are allowed.`);
49
+ return value;
50
+ };
51
+ const buildSelector = ({
52
+ themeId,
53
+ mode,
54
+ selector
55
+ }) => {
56
+ if (selector) return selector;
57
+ if (!themeId) return mode ? `:root[data-tt-mode="${mode}"]` : ":root";
58
+ let s = `[data-tt-theme="${sanitizeId(themeId)}"]`;
59
+ if (mode) s += `[data-tt-mode="${mode}"]`;
60
+ return s;
61
+ };
62
+ /** Matches container query length units: cqi, cqb, cqw, cqh, cqmin, cqmax */
63
+ const CQ_UNIT_RE = /cq(?:i|b|w|h|min|max)(?![a-z])/i;
64
+ /** Check if a CSS value contains container query units. */
65
+ const hasCqUnits = value => {
66
+ return typeof value === "string" && CQ_UNIT_RE.test(value);
67
+ };
68
+ /**
69
+ * Replace container query units with viewport-safe equivalents.
70
+ *
71
+ * cqi → vw, cqb → vh, cqw → vw, cqh → vh, cqmin → vmin, cqmax → vmax
72
+ */
73
+ const toViewportFallback = value => {
74
+ return value.replace(/cqmin(?![a-z])/gi, "vmin").replace(/cqmax(?![a-z])/gi, "vmax").replace(/cqi(?![a-z])/gi, "vw").replace(/cqb(?![a-z])/gi, "vh").replace(/cqw(?![a-z])/gi, "vw").replace(/cqh(?![a-z])/gi, "vh");
75
+ };
76
+ /**
77
+ * Extract entries from a CSS vars record whose values contain CQ units.
78
+ */
79
+ const extractContainerQueryVars = vars => {
80
+ const cqVars = {};
81
+ for (const [name, value] of Object.entries(vars)) if (hasCqUnits(value)) cqVars[name] = value;
82
+ return cqVars;
83
+ };
84
+ /**
85
+ * Build CSS vars for reduced-motion overrides.
86
+ *
87
+ * Derives every `*.duration` path from the theme's `semantic.motion` structure,
88
+ * so adding a new motion role never silently omits it from the
89
+ * `@media (prefers-reduced-motion: reduce)` block.
90
+ *
91
+ * Sets all semantic motion duration vars to `var(--tt-core-motion-duration-none)` (0ms).
92
+ * Emitted inside `@media (prefers-reduced-motion: reduce)`.
93
+ */
94
+ const buildReducedMotionVars = theme => {
95
+ const noneVar = `var(${toCssVarName("core.motion.duration.none")})`;
96
+ const flat = flattenObject(theme.semantic.motion, "semantic.motion");
97
+ const vars = {};
98
+ for (const path of Object.keys(flat)) if (path.endsWith(".duration")) vars[toCssVarName(path)] = noneVar;
99
+ return vars;
100
+ };
101
+ /**
102
+ * Build CSS vars for coarse-pointer hit target overrides.
103
+ *
104
+ * The semantic hit tokens default to fine-pointer values. This record
105
+ * contains the coarse overrides, to be emitted inside
106
+ * `@media (any-pointer: coarse)`.
107
+ *
108
+ * Derives every `*.coarse.*` path from `core.sizing.hit.coarse` dynamically,
109
+ * so adding a new step to `CoreSizeHitScale` never silently omits it here.
110
+ */
111
+ const buildCoarseHitVars = theme => {
112
+ const vars = {};
113
+ for (const [key, value] of Object.entries(theme.core.sizing.hit.coarse)) if (typeof value === "string") vars[toCssVarName(`semantic.sizing.hit.${key}`)] = value;
114
+ return vars;
115
+ };
116
+ /**
117
+ * Render a complete scoped CSS block from a vars record.
118
+ *
119
+ * Includes the base selector block, optional CQ `@supports` block,
120
+ * coarse-pointer `@media` block, and reduced-motion `@media` block.
121
+ * This is the single implementation shared by `toCssVars` and `bundleToCssVars`.
122
+ */
123
+ const buildCssBlock = ({
124
+ selector,
125
+ vars,
126
+ containerQueryVars,
127
+ coarseHitVars,
128
+ reducedMotionVars,
129
+ colorScheme
130
+ }) => {
131
+ /** Maps a vars record to indented CSS declaration lines (4-space, for nested at-rule blocks). */
132
+ const varLines = v => {
133
+ return Object.entries(v).map(([name, val]) => {
134
+ return ` ${name}: ${val};`;
135
+ });
136
+ };
137
+ /** Builds a complete at-rule block, or empty string if the vars record is empty. */
138
+ const atRuleBlock = (atRule, v) => {
139
+ const lines = varLines(v);
140
+ return lines.length > 0 ? `${atRule} {\n ${selector} {\n${lines.join("\n")}\n }\n}` : "";
141
+ };
142
+ const baseLines = [];
143
+ if (colorScheme) baseLines.push(` color-scheme: ${colorScheme};`);
144
+ for (const [name, value] of Object.entries(vars)) if (hasCqUnits(value)) baseLines.push(` ${name}: ${toViewportFallback(String(value))};`);else baseLines.push(` ${name}: ${value};`);
145
+ const baseBlock = `${selector} {\n${baseLines.join("\n")}\n}`;
146
+ const cqContent = atRuleBlock("@supports (width: 1cqi)", containerQueryVars);
147
+ const cqBlock = cqContent ? `\n\n${cqContent}` : "";
148
+ const coarseBlock = atRuleBlock("@media (any-pointer: coarse)", coarseHitVars);
149
+ const reducedMotionBlock = atRuleBlock("@media (prefers-reduced-motion: reduce)", reducedMotionVars);
150
+ return [baseBlock + cqBlock, coarseBlock, reducedMotionBlock].filter(Boolean).join("\n\n");
151
+ };
152
+ /**
153
+ * Internal: convert a single `ThemeTokens` into CSS custom properties.
154
+ * Use the public overloaded `toCssVars()` instead.
155
+ */
156
+ const toCssVarsBase = (theme, options = {}) => {
157
+ const cssVars = buildCssVars(theme);
158
+ const coarseHitVars = buildCoarseHitVars(theme);
159
+ const reducedMotionVars = buildReducedMotionVars(theme);
160
+ const containerQueryVars = extractContainerQueryVars(cssVars);
161
+ const selector = buildSelector(options);
162
+ const {
163
+ colorScheme,
164
+ mode
165
+ } = options;
166
+ const effectiveColorScheme = colorScheme ?? mode;
167
+ return {
168
+ cssVars,
169
+ coarseHitVars,
170
+ reducedMotionVars,
171
+ containerQueryVars,
172
+ selector,
173
+ toCssString: () => {
174
+ return buildCssBlock({
175
+ selector,
176
+ vars: cssVars,
177
+ containerQueryVars,
178
+ coarseHitVars,
179
+ reducedMotionVars,
180
+ colorScheme: effectiveColorScheme
181
+ });
182
+ }
183
+ };
184
+ };
185
+ /** Type guard: checks if the input is a ThemeBundle. */
186
+ const isThemeBundle = input => {
187
+ return "baseMode" in input && "base" in input;
188
+ };
189
+ /**
190
+ * Compute a diff record: only entries in `full` whose values differ from `base`.
191
+ */
192
+ const diffCssVars = ({
193
+ base,
194
+ full
195
+ }) => {
196
+ const diff = {};
197
+ for (const [key, value] of Object.entries(full)) if (base[key] !== value) diff[key] = value;
198
+ return diff;
199
+ };
200
+ /**
201
+ * Convert a `ThemeBundle` into scoped CSS custom properties with optimized
202
+ * alternate-mode output (diff-only).
203
+ *
204
+ * @example
205
+ * ```ts
206
+ * import { toCssVars } from '@ttoss/fsl-theme/css';
207
+ * import { createTheme } from '@ttoss/fsl-theme';
208
+ *
209
+ * const myBundle = createTheme();
210
+ * const css = toCssVars(myBundle, { themeId: 'default' }).toCssString();
211
+ * // → base block (all vars) + dark block (only changed vars) + coarse block
212
+ * ```
213
+ */
214
+ const bundleToCssVars = (bundle, options) => {
215
+ const {
216
+ themeId
217
+ } = options;
218
+ const {
219
+ baseMode,
220
+ base: baseTheme,
221
+ alternate
222
+ } = bundle;
223
+ const alternateMode = baseMode === "light" ? "dark" : "light";
224
+ const baseResult = toCssVarsBase(baseTheme, {
225
+ themeId,
226
+ colorScheme: baseMode
227
+ });
228
+ if (!alternate) return {
229
+ base: baseResult,
230
+ toCssString: () => {
231
+ return baseResult.toCssString();
232
+ }
233
+ };
234
+ const alternateTheme = {
235
+ core: baseTheme.core,
236
+ semantic: deepMerge(baseTheme.semantic, alternate.semantic)
237
+ };
238
+ const fullAlternateVars = buildCssVars(alternateTheme);
239
+ const diffVars = diffCssVars({
240
+ base: baseResult.cssVars,
241
+ full: fullAlternateVars
242
+ });
243
+ const alternateSelector = buildSelector({
244
+ themeId,
245
+ mode: alternateMode
246
+ });
247
+ const altCoarseHitVars = {};
248
+ const altReducedMotionVars = diffCssVars({
249
+ base: baseResult.reducedMotionVars,
250
+ full: buildReducedMotionVars(alternateTheme)
251
+ });
252
+ const altContainerQueryVars = extractContainerQueryVars(diffVars);
253
+ const alternateResult = {
254
+ cssVars: diffVars,
255
+ coarseHitVars: altCoarseHitVars,
256
+ reducedMotionVars: altReducedMotionVars,
257
+ containerQueryVars: altContainerQueryVars,
258
+ selector: alternateSelector,
259
+ toCssString: () => {
260
+ return buildCssBlock({
261
+ selector: alternateSelector,
262
+ vars: diffVars,
263
+ containerQueryVars: altContainerQueryVars,
264
+ coarseHitVars: altCoarseHitVars,
265
+ reducedMotionVars: altReducedMotionVars,
266
+ colorScheme: alternateMode
267
+ });
268
+ }
269
+ };
270
+ return {
271
+ base: baseResult,
272
+ alternate: alternateResult,
273
+ toCssString: () => {
274
+ const parts = [baseResult.toCssString()];
275
+ if (Object.keys(diffVars).length > 0) parts.push(alternateResult.toCssString());
276
+ return parts.join("\n\n");
277
+ }
278
+ };
279
+ };
280
+ function toCssVars(input, options) {
281
+ if (isThemeBundle(input)) return bundleToCssVars(input, options ?? {});
282
+ return toCssVarsBase(input, options);
283
+ }
284
+
285
+ //#endregion
286
+ export { toCssVars as n, toCssVarName as t };
@@ -0,0 +1,297 @@
1
+ /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
+ const require_helpers = require('./helpers-4p4-QVt_.cjs');
3
+ const require_tokenRegistry = require('./tokenRegistry-OhaJ9sPJ.cjs');
4
+
5
+ //#region src/roots/toCssVars.ts
6
+ /**
7
+ * Convert a full token path to a CSS custom property name.
8
+ *
9
+ * `core.colors.brand.500` → `--tt-core-colors-brand-500`
10
+ * `semantic.colors.action.primary.background.default` → `--tt-colors-action-primary-background-default`
11
+ */
12
+ const toCssVarName = tokenPath => {
13
+ for (const [prefix, cssPrefix] of require_tokenRegistry.CSS_PATH_PREFIXES) if (tokenPath.startsWith(prefix)) return `${cssPrefix}${tokenPath.slice(prefix.length).replace(/\./g, "-")}`;
14
+ return `--tt-${tokenPath.replace(/\./g, "-")}`;
15
+ };
16
+ /**
17
+ * Replace all embedded `{token.path}` refs inside a raw string with `var(--tt-...)` references.
18
+ *
19
+ * Handles compound semantic values like:
20
+ * `clamp({core.spacing.4}, {core.spacing.6}, {core.spacing.12})`
21
+ * → `clamp(var(--tt-core-spacing-4), var(--tt-core-spacing-6), var(--tt-core-spacing-12))`
22
+ */
23
+ const inlineRefsToVars = value => {
24
+ return value.replace(require_helpers.COMPOUND_REF_RE, (_match, path) => {
25
+ return `var(${toCssVarName(path)})`;
26
+ });
27
+ };
28
+ /**
29
+ * Build a flat CSS custom properties record from a ThemeTokens.
30
+ *
31
+ * Core tokens get raw values. Semantic tokens get `var()` references
32
+ * to preserve the cascade relationship at runtime.
33
+ */
34
+ const buildCssVars = theme => {
35
+ const vars = {};
36
+ const {
37
+ core: coreFlat,
38
+ semantic: semanticFlat
39
+ } = require_helpers.flattenTheme(theme);
40
+ for (const [path, value] of Object.entries(coreFlat)) vars[toCssVarName(path)] = value;
41
+ for (const [path, value] of Object.entries(semanticFlat)) {
42
+ const varName = toCssVarName(path);
43
+ if (typeof value === "string" && value.includes("{")) vars[varName] = inlineRefsToVars(value);else vars[varName] = value;
44
+ }
45
+ return vars;
46
+ };
47
+ const sanitizeId = value => {
48
+ if (!require_helpers.SAFE_ID_RE.test(value)) throw new Error(`Invalid themeId "${value}". Only alphanumeric characters, hyphens, and underscores are allowed.`);
49
+ return value;
50
+ };
51
+ const buildSelector = ({
52
+ themeId,
53
+ mode,
54
+ selector
55
+ }) => {
56
+ if (selector) return selector;
57
+ if (!themeId) return mode ? `:root[data-tt-mode="${mode}"]` : ":root";
58
+ let s = `[data-tt-theme="${sanitizeId(themeId)}"]`;
59
+ if (mode) s += `[data-tt-mode="${mode}"]`;
60
+ return s;
61
+ };
62
+ /** Matches container query length units: cqi, cqb, cqw, cqh, cqmin, cqmax */
63
+ const CQ_UNIT_RE = /cq(?:i|b|w|h|min|max)(?![a-z])/i;
64
+ /** Check if a CSS value contains container query units. */
65
+ const hasCqUnits = value => {
66
+ return typeof value === "string" && CQ_UNIT_RE.test(value);
67
+ };
68
+ /**
69
+ * Replace container query units with viewport-safe equivalents.
70
+ *
71
+ * cqi → vw, cqb → vh, cqw → vw, cqh → vh, cqmin → vmin, cqmax → vmax
72
+ */
73
+ const toViewportFallback = value => {
74
+ return value.replace(/cqmin(?![a-z])/gi, "vmin").replace(/cqmax(?![a-z])/gi, "vmax").replace(/cqi(?![a-z])/gi, "vw").replace(/cqb(?![a-z])/gi, "vh").replace(/cqw(?![a-z])/gi, "vw").replace(/cqh(?![a-z])/gi, "vh");
75
+ };
76
+ /**
77
+ * Extract entries from a CSS vars record whose values contain CQ units.
78
+ */
79
+ const extractContainerQueryVars = vars => {
80
+ const cqVars = {};
81
+ for (const [name, value] of Object.entries(vars)) if (hasCqUnits(value)) cqVars[name] = value;
82
+ return cqVars;
83
+ };
84
+ /**
85
+ * Build CSS vars for reduced-motion overrides.
86
+ *
87
+ * Derives every `*.duration` path from the theme's `semantic.motion` structure,
88
+ * so adding a new motion role never silently omits it from the
89
+ * `@media (prefers-reduced-motion: reduce)` block.
90
+ *
91
+ * Sets all semantic motion duration vars to `var(--tt-core-motion-duration-none)` (0ms).
92
+ * Emitted inside `@media (prefers-reduced-motion: reduce)`.
93
+ */
94
+ const buildReducedMotionVars = theme => {
95
+ const noneVar = `var(${toCssVarName("core.motion.duration.none")})`;
96
+ const flat = require_helpers.flattenObject(theme.semantic.motion, "semantic.motion");
97
+ const vars = {};
98
+ for (const path of Object.keys(flat)) if (path.endsWith(".duration")) vars[toCssVarName(path)] = noneVar;
99
+ return vars;
100
+ };
101
+ /**
102
+ * Build CSS vars for coarse-pointer hit target overrides.
103
+ *
104
+ * The semantic hit tokens default to fine-pointer values. This record
105
+ * contains the coarse overrides, to be emitted inside
106
+ * `@media (any-pointer: coarse)`.
107
+ *
108
+ * Derives every `*.coarse.*` path from `core.sizing.hit.coarse` dynamically,
109
+ * so adding a new step to `CoreSizeHitScale` never silently omits it here.
110
+ */
111
+ const buildCoarseHitVars = theme => {
112
+ const vars = {};
113
+ for (const [key, value] of Object.entries(theme.core.sizing.hit.coarse)) if (typeof value === "string") vars[toCssVarName(`semantic.sizing.hit.${key}`)] = value;
114
+ return vars;
115
+ };
116
+ /**
117
+ * Render a complete scoped CSS block from a vars record.
118
+ *
119
+ * Includes the base selector block, optional CQ `@supports` block,
120
+ * coarse-pointer `@media` block, and reduced-motion `@media` block.
121
+ * This is the single implementation shared by `toCssVars` and `bundleToCssVars`.
122
+ */
123
+ const buildCssBlock = ({
124
+ selector,
125
+ vars,
126
+ containerQueryVars,
127
+ coarseHitVars,
128
+ reducedMotionVars,
129
+ colorScheme
130
+ }) => {
131
+ /** Maps a vars record to indented CSS declaration lines (4-space, for nested at-rule blocks). */
132
+ const varLines = v => {
133
+ return Object.entries(v).map(([name, val]) => {
134
+ return ` ${name}: ${val};`;
135
+ });
136
+ };
137
+ /** Builds a complete at-rule block, or empty string if the vars record is empty. */
138
+ const atRuleBlock = (atRule, v) => {
139
+ const lines = varLines(v);
140
+ return lines.length > 0 ? `${atRule} {\n ${selector} {\n${lines.join("\n")}\n }\n}` : "";
141
+ };
142
+ const baseLines = [];
143
+ if (colorScheme) baseLines.push(` color-scheme: ${colorScheme};`);
144
+ for (const [name, value] of Object.entries(vars)) if (hasCqUnits(value)) baseLines.push(` ${name}: ${toViewportFallback(String(value))};`);else baseLines.push(` ${name}: ${value};`);
145
+ const baseBlock = `${selector} {\n${baseLines.join("\n")}\n}`;
146
+ const cqContent = atRuleBlock("@supports (width: 1cqi)", containerQueryVars);
147
+ const cqBlock = cqContent ? `\n\n${cqContent}` : "";
148
+ const coarseBlock = atRuleBlock("@media (any-pointer: coarse)", coarseHitVars);
149
+ const reducedMotionBlock = atRuleBlock("@media (prefers-reduced-motion: reduce)", reducedMotionVars);
150
+ return [baseBlock + cqBlock, coarseBlock, reducedMotionBlock].filter(Boolean).join("\n\n");
151
+ };
152
+ /**
153
+ * Internal: convert a single `ThemeTokens` into CSS custom properties.
154
+ * Use the public overloaded `toCssVars()` instead.
155
+ */
156
+ const toCssVarsBase = (theme, options = {}) => {
157
+ const cssVars = buildCssVars(theme);
158
+ const coarseHitVars = buildCoarseHitVars(theme);
159
+ const reducedMotionVars = buildReducedMotionVars(theme);
160
+ const containerQueryVars = extractContainerQueryVars(cssVars);
161
+ const selector = buildSelector(options);
162
+ const {
163
+ colorScheme,
164
+ mode
165
+ } = options;
166
+ const effectiveColorScheme = colorScheme ?? mode;
167
+ return {
168
+ cssVars,
169
+ coarseHitVars,
170
+ reducedMotionVars,
171
+ containerQueryVars,
172
+ selector,
173
+ toCssString: () => {
174
+ return buildCssBlock({
175
+ selector,
176
+ vars: cssVars,
177
+ containerQueryVars,
178
+ coarseHitVars,
179
+ reducedMotionVars,
180
+ colorScheme: effectiveColorScheme
181
+ });
182
+ }
183
+ };
184
+ };
185
+ /** Type guard: checks if the input is a ThemeBundle. */
186
+ const isThemeBundle = input => {
187
+ return "baseMode" in input && "base" in input;
188
+ };
189
+ /**
190
+ * Compute a diff record: only entries in `full` whose values differ from `base`.
191
+ */
192
+ const diffCssVars = ({
193
+ base,
194
+ full
195
+ }) => {
196
+ const diff = {};
197
+ for (const [key, value] of Object.entries(full)) if (base[key] !== value) diff[key] = value;
198
+ return diff;
199
+ };
200
+ /**
201
+ * Convert a `ThemeBundle` into scoped CSS custom properties with optimized
202
+ * alternate-mode output (diff-only).
203
+ *
204
+ * @example
205
+ * ```ts
206
+ * import { toCssVars } from '@ttoss/fsl-theme/css';
207
+ * import { createTheme } from '@ttoss/fsl-theme';
208
+ *
209
+ * const myBundle = createTheme();
210
+ * const css = toCssVars(myBundle, { themeId: 'default' }).toCssString();
211
+ * // → base block (all vars) + dark block (only changed vars) + coarse block
212
+ * ```
213
+ */
214
+ const bundleToCssVars = (bundle, options) => {
215
+ const {
216
+ themeId
217
+ } = options;
218
+ const {
219
+ baseMode,
220
+ base: baseTheme,
221
+ alternate
222
+ } = bundle;
223
+ const alternateMode = baseMode === "light" ? "dark" : "light";
224
+ const baseResult = toCssVarsBase(baseTheme, {
225
+ themeId,
226
+ colorScheme: baseMode
227
+ });
228
+ if (!alternate) return {
229
+ base: baseResult,
230
+ toCssString: () => {
231
+ return baseResult.toCssString();
232
+ }
233
+ };
234
+ const alternateTheme = {
235
+ core: baseTheme.core,
236
+ semantic: require_helpers.deepMerge(baseTheme.semantic, alternate.semantic)
237
+ };
238
+ const fullAlternateVars = buildCssVars(alternateTheme);
239
+ const diffVars = diffCssVars({
240
+ base: baseResult.cssVars,
241
+ full: fullAlternateVars
242
+ });
243
+ const alternateSelector = buildSelector({
244
+ themeId,
245
+ mode: alternateMode
246
+ });
247
+ const altCoarseHitVars = {};
248
+ const altReducedMotionVars = diffCssVars({
249
+ base: baseResult.reducedMotionVars,
250
+ full: buildReducedMotionVars(alternateTheme)
251
+ });
252
+ const altContainerQueryVars = extractContainerQueryVars(diffVars);
253
+ const alternateResult = {
254
+ cssVars: diffVars,
255
+ coarseHitVars: altCoarseHitVars,
256
+ reducedMotionVars: altReducedMotionVars,
257
+ containerQueryVars: altContainerQueryVars,
258
+ selector: alternateSelector,
259
+ toCssString: () => {
260
+ return buildCssBlock({
261
+ selector: alternateSelector,
262
+ vars: diffVars,
263
+ containerQueryVars: altContainerQueryVars,
264
+ coarseHitVars: altCoarseHitVars,
265
+ reducedMotionVars: altReducedMotionVars,
266
+ colorScheme: alternateMode
267
+ });
268
+ }
269
+ };
270
+ return {
271
+ base: baseResult,
272
+ alternate: alternateResult,
273
+ toCssString: () => {
274
+ const parts = [baseResult.toCssString()];
275
+ if (Object.keys(diffVars).length > 0) parts.push(alternateResult.toCssString());
276
+ return parts.join("\n\n");
277
+ }
278
+ };
279
+ };
280
+ function toCssVars(input, options) {
281
+ if (isThemeBundle(input)) return bundleToCssVars(input, options ?? {});
282
+ return toCssVarsBase(input, options);
283
+ }
284
+
285
+ //#endregion
286
+ Object.defineProperty(exports, 'toCssVarName', {
287
+ enumerable: true,
288
+ get: function () {
289
+ return toCssVarName;
290
+ }
291
+ });
292
+ Object.defineProperty(exports, 'toCssVars', {
293
+ enumerable: true,
294
+ get: function () {
295
+ return toCssVars;
296
+ }
297
+ });