import * as React from 'react'; import { createStyles, withStyles, createMuiTheme, MuiThemeProvider, Theme, withTheme, StyleRules, StyleRulesCallback, StyledComponentProps, WithStyles, } from '@material-ui/core/styles'; import Button from '@material-ui/core/Button/Button'; import blue from '@material-ui/core/colors/blue'; import { WithTheme } from '@material-ui/core/styles/withTheme'; import { PropsOf, StandardProps } from '@material-ui/core'; import { TypographyStyle } from '@material-ui/core/styles/createTypography'; // Shared types for examples interface ComponentProps extends WithStyles { text: string; } // Example 1 const styles = ({ palette, spacing }: Theme) => ({ root: { padding: spacing.unit, backgroundColor: palette.background.default, color: palette.primary.dark, }, }); const StyledExampleOne = withStyles(styles)(({ classes, text }: ComponentProps) => (
{text}
)); ; // Example 2 const Component: React.SFC> = ({ classes, text }) => (
{text}
); const StyledExampleTwo = withStyles(styles)(Component); ; // Example 3 const styleRule = createStyles({ root: { display: 'flex', alignItems: 'stretch', height: '100vh', width: '100%', }, }); const ComponentWithChildren: React.SFC> = ({ classes, children }) => (
{children}
); const StyledExampleThree = withStyles(styleRule)(ComponentWithChildren); ; // Also works with a plain object const stylesAsPojo = { root: { backgroundColor: 'hotpink', }, }; const AnotherStyledSFC = withStyles({ root: { backgroundColor: 'hotpink' }, })(({ classes }: WithStyles<'root'>) =>
Stylish!
); // Overriding styles const theme = createMuiTheme({ palette: { type: 'dark', primary: blue, contrastThreshold: 3, tonalOffset: 0.2, common: { white: '#ffffff', }, }, typography: { h1: { fontSize: 24, }, fontSize: 18, }, mixins: { toolbar: { backgroundColor: 'red', }, }, breakpoints: { step: 3, }, transitions: { duration: { short: 50, }, }, spacing: {}, zIndex: { appBar: 42, }, overrides: { MuiButton: { // Name of the styleSheet root: { // Name of the rule background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)', borderRadius: 3, border: 0, color: 'white', height: 48, padding: '0 30px', boxShadow: '0 3px 5px 2px rgba(255, 105, 135, .3)', }, }, }, props: { MuiButton: { disabled: true, }, MuiAppBar: { position: 'fixed', }, }, }); const theme2 = createMuiTheme({ palette: { primary: { main: blue[500], }, }, props: { MuiButton: { disabled: false, TouchRippleProps: { center: true, }, }, MuiTable: { cellPadding: 12, }, MuiButtonBase: { disableRipple: true, }, }, }); function OverridesTheme() { return ( ); } // withTheme const ComponentWithTheme = withTheme()(({ theme }: WithTheme) =>
{theme.spacing.unit}
); ; // withStyles + withTheme type AllTheProps = WithTheme & WithStyles; const StyledComponent = withStyles(styles)(({ theme, classes }: AllTheProps) => (
{theme.palette.text.primary}
)); // missing prop theme ; // $ExpectError const AllTheComposition = withTheme()(StyledComponent); ; { const Foo = withTheme()( class extends React.Component { render() { return null; } }, ); ; } declare const themed: boolean; { // Test that withTheme: true guarantees the presence of the theme const Foo = withStyles({}, { withTheme: true })( class extends React.Component { render() { return
; } }, ); ; const Bar = withStyles({}, { withTheme: true })(({ theme }: WithStyles) => (
)); ; } // Can't use withStyles effectively as a decorator in TypeScript // due to https://github.com/Microsoft/TypeScript/issues/4881 // @withStyles(styles) const DecoratedComponent = withStyles(styles)( class extends React.Component> { render() { const { classes, text } = this.props; return
{text}
; } }, ); // no 'classes' property required at element creation time (#8267) ; // Allow nested pseudo selectors withStyles(theme => createStyles({ guttered: theme.mixins.gutters({ '&:hover': { textDecoration: 'none', }, }), listItem: { '&:hover $listItemIcon': { visibility: 'inherit', }, }, }), ); { // allow top level media queries // https://github.com/mui-org/material-ui/issues/12277 // typescript thinks `content` is the CSS property not a classname const ambiguousStyles = createStyles({ content: { minHeight: '100vh', }, '@media (min-width: 960px)': { // $ExpectError content: { display: 'flex', }, }, }); const styles = createStyles({ contentClass: { minHeight: '100vh', }, '@media (min-width: 960px)': { contentClass: { display: 'flex', }, }, }); } { const styles = (theme: Theme) => createStyles({ // Styled similar to ListItemText root: { '&:first-child': { paddingLeft: 0, }, flex: '1 1 auto', padding: '0 16px', }, iiiinset: { '&:first-child': { paddingLeft: theme.spacing.unit * 7, }, }, row: { alignItems: 'center', display: 'flex', flexDirection: 'row', }, }); interface ListItemContentProps extends WithStyles { children?: React.ReactElement; inset?: boolean; row?: boolean; } const ListItemContent = withStyles(styles, { name: 'ui-ListItemContent' })( ({ children, classes, inset, row }: ListItemContentProps) => (
{children}
), ); } { interface FooProps extends WithStyles<'x' | 'y'> { a: number; b: boolean; } const ListItemContent = withStyles({ x: {}, y: {} })((props: FooProps) =>
); } { // https://github.com/mui-org/material-ui/issues/11109 // The real test here is with "strictFunctionTypes": false, // but we don't have a way currently to test under varying // TypeScript configurations. interface ComponentProps extends WithStyles { caption: string; } const styles = (theme: Theme) => createStyles({ content: { margin: 4, }, }); const Component = (props: ComponentProps) => { return
Hello {props.caption}
; }; const StyledComponent = withStyles(styles)(Component); class App extends React.Component { render() { return (
); } } ; } { // https://github.com/mui-org/material-ui/issues/11191 const styles = (theme: Theme) => createStyles({ main: {}, }); interface Props extends WithStyles { someProp?: string; } class SomeComponent extends React.PureComponent { render() { return
; } } const DecoratedSomeComponent = withStyles(styles)(SomeComponent); ; } { // https://github.com/mui-org/material-ui/issues/11312 withStyles(styles, { name: 'MyComponent', index: 0 })(() =>
); } { // https://github.com/mui-org/material-ui/issues/11164 const style: StyleRulesCallback = theme => ({ text: theme.typography.body2, }); } { // can't provide own `classes` type interface Props { classes: number; } class Component extends React.Component> {} // $ExpectError const StyledComponent = withStyles(styles)(Component); // implicit SFC withStyles(styles)((props: Props) => null); // $ExpectError withStyles(styles)((props: Props & WithStyles) => null); // $ExpectError withStyles(styles)((props: Props & { children?: React.ReactNode }) => null); // $ExpectError withStyles(styles)( (props: Props & WithStyles & { children?: React.ReactNode }) => null, // $ExpectError ); // explicit not but with "Property 'children' is missing in type 'ValidationMap'". // which is not helpful const StatelessComponent: React.SFC = props => null; const StatelessComponentWithStyles: React.SFC> = props => null; withStyles(styles)(StatelessComponent); // $ExpectError withStyles(styles)(StatelessComponentWithStyles); // $ExpectError } { // https://github.com/mui-org/material-ui/issues/12670 interface Props { nonDefaulted: string; defaulted: number; } class MyButton extends React.Component> { static defaultProps = { defaulted: 0, }; render() { const { classes, nonDefaulted, defaulted } = this.props; return ( ); } } const styles = () => createStyles({ btn: { color: 'red', }, }); const StyledMyButton = withStyles(styles)(MyButton); const CorrectUsage = () => ; // Property 'nonDefaulted' is missing in type '{}' const MissingPropUsage = () => ; // $ExpectError }