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