@servicetitan/hammer-token 0.0.0-rc-1.47.0-20251104205759 → 0.0.0-rc-3.0.0-20260114215531
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -1
- package/README.md +222 -0
- package/build/web/core/component-variables.scss +114 -130
- package/build/web/core/component.d.ts +65 -0
- package/build/web/core/component.js +248 -267
- package/build/web/core/component.scss +63 -69
- package/build/web/core/css-utils/a2-border.css +39 -41
- package/build/web/core/css-utils/a2-color.css +351 -227
- package/build/web/core/css-utils/a2-font.css +0 -2
- package/build/web/core/css-utils/a2-spacing.css +0 -2
- package/build/web/core/css-utils/a2-utils.css +418 -292
- package/build/web/core/css-utils/border.css +39 -41
- package/build/web/core/css-utils/color.css +351 -227
- package/build/web/core/css-utils/font.css +0 -2
- package/build/web/core/css-utils/spacing.css +0 -2
- package/build/web/core/css-utils/utils.css +418 -292
- package/build/web/core/index.d.ts +6 -0
- package/build/web/core/index.js +1 -1
- package/build/web/core/primitive-variables.scss +130 -71
- package/build/web/core/primitive.d.ts +185 -0
- package/build/web/core/primitive.js +328 -72
- package/build/web/core/primitive.scss +183 -124
- package/build/web/core/semantic-variables.scss +287 -220
- package/build/web/core/semantic.d.ts +194 -0
- package/build/web/core/semantic.js +875 -347
- package/build/web/core/semantic.scss +192 -140
- package/build/web/index.d.ts +3 -4
- package/build/web/index.js +0 -1
- package/build/web/types.d.ts +17 -0
- package/config.js +121 -496
- package/package.json +5 -4
- package/src/global/primitive/breakpoint.tokens.json +39 -0
- package/src/global/primitive/color.tokens.json +536 -0
- package/src/global/primitive/duration.tokens.json +32 -0
- package/src/global/primitive/font.tokens.json +103 -0
- package/src/global/primitive/radius.tokens.json +67 -0
- package/src/global/primitive/size.tokens.json +123 -0
- package/src/global/primitive/transition.tokens.json +20 -0
- package/src/theme/core/background.tokens.json +981 -0
- package/src/theme/core/border.tokens.json +148 -0
- package/src/theme/core/charts.tokens.json +802 -0
- package/src/theme/core/component/button.tokens.json +752 -0
- package/src/theme/core/component/checkbox.tokens.json +292 -0
- package/src/theme/core/focus.tokens.json +48 -0
- package/src/theme/core/foreground.tokens.json +288 -0
- package/src/theme/core/shadow.tokens.json +43 -0
- package/src/theme/core/status.tokens.json +70 -0
- package/src/theme/core/typography.tokens.json +100 -0
- package/src/utils/copy-css-utils-cli.js +13 -0
- package/src/utils/css-utils-format-utils.js +98 -1
- package/src/utils/sd-build-configs.js +372 -0
- package/src/utils/sd-formats.js +752 -0
- package/src/utils/sd-transforms.js +126 -0
- package/src/utils/token-helpers.js +555 -0
- package/tsconfig.json +18 -0
- package/.turbo/turbo-build.log +0 -37
- package/build/web/core/raw.js +0 -234
- package/src/global/primitive/breakpoint.js +0 -19
- package/src/global/primitive/color.js +0 -231
- package/src/global/primitive/duration.js +0 -16
- package/src/global/primitive/font.js +0 -60
- package/src/global/primitive/radius.js +0 -31
- package/src/global/primitive/size.js +0 -55
- package/src/global/primitive/transition.js +0 -16
- package/src/theme/core/background.js +0 -170
- package/src/theme/core/border.js +0 -103
- package/src/theme/core/charts.js +0 -464
- package/src/theme/core/component/button.js +0 -708
- package/src/theme/core/component/checkbox.js +0 -405
- package/src/theme/core/focus.js +0 -35
- package/src/theme/core/foreground.js +0 -148
- package/src/theme/core/overlay.js +0 -137
- package/src/theme/core/shadow.js +0 -29
- package/src/theme/core/status.js +0 -49
- package/src/theme/core/typography.js +0 -82
- package/type/types.ts +0 -344
|
@@ -0,0 +1,752 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-require-imports */
|
|
2
|
+
/**
|
|
3
|
+
* Style Dictionary format registrations
|
|
4
|
+
* @module sd-formats
|
|
5
|
+
*/
|
|
6
|
+
const {
|
|
7
|
+
generateBorderClasses,
|
|
8
|
+
generateColorClasses,
|
|
9
|
+
generateFontClasses,
|
|
10
|
+
generateSpacingClasses,
|
|
11
|
+
} = require("./css-utils-format-utils");
|
|
12
|
+
const {
|
|
13
|
+
getTokenName,
|
|
14
|
+
getTokenType,
|
|
15
|
+
getDtcgValue,
|
|
16
|
+
getDarkValue,
|
|
17
|
+
hasDarkValue,
|
|
18
|
+
isCompositeColor,
|
|
19
|
+
isDimensionValue,
|
|
20
|
+
getTokenValue,
|
|
21
|
+
buildTokenMap,
|
|
22
|
+
buildFallbackWithRefs,
|
|
23
|
+
} = require("./token-helpers");
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Builds the CSS utils output string with layer declarations and @supports blocks.
|
|
27
|
+
* Creates a structured CSS output with fallback classes and dark-aware variants.
|
|
28
|
+
* @param {string} fallback - The fallback CSS classes (light mode only)
|
|
29
|
+
* @param {string} [darkAwareClasses=''] - The dark-aware CSS classes with light-dark()
|
|
30
|
+
* @returns {string} The complete CSS output with layer and @supports structure
|
|
31
|
+
*/
|
|
32
|
+
const buildCssUtilsOutput = (fallback, darkAwareClasses = "") => {
|
|
33
|
+
const supportsBlock = darkAwareClasses
|
|
34
|
+
? `\n@supports (color: light-dark(#fff, #000)) {\n ${darkAwareClasses.replaceAll("\n", "\n ")}\n}`
|
|
35
|
+
: "";
|
|
36
|
+
const supportsBlockNested = darkAwareClasses
|
|
37
|
+
? `\n @supports (color: light-dark(#fff, #000)) {\n ${darkAwareClasses.replaceAll("\n", "\n ")}\n }`
|
|
38
|
+
: "";
|
|
39
|
+
|
|
40
|
+
return `@layer starter, reset, base, state, application;
|
|
41
|
+
|
|
42
|
+
${fallback}${supportsBlock}
|
|
43
|
+
|
|
44
|
+
@layer application {
|
|
45
|
+
${fallback.replaceAll("\n", "\n ")}${supportsBlockNested}
|
|
46
|
+
}`;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Registers CSS utility class formats for a given class prefix.
|
|
51
|
+
* Creates format registrations for: All utils, Borders, Colors, Fonts, and Spacing.
|
|
52
|
+
* Each format generates CSS utility classes with CSS variable fallbacks and light-dark() support.
|
|
53
|
+
* @param {import('style-dictionary').default} StyleDictionary - The Style Dictionary class instance
|
|
54
|
+
* @param {string} prefix - CSS class prefix (e.g., '' or 'a2-')
|
|
55
|
+
* @param {Function} usesReferences - Function to check if a value uses references
|
|
56
|
+
* @param {Function} resolveReferences - Function to resolve references
|
|
57
|
+
* @param {string} [cssVarPrefix=''] - Prefix for CSS variable names (e.g., 'a2-')
|
|
58
|
+
* @returns {void}
|
|
59
|
+
*/
|
|
60
|
+
const registerCssUtilsFormats = (
|
|
61
|
+
StyleDictionary,
|
|
62
|
+
prefix,
|
|
63
|
+
usesReferences,
|
|
64
|
+
resolveReferences,
|
|
65
|
+
cssVarPrefix = "",
|
|
66
|
+
) => {
|
|
67
|
+
/**
|
|
68
|
+
* Format: custom/CSSUtils/{prefix}All
|
|
69
|
+
* Generates all CSS utility classes including colors, borders, typography, and spacing.
|
|
70
|
+
*/
|
|
71
|
+
StyleDictionary.registerFormat({
|
|
72
|
+
name: `custom/CSSUtils/${prefix}All`,
|
|
73
|
+
format: ({ dictionary }) => {
|
|
74
|
+
const allTokens = dictionary.allTokens || [];
|
|
75
|
+
// Build token map once for O(1) lookups
|
|
76
|
+
const tokenMap = buildTokenMap(dictionary);
|
|
77
|
+
|
|
78
|
+
// Dark-aware color tokens with recursive var chain and light-dark at primitive level
|
|
79
|
+
const colorTokens = allTokens
|
|
80
|
+
.filter(hasDarkValue) // Only tokens with dark values for @supports block
|
|
81
|
+
.map((token) => {
|
|
82
|
+
const name = getTokenName(token).replace("Default", "");
|
|
83
|
+
// Use useLightDark to get: light-dark(var(--light-ref, #hex), var(--dark-ref, #hex))
|
|
84
|
+
const value = buildFallbackWithRefs(
|
|
85
|
+
token,
|
|
86
|
+
dictionary,
|
|
87
|
+
tokenMap,
|
|
88
|
+
{ useLightDark: true, cssVarPrefix },
|
|
89
|
+
usesReferences,
|
|
90
|
+
resolveReferences,
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
if (
|
|
94
|
+
name.startsWith("status-color") ||
|
|
95
|
+
name.startsWith("foreground-color") ||
|
|
96
|
+
name.startsWith("background-color") ||
|
|
97
|
+
name.startsWith("overlay-color")
|
|
98
|
+
) {
|
|
99
|
+
return generateColorClasses(name, value, { prefix });
|
|
100
|
+
}
|
|
101
|
+
if (name.startsWith("border-color")) {
|
|
102
|
+
return generateBorderClasses(name, value, { prefix });
|
|
103
|
+
}
|
|
104
|
+
return null;
|
|
105
|
+
})
|
|
106
|
+
.flat()
|
|
107
|
+
.filter((t) => t != null)
|
|
108
|
+
.sort((a, b) => a.localeCompare(b))
|
|
109
|
+
.join("\n");
|
|
110
|
+
|
|
111
|
+
// Non-color tokens (border radius/width, typography, spacing) with recursive var chain
|
|
112
|
+
const nonColorTokens = allTokens
|
|
113
|
+
.map((token) => {
|
|
114
|
+
const value = buildFallbackWithRefs(
|
|
115
|
+
token,
|
|
116
|
+
dictionary,
|
|
117
|
+
tokenMap,
|
|
118
|
+
{ isDark: false, cssVarPrefix },
|
|
119
|
+
usesReferences,
|
|
120
|
+
resolveReferences,
|
|
121
|
+
);
|
|
122
|
+
const name = getTokenName(token).replace("Default", "");
|
|
123
|
+
|
|
124
|
+
if (name.startsWith("border")) {
|
|
125
|
+
return generateBorderClasses(name, value, { prefix });
|
|
126
|
+
}
|
|
127
|
+
if (name.startsWith("typography")) {
|
|
128
|
+
return generateFontClasses(name, value, { prefix });
|
|
129
|
+
}
|
|
130
|
+
if (name.startsWith("size")) {
|
|
131
|
+
return generateSpacingClasses(name, value, { prefix });
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
})
|
|
135
|
+
.flat()
|
|
136
|
+
.filter((t) => t != null)
|
|
137
|
+
.sort((a, b) => a.localeCompare(b))
|
|
138
|
+
.join("\n");
|
|
139
|
+
|
|
140
|
+
// Fallback color tokens (light values only, with recursive var chain)
|
|
141
|
+
const colorFallbackTokens = allTokens
|
|
142
|
+
.map((token) => {
|
|
143
|
+
const value = buildFallbackWithRefs(
|
|
144
|
+
token,
|
|
145
|
+
dictionary,
|
|
146
|
+
tokenMap,
|
|
147
|
+
{ isDark: false, cssVarPrefix },
|
|
148
|
+
usesReferences,
|
|
149
|
+
resolveReferences,
|
|
150
|
+
);
|
|
151
|
+
const name = getTokenName(token).replace("Default", "");
|
|
152
|
+
|
|
153
|
+
if (
|
|
154
|
+
name.startsWith("status-color") ||
|
|
155
|
+
name.startsWith("foreground-color") ||
|
|
156
|
+
name.startsWith("background-color") ||
|
|
157
|
+
name.startsWith("overlay-color")
|
|
158
|
+
) {
|
|
159
|
+
return generateColorClasses(name, value, { prefix });
|
|
160
|
+
}
|
|
161
|
+
if (name.startsWith("border-color")) {
|
|
162
|
+
return generateBorderClasses(name, value, { prefix });
|
|
163
|
+
}
|
|
164
|
+
return null;
|
|
165
|
+
})
|
|
166
|
+
.flat()
|
|
167
|
+
.filter((t) => t != null)
|
|
168
|
+
.sort((a, b) => a.localeCompare(b))
|
|
169
|
+
.join("\n");
|
|
170
|
+
|
|
171
|
+
const withSr = nonColorTokens.concat(
|
|
172
|
+
"\n",
|
|
173
|
+
".sr-only {border: 0; clip: rect(0, 0, 0, 0); height: 1px; margin: -1px; overflow: hidden; padding-block: 0; padding-inline: 0; position: absolute; white-space: nowrap; width: 1px;}",
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
return `@layer starter, reset, base, state, application;
|
|
177
|
+
|
|
178
|
+
${withSr}
|
|
179
|
+
${colorFallbackTokens}
|
|
180
|
+
|
|
181
|
+
@supports (color: light-dark(#fff, #000)) {
|
|
182
|
+
${colorTokens.replaceAll("\n", "\n ")}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
@layer application {
|
|
186
|
+
${withSr.replaceAll("\n", "\n ")}
|
|
187
|
+
${colorFallbackTokens.replaceAll("\n", "\n ")}
|
|
188
|
+
|
|
189
|
+
@supports (color: light-dark(#fff, #000)) {
|
|
190
|
+
${colorTokens.replaceAll("\n", "\n ")}
|
|
191
|
+
}
|
|
192
|
+
}`;
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Format: custom/CSSUtils/{prefix}Borders
|
|
198
|
+
* Generates CSS utility classes for border tokens (radius, width, color).
|
|
199
|
+
*/
|
|
200
|
+
StyleDictionary.registerFormat({
|
|
201
|
+
name: `custom/CSSUtils/${prefix}Borders`,
|
|
202
|
+
format: ({ dictionary }) => {
|
|
203
|
+
const allTokens = dictionary.allTokens || [];
|
|
204
|
+
// Build token map once for O(1) lookups
|
|
205
|
+
const tokenMap = buildTokenMap(dictionary);
|
|
206
|
+
|
|
207
|
+
// Dark-aware classes with light-dark() for @supports block
|
|
208
|
+
// Uses recursive var chain with light-dark at primitive level
|
|
209
|
+
const darkAwareClasses = allTokens
|
|
210
|
+
.filter((token) => {
|
|
211
|
+
const name = getTokenName(token);
|
|
212
|
+
return name.includes("color") && name.includes("border");
|
|
213
|
+
})
|
|
214
|
+
.filter(hasDarkValue) // Only tokens with dark values
|
|
215
|
+
.map((token) => {
|
|
216
|
+
// Use useLightDark to get: light-dark(var(--light-ref, #hex), var(--dark-ref, #hex))
|
|
217
|
+
const value = buildFallbackWithRefs(
|
|
218
|
+
token,
|
|
219
|
+
dictionary,
|
|
220
|
+
tokenMap,
|
|
221
|
+
{ useLightDark: true, cssVarPrefix },
|
|
222
|
+
usesReferences,
|
|
223
|
+
resolveReferences,
|
|
224
|
+
);
|
|
225
|
+
const name = getTokenName(token).replace("Default", "");
|
|
226
|
+
// Pass value directly - it already contains light-dark()
|
|
227
|
+
return generateBorderClasses(name, value, { prefix });
|
|
228
|
+
})
|
|
229
|
+
.flat()
|
|
230
|
+
.sort((a, b) => a.localeCompare(b))
|
|
231
|
+
.join("\n");
|
|
232
|
+
|
|
233
|
+
// Fallback classes (light values only, with recursive var chain)
|
|
234
|
+
const fallback = allTokens
|
|
235
|
+
.filter((token) => getTokenName(token).startsWith("border"))
|
|
236
|
+
.map((token) => {
|
|
237
|
+
const value = buildFallbackWithRefs(
|
|
238
|
+
token,
|
|
239
|
+
dictionary,
|
|
240
|
+
tokenMap,
|
|
241
|
+
{ isDark: false, cssVarPrefix },
|
|
242
|
+
usesReferences,
|
|
243
|
+
resolveReferences,
|
|
244
|
+
);
|
|
245
|
+
const name = getTokenName(token).replace("Default", "");
|
|
246
|
+
return generateBorderClasses(name, value, { prefix });
|
|
247
|
+
})
|
|
248
|
+
.flat()
|
|
249
|
+
.sort((a, b) => a.localeCompare(b))
|
|
250
|
+
.join("\n");
|
|
251
|
+
|
|
252
|
+
return buildCssUtilsOutput(fallback, darkAwareClasses);
|
|
253
|
+
},
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Format: custom/CSSUtils/{prefix}Colors
|
|
258
|
+
* Generates CSS utility classes for color tokens (background, foreground, status, overlay).
|
|
259
|
+
*/
|
|
260
|
+
StyleDictionary.registerFormat({
|
|
261
|
+
name: `custom/CSSUtils/${prefix}Colors`,
|
|
262
|
+
format: ({ dictionary }) => {
|
|
263
|
+
const allTokens = dictionary.allTokens || [];
|
|
264
|
+
// Build token map once for O(1) lookups
|
|
265
|
+
const tokenMap = buildTokenMap(dictionary);
|
|
266
|
+
|
|
267
|
+
// Dark-aware classes with recursive var chain and light-dark at primitive level
|
|
268
|
+
const result = allTokens
|
|
269
|
+
.filter((token) => getTokenName(token).includes("color"))
|
|
270
|
+
.filter(hasDarkValue) // Only tokens with dark values for @supports block
|
|
271
|
+
.map((token) => {
|
|
272
|
+
// Use useLightDark to get: light-dark(var(--light-ref, #hex), var(--dark-ref, #hex))
|
|
273
|
+
const value = buildFallbackWithRefs(
|
|
274
|
+
token,
|
|
275
|
+
dictionary,
|
|
276
|
+
tokenMap,
|
|
277
|
+
{ useLightDark: true, cssVarPrefix },
|
|
278
|
+
usesReferences,
|
|
279
|
+
resolveReferences,
|
|
280
|
+
);
|
|
281
|
+
const name = getTokenName(token).replace("Default", "");
|
|
282
|
+
// Pass value directly - it already contains light-dark()
|
|
283
|
+
return generateColorClasses(name, value, { prefix });
|
|
284
|
+
})
|
|
285
|
+
.flat()
|
|
286
|
+
.filter(Boolean)
|
|
287
|
+
.sort((a, b) => a.localeCompare(b))
|
|
288
|
+
.join("\n");
|
|
289
|
+
|
|
290
|
+
// Fallback classes (light values only, with recursive var chain)
|
|
291
|
+
const fallback = allTokens
|
|
292
|
+
.map((token) => {
|
|
293
|
+
const value = buildFallbackWithRefs(
|
|
294
|
+
token,
|
|
295
|
+
dictionary,
|
|
296
|
+
tokenMap,
|
|
297
|
+
{ isDark: false, cssVarPrefix },
|
|
298
|
+
usesReferences,
|
|
299
|
+
resolveReferences,
|
|
300
|
+
);
|
|
301
|
+
const name = getTokenName(token).replace("Default", "");
|
|
302
|
+
return generateColorClasses(name, value, { prefix });
|
|
303
|
+
})
|
|
304
|
+
.flat()
|
|
305
|
+
.filter(Boolean)
|
|
306
|
+
.sort((a, b) => a.localeCompare(b))
|
|
307
|
+
.join("\n");
|
|
308
|
+
|
|
309
|
+
return buildCssUtilsOutput(fallback, result);
|
|
310
|
+
},
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Format: custom/CSSUtils/{prefix}Fonts
|
|
315
|
+
* Generates CSS utility classes for typography tokens (font-family, font-weight, font-size).
|
|
316
|
+
*/
|
|
317
|
+
StyleDictionary.registerFormat({
|
|
318
|
+
name: `custom/CSSUtils/${prefix}Fonts`,
|
|
319
|
+
format: ({ dictionary }) => {
|
|
320
|
+
const fallback = (dictionary.allTokens || [])
|
|
321
|
+
.map((token) => {
|
|
322
|
+
const value = getTokenValue(token, dictionary, {}, resolveReferences);
|
|
323
|
+
const name = getTokenName(token).replace("Default", "");
|
|
324
|
+
return generateFontClasses(name, value, { prefix });
|
|
325
|
+
})
|
|
326
|
+
.flat()
|
|
327
|
+
.filter(Boolean)
|
|
328
|
+
.sort((a, b) => a.localeCompare(b))
|
|
329
|
+
.join("\n");
|
|
330
|
+
|
|
331
|
+
return buildCssUtilsOutput(fallback);
|
|
332
|
+
},
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Format: custom/CSSUtils/{prefix}Spacing
|
|
337
|
+
* Generates CSS utility classes for spacing/size tokens (margin, padding).
|
|
338
|
+
*/
|
|
339
|
+
StyleDictionary.registerFormat({
|
|
340
|
+
name: `custom/CSSUtils/${prefix}Spacing`,
|
|
341
|
+
format: ({ dictionary }) => {
|
|
342
|
+
const fallback = (dictionary.allTokens || [])
|
|
343
|
+
.filter((token) => getTokenName(token).startsWith("size"))
|
|
344
|
+
.map((token) => {
|
|
345
|
+
const value = getTokenValue(token, dictionary, {}, resolveReferences);
|
|
346
|
+
const name = getTokenName(token).replace("Default", "");
|
|
347
|
+
return generateSpacingClasses(name, value, { prefix });
|
|
348
|
+
})
|
|
349
|
+
.flat()
|
|
350
|
+
.filter(Boolean)
|
|
351
|
+
.sort((a, b) => a.localeCompare(b))
|
|
352
|
+
.join("\n");
|
|
353
|
+
|
|
354
|
+
return buildCssUtilsOutput(fallback);
|
|
355
|
+
},
|
|
356
|
+
});
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Registers all custom Style Dictionary formats including SCSS variables, ES6 exports,
|
|
361
|
+
* CSS variables, and CSS utility classes.
|
|
362
|
+
* @param {import('style-dictionary').default} StyleDictionary - The Style Dictionary class instance
|
|
363
|
+
* @param {Function} usesReferences - Function to check if a value uses references
|
|
364
|
+
* @param {Function} resolveReferences - Function to resolve references
|
|
365
|
+
* @param {string} [cssVarPrefix=''] - Prefix for CSS variable names (e.g., 'a2-')
|
|
366
|
+
* @returns {void}
|
|
367
|
+
* @example
|
|
368
|
+
* const StyleDictionary = require('style-dictionary');
|
|
369
|
+
* registerFormats(StyleDictionary, usesReferences, resolveReferences, 'a2-');
|
|
370
|
+
*/
|
|
371
|
+
const registerFormats = (
|
|
372
|
+
StyleDictionary,
|
|
373
|
+
usesReferences,
|
|
374
|
+
resolveReferences,
|
|
375
|
+
cssVarPrefix = "",
|
|
376
|
+
) => {
|
|
377
|
+
/**
|
|
378
|
+
* Format: custom/scss-variables
|
|
379
|
+
* Generates SCSS variables with CSS var() fallbacks and light-dark() support.
|
|
380
|
+
* Output format: $var: var(--var, value);
|
|
381
|
+
*/
|
|
382
|
+
StyleDictionary.registerFormat({
|
|
383
|
+
name: "custom/scss-variables",
|
|
384
|
+
format: ({ dictionary }) => {
|
|
385
|
+
// Build token lookup map once for O(1) lookups
|
|
386
|
+
const tokensByName = buildTokenMap(dictionary);
|
|
387
|
+
|
|
388
|
+
return dictionary.allTokens
|
|
389
|
+
.map((token) => {
|
|
390
|
+
const name = getTokenName(token);
|
|
391
|
+
|
|
392
|
+
// Special handling for overlay-color (no CSS variable)
|
|
393
|
+
if (name.startsWith("overlay-color")) {
|
|
394
|
+
return `$${name}: ${getTokenValue(token, dictionary, {}, resolveReferences)};`;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Build fallback with light-dark() at the level where values differ
|
|
398
|
+
const fallback = buildFallbackWithRefs(
|
|
399
|
+
token,
|
|
400
|
+
dictionary,
|
|
401
|
+
tokensByName,
|
|
402
|
+
{ useLightDark: true, cssVarPrefix },
|
|
403
|
+
usesReferences,
|
|
404
|
+
resolveReferences,
|
|
405
|
+
);
|
|
406
|
+
return `$${name}: var(--${cssVarPrefix}${name}, ${fallback});`;
|
|
407
|
+
})
|
|
408
|
+
.join("\n");
|
|
409
|
+
},
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Format: custom/scss-variables-map
|
|
414
|
+
* Generates SCSS variable maps for both primitive and semantic tokens.
|
|
415
|
+
* Creates separate $light, $dark, and $nonColor maps for tokens with appearance variants.
|
|
416
|
+
*/
|
|
417
|
+
StyleDictionary.registerFormat({
|
|
418
|
+
name: "custom/scss-variables-map",
|
|
419
|
+
format: ({ dictionary, file }) => {
|
|
420
|
+
const allTokens = dictionary.allTokens || [];
|
|
421
|
+
const hasAppearanceVariants = allTokens.some(hasDarkValue);
|
|
422
|
+
|
|
423
|
+
// Check if this is for component tokens - they need only the final primitive reference
|
|
424
|
+
const isComponentBuild = file.destination?.includes("component");
|
|
425
|
+
|
|
426
|
+
// Build token lookup map once for O(1) lookups
|
|
427
|
+
const tokensByName = buildTokenMap(dictionary);
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Builds a nested CSS var chain, skipping tokens with $extensions.appearance or from component folder.
|
|
431
|
+
* @param {Object} token - The token object
|
|
432
|
+
* @param {boolean} [isDark=false] - Whether to get dark mode value
|
|
433
|
+
* @param {string} [prefix=cssVarPrefix] - CSS variable prefix
|
|
434
|
+
* @returns {string} The CSS var chain
|
|
435
|
+
* @example
|
|
436
|
+
* // Returns: var(--a2-border-radius-medium, var(--a2-radius-2, 0.375rem))
|
|
437
|
+
*/
|
|
438
|
+
const getNoLightDarkRef = (
|
|
439
|
+
token,
|
|
440
|
+
isDark = false,
|
|
441
|
+
prefix = cssVarPrefix,
|
|
442
|
+
) => {
|
|
443
|
+
/**
|
|
444
|
+
* Recursively builds the var chain for a token and its references.
|
|
445
|
+
* @param {Object} currentToken - The current token being processed
|
|
446
|
+
* @param {Set<string>} [visited=new Set()] - Set of visited token names to prevent cycles
|
|
447
|
+
* @param {boolean} [isFirst=true] - Whether this is the first token in the chain
|
|
448
|
+
* @returns {string} The CSS var chain
|
|
449
|
+
*/
|
|
450
|
+
const buildChain = (
|
|
451
|
+
currentToken,
|
|
452
|
+
visited = new Set(),
|
|
453
|
+
isFirst = true,
|
|
454
|
+
) => {
|
|
455
|
+
const tokenName = getTokenName(currentToken);
|
|
456
|
+
if (visited.has(tokenName)) {
|
|
457
|
+
return getTokenValue(
|
|
458
|
+
currentToken,
|
|
459
|
+
dictionary,
|
|
460
|
+
{ isDark, forScssMap: true },
|
|
461
|
+
resolveReferences,
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
visited.add(tokenName);
|
|
465
|
+
|
|
466
|
+
// Check if this token should be skipped in the chain
|
|
467
|
+
const hasAppearance =
|
|
468
|
+
currentToken.original?.$extensions?.appearance !== undefined ||
|
|
469
|
+
currentToken.$extensions?.appearance !== undefined;
|
|
470
|
+
const isComponentToken =
|
|
471
|
+
currentToken.filePath?.includes("/component/");
|
|
472
|
+
const shouldSkip = hasAppearance || (isFirst && isComponentToken);
|
|
473
|
+
|
|
474
|
+
// Get the value (considering light/dark mode)
|
|
475
|
+
const valueToFollow = isDark
|
|
476
|
+
? (currentToken.original?.$extensions?.appearance?.dark?.$value ??
|
|
477
|
+
currentToken.original?.$value ??
|
|
478
|
+
getDtcgValue(currentToken))
|
|
479
|
+
: (currentToken.original?.$extensions?.appearance?.light?.$value ??
|
|
480
|
+
currentToken.original?.$value ??
|
|
481
|
+
getDtcgValue(currentToken));
|
|
482
|
+
|
|
483
|
+
// If value is a reference, try to follow it
|
|
484
|
+
if (
|
|
485
|
+
typeof valueToFollow === "string" &&
|
|
486
|
+
valueToFollow.includes("{")
|
|
487
|
+
) {
|
|
488
|
+
const match = valueToFollow.match(/\{([^{}]+)\}/);
|
|
489
|
+
if (match) {
|
|
490
|
+
const refPath = match[1];
|
|
491
|
+
const refToken = tokensByName.get(refPath.replace(/\./g, "-"));
|
|
492
|
+
if (refToken) {
|
|
493
|
+
// Recursively build the chain for the referenced token
|
|
494
|
+
const innerChain = buildChain(refToken, visited, false);
|
|
495
|
+
|
|
496
|
+
// Skip this token in the chain if it has appearance or is component
|
|
497
|
+
if (shouldSkip) {
|
|
498
|
+
return innerChain;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Include this token in the chain
|
|
502
|
+
return `var(--${prefix}${tokenName}, ${innerChain})`;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// No reference or can't follow - this is the final value
|
|
508
|
+
if (shouldSkip) {
|
|
509
|
+
return getTokenValue(
|
|
510
|
+
currentToken,
|
|
511
|
+
dictionary,
|
|
512
|
+
{ isDark, forScssMap: true },
|
|
513
|
+
resolveReferences,
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// Include in chain with final value
|
|
518
|
+
const finalValue = getTokenValue(
|
|
519
|
+
currentToken,
|
|
520
|
+
dictionary,
|
|
521
|
+
{ isDark, forScssMap: true },
|
|
522
|
+
resolveReferences,
|
|
523
|
+
);
|
|
524
|
+
return `var(--${prefix}${tokenName}, ${finalValue})`;
|
|
525
|
+
};
|
|
526
|
+
|
|
527
|
+
return buildChain(token);
|
|
528
|
+
};
|
|
529
|
+
|
|
530
|
+
if (hasAppearanceVariants) {
|
|
531
|
+
/**
|
|
532
|
+
* Checks if a token is a color type token.
|
|
533
|
+
* @param {Object} token - The token object
|
|
534
|
+
* @returns {boolean} True if the token is a color type
|
|
535
|
+
*/
|
|
536
|
+
const isColorToken = (token) => getTokenType(token) === "color";
|
|
537
|
+
|
|
538
|
+
const light = allTokens
|
|
539
|
+
.filter(isColorToken)
|
|
540
|
+
.map((token) => {
|
|
541
|
+
const name = getTokenName(token);
|
|
542
|
+
// For components, get innermost var; for semantic, get full fallback chain
|
|
543
|
+
const fallback = isComponentBuild
|
|
544
|
+
? getNoLightDarkRef(token, false)
|
|
545
|
+
: buildFallbackWithRefs(
|
|
546
|
+
token,
|
|
547
|
+
dictionary,
|
|
548
|
+
tokensByName,
|
|
549
|
+
{
|
|
550
|
+
useLightDark: false,
|
|
551
|
+
isDark: false,
|
|
552
|
+
cssVarPrefix,
|
|
553
|
+
forScssMap: true,
|
|
554
|
+
},
|
|
555
|
+
usesReferences,
|
|
556
|
+
resolveReferences,
|
|
557
|
+
);
|
|
558
|
+
return ` ${name}: ${fallback},`;
|
|
559
|
+
})
|
|
560
|
+
.join("\n");
|
|
561
|
+
|
|
562
|
+
const dark = allTokens
|
|
563
|
+
.filter(isColorToken)
|
|
564
|
+
.map((token) => {
|
|
565
|
+
const name = getTokenName(token);
|
|
566
|
+
const fallback = isComponentBuild
|
|
567
|
+
? getNoLightDarkRef(token, true)
|
|
568
|
+
: buildFallbackWithRefs(
|
|
569
|
+
token,
|
|
570
|
+
dictionary,
|
|
571
|
+
tokensByName,
|
|
572
|
+
{
|
|
573
|
+
useLightDark: false,
|
|
574
|
+
isDark: true,
|
|
575
|
+
cssVarPrefix,
|
|
576
|
+
forScssMap: true,
|
|
577
|
+
},
|
|
578
|
+
usesReferences,
|
|
579
|
+
resolveReferences,
|
|
580
|
+
);
|
|
581
|
+
return ` ${name}: ${fallback},`;
|
|
582
|
+
})
|
|
583
|
+
.join("\n");
|
|
584
|
+
|
|
585
|
+
const nonColor = allTokens
|
|
586
|
+
.filter((token) => !isColorToken(token))
|
|
587
|
+
.map((token) => {
|
|
588
|
+
const name = getTokenName(token);
|
|
589
|
+
const fallback = isComponentBuild
|
|
590
|
+
? getNoLightDarkRef(token, false)
|
|
591
|
+
: buildFallbackWithRefs(
|
|
592
|
+
token,
|
|
593
|
+
dictionary,
|
|
594
|
+
tokensByName,
|
|
595
|
+
{ useLightDark: false, cssVarPrefix, forScssMap: true },
|
|
596
|
+
usesReferences,
|
|
597
|
+
resolveReferences,
|
|
598
|
+
);
|
|
599
|
+
return ` ${name}: ${fallback},`;
|
|
600
|
+
})
|
|
601
|
+
.join("\n");
|
|
602
|
+
|
|
603
|
+
return `$light: (\n${light}\n);\n$dark: (\n${dark}\n);\n$nonColor: (\n${nonColor}\n);`;
|
|
604
|
+
} else {
|
|
605
|
+
const vars = allTokens
|
|
606
|
+
.map((token) => {
|
|
607
|
+
const name = getTokenName(token);
|
|
608
|
+
const fallback = isComponentBuild
|
|
609
|
+
? getNoLightDarkRef(token, false)
|
|
610
|
+
: buildFallbackWithRefs(
|
|
611
|
+
token,
|
|
612
|
+
dictionary,
|
|
613
|
+
tokensByName,
|
|
614
|
+
{ useLightDark: false, cssVarPrefix, forScssMap: true },
|
|
615
|
+
usesReferences,
|
|
616
|
+
resolveReferences,
|
|
617
|
+
);
|
|
618
|
+
return ` ${name}: ${fallback},`;
|
|
619
|
+
})
|
|
620
|
+
.join("\n");
|
|
621
|
+
|
|
622
|
+
return `$token: (\n${vars}\n);`;
|
|
623
|
+
}
|
|
624
|
+
},
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* Format: custom/es6-variable
|
|
629
|
+
* Generates ES6 module exports for tokens with TypeScript-compatible JSDoc types.
|
|
630
|
+
* Tokens with dark variants include an extensions.appearance.dark.value property.
|
|
631
|
+
*/
|
|
632
|
+
StyleDictionary.registerFormat({
|
|
633
|
+
name: "custom/es6-variable",
|
|
634
|
+
format: ({ dictionary }) => {
|
|
635
|
+
const typeDefinitions = `/**
|
|
636
|
+
* @typedef {Object} TokenValue
|
|
637
|
+
* @property {string} value
|
|
638
|
+
*/
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* @typedef {Object} TokenWithAppearance
|
|
642
|
+
* @property {string} value
|
|
643
|
+
* @property {Object} extensions
|
|
644
|
+
* @property {Object} extensions.appearance
|
|
645
|
+
* @property {Object} extensions.appearance.dark
|
|
646
|
+
* @property {string} extensions.appearance.dark.value
|
|
647
|
+
*/
|
|
648
|
+
|
|
649
|
+
`;
|
|
650
|
+
/**
|
|
651
|
+
* Normalizes a token value, handling composite colors and dimensions.
|
|
652
|
+
* @param {*} value - The value to normalize
|
|
653
|
+
* @returns {string} The normalized value string
|
|
654
|
+
*/
|
|
655
|
+
const normalizeValue = (value) => {
|
|
656
|
+
if (isCompositeColor(value)) {
|
|
657
|
+
const alphaHex = Math.round(value.alpha * 255)
|
|
658
|
+
.toString(16)
|
|
659
|
+
.padStart(2, "0")
|
|
660
|
+
.toUpperCase();
|
|
661
|
+
return `${value.color}${alphaHex}`;
|
|
662
|
+
}
|
|
663
|
+
if (isDimensionValue(value)) {
|
|
664
|
+
return `${value.value}${value.unit}`;
|
|
665
|
+
}
|
|
666
|
+
return value;
|
|
667
|
+
};
|
|
668
|
+
|
|
669
|
+
return (
|
|
670
|
+
typeDefinitions +
|
|
671
|
+
dictionary.allTokens
|
|
672
|
+
.map((token) => {
|
|
673
|
+
const name = getTokenName(token);
|
|
674
|
+
const pascalName = name
|
|
675
|
+
.split("-")
|
|
676
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
677
|
+
.join("");
|
|
678
|
+
const lightValue = normalizeValue(getDtcgValue(token));
|
|
679
|
+
|
|
680
|
+
if (hasDarkValue(token)) {
|
|
681
|
+
const darkValue = normalizeValue(getDarkValue(token));
|
|
682
|
+
return `/** @type {TokenWithAppearance} */
|
|
683
|
+
export const ${pascalName} = {
|
|
684
|
+
value: ${JSON.stringify(lightValue)},
|
|
685
|
+
extensions: {
|
|
686
|
+
appearance: {
|
|
687
|
+
dark: {
|
|
688
|
+
value: ${JSON.stringify(darkValue)}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
};`;
|
|
693
|
+
}
|
|
694
|
+
return `/** @type {TokenValue} */
|
|
695
|
+
export const ${pascalName} = { value: ${JSON.stringify(lightValue)} };`;
|
|
696
|
+
})
|
|
697
|
+
.join("\n")
|
|
698
|
+
);
|
|
699
|
+
},
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* Format: custom/CSSVariables
|
|
704
|
+
* Generates CSS custom properties in a :root selector with light-dark() support.
|
|
705
|
+
*/
|
|
706
|
+
StyleDictionary.registerFormat({
|
|
707
|
+
name: "custom/CSSVariables",
|
|
708
|
+
format: ({ dictionary }) => {
|
|
709
|
+
const cssVars = dictionary.allTokens
|
|
710
|
+
.map((token) => {
|
|
711
|
+
const name = getTokenName(token).replace("-default", "");
|
|
712
|
+
const light = getTokenValue(token, dictionary, {}, resolveReferences);
|
|
713
|
+
const hasDarkExt =
|
|
714
|
+
token.$extensions?.appearance?.dark?.$value !== undefined;
|
|
715
|
+
const darkSource = token.dark || token.original?.dark;
|
|
716
|
+
const dark =
|
|
717
|
+
hasDarkExt || (darkSource && darkSource.value !== undefined)
|
|
718
|
+
? getTokenValue(
|
|
719
|
+
token,
|
|
720
|
+
dictionary,
|
|
721
|
+
{ isDark: true },
|
|
722
|
+
resolveReferences,
|
|
723
|
+
)
|
|
724
|
+
: null;
|
|
725
|
+
|
|
726
|
+
if (dark) {
|
|
727
|
+
return ` --${cssVarPrefix}${name}: light-dark(${light}, ${dark});`;
|
|
728
|
+
}
|
|
729
|
+
return ` --${cssVarPrefix}${name}: ${light};`;
|
|
730
|
+
})
|
|
731
|
+
.join(`\n`);
|
|
732
|
+
|
|
733
|
+
return `:root {\n${cssVars}\n}`;
|
|
734
|
+
},
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
// Register CSS utils formats for each prefix
|
|
738
|
+
const CSS_UTILS_PREFIXES = ["", "a2-"];
|
|
739
|
+
CSS_UTILS_PREFIXES.forEach((prefix) => {
|
|
740
|
+
registerCssUtilsFormats(
|
|
741
|
+
StyleDictionary,
|
|
742
|
+
prefix,
|
|
743
|
+
usesReferences,
|
|
744
|
+
resolveReferences,
|
|
745
|
+
cssVarPrefix,
|
|
746
|
+
);
|
|
747
|
+
});
|
|
748
|
+
};
|
|
749
|
+
|
|
750
|
+
module.exports = {
|
|
751
|
+
registerFormats,
|
|
752
|
+
};
|