@mui/system
Version:
MUI System is a set of CSS utilities to help you build custom designs more efficiently. It makes it possible to rapidly lay out custom designs.
166 lines (161 loc) • 5.96 kB
JavaScript
import responsivePropType from "../responsivePropType/index.mjs";
import { iterateBreakpoints } from "../breakpoints/index.mjs";
import { getPath } from "../style/index.mjs";
/* eslint-disable guard-for-in */
const EMPTY_THEME = {
internal_cache: {}
};
const properties = {
m: 'margin',
p: 'padding'
};
const directions = {
t: 'Top',
r: 'Right',
b: 'Bottom',
l: 'Left',
x: ['Left', 'Right'],
y: ['Top', 'Bottom']
};
const aliases = {
marginX: 'mx',
marginY: 'my',
paddingX: 'px',
paddingY: 'py'
};
const CSS_PROPERTIES = {};
for (const key in properties) {
CSS_PROPERTIES[key] = [properties[key]];
}
for (const keyProperty in properties) {
for (const keyDirection in directions) {
const property = properties[keyProperty];
const direction = directions[keyDirection];
const value = Array.isArray(direction) ? direction.map(dir => property + dir) : [property + direction];
CSS_PROPERTIES[keyProperty + keyDirection] = value;
}
}
for (const key in aliases) {
CSS_PROPERTIES[key] = CSS_PROPERTIES[aliases[key]];
}
/** @internal */
export const marginKeys = new Set(['m', 'mt', 'mr', 'mb', 'ml', 'mx', 'my', 'margin', 'marginTop', 'marginRight', 'marginBottom', 'marginLeft', 'marginX', 'marginY', 'marginInline', 'marginInlineStart', 'marginInlineEnd', 'marginBlock', 'marginBlockStart', 'marginBlockEnd']);
/** @internal */
export const paddingKeys = new Set(['p', 'pt', 'pr', 'pb', 'pl', 'px', 'py', 'padding', 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft', 'paddingX', 'paddingY', 'paddingInline', 'paddingInlineStart', 'paddingInlineEnd', 'paddingBlock', 'paddingBlockStart', 'paddingBlockEnd']);
const spacingKeys = new Set([...marginKeys, ...paddingKeys]);
export function createUnaryUnit(theme, themeKey, defaultValue, propName) {
const themeSpacing = getPath(theme, themeKey, true) ?? defaultValue;
if (typeof themeSpacing === 'number' || typeof themeSpacing === 'string') {
return val => {
if (typeof val === 'string') {
return val;
}
if (process.env.NODE_ENV !== 'production') {
if (typeof val !== 'number') {
console.error(`MUI: Expected ${propName} argument to be a number or a string, got ${val}.`);
}
}
if (typeof themeSpacing === 'string') {
if (themeSpacing.startsWith('var(') && val === 0) {
return 0;
}
if (themeSpacing.startsWith('var(') && val === 1) {
return themeSpacing;
}
return `calc(${val} * ${themeSpacing})`;
}
return themeSpacing * val;
};
}
if (Array.isArray(themeSpacing)) {
return val => {
if (typeof val === 'string') {
return val;
}
const abs = Math.abs(val);
if (process.env.NODE_ENV !== 'production') {
if (!Number.isInteger(abs)) {
console.error([`MUI: The \`theme.${themeKey}\` array type cannot be combined with non integer values.` + `You should either use an integer value that can be used as index, or define the \`theme.${themeKey}\` as a number.`].join('\n'));
} else if (abs > themeSpacing.length - 1) {
console.error([`MUI: The value provided (${abs}) overflows.`, `The supported values are: ${JSON.stringify(themeSpacing)}.`, `${abs} > ${themeSpacing.length - 1}, you need to add the missing values.`].join('\n'));
}
}
const transformed = themeSpacing[abs];
if (val >= 0) {
return transformed;
}
if (typeof transformed === 'number') {
return -transformed;
}
if (typeof transformed === 'string' && transformed.startsWith('var(')) {
return `calc(-1 * ${transformed})`;
}
return `-${transformed}`;
};
}
if (typeof themeSpacing === 'function') {
return themeSpacing;
}
if (process.env.NODE_ENV !== 'production') {
console.error([`MUI: The \`theme.${themeKey}\` value (${themeSpacing}) is invalid.`, 'It should be a number, an array or a function.'].join('\n'));
}
return () => undefined;
}
export function createUnarySpacing(theme) {
return createUnaryUnit(theme, 'spacing', 8, 'spacing');
}
export function getValue(transformer, propValue) {
if (typeof propValue === 'string' || propValue == null) {
return propValue;
}
return transformer(propValue);
}
// Avoid allocations
const container = [''];
function style(props, keys) {
const theme = props.theme ?? EMPTY_THEME;
const transformer = theme?.internal_cache?.unarySpacing ?? createUnarySpacing(theme);
const result = {};
for (const prop in props) {
if (!keys.has(prop)) {
continue;
}
const cssProperties = CSS_PROPERTIES[prop] ?? (container[0] = prop, container);
const propValue = props[prop];
iterateBreakpoints(result, props.theme, propValue, (mediaKey, value) => {
const target = mediaKey ? result[mediaKey] : result;
for (let i = 0; i < cssProperties.length; i += 1) {
target[cssProperties[i]] = getValue(transformer, value);
}
});
}
return result;
}
function marginFn(props) {
return style(props, marginKeys);
}
marginFn.propTypes = process.env.NODE_ENV !== 'production' ? Array.from(marginKeys).reduce((obj, key) => {
obj[key] = responsivePropType;
return obj;
}, {}) : {};
marginFn.filterProps = marginKeys;
export const margin = marginFn;
function paddingFn(props) {
return style(props, paddingKeys);
}
paddingFn.propTypes = process.env.NODE_ENV !== 'production' ? Array.from(paddingKeys).reduce((obj, key) => {
obj[key] = responsivePropType;
return obj;
}, {}) : {};
paddingFn.filterProps = paddingKeys;
export const padding = paddingFn;
function spacingFn(props) {
return style(props, spacingKeys);
}
spacingFn.propTypes = process.env.NODE_ENV !== 'production' ? Array.from(spacingKeys).reduce((obj, key) => {
obj[key] = responsivePropType;
return obj;
}, {}) : {};
spacingFn.filterProps = spacingKeys;
const spacing = spacingFn;
export default spacing;