@massimo-cassandro/minimo 1.18.3 → 1.19.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.
- package/README.md +5 -1
- package/design-tokens/tokens/src/components/modal-popup/modal-popup.minimo.tokens.jsonc +1 -1
- package/design-tokens/utilities/build-tokens-src/config.mjs +5 -0
- package/design-tokens/utilities/build-tokens-src/formats/css.mjs +18 -2
- package/design-tokens/utilities/build-tokens-src/merge-css.mjs +60 -0
- package/design-tokens/utilities/build-tokens.mjs +12 -0
- package/design-tokens/utilities/tokens-config-sample.mjs +8 -0
- package/dev-tools/README.md +8 -0
- package/dev-tools/starter-kit/starter-install.sh +46 -26
- package/package.json +1 -1
- package/src/components/modal-popup/modal-popup.minimo.tokens.mjs +1 -1
- package/src/custom-properties.css +1 -1
- package/design-tokens/utilities/readme.md +0 -185
package/README.md
CHANGED
|
@@ -31,6 +31,10 @@ rm -rf package
|
|
|
31
31
|
|
|
32
32
|
---
|
|
33
33
|
|
|
34
|
+
## Design tokens
|
|
35
|
+
|
|
36
|
+
Minimo comes with a set of design tokens and some utilities to manage them. See [Design Tokens readme](design-tokens/README.md).
|
|
37
|
+
|
|
34
38
|
## Dev Tools
|
|
35
39
|
|
|
36
40
|
The [`dev-tools`](./dev-tools/README.md) directory contains a set of standalone Node.js CLI utilities for managing a web project — updating dependencies, bumping the version and changelog, and generating/optimizing SVG icons and favicons. They are published as part of the `minimo` package and exposed via the `bin` entries in `package.json` (`update-version`, `upd@m`, `svgIconsTools`, `create-favicons`); see the [Dev Tools README](./dev-tools/README.md) for the full list and usage.
|
|
@@ -38,7 +42,7 @@ The [`dev-tools`](./dev-tools/README.md) directory contains a set of standalone
|
|
|
38
42
|
|
|
39
43
|
## Docs & Demo
|
|
40
44
|
|
|
41
|
-
[Docs](docs)
|
|
45
|
+
[Docs](docs/README.md)
|
|
42
46
|
|
|
43
47
|
[Demo](https://massimo-cassandro.github.io/minimo/) (in progress)
|
|
44
48
|
|
|
@@ -75,6 +75,11 @@ export const penpotExpressions = VALID_EXPR_MODES.includes(buildConfig.penpotExp
|
|
|
75
75
|
? buildConfig.penpotExpressions
|
|
76
76
|
: 'resolve';
|
|
77
77
|
|
|
78
|
+
// mergeCustomProps: if true, custom properties already present in the CSS
|
|
79
|
+
// destination file take priority over the ones generated by this build (see
|
|
80
|
+
// build-tokens-src/merge-css.mjs). Default: false.
|
|
81
|
+
export const mergeCustomProps = buildConfig.mergeCustomProps === true;
|
|
82
|
+
|
|
78
83
|
// ---------------------------------------------------------------------------
|
|
79
84
|
// Source: resolve patterns relative to the config directory and normalise to
|
|
80
85
|
// forward-slash absolute paths (fast-glob, used internally by Style Dictionary,
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
// - individual properties for letterSpacing, textTransform, textDecoration
|
|
7
7
|
|
|
8
8
|
import StyleDictionary from 'style-dictionary';
|
|
9
|
+
import { mergeCustomProps, parseCustomProps } from '../merge-css.mjs';
|
|
9
10
|
|
|
10
11
|
const BASE_FONT_SIZE = 16;
|
|
11
12
|
|
|
@@ -224,7 +225,22 @@ StyleDictionary.registerFormat({
|
|
|
224
225
|
return [` --${token.name}: ${value};`];
|
|
225
226
|
});
|
|
226
227
|
|
|
227
|
-
|
|
228
|
-
|
|
228
|
+
// Build a name → declaration-tail map from the declarations generated
|
|
229
|
+
// above, then merge with any pre-existing custom properties loaded via
|
|
230
|
+
// loadExistingCustomProps() (see ../merge-css.mjs). Pre-existing values
|
|
231
|
+
// (including trailing comments) take priority when both exist;
|
|
232
|
+
// pre-existing-only properties are kept.
|
|
233
|
+
const generatedProps = parseCustomProps(lines.join('\n'));
|
|
234
|
+
const finalProps = mergeCustomProps(generatedProps);
|
|
235
|
+
|
|
236
|
+
// Final output is always sorted alphabetically ascending by property
|
|
237
|
+
// name, regardless of merge — this also keeps pre-existing-only
|
|
238
|
+
// properties from merge-css.mjs in order instead of trailing at the end.
|
|
239
|
+
const outLines = Object.entries(finalProps)
|
|
240
|
+
.sort(([a], [b]) => a.localeCompare(b, 'en', { numeric: true, sensitivity: 'base' }))
|
|
241
|
+
.map(([name, tail]) => ` --${name}: ${tail}`);
|
|
242
|
+
|
|
243
|
+
customPropsCount = outLines.length;
|
|
244
|
+
return `${selector} {\n${outLines.join('\n')}\n}\n`;
|
|
229
245
|
},
|
|
230
246
|
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// build-tokens-src/merge-css.mjs
|
|
2
|
+
// Supports the `mergeCustomProps` config option: pre-existing custom
|
|
3
|
+
// properties in the CSS destination file take priority over the ones
|
|
4
|
+
// generated by the current build (manual overrides/additions survive rebuilds).
|
|
5
|
+
//
|
|
6
|
+
// Usage:
|
|
7
|
+
// 1. Call loadExistingCustomProps(absDestPath) BEFORE Style Dictionary runs,
|
|
8
|
+
// since it reads the file that is about to be overwritten.
|
|
9
|
+
// 2. The css/variables-sorted format (see formats/css.mjs) calls
|
|
10
|
+
// mergeCustomProps(generatedMap) while building the output, right before
|
|
11
|
+
// serialising the final CSS text.
|
|
12
|
+
|
|
13
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
14
|
+
|
|
15
|
+
const CUSTOM_PROP_RE = /^\s*--([\w-]+):\s*(.+)$/gm;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Parses `--name: <tail>` declarations out of a CSS text block. <tail> is
|
|
19
|
+
* captured verbatim (value, terminating `;`, and anything else on the same
|
|
20
|
+
* line, e.g. a trailing comment) so it round-trips unchanged through a merge.
|
|
21
|
+
* Only single-line declarations are supported.
|
|
22
|
+
* @param {string} cssText
|
|
23
|
+
* @returns {Record<string,string>} name → declaration-tail map, in first-seen order
|
|
24
|
+
*/
|
|
25
|
+
export const parseCustomProps = (cssText) => {
|
|
26
|
+
/** @type {Record<string,string>} */
|
|
27
|
+
const map = {};
|
|
28
|
+
for (const match of cssText.matchAll(CUSTOM_PROP_RE)) {
|
|
29
|
+
map[match[1]] = match[2].trim();
|
|
30
|
+
}
|
|
31
|
+
return map;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// null = merge disabled, or destination file not found yet (first build)
|
|
35
|
+
/** @type {Record<string,string>|null} */
|
|
36
|
+
let existingCustomProps = null;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Reads the CSS destination file (if it exists) and stores a name → value
|
|
40
|
+
* map of its current custom properties for later merging.
|
|
41
|
+
* @param {string} absDestPath absolute path of the CSS file to read
|
|
42
|
+
* @returns {Record<string,string>|null}
|
|
43
|
+
*/
|
|
44
|
+
export const loadExistingCustomProps = (absDestPath) => {
|
|
45
|
+
existingCustomProps = existsSync(absDestPath)
|
|
46
|
+
? parseCustomProps(readFileSync(absDestPath, 'utf8'))
|
|
47
|
+
: null;
|
|
48
|
+
return existingCustomProps;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Merges freshly generated custom properties with the ones previously loaded
|
|
53
|
+
* via loadExistingCustomProps(). Pre-existing values take priority; custom
|
|
54
|
+
* properties found only in the pre-existing file (no longer generated) are
|
|
55
|
+
* kept as well.
|
|
56
|
+
* @param {Record<string,string>} generated name → value map produced by this build
|
|
57
|
+
* @returns {Record<string,string>}
|
|
58
|
+
*/
|
|
59
|
+
export const mergeCustomProps = (generated) =>
|
|
60
|
+
existingCustomProps ? { ...generated, ...existingCustomProps } : generated;
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
penpotFormat,
|
|
32
32
|
penpotExpressions,
|
|
33
33
|
source,
|
|
34
|
+
mergeCustomProps,
|
|
34
35
|
} from './build-tokens-src/config.mjs';
|
|
35
36
|
|
|
36
37
|
// ── 2. Custom transforms ─────────────────────────────────────────────────────
|
|
@@ -38,7 +39,9 @@ import './build-tokens-src/transforms.mjs';
|
|
|
38
39
|
|
|
39
40
|
// ── 3. CSS format ─────────────────────────────────────────────────────────────
|
|
40
41
|
// customPropsCount is updated by the format at render time
|
|
42
|
+
// loadExistingCustomProps supports the mergeCustomProps option (see below)
|
|
41
43
|
import { customPropsCount } from './build-tokens-src/formats/css.mjs';
|
|
44
|
+
import { loadExistingCustomProps } from './build-tokens-src/merge-css.mjs';
|
|
42
45
|
|
|
43
46
|
// ── 4. Penpot format ──────────────────────────────────────────────────────────
|
|
44
47
|
import { buildPenpotFiles, collectConcreteFilePaths } from './build-tokens-src/formats/penpot.mjs';
|
|
@@ -46,6 +49,15 @@ import { buildPenpotFiles, collectConcreteFilePaths } from './build-tokens-src/f
|
|
|
46
49
|
// ── 5. Platforms builder ──────────────────────────────────────────────────────
|
|
47
50
|
import { buildPlatforms } from './build-tokens-src/platforms.mjs';
|
|
48
51
|
|
|
52
|
+
// ── 5b. Pre-existing custom properties (mergeCustomProps option) ────────────
|
|
53
|
+
// Read before Style Dictionary runs, since it overwrites the destination
|
|
54
|
+
// file. The css/variables-sorted format (formats/css.mjs) merges these
|
|
55
|
+
// values in — pre-existing values take priority — right before serialising
|
|
56
|
+
// the final CSS output. See merge-css.mjs.
|
|
57
|
+
if (mergeCustomProps) {
|
|
58
|
+
loadExistingCustomProps(path.join(buildPath, destFile));
|
|
59
|
+
}
|
|
60
|
+
|
|
49
61
|
// ── 6. Collect concrete source file paths (multi-file Penpot mode only) ──────
|
|
50
62
|
// Source entries may be glob patterns. SD expands them internally and stores
|
|
51
63
|
// the concrete path in token.filePath. We need those concrete paths to build
|
|
@@ -75,6 +75,14 @@ const config = {
|
|
|
75
75
|
// e.g. {size.base} = 16px, "{size.base} * .25" -> "4px"
|
|
76
76
|
penpotExpressions: 'resolve',
|
|
77
77
|
|
|
78
|
+
// If true, custom properties already present in the CSS destination file
|
|
79
|
+
// (destFile, from a previous build) take priority over the ones generated
|
|
80
|
+
// by this build. Properties found only in the pre-existing file (no longer
|
|
81
|
+
// generated) are kept too. Useful to preserve manual overrides/additions
|
|
82
|
+
// made directly in the compiled CSS across rebuilds. Ignored on the first
|
|
83
|
+
// build, when destFile does not exist yet. Default: false.
|
|
84
|
+
mergeCustomProps: false,
|
|
85
|
+
|
|
78
86
|
|
|
79
87
|
|
|
80
88
|
// ---------------------------------------------------------------------------
|
package/dev-tools/README.md
CHANGED
|
@@ -34,6 +34,14 @@ zsh package/dev-tools/starter-kit/starter-install.sh
|
|
|
34
34
|
rm -rf package
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
+
To test the installation skipping all `npm install` commands, use the `--no-npm` parameter:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
curl -sL "$(npm view @massimo-cassandro/minimo dist.tarball)" | tar xz package/dev-tools/starter-kit
|
|
41
|
+
zsh package/dev-tools/starter-kit/starter-install.sh --no-npm
|
|
42
|
+
rm -rf package
|
|
43
|
+
```
|
|
44
|
+
|
|
37
45
|
## SVG adn favicons tools
|
|
38
46
|
|
|
39
47
|
```bash
|
|
@@ -18,6 +18,23 @@ if [ -z "$ZSH_VERSION" ]; then
|
|
|
18
18
|
exit 1
|
|
19
19
|
fi
|
|
20
20
|
|
|
21
|
+
# --no-npm: salta le installazioni npm (utile per testare rapidamente lo script)
|
|
22
|
+
SKIP_NPM=0
|
|
23
|
+
for ARG in "$@"; do
|
|
24
|
+
if [ "$ARG" = "--no-npm" ]; then
|
|
25
|
+
SKIP_NPM=1
|
|
26
|
+
fi
|
|
27
|
+
done
|
|
28
|
+
|
|
29
|
+
# Wrapper: esegue "npm i ..." a meno che SKIP_NPM sia attivo
|
|
30
|
+
npm_i() {
|
|
31
|
+
if [ "$SKIP_NPM" = "1" ]; then
|
|
32
|
+
echo "(--no-npm) skip: npm i $*"
|
|
33
|
+
else
|
|
34
|
+
npm i "$@"
|
|
35
|
+
fi
|
|
36
|
+
}
|
|
37
|
+
|
|
21
38
|
# Configurazione variabili
|
|
22
39
|
# BASE_URL="https://raw.githubusercontent.com/massimo-cassandro/minimo/refs/heads/main"
|
|
23
40
|
|
|
@@ -139,28 +156,28 @@ fi
|
|
|
139
156
|
|
|
140
157
|
|
|
141
158
|
echo -e "\n${GREEN}...eslint${NC}"
|
|
142
|
-
|
|
159
|
+
npm_i -D @massimo-cassandro/eslint-config
|
|
143
160
|
safe_cat "${TEMPLATES_DIR}/eslint.config.mjs" eslint.config.mjs new
|
|
144
161
|
|
|
145
162
|
echo -e "\n${GREEN}...stylelint${NC}"
|
|
146
|
-
|
|
163
|
+
npm_i -D @massimo-cassandro/stylelint-config
|
|
147
164
|
safe_cat "${TEMPLATES_DIR}/stylelint.config.mjs" stylelint.config.mjs new
|
|
148
165
|
|
|
149
166
|
echo -e "\n${GREEN}...webpack${NC}"
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
167
|
+
npm_i -D webpack-cli webpack-dev-server webpack-manifest-plugin webpack
|
|
168
|
+
npm_i -D @babel/core @babel/preset-env babel-loader terser-webpack-plugin
|
|
169
|
+
npm_i -D webpack-remove-empty-scripts copy-webpack-plugin html-loader html-webpack-plugin
|
|
170
|
+
npm_i -D postcss autoprefixer postcss-custom-media @csstools/postcss-global-data postcss-loader postcss-preset-env
|
|
154
171
|
# NB: niente cssnano: la minificazione è di css-minimizer-webpack-plugin e cssnano
|
|
155
172
|
# nel loader postcss eliminerebbe i commenti `purgecss ignore` prima di PurgeCSS
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
173
|
+
npm_i -D mini-css-extract-plugin style-loader css-loader css-minimizer-webpack-plugin
|
|
174
|
+
npm_i -D responsive-loader
|
|
175
|
+
npm_i -D process dotenv-webpack
|
|
176
|
+
npm_i -D svgo svg-url-loader svgo-loader svgo-add-viewbox mini-svg-data-uri
|
|
177
|
+
npm_i -D ejs-loader
|
|
178
|
+
npm_i -D purgecss-webpack-plugin glob
|
|
162
179
|
|
|
163
|
-
|
|
180
|
+
npm_i -D style-dictionary
|
|
164
181
|
|
|
165
182
|
safe_cat "${WEBPACK_SOURCE_DIR}/webpack.config.mjs" "${FRONTEND_INSTALL_PATH}/webpack.config.mjs"
|
|
166
183
|
safe_cat "${WEBPACK_SOURCE_DIR}/webpack-template.ejs" "${FRONTEND_INSTALL_PATH}/webpack-template.ejs"
|
|
@@ -168,15 +185,6 @@ safe_cat "${WEBPACK_SOURCE_DIR}/webpack-template.ejs" "${FRONTEND_INSTALL_PATH}/
|
|
|
168
185
|
# cartella webpack
|
|
169
186
|
WEBPACK_LOCAL_DIR="${FRONTEND_INSTALL_PATH}/webpack-modules"
|
|
170
187
|
WEBPACK_MODULES_REMOTE_URL="${WEBPACK_SOURCE_DIR}/webpack-modules"
|
|
171
|
-
FILES=(
|
|
172
|
-
'css-rules.mjs'
|
|
173
|
-
'get-jsConfig-aliases.mjs'
|
|
174
|
-
'mini-svg-data-uri-loader.cjs'
|
|
175
|
-
'svg-rules.mjs'
|
|
176
|
-
'svgo.config.mjs'
|
|
177
|
-
'postcss.config.mjs'
|
|
178
|
-
'purgecss-variables-safelist.mjs'
|
|
179
|
-
)
|
|
180
188
|
|
|
181
189
|
# se la cartella esiste già, i moduli vengono copiati in NEW-webpack-modules
|
|
182
190
|
# (da integrare manualmente o rimuovere)
|
|
@@ -188,18 +196,30 @@ fi
|
|
|
188
196
|
|
|
189
197
|
mkdir -p "$WEBPACK_LOCAL_DIR"
|
|
190
198
|
|
|
191
|
-
|
|
192
|
-
|
|
199
|
+
# copia tutti i file presenti in webpack-modules,
|
|
200
|
+
for FILE in "${WEBPACK_MODULES_REMOTE_URL}"/*; do
|
|
201
|
+
[ -f "$FILE" ] || continue
|
|
202
|
+
safe_cat "$FILE" "${WEBPACK_LOCAL_DIR}/$(basename "$FILE")"
|
|
193
203
|
done
|
|
194
204
|
|
|
195
205
|
echo -e "\n${GREEN}Creating a template of your frontend application's folder structured${NC}"
|
|
196
206
|
|
|
197
|
-
TEMPLATE_DIR_NAME="
|
|
207
|
+
TEMPLATE_DIR_NAME="__frontend_dir__"
|
|
198
208
|
mkdir -p "$TEMPLATE_DIR_NAME"
|
|
199
209
|
cd "$TEMPLATE_DIR_NAME"
|
|
200
|
-
mkdir -p error-pages imgs icons src
|
|
210
|
+
mkdir -p error-pages imgs icons src css favicons design-tokens
|
|
201
211
|
cd ..
|
|
202
212
|
|
|
213
|
+
# copia dei file css presenti nella root di minimo/src
|
|
214
|
+
# (custom-properties.css, custom-media.css, fonts.css, minimo.css, ...):
|
|
215
|
+
MINIMO_ROOT_CSS_DIR="${BASE_URL}/../../src"
|
|
216
|
+
for FILE in "${MINIMO_ROOT_CSS_DIR}"/*.css; do
|
|
217
|
+
safe_cat "$FILE" "${TEMPLATE_DIR_NAME}/css/$(basename "$FILE")"
|
|
218
|
+
done
|
|
219
|
+
|
|
220
|
+
# copia tokens.config.mjs
|
|
221
|
+
safe_cat "${BASE_URL}/../../design-tokens/tokens-config.mjs" "${TEMPLATE_DIR_NAME}/css/tokens-config.mjs"
|
|
222
|
+
|
|
203
223
|
# template delle entry css (globale/di pagina e critical): ogni entry deve
|
|
204
224
|
# importare direttamente custom-properties.css (vedi commenti nei file stessi)
|
|
205
225
|
safe_cat "${TEMPLATES_DIR}/entry-tpl.css" "${TEMPLATE_DIR_NAME}/src/entry-tpl.css"
|
package/package.json
CHANGED
|
@@ -232,7 +232,7 @@
|
|
|
232
232
|
--mpopup-header-padding: var(--size-xs);
|
|
233
233
|
--mpopup-height: max-content;
|
|
234
234
|
--mpopup-max-height: 5.625rem;
|
|
235
|
-
--mpopup-max-width:
|
|
235
|
+
--mpopup-max-width: 4.375rem;
|
|
236
236
|
--mpopup-min-height: 18.75rem;
|
|
237
237
|
--mpopup-min-width: 25rem;
|
|
238
238
|
--mpopup-width: max-content;
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
# Design Token Utilities
|
|
2
|
-
|
|
3
|
-
A set of Node.js scripts for managing CSS design tokens in a project. Built on top of [Style Dictionary v5](https://styledictionary.com/).
|
|
4
|
-
|
|
5
|
-
## Scripts
|
|
6
|
-
|
|
7
|
-
| Script | Purpose |
|
|
8
|
-
|---|---|
|
|
9
|
-
| `build-tokens.mjs` | Generates a CSS custom properties file from design token source files |
|
|
10
|
-
| `check-unresolved-custom-props.mjs` | Scans CSS files and reports any `var(--...)` references not found in the generated token file |
|
|
11
|
-
|
|
12
|
-
Both scripts share the same config file, passed via `--config`.
|
|
13
|
-
|
|
14
|
-
## Setup
|
|
15
|
-
|
|
16
|
-
The scripts are intended to be used as npm scripts. Add them to your `package.json`:
|
|
17
|
-
|
|
18
|
-
```json
|
|
19
|
-
{
|
|
20
|
-
"scripts": {
|
|
21
|
-
"build tokens": "npx buildTokens --config ./path/to/tokens-config.mjs",
|
|
22
|
-
"check unresolved props": "npx checkUnresolvedProps --config ./path/to/tokens-config.mjs"
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
### Dependencies
|
|
28
|
-
|
|
29
|
-
The following packages must be present in your project:
|
|
30
|
-
|
|
31
|
-
```json
|
|
32
|
-
{
|
|
33
|
-
"style-dictionary": "^5",
|
|
34
|
-
"stylelint": "^16"
|
|
35
|
-
}
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
## Configuration file
|
|
39
|
-
|
|
40
|
-
Both scripts read a shared config file passed with `--config`. Use `tokens-config-sample.mjs` as a starting point.
|
|
41
|
-
|
|
42
|
-
Read comments inside the sample file for more info.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
## `build-tokens.mjs`
|
|
46
|
-
|
|
47
|
-
Reads design token source files and generates:
|
|
48
|
-
- A **CSS file** containing all tokens as custom properties inside `:root { ... }`
|
|
49
|
-
- Optionally, one or more **W3C DTCG JSON/JSONC** files to import into Penpot/Figma (use in Figma requires a plugin).
|
|
50
|
-
|
|
51
|
-
### Usage
|
|
52
|
-
|
|
53
|
-
```sh
|
|
54
|
-
npx buildTokens --config ./path/to/tokens-config.mjs
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
### Source files
|
|
58
|
-
|
|
59
|
-
The `source` array accepts any combination of:
|
|
60
|
-
- Concrete file paths: `'./tokens/colors.jsonc'`
|
|
61
|
-
- Glob patterns: `'./tokens/**/*.{json,jsonc,mjs}'`
|
|
62
|
-
|
|
63
|
-
**Supported formats:**
|
|
64
|
-
- `.json` / `.jsonc` — parsed directly as token data
|
|
65
|
-
- `.mjs` / `.js` — imported as ES modules; must export a W3C DTCG-compliant object as `default`
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
### Token file format (JS example)
|
|
69
|
-
|
|
70
|
-
When using `.mjs` source files, export a default object following the [W3C Design Token Community Group format](https://design-tokens.github.io/community-group/format/):
|
|
71
|
-
|
|
72
|
-
```js
|
|
73
|
-
// colors.tokens.mjs
|
|
74
|
-
export default {
|
|
75
|
-
color: {
|
|
76
|
-
brand: {
|
|
77
|
-
primary: { $type: 'color', $value: '#0057FF' },
|
|
78
|
-
secondary: { $type: 'color', $value: '#FF6B00' },
|
|
79
|
-
},
|
|
80
|
-
neutral: {
|
|
81
|
-
'100': { $type: 'color', $value: '#F5F5F5' },
|
|
82
|
-
'900': { $type: 'color', $value: '#1A1A1A' },
|
|
83
|
-
},
|
|
84
|
-
},
|
|
85
|
-
semantic: {
|
|
86
|
-
color: {
|
|
87
|
-
text: {
|
|
88
|
-
primary: { $type: 'color', $value: '{color.neutral.900}' }, // alias
|
|
89
|
-
},
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
};
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
The main advantage of `.mjs` over `.json` is the ability to use JavaScript variables, comments, and computed values within the token definition.
|
|
96
|
-
|
|
97
|
-
Values can be expressions like `"{size.base} * .25"`, see `tokens-config-sample.mjs` for more info.
|
|
98
|
-
|
|
99
|
-
### Custom transforms
|
|
100
|
-
|
|
101
|
-
The following transforms are registered on top of Style Dictionary's built-ins:
|
|
102
|
-
|
|
103
|
-
| Name | Type | Description |
|
|
104
|
-
|---|---|---|
|
|
105
|
-
| `shadow/css` | value | Converts shadow objects (single or array) to a `box-shadow` CSS string. px values are converted to rem. |
|
|
106
|
-
| `size/pxToRem-smart` | value | Converts `dimension` token values from px to rem. Skips values already in rem. |
|
|
107
|
-
| `color/css-modern` | value | Color passthrough with transitive alias support. |
|
|
108
|
-
| `gradient/css` | value | Converts gradient objects to CSS `linear-gradient`, `radial-gradient` or `conic-gradient`. |
|
|
109
|
-
| `composite/css` | value | Converts `border`, `outline`, `transition` and `animation` objects to their CSS shorthand. |
|
|
110
|
-
| `typography/css` | value | Typography passthrough — the format handles exploding the value into individual properties. |
|
|
111
|
-
|
|
112
|
-
### CSS output
|
|
113
|
-
|
|
114
|
-
All tokens are output as CSS custom properties inside `:root`, sorted alphabetically.
|
|
115
|
-
|
|
116
|
-
Typography tokens are expanded into multiple properties:
|
|
117
|
-
- `--token-name-font` — a `font` shorthand (when both `fontSize` and `fontFamily` are present)
|
|
118
|
-
- `--token-name-letter-spacing`, `--token-name-text-transform`, `--token-name-text-decoration` — individual properties
|
|
119
|
-
|
|
120
|
-
The generated file is linted and auto-fixed with stylelint using the config specified in `stylelintConfigPath`.
|
|
121
|
-
|
|
122
|
-
### Penpot output
|
|
123
|
-
|
|
124
|
-
When `penpotBuildPath` is set, the script also generates W3C DTCG token files for import into Penpot via the [Design Tokens plugin](https://penpot.app/penpot-files/design-tokens).
|
|
125
|
-
|
|
126
|
-
**Single file** (`penpotDestFile` is a string):
|
|
127
|
-
```
|
|
128
|
-
penpotBuildPath/tokens.jsonc ← all tokens in one file
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
**One file per source** (`penpotDestFile` is `null` or omitted):
|
|
132
|
-
```
|
|
133
|
-
penpotBuildPath/colors.tokens.jsonc
|
|
134
|
-
penpotBuildPath/spacing.tokens.jsonc
|
|
135
|
-
penpotBuildPath/typography.tokens.jsonc
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
The `penpotFormat` option controls the output:
|
|
139
|
-
|
|
140
|
-
| Value | Extension | Disclaimer header |
|
|
141
|
-
|---|---|---|
|
|
142
|
-
| `'jsonc'` | `.jsonc` | Yes |
|
|
143
|
-
| `'json'` | `.json` | No |
|
|
144
|
-
|
|
145
|
-
Alias references (`{color.brand.primary}`) are preserved in the output so Penpot maintains token links between primitive and semantic tokens.
|
|
146
|
-
|
|
147
|
-
> Penpot token files intentionally use a minimal set of transforms (no px→rem conversion, no shorthand expansion) because Penpot expects original values and structured objects, not resolved CSS strings.
|
|
148
|
-
|
|
149
|
-
---
|
|
150
|
-
|
|
151
|
-
## `check-unresolved-custom-props.mjs`
|
|
152
|
-
|
|
153
|
-
Scans all `.css` files in `dir_to_check` (recursively) and reports any `var(--...)` references that are not defined in the generated token CSS file or in any `extra_custom_props_files`.
|
|
154
|
-
|
|
155
|
-
Results are written to `unresolved-props.md` in the same directory as the config file.
|
|
156
|
-
|
|
157
|
-
### Usage
|
|
158
|
-
|
|
159
|
-
```sh
|
|
160
|
-
npx checkUnresolvedProps --config ./path/to/tokens-config.mjs
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
### Output
|
|
164
|
-
|
|
165
|
-
The script creates a `unresolved-props.md` file next to the config file. Each line links to the file and line number where the unresolved property is used:
|
|
166
|
-
|
|
167
|
-
```markdown
|
|
168
|
-
* [components.css :: 42](../src/components.css#L42) -> var(--color-action-hover)
|
|
169
|
-
* [layout.css :: 17](../src/layout.css#L17) -> var(--spacing-missing)
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
In VS Code, Option/Alt-clicking on the URL opens the file at the required line.
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
### Excluding properties
|
|
176
|
-
|
|
177
|
-
Use `exclude_pattern` to suppress false positives — for example, internal/private custom properties that are defined dynamically or inline:
|
|
178
|
-
|
|
179
|
-
```js
|
|
180
|
-
// skips all custom props starting with `--_` or `--js-`
|
|
181
|
-
exclude_pattern: [
|
|
182
|
-
/^--_/,
|
|
183
|
-
/^--js-/,
|
|
184
|
-
]
|
|
185
|
-
```
|