@massimo-cassandro/minimo 1.35.1 → 1.36.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/dev-tools/design-tokens-builder/README.md +1 -1
- package/dev-tools/design-tokens-builder/build-tokens-src/build-source-modes.mjs +2 -2
- package/dev-tools/design-tokens-builder/build-tokens-src/config.mjs +13 -2
- package/dev-tools/design-tokens-builder/build-tokens-src/formats/css.mjs +15 -3
- package/dev-tools/design-tokens-builder/build-tokens-src/merge-css.mjs +61 -9
- package/dev-tools/design-tokens-builder/build-tokens.mjs +1 -1
- package/dev-tools/design-tokens-builder/tokens-config-sample.mjs +21 -9
- package/package.json +1 -1
- package/src/css/table.css +9 -14
|
@@ -163,7 +163,7 @@ When set, each mode has its own `source` array, and the generated CSS composes a
|
|
|
163
163
|
|
|
164
164
|
Tokens of a non-base mode can reference tokens defined in the base mode (e.g. a dark token using `{color.1}` defined in light, output as `var(--color-1)`). References to a non-base mode's tokens (from the base mode or from another non-base mode) fail with a "reference not defined" error, since the target would be undefined outside its own `@media` block.
|
|
165
165
|
|
|
166
|
-
`customPropsGroups`, `mergeCustomProps`, `addLayer`, `pxToRem` etc. all apply the same way as with a single `source
|
|
166
|
+
`customPropsGroups`, `mergeCustomProps`, `addLayer`, `pxToRem` etc. all apply the same way as with a single `source` (`mergeCustomProps` set to an array of strings/RegExps matches the token files of every mode). The JSON output (when `jsonBuildPath` is set) is produced once per mode, with the mode name appended to each filename (e.g. `tokens-light.jsonc` / `tokens-dark.jsonc`).
|
|
167
167
|
|
|
168
168
|
---
|
|
169
169
|
|
|
@@ -44,7 +44,7 @@ import { LEGACY_TOKENS_PARSER_NAME } from './legacy-tokens-parser.mjs';
|
|
|
44
44
|
* @param {{name:string,prefixes:string[]}[]} opts.customPropsGroups
|
|
45
45
|
* @param {boolean} opts.pxToRem
|
|
46
46
|
* @param {string|null} opts.addLayer
|
|
47
|
-
* @param {boolean}
|
|
47
|
+
* @param {boolean|(string|RegExp)[]} opts.mergeCustomProps true = merge all sources, array = only the matching token source files
|
|
48
48
|
* @returns {Promise<{cssDestPath: string, totalCustomProps: number, jsonFilesByMode: Record<string, object[]>}>}
|
|
49
49
|
*/
|
|
50
50
|
export const buildSourceModes = async ({
|
|
@@ -66,7 +66,7 @@ export const buildSourceModes = async ({
|
|
|
66
66
|
// Read the pre-existing destFile (if any) BEFORE any Style Dictionary
|
|
67
67
|
// instance runs, since the first one to write would overwrite it.
|
|
68
68
|
if (mergeCustomProps) {
|
|
69
|
-
loadExistingCustomPropsScoped(path.join(buildPath, destFile), baseMode);
|
|
69
|
+
loadExistingCustomPropsScoped(path.join(buildPath, destFile), baseMode, mergeCustomProps);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
const cssTransforms = pxToRem
|
|
@@ -84,8 +84,19 @@ export const pxToRem = buildConfig.pxToRem !== false;
|
|
|
84
84
|
|
|
85
85
|
// mergeCustomProps: if true, custom properties already present in the CSS
|
|
86
86
|
// destination file take priority over the ones generated by this build (see
|
|
87
|
-
// build-tokens-src/merge-css.mjs).
|
|
88
|
-
|
|
87
|
+
// build-tokens-src/merge-css.mjs). It can also be an array of strings/RegExps:
|
|
88
|
+
// only the properties generated by the token source files matching one of its
|
|
89
|
+
// entries are merged. An empty or invalid value means false. Default: false.
|
|
90
|
+
/** @type {boolean|(string|RegExp)[]} */
|
|
91
|
+
export const mergeCustomProps = (() => {
|
|
92
|
+
const value = buildConfig.mergeCustomProps;
|
|
93
|
+
if (value === true) return true;
|
|
94
|
+
if (Array.isArray(value)) {
|
|
95
|
+
const entries = value.filter((entry) => typeof entry === 'string' || entry instanceof RegExp);
|
|
96
|
+
return entries.length ? entries : false;
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
})();
|
|
89
100
|
|
|
90
101
|
// addLayer: wraps the generated custom properties inside a CSS `@layer`
|
|
91
102
|
// at-rule (see formats/css.mjs), e.g. `@layer project { :root { ... } }`.
|
|
@@ -192,6 +192,18 @@ StyleDictionary.registerFormat({
|
|
|
192
192
|
// Tokens loaded via `include` (sourceModes: base-mode tokens made
|
|
193
193
|
// available to other modes) stay in tokenByPath, so references to them
|
|
194
194
|
// resolve to var(--name), but are not declared in this mode's block.
|
|
195
|
+
// property name → token source file, used by mergeCustomProps when the
|
|
196
|
+
// merge is limited to some source files (a token may generate several
|
|
197
|
+
// properties, e.g. typography)
|
|
198
|
+
/** @type {Record<string,string>} */
|
|
199
|
+
const sourceFileMap = {};
|
|
200
|
+
const trackSource = (token, tokenLines) => {
|
|
201
|
+
for (const name of Object.keys(parseCustomProps(tokenLines.join('\n')))) {
|
|
202
|
+
sourceFileMap[name] = token.filePath;
|
|
203
|
+
}
|
|
204
|
+
return tokenLines;
|
|
205
|
+
};
|
|
206
|
+
|
|
195
207
|
const lines = dictionary.allTokens
|
|
196
208
|
.filter((token) => token.isSource !== false)
|
|
197
209
|
// .sort((a, b) => a.name.localeCompare(b.name, 'en', {numeric: true, sensitivity: 'base'}))
|
|
@@ -207,7 +219,7 @@ StyleDictionary.registerFormat({
|
|
|
207
219
|
.split('\n')
|
|
208
220
|
.map((line) => `${line}${commentSuffix}`)
|
|
209
221
|
.join('\n');
|
|
210
|
-
return [typographyLines];
|
|
222
|
+
return trackSource(token, [typographyLines]);
|
|
211
223
|
}
|
|
212
224
|
|
|
213
225
|
let value;
|
|
@@ -259,7 +271,7 @@ StyleDictionary.registerFormat({
|
|
|
259
271
|
.replace(/\(\s+/g, '(')
|
|
260
272
|
.replace(/\s+\)/g, ')');
|
|
261
273
|
|
|
262
|
-
return [` --${token.name}: ${value};${commentSuffix}`];
|
|
274
|
+
return trackSource(token, [` --${token.name}: ${value};${commentSuffix}`]);
|
|
263
275
|
});
|
|
264
276
|
|
|
265
277
|
// Build a name → declaration-tail map from the declarations generated
|
|
@@ -271,7 +283,7 @@ StyleDictionary.registerFormat({
|
|
|
271
283
|
// scopes the merge to that mode, so same-named props with different
|
|
272
284
|
// values across modes are never mixed up.
|
|
273
285
|
const generatedProps = parseCustomProps(lines.join('\n'));
|
|
274
|
-
const finalProps = mergeCustomProps(generatedProps, options.mode ?? null);
|
|
286
|
+
const finalProps = mergeCustomProps(generatedProps, options.mode ?? null, sourceFileMap);
|
|
275
287
|
|
|
276
288
|
// Final output is always sorted alphabetically ascending by property
|
|
277
289
|
// name, regardless of merge — this also keeps pre-existing-only
|
|
@@ -10,6 +10,12 @@
|
|
|
10
10
|
// mergeCustomProps(generatedMap) while building the output, right before
|
|
11
11
|
// serialising the final CSS text.
|
|
12
12
|
//
|
|
13
|
+
// `mergeCustomProps` may also be an array of strings/RegExps: in that case
|
|
14
|
+
// only the generated properties whose token source file matches one of the
|
|
15
|
+
// entries are merged (pre-existing value wins); the others are overwritten by
|
|
16
|
+
// the generated value. Pre-existing properties that are no longer generated
|
|
17
|
+
// (no token, hence no source file) are always kept. See matchesSource().
|
|
18
|
+
//
|
|
13
19
|
// Usage (sourceModes build, see build-source-modes.mjs):
|
|
14
20
|
// 1. Call loadExistingCustomPropsScoped(absDestPath, baseMode) BEFORE any
|
|
15
21
|
// of the per-mode Style Dictionary instances run.
|
|
@@ -36,7 +42,11 @@ export const parseCustomProps = (cssText) => {
|
|
|
36
42
|
/** @type {Record<string,string>} */
|
|
37
43
|
const map = {};
|
|
38
44
|
for (const match of cssText.matchAll(CUSTOM_PROP_RE)) {
|
|
39
|
-
|
|
45
|
+
let tail = match[2].trim();
|
|
46
|
+
// A multi-line comment is cut at the end of the line (only single-line
|
|
47
|
+
// declarations are parsed): close it, or the resulting CSS would be invalid
|
|
48
|
+
if (tail.lastIndexOf('/*') > tail.lastIndexOf('*/')) tail += ' */';
|
|
49
|
+
map[match[1]] = tail;
|
|
40
50
|
}
|
|
41
51
|
return map;
|
|
42
52
|
};
|
|
@@ -124,6 +134,32 @@ const splitModeScopes = (cssText) => {
|
|
|
124
134
|
return scopes;
|
|
125
135
|
};
|
|
126
136
|
|
|
137
|
+
// `true` = merge every source; an array = merge only the properties generated
|
|
138
|
+
// by the token source files matching one of its entries. Set by the
|
|
139
|
+
// loadExistingCustomProps*() functions.
|
|
140
|
+
/** @type {true|(string|RegExp)[]} */
|
|
141
|
+
let mergeSources = true;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Whether a token source file matches one of the `mergeCustomProps` array
|
|
145
|
+
* entries: a string matches if it is contained in the file path (path
|
|
146
|
+
* separators normalised to `/`), a RegExp if it tests true against it.
|
|
147
|
+
* @param {(string|RegExp)[]} sources
|
|
148
|
+
* @param {string|undefined} filePath token source file path
|
|
149
|
+
* @returns {boolean}
|
|
150
|
+
*/
|
|
151
|
+
const matchesSource = (sources, filePath) => {
|
|
152
|
+
if (!filePath) return false;
|
|
153
|
+
const normalized = filePath.replace(/\\/g, '/');
|
|
154
|
+
return sources.some((entry) => {
|
|
155
|
+
if (entry instanceof RegExp) {
|
|
156
|
+
entry.lastIndex = 0;
|
|
157
|
+
return entry.test(normalized);
|
|
158
|
+
}
|
|
159
|
+
return normalized.includes(entry.replace(/\\/g, '/'));
|
|
160
|
+
});
|
|
161
|
+
};
|
|
162
|
+
|
|
127
163
|
// null = merge disabled, or destination file not found yet (first build)
|
|
128
164
|
/** @type {Record<string,string>|null} */
|
|
129
165
|
let existingCustomProps = null;
|
|
@@ -137,9 +173,12 @@ let scopedExistingCustomProps = null;
|
|
|
137
173
|
* Reads the CSS destination file (if it exists) and stores a name → value
|
|
138
174
|
* map of its current custom properties for later merging.
|
|
139
175
|
* @param {string} absDestPath absolute path of the CSS file to read
|
|
176
|
+
* @param {true|(string|RegExp)[]} [sources] `true` merges every source, an
|
|
177
|
+
* array only the token source files matching one of its entries (default: true)
|
|
140
178
|
* @returns {Record<string,string>|null}
|
|
141
179
|
*/
|
|
142
|
-
export const loadExistingCustomProps = (absDestPath) => {
|
|
180
|
+
export const loadExistingCustomProps = (absDestPath, sources = true) => {
|
|
181
|
+
mergeSources = sources;
|
|
143
182
|
existingCustomProps = existsSync(absDestPath)
|
|
144
183
|
? parseCustomProps(readFileSync(absDestPath, 'utf8'))
|
|
145
184
|
: null;
|
|
@@ -154,9 +193,12 @@ export const loadExistingCustomProps = (absDestPath) => {
|
|
|
154
193
|
* @param {string} baseMode mode whose declarations live in the top-level,
|
|
155
194
|
* non-nested `:root { ... }` block (no default — always passed explicitly
|
|
156
195
|
* by build-source-modes.mjs, from the resolved sourceModesBase)
|
|
196
|
+
* @param {true|(string|RegExp)[]} [sources] `true` merges every source, an
|
|
197
|
+
* array only the token source files matching one of its entries (default: true)
|
|
157
198
|
* @returns {Record<string, Record<string,string>>|null}
|
|
158
199
|
*/
|
|
159
|
-
export const loadExistingCustomPropsScoped = (absDestPath, baseMode) => {
|
|
200
|
+
export const loadExistingCustomPropsScoped = (absDestPath, baseMode, sources = true) => {
|
|
201
|
+
mergeSources = sources;
|
|
160
202
|
if (!existsSync(absDestPath)) {
|
|
161
203
|
scopedExistingCustomProps = null;
|
|
162
204
|
return scopedExistingCustomProps;
|
|
@@ -177,16 +219,26 @@ export const loadExistingCustomPropsScoped = (absDestPath, baseMode) => {
|
|
|
177
219
|
* Merges freshly generated custom properties with the ones previously loaded
|
|
178
220
|
* via loadExistingCustomProps() / loadExistingCustomPropsScoped(). Pre-existing
|
|
179
221
|
* values take priority; custom properties found only in the pre-existing file
|
|
180
|
-
* (no longer generated) are kept as well.
|
|
222
|
+
* (no longer generated) are kept as well. When the merge is limited to some
|
|
223
|
+
* token source files (array option), a generated property whose source file
|
|
224
|
+
* does not match is not overridden by its pre-existing value.
|
|
181
225
|
* @param {Record<string,string>} generated name → value map produced by this build
|
|
182
226
|
* @param {string|null} [mode] when set (sourceModes build), looks up the
|
|
183
227
|
* pre-existing props scoped to this mode instead of the flat/global map (default: null)
|
|
228
|
+
* @param {Record<string,string>} [sourceFileMap] property name → token source
|
|
229
|
+
* file path, used only when the merge is limited to some sources (default: {})
|
|
184
230
|
* @returns {Record<string,string>}
|
|
185
231
|
*/
|
|
186
|
-
export const mergeCustomProps = (generated, mode = null) => {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
232
|
+
export const mergeCustomProps = (generated, mode = null, sourceFileMap = {}) => {
|
|
233
|
+
const existing = mode !== null ? scopedExistingCustomProps?.[mode] : existingCustomProps;
|
|
234
|
+
if (!existing) return generated;
|
|
235
|
+
if (mergeSources === true) return { ...generated, ...existing };
|
|
236
|
+
|
|
237
|
+
const merged = { ...generated };
|
|
238
|
+
for (const [name, tail] of Object.entries(existing)) {
|
|
239
|
+
if (!(name in generated) || matchesSource(mergeSources, sourceFileMap[name])) {
|
|
240
|
+
merged[name] = tail;
|
|
241
|
+
}
|
|
190
242
|
}
|
|
191
|
-
return
|
|
243
|
+
return merged;
|
|
192
244
|
};
|
|
@@ -116,7 +116,7 @@ if (sourceModes) {
|
|
|
116
116
|
// pre-existing values take priority — right before serialising the final
|
|
117
117
|
// CSS output. See merge-css.mjs.
|
|
118
118
|
if (mergeCustomProps) {
|
|
119
|
-
loadExistingCustomProps(path.join(buildPath, destFile));
|
|
119
|
+
loadExistingCustomProps(path.join(buildPath, destFile), mergeCustomProps);
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
// Collect concrete source file paths (multi-file JSON mode only). Source
|
|
@@ -113,13 +113,25 @@ const config = {
|
|
|
113
113
|
// are never touched regardless of this option.
|
|
114
114
|
pxToRem: false,
|
|
115
115
|
|
|
116
|
-
//
|
|
117
|
-
// (destFile, from a previous build)
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
//
|
|
121
|
-
//
|
|
122
|
-
//
|
|
116
|
+
// Preserves custom properties already present in the CSS destination file
|
|
117
|
+
// (destFile, from a previous build) across rebuilds: their values take
|
|
118
|
+
// priority over the ones generated by this build. Useful to keep manual
|
|
119
|
+
// overrides/additions made directly in the compiled CSS. Ignored on the
|
|
120
|
+
// first build, when destFile does not exist yet. Accepted values:
|
|
121
|
+
// false (default) - no merge: the destination file is fully regenerated
|
|
122
|
+
// true - merge all the sources
|
|
123
|
+
// array - strings and/or RegExps matched against the path of the
|
|
124
|
+
// token source files (those in `source` or `sourceModes`):
|
|
125
|
+
// only the properties generated by a matching file are
|
|
126
|
+
// merged, the others are overwritten by the generated value.
|
|
127
|
+
// A string matches if contained in the file path.
|
|
128
|
+
// An empty array is treated as false.
|
|
129
|
+
// e.g. ['/theme.minimo.tokens', /colors\.tokens\.(mjs|jsonc?)$/]
|
|
130
|
+
// With true or an array, properties found only in the pre-existing file (no
|
|
131
|
+
// longer generated, e.g. added by hand) are always kept.
|
|
132
|
+
// Comments at the end of a custom property line are preserved; full-line
|
|
133
|
+
// comments are lost, and a multi-line comment is cut at the end of its first
|
|
134
|
+
// line (and closed, to keep the CSS valid).
|
|
123
135
|
mergeCustomProps: false,
|
|
124
136
|
|
|
125
137
|
// Wraps the generated custom properties inside a CSS `@layer` at-rule,
|
|
@@ -202,11 +214,11 @@ const config = {
|
|
|
202
214
|
// Additional CSS files that define custom properties used in the project
|
|
203
215
|
// but not generated by build-tokens (e.g. third-party libraries)
|
|
204
216
|
extraCustomPropsFiles: [
|
|
205
|
-
//
|
|
217
|
+
// `${node_modules_path}/open-props/open-props.min.css`
|
|
206
218
|
],
|
|
207
219
|
|
|
208
220
|
// Directory containing the CSS files to scan for unresolved custom properties
|
|
209
|
-
dirToCheck: '
|
|
221
|
+
dirToCheck: '../../app',
|
|
210
222
|
|
|
211
223
|
// Regular expressions for custom property names to exclude from the check.
|
|
212
224
|
// Useful for intentionally private/internal props (e.g. prefixed with --_).
|
package/package.json
CHANGED
package/src/css/table.css
CHANGED
|
@@ -11,17 +11,12 @@
|
|
|
11
11
|
/* TODO opzione per attivare/disattuvare alternate color */
|
|
12
12
|
.table {
|
|
13
13
|
|
|
14
|
-
--_alternate-row-bg: var(--table-body-tr-alt-bg-color);
|
|
15
|
-
--_hover-row-bg: var(--table-body-tr-hover-bg-color);
|
|
16
|
-
--_border-color: var(--table-border-color);
|
|
17
|
-
--_border: 1px solid var(--_border-color);
|
|
18
|
-
|
|
19
14
|
width: 100%;
|
|
20
15
|
margin: 1rem 0;
|
|
21
16
|
border-collapse: collapse;
|
|
22
17
|
|
|
23
18
|
tr {
|
|
24
|
-
border-bottom: var(--
|
|
19
|
+
border-bottom: 1px solid var(--table-border-color);
|
|
25
20
|
}
|
|
26
21
|
|
|
27
22
|
thead {
|
|
@@ -34,7 +29,7 @@
|
|
|
34
29
|
tfoot {
|
|
35
30
|
background-color: var(--table-tfoot-background-color);
|
|
36
31
|
tr:first-child {
|
|
37
|
-
border-block-start: var(--table-tfoot-border-width) solid var(--
|
|
32
|
+
border-block-start: var(--table-tfoot-border-width) solid var(--table-border-color);
|
|
38
33
|
}
|
|
39
34
|
th, td {
|
|
40
35
|
font-weight: var(--table-tfoot-font-weight);
|
|
@@ -43,12 +38,12 @@
|
|
|
43
38
|
|
|
44
39
|
tbody {
|
|
45
40
|
tr:nth-child(even) {
|
|
46
|
-
background-color: var(--
|
|
41
|
+
background-color: var(--table-body-tr-alt-bg-color);
|
|
47
42
|
}
|
|
48
43
|
|
|
49
44
|
@media (hover: hover) {
|
|
50
45
|
tr:hover {
|
|
51
|
-
background-color: var(--
|
|
46
|
+
background-color: var(--table-body-tr-hover-bg-color);
|
|
52
47
|
}
|
|
53
48
|
}
|
|
54
49
|
}
|
|
@@ -66,11 +61,11 @@
|
|
|
66
61
|
}
|
|
67
62
|
|
|
68
63
|
&.table-bordered {
|
|
69
|
-
border: var(--
|
|
64
|
+
border: 1px solid var(--table-border-color);
|
|
70
65
|
|
|
71
66
|
th, td {
|
|
72
67
|
&:not(:first-child) {
|
|
73
|
-
border-inline-start: var(--
|
|
68
|
+
border-inline-start: 1px solid var(--table-border-color);
|
|
74
69
|
}
|
|
75
70
|
}
|
|
76
71
|
}
|
|
@@ -80,9 +75,9 @@
|
|
|
80
75
|
/*
|
|
81
76
|
@media (prefers-color-scheme: dark) {
|
|
82
77
|
.table {
|
|
83
|
-
--
|
|
84
|
-
--
|
|
85
|
-
--
|
|
78
|
+
--table-border-color: var(--_stone-8);
|
|
79
|
+
--table-body-tr-alt-bg-color: color-mix(in srgb, var(--_stone-12) 60%, transparent);
|
|
80
|
+
--table-body-tr-hover-bg-color: color-mix(in srgb, var(--_blue-12) 60%, transparent);
|
|
86
81
|
}
|
|
87
82
|
}
|
|
88
83
|
*/
|