Skip to content

Commit

Permalink
[withStyles] Better theme.props support
Browse files Browse the repository at this point in the history
  • Loading branch information
oliviertassinari committed Sep 2, 2018
1 parent 4ea2ba5 commit 1f0b31e
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 22 deletions.
19 changes: 16 additions & 3 deletions packages/material-ui/src/styles/getThemeProps.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
/* eslint-disable no-restricted-syntax */

function getThemeProps(params) {
const { theme, name } = params;
const { theme, name, props } = params;

if (!name || !theme.props || !theme.props[name]) {
return {};
return props;
}

// Resolve default props, code borrow from React source.
// https://github.com/facebook/react/blob/15a8f031838a553e41c0b66eb1bcf1da8448104d/packages/react/src/ReactElement.js#L221
const defaultProps = theme.props[name];
let propName;

for (propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}

return theme.props[name];
return props;
}

export default getThemeProps;
3 changes: 3 additions & 0 deletions packages/material-ui/src/styles/getThemeProps.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ describe('getThemeProps', () => {
const props = getThemeProps({
theme: {},
name: 'MuiFoo',
props: {},
});
assert.deepEqual(props, {});
});
Expand All @@ -20,6 +21,7 @@ describe('getThemeProps', () => {
},
},
name: 'MuiFoo',
props: {},
});
assert.deepEqual(props, {});
});
Expand All @@ -34,6 +36,7 @@ describe('getThemeProps', () => {
},
},
name: 'MuiFoo',
props: {},
});
assert.deepEqual(props, {
disableRipple: true,
Expand Down
6 changes: 3 additions & 3 deletions packages/material-ui/src/styles/withStyles.js
Original file line number Diff line number Diff line change
Expand Up @@ -275,15 +275,15 @@ const withStyles = (stylesOrCreator, options = {}) => Component => {
render() {
const { classes, innerRef, ...other } = this.props;

const more = getThemeProps({ theme: this.theme, name });
const more = getThemeProps({ theme: this.theme, name, props: other });

// Provide the theme to the wrapped component.
// So we don't have to use the `withTheme()` Higher-order Component.
if (withTheme) {
if (withTheme && !more.theme) {
more.theme = this.theme;
}

return <Component {...more} classes={this.getClasses()} ref={innerRef} {...other} />;
return <Component {...more} classes={this.getClasses()} ref={innerRef} />;
}
}

Expand Down
22 changes: 22 additions & 0 deletions packages/material-ui/src/styles/withStyles.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,28 @@ describe('withStyles', () => {
assert.strictEqual(sheetsRegistry.registry.length, 0);
});

it('should support theme.props', () => {
const styles = { root: { display: 'flex' } };
const StyledComponent = withStyles(styles, { name: 'MuiFoo' })(Empty);

const wrapper = mount(
<MuiThemeProvider
theme={createMuiTheme({
props: {
MuiFoo: {
foo: 'bar',
},
},
})}
>
<StyledComponent foo={undefined} />
</MuiThemeProvider>,
);

assert.strictEqual(wrapper.find(Empty).props().foo, 'bar');
wrapper.unmount();
});

it('should work when depending on a theme', () => {
const styles = theme => ({ root: { padding: theme.spacing.unit } });
const StyledComponent = withStyles(styles, { name: 'MuiTextField' })(Empty);
Expand Down
30 changes: 14 additions & 16 deletions packages/material-ui/src/withWidth/withWidth.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,36 +98,34 @@ const withWidth = (options = {}) => Component => {
}

render() {
const { initialWidth, theme, width, ...other } = this.props;

const props = {
width:
width ||
this.state.width ||
initialWidth ||
initialWidthOption ||
getThemeProps({ theme, name: 'MuiWithWidth' }).initialWidth,
const { initialWidth, theme, width, ...other } = getThemeProps({
theme: this.props.theme,
name: 'MuiWithWidth',
props: { ...this.props },
});

const more = {
width: width || this.state.width || initialWidth || initialWidthOption,
...other,
};
const more = {};

if (withThemeOption) {
more.theme = theme;
}

// When rendering the component on the server,
// we have no idea about the client browser screen width.
// In order to prevent blinks and help the reconciliation of the React tree
// we are not rendering the child component.
//
// An alternative is to use the `initialWidth` property.
if (props.width === undefined) {
if (more.width === undefined) {
return null;
}

if (withThemeOption) {
more.theme = theme;
}

return (
<EventListener target="window" onResize={this.handleResize}>
<Component {...more} {...props} />
<Component {...more} />
</EventListener>
);
}
Expand Down

0 comments on commit 1f0b31e

Please sign in to comment.