@massimo-cassandro/minimo 0.4.3 → 0.5.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 (45) hide show
  1. package/design-tokens/badge.minimo.tokens.jsonc +2 -2
  2. package/design-tokens/basic.minimo.tokens.jsonc +1 -1
  3. package/design-tokens/btn-primary.minimo.tokens.jsonc +2 -2
  4. package/design-tokens/color-accent.minimo.tokens.jsonc +2 -2
  5. package/design-tokens/color-neutral.minimo.tokens.jsonc +2 -2
  6. package/design-tokens/color-primary.minimo.tokens.jsonc +6 -2
  7. package/design-tokens/color-secondary.minimo.tokens.jsonc +2 -2
  8. package/design-tokens/components/recaptcha.minimo.tokens.jsonc +1 -1
  9. package/design-tokens/components/spinner.minimo.tokens.jsonc +1 -1
  10. package/design-tokens/recaptcha.minimo.tokens.jsonc +1 -1
  11. package/design-tokens/spinner.minimo.tokens.jsonc +1 -1
  12. package/design-tokens/status.minimo.tokens.jsonc +4 -4
  13. package/design-tokens-src/badge.minimo.tokens.jsonc +2 -2
  14. package/design-tokens-src/basic.minimo.tokens.jsonc +1 -1
  15. package/design-tokens-src/btn-primary.minimo.tokens.jsonc +2 -2
  16. package/design-tokens-src/{btn-secondary.minimo.tokens.jsonc → btn-secondary.minimo.tokens.mjs} +7 -6
  17. package/design-tokens-src/color-accent.minimo.tokens.mjs +13 -0
  18. package/design-tokens-src/color-neutral.minimo.tokens.mjs +12 -0
  19. package/design-tokens-src/color-primary.minimo.tokens.mjs +13 -0
  20. package/design-tokens-src/color-secondary.minimo.tokens.mjs +12 -0
  21. package/design-tokens-src/components/recaptcha.minimo.tokens.jsonc +1 -1
  22. package/design-tokens-src/components/sf-macro.minimo.tokens.jsonc +1 -1
  23. package/design-tokens-src/components/spinner.minimo.tokens.jsonc +1 -1
  24. package/design-tokens-src/status.minimo.tokens.jsonc +4 -4
  25. package/design-tokens-src/web-components/simple-datatable.minimo.tokens.jsonc +2 -2
  26. package/design-tokens-utilities/build-tokens-src/config.mjs +8 -0
  27. package/design-tokens-utilities/build-tokens-src/formats/css.mjs +10 -2
  28. package/design-tokens-utilities/build-tokens-src/formats/penpot.mjs +20 -9
  29. package/design-tokens-utilities/build-tokens-src/lib/color-scale.mjs +81 -0
  30. package/design-tokens-utilities/build-tokens-src/platforms.mjs +4 -1
  31. package/design-tokens-utilities/build-tokens.mjs +3 -1
  32. package/design-tokens-utilities/check-unresolved-custom-props.mjs +21 -14
  33. package/design-tokens-utilities/tokens-config-sample.mjs +6 -0
  34. package/package.json +1 -1
  35. package/src/components/modal-alert/modal-alert.css +5 -5
  36. package/src/components/popup-page/popup-page.css +1 -1
  37. package/src/components/recaptcha/recaptcha.css +1 -1
  38. package/src/css/alerts.css +4 -4
  39. package/src/css/buttons/status-buttons.css +4 -4
  40. package/src/css/forms/forms.css +1 -1
  41. package/src/custom-properties-default.css +23 -22
  42. package/design-tokens-src/color-accent.minimo.tokens.jsonc +0 -13
  43. package/design-tokens-src/color-neutral.minimo.tokens.jsonc +0 -12
  44. package/design-tokens-src/color-primary.minimo.tokens.jsonc +0 -12
  45. package/design-tokens-src/color-secondary.minimo.tokens.jsonc +0 -12
@@ -9,12 +9,12 @@
9
9
  "background": {
10
10
  "color": {
11
11
  "$type": "color",
12
- "$value": "{primary.base}"
12
+ "$value": "{primary.100}"
13
13
  }
14
14
  },
15
15
  "color": {
16
16
  "$type": "color",
17
- "$value": "{primary.on-base}"
17
+ "$value": "{primary.100-fg}"
18
18
  },
19
19
  "font": {
20
20
  "size": {
@@ -28,7 +28,7 @@
28
28
  "text": {
29
29
  "muted": {
30
30
  "$type": "color",
31
- "$value": "{neutral.base}"
31
+ "$value": "{neutral.100}"
32
32
  },
33
33
  "dim": {
34
34
  "$type": "color",
@@ -10,12 +10,12 @@
10
10
  "background": {
11
11
  "color": {
12
12
  "$type": "color",
13
- "$value": "{primary.base}"
13
+ "$value": "{primary.100}"
14
14
  }
15
15
  },
16
16
  "color": {
17
17
  "$type": "color",
18
- "$value": "{primary.on-base}"
18
+ "$value": "{primary.100-fg}"
19
19
  },
20
20
  "border": {
21
21
  "color": {
@@ -6,11 +6,11 @@
6
6
  // -----------------------------------------------------------------------
7
7
  {
8
8
  "accent": {
9
- "base": {
9
+ "100": {
10
10
  "$type": "color",
11
11
  "$value": "#567d0d"
12
12
  },
13
- "on-base": {
13
+ "100-fg": {
14
14
  "$type": "color",
15
15
  "$value": "#fff"
16
16
  }
@@ -6,11 +6,11 @@
6
6
  // -----------------------------------------------------------------------
7
7
  {
8
8
  "neutral": {
9
- "base": {
9
+ "100": {
10
10
  "$type": "color",
11
11
  "$value": "#666"
12
12
  },
13
- "on-base": {
13
+ "100-fg": {
14
14
  "$type": "color",
15
15
  "$value": "#fff"
16
16
  }
@@ -6,11 +6,15 @@
6
6
  // -----------------------------------------------------------------------
7
7
  {
8
8
  "primary": {
9
- "base": {
9
+ "100": {
10
10
  "$type": "color",
11
11
  "$value": "#083865"
12
12
  },
13
- "on-base": {
13
+ "080": {
14
+ "$type": "color",
15
+ "$value": "#0957A0"
16
+ },
17
+ "100-fg": {
14
18
  "$type": "color",
15
19
  "$value": "#fff"
16
20
  }
@@ -6,11 +6,11 @@
6
6
  // -----------------------------------------------------------------------
7
7
  {
8
8
  "secondary": {
9
- "base": {
9
+ "100": {
10
10
  "$type": "color",
11
11
  "$value": "#650853"
12
12
  },
13
- "on-base": {
13
+ "100-fg": {
14
14
  "$type": "color",
15
15
  "$value": "#fff"
16
16
  }
@@ -19,7 +19,7 @@
19
19
  "$value": "#000"
20
20
  }
21
21
  },
22
- "foreground": {
22
+ "fg": {
23
23
  "$type": "color",
24
24
  "$value": "#fff"
25
25
  }
@@ -12,7 +12,7 @@
12
12
  },
13
13
  "color": {
14
14
  "$type": "color",
15
- "$value": "{primary.base}"
15
+ "$value": "{primary.100}"
16
16
  },
17
17
  "stroke": {
18
18
  "width": {
@@ -19,7 +19,7 @@
19
19
  "$value": "#000"
20
20
  }
21
21
  },
22
- "foreground": {
22
+ "fg": {
23
23
  "$type": "color",
24
24
  "$value": "#fff"
25
25
  }
@@ -12,7 +12,7 @@
12
12
  },
13
13
  "color": {
14
14
  "$type": "color",
15
- "$value": "{primary.base}"
15
+ "$value": "{primary.100}"
16
16
  },
17
17
  "stroke": {
18
18
  "width": {
@@ -17,7 +17,7 @@
17
17
  "$value": "{status.danger.color}"
18
18
  }
19
19
  },
20
- "foreground": {
20
+ "fg": {
21
21
  "$type": "color",
22
22
  "$value": "#fff"
23
23
  },
@@ -39,7 +39,7 @@
39
39
  "$value": "{status.success.color}"
40
40
  }
41
41
  },
42
- "foreground": {
42
+ "fg": {
43
43
  "$type": "color",
44
44
  "$value": "#fff"
45
45
  },
@@ -61,7 +61,7 @@
61
61
  "$value": "{status.info.color}"
62
62
  }
63
63
  },
64
- "foreground": {
64
+ "fg": {
65
65
  "$type": "color",
66
66
  "$value": "#fff"
67
67
  },
@@ -83,7 +83,7 @@
83
83
  "$value": "{status.warning.color}"
84
84
  }
85
85
  },
86
- "foreground": {
86
+ "fg": {
87
87
  "$type": "color",
88
88
  "$value": "#4f2900"
89
89
  },
@@ -2,12 +2,12 @@
2
2
  "badge": {
3
3
  "background": {
4
4
  "color": {
5
- "$value": "{primary.base}",
5
+ "$value": "{primary.100}",
6
6
  "$type": "color"
7
7
  }
8
8
  },
9
9
  "color": {
10
- "$value": "{primary.on-base}",
10
+ "$value": "{primary.100-fg}",
11
11
  "$type": "color"
12
12
  },
13
13
  "font": {
@@ -22,7 +22,7 @@
22
22
  "text": {
23
23
  "muted": {
24
24
  "$type": "color",
25
- "$value": "{neutral.base}"
25
+ "$value": "{neutral.100}"
26
26
  },
27
27
  "dim": {
28
28
  "$type": "color",
@@ -3,12 +3,12 @@
3
3
  "primary": {
4
4
  "background": {
5
5
  "color": {
6
- "$value": "{primary.base}",
6
+ "$value": "{primary.100}",
7
7
  "$type": "color"
8
8
  }
9
9
  },
10
10
  "color": {
11
- "$value": "{primary.on-base}",
11
+ "$value": "{primary.100-fg}",
12
12
  "$type": "color"
13
13
  },
14
14
 
@@ -1,13 +1,14 @@
1
- {
2
- "btn": {
3
- "secondary": {
1
+ export default {
2
+ btn: {
4
3
 
5
- "hollow": {
4
+ secondary: {
5
+
6
+ hollow: {
6
7
 
7
- } // end hollow
8
+ }
8
9
  } // end secondary
9
10
  } // end btn
10
- }
11
+ };
11
12
  // --btn-secondary-bg-color: var(--_secondary);
12
13
  // --btn-secondary-fg-color: var(--_secondary-fg);
13
14
  // --btn-secondary-border-color: var(--_secondary);
@@ -0,0 +1,13 @@
1
+ export default {
2
+ accent: {
3
+ 100: {
4
+ $value: '#567d0d',
5
+ $type: 'color'
6
+ },
7
+ '100-fg': {
8
+ $value: '#fff',
9
+ $type: 'color'
10
+ }
11
+ }
12
+
13
+ };
@@ -0,0 +1,12 @@
1
+ export default {
2
+ neutral: {
3
+ 100: {
4
+ $value: '#666',
5
+ $type: 'color'
6
+ },
7
+ '100-fg': {
8
+ $value: '#fff',
9
+ $type: 'color'
10
+ }
11
+ }
12
+ };
@@ -0,0 +1,13 @@
1
+ export default {
2
+ primary: {
3
+
4
+ 100: {
5
+ $value: '#083865',
6
+ $type: 'color'
7
+ },
8
+ '100-fg': {
9
+ $value: '#fff',
10
+ $type: 'color'
11
+ }
12
+ }
13
+ };
@@ -0,0 +1,12 @@
1
+ export default {
2
+ secondary: {
3
+ 100: {
4
+ $value: '#650853',
5
+ $type: 'color'
6
+ },
7
+ '100-fg': {
8
+ $value: '#fff',
9
+ $type: 'color'
10
+ }
11
+ }
12
+ };
@@ -15,7 +15,7 @@
15
15
  "$value": "#000"
16
16
  }
17
17
  },
18
- "foreground": {
18
+ "fg": {
19
19
  "$type": "color",
20
20
  "$value": "#fff"
21
21
  },
@@ -36,7 +36,7 @@
36
36
  "border": {
37
37
  "$type": "border",
38
38
  "$value": {
39
- "color": "{neutral.base}",
39
+ "color": "{neutral.100}",
40
40
  "width": "1px",
41
41
  "style": "solid"
42
42
  }
@@ -7,7 +7,7 @@
7
7
  },
8
8
 
9
9
  "color": {
10
- "$value": "{primary.base}",
10
+ "$value": "{primary.100}",
11
11
  "$type": "color"
12
12
  },
13
13
 
@@ -12,7 +12,7 @@
12
12
  "$type": "color"
13
13
  }
14
14
  },
15
- "foreground": {
15
+ "fg": {
16
16
  "$value": "#fff",
17
17
  "$type": "color"
18
18
  },
@@ -34,7 +34,7 @@
34
34
  "$type": "color"
35
35
  }
36
36
  },
37
- "foreground": {
37
+ "fg": {
38
38
  "$value": "#fff",
39
39
  "$type": "color"
40
40
  },
@@ -56,7 +56,7 @@
56
56
  "$type": "color"
57
57
  }
58
58
  },
59
- "foreground": {
59
+ "fg": {
60
60
  "$value": "#fff",
61
61
  "$type": "color"
62
62
  },
@@ -78,7 +78,7 @@
78
78
  "$type": "color"
79
79
  }
80
80
  },
81
- "foreground": {
81
+ "fg": {
82
82
  "$value": "#4f2900",
83
83
  "$type": "color"
84
84
  },
@@ -5,7 +5,7 @@
5
5
  "hover": {
6
6
  "background": {
7
7
  "color": {
8
- "$value": "color-mix(in srgb, {table.thead.background.color} 90%, {accent.base})",
8
+ "$value": "color-mix(in srgb, {table.thead.background.color} 90%, {accent.100})",
9
9
  "$type": "color"
10
10
  }
11
11
  }
@@ -16,7 +16,7 @@
16
16
  "border": {
17
17
  "$type": "border",
18
18
  "$value": {
19
- "color": "{neutral.base}",
19
+ "color": "{neutral.100}",
20
20
  "width": "{btn.border.width}",
21
21
  // "style": "solid"
22
22
  }
@@ -68,6 +68,14 @@ 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
+
71
79
  const VALID_EXPR_MODES = ['keep', 'calc', 'resolve'];
72
80
  export const penpotExpressions = VALID_EXPR_MODES.includes(buildConfig.penpotExpressions)
73
81
  ? buildConfig.penpotExpressions
@@ -6,6 +6,7 @@
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';
9
10
 
10
11
  const BASE_FONT_SIZE = 16;
11
12
 
@@ -147,6 +148,8 @@ StyleDictionary.registerFormat({
147
148
 
148
149
  const resolveRefs = makeResolveRefs(tokenByPath);
149
150
 
151
+ const colorScalePrefixes = options.colorScalePrefixes ?? [];
152
+
150
153
  const lines = dictionary.allTokens
151
154
  .slice()
152
155
  .sort((a, b) => a.name.localeCompare(b.name))
@@ -154,8 +157,13 @@ StyleDictionary.registerFormat({
154
157
  const type = token.$type ?? token.type;
155
158
  const orig = token.original?.$value ?? token.original?.value;
156
159
 
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
+
157
165
  if (type === 'typography') {
158
- return [buildTypography(token.name, orig ?? {}, resolveRefs)];
166
+ return [buildTypography(tokenName, orig ?? {}, resolveRefs)];
159
167
  }
160
168
 
161
169
  let value;
@@ -192,7 +200,7 @@ StyleDictionary.registerFormat({
192
200
  value = String(token.$value ?? token.value);
193
201
  }
194
202
 
195
- return [` --${token.name}: ${value};`];
203
+ return [` --${tokenName}: ${value};`];
196
204
  });
197
205
 
198
206
  customPropsCount = lines.length;
@@ -33,6 +33,7 @@
33
33
 
34
34
  import StyleDictionary from 'style-dictionary';
35
35
  import path from 'path';
36
+ import { padTokenPath } from '../lib/color-scale.mjs';
36
37
 
37
38
  // Disclaimer prepended to every generated file when penpotFormat is 'jsonc'
38
39
  const DISCLAIMER = [
@@ -126,20 +127,28 @@ StyleDictionary.registerFormat({
126
127
  name: 'json/penpot',
127
128
  format: ({ dictionary, options }) => {
128
129
  const root = {};
129
- const expressionMode = options.penpotExpressions ?? 'keep'; // 'keep' | 'calc' | 'resolve'
130
+ const expressionMode = options.penpotExpressions ?? 'keep';
131
+ const colorScalePrefixes = options.colorScalePrefixes ?? [];
130
132
  const tokenMap = (expressionMode === 'resolve') ? makeTokenMap(dictionary) : null;
131
133
 
132
134
  for (const token of dictionary.allTokens) {
133
- // Rebuild the nested tree from the token path
135
+ const type = token.$type ?? token.type;
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
134
144
  let node = root;
135
- for (let i = 0; i < token.path.length - 1; i++) {
136
- const segment = token.path[i];
145
+ for (let i = 0; i < tokenPath.length - 1; i++) {
146
+ const segment = tokenPath[i];
137
147
  node[segment] = node[segment] ?? {};
138
148
  node = node[segment];
139
149
  }
140
150
 
141
- const leafKey = token.path[token.path.length - 1];
142
- const type = token.$type ?? token.type;
151
+ const leafKey = tokenPath[tokenPath.length - 1];
143
152
  const orig = token.original?.$value ?? token.original?.value;
144
153
 
145
154
  // ── Value resolution ────────────────────────────────────────────────────
@@ -223,13 +232,15 @@ export const collectConcreteFilePaths = async (sd) => {
223
232
  // @param {string|null} penpotDestFile Aggregated file base name, or null
224
233
  // @param {'json'|'jsonc'} penpotFormat Output format
225
234
  // @param {'keep'|'calc'|'resolve'} penpotExpressions Expression handling mode
235
+ // @param {string[]} colorScalePrefixes Color token prefixes for numeric scale zero-padding
226
236
  // @returns {object[]} File descriptors for the Style Dictionary platform
227
237
 
228
238
  export const buildPenpotFiles = (
229
239
  concreteFilePaths,
230
240
  penpotDestFile,
231
241
  penpotFormat = 'json',
232
- penpotExpressions = 'keep'
242
+ penpotExpressions = 'keep',
243
+ colorScalePrefixes = []
233
244
  ) => {
234
245
  const ext = penpotFormat === 'jsonc' ? '.jsonc' : '.json';
235
246
  const jsonc = penpotFormat === 'jsonc';
@@ -238,7 +249,7 @@ export const buildPenpotFiles = (
238
249
  return [{
239
250
  destination: penpotDestFile + ext,
240
251
  format: 'json/penpot',
241
- options: { jsonc, penpotExpressions },
252
+ options: { jsonc, penpotExpressions, colorScalePrefixes },
242
253
  }];
243
254
  }
244
255
 
@@ -252,7 +263,7 @@ export const buildPenpotFiles = (
252
263
  return {
253
264
  destination: destName,
254
265
  format: 'json/penpot',
255
- options: { jsonc, penpotExpressions },
266
+ options: { jsonc, penpotExpressions, colorScalePrefixes },
256
267
  filter: (token) => {
257
268
  const fp = token.filePath ? path.resolve(token.filePath) : '';
258
269
  return fp === absPath;
@@ -0,0 +1,81 @@
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, '\\$&');
@@ -40,6 +40,7 @@ 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.
43
44
  * @returns {object} platforms object ready for Style Dictionary config
44
45
  */
45
46
  export const buildPlatforms = ({
@@ -49,6 +50,7 @@ export const buildPlatforms = ({
49
50
  penpotDestFile,
50
51
  penpotFormat,
51
52
  penpotExpressions = 'keep',
53
+ colorScalePrefixes = [],
52
54
  concreteFilePaths = [],
53
55
  }) => {
54
56
  const platforms = {
@@ -62,6 +64,7 @@ export const buildPlatforms = ({
62
64
  options: {
63
65
  outputReferences: true,
64
66
  showFileHeader: true,
67
+ colorScalePrefixes,
65
68
  },
66
69
  },
67
70
  ],
@@ -72,7 +75,7 @@ export const buildPlatforms = ({
72
75
  platforms.penpot = {
73
76
  buildPath: penpotBuildPath + '/',
74
77
  transforms: PENPOT_TRANSFORMS,
75
- files: buildPenpotFiles(concreteFilePaths, penpotDestFile, penpotFormat, penpotExpressions),
78
+ files: buildPenpotFiles(concreteFilePaths, penpotDestFile, penpotFormat, penpotExpressions, colorScalePrefixes),
76
79
  };
77
80
  }
78
81
 
@@ -28,6 +28,7 @@ import {
28
28
  penpotDestFile,
29
29
  penpotFormat,
30
30
  penpotExpressions,
31
+ colorScalePrefixes,
31
32
  source,
32
33
  } from './build-tokens-src/config.mjs';
33
34
 
@@ -71,6 +72,7 @@ const sd = new StyleDictionary({
71
72
  penpotDestFile,
72
73
  penpotFormat,
73
74
  penpotExpressions,
75
+ colorScalePrefixes,
74
76
  concreteFilePaths,
75
77
  }),
76
78
  });
@@ -94,7 +96,7 @@ console.log(styleText(['yellow'], `[build-tokens] source : ${source.map(sho
94
96
  console.log(styleText(['yellow'], `[build-tokens] dest file : ${short(path.join(buildPath, destFile))}`));
95
97
 
96
98
  if (penpotBuildPath) {
97
- const penpotFiles = buildPenpotFiles(concreteFilePaths, penpotDestFile, penpotFormat, penpotExpressions);
99
+ const penpotFiles = buildPenpotFiles(concreteFilePaths, penpotDestFile, penpotFormat, penpotExpressions, colorScalePrefixes);
98
100
  if (penpotFiles.length === 1) {
99
101
  console.log(styleText(['yellow'],
100
102
  `[build-tokens] penpot json : ${short(path.join(penpotBuildPath, penpotFiles[0].destination))}`
@@ -8,17 +8,18 @@
8
8
  //
9
9
  // Usage: node check-unresolved-custom-props.mjs --config ./path/to/config.mjs
10
10
 
11
- // TODO rimuovere/non generare file result se vuoto
11
+
12
+ /* globals process */
12
13
 
13
14
  import path from 'path';
14
15
  import fs from 'node:fs';
15
- import { fileURLToPath, pathToFileURL } from 'url';
16
- import { dirname } from 'path';
16
+ import { /* fileURLToPath, */pathToFileURL } from 'url';
17
+ // import { dirname } from 'path';
17
18
  import { glob } from 'node:fs/promises';
18
19
  import { styleText, parseArgs } from 'node:util';
19
20
 
20
- const __filename = fileURLToPath(import.meta.url);
21
- const __dirname = dirname(__filename);
21
+ // const __filename = fileURLToPath(import.meta.url);
22
+ // const __dirname = dirname(__filename);
22
23
 
23
24
  // ---------------------------------------------------------------------------
24
25
  // 1. Parse flags
@@ -118,15 +119,21 @@ async function run() {
118
119
  `${unresolved_props.length} unresolved custom properties found -> ${path.relative(process.cwd(), result_file)}`
119
120
  ));
120
121
 
121
- fs.writeFileSync(
122
- result_file,
123
- unresolved_props
124
- .map(item =>
125
- `* [${path.basename(item.file)} :: ${item.line}](${item.file}#L${item.line}) -> var(${item.prop})`
126
- )
127
- .join('\n'),
128
- 'utf-8'
129
- );
122
+ if(unresolved_props.length) {
123
+ fs.writeFileSync(
124
+ result_file,
125
+ unresolved_props
126
+ .map(item =>
127
+ `* [${path.basename(item.file, '.css')}](${item.file}#L${item.line}) -> \`${item.prop}\``
128
+ )
129
+ .join('\n'),
130
+ 'utf-8'
131
+ );
132
+ } else {
133
+ if (fs.existsSync(result_file)) {
134
+ fs.unlinkSync(result_file);
135
+ }
136
+ }
130
137
 
131
138
  console.log(styleText(['green'], '**** DONE ****'));
132
139
 
@@ -75,6 +75,12 @@ const config = {
75
75
  // e.g. {size.base} = 16px, "{size.base} * .25" -> "4px"
76
76
  penpotExpressions: 'resolve',
77
77
 
78
+ // Color token prefixes for which the numeric scale segment is zero-padded
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'],
83
+
78
84
  // ---------------------------------------------------------------------------
79
85
  // check-unresolved-custom-props.mjs settings
80
86
  // ---------------------------------------------------------------------------
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@massimo-cassandro/minimo",
3
- "version": "0.4.3",
3
+ "version": "0.5.0",
4
4
  "description": "Light css framework",
5
5
  "type": "module",
6
6
  "homepage": "https://github.com/massimo-cassandro/minimo#readme",
@@ -5,19 +5,19 @@
5
5
 
6
6
  .modal-alert {
7
7
  --malert-success-color: var(--status-success-color);
8
- --malert-success-color-fg: var(--status-success-foreground);
8
+ --malert-success-color-fg: var(--status-success-fg);
9
9
 
10
10
  --malert-info-color: var(--status-info-color);
11
- --malert-info-color-fg: var(--status-info-foreground);
11
+ --malert-info-color-fg: var(--status-info-fg);
12
12
 
13
13
  --malert-warning-color: var(--status-warning-color);
14
- --malert-warning-color-fg: var(--status-warning-foreground);
14
+ --malert-warning-color-fg: var(--status-warning-fg);
15
15
 
16
16
  --malert-error-color: var(--status-danger-color);
17
- --malert-error-color-fg: var(--status-danger-foreground);
17
+ --malert-error-color-fg: var(--status-danger-fg);
18
18
 
19
19
  --malert-confirm-color: var(--status-warning-color);
20
- --malert-confirm-color-fg: var(--status-warning-foreground);
20
+ --malert-confirm-color-fg: var(--status-warning-fg);
21
21
 
22
22
  /* --malert-marks-stroke-width: 6px; */
23
23
  --malert-backdrop: rgb(0 0 0 / .3);
@@ -37,7 +37,7 @@
37
37
  aspect-ratio: 1;
38
38
  padding: 4px;
39
39
  background-color: var(--body-background-color);
40
- border: 1px solid var(--neutral-base);
40
+ border: 1px solid var(--neutral-100);
41
41
  border-radius: 50%;
42
42
  box-shadow: var(--shadow-3);
43
43
 
@@ -50,7 +50,7 @@
50
50
  left: 50%;
51
51
  display: block;
52
52
  padding: var(--size-xs);
53
- color: var(--recaptcha-alert-foreground, #fff);
53
+ color: var(--recaptcha-alert-fg, #fff);
54
54
  background-color: var(--recaptcha-alert-background-color, #000);
55
55
  border: .5px solid currentColor;
56
56
  border-radius: var(--radius-xs);
@@ -26,24 +26,24 @@
26
26
 
27
27
  /* alert-error / alert-danger (default) */
28
28
  --_alert-bg-color: var(--status-danger-background-color);
29
- --_alert-fg-color: var(--status-danger-foreground);
29
+ --_alert-fg-color: var(--status-danger-fg);
30
30
  --_alert-border-color: var(--status-danger-border-color);
31
31
 
32
32
  position: relative;
33
33
 
34
34
  &.alert-warning, &.alert-notice {
35
35
  --_alert-bg-color: var(--status-warning-color);
36
- --_alert-fg-color: var(--status-warning-foreground);
36
+ --_alert-fg-color: var(--status-warning-fg);
37
37
  --_alert-border-color: var(--status-warning-border-color);
38
38
  }
39
39
  &.alert-info {
40
40
  --_alert-bg-color: var(--status-info-color);
41
- --_alert-fg-color: var(--status-info-foreground);
41
+ --_alert-fg-color: var(--status-info-fg);
42
42
  --_alert-border-color: var(--status-info-border-color);
43
43
  }
44
44
  &.alert-success {
45
45
  --_alert-bg-color: var(--status-success-color);
46
- --_alert-fg-color: var(--status-success-foreground);
46
+ --_alert-fg-color: var(--status-success-fg);
47
47
  --_alert-border-color: var(--status-success-border-color);
48
48
  }
49
49
 
@@ -2,21 +2,21 @@
2
2
 
3
3
  &.btn-success {
4
4
  --_bg: var(--status-success-color);
5
- --_fg: var(--status-success-foreground);
5
+ --_fg: var(--status-success-fg);
6
6
  --_btn-bg-color: var(--_bg);
7
7
  --_btn-fg-color: var(--_fg);
8
8
  --_btn-border-color: var(--status-success-border-color);
9
9
  }
10
10
  &.btn-info {
11
11
  --_bg: var(--status-info-color);
12
- --_fg: var(--status-info-foreground);
12
+ --_fg: var(--status-info-fg);
13
13
  --_btn-bg-color: var(--_bg);
14
14
  --_btn-fg-color: var(--_fg);
15
15
  --_btn-border-color: var(--status-info-border-color);
16
16
  }
17
17
  &.btn-danger, &.btn-error {
18
18
  --_bg: var(--status-danger-color);
19
- --_fg: var(--status-danger-foreground);
19
+ --_fg: var(--status-danger-fg);
20
20
  --_btn-bg-color: var(--_bg);
21
21
  --_btn-fg-color: var(--_fg);
22
22
  --_btn-border-color: var(--status-danger-border-color);
@@ -25,7 +25,7 @@
25
25
 
26
26
  &.btn-warning {
27
27
  --_bg: var(--status-warning-color);
28
- --_fg: var(--status-warning-foreground);
28
+ --_fg: var(--status-warning-fg);
29
29
  --_btn-bg-color: var(--_bg);
30
30
  --_btn-fg-color: var(--_fg);
31
31
  --_btn-border-color: var(--status-warning-border-color);
@@ -99,7 +99,7 @@ select.form-control, .form-select {
99
99
 
100
100
  input[type='checkbox'] {
101
101
  color: var(--form-control-text-color);
102
- accent-color: var(--accent-base);
102
+ accent-color: var(--accent-100);
103
103
  transform-origin: center;
104
104
  scale: 1.3;
105
105
  }
@@ -1,10 +1,10 @@
1
1
  :root {
2
- --accent-base: #567d0d;
3
- --accent-on-base: #fff;
2
+ --accent-100: #567d0d;
3
+ --accent-100-fg: #fff;
4
4
  --alert-border-radius: var(--radius-sm);
5
5
  --alert-box-shadow: 0 0 .5rem 0 oklch(0% 0 0 / .5);
6
- --badge-background-color: var(--primary-base);
7
- --badge-color: var(--primary-on-base);
6
+ --badge-background-color: var(--primary-100);
7
+ --badge-color: var(--primary-100-fg);
8
8
  --badge-font-size: var(--font-size-xs);
9
9
  --badge-font-weight: var(--font-weight-semibold);
10
10
  --badge-lg-font-size: var(--font-size-base);
@@ -47,9 +47,9 @@
47
47
  --btn-primary-active-background-color: calc(color-mix(in srgb, var(--btn-primary-background-color) 60%, #000) ;);
48
48
  --btn-primary-active-border-color: var(--btn-primary-active-background-color);
49
49
  --btn-primary-active-color: var(--btn-primary-color);
50
- --btn-primary-background-color: var(--primary-base);
50
+ --btn-primary-background-color: var(--primary-100);
51
51
  --btn-primary-border-color: var(--btn-primary-background-color);
52
- --btn-primary-color: var(--primary-on-base);
52
+ --btn-primary-color: var(--primary-100-fg);
53
53
  --btn-primary-focus-outline-color: calc(color-mix(in srgb, var(--btn-primary-background-color) 60%, transparent) ;);
54
54
  --btn-primary-hollow-background-color: var(--btn-primary-color);
55
55
  --btn-primary-hollow-color: var(--btn-primary-background-color);
@@ -166,11 +166,12 @@
166
166
  --link-focus-outline-color: var(--link-color);
167
167
  --link-focus-outline-width: .125rem;
168
168
  --link-visited-color: #ae0da3;
169
- --neutral-base: #666;
170
- --neutral-on-base: #fff;
169
+ --neutral-100: #666;
170
+ --neutral-100-fg: #fff;
171
171
  --overlay-color: rgb(0 0 0 / .6);
172
- --primary-base: #083865;
173
- --primary-on-base: #fff;
172
+ --primary-100: #083865;
173
+ --primary-100-fg: #fff;
174
+ --primary-080: #0957a0;
174
175
  --radius-base: var(--size-base);
175
176
  --radius-lg: var(--size-lg);
176
177
  --radius-md: var(--size-md);
@@ -180,19 +181,19 @@
180
181
  --radius-xs: var(--size-xs);
181
182
  --radius-xxs: var(--size-xxs);
182
183
  --recaptcha-alert-background-color: #000;
183
- --recaptcha-alert-foreground: #fff;
184
+ --recaptcha-alert-fg: #fff;
184
185
  --recaptcha-alert-overlay-color: rgb(0 0 0 / .5);
185
186
  --sdt-hover-background-color: var(--btn-primary-background-color);
186
187
  --sdt-hover-color: var(--btn-primary-color);
187
- --sdt-pagination-border: var(--btn-border-width) var(--neutral-base);
188
+ --sdt-pagination-border: var(--btn-border-width) var(--neutral-100);
188
189
  --sdt-pagination-padding-block: var(--size-xxs);
189
190
  --sdt-pagination-padding-inline: var(--size-xs);
190
- --sdt-thead-hover-background-color: calc(color-mix(in srgb, var(--table-thead-background-color) 90%, var(--accent-base)));
191
- --secondary-base: #650853;
192
- --secondary-on-base: #fff;
191
+ --sdt-thead-hover-background-color: calc(color-mix(in srgb, var(--table-thead-background-color) 90%, var(--accent-100)));
192
+ --secondary-100: #650853;
193
+ --secondary-100-fg: #fff;
193
194
  --sf-macro-btn-close-background-color: var(--body-background-color);
194
195
  --sf-macro-btn-close-size: 2rem;
195
- --sf-macro-rows-border: 1px solid var(--neutral-base);
196
+ --sf-macro-rows-border: 1px solid var(--neutral-100);
196
197
  --sf-macro-rows-border-radius: var(--radius-xs);
197
198
  --sf-macro-rows-even-background-color: var(--body-background-color);
198
199
  --sf-macro-rows-hover-background-color: calc(color-mix(in srgb, var(--body-background-color) 95%, #000));
@@ -207,25 +208,25 @@
207
208
  --size-xl: 2rem;
208
209
  --size-xs: .5rem;
209
210
  --size-xxs: .25rem;
210
- --spinner-color: var(--primary-base);
211
+ --spinner-color: var(--primary-100);
211
212
  --spinner-size: var(--size-lg);
212
213
  --spinner-stroke-width: .125rem;
213
214
  --status-danger-background-color: var(--status-danger-color);
214
215
  --status-danger-border-color: var(--status-danger-color);
215
216
  --status-danger-color: #c00;
216
- --status-danger-foreground: #fff;
217
+ --status-danger-fg: #fff;
217
218
  --status-info-background-color: var(--status-info-color);
218
219
  --status-info-border-color: var(--status-info-color);
219
220
  --status-info-color: #0665c5;
220
- --status-info-foreground: #fff;
221
+ --status-info-fg: #fff;
221
222
  --status-success-background-color: var(--status-success-color);
222
223
  --status-success-border-color: var(--status-success-color);
223
224
  --status-success-color: #046d19;
224
- --status-success-foreground: #fff;
225
+ --status-success-fg: #fff;
225
226
  --status-warning-background-color: var(--status-warning-color);
226
227
  --status-warning-border-color: var(--status-warning-color);
227
228
  --status-warning-color: #fc0;
228
- --status-warning-foreground: #4f2900;
229
+ --status-warning-fg: #4f2900;
229
230
  --table-body-border-width: .0625rem;
230
231
  --table-body-tr-alt-bg-color: #efefef;
231
232
  --table-body-tr-hover-bg-color: #cbcbcb;
@@ -237,7 +238,7 @@
237
238
  --table-thead-border-width: .1875rem;
238
239
  --text-color: #000;
239
240
  --text-dim: var(--text-muted);
240
- --text-muted: var(--neutral-base);
241
+ --text-muted: var(--neutral-100);
241
242
  --text-negative: #fff;
242
243
  --text-selected-background-color: #ddd;
243
244
  --text-selected-text: var(--body-text);
@@ -1,13 +0,0 @@
1
- {
2
- "accent": {
3
- "base": {
4
- "$value": "#567d0d",
5
- "$type": "color"
6
- },
7
- "on-base": {
8
- "$value": "#fff",
9
- "$type": "color"
10
- }
11
- }
12
-
13
- }
@@ -1,12 +0,0 @@
1
- {
2
- "neutral": {
3
- "base": {
4
- "$value": "#666",
5
- "$type": "color"
6
- },
7
- "on-base": {
8
- "$value": "#fff",
9
- "$type": "color"
10
- }
11
- }
12
- }
@@ -1,12 +0,0 @@
1
- {
2
- "primary": {
3
- "base": {
4
- "$value": "#083865",
5
- "$type": "color"
6
- },
7
- "on-base": {
8
- "$value": "#fff",
9
- "$type": "color"
10
- }
11
- }
12
- }
@@ -1,12 +0,0 @@
1
- {
2
- "secondary": {
3
- "base": {
4
- "$value": "#650853",
5
- "$type": "color"
6
- },
7
- "on-base": {
8
- "$value": "#fff",
9
- "$type": "color"
10
- }
11
- }
12
- }