UNPKG

8.02 kBJavaScriptView Raw
1import _extends from "@babel/runtime/helpers/esm/extends";
2import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
3import { formatMuiErrorMessage as _formatMuiErrorMessage } from "@material-ui/utils";
4import { deepmerge } from '@material-ui/utils';
5import common from '../colors/common';
6import grey from '../colors/grey';
7import indigo from '../colors/indigo';
8import pink from '../colors/pink';
9import red from '../colors/red';
10import orange from '../colors/orange';
11import blue from '../colors/blue';
12import green from '../colors/green';
13import { darken, getContrastRatio, lighten } from './colorManipulator';
14export const light = {
15 // The colors used to style the text.
16 text: {
17 // The most important text.
18 primary: 'rgba(0, 0, 0, 0.87)',
19 // Secondary text.
20 secondary: 'rgba(0, 0, 0, 0.54)',
21 // Disabled text have even lower visual prominence.
22 disabled: 'rgba(0, 0, 0, 0.38)',
23 // Text hints.
24 hint: 'rgba(0, 0, 0, 0.38)'
25 },
26 // The color used to divide different elements.
27 divider: 'rgba(0, 0, 0, 0.12)',
28 // The background colors used to style the surfaces.
29 // Consistency between these values is important.
30 background: {
31 paper: common.white,
32 default: grey[50]
33 },
34 // The colors used to style the action elements.
35 action: {
36 // The color of an active action like an icon button.
37 active: 'rgba(0, 0, 0, 0.54)',
38 // The color of an hovered action.
39 hover: 'rgba(0, 0, 0, 0.04)',
40 hoverOpacity: 0.04,
41 // The color of a selected action.
42 selected: 'rgba(0, 0, 0, 0.08)',
43 selectedOpacity: 0.08,
44 // The color of a disabled action.
45 disabled: 'rgba(0, 0, 0, 0.26)',
46 // The background color of a disabled action.
47 disabledBackground: 'rgba(0, 0, 0, 0.12)',
48 disabledOpacity: 0.38,
49 focus: 'rgba(0, 0, 0, 0.12)',
50 focusOpacity: 0.12,
51 activatedOpacity: 0.12
52 }
53};
54export const dark = {
55 text: {
56 primary: common.white,
57 secondary: 'rgba(255, 255, 255, 0.7)',
58 disabled: 'rgba(255, 255, 255, 0.5)',
59 hint: 'rgba(255, 255, 255, 0.5)',
60 icon: 'rgba(255, 255, 255, 0.5)'
61 },
62 divider: 'rgba(255, 255, 255, 0.12)',
63 background: {
64 paper: grey[800],
65 default: '#303030'
66 },
67 action: {
68 active: common.white,
69 hover: 'rgba(255, 255, 255, 0.08)',
70 hoverOpacity: 0.08,
71 selected: 'rgba(255, 255, 255, 0.16)',
72 selectedOpacity: 0.16,
73 disabled: 'rgba(255, 255, 255, 0.3)',
74 disabledBackground: 'rgba(255, 255, 255, 0.12)',
75 disabledOpacity: 0.38,
76 focus: 'rgba(255, 255, 255, 0.12)',
77 focusOpacity: 0.12,
78 activatedOpacity: 0.24
79 }
80};
81
82function addLightOrDark(intent, direction, shade, tonalOffset) {
83 const tonalOffsetLight = tonalOffset.light || tonalOffset;
84 const tonalOffsetDark = tonalOffset.dark || tonalOffset * 1.5;
85
86 if (!intent[direction]) {
87 if (intent.hasOwnProperty(shade)) {
88 intent[direction] = intent[shade];
89 } else if (direction === 'light') {
90 intent.light = lighten(intent.main, tonalOffsetLight);
91 } else if (direction === 'dark') {
92 intent.dark = darken(intent.main, tonalOffsetDark);
93 }
94 }
95}
96
97export default function createPalette(palette) {
98 const {
99 primary = {
100 light: indigo[300],
101 main: indigo[500],
102 dark: indigo[700]
103 },
104 secondary = {
105 light: pink.A200,
106 main: pink.A400,
107 dark: pink.A700
108 },
109 error = {
110 light: red[300],
111 main: red[500],
112 dark: red[700]
113 },
114 warning = {
115 light: orange[300],
116 main: orange[500],
117 dark: orange[700]
118 },
119 info = {
120 light: blue[300],
121 main: blue[500],
122 dark: blue[700]
123 },
124 success = {
125 light: green[300],
126 main: green[500],
127 dark: green[700]
128 },
129 type = 'light',
130 contrastThreshold = 3,
131 tonalOffset = 0.2
132 } = palette,
133 other = _objectWithoutPropertiesLoose(palette, ["primary", "secondary", "error", "warning", "info", "success", "type", "contrastThreshold", "tonalOffset"]); // Use the same logic as
134 // Bootstrap: https://github.com/twbs/bootstrap/blob/1d6e3710dd447de1a200f29e8fa521f8a0908f70/scss/_functions.scss#L59
135 // and material-components-web https://github.com/material-components/material-components-web/blob/ac46b8863c4dab9fc22c4c662dc6bd1b65dd652f/packages/mdc-theme/_functions.scss#L54
136
137
138 function getContrastText(background) {
139 const contrastText = getContrastRatio(background, dark.text.primary) >= contrastThreshold ? dark.text.primary : light.text.primary;
140
141 if (process.env.NODE_ENV !== 'production') {
142 const contrast = getContrastRatio(background, contrastText);
143
144 if (contrast < 3) {
145 console.error([`Material-UI: The contrast ratio of ${contrast}:1 for ${contrastText} on ${background}`, 'falls below the WCAG recommended absolute minimum contrast ratio of 3:1.', 'https://www.w3.org/TR/2008/REC-WCAG20-20081211/#visual-audio-contrast-contrast'].join('\n'));
146 }
147 }
148
149 return contrastText;
150 }
151
152 const augmentColor = (color, mainShade = 500, lightShade = 300, darkShade = 700) => {
153 color = _extends({}, color);
154
155 if (!color.main && color[mainShade]) {
156 color.main = color[mainShade];
157 }
158
159 if (!color.main) {
160 throw new Error(process.env.NODE_ENV !== "production" ? `Material-UI: The color provided to augmentColor(color) is invalid.
161The color object needs to have a \`main\` property or a \`${mainShade}\` property.` : _formatMuiErrorMessage(4, mainShade));
162 }
163
164 if (typeof color.main !== 'string') {
165 throw new Error(process.env.NODE_ENV !== "production" ? `Material-UI: The color provided to augmentColor(color) is invalid.
166\`color.main\` should be a string, but \`${JSON.stringify(color.main)}\` was provided instead.
167
168Did you intend to use one of the following approaches?
169
170import { green } from "@material-ui/core/colors";
171
172const theme1 = createTheme({ palette: {
173 primary: green,
174} });
175
176const theme2 = createTheme({ palette: {
177 primary: { main: green[500] },
178} });` : _formatMuiErrorMessage(5, JSON.stringify(color.main)));
179 }
180
181 addLightOrDark(color, 'light', lightShade, tonalOffset);
182 addLightOrDark(color, 'dark', darkShade, tonalOffset);
183
184 if (!color.contrastText) {
185 color.contrastText = getContrastText(color.main);
186 }
187
188 return color;
189 };
190
191 const types = {
192 dark,
193 light
194 };
195
196 if (process.env.NODE_ENV !== 'production') {
197 if (!types[type]) {
198 console.error(`Material-UI: The palette type \`${type}\` is not supported.`);
199 }
200 }
201
202 const paletteOutput = deepmerge(_extends({
203 // A collection of common colors.
204 common,
205 // The palette type, can be light or dark.
206 type,
207 // The colors used to represent primary interface elements for a user.
208 primary: augmentColor(primary),
209 // The colors used to represent secondary interface elements for a user.
210 secondary: augmentColor(secondary, 'A400', 'A200', 'A700'),
211 // The colors used to represent interface elements that the user should be made aware of.
212 error: augmentColor(error),
213 // The colors used to represent potentially dangerous actions or important messages.
214 warning: augmentColor(warning),
215 // The colors used to present information to the user that is neutral and not necessarily important.
216 info: augmentColor(info),
217 // The colors used to indicate the successful completion of an action that user triggered.
218 success: augmentColor(success),
219 // The grey colors.
220 grey,
221 // Used by `getContrastText()` to maximize the contrast between
222 // the background and the text.
223 contrastThreshold,
224 // Takes a background color and returns the text color that maximizes the contrast.
225 getContrastText,
226 // Generate a rich color object.
227 augmentColor,
228 // Used by the functions below to shift a color's luminance by approximately
229 // two indexes within its tonal palette.
230 // E.g., shift from Red 500 to Red 300 or Red 700.
231 tonalOffset
232 }, types[type]), other);
233 return paletteOutput;
234}
\No newline at end of file