diff --git a/docs/pages/api-docs/mobile-stepper.json b/docs/pages/api-docs/mobile-stepper.json index 589b8428827995..881c9b01f41cd5 100644 --- a/docs/pages/api-docs/mobile-stepper.json +++ b/docs/pages/api-docs/mobile-stepper.json @@ -13,6 +13,7 @@ }, "default": "'bottom'" }, + "sx": { "type": { "name": "object" } }, "variant": { "type": { "name": "enum", @@ -41,6 +42,6 @@ "filename": "/packages/material-ui/src/MobileStepper/MobileStepper.js", "inheritance": { "component": "Paper", "pathname": "/api/paper/" }, "demos": "", - "styledComponent": false, + "styledComponent": true, "cssComponent": false } diff --git a/docs/translations/api-docs/mobile-stepper/mobile-stepper.json b/docs/translations/api-docs/mobile-stepper/mobile-stepper.json index fbb4937f610891..bf775aa47ea017 100644 --- a/docs/translations/api-docs/mobile-stepper/mobile-stepper.json +++ b/docs/translations/api-docs/mobile-stepper/mobile-stepper.json @@ -8,6 +8,7 @@ "nextButton": "A next button element. For instance, it can be a Button or an IconButton.", "position": "Set the positioning type.", "steps": "The total steps.", + "sx": "The system prop that allows defining system overrides as well as additional CSS styles. See the `sx` page for more details.", "variant": "The variant to use." }, "classDescriptions": { diff --git a/packages/material-ui/src/MobileStepper/MobileStepper.d.ts b/packages/material-ui/src/MobileStepper/MobileStepper.d.ts index 42919b12821756..67c17ff2f0e660 100644 --- a/packages/material-ui/src/MobileStepper/MobileStepper.d.ts +++ b/packages/material-ui/src/MobileStepper/MobileStepper.d.ts @@ -1,5 +1,6 @@ import * as React from 'react'; -import { InternalStandardProps as StandardProps } from '..'; +import { SxProps } from '@material-ui/system'; +import { InternalStandardProps as StandardProps, Theme } from '..'; import { PaperProps } from '../Paper'; import { LinearProgressProps } from '../LinearProgress'; @@ -52,6 +53,10 @@ export interface MobileStepperProps extends StandardProps; /** * The variant to use. * @default 'dots' diff --git a/packages/material-ui/src/MobileStepper/MobileStepper.js b/packages/material-ui/src/MobileStepper/MobileStepper.js index 081fc410987dec..6659cf563deb7f 100644 --- a/packages/material-ui/src/MobileStepper/MobileStepper.js +++ b/packages/material-ui/src/MobileStepper/MobileStepper.js @@ -1,47 +1,101 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import clsx from 'clsx'; -import { integerPropType } from '@material-ui/utils'; -import withStyles from '../styles/withStyles'; +import { integerPropType, deepmerge } from '@material-ui/utils'; +import { unstable_composeClasses as composeClasses } from '@material-ui/unstyled'; import Paper from '../Paper'; import capitalize from '../utils/capitalize'; import LinearProgress from '../LinearProgress'; -export const styles = (theme) => ({ - /* Styles applied to the root element. */ - root: { - display: 'flex', - flexDirection: 'row', - justifyContent: 'space-between', - alignItems: 'center', - background: theme.palette.background.default, - padding: 8, +import useThemeProps from '../styles/useThemeProps'; +import experimentalStyled from '../styles/experimentalStyled'; +import mobileStepperClasses, { getMobileStepperUtilityClass } from './mobileStepperClasses'; + +const overridesResolver = (props, styles) => { + const { styleProps } = props; + + return deepmerge( + { + ...styles[`position${capitalize(styleProps.position)}`], + [`& .${mobileStepperClasses.dots}`]: styles.dots, + [`& .${mobileStepperClasses.dot}`]: { + ...styles.dot, + ...(styleProps.dotActive && styles.dotActive), + }, + [`& .${mobileStepperClasses.dotActive}`]: styles.dotActive, + [`& .${mobileStepperClasses.progress}`]: styles.progress, + }, + styles.root || {}, + ); +}; + +const useUtilityClasses = (styleProps) => { + const { classes, position } = styleProps; + + const slots = { + root: ['root', `position${capitalize(position)}`], + dots: ['dots'], + dot: ['dot'], + dotActive: ['dotActive'], + progress: ['progress'], + }; + + return composeClasses(slots, getMobileStepperUtilityClass, classes); +}; + +const MobileStepperRoot = experimentalStyled( + Paper, + {}, + { + name: 'MuiMobileStepper', + slot: 'Root', + overridesResolver, }, +)(({ theme, styleProps }) => ({ + /* Styles applied to the root element. */ + display: 'flex', + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + background: theme.palette.background.default, + padding: 8, /* Styles applied to the root element if `position="bottom"`. */ - positionBottom: { + ...(styleProps.position === 'bottom' && { position: 'fixed', bottom: 0, left: 0, right: 0, zIndex: theme.zIndex.mobileStepper, - }, + }), /* Styles applied to the root element if `position="top"`. */ - positionTop: { + ...(styleProps.position === 'top' && { position: 'fixed', top: 0, left: 0, right: 0, zIndex: theme.zIndex.mobileStepper, - }, - /* Styles applied to the root element if `position="static"`. */ - positionStatic: {}, + }), +})); + +const MobileStepperDots = experimentalStyled( + 'div', + {}, + { name: 'MuiMobileStepper', slot: 'Dots' }, +)(({ styleProps }) => ({ /* Styles applied to the dots container if `variant="dots"`. */ - dots: { + ...(styleProps.variant === 'dots' && { display: 'flex', flexDirection: 'row', - }, + }), +})); + +const MobileStepperDot = experimentalStyled( + 'div', + {}, + { name: 'MuiMobileStepper', slot: 'Dot' }, +)(({ theme, styleProps }) => ({ /* Styles applied to each dot if `variant="dots"`. */ - dot: { + ...(styleProps.variant === 'dots' && { transition: theme.transitions.create('background-color', { duration: theme.transitions.duration.shortest, }), @@ -50,22 +104,29 @@ export const styles = (theme) => ({ width: 8, height: 8, margin: '0 2px', - }, - /* Styles applied to a dot if `variant="dots"` and this is the active step. */ - dotActive: { - backgroundColor: theme.palette.primary.main, - }, + /* Styles applied to a dot if `variant="dots"` and this is the active step. */ + ...(styleProps.dotActive && { + backgroundColor: theme.palette.primary.main, + }), + }), +})); + +const MobileStepperProgress = experimentalStyled( + LinearProgress, + {}, + { name: 'MuiMobileStepper', slot: 'Progress' }, +)(({ styleProps }) => ({ /* Styles applied to the Linear Progress component if `variant="progress"`. */ - progress: { + ...(styleProps.variant === 'progress' && { width: '50%', - }, -}); + }), +})); -const MobileStepper = React.forwardRef(function MobileStepper(props, ref) { +const MobileStepper = React.forwardRef(function MobileStepper(inProps, ref) { + const props = useThemeProps({ props: inProps, name: 'MuiMobileStepper' }); const { activeStep = 0, backButton, - classes, className, LinearProgressProps, nextButton, @@ -75,12 +136,22 @@ const MobileStepper = React.forwardRef(function MobileStepper(props, ref) { ...other } = props; + const styleProps = { + ...props, + activeStep, + position, + variant, + }; + + const classes = useUtilityClasses(styleProps); + return ( - {backButton} @@ -91,20 +162,20 @@ const MobileStepper = React.forwardRef(function MobileStepper(props, ref) { )} {variant === 'dots' && ( -
+ {[...new Array(steps)].map((_, index) => ( -
))} -
+
)} {variant === 'progress' && ( - + ); }); @@ -157,6 +228,10 @@ MobileStepper.propTypes /* remove-proptypes */ = { * The total steps. */ steps: integerPropType.isRequired, + /** + * The system prop that allows defining system overrides as well as additional CSS styles. + */ + sx: PropTypes.object, /** * The variant to use. * @default 'dots' @@ -164,4 +239,4 @@ MobileStepper.propTypes /* remove-proptypes */ = { variant: PropTypes.oneOf(['dots', 'progress', 'text']), }; -export default withStyles(styles, { name: 'MuiMobileStepper' })(MobileStepper); +export default MobileStepper; diff --git a/packages/material-ui/src/MobileStepper/MobileStepper.test.js b/packages/material-ui/src/MobileStepper/MobileStepper.test.js index 9fa6c4980d351e..98c65046634ec7 100644 --- a/packages/material-ui/src/MobileStepper/MobileStepper.test.js +++ b/packages/material-ui/src/MobileStepper/MobileStepper.test.js @@ -1,22 +1,15 @@ import * as React from 'react'; import { expect } from 'chai'; -import { - getClasses, - createMount, - createClientRender, - describeConformance, - screen, -} from 'test/utils'; -import KeyboardArrowLeft from '../internal/svg-icons/KeyboardArrowLeft'; +import { createMount, createClientRender, describeConformanceV5, screen } from 'test/utils'; +import Paper, { paperClasses } from '@material-ui/core/Paper'; +import Button from '@material-ui/core/Button'; +import MobileStepper, { mobileStepperClasses as classes } from '@material-ui/core/MobileStepper'; import KeyboardArrowRight from '../internal/svg-icons/KeyboardArrowRight'; -import Paper, { paperClasses } from '../Paper'; -import Button from '../Button/Button'; -import MobileStepper from './MobileStepper'; +import KeyboardArrowLeft from '../internal/svg-icons/KeyboardArrowLeft'; describe('', () => { const mount = createMount(); const render = createClientRender(); - let classes; const defaultProps = { steps: 2, nextButton: ( @@ -33,16 +26,17 @@ describe('', () => { ), }; - before(() => { - classes = getClasses(); - }); - - describeConformance(, () => ({ + describeConformanceV5(, () => ({ classes, inheritComponent: Paper, mount, + render, + muiName: 'MuiMobileStepper', + testVariantProps: { variant: 'progress' }, + testDeepOverrides: { slotName: 'dot', slotClassName: classes.dot }, + testStateOverrides: { prop: 'position', value: 'static', styleKey: 'positionStatic' }, refInstanceof: window.HTMLDivElement, - skip: ['componentProp'], + skip: ['componentProp', 'componentsProp'], })); it('should render a Paper with 0 elevation', () => { diff --git a/packages/material-ui/src/MobileStepper/index.d.ts b/packages/material-ui/src/MobileStepper/index.d.ts index fb4b8e3425069f..3d89f5f994bd51 100644 --- a/packages/material-ui/src/MobileStepper/index.d.ts +++ b/packages/material-ui/src/MobileStepper/index.d.ts @@ -1,2 +1,5 @@ export { default } from './MobileStepper'; export * from './MobileStepper'; + +export { default as mobileStepperClasses } from './mobileStepperClasses'; +export * from './mobileStepperClasses'; diff --git a/packages/material-ui/src/MobileStepper/index.js b/packages/material-ui/src/MobileStepper/index.js index 3d03d2a032e9e6..ef2f34beedbca9 100644 --- a/packages/material-ui/src/MobileStepper/index.js +++ b/packages/material-ui/src/MobileStepper/index.js @@ -1 +1,4 @@ export { default } from './MobileStepper'; + +export { default as mobileStepperClasses } from './mobileStepperClasses'; +export * from './mobileStepperClasses'; diff --git a/packages/material-ui/src/MobileStepper/mobileStepperClasses.d.ts b/packages/material-ui/src/MobileStepper/mobileStepperClasses.d.ts new file mode 100644 index 00000000000000..40222a7672fd26 --- /dev/null +++ b/packages/material-ui/src/MobileStepper/mobileStepperClasses.d.ts @@ -0,0 +1,7 @@ +import { MobileStepperClassKey } from './MobileStepper'; + +declare const mobileStepperClasses: Record; + +export function getMobileStepperUtilityClass(slot: string): string; + +export default mobileStepperClasses; diff --git a/packages/material-ui/src/MobileStepper/mobileStepperClasses.js b/packages/material-ui/src/MobileStepper/mobileStepperClasses.js new file mode 100644 index 00000000000000..a15e3d2e9933f7 --- /dev/null +++ b/packages/material-ui/src/MobileStepper/mobileStepperClasses.js @@ -0,0 +1,18 @@ +import { generateUtilityClass, generateUtilityClasses } from '@material-ui/unstyled'; + +export function getMobileStepperUtilityClass(slot) { + return generateUtilityClass('MuiMobileStepper', slot); +} + +const mobileStepperClasses = generateUtilityClasses('MuiMobileStepper', [ + 'root', + 'positionBottom', + 'positionTop', + 'positionStatic', + 'dots', + 'dot', + 'dotActive', + 'progress', +]); + +export default mobileStepperClasses;