-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
/
styleFunctionSx.js
144 lines (116 loc) · 4.04 KB
/
styleFunctionSx.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import capitalize from '@mui/utils/capitalize';
import merge from '../merge';
import { getPath, getStyleValue as getValue } from '../style';
import {
handleBreakpoints,
createEmptyBreakpointObject,
removeUnusedBreakpoints,
} from '../breakpoints';
import { sortContainerQueries } from '../cssContainerQueries';
import defaultSxConfig from './defaultSxConfig';
function objectsHaveSameKeys(...objects) {
const allKeys = objects.reduce((keys, object) => keys.concat(Object.keys(object)), []);
const union = new Set(allKeys);
return objects.every((object) => union.size === Object.keys(object).length);
}
function callIfFn(maybeFn, arg) {
return typeof maybeFn === 'function' ? maybeFn(arg) : maybeFn;
}
// eslint-disable-next-line @typescript-eslint/naming-convention
export function unstable_createStyleFunctionSx() {
function getThemeValue(prop, val, theme, config) {
const props = {
[prop]: val,
theme,
};
const options = config[prop];
if (!options) {
return { [prop]: val };
}
const { cssProperty = prop, themeKey, transform, style } = options;
if (val == null) {
return null;
}
// TODO v6: remove, see https://github.com/mui/material-ui/pull/38123
if (themeKey === 'typography' && val === 'inherit') {
return { [prop]: val };
}
const themeMapping = getPath(theme, themeKey) || {};
if (style) {
return style(props);
}
const styleFromPropValue = (propValueFinal) => {
let value = getValue(themeMapping, transform, propValueFinal);
if (propValueFinal === value && typeof propValueFinal === 'string') {
// Haven't found value
value = getValue(
themeMapping,
transform,
`${prop}${propValueFinal === 'default' ? '' : capitalize(propValueFinal)}`,
propValueFinal,
);
}
if (cssProperty === false) {
return value;
}
return {
[cssProperty]: value,
};
};
return handleBreakpoints(props, val, styleFromPropValue);
}
function styleFunctionSx(props) {
const { sx, theme = {} } = props || {};
if (!sx) {
return null; // Emotion & styled-components will neglect null
}
const config = theme.unstable_sxConfig ?? defaultSxConfig;
/*
* Receive `sxInput` as object or callback
* and then recursively check keys & values to create media query object styles.
* (the result will be used in `styled`)
*/
function traverse(sxInput) {
let sxObject = sxInput;
if (typeof sxInput === 'function') {
sxObject = sxInput(theme);
} else if (typeof sxInput !== 'object') {
// value
return sxInput;
}
if (!sxObject) {
return null;
}
const emptyBreakpoints = createEmptyBreakpointObject(theme.breakpoints);
const breakpointsKeys = Object.keys(emptyBreakpoints);
let css = emptyBreakpoints;
Object.keys(sxObject).forEach((styleKey) => {
const value = callIfFn(sxObject[styleKey], theme);
if (value !== null && value !== undefined) {
if (typeof value === 'object') {
if (config[styleKey]) {
css = merge(css, getThemeValue(styleKey, value, theme, config));
} else {
const breakpointsValues = handleBreakpoints({ theme }, value, (x) => ({
[styleKey]: x,
}));
if (objectsHaveSameKeys(breakpointsValues, value)) {
css[styleKey] = styleFunctionSx({ sx: value, theme });
} else {
css = merge(css, breakpointsValues);
}
}
} else {
css = merge(css, getThemeValue(styleKey, value, theme, config));
}
}
});
return sortContainerQueries(theme, removeUnusedBreakpoints(breakpointsKeys, css));
}
return Array.isArray(sx) ? sx.map(traverse) : traverse(sx);
}
return styleFunctionSx;
}
const styleFunctionSx = unstable_createStyleFunctionSx();
styleFunctionSx.filterProps = ['sx'];
export default styleFunctionSx;