@baloise/ds-tokens 19.9.4 → 20.0.0-next.4
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/LICENSE +2 -2
- package/README.md +2 -6
- package/dist/css/base.tokens.css +1417 -0
- package/dist/css/tcs.tokens.css +35 -0
- package/dist/docs/base.tokens.json +49885 -0
- package/dist/js/base.tokens.js +1236 -0
- package/dist/out-tsc/config.base.js +85 -0
- package/dist/out-tsc/config.brand.js +82 -0
- package/dist/out-tsc/formatter.js +236 -0
- package/dist/out-tsc/index.js +43 -0
- package/dist/out-tsc/transformers.js +150 -0
- package/dist/sass/base.tokens.scss +1192 -0
- package/dist/web/base.tokens.json +1191 -0
- package/package.json +13 -8
- package/dist/deprecated/tokens.css +0 -119
- package/dist/deprecated/tokens.css.scss +0 -119
- package/dist/deprecated/tokens.docs.json +0 -2764
- package/dist/deprecated/tokens.json +0 -114
- package/dist/deprecated/tokens.less +0 -116
- package/dist/deprecated/tokens.scss +0 -116
- package/dist/figma/color.json +0 -606
- package/dist/figma/size.json +0 -232
- package/dist/tokens.css +0 -270
- package/dist/tokens.css.scss +0 -270
- package/dist/tokens.docs.json +0 -5853
- package/dist/tokens.esm.js +0 -268
- package/dist/tokens.js +0 -270
- package/dist/tokens.json +0 -265
- package/dist/tokens.less +0 -267
- package/dist/tokens.scss +0 -267
- package/dist/types/tokens.d.ts +0 -350
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
const basePxFontSize = 16;
|
|
2
|
+
const mode = 'Base';
|
|
3
|
+
const config = {
|
|
4
|
+
source: [`tokens/${mode}.tokens.json`],
|
|
5
|
+
platforms: {
|
|
6
|
+
css: {
|
|
7
|
+
transformGroup: 'css',
|
|
8
|
+
transforms: ['ds/css/name', 'ds/color/rgba', 'ds/size/round', 'ds/size/rem'],
|
|
9
|
+
basePxFontSize,
|
|
10
|
+
buildPath: 'dist/',
|
|
11
|
+
prefix: 'ds',
|
|
12
|
+
files: [
|
|
13
|
+
{
|
|
14
|
+
format: 'ds/css/variables-responsive',
|
|
15
|
+
destination: `css/${mode.toLowerCase()}.tokens.css`,
|
|
16
|
+
},
|
|
17
|
+
],
|
|
18
|
+
options: {
|
|
19
|
+
outputReferences: true,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
scss: {
|
|
23
|
+
transformGroup: 'scss',
|
|
24
|
+
transforms: ['ds/css/name', 'ds/color/rgba', 'ds/size/round', 'ds/size/rem'],
|
|
25
|
+
basePxFontSize,
|
|
26
|
+
buildPath: 'dist/',
|
|
27
|
+
prefix: 'ds',
|
|
28
|
+
files: [
|
|
29
|
+
{
|
|
30
|
+
format: 'scss/variables',
|
|
31
|
+
destination: `sass/${mode.toLowerCase()}.tokens.scss`,
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
options: {
|
|
35
|
+
outputReferences: true,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
web: {
|
|
39
|
+
transformGroup: 'web',
|
|
40
|
+
transforms: ['ds/css/name', 'ds/color/hex', 'ds/size/rem'],
|
|
41
|
+
prefix: 'ds',
|
|
42
|
+
buildPath: 'dist/',
|
|
43
|
+
files: [
|
|
44
|
+
{
|
|
45
|
+
format: 'json/flat',
|
|
46
|
+
destination: `web/${mode.toLowerCase()}.tokens.json`,
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
options: {
|
|
50
|
+
outputReferences: true,
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
docs: {
|
|
54
|
+
transformGroup: 'web',
|
|
55
|
+
transforms: ['ds/css/name', 'ds/color/hex', 'ds/size/rem'],
|
|
56
|
+
prefix: 'ds',
|
|
57
|
+
buildPath: 'dist/',
|
|
58
|
+
files: [
|
|
59
|
+
{
|
|
60
|
+
format: 'json',
|
|
61
|
+
destination: `docs/${mode.toLowerCase()}.tokens.json`,
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
options: {
|
|
65
|
+
outputReferences: true,
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
javascript: {
|
|
69
|
+
transformGroup: 'js',
|
|
70
|
+
transforms: ['ds/js/name', 'ds/color/hex', 'ds/size/round'],
|
|
71
|
+
prefix: 'ds',
|
|
72
|
+
buildPath: 'dist/',
|
|
73
|
+
files: [
|
|
74
|
+
{
|
|
75
|
+
format: 'javascript/es6',
|
|
76
|
+
destination: `js/${mode.toLowerCase()}.tokens.js`,
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
options: {
|
|
80
|
+
outputReferences: true,
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
export default config;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, unlinkSync } from 'fs';
|
|
2
|
+
const basePxFontSize = 16;
|
|
3
|
+
/**
|
|
4
|
+
* Recursively walks both token trees and returns only the tokens whose
|
|
5
|
+
* `$value` differs from the base. Keeps the full hierarchy so Style
|
|
6
|
+
* Dictionary can still resolve references.
|
|
7
|
+
*/
|
|
8
|
+
function computeTokenDiff(base, brand) {
|
|
9
|
+
const result = {};
|
|
10
|
+
for (const [key, brandVal] of Object.entries(brand)) {
|
|
11
|
+
if (typeof brandVal !== 'object' || brandVal === null)
|
|
12
|
+
continue;
|
|
13
|
+
const baseVal = (base?.[key] ?? {});
|
|
14
|
+
if ('$value' in brandVal) {
|
|
15
|
+
// Token leaf — only keep it when the value actually changed
|
|
16
|
+
const brandSerialized = JSON.stringify(brandVal['$value']);
|
|
17
|
+
const baseSerialized = JSON.stringify(baseVal['$value']);
|
|
18
|
+
if (brandSerialized !== baseSerialized) {
|
|
19
|
+
result[key] = brandVal;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
// Group node — recurse and only include if something inside changed
|
|
24
|
+
const nested = computeTokenDiff(baseVal, brandVal);
|
|
25
|
+
if (Object.keys(nested).length > 0) {
|
|
26
|
+
result[key] = nested;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Creates a Style Dictionary config for a brand override build.
|
|
34
|
+
*
|
|
35
|
+
* Computes the diff between Base and the brand token file so that only
|
|
36
|
+
* genuinely changed tokens end up in the output CSS. Works whether the brand
|
|
37
|
+
* file is a minimal override or a full Figma-mode export with all tokens.
|
|
38
|
+
*
|
|
39
|
+
* Returns the config and a `cleanup` function that removes the temporary diff
|
|
40
|
+
* file that was written to disk so Style Dictionary can mark it as `source`.
|
|
41
|
+
*/
|
|
42
|
+
export function createBrandConfig(mode) {
|
|
43
|
+
const selector = `[data-theme="${mode.toLowerCase()}"]`;
|
|
44
|
+
const tmpFile = `tokens/.${mode.toLowerCase()}-diff.tmp.json`;
|
|
45
|
+
const baseJson = JSON.parse(readFileSync(`tokens/Base.tokens.json`, 'utf8'));
|
|
46
|
+
const brandJson = JSON.parse(readFileSync(`tokens/${mode}.tokens.json`, 'utf8'));
|
|
47
|
+
const diffTokens = computeTokenDiff(baseJson, brandJson);
|
|
48
|
+
// Write diff to a temp file — Style Dictionary only marks file-based source
|
|
49
|
+
// tokens as isSource:true, which is required for the brand formatter filter.
|
|
50
|
+
writeFileSync(tmpFile, JSON.stringify(diffTokens));
|
|
51
|
+
const config = {
|
|
52
|
+
include: [`tokens/Base.tokens.json`],
|
|
53
|
+
source: [tmpFile],
|
|
54
|
+
platforms: {
|
|
55
|
+
css: {
|
|
56
|
+
transforms: ['name/kebab', 'ds/css/name', 'ds/color/rgba', 'ds/size/round', 'ds/size/rem'],
|
|
57
|
+
basePxFontSize,
|
|
58
|
+
buildPath: 'dist/',
|
|
59
|
+
prefix: 'ds',
|
|
60
|
+
files: [
|
|
61
|
+
{
|
|
62
|
+
format: 'ds/css/variables-brand',
|
|
63
|
+
destination: `css/${mode.toLowerCase()}.tokens.css`,
|
|
64
|
+
options: {
|
|
65
|
+
selector,
|
|
66
|
+
outputReferences: true,
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
const cleanup = () => {
|
|
74
|
+
try {
|
|
75
|
+
unlinkSync(tmpFile);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// ignore — file may already be gone
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
return { config, cleanup };
|
|
82
|
+
}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { fileHeader, formattedVariables } from 'style-dictionary/utils';
|
|
2
|
+
import { propertyFormatNames } from 'style-dictionary/enums';
|
|
3
|
+
export const registerCustomFormatters = (sd) => {
|
|
4
|
+
/**
|
|
5
|
+
* CSS Responsive Formatter
|
|
6
|
+
* ------------------------------------------------------
|
|
7
|
+
*/
|
|
8
|
+
sd.registerFormat({
|
|
9
|
+
name: 'ds/css/variables-responsive',
|
|
10
|
+
format: async ({ dictionary, file, options }) => {
|
|
11
|
+
const { outputReferences } = options;
|
|
12
|
+
const header = await fileHeader({ file });
|
|
13
|
+
// find reponsive tokens in dictionary which ends with -mobile, -tablet or -desktop
|
|
14
|
+
const baseTokensOriginal = dictionary.allTokens.filter(token => token.name.endsWith('-mobile'));
|
|
15
|
+
// create a deeop copy of base tokens
|
|
16
|
+
const baseTokens = JSON.parse(JSON.stringify(baseTokensOriginal));
|
|
17
|
+
const deviceBaseTokens = JSON.parse(JSON.stringify(baseTokensOriginal));
|
|
18
|
+
//
|
|
19
|
+
// Base tokens
|
|
20
|
+
// ------------------------------------------------------
|
|
21
|
+
// same as mobile but without the suffix
|
|
22
|
+
baseTokens.forEach(token => {
|
|
23
|
+
token.name = token.name.replace('-mobile', '');
|
|
24
|
+
});
|
|
25
|
+
const baseDictionary = {
|
|
26
|
+
...dictionary,
|
|
27
|
+
allTokens: baseTokens,
|
|
28
|
+
};
|
|
29
|
+
//
|
|
30
|
+
// Device tokens
|
|
31
|
+
// ------------------------------------------------------
|
|
32
|
+
// same as mobile but without the suffix
|
|
33
|
+
deviceBaseTokens.forEach(token => {
|
|
34
|
+
token.name = token.name.replace('-mobile', '-device');
|
|
35
|
+
});
|
|
36
|
+
const deviceBaseDictionary = {
|
|
37
|
+
...dictionary,
|
|
38
|
+
allTokens: deviceBaseTokens,
|
|
39
|
+
};
|
|
40
|
+
const tabletTokensOriginal = dictionary.allTokens.filter(token => token.name.endsWith('-tablet'));
|
|
41
|
+
const deviceTabletTokens = JSON.parse(JSON.stringify(tabletTokensOriginal));
|
|
42
|
+
deviceTabletTokens.forEach(token => {
|
|
43
|
+
token.name = token.name.replace('-tablet', '-device');
|
|
44
|
+
});
|
|
45
|
+
const deviceTabletDictionary = {
|
|
46
|
+
...dictionary,
|
|
47
|
+
allTokens: deviceTabletTokens,
|
|
48
|
+
};
|
|
49
|
+
const desktopTokensOriginal = dictionary.allTokens.filter(token => token.name.endsWith('-desktop'));
|
|
50
|
+
const deviceDesktopTokens = JSON.parse(JSON.stringify(desktopTokensOriginal));
|
|
51
|
+
deviceDesktopTokens.forEach(token => {
|
|
52
|
+
token.name = token.name.replace('-desktop', '-device');
|
|
53
|
+
});
|
|
54
|
+
const deviceDesktopDictionary = {
|
|
55
|
+
...dictionary,
|
|
56
|
+
allTokens: deviceDesktopTokens,
|
|
57
|
+
};
|
|
58
|
+
// const mobileCss =
|
|
59
|
+
// ':root {\n' +
|
|
60
|
+
// formattedVariables({
|
|
61
|
+
// format: propertyFormatNames.css,
|
|
62
|
+
// dictionary,
|
|
63
|
+
// outputReferences,
|
|
64
|
+
// usesDtcg: true,
|
|
65
|
+
// }) +
|
|
66
|
+
// '\n\n' +
|
|
67
|
+
// ' /* Base tokens */\n' +
|
|
68
|
+
// formattedVariables({
|
|
69
|
+
// format: propertyFormatNames.css,
|
|
70
|
+
// dictionary: baseDictionary,
|
|
71
|
+
// outputReferences,
|
|
72
|
+
// usesDtcg: true,
|
|
73
|
+
// }) +
|
|
74
|
+
// '\n\n' +
|
|
75
|
+
// ' /* Device tokens */\n' +
|
|
76
|
+
// formattedVariables({
|
|
77
|
+
// format: propertyFormatNames.css,
|
|
78
|
+
// dictionary: deviceBaseDictionary,
|
|
79
|
+
// outputReferences,
|
|
80
|
+
// usesDtcg: true,
|
|
81
|
+
// }) +
|
|
82
|
+
// '\n}\n\n' +
|
|
83
|
+
// '/* Device tokens: Tablet */\n' +
|
|
84
|
+
// `\n@media (min-width: 769px) {\n` +
|
|
85
|
+
// formattedVariables({
|
|
86
|
+
// format: propertyFormatNames.css,
|
|
87
|
+
// dictionary: deviceTabletDictionary,
|
|
88
|
+
// outputReferences,
|
|
89
|
+
// usesDtcg: true,
|
|
90
|
+
// }) +
|
|
91
|
+
// `\n}\n\n` +
|
|
92
|
+
// '/* Device tokens: Desktop */\n' +
|
|
93
|
+
// `\n@media (min-width: 1024px) {\n` +
|
|
94
|
+
// formattedVariables({
|
|
95
|
+
// format: propertyFormatNames.css,
|
|
96
|
+
// dictionary: deviceDesktopDictionary,
|
|
97
|
+
// outputReferences,
|
|
98
|
+
// usesDtcg: true,
|
|
99
|
+
// }) +
|
|
100
|
+
// `\n}\n` +
|
|
101
|
+
// '\n'
|
|
102
|
+
return (header +
|
|
103
|
+
':root {\n' +
|
|
104
|
+
formattedVariables({
|
|
105
|
+
format: propertyFormatNames.css,
|
|
106
|
+
dictionary,
|
|
107
|
+
outputReferences,
|
|
108
|
+
usesDtcg: true,
|
|
109
|
+
}) +
|
|
110
|
+
'\n\n' +
|
|
111
|
+
' /* Base tokens */\n' +
|
|
112
|
+
formattedVariables({
|
|
113
|
+
format: propertyFormatNames.css,
|
|
114
|
+
dictionary: baseDictionary,
|
|
115
|
+
outputReferences,
|
|
116
|
+
usesDtcg: true,
|
|
117
|
+
}) +
|
|
118
|
+
'\n\n' +
|
|
119
|
+
' /* Device tokens */\n' +
|
|
120
|
+
formattedVariables({
|
|
121
|
+
format: propertyFormatNames.css,
|
|
122
|
+
dictionary: deviceBaseDictionary,
|
|
123
|
+
outputReferences,
|
|
124
|
+
usesDtcg: true,
|
|
125
|
+
}) +
|
|
126
|
+
'\n}\n\n' +
|
|
127
|
+
'/* Device tokens: Tablet */\n' +
|
|
128
|
+
`\n@media (min-width: 769px) {\n` +
|
|
129
|
+
':root {\n' +
|
|
130
|
+
formattedVariables({
|
|
131
|
+
format: propertyFormatNames.css,
|
|
132
|
+
dictionary: deviceTabletDictionary,
|
|
133
|
+
outputReferences,
|
|
134
|
+
usesDtcg: true,
|
|
135
|
+
}) +
|
|
136
|
+
`\n}` +
|
|
137
|
+
`\n}\n\n` +
|
|
138
|
+
'/* Device tokens: Desktop */\n' +
|
|
139
|
+
`\n@media (min-width: 1024px) {\n` +
|
|
140
|
+
':root {\n' +
|
|
141
|
+
formattedVariables({
|
|
142
|
+
format: propertyFormatNames.css,
|
|
143
|
+
dictionary: deviceDesktopDictionary,
|
|
144
|
+
outputReferences,
|
|
145
|
+
usesDtcg: true,
|
|
146
|
+
}) +
|
|
147
|
+
`\n}` +
|
|
148
|
+
`\n}\n` +
|
|
149
|
+
'\n');
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
/**
|
|
153
|
+
* CSS Brand Formatter
|
|
154
|
+
* ------------------------------------------------------
|
|
155
|
+
*/
|
|
156
|
+
sd.registerFormat({
|
|
157
|
+
name: 'ds/css/variables-brand',
|
|
158
|
+
format: async ({ dictionary, file, options }) => {
|
|
159
|
+
const { outputReferences } = options;
|
|
160
|
+
const selector = options.selector ?? '[data-theme="brand"]';
|
|
161
|
+
const header = await fileHeader({ file });
|
|
162
|
+
// Only emit tokens that come from the brand source file, not from include (base)
|
|
163
|
+
const sourceTokens = dictionary.allTokens.filter(token => token.isSource);
|
|
164
|
+
const sourceDictionary = { ...dictionary, allTokens: sourceTokens };
|
|
165
|
+
const baseTokensOriginal = sourceTokens.filter(token => token.name.endsWith('-mobile'));
|
|
166
|
+
const baseTokens = JSON.parse(JSON.stringify(baseTokensOriginal));
|
|
167
|
+
const deviceBaseTokens = JSON.parse(JSON.stringify(baseTokensOriginal));
|
|
168
|
+
baseTokens.forEach(token => {
|
|
169
|
+
token.name = token.name.replace('-mobile', '');
|
|
170
|
+
});
|
|
171
|
+
deviceBaseTokens.forEach(token => {
|
|
172
|
+
token.name = token.name.replace('-mobile', '-device');
|
|
173
|
+
});
|
|
174
|
+
const baseDictionary = { ...dictionary, allTokens: baseTokens };
|
|
175
|
+
const deviceBaseDictionary = { ...dictionary, allTokens: deviceBaseTokens };
|
|
176
|
+
const tabletTokensOriginal = sourceTokens.filter(token => token.name.endsWith('-tablet'));
|
|
177
|
+
const deviceTabletTokens = JSON.parse(JSON.stringify(tabletTokensOriginal));
|
|
178
|
+
deviceTabletTokens.forEach(token => {
|
|
179
|
+
token.name = token.name.replace('-tablet', '-device');
|
|
180
|
+
});
|
|
181
|
+
const deviceTabletDictionary = { ...dictionary, allTokens: deviceTabletTokens };
|
|
182
|
+
const desktopTokensOriginal = sourceTokens.filter(token => token.name.endsWith('-desktop'));
|
|
183
|
+
const deviceDesktopTokens = JSON.parse(JSON.stringify(desktopTokensOriginal));
|
|
184
|
+
deviceDesktopTokens.forEach(token => {
|
|
185
|
+
token.name = token.name.replace('-desktop', '-device');
|
|
186
|
+
});
|
|
187
|
+
const deviceDesktopDictionary = { ...dictionary, allTokens: deviceDesktopTokens };
|
|
188
|
+
return (header +
|
|
189
|
+
`${selector} {\n` +
|
|
190
|
+
formattedVariables({
|
|
191
|
+
format: propertyFormatNames.css,
|
|
192
|
+
dictionary: sourceDictionary,
|
|
193
|
+
outputReferences,
|
|
194
|
+
usesDtcg: true,
|
|
195
|
+
}) +
|
|
196
|
+
'\n\n /* Base tokens */\n' +
|
|
197
|
+
formattedVariables({
|
|
198
|
+
format: propertyFormatNames.css,
|
|
199
|
+
dictionary: baseDictionary,
|
|
200
|
+
outputReferences,
|
|
201
|
+
usesDtcg: true,
|
|
202
|
+
}) +
|
|
203
|
+
'\n\n /* Device tokens */\n' +
|
|
204
|
+
formattedVariables({
|
|
205
|
+
format: propertyFormatNames.css,
|
|
206
|
+
dictionary: deviceBaseDictionary,
|
|
207
|
+
outputReferences,
|
|
208
|
+
usesDtcg: true,
|
|
209
|
+
}) +
|
|
210
|
+
'\n}\n\n' +
|
|
211
|
+
'/* Device tokens: Tablet */\n' +
|
|
212
|
+
`\n@media (min-width: 769px) {\n` +
|
|
213
|
+
`${selector} {\n` +
|
|
214
|
+
formattedVariables({
|
|
215
|
+
format: propertyFormatNames.css,
|
|
216
|
+
dictionary: deviceTabletDictionary,
|
|
217
|
+
outputReferences,
|
|
218
|
+
usesDtcg: true,
|
|
219
|
+
}) +
|
|
220
|
+
`\n}` +
|
|
221
|
+
`\n}\n\n` +
|
|
222
|
+
'/* Device tokens: Desktop */\n' +
|
|
223
|
+
`\n@media (min-width: 1024px) {\n` +
|
|
224
|
+
`${selector} {\n` +
|
|
225
|
+
formattedVariables({
|
|
226
|
+
format: propertyFormatNames.css,
|
|
227
|
+
dictionary: deviceDesktopDictionary,
|
|
228
|
+
outputReferences,
|
|
229
|
+
usesDtcg: true,
|
|
230
|
+
}) +
|
|
231
|
+
`\n}` +
|
|
232
|
+
`\n}\n` +
|
|
233
|
+
'\n');
|
|
234
|
+
},
|
|
235
|
+
});
|
|
236
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import StyleDictionary from 'style-dictionary';
|
|
2
|
+
import { copy, ensureDir, pathExists } from 'fs-extra';
|
|
3
|
+
import { resolve } from 'path';
|
|
4
|
+
console.log(`
|
|
5
|
+
\x1b[35m┃\x1b[0m
|
|
6
|
+
\x1b[35m┃\x1b[0m \x1b[1;37m🧩 Helvetia Design System\x1b[0m
|
|
7
|
+
\x1b[35m┃\x1b[0m \x1b[90m🎨 Building Tokens Package\x1b[0m
|
|
8
|
+
\x1b[35m┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m
|
|
9
|
+
`);
|
|
10
|
+
import { registerCustomTransformers } from './transformers.js';
|
|
11
|
+
import { registerCustomFormatters } from './formatter.js';
|
|
12
|
+
registerCustomTransformers(StyleDictionary);
|
|
13
|
+
registerCustomFormatters(StyleDictionary);
|
|
14
|
+
import ConfigBase from './config.base.js';
|
|
15
|
+
import { createBrandConfig } from './config.brand.js';
|
|
16
|
+
// Base build
|
|
17
|
+
const StyleDictionaryBase = new StyleDictionary(ConfigBase);
|
|
18
|
+
StyleDictionaryBase.buildAllPlatforms();
|
|
19
|
+
// Brand builds — add new brand names here (must match tokens/<Name>.tokens.json)
|
|
20
|
+
const brands = ['Tcs'];
|
|
21
|
+
for (const brand of brands) {
|
|
22
|
+
const { config, cleanup } = createBrandConfig(brand);
|
|
23
|
+
try {
|
|
24
|
+
const sd = new StyleDictionary(config);
|
|
25
|
+
await sd.buildAllPlatforms();
|
|
26
|
+
}
|
|
27
|
+
finally {
|
|
28
|
+
cleanup();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// copy generated files to css folder in core assets
|
|
32
|
+
const projectRoot = process.cwd();
|
|
33
|
+
const sourceDir = resolve(projectRoot, 'dist', 'css');
|
|
34
|
+
const targetDir = resolve(projectRoot, '..', 'core', 'www', 'assets', 'tokens');
|
|
35
|
+
(async () => {
|
|
36
|
+
await ensureDir(targetDir);
|
|
37
|
+
if (await pathExists(sourceDir)) {
|
|
38
|
+
await copy(sourceDir, targetDir, { overwrite: true });
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
console.warn(`Tokens CSS directory not found at: ${sourceDir}`);
|
|
42
|
+
}
|
|
43
|
+
})();
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
export const registerCustomTransformers = (sd) => {
|
|
2
|
+
/**
|
|
3
|
+
* Transform color tokens with hex and alpha properties to rgba() format
|
|
4
|
+
*/
|
|
5
|
+
sd.registerTransform({
|
|
6
|
+
type: `value`,
|
|
7
|
+
transitive: true,
|
|
8
|
+
name: `ds/color/rgba`,
|
|
9
|
+
filter: token => token.$type === 'color',
|
|
10
|
+
transform: token => {
|
|
11
|
+
const value = token.$value ?? token.value;
|
|
12
|
+
// Handle object values with hex and alpha properties
|
|
13
|
+
if (typeof value === 'object' && value !== null && 'hex' in value && 'alpha' in value && value.alpha < 1) {
|
|
14
|
+
const hex = value.hex.replace('#', '');
|
|
15
|
+
const r = parseInt(hex.substring(0, 2), 16);
|
|
16
|
+
const g = parseInt(hex.substring(2, 4), 16);
|
|
17
|
+
const b = parseInt(hex.substring(4, 6), 16);
|
|
18
|
+
const a = parseFloat(value.alpha);
|
|
19
|
+
return `rgba(${r}, ${g}, ${b}, ${a})`;
|
|
20
|
+
}
|
|
21
|
+
if (value.hex) {
|
|
22
|
+
return value.hex;
|
|
23
|
+
}
|
|
24
|
+
return value;
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* Transform color tokens with hex
|
|
29
|
+
*/
|
|
30
|
+
sd.registerTransform({
|
|
31
|
+
type: `value`,
|
|
32
|
+
transitive: true,
|
|
33
|
+
name: `ds/color/hex`,
|
|
34
|
+
filter: token => token.$type === 'color',
|
|
35
|
+
transform: token => {
|
|
36
|
+
const value = token.$value ?? token.value;
|
|
37
|
+
// Handle object values with hex and alpha properties
|
|
38
|
+
if (typeof value === 'object' && value !== null && 'hex' in value && 'alpha' in value) {
|
|
39
|
+
return value.hex;
|
|
40
|
+
}
|
|
41
|
+
return value;
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
/**
|
|
45
|
+
* Transform token names for CSS usage
|
|
46
|
+
*/
|
|
47
|
+
sd.registerTransform({
|
|
48
|
+
type: `name`,
|
|
49
|
+
transitive: true,
|
|
50
|
+
name: `ds/css/name`,
|
|
51
|
+
transform: token => {
|
|
52
|
+
let tokenName = token.name;
|
|
53
|
+
const isComponent = token.path.includes('🧩 Component');
|
|
54
|
+
if (isComponent) {
|
|
55
|
+
tokenName = tokenName.replace('-component', '');
|
|
56
|
+
}
|
|
57
|
+
// we use t-shirt sizes and need to make sure that 2xl becomes 2xl and not 2-xl
|
|
58
|
+
// check if token names has number followed by xl or xs and replace it with numberxl without dash
|
|
59
|
+
if (/-?([0-9]+)-(xl|xs)/.test(tokenName)) {
|
|
60
|
+
tokenName = tokenName.replace(/-?([0-9]+)-(xl|xs)/, '-$1$2');
|
|
61
|
+
}
|
|
62
|
+
// check that no name has double dash and replace it with single dash
|
|
63
|
+
if (tokenName.includes('--')) {
|
|
64
|
+
tokenName = tokenName.replace(/--+/g, '-');
|
|
65
|
+
}
|
|
66
|
+
return tokenName;
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
/**
|
|
70
|
+
* Transform token names for CSS usage
|
|
71
|
+
*/
|
|
72
|
+
sd.registerTransform({
|
|
73
|
+
type: `name`,
|
|
74
|
+
transitive: true,
|
|
75
|
+
name: `ds/js/name`,
|
|
76
|
+
transform: token => {
|
|
77
|
+
let tokenName = token.name;
|
|
78
|
+
tokenName = tokenName.replace('Primitive', 'Global');
|
|
79
|
+
tokenName = tokenName.replace('Semantic', 'Alias');
|
|
80
|
+
return tokenName;
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
/**
|
|
84
|
+
* Transform size tokens from px to rem
|
|
85
|
+
*/
|
|
86
|
+
sd.registerTransform({
|
|
87
|
+
type: `value`,
|
|
88
|
+
transitive: true,
|
|
89
|
+
name: `ds/size/rem`,
|
|
90
|
+
filter: token => token.$type === 'number',
|
|
91
|
+
transform: token => {
|
|
92
|
+
// const name = token.name
|
|
93
|
+
const value = token.$value;
|
|
94
|
+
// const originalValue = token.original.$value
|
|
95
|
+
const path = token.path;
|
|
96
|
+
// const isReference =
|
|
97
|
+
// typeof originalValue === 'string' && originalValue.startsWith('{') && originalValue.endsWith('}')
|
|
98
|
+
if (`${value}`.endsWith('px')) {
|
|
99
|
+
return value;
|
|
100
|
+
}
|
|
101
|
+
if (`${value}`.endsWith('rem')) {
|
|
102
|
+
return value;
|
|
103
|
+
}
|
|
104
|
+
// Number only values with no unit
|
|
105
|
+
const tokenToBeNumberOnly = [
|
|
106
|
+
'LineHeight',
|
|
107
|
+
'FontWeight',
|
|
108
|
+
'Opacity',
|
|
109
|
+
'🌫️ Opacity',
|
|
110
|
+
'Z-Index',
|
|
111
|
+
'🗂️ Z-Index',
|
|
112
|
+
'Interaction',
|
|
113
|
+
'✨ Interaction',
|
|
114
|
+
];
|
|
115
|
+
if (tokenToBeNumberOnly.some(ignored => path.includes(ignored))) {
|
|
116
|
+
return Math.round(value * 10) / 10;
|
|
117
|
+
}
|
|
118
|
+
// Number only values with no unit
|
|
119
|
+
const tokenToBeNumberPixel = ['📐 Breakpoint', 'Breakpoint', '🗃️ Container', 'Container'];
|
|
120
|
+
if (tokenToBeNumberPixel.some(ignored => path.includes(ignored))) {
|
|
121
|
+
return value + 'px';
|
|
122
|
+
}
|
|
123
|
+
// Extra case for rounded radius
|
|
124
|
+
if (value === 9999) {
|
|
125
|
+
return value + 'px';
|
|
126
|
+
}
|
|
127
|
+
// turn pixel into rem
|
|
128
|
+
return value / 16 + 'rem';
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
sd.registerTransform({
|
|
132
|
+
type: `value`,
|
|
133
|
+
transitive: true,
|
|
134
|
+
name: `ds/size/round`,
|
|
135
|
+
filter: token => token.$type === 'number',
|
|
136
|
+
transform: token => {
|
|
137
|
+
const value = token.$value ?? token.value;
|
|
138
|
+
const name = token.name;
|
|
139
|
+
const tokenName = Array.isArray(name) ? name.join('-') : String(name ?? '');
|
|
140
|
+
// if line-height round the value to 1 decimal place
|
|
141
|
+
if (tokenName.includes('line-height') ||
|
|
142
|
+
tokenName.includes('opacity') ||
|
|
143
|
+
tokenName.includes('LineHeight') ||
|
|
144
|
+
tokenName.includes('Opacity')) {
|
|
145
|
+
return Math.round(value * 10) / 10;
|
|
146
|
+
}
|
|
147
|
+
return value;
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
};
|