@cmotino/cm-web-components 0.1.0 → 0.2.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 CHANGED
@@ -13,8 +13,7 @@ A React component library built on Material UI.
13
13
  `CmThemeProvider` applies the default look. Use `createCmTheme` to override it for your project:
14
14
 
15
15
  ```tsx
16
- import Button from '@mui/material/Button'
17
- import { CmThemeProvider, createCmTheme } from '@cmotino/cm-web-components'
16
+ import { Button, CmThemeProvider, createCmTheme } from '@cmotino/cm-web-components'
18
17
 
19
18
  const theme = createCmTheme({
20
19
  palette: { primary: { main: '#0b6e4f' } },
@@ -45,7 +44,41 @@ createCmTheme({
45
44
  createCmTheme({ cssVariables: { colorSchemeSelector: 'class' } })
46
45
  ```
47
46
 
48
- `CmThemeProvider` adds no global styles. Pass `baseline` to include MUI's `CssBaseline`. Fonts are up to your project.
47
+ `CmThemeProvider` adds no global styles. Pass `baseline` to include MUI's `CssBaseline`. The theme uses `Inter, sans-serif` but doesn't load the font, so load Inter in your project, for example with `@fontsource/inter`.
48
+
49
+ **The default theme turns on MUI's keyboard focus ring for every MUI component.** Change it with `focusVisible`, or turn it off with `false`:
50
+
51
+ ```ts
52
+ createCmTheme({ focusVisible: { outlineColor: '#0b6e4f' } })
53
+ createCmTheme({ focusVisible: false })
54
+ ```
55
+
56
+ ## Button
57
+
58
+ `Button` is MUI's `Button` with the library's default look: no uppercase text, no elevation and a keyboard focus ring. Every MUI prop works, including `loading`, `startIcon` and `component`:
59
+
60
+ ```tsx
61
+ import { Button } from '@cmotino/cm-web-components'
62
+ import { Link as RouterLink } from 'react-router'
63
+
64
+ <Button variant="contained" loading={isSaving} onClick={handleSave}>Save</Button>
65
+
66
+ <Button component={RouterLink} to="/settings">Settings</Button>
67
+ ```
68
+
69
+ **Use an object for `styleOverrides.root`.** An object merges with the library defaults. A function replaces them, so the label goes back to uppercase unless the function sets `textTransform` itself:
70
+
71
+ ```ts
72
+ createCmTheme({
73
+ components: {
74
+ MuiButton: { styleOverrides: { root: { fontWeight: 700 } } },
75
+ },
76
+ })
77
+ ```
78
+
79
+ **`ButtonProps` describes the `<button>` form only.** A wrapper of your own around the link form needs to declare link props such as `target` itself.
80
+
81
+ The look comes from the theme, so without `CmThemeProvider` a `Button` renders with the surrounding MUI theme, and MUI's own `Button` used under the library theme gets the library look.
49
82
 
50
83
  ## Development
51
84
 
@@ -0,0 +1,2 @@
1
+ export { default as Button } from '@mui/material/Button';
2
+ export type { ButtonProps } from '@mui/material/Button';
@@ -0,0 +1 @@
1
+ export { default as Button } from "@mui/material/Button";
package/dist/index.d.ts CHANGED
@@ -1 +1,2 @@
1
+ export * from './components/Button/index.ts';
1
2
  export * from './theme/index.ts';
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { Button } from "./components/Button/index.js";
1
2
  import { createCmTheme } from "./theme/createCmTheme.js";
2
3
  import { CmThemeProvider } from "./theme/CmThemeProvider.js";
3
- export { CmThemeProvider, createCmTheme };
4
+ export { Button, CmThemeProvider, createCmTheme };
@@ -1,4 +1,13 @@
1
1
  import type { Theme, ThemeOptions } from '@mui/material/styles';
2
+ declare module '@mui/material/styles' {
3
+ interface Palette {
4
+ /** The shadow of `shadows[1]`, set per color scheme. */
5
+ baseShadow: string;
6
+ }
7
+ interface PaletteOptions {
8
+ baseShadow?: string;
9
+ }
10
+ }
2
11
  /**
3
12
  * Creates a theme from the library defaults and a project's overrides.
4
13
  *
@@ -1,7 +1,22 @@
1
1
  import { defaultThemeOptions } from "./defaultTheme.js";
2
+ import { baseShadow } from "./tokens.js";
2
3
  import { createTheme } from "@mui/material/styles";
3
4
  import deepmerge from "@mui/utils/deepmerge";
4
5
  // src/theme/createCmTheme.ts
6
+ var muiShadows;
7
+ /**
8
+ * MUI's shadows, with `shadows[1]` replaced by the color scheme's `baseShadow`.
9
+ * Shadows can't differ between color schemes, so the CSS variable does that.
10
+ */
11
+ function createShadows(options) {
12
+ const { cssVariables } = options;
13
+ const prefix = typeof cssVariables === "object" ? cssVariables.cssVarPrefix ?? "mui" : "mui";
14
+ const name = prefix ? `--${prefix}-palette-baseShadow` : "--palette-baseShadow";
15
+ muiShadows ??= createTheme().shadows;
16
+ const shadows = muiShadows.slice();
17
+ shadows[1] = `var(${name}, ${baseShadow.light})`;
18
+ return shadows;
19
+ }
5
20
  /**
6
21
  * Creates a theme from the library defaults and a project's overrides.
7
22
  *
@@ -12,6 +27,8 @@ import deepmerge from "@mui/utils/deepmerge";
12
27
  * schemes defined, `createTheme(defaults, overrides)` silently ignores them.
13
28
  */
14
29
  function createCmTheme(overrides = {}) {
15
- return createTheme(deepmerge(defaultThemeOptions, overrides));
30
+ const options = deepmerge(defaultThemeOptions, overrides);
31
+ options.shadows ??= createShadows(options);
32
+ return createTheme(options);
16
33
  }
17
34
  export { createCmTheme };
@@ -1,9 +1,148 @@
1
+ import { baseShadow, brand, gray, green, orange, red } from "./tokens.js";
2
+ import { alpha } from "@mui/material/styles";
1
3
  // src/theme/defaultTheme.ts
2
4
  var defaultThemeOptions = {
3
5
  cssVariables: true,
4
6
  colorSchemes: {
5
- light: true,
6
- dark: true
7
- }
7
+ light: { palette: {
8
+ primary: {
9
+ light: brand[200],
10
+ main: brand[400],
11
+ dark: brand[700],
12
+ contrastText: brand[50]
13
+ },
14
+ info: {
15
+ light: brand[100],
16
+ main: brand[300],
17
+ dark: brand[600],
18
+ contrastText: gray[50]
19
+ },
20
+ warning: {
21
+ light: orange[300],
22
+ main: orange[400],
23
+ dark: orange[800]
24
+ },
25
+ error: {
26
+ light: red[300],
27
+ main: red[400],
28
+ dark: red[800]
29
+ },
30
+ success: {
31
+ light: green[300],
32
+ main: green[400],
33
+ dark: green[800]
34
+ },
35
+ grey: { ...gray },
36
+ divider: alpha(gray[300], .4),
37
+ background: {
38
+ default: "hsl(0, 0%, 99%)",
39
+ paper: "hsl(220, 35%, 97%)"
40
+ },
41
+ text: {
42
+ primary: gray[800],
43
+ secondary: gray[600]
44
+ },
45
+ action: {
46
+ hover: alpha(gray[200], .2),
47
+ selected: alpha(gray[200], .3)
48
+ },
49
+ baseShadow: baseShadow.light
50
+ } },
51
+ dark: { palette: {
52
+ primary: {
53
+ light: brand[300],
54
+ main: brand[400],
55
+ dark: brand[700],
56
+ contrastText: brand[50]
57
+ },
58
+ info: {
59
+ light: brand[500],
60
+ main: brand[700],
61
+ dark: brand[900],
62
+ contrastText: brand[300]
63
+ },
64
+ warning: {
65
+ light: orange[400],
66
+ main: orange[500],
67
+ dark: orange[700]
68
+ },
69
+ error: {
70
+ light: red[400],
71
+ main: red[500],
72
+ dark: red[700]
73
+ },
74
+ success: {
75
+ light: green[400],
76
+ main: green[500],
77
+ dark: green[700]
78
+ },
79
+ grey: { ...gray },
80
+ divider: alpha(gray[700], .6),
81
+ background: {
82
+ default: gray[900],
83
+ paper: "hsl(220, 30%, 7%)"
84
+ },
85
+ text: {
86
+ primary: "hsl(0, 0%, 100%)",
87
+ secondary: gray[400]
88
+ },
89
+ action: {
90
+ hover: alpha(gray[600], .2),
91
+ selected: alpha(gray[600], .3)
92
+ },
93
+ baseShadow: baseShadow.dark
94
+ } }
95
+ },
96
+ typography: {
97
+ fontFamily: "Inter, sans-serif",
98
+ h1: {
99
+ fontSize: "3rem",
100
+ fontWeight: 600,
101
+ lineHeight: 1.2,
102
+ letterSpacing: -.5
103
+ },
104
+ h2: {
105
+ fontSize: "2.25rem",
106
+ fontWeight: 600,
107
+ lineHeight: 1.2
108
+ },
109
+ h3: {
110
+ fontSize: "1.875rem",
111
+ lineHeight: 1.2
112
+ },
113
+ h4: {
114
+ fontSize: "1.5rem",
115
+ fontWeight: 600,
116
+ lineHeight: 1.5
117
+ },
118
+ h5: {
119
+ fontSize: "1.25rem",
120
+ fontWeight: 600
121
+ },
122
+ h6: {
123
+ fontSize: "1.125rem",
124
+ fontWeight: 600
125
+ },
126
+ subtitle1: { fontSize: "1.125rem" },
127
+ subtitle2: {
128
+ fontSize: "0.875rem",
129
+ fontWeight: 500
130
+ },
131
+ body1: { fontSize: "0.875rem" },
132
+ body2: {
133
+ fontSize: "0.875rem",
134
+ fontWeight: 400
135
+ },
136
+ caption: {
137
+ fontSize: "0.75rem",
138
+ fontWeight: 400
139
+ }
140
+ },
141
+ shape: { borderRadius: 8 },
142
+ focusVisible: true,
143
+ components: { MuiButton: {
144
+ defaultProps: { disableElevation: true },
145
+ styleOverrides: { root: { textTransform: "none" } }
146
+ } }
8
147
  };
9
148
  export { defaultThemeOptions };
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Color scales for the default theme, taken from `references/theme/themePrimitives.ts`.
3
+ * They're private: components read colors from the theme, never from here.
4
+ */
5
+ export declare const brand: {
6
+ 50: string;
7
+ 100: string;
8
+ 200: string;
9
+ 300: string;
10
+ 400: string;
11
+ 500: string;
12
+ 600: string;
13
+ 700: string;
14
+ 800: string;
15
+ 900: string;
16
+ };
17
+ export declare const gray: {
18
+ 50: string;
19
+ 100: string;
20
+ 200: string;
21
+ 300: string;
22
+ 400: string;
23
+ 500: string;
24
+ 600: string;
25
+ 700: string;
26
+ 800: string;
27
+ 900: string;
28
+ };
29
+ export declare const green: {
30
+ 50: string;
31
+ 100: string;
32
+ 200: string;
33
+ 300: string;
34
+ 400: string;
35
+ 500: string;
36
+ 600: string;
37
+ 700: string;
38
+ 800: string;
39
+ 900: string;
40
+ };
41
+ export declare const orange: {
42
+ 50: string;
43
+ 100: string;
44
+ 200: string;
45
+ 300: string;
46
+ 400: string;
47
+ 500: string;
48
+ 600: string;
49
+ 700: string;
50
+ 800: string;
51
+ 900: string;
52
+ };
53
+ export declare const red: {
54
+ 50: string;
55
+ 100: string;
56
+ 200: string;
57
+ 300: string;
58
+ 400: string;
59
+ 500: string;
60
+ 600: string;
61
+ 700: string;
62
+ 800: string;
63
+ 900: string;
64
+ };
65
+ export declare const baseShadow: {
66
+ light: string;
67
+ dark: string;
68
+ };
@@ -0,0 +1,70 @@
1
+ // src/theme/tokens.ts
2
+ /**
3
+ * Color scales for the default theme, taken from `references/theme/themePrimitives.ts`.
4
+ * They're private: components read colors from the theme, never from here.
5
+ */
6
+ var brand = {
7
+ 50: "hsl(210, 100%, 95%)",
8
+ 100: "hsl(210, 100%, 92%)",
9
+ 200: "hsl(210, 100%, 80%)",
10
+ 300: "hsl(210, 100%, 65%)",
11
+ 400: "hsl(210, 98%, 48%)",
12
+ 500: "hsl(210, 98%, 42%)",
13
+ 600: "hsl(210, 98%, 55%)",
14
+ 700: "hsl(210, 100%, 35%)",
15
+ 800: "hsl(210, 100%, 16%)",
16
+ 900: "hsl(210, 100%, 21%)"
17
+ };
18
+ var gray = {
19
+ 50: "hsl(220, 35%, 97%)",
20
+ 100: "hsl(220, 30%, 94%)",
21
+ 200: "hsl(220, 20%, 88%)",
22
+ 300: "hsl(220, 20%, 80%)",
23
+ 400: "hsl(220, 20%, 65%)",
24
+ 500: "hsl(220, 20%, 42%)",
25
+ 600: "hsl(220, 20%, 35%)",
26
+ 700: "hsl(220, 20%, 25%)",
27
+ 800: "hsl(220, 30%, 6%)",
28
+ 900: "hsl(220, 35%, 3%)"
29
+ };
30
+ var green = {
31
+ 50: "hsl(120, 80%, 98%)",
32
+ 100: "hsl(120, 75%, 94%)",
33
+ 200: "hsl(120, 75%, 87%)",
34
+ 300: "hsl(120, 61%, 77%)",
35
+ 400: "hsl(120, 44%, 53%)",
36
+ 500: "hsl(120, 59%, 30%)",
37
+ 600: "hsl(120, 70%, 25%)",
38
+ 700: "hsl(120, 75%, 16%)",
39
+ 800: "hsl(120, 84%, 10%)",
40
+ 900: "hsl(120, 87%, 6%)"
41
+ };
42
+ var orange = {
43
+ 50: "hsl(45, 100%, 97%)",
44
+ 100: "hsl(45, 92%, 90%)",
45
+ 200: "hsl(45, 94%, 80%)",
46
+ 300: "hsl(45, 90%, 65%)",
47
+ 400: "hsl(45, 90%, 40%)",
48
+ 500: "hsl(45, 90%, 35%)",
49
+ 600: "hsl(45, 91%, 25%)",
50
+ 700: "hsl(45, 94%, 20%)",
51
+ 800: "hsl(45, 95%, 16%)",
52
+ 900: "hsl(45, 93%, 12%)"
53
+ };
54
+ var red = {
55
+ 50: "hsl(0, 100%, 97%)",
56
+ 100: "hsl(0, 92%, 90%)",
57
+ 200: "hsl(0, 94%, 80%)",
58
+ 300: "hsl(0, 90%, 65%)",
59
+ 400: "hsl(0, 90%, 40%)",
60
+ 500: "hsl(0, 90%, 30%)",
61
+ 600: "hsl(0, 91%, 25%)",
62
+ 700: "hsl(0, 94%, 18%)",
63
+ 800: "hsl(0, 95%, 12%)",
64
+ 900: "hsl(0, 93%, 6%)"
65
+ };
66
+ var baseShadow = {
67
+ light: "hsla(220, 30%, 5%, 0.07) 0px 4px 16px 0px, hsla(220, 25%, 10%, 0.07) 0px 8px 16px -5px",
68
+ dark: "hsla(220, 30%, 5%, 0.7) 0px 4px 16px 0px, hsla(220, 25%, 10%, 0.8) 0px 8px 16px -5px"
69
+ };
70
+ export { baseShadow, brand, gray, green, orange, red };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cmotino/cm-web-components",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "storybook dev -p 6006",
@@ -20,7 +20,7 @@
20
20
  "@emotion/react": "^11.14.0",
21
21
  "@emotion/styled": "^11.14.1",
22
22
  "@eslint/js": "^10.0.1",
23
- "@fontsource/roboto": "^5.3.0",
23
+ "@fontsource/inter": "^5.3.0",
24
24
  "@mui/icons-material": "^9.5.0",
25
25
  "@mui/material": "^9.5.0",
26
26
  "@rolldown/plugin-babel": "^0.3.0",