react-mcu 1.0.1 → 1.0.3

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 CHANGED
@@ -1,43 +1,141 @@
1
- # react-mcu
2
-
3
1
  [![npm version](https://img.shields.io/npm/v/react-mcu.svg)](https://www.npmjs.com/package/react-mcu)
2
+ [![](https://img.shields.io/badge/chromatic-171c23.svg?logo=chromatic)](https://www.chromatic.com/library?appId=695eb517cb602e59b4cc045c&branch=main)
3
+ [![](https://img.shields.io/badge/storybook-171c23.svg?logo=storybook)](https://main--695eb517cb602e59b4cc045c.chromatic.com)
4
4
 
5
- A React component library.
6
-
7
- ## Installation
5
+ It injects `--mcu-*` CSS variables into the page, based on
6
+ [m3 color system](https://m3.material.io/styles/color/roles).
8
7
 
9
- ```bash
10
- npm install react-mcu
11
- ```
8
+ https://material-foundation.github.io/material-theme-builder/
12
9
 
13
- ## Usage
10
+ # Usage
14
11
 
15
12
  ```tsx
16
13
  import { Mcu } from "react-mcu";
17
14
 
18
- function App() {
19
- return <Mcu />;
20
- }
15
+ <Mcu
16
+ source="#0e1216"
17
+ scheme="vibrant"
18
+ contrast={0.5}
19
+ customColors={[
20
+ { name: "myCustomColor1", hex: "#FF5733", blend: true },
21
+ { name: "myCustomColor2", hex: "#3498DB", blend: false },
22
+ ]}
23
+ >
24
+ <p style={{
25
+ backgroundColor: "var(--mcu-surface)",
26
+ color: "var(--mcu-on-surface)",
27
+ }}>
28
+ Hello, MCU <span style={{
29
+ backgroundColor: "var(--mcu-my-custom-color1)",
30
+ color: "var(--mcu-my-custom-color2)",
31
+ }}>colors<span>!
32
+ </p>
33
+ </Mcu>
21
34
  ```
22
35
 
23
- ## Components
24
-
25
- ### Mcu
36
+ https://github.com/user-attachments/assets/5b67c961-d7a4-4b64-9356-4ada26bc9be4
26
37
 
27
- A simple component that renders "Hello World".
38
+ A `useMcu` hook is also provided:
28
39
 
29
40
  ```tsx
30
- <Mcu />
41
+ import { useMcu } from "react-mcu";
42
+
43
+ const { initials, setMcuConfig, getMcuColor } = useMcu();
44
+
45
+ return (
46
+ <button onClick={() => setMcuConfig({ ...initials, source: "#FF5722" })}>
47
+ Change to {getMcuColor("primary", "light")}
48
+ </button>
49
+ );
31
50
  ```
32
51
 
33
- ## Contributing
52
+ ## Tailwind
53
+
54
+ Compatible with Tailwind through
55
+ [theme variables](https://tailwindcss.com/docs/theme):
56
+
57
+ ```css
58
+ @theme {
59
+ --color-background: var(--mcu-background);
60
+ --color-on-background: var(--mcu-on-background);
61
+ --color-surface: var(--mcu-surface);
62
+ --color-surface-dim: var(--mcu-surface-dim);
63
+ --color-surface-bright: var(--mcu-surface-bright);
64
+ --color-surface-container-lowest: var(--mcu-surface-container-lowest);
65
+ --color-surface-container-low: var(--mcu-surface-container-low);
66
+ --color-surface-container: var(--mcu-surface-container);
67
+ --color-surface-container-high: var(--mcu-surface-container-high);
68
+ --color-surface-container-highest: var(--mcu-surface-container-highest);
69
+ --color-on-surface: var(--mcu-on-surface);
70
+ --color-on-surface-variant: var(--mcu-on-surface-variant);
71
+ --color-outline: var(--mcu-outline);
72
+ --color-outline-variant: var(--mcu-outline-variant);
73
+ --color-inverse-surface: var(--mcu-inverse-surface);
74
+ --color-inverse-on-surface: var(--mcu-inverse-on-surface);
75
+ --color-primary: var(--mcu-primary);
76
+ --color-on-primary: var(--mcu-on-primary);
77
+ --color-primary-container: var(--mcu-primary-container);
78
+ --color-on-primary-container: var(--mcu-on-primary-container);
79
+ --color-primary-fixed: var(--mcu-primary-fixed);
80
+ --color-primary-fixed-dim: var(--mcu-primary-fixed-dim);
81
+ --color-on-primary-fixed: var(--mcu-on-primary-fixed);
82
+ --color-on-primary-fixed-variant: var(--mcu-on-primary-fixed-variant);
83
+ --color-inverse-primary: var(--mcu-inverse-primary);
84
+ --color-secondary: var(--mcu-secondary);
85
+ --color-on-secondary: var(--mcu-on-secondary);
86
+ --color-secondary-container: var(--mcu-secondary-container);
87
+ --color-on-secondary-container: var(--mcu-on-secondary-container);
88
+ --color-secondary-fixed: var(--mcu-secondary-fixed);
89
+ --color-secondary-fixed-dim: var(--mcu-secondary-fixed-dim);
90
+ --color-on-secondary-fixed: var(--mcu-on-secondary-fixed);
91
+ --color-on-secondary-fixed-variant: var(--mcu-on-secondary-fixed-variant);
92
+ --color-tertiary: var(--mcu-tertiary);
93
+ --color-on-tertiary: var(--mcu-on-tertiary);
94
+ --color-tertiary-container: var(--mcu-tertiary-container);
95
+ --color-on-tertiary-container: var(--mcu-on-tertiary-container);
96
+ --color-tertiary-fixed: var(--mcu-tertiary-fixed);
97
+ --color-tertiary-fixed-dim: var(--mcu-tertiary-fixed-dim);
98
+ --color-on-tertiary-fixed: var(--mcu-on-tertiary-fixed);
99
+ --color-on-tertiary-fixed-variant: var(--mcu-on-tertiary-fixed-variant);
100
+ --color-error: var(--mcu-error);
101
+ --color-on-error: var(--mcu-on-error);
102
+ --color-error-container: var(--mcu-error-container);
103
+ --color-on-error-container: var(--mcu-on-error-container);
104
+ }
105
+ ```
34
106
 
35
- When submitting a pull request, please include a changeset to document your changes:
107
+ # Dev
108
+
109
+ ## INSTALL
110
+
111
+ Pre-requisites:
112
+
113
+ - Install [nvm](https://github.com/nvm-sh/nvm), then:
114
+ ```sh
115
+ $ nvm install
116
+ $ nvm use
117
+ $ node -v # make sure your version satisfies package.json#engines.node
118
+ ```
119
+ nb: if you want this node version to be your default nvm's one:
120
+ `nvm alias default node`
121
+ - Install pnpm, with:
122
+ ```sh
123
+ $ corepack enable
124
+ $ corepack prepare --activate # it reads "packageManager"
125
+ $ pnpm -v # make sure your version satisfies package.json#engines.pnpm
126
+ ```
127
+
128
+ ```sh
129
+ $ pnpm i
130
+ ```
131
+
132
+ ## CONTRIBUTING
133
+
134
+ When submitting a pull request, please include a changeset to document your
135
+ changes:
36
136
 
37
137
  ```bash
38
- pnpm dlx changeset
138
+ pnpm exec changeset
39
139
  ```
40
140
 
41
141
  This helps us maintain the changelog and version the package appropriately.
42
-
43
- bump02
package/dist/index.d.ts CHANGED
@@ -1,5 +1,28 @@
1
- interface McuProps {
2
- }
3
- declare const Mcu: React.FC<McuProps>;
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { SchemeTonalSpot, SchemeMonochrome, SchemeNeutral, SchemeVibrant, SchemeExpressive, SchemeFidelity, SchemeContent, CustomColor } from '@material/material-color-utilities';
4
3
 
5
- export { Mcu, type McuProps };
4
+ type HexCustomColor = Omit<CustomColor, "value"> & {
5
+ hex: string;
6
+ };
7
+ type McuConfig = {
8
+ source: string;
9
+ scheme: SchemeName;
10
+ contrast: number;
11
+ customColors: HexCustomColor[];
12
+ };
13
+ declare const schemesMap: {
14
+ readonly tonalSpot: typeof SchemeTonalSpot;
15
+ readonly monochrome: typeof SchemeMonochrome;
16
+ readonly neutral: typeof SchemeNeutral;
17
+ readonly vibrant: typeof SchemeVibrant;
18
+ readonly expressive: typeof SchemeExpressive;
19
+ readonly fidelity: typeof SchemeFidelity;
20
+ readonly content: typeof SchemeContent;
21
+ };
22
+ declare const schemeNames: (keyof typeof schemesMap)[];
23
+ type SchemeName = (typeof schemeNames)[number];
24
+ declare function Mcu({ source, scheme, contrast, customColors, children, }: McuConfig & {
25
+ children: React.ReactNode;
26
+ }): react_jsx_runtime.JSX.Element;
27
+
28
+ export { Mcu };
package/dist/index.js CHANGED
@@ -1,8 +1,248 @@
1
1
  // src/Mcu.tsx
2
+ import {
3
+ argbFromHex,
4
+ Hct,
5
+ hexFromArgb as hexFromArgb2,
6
+ MaterialDynamicColors,
7
+ SchemeContent,
8
+ SchemeExpressive,
9
+ SchemeFidelity,
10
+ SchemeMonochrome,
11
+ SchemeNeutral,
12
+ SchemeTonalSpot,
13
+ SchemeVibrant
14
+ } from "@material/material-color-utilities";
15
+ import { kebabCase } from "lodash-es";
16
+ import { useMemo as useMemo2 } from "react";
17
+
18
+ // src/Mcu.context.tsx
19
+ import { hexFromArgb } from "@material/material-color-utilities";
20
+ import {
21
+ useCallback,
22
+ useInsertionEffect,
23
+ useMemo,
24
+ useState
25
+ } from "react";
26
+
27
+ // src/lib/createRequiredContext.ts
28
+ import { createContext, useContext } from "react";
29
+ var createRequiredContext = () => {
30
+ const Ctx = createContext(null);
31
+ const useCtx = () => {
32
+ const contextValue = useContext(Ctx);
33
+ if (contextValue === null) {
34
+ throw new Error("Context value is null");
35
+ }
36
+ return contextValue;
37
+ };
38
+ return [useCtx, Ctx.Provider, Ctx];
39
+ };
40
+
41
+ // src/Mcu.context.tsx
2
42
  import { jsx } from "react/jsx-runtime";
3
- var Mcu = () => {
4
- return /* @__PURE__ */ jsx("div", { children: "hello react-mcu" });
43
+ var [useMcu, Provider, McuContext] = createRequiredContext();
44
+ var McuProvider = ({
45
+ source: initialSource,
46
+ scheme: initialScheme,
47
+ contrast: initialContrast,
48
+ customColors: initialCustomColors,
49
+ styleId,
50
+ children
51
+ }) => {
52
+ const [initials] = useState(() => ({
53
+ source: initialSource,
54
+ scheme: initialScheme,
55
+ contrast: initialContrast,
56
+ customColors: initialCustomColors
57
+ }));
58
+ const [mcuConfig, setMcuConfig] = useState(initials);
59
+ const { css, mergedColorsLight, mergedColorsDark } = useMemo(
60
+ () => generateCss(mcuConfig),
61
+ [mcuConfig]
62
+ );
63
+ useInsertionEffect(() => {
64
+ let tag = document.getElementById(styleId);
65
+ if (!tag) {
66
+ tag = document.createElement("style");
67
+ tag.id = styleId;
68
+ document.head.appendChild(tag);
69
+ }
70
+ tag.textContent = css;
71
+ }, [css, styleId]);
72
+ const getMcuColor = useCallback(
73
+ (colorName, theme) => {
74
+ return hexFromArgb(
75
+ (theme === "light" ? mergedColorsLight : mergedColorsDark)[colorName]
76
+ );
77
+ },
78
+ [mergedColorsDark, mergedColorsLight]
79
+ );
80
+ const value = useMemo(
81
+ () => ({
82
+ initials,
83
+ setMcuConfig,
84
+ getMcuColor
85
+ }),
86
+ [getMcuColor, initials]
87
+ );
88
+ return /* @__PURE__ */ jsx(Provider, { value, children });
89
+ };
90
+
91
+ // src/Mcu.tsx
92
+ import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
93
+ var schemesMap = {
94
+ tonalSpot: SchemeTonalSpot,
95
+ monochrome: SchemeMonochrome,
96
+ neutral: SchemeNeutral,
97
+ vibrant: SchemeVibrant,
98
+ expressive: SchemeExpressive,
99
+ fidelity: SchemeFidelity,
100
+ content: SchemeContent
101
+ };
102
+ var schemeNames = Object.keys(
103
+ schemesMap
104
+ );
105
+ var mcuStyleId = "mcu-styles";
106
+ function Mcu({
107
+ source,
108
+ scheme,
109
+ contrast,
110
+ customColors,
111
+ children
112
+ }) {
113
+ const config = useMemo2(
114
+ () => ({
115
+ source,
116
+ scheme,
117
+ contrast,
118
+ customColors
119
+ }),
120
+ [contrast, customColors, scheme, source]
121
+ );
122
+ const { css } = useMemo2(() => generateCss(config), [config]);
123
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
124
+ /* @__PURE__ */ jsx2("style", { id: mcuStyleId, children: css }),
125
+ /* @__PURE__ */ jsx2(McuProvider, { ...config, styleId: mcuStyleId, children })
126
+ ] });
127
+ }
128
+ var tokenNames = [
129
+ "background",
130
+ "onBackground",
131
+ "surface",
132
+ "surfaceDim",
133
+ "surfaceBright",
134
+ "surfaceContainerLowest",
135
+ "surfaceContainerLow",
136
+ "surfaceContainer",
137
+ "surfaceContainerHigh",
138
+ "surfaceContainerHighest",
139
+ "onSurface",
140
+ "onSurfaceVariant",
141
+ "outline",
142
+ "outlineVariant",
143
+ "inverseSurface",
144
+ "inverseOnSurface",
145
+ "primary",
146
+ // "primaryDim",
147
+ "onPrimary",
148
+ "primaryContainer",
149
+ "onPrimaryContainer",
150
+ "primaryFixed",
151
+ "primaryFixedDim",
152
+ "onPrimaryFixed",
153
+ "onPrimaryFixedVariant",
154
+ "inversePrimary",
155
+ "primaryFixed",
156
+ "primaryFixedDim",
157
+ "onPrimaryFixed",
158
+ "onPrimaryFixedVariant",
159
+ "secondary",
160
+ // "secondaryDim",
161
+ "onSecondary",
162
+ "secondaryContainer",
163
+ "onSecondaryContainer",
164
+ "secondaryFixed",
165
+ "secondaryFixedDim",
166
+ "onSecondaryFixed",
167
+ "onSecondaryFixedVariant",
168
+ "tertiary",
169
+ // "tertiaryDim",
170
+ "onTertiary",
171
+ "tertiaryContainer",
172
+ "onTertiaryContainer",
173
+ "tertiaryFixed",
174
+ "tertiaryFixedDim",
175
+ "onTertiaryFixed",
176
+ "onTertiaryFixedVariant",
177
+ "error",
178
+ // "errorDim",
179
+ "onError",
180
+ "errorContainer",
181
+ "onErrorContainer",
182
+ "scrim",
183
+ // added manually, was missing
184
+ "shadow"
185
+ // added manually, was missing
186
+ ];
187
+ function toRecord(arr, getEntry) {
188
+ return arr.reduce(
189
+ (acc, item) => {
190
+ const [key, value] = getEntry(item);
191
+ acc[key] = value;
192
+ return acc;
193
+ },
194
+ {}
195
+ );
196
+ }
197
+ function mergeBaseAndCustomColors(scheme, customColors) {
198
+ const baseVars = toRecord(tokenNames, (tokenName) => {
199
+ const dynamicColor = MaterialDynamicColors[tokenName];
200
+ const argb = dynamicColor.getArgb(scheme);
201
+ return [tokenName, argb];
202
+ });
203
+ const customVars = toRecord(customColors, (color) => [
204
+ color.name,
205
+ color.value
206
+ ]);
207
+ return { ...baseVars, ...customVars };
208
+ }
209
+ var cssVar = (colorName, colorValue) => {
210
+ const name = `--mcu-${kebabCase(colorName)}`;
211
+ const value = hexFromArgb2(colorValue);
212
+ return `${name}:${value};`;
213
+ };
214
+ var toCssVars = (mergedColors) => {
215
+ return Object.entries(mergedColors).map(([name, value]) => cssVar(name, value)).join(" ");
5
216
  };
217
+ function generateCss({
218
+ source: hexSource,
219
+ customColors: hexCustomColors,
220
+ scheme,
221
+ contrast
222
+ }) {
223
+ console.log("MCU generateCss");
224
+ const sourceArgb = argbFromHex(hexSource);
225
+ const hct = Hct.fromInt(sourceArgb);
226
+ const SchemeClass = schemesMap[scheme];
227
+ const lightScheme = new SchemeClass(hct, false, contrast);
228
+ const darkScheme = new SchemeClass(hct, true, contrast);
229
+ const customColors = hexCustomColors.map(({ hex, ...rest }) => ({
230
+ ...rest,
231
+ value: argbFromHex(hex)
232
+ }));
233
+ const mergedColorsLight = mergeBaseAndCustomColors(lightScheme, customColors);
234
+ const mergedColorsDark = mergeBaseAndCustomColors(darkScheme, customColors);
235
+ const lightVars = toCssVars(mergedColorsLight);
236
+ const darkVars = toCssVars(mergedColorsDark);
237
+ return {
238
+ css: `
239
+ :root { ${lightVars} }
240
+ .dark { ${darkVars} }
241
+ `,
242
+ mergedColorsLight,
243
+ mergedColorsDark
244
+ };
245
+ }
6
246
  export {
7
247
  Mcu
8
248
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-mcu",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "A React component library",
5
5
  "keywords": [
6
6
  "react",
@@ -28,25 +28,35 @@
28
28
  ],
29
29
  "type": "module",
30
30
  "devDependencies": {
31
- "@arethetypeswrong/cli": "^0.15.4",
31
+ "@arethetypeswrong/cli": "^0.18.2",
32
32
  "@changesets/cli": "^2.27.7",
33
+ "@storybook/react-vite": "^10.1.11",
33
34
  "@testing-library/dom": "^10.4.1",
34
35
  "@testing-library/react": "^16.3.1",
36
+ "@types/lodash-es": "^4.17.12",
35
37
  "@types/react": "^19.2.7",
36
38
  "@types/react-dom": "^19.2.3",
37
39
  "@vitejs/plugin-react": "^5.1.2",
40
+ "chromatic": "^13.3.5",
41
+ "husky": "^9.1.7",
38
42
  "jsdom": "^27.4.0",
43
+ "lint-staged": "^16.2.7",
39
44
  "prettier": "^3.3.3",
40
45
  "react": "^19.2.3",
41
46
  "react-dom": "^19.2.3",
47
+ "storybook": "^10.1.11",
42
48
  "tsup": "^8.2.4",
43
49
  "typescript": "^5.5.4",
44
- "vitest": "^2.0.5"
50
+ "vitest": "^4.0.16"
45
51
  },
46
52
  "peerDependencies": {
47
53
  "react": "^19.2.3",
48
54
  "react-dom": "^19.2.3"
49
55
  },
56
+ "dependencies": {
57
+ "@material/material-color-utilities": "^0.3.0",
58
+ "lodash-es": "^4.17.22"
59
+ },
50
60
  "scripts": {
51
61
  "build": "tsup",
52
62
  "ci": "pnpm run build && pnpm run check-format && pnpm run check-exports && pnpm run lint && pnpm run test",
@@ -56,6 +66,9 @@
56
66
  "check-format": "prettier --check .",
57
67
  "check-exports": "attw --pack . --ignore-rules cjs-resolves-to-esm no-resolution",
58
68
  "release": "pnpm run build && changeset publish",
59
- "local-release": "pnpm run ci && changeset version && changeset publish"
69
+ "local-release": "pnpm run ci && changeset version && changeset publish",
70
+ "storybook": "storybook dev -p 6006",
71
+ "build-storybook": "storybook build",
72
+ "chromatic": "chromatic --project-token $CHROMATIC_PROJECT_TOKEN"
60
73
  }
61
74
  }