@kyralabs/m3e-tokens 1.0.1 → 1.1.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 +21 -0
- package/dist/cli/theme.js +93 -18
- package/dist/cli/theme.js.map +1 -1
- package/dist/theme.d.ts +27 -2
- package/dist/theme.js +49 -4
- package/dist/theme.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -35,6 +35,27 @@ or from the command line:
|
|
|
35
35
|
npx m3e-theme --seed "#6750A4" --variant expressive > theme.css
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
+
Optional core colors replace the palettes the variant would derive from the seed, like Material
|
|
39
|
+
Theme Builder's: `secondary`, `tertiary`, `neutral`, `neutralVariant` and `error`. Each palette
|
|
40
|
+
keeps the given color's hue and chroma (`TonalPalette.fromInt`); the variant still maps the roles
|
|
41
|
+
to tones. For example, a red primary on grey surfaces:
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
createTheme({
|
|
45
|
+
seed: '#d84848',
|
|
46
|
+
variant: 'fidelity',
|
|
47
|
+
coreColors: { neutral: '#808080', neutralVariant: '#808080' },
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```sh
|
|
52
|
+
npx m3e-theme --seed "#d84848" --variant fidelity --neutral "#808080" --neutral-variant "#808080"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The CLI flags are `--secondary`, `--tertiary`, `--neutral`, `--neutral-variant` and `--error`.
|
|
56
|
+
With spec 2025 (the `tonalSpot`, `neutral`, `vibrant` and `expressive` variants) the outline and
|
|
57
|
+
surface-variant roles come from the neutral palette, so `neutralVariant` has no effect there.
|
|
58
|
+
|
|
38
59
|
Other entries: `./components/<name>.css` (component tokens), `./material-symbols.css` (Rounded;
|
|
39
60
|
`-outlined` and `-sharp` too), `./fonts-full.css` (every Google Sans Flex axis), and JS token
|
|
40
61
|
objects from `.` and `./components`.
|
package/dist/cli/theme.js
CHANGED
|
@@ -5089,13 +5089,55 @@ var COLOR_ROLES = Object.getOwnPropertyNames(
|
|
|
5089
5089
|
var rolesFor = (specVersion) => specVersion === "2025" ? COLOR_ROLES : COLOR_ROLES.filter((r) => !SPEC_2025_ONLY_ROLES.includes(r));
|
|
5090
5090
|
var HEX = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
|
|
5091
5091
|
var normalizeHex = (hex) => hexFromArgb(argbFromHex(hex));
|
|
5092
|
-
|
|
5093
|
-
|
|
5092
|
+
var CORE_COLORS = ["secondary", "tertiary", "neutral", "neutralVariant", "error"];
|
|
5093
|
+
function normalizeCoreColors(coreColors, caller) {
|
|
5094
|
+
const out = {};
|
|
5095
|
+
for (const key of Object.keys(coreColors)) {
|
|
5096
|
+
if (!CORE_COLORS.includes(key)) {
|
|
5097
|
+
throw new Error(`${caller}: unknown core color "${key}"`);
|
|
5098
|
+
}
|
|
5099
|
+
}
|
|
5100
|
+
for (const key of CORE_COLORS) {
|
|
5101
|
+
const hex = coreColors[key];
|
|
5102
|
+
if (hex === void 0) continue;
|
|
5103
|
+
if (typeof hex !== "string" || !HEX.test(hex)) {
|
|
5104
|
+
throw new Error(
|
|
5105
|
+
`${caller}: core color ${key} must be #rgb or #rrggbb, got ${JSON.stringify(hex)}`
|
|
5106
|
+
);
|
|
5107
|
+
}
|
|
5108
|
+
out[key] = normalizeHex(hex);
|
|
5109
|
+
}
|
|
5110
|
+
return out;
|
|
5111
|
+
}
|
|
5112
|
+
function withCoreColors(scheme, coreColors) {
|
|
5113
|
+
if (CORE_COLORS.every((key) => coreColors[key] === void 0)) return scheme;
|
|
5114
|
+
const palette = (key) => {
|
|
5115
|
+
const hex = coreColors[key];
|
|
5116
|
+
return hex === void 0 ? void 0 : TonalPalette.fromInt(argbFromHex(hex));
|
|
5117
|
+
};
|
|
5118
|
+
return new DynamicScheme({
|
|
5119
|
+
sourceColorHct: scheme.sourceColorHct,
|
|
5120
|
+
variant: scheme.variant,
|
|
5121
|
+
contrastLevel: scheme.contrastLevel,
|
|
5122
|
+
isDark: scheme.isDark,
|
|
5123
|
+
platform: scheme.platform,
|
|
5124
|
+
specVersion: scheme.specVersion,
|
|
5125
|
+
primaryPalette: scheme.primaryPalette,
|
|
5126
|
+
secondaryPalette: palette("secondary") ?? scheme.secondaryPalette,
|
|
5127
|
+
tertiaryPalette: palette("tertiary") ?? scheme.tertiaryPalette,
|
|
5128
|
+
neutralPalette: palette("neutral") ?? scheme.neutralPalette,
|
|
5129
|
+
neutralVariantPalette: palette("neutralVariant") ?? scheme.neutralVariantPalette,
|
|
5130
|
+
errorPalette: palette("error") ?? scheme.errorPalette
|
|
5131
|
+
});
|
|
5132
|
+
}
|
|
5133
|
+
function schemeColors(seed, variant, isDark, contrast, specVersion, coreColors = {}) {
|
|
5134
|
+
const variantScheme = new SCHEMES[variant](
|
|
5094
5135
|
Hct.fromInt(argbFromHex(seed)),
|
|
5095
5136
|
isDark,
|
|
5096
5137
|
contrast,
|
|
5097
5138
|
specVersion
|
|
5098
5139
|
);
|
|
5140
|
+
const scheme = withCoreColors(variantScheme, normalizeCoreColors(coreColors, "schemeColors"));
|
|
5099
5141
|
const out = {};
|
|
5100
5142
|
for (const role of rolesFor(specVersion)) {
|
|
5101
5143
|
const method = dynamicColors[role];
|
|
@@ -5127,9 +5169,11 @@ function createTheme(options) {
|
|
|
5127
5169
|
`createTheme: contrast must be within [-1, 1], got ${String(options.contrast)}`
|
|
5128
5170
|
);
|
|
5129
5171
|
}
|
|
5172
|
+
const coreColors = normalizeCoreColors(options.coreColors ?? {}, "createTheme");
|
|
5173
|
+
const hasCoreColors = Object.keys(coreColors).length > 0;
|
|
5130
5174
|
const roles = rolesFor(specVersion);
|
|
5131
5175
|
const build = (isDark, extra) => {
|
|
5132
|
-
const colors = schemeColors(seed, variant, isDark, contrast, specVersion);
|
|
5176
|
+
const colors = schemeColors(seed, variant, isDark, contrast, specVersion, coreColors);
|
|
5133
5177
|
for (const [role, hex] of Object.entries(extra ?? {})) {
|
|
5134
5178
|
if (!roles.includes(role)) throw new Error(`createTheme: unknown color role "${role}"`);
|
|
5135
5179
|
if (!HEX.test(hex)) throw new Error(`createTheme: override ${role} must be a hex color`);
|
|
@@ -5150,6 +5194,7 @@ function createTheme(options) {
|
|
|
5150
5194
|
cssText,
|
|
5151
5195
|
tokens: {
|
|
5152
5196
|
seed: normalizeHex(seed),
|
|
5197
|
+
...hasCoreColors ? { coreColors } : {},
|
|
5153
5198
|
variant,
|
|
5154
5199
|
contrast,
|
|
5155
5200
|
specVersion,
|
|
@@ -5159,18 +5204,30 @@ function createTheme(options) {
|
|
|
5159
5204
|
}
|
|
5160
5205
|
};
|
|
5161
5206
|
}
|
|
5162
|
-
|
|
5163
|
-
// src/cli/theme.ts
|
|
5164
5207
|
var USAGE = `usage: m3e-theme --seed <#hex> [options]
|
|
5165
5208
|
|
|
5166
|
-
--variant
|
|
5167
|
-
--mode
|
|
5168
|
-
--contrast
|
|
5169
|
-
--spec
|
|
5170
|
-
--motion
|
|
5171
|
-
--selector
|
|
5172
|
-
--out
|
|
5173
|
-
|
|
5209
|
+
--variant ${VARIANTS.join(" | ")} (default tonalSpot)
|
|
5210
|
+
--mode light | dark | system (default system)
|
|
5211
|
+
--contrast -1\u20261 or ${Object.keys(CONTRAST).join(" | ")} (default standard)
|
|
5212
|
+
--spec ${SPEC_VERSIONS.join(" | ")} (default 2025)
|
|
5213
|
+
--motion expressive | standard (default expressive)
|
|
5214
|
+
--selector single compound selector (default :root)
|
|
5215
|
+
--out file to write (default stdout)
|
|
5216
|
+
|
|
5217
|
+
Core colors (optional; each replaces the palette derived from --seed):
|
|
5218
|
+
--secondary <#hex>
|
|
5219
|
+
--tertiary <#hex>
|
|
5220
|
+
--neutral <#hex> surfaces and backgrounds
|
|
5221
|
+
--neutral-variant <#hex> surface variants and outlines
|
|
5222
|
+
--error <#hex>`;
|
|
5223
|
+
var CORE_COLOR_FLAGS = {
|
|
5224
|
+
secondary: "secondary",
|
|
5225
|
+
tertiary: "tertiary",
|
|
5226
|
+
neutral: "neutral",
|
|
5227
|
+
"neutral-variant": "neutralVariant",
|
|
5228
|
+
error: "error"
|
|
5229
|
+
};
|
|
5230
|
+
function parseThemeArgs(argv) {
|
|
5174
5231
|
const { values } = parseArgs({
|
|
5175
5232
|
args: argv,
|
|
5176
5233
|
options: {
|
|
@@ -5182,16 +5239,24 @@ function run(argv) {
|
|
|
5182
5239
|
motion: { type: "string" },
|
|
5183
5240
|
selector: { type: "string" },
|
|
5184
5241
|
out: { type: "string" },
|
|
5242
|
+
secondary: { type: "string" },
|
|
5243
|
+
tertiary: { type: "string" },
|
|
5244
|
+
neutral: { type: "string" },
|
|
5245
|
+
"neutral-variant": { type: "string" },
|
|
5246
|
+
error: { type: "string" },
|
|
5185
5247
|
help: { type: "boolean", short: "h" }
|
|
5186
5248
|
}
|
|
5187
5249
|
});
|
|
5188
|
-
if (values.help || !values.seed) {
|
|
5189
|
-
|
|
5190
|
-
|
|
5250
|
+
if (values.help || !values.seed) return { help: true, exitCode: values.help ? 0 : 2 };
|
|
5251
|
+
const coreColors = {};
|
|
5252
|
+
for (const [flag, key] of Object.entries(CORE_COLOR_FLAGS)) {
|
|
5253
|
+
const value = values[flag];
|
|
5254
|
+
if (value !== void 0) coreColors[key] = value;
|
|
5191
5255
|
}
|
|
5192
5256
|
const contrast = values.contrast;
|
|
5193
5257
|
const options = {
|
|
5194
5258
|
seed: values.seed,
|
|
5259
|
+
...Object.keys(coreColors).length > 0 ? { coreColors } : {},
|
|
5195
5260
|
...values.variant ? { variant: values.variant } : {},
|
|
5196
5261
|
...values.mode ? { mode: values.mode } : {},
|
|
5197
5262
|
...contrast === void 0 ? {} : { contrast: contrast in CONTRAST ? contrast : Number(contrast) },
|
|
@@ -5199,8 +5264,18 @@ function run(argv) {
|
|
|
5199
5264
|
...values.motion ? { motionScheme: values.motion } : {},
|
|
5200
5265
|
...values.selector ? { selector: values.selector } : {}
|
|
5201
5266
|
};
|
|
5202
|
-
|
|
5203
|
-
|
|
5267
|
+
return { help: false, options, out: values.out };
|
|
5268
|
+
}
|
|
5269
|
+
|
|
5270
|
+
// src/cli/theme.ts
|
|
5271
|
+
function run(argv) {
|
|
5272
|
+
const args = parseThemeArgs(argv);
|
|
5273
|
+
if (args.help) {
|
|
5274
|
+
console.error(USAGE);
|
|
5275
|
+
return args.exitCode;
|
|
5276
|
+
}
|
|
5277
|
+
const { cssText } = createTheme(args.options);
|
|
5278
|
+
if (args.out) writeFileSync(args.out, cssText);
|
|
5204
5279
|
else process.stdout.write(cssText);
|
|
5205
5280
|
return 0;
|
|
5206
5281
|
}
|