Skip to content

Commit

Permalink
[experimentalStyled] Add name and slot options (#23964)
Browse files Browse the repository at this point in the history
  • Loading branch information
mnajdova committed Dec 13, 2020
1 parent 4d9c632 commit 3506dda
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 17 deletions.
4 changes: 2 additions & 2 deletions packages/material-ui/src/Badge/Badge.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const overridesResolver = (props, styles) => {
const BadgeRoot = styled(
'span',
{},
{ muiName: 'MuiBadge', overridesResolver },
{ name: 'Badge', slot: 'Root', overridesResolver },
)({
position: 'relative',
display: 'inline-flex',
Expand All @@ -68,7 +68,7 @@ const BadgeRoot = styled(
const BadgeBadge = styled(
'span',
{},
{ muiName: 'MuiBadge-badge', overridesResolver },
{ name: 'Badge', slot: 'Badge', overridesResolver },
)((props) => ({
display: 'flex',
flexDirection: 'row',
Expand Down
22 changes: 15 additions & 7 deletions packages/material-ui/src/Slider/Slider.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,11 @@ const overridesResolver = (props, styles) => {
export const SliderRoot = experimentalStyled(
'span',
{},
{ muiName: 'MuiSlider', overridesResolver },
{
name: 'Slider',
slot: 'Root',
overridesResolver,
},
)((props) => ({
height: 2,
width: '100%',
Expand Down Expand Up @@ -131,7 +135,7 @@ export const SliderRoot = experimentalStyled(
export const SliderRail = experimentalStyled(
'span',
{},
{ muiName: 'MuiSlider-rail' },
{ name: 'Slider', slot: 'Rail' },
)((props) => ({
display: 'block',
position: 'absolute',
Expand All @@ -152,7 +156,7 @@ export const SliderRail = experimentalStyled(
export const SliderTrack = experimentalStyled(
'span',
{},
{ muiName: 'MuiSlider-track' },
{ name: 'Slider', slot: 'Track' },
)((props) => ({
display: 'block',
position: 'absolute',
Expand All @@ -177,7 +181,7 @@ export const SliderTrack = experimentalStyled(
export const SliderThumb = experimentalStyled(
'span',
{},
{ muiName: 'MuiSlider-thumb' },
{ name: 'Slider', slot: 'Thumb' },
)((props) => ({
position: 'absolute',
width: 12,
Expand Down Expand Up @@ -240,7 +244,11 @@ export const SliderThumb = experimentalStyled(
}),
}));

export const SliderValueLabel = experimentalStyled(SliderValueLabelUnstyled)((props) => ({
export const SliderValueLabel = experimentalStyled(
SliderValueLabelUnstyled,
{},
{ name: 'Slider', slot: 'ValueLabel' },
)((props) => ({
// IE 11 centering bug, to remove from the customization demos once no longer supported
left: 'calc(-50% - 4px)',
[`&.${sliderClasses.valueLabelOpen}`]: {
Expand All @@ -262,7 +270,7 @@ export const SliderValueLabel = experimentalStyled(SliderValueLabelUnstyled)((pr
export const SliderMark = experimentalStyled(
'span',
{},
{ muiName: 'MuiSlider-mark' },
{ name: 'Slider', slot: 'Mark' },
)((props) => ({
position: 'absolute',
width: 2,
Expand All @@ -278,7 +286,7 @@ export const SliderMark = experimentalStyled(
export const SliderMarkLabel = experimentalStyled(
'span',
{},
{ muiName: 'MuiSlider-markLabel' },
{ name: 'Slider', slot: 'MarkLabel' },
)((props) => ({
...props.theme.typography.body2,
color: props.theme.palette.text.secondary,
Expand Down
3 changes: 2 additions & 1 deletion packages/material-ui/src/styles/experimentalStyled.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,8 @@ export interface StyledOptions {
}

interface MuiStyledOptions<Theme extends object = any> {
muiName: string;
name?: string;
slot?: string;
overridesResolver?: (props: any, styles: string | object, name: string) => string | object;
skipSx?: boolean;
}
Expand Down
32 changes: 29 additions & 3 deletions packages/material-ui/src/styles/experimentalStyled.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,30 @@ const variantsResolver = (props, styles, theme, name) => {
const shouldForwardProp = (prop) =>
prop !== 'styleProps' && prop !== 'theme' && prop !== 'isRtl' && prop !== 'sx' && prop !== 'as';

const lowercaseFirstLetter = (string) => {
return string.charAt(0).toLowerCase() + string.slice(1);
};

const experimentalStyled = (tag, options, muiOptions = {}) => {
const name = muiOptions.muiName;
const componentName = muiOptions.name;
const componentSlot = muiOptions.slot;
const skipSx = muiOptions.skipSx || false;
const defaultStyledResolver = styled(tag, { shouldForwardProp, label: name, ...options });

let displayName;
let name;
let className;

if (componentName) {
displayName = `${componentName}${componentSlot || ''}`;
name = !componentSlot || componentSlot === 'Root' ? `Mui${componentName}` : null;
className = `Mui${componentName}-${lowercaseFirstLetter(componentSlot || 'Root')}`;
}

const defaultStyledResolver = styled(tag, {
shouldForwardProp,
label: className || componentName || '',
...options,
});
const muiStyledResolver = (styleArg, ...expressions) => {
const expressionsWithDefaultTheme = expressions
? expressions.map((stylesArg) => {
Expand Down Expand Up @@ -116,7 +136,13 @@ const experimentalStyled = (tag, options, muiOptions = {}) => {
styleArg({ theme: isEmpty(themeInput) ? defaultTheme : themeInput, ...other });
}

return defaultStyledResolver(transformedStyleArg, ...expressionsWithDefaultTheme);
const Component = defaultStyledResolver(transformedStyleArg, ...expressionsWithDefaultTheme);

if (displayName || name) {
Component.displayName = displayName || name;
}

return Component;
};
return muiStyledResolver;
};
Expand Down
84 changes: 80 additions & 4 deletions packages/material-ui/src/styles/experimentalStyled.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ describe('experimentalStyled', () => {
Test = styled(
'div',
{ shouldForwardProp: (prop) => prop !== 'variant' && prop !== 'size' && prop !== 'sx' },
{ muiName: 'MuiTest', overridesResolver: testOverridesResolver },
{ name: 'Test', slot: 'Root', overridesResolver: testOverridesResolver },
)`
width: 200px;
height: 300px;
Expand All @@ -185,7 +185,7 @@ describe('experimentalStyled', () => {
TestObj = styled(
'div',
{ shouldForwardProp: (prop) => prop !== 'variant' && prop !== 'size' && prop !== 'sx' },
{ muiName: 'MuiTest', overridesResolver: testOverridesResolver },
{ name: 'Test', overridesResolver: testOverridesResolver },
)({
width: '200px',
height: '300px',
Expand Down Expand Up @@ -363,7 +363,7 @@ describe('experimentalStyled', () => {
const TestNoSx = styled(
'div',
{ shouldForwardProp: (prop) => prop !== 'variant' && prop !== 'size' && prop !== 'sx' },
{ muiName: 'MuiTest', overridesResolver: testOverridesResolver, skipSx: true },
{ overridesResolver: testOverridesResolver, skipSx: true },
)(({ sx = {} }) => ({
...(sx.mt && {
marginTop: `${sx.mt * -1}px`,
Expand All @@ -384,7 +384,7 @@ describe('experimentalStyled', () => {
const TestWithSx = styled(
'div',
{ shouldForwardProp: (prop) => prop !== 'variant' && prop !== 'size' && prop !== 'sx' },
{ muiName: 'MuiTest', overridesResolver: testOverridesResolver },
{ overridesResolver: testOverridesResolver },
)(({ sx = {} }) => ({
...(sx.mt && {
marginTop: `${sx.m * -1}px`,
Expand All @@ -402,5 +402,81 @@ describe('experimentalStyled', () => {
marginTop: '8px',
});
});

it('should set displayName properly', () => {
const Component = styled(
'div',
{ shouldForwardProp: (prop) => prop !== 'variant' && prop !== 'size' && prop !== 'sx' },
{ name: 'Component' },
)`
width: 200px;
height: 300px;
`;

expect(Component.displayName).to.equal('Component');
});

it('should set displayName as name + slot if both are specified', () => {
const Component = styled(
'div',
{ shouldForwardProp: (prop) => prop !== 'variant' && prop !== 'size' && prop !== 'sx' },
{ name: 'Component', slot: 'Root' },
)`
width: 200px;
height: 300px;
`;

expect(Component.displayName).to.equal('ComponentRoot');
});

it('should set the className when generating the classes', () => {
const Component = styled(
'div',
{ shouldForwardProp: (prop) => prop !== 'variant' && prop !== 'size' && prop !== 'sx' },
{ name: 'Component', slot: 'Slot' },
)`
width: 200px;
height: 300px;
`;

const { container } = render(<Component>Test</Component>);

const classList = Array.from(container.firstChild.classList);
const regExp = new RegExp(`.*-MuiComponent-slot$`);
let containsValidClass = false;

classList.forEach((className) => {
if (regExp.test(className)) {
containsValidClass = true;
}
});

expect(containsValidClass).to.equal(true);
});

it('should set the className as root if no slot is specified', () => {
const Component = styled(
'div',
{ shouldForwardProp: (prop) => prop !== 'variant' && prop !== 'size' && prop !== 'sx' },
{ name: 'Component' },
)`
width: 200px;
height: 300px;
`;

const { container } = render(<Component>Test</Component>);

const classList = Array.from(container.firstChild.classList);
const regExp = new RegExp(`.*-MuiComponent-root$`);
let containsValidClass = false;

classList.forEach((className) => {
if (regExp.test(className)) {
containsValidClass = true;
}
});

expect(containsValidClass).to.equal(true);
});
});
});

0 comments on commit 3506dda

Please sign in to comment.