Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[muiStyled] Support default theme when none is available #22791

Merged
merged 40 commits into from
Oct 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
c2d31cc
add emotion peer dependencies
mnajdova Sep 25, 2020
5ae933f
fixed types & tests
mnajdova Sep 25, 2020
18b0668
prettier
mnajdova Sep 25, 2020
f0ef95c
Merge branch 'next' of https://github.com/mui-org/material-ui into next
mnajdova Sep 28, 2020
c7bebb8
Merge branch 'next' of https://github.com/mui-org/material-ui into next
mnajdova Sep 28, 2020
92b2d6e
Merge branch 'next' of https://github.com/mui-org/material-ui into next
mnajdova Sep 28, 2020
76256f1
wip
mnajdova Sep 28, 2020
8661306
added ThemeProvider
mnajdova Sep 28, 2020
61d7fac
exported ThemeProvider from styled-engine-sc
mnajdova Sep 28, 2020
c9fcdc1
tests wip
mnajdova Sep 28, 2020
48305e9
tests
mnajdova Sep 28, 2020
1c04d40
prettier
mnajdova Sep 28, 2020
27d9f73
Update packages/material-ui/src/styles/muiStyled.d.ts
mnajdova Sep 29, 2020
b149da5
Update packages/material-ui/src/styles/customStyled.d.ts
mnajdova Sep 29, 2020
05217a7
renamed styled -> legacy_styled, renamed customStyled -> styled
mnajdova Sep 29, 2020
3bf96aa
fixed tests
mnajdova Sep 29, 2020
551157f
added migration step, exported styled with deprecation warning
mnajdova Sep 29, 2020
a03252c
prettier
mnajdova Sep 29, 2020
179a6e2
renamed legacy_styled back to styled
mnajdova Sep 29, 2020
9878176
renamed styled to experimentalStyled
mnajdova Sep 29, 2020
17ce5d4
fix
mnajdova Sep 29, 2020
b7ccb20
specify ThemeProvider as export from emotion-theming
mnajdova Sep 29, 2020
72398c8
refactored muiStyled to be used as simple styled utility too
mnajdova Sep 29, 2020
58a1fb9
fix lint issues
mnajdova Sep 29, 2020
aac9e83
renamed muiStyled to experimentalStyled
mnajdova Sep 30, 2020
5774c19
refactored to use ThemeContext
mnajdova Sep 30, 2020
8016f92
Update packages/material-ui-styles/README.md
mnajdova Sep 30, 2020
6bc05c1
Update packages/material-ui-styles/README.md
mnajdova Sep 30, 2020
9757a00
Update packages/material-ui-styles/package.json
mnajdova Sep 30, 2020
bb880fe
Moved nesting ThemeProvider to core
mnajdova Oct 1, 2020
73d6589
Update packages/material-ui/src/styles/experimentalStyled.d.ts
mnajdova Oct 1, 2020
6e2b480
Update packages/material-ui/src/styles/experimentalStyled.d.ts
mnajdova Oct 1, 2020
0c8be58
added test
mnajdova Oct 1, 2020
a001588
fixed docs generation
mnajdova Oct 1, 2020
e676780
Update packages/material-ui/src/styles/ThemeProvider.js
mnajdova Oct 1, 2020
0298222
Update packages/material-ui/src/styles/experimentalStyled.d.ts
mnajdova Oct 1, 2020
c96062d
addressed comments
mnajdova Oct 1, 2020
3e419ac
Update packages/material-ui/src/styles/ThemeProvider.js
mnajdova Oct 2, 2020
4fccc26
Update packages/material-ui/src/styles/ThemeProvider.js
mnajdova Oct 2, 2020
dcc97fa
docs:api
mnajdova Oct 2, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions docs/pages/api-docs/theme-provider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';
import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs';
import { prepareMarkdown } from 'docs/src/modules/utils/parseMarkdown';

const pageFilename = 'api/theme-provider';
const requireRaw = require.context('!raw-loader!./', false, /\/theme-provider\.md$/);

export default function Page({ docs }) {
return <MarkdownDocs docs={docs} />;
}

Page.getInitialProps = () => {
const { demos, docs } = prepareMarkdown({ pageFilename, requireRaw });
return { demos, docs };
};
33 changes: 33 additions & 0 deletions docs/pages/api-docs/theme-provider.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
filename: /packages/material-ui/src/styles/ThemeProvider.js
---

<!--- This documentation is automatically generated, do not try to edit it. -->

# ThemeProvider API

<p class="description">The API documentation of the ThemeProvider React component. Learn more about the props and the CSS customization points.</p>

## Import

```js
import ThemeProvider from '@material-ui/core/styles/ThemeProvider.js/ThemeProvider';
// or
import { ThemeProvider } from '@material-ui/core/styles/ThemeProvider.js';
```

You can learn more about the difference by [reading this guide](/guides/minimizing-bundle-size/).

This component makes the `theme` available down the React tree.
It should preferably be used at **the root of your component tree**.



## Props

| Name | Type | Default | Description |
|:-----|:-----|:--------|:------------|

The component cannot hold a ref.


13 changes: 5 additions & 8 deletions docs/src/pages/components/slider-styled/ContinuousSlider.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,24 @@
import * as React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import { experimentalStyled as styled } from '@material-ui/core/styles';
import Grid from '@material-ui/core/Grid';
import Typography from '@material-ui/core/Typography';
import Slider from '@material-ui/lab/SliderStyled';
import VolumeDown from '@material-ui/icons/VolumeDown';
import VolumeUp from '@material-ui/icons/VolumeUp';

const useStyles = makeStyles({
root: {
width: 200,
},
const Root = styled('div')({
width: 200,
});

export default function ContinuousSlider() {
const classes = useStyles();
const [value, setValue] = React.useState(30);

const handleChange = (event, newValue) => {
setValue(newValue);
};

return (
<div className={classes.root}>
<Root>
<Typography id="continuous-slider" gutterBottom>
Volume
</Typography>
Expand All @@ -44,6 +41,6 @@ export default function ContinuousSlider() {
Disabled slider
</Typography>
<Slider disabled defaultValue={30} aria-labelledby="disabled-slider" />
</div>
</Root>
);
}
13 changes: 5 additions & 8 deletions docs/src/pages/components/slider-styled/ContinuousSlider.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
import * as React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import { experimentalStyled as styled } from '@material-ui/core/styles';
import Grid from '@material-ui/core/Grid';
import Typography from '@material-ui/core/Typography';
import Slider from '@material-ui/lab/SliderStyled';
import VolumeDown from '@material-ui/icons/VolumeDown';
import VolumeUp from '@material-ui/icons/VolumeUp';

const useStyles = makeStyles({
root: {
width: 200,
},
const Root = styled('div')({
width: 200,
});

export default function ContinuousSlider() {
const classes = useStyles();
const [value, setValue] = React.useState<number>(30);

const handleChange = (
Expand All @@ -24,7 +21,7 @@ export default function ContinuousSlider() {
};

return (
<div className={classes.root}>
<Root>
<Typography id="continuous-slider" gutterBottom>
Volume
</Typography>
Expand All @@ -47,6 +44,6 @@ export default function ContinuousSlider() {
Disabled slider
</Typography>
<Slider disabled defaultValue={30} aria-labelledby="disabled-slider" />
</div>
</Root>
);
}
4 changes: 2 additions & 2 deletions packages/material-ui-lab/src/SliderStyled/SliderStyled.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import { useThemeProps, muiStyled, fade, lighten, darken } from '@material-ui/core/styles';
import { useThemeProps, experimentalStyled, fade, lighten, darken } from '@material-ui/core/styles';
import { capitalize } from '@material-ui/core/utils';
import SliderUnstyled from '../SliderUnstyled';
import ValueLabelStyled from './ValueLabelStyled';
Expand Down Expand Up @@ -48,7 +48,7 @@ const overridesResolver = (props, styles, name) => {
return styleOverrides;
};

const SliderRoot = muiStyled(
const SliderRoot = experimentalStyled(
'span',
{},
{ muiName: 'MuiSlider', overridesResolver },
Expand Down
4 changes: 2 additions & 2 deletions packages/material-ui-lab/src/SliderStyled/ValueLabelStyled.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { useThemeProps, muiStyled } from '@material-ui/core/styles';
import { useThemeProps, experimentalStyled } from '@material-ui/core/styles';
import ValueLabelUnstyled from '../SliderUnstyled/ValueLabelUnstyled';

const overridesResolver = (_, styles) => {
Expand All @@ -16,7 +16,7 @@ const overridesResolver = (_, styles) => {
return styleOverrides;
};

const ValueLabelRoot = muiStyled(
const ValueLabelRoot = experimentalStyled(
'span',
{},
{ muiName: 'PrivateValueLabel', overridesResolver },
Expand Down
2 changes: 2 additions & 0 deletions packages/material-ui-styled-engine-sc/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ export default function styled(tag, options) {

return scStyled(tag);
}

export { ThemeContext } from 'styled-components';
1 change: 1 addition & 0 deletions packages/material-ui-styled-engine/src/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from '@emotion/styled';
export { default } from '@emotion/styled';
export { ThemeContext } from '@emotion/core';
1 change: 1 addition & 0 deletions packages/material-ui-styled-engine/src/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { default } from '@emotion/styled';
export { ThemeContext } from '@emotion/core';
17 changes: 17 additions & 0 deletions packages/material-ui/src/styles/ThemeProvider.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { DefaultTheme } from '@material-ui/styles';

export interface ThemeProviderProps<Theme = DefaultTheme> {
children?: React.ReactNode;
theme: Partial<Theme> | ((outerTheme: Theme) => Theme);
}

/**
* This component makes the `theme` available down the React tree.
* It should preferably be used at **the root of your component tree**.
* API:
*
* - [ThemeProvider API](https://material-ui.com/api/theme-provider/)
*/
export default function ThemeProvider<T = DefaultTheme>(
props: ThemeProviderProps<T>
): React.ReactElement<ThemeProviderProps<T>>;
53 changes: 53 additions & 0 deletions packages/material-ui/src/styles/ThemeProvider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from 'react';
import PropTypes from 'prop-types';
import { ThemeProvider as MuiThemeProvider } from '@material-ui/styles';
import { exactProp } from '@material-ui/utils';
import { ThemeContext as StyledEngineThemeContext } from '@material-ui/styled-engine';
import useTheme from './useTheme';

function InnerThemeProvider({ children }) {
const theme = useTheme();
return (
<StyledEngineThemeContext.Provider value={typeof theme === 'object' ? theme : {}}>
{children}
</StyledEngineThemeContext.Provider>
);
}

InnerThemeProvider.propTypes = {
/**
* Your component tree.
*/
children: PropTypes.node,
};

/**
* This component makes the `theme` available down the React tree.
* It should preferably be used at **the root of your component tree**.
*/
function ThemeProvider(props) {
const { children, theme: localTheme } = props;

return (
<MuiThemeProvider theme={localTheme}>
<InnerThemeProvider>{children}</InnerThemeProvider>
</MuiThemeProvider>
);
}

ThemeProvider.propTypes = {
/**
* Your component tree.
*/
children: PropTypes.node,
/**
* A theme object. You can provide a function to extend the outer theme.
*/
theme: PropTypes.oneOfType([PropTypes.object, PropTypes.func]).isRequired,
};

if (process.env.NODE_ENV !== 'production') {
ThemeProvider.propTypes = exactProp(ThemeProvider.propTypes);
}

export default ThemeProvider;
44 changes: 44 additions & 0 deletions packages/material-ui/src/styles/ThemeProvider.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from 'react';
import { expect } from 'chai';
import { createClientRender } from 'test/utils';
import { useTheme } from '@material-ui/styles';
import { ThemeContext } from '@material-ui/styled-engine';
import ThemeProvider from './ThemeProvider';

describe('ThemeProvider', () => {
const render = createClientRender();

it('should provide the theme to the mui theme context', () => {
let theme;

function Test() {
theme = useTheme();

return null;
}

render(
<ThemeProvider theme={{ foo: 'foo' }}>
<Test />
</ThemeProvider>,
);
expect(theme).to.deep.equal({ foo: 'foo' });
});

it('should provide the theme to the styled engine theme context', () => {
let theme;

function Test() {
theme = React.useContext(ThemeContext);

return null;
}

render(
<ThemeProvider theme={{ foo: 'foo' }}>
<Test />
</ThemeProvider>,
);
expect(theme).to.deep.equal({ foo: 'foo' });
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ interface MuiStyledOptions<Theme extends object = any> {
overridesResolver?: (props: any, styles: string | object, name: string) => string | object;
}

export interface CreateStyled<Theme extends object = any> {
export interface CreateMUIStyled<Theme extends object = any> {
<Tag extends React.ComponentType<any>, ExtraProps = {}>(
tag: Tag,
options?: StyledOptions,
Expand All @@ -198,11 +198,13 @@ export interface CreateStyled<Theme extends object = any> {
}

/**
* Cutom styled functionality that support mui specific config.
* Custom styled utility that has a default MUI theme.
*
* @param options Takes an incomplete theme object and adds the missing parts.
* @returns A complete, ready to use theme object.
* @param tag HTML tag or component that should serve as base.
* @param options Styled options for the created component.
* @param muiOptions Material-UI specific style options.
* @returns React component that has styles attached to it.
*/
declare const muiStyled: CreateStyled;
declare const experimentalStyled: CreateMUIStyled;

export default muiStyled;
export default experimentalStyled;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import styled from '@material-ui/styled-engine';
import { propsToClassKey } from '@material-ui/styles';
import defaultTheme from './defaultTheme';

function isEmpty(obj) {
return Object.keys(obj).length === 0;
}

const getStyleOverrides = (name, theme) => {
let styleOverrides = {};

Expand Down Expand Up @@ -41,7 +45,7 @@ const variantsResolver = (props, styles, theme, name) => {
themeVariants.forEach((themeVariant) => {
let isMatch = true;
Object.keys(themeVariant.props).forEach((key) => {
if (styleProps[key] !== themeVariant.props[key]) {
if (styleProps[key] !== themeVariant.props[key] && props[key] !== themeVariant.props[key]) {
isMatch = false;
}
});
Expand All @@ -56,25 +60,34 @@ const variantsResolver = (props, styles, theme, name) => {

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

const muiStyled = (tag, options, muiOptions) => {
const experimentalStyled = (tag, options, muiOptions = {}) => {
const name = muiOptions.muiName;
const defaultStyledResolver = styled(tag, { shouldForwardProp, label: name, ...options });
const muiStyledResolver = (...styles) => {
if (muiOptions.overridesResolver) {
styles.push((props) => {
const theme = props.theme || defaultTheme;
const stylesWithDefaultTheme = styles.map((stylesArg) => {
return typeof stylesArg === 'function'
? ({ theme: themeInput, ...rest }) =>
stylesArg({ theme: isEmpty(themeInput) ? defaultTheme : themeInput, ...rest })
eps1lon marked this conversation as resolved.
Show resolved Hide resolved
: stylesArg;
});

if (name && muiOptions.overridesResolver) {
stylesWithDefaultTheme.push((props) => {
const theme = isEmpty(props.theme) ? defaultTheme : props.theme;
return muiOptions.overridesResolver(props, getStyleOverrides(name, theme), name);
});
}

styles.push((props) => {
const theme = props.theme || defaultTheme;
return variantsResolver(props, getVariantStyles(name, theme), theme, name);
});
if (name) {
stylesWithDefaultTheme.push((props) => {
const theme = isEmpty(props.theme) ? defaultTheme : props.theme;
return variantsResolver(props, getVariantStyles(name, theme), theme, name);
});
}

return defaultStyledResolver(...styles);
return defaultStyledResolver(...stylesWithDefaultTheme);
};
return muiStyledResolver;
};

export default muiStyled;
export default experimentalStyled;
Loading