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 6cc90a6529fad7..e05e1b56ee9715 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 @@ -1868,6 +1868,36 @@ Here's how to migrate: }, ``` +## StepContent + +Use the [codemod](https://github.com/mui/material-ui/tree/HEAD/packages/mui-codemod#step-content-props) below to migrate the code as described in the following sections: + +```bash +npx @mui/codemod@latest deprecations/step-content-props +``` + +### TransitionComponent + +The StepContent's `TransitionComponent` prop was deprecated in favor of `slots.transition`: + +```diff + +``` + +### TransitionProps + +The StepContent's `TransitionProps` prop was deprecated in favor of `slotProps.transition`: + +```diff + +``` + ## SpeedDial Use the [codemod](https://github.com/mui/material-ui/tree/HEAD/packages/mui-codemod#speed-dial-props) below to migrate the code as described in the following sections: diff --git a/docs/pages/material-ui/api/step-content.json b/docs/pages/material-ui/api/step-content.json index 43987734f58189..9d0be37cff38d7 100644 --- a/docs/pages/material-ui/api/step-content.json +++ b/docs/pages/material-ui/api/step-content.json @@ -2,6 +2,14 @@ "props": { "children": { "type": { "name": "node" } }, "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, + "slotProps": { + "type": { "name": "shape", "description": "{ transition?: func
| object }" }, + "default": "{}" + }, + "slots": { + "type": { "name": "shape", "description": "{ transition?: elementType }" }, + "default": "{}" + }, "sx": { "type": { "name": "union", @@ -9,7 +17,12 @@ }, "additionalInfo": { "sx": true } }, - "TransitionComponent": { "type": { "name": "elementType" }, "default": "Collapse" }, + "TransitionComponent": { + "type": { "name": "elementType" }, + "default": "Collapse", + "deprecated": true, + "deprecationInfo": "Use slots.transition instead. This prop will be removed in v7. How to migrate." + }, "transitionDuration": { "type": { "name": "union", @@ -17,13 +30,25 @@ }, "default": "'auto'" }, - "TransitionProps": { "type": { "name": "object" } } + "TransitionProps": { + "type": { "name": "object" }, + "deprecated": true, + "deprecationInfo": "Use slotProps.transition instead. This prop will be removed in v7. See Migrating from deprecated APIs for more details." + } }, "name": "StepContent", "imports": [ "import StepContent from '@mui/material/StepContent';", "import { StepContent } from '@mui/material';" ], + "slots": [ + { + "name": "transition", + "description": "The component that renders the transition slot.\n[Follow this guide](https://mui.com/material-ui/transitions/#transitioncomponent-prop) to learn more about the requirements for this component.", + "default": "Collapse", + "class": "MuiStepContent-transition" + } + ], "classes": [ { "key": "last", @@ -36,12 +61,6 @@ "className": "MuiStepContent-root", "description": "Styles applied to the root element.", "isGlobal": false - }, - { - "key": "transition", - "className": "MuiStepContent-transition", - "description": "Styles applied to the Transition component.", - "isGlobal": false } ], "spread": true, diff --git a/docs/translations/api-docs/step-content/step-content.json b/docs/translations/api-docs/step-content/step-content.json index feb80f01254ee7..243bf993ea16f3 100644 --- a/docs/translations/api-docs/step-content/step-content.json +++ b/docs/translations/api-docs/step-content/step-content.json @@ -3,6 +3,8 @@ "propDescriptions": { "children": { "description": "The content of the component." }, "classes": { "description": "Override or extend the styles applied to the component." }, + "slotProps": { "description": "The props used for each slot inside." }, + "slots": { "description": "The components used for each slot inside." }, "sx": { "description": "The system prop that allows defining system overrides as well as additional CSS styles." }, @@ -22,10 +24,9 @@ "nodeName": "the root element", "conditions": "last={true} (controlled by Step)" }, - "root": { "description": "Styles applied to the root element." }, - "transition": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the Transition component" - } + "root": { "description": "Styles applied to the root element." } + }, + "slotDescriptions": { + "transition": "The component that renders the transition slot. Follow this guide to learn more about the requirements for this component." } } diff --git a/packages/mui-codemod/README.md b/packages/mui-codemod/README.md index 19ba7a0253033e..92fb762bf05f5d 100644 --- a/packages/mui-codemod/README.md +++ b/packages/mui-codemod/README.md @@ -1509,6 +1509,21 @@ JS transforms: npx @mui/codemod@next deprecations/step-connector-classes ``` +#### `step-content-props` + +```diff + +``` + +```bash +npx @mui/codemod@latest deprecations/step-content-props +``` + #### `step-label-props` ```diff diff --git a/packages/mui-codemod/src/deprecations/all/deprecations-all.js b/packages/mui-codemod/src/deprecations/all/deprecations-all.js index cf21975ab4e731..91658509b72b89 100644 --- a/packages/mui-codemod/src/deprecations/all/deprecations-all.js +++ b/packages/mui-codemod/src/deprecations/all/deprecations-all.js @@ -22,6 +22,7 @@ import transformPaginationItemClasses from '../pagination-item-classes'; import transformSpeedDialProps from '../speed-dial-props'; import transformTableSortLabelClasses from '../table-sort-label-classes'; import transformStepConnectorClasses from '../step-connector-classes'; +import transformStepContentProps from '../step-content-props'; import transformStepLabelProps from '../step-label-props'; import transformTextFieldProps from '../text-field-props'; import transformTabClasses from '../tab-classes'; @@ -56,6 +57,7 @@ export default function deprecationsAll(file, api, options) { file.source = transformPaginationItemClasses(file, api, options); file.source = transformSpeedDialProps(file, api, options); file.source = transformStepConnectorClasses(file, api, options); + file.source = transformStepContentProps(file, api, options); file.source = transformStepLabelProps(file, api, options); file.source = transformTableSortLabelClasses(file, api, options); file.source = transformTextFieldProps(file, api, options); diff --git a/packages/mui-codemod/src/deprecations/step-content-props/index.js b/packages/mui-codemod/src/deprecations/step-content-props/index.js new file mode 100644 index 00000000000000..5262af8de680c8 --- /dev/null +++ b/packages/mui-codemod/src/deprecations/step-content-props/index.js @@ -0,0 +1 @@ +export { default } from './step-content-props'; diff --git a/packages/mui-codemod/src/deprecations/step-content-props/step-content-props.js b/packages/mui-codemod/src/deprecations/step-content-props/step-content-props.js new file mode 100644 index 00000000000000..794562703e297e --- /dev/null +++ b/packages/mui-codemod/src/deprecations/step-content-props/step-content-props.js @@ -0,0 +1,28 @@ +import movePropIntoSlots from '../utils/movePropIntoSlots'; +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; + + movePropIntoSlots(j, { + root, + componentName: 'StepContent', + propName: 'TransitionComponent', + slotName: 'transition', + }); + + movePropIntoSlotProps(j, { + root, + componentName: 'StepContent', + propName: 'TransitionProps', + slotName: 'transition', + }); + + return root.toSource(printOptions); +} diff --git a/packages/mui-codemod/src/deprecations/step-content-props/step-content-props.test.js b/packages/mui-codemod/src/deprecations/step-content-props/step-content-props.test.js new file mode 100644 index 00000000000000..770ab45628fb66 --- /dev/null +++ b/packages/mui-codemod/src/deprecations/step-content-props/step-content-props.test.js @@ -0,0 +1,53 @@ +import path from 'path'; +import { expect } from 'chai'; +import { jscodeshift } from '../../../testUtils'; +import transform from './step-content-props'; +import readFile from '../../util/readFile'; + +function read(fileName) { + return readFile(path.join(__dirname, fileName)); +} + +describe('@mui/codemod', () => { + describe('deprecations', () => { + describe('step-content-props', () => { + it('transforms props as needed', () => { + const actual = transform({ source: read('./test-cases/actual.js') }, { jscodeshift }, {}); + + const expected = read('./test-cases/expected.js'); + expect(actual).to.equal(expected, 'The transformed version should be correct'); + }); + + it('should be idempotent', () => { + const actual = transform({ source: read('./test-cases/expected.js') }, { jscodeshift }, {}); + + const expected = read('./test-cases/expected.js'); + expect(actual).to.equal(expected, 'The transformed version should be correct'); + }); + }); + + describe('[theme] step-content-props', () => { + it('transforms props as needed', () => { + const actual = transform( + { source: read('./test-cases/theme.actual.js') }, + { jscodeshift }, + {}, + ); + + const expected = read('./test-cases/theme.expected.js'); + expect(actual).to.equal(expected, 'The transformed version should be correct'); + }); + + it('should be idempotent', () => { + const actual = transform( + { source: read('./test-cases/theme.expected.js') }, + { jscodeshift }, + {}, + ); + + const expected = read('./test-cases/theme.expected.js'); + expect(actual).to.equal(expected, 'The transformed version should be correct'); + }); + }); + }); +}); diff --git a/packages/mui-codemod/src/deprecations/step-content-props/test-cases/actual.js b/packages/mui-codemod/src/deprecations/step-content-props/test-cases/actual.js new file mode 100644 index 00000000000000..22d30f29105a39 --- /dev/null +++ b/packages/mui-codemod/src/deprecations/step-content-props/test-cases/actual.js @@ -0,0 +1,32 @@ +import StepContent from '@mui/material/StepContent'; +import { StepContent as MyStepContent } from '@mui/material'; + +; +; +; +; +; +; +// should skip non MUI components +; diff --git a/packages/mui-codemod/src/deprecations/step-content-props/test-cases/expected.js b/packages/mui-codemod/src/deprecations/step-content-props/test-cases/expected.js new file mode 100644 index 00000000000000..1ff755d1ea9433 --- /dev/null +++ b/packages/mui-codemod/src/deprecations/step-content-props/test-cases/expected.js @@ -0,0 +1,42 @@ +import StepContent from '@mui/material/StepContent'; +import { StepContent as MyStepContent } from '@mui/material'; + +; +; +; +; +; +; +// should skip non MUI components +; diff --git a/packages/mui-codemod/src/deprecations/step-content-props/test-cases/theme.actual.js b/packages/mui-codemod/src/deprecations/step-content-props/test-cases/theme.actual.js new file mode 100644 index 00000000000000..3f5550e24d38e9 --- /dev/null +++ b/packages/mui-codemod/src/deprecations/step-content-props/test-cases/theme.actual.js @@ -0,0 +1,26 @@ +fn({ + MuiStepContent: { + defaultProps: { + TransitionComponent: CustomTransition, + TransitionProps: { unmountOnExit: true }, + }, + }, +}); + +fn({ + MuiStepContent: { + defaultProps: { + TransitionComponent: ComponentTransition, + slots: { transition: SlotTransition }, + }, + }, +}); + +fn({ + MuiStepContent: { + defaultProps: { + slotProps: { transition: { id: 'test' } }, + TransitionProps: { unmountOnExit: true }, + }, + }, +}); diff --git a/packages/mui-codemod/src/deprecations/step-content-props/test-cases/theme.expected.js b/packages/mui-codemod/src/deprecations/step-content-props/test-cases/theme.expected.js new file mode 100644 index 00000000000000..48da8df87abe77 --- /dev/null +++ b/packages/mui-codemod/src/deprecations/step-content-props/test-cases/theme.expected.js @@ -0,0 +1,32 @@ +fn({ + MuiStepContent: { + defaultProps: { + slots: { + transition: CustomTransition + }, + + slotProps: { + transition: { unmountOnExit: true } + } + }, + }, +}); + +fn({ + MuiStepContent: { + defaultProps: { + slots: { transition: SlotTransition } + }, + }, +}); + +fn({ + MuiStepContent: { + defaultProps: { + slotProps: { transition: { + ...{ unmountOnExit: true }, + ...{ id: 'test' } + } } + }, + }, +}); diff --git a/packages/mui-material/src/StepContent/StepContent.d.ts b/packages/mui-material/src/StepContent/StepContent.d.ts index 2fc588386d0006..9ed3cf976792c7 100644 --- a/packages/mui-material/src/StepContent/StepContent.d.ts +++ b/packages/mui-material/src/StepContent/StepContent.d.ts @@ -1,11 +1,38 @@ import * as React from 'react'; import { SxProps } from '@mui/system'; -import { InternalStandardProps as StandardProps } from '..'; +import { CollapseProps, InternalStandardProps as StandardProps } from '..'; import { Theme } from '../styles'; import { TransitionProps } from '../transitions/transition'; import { StepContentClasses } from './stepContentClasses'; +import { CreateSlotsAndSlotProps, SlotProps } from '../utils/types'; -export interface StepContentProps extends StandardProps> { +export interface StepContentSlots { + /** + * The component that renders the transition slot. + * [Follow this guide](https://mui.com/material-ui/transitions/#transitioncomponent-prop) to learn more about the requirements for this component. + * @default Collapse + */ + transition?: React.JSXElementConstructor< + TransitionProps & { children?: React.ReactElement } + >; +} + +export type StepContentSlotsAndSlotProps = CreateSlotsAndSlotProps< + StepContentSlots, + { + /** + * Props forwared to the transition slot. + * By default, the available props are based on the [Collapse](https://mui.com/material-ui/api/collapse/#props) component + */ + transition: SlotProps, {}, StepContentOwnerState>; + } +>; + +export interface StepContentOwnerState extends StepContentProps {} + +export interface StepContentProps + extends StandardProps>, + StepContentSlotsAndSlotProps { /** * The content of the component. */ @@ -22,6 +49,7 @@ export interface StepContentProps extends StandardProps } @@ -37,6 +65,7 @@ export interface StepContentProps extends StandardProps { const { classes, last } = ownerState; @@ -62,6 +63,8 @@ const StepContent = React.forwardRef(function StepContent(inProps, ref) { TransitionComponent = Collapse, transitionDuration: transitionDurationProp = 'auto', TransitionProps, + slots = {}, + slotProps = {}, ...other } = props; @@ -83,6 +86,23 @@ const StepContent = React.forwardRef(function StepContent(inProps, ref) { transitionDuration = undefined; } + const externalForwardedProps = { + slots, + slotProps: { transition: TransitionProps, ...slotProps }, + }; + + const [TransitionSlot, transitionProps] = useSlot('transition', { + elementType: StepContentTransition, + externalForwardedProps, + ownerState, + className: classes.transition, + additionalProps: { + in: active || expanded, + timeout: transitionDuration, + unmountOnExit: true, + }, + }); + return ( - + {children} - + ); }); @@ -122,6 +134,20 @@ StepContent.propTypes /* remove-proptypes */ = { * @ignore */ className: PropTypes.string, + /** + * The props used for each slot inside. + * @default {} + */ + slotProps: PropTypes.shape({ + transition: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), + /** + * The components used for each slot inside. + * @default {} + */ + slots: PropTypes.shape({ + transition: PropTypes.elementType, + }), /** * The system prop that allows defining system overrides as well as additional CSS styles. */ @@ -134,6 +160,7 @@ StepContent.propTypes /* remove-proptypes */ = { * The component used for the transition. * [Follow this guide](https://mui.com/material-ui/transitions/#transitioncomponent-prop) to learn more about the requirements for this component. * @default Collapse + * @deprecated Use `slots.transition` instead. This prop will be removed in v7. [How to migrate](/material-ui/migration/migrating-from-deprecated-apis/). */ TransitionComponent: PropTypes.elementType, /** @@ -155,6 +182,7 @@ StepContent.propTypes /* remove-proptypes */ = { /** * Props applied to the transition element. * By default, the element is based on this [`Transition`](https://reactcommunity.org/react-transition-group/transition/) component. + * @deprecated Use `slotProps.transition` instead. This prop will be removed in v7. See [Migrating from deprecated APIs](/material-ui/migration/migrating-from-deprecated-apis/) for more details. */ TransitionProps: PropTypes.object, }; diff --git a/packages/mui-material/src/StepContent/StepContent.test.js b/packages/mui-material/src/StepContent/StepContent.test.js index 67d874c25a9b73..b76d89d2c244eb 100644 --- a/packages/mui-material/src/StepContent/StepContent.test.js +++ b/packages/mui-material/src/StepContent/StepContent.test.js @@ -24,6 +24,12 @@ describe('', () => { return { container: container.firstChild.firstChild, ...other }; }, skip: ['componentProp', 'componentsProp', 'themeVariants'], + slots: { + transition: { + expectedClassName: classes.transition, + testWithElement: null, + }, + }, })); it('renders children inside an Collapse component', () => {