react-mcu 1.2.0 → 1.3.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/README.md +39 -0
- package/dist/index.d.ts +112 -28
- package/dist/index.js +508 -285
- package/package.json +25 -3
- package/src/cli.ts +116 -0
package/README.md
CHANGED
|
@@ -35,6 +35,8 @@ Extra:
|
|
|
35
35
|
|
|
36
36
|
- [x] `contrastAllColors`: contrast also applies to custom-colors and shades
|
|
37
37
|
(not only the core-colors)
|
|
38
|
+
- [x] `adaptiveShades`: shades adapt to the light/dark mode (instead of being
|
|
39
|
+
fixed)
|
|
38
40
|
|
|
39
41
|
# Usage
|
|
40
42
|
|
|
@@ -173,6 +175,37 @@ Simply override/remap
|
|
|
173
175
|
> Make sure `:root, .dark { ... }` comes AFTER `.root { ... } .dark { ... }` to
|
|
174
176
|
> take precedence.
|
|
175
177
|
|
|
178
|
+
## Programmatic API
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
import { builder } from "react-mcu";
|
|
182
|
+
|
|
183
|
+
const theme = builder("#6750A4", {
|
|
184
|
+
scheme: "vibrant",
|
|
185
|
+
contrast: 0.5,
|
|
186
|
+
primary: "#FF0000",
|
|
187
|
+
secondary: "#00FF00",
|
|
188
|
+
customColors: [
|
|
189
|
+
{ name: "brand", hex: "#FF5733", blend: true },
|
|
190
|
+
{ name: "success", hex: "#28A745", blend: false },
|
|
191
|
+
],
|
|
192
|
+
contrastAllColors: true,
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
theme.toJson();
|
|
196
|
+
theme.toCss();
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## CLI
|
|
200
|
+
|
|
201
|
+
```sh
|
|
202
|
+
$ npx react-mcu builder "#6750A4"
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
will generate a `mcu-theme` folder with: `Light.tokens.json` and `Dark.tokens.json` [design-tokens](https://www.designtokens.org/tr/2025.10/) files, you can (both) import into Figma.
|
|
206
|
+
|
|
207
|
+
See `npx react-mcu builder --help` for all available options.
|
|
208
|
+
|
|
176
209
|
# Dev
|
|
177
210
|
|
|
178
211
|
## INSTALL
|
|
@@ -198,6 +231,12 @@ Pre-requisites:
|
|
|
198
231
|
$ pnpm i
|
|
199
232
|
```
|
|
200
233
|
|
|
234
|
+
## Validation
|
|
235
|
+
|
|
236
|
+
```sh
|
|
237
|
+
$ pnpm run lgtm
|
|
238
|
+
```
|
|
239
|
+
|
|
201
240
|
## CONTRIBUTING
|
|
202
241
|
|
|
203
242
|
When submitting a pull request, please include a changeset to document your
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { CustomColor, TonalPalette } from '@material/material-color-utilities';
|
|
1
2
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { SchemeTonalSpot, SchemeMonochrome, SchemeNeutral, SchemeVibrant, SchemeExpressive, SchemeFidelity, SchemeContent, CustomColor } from '@material/material-color-utilities';
|
|
3
3
|
|
|
4
4
|
type HexCustomColor = Omit<CustomColor, "value"> & {
|
|
5
5
|
hex: string;
|
|
@@ -29,52 +29,136 @@ type McuConfig = {
|
|
|
29
29
|
* When false (default), colors may be adjusted for better harmonization.
|
|
30
30
|
* Corresponds to "Color match - Stay true to my color inputs" in Material Theme Builder.
|
|
31
31
|
*
|
|
32
|
-
* @default false
|
|
33
32
|
* @deprecated Not yet implemented. This prop is currently ignored.
|
|
34
33
|
*/
|
|
35
34
|
colorMatch?: boolean;
|
|
36
35
|
/**
|
|
37
36
|
* Array of custom colors to include in the generated palette.
|
|
38
|
-
*
|
|
39
|
-
* @example
|
|
40
|
-
* ```ts
|
|
41
|
-
* customColors={[
|
|
42
|
-
* { name: "brand", hex: "#FF5733", blend: true },
|
|
43
|
-
* { name: "success", hex: "#28A745", blend: false }
|
|
44
|
-
* ]}
|
|
45
|
-
* ```
|
|
37
|
+
* Each custom color can be blended with the source color for harmonization.
|
|
46
38
|
*/
|
|
47
39
|
customColors?: HexCustomColor[];
|
|
48
40
|
/**
|
|
49
|
-
*
|
|
50
|
-
* When
|
|
51
|
-
*
|
|
52
|
-
* @default false
|
|
41
|
+
* Apply contrast adjustment to tonal palette shades when true.
|
|
42
|
+
* When true, all tonal palette shades are adjusted based on the contrast level.
|
|
43
|
+
* When false (default), contrast adjustments only apply to core Material Design tokens.
|
|
53
44
|
*/
|
|
54
45
|
contrastAllColors?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Adapt tonal palette shades for dark mode.
|
|
48
|
+
* When true, tonal palette shades automatically invert for dark mode
|
|
49
|
+
* (high values become dark, low values become light).
|
|
50
|
+
* When false (default), tonal palette values remain constant across light/dark mode.
|
|
51
|
+
*/
|
|
52
|
+
adaptiveShades?: boolean;
|
|
55
53
|
};
|
|
56
|
-
declare const
|
|
57
|
-
readonly tonalSpot: typeof SchemeTonalSpot;
|
|
58
|
-
readonly monochrome: typeof SchemeMonochrome;
|
|
59
|
-
readonly neutral: typeof SchemeNeutral;
|
|
60
|
-
readonly vibrant: typeof SchemeVibrant;
|
|
61
|
-
readonly expressive: typeof SchemeExpressive;
|
|
62
|
-
readonly fidelity: typeof SchemeFidelity;
|
|
63
|
-
readonly content: typeof SchemeContent;
|
|
64
|
-
};
|
|
65
|
-
declare const schemeNames: (keyof typeof schemesMap)[];
|
|
54
|
+
declare const schemeNames: readonly ["tonalSpot", "monochrome", "neutral", "vibrant", "expressive", "fidelity", "content"];
|
|
66
55
|
type SchemeName = (typeof schemeNames)[number];
|
|
67
|
-
declare
|
|
56
|
+
declare const tokenNames: readonly ["background", "error", "errorContainer", "inverseOnSurface", "inversePrimary", "inverseSurface", "onBackground", "onError", "onErrorContainer", "onPrimary", "onPrimaryContainer", "onPrimaryFixed", "onPrimaryFixedVariant", "onSecondary", "onSecondaryContainer", "onSecondaryFixed", "onSecondaryFixedVariant", "onSurface", "onSurfaceVariant", "onTertiary", "onTertiaryContainer", "onTertiaryFixed", "onTertiaryFixedVariant", "outline", "outlineVariant", "primary", "primaryContainer", "primaryFixed", "primaryFixedDim", "scrim", "secondary", "secondaryContainer", "secondaryFixed", "secondaryFixedDim", "shadow", "surface", "surfaceBright", "surfaceContainer", "surfaceContainerHigh", "surfaceContainerHighest", "surfaceContainerLow", "surfaceContainerLowest", "surfaceDim", "surfaceTint", "surfaceVariant", "tertiary", "tertiaryContainer", "tertiaryFixed", "tertiaryFixedDim"];
|
|
57
|
+
type TokenName = (typeof tokenNames)[number];
|
|
58
|
+
declare function builder(hexSource: McuConfig["source"], { scheme, contrast, primary, secondary, tertiary, neutral, neutralVariant, error, customColors: hexCustomColors, contrastAllColors, adaptiveShades, }?: Omit<McuConfig, "source">): {
|
|
59
|
+
toCss(): string;
|
|
60
|
+
toJson(): {
|
|
61
|
+
seed: string;
|
|
62
|
+
coreColors: Record<string, string>;
|
|
63
|
+
extendedColors: {
|
|
64
|
+
name: string;
|
|
65
|
+
color: string;
|
|
66
|
+
description: string;
|
|
67
|
+
harmonized: boolean;
|
|
68
|
+
}[];
|
|
69
|
+
schemes: Record<string, Record<string, string>>;
|
|
70
|
+
palettes: Record<string, Record<string, string>>;
|
|
71
|
+
};
|
|
72
|
+
toFigmaTokens(): {
|
|
73
|
+
"Light.tokens.json": {
|
|
74
|
+
Schemes: Record<string, {
|
|
75
|
+
$type: "color";
|
|
76
|
+
$value: {
|
|
77
|
+
colorSpace: "srgb";
|
|
78
|
+
components: number[];
|
|
79
|
+
alpha: number;
|
|
80
|
+
hex: string;
|
|
81
|
+
};
|
|
82
|
+
$extensions: {
|
|
83
|
+
"com.figma.scopes": string[];
|
|
84
|
+
"com.figma.isOverride": boolean;
|
|
85
|
+
};
|
|
86
|
+
}>;
|
|
87
|
+
Palettes: Record<string, Record<string, {
|
|
88
|
+
$type: "color";
|
|
89
|
+
$value: {
|
|
90
|
+
colorSpace: "srgb";
|
|
91
|
+
components: number[];
|
|
92
|
+
alpha: number;
|
|
93
|
+
hex: string;
|
|
94
|
+
};
|
|
95
|
+
$extensions: {
|
|
96
|
+
"com.figma.scopes": string[];
|
|
97
|
+
"com.figma.isOverride": boolean;
|
|
98
|
+
};
|
|
99
|
+
}>>;
|
|
100
|
+
$extensions: {
|
|
101
|
+
"com.figma.modeName": string;
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
"Dark.tokens.json": {
|
|
105
|
+
Schemes: Record<string, {
|
|
106
|
+
$type: "color";
|
|
107
|
+
$value: {
|
|
108
|
+
colorSpace: "srgb";
|
|
109
|
+
components: number[];
|
|
110
|
+
alpha: number;
|
|
111
|
+
hex: string;
|
|
112
|
+
};
|
|
113
|
+
$extensions: {
|
|
114
|
+
"com.figma.scopes": string[];
|
|
115
|
+
"com.figma.isOverride": boolean;
|
|
116
|
+
};
|
|
117
|
+
}>;
|
|
118
|
+
Palettes: Record<string, Record<string, {
|
|
119
|
+
$type: "color";
|
|
120
|
+
$value: {
|
|
121
|
+
colorSpace: "srgb";
|
|
122
|
+
components: number[];
|
|
123
|
+
alpha: number;
|
|
124
|
+
hex: string;
|
|
125
|
+
};
|
|
126
|
+
$extensions: {
|
|
127
|
+
"com.figma.scopes": string[];
|
|
128
|
+
"com.figma.isOverride": boolean;
|
|
129
|
+
};
|
|
130
|
+
}>>;
|
|
131
|
+
$extensions: {
|
|
132
|
+
"com.figma.modeName": string;
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
mergedColorsLight: {
|
|
137
|
+
[x: string]: number;
|
|
138
|
+
};
|
|
139
|
+
mergedColorsDark: {
|
|
140
|
+
[x: string]: number;
|
|
141
|
+
};
|
|
142
|
+
allPalettes: {
|
|
143
|
+
primary: TonalPalette;
|
|
144
|
+
secondary: TonalPalette;
|
|
145
|
+
tertiary: TonalPalette;
|
|
146
|
+
error: TonalPalette;
|
|
147
|
+
neutral: TonalPalette;
|
|
148
|
+
"neutral-variant": TonalPalette;
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
declare function Mcu({ source, scheme, contrast, primary, secondary, tertiary, neutral, neutralVariant, error, colorMatch, customColors, contrastAllColors, adaptiveShades, children, }: McuConfig & {
|
|
68
153
|
children?: React.ReactNode;
|
|
69
154
|
}): react_jsx_runtime.JSX.Element;
|
|
70
|
-
declare const tokenNames: readonly ["background", "onBackground", "surface", "surfaceDim", "surfaceBright", "surfaceContainerLowest", "surfaceContainerLow", "surfaceContainer", "surfaceContainerHigh", "surfaceContainerHighest", "onSurface", "onSurfaceVariant", "outline", "outlineVariant", "inverseSurface", "inverseOnSurface", "primary", "onPrimary", "primaryContainer", "onPrimaryContainer", "primaryFixed", "primaryFixedDim", "onPrimaryFixed", "onPrimaryFixedVariant", "inversePrimary", "primaryFixed", "primaryFixedDim", "onPrimaryFixed", "onPrimaryFixedVariant", "secondary", "onSecondary", "secondaryContainer", "onSecondaryContainer", "secondaryFixed", "secondaryFixedDim", "onSecondaryFixed", "onSecondaryFixedVariant", "tertiary", "onTertiary", "tertiaryContainer", "onTertiaryContainer", "tertiaryFixed", "tertiaryFixedDim", "onTertiaryFixed", "onTertiaryFixedVariant", "error", "onError", "errorContainer", "onErrorContainer", "scrim", "shadow"];
|
|
71
|
-
type TokenName = (typeof tokenNames)[number];
|
|
72
155
|
|
|
73
156
|
type Api = {
|
|
74
157
|
initials: McuConfig;
|
|
75
158
|
setMcuConfig: (config: McuConfig) => void;
|
|
76
159
|
getMcuColor: (colorName: TokenName, theme?: string) => string;
|
|
160
|
+
allPalettes: Record<string, TonalPalette>;
|
|
77
161
|
};
|
|
78
162
|
declare const useMcu: () => Api;
|
|
79
163
|
|
|
80
|
-
export { Mcu, useMcu };
|
|
164
|
+
export { Mcu, builder, useMcu };
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
// src/
|
|
3
|
+
// src/lib/builder.ts
|
|
4
4
|
import {
|
|
5
5
|
argbFromHex,
|
|
6
6
|
Blend,
|
|
7
|
+
blueFromArgb,
|
|
7
8
|
DynamicColor,
|
|
8
9
|
DynamicScheme,
|
|
10
|
+
greenFromArgb,
|
|
9
11
|
Hct,
|
|
10
|
-
hexFromArgb
|
|
12
|
+
hexFromArgb,
|
|
11
13
|
MaterialDynamicColors,
|
|
14
|
+
redFromArgb,
|
|
12
15
|
SchemeContent,
|
|
13
16
|
SchemeExpressive,
|
|
14
17
|
SchemeFidelity,
|
|
@@ -18,94 +21,12 @@ import {
|
|
|
18
21
|
SchemeVibrant,
|
|
19
22
|
TonalPalette
|
|
20
23
|
} from "@material/material-color-utilities";
|
|
21
|
-
import { kebabCase, upperFirst } from "lodash-es";
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
// src/Mcu.context.tsx
|
|
25
|
-
import { hexFromArgb } from "@material/material-color-utilities";
|
|
26
|
-
import {
|
|
27
|
-
useCallback,
|
|
28
|
-
useInsertionEffect,
|
|
29
|
-
useMemo,
|
|
30
|
-
useState
|
|
31
|
-
} from "react";
|
|
32
|
-
|
|
33
|
-
// src/lib/createRequiredContext.ts
|
|
34
|
-
import { createContext, useContext } from "react";
|
|
35
|
-
var createRequiredContext = () => {
|
|
36
|
-
const Ctx = createContext(null);
|
|
37
|
-
const useCtx = () => {
|
|
38
|
-
const contextValue = useContext(Ctx);
|
|
39
|
-
if (contextValue === null) {
|
|
40
|
-
throw new Error("Context value is null");
|
|
41
|
-
}
|
|
42
|
-
return contextValue;
|
|
43
|
-
};
|
|
44
|
-
return [useCtx, Ctx.Provider, Ctx];
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
// src/Mcu.context.tsx
|
|
48
|
-
import { jsx } from "react/jsx-runtime";
|
|
49
|
-
var [useMcu, Provider, McuContext] = createRequiredContext();
|
|
50
|
-
var McuProvider = ({
|
|
51
|
-
source: initialSource,
|
|
52
|
-
scheme: initialScheme,
|
|
53
|
-
contrast: initialContrast,
|
|
54
|
-
customColors: initialCustomColors,
|
|
55
|
-
contrastAllColors: initialContrastAllColors,
|
|
56
|
-
styleId,
|
|
57
|
-
children
|
|
58
|
-
}) => {
|
|
59
|
-
const [initials] = useState(() => ({
|
|
60
|
-
source: initialSource,
|
|
61
|
-
scheme: initialScheme,
|
|
62
|
-
contrast: initialContrast,
|
|
63
|
-
customColors: initialCustomColors,
|
|
64
|
-
contrastAllColors: initialContrastAllColors
|
|
65
|
-
}));
|
|
66
|
-
const [mcuConfig, setMcuConfig] = useState(initials);
|
|
67
|
-
const { css, mergedColorsLight, mergedColorsDark } = useMemo(
|
|
68
|
-
() => generateCss(mcuConfig),
|
|
69
|
-
[mcuConfig]
|
|
70
|
-
);
|
|
71
|
-
useInsertionEffect(() => {
|
|
72
|
-
let tag = document.getElementById(styleId);
|
|
73
|
-
if (!tag) {
|
|
74
|
-
tag = document.createElement("style");
|
|
75
|
-
tag.id = styleId;
|
|
76
|
-
document.head.appendChild(tag);
|
|
77
|
-
}
|
|
78
|
-
tag.textContent = css;
|
|
79
|
-
}, [css, styleId]);
|
|
80
|
-
const getMcuColor = useCallback(
|
|
81
|
-
(colorName, theme) => {
|
|
82
|
-
return hexFromArgb(
|
|
83
|
-
(theme === "light" ? mergedColorsLight : mergedColorsDark)[colorName]
|
|
84
|
-
);
|
|
85
|
-
},
|
|
86
|
-
[mergedColorsDark, mergedColorsLight]
|
|
87
|
-
);
|
|
88
|
-
const value = useMemo(
|
|
89
|
-
() => ({
|
|
90
|
-
initials,
|
|
91
|
-
setMcuConfig,
|
|
92
|
-
getMcuColor
|
|
93
|
-
}),
|
|
94
|
-
[getMcuColor, initials]
|
|
95
|
-
);
|
|
96
|
-
return /* @__PURE__ */ jsx(Provider, { value, children });
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
// src/Mcu.tsx
|
|
100
|
-
import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
101
|
-
function adjustToneForContrast(baseTone, contrastLevel, isDark, adjustmentFactor = DEFAULT_CONTRAST_ADJUSTMENT_FACTOR) {
|
|
24
|
+
import { kebabCase, startCase, upperFirst } from "lodash-es";
|
|
25
|
+
function adjustToneForContrast(baseTone, contrastLevel, adjustmentFactor = DEFAULT_CONTRAST_ADJUSTMENT_FACTOR) {
|
|
102
26
|
if (contrastLevel === 0) return baseTone;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
} else {
|
|
107
|
-
adjustedTone = baseTone - contrastLevel * baseTone * adjustmentFactor;
|
|
108
|
-
}
|
|
27
|
+
const distanceToCenter = baseTone - 50;
|
|
28
|
+
const delta = distanceToCenter * contrastLevel * adjustmentFactor;
|
|
29
|
+
const adjustedTone = baseTone + delta;
|
|
109
30
|
return Math.max(0, Math.min(100, adjustedTone));
|
|
110
31
|
}
|
|
111
32
|
var schemesMap = {
|
|
@@ -117,14 +38,11 @@ var schemesMap = {
|
|
|
117
38
|
fidelity: SchemeFidelity,
|
|
118
39
|
content: SchemeContent
|
|
119
40
|
};
|
|
120
|
-
var schemeNames = Object.keys(
|
|
121
|
-
schemesMap
|
|
122
|
-
);
|
|
123
41
|
var DEFAULT_SCHEME = "tonalSpot";
|
|
124
42
|
var DEFAULT_CONTRAST = 0;
|
|
125
|
-
var DEFAULT_COLOR_MATCH = false;
|
|
126
43
|
var DEFAULT_CUSTOM_COLORS = [];
|
|
127
44
|
var DEFAULT_CONTRAST_ALL_COLORS = false;
|
|
45
|
+
var DEFAULT_ADAPTIVE_SHADES = false;
|
|
128
46
|
var DEFAULT_BLEND = true;
|
|
129
47
|
var DEFAULT_CONTRAST_ADJUSTMENT_FACTOR = 0.2;
|
|
130
48
|
var STANDARD_TONES = [
|
|
@@ -159,135 +77,67 @@ var Variant = {
|
|
|
159
77
|
FRUIT_SALAD: 8
|
|
160
78
|
};
|
|
161
79
|
var schemeToVariant = {
|
|
162
|
-
tonalSpot: Variant.TONAL_SPOT,
|
|
163
80
|
monochrome: Variant.MONOCHROME,
|
|
164
81
|
neutral: Variant.NEUTRAL,
|
|
82
|
+
tonalSpot: Variant.TONAL_SPOT,
|
|
165
83
|
vibrant: Variant.VIBRANT,
|
|
166
84
|
expressive: Variant.EXPRESSIVE,
|
|
167
85
|
fidelity: Variant.FIDELITY,
|
|
168
86
|
content: Variant.CONTENT
|
|
169
87
|
};
|
|
170
|
-
var mcuStyleId = "mcu-styles";
|
|
171
|
-
function Mcu({
|
|
172
|
-
source,
|
|
173
|
-
scheme = DEFAULT_SCHEME,
|
|
174
|
-
contrast = DEFAULT_CONTRAST,
|
|
175
|
-
primary,
|
|
176
|
-
secondary,
|
|
177
|
-
tertiary,
|
|
178
|
-
neutral,
|
|
179
|
-
neutralVariant,
|
|
180
|
-
error,
|
|
181
|
-
colorMatch = DEFAULT_COLOR_MATCH,
|
|
182
|
-
customColors = DEFAULT_CUSTOM_COLORS,
|
|
183
|
-
contrastAllColors = DEFAULT_CONTRAST_ALL_COLORS,
|
|
184
|
-
children
|
|
185
|
-
}) {
|
|
186
|
-
const config = useMemo2(
|
|
187
|
-
() => ({
|
|
188
|
-
source,
|
|
189
|
-
scheme,
|
|
190
|
-
contrast,
|
|
191
|
-
primary,
|
|
192
|
-
secondary,
|
|
193
|
-
tertiary,
|
|
194
|
-
neutral,
|
|
195
|
-
neutralVariant,
|
|
196
|
-
error,
|
|
197
|
-
colorMatch,
|
|
198
|
-
customColors,
|
|
199
|
-
// extras features
|
|
200
|
-
contrastAllColors
|
|
201
|
-
}),
|
|
202
|
-
[
|
|
203
|
-
contrast,
|
|
204
|
-
customColors,
|
|
205
|
-
scheme,
|
|
206
|
-
source,
|
|
207
|
-
primary,
|
|
208
|
-
secondary,
|
|
209
|
-
tertiary,
|
|
210
|
-
neutral,
|
|
211
|
-
neutralVariant,
|
|
212
|
-
error,
|
|
213
|
-
colorMatch,
|
|
214
|
-
contrastAllColors
|
|
215
|
-
]
|
|
216
|
-
);
|
|
217
|
-
const { css } = useMemo2(() => generateCss(config), [config]);
|
|
218
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
219
|
-
/* @__PURE__ */ jsx2("style", { id: mcuStyleId, children: css }),
|
|
220
|
-
/* @__PURE__ */ jsx2(McuProvider, { ...config, styleId: mcuStyleId, children })
|
|
221
|
-
] });
|
|
222
|
-
}
|
|
223
88
|
var tokenNames = [
|
|
224
89
|
"background",
|
|
90
|
+
"error",
|
|
91
|
+
"errorContainer",
|
|
92
|
+
"inverseOnSurface",
|
|
93
|
+
"inversePrimary",
|
|
94
|
+
"inverseSurface",
|
|
225
95
|
"onBackground",
|
|
226
|
-
"
|
|
227
|
-
"
|
|
228
|
-
"
|
|
229
|
-
"
|
|
230
|
-
"
|
|
231
|
-
"
|
|
232
|
-
"
|
|
233
|
-
"
|
|
96
|
+
"onError",
|
|
97
|
+
"onErrorContainer",
|
|
98
|
+
"onPrimary",
|
|
99
|
+
"onPrimaryContainer",
|
|
100
|
+
"onPrimaryFixed",
|
|
101
|
+
"onPrimaryFixedVariant",
|
|
102
|
+
"onSecondary",
|
|
103
|
+
"onSecondaryContainer",
|
|
104
|
+
"onSecondaryFixed",
|
|
105
|
+
"onSecondaryFixedVariant",
|
|
234
106
|
"onSurface",
|
|
235
107
|
"onSurfaceVariant",
|
|
108
|
+
"onTertiary",
|
|
109
|
+
"onTertiaryContainer",
|
|
110
|
+
"onTertiaryFixed",
|
|
111
|
+
"onTertiaryFixedVariant",
|
|
236
112
|
"outline",
|
|
237
113
|
"outlineVariant",
|
|
238
|
-
"inverseSurface",
|
|
239
|
-
"inverseOnSurface",
|
|
240
114
|
"primary",
|
|
241
|
-
// "primaryDim",
|
|
242
|
-
"onPrimary",
|
|
243
115
|
"primaryContainer",
|
|
244
|
-
"onPrimaryContainer",
|
|
245
116
|
"primaryFixed",
|
|
246
117
|
"primaryFixedDim",
|
|
247
|
-
"
|
|
248
|
-
"onPrimaryFixedVariant",
|
|
249
|
-
"inversePrimary",
|
|
250
|
-
"primaryFixed",
|
|
251
|
-
"primaryFixedDim",
|
|
252
|
-
"onPrimaryFixed",
|
|
253
|
-
"onPrimaryFixedVariant",
|
|
118
|
+
"scrim",
|
|
254
119
|
"secondary",
|
|
255
|
-
// "secondaryDim",
|
|
256
|
-
"onSecondary",
|
|
257
120
|
"secondaryContainer",
|
|
258
|
-
"onSecondaryContainer",
|
|
259
121
|
"secondaryFixed",
|
|
260
122
|
"secondaryFixedDim",
|
|
261
|
-
"
|
|
262
|
-
"
|
|
123
|
+
"shadow",
|
|
124
|
+
"surface",
|
|
125
|
+
"surfaceBright",
|
|
126
|
+
"surfaceContainer",
|
|
127
|
+
"surfaceContainerHigh",
|
|
128
|
+
"surfaceContainerHighest",
|
|
129
|
+
"surfaceContainerLow",
|
|
130
|
+
"surfaceContainerLowest",
|
|
131
|
+
"surfaceDim",
|
|
132
|
+
"surfaceTint",
|
|
133
|
+
"surfaceVariant",
|
|
263
134
|
"tertiary",
|
|
264
|
-
// "tertiaryDim",
|
|
265
|
-
"onTertiary",
|
|
266
135
|
"tertiaryContainer",
|
|
267
|
-
"onTertiaryContainer",
|
|
268
136
|
"tertiaryFixed",
|
|
269
|
-
"tertiaryFixedDim"
|
|
270
|
-
"onTertiaryFixed",
|
|
271
|
-
"onTertiaryFixedVariant",
|
|
272
|
-
"error",
|
|
273
|
-
// "errorDim",
|
|
274
|
-
"onError",
|
|
275
|
-
"errorContainer",
|
|
276
|
-
"onErrorContainer",
|
|
277
|
-
"scrim",
|
|
278
|
-
// added manually, was missing
|
|
279
|
-
"shadow"
|
|
280
|
-
// added manually, was missing
|
|
137
|
+
"tertiaryFixedDim"
|
|
281
138
|
];
|
|
282
139
|
function toRecord(arr, getEntry) {
|
|
283
|
-
return arr.
|
|
284
|
-
(acc, item) => {
|
|
285
|
-
const [key, value] = getEntry(item);
|
|
286
|
-
acc[key] = value;
|
|
287
|
-
return acc;
|
|
288
|
-
},
|
|
289
|
-
{}
|
|
290
|
-
);
|
|
140
|
+
return Object.fromEntries(arr.map(getEntry));
|
|
291
141
|
}
|
|
292
142
|
function getPalette(palettes, colorName) {
|
|
293
143
|
const palette = palettes[colorName];
|
|
@@ -310,7 +160,7 @@ function mergeBaseAndCustomColors(scheme, customColors, colorPalettes, contrastA
|
|
|
310
160
|
const getPaletteForColor = (s) => getPalette(colorPalettes, colorname);
|
|
311
161
|
const getTone = (baseTone) => (s) => {
|
|
312
162
|
if (!contrastAllColors) return baseTone;
|
|
313
|
-
return adjustToneForContrast(baseTone, s.contrastLevel
|
|
163
|
+
return adjustToneForContrast(baseTone, s.contrastLevel);
|
|
314
164
|
};
|
|
315
165
|
const colorDynamicColor = new DynamicColor(
|
|
316
166
|
colorname,
|
|
@@ -349,25 +199,6 @@ function mergeBaseAndCustomColors(scheme, customColors, colorPalettes, contrastA
|
|
|
349
199
|
});
|
|
350
200
|
return { ...baseVars, ...customVars };
|
|
351
201
|
}
|
|
352
|
-
var cssVar = (colorName, colorValue) => {
|
|
353
|
-
const name = `--mcu-${kebabCase(colorName)}`;
|
|
354
|
-
const value = hexFromArgb2(colorValue);
|
|
355
|
-
return `${name}:${value};`;
|
|
356
|
-
};
|
|
357
|
-
var generateTonalPaletteVars = (paletteName, palette, scheme, applyContrast = false) => {
|
|
358
|
-
return STANDARD_TONES.map((tone) => {
|
|
359
|
-
let toneToUse = tone;
|
|
360
|
-
if (applyContrast && scheme) {
|
|
361
|
-
toneToUse = adjustToneForContrast(
|
|
362
|
-
tone,
|
|
363
|
-
scheme.contrastLevel,
|
|
364
|
-
scheme.isDark
|
|
365
|
-
);
|
|
366
|
-
}
|
|
367
|
-
const color = palette.tone(toneToUse);
|
|
368
|
-
return cssVar(`${paletteName}-${tone}`, color);
|
|
369
|
-
}).join(" ");
|
|
370
|
-
};
|
|
371
202
|
function createColorPalette(colorDef, baseScheme, effectiveSourceForHarmonization) {
|
|
372
203
|
const colorArgb = argbFromHex(colorDef.hex);
|
|
373
204
|
const harmonizedArgb = colorDef.blend ? Blend.harmonize(colorArgb, effectiveSourceForHarmonization) : colorArgb;
|
|
@@ -386,11 +217,7 @@ function createColorPalette(colorDef, baseScheme, effectiveSourceForHarmonizatio
|
|
|
386
217
|
}
|
|
387
218
|
return TonalPalette.fromHueAndChroma(hct.hue, targetChroma);
|
|
388
219
|
}
|
|
389
|
-
|
|
390
|
-
return Object.entries(mergedColors).map(([name, value]) => cssVar(name, value)).join(" ");
|
|
391
|
-
};
|
|
392
|
-
function generateCss({
|
|
393
|
-
source: hexSource,
|
|
220
|
+
function builder(hexSource, {
|
|
394
221
|
scheme = DEFAULT_SCHEME,
|
|
395
222
|
contrast = DEFAULT_CONTRAST,
|
|
396
223
|
primary,
|
|
@@ -399,11 +226,12 @@ function generateCss({
|
|
|
399
226
|
neutral,
|
|
400
227
|
neutralVariant,
|
|
401
228
|
error,
|
|
402
|
-
colorMatch = DEFAULT_COLOR_MATCH,
|
|
403
229
|
customColors: hexCustomColors = DEFAULT_CUSTOM_COLORS,
|
|
404
|
-
contrastAllColors = DEFAULT_CONTRAST_ALL_COLORS
|
|
405
|
-
|
|
230
|
+
contrastAllColors = DEFAULT_CONTRAST_ALL_COLORS,
|
|
231
|
+
adaptiveShades = DEFAULT_ADAPTIVE_SHADES
|
|
232
|
+
} = {}) {
|
|
406
233
|
const sourceArgb = argbFromHex(hexSource);
|
|
234
|
+
const sourceHct = Hct.fromInt(sourceArgb);
|
|
407
235
|
const effectiveSource = primary || hexSource;
|
|
408
236
|
const effectiveSourceArgb = argbFromHex(effectiveSource);
|
|
409
237
|
const effectiveSourceForHarmonization = primary ? argbFromHex(primary) : sourceArgb;
|
|
@@ -462,12 +290,8 @@ function generateCss({
|
|
|
462
290
|
createColorPalette(colorDef, baseScheme, effectiveSourceForHarmonization)
|
|
463
291
|
])
|
|
464
292
|
);
|
|
465
|
-
const createSchemes = (baseConfig) => [
|
|
466
|
-
new DynamicScheme({ ...baseConfig, isDark: false }),
|
|
467
|
-
new DynamicScheme({ ...baseConfig, isDark: true })
|
|
468
|
-
];
|
|
469
293
|
const variant = schemeToVariant[scheme];
|
|
470
|
-
const
|
|
294
|
+
const schemeConfig = {
|
|
471
295
|
sourceColorArgb: effectiveSourceArgb,
|
|
472
296
|
variant,
|
|
473
297
|
contrastLevel: contrast,
|
|
@@ -476,12 +300,26 @@ function generateCss({
|
|
|
476
300
|
tertiaryPalette: colorPalettes["tertiary"] || baseScheme.tertiaryPalette,
|
|
477
301
|
neutralPalette: colorPalettes["neutral"] || baseScheme.neutralPalette,
|
|
478
302
|
neutralVariantPalette: colorPalettes["neutralVariant"] || baseScheme.neutralVariantPalette
|
|
479
|
-
}
|
|
303
|
+
};
|
|
304
|
+
const lightScheme = new DynamicScheme({ ...schemeConfig, isDark: false });
|
|
305
|
+
const darkScheme = new DynamicScheme({ ...schemeConfig, isDark: true });
|
|
480
306
|
const errorPalette = colorPalettes["error"];
|
|
481
307
|
if (errorPalette) {
|
|
482
308
|
lightScheme.errorPalette = errorPalette;
|
|
483
309
|
darkScheme.errorPalette = errorPalette;
|
|
484
310
|
}
|
|
311
|
+
const allPalettes = {
|
|
312
|
+
primary: lightScheme.primaryPalette,
|
|
313
|
+
secondary: lightScheme.secondaryPalette,
|
|
314
|
+
tertiary: lightScheme.tertiaryPalette,
|
|
315
|
+
error: lightScheme.errorPalette,
|
|
316
|
+
neutral: lightScheme.neutralPalette,
|
|
317
|
+
"neutral-variant": lightScheme.neutralVariantPalette,
|
|
318
|
+
// Add custom color palettes
|
|
319
|
+
...Object.fromEntries(
|
|
320
|
+
definedColors.filter((c) => !c.core).map((colorDef) => [colorDef.name, colorPalettes[colorDef.name]])
|
|
321
|
+
)
|
|
322
|
+
};
|
|
485
323
|
const customColors = definedColors.filter((c) => !c.core).map((c) => ({
|
|
486
324
|
name: c.name,
|
|
487
325
|
blend: c.blend ?? DEFAULT_BLEND,
|
|
@@ -499,67 +337,452 @@ function generateCss({
|
|
|
499
337
|
colorPalettes,
|
|
500
338
|
contrastAllColors
|
|
501
339
|
);
|
|
502
|
-
const lightVars = toCssVars(mergedColorsLight);
|
|
503
|
-
const darkVars = toCssVars(mergedColorsDark);
|
|
504
|
-
const allTonalVars = [
|
|
505
|
-
// Core colors from the scheme
|
|
506
|
-
generateTonalPaletteVars(
|
|
507
|
-
"primary",
|
|
508
|
-
lightScheme.primaryPalette,
|
|
509
|
-
lightScheme,
|
|
510
|
-
contrastAllColors
|
|
511
|
-
),
|
|
512
|
-
generateTonalPaletteVars(
|
|
513
|
-
"secondary",
|
|
514
|
-
lightScheme.secondaryPalette,
|
|
515
|
-
lightScheme,
|
|
516
|
-
contrastAllColors
|
|
517
|
-
),
|
|
518
|
-
generateTonalPaletteVars(
|
|
519
|
-
"tertiary",
|
|
520
|
-
lightScheme.tertiaryPalette,
|
|
521
|
-
lightScheme,
|
|
522
|
-
contrastAllColors
|
|
523
|
-
),
|
|
524
|
-
generateTonalPaletteVars(
|
|
525
|
-
"error",
|
|
526
|
-
lightScheme.errorPalette,
|
|
527
|
-
lightScheme,
|
|
528
|
-
contrastAllColors
|
|
529
|
-
),
|
|
530
|
-
generateTonalPaletteVars(
|
|
531
|
-
"neutral",
|
|
532
|
-
lightScheme.neutralPalette,
|
|
533
|
-
lightScheme,
|
|
534
|
-
contrastAllColors
|
|
535
|
-
),
|
|
536
|
-
generateTonalPaletteVars(
|
|
537
|
-
"neutral-variant",
|
|
538
|
-
lightScheme.neutralVariantPalette,
|
|
539
|
-
lightScheme,
|
|
540
|
-
contrastAllColors
|
|
541
|
-
),
|
|
542
|
-
// Custom colors from our unified palette map
|
|
543
|
-
...customColors.map((customColorObj) => {
|
|
544
|
-
const palette = getPalette(colorPalettes, customColorObj.name);
|
|
545
|
-
return generateTonalPaletteVars(
|
|
546
|
-
kebabCase(customColorObj.name),
|
|
547
|
-
palette,
|
|
548
|
-
lightScheme,
|
|
549
|
-
contrastAllColors
|
|
550
|
-
);
|
|
551
|
-
})
|
|
552
|
-
].join(" ");
|
|
553
340
|
return {
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
341
|
+
//
|
|
342
|
+
// ██████ ███████ ███████
|
|
343
|
+
// ██ ██ ██
|
|
344
|
+
// ██ ███████ ███████
|
|
345
|
+
// ██ ██ ██
|
|
346
|
+
// ██████ ███████ ███████
|
|
347
|
+
//
|
|
348
|
+
toCss() {
|
|
349
|
+
function cssVar(colorName, colorValue) {
|
|
350
|
+
const name = `--mcu-${kebabCase(colorName)}`;
|
|
351
|
+
const value = hexFromArgb(colorValue);
|
|
352
|
+
return `${name}:${value};`;
|
|
353
|
+
}
|
|
354
|
+
function toCssVars(mergedColors) {
|
|
355
|
+
return Object.entries(mergedColors).map(([name, value]) => cssVar(name, value)).join(" ");
|
|
356
|
+
}
|
|
357
|
+
function generateTonalPaletteVars(paletteName, palette, scheme2, applyContrast, adaptiveShades2) {
|
|
358
|
+
return STANDARD_TONES.map((tone) => {
|
|
359
|
+
let toneToUse = tone;
|
|
360
|
+
if (adaptiveShades2 && scheme2.isDark) {
|
|
361
|
+
toneToUse = 100 - tone;
|
|
362
|
+
}
|
|
363
|
+
if (applyContrast) {
|
|
364
|
+
toneToUse = adjustToneForContrast(toneToUse, scheme2.contrastLevel);
|
|
365
|
+
}
|
|
366
|
+
const color = palette.tone(toneToUse);
|
|
367
|
+
return cssVar(`${paletteName}-${tone}`, color);
|
|
368
|
+
}).join(" ");
|
|
369
|
+
}
|
|
370
|
+
function generateTonalVars(s) {
|
|
371
|
+
return Object.entries(allPalettes).map(
|
|
372
|
+
([name, palette]) => generateTonalPaletteVars(
|
|
373
|
+
kebabCase(name),
|
|
374
|
+
palette,
|
|
375
|
+
s,
|
|
376
|
+
contrastAllColors,
|
|
377
|
+
adaptiveShades
|
|
378
|
+
)
|
|
379
|
+
).join(" ");
|
|
380
|
+
}
|
|
381
|
+
const lightVars = toCssVars(mergedColorsLight);
|
|
382
|
+
const darkVars = toCssVars(mergedColorsDark);
|
|
383
|
+
const lightTonalVars = generateTonalVars(lightScheme);
|
|
384
|
+
const darkTonalVars = generateTonalVars(darkScheme);
|
|
385
|
+
return `
|
|
386
|
+
:root { ${lightVars} ${lightTonalVars} }
|
|
387
|
+
.dark { ${darkVars} ${adaptiveShades ? darkTonalVars : lightTonalVars} }
|
|
388
|
+
`;
|
|
389
|
+
},
|
|
390
|
+
//
|
|
391
|
+
// ██ ███████ ██████ ███ ██
|
|
392
|
+
// ██ ██ ██ ██ ████ ██
|
|
393
|
+
// ██ ███████ ██ ██ ██ ██ ██
|
|
394
|
+
// ██ ██ ██ ██ ██ ██ ██ ██
|
|
395
|
+
// █████ ███████ ██████ ██ ████
|
|
396
|
+
//
|
|
397
|
+
toJson() {
|
|
398
|
+
const fixtureTokenOrder = [
|
|
399
|
+
"primary",
|
|
400
|
+
"surfaceTint",
|
|
401
|
+
"onPrimary",
|
|
402
|
+
"primaryContainer",
|
|
403
|
+
"onPrimaryContainer",
|
|
404
|
+
"secondary",
|
|
405
|
+
"onSecondary",
|
|
406
|
+
"secondaryContainer",
|
|
407
|
+
"onSecondaryContainer",
|
|
408
|
+
"tertiary",
|
|
409
|
+
"onTertiary",
|
|
410
|
+
"tertiaryContainer",
|
|
411
|
+
"onTertiaryContainer",
|
|
412
|
+
"error",
|
|
413
|
+
"onError",
|
|
414
|
+
"errorContainer",
|
|
415
|
+
"onErrorContainer",
|
|
416
|
+
"background",
|
|
417
|
+
"onBackground",
|
|
418
|
+
"surface",
|
|
419
|
+
"onSurface",
|
|
420
|
+
"surfaceVariant",
|
|
421
|
+
"onSurfaceVariant",
|
|
422
|
+
"outline",
|
|
423
|
+
"outlineVariant",
|
|
424
|
+
"shadow",
|
|
425
|
+
"scrim",
|
|
426
|
+
"inverseSurface",
|
|
427
|
+
"inverseOnSurface",
|
|
428
|
+
"inversePrimary",
|
|
429
|
+
"primaryFixed",
|
|
430
|
+
"onPrimaryFixed",
|
|
431
|
+
"primaryFixedDim",
|
|
432
|
+
"onPrimaryFixedVariant",
|
|
433
|
+
"secondaryFixed",
|
|
434
|
+
"onSecondaryFixed",
|
|
435
|
+
"secondaryFixedDim",
|
|
436
|
+
"onSecondaryFixedVariant",
|
|
437
|
+
"tertiaryFixed",
|
|
438
|
+
"onTertiaryFixed",
|
|
439
|
+
"tertiaryFixedDim",
|
|
440
|
+
"onTertiaryFixedVariant",
|
|
441
|
+
"surfaceDim",
|
|
442
|
+
"surfaceBright",
|
|
443
|
+
"surfaceContainerLowest",
|
|
444
|
+
"surfaceContainerLow",
|
|
445
|
+
"surfaceContainer",
|
|
446
|
+
"surfaceContainerHigh",
|
|
447
|
+
"surfaceContainerHighest"
|
|
448
|
+
];
|
|
449
|
+
const neuHct = neutral ? Hct.fromInt(argbFromHex(neutral)) : sourceHct;
|
|
450
|
+
const nvHct = neutralVariant ? Hct.fromInt(argbFromHex(neutralVariant)) : sourceHct;
|
|
451
|
+
const rawPalettes = {
|
|
452
|
+
primary: TonalPalette.fromInt(effectiveSourceArgb),
|
|
453
|
+
secondary: secondary ? TonalPalette.fromInt(argbFromHex(secondary)) : TonalPalette.fromHueAndChroma(sourceHct.hue, sourceHct.chroma / 3),
|
|
454
|
+
tertiary: tertiary ? TonalPalette.fromInt(argbFromHex(tertiary)) : TonalPalette.fromHueAndChroma(
|
|
455
|
+
(sourceHct.hue + 60) % 360,
|
|
456
|
+
sourceHct.chroma / 2
|
|
457
|
+
),
|
|
458
|
+
neutral: TonalPalette.fromHueAndChroma(
|
|
459
|
+
neuHct.hue,
|
|
460
|
+
Math.min(neuHct.chroma / 12, 4)
|
|
461
|
+
),
|
|
462
|
+
"neutral-variant": TonalPalette.fromHueAndChroma(
|
|
463
|
+
nvHct.hue,
|
|
464
|
+
Math.min(nvHct.chroma / 6, 8)
|
|
465
|
+
)
|
|
466
|
+
};
|
|
467
|
+
function buildJsonSchemes() {
|
|
468
|
+
function extractSchemeColors(scheme2, backgroundScheme) {
|
|
469
|
+
const colors = {};
|
|
470
|
+
for (const tokenName of fixtureTokenOrder) {
|
|
471
|
+
const dynamicColor = MaterialDynamicColors[tokenName];
|
|
472
|
+
const useScheme = backgroundScheme && (tokenName === "background" || tokenName === "onBackground") ? backgroundScheme : scheme2;
|
|
473
|
+
colors[tokenName] = hexFromArgb(
|
|
474
|
+
dynamicColor.getArgb(useScheme)
|
|
475
|
+
).toUpperCase();
|
|
476
|
+
}
|
|
477
|
+
return colors;
|
|
478
|
+
}
|
|
479
|
+
function resolveOverridePalette(hex, role) {
|
|
480
|
+
if (!hex) return null;
|
|
481
|
+
return new SchemeClass(Hct.fromInt(argbFromHex(hex)), false, 0)[role];
|
|
482
|
+
}
|
|
483
|
+
const secPalette = resolveOverridePalette(secondary, "primaryPalette");
|
|
484
|
+
const terPalette = resolveOverridePalette(tertiary, "primaryPalette");
|
|
485
|
+
const errPalette = resolveOverridePalette(error, "primaryPalette");
|
|
486
|
+
const neuPalette = resolveOverridePalette(neutral, "neutralPalette");
|
|
487
|
+
const nvPalette = resolveOverridePalette(
|
|
488
|
+
neutralVariant,
|
|
489
|
+
"neutralVariantPalette"
|
|
490
|
+
);
|
|
491
|
+
const jsonSchemes = {};
|
|
492
|
+
const jsonContrastLevels = [
|
|
493
|
+
{ name: "light", isDark: false, contrast: 0 },
|
|
494
|
+
{ name: "light-medium-contrast", isDark: false, contrast: 0.5 },
|
|
495
|
+
{ name: "light-high-contrast", isDark: false, contrast: 1 },
|
|
496
|
+
{ name: "dark", isDark: true, contrast: 0 },
|
|
497
|
+
{ name: "dark-medium-contrast", isDark: true, contrast: 0.5 },
|
|
498
|
+
{ name: "dark-high-contrast", isDark: true, contrast: 1 }
|
|
499
|
+
];
|
|
500
|
+
for (const { name, isDark, contrast: contrast2 } of jsonContrastLevels) {
|
|
501
|
+
const baseScheme2 = new SchemeClass(primaryHct, isDark, contrast2);
|
|
502
|
+
const composedScheme = new DynamicScheme({
|
|
503
|
+
sourceColorArgb: effectiveSourceArgb,
|
|
504
|
+
variant: schemeToVariant[scheme],
|
|
505
|
+
contrastLevel: contrast2,
|
|
506
|
+
isDark,
|
|
507
|
+
primaryPalette: baseScheme2.primaryPalette,
|
|
508
|
+
secondaryPalette: secPalette || baseScheme2.secondaryPalette,
|
|
509
|
+
tertiaryPalette: terPalette || baseScheme2.tertiaryPalette,
|
|
510
|
+
neutralPalette: neuPalette || baseScheme2.neutralPalette,
|
|
511
|
+
neutralVariantPalette: nvPalette || baseScheme2.neutralVariantPalette
|
|
512
|
+
});
|
|
513
|
+
if (errPalette) composedScheme.errorPalette = errPalette;
|
|
514
|
+
jsonSchemes[name] = extractSchemeColors(composedScheme, baseScheme2);
|
|
515
|
+
}
|
|
516
|
+
return jsonSchemes;
|
|
517
|
+
}
|
|
518
|
+
function rawPalettesToJson() {
|
|
519
|
+
const jsonPalettes = {};
|
|
520
|
+
const RAW_PALETTE_NAMES = [
|
|
521
|
+
"primary",
|
|
522
|
+
"secondary",
|
|
523
|
+
"tertiary",
|
|
524
|
+
"neutral",
|
|
525
|
+
"neutral-variant"
|
|
526
|
+
];
|
|
527
|
+
for (const name of RAW_PALETTE_NAMES) {
|
|
528
|
+
const palette = rawPalettes[name];
|
|
529
|
+
const tones = {};
|
|
530
|
+
for (const tone of STANDARD_TONES) {
|
|
531
|
+
tones[tone.toString()] = hexFromArgb(
|
|
532
|
+
palette.tone(tone)
|
|
533
|
+
).toUpperCase();
|
|
534
|
+
}
|
|
535
|
+
jsonPalettes[name] = tones;
|
|
536
|
+
}
|
|
537
|
+
return jsonPalettes;
|
|
538
|
+
}
|
|
539
|
+
function buildCoreColors(opts) {
|
|
540
|
+
const colors = { primary: opts.primary };
|
|
541
|
+
if (opts.secondary) colors.secondary = opts.secondary.toUpperCase();
|
|
542
|
+
if (opts.tertiary) colors.tertiary = opts.tertiary.toUpperCase();
|
|
543
|
+
if (opts.error) colors.error = opts.error.toUpperCase();
|
|
544
|
+
if (opts.neutral) colors.neutral = opts.neutral.toUpperCase();
|
|
545
|
+
if (opts.neutralVariant)
|
|
546
|
+
colors.neutralVariant = opts.neutralVariant.toUpperCase();
|
|
547
|
+
return colors;
|
|
548
|
+
}
|
|
549
|
+
const seed = hexSource.toUpperCase();
|
|
550
|
+
const coreColors = buildCoreColors({
|
|
551
|
+
primary: (primary || hexSource).toUpperCase(),
|
|
552
|
+
secondary,
|
|
553
|
+
tertiary,
|
|
554
|
+
error,
|
|
555
|
+
neutral,
|
|
556
|
+
neutralVariant
|
|
557
|
+
});
|
|
558
|
+
const extendedColors = hexCustomColors.map((c) => ({
|
|
559
|
+
name: c.name,
|
|
560
|
+
color: c.hex.toUpperCase(),
|
|
561
|
+
description: "",
|
|
562
|
+
harmonized: c.blend ?? DEFAULT_BLEND
|
|
563
|
+
}));
|
|
564
|
+
return {
|
|
565
|
+
seed,
|
|
566
|
+
coreColors,
|
|
567
|
+
extendedColors,
|
|
568
|
+
schemes: buildJsonSchemes(),
|
|
569
|
+
palettes: rawPalettesToJson()
|
|
570
|
+
};
|
|
571
|
+
},
|
|
572
|
+
//
|
|
573
|
+
// ███████ ██ ██████ ███ ███ █████
|
|
574
|
+
// ██ ██ ██ ████ ████ ██ ██
|
|
575
|
+
// █████ ██ ██ ███ ██ ████ ██ ███████
|
|
576
|
+
// ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
577
|
+
// ██ ██ ██████ ██ ██ ██ ██
|
|
578
|
+
//
|
|
579
|
+
toFigmaTokens() {
|
|
580
|
+
function argbToFigmaColorValue(argb) {
|
|
581
|
+
return {
|
|
582
|
+
colorSpace: "srgb",
|
|
583
|
+
components: [
|
|
584
|
+
redFromArgb(argb) / 255,
|
|
585
|
+
greenFromArgb(argb) / 255,
|
|
586
|
+
blueFromArgb(argb) / 255
|
|
587
|
+
],
|
|
588
|
+
alpha: 1,
|
|
589
|
+
hex: hexFromArgb(argb).toUpperCase()
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
function figmaToken(argb) {
|
|
593
|
+
return {
|
|
594
|
+
$type: "color",
|
|
595
|
+
$value: argbToFigmaColorValue(argb),
|
|
596
|
+
$extensions: {
|
|
597
|
+
"com.figma.scopes": ["ALL_SCOPES"],
|
|
598
|
+
"com.figma.isOverride": true
|
|
599
|
+
}
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
function buildFigmaSchemeTokens(mergedColors) {
|
|
603
|
+
const tokens = {};
|
|
604
|
+
for (const [name, argb] of Object.entries(mergedColors)) {
|
|
605
|
+
tokens[startCase(name)] = figmaToken(argb);
|
|
606
|
+
}
|
|
607
|
+
return tokens;
|
|
608
|
+
}
|
|
609
|
+
function buildFigmaPaletteTokens(isDark) {
|
|
610
|
+
const palettes = {};
|
|
611
|
+
for (const [name, palette] of Object.entries(allPalettes)) {
|
|
612
|
+
const tones = {};
|
|
613
|
+
for (const tone of STANDARD_TONES) {
|
|
614
|
+
let toneToUse = tone;
|
|
615
|
+
if (adaptiveShades && isDark) {
|
|
616
|
+
toneToUse = 100 - tone;
|
|
617
|
+
}
|
|
618
|
+
if (contrastAllColors) {
|
|
619
|
+
toneToUse = adjustToneForContrast(toneToUse, contrast);
|
|
620
|
+
}
|
|
621
|
+
const argb = palette.tone(toneToUse);
|
|
622
|
+
tones[tone.toString()] = figmaToken(argb);
|
|
623
|
+
}
|
|
624
|
+
palettes[startCase(name)] = tones;
|
|
625
|
+
}
|
|
626
|
+
return palettes;
|
|
627
|
+
}
|
|
628
|
+
function buildModeFile(modeName, mergedColors, isDark) {
|
|
629
|
+
return {
|
|
630
|
+
Schemes: buildFigmaSchemeTokens(mergedColors),
|
|
631
|
+
Palettes: buildFigmaPaletteTokens(isDark),
|
|
632
|
+
$extensions: {
|
|
633
|
+
"com.figma.modeName": modeName
|
|
634
|
+
}
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
return {
|
|
638
|
+
"Light.tokens.json": buildModeFile("Light", mergedColorsLight, false),
|
|
639
|
+
"Dark.tokens.json": buildModeFile("Dark", mergedColorsDark, true)
|
|
640
|
+
};
|
|
641
|
+
},
|
|
642
|
+
//
|
|
643
|
+
// API
|
|
644
|
+
//
|
|
558
645
|
mergedColorsLight,
|
|
559
|
-
mergedColorsDark
|
|
646
|
+
mergedColorsDark,
|
|
647
|
+
allPalettes
|
|
560
648
|
};
|
|
561
649
|
}
|
|
650
|
+
|
|
651
|
+
// src/Mcu.tsx
|
|
652
|
+
import { useMemo as useMemo2 } from "react";
|
|
653
|
+
|
|
654
|
+
// src/Mcu.context.tsx
|
|
655
|
+
import {
|
|
656
|
+
hexFromArgb as hexFromArgb2
|
|
657
|
+
} from "@material/material-color-utilities";
|
|
658
|
+
import React, {
|
|
659
|
+
useCallback,
|
|
660
|
+
useInsertionEffect,
|
|
661
|
+
useMemo,
|
|
662
|
+
useState
|
|
663
|
+
} from "react";
|
|
664
|
+
|
|
665
|
+
// src/lib/createRequiredContext.ts
|
|
666
|
+
import { createContext, useContext } from "react";
|
|
667
|
+
var createRequiredContext = () => {
|
|
668
|
+
const Ctx = createContext(null);
|
|
669
|
+
const useCtx = () => {
|
|
670
|
+
const contextValue = useContext(Ctx);
|
|
671
|
+
if (contextValue === null) {
|
|
672
|
+
throw new Error("Context value is null");
|
|
673
|
+
}
|
|
674
|
+
return contextValue;
|
|
675
|
+
};
|
|
676
|
+
return [useCtx, Ctx.Provider, Ctx];
|
|
677
|
+
};
|
|
678
|
+
|
|
679
|
+
// src/Mcu.context.tsx
|
|
680
|
+
import { jsx } from "react/jsx-runtime";
|
|
681
|
+
var [useMcu, Provider, McuContext] = createRequiredContext();
|
|
682
|
+
var McuProvider = ({
|
|
683
|
+
styleId,
|
|
684
|
+
children,
|
|
685
|
+
...configProps
|
|
686
|
+
}) => {
|
|
687
|
+
const [initials] = useState(() => configProps);
|
|
688
|
+
const [mcuConfig, setMcuConfig] = useState(initials);
|
|
689
|
+
const configKey = JSON.stringify(configProps);
|
|
690
|
+
React.useEffect(() => {
|
|
691
|
+
setMcuConfig(configProps);
|
|
692
|
+
}, [configKey]);
|
|
693
|
+
const { css, mergedColorsLight, mergedColorsDark, allPalettes } = useMemo(() => {
|
|
694
|
+
const { toCss, ...rest } = builder(mcuConfig.source, mcuConfig);
|
|
695
|
+
return { css: toCss(), ...rest };
|
|
696
|
+
}, [mcuConfig]);
|
|
697
|
+
useInsertionEffect(() => {
|
|
698
|
+
let tag = document.getElementById(styleId);
|
|
699
|
+
if (!tag) {
|
|
700
|
+
tag = document.createElement("style");
|
|
701
|
+
tag.id = styleId;
|
|
702
|
+
document.head.appendChild(tag);
|
|
703
|
+
}
|
|
704
|
+
tag.textContent = css;
|
|
705
|
+
}, [css, styleId]);
|
|
706
|
+
const getMcuColor = useCallback(
|
|
707
|
+
(colorName, theme) => {
|
|
708
|
+
const mergedColors = theme === "light" ? mergedColorsLight : mergedColorsDark;
|
|
709
|
+
const colorValue = mergedColors[colorName];
|
|
710
|
+
if (colorValue === void 0) {
|
|
711
|
+
throw new Error(`Unknown MCU token '${colorName}'`);
|
|
712
|
+
}
|
|
713
|
+
return hexFromArgb2(colorValue);
|
|
714
|
+
},
|
|
715
|
+
[mergedColorsDark, mergedColorsLight]
|
|
716
|
+
);
|
|
717
|
+
const value = useMemo(
|
|
718
|
+
() => ({
|
|
719
|
+
initials,
|
|
720
|
+
setMcuConfig,
|
|
721
|
+
getMcuColor,
|
|
722
|
+
allPalettes
|
|
723
|
+
}),
|
|
724
|
+
[getMcuColor, initials, allPalettes]
|
|
725
|
+
);
|
|
726
|
+
return /* @__PURE__ */ jsx(Provider, { value, children });
|
|
727
|
+
};
|
|
728
|
+
|
|
729
|
+
// src/Mcu.tsx
|
|
730
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
731
|
+
var mcuStyleId = "mcu-styles";
|
|
732
|
+
var DEFAULT_COLOR_MATCH = false;
|
|
733
|
+
function Mcu({
|
|
734
|
+
source,
|
|
735
|
+
scheme = DEFAULT_SCHEME,
|
|
736
|
+
contrast = DEFAULT_CONTRAST,
|
|
737
|
+
primary,
|
|
738
|
+
secondary,
|
|
739
|
+
tertiary,
|
|
740
|
+
neutral,
|
|
741
|
+
neutralVariant,
|
|
742
|
+
error,
|
|
743
|
+
colorMatch = DEFAULT_COLOR_MATCH,
|
|
744
|
+
customColors = DEFAULT_CUSTOM_COLORS,
|
|
745
|
+
contrastAllColors = DEFAULT_CONTRAST_ALL_COLORS,
|
|
746
|
+
adaptiveShades = DEFAULT_ADAPTIVE_SHADES,
|
|
747
|
+
children
|
|
748
|
+
}) {
|
|
749
|
+
const config = useMemo2(
|
|
750
|
+
() => ({
|
|
751
|
+
source,
|
|
752
|
+
scheme,
|
|
753
|
+
contrast,
|
|
754
|
+
primary,
|
|
755
|
+
secondary,
|
|
756
|
+
tertiary,
|
|
757
|
+
neutral,
|
|
758
|
+
neutralVariant,
|
|
759
|
+
error,
|
|
760
|
+
colorMatch,
|
|
761
|
+
customColors,
|
|
762
|
+
// extras features
|
|
763
|
+
contrastAllColors,
|
|
764
|
+
adaptiveShades
|
|
765
|
+
}),
|
|
766
|
+
[
|
|
767
|
+
contrast,
|
|
768
|
+
customColors,
|
|
769
|
+
scheme,
|
|
770
|
+
source,
|
|
771
|
+
primary,
|
|
772
|
+
secondary,
|
|
773
|
+
tertiary,
|
|
774
|
+
neutral,
|
|
775
|
+
neutralVariant,
|
|
776
|
+
error,
|
|
777
|
+
colorMatch,
|
|
778
|
+
contrastAllColors,
|
|
779
|
+
adaptiveShades
|
|
780
|
+
]
|
|
781
|
+
);
|
|
782
|
+
return /* @__PURE__ */ jsx2(McuProvider, { ...config, styleId: mcuStyleId, children });
|
|
783
|
+
}
|
|
562
784
|
export {
|
|
563
785
|
Mcu,
|
|
786
|
+
builder,
|
|
564
787
|
useMcu
|
|
565
788
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-mcu",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "A React component library",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -28,32 +28,50 @@
|
|
|
28
28
|
"dist",
|
|
29
29
|
"src/tailwind.css"
|
|
30
30
|
],
|
|
31
|
+
"bin": {
|
|
32
|
+
"react-mcu": "./src/cli.ts"
|
|
33
|
+
},
|
|
31
34
|
"type": "module",
|
|
32
35
|
"devDependencies": {
|
|
33
36
|
"@arethetypeswrong/cli": "^0.18.2",
|
|
34
37
|
"@changesets/cli": "^2.27.7",
|
|
38
|
+
"@chromatic-com/storybook": "^5.0.0",
|
|
39
|
+
"@eslint/js": "^10.0.1",
|
|
35
40
|
"@storybook/addon-docs": "^10.1.11",
|
|
36
41
|
"@storybook/addon-themes": "^10.1.11",
|
|
37
42
|
"@storybook/react-vite": "^10.1.11",
|
|
38
43
|
"@tailwindcss/postcss": "^4.1.18",
|
|
39
44
|
"@testing-library/dom": "^10.4.1",
|
|
40
45
|
"@testing-library/react": "^16.3.1",
|
|
46
|
+
"@types/culori": "^4.0.1",
|
|
41
47
|
"@types/lodash-es": "^4.17.12",
|
|
42
48
|
"@types/react": "^19.2.7",
|
|
43
49
|
"@types/react-dom": "^19.2.3",
|
|
44
50
|
"@vitejs/plugin-react": "^5.1.2",
|
|
51
|
+
"ajv": "^8.18.0",
|
|
52
|
+
"ajv-formats": "^3.0.1",
|
|
45
53
|
"chromatic": "^13.3.5",
|
|
54
|
+
"class-variance-authority": "^0.7.1",
|
|
55
|
+
"clsx": "^2.1.1",
|
|
56
|
+
"culori": "^4.0.2",
|
|
57
|
+
"eslint": "^10.0.0",
|
|
58
|
+
"eslint-plugin-react-hooks": "^7.0.1",
|
|
59
|
+
"eslint-plugin-sonarjs": "^3.0.7",
|
|
60
|
+
"globals": "^17.3.0",
|
|
46
61
|
"husky": "^9.1.7",
|
|
47
62
|
"jsdom": "^27.4.0",
|
|
48
63
|
"lint-staged": "^16.2.7",
|
|
49
64
|
"postcss": "^8.5.6",
|
|
50
65
|
"prettier": "^3.3.3",
|
|
66
|
+
"prettier-plugin-organize-imports": "^4.3.0",
|
|
51
67
|
"react": "^19.2.3",
|
|
52
68
|
"react-dom": "^19.2.3",
|
|
53
69
|
"storybook": "^10.1.11",
|
|
70
|
+
"tailwind-merge": "^3.4.0",
|
|
54
71
|
"tailwindcss": "^4.1.18",
|
|
55
72
|
"tsup": "^8.2.4",
|
|
56
73
|
"typescript": "^5.5.4",
|
|
74
|
+
"typescript-eslint": "^8.55.0",
|
|
57
75
|
"vitest": "^4.0.16"
|
|
58
76
|
},
|
|
59
77
|
"peerDependencies": {
|
|
@@ -62,13 +80,17 @@
|
|
|
62
80
|
},
|
|
63
81
|
"dependencies": {
|
|
64
82
|
"@material/material-color-utilities": "^0.3.0",
|
|
65
|
-
"
|
|
83
|
+
"commander": "^14.0.3",
|
|
84
|
+
"lodash-es": "^4.17.22",
|
|
85
|
+
"tsx": "^4.21.0"
|
|
66
86
|
},
|
|
67
87
|
"scripts": {
|
|
68
88
|
"build": "tsup",
|
|
69
|
-
"
|
|
89
|
+
"lint": "eslint .",
|
|
90
|
+
"lgtm": "pnpm run build && pnpm run lint && pnpm run check-format && pnpm run check-exports && pnpm run typecheck && pnpm run test",
|
|
70
91
|
"typecheck": "tsc",
|
|
71
92
|
"test": "vitest run",
|
|
93
|
+
"pretest": "bash scripts/download-dtcg-schemas.sh",
|
|
72
94
|
"format": "prettier --write .",
|
|
73
95
|
"check-format": "prettier --check .",
|
|
74
96
|
"check-exports": "attw --pack . --ignore-rules cjs-resolves-to-esm no-resolution",
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
|
|
3
|
+
// @example
|
|
4
|
+
|
|
5
|
+
// ```sh
|
|
6
|
+
// $ npx tsx src/cli.ts builder '#6750A4'
|
|
7
|
+
// $ npx tsx src/cli.ts builder '#6750A4' --format css
|
|
8
|
+
// $ npx tsx src/cli.ts builder '#6750A4' --adaptive-shades --format figma
|
|
9
|
+
// ```
|
|
10
|
+
|
|
11
|
+
import * as fs from "node:fs";
|
|
12
|
+
import * as path from "node:path";
|
|
13
|
+
|
|
14
|
+
import { Command, Option } from "commander";
|
|
15
|
+
import {
|
|
16
|
+
builder,
|
|
17
|
+
DEFAULT_ADAPTIVE_SHADES,
|
|
18
|
+
DEFAULT_BLEND,
|
|
19
|
+
DEFAULT_CONTRAST,
|
|
20
|
+
DEFAULT_CONTRAST_ALL_COLORS,
|
|
21
|
+
DEFAULT_SCHEME,
|
|
22
|
+
schemeNames,
|
|
23
|
+
} from "./lib/builder";
|
|
24
|
+
|
|
25
|
+
const program = new Command();
|
|
26
|
+
|
|
27
|
+
program.name("react-mcu").description("m3 color system for react");
|
|
28
|
+
|
|
29
|
+
program
|
|
30
|
+
.command("builder")
|
|
31
|
+
.description("Generate a color theme from a source color")
|
|
32
|
+
.argument("<source>", "Source color in hex format (e.g. #6750A4)")
|
|
33
|
+
.addOption(
|
|
34
|
+
new Option("--scheme <name>", "Color scheme variant")
|
|
35
|
+
.choices(schemeNames)
|
|
36
|
+
.default(DEFAULT_SCHEME),
|
|
37
|
+
)
|
|
38
|
+
.option(
|
|
39
|
+
"--contrast <number>",
|
|
40
|
+
"Contrast level from -1.0 to 1.0",
|
|
41
|
+
parseFloat,
|
|
42
|
+
DEFAULT_CONTRAST,
|
|
43
|
+
)
|
|
44
|
+
.option("--primary <hex>", "Primary color override")
|
|
45
|
+
.option("--secondary <hex>", "Secondary color override")
|
|
46
|
+
.option("--tertiary <hex>", "Tertiary color override")
|
|
47
|
+
.option("--error <hex>", "Error color override")
|
|
48
|
+
.option("--neutral <hex>", "Neutral color override")
|
|
49
|
+
.option("--neutral-variant <hex>", "Neutral variant color override")
|
|
50
|
+
.option(
|
|
51
|
+
"--custom-colors <json>",
|
|
52
|
+
'Custom colors as JSON array (e.g. \'[{"name":"brand","hex":"#FF5733","blend":true}]\')',
|
|
53
|
+
)
|
|
54
|
+
.option("--format <type>", "Output format: json, css, or figma", "figma")
|
|
55
|
+
.option("--output <dir>", "Output directory (required for figma format)")
|
|
56
|
+
.option(
|
|
57
|
+
"--adaptive-shades",
|
|
58
|
+
"Adapt tonal palette shades for dark mode",
|
|
59
|
+
DEFAULT_ADAPTIVE_SHADES,
|
|
60
|
+
)
|
|
61
|
+
.option(
|
|
62
|
+
"--contrast-all-colors",
|
|
63
|
+
"Apply contrast adjustment to tonal palette shades",
|
|
64
|
+
DEFAULT_CONTRAST_ALL_COLORS,
|
|
65
|
+
)
|
|
66
|
+
.action((source: string, opts) => {
|
|
67
|
+
let customColors: { name: string; hex: string; blend: boolean }[] = [];
|
|
68
|
+
if (opts.customColors) {
|
|
69
|
+
try {
|
|
70
|
+
const parsed = JSON.parse(opts.customColors) as {
|
|
71
|
+
name: string;
|
|
72
|
+
hex: string;
|
|
73
|
+
blend?: boolean;
|
|
74
|
+
}[];
|
|
75
|
+
customColors = parsed.map((c) => ({
|
|
76
|
+
name: c.name,
|
|
77
|
+
hex: c.hex,
|
|
78
|
+
blend: c.blend ?? DEFAULT_BLEND,
|
|
79
|
+
}));
|
|
80
|
+
} catch {
|
|
81
|
+
console.error("Error: --custom-colors must be valid JSON");
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const result = builder(source, {
|
|
87
|
+
scheme: opts.scheme,
|
|
88
|
+
contrast: opts.contrast,
|
|
89
|
+
primary: opts.primary,
|
|
90
|
+
secondary: opts.secondary,
|
|
91
|
+
tertiary: opts.tertiary,
|
|
92
|
+
error: opts.error,
|
|
93
|
+
neutral: opts.neutral,
|
|
94
|
+
neutralVariant: opts.neutralVariant,
|
|
95
|
+
customColors,
|
|
96
|
+
adaptiveShades: opts.adaptiveShades,
|
|
97
|
+
contrastAllColors: opts.contrastAllColors,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
if (opts.format === "css") {
|
|
101
|
+
process.stdout.write(result.toCss());
|
|
102
|
+
} else if (opts.format === "figma") {
|
|
103
|
+
const outputDir = opts.output ?? "mcu-theme";
|
|
104
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
105
|
+
const files = result.toFigmaTokens();
|
|
106
|
+
for (const [filename, content] of Object.entries(files)) {
|
|
107
|
+
const filePath = path.join(outputDir, filename);
|
|
108
|
+
fs.writeFileSync(filePath, JSON.stringify(content, null, 2) + "\n");
|
|
109
|
+
console.error(`wrote ${filePath}`);
|
|
110
|
+
}
|
|
111
|
+
} else {
|
|
112
|
+
process.stdout.write(JSON.stringify(result.toJson(), null, 2) + "\n");
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
program.parse();
|