@primer/primitives 11.4.0-rc.f798df25 → 11.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) hide show
  1. package/dist/build/filters/hasLlmExtensions.d.ts +7 -0
  2. package/dist/build/filters/hasLlmExtensions.js +11 -0
  3. package/dist/build/filters/index.d.ts +1 -0
  4. package/dist/build/filters/index.js +1 -0
  5. package/dist/build/formats/index.d.ts +1 -0
  6. package/dist/build/formats/index.js +1 -0
  7. package/dist/build/formats/markdownLlmGuidelines.d.ts +10 -0
  8. package/dist/build/formats/markdownLlmGuidelines.js +194 -0
  9. package/dist/build/platforms/index.d.ts +1 -0
  10. package/dist/build/platforms/index.js +1 -0
  11. package/dist/build/platforms/llmGuidelines.d.ts +2 -0
  12. package/dist/build/platforms/llmGuidelines.js +17 -0
  13. package/dist/build/preprocessors/inheritGroupProperties.d.ts +7 -0
  14. package/dist/build/preprocessors/inheritGroupProperties.js +70 -0
  15. package/dist/build/primerStyleDictionary.js +7 -1
  16. package/dist/build/schemas/borderToken.d.ts +6 -0
  17. package/dist/build/schemas/borderToken.js +6 -0
  18. package/dist/build/schemas/colorToken.d.ts +4 -0
  19. package/dist/build/schemas/colorToken.js +2 -0
  20. package/dist/build/schemas/cubicBezierToken.d.ts +6 -0
  21. package/dist/build/schemas/cubicBezierToken.js +10 -2
  22. package/dist/build/schemas/designToken.d.ts +1 -1
  23. package/dist/build/schemas/designToken.js +113 -21
  24. package/dist/build/schemas/dimensionToken.d.ts +6 -2
  25. package/dist/build/schemas/dimensionToken.js +6 -2
  26. package/dist/build/schemas/durationToken.d.ts +6 -0
  27. package/dist/build/schemas/durationToken.js +6 -0
  28. package/dist/build/schemas/fontFamilyToken.d.ts +4 -0
  29. package/dist/build/schemas/fontFamilyToken.js +2 -0
  30. package/dist/build/schemas/fontWeightToken.d.ts +4 -0
  31. package/dist/build/schemas/fontWeightToken.js +2 -0
  32. package/dist/build/schemas/gradientToken.d.ts +4 -0
  33. package/dist/build/schemas/gradientToken.js +2 -0
  34. package/dist/build/schemas/llmExtension.d.ts +9 -0
  35. package/dist/build/schemas/llmExtension.js +11 -0
  36. package/dist/build/schemas/numberToken.d.ts +4 -0
  37. package/dist/build/schemas/numberToken.js +2 -0
  38. package/dist/build/schemas/shadowToken.d.ts +4 -0
  39. package/dist/build/schemas/shadowToken.js +2 -0
  40. package/dist/build/schemas/stringToken.d.ts +6 -0
  41. package/dist/build/schemas/stringToken.js +6 -0
  42. package/dist/build/schemas/transitionToken.d.ts +6 -0
  43. package/dist/build/schemas/transitionToken.js +6 -0
  44. package/dist/build/schemas/typographyToken.d.ts +6 -0
  45. package/dist/build/schemas/typographyToken.js +6 -0
  46. package/dist/build/schemas/validTokenType.d.ts +5 -1
  47. package/dist/build/schemas/validTokenType.js +71 -17
  48. package/dist/build/schemas/viewportRangeToken.d.ts +6 -0
  49. package/dist/build/schemas/viewportRangeToken.js +6 -0
  50. package/dist/css/base/motion/motion.css +5 -4
  51. package/dist/css/functional/size/border.css +9 -14
  52. package/dist/css/functional/size/radius.css +7 -0
  53. package/dist/css/functional/size/size-coarse.css +3 -3
  54. package/dist/css/functional/size/size-fine.css +3 -3
  55. package/dist/css/functional/size/viewport.css +1 -1
  56. package/dist/css/functional/themes/dark-colorblind-high-contrast.css +176 -176
  57. package/dist/css/functional/themes/dark-colorblind.css +176 -176
  58. package/dist/css/functional/themes/dark-dimmed-high-contrast.css +176 -176
  59. package/dist/css/functional/themes/dark-dimmed.css +176 -176
  60. package/dist/css/functional/themes/dark-high-contrast.css +176 -176
  61. package/dist/css/functional/themes/dark-tritanopia-high-contrast.css +176 -176
  62. package/dist/css/functional/themes/dark-tritanopia.css +176 -176
  63. package/dist/css/functional/themes/dark.css +176 -176
  64. package/dist/css/functional/themes/light-colorblind-high-contrast.css +176 -176
  65. package/dist/css/functional/themes/light-colorblind.css +176 -176
  66. package/dist/css/functional/themes/light-high-contrast.css +176 -176
  67. package/dist/css/functional/themes/light-tritanopia-high-contrast.css +176 -176
  68. package/dist/css/functional/themes/light-tritanopia.css +176 -176
  69. package/dist/css/functional/themes/light.css +176 -176
  70. package/dist/css/functional/typography/typography.css +4 -4
  71. package/dist/css/primitives.css +1 -0
  72. package/dist/docs/base/motion/motion.json +85 -8
  73. package/dist/docs/functional/size/border.json +42 -177
  74. package/dist/docs/functional/size/radius.json +209 -0
  75. package/dist/docs/functional/size/size-coarse.json +45 -3
  76. package/dist/docs/functional/size/size-fine.json +45 -3
  77. package/dist/docs/functional/size/viewport.json +2 -2
  78. package/dist/docs/functional/themes/dark-colorblind-high-contrast.json +934 -90
  79. package/dist/docs/functional/themes/dark-colorblind.json +934 -90
  80. package/dist/docs/functional/themes/dark-dimmed-high-contrast.json +934 -90
  81. package/dist/docs/functional/themes/dark-dimmed.json +972 -128
  82. package/dist/docs/functional/themes/dark-high-contrast.json +934 -90
  83. package/dist/docs/functional/themes/dark-tritanopia-high-contrast.json +934 -90
  84. package/dist/docs/functional/themes/dark-tritanopia.json +934 -90
  85. package/dist/docs/functional/themes/dark.json +934 -90
  86. package/dist/docs/functional/themes/light-colorblind-high-contrast.json +934 -90
  87. package/dist/docs/functional/themes/light-colorblind.json +934 -90
  88. package/dist/docs/functional/themes/light-high-contrast.json +934 -90
  89. package/dist/docs/functional/themes/light-tritanopia-high-contrast.json +934 -90
  90. package/dist/docs/functional/themes/light-tritanopia.json +934 -90
  91. package/dist/docs/functional/themes/light.json +934 -90
  92. package/dist/docs/functional/typography/typography.json +172 -8
  93. package/dist/fallbacks/base/motion/motion.json +1 -0
  94. package/dist/fallbacks/functional/size/border.json +0 -5
  95. package/dist/fallbacks/functional/size/radius.json +7 -0
  96. package/dist/fallbacks/functional/size/viewport.json +1 -1
  97. package/dist/figma/dimension/dimension.json +30 -20
  98. package/dist/figma/themes/dark-colorblind.json +85 -0
  99. package/dist/figma/themes/dark-dimmed.json +134 -49
  100. package/dist/figma/themes/dark-high-contrast.json +85 -0
  101. package/dist/figma/themes/dark-tritanopia.json +85 -0
  102. package/dist/figma/themes/dark.json +85 -0
  103. package/dist/figma/themes/light-colorblind.json +85 -0
  104. package/dist/figma/themes/light-high-contrast.json +85 -0
  105. package/dist/figma/themes/light-tritanopia.json +85 -0
  106. package/dist/figma/themes/light.json +85 -0
  107. package/dist/figma/typography/typography.json +44 -40
  108. package/dist/internalCss/dark-colorblind-high-contrast.css +194 -204
  109. package/dist/internalCss/dark-colorblind.css +194 -204
  110. package/dist/internalCss/dark-dimmed-high-contrast.css +194 -204
  111. package/dist/internalCss/dark-dimmed.css +194 -204
  112. package/dist/internalCss/dark-high-contrast.css +194 -204
  113. package/dist/internalCss/dark-tritanopia-high-contrast.css +194 -204
  114. package/dist/internalCss/dark-tritanopia.css +194 -204
  115. package/dist/internalCss/dark.css +194 -204
  116. package/dist/internalCss/light-colorblind-high-contrast.css +194 -204
  117. package/dist/internalCss/light-colorblind.css +194 -204
  118. package/dist/internalCss/light-high-contrast.css +194 -204
  119. package/dist/internalCss/light-tritanopia-high-contrast.css +194 -204
  120. package/dist/internalCss/light-tritanopia.css +194 -204
  121. package/dist/internalCss/light.css +194 -204
  122. package/dist/styleLint/base/motion/motion.json +85 -8
  123. package/dist/styleLint/functional/size/border.json +34 -169
  124. package/dist/styleLint/functional/size/radius.json +209 -0
  125. package/dist/styleLint/functional/size/size-coarse.json +42 -0
  126. package/dist/styleLint/functional/size/size-fine.json +42 -0
  127. package/dist/styleLint/functional/size/viewport.json +2 -2
  128. package/dist/styleLint/functional/themes/dark-colorblind-high-contrast.json +846 -2
  129. package/dist/styleLint/functional/themes/dark-colorblind.json +846 -2
  130. package/dist/styleLint/functional/themes/dark-dimmed-high-contrast.json +846 -2
  131. package/dist/styleLint/functional/themes/dark-dimmed.json +884 -40
  132. package/dist/styleLint/functional/themes/dark-high-contrast.json +846 -2
  133. package/dist/styleLint/functional/themes/dark-tritanopia-high-contrast.json +846 -2
  134. package/dist/styleLint/functional/themes/dark-tritanopia.json +846 -2
  135. package/dist/styleLint/functional/themes/dark.json +846 -2
  136. package/dist/styleLint/functional/themes/light-colorblind-high-contrast.json +846 -2
  137. package/dist/styleLint/functional/themes/light-colorblind.json +846 -2
  138. package/dist/styleLint/functional/themes/light-high-contrast.json +846 -2
  139. package/dist/styleLint/functional/themes/light-tritanopia-high-contrast.json +846 -2
  140. package/dist/styleLint/functional/themes/light-tritanopia.json +846 -2
  141. package/dist/styleLint/functional/themes/light.json +846 -2
  142. package/dist/styleLint/functional/typography/typography.json +168 -4
  143. package/guidelines/color.llm.md +16 -0
  144. package/guidelines/guidelines.llm.md +34 -0
  145. package/guidelines/motion.llm.md +41 -0
  146. package/guidelines/spacing.llm.md +20 -0
  147. package/guidelines/typography.llm.md +14 -0
  148. package/package.json +5 -3
  149. package/src/tokens/base/motion/easing.json5 +39 -4
  150. package/src/tokens/functional/border/border.json5 +25 -0
  151. package/src/tokens/functional/color/bgColor.json5 +157 -0
  152. package/src/tokens/functional/color/borderColor.json5 +146 -0
  153. package/src/tokens/functional/color/control.json5 +24 -0
  154. package/src/tokens/functional/color/data-vis.json5 +7 -0
  155. package/src/tokens/functional/color/fgColor.json5 +93 -1
  156. package/src/tokens/functional/color/focus.json5 +5 -0
  157. package/src/tokens/functional/color/selection.json5 +5 -0
  158. package/src/tokens/functional/shadow/shadow.json5 +10 -0
  159. package/src/tokens/functional/size/border.json5 +17 -69
  160. package/src/tokens/functional/size/radius.json5 +90 -0
  161. package/src/tokens/functional/size/size-coarse.json5 +24 -3
  162. package/src/tokens/functional/size/size-fine.json5 +45 -24
  163. package/src/tokens/functional/size/size.json5 +35 -0
  164. package/src/tokens/functional/size/viewport.json5 +1 -1
  165. package/src/tokens/functional/typography/font-stack.json5 +60 -0
  166. package/src/tokens/functional/typography/typography.json5 +67 -44
  167. package/token-guidelines.llm.md +695 -0
@@ -0,0 +1,7 @@
1
+ import type { TransformedToken } from 'style-dictionary/types';
2
+ /**
3
+ * @description Checks if token has LLM extensions (`org.primer.llm` in `$extensions`)
4
+ * @param arguments [TransformedToken](https://github.com/amzn/style-dictionary/blob/main/types/TransformedToken.d.ts)
5
+ * @returns boolean
6
+ */
7
+ export declare const hasLlmExtensions: (token: TransformedToken) => boolean;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @description Checks if token has LLM extensions (`org.primer.llm` in `$extensions`)
3
+ * @param arguments [TransformedToken](https://github.com/amzn/style-dictionary/blob/main/types/TransformedToken.d.ts)
4
+ * @returns boolean
5
+ */
6
+ export const hasLlmExtensions = (token) => {
7
+ return (token.$extensions !== undefined &&
8
+ token.$extensions !== null &&
9
+ typeof token.$extensions === 'object' &&
10
+ 'org.primer.llm' in token.$extensions);
11
+ };
@@ -1,3 +1,4 @@
1
+ export { hasLlmExtensions } from './hasLlmExtensions.js';
1
2
  export { isBorder } from './isBorder.js';
2
3
  export { isColor } from './isColor.js';
3
4
  export { isColorWithAlpha } from './isColorWithAlpha.js';
@@ -1,3 +1,4 @@
1
+ export { hasLlmExtensions } from './hasLlmExtensions.js';
1
2
  export { isBorder } from './isBorder.js';
2
3
  export { isColor } from './isColor.js';
3
4
  export { isColorWithAlpha } from './isColorWithAlpha.js';
@@ -1,5 +1,6 @@
1
1
  export { cssCustomMedia } from './cssCustomMedia.js';
2
2
  export { cssAdvanced } from './cssAdvanced.js';
3
+ export { markdownLlmGuidelines } from './markdownLlmGuidelines.js';
3
4
  export { jsonFigma } from './jsonFigma.js';
4
5
  export { javascriptCommonJs } from './javascriptCommonJs.js';
5
6
  export { javascriptEsm } from './javascriptEsm.js';
@@ -1,5 +1,6 @@
1
1
  export { cssCustomMedia } from './cssCustomMedia.js';
2
2
  export { cssAdvanced } from './cssAdvanced.js';
3
+ export { markdownLlmGuidelines } from './markdownLlmGuidelines.js';
3
4
  export { jsonFigma } from './jsonFigma.js';
4
5
  export { javascriptCommonJs } from './javascriptCommonJs.js';
5
6
  export { javascriptEsm } from './javascriptEsm.js';
@@ -0,0 +1,10 @@
1
+ import type { FormatFn } from 'style-dictionary/types';
2
+ /**
3
+ * @description Outputs a markdown file with LLM token guidelines, extracting
4
+ * description from $description and usage/rules from $extensions['org.primer.llm'].
5
+ * Tokens with identical guidelines (from group-level inheritance) are consolidated
6
+ * into a single entry listing all token names.
7
+ * @param FormatFnArguments
8
+ * @returns formatted markdown `string`
9
+ */
10
+ export declare const markdownLlmGuidelines: FormatFn;
@@ -0,0 +1,194 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { sortByName } from 'style-dictionary/utils';
11
+ /**
12
+ * Creates a unique key for grouping tokens with identical guidelines
13
+ */
14
+ function createGuidelineKey(guideline) {
15
+ var _a;
16
+ return JSON.stringify({
17
+ description: guideline.description || '',
18
+ usage: ((_a = guideline.usage) === null || _a === void 0 ? void 0 : _a.sort()) || [],
19
+ rules: guideline.rules || '',
20
+ });
21
+ }
22
+ /**
23
+ * Extracts category from token name
24
+ * - For "base-*" tokens, uses second word (e.g., "base-easing-ease" -> "easing")
25
+ * - Otherwise uses first word (e.g., "bgColor-danger-emphasis" -> "bgColor")
26
+ */
27
+ function extractCategory(tokenName) {
28
+ const parts = tokenName.split('-');
29
+ if (parts[0] === 'base' && parts[1]) {
30
+ return parts[1];
31
+ }
32
+ return parts[0] || 'other';
33
+ }
34
+ /**
35
+ * Formats category name for display
36
+ */
37
+ function formatCategoryName(category) {
38
+ const categoryMap = {
39
+ bgColor: 'background color',
40
+ fgColor: 'text and foreground color',
41
+ };
42
+ if (categoryMap[category]) {
43
+ return categoryMap[category];
44
+ }
45
+ // Capitalize first letter
46
+ return category.charAt(0).toUpperCase() + category.slice(1);
47
+ }
48
+ /**
49
+ * Creates a key for grouping by usage and rules only (not description)
50
+ */
51
+ function createUsageRulesKey(guideline) {
52
+ var _a;
53
+ return JSON.stringify({
54
+ usage: ((_a = guideline.usage) === null || _a === void 0 ? void 0 : _a.sort()) || [],
55
+ rules: guideline.rules || '',
56
+ });
57
+ }
58
+ /**
59
+ * Extracts a subcategory name from token names for headings
60
+ * e.g., "border-accent-emphasis" -> "accent"
61
+ */
62
+ function extractSubcategory(tokenNames) {
63
+ if (tokenNames.length < 2)
64
+ return null;
65
+ // Get the second part of each token name
66
+ const subcategories = tokenNames.map(name => {
67
+ const parts = name.split('-');
68
+ return parts[1] || null;
69
+ });
70
+ // Check if all tokens share the same subcategory
71
+ const uniqueSubcats = [...new Set(subcategories.filter(Boolean))];
72
+ if (uniqueSubcats.length === 1) {
73
+ return uniqueSubcats[0];
74
+ }
75
+ return null;
76
+ }
77
+ /**
78
+ * @description Outputs a markdown file with LLM token guidelines, extracting
79
+ * description from $description and usage/rules from $extensions['org.primer.llm'].
80
+ * Tokens with identical guidelines (from group-level inheritance) are consolidated
81
+ * into a single entry listing all token names.
82
+ * @param FormatFnArguments
83
+ * @returns formatted markdown `string`
84
+ */
85
+ export const markdownLlmGuidelines = (_a) => __awaiter(void 0, [_a], void 0, function* ({ dictionary }) {
86
+ var _b;
87
+ const tokens = dictionary.allTokens.sort(sortByName);
88
+ const guidelines = [];
89
+ for (const token of tokens) {
90
+ const llmExt = (_b = token.$extensions) === null || _b === void 0 ? void 0 : _b['org.primer.llm'];
91
+ if (!llmExt)
92
+ continue;
93
+ const guideline = {
94
+ name: token.name,
95
+ category: extractCategory(token.name),
96
+ };
97
+ if (token.$description && typeof token.$description === 'string') {
98
+ guideline.description = token.$description;
99
+ }
100
+ if (llmExt.usage && Array.isArray(llmExt.usage)) {
101
+ guideline.usage = llmExt.usage;
102
+ }
103
+ if (llmExt.rules && typeof llmExt.rules === 'string') {
104
+ guideline.rules = llmExt.rules;
105
+ }
106
+ guidelines.push(guideline);
107
+ }
108
+ // Group by category
109
+ const grouped = {};
110
+ for (const guideline of guidelines) {
111
+ if (!Object.hasOwn(grouped, guideline.category)) {
112
+ grouped[guideline.category] = [];
113
+ }
114
+ grouped[guideline.category].push(guideline);
115
+ }
116
+ // Build markdown output
117
+ const lines = ['# Token Guidelines', ''];
118
+ for (const category of Object.keys(grouped).sort()) {
119
+ lines.push(`## ${formatCategoryName(category)}`, '');
120
+ const categoryGuidelines = grouped[category];
121
+ // Check if all tokens in category share the same usage/rules AND there are multiple tokens
122
+ const usageRulesKeys = new Set(categoryGuidelines.map(createUsageRulesKey));
123
+ const sharedUsageRules = usageRulesKeys.size === 1 && categoryGuidelines.length > 1;
124
+ // If shared, output usage/rules once at category level
125
+ if (sharedUsageRules) {
126
+ const first = categoryGuidelines[0];
127
+ if (first.usage && first.usage.length > 0) {
128
+ lines.push(`**Usage:** ${first.usage.join(', ')}`);
129
+ }
130
+ if (first.rules) {
131
+ lines.push(`**Rules:** ${first.rules}`);
132
+ }
133
+ lines.push('');
134
+ }
135
+ // Group tokens with identical guidelines (description + usage + rules)
136
+ const consolidatedGroups = new Map();
137
+ for (const guideline of categoryGuidelines) {
138
+ const key = createGuidelineKey(guideline);
139
+ if (!consolidatedGroups.has(key)) {
140
+ consolidatedGroups.set(key, []);
141
+ }
142
+ consolidatedGroups.get(key).push(guideline);
143
+ }
144
+ for (const [, guidelinesGroup] of consolidatedGroups) {
145
+ const first = guidelinesGroup[0];
146
+ const tokenNames = guidelinesGroup.map(g => g.name);
147
+ if (guidelinesGroup.length > 1) {
148
+ // Multiple tokens share the same guidelines - consolidate
149
+ const subcategory = extractSubcategory(tokenNames);
150
+ if (subcategory) {
151
+ lines.push(`### ${subcategory}`);
152
+ }
153
+ else {
154
+ // No common subcategory - use "general" or skip heading if description serves as intro
155
+ if (first.description && consolidatedGroups.size > 1) {
156
+ lines.push(`### general`);
157
+ }
158
+ }
159
+ if (first.description) {
160
+ lines.push(first.description);
161
+ }
162
+ // Only show usage/rules if not already shown at category level
163
+ if (!sharedUsageRules) {
164
+ if (first.usage && first.usage.length > 0) {
165
+ lines.push(`**Usage:** ${first.usage.join(', ')}`);
166
+ }
167
+ if (first.rules) {
168
+ lines.push(`**Rules:** ${first.rules}`);
169
+ }
170
+ }
171
+ lines.push(`**Tokens:** ${tokenNames.join(', ')}`);
172
+ lines.push('');
173
+ }
174
+ else {
175
+ // Single token - output individually
176
+ lines.push(`### ${first.name}`);
177
+ if (first.description) {
178
+ lines.push(first.description);
179
+ }
180
+ // Only show usage/rules if not already shown at category level
181
+ if (!sharedUsageRules) {
182
+ if (first.usage && first.usage.length > 0) {
183
+ lines.push(`**Usage:** ${first.usage.join(', ')}`);
184
+ }
185
+ if (first.rules) {
186
+ lines.push(`**Rules:** ${first.rules}`);
187
+ }
188
+ }
189
+ lines.push('');
190
+ }
191
+ }
192
+ }
193
+ return lines.join('\n');
194
+ });
@@ -1,3 +1,4 @@
1
+ export { llmGuidelines } from './llmGuidelines.js';
1
2
  export { css } from './css.js';
2
3
  export { deprecatedJson } from './deprecatedJson.js';
3
4
  export { docJson } from './docJson.js';
@@ -1,3 +1,4 @@
1
+ export { llmGuidelines } from './llmGuidelines.js';
1
2
  export { css } from './css.js';
2
3
  export { deprecatedJson } from './deprecatedJson.js';
3
4
  export { docJson } from './docJson.js';
@@ -0,0 +1,2 @@
1
+ import type { PlatformInitializer } from '../types/platformInitializer.js';
2
+ export declare const llmGuidelines: PlatformInitializer;
@@ -0,0 +1,17 @@
1
+ import { hasLlmExtensions } from '../filters/index.js';
2
+ export const llmGuidelines = (outputFile, prefix, buildPath) => ({
3
+ prefix,
4
+ buildPath,
5
+ preprocessors: ['inheritGroupProperties'],
6
+ transforms: ['name/pathToKebabCase'],
7
+ files: [
8
+ {
9
+ destination: outputFile,
10
+ format: 'json/llm-guidelines',
11
+ filter: hasLlmExtensions,
12
+ options: {
13
+ outputReferences: false,
14
+ },
15
+ },
16
+ ],
17
+ });
@@ -0,0 +1,7 @@
1
+ import type { Preprocessor } from 'style-dictionary/types';
2
+ /**
3
+ * Preprocessor that inherits group-level $description and $extensions to child tokens.
4
+ * This enables W3C Design Tokens group properties to be available on individual tokens
5
+ * during formatting.
6
+ */
7
+ export declare const inheritGroupProperties: Preprocessor;
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Recursively walks tokens and inherits group-level properties to child tokens.
3
+ * Group properties ($description, $extensions at group level) are merged into child tokens
4
+ * that don't have their own values for those properties.
5
+ *
6
+ * Per W3C Design Tokens spec: https://www.designtokens.org/tr/drafts/format/#group-properties
7
+ */
8
+ function inheritProperties(tokens, inheritedProps = {}) {
9
+ var _a;
10
+ const result = {};
11
+ // Extract group-level properties from current level
12
+ const currentGroupProps = {};
13
+ if (typeof tokens.$description === 'string') {
14
+ currentGroupProps.$description = tokens.$description;
15
+ }
16
+ if (tokens.$extensions && typeof tokens.$extensions === 'object') {
17
+ currentGroupProps.$extensions = tokens.$extensions;
18
+ }
19
+ // Merge inherited with current (current takes precedence)
20
+ const mergedProps = Object.assign(Object.assign({}, inheritedProps), currentGroupProps);
21
+ // Merge $extensions deeply
22
+ if (inheritedProps.$extensions || currentGroupProps.$extensions) {
23
+ mergedProps.$extensions = Object.assign(Object.assign({}, inheritedProps.$extensions), currentGroupProps.$extensions);
24
+ }
25
+ for (const [key, value] of Object.entries(tokens)) {
26
+ // Skip group-level properties (they're inherited, not copied)
27
+ if (key === '$description' || key === '$extensions') {
28
+ continue;
29
+ }
30
+ if (typeof value !== 'object' || value === null) {
31
+ result[key] = value;
32
+ continue;
33
+ }
34
+ const tokenValue = value;
35
+ // Check if this is a design token (has $value or value)
36
+ if ('$value' in tokenValue || 'value' in tokenValue) {
37
+ // It's a token - merge inherited properties
38
+ const token = tokenValue;
39
+ // Only inherit $description if token doesn't have its own
40
+ const inheritedDescription = !token.$description && mergedProps.$description ? mergedProps.$description : undefined;
41
+ // Merge $extensions (token-level takes precedence over inherited)
42
+ let mergedExtensions = token.$extensions;
43
+ if (mergedProps.$extensions) {
44
+ const inheritedLlm = mergedProps.$extensions['org.primer.llm'];
45
+ const tokenLlm = (_a = token.$extensions) === null || _a === void 0 ? void 0 : _a['org.primer.llm'];
46
+ if (inheritedLlm && !tokenLlm) {
47
+ // Token has no LLM extension, inherit from group
48
+ mergedExtensions = Object.assign(Object.assign({}, token.$extensions), { 'org.primer.llm': inheritedLlm });
49
+ }
50
+ }
51
+ result[key] = Object.assign(Object.assign(Object.assign({}, token), (inheritedDescription ? { $description: inheritedDescription } : {})), (mergedExtensions ? { $extensions: mergedExtensions } : {}));
52
+ }
53
+ else {
54
+ // It's a nested group - recurse with merged properties
55
+ result[key] = inheritProperties(tokenValue, mergedProps);
56
+ }
57
+ }
58
+ return result;
59
+ }
60
+ /**
61
+ * Preprocessor that inherits group-level $description and $extensions to child tokens.
62
+ * This enables W3C Design Tokens group properties to be available on individual tokens
63
+ * during formatting.
64
+ */
65
+ export const inheritGroupProperties = {
66
+ name: 'inheritGroupProperties',
67
+ preprocessor: (dictionary) => {
68
+ return inheritProperties(dictionary);
69
+ },
70
+ };
@@ -1,7 +1,8 @@
1
1
  import StyleDictionary from 'style-dictionary';
2
2
  import { borderToCss, colorToRgbAlpha, colorToHex, colorToRgbaFloat, cubicBezierToCss, dimensionToRem, dimensionToPixelUnitless, durationToCss, figmaAttributes, fontFamilyToCss, fontFamilyToFigma, fontWeightToNumber, gradientToCss, jsonDeprecated, namePathToDotNotation, namePathToCamelCase, namePathToPascalCase, namePathToKebabCase, namePathToSlashNotation, namePathToFigma, shadowToCss, typographyToCss, dimensionToRemPxArray, floatToPixel, floatToPixelUnitless, transitionToCss, } from './transformers/index.js';
3
- import { javascriptCommonJs, javascriptEsm, typescriptExportDefinition, jsonNestedPrefixed, cssCustomMedia, jsonOneDimensional, jsonPostCssFallback, cssAdvanced, jsonFigma, } from './formats/index.js';
3
+ import { javascriptCommonJs, javascriptEsm, typescriptExportDefinition, jsonNestedPrefixed, cssCustomMedia, jsonOneDimensional, jsonPostCssFallback, cssAdvanced, jsonFigma, markdownLlmGuidelines, } from './formats/index.js';
4
4
  import { themeOverrides } from './preprocessors/themeOverrides.js';
5
+ import { inheritGroupProperties } from './preprocessors/inheritGroupProperties.js';
5
6
  import { colorAlphaToCss } from './transformers/colorAlphaToCss.js';
6
7
  /**
7
8
  * @name {@link PrimerStyleDictionary}
@@ -55,6 +56,10 @@ PrimerStyleDictionary.registerFormat({
55
56
  name: 'json/figma',
56
57
  format: jsonFigma,
57
58
  });
59
+ PrimerStyleDictionary.registerFormat({
60
+ name: 'json/llm-guidelines',
61
+ format: markdownLlmGuidelines,
62
+ });
58
63
  /**
59
64
  * Transformers
60
65
  *
@@ -88,3 +93,4 @@ PrimerStyleDictionary.registerTransform(fontFamilyToCss);
88
93
  PrimerStyleDictionary.registerTransform(fontFamilyToFigma);
89
94
  PrimerStyleDictionary.registerTransform(gradientToCss);
90
95
  PrimerStyleDictionary.registerPreprocessor(themeOverrides);
96
+ PrimerStyleDictionary.registerPreprocessor(inheritGroupProperties);
@@ -31,4 +31,10 @@ export declare const borderToken: z.ZodObject<{
31
31
  width: z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodString, z.ZodLiteral<"0">, z.ZodLiteral<0>]>, z.ZodString]>;
32
32
  }, z.core.$strip>, z.ZodString]>;
33
33
  $type: z.ZodLiteral<"string" | "number" | "border" | "color" | "fontFamily" | "fontWeight" | "transition" | "dimension" | "duration" | "gradient" | "shadow" | "typography" | "cubicBezier" | "custom-viewportRange">;
34
+ $extensions: z.ZodOptional<z.ZodObject<{
35
+ 'org.primer.llm': z.ZodOptional<z.ZodObject<{
36
+ usage: z.ZodOptional<z.ZodArray<z.ZodString>>;
37
+ rules: z.ZodOptional<z.ZodString>;
38
+ }, z.core.$strip>>;
39
+ }, z.core.$strip>>;
34
40
  }, z.core.$strict>;
@@ -4,6 +4,7 @@ import { referenceValue } from './referenceValue.js';
4
4
  import { colorHexValue } from './colorHexValue.js';
5
5
  import { dimensionValue } from './dimensionValue.js';
6
6
  import { tokenType } from './tokenType.js';
7
+ import { llmExtension } from './llmExtension.js';
7
8
  export const borderValue = z.object({
8
9
  color: z.union([colorHexValue, referenceValue]),
9
10
  style: z.enum(['solid', 'dashed', 'dotted', 'double', 'groove', 'ridge', 'outset', 'inset']),
@@ -13,5 +14,10 @@ export const borderToken = baseToken
13
14
  .extend({
14
15
  $value: z.union([borderValue, referenceValue]),
15
16
  $type: tokenType('border'),
17
+ $extensions: z
18
+ .object({
19
+ 'org.primer.llm': llmExtension,
20
+ })
21
+ .optional(),
16
22
  })
17
23
  .strict();
@@ -98,5 +98,9 @@ export declare const colorToken: z.ZodObject<{
98
98
  alpha: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodAny>>>;
99
99
  }, z.core.$strict>]>>;
100
100
  }, z.core.$strict>>;
101
+ 'org.primer.llm': z.ZodOptional<z.ZodObject<{
102
+ usage: z.ZodOptional<z.ZodArray<z.ZodString>>;
103
+ rules: z.ZodOptional<z.ZodString>;
104
+ }, z.core.$strip>>;
101
105
  }, z.core.$strict>>;
102
106
  }, z.core.$strict>;
@@ -6,6 +6,7 @@ import { baseToken } from './baseToken.js';
6
6
  import { collection, mode } from './collections.js';
7
7
  import { scopes } from './scopes.js';
8
8
  import { tokenType } from './tokenType.js';
9
+ import { llmExtension } from './llmExtension.js';
9
10
  const baseColorToken = baseToken.extend({
10
11
  $value: z.union([colorHexValue, referenceValue]),
11
12
  alpha: alphaValue.optional().nullable(),
@@ -75,6 +76,7 @@ export const colorToken = baseColorToken
75
76
  })
76
77
  .strict()
77
78
  .optional(),
79
+ 'org.primer.llm': llmExtension,
78
80
  })
79
81
  .strict()
80
82
  .optional(),
@@ -4,4 +4,10 @@ export declare const cubicBezierToken: z.ZodObject<{
4
4
  $deprecated: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodBoolean]>>;
5
5
  $value: z.ZodUnion<readonly [z.ZodArray<z.ZodNumber>, z.ZodString]>;
6
6
  $type: z.ZodLiteral<"string" | "number" | "border" | "color" | "fontFamily" | "fontWeight" | "transition" | "dimension" | "duration" | "gradient" | "shadow" | "typography" | "cubicBezier" | "custom-viewportRange">;
7
+ $extensions: z.ZodOptional<z.ZodObject<{
8
+ 'org.primer.llm': z.ZodOptional<z.ZodObject<{
9
+ usage: z.ZodOptional<z.ZodArray<z.ZodString>>;
10
+ rules: z.ZodOptional<z.ZodString>;
11
+ }, z.core.$strip>>;
12
+ }, z.core.$strip>>;
7
13
  }, z.core.$strict>;
@@ -2,7 +2,15 @@ import { z } from 'zod';
2
2
  import { baseToken } from './baseToken.js';
3
3
  import { referenceValue } from './referenceValue.js';
4
4
  import { tokenType } from './tokenType.js';
5
- export const cubicBezierToken = baseToken.extend({
5
+ import { llmExtension } from './llmExtension.js';
6
+ export const cubicBezierToken = baseToken
7
+ .extend({
6
8
  $value: z.union([z.array(z.number()).length(4), referenceValue]),
7
9
  $type: tokenType('cubicBezier'),
8
- });
10
+ $extensions: z
11
+ .object({
12
+ 'org.primer.llm': llmExtension,
13
+ })
14
+ .optional(),
15
+ })
16
+ .strict();
@@ -1,2 +1,2 @@
1
1
  import { z } from 'zod';
2
- export declare const designToken: z.ZodRecord<z.ZodString, z.ZodLazy<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>>;
2
+ export declare const designToken: z.ZodType<unknown>;
@@ -14,26 +14,118 @@ import { durationToken } from './durationToken.js';
14
14
  import { cubicBezierToken } from './cubicBezierToken.js';
15
15
  import { gradientToken } from './gradientToken.js';
16
16
  import { transitionToken } from './transitionToken.js';
17
+ import { llmExtension } from './llmExtension.js';
18
+ /**
19
+ * Group-level extensions schema (W3C Design Tokens spec)
20
+ * https://www.designtokens.org/tr/drafts/format/#group-properties
21
+ */
22
+ const groupExtensions = z
23
+ .object({
24
+ 'org.primer.llm': llmExtension,
25
+ })
26
+ .passthrough();
27
+ /**
28
+ * All valid token types with $type discriminator
29
+ */
30
+ const tokenTypes = z.discriminatedUnion('$type', [
31
+ colorToken,
32
+ cubicBezierToken,
33
+ dimensionToken,
34
+ shadowToken,
35
+ borderToken,
36
+ fontFamilyToken,
37
+ fontWeightToken,
38
+ gradientToken,
39
+ typographyToken,
40
+ viewportRangeToken,
41
+ numberToken,
42
+ durationToken,
43
+ stringToken,
44
+ transitionToken,
45
+ ]);
46
+ /**
47
+ * Validates a record allowing both token names and group properties ($description, $extensions)
48
+ * Recursively validates nested groups
49
+ */
50
+ const createDesignTokenSchema = () => {
51
+ return z.record(z.string(), z.unknown()).superRefine((obj, ctx) => {
52
+ for (const [key, value] of Object.entries(obj)) {
53
+ if (key === '$description') {
54
+ // Group-level $description must be a string
55
+ if (typeof value !== 'string') {
56
+ ctx.addIssue({
57
+ code: z.ZodIssueCode.custom,
58
+ message: `$description must be a string, got ${typeof value}`,
59
+ path: [key],
60
+ });
61
+ }
62
+ }
63
+ else if (key === '$extensions') {
64
+ // Group-level $extensions must be an object
65
+ if (typeof value !== 'object' || value === null) {
66
+ ctx.addIssue({
67
+ code: z.ZodIssueCode.custom,
68
+ message: `$extensions must be an object`,
69
+ path: [key],
70
+ });
71
+ }
72
+ else {
73
+ const result = groupExtensions.safeParse(value);
74
+ if (!result.success) {
75
+ for (const issue of result.error.issues) {
76
+ ctx.addIssue(Object.assign(Object.assign({}, issue), { path: [key, ...issue.path] }));
77
+ }
78
+ }
79
+ }
80
+ }
81
+ else if (key.startsWith('$')) {
82
+ // Unknown $-prefixed keys at group level are not allowed
83
+ ctx.addIssue({
84
+ code: z.ZodIssueCode.custom,
85
+ message: `Unknown group property: ${key}. Only $description and $extensions are allowed.`,
86
+ path: [key],
87
+ });
88
+ }
89
+ else {
90
+ // Validate token name
91
+ const nameResult = tokenName.safeParse(key);
92
+ if (!nameResult.success) {
93
+ for (const issue of nameResult.error.issues) {
94
+ ctx.addIssue(Object.assign(Object.assign({}, issue), { path: [key] }));
95
+ }
96
+ }
97
+ // Validate value as either a token or nested group
98
+ if (typeof value === 'object' && value !== null) {
99
+ // Check if it's a token (has $type) or a nested group
100
+ if ('$type' in value) {
101
+ const tokenResult = tokenTypes.safeParse(value);
102
+ if (!tokenResult.success) {
103
+ for (const issue of tokenResult.error.issues) {
104
+ ctx.addIssue(Object.assign(Object.assign({}, issue), { path: [key, ...issue.path] }));
105
+ }
106
+ }
107
+ }
108
+ else {
109
+ // Recursively validate nested group
110
+ const nestedResult = designToken.safeParse(value);
111
+ if (!nestedResult.success) {
112
+ for (const issue of nestedResult.error.issues) {
113
+ ctx.addIssue(Object.assign(Object.assign({}, issue), { path: [key, ...issue.path] }));
114
+ }
115
+ }
116
+ }
117
+ }
118
+ else {
119
+ ctx.addIssue({
120
+ code: z.ZodIssueCode.custom,
121
+ message: `Expected token or group object, got ${typeof value}`,
122
+ path: [key],
123
+ });
124
+ }
125
+ }
126
+ }
127
+ });
128
+ };
17
129
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
18
130
  // @ts-ignore: TODO: fix this
19
- export const designToken = z.record(tokenName, z.lazy(() => {
20
- return z.union([
21
- z.discriminatedUnion('$type', [
22
- colorToken,
23
- cubicBezierToken,
24
- dimensionToken,
25
- shadowToken,
26
- borderToken,
27
- fontFamilyToken,
28
- fontWeightToken,
29
- gradientToken,
30
- typographyToken,
31
- viewportRangeToken,
32
- numberToken,
33
- durationToken,
34
- stringToken,
35
- transitionToken,
36
- ]),
37
- designToken,
38
- ]);
39
- }));
131
+ export const designToken = createDesignTokenSchema();
@@ -5,10 +5,14 @@ export declare const dimensionToken: z.ZodObject<{
5
5
  $value: z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodString, z.ZodLiteral<"0">, z.ZodLiteral<0>]>, z.ZodString]>;
6
6
  $type: z.ZodLiteral<"string" | "number" | "border" | "color" | "fontFamily" | "fontWeight" | "transition" | "dimension" | "duration" | "gradient" | "shadow" | "typography" | "cubicBezier" | "custom-viewportRange">;
7
7
  $extensions: z.ZodOptional<z.ZodObject<{
8
- 'org.primer.figma': z.ZodObject<{
8
+ 'org.primer.figma': z.ZodOptional<z.ZodObject<{
9
9
  collection: z.ZodString;
10
10
  scopes: z.ZodArray<z.ZodString>;
11
11
  group: z.ZodOptional<z.ZodString>;
12
- }, z.core.$strip>;
12
+ }, z.core.$strip>>;
13
+ 'org.primer.llm': z.ZodOptional<z.ZodObject<{
14
+ usage: z.ZodOptional<z.ZodArray<z.ZodString>>;
15
+ rules: z.ZodOptional<z.ZodString>;
16
+ }, z.core.$strip>>;
13
17
  }, z.core.$strip>>;
14
18
  }, z.core.$strict>;