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 628c7b497c9cc4..8baab6a5dec4e0 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 @@ -905,3 +905,22 @@ The Slider's `componentsProps` was deprecated in favor of `slotProps`: + slotProps={{ track: { testid: 'test-id' } }} /> ``` + +## StepLabel + +Use the [codemod](https://github.com/mui/material-ui/tree/HEAD/packages/mui-codemod#step-label-props) below to migrate the code as described in the following sections: + +```bash +npx @mui/codemod@latest deprecations/step-label-props +``` + +### componentsProps + +The StepLabel's `componentsProps` was deprecated in favor of `slotProps`: + +```diff + +``` diff --git a/docs/pages/material-ui/api/step-label.json b/docs/pages/material-ui/api/step-label.json index 2f77fe012d8ec7..cc855fad1f48fa 100644 --- a/docs/pages/material-ui/api/step-label.json +++ b/docs/pages/material-ui/api/step-label.json @@ -4,13 +4,19 @@ "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, "componentsProps": { "type": { "name": "shape", "description": "{ label?: object }" }, - "default": "{}" + "default": "{}", + "deprecated": true, + "deprecationInfo": "use the slotProps prop instead. This prop will be removed in v7. How to migrate." }, "error": { "type": { "name": "bool" }, "default": "false" }, "icon": { "type": { "name": "node" } }, "optional": { "type": { "name": "node" } }, "slotProps": { - "type": { "name": "shape", "description": "{ label?: object }" }, + "type": { "name": "shape", "description": "{ label?: func
| object }" }, + "default": "{}" + }, + "slots": { + "type": { "name": "shape", "description": "{ label?: elementType }" }, "default": "{}" }, "StepIconComponent": { "type": { "name": "elementType" } }, @@ -28,6 +34,14 @@ "import StepLabel from '@mui/material/StepLabel';", "import { StepLabel } from '@mui/material';" ], + "slots": [ + { + "name": "label", + "description": "The component that renders the label.", + "default": "span", + "class": "MuiStepLabel-label" + } + ], "classes": [ { "key": "active", @@ -71,12 +85,6 @@ "description": "Styles applied to the `icon` container element.", "isGlobal": false }, - { - "key": "label", - "className": "MuiStepLabel-label", - "description": "Styles applied to the label element that wraps `children`.", - "isGlobal": false - }, { "key": "labelContainer", "className": "MuiStepLabel-labelContainer", diff --git a/docs/translations/api-docs/step-label/step-label.json b/docs/translations/api-docs/step-label/step-label.json index 48a77b4b7f3ade..7a68d574ce6f9d 100644 --- a/docs/translations/api-docs/step-label/step-label.json +++ b/docs/translations/api-docs/step-label/step-label.json @@ -10,6 +10,7 @@ "icon": { "description": "Override the default label of the step icon." }, "optional": { "description": "The optional node to display." }, "slotProps": { "description": "The props used for each slot inside." }, + "slots": { "description": "The components used for each slot inside." }, "StepIconComponent": { "description": "The component to render in place of the StepIcon." }, @@ -55,10 +56,6 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the icon container element" }, - "label": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the label element that wraps children" - }, "labelContainer": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the container element which wraps label and optional" @@ -69,5 +66,6 @@ "nodeName": "the root element", "conditions": "orientation=\"vertical\"" } - } + }, + "slotDescriptions": { "label": "The component that renders the label." } } diff --git a/packages/mui-codemod/README.md b/packages/mui-codemod/README.md index d71dc32948895e..465fba0845dacf 100644 --- a/packages/mui-codemod/README.md +++ b/packages/mui-codemod/README.md @@ -909,6 +909,28 @@ npx @mui/codemod@next deprecations/pagination-item-classes npx @mui/codemod@next deprecations/slider-props ``` +#### `step-label-props` + +```diff + +``` + +```diff + MuiStepLabel: { + defaultProps: { +- componentsProps={{ label: labelProps }} ++ slotProps={{ label: labelProps }} + }, + }, +``` + +```bash +npx @mui/codemod@latest deprecations/step-label-props +``` + ### v5.0.0 #### `base-use-named-exports` diff --git a/packages/mui-codemod/src/deprecations/all/deprecations-all.js b/packages/mui-codemod/src/deprecations/all/deprecations-all.js index 8d6f3aed3aa557..30af0e6d4a7aa8 100644 --- a/packages/mui-codemod/src/deprecations/all/deprecations-all.js +++ b/packages/mui-codemod/src/deprecations/all/deprecations-all.js @@ -7,6 +7,7 @@ import transformButtonGroupClasses from '../button-group-classes'; import transformChipClasses from '../chip-classes'; import transformPaginationItemClasses from '../pagination-item-classes'; import transformAlertClasses from '../alert-classes'; +import transformStepLabelProps from '../step-label-props'; /** * @param {import('jscodeshift').FileInfo} file @@ -22,6 +23,7 @@ export default function deprecationsAll(file, api, options) { file.source = transformChipClasses(file, api, options); file.source = transformPaginationItemClasses(file, api, options); file.source = transformAlertClasses(file, api, options); + file.source = transformStepLabelProps(file, api, options); return file.source; } diff --git a/packages/mui-codemod/src/deprecations/step-label-props/index.js b/packages/mui-codemod/src/deprecations/step-label-props/index.js new file mode 100644 index 00000000000000..dacfd195c56c35 --- /dev/null +++ b/packages/mui-codemod/src/deprecations/step-label-props/index.js @@ -0,0 +1 @@ +export { default } from './step-label-props'; diff --git a/packages/mui-codemod/src/deprecations/step-label-props/step-label-props.js b/packages/mui-codemod/src/deprecations/step-label-props/step-label-props.js new file mode 100644 index 00000000000000..d71fbba3a84810 --- /dev/null +++ b/packages/mui-codemod/src/deprecations/step-label-props/step-label-props.js @@ -0,0 +1,15 @@ +import replaceComponentsWithSlots from '../utils/replaceComponentsWithSlots'; + +/** + * @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; + + replaceComponentsWithSlots(j, { root, componentName: 'StepLabel' }); + + return root.toSource(printOptions); +} diff --git a/packages/mui-codemod/src/deprecations/step-label-props/step-label-props.test.js b/packages/mui-codemod/src/deprecations/step-label-props/step-label-props.test.js new file mode 100644 index 00000000000000..90edfeab7791e4 --- /dev/null +++ b/packages/mui-codemod/src/deprecations/step-label-props/step-label-props.test.js @@ -0,0 +1,53 @@ +import path from 'path'; +import { expect } from 'chai'; +import { jscodeshift } from '../../../testUtils'; +import transform from './step-label-props'; +import readFile from '../../util/readFile'; + +function read(fileName) { + return readFile(path.join(__dirname, fileName)); +} + +describe('@mui/codemod', () => { + describe('deprecations', () => { + describe('step-label-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-label-props', () => { + it('transforms props as needed', () => { + const actual = transform( + { source: read('./test-cases/theme.actual.js') }, + { jscodeshift }, + { printOptions: { trailingComma: false } }, + ); + + 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-label-props/test-cases/actual.js b/packages/mui-codemod/src/deprecations/step-label-props/test-cases/actual.js new file mode 100644 index 00000000000000..9caf4e5a411080 --- /dev/null +++ b/packages/mui-codemod/src/deprecations/step-label-props/test-cases/actual.js @@ -0,0 +1,8 @@ +import StepLabel from '@mui/material/StepLabel'; + +; +; diff --git a/packages/mui-codemod/src/deprecations/step-label-props/test-cases/expected.js b/packages/mui-codemod/src/deprecations/step-label-props/test-cases/expected.js new file mode 100644 index 00000000000000..b26c217086b36d --- /dev/null +++ b/packages/mui-codemod/src/deprecations/step-label-props/test-cases/expected.js @@ -0,0 +1,9 @@ +import StepLabel from '@mui/material/StepLabel'; + +; +; diff --git a/packages/mui-codemod/src/deprecations/step-label-props/test-cases/theme.actual.js b/packages/mui-codemod/src/deprecations/step-label-props/test-cases/theme.actual.js new file mode 100644 index 00000000000000..4f68c1fe687871 --- /dev/null +++ b/packages/mui-codemod/src/deprecations/step-label-props/test-cases/theme.actual.js @@ -0,0 +1,16 @@ +fn({ + MuiStepLabel: { + defaultProps: { + componentsProps: { label: componentsLabelProps }, + }, + }, +}); + +fn({ + MuiStepLabel: { + defaultProps: { + componentsProps: { label: componentsLabelProps }, + slotProps: { label: slotLabelProps }, + }, + }, +}); diff --git a/packages/mui-codemod/src/deprecations/step-label-props/test-cases/theme.expected.js b/packages/mui-codemod/src/deprecations/step-label-props/test-cases/theme.expected.js new file mode 100644 index 00000000000000..c8874c72137cab --- /dev/null +++ b/packages/mui-codemod/src/deprecations/step-label-props/test-cases/theme.expected.js @@ -0,0 +1,22 @@ +fn({ + MuiStepLabel: { + defaultProps: { + slotProps: { + label: componentsLabelProps + } + }, + }, +}); + +fn({ + MuiStepLabel: { + defaultProps: { + slotProps: { + label: { + ...componentsLabelProps, + ...slotLabelProps + } + } + }, + }, +}); diff --git a/packages/mui-material/src/StepLabel/StepLabel.d.ts b/packages/mui-material/src/StepLabel/StepLabel.d.ts index 10d75f9151552b..bd389907657f0d 100644 --- a/packages/mui-material/src/StepLabel/StepLabel.d.ts +++ b/packages/mui-material/src/StepLabel/StepLabel.d.ts @@ -4,8 +4,28 @@ import { InternalStandardProps as StandardProps } from '..'; import { StepIconProps } from '../StepIcon'; import { Theme } from '../styles'; import { StepLabelClasses } from './stepLabelClasses'; +import { CreateSlotsAndSlotProps, SlotProps } from '../utils/types'; -export interface StepLabelProps extends StandardProps> { +export interface StepLabelSlots { + /** + * The component that renders the label. + * @default span + */ + label?: React.ElementType; +} + +export type StepLabelSlotsAndSlotProps = CreateSlotsAndSlotProps< + StepLabelSlots, + { + label: SlotProps>, {}, StepLabelOwnerState>; + } +>; + +export interface StepLabelOwnerState extends StepLabelProps {} + +export interface StepLabelProps + extends StandardProps>, + StepLabelSlotsAndSlotProps { /** * In most cases will simply be a string containing a title for the label. */ @@ -17,6 +37,7 @@ export interface StepLabelProps extends StandardProps; - }; /** * The component to render in place of the [`StepIcon`](/material-ui/api/step-icon/). */ @@ -75,6 +85,8 @@ export type StepLabelClasskey = keyof NonNullable; * * - [StepLabel API](https://mui.com/material-ui/api/step-label/) */ -declare const StepLabel: ((props: StepLabelProps) => JSX.Element) & { muiName: string }; +declare const StepLabel: ((props: StepLabelProps) => JSX.Element) & { + muiName: string; +}; export default StepLabel; diff --git a/packages/mui-material/src/StepLabel/StepLabel.js b/packages/mui-material/src/StepLabel/StepLabel.js index 03bed601ec0a9f..42efdda24b6a68 100644 --- a/packages/mui-material/src/StepLabel/StepLabel.js +++ b/packages/mui-material/src/StepLabel/StepLabel.js @@ -8,6 +8,7 @@ import StepIcon from '../StepIcon'; import StepperContext from '../Stepper/StepperContext'; import { createUseThemeProps, styled } from '../zero-styled'; import stepLabelClasses, { getStepLabelUtilityClass } from './stepLabelClasses'; +import useSlot from '../utils/useSlot'; const useThemeProps = createUseThemeProps('MuiStepLabel'); @@ -132,6 +133,7 @@ const StepLabel = React.forwardRef(function StepLabel(inProps, ref) { error = false, icon: iconProp, optional, + slots = {}, slotProps = {}, StepIconComponent: StepIconComponentProp, StepIconProps, @@ -160,7 +162,19 @@ const StepLabel = React.forwardRef(function StepLabel(inProps, ref) { const classes = useUtilityClasses(ownerState); - const labelSlotProps = slotProps.label ?? componentsProps.label; + const externalForwardedProps = { + slots, + slotProps: { + ...componentsProps, + ...slotProps, + }, + }; + + const [LabelSlot, labelProps] = useSlot('label', { + elementType: StepLabelLabel, + externalForwardedProps, + ownerState, + }); return ( {children ? ( - + {children} - + ) : null} {optional} @@ -216,6 +226,7 @@ StepLabel.propTypes /* remove-proptypes */ = { /** * The props used for each slot inside. * @default {} + * @deprecated use the `slotProps` prop instead. This prop will be removed in v7. [How to migrate](/material-ui/migration/migrating-from-deprecated-apis/). */ componentsProps: PropTypes.shape({ label: PropTypes.object, @@ -238,7 +249,14 @@ StepLabel.propTypes /* remove-proptypes */ = { * @default {} */ slotProps: PropTypes.shape({ - label: PropTypes.object, + label: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), + /** + * The components used for each slot inside. + * @default {} + */ + slots: PropTypes.shape({ + label: PropTypes.elementType, }), /** * The component to render in place of the [`StepIcon`](/material-ui/api/step-icon/). diff --git a/packages/mui-material/src/StepLabel/StepLabel.test.js b/packages/mui-material/src/StepLabel/StepLabel.test.js index 05c2959f51bdcb..912a1a2b98d578 100644 --- a/packages/mui-material/src/StepLabel/StepLabel.test.js +++ b/packages/mui-material/src/StepLabel/StepLabel.test.js @@ -18,16 +18,10 @@ describe('', () => { render, refInstanceof: window.HTMLSpanElement, testVariantProps: { error: true }, - testLegacyComponentsProp: true, slots: { label: { expectedClassName: classes.label }, }, - skip: [ - 'componentProp', - 'componentsProp', - 'slotsProp', - 'slotPropsCallback', // not supported yet - ], + skip: ['componentProp', 'componentsProp'], })); describe('label content', () => {