From e29461666ddf142a16346db7430fd6331bd3e174 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 16 Jan 2025 14:18:13 +0700 Subject: [PATCH 1/3] update MobileStepper and add tests --- .../pages/material-ui/api/mobile-stepper.json | 68 +++++++---- .../mobile-stepper/mobile-stepper.json | 26 ++--- .../src/MobileStepper/MobileStepper.d.ts | 70 +++++++++++- .../src/MobileStepper/MobileStepper.js | 108 ++++++++++++++---- .../src/MobileStepper/MobileStepper.test.js | 45 +++++++- 5 files changed, 251 insertions(+), 66 deletions(-) diff --git a/docs/pages/material-ui/api/mobile-stepper.json b/docs/pages/material-ui/api/mobile-stepper.json index b6b26d17507456..e1bfd3f6c82f8c 100644 --- a/docs/pages/material-ui/api/mobile-stepper.json +++ b/docs/pages/material-ui/api/mobile-stepper.json @@ -4,7 +4,11 @@ "activeStep": { "type": { "name": "custom", "description": "integer" }, "default": "0" }, "backButton": { "type": { "name": "node" } }, "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, - "LinearProgressProps": { "type": { "name": "object" } }, + "LinearProgressProps": { + "type": { "name": "object" }, + "deprecated": true, + "deprecationInfo": "Use slotProps.progress instead. This prop will be removed in v7. See Migrating from deprecated APIs for more details." + }, "nextButton": { "type": { "name": "node" } }, "position": { "type": { @@ -13,6 +17,20 @@ }, "default": "'bottom'" }, + "slotProps": { + "type": { + "name": "shape", + "description": "{ dot?: func
| object, dots?: func
| object, progress?: func
| object, root?: func
| object }" + }, + "default": "{}" + }, + "slots": { + "type": { + "name": "shape", + "description": "{ dot?: elementType, dots?: elementType, progress?: elementType, root?: elementType }" + }, + "default": "{}" + }, "sx": { "type": { "name": "union", @@ -33,25 +51,39 @@ "import MobileStepper from '@mui/material/MobileStepper';", "import { MobileStepper } from '@mui/material';" ], - "classes": [ + "slots": [ { - "key": "dot", - "className": "MuiMobileStepper-dot", - "description": "Styles applied to each dot if `variant=\"dots\"`.", - "isGlobal": false + "name": "root", + "description": "The component that renders the root slot.", + "default": "Paper", + "class": "MuiMobileStepper-root" + }, + { + "name": "progress", + "description": "The component that renders the progress slot.", + "default": "LinearProgress", + "class": "MuiMobileStepper-progress" + }, + { + "name": "dots", + "description": "The component that renders the dots slot.", + "default": "'div'", + "class": "MuiMobileStepper-dots" }, + { + "name": "dot", + "description": "The component that renders the dot slot.", + "default": "'div'", + "class": "MuiMobileStepper-dot" + } + ], + "classes": [ { "key": "dotActive", "className": "MuiMobileStepper-dotActive", "description": "Styles applied to a dot if `variant=\"dots\"` and this is the active step.", "isGlobal": false }, - { - "key": "dots", - "className": "MuiMobileStepper-dots", - "description": "Styles applied to the dots container if `variant=\"dots\"`.", - "isGlobal": false - }, { "key": "positionBottom", "className": "MuiMobileStepper-positionBottom", @@ -69,18 +101,6 @@ "className": "MuiMobileStepper-positionTop", "description": "Styles applied to the root element if `position=\"top\"`.", "isGlobal": false - }, - { - "key": "progress", - "className": "MuiMobileStepper-progress", - "description": "Styles applied to the Linear Progress component if `variant=\"progress\"`.", - "isGlobal": false - }, - { - "key": "root", - "className": "MuiMobileStepper-root", - "description": "Styles applied to the root element.", - "isGlobal": false } ], "spread": true, diff --git a/docs/translations/api-docs/mobile-stepper/mobile-stepper.json b/docs/translations/api-docs/mobile-stepper/mobile-stepper.json index e04dc8898bae42..1f3e0ba5dc9fe8 100644 --- a/docs/translations/api-docs/mobile-stepper/mobile-stepper.json +++ b/docs/translations/api-docs/mobile-stepper/mobile-stepper.json @@ -15,6 +15,8 @@ "description": "A next button element. For instance, it can be a Button or an IconButton." }, "position": { "description": "Set the positioning type." }, + "slotProps": { "description": "The props used for each slot inside." }, + "slots": { "description": "The components used for each slot inside." }, "steps": { "description": "The total steps." }, "sx": { "description": "The system prop that allows defining system overrides as well as additional CSS styles." @@ -22,21 +24,11 @@ "variant": { "description": "The variant to use." } }, "classDescriptions": { - "dot": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "each dot", - "conditions": "variant=\"dots\"" - }, "dotActive": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "a dot", "conditions": "variant=\"dots\" and this is the active step" }, - "dots": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the dots container", - "conditions": "variant=\"dots\"" - }, "positionBottom": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the root element", @@ -51,12 +43,12 @@ "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the root element", "conditions": "position=\"top\"" - }, - "progress": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the Linear Progress component", - "conditions": "variant=\"progress\"" - }, - "root": { "description": "Styles applied to the root element." } + } + }, + "slotDescriptions": { + "dot": "The component that renders the dot slot.", + "dots": "The component that renders the dots slot.", + "progress": "The component that renders the progress slot.", + "root": "The component that renders the root slot." } } diff --git a/packages/mui-material/src/MobileStepper/MobileStepper.d.ts b/packages/mui-material/src/MobileStepper/MobileStepper.d.ts index 9a05cabb4b9b5d..efb7da7c4b01a6 100644 --- a/packages/mui-material/src/MobileStepper/MobileStepper.d.ts +++ b/packages/mui-material/src/MobileStepper/MobileStepper.d.ts @@ -4,8 +4,73 @@ import { InternalStandardProps as StandardProps, Theme } from '..'; import { PaperProps } from '../Paper'; import { LinearProgressProps } from '../LinearProgress'; import { MobileStepperClasses } from './mobileStepperClasses'; +import { CreateSlotsAndSlotProps, SlotProps } from '../utils/types'; -export interface MobileStepperProps extends StandardProps { +export interface MobileStepperSlots { + /** + * The component that renders the root slot. + * @default Paper + */ + root: React.ElementType; + /** + * The component that renders the progress slot. + * @default LinearProgress + */ + progress: React.ElementType; + /** + * The component that renders the dots slot. + * @default 'div' + */ + dots: React.ElementType; + /** + * The component that renders the dot slot. + * @default 'div' + */ + dot: React.ElementType; +} + +export interface MobileStepperRootSlotPropsOverrides {} +export interface MobileStepperProgressSlotPropsOverrides {} +export interface MobileStepperDotsSlotPropsOverrides {} +export interface MobileStepperDotSlotPropsOverrides {} + +export type MobileStepperSlotsAndSlotProps = CreateSlotsAndSlotProps< + MobileStepperSlots, + { + /** + * Props forwarded to the root slot. + * By default, the avaible props are based on the [Paper](https://mui.com/material-ui/api/paper/#props) component. + */ + root: SlotProps< + React.ElementType, + MobileStepperRootSlotPropsOverrides, + MobileStepperOwnerState + >; + /** + * Props forwarded to the progress slot. + * By default, the avaible props are based on the [LinearProgress](https://mui.com/material-ui/api/linear-progress/#props) component. + */ + progress: SlotProps< + React.ElementType, + MobileStepperProgressSlotPropsOverrides, + MobileStepperOwnerState + >; + /** + * Props forwarded to the dots slot. + * By default, the avaible props are based on the div element. + */ + dots: SlotProps<'div', MobileStepperDotsSlotPropsOverrides, MobileStepperOwnerState>; + /** + * Props forwarded to the dot slot. + * By default, the avaible props are based on the div element. + */ + dot: SlotProps<'div', MobileStepperDotSlotPropsOverrides, MobileStepperOwnerState>; + } +>; + +export interface MobileStepperProps + extends StandardProps, + MobileStepperSlotsAndSlotProps { /** * Set the active step (zero based index). * Defines which dot is highlighted when the variant is 'dots'. @@ -22,6 +87,7 @@ export interface MobileStepperProps extends StandardProps; /** * Props applied to the `LinearProgress` element. + * @deprecated Use `slotProps.progress` instead. This prop will be removed in v7. See [Migrating from deprecated APIs](/material-ui/migration/migrating-from-deprecated-apis/) for more details. */ LinearProgressProps?: Partial; /** @@ -48,6 +114,8 @@ export interface MobileStepperProps extends StandardProps {} + /** * * Demos: diff --git a/packages/mui-material/src/MobileStepper/MobileStepper.js b/packages/mui-material/src/MobileStepper/MobileStepper.js index 9a8a4974c14d62..666d71255866a1 100644 --- a/packages/mui-material/src/MobileStepper/MobileStepper.js +++ b/packages/mui-material/src/MobileStepper/MobileStepper.js @@ -12,6 +12,7 @@ import memoTheme from '../utils/memoTheme'; import { useDefaultProps } from '../DefaultPropsProvider'; import slotShouldForwardProp from '../styles/slotShouldForwardProp'; import { getMobileStepperUtilityClass } from './mobileStepperClasses'; +import useSlot from '../utils/useSlot'; const useUtilityClasses = (ownerState) => { const { classes, position } = ownerState; @@ -142,6 +143,8 @@ const MobileStepper = React.forwardRef(function MobileStepper(inProps, ref) { position = 'bottom', steps, variant = 'dots', + slots = {}, + slotProps = {}, ...other } = props; @@ -163,15 +166,57 @@ const MobileStepper = React.forwardRef(function MobileStepper(inProps, ref) { const classes = useUtilityClasses(ownerState); + const externalForwardedProps = { + slots, + slotProps: { + progress: LinearProgressProps, + ...slotProps, + }, + }; + + const [RootSlot, rootSlotProps] = useSlot('root', { + ref, + elementType: MobileStepperRoot, + shouldForwardComponentProp: true, + className: clsx(classes.root, className), + externalForwardedProps: { + ...externalForwardedProps, + ...other, + }, + ownerState, + additionalProps: { + square: true, + elevation: 0, + }, + }); + + const [DotsSlot, dotsSlotProps] = useSlot('dots', { + className: classes.dots, + elementType: MobileStepperDots, + externalForwardedProps, + ownerState, + }); + + const [DotSlot, dotSlotProps] = useSlot('dot', { + elementType: MobileStepperDot, + externalForwardedProps, + ownerState, + }); + + const [ProgressSlot, progressSlotProps] = useSlot('progress', { + className: classes.progress, + elementType: MobileStepperProgress, + shouldForwardComponentProp: true, + externalForwardedProps, + ownerState, + additionalProps: { + value, + variant: 'determinate', + }, + }); + return ( - + {backButton} {variant === 'text' && ( @@ -180,30 +225,26 @@ const MobileStepper = React.forwardRef(function MobileStepper(inProps, ref) { )} {variant === 'dots' && ( - + {[...new Array(steps)].map((_, index) => ( - ))} - + )} - {variant === 'progress' && ( - - )} + {variant === 'progress' && } {nextButton} - + ); }); @@ -232,6 +273,7 @@ MobileStepper.propTypes /* remove-proptypes */ = { className: PropTypes.string, /** * Props applied to the `LinearProgress` element. + * @deprecated Use `slotProps.progress` instead. This prop will be removed in v7. See [Migrating from deprecated APIs](/material-ui/migration/migrating-from-deprecated-apis/) for more details. */ LinearProgressProps: PropTypes.object, /** @@ -243,6 +285,26 @@ MobileStepper.propTypes /* remove-proptypes */ = { * @default 'bottom' */ position: PropTypes.oneOf(['bottom', 'static', 'top']), + /** + * The props used for each slot inside. + * @default {} + */ + slotProps: PropTypes.shape({ + dot: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + dots: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + progress: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), + /** + * The components used for each slot inside. + * @default {} + */ + slots: PropTypes.shape({ + dot: PropTypes.elementType, + dots: PropTypes.elementType, + progress: PropTypes.elementType, + root: PropTypes.elementType, + }), /** * The total steps. */ diff --git a/packages/mui-material/src/MobileStepper/MobileStepper.test.js b/packages/mui-material/src/MobileStepper/MobileStepper.test.js index 6bd31fa8291e19..d2c008d1c79812 100644 --- a/packages/mui-material/src/MobileStepper/MobileStepper.test.js +++ b/packages/mui-material/src/MobileStepper/MobileStepper.test.js @@ -26,7 +26,15 @@ describe('', () => { ), }; - describeConformance(, () => ({ + function CustomPaper({ square, ownerState, ...other }) { + return ; + } + + function CustomDot({ dotActive, ownerState, ...other }) { + return ; + } + + describeConformance(, () => ({ classes, inheritComponent: Paper, render, @@ -35,9 +43,44 @@ describe('', () => { testDeepOverrides: { slotName: 'dot', slotClassName: classes.dot }, testStateOverrides: { prop: 'position', value: 'static', styleKey: 'positionStatic' }, refInstanceof: window.HTMLDivElement, + slots: { + root: { + expectedClassName: classes.root, + testWithComponent: CustomPaper, + testWithElement: CustomPaper, + }, + dots: { + expectedClassName: classes.dots, + }, + dot: { + expectedClassName: classes.dot, + testWithComponent: CustomDot, + testWithElement: CustomDot, + }, + }, skip: ['componentProp', 'componentsProp'], })); + describeConformance(, () => ({ + render, + slots: { + root: { + expectedClassName: classes.root, + testWithComponent: CustomPaper, + testWithElement: CustomPaper, + }, + progress: { + expectedClassName: classes.progress, + }, + }, + only: [ + 'slotPropsProp', + 'slotPropsCallback', + 'slotPropsCallbackWithPropsAsOwnerState', + 'slotsProp', + ], + })); + it('should render a Paper with 0 elevation', () => { const { container } = render(); expect(container.firstChild).to.have.class(paperClasses.elevation0); From 48efb2f76d81f33f69013daf2b7cee8decad65cd Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 16 Jan 2025 14:29:45 +0700 Subject: [PATCH 2/3] add codemod --- .../pages/material-ui/api/mobile-stepper.json | 1 - .../src/deprecations/all/deprecations-all.js | 2 ++ .../mobile-stepper-props/index.js | 1 + .../mobile-stepper-props.js | 20 +++++++++++++++++++ .../mobile-stepper-props.test.js | 13 ++++++++++++ .../mobile-stepper-props/test-cases/actual.js | 15 ++++++++++++++ .../test-cases/expected.js | 19 ++++++++++++++++++ .../src/MobileStepper/MobileStepper.test.js | 1 + 8 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 packages/mui-codemod/src/deprecations/mobile-stepper-props/index.js create mode 100644 packages/mui-codemod/src/deprecations/mobile-stepper-props/mobile-stepper-props.js create mode 100644 packages/mui-codemod/src/deprecations/mobile-stepper-props/mobile-stepper-props.test.js create mode 100644 packages/mui-codemod/src/deprecations/mobile-stepper-props/test-cases/actual.js create mode 100644 packages/mui-codemod/src/deprecations/mobile-stepper-props/test-cases/expected.js diff --git a/docs/pages/material-ui/api/mobile-stepper.json b/docs/pages/material-ui/api/mobile-stepper.json index e1bfd3f6c82f8c..762e1c0ea5b112 100644 --- a/docs/pages/material-ui/api/mobile-stepper.json +++ b/docs/pages/material-ui/api/mobile-stepper.json @@ -106,7 +106,6 @@ "spread": true, "themeDefaultProps": true, "muiName": "MuiMobileStepper", - "forwardsRefTo": "HTMLDivElement", "filename": "/packages/mui-material/src/MobileStepper/MobileStepper.js", "inheritance": { "component": "Paper", "pathname": "/material-ui/api/paper/" }, "demos": "", diff --git a/packages/mui-codemod/src/deprecations/all/deprecations-all.js b/packages/mui-codemod/src/deprecations/all/deprecations-all.js index 7461bca69707b4..36f6d688c791ca 100644 --- a/packages/mui-codemod/src/deprecations/all/deprecations-all.js +++ b/packages/mui-codemod/src/deprecations/all/deprecations-all.js @@ -32,6 +32,7 @@ import transformToggleButtonGroupClasses from '../toggle-button-group-classes'; import transformTooltipProps from '../tooltip-props'; import transformTablePaginationProps from '../table-pagination-props'; import transformCardHeaderProps from '../card-header-props'; +import transformMobileStepperProps from '../mobile-stepper-props'; /** * @param {import('jscodeshift').FileInfo} file @@ -72,6 +73,7 @@ export default function deprecationsAll(file, api, options) { file.source = transformTooltipProps(file, api, options); file.source = transformTablePaginationProps(file, api, options); file.source = transformCardHeaderProps(file, api, options); + file.source = transformMobileStepperProps(file, api, options); return file.source; } diff --git a/packages/mui-codemod/src/deprecations/mobile-stepper-props/index.js b/packages/mui-codemod/src/deprecations/mobile-stepper-props/index.js new file mode 100644 index 00000000000000..f3e01eb0471e93 --- /dev/null +++ b/packages/mui-codemod/src/deprecations/mobile-stepper-props/index.js @@ -0,0 +1 @@ +export { default } from './mobile-stepper-props'; diff --git a/packages/mui-codemod/src/deprecations/mobile-stepper-props/mobile-stepper-props.js b/packages/mui-codemod/src/deprecations/mobile-stepper-props/mobile-stepper-props.js new file mode 100644 index 00000000000000..39dc194da8073d --- /dev/null +++ b/packages/mui-codemod/src/deprecations/mobile-stepper-props/mobile-stepper-props.js @@ -0,0 +1,20 @@ +import movePropIntoSlotProps from '../utils/movePropIntoSlotProps'; + +/** + * @param {import('jscodeshift').FileInfo} file + * @param {import('jscodeshift').API} api + */ +export default function transformer(file, api, options) { + const j = api.jscodeshift; + const root = j(file.source); + const printOptions = options.printOptions; + + movePropIntoSlotProps(j, { + root, + componentName: 'MobileStepper', + propName: 'LinearProgressProps', + slotName: 'progress', + }); + + return root.toSource(printOptions); +} diff --git a/packages/mui-codemod/src/deprecations/mobile-stepper-props/mobile-stepper-props.test.js b/packages/mui-codemod/src/deprecations/mobile-stepper-props/mobile-stepper-props.test.js new file mode 100644 index 00000000000000..d02dedc2e56a75 --- /dev/null +++ b/packages/mui-codemod/src/deprecations/mobile-stepper-props/mobile-stepper-props.test.js @@ -0,0 +1,13 @@ +import { describeJscodeshiftTransform } from '../../../testUtils'; +import transform from './mobile-stepper-props'; + +describe('@mui/codemod', () => { + describe('deprecations', () => { + describeJscodeshiftTransform({ + transform, + transformName: 'mobile-stepper-props', + dirname: __dirname, + testCases: [{ actual: '/test-cases/actual.js', expected: '/test-cases/expected.js' }], + }); + }); +}); diff --git a/packages/mui-codemod/src/deprecations/mobile-stepper-props/test-cases/actual.js b/packages/mui-codemod/src/deprecations/mobile-stepper-props/test-cases/actual.js new file mode 100644 index 00000000000000..07593685418ec3 --- /dev/null +++ b/packages/mui-codemod/src/deprecations/mobile-stepper-props/test-cases/actual.js @@ -0,0 +1,15 @@ +import MobileStepper from '@mui/material/MobileStepper'; +import { MobileStepper as MyMobileStepper } from '@mui/material'; + +; +; + +; diff --git a/packages/mui-codemod/src/deprecations/mobile-stepper-props/test-cases/expected.js b/packages/mui-codemod/src/deprecations/mobile-stepper-props/test-cases/expected.js new file mode 100644 index 00000000000000..317d01d761b9c9 --- /dev/null +++ b/packages/mui-codemod/src/deprecations/mobile-stepper-props/test-cases/expected.js @@ -0,0 +1,19 @@ +import MobileStepper from '@mui/material/MobileStepper'; +import { MobileStepper as MyMobileStepper } from '@mui/material'; + +; +; + +; diff --git a/packages/mui-material/src/MobileStepper/MobileStepper.test.js b/packages/mui-material/src/MobileStepper/MobileStepper.test.js index d2c008d1c79812..e2c14b93fb68ce 100644 --- a/packages/mui-material/src/MobileStepper/MobileStepper.test.js +++ b/packages/mui-material/src/MobileStepper/MobileStepper.test.js @@ -62,6 +62,7 @@ describe('', () => { })); describeConformance(, () => ({ + inheritComponent: Paper, render, slots: { root: { From e2625dddd1d1c6a874fc230d396b28c633821fd2 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 16 Jan 2025 14:30:51 +0700 Subject: [PATCH 3/3] update migration doc --- .../migrating-from-deprecated-apis.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/data/material/migration/migrating-from-deprecated-apis/migrating-from-deprecated-apis.md b/docs/data/material/migration/migrating-from-deprecated-apis/migrating-from-deprecated-apis.md index d7a58966f60079..700dcc56f5ab13 100644 --- a/docs/data/material/migration/migrating-from-deprecated-apis/migrating-from-deprecated-apis.md +++ b/docs/data/material/migration/migrating-from-deprecated-apis/migrating-from-deprecated-apis.md @@ -1469,6 +1469,25 @@ Here's how to migrate: } ``` +## MobileStepper + +Use the [codemod](https://github.com/mui/material-ui/tree/HEAD/packages/mui-codemod#mobile-stepper-props) below to migrate the code as described in the following sections: + +```bash +npx @mui/codemod@latest deprecations/mobile-stepper-props +``` + +### LinearProgressProps + +The MobileStepper's `LinearProgressProps` prop was deprecated in favor of `slotProps.progress`: + +```diff + +``` + ## Modal Use the [codemod](https://github.com/mui/material-ui/tree/HEAD/packages/mui-codemod#modal-props) below to migrate the code as described in the following sections: