@linagora/twake-mui 5.1.0 → 5.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.
@@ -61,13 +61,22 @@ export const makePalette = (mode = 'light', palette = paletteData) => {
61
61
  text: {
62
62
  primary: palette.Common.white,
63
63
  secondary: alpha(palette.Common.white, 0.64),
64
- disabled: alpha(palette.Common.white, 0.4)
64
+ disabled: alpha(palette.Common.white, 0.4),
65
+ icon: palette.Common.white
65
66
  },
66
67
  background: {
67
68
  default: palette.Grey.A400,
68
69
  paper: palette.Grey[800],
69
70
  contrast: alpha(palette.Common.white, 0.072)
70
71
  },
72
+ border: {
73
+ main: alpha(palette.Common.white, 0.24),
74
+ disabled: alpha(palette.Common.white, 0.12),
75
+ ghost: alpha(palette.Common.white, 0.48),
76
+ ghostDisabled: alpha(palette.Common.white, 0.24),
77
+ opacity: 0.48,
78
+ ghostOpacity: 0.48
79
+ },
71
80
  divider: alpha(palette.Common.white, 0.16),
72
81
  action: {
73
82
  active: palette.Common.white,
@@ -142,13 +151,22 @@ export const makePalette = (mode = 'light', palette = paletteData) => {
142
151
  text: {
143
152
  primary: alpha(palette.Grey[900], 0.9),
144
153
  secondary: alpha(palette.Grey[900], 0.64),
145
- disabled: alpha(palette.Grey[900], 0.32)
154
+ disabled: alpha(palette.Grey[900], 0.32),
155
+ icon: alpha(palette.Grey[900], 0.72)
146
156
  },
147
157
  background: {
148
158
  default: palette.Grey[100],
149
159
  paper: palette.Common.white,
150
160
  contrast: alpha(palette.Grey[900], 0.048)
151
161
  },
162
+ border: {
163
+ main: alpha(palette.Grey[900], 0.16),
164
+ disabled: alpha(palette.Grey[900], 0.08),
165
+ ghost: alpha(palette.Grey[900], 0.48),
166
+ ghostDisabled: alpha(palette.Grey[900], 0.16),
167
+ opacity: 0.32,
168
+ ghostOpacity: 0.48
169
+ },
152
170
  divider: alpha(palette.Grey[900], 0.12),
153
171
  action: {
154
172
  active: alpha(palette.Grey[900], 0.56),
@@ -0,0 +1,3 @@
1
+ import { Shadows } from '@mui/material/styles';
2
+ import { PaletteJson } from './types';
3
+ export declare const makeShadows: (mode?: "light" | "dark", palette?: PaletteJson) => Shadows;
@@ -0,0 +1,52 @@
1
+ import { alpha } from '@mui/material/styles';
2
+ import paletteJson from './palette.json';
3
+ const paletteData = paletteJson;
4
+ /**
5
+ * Each elevation is two offset layers plus a constant hairline outline.
6
+ * Tuple is [y1, blur1, spread1, opacity1, y2, blur2, spread2, opacity2];
7
+ * the x offset is always 0.
8
+ */
9
+ const elevations = [
10
+ [2, 4, 0, 0.08, 4, 16, 0, 0.06],
11
+ [3, 5, 0, 0.09, 4, 17, 0, 0.07],
12
+ [3, 5, -1, 0.09, 5, 19, 1, 0.08],
13
+ [3, 6, -1, 0.1, 5, 20, 1, 0.08],
14
+ [4, 6, -1, 0.11, 5, 22, 1, 0.09],
15
+ [4, 7, -2, 0.11, 6, 23, 2, 0.1],
16
+ [5, 7, -2, 0.12, 6, 24, 2, 0.11],
17
+ [5, 8, -2, 0.13, 6, 26, 2, 0.11],
18
+ [5, 8, -3, 0.14, 7, 27, 3, 0.12],
19
+ [6, 9, -3, 0.14, 7, 29, 3, 0.13],
20
+ [6, 9, -3, 0.15, 7, 30, 3, 0.14],
21
+ [7, 10, -4, 0.16, 8, 31, 4, 0.15],
22
+ [7, 10, -4, 0.16, 8, 33, 4, 0.15],
23
+ [8, 11, -5, 0.17, 9, 34, 5, 0.16],
24
+ [8, 11, -5, 0.18, 9, 35, 5, 0.17],
25
+ [9, 12, -5, 0.18, 9, 37, 5, 0.18],
26
+ [9, 12, -6, 0.19, 10, 38, 6, 0.19],
27
+ [9, 13, -6, 0.2, 10, 40, 6, 0.19],
28
+ [10, 13, -6, 0.21, 10, 41, 6, 0.2],
29
+ [10, 14, -7, 0.21, 11, 42, 7, 0.21],
30
+ [11, 14, -7, 0.22, 11, 44, 7, 0.22],
31
+ [11, 15, -7, 0.23, 11, 45, 7, 0.22],
32
+ [12, 15, -8, 0.23, 12, 47, 8, 0.23],
33
+ [12, 16, -8, 0.24, 12, 48, 8, 0.24]
34
+ ];
35
+ const OUTLINE_OPACITY = 0.12;
36
+ /**
37
+ * cozy-ui defines a flat 26th elevation outside the ramp. MUI's `Shadows`
38
+ * contract stops at 25, so `theme.shadows[25]` is reachable at runtime but not
39
+ * through the type. Kept to stay iso with cozy-ui.
40
+ */
41
+ const EXTRA_ELEVATION_OPACITY = 0.04;
42
+ export const makeShadows = (mode = 'light', palette = paletteData) => {
43
+ const shadowColor = mode === 'dark' ? palette.Common.black : palette.Grey[900];
44
+ const outline = `0px 0px 0px 0.5px ${alpha(shadowColor, OUTLINE_OPACITY)}`;
45
+ const shadows = elevations.map(([y1, blur1, spread1, o1, y2, blur2, spread2, o2]) => [
46
+ `0px ${y1}px ${blur1}px ${spread1}px ${alpha(shadowColor, o1)}`,
47
+ `0px ${y2}px ${blur2}px ${spread2}px ${alpha(shadowColor, o2)}`,
48
+ outline
49
+ ].join(', '));
50
+ const extraElevation = `0px 1px 4px ${alpha(shadowColor, EXTRA_ELEVATION_OPACITY)}`;
51
+ return ['none', ...shadows, extraElevation];
52
+ };
@@ -1,7 +1,8 @@
1
1
  import { createTheme } from '@mui/material/styles';
2
- import { makeDarkOverrides } from './makeDarkOverrides';
3
- import { makeLightOverrides } from './makeLightOverrides';
2
+ import { darkOverrides } from './darkOverrides';
3
+ import { lightOverrides } from './lightOverrides';
4
4
  import { makePalette } from './makePalette';
5
+ import { makeShadows } from './makeShadows';
5
6
  import { makeTypography } from './makeTypography';
6
7
  // DatePicker styles are applied through component overrides
7
8
  const themesCommonConfig = {
@@ -27,9 +28,10 @@ export const makeTheme = (mode = 'light') => {
27
28
  const theme = createTheme({
28
29
  ...themesCommonConfig,
29
30
  palette,
30
- typography
31
+ typography,
32
+ shadows: makeShadows(mode)
31
33
  });
32
- const components = mode === 'dark' ? makeDarkOverrides(theme) : makeLightOverrides(theme);
34
+ const components = mode === 'dark' ? darkOverrides : lightOverrides;
33
35
  // Create the final theme with components
34
36
  return createTheme({
35
37
  ...theme,
@@ -57,6 +57,9 @@ export interface BorderPalette {
57
57
  main: string;
58
58
  disabled: string;
59
59
  ghost: string;
60
+ ghostDisabled: string;
61
+ opacity: number;
62
+ ghostOpacity: number;
60
63
  }
61
64
  export interface PaletteJson {
62
65
  Primary: PaletteColor;
@@ -103,3 +106,22 @@ export interface TypographyVariants {
103
106
  overline: TypographyConfig;
104
107
  }
105
108
  export type MakeTypography = () => TypographyOptions;
109
+ /**
110
+ * Twake additions on top of the MUI palette, mirroring cozy-ui. MUI does not
111
+ * declare them, so without this augmentation consumers reading
112
+ * `theme.palette.background.contrast` get a type error.
113
+ */
114
+ declare module '@mui/material/styles' {
115
+ interface TypeBackground {
116
+ contrast: string;
117
+ }
118
+ interface TypeText {
119
+ icon: string;
120
+ }
121
+ interface Palette {
122
+ border: BorderPalette;
123
+ }
124
+ interface PaletteOptions {
125
+ border?: Partial<BorderPalette>;
126
+ }
127
+ }
@@ -0,0 +1,7 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import React from 'react';
3
+ declare function ThemePlaygroundContent(): React.ReactElement;
4
+ declare const meta: Meta<typeof ThemePlaygroundContent>;
5
+ export default meta;
6
+ type Story = StoryObj<typeof ThemePlaygroundContent>;
7
+ export declare const Docs: Story;
@@ -0,0 +1,231 @@
1
+ import { Button, Stack, Chip } from '@mui/material';
2
+ import React from 'react';
3
+ import { TwakeMuiThemeProvider } from '../components/ThemeProvider';
4
+ import { makePalette } from '../lib/makePalette';
5
+ const customPalette = {
6
+ Primary: {
7
+ '50': '#FFF9F6',
8
+ '100': '#FFF5F0',
9
+ '200': '#FFF1E3',
10
+ '300': '#FFD8BF',
11
+ '400': '#FFAE7B',
12
+ '500': '#FF8D46',
13
+ '600': '#F67E35',
14
+ '700': '#F66F35',
15
+ '800': '#E55B31',
16
+ '900': '#7A411E',
17
+ ContrastText: '#fff'
18
+ },
19
+ Secondary: {
20
+ '50': '#E5FFFF',
21
+ '100': '#B3FFFF',
22
+ '200': '#80FFFF',
23
+ '300': '#4DFFFF',
24
+ '400': '#1AFFFF',
25
+ '500': '#00FFFF',
26
+ '600': '#00CCCC',
27
+ '700': '#009999',
28
+ '800': '#006666',
29
+ '900': '#003333',
30
+ ContrastText: '#000'
31
+ },
32
+ Error: {
33
+ '50': '#FFE5E5',
34
+ '100': '#FFB3B3',
35
+ '200': '#FF8080',
36
+ '300': '#FF4D4D',
37
+ '400': '#FF1A1A',
38
+ '500': '#FF0000',
39
+ '600': '#CC0000',
40
+ '700': '#990000',
41
+ '800': '#660000',
42
+ '900': '#330000',
43
+ ContrastText: '#fff'
44
+ },
45
+ Warning: {
46
+ '50': '#FFFFE5',
47
+ '100': '#FFFFB3',
48
+ '200': '#FFFF80',
49
+ '300': '#FFFF4D',
50
+ '400': '#FFFF1A',
51
+ '500': '#FFFF00',
52
+ '600': '#CCCC00',
53
+ '700': '#999900',
54
+ '800': '#666600',
55
+ '900': '#333300',
56
+ ContrastText: '#000'
57
+ },
58
+ Success: {
59
+ '50': '#E5FFE5',
60
+ '100': '#B3FFB3',
61
+ '200': '#80FF80',
62
+ '300': '#4DFF4D',
63
+ '400': '#1AFF1A',
64
+ '500': '#00FF00',
65
+ '600': '#00CC00',
66
+ '700': '#009900',
67
+ '800': '#006600',
68
+ '900': '#003300',
69
+ ContrastText: '#000'
70
+ },
71
+ Info: {
72
+ '50': '#F0E5FF',
73
+ '100': '#D1B3FF',
74
+ '200': '#B380FF',
75
+ '300': '#944DFF',
76
+ '400': '#751AFF',
77
+ '500': '#6600FF',
78
+ '600': '#5200CC',
79
+ '700': '#3D0099',
80
+ '800': '#290066',
81
+ '900': '#140033'
82
+ },
83
+ Grey: {
84
+ '50': '#F2F2F2',
85
+ '100': '#00FF00',
86
+ '200': '#CCCCCC',
87
+ '300': '#B3B3B3',
88
+ '400': '#808080',
89
+ '500': '#808080',
90
+ '600': '#666666',
91
+ '700': '#4D4D4D',
92
+ '800': '#00FF00',
93
+ '900': '#FF00FF',
94
+ A100: '#FFFFFF',
95
+ A200: '#F0F0F0',
96
+ A400: '#00FF00',
97
+ A700: '#262626',
98
+ A900: '#0D0D0D'
99
+ },
100
+ Common: {
101
+ black: '#FF0000',
102
+ white: '#0000ff'
103
+ }
104
+ };
105
+ const BASE_PALETTE = makePalette('light', customPalette);
106
+ function ColorSwatch({ label, color }) {
107
+ return (React.createElement(Stack, { direction: "row", spacing: 1 },
108
+ React.createElement("div", { style: {
109
+ width: 24,
110
+ height: 24,
111
+ borderRadius: 4,
112
+ backgroundColor: color,
113
+ border: '1px solid rgba(0,0,0,0.1)'
114
+ } }),
115
+ React.createElement("code", { style: { fontSize: 12, color: '#666' } }, label),
116
+ React.createElement("code", { style: { fontSize: 12 } }, color)));
117
+ }
118
+ function ThemePlaygroundContent() {
119
+ const primaryMain = BASE_PALETTE.primary.main;
120
+ const secondaryMain = BASE_PALETTE.secondary
121
+ .main;
122
+ const textPrimary = BASE_PALETTE.text.primary;
123
+ const textSecondary = BASE_PALETTE.text.secondary;
124
+ const backgroundDefault = BASE_PALETTE.background.default;
125
+ const backgroundPaper = BASE_PALETTE.background.paper;
126
+ return (React.createElement(TwakeMuiThemeProvider, { themeOptions: { palette: BASE_PALETTE } },
127
+ React.createElement(Stack, { spacing: 4, sx: { p: 3, minWidth: 640 } },
128
+ React.createElement("section", null,
129
+ React.createElement("h3", { style: { marginTop: 0, marginBottom: 12 } }, "Palette Colors"),
130
+ React.createElement(Stack, { spacing: 1 },
131
+ React.createElement(ColorSwatch, { label: "primary.main", color: primaryMain }),
132
+ React.createElement(ColorSwatch, { label: "secondary.main", color: secondaryMain }),
133
+ React.createElement(ColorSwatch, { label: "text.primary", color: textPrimary }),
134
+ React.createElement(ColorSwatch, { label: "text.secondary", color: textSecondary }),
135
+ React.createElement(ColorSwatch, { label: "background.default", color: backgroundDefault }),
136
+ React.createElement(ColorSwatch, { label: "background.paper", color: backgroundPaper }))),
137
+ React.createElement("section", null,
138
+ React.createElement("h3", { style: { marginTop: 0, marginBottom: 12 } }, "Buttons"),
139
+ React.createElement(Stack, { spacing: 2 },
140
+ React.createElement(Stack, { direction: "row", spacing: 2 },
141
+ React.createElement(Button, { variant: "contained", color: "primary" }, "Contained primary"),
142
+ React.createElement(Button, { variant: "outlined", color: "primary" }, "Outlined primary"),
143
+ React.createElement(Button, { variant: "text", color: "primary" }, "Text primary")),
144
+ React.createElement(Stack, { direction: "row", spacing: 2 },
145
+ React.createElement(Button, { variant: "contained", color: "secondary" }, "Contained secondary"),
146
+ React.createElement(Button, { variant: "outlined", color: "secondary" }, "Outlined secondary"),
147
+ React.createElement(Button, { variant: "text", color: "secondary" }, "Text secondary")),
148
+ React.createElement(Stack, { direction: "row", spacing: 2 },
149
+ React.createElement(Button, { variant: "contained", disabled: true }, "Disabled")))),
150
+ React.createElement("section", null,
151
+ React.createElement("h3", { style: { marginTop: 0, marginBottom: 12 } }, "Chips"),
152
+ React.createElement(Stack, { direction: "row", spacing: 2 },
153
+ React.createElement(Chip, { label: "Primary filled", color: "primary" }),
154
+ React.createElement(Chip, { label: "Primary outlined", color: "primary", variant: "outlined" }),
155
+ React.createElement(Chip, { label: "Secondary filled", color: "secondary" }),
156
+ React.createElement(Chip, { label: "Secondary outlined", color: "secondary", variant: "outlined" }))),
157
+ React.createElement("section", null,
158
+ React.createElement("h3", { style: { marginTop: 0, marginBottom: 12 } }, "Typography"),
159
+ React.createElement(Stack, { spacing: 0.5 },
160
+ React.createElement("span", { style: {
161
+ color: textPrimary,
162
+ fontSize: 15
163
+ } }, "text.primary \u2014 The quick brown fox"),
164
+ React.createElement("span", { style: {
165
+ color: textSecondary,
166
+ fontSize: 13
167
+ } }, "text.secondary \u2014 The quick brown fox"))),
168
+ React.createElement("section", null,
169
+ React.createElement("h3", { style: { marginTop: 0, marginBottom: 12 } }, "Backgrounds"),
170
+ React.createElement(Stack, { direction: "row", spacing: 2 },
171
+ React.createElement(Stack, { sx: {
172
+ width: 120,
173
+ height: 64,
174
+ borderRadius: 1,
175
+ border: '1px solid',
176
+ borderColor: 'divider',
177
+ bgcolor: 'background.default',
178
+ alignItems: 'center',
179
+ justifyContent: 'center'
180
+ } },
181
+ React.createElement("code", { style: { fontSize: 10 } }, "default")),
182
+ React.createElement(Stack, { sx: {
183
+ width: 120,
184
+ height: 64,
185
+ borderRadius: 1,
186
+ border: '1px solid',
187
+ borderColor: 'divider',
188
+ bgcolor: 'background.paper',
189
+ alignItems: 'center',
190
+ justifyContent: 'center'
191
+ } },
192
+ React.createElement("code", { style: { fontSize: 10 } }, "paper")))))));
193
+ }
194
+ const meta = {
195
+ title: 'ThemePlayground',
196
+ component: ThemePlaygroundContent,
197
+ parameters: { layout: 'centered' },
198
+ tags: ['autodocs']
199
+ };
200
+ export default meta;
201
+ export const Docs = {
202
+ parameters: {
203
+ docs: {
204
+ source: {
205
+ code: `import { makePalette } from '@linagora/twake-mui'
206
+ import type { PaletteJson } from '@linagora/twake-mui'
207
+
208
+ const customPalette: PaletteJson = {
209
+ Primary: {
210
+ '500': '#FF00AA',
211
+ ContrastText: '#fff'
212
+ },
213
+ Secondary: {
214
+ '500': '#00FFFF',
215
+ ContrastText: '#000'
216
+ },
217
+ // ...Error, Warning, Success, Info, Grey, Common
218
+ }
219
+
220
+ // Generate a full MUI palette from your design tokens
221
+ const basePalette = makePalette('light', customPalette)
222
+
223
+ <TwakeMuiThemeProvider
224
+ themeOptions={{palette: basePalette}}
225
+ >
226
+ <YourApp />
227
+ </TwakeMuiThemeProvider>`
228
+ }
229
+ }
230
+ }
231
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@linagora/twake-mui",
3
3
  "type": "module",
4
- "version": "5.1.0",
4
+ "version": "5.2.0",
5
5
  "description": "MUI v9 theme system for Twake applications",
6
6
  "author": "Twake",
7
7
  "license": "MIT",
@@ -1,2 +0,0 @@
1
- import { Theme, ThemeOptions } from '@mui/material/styles';
2
- export declare const makeDarkOverrides: (theme: Theme) => NonNullable<ThemeOptions["components"]>;
@@ -1,9 +0,0 @@
1
- import { merge } from 'lodash';
2
- import { makeLightOverrides } from './makeLightOverrides';
3
- export const makeDarkOverrides = (theme) => {
4
- const makeOverridesForDarkTheme = (
5
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
6
- theme) => ({});
7
- const DarkOverrides = merge(makeLightOverrides(theme), makeOverridesForDarkTheme(theme));
8
- return DarkOverrides;
9
- };
@@ -1,2 +0,0 @@
1
- import { Theme, ThemeOptions } from '@mui/material/styles';
2
- export declare const makeLightOverrides: (theme: Theme) => NonNullable<ThemeOptions["components"]>;