@grantcodes/style-dictionary 1.1.0 ā 1.2.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.
- package/.turbo/turbo-build.log +44 -0
- package/.turbo/turbo-lint.log +5 -0
- package/README.md +37 -0
- package/biome.json +9 -0
- package/build.js +10 -0
- package/config.js +485 -0
- package/demo.html +171 -0
- package/lib/color-generator.js +13 -0
- package/lib/get-style-dictionary-config.js +223 -0
- package/lib/get-themes.js +10 -0
- package/lib/index.js +3 -0
- package/package.json +57 -35
- package/tests/tokens.test.js +87 -0
- package/tokens/core/tier-1-definitions/colors.json +175 -0
- package/tokens/core/tier-1-definitions/z-index.json +29 -0
- package/tokens/grantcodes/tier-1-definitions/animation.json +27 -0
- package/tokens/grantcodes/tier-1-definitions/borders.json +36 -0
- package/tokens/grantcodes/tier-1-definitions/colors.json +35 -0
- package/tokens/grantcodes/tier-1-definitions/shadows.json +39 -0
- package/tokens/grantcodes/tier-1-definitions/typography.json +133 -0
- package/tokens/grantcodes/tier-2-usage/00-colors-background.json +72 -0
- package/tokens/grantcodes/tier-2-usage/00-colors-border.json +42 -0
- package/tokens/grantcodes/tier-2-usage/00-colors-content.json +45 -0
- package/tokens/grantcodes/tier-2-usage/animation.json +23 -0
- package/tokens/grantcodes/tier-2-usage/borders.json +26 -0
- package/tokens/grantcodes/tier-2-usage/shadows.json +39 -0
- package/tokens/grantcodes/tier-2-usage/typography-usage.json +277 -0
- package/tokens/grantcodes/tier-3-components/button.json +94 -0
- package/tokens/grantcodes/tier-3-components/focus-ring.json +26 -0
- package/tokens/grantcodes/tier-3-components/form.json +69 -0
- package/tokens/grantcodes/tier-3-components/link.json +39 -0
- package/tokens/todomap/tier-1-definitions/colors.json +92 -0
- package/tokens/todomap/tier-1-definitions/typography.json +10 -0
- package/tokens/todomap/tier-2-usage/00-colors-background.json +36 -0
- package/tokens/todomap/tier-2-usage/00-colors-content.json +33 -0
- package/tokens/todomap/tier-2-usage/typography-usage.json +20 -0
- package/tokens/todomap/tier-3-components/button.json +141 -0
- package/tokens/todomap/tier-3-components/focus-ring.json +26 -0
- package/tokens/todomap/tier-3-components/form.json +69 -0
- package/tokens/todomap/tier-3-components/link.json +39 -0
- package/tokens/wireframe/tier-1-definitions/animation.json +18 -0
- package/tokens/wireframe/tier-1-definitions/borders.json +42 -0
- package/tokens/wireframe/tier-1-definitions/colors.json +36 -0
- package/tokens/wireframe/tier-1-definitions/shadows.json +39 -0
- package/tokens/wireframe/tier-1-definitions/typography.json +130 -0
- package/tokens/wireframe/tier-2-usage/00-colors-background.json +86 -0
- package/tokens/wireframe/tier-2-usage/00-colors-border.json +42 -0
- package/tokens/wireframe/tier-2-usage/00-colors-content.json +45 -0
- package/tokens/wireframe/tier-2-usage/animation.json +24 -0
- package/tokens/wireframe/tier-2-usage/borders.json +33 -0
- package/tokens/wireframe/tier-2-usage/shadows.json +39 -0
- package/tokens/wireframe/tier-2-usage/typography-usage.json +445 -0
- package/tokens/wireframe/tier-3-components/button.json +94 -0
- package/tokens/wireframe/tier-3-components/focus-ring.json +26 -0
- package/tokens/wireframe/tier-3-components/form.json +69 -0
- package/tokens/wireframe/tier-3-components/link.json +39 -0
- package/.github/workflows/create-release.yml +0 -45
- package/.simple-git-hooks.cjs +0 -1
- package/commitlint.config.cjs +0 -1
- package/dist/css/default/style-dictionary.css +0 -181
- package/dist/css/todomap/style-dictionary.css +0 -181
- package/dist/js/default/style-dictionary.js +0 -179
- package/dist/js/todomap/style-dictionary.js +0 -179
- package/dist/scss/default/_style-dictionary.scss +0 -181
- package/dist/scss/todomap/_style-dictionary.scss +0 -181
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
|
|
2
|
+
> @grantcodes/style-dictionary@1.2.0 build /home/grantcodes/projects/@grantcodes/ui/packages/style-dictionary
|
|
3
|
+
> node ./build.js
|
|
4
|
+
|
|
5
|
+
š§ No theme specified, building all themes...
|
|
6
|
+
|
|
7
|
+
šļø Building WIREFRAME theme
|
|
8
|
+
|
|
9
|
+
šļø Building GRANTCODES theme
|
|
10
|
+
|
|
11
|
+
šļø Building TODOMAP theme
|
|
12
|
+
|
|
13
|
+
css
|
|
14
|
+
āļø dist/css/todomap/tokens.css
|
|
15
|
+
āļø dist/css/todomap/todomap.css
|
|
16
|
+
|
|
17
|
+
json
|
|
18
|
+
āļø dist/json/todomap/tokens.json
|
|
19
|
+
|
|
20
|
+
css
|
|
21
|
+
āļø dist/css/grantcodes/tokens.css
|
|
22
|
+
āļø dist/css/grantcodes/grantcodes.css
|
|
23
|
+
|
|
24
|
+
json
|
|
25
|
+
āļø dist/json/grantcodes/tokens.json
|
|
26
|
+
|
|
27
|
+
css
|
|
28
|
+
āļø dist/css/wireframe/tokens.css
|
|
29
|
+
āļø dist/css/wireframe/wireframe.css
|
|
30
|
+
|
|
31
|
+
json
|
|
32
|
+
āļø dist/json/wireframe/tokens.json
|
|
33
|
+
|
|
34
|
+
ts
|
|
35
|
+
āļø dist/js/todomap/style-dictionary.js
|
|
36
|
+
āļø dist/js/todomap/style-dictionary.d.ts
|
|
37
|
+
|
|
38
|
+
ts
|
|
39
|
+
āļø dist/js/grantcodes/style-dictionary.js
|
|
40
|
+
āļø dist/js/grantcodes/style-dictionary.d.ts
|
|
41
|
+
|
|
42
|
+
ts
|
|
43
|
+
āļø dist/js/wireframe/style-dictionary.js
|
|
44
|
+
āļø dist/js/wireframe/style-dictionary.d.ts
|
package/README.md
CHANGED
|
@@ -1,3 +1,40 @@
|
|
|
1
1
|
# @grantcodes/style-dictionary
|
|
2
2
|
|
|
3
3
|
This is my personal [style dictionary](https://github.com/amzn/style-dictionary) that I use for various personal projects.
|
|
4
|
+
|
|
5
|
+
## Naming & structure
|
|
6
|
+
|
|
7
|
+
It follows [Brad Frost's](https://bradfrost.com) recommended token structure.
|
|
8
|
+
|
|
9
|
+
Priciples:
|
|
10
|
+
|
|
11
|
+
- Clarity over cleverness - keep the names simple and understandable
|
|
12
|
+
- Legibility over succinctiness - long but readable variables > short hard to understand variables
|
|
13
|
+
- Consistency is key
|
|
14
|
+
- Use existing conventions
|
|
15
|
+
- Be environment agnostic - don't name things specifically for the web or mobile
|
|
16
|
+
|
|
17
|
+
### Tier 1 tokens
|
|
18
|
+
|
|
19
|
+
| Namespace | Category | Property | Variant / Scale | CSS Variable |
|
|
20
|
+
---------------------------------------------------------------
|
|
21
|
+
| g | color | red | 100 | --g-color-red-100 |
|
|
22
|
+
| g | typography | | | --g- |
|
|
23
|
+
| g | spacing | | | --g- |
|
|
24
|
+
| g | border | | | --g- |
|
|
25
|
+
| g | shadow | | | --g- |
|
|
26
|
+
| g | animation | | | --g- |
|
|
27
|
+
| g | breakpoint | | | --g- |
|
|
28
|
+
| g | z-index | | | --g- |
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
```css
|
|
35
|
+
|
|
36
|
+
@import "@grantcodes/style-dictionary";
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
```
|
package/biome.json
ADDED
package/build.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build script to create style dictionary outputs for each theme
|
|
3
|
+
* This now uses the config.js file which contains all the build logic
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// The build logic is now in config.js and runs automatically when executed
|
|
7
|
+
// This file can be kept for backwards compatibility or removed
|
|
8
|
+
// Run: node config.js or node build.js (which runs config.js)
|
|
9
|
+
|
|
10
|
+
import "./config.js";
|
package/config.js
ADDED
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
import StyleDictionary from "style-dictionary";
|
|
2
|
+
import minimist from "minimist";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* List of themes to build
|
|
6
|
+
* 1) Add your new theme here in order to have it show up in the dropdown
|
|
7
|
+
*/
|
|
8
|
+
const AVAILABLE_THEMES = ["wireframe", "grantcodes", "todomap"];
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Look for args passed on the command line
|
|
12
|
+
* 1) Used to build a single theme if needed
|
|
13
|
+
* 2) Pass in the theme name as an argument
|
|
14
|
+
* 3) If no argument is passed, build all themes
|
|
15
|
+
*/
|
|
16
|
+
const args = minimist(process.argv.slice(2));
|
|
17
|
+
const theme = args.theme;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Helper function to check if token is from tier-2 or tier-3
|
|
21
|
+
* 1) Used to determine if the token should be included in the theme tokens to apply `theme` prefix
|
|
22
|
+
*/
|
|
23
|
+
const isHigherTierToken = (filePath) => {
|
|
24
|
+
const isHigherTier =
|
|
25
|
+
filePath.includes("tier-2-usage") || filePath.includes("tier-3-components");
|
|
26
|
+
return isHigherTier;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Transform shadow tokens
|
|
31
|
+
* 1) Used to transform the individual shadow tokens into a single box-shadow-sm, box-shadow-md, etc. with x, y, blur, spread, and color concatenated
|
|
32
|
+
*/
|
|
33
|
+
const transformShadowTokens = (dictionary, size, themeTokens) => {
|
|
34
|
+
const shadowProps = dictionary.allTokens.filter(
|
|
35
|
+
(p) =>
|
|
36
|
+
isHigherTierToken(p.filePath) &&
|
|
37
|
+
p.path[0] === "box-shadow" &&
|
|
38
|
+
p.path[1] === size,
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const x = shadowProps.find((p) => p.path[2] === "x")?.value || "0px";
|
|
42
|
+
const y = shadowProps.find((p) => p.path[2] === "y")?.value || "0px";
|
|
43
|
+
const blur = shadowProps.find((p) => p.path[2] === "blur")?.value || "0px";
|
|
44
|
+
const spread =
|
|
45
|
+
shadowProps.find((p) => p.path[2] === "spread")?.value || "0px";
|
|
46
|
+
const color =
|
|
47
|
+
shadowProps.find((p) => p.path[2] === "color")?.value || "transparent";
|
|
48
|
+
|
|
49
|
+
/* 1 */
|
|
50
|
+
themeTokens.push(
|
|
51
|
+
` --g-theme-box-shadow-${size}: ${x} ${y} ${blur} ${spread} ${color};`,
|
|
52
|
+
);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Transform line height tokens
|
|
57
|
+
* 1) Used to transform the line height tokens to a unitless value for CSS by dividing the line height by the font size
|
|
58
|
+
*/
|
|
59
|
+
const transformLineHeight = (
|
|
60
|
+
dictionary,
|
|
61
|
+
prop,
|
|
62
|
+
outputArray,
|
|
63
|
+
formatTokenName,
|
|
64
|
+
) => {
|
|
65
|
+
const cleanPath = prop.path
|
|
66
|
+
.map((segment) =>
|
|
67
|
+
segment.startsWith("@") ? segment.substring(1) : segment,
|
|
68
|
+
)
|
|
69
|
+
.filter((segment) => segment !== "")
|
|
70
|
+
.join("-");
|
|
71
|
+
|
|
72
|
+
// For tier-1 tokens (typography.line-height.16), find matching font-size (typography.font-size.16)
|
|
73
|
+
// For tier-2/3 tokens (typography.headline-lg.line-height), find matching font-size (typography.headline-lg.font-size)
|
|
74
|
+
const isTier1 =
|
|
75
|
+
prop.path.length === 3 &&
|
|
76
|
+
prop.path[0] === "typography" &&
|
|
77
|
+
prop.path[1] === "line-height";
|
|
78
|
+
let fontSizePath;
|
|
79
|
+
if (isTier1) {
|
|
80
|
+
// Tier-1: typography.line-height.16 -> typography.font-size.16
|
|
81
|
+
fontSizePath = ["typography", "font-size", prop.path[2]];
|
|
82
|
+
} else {
|
|
83
|
+
// Tier-2/3: typography.headline-lg.line-height -> typography.headline-lg.font-size
|
|
84
|
+
fontSizePath = [...prop.path.slice(0, -1), "font-size"];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const fontSizeProp = dictionary.allTokens.find(
|
|
88
|
+
(p) => p.path.join(".") === fontSizePath.join("."),
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
// Parse line-height value to pixels
|
|
92
|
+
let lineHeightPx;
|
|
93
|
+
if (prop.value.endsWith("px")) {
|
|
94
|
+
lineHeightPx = parseFloat(prop.value.replace("px", ""));
|
|
95
|
+
} else if (prop.value.endsWith("rem")) {
|
|
96
|
+
lineHeightPx = parseFloat(prop.value.replace("rem", "")) * 16;
|
|
97
|
+
} else {
|
|
98
|
+
lineHeightPx = parseFloat(prop.value);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (fontSizeProp) {
|
|
102
|
+
// Found matching font-size - use it for calculation
|
|
103
|
+
let fontSizePx;
|
|
104
|
+
if (fontSizeProp.value.endsWith("px")) {
|
|
105
|
+
fontSizePx = parseFloat(fontSizeProp.value.replace("px", ""));
|
|
106
|
+
} else if (fontSizeProp.value.endsWith("rem")) {
|
|
107
|
+
fontSizePx = parseFloat(fontSizeProp.value.replace("rem", "")) * 16;
|
|
108
|
+
} else {
|
|
109
|
+
fontSizePx = parseFloat(fontSizeProp.value);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (fontSizePx > 0) {
|
|
113
|
+
const unitlessValue = (lineHeightPx / fontSizePx).toFixed(2);
|
|
114
|
+
outputArray.push(
|
|
115
|
+
` ${formatTokenName(cleanPath, prop)}: ${unitlessValue};`,
|
|
116
|
+
);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
} else if (isTier1 && lineHeightPx > 0) {
|
|
120
|
+
// For tier-1 tokens without matching font-size, use 16px as base font-size
|
|
121
|
+
const BASE_FONT_SIZE = 16;
|
|
122
|
+
const unitlessValue = (lineHeightPx / BASE_FONT_SIZE).toFixed(2);
|
|
123
|
+
outputArray.push(
|
|
124
|
+
` ${formatTokenName(cleanPath, prop)}: ${unitlessValue};`,
|
|
125
|
+
);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Fallback: output as-is if we can't calculate
|
|
130
|
+
outputArray.push(` ${formatTokenName(cleanPath, prop)}: ${prop.value};`);
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Format variables
|
|
135
|
+
* 1) Used to format the inner contents of the :root or .[theme-name] ruleset
|
|
136
|
+
*/
|
|
137
|
+
const formatVariables = (dictionary) => {
|
|
138
|
+
const processedShadows = new Set();
|
|
139
|
+
const tier1Tokens = [];
|
|
140
|
+
const themeTokens = [];
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Format token global prefix and tier 2/3 identifier
|
|
144
|
+
* 1) If the token is from tier-2 or tier-3, prefix it with `g-theme-`
|
|
145
|
+
* 2) Otherwise, prefix it with `g-`
|
|
146
|
+
*/
|
|
147
|
+
const formatTokenName = (cleanPath, prop) => {
|
|
148
|
+
if (isHigherTierToken(prop.filePath)) {
|
|
149
|
+
return `--g-theme-${cleanPath}`;
|
|
150
|
+
}
|
|
151
|
+
return `--g-${cleanPath}`;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Get all box-shadow values from tier 2/3
|
|
156
|
+
* 1) Used to determine which box-shadow values to transform into a single box-shadow-sm, box-shadow-md, etc.
|
|
157
|
+
*/
|
|
158
|
+
const shadowSizes = dictionary.tokens.shadow
|
|
159
|
+
? Object.keys(dictionary.tokens.shadow)
|
|
160
|
+
.map((key) => key.split("-")[0])
|
|
161
|
+
.filter((value, index, self) => self.indexOf(value) === index) // Get unique sizes
|
|
162
|
+
: [];
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Iterate over all tokens and format them
|
|
166
|
+
*
|
|
167
|
+
*/
|
|
168
|
+
dictionary.allTokens.forEach((prop) => {
|
|
169
|
+
/**
|
|
170
|
+
* 1) Always include z-index and size tokens from core
|
|
171
|
+
*/
|
|
172
|
+
if (prop.path[0] === "z-index") {
|
|
173
|
+
const cleanPath = prop.path
|
|
174
|
+
.map((segment) =>
|
|
175
|
+
segment.startsWith("@") ? segment.substring(1) : segment,
|
|
176
|
+
)
|
|
177
|
+
.filter((segment) => segment !== "")
|
|
178
|
+
.join("-");
|
|
179
|
+
tier1Tokens.push(` ${formatTokenName(cleanPath, prop)}: ${prop.value};`);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Handle box-shadow token transformations
|
|
185
|
+
* If the token is from tier-2 or tier-3 and is a box-shadow, transform it into a single box-shadow-sm, box-shadow-md, etc.
|
|
186
|
+
*/
|
|
187
|
+
if (
|
|
188
|
+
isHigherTierToken(prop.filePath) &&
|
|
189
|
+
prop.path[0] === "box-shadow" &&
|
|
190
|
+
shadowSizes.includes(prop.path[1])
|
|
191
|
+
) {
|
|
192
|
+
const size = prop.path[1];
|
|
193
|
+
if (processedShadows.has(size)) return;
|
|
194
|
+
processedShadows.add(size);
|
|
195
|
+
transformShadowTokens(dictionary, size, themeTokens);
|
|
196
|
+
} else if (
|
|
197
|
+
prop.path[0] === "typography" &&
|
|
198
|
+
prop.path.includes("line-height")
|
|
199
|
+
) {
|
|
200
|
+
/**
|
|
201
|
+
* Handle line heights in typography (both tier-1 and tier-2/3)
|
|
202
|
+
* 1) Transform line-height tokens to unitless values by dividing by font-size
|
|
203
|
+
*/
|
|
204
|
+
const outputArray = isHigherTierToken(prop.filePath)
|
|
205
|
+
? themeTokens
|
|
206
|
+
: tier1Tokens;
|
|
207
|
+
transformLineHeight(dictionary, prop, outputArray, formatTokenName);
|
|
208
|
+
} else if (!prop.path.includes("box-shadow") || prop.path.length > 3) {
|
|
209
|
+
/**
|
|
210
|
+
* Handle all other properties
|
|
211
|
+
* 1) If the token is not a box-shadow or typography token, format it as a normal token
|
|
212
|
+
*/
|
|
213
|
+
const cleanPath = prop.path
|
|
214
|
+
.map((segment) =>
|
|
215
|
+
segment.startsWith("@") ? segment.substring(1) : segment,
|
|
216
|
+
)
|
|
217
|
+
.filter((segment) => segment !== "")
|
|
218
|
+
.join("-");
|
|
219
|
+
|
|
220
|
+
const token = ` ${formatTokenName(cleanPath, prop)}: ${prop.value};`;
|
|
221
|
+
if (isHigherTierToken(prop.filePath)) {
|
|
222
|
+
themeTokens.push(token);
|
|
223
|
+
} else {
|
|
224
|
+
tier1Tokens.push(token);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
return [...new Set([...tier1Tokens, ...themeTokens])].join("\n");
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Transform shadow tokens for JSON format
|
|
234
|
+
* Combines individual shadow properties into a single value
|
|
235
|
+
*/
|
|
236
|
+
const transformShadowTokensJSON = (dictionary, size) => {
|
|
237
|
+
const shadowProps = dictionary.allTokens.filter(
|
|
238
|
+
(p) =>
|
|
239
|
+
isHigherTierToken(p.filePath) &&
|
|
240
|
+
p.path[0] === "box-shadow" &&
|
|
241
|
+
p.path[1] === size,
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
const x = shadowProps.find((p) => p.path[2] === "x")?.value || "0px";
|
|
245
|
+
const y = shadowProps.find((p) => p.path[2] === "y")?.value || "0px";
|
|
246
|
+
const blur = shadowProps.find((p) => p.path[2] === "blur")?.value || "0px";
|
|
247
|
+
const spread =
|
|
248
|
+
shadowProps.find((p) => p.path[2] === "spread")?.value || "0px";
|
|
249
|
+
const color =
|
|
250
|
+
shadowProps.find((p) => p.path[2] === "color")?.value || "transparent";
|
|
251
|
+
|
|
252
|
+
return `${x} ${y} ${blur} ${spread} ${color}`;
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Generate a Theme-Specific Config
|
|
257
|
+
* This accepts a theme parameter, which is used to control which set of
|
|
258
|
+
* tokens to compile, and to define theme-specific compiled output.
|
|
259
|
+
* @param {string} theme
|
|
260
|
+
*/
|
|
261
|
+
const getStyleDictionaryConfig = (theme) => {
|
|
262
|
+
// Register the JSON formatter
|
|
263
|
+
StyleDictionary.registerFormat({
|
|
264
|
+
name: "json/flat/custom",
|
|
265
|
+
format: function (dictionary) {
|
|
266
|
+
const transformedTokens = {};
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Get all box-shadow values from tier 2/3
|
|
270
|
+
* 1) Used to determine which box-shadow values to transform into a single box-shadow-sm, box-shadow-md, etc.
|
|
271
|
+
*/
|
|
272
|
+
const shadowSizes = dictionary.tokens.shadow
|
|
273
|
+
? Object.keys(dictionary.tokens.shadow)
|
|
274
|
+
.map((key) => key.split("-")[0])
|
|
275
|
+
.filter((value, index, self) => self.indexOf(value) === index) // Get unique sizes
|
|
276
|
+
: [];
|
|
277
|
+
|
|
278
|
+
// Process regular tokens
|
|
279
|
+
dictionary.allTokens.forEach((token) => {
|
|
280
|
+
// Remove the isHigherTierToken check to include all tokens
|
|
281
|
+
if (token.path[0] === "box-shadow" && token.path.length > 2) return;
|
|
282
|
+
const prefix = isHigherTierToken(token.filePath) ? "g-theme-" : "g-";
|
|
283
|
+
transformedTokens[`${prefix}${token.path.join("-")}`] = token.value;
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
// Process shadow tokens
|
|
287
|
+
shadowSizes.forEach((size) => {
|
|
288
|
+
transformedTokens[`g-theme-box-shadow-${size}`] =
|
|
289
|
+
transformShadowTokensJSON(dictionary, size);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
return JSON.stringify(transformedTokens, null, 2);
|
|
293
|
+
},
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Register the CSS formatter
|
|
298
|
+
* 1) Used to format the inner contents of the .[theme-name] ruleset for Storybook only or if you want to define tokens using a theme name
|
|
299
|
+
*/
|
|
300
|
+
StyleDictionary.registerFormat({
|
|
301
|
+
name: "css/variables-themed",
|
|
302
|
+
format: function (dictionary) {
|
|
303
|
+
return `.${theme} {\n${formatVariables(dictionary)}\n}\n`;
|
|
304
|
+
},
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Define the base pixel value for rem conversion
|
|
309
|
+
*/
|
|
310
|
+
const BASE_FONT_SIZE = 16; // Typically 16px = 1rem
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Register the size/px-to-rem transform
|
|
314
|
+
* 1) Used to convert px values to rem values
|
|
315
|
+
* 2) Match only properties with px values
|
|
316
|
+
* 3) Only transform if it's a valid px value
|
|
317
|
+
*/
|
|
318
|
+
StyleDictionary.registerTransform({
|
|
319
|
+
name: "size/px-to-rem",
|
|
320
|
+
type: "value",
|
|
321
|
+
matcher: function (prop) {
|
|
322
|
+
/* 2 */
|
|
323
|
+
return (
|
|
324
|
+
prop &&
|
|
325
|
+
prop.value &&
|
|
326
|
+
typeof prop.value === "string" &&
|
|
327
|
+
prop.value.endsWith("px")
|
|
328
|
+
);
|
|
329
|
+
},
|
|
330
|
+
transform: function (prop) {
|
|
331
|
+
if (!prop || !prop.value) return prop.value;
|
|
332
|
+
/* 3 */
|
|
333
|
+
const pxValue = prop.value.trim();
|
|
334
|
+
if (!pxValue.endsWith("px")) return prop.value;
|
|
335
|
+
|
|
336
|
+
const pixels = parseFloat(pxValue);
|
|
337
|
+
if (isNaN(pixels)) return prop.value;
|
|
338
|
+
|
|
339
|
+
const remValue = Number((pixels / BASE_FONT_SIZE).toFixed(4)).toString();
|
|
340
|
+
return `${remValue}rem`;
|
|
341
|
+
},
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Register the CSS formatter
|
|
346
|
+
* 1) Used to format the inner contents of the :root ruleset for Storybook only or if you want to define tokens with theme prefix
|
|
347
|
+
*/
|
|
348
|
+
StyleDictionary.registerFormat({
|
|
349
|
+
name: "css/custom-variables",
|
|
350
|
+
format: function (dictionary) {
|
|
351
|
+
return `:root {\n${formatVariables(dictionary)}\n}`;
|
|
352
|
+
},
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Register the name/theme-prefix transform
|
|
357
|
+
* 1) Used to prefix the token name with the theme name
|
|
358
|
+
* 2) If the token is from tier-2 or tier-3, prefix it with `GTheme` for JS
|
|
359
|
+
* 3) Otherwise, prefix it with `G` for JS
|
|
360
|
+
*/
|
|
361
|
+
StyleDictionary.registerTransform({
|
|
362
|
+
name: "name/theme-prefix",
|
|
363
|
+
type: "name",
|
|
364
|
+
transform: function (token) {
|
|
365
|
+
const cleanPath = token.path
|
|
366
|
+
.map((segment) =>
|
|
367
|
+
segment.startsWith("@") ? segment.substring(1) : segment,
|
|
368
|
+
)
|
|
369
|
+
.filter((segment) => segment !== "")
|
|
370
|
+
.join("-");
|
|
371
|
+
|
|
372
|
+
/* 2 */
|
|
373
|
+
if (isHigherTierToken(token.filePath)) {
|
|
374
|
+
return `GTheme${cleanPath
|
|
375
|
+
.split("-")
|
|
376
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
377
|
+
.join("")}`;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/* 3 */
|
|
381
|
+
return `G${cleanPath
|
|
382
|
+
.split("-")
|
|
383
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
384
|
+
.join("")}`;
|
|
385
|
+
},
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Register the custom/css transform group
|
|
390
|
+
*/
|
|
391
|
+
StyleDictionary.registerTransformGroup({
|
|
392
|
+
name: "custom/css",
|
|
393
|
+
transforms: ["attribute/cti", "name/kebab", "size/px-to-rem"],
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Register the custom/js transform group
|
|
398
|
+
*/
|
|
399
|
+
StyleDictionary.registerTransformGroup({
|
|
400
|
+
name: "custom/js",
|
|
401
|
+
transforms: ["attribute/cti", "name/theme-prefix", "size/px-to-rem"],
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Define the config
|
|
406
|
+
* 1) Used to define the platforms, prefixes, etc. to build the tokens with/for
|
|
407
|
+
*/
|
|
408
|
+
const config = {
|
|
409
|
+
source: [`./tokens/core/**/*.json`, `./tokens/${theme}/**/*.json`],
|
|
410
|
+
log: {
|
|
411
|
+
// Set the log level to show errors, warnings, and info messages
|
|
412
|
+
verbosity: "verbose",
|
|
413
|
+
},
|
|
414
|
+
platforms: {
|
|
415
|
+
ts: {
|
|
416
|
+
transformGroup: "custom/js",
|
|
417
|
+
prefix: "G",
|
|
418
|
+
buildPath: `./dist/js/${theme}/`,
|
|
419
|
+
filter: {
|
|
420
|
+
attributes: {
|
|
421
|
+
category: "theme",
|
|
422
|
+
},
|
|
423
|
+
},
|
|
424
|
+
files: [
|
|
425
|
+
{
|
|
426
|
+
destination: "style-dictionary.js",
|
|
427
|
+
format: "javascript/es6",
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
destination: "style-dictionary.d.ts",
|
|
431
|
+
format: "typescript/es6-declarations",
|
|
432
|
+
},
|
|
433
|
+
],
|
|
434
|
+
},
|
|
435
|
+
css: {
|
|
436
|
+
transformGroup: "custom/css",
|
|
437
|
+
prefix: "g",
|
|
438
|
+
buildPath: `./dist/css/${theme}/`,
|
|
439
|
+
files: [
|
|
440
|
+
{
|
|
441
|
+
destination: "tokens.css",
|
|
442
|
+
format: "css/custom-variables",
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
destination: `${theme}.css`,
|
|
446
|
+
format: "css/variables-themed",
|
|
447
|
+
},
|
|
448
|
+
],
|
|
449
|
+
},
|
|
450
|
+
json: {
|
|
451
|
+
transformGroup: "custom/css",
|
|
452
|
+
prefix: "g",
|
|
453
|
+
buildPath: `./dist/json/${theme}/`,
|
|
454
|
+
files: [
|
|
455
|
+
{
|
|
456
|
+
destination: "tokens.json",
|
|
457
|
+
format: "json/flat/custom",
|
|
458
|
+
},
|
|
459
|
+
],
|
|
460
|
+
},
|
|
461
|
+
},
|
|
462
|
+
};
|
|
463
|
+
|
|
464
|
+
return config;
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Build the tokens
|
|
469
|
+
* 1) If no theme is specified, build all themes
|
|
470
|
+
* 2) Otherwise, build the specified theme
|
|
471
|
+
*/
|
|
472
|
+
if (!theme) {
|
|
473
|
+
console.log("š§ No theme specified, building all themes...");
|
|
474
|
+
AVAILABLE_THEMES.forEach((themeName) => {
|
|
475
|
+
console.log(`\nšļø Building ${themeName.toUpperCase()} theme`);
|
|
476
|
+
const themeConfig = getStyleDictionaryConfig(themeName);
|
|
477
|
+
const StyleDictionaryExtended = new StyleDictionary(themeConfig);
|
|
478
|
+
StyleDictionaryExtended.buildAllPlatforms();
|
|
479
|
+
});
|
|
480
|
+
} else {
|
|
481
|
+
console.log(`š§ Building ${theme.toUpperCase()} theme`);
|
|
482
|
+
const config = getStyleDictionaryConfig(theme);
|
|
483
|
+
const StyleDictionaryExtended = new StyleDictionary(config);
|
|
484
|
+
StyleDictionaryExtended.buildAllPlatforms();
|
|
485
|
+
}
|