@massimo-cassandro/minimo 0.5.0 → 0.5.1
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/design-tokens/color-primary.minimo.tokens.jsonc +0 -4
- package/design-tokens-utilities/build-tokens-src/config.mjs +0 -8
- package/design-tokens-utilities/build-tokens-src/formats/css.mjs +2 -10
- package/design-tokens-utilities/build-tokens-src/formats/penpot.mjs +9 -20
- package/design-tokens-utilities/build-tokens-src/platforms.mjs +1 -4
- package/design-tokens-utilities/build-tokens.mjs +1 -3
- package/design-tokens-utilities/tokens-config-sample.mjs +1 -5
- package/package.json +1 -1
- package/src/custom-properties-default.css +0 -1
- package/design-tokens-utilities/build-tokens-src/lib/color-scale.mjs +0 -81
|
@@ -68,14 +68,6 @@ export const penpotFormat = buildConfig.penpotFormat === 'jsonc' ? 'jsonc' : 'js
|
|
|
68
68
|
// 'keep' (default) — write the expression as-is
|
|
69
69
|
// 'calc' — wrap in CSS calc()
|
|
70
70
|
// 'resolve' — evaluate numerically; unit inherited from the first referenced token
|
|
71
|
-
// colorScalePrefixes: list of color token prefixes for which the numeric scale
|
|
72
|
-
// segment is zero-padded to 3 digits (e.g. --neutral-80 -> --neutral-080).
|
|
73
|
-
// Applied to both CSS custom property names and Penpot DTCG token keys.
|
|
74
|
-
// Set to an empty array or omit to disable.
|
|
75
|
-
export const colorScalePrefixes = Array.isArray(buildConfig.colorScalePrefixes)
|
|
76
|
-
? buildConfig.colorScalePrefixes
|
|
77
|
-
: [];
|
|
78
|
-
|
|
79
71
|
const VALID_EXPR_MODES = ['keep', 'calc', 'resolve'];
|
|
80
72
|
export const penpotExpressions = VALID_EXPR_MODES.includes(buildConfig.penpotExpressions)
|
|
81
73
|
? buildConfig.penpotExpressions
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
// - individual properties for letterSpacing, textTransform, textDecoration
|
|
7
7
|
|
|
8
8
|
import StyleDictionary from 'style-dictionary';
|
|
9
|
-
import { padColorName } from '../lib/color-scale.mjs';
|
|
10
9
|
|
|
11
10
|
const BASE_FONT_SIZE = 16;
|
|
12
11
|
|
|
@@ -148,8 +147,6 @@ StyleDictionary.registerFormat({
|
|
|
148
147
|
|
|
149
148
|
const resolveRefs = makeResolveRefs(tokenByPath);
|
|
150
149
|
|
|
151
|
-
const colorScalePrefixes = options.colorScalePrefixes ?? [];
|
|
152
|
-
|
|
153
150
|
const lines = dictionary.allTokens
|
|
154
151
|
.slice()
|
|
155
152
|
.sort((a, b) => a.name.localeCompare(b.name))
|
|
@@ -157,13 +154,8 @@ StyleDictionary.registerFormat({
|
|
|
157
154
|
const type = token.$type ?? token.type;
|
|
158
155
|
const orig = token.original?.$value ?? token.original?.value;
|
|
159
156
|
|
|
160
|
-
// Apply zero-padding to color scale names (e.g. --neutral-80 -> --neutral-080)
|
|
161
|
-
const tokenName = (type === 'color')
|
|
162
|
-
? padColorName(token.name, colorScalePrefixes)
|
|
163
|
-
: token.name;
|
|
164
|
-
|
|
165
157
|
if (type === 'typography') {
|
|
166
|
-
return [buildTypography(
|
|
158
|
+
return [buildTypography(token.name, orig ?? {}, resolveRefs)];
|
|
167
159
|
}
|
|
168
160
|
|
|
169
161
|
let value;
|
|
@@ -200,7 +192,7 @@ StyleDictionary.registerFormat({
|
|
|
200
192
|
value = String(token.$value ?? token.value);
|
|
201
193
|
}
|
|
202
194
|
|
|
203
|
-
return [` --${
|
|
195
|
+
return [` --${token.name}: ${value};`];
|
|
204
196
|
});
|
|
205
197
|
|
|
206
198
|
customPropsCount = lines.length;
|
|
@@ -33,7 +33,6 @@
|
|
|
33
33
|
|
|
34
34
|
import StyleDictionary from 'style-dictionary';
|
|
35
35
|
import path from 'path';
|
|
36
|
-
import { padTokenPath } from '../lib/color-scale.mjs';
|
|
37
36
|
|
|
38
37
|
// Disclaimer prepended to every generated file when penpotFormat is 'jsonc'
|
|
39
38
|
const DISCLAIMER = [
|
|
@@ -127,28 +126,20 @@ StyleDictionary.registerFormat({
|
|
|
127
126
|
name: 'json/penpot',
|
|
128
127
|
format: ({ dictionary, options }) => {
|
|
129
128
|
const root = {};
|
|
130
|
-
const expressionMode
|
|
131
|
-
const colorScalePrefixes = options.colorScalePrefixes ?? [];
|
|
129
|
+
const expressionMode = options.penpotExpressions ?? 'keep'; // 'keep' | 'calc' | 'resolve'
|
|
132
130
|
const tokenMap = (expressionMode === 'resolve') ? makeTokenMap(dictionary) : null;
|
|
133
131
|
|
|
134
132
|
for (const token of dictionary.allTokens) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
// Apply zero-padding to color scale path segments
|
|
138
|
-
// e.g. ['neutral', '80'] -> ['neutral', '080']
|
|
139
|
-
const tokenPath = (type === 'color')
|
|
140
|
-
? padTokenPath(token.path, colorScalePrefixes)
|
|
141
|
-
: token.path;
|
|
142
|
-
|
|
143
|
-
// Rebuild the nested tree from the (possibly padded) token path
|
|
133
|
+
// Rebuild the nested tree from the token path
|
|
144
134
|
let node = root;
|
|
145
|
-
for (let i = 0; i <
|
|
146
|
-
const segment =
|
|
135
|
+
for (let i = 0; i < token.path.length - 1; i++) {
|
|
136
|
+
const segment = token.path[i];
|
|
147
137
|
node[segment] = node[segment] ?? {};
|
|
148
138
|
node = node[segment];
|
|
149
139
|
}
|
|
150
140
|
|
|
151
|
-
const leafKey =
|
|
141
|
+
const leafKey = token.path[token.path.length - 1];
|
|
142
|
+
const type = token.$type ?? token.type;
|
|
152
143
|
const orig = token.original?.$value ?? token.original?.value;
|
|
153
144
|
|
|
154
145
|
// ── Value resolution ────────────────────────────────────────────────────
|
|
@@ -232,15 +223,13 @@ export const collectConcreteFilePaths = async (sd) => {
|
|
|
232
223
|
// @param {string|null} penpotDestFile Aggregated file base name, or null
|
|
233
224
|
// @param {'json'|'jsonc'} penpotFormat Output format
|
|
234
225
|
// @param {'keep'|'calc'|'resolve'} penpotExpressions Expression handling mode
|
|
235
|
-
// @param {string[]} colorScalePrefixes Color token prefixes for numeric scale zero-padding
|
|
236
226
|
// @returns {object[]} File descriptors for the Style Dictionary platform
|
|
237
227
|
|
|
238
228
|
export const buildPenpotFiles = (
|
|
239
229
|
concreteFilePaths,
|
|
240
230
|
penpotDestFile,
|
|
241
231
|
penpotFormat = 'json',
|
|
242
|
-
penpotExpressions = 'keep'
|
|
243
|
-
colorScalePrefixes = []
|
|
232
|
+
penpotExpressions = 'keep'
|
|
244
233
|
) => {
|
|
245
234
|
const ext = penpotFormat === 'jsonc' ? '.jsonc' : '.json';
|
|
246
235
|
const jsonc = penpotFormat === 'jsonc';
|
|
@@ -249,7 +238,7 @@ export const buildPenpotFiles = (
|
|
|
249
238
|
return [{
|
|
250
239
|
destination: penpotDestFile + ext,
|
|
251
240
|
format: 'json/penpot',
|
|
252
|
-
options: { jsonc, penpotExpressions
|
|
241
|
+
options: { jsonc, penpotExpressions },
|
|
253
242
|
}];
|
|
254
243
|
}
|
|
255
244
|
|
|
@@ -263,7 +252,7 @@ export const buildPenpotFiles = (
|
|
|
263
252
|
return {
|
|
264
253
|
destination: destName,
|
|
265
254
|
format: 'json/penpot',
|
|
266
|
-
options: { jsonc, penpotExpressions
|
|
255
|
+
options: { jsonc, penpotExpressions },
|
|
267
256
|
filter: (token) => {
|
|
268
257
|
const fp = token.filePath ? path.resolve(token.filePath) : '';
|
|
269
258
|
return fp === absPath;
|
|
@@ -40,7 +40,6 @@ const PENPOT_TRANSFORMS = [
|
|
|
40
40
|
* Collected from sd.allTokens after SD initialisation.
|
|
41
41
|
* Ignored when penpotDestFile is set.
|
|
42
42
|
* @param {'keep'|'calc'|'resolve'} opts.penpotExpressions How to handle math expressions in dimension tokens.
|
|
43
|
-
* @param {string[]} opts.colorScalePrefixes Color token prefixes for numeric scale zero-padding.
|
|
44
43
|
* @returns {object} platforms object ready for Style Dictionary config
|
|
45
44
|
*/
|
|
46
45
|
export const buildPlatforms = ({
|
|
@@ -50,7 +49,6 @@ export const buildPlatforms = ({
|
|
|
50
49
|
penpotDestFile,
|
|
51
50
|
penpotFormat,
|
|
52
51
|
penpotExpressions = 'keep',
|
|
53
|
-
colorScalePrefixes = [],
|
|
54
52
|
concreteFilePaths = [],
|
|
55
53
|
}) => {
|
|
56
54
|
const platforms = {
|
|
@@ -64,7 +62,6 @@ export const buildPlatforms = ({
|
|
|
64
62
|
options: {
|
|
65
63
|
outputReferences: true,
|
|
66
64
|
showFileHeader: true,
|
|
67
|
-
colorScalePrefixes,
|
|
68
65
|
},
|
|
69
66
|
},
|
|
70
67
|
],
|
|
@@ -75,7 +72,7 @@ export const buildPlatforms = ({
|
|
|
75
72
|
platforms.penpot = {
|
|
76
73
|
buildPath: penpotBuildPath + '/',
|
|
77
74
|
transforms: PENPOT_TRANSFORMS,
|
|
78
|
-
files: buildPenpotFiles(concreteFilePaths, penpotDestFile, penpotFormat, penpotExpressions
|
|
75
|
+
files: buildPenpotFiles(concreteFilePaths, penpotDestFile, penpotFormat, penpotExpressions),
|
|
79
76
|
};
|
|
80
77
|
}
|
|
81
78
|
|
|
@@ -28,7 +28,6 @@ import {
|
|
|
28
28
|
penpotDestFile,
|
|
29
29
|
penpotFormat,
|
|
30
30
|
penpotExpressions,
|
|
31
|
-
colorScalePrefixes,
|
|
32
31
|
source,
|
|
33
32
|
} from './build-tokens-src/config.mjs';
|
|
34
33
|
|
|
@@ -72,7 +71,6 @@ const sd = new StyleDictionary({
|
|
|
72
71
|
penpotDestFile,
|
|
73
72
|
penpotFormat,
|
|
74
73
|
penpotExpressions,
|
|
75
|
-
colorScalePrefixes,
|
|
76
74
|
concreteFilePaths,
|
|
77
75
|
}),
|
|
78
76
|
});
|
|
@@ -96,7 +94,7 @@ console.log(styleText(['yellow'], `[build-tokens] source : ${source.map(sho
|
|
|
96
94
|
console.log(styleText(['yellow'], `[build-tokens] dest file : ${short(path.join(buildPath, destFile))}`));
|
|
97
95
|
|
|
98
96
|
if (penpotBuildPath) {
|
|
99
|
-
const penpotFiles = buildPenpotFiles(concreteFilePaths, penpotDestFile, penpotFormat, penpotExpressions
|
|
97
|
+
const penpotFiles = buildPenpotFiles(concreteFilePaths, penpotDestFile, penpotFormat, penpotExpressions);
|
|
100
98
|
if (penpotFiles.length === 1) {
|
|
101
99
|
console.log(styleText(['yellow'],
|
|
102
100
|
`[build-tokens] penpot json : ${short(path.join(penpotBuildPath, penpotFiles[0].destination))}`
|
|
@@ -75,11 +75,7 @@ const config = {
|
|
|
75
75
|
// e.g. {size.base} = 16px, "{size.base} * .25" -> "4px"
|
|
76
76
|
penpotExpressions: 'resolve',
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
// to 3 digits in both CSS output and Penpot token files.
|
|
80
|
-
// e.g. --neutral-80 -> --neutral-080, --primary-5 -> --primary-005
|
|
81
|
-
// Set to an empty array or omit to disable.
|
|
82
|
-
colorScalePrefixes: ['primary', 'secondary', 'neutral'],
|
|
78
|
+
|
|
83
79
|
|
|
84
80
|
// ---------------------------------------------------------------------------
|
|
85
81
|
// check-unresolved-custom-props.mjs settings
|
package/package.json
CHANGED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
// build-tokens-src/lib/color-scale.mjs
|
|
2
|
-
// Shared helper for color scale zero-padding.
|
|
3
|
-
//
|
|
4
|
-
// When colorScalePrefixes is configured, color tokens whose name matches
|
|
5
|
-
// --<prefix>-<number> (e.g. --primary-100, --neutral-80)
|
|
6
|
-
// have the numeric segment zero-padded to 3 digits:
|
|
7
|
-
// --primary-100 -> --primary-100 (unchanged, already 3 digits)
|
|
8
|
-
// --neutral-80 -> --neutral-080
|
|
9
|
-
// --secondary-5 -> --secondary-005
|
|
10
|
-
//
|
|
11
|
-
// The same transformation is applied to CSS custom property names and to
|
|
12
|
-
// Penpot DTCG token keys, so both outputs stay in sync.
|
|
13
|
-
//
|
|
14
|
-
// Configuration (in the project config file):
|
|
15
|
-
// colorScalePrefixes: ['primary', 'secondary', 'neutral']
|
|
16
|
-
//
|
|
17
|
-
// Set to an empty array or omit to disable the feature entirely.
|
|
18
|
-
|
|
19
|
-
// ---------------------------------------------------------------------------
|
|
20
|
-
// padColorName
|
|
21
|
-
//
|
|
22
|
-
// Given a full token name (kebab-case, no leading --) and the list of
|
|
23
|
-
// configured prefixes, returns the name with the numeric segment zero-padded
|
|
24
|
-
// if applicable, or the original name unchanged otherwise.
|
|
25
|
-
//
|
|
26
|
-
// Examples:
|
|
27
|
-
// padColorName('primary-100', ['primary']) -> 'primary-100'
|
|
28
|
-
// padColorName('neutral-80', ['neutral']) -> 'neutral-080'
|
|
29
|
-
// padColorName('neutral-80', []) -> 'neutral-80'
|
|
30
|
-
// padColorName('size-base', ['primary']) -> 'size-base'
|
|
31
|
-
// ---------------------------------------------------------------------------
|
|
32
|
-
export const padColorName = (name, prefixes) => {
|
|
33
|
-
if (!prefixes || prefixes.length === 0) return name;
|
|
34
|
-
|
|
35
|
-
// Match: <prefix>-<integer> optionally followed by more segments
|
|
36
|
-
// The number must be a pure integer (no decimals, no units).
|
|
37
|
-
const pattern = new RegExp(
|
|
38
|
-
`^(${prefixes.map(p => escapeRegex(p)).join('|')})-([0-9]+)(-.+)?$`
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
const match = name.match(pattern);
|
|
42
|
-
if (!match) return name;
|
|
43
|
-
|
|
44
|
-
const [, prefix, num, rest = ''] = match;
|
|
45
|
-
const padded = num.padStart(3, '0');
|
|
46
|
-
|
|
47
|
-
return `${prefix}-${padded}${rest}`;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
// ---------------------------------------------------------------------------
|
|
51
|
-
// padTokenPath
|
|
52
|
-
//
|
|
53
|
-
// Applies the same zero-padding logic to a DTCG token path array.
|
|
54
|
-
// Used by the Penpot format to rename leaf keys and intermediate path segments.
|
|
55
|
-
//
|
|
56
|
-
// The segment to pad is the one immediately following the matching prefix.
|
|
57
|
-
// If the prefix occupies multiple path segments this function is intentionally
|
|
58
|
-
// conservative: it only pads when the prefix is a single path segment.
|
|
59
|
-
//
|
|
60
|
-
// Examples (path arrays):
|
|
61
|
-
// ['primary', '100'] -> ['primary', '100'] (unchanged)
|
|
62
|
-
// ['neutral', '80'] -> ['neutral', '080']
|
|
63
|
-
// ['color', 'neutral', '80'] with prefix 'neutral' -> ['color', 'neutral', '080']
|
|
64
|
-
// ---------------------------------------------------------------------------
|
|
65
|
-
export const padTokenPath = (pathArr, prefixes) => {
|
|
66
|
-
if (!prefixes || prefixes.length === 0) return pathArr;
|
|
67
|
-
|
|
68
|
-
return pathArr.map((segment, i) => {
|
|
69
|
-
// Is this segment a pure integer and is the previous segment a prefix?
|
|
70
|
-
if (i === 0) return segment;
|
|
71
|
-
const prev = pathArr[i - 1];
|
|
72
|
-
if (!prefixes.includes(prev)) return segment;
|
|
73
|
-
if (!/^[0-9]+$/.test(segment)) return segment;
|
|
74
|
-
return segment.padStart(3, '0');
|
|
75
|
-
});
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
// ---------------------------------------------------------------------------
|
|
79
|
-
// Internal: escape special regex characters in a prefix string
|
|
80
|
-
// ---------------------------------------------------------------------------
|
|
81
|
-
const escapeRegex = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|