Skip to content

Commit

Permalink
[core] Update classes generation logic (#24371)
Browse files Browse the repository at this point in the history
  • Loading branch information
mnajdova committed Jan 12, 2021
1 parent 6b18675 commit d07811d
Show file tree
Hide file tree
Showing 14 changed files with 202 additions and 152 deletions.
40 changes: 16 additions & 24 deletions packages/material-ui-unstyled/src/BadgeUnstyled/BadgeUnstyled.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,25 @@ import PropTypes from 'prop-types';
import clsx from 'clsx';
import { unstable_capitalize as capitalize, usePreviousProps } from '@material-ui/utils';
import isHostComponent from '../utils/isHostComponent';
import badgeUnstyledClasses, { getBadgeUtilityClass } from './badgeUnstyledClasses';
import composeClasses from '../composeClasses';
import { getBadgeUtilityClass } from './badgeUnstyledClasses';

const useUtilityClasses = (styleProps) => {
const { variant, anchorOrigin, overlap, invisible, classes = {} } = styleProps;

return {
root: clsx(badgeUnstyledClasses.root, classes.root),
badge: clsx(
badgeUnstyledClasses.badge,
classes.badge,
getBadgeUtilityClass(variant),
badgeUnstyledClasses[
`anchorOrigin${capitalize(anchorOrigin.vertical)}${capitalize(
anchorOrigin.horizontal,
)}${capitalize(overlap)}`
],
classes[
`anchorOrigin${capitalize(anchorOrigin.vertical)}${capitalize(
anchorOrigin.horizontal,
)}${capitalize(overlap)}`
],
{
[badgeUnstyledClasses.invisible]: invisible,
[classes.invisible]: invisible,
},
),
const { variant, anchorOrigin, overlap, invisible, classes } = styleProps;

const slots = {
root: ['root'],
badge: [
'badge',
variant,
`anchorOrigin${capitalize(anchorOrigin.vertical)}${capitalize(
anchorOrigin.horizontal,
)}${capitalize(overlap)}`,
invisible && 'invisible',
],
};

return composeClasses({ slots, classes, getUtilityClass: getBadgeUtilityClass });
};

const BadgeUnstyled = React.forwardRef(function BadgeUnstyled(props, ref) {
Expand Down
56 changes: 26 additions & 30 deletions packages/material-ui-unstyled/src/SliderUnstyled/SliderUnstyled.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import {
visuallyHidden,
} from '@material-ui/utils';
import isHostComponent from '../utils/isHostComponent';
import sliderUnstyledClasses from './sliderUnstyledClasses';
import composeClasses from '../composeClasses';
import { getSliderUtilityClass } from './sliderUnstyledClasses';
import SliderValueLabelUnstyled from './SliderValueLabelUnstyled';

function asc(a, b) {
Expand Down Expand Up @@ -150,36 +151,31 @@ function doesSupportTouchActionNone() {
}

const useUtilityClasses = (styleProps) => {
const { disabled, marked, orientation, track, classes = {} } = styleProps;

return {
root: clsx(sliderUnstyledClasses.root, classes.root, {
[sliderUnstyledClasses.disabled]: disabled,
[classes.disabled]: disabled,
[sliderUnstyledClasses.marked]: marked,
[classes.marked]: marked,
[sliderUnstyledClasses.vertical]: orientation === 'vertical',
[classes.vertical]: orientation === 'vertical',
[sliderUnstyledClasses.trackInverted]: track === 'inverted',
[classes.trackInverted]: track === 'inverted',
[sliderUnstyledClasses.trackFalse]: track === false,
[classes.trackFalse]: track === false,
}),
rail: clsx(sliderUnstyledClasses.rail, classes.rail),
track: clsx(sliderUnstyledClasses.track, classes.track),
mark: clsx(sliderUnstyledClasses.mark, classes.mark),
markActive: clsx(sliderUnstyledClasses.markActive, classes.markActive),
markLabel: clsx(sliderUnstyledClasses.markLabel, classes.markLabel),
markLabelActive: clsx(sliderUnstyledClasses.markLabelActive, classes.markLabelActive),
valueLabel: clsx(sliderUnstyledClasses.valueLabel, classes.valueLabel),
thumb: clsx(sliderUnstyledClasses.thumb, classes.thumb, {
[classes.disabled]: disabled,
[sliderUnstyledClasses.disabled]: disabled,
}),
active: clsx(sliderUnstyledClasses.active, classes.active),
disabled: clsx(sliderUnstyledClasses.disabled, classes.disabled),
focusVisible: clsx(sliderUnstyledClasses.focusVisible, classes.focusVisible),
const { disabled, marked, orientation, track, classes } = styleProps;

const slots = {
root: [
'root',
disabled && 'disabled',
marked && 'marked',
orientation === 'vertical' && 'vertical',
track === 'inverted' && 'trackInverted',
track === false && 'trackFalse',
],
rail: ['rail'],
track: ['track'],
mark: ['mark'],
markActive: ['markActive'],
markLabel: ['markLabel'],
markLabelActive: ['markLabelActive'],
valueLabel: ['valueLabel'],
thumb: ['thumb', disabled && 'disabled'],
active: ['active'],
disabled: ['disabled'],
focusVisible: ['focusVisible'],
};

return composeClasses({ slots, classes, getUtilityClass: getSliderUtilityClass });
};

const Forward = ({ children }) => children;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default function composeClasses<T extends keyof any>(options: {
slots: Record<T, string[]>;
classes?: Record<string, string>;
getUtilityClass: (slot: string) => string;
}): Record<T, string>;
21 changes: 21 additions & 0 deletions packages/material-ui-unstyled/src/composeClasses/composeClasses.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
function composeClasses({ slots, classes, getUtilityClass }) {
const output = {};

Object.keys(slots).forEach((slot) => {
output[slot] = slots[slot]
.reduce((acc, key) => {
if (key) {
if (classes && classes[key]) {
acc.push(classes[key]);
}
acc.push(getUtilityClass(key));
}
return acc;
}, [])
.join(' ');
});

return output;
}

export default composeClasses;
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { expect } from 'chai';
import composeClasses from './composeClasses';

describe('composeClasses', () => {
it('should generate the classes based on the slots', () => {
expect(
composeClasses({
slots: {
root: ['root', 'standard'],
slot: ['slot'],
},
getUtilityClass: (slot) => `MuiTest-${slot}`,
}),
).to.deep.equal({
root: 'MuiTest-root MuiTest-standard',
slot: 'MuiTest-slot',
});
});

it('should consider classes if available', () => {
expect(
composeClasses({
slots: {
root: ['root', 'standard'],
slot: ['slot'],
},
getUtilityClass: (slot) => `MuiTest-${slot}`,
classes: {
standard: 'standardOverride',
slot: 'slotOverride',
},
}),
).to.deep.equal({
root: 'MuiTest-root standardOverride MuiTest-standard',
slot: 'slotOverride MuiTest-slot',
});
});

it('should ignore false values', () => {
expect(
composeClasses({
slots: {
root: ['root', false, 'standard'],
slot: ['slot'],
},
getUtilityClass: (slot) => `MuiTest-${slot}`,
classes: {
standard: 'standardOverride',
slot: 'slotOverride',
},
}),
).to.deep.equal({
root: 'MuiTest-root standardOverride MuiTest-standard',
slot: 'slotOverride MuiTest-slot',
});
});
});
2 changes: 2 additions & 0 deletions packages/material-ui-unstyled/src/composeClasses/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default } from './composeClasses';
export * from './composeClasses';
1 change: 1 addition & 0 deletions packages/material-ui-unstyled/src/composeClasses/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './composeClasses';
3 changes: 3 additions & 0 deletions packages/material-ui-unstyled/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,7 @@ export * from './generateUtilityClass';
export { default as generateUtilityClasses } from './generateUtilityClasses';
export * from './generateUtilityClasses';

export { default as unstable_composeClasses } from './composeClasses';
export * from './composeClasses';

export * from './utils';
2 changes: 2 additions & 0 deletions packages/material-ui-unstyled/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ export { default as generateUtilityClass } from './generateUtilityClass';

export { default as generateUtilityClasses } from './generateUtilityClasses';

export { default as unstable_composeClasses } from './composeClasses';

export * from './utils';
16 changes: 8 additions & 8 deletions packages/material-ui/src/Avatar/Avatar.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { deepmerge } from '@material-ui/utils';
import { unstable_composeClasses as composeClasses } from '@material-ui/unstyled';
import experimentalStyled from '../styles/experimentalStyled';
import useThemeProps from '../styles/useThemeProps';
import Person from '../internal/svg-icons/Person';
Expand All @@ -19,16 +20,15 @@ const overridesResolver = (props, styles) => {
};

const useUtilityClasses = (styleProps) => {
const { classes = {}, variant, colorDefault } = styleProps;
const { classes, variant, colorDefault } = styleProps;

return {
root: clsx(avatarClasses.root, classes.root, getAvatarUtilityClass(variant), classes[variant], {
[avatarClasses.colorDefault]: colorDefault,
[classes.colorDefault]: colorDefault,
}),
img: clsx(avatarClasses.img, classes.img),
fallback: clsx(avatarClasses.fallback, classes.fallback),
const slots = {
root: ['root', variant, colorDefault && 'colorDefault'],
img: ['img'],
fallback: ['fallback'],
};

return composeClasses({ slots, classes, getUtilityClass: getAvatarUtilityClass });
};

const AvatarRoot = experimentalStyled(
Expand Down
51 changes: 17 additions & 34 deletions packages/material-ui/src/Button/Button.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { deepmerge } from '@material-ui/utils';
import { unstable_composeClasses as composeClasses } from '@material-ui/unstyled';
import experimentalStyled from '../styles/experimentalStyled';
import useThemeProps from '../styles/useThemeProps';
import { alpha } from '../styles/colorManipulator';
Expand Down Expand Up @@ -35,41 +36,23 @@ const overridesResolver = (props, styles) => {
const useUtilityClasses = (styleProps) => {
const { color, disableElevation, fullWidth, size, variant, classes = {} } = styleProps;

return {
root: clsx(
buttonClasses.root,
classes.root,
getButtonUtilityClass(variant),
classes[variant],
getButtonUtilityClass(`${variant}${capitalize(color)}`),
classes[[`${variant}${capitalize(color)}`]],
getButtonUtilityClass(`size${capitalize(size)}`),
classes[`size${capitalize(size)}`],
getButtonUtilityClass(`${variant}Size${capitalize(size)}`),
classes[`${variant}Size${capitalize(size)}`],
{
[buttonClasses.colorInherit]: color === 'inherit',
[classes.colorInherit]: color === 'inherit',
[buttonClasses.disableElevation]: disableElevation,
[classes.disableElevation]: disableElevation,
[buttonClasses.fullWidth]: fullWidth,
[classes.fullWidth]: fullWidth,
},
),
label: clsx(buttonClasses.label, classes.label),
startIcon: clsx(
buttonClasses.startIcon,
classes.startIcon,
getButtonUtilityClass(`iconSize${capitalize(size)}`),
classes[`iconSize${capitalize(size)}`],
),
endIcon: clsx(
buttonClasses.endIcon,
classes.endIcon,
getButtonUtilityClass(`iconSize${capitalize(size)}`),
classes[`iconSize${capitalize(size)}`],
),
const slots = {
root: [
'root',
variant,
`${variant}${capitalize(color)}`,
`size${capitalize(size)}`,
`${variant}Size${capitalize(size)}`,
color === 'inherit' && 'colorInherit',
disableElevation && 'disableElevation',
fullWidth && 'fullWidth',
],
label: ['label'],
startIcon: ['startIcon', `iconSize${capitalize(size)}`],
endIcon: ['endIcon', `iconSize${capitalize(size)}`],
};

return composeClasses({ slots, classes, getUtilityClass: getButtonUtilityClass });
};

const commonIconStyles = (styleProps) => ({
Expand Down
25 changes: 16 additions & 9 deletions packages/material-ui/src/ButtonBase/ButtonBase.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import * as React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { deepmerge, elementTypeAcceptingRef, refType } from '@material-ui/utils';
import { unstable_composeClasses as composeClasses } from '@material-ui/unstyled';
import experimentalStyled from '../styles/experimentalStyled';
import useThemeProps from '../styles/useThemeProps';
import useForkRef from '../utils/useForkRef';
import useEventCallback from '../utils/useEventCallback';
import useIsFocusVisible from '../utils/useIsFocusVisible';
import TouchRipple from './TouchRipple';
import buttonBaseClasses from './buttonBaseClasses';
import { getButtonBaseUtilityClass } from './buttonBaseClasses';

const overridesResolver = (props, styles) => {
const { styleProps } = props;
Expand All @@ -22,15 +23,21 @@ const overridesResolver = (props, styles) => {
const useUtilityClasses = (styleProps) => {
const { disabled, focusVisible, focusVisibleClassName, classes = {} } = styleProps;

return {
root: clsx(buttonBaseClasses.root, classes.root, {
[buttonBaseClasses.disabled]: disabled,
[classes.disabled]: disabled,
[buttonBaseClasses.focusVisible]: focusVisible,
[classes.focusVisible]: focusVisible,
[focusVisibleClassName]: focusVisible,
}),
const slots = {
root: ['root', disabled && 'disabled', focusVisible && 'focusVisible'],
};

const composedClasses = composeClasses({
slots,
classes,
getUtilityClass: getButtonBaseUtilityClass,
});

if (focusVisible && focusVisibleClassName) {
composedClasses.root += ` ${focusVisibleClassName}`;
}

return composedClasses;
};

export const ButtonBaseRoot = experimentalStyled(
Expand Down

0 comments on commit d07811d

Please sign in to comment.