Skip to content

Commit

Permalink
[Slider] Add sx prop in SliderStyled (mui#23205)
Browse files Browse the repository at this point in the history
  • Loading branch information
mnajdova authored and mbrookes committed Oct 23, 2020
1 parent e9cca64 commit 5f99c53
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 58 deletions.
36 changes: 23 additions & 13 deletions packages/material-ui-lab/src/SliderStyled/SliderStyled.d.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
import * as React from 'react';
import { OverridableComponent, OverrideProps } from '@material-ui/core/OverridableComponent';
import { SliderTypeMap } from '../SliderUnstyled';
import { SxProps } from '@material-ui/core/Box';
import { ExtendSliderUnstyledTypeMap, ExtendSliderUnstyled } from '../SliderUnstyled';

export type SliderProps<
D extends React.ElementType = SliderTypeMap['defaultComponent'],
export type SliderStyledTypeMap<
D extends React.ElementType = 'span',
P = {}
> = OverrideProps<SliderTypeMap<P, D>, D>;
> = ExtendSliderUnstyledTypeMap<{
props: P & {
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx?: SxProps;
};
defaultComponent: D;
}>;

type SliderRootProps = NonNullable<SliderProps['componentsProps']>['root'];
type SliderMarkProps = NonNullable<SliderProps['componentsProps']>['mark'];
type SliderMarkLabelProps = NonNullable<SliderProps['componentsProps']>['markLabel'];
type SliderRailProps = NonNullable<SliderProps['componentsProps']>['rail'];
type SliderTrackProps = NonNullable<SliderProps['componentsProps']>['track'];
type SliderThumbProps = NonNullable<SliderProps['componentsProps']>['thumb'];
type SliderValueLabel = NonNullable<SliderProps['componentsProps']>['valueLabel'];
type SliderRootProps = NonNullable<SliderStyledTypeMap['props']['componentsProps']>['root'];
type SliderMarkProps = NonNullable<SliderStyledTypeMap['props']['componentsProps']>['mark'];
type SliderMarkLabelProps = NonNullable<
SliderStyledTypeMap['props']['componentsProps']
>['markLabel'];
type SliderRailProps = NonNullable<SliderStyledTypeMap['props']['componentsProps']>['rail'];
type SliderTrackProps = NonNullable<SliderStyledTypeMap['props']['componentsProps']>['track'];
type SliderThumbProps = NonNullable<SliderStyledTypeMap['props']['componentsProps']>['thumb'];
type SliderValueLabel = NonNullable<SliderStyledTypeMap['props']['componentsProps']>['valueLabel'];

export const SliderRoot: React.FC<SliderRootProps>;
export const SliderMark: React.FC<SliderMarkProps>;
Expand All @@ -33,6 +43,6 @@ export const SliderValueLabel: React.FC<SliderValueLabel>;
*
* - [SliderStyled API](https://material-ui.com/api/slider-styled/)
*/
declare const Slider: OverridableComponent<SliderTypeMap>;
declare const Slider: ExtendSliderUnstyled<SliderStyledTypeMap>;

export default Slider;
4 changes: 4 additions & 0 deletions packages/material-ui-lab/src/SliderStyled/SliderStyled.js
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,10 @@ Slider.propTypes = {
* @default 1
*/
step: PropTypes.number,
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx: PropTypes.object,
/**
* The track presentation:
*
Expand Down
14 changes: 13 additions & 1 deletion packages/material-ui-lab/src/SliderUnstyled/SliderUnstyled.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { OverridableComponent } from '@material-ui/core/OverridableComponent';
import { OverridableComponent, OverridableTypeMap } from '@material-ui/core/OverridableComponent';

export interface Mark {
value: number;
Expand Down Expand Up @@ -195,6 +195,18 @@ export interface SliderTypeMap<P = {}, D extends React.ElementType = 'span'> {
defaultComponent: D;
}

/**
* Utility to create component types that inherit props from SliderUnstyled.
*/
export interface ExtendSliderUnstyledTypeMap<M extends OverridableTypeMap> {
props: M['props'] & Omit<SliderTypeMap['props'], 'classes'>;
defaultComponent: M['defaultComponent'];
}

export type ExtendSliderUnstyled<M extends OverridableTypeMap> = OverridableComponent<
ExtendSliderUnstyledTypeMap<M>
>;

/**
*
* Demos:
Expand Down
11 changes: 9 additions & 2 deletions packages/material-ui-styled-engine-sc/src/index.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import scStyled from 'styled-components';

export default function styled(tag, options) {
let scStyledPrepared;

if (options) {
return scStyled(tag).withConfig({
scStyledPrepared = scStyled(tag).withConfig({
displayName: options.label,
shouldForwardProp: options.shouldForwardProp,
});
} else {
scStyledPrepared = scStyled(tag);
}

return scStyled(tag);
// TODO: This should not be required once we solve the warning `You have illegal escape sequence in your template literal`
return (styles) => {
return scStyledPrepared(...styles);
};
}

export { ThemeContext } from 'styled-components';
3 changes: 2 additions & 1 deletion packages/material-ui/src/Box/Box.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ export type BoxStyleFunction = ComposedStyleFunction<
type SystemProps = PropsFor<BoxStyleFunction>;
type ElementProps = Omit<React.HTMLAttributes<HTMLElement>, keyof SystemProps>;
type SxPropsValue = Omit<CSSObject, keyof SystemProps> & SystemProps;
type SxProps = {

export type SxProps = {
[Name in keyof SxPropsValue]?:
| SxPropsValue[Name]
| ((theme: Theme) => CSSObject | SxPropsValue[Name])
Expand Down
2 changes: 1 addition & 1 deletion packages/material-ui/src/Box/styleFunction.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const getThemeValue = (prop, value, theme) => {
return { [prop]: value };
};

const styleFunctionSx = (styles, theme) => {
export const styleFunctionSx = (styles, theme) => {
if (!styles) return null;

if (typeof styles === 'function') {
Expand Down
10 changes: 8 additions & 2 deletions packages/material-ui/src/styles/experimentalStyled.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import styled from '@material-ui/styled-engine';
import { propsToClassKey } from '@material-ui/styles';
import { styleFunctionSx } from '../Box/styleFunction';
import defaultTheme from './defaultTheme';

function isEmpty(obj) {
Expand Down Expand Up @@ -58,7 +59,7 @@ const variantsResolver = (props, styles, theme, name) => {
return variantsStyles;
};

const shouldForwardProp = (prop) => prop !== 'styleProps' && prop !== 'theme';
const shouldForwardProp = (prop) => prop !== 'styleProps' && prop !== 'theme' && prop !== 'sx';

const experimentalStyled = (tag, options, muiOptions = {}) => {
const name = muiOptions.muiName;
Expand All @@ -85,7 +86,12 @@ const experimentalStyled = (tag, options, muiOptions = {}) => {
});
}

return defaultStyledResolver(...stylesWithDefaultTheme);
stylesWithDefaultTheme.push((props) => {
const theme = isEmpty(props.theme) ? defaultTheme : props.theme;
return styleFunctionSx(props.sx, theme);
});

return defaultStyledResolver(stylesWithDefaultTheme);
};
return muiStyledResolver;
};
Expand Down
85 changes: 47 additions & 38 deletions packages/material-ui/src/styles/experimentalStyled.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { expect } from 'chai';
import { createClientRender, screen } from 'test/utils';
import { createClientRender } from 'test/utils';
import createMuiTheme from './createMuiTheme';
import styled from './experimentalStyled';
import ThemeProvider from './ThemeProvider';
Expand All @@ -13,9 +13,9 @@ describe('experimentalStyled', () => {
width: '200px',
});

render(<Div data-testid="component">Test</Div>);
const { container } = render(<Div>Test</Div>);

expect(screen.getByTestId('component')).toHaveComputedStyle({
expect(container.firstChild).toHaveComputedStyle({
width: '200px',
});
});
Expand All @@ -25,9 +25,9 @@ describe('experimentalStyled', () => {
width: props.theme.spacing(1),
}));

render(<Div data-testid="component">Test</Div>);
const { container } = render(<Div>Test</Div>);

expect(screen.getByTestId('component')).toHaveComputedStyle({
expect(container.firstChild).toHaveComputedStyle({
width: '8px',
});
});
Expand All @@ -41,13 +41,13 @@ describe('experimentalStyled', () => {
spacing: 10,
});

render(
const { container } = render(
<ThemeProvider theme={theme}>
<Div data-testid="component">Test</Div>
<Div>Test</Div>
</ThemeProvider>,
);

expect(screen.getByTestId('component')).toHaveComputedStyle({
expect(container.firstChild).toHaveComputedStyle({
width: '10px',
});
});
Expand All @@ -64,6 +64,11 @@ describe('experimentalStyled', () => {

before(() => {
theme = createMuiTheme({
palette: {
primary: {
main: 'rgb(0, 0, 255)',
},
},
components: {
MuiTest: {
variants: [
Expand Down Expand Up @@ -92,69 +97,61 @@ describe('experimentalStyled', () => {
...(props.variant && styles[props.variant]),
});

// FIXME: Should not error in DEV
expect(() => {
Test = styled(
'div',
{ shouldForwardProp: (prop) => prop !== 'variant' && prop !== 'size' },
{ muiName: 'MuiTest', overridesResolver: testOverridesResolver },
)`
width: 200px;
height: 300px;
`;
}).toErrorDev([
'You have illegal escape sequence in your template literal',
'You have illegal escape sequence in your template literal',
]);
Test = styled(
'div',
{ shouldForwardProp: (prop) => prop !== 'variant' && prop !== 'size' && prop !== 'sx' },
{ muiName: 'MuiTest', overridesResolver: testOverridesResolver },
)`
width: 200px;
height: 300px;
`;
});

it('should work with specified muiOptions', () => {
render(<Test data-testid="component">Test</Test>);
const { container } = render(<Test>Test</Test>);

expect(screen.getByTestId('component')).toHaveComputedStyle({
expect(container.firstChild).toHaveComputedStyle({
width: '200px',
height: '300px',
});
});

it('overrides should be respected', () => {
render(
const { container } = render(
<ThemeProvider theme={theme}>
<Test data-testid="component">Test</Test>
<Test>Test</Test>
</ThemeProvider>,
);

expect(screen.getByTestId('component')).toHaveComputedStyle({
expect(container.firstChild).toHaveComputedStyle({
width: '250px',
height: '300px',
});
});

it('overrides should be respected when prop is specified', () => {
render(
const { container } = render(
<ThemeProvider theme={theme}>
<Test variant="rect" data-testid="component">
Test
</Test>
<Test variant="rect">Test</Test>
</ThemeProvider>,
);

expect(screen.getByTestId('component')).toHaveComputedStyle({
expect(container.firstChild).toHaveComputedStyle({
width: '250px',
height: '250px',
});
});

it('variants should win over overrides', () => {
render(
const { container } = render(
<ThemeProvider theme={theme}>
<Test data-testid="component" variant="rect" size="large">
<Test variant="rect" size="large">
Test
</Test>
</ThemeProvider>,
);

expect(screen.getByTestId('component')).toHaveComputedStyle({
expect(container.firstChild).toHaveComputedStyle({
width: '400px',
height: '400px',
});
Expand All @@ -165,18 +162,30 @@ describe('experimentalStyled', () => {
width: 500px;
`;

render(
const { container } = render(
<ThemeProvider theme={theme}>
<CustomTest data-testid="component" variant="rect" size="large">
<CustomTest variant="rect" size="large">
Test
</CustomTest>
</ThemeProvider>,
);

expect(screen.getByTestId('component')).toHaveComputedStyle({
expect(container.firstChild).toHaveComputedStyle({
width: '500px',
height: '400px',
});
});

it('should resolve the sx prop', () => {
const { container } = render(
<ThemeProvider theme={theme}>
<Test sx={{ color: 'primary.main' }}>Test</Test>
</ThemeProvider>,
);

expect(container.firstChild).toHaveComputedStyle({
color: 'rgb(0, 0, 255)',
});
});
});
});

0 comments on commit 5f99c53

Please sign in to comment.