@ttoss/fsl-theme 1.1.12 → 1.1.14
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/dist/Types-BiBa17RL.d.cts +1427 -0
- package/dist/Types-BiBa17RL.d.mts +1427 -0
- package/dist/baseBundle-DxvXyhGa.mjs +17 -0
- package/dist/baseBundle-iEFf5nqT.cjs +22 -0
- package/dist/{esm/chunk-SE5Z52RE.js → createTheme-BLNYztZU.mjs} +76 -172
- package/dist/createTheme-Cv6RP9D6.cjs +1825 -0
- package/dist/css.cjs +48 -0
- package/dist/{css.d.ts → css.d.cts} +67 -63
- package/dist/css.d.mts +168 -0
- package/dist/css.mjs +42 -0
- package/dist/dataviz/index.cjs +45 -0
- package/dist/dataviz/{index.d.ts → index.d.cts} +9 -5
- package/dist/dataviz/index.d.mts +66 -0
- package/dist/dataviz/index.mjs +39 -0
- package/dist/dtcg.cjs +115 -0
- package/dist/{dtcg.d.ts → dtcg.d.cts} +9 -7
- package/dist/dtcg.d.mts +51 -0
- package/dist/dtcg.mjs +112 -0
- package/dist/helpers-4p4-QVt_.cjs +258 -0
- package/dist/helpers-CaswNJMy.mjs +211 -0
- package/dist/{index.d.ts → index-CsIjfw86.d.cts} +42 -34
- package/dist/index-nJrjI0BA.d.mts +94 -0
- package/dist/index.cjs +16 -0
- package/dist/index.d.cts +6 -0
- package/dist/index.d.mts +6 -0
- package/dist/index.mjs +7 -0
- package/dist/{react.d.ts → react-CGa6FlNL.d.cts} +130 -106
- package/dist/react-DnKxR2gK.d.mts +370 -0
- package/dist/react-EUwpdvY7.cjs +481 -0
- package/dist/react.cjs +12 -0
- package/dist/react.d.cts +4 -0
- package/dist/react.d.mts +4 -0
- package/dist/react.mjs +412 -0
- package/dist/runtime-entry.cjs +9 -0
- package/dist/runtime-entry.d.cts +3 -0
- package/dist/runtime-entry.d.mts +3 -0
- package/dist/runtime-entry.mjs +3 -0
- package/dist/{runtime-entry.d.ts → ssrScript-BVysxDws.d.cts} +26 -23
- package/dist/ssrScript-BVysxDws.d.mts +98 -0
- package/dist/ssrScript-CRfrN8Pm.cjs +202 -0
- package/dist/ssrScript-D3kGPQpi.mjs +179 -0
- package/dist/themes/bruttal.cjs +75 -0
- package/dist/themes/bruttal.d.cts +3 -0
- package/dist/themes/bruttal.d.mts +3 -0
- package/dist/themes/bruttal.mjs +72 -0
- package/dist/themes/corporate.cjs +34 -0
- package/dist/themes/corporate.d.cts +3 -0
- package/dist/themes/corporate.d.mts +3 -0
- package/dist/{esm/chunk-TPMN75JM.js → themes/corporate.mjs} +7 -5
- package/dist/themes/oca.cjs +34 -0
- package/dist/themes/oca.d.cts +3 -0
- package/dist/themes/oca.d.mts +3 -0
- package/dist/{esm/chunk-DU4QDQUC.js → themes/oca.mjs} +7 -5
- package/dist/themes/ventures.cjs +34 -0
- package/dist/themes/ventures.d.cts +3 -0
- package/dist/themes/ventures.d.mts +3 -0
- package/dist/{esm/chunk-BXKVVQEP.js → themes/ventures.mjs} +7 -5
- package/dist/toCssVars-CYZCe-on.mjs +286 -0
- package/dist/toCssVars-DudHKvt2.cjs +297 -0
- package/dist/{esm/chunk-4Q4P3JBB.js → tokenRegistry-DjgSN3oU.mjs} +23 -20
- package/dist/tokenRegistry-OhaJ9sPJ.cjs +199 -0
- package/dist/vars.cjs +127 -0
- package/dist/{vars.d.ts → vars.d.cts} +8 -7
- package/dist/vars.d.mts +128 -0
- package/dist/vars.mjs +123 -0
- package/dist/withDataviz-B4pVsOwV.cjs +192 -0
- package/dist/{esm/chunk-FBVUI2PK.js → withDataviz-DY5s7R51.mjs} +40 -12
- package/package.json +6 -6
- package/dist/Types-6tR0_2Ss.d.ts +0 -1452
- package/dist/esm/chunk-5PWPAQMC.js +0 -9
- package/dist/esm/chunk-HRNXVRS3.js +0 -54
- package/dist/esm/chunk-IJGA42O6.js +0 -141
- package/dist/esm/chunk-PQPQNZ73.js +0 -262
- package/dist/esm/chunk-UMRQ4OTX.js +0 -11
- package/dist/esm/chunk-VL6EGE6Z.js +0 -222
- package/dist/esm/chunk-WVQSTQD5.js +0 -192
- package/dist/esm/css.js +0 -6
- package/dist/esm/dataviz/index.js +0 -19
- package/dist/esm/dtcg.js +0 -65
- package/dist/esm/index.js +0 -10
- package/dist/esm/react.js +0 -8
- package/dist/esm/runtime-entry.js +0 -4
- package/dist/esm/themes/bruttal.js +0 -6
- package/dist/esm/themes/corporate.js +0 -6
- package/dist/esm/themes/oca.js +0 -6
- package/dist/esm/themes/ventures.js +0 -6
- package/dist/esm/vars.js +0 -28
- package/dist/themes/bruttal.d.ts +0 -5
- package/dist/themes/corporate.d.ts +0 -5
- package/dist/themes/oca.d.ts +0 -5
- 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;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { n as createTheme } from "../createTheme-BLNYztZU.mjs";
|
|
3
|
+
import { t as withDataviz } from "../withDataviz-DY5s7R51.mjs";
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
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
|
-
|
|
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
|
+
});
|