@servicetitan/hammer-token 0.0.0-rc-1.48.0-20251104214834 → 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.
Files changed (76) hide show
  1. package/CHANGELOG.md +29 -1
  2. package/README.md +222 -0
  3. package/build/web/core/component-variables.scss +114 -130
  4. package/build/web/core/component.d.ts +65 -0
  5. package/build/web/core/component.js +248 -267
  6. package/build/web/core/component.scss +63 -69
  7. package/build/web/core/css-utils/a2-border.css +39 -41
  8. package/build/web/core/css-utils/a2-color.css +351 -227
  9. package/build/web/core/css-utils/a2-font.css +0 -2
  10. package/build/web/core/css-utils/a2-spacing.css +0 -2
  11. package/build/web/core/css-utils/a2-utils.css +418 -292
  12. package/build/web/core/css-utils/border.css +39 -41
  13. package/build/web/core/css-utils/color.css +351 -227
  14. package/build/web/core/css-utils/font.css +0 -2
  15. package/build/web/core/css-utils/spacing.css +0 -2
  16. package/build/web/core/css-utils/utils.css +418 -292
  17. package/build/web/core/index.d.ts +6 -0
  18. package/build/web/core/index.js +1 -1
  19. package/build/web/core/primitive-variables.scss +130 -71
  20. package/build/web/core/primitive.d.ts +185 -0
  21. package/build/web/core/primitive.js +328 -72
  22. package/build/web/core/primitive.scss +183 -124
  23. package/build/web/core/semantic-variables.scss +287 -220
  24. package/build/web/core/semantic.d.ts +194 -0
  25. package/build/web/core/semantic.js +875 -347
  26. package/build/web/core/semantic.scss +192 -140
  27. package/build/web/index.d.ts +3 -4
  28. package/build/web/index.js +0 -1
  29. package/build/web/types.d.ts +17 -0
  30. package/config.js +121 -496
  31. package/package.json +5 -4
  32. package/src/global/primitive/breakpoint.tokens.json +39 -0
  33. package/src/global/primitive/color.tokens.json +536 -0
  34. package/src/global/primitive/duration.tokens.json +32 -0
  35. package/src/global/primitive/font.tokens.json +103 -0
  36. package/src/global/primitive/radius.tokens.json +67 -0
  37. package/src/global/primitive/size.tokens.json +123 -0
  38. package/src/global/primitive/transition.tokens.json +20 -0
  39. package/src/theme/core/background.tokens.json +981 -0
  40. package/src/theme/core/border.tokens.json +148 -0
  41. package/src/theme/core/charts.tokens.json +802 -0
  42. package/src/theme/core/component/button.tokens.json +752 -0
  43. package/src/theme/core/component/checkbox.tokens.json +292 -0
  44. package/src/theme/core/focus.tokens.json +48 -0
  45. package/src/theme/core/foreground.tokens.json +288 -0
  46. package/src/theme/core/shadow.tokens.json +43 -0
  47. package/src/theme/core/status.tokens.json +70 -0
  48. package/src/theme/core/typography.tokens.json +100 -0
  49. package/src/utils/copy-css-utils-cli.js +13 -0
  50. package/src/utils/css-utils-format-utils.js +98 -1
  51. package/src/utils/sd-build-configs.js +372 -0
  52. package/src/utils/sd-formats.js +752 -0
  53. package/src/utils/sd-transforms.js +126 -0
  54. package/src/utils/token-helpers.js +555 -0
  55. package/tsconfig.json +18 -0
  56. package/.turbo/turbo-build.log +0 -37
  57. package/build/web/core/raw.js +0 -234
  58. package/src/global/primitive/breakpoint.js +0 -19
  59. package/src/global/primitive/color.js +0 -231
  60. package/src/global/primitive/duration.js +0 -16
  61. package/src/global/primitive/font.js +0 -60
  62. package/src/global/primitive/radius.js +0 -31
  63. package/src/global/primitive/size.js +0 -55
  64. package/src/global/primitive/transition.js +0 -16
  65. package/src/theme/core/background.js +0 -170
  66. package/src/theme/core/border.js +0 -103
  67. package/src/theme/core/charts.js +0 -464
  68. package/src/theme/core/component/button.js +0 -708
  69. package/src/theme/core/component/checkbox.js +0 -405
  70. package/src/theme/core/focus.js +0 -35
  71. package/src/theme/core/foreground.js +0 -148
  72. package/src/theme/core/overlay.js +0 -137
  73. package/src/theme/core/shadow.js +0 -29
  74. package/src/theme/core/status.js +0 -49
  75. package/src/theme/core/typography.js +0 -82
  76. 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
+ };