@massimo-cassandro/minimo 0.3.5 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/README.md +1 -1
  2. package/design-tokens/alerts.minimo.tokens.jsonc +28 -0
  3. package/design-tokens/badge.minimo.tokens.jsonc +42 -0
  4. package/design-tokens/basic.minimo.tokens.jsonc +58 -0
  5. package/design-tokens/btn-close.minimo.tokens.jsonc +96 -0
  6. package/design-tokens/btn-primary.minimo.tokens.jsonc +96 -0
  7. package/design-tokens/btn.minimo.tokens.jsonc +196 -0
  8. package/design-tokens/color-accent.minimo.tokens.jsonc +18 -0
  9. package/design-tokens/color-neutral.minimo.tokens.jsonc +18 -0
  10. package/design-tokens/color-primary.minimo.tokens.jsonc +18 -0
  11. package/design-tokens/color-secondary.minimo.tokens.jsonc +18 -0
  12. package/design-tokens/components/recaptcha.minimo.tokens.jsonc +28 -0
  13. package/design-tokens/components/sf-macro.minimo.tokens.jsonc +66 -0
  14. package/design-tokens/components/spinner.minimo.tokens.jsonc +24 -0
  15. package/design-tokens/components/toast.minimo.tokens.jsonc +32 -0
  16. package/design-tokens/flex-grid.minimo.tokens.jsonc +24 -0
  17. package/design-tokens/form.minimo.tokens.jsonc +304 -0
  18. package/design-tokens/headings.minimo.tokens.jsonc +62 -0
  19. package/design-tokens/link.minimo.tokens.jsonc +44 -0
  20. package/design-tokens/radius.minimo.tokens.jsonc +42 -0
  21. package/design-tokens/recaptcha.minimo.tokens.jsonc +28 -0
  22. package/design-tokens/sf-macro.minimo.tokens.jsonc +66 -0
  23. package/design-tokens/simple-datatable.minimo.tokens.jsonc +51 -0
  24. package/design-tokens/size.minimo.tokens.jsonc +46 -0
  25. package/design-tokens/spinner.minimo.tokens.jsonc +24 -0
  26. package/design-tokens/status.minimo.tokens.jsonc +98 -0
  27. package/design-tokens/table.minimo.tokens.jsonc +64 -0
  28. package/design-tokens/toast.minimo.tokens.jsonc +32 -0
  29. package/design-tokens/typography.minimo.tokens.jsonc +102 -0
  30. package/design-tokens/utility.minimo.tokens.jsonc +14 -0
  31. package/design-tokens/web-components/simple-datatable.minimo.tokens.jsonc +51 -0
  32. package/design-tokens/z-index.minimo.tokens.jsonc +14 -0
  33. package/design-tokens-src/_readme.md +27 -0
  34. package/design-tokens-src/alerts.minimo.tokens.mjs +25 -0
  35. package/design-tokens-src/components/sf-macro.minimo.tokens.jsonc +66 -0
  36. package/{src/design-tokens → design-tokens-src}/form.minimo.tokens.jsonc +9 -8
  37. package/design-tokens-src/size.minimo.tokens.jsonc +105 -0
  38. package/design-tokens-utilities/build-tokens-src/config.mjs +108 -0
  39. package/design-tokens-utilities/build-tokens-src/formats/css.mjs +201 -0
  40. package/design-tokens-utilities/build-tokens-src/formats/penpot.mjs +262 -0
  41. package/design-tokens-utilities/build-tokens-src/platforms.mjs +80 -0
  42. package/design-tokens-utilities/build-tokens-src/transforms.mjs +200 -0
  43. package/design-tokens-utilities/build-tokens.mjs +114 -0
  44. package/design-tokens-utilities/check-unresolved-custom-props.mjs +137 -0
  45. package/design-tokens-utilities/readme.md +185 -0
  46. package/design-tokens-utilities/tokens-config-sample.mjs +98 -0
  47. package/package.json +10 -6
  48. package/src/components/auto-datatable/auto-datatable.css +4 -4
  49. package/src/components/modal-alert/modal-alert.css +5 -5
  50. package/src/components/{overlay.js → overlay/overlay.js} +1 -1
  51. package/src/{css/dialog-content.css → components/popup-page/popup-page.css} +1 -1
  52. package/src/components/{dialog-content.js → popup-page/popup-page.js} +6 -4
  53. package/src/components/sf-macro/sf-macro.css +7 -14
  54. package/src/css/alerts.css +3 -3
  55. package/src/css/buttons/status-buttons.css +4 -4
  56. package/src/css/forms/fieldset.css +2 -2
  57. package/src/custom-properties-default.css +24 -12
  58. package/src/icons/x.svg +1 -0
  59. package/src/web-components/simple-datatable/simple-datatable.js +2 -2
  60. package/src/web-components/simple-datatable/simple-datatable.module.css +3 -3
  61. package/src/web-components/simple-datatable/src/parse-cols.js +2 -2
  62. package/src/design-tokens/TODO.md +0 -2
  63. package/src/design-tokens/alerts.minimo.tokens.jsonc +0 -25
  64. package/src/design-tokens/size.minimo.tokens.jsonc +0 -101
  65. package/src/design-tokens-utilities/build-tokens.mjs +0 -503
  66. package/src/design-tokens-utilities/check-unresolved-custom-props.mjs +0 -131
  67. package/src/design-tokens-utilities/config-templates/tokens-config.mjs +0 -34
  68. package/src/design-tokens-utilities/readme.md +0 -12
  69. /package/{src/design-tokens → design-tokens-src}/badge.minimo.tokens.jsonc +0 -0
  70. /package/{src/design-tokens → design-tokens-src}/basic.minimo.tokens.jsonc +0 -0
  71. /package/{src/design-tokens → design-tokens-src}/btn-close.minimo.tokens.jsonc +0 -0
  72. /package/{src/design-tokens → design-tokens-src}/btn-primary.minimo.tokens.jsonc +0 -0
  73. /package/{src/design-tokens → design-tokens-src}/btn-secondary.minimo.tokens.jsonc +0 -0
  74. /package/{src/design-tokens → design-tokens-src}/btn.minimo.tokens.jsonc +0 -0
  75. /package/{src/design-tokens → design-tokens-src}/color-accent.minimo.tokens.jsonc +0 -0
  76. /package/{src/design-tokens → design-tokens-src}/color-neutral.minimo.tokens.jsonc +0 -0
  77. /package/{src/design-tokens → design-tokens-src}/color-primary.minimo.tokens.jsonc +0 -0
  78. /package/{src/design-tokens → design-tokens-src}/color-secondary.minimo.tokens.jsonc +0 -0
  79. /package/{src/components/recaptcha → design-tokens-src/components}/recaptcha.minimo.tokens.jsonc +0 -0
  80. /package/{src/components/spinner → design-tokens-src/components}/spinner.minimo.tokens.jsonc +0 -0
  81. /package/{src/components/toast → design-tokens-src/components}/toast.minimo.tokens.jsonc +0 -0
  82. /package/{src/design-tokens → design-tokens-src}/flex-grid.minimo.tokens.jsonc +0 -0
  83. /package/{src/design-tokens → design-tokens-src}/gradients-shadowes.minimo.tokens.jsonc +0 -0
  84. /package/{src/design-tokens → design-tokens-src}/headings.minimo.tokens.jsonc +0 -0
  85. /package/{src/design-tokens → design-tokens-src}/link.minimo.tokens.jsonc +0 -0
  86. /package/{src/design-tokens → design-tokens-src}/radius.minimo.tokens.jsonc +0 -0
  87. /package/{src/design-tokens → design-tokens-src}/status.minimo.tokens.jsonc +0 -0
  88. /package/{src/design-tokens → design-tokens-src}/table.minimo.tokens.jsonc +0 -0
  89. /package/{src/design-tokens → design-tokens-src}/typography.minimo.tokens.jsonc +0 -0
  90. /package/{src/design-tokens → design-tokens-src}/utility.minimo.tokens.jsonc +0 -0
  91. /package/{src/web-components/simple-datatable → design-tokens-src/web-components}/simple-datatable.minimo.tokens.jsonc +0 -0
  92. /package/{src/design-tokens → design-tokens-src}/z-index.minimo.tokens.jsonc +0 -0
  93. /package/src/{css → components/overlay}/overlay.css +0 -0
  94. /package/src/{web-components/simple-datatable/icons → icons}/arrow-down.svg +0 -0
  95. /package/src/{web-components/simple-datatable/icons → icons}/arrow-up.svg +0 -0
  96. /package/src/{web-components/simple-datatable/icons → icons}/arrows-down-up.svg +0 -0
  97. /package/src/{web-components/simple-datatable/icons → icons}/caret-left.svg +0 -0
  98. /package/src/{web-components/simple-datatable/icons → icons}/caret-right.svg +0 -0
  99. /package/src/{web-components/simple-datatable/icons → icons}/check-bold.svg +0 -0
  100. /package/src/{components/modal-alert/svg → icons}/check-circle-duotone.svg +0 -0
  101. /package/src/{components/modal-alert/svg → icons}/info-duotone.svg +0 -0
  102. /package/src/{components/modal-alert/svg → icons}/question-duotone.svg +0 -0
  103. /package/src/{components/modal-alert/svg → icons}/warning-duotone.svg +0 -0
  104. /package/src/{web-components/simple-datatable/icons → icons}/x-bold.svg +0 -0
  105. /package/src/{components/modal-alert/svg → icons}/x-circle-duotone.svg +0 -0
@@ -80,19 +80,19 @@
80
80
 
81
81
  &:not(.sortAscending):not(.sortDescending){
82
82
  .sortBtn::after {
83
- content: url('./icons/arrows-down-up.svg?cssInline');
83
+ content: url('../../icons/arrows-down-up.svg?cssInline');
84
84
  opacity: .4;
85
85
  }
86
86
  }
87
87
  }
88
88
  .sortAscending {
89
89
  .sortBtn::after {
90
- content: url('./icons/arrow-up.svg?cssInline');
90
+ content: url('../../icons/arrow-up.svg?cssInline');
91
91
  }
92
92
  }
93
93
  .sortDescending {
94
94
  .sortBtn::after {
95
- content: url('./icons/arrow-down.svg?cssInline');
95
+ content: url('../../icons/arrow-down.svg?cssInline');
96
96
  }
97
97
  }
98
98
 
@@ -6,8 +6,8 @@ import { classnames } from '@massimo-cassandro/js-utilities/index.js';
6
6
 
7
7
  import * as styles from '../simple-datatable.module.css';
8
8
 
9
- import checkIcon from '../icons/check-bold.svg?inline';
10
- import xIcon from '../icons/x-bold.svg?inline';
9
+ import checkIcon from '../../../icons/check-bold.svg?inline';
10
+ import xIcon from '../../../icons/x-bold.svg?inline';
11
11
 
12
12
  // col_obj è l'oggetto che descrive una singola colonna del datatable
13
13
  // vine utilizzato per produrre l'oggetto columns di simple-datatable
@@ -1,2 +0,0 @@
1
- * conversione in js?
2
- * automatizzare la creazione di proprietà ricorrenti (es il padding)
@@ -1,25 +0,0 @@
1
- {
2
- "alert": {
3
- "border": {
4
- "radius": {
5
- "$value": "{radius.sm}",
6
- "$type": "dimension"
7
- },
8
- },
9
-
10
- "box-shadow": {
11
- // "$type": "string",
12
- // "$value": "none"
13
- "$type": "shadow",
14
- "$value": [
15
- {
16
- "offsetX": 0,
17
- "offsetY": 0,
18
- "blur": "8px",
19
- "spread": 0,
20
- "color": "oklch(0 0 0 / 0.5)"
21
- }
22
- ]
23
- }
24
- }
25
- }
@@ -1,101 +0,0 @@
1
- {
2
-
3
-
4
- // in attesa di modifica dello script per il parser automatico delle espressioni
5
- // NB: "$type": "string" necessario, dimension converte i valori come se fossero px
6
- "size": {
7
- "xs": {
8
- "$value": ".5rem",
9
- "$type": "dimension",
10
- "$description": ""
11
- },
12
- "md": {
13
- "$value": "1.2rem",
14
- "$type": "dimension",
15
- "$description": ""
16
- },
17
- "3xl": {
18
- "$value": "4rem",
19
- "$type": "dimension",
20
- "$description": ""
21
- },
22
- "2xl": {
23
- "$value": "3rem",
24
- "$type": "dimension",
25
- "$description": ""
26
- },
27
- "base": {
28
- "$value": "1rem",
29
- "$type": "dimension",
30
- "$description": ""
31
- },
32
- "lg": {
33
- "$value": "1.5rem",
34
- "$type": "dimension",
35
- "$description": ""
36
- },
37
- "xxs": {
38
- "$value": ".25rem",
39
- "$type": "dimension",
40
- "$description": ""
41
- },
42
- "xl": {
43
- "$value": "2rem",
44
- "$type": "dimension",
45
- "$description": ""
46
- },
47
- "sm": {
48
- "$value": ".75rem",
49
- "$type": "dimension",
50
- "$description": ""
51
- }
52
- },
53
-
54
- // "size": {
55
- // "xxs": {
56
- // "$value": "{size.base} * .25",
57
- // "$type": "dimension",
58
- // "$description": ""
59
- // },
60
- // "xs": {
61
- // "$value": "{size.base} * .5",
62
- // "$type": "dimension",
63
- // "$description": ""
64
- // },
65
- // "sm": {
66
- // "$value": "{size.base} * .75",
67
- // "$type": "dimension",
68
- // "$description": ""
69
- // },
70
- // "base": {
71
- // "$value": "1rem",
72
- // "$type": "dimension",
73
- // "$description": ""
74
- // },
75
- // "md": {
76
- // "$value": "{size.base} * 1.2",
77
- // "$type": "dimension",
78
- // "$description": ""
79
- // },
80
- // "lg": {
81
- // "$value": "{size.base} * 1.5",
82
- // "$type": "dimension",
83
- // "$description": ""
84
- // },
85
- // "xl": {
86
- // "$value": "{size.base} * 2",
87
- // "$type": "dimension",
88
- // "$description": ""
89
- // },
90
- // "2xl": {
91
- // "$value": "{size.base} * 3",
92
- // "$type": "dimension",
93
- // "$description": ""
94
- // },
95
- // "3xl": {
96
- // "$value": "{size.base} * 4",
97
- // "$type": "dimension",
98
- // "$description": ""
99
- // }
100
- // }
101
- }
@@ -1,503 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // StyleDictionary v.5
4
- import StyleDictionary from 'style-dictionary';
5
- import path from 'path';
6
- import { pathToFileURL } from 'url';
7
- import { styleText } from 'node:util';
8
-
9
- import { homedir } from 'os';
10
-
11
- import stylelint from 'stylelint';
12
-
13
- // ---------------------------------------------------------------------------
14
- // Risoluzione del config file tramite flag --config
15
- // ---------------------------------------------------------------------------
16
- const args = process.argv.slice(2);
17
- const configFlagIndex = args.indexOf('--config');
18
-
19
- if (configFlagIndex === -1 || !args[configFlagIndex + 1]) {
20
- console.error('Errore: devi specificare il file di configurazione con --config ./path/to/config/file');
21
- process.exit(1);
22
- }
23
-
24
- let customPropsCount;
25
-
26
- // Il percorso passato è relativo alla CWD (root del progetto)
27
- const configArgPath = args[configFlagIndex + 1];
28
- const configAbsPath = path.resolve(process.cwd(), configArgPath);
29
-
30
- // La directory del config file: usata come base per risolvere i percorsi interni
31
- const configDir = path.dirname(configAbsPath);
32
-
33
- // Importa il config dinamicamente (usa fileURL per compatibilità ESM su Windows)
34
- const buildConfig = (await import(pathToFileURL(configAbsPath))).default;
35
-
36
- // Helper: risolve un percorso relativo rispetto alla dir del config file.
37
- // Se il percorso è già assoluto lo lascia intatto.
38
- const resolveFromConfig = (p) => path.resolve(configDir, p);
39
-
40
- // Risolve tutti i percorsi dichiarati nel config
41
- const stylelintConfigPath = resolveFromConfig(buildConfig.stylelintConfigPath);
42
- const buildPath = resolveFromConfig(buildConfig.buildPath);
43
- const destFile = buildConfig.destFile; // nome file, non un percorso da risolvere
44
-
45
- // source può contenere glob/percorsi: li risolviamo tutti rispetto alla configDir.
46
- // path.resolve non gestisce i glob, quindi usiamo path.posix per mantenere le slash
47
- // forward anche su Windows (fast-glob le richiede).
48
- const source = buildConfig.source.map((s) => {
49
- if (path.isAbsolute(s)) return s; // già assoluto, niente da fare
50
-
51
- // Unisce configDir + s e normalizza, poi ri-converte in forward-slash per fast-glob
52
- const joined = path.join(configDir, s);
53
- // Su Windows path.join usa '\', fast-glob vuole '/': normalizziamo sempre
54
- return joined.split(path.sep).join('/');
55
- });
56
-
57
- const stylelintConfig = await import(pathToFileURL(stylelintConfigPath)).then(m => m.default);
58
-
59
- // ---------------------------------------------------------------------------
60
- // 1. Shadow Transform
61
- // ---------------------------------------------------------------------------
62
- StyleDictionary.registerTransform({
63
- name: 'shadow/css',
64
- type: 'value',
65
- transitive: true,
66
- filter: (token) => (token.$type === 'shadow' || token.type === 'shadow'),
67
- transform: (token) => {
68
- const original = token.original?.$value ?? token.original?.value;
69
-
70
- const value = (typeof original === 'string' && original.startsWith('{'))
71
- ? (token.$value ?? token.value)
72
- : (original ?? token.$value ?? token.value);
73
-
74
- const shadows = Array.isArray(value) ? value : [value];
75
-
76
- if (shadows.length === 1 && typeof shadows[0] === 'string') {
77
- return shadows[0];
78
- }
79
-
80
- const BASE_FONT_SIZE = 16;
81
- const toRem = (val) => {
82
- if (val === undefined || val === null) return '0';
83
- const str = String(val).trim();
84
- const num = parseFloat(str);
85
- if (isNaN(num)) return str;
86
- if (num === 0) return '0';
87
- if (str.endsWith('px')) return `${num / BASE_FONT_SIZE}rem`;
88
- return str;
89
- };
90
-
91
- return shadows
92
- .map((s) => {
93
- const offsetX = toRem(s.offsetX ?? s.x);
94
- const offsetY = toRem(s.offsetY ?? s.y);
95
- const blur = toRem(s.blur);
96
- const spread = toRem(s.spread);
97
- const color = s.color ?? 'transparent';
98
- const inset = s.inset ? 'inset ' : '';
99
- return `${inset}${offsetX} ${offsetY} ${blur} ${spread} ${color}`;
100
- })
101
- .join(', ');
102
- }
103
- });
104
-
105
- // ---------------------------------------------------------------------------
106
- // 2. PX to REM Transform
107
- // ---------------------------------------------------------------------------
108
- StyleDictionary.registerTransform({
109
- name: 'size/pxToRem-smart',
110
- type: 'value',
111
- filter: (token) => {
112
- const value = token.$value || token.value;
113
- return (token.$type === 'dimension' || token.type === 'dimension')
114
- && typeof value === 'string'
115
- && !value.endsWith('rem');
116
- },
117
- transform: (token) => {
118
- const baseFontSize = 16;
119
- const value = token.$value || token.value;
120
- const floatValue = parseFloat(value);
121
-
122
- if (isNaN(floatValue)) return value;
123
-
124
- return `${floatValue / baseFontSize}rem`;
125
- }
126
- });
127
-
128
- // ---------------------------------------------------------------------------
129
- // 3. Color passthrough
130
- // ---------------------------------------------------------------------------
131
- StyleDictionary.registerTransform({
132
- name: 'color/css-modern',
133
- type: 'value',
134
- transitive: true,
135
- filter: (token) => token.$type === 'color' || token.type === 'color',
136
- transform: (token) => {
137
- const value = token.$value ?? token.value;
138
- if (typeof value === 'string') return value;
139
- return value;
140
- }
141
- });
142
-
143
- // ---------------------------------------------------------------------------
144
- // 4. Gradient Transform
145
- // ---------------------------------------------------------------------------
146
- StyleDictionary.registerTransform({
147
- name: 'gradient/css',
148
- type: 'value',
149
- transitive: true,
150
- filter: (token) => token.$type === 'gradient' || token.type === 'gradient',
151
- transform: (token) => {
152
- const original = token.original?.$value ?? token.original?.value;
153
-
154
- const value = (typeof original === 'string' && original.startsWith('{'))
155
- ? (token.$value ?? token.value)
156
- : (original ?? token.$value ?? token.value);
157
-
158
- if (typeof value === 'string') return value;
159
-
160
- const { type = 'linear', angle = 90, stops = [] } = value;
161
-
162
- const stopsList = stops
163
- .map((s) => {
164
- let color = s.color ?? 'transparent';
165
- if (s.alpha !== undefined) {
166
- color = `color-mix(in srgb, ${color} ${s.alpha * 100}%, transparent)`;
167
- }
168
- const position = s.position !== undefined ? ` ${s.position * 100}%` : '';
169
- return `${color}${position}`;
170
- })
171
- .join(', ');
172
-
173
- if (type === 'linear') return `linear-gradient(${angle}deg, ${stopsList})`;
174
- if (type === 'radial') return `radial-gradient(circle, ${stopsList})`;
175
- if (type === 'conic') return `conic-gradient(from ${angle}deg, ${stopsList})`;
176
-
177
- return `linear-gradient(${angle}${typeof angle === 'number'? 'deg' : ''}, ${stopsList})`;
178
- }
179
- });
180
-
181
- // ---------------------------------------------------------------------------
182
- // 5. Composite Transform (border, outline, transition, animation)
183
- // Tutti i tipi che hanno un shorthand CSS diretto.
184
- // ---------------------------------------------------------------------------
185
- StyleDictionary.registerTransform({
186
- name: 'composite/css',
187
- type: 'value',
188
- transitive: true,
189
- filter: (token) => {
190
- const type = token.$type ?? token.type;
191
- const value = token.$value ?? token.value;
192
- return (
193
- typeof value === 'object' &&
194
- value !== null &&
195
- !Array.isArray(value) &&
196
- ['border', 'outline', 'transition', 'animation'].includes(type)
197
- );
198
- },
199
- transform: (token) => {
200
- const type = token.$type ?? token.type;
201
- const v = token.$value ?? token.value;
202
-
203
- if (type === 'border') {
204
- const parts = [v.width ?? '1px'];
205
- if (v.style !== undefined && v.style !== null && v.style !== '') parts.push(v.style);
206
- parts.push(v.color ?? 'transparent');
207
- return parts.join(' ');
208
- }
209
-
210
- if (type === 'outline') {
211
- return `${v.width ?? '1px'} ${v.style ?? 'solid'} ${v.color ?? 'transparent'}`;
212
- }
213
-
214
- if (type === 'transition') {
215
- // Ordine: duration | timing-function | delay | property
216
- return [
217
- v.duration ?? '0s',
218
- v.timingFunction ?? 'ease',
219
- v.delay ?? '0s',
220
- v.property ?? 'all',
221
- ].join(' ');
222
- }
223
-
224
- if (type === 'animation') {
225
- // Ordine: duration | timing-function | delay | iteration-count |
226
- // direction | fill-mode | play-state | name
227
- return [
228
- v.duration ?? '0s',
229
- v.timingFunction ?? 'ease',
230
- v.delay ?? '0s',
231
- v.iterationCount ?? '1',
232
- v.direction ?? 'normal',
233
- v.fillMode ?? 'none',
234
- v.playState ?? 'running',
235
- v.name ?? 'none',
236
- ].join(' ');
237
- }
238
- }
239
- });
240
-
241
- // ---------------------------------------------------------------------------
242
- // 6. Typography Transform
243
- // Restituisce l'oggetto così com'è: il format lo esploderà in più props.
244
- // ---------------------------------------------------------------------------
245
- StyleDictionary.registerTransform({
246
- name: 'typography/css',
247
- type: 'value',
248
- transitive: true,
249
- filter: (token) => token.$type === 'typography' || token.type === 'typography',
250
- transform: (token) => token.$value ?? token.value,
251
- });
252
-
253
- // ---------------------------------------------------------------------------
254
- // Format: css/variables-sorted
255
- // ---------------------------------------------------------------------------
256
- StyleDictionary.registerFormat({
257
- name: 'css/variables-sorted',
258
- format: ({ dictionary, options }) => {
259
- const selector = options.selector ?? ':root';
260
-
261
- const tokenByPath = {};
262
- for (const token of dictionary.allTokens) {
263
- tokenByPath[token.path.join('.')] = token;
264
- }
265
-
266
- const resolveRefs = (str) =>
267
- String(str).replace(/\{([^}]+)\}/g, (_, p) => {
268
- const ref = tokenByPath[p];
269
- return ref ? `var(--${ref.name})` : `{${p}}`;
270
- });
271
-
272
- const BASE_FONT_SIZE = 16;
273
- const toRem = (val) => {
274
- if (val === undefined || val === null) return '0';
275
- const str = String(val).trim();
276
- const num = parseFloat(str);
277
- if (isNaN(num) || num === 0) return num === 0 ? '0' : str;
278
- if (str.endsWith('px')) return `${num / BASE_FONT_SIZE}rem`;
279
- return str;
280
- };
281
-
282
- const buildShadow = (original) => {
283
- const shadows = Array.isArray(original) ? original : [original];
284
- return shadows.map((s) => {
285
- const offsetX = toRem(s.offsetX ?? s.x);
286
- const offsetY = toRem(s.offsetY ?? s.y);
287
- const blur = toRem(s.blur);
288
- const spread = toRem(s.spread);
289
- const color = resolveRefs(s.color ?? 'transparent');
290
- const inset = s.inset ? 'inset ' : '';
291
- return `${inset}${offsetX} ${offsetY} ${blur} ${spread} ${color}`;
292
- }).join(', ');
293
- };
294
-
295
- const buildGradient = (original) => {
296
- const { type = 'linear', angle = 90, stops = [] } = original;
297
- const stopsList = stops.map((s) => {
298
- let color = resolveRefs(s.color ?? 'transparent');
299
- if (s.alpha !== undefined) {
300
- color = `color-mix(in srgb, ${color} ${s.alpha * 100}%, transparent)`;
301
- }
302
- const position = s.position !== undefined ? ` ${s.position * 100}%` : '';
303
- return `${color}${position}`;
304
- }).join(', ');
305
-
306
- if (type === 'radial') return `radial-gradient(circle, ${stopsList})`;
307
- if (type === 'conic') return `conic-gradient(from ${angle}deg, ${stopsList})`;
308
- return `linear-gradient(${angle}deg, ${stopsList})`;
309
- };
310
-
311
- // border e outline: shorthand con resolveRefs su tutti i campi; style è opzionale
312
- const buildBorderLike = (original) => {
313
- const parts = [resolveRefs(String(original.width ?? '1px'))];
314
- if (original.style !== undefined && original.style !== null && original.style !== '') {
315
- parts.push(resolveRefs(String(original.style)));
316
- }
317
- parts.push(resolveRefs(String(original.color ?? 'transparent')));
318
- return parts.join(' ');
319
- };
320
-
321
- // transition: resolveRefs su tutti i campi
322
- const buildTransition = (original) => [
323
- resolveRefs(String(original.duration ?? '0s')),
324
- resolveRefs(String(original.timingFunction ?? 'ease')),
325
- resolveRefs(String(original.delay ?? '0s')),
326
- resolveRefs(String(original.property ?? 'all')),
327
- ].join(' ');
328
-
329
- // animation: resolveRefs su tutti i campi
330
- const buildAnimation = (original) => [
331
- resolveRefs(String(original.duration ?? '0s')),
332
- resolveRefs(String(original.timingFunction ?? 'ease')),
333
- resolveRefs(String(original.delay ?? '0s')),
334
- resolveRefs(String(original.iterationCount ?? '1')),
335
- resolveRefs(String(original.direction ?? 'normal')),
336
- resolveRefs(String(original.fillMode ?? 'none')),
337
- resolveRefs(String(original.playState ?? 'running')),
338
- resolveRefs(String(original.name ?? 'none')),
339
- ].join(' ');
340
-
341
- const buildTypography = (tokenName, original) => {
342
- const {
343
- fontStyle,
344
- fontVariant,
345
- fontWeight,
346
- fontStretch,
347
- fontSize,
348
- lineHeight,
349
- fontFamily,
350
- // queste non entrano nel shorthand font
351
- letterSpacing,
352
- textTransform,
353
- textDecoration,
354
- } = original;
355
-
356
- const lines = [];
357
-
358
- // shorthand font se ci sono size e family (requisiti minimi CSS)
359
- if (fontSize && fontFamily) {
360
- const parts = [];
361
- if (fontStyle) parts.push(resolveRefs(String(fontStyle)));
362
- if (fontVariant) parts.push(resolveRefs(String(fontVariant)));
363
- if (fontWeight) parts.push(resolveRefs(String(fontWeight)));
364
- if (fontStretch) parts.push(resolveRefs(String(fontStretch)));
365
-
366
- const sizeSlash = lineHeight
367
- ? `${resolveRefs(String(fontSize))}/${resolveRefs(String(lineHeight))}`
368
- : resolveRefs(String(fontSize));
369
-
370
- parts.push(sizeSlash);
371
- parts.push(resolveRefs(String(fontFamily)));
372
-
373
- lines.push(` --${tokenName}-font: ${parts.join(' ')};`);
374
- }
375
-
376
- // proprietà che non entrano nel shorthand font
377
- const EXTRA_PROPS = {
378
- letterSpacing: ['letter-spacing', letterSpacing],
379
- textTransform: ['text-transform', textTransform],
380
- textDecoration: ['text-decoration', textDecoration],
381
- // fallback: se mancano size o family, le esponiamo comunque separatamente
382
- ...(!fontSize ? { fontSize: ['font-size', original.fontSize] } : {}),
383
- ...(!fontFamily ? { fontFamily: ['font-family', original.fontFamily] } : {}),
384
- };
385
-
386
- for (const [, [cssProp, val]] of Object.entries(EXTRA_PROPS)) {
387
- if (val !== undefined) {
388
- lines.push(` --${tokenName}-${cssProp}: ${resolveRefs(String(val))};`);
389
- }
390
- }
391
-
392
- return lines.join('\n');
393
- };
394
-
395
- const lines = dictionary.allTokens
396
- .slice()
397
- .sort((a, b) => a.name.localeCompare(b.name))
398
- .flatMap((token) => {
399
- const type = token.$type ?? token.type;
400
- const orig = token.original?.$value ?? token.original?.value;
401
-
402
- // typography: genera più righe, una per proprietà
403
- if (type === 'typography') {
404
- return [buildTypography(token.name, orig ?? {})];
405
- }
406
-
407
- let value;
408
-
409
- if (type === 'shadow' && options.outputReferences) {
410
- value = (typeof orig === 'string' && orig.startsWith('{'))
411
- ? resolveRefs(orig)
412
- : buildShadow(orig);
413
-
414
- } else if (type === 'gradient' && options.outputReferences) {
415
- value = (typeof orig === 'string' && orig.startsWith('{'))
416
- ? resolveRefs(orig)
417
- : buildGradient(orig);
418
-
419
- } else if ((type === 'border' || type === 'outline') && options.outputReferences) {
420
- value = (typeof orig === 'string' && orig.startsWith('{'))
421
- ? resolveRefs(orig)
422
- : buildBorderLike(orig);
423
-
424
- } else if (type === 'transition' && options.outputReferences) {
425
- value = (typeof orig === 'string' && orig.startsWith('{'))
426
- ? resolveRefs(orig)
427
- : buildTransition(orig);
428
-
429
- } else if (type === 'animation' && options.outputReferences) {
430
- value = (typeof orig === 'string' && orig.startsWith('{'))
431
- ? resolveRefs(orig)
432
- : buildAnimation(orig);
433
-
434
- } else if (options.outputReferences && typeof orig === 'string' && orig.includes('{')) {
435
- value = resolveRefs(orig);
436
-
437
- } else {
438
- value = String(token.$value ?? token.value);
439
- }
440
-
441
- return [` --${token.name}: ${value};`];
442
- });
443
-
444
- customPropsCount = lines.length;
445
- return `${selector} {\n${lines.join('\n')}\n}\n`;
446
- }
447
- });
448
-
449
- // ---------------------------------------------------------------------------
450
- // Style Dictionary config
451
- // ---------------------------------------------------------------------------
452
- const config = {
453
- source,
454
-
455
- log: {
456
- verbosity: 'verbose'
457
- },
458
-
459
- platforms: {
460
- css: {
461
- buildPath: buildPath + '/',
462
- transforms: [
463
- 'attribute/cti',
464
- 'name/kebab',
465
- 'time/seconds',
466
- 'asset/url',
467
- 'size/pxToRem-smart',
468
- 'color/css-modern',
469
- 'shadow/css',
470
- 'gradient/css',
471
- 'composite/css', // border, outline, transition, animation
472
- 'typography/css', // typography (esploso nel format)
473
- ],
474
- files: [
475
- {
476
- destination: destFile,
477
- format: 'css/variables-sorted',
478
- options: {
479
- outputReferences: true,
480
- showFileHeader: true,
481
- }
482
- }
483
- ]
484
- }
485
- }
486
- };
487
-
488
- const sd = new StyleDictionary(config);
489
- await sd.buildAllPlatforms();
490
-
491
- await stylelint.lint({
492
- config: stylelintConfig,
493
- files: [ path.join(buildPath, destFile) ],
494
- fix: true
495
- });
496
-
497
- console.log(styleText(['yellow'], `[build-tokens] config file : ${configAbsPath.replace(homedir(), '~')}` ));
498
- console.log(styleText(['yellow'], `[build-tokens] source : ${source.map(i => i.replace(homedir(), '~'))}` ));
499
- console.log(styleText(['yellow'], `[build-tokens] dest file : ${path.join(buildPath, destFile).replace(homedir(), '~')}` ));
500
-
501
- console.log(styleText(['green'], `[build-tokens] ${customPropsCount} custom props elaborate`));
502
-
503
- console.log(styleText(['green'], '**** FINE ****'));