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 bc806137a91255..6e5484cae23ae2 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 @@ -855,6 +855,36 @@ Here's how to migrate: }, ``` +## CardHeader + +Use the [codemod](https://github.com/mui/material-ui/tree/HEAD/packages/mui-codemod#card-header-props) below to migrate the code as described in the following sections: + +```bash +npx @mui/codemod@latest deprecations/card-header-props <path> +``` + +### titleTypographyProps + +The CardHeader's `titleTypographyProps` props were deprecated in favor of `slotProps.title`: + +```diff + <CardHeader +- titleTypographyProps={titleTypographyProps} ++ slotProps={{ title: titleTypographyProps }} + /> +``` + +### subheaderTypographyProps + +The CardHeader's `subheaderTypographyProps` props were deprecated in favor of `slotProps.subheader`: + +```diff + <CardHeader +- subheaderTypographyProps={subheaderTypographyProps} ++ slotProps={{ subheader: subheaderTypographyProps }} + /> +``` + ## Chip Use the [codemod](https://github.com/mui/material-ui/tree/HEAD/packages/mui-codemod#chip-classes) below to migrate the code as described in the following sections: diff --git a/docs/pages/material-ui/api/card-header.json b/docs/pages/material-ui/api/card-header.json index b015bc34e96a6b..27d456fe1e0918 100644 --- a/docs/pages/material-ui/api/card-header.json +++ b/docs/pages/material-ui/api/card-header.json @@ -5,8 +5,26 @@ "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, "component": { "type": { "name": "elementType" } }, "disableTypography": { "type": { "name": "bool" }, "default": "false" }, + "slotProps": { + "type": { + "name": "shape", + "description": "{ action?: func<br>| object, avatar?: func<br>| object, content?: func<br>| object, root?: func<br>| object, subheader?: func<br>| object, title?: func<br>| object }" + }, + "default": "{}" + }, + "slots": { + "type": { + "name": "shape", + "description": "{ action?: elementType, avatar?: elementType, content?: elementType, root?: elementType, subheader?: elementType, title?: elementType }" + }, + "default": "{}" + }, "subheader": { "type": { "name": "node" } }, - "subheaderTypographyProps": { "type": { "name": "object" } }, + "subheaderTypographyProps": { + "type": { "name": "object" }, + "deprecated": true, + "deprecationInfo": "Use <code>slotProps.subheader</code> instead. This prop will be removed in v7. See <a href=\"/material-ui/migration/migrating-from-deprecated-apis/\">Migrating from deprecated APIs</a> for more details." + }, "sx": { "type": { "name": "union", @@ -15,51 +33,56 @@ "additionalInfo": { "sx": true } }, "title": { "type": { "name": "node" } }, - "titleTypographyProps": { "type": { "name": "object" } } + "titleTypographyProps": { + "type": { "name": "object" }, + "deprecated": true, + "deprecationInfo": "Use <code>slotProps.title</code> instead. This prop will be removed in v7. See <a href=\"/material-ui/migration/migrating-from-deprecated-apis/\">Migrating from deprecated APIs</a> for more details." + } }, "name": "CardHeader", "imports": [ "import CardHeader from '@mui/material/CardHeader';", "import { CardHeader } from '@mui/material';" ], - "classes": [ + "slots": [ { - "key": "action", - "className": "MuiCardHeader-action", - "description": "Styles applied to the action element.", - "isGlobal": false + "name": "root", + "description": "The component that renders the root slot.", + "default": "'div'", + "class": "MuiCardHeader-root" }, { - "key": "avatar", - "className": "MuiCardHeader-avatar", - "description": "Styles applied to the avatar element.", - "isGlobal": false + "name": "avatar", + "description": "The component that renders the avatar slot.", + "default": "'div'", + "class": "MuiCardHeader-avatar" }, { - "key": "content", - "className": "MuiCardHeader-content", - "description": "Styles applied to the content wrapper element.", - "isGlobal": false + "name": "action", + "description": "The component that renders the action slot.", + "default": "'div'", + "class": "MuiCardHeader-action" }, { - "key": "root", - "className": "MuiCardHeader-root", - "description": "Styles applied to the root element.", - "isGlobal": false + "name": "content", + "description": "The component that renders the content slot.", + "default": "'div'", + "class": "MuiCardHeader-content" }, { - "key": "subheader", - "className": "MuiCardHeader-subheader", - "description": "Styles applied to the subheader Typography element.", - "isGlobal": false + "name": "title", + "description": "The component that renders the title slot (as long as disableTypography is not `true`).\n[Follow this guide](https://mui.com/material-ui/api/typography/#props) to learn more about the requirements for this component.", + "default": "Typography", + "class": "MuiCardHeader-title" }, { - "key": "title", - "className": "MuiCardHeader-title", - "description": "Styles applied to the title Typography element.", - "isGlobal": false + "name": "subheader", + "description": "The component that renders the subheader slot (as long as disableTypography is not `true`).\n[Follow this guide](https://mui.com/material-ui/api/typography/#props) to learn more about the requirements for this component.", + "default": "Typography", + "class": "MuiCardHeader-subheader" } ], + "classes": [], "spread": true, "themeDefaultProps": true, "muiName": "MuiCardHeader", diff --git a/docs/translations/api-docs/card-header/card-header.json b/docs/translations/api-docs/card-header/card-header.json index 677debb60cfb32..9f78623d5f6c98 100644 --- a/docs/translations/api-docs/card-header/card-header.json +++ b/docs/translations/api-docs/card-header/card-header.json @@ -10,6 +10,8 @@ "disableTypography": { "description": "If <code>true</code>, <code>subheader</code> and <code>title</code> won't be wrapped by a Typography component. This can be useful to render an alternative Typography variant by wrapping the <code>title</code> text, and optional <code>subheader</code> text with the Typography component." }, + "slotProps": { "description": "The props used for each slot inside." }, + "slots": { "description": "The components used for each slot inside." }, "subheader": { "description": "The content of the component." }, "subheaderTypographyProps": { "description": "These props will be forwarded to the subheader (as long as disableTypography is not <code>true</code>)." @@ -22,27 +24,13 @@ "description": "These props will be forwarded to the title (as long as disableTypography is not <code>true</code>)." } }, - "classDescriptions": { - "action": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the action element" - }, - "avatar": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the avatar element" - }, - "content": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the content wrapper element" - }, - "root": { "description": "Styles applied to the root element." }, - "subheader": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the subheader Typography element" - }, - "title": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the title Typography element" - } + "classDescriptions": {}, + "slotDescriptions": { + "action": "The component that renders the action slot.", + "avatar": "The component that renders the avatar slot.", + "content": "The component that renders the content slot.", + "root": "The component that renders the root slot.", + "subheader": "The component that renders the subheader slot (as long as disableTypography is not <code>true</code>). <a href=\"https://mui.com/material-ui/api/typography/#props\">Follow this guide</a> to learn more about the requirements for this component.", + "title": "The component that renders the title slot (as long as disableTypography is not <code>true</code>). <a href=\"https://mui.com/material-ui/api/typography/#props\">Follow this guide</a> to learn more about the requirements for this component." } } diff --git a/packages/mui-codemod/src/deprecations/all/deprecations-all.js b/packages/mui-codemod/src/deprecations/all/deprecations-all.js index 80a7f5138b9a68..7461bca69707b4 100644 --- a/packages/mui-codemod/src/deprecations/all/deprecations-all.js +++ b/packages/mui-codemod/src/deprecations/all/deprecations-all.js @@ -31,6 +31,7 @@ import transformTabClasses from '../tab-classes'; import transformToggleButtonGroupClasses from '../toggle-button-group-classes'; import transformTooltipProps from '../tooltip-props'; import transformTablePaginationProps from '../table-pagination-props'; +import transformCardHeaderProps from '../card-header-props'; /** * @param {import('jscodeshift').FileInfo} file @@ -70,6 +71,7 @@ export default function deprecationsAll(file, api, options) { file.source = transformToggleButtonGroupClasses(file, api, options); file.source = transformTooltipProps(file, api, options); file.source = transformTablePaginationProps(file, api, options); + file.source = transformCardHeaderProps(file, api, options); return file.source; } diff --git a/packages/mui-codemod/src/deprecations/card-header-props/card-header-props.js b/packages/mui-codemod/src/deprecations/card-header-props/card-header-props.js new file mode 100644 index 00000000000000..f0909e8bf5534b --- /dev/null +++ b/packages/mui-codemod/src/deprecations/card-header-props/card-header-props.js @@ -0,0 +1,27 @@ +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: 'CardHeader', + propName: 'titleTypographyProps', + slotName: 'title', + }); + + movePropIntoSlotProps(j, { + root, + componentName: 'CardHeader', + propName: 'subheaderTypographyProps', + slotName: 'subheader', + }); + + return root.toSource(printOptions); +} diff --git a/packages/mui-codemod/src/deprecations/card-header-props/card-header-props.test.js b/packages/mui-codemod/src/deprecations/card-header-props/card-header-props.test.js new file mode 100644 index 00000000000000..89914c8db31611 --- /dev/null +++ b/packages/mui-codemod/src/deprecations/card-header-props/card-header-props.test.js @@ -0,0 +1,13 @@ +import { describeJscodeshiftTransform } from '../../../testUtils'; +import transform from './card-header-props'; + +describe('@mui/codemod', () => { + describe('deprecations', () => { + describeJscodeshiftTransform({ + transform, + transformName: 'tooltip-props', + dirname: __dirname, + testCases: [{ actual: '/test-cases/actual.js', expected: '/test-cases/expected.js' }], + }); + }); +}); diff --git a/packages/mui-codemod/src/deprecations/card-header-props/index.js b/packages/mui-codemod/src/deprecations/card-header-props/index.js new file mode 100644 index 00000000000000..2d5aa627385444 --- /dev/null +++ b/packages/mui-codemod/src/deprecations/card-header-props/index.js @@ -0,0 +1 @@ +export { default } from './card-header-props'; diff --git a/packages/mui-codemod/src/deprecations/card-header-props/test-cases/actual.js b/packages/mui-codemod/src/deprecations/card-header-props/test-cases/actual.js new file mode 100644 index 00000000000000..e2456cfe52aba0 --- /dev/null +++ b/packages/mui-codemod/src/deprecations/card-header-props/test-cases/actual.js @@ -0,0 +1,26 @@ +import CardHeader from '@mui/material/CardHeader'; +import { CardHeader as MyCardHeader } from '@mui/material'; + +<CardHeader + titleTypographyProps={{ variant: 'h6' }} + subheaderTypographyProps={{ variant: 'body2' }} +/>; +<CardHeader + titleTypographyProps={{ variant: 'h6' }} + subheaderTypographyProps={{ variant: 'body2' }} + slotProps={{ title: { variant: 'h1' }, subheader: { variant: 'h2' } }} +/>; +<CardHeader + titleTypographyProps={{ variant: 'h6' }} + subheaderTypographyProps={{ variant: 'body2' }} + slotProps={{ title: { sx: { color: 'red' } }, subheader: { sx: { color: 'red' } } }} +/>; +<MyCardHeader + titleTypographyProps={{ variant: 'h6' }} + subheaderTypographyProps={{ variant: 'body2' }} +/>; + +<CustomCardHeader + titleTypographyProps={{ variant: 'h6' }} + subheaderTypographyProps={{ variant: 'body2' }} +/>; diff --git a/packages/mui-codemod/src/deprecations/card-header-props/test-cases/expected.js b/packages/mui-codemod/src/deprecations/card-header-props/test-cases/expected.js new file mode 100644 index 00000000000000..03bb60cc95ae91 --- /dev/null +++ b/packages/mui-codemod/src/deprecations/card-header-props/test-cases/expected.js @@ -0,0 +1,34 @@ +import CardHeader from '@mui/material/CardHeader'; +import { CardHeader as MyCardHeader } from '@mui/material'; + +<CardHeader + slotProps={{ + title: { variant: 'h6' }, + subheader: { variant: 'body2' } + }} />; +<CardHeader + slotProps={{ title: { + ...{ variant: 'h6' }, + ...{ variant: 'h1' } + }, subheader: { + ...{ variant: 'body2' }, + ...{ variant: 'h2' } + } }} />; +<CardHeader + slotProps={{ title: { + ...{ variant: 'h6' }, + ...{ sx: { color: 'red' } } + }, subheader: { + ...{ variant: 'body2' }, + ...{ sx: { color: 'red' } } + } }} />; +<MyCardHeader + slotProps={{ + title: { variant: 'h6' }, + subheader: { variant: 'body2' } + }} />; + +<CustomCardHeader + titleTypographyProps={{ variant: 'h6' }} + subheaderTypographyProps={{ variant: 'body2' }} +/>; diff --git a/packages/mui-material/src/CardHeader/CardHeader.d.ts b/packages/mui-material/src/CardHeader/CardHeader.d.ts index 4fce9fed0685d3..1f5292645f9912 100644 --- a/packages/mui-material/src/CardHeader/CardHeader.d.ts +++ b/packages/mui-material/src/CardHeader/CardHeader.d.ts @@ -3,8 +3,116 @@ import { SxProps } from '@mui/system'; import { TypographyProps } from '../Typography'; import { OverridableComponent, OverrideProps } from '../OverridableComponent'; import { Theme } from '..'; +import { CreateSlotsAndSlotProps, SlotProps } from '../utils/types'; import { CardHeaderClasses } from './cardHeaderClasses'; +export interface CardHeaderRootSlotPropsOverrides {} + +export interface CardHeaderAvatarSlotPropsOverrides {} + +export interface CardHeaderActionSlotPropsOverrides {} + +export interface CardHeaderContentSlotPropsOverrides {} + +export interface CardHeaderTitleSlotPropsOverrides {} + +export interface CardHeaderSubheaderSlotPropsOverrides {} + +export interface CardHeaderSlots { + /** + * The component that renders the root slot. + * @default 'div' + */ + root: React.ElementType; + /** + * The component that renders the avatar slot. + * @default 'div' + */ + avatar: React.ElementType; + /** + * The component that renders the action slot. + * @default 'div' + */ + action: React.ElementType; + /** + * The component that renders the content slot. + * @default 'div' + */ + content: React.ElementType; + /** + * The component that renders the title slot (as long as disableTypography is not `true`). + * [Follow this guide](https://mui.com/material-ui/api/typography/#props) to learn more about the requirements for this component. + * @default Typography + */ + title: React.ElementType; + /** + * The component that renders the subheader slot (as long as disableTypography is not `true`). + * [Follow this guide](https://mui.com/material-ui/api/typography/#props) to learn more about the requirements for this component. + * @default Typography + */ + subheader: React.ElementType; +} + +export type CardHeaderSlotsAndSlotProps = CreateSlotsAndSlotProps< + CardHeaderSlots, + { + /** + * Props forwarded to the root slot. + * By default, the avaible props are based on the div element. + */ + root: SlotProps< + React.ElementType<React.DetailsHTMLAttributes<HTMLDivElement>>, + CardHeaderRootSlotPropsOverrides, + CardHeaderOwnerState + >; + /** + * Props forwarded to the avatar slot. + * By default, the avaible props are based on the div element. + */ + avatar: SlotProps< + React.ElementType<React.DetailsHTMLAttributes<HTMLDivElement>>, + CardHeaderAvatarSlotPropsOverrides, + CardHeaderOwnerState + >; + /** + * Props forwarded to the action slot. + * By default, the avaible props are based on the div element. + */ + action: SlotProps< + React.ElementType<React.DetailsHTMLAttributes<HTMLDivElement>>, + CardHeaderActionSlotPropsOverrides, + CardHeaderOwnerState + >; + /** + * Props forwarded to the content slot. + * By default, the avaible props are based on the div element. + */ + content: SlotProps< + React.ElementType<React.DetailsHTMLAttributes<HTMLDivElement>>, + CardHeaderContentSlotPropsOverrides, + CardHeaderOwnerState + >; + /** + * Props forwarded to the title slot (as long as disableTypography is not `true`). + * By default, the avaible props are based on the [Typography](https://mui.com/material-ui/api/typography/#props) component. + */ + title: SlotProps< + React.ElementType<TypographyProps>, + CardHeaderTitleSlotPropsOverrides, + CardHeaderOwnerState + >; + /** + * Props forwarded to the subheader slot (as long as disableTypography is not `true`). + * By default, the avaible props are based on the [Typography](https://mui.com/material-ui/api/typography/#props) component. + */ + subheader: SlotProps< + React.ElementType<TypographyProps>, + CardHeaderSubheaderSlotPropsOverrides, + CardHeaderOwnerState + >; + } +>; + export interface CardHeaderOwnProps< TitleTypographyComponent extends React.ElementType = 'span', SubheaderTypographyComponent extends React.ElementType = 'span', @@ -36,6 +144,7 @@ export interface CardHeaderOwnProps< /** * These props will be forwarded to the subheader * (as long as disableTypography is not `true`). + * @deprecated Use `slotProps.subheader` instead. This prop will be removed in v7. See [Migrating from deprecated APIs](/material-ui/migration/migrating-from-deprecated-apis/) for more details. */ subheaderTypographyProps?: TypographyProps< SubheaderTypographyComponent, @@ -54,6 +163,7 @@ export interface CardHeaderOwnProps< /** * These props will be forwarded to the title * (as long as disableTypography is not `true`). + * @deprecated Use `slotProps.title` instead. This prop will be removed in v7. See [Migrating from deprecated APIs](/material-ui/migration/migrating-from-deprecated-apis/) for more details. */ titleTypographyProps?: TypographyProps< TitleTypographyComponent, @@ -63,6 +173,8 @@ export interface CardHeaderOwnProps< >; } +export interface CardHeaderOwnerState extends CardHeaderOwnProps {} + export interface CardHeaderTypeMap< AdditionalProps = {}, RootComponent extends React.ElementType = 'div', @@ -70,7 +182,8 @@ export interface CardHeaderTypeMap< SubheaderTypographyComponent extends React.ElementType = 'span', > { props: AdditionalProps & - CardHeaderOwnProps<TitleTypographyComponent, SubheaderTypographyComponent>; + CardHeaderOwnProps<TitleTypographyComponent, SubheaderTypographyComponent> & + CardHeaderSlotsAndSlotProps; defaultComponent: RootComponent; } /** diff --git a/packages/mui-material/src/CardHeader/CardHeader.js b/packages/mui-material/src/CardHeader/CardHeader.js index 88bcd6c709fcdf..5a669c5f31f2bc 100644 --- a/packages/mui-material/src/CardHeader/CardHeader.js +++ b/packages/mui-material/src/CardHeader/CardHeader.js @@ -1,12 +1,12 @@ 'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; -import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; import Typography, { typographyClasses } from '../Typography'; import { styled } from '../zero-styled'; import { useDefaultProps } from '../DefaultPropsProvider'; import cardHeaderClasses, { getCardHeaderUtilityClass } from './cardHeaderClasses'; +import useSlot from '../utils/useSlot'; const useUtilityClasses = (ownerState) => { const { classes } = ownerState; @@ -80,13 +80,14 @@ const CardHeader = React.forwardRef(function CardHeader(inProps, ref) { const { action, avatar, - className, component = 'div', disableTypography = false, subheader: subheaderProp, subheaderTypographyProps, title: titleProp, titleTypographyProps, + slots = {}, + slotProps = {}, ...other } = props; @@ -98,59 +99,88 @@ const CardHeader = React.forwardRef(function CardHeader(inProps, ref) { const classes = useUtilityClasses(ownerState); + const externalForwardedProps = { + slots, + slotProps: { + title: titleTypographyProps, + subheader: subheaderTypographyProps, + ...slotProps, + }, + }; + let title = titleProp; + const [TitleSlot, titleSlotProps] = useSlot('title', { + className: classes.title, + elementType: Typography, + externalForwardedProps, + ownerState, + additionalProps: { + variant: avatar ? 'body2' : 'h5', + component: 'span', + }, + }); if (title != null && title.type !== Typography && !disableTypography) { - title = ( - <Typography - variant={avatar ? 'body2' : 'h5'} - className={classes.title} - component="span" - {...titleTypographyProps} - > - {title} - </Typography> - ); + title = <TitleSlot {...titleSlotProps}>{title}</TitleSlot>; } let subheader = subheaderProp; + const [SubheaderSlot, subheaderSlotProps] = useSlot('subheader', { + className: classes.subheader, + elementType: Typography, + externalForwardedProps, + ownerState, + additionalProps: { + variant: avatar ? 'body2' : 'body1', + color: 'textSecondary', + component: 'span', + }, + }); if (subheader != null && subheader.type !== Typography && !disableTypography) { - subheader = ( - <Typography - variant={avatar ? 'body2' : 'body1'} - className={classes.subheader} - color="textSecondary" - component="span" - {...subheaderTypographyProps} - > - {subheader} - </Typography> - ); + subheader = <SubheaderSlot {...subheaderSlotProps}>{subheader}</SubheaderSlot>; } + const [RootSlot, rootSlotProps] = useSlot('root', { + ref, + className: classes.root, + elementType: CardHeaderRoot, + externalForwardedProps: { + ...externalForwardedProps, + ...other, + component, + }, + ownerState, + }); + + const [AvatarSlot, avatarSlotProps] = useSlot('avatar', { + className: classes.avatar, + elementType: CardHeaderAvatar, + externalForwardedProps, + ownerState, + }); + + const [ContentSlot, contentSlotProps] = useSlot('content', { + className: classes.content, + elementType: CardHeaderContent, + externalForwardedProps, + ownerState, + }); + + const [ActionSlot, actionSlotProps] = useSlot('action', { + className: classes.action, + elementType: CardHeaderAction, + externalForwardedProps, + ownerState, + }); + return ( - <CardHeaderRoot - className={clsx(classes.root, className)} - as={component} - ref={ref} - ownerState={ownerState} - {...other} - > - {avatar && ( - <CardHeaderAvatar className={classes.avatar} ownerState={ownerState}> - {avatar} - </CardHeaderAvatar> - )} - - <CardHeaderContent className={classes.content} ownerState={ownerState}> + <RootSlot {...rootSlotProps}> + {avatar && <AvatarSlot {...avatarSlotProps}>{avatar}</AvatarSlot>} + <ContentSlot {...contentSlotProps}> {title} {subheader} - </CardHeaderContent> - {action && ( - <CardHeaderAction className={classes.action} ownerState={ownerState}> - {action} - </CardHeaderAction> - )} - </CardHeaderRoot> + </ContentSlot> + {action && <ActionSlot {...actionSlotProps}>{action}</ActionSlot>} + </RootSlot> ); }); @@ -175,10 +205,6 @@ CardHeader.propTypes /* remove-proptypes */ = { * Override or extend the styles applied to the component. */ classes: PropTypes.object, - /** - * @ignore - */ - className: PropTypes.string, /** * The component used for the root node. * Either a string to use a HTML element or a component. @@ -192,6 +218,30 @@ CardHeader.propTypes /* remove-proptypes */ = { * @default false */ disableTypography: PropTypes.bool, + /** + * The props used for each slot inside. + * @default {} + */ + slotProps: PropTypes.shape({ + action: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + avatar: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + content: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + subheader: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + title: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), + /** + * The components used for each slot inside. + * @default {} + */ + slots: PropTypes.shape({ + action: PropTypes.elementType, + avatar: PropTypes.elementType, + content: PropTypes.elementType, + root: PropTypes.elementType, + subheader: PropTypes.elementType, + title: PropTypes.elementType, + }), /** * The content of the component. */ @@ -199,6 +249,7 @@ CardHeader.propTypes /* remove-proptypes */ = { /** * These props will be forwarded to the subheader * (as long as disableTypography is not `true`). + * @deprecated Use `slotProps.subheader` instead. This prop will be removed in v7. See [Migrating from deprecated APIs](/material-ui/migration/migrating-from-deprecated-apis/) for more details. */ subheaderTypographyProps: PropTypes.object, /** @@ -216,6 +267,7 @@ CardHeader.propTypes /* remove-proptypes */ = { /** * These props will be forwarded to the title * (as long as disableTypography is not `true`). + * @deprecated Use `slotProps.title` instead. This prop will be removed in v7. See [Migrating from deprecated APIs](/material-ui/migration/migrating-from-deprecated-apis/) for more details. */ titleTypographyProps: PropTypes.object, }; diff --git a/packages/mui-material/src/CardHeader/CardHeader.spec.tsx b/packages/mui-material/src/CardHeader/CardHeader.spec.tsx index 62b8735bbd5f55..ac418546aeb535 100644 --- a/packages/mui-material/src/CardHeader/CardHeader.spec.tsx +++ b/packages/mui-material/src/CardHeader/CardHeader.spec.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { styled } from '@mui/material/styles'; import CardHeader, { CardHeaderProps, CardHeaderTypeMap } from '@mui/material/CardHeader'; const CustomComponent: React.FC<{ stringProp: string; numberProp: number }> = @@ -306,3 +307,49 @@ function mixedTypographyPropsTest() { subheaderTypographyProps={{ component: CustomComponent, numberProp: 2 }} />; } + +<CardHeader + slotProps={{ + root: { + component: 'div', + className: 'flex', + 'data-testid': 'hello', + }, + action: { + component: 'div', + className: 'flex', + 'data-testid': 'hello', + }, + avatar: { + component: 'div', + className: 'flex', + 'data-testid': 'hello', + }, + content: { + component: 'div', + className: 'flex', + 'data-testid': 'hello', + }, + title: { + component: 'div', + className: 'flex', + 'data-testid': 'hello', + }, + subheader: { + component: 'div', + className: 'flex', + 'data-testid': 'hello', + }, + }} +/>; +const CustomSlot = styled('div')({}); +<CardHeader + slots={{ + action: CustomSlot, + avatar: CustomSlot, + content: CustomSlot, + root: CustomSlot, + subheader: CustomSlot, + title: CustomSlot, + }} +/>; diff --git a/packages/mui-material/src/CardHeader/CardHeader.test.js b/packages/mui-material/src/CardHeader/CardHeader.test.js index 2c40497429048f..2cdab69941ef76 100644 --- a/packages/mui-material/src/CardHeader/CardHeader.test.js +++ b/packages/mui-material/src/CardHeader/CardHeader.test.js @@ -2,23 +2,48 @@ import * as React from 'react'; import { expect } from 'chai'; import { createRenderer } from '@mui/internal-test-utils'; import { typographyClasses } from '@mui/material/Typography'; +import Avatar from '@mui/material/Avatar'; +import IconButton from '@mui/material/IconButton'; import CardHeader, { cardHeaderClasses as classes } from '@mui/material/CardHeader'; import describeConformance from '../../test/describeConformance'; describe('<CardHeader />', () => { const { render } = createRenderer(); - describeConformance(<CardHeader />, () => ({ - classes, - inheritComponent: 'div', - render, - muiName: 'MuiCardHeader', - refInstanceof: window.HTMLDivElement, - testDeepOverrides: { slotName: 'content', slotClassName: classes.content }, - testComponentPropWith: 'span', - testVariantProps: { variant: 'foo' }, - skip: ['componentsProp'], - })); + describeConformance( + <CardHeader title="title" subheader="subheader" avatar={<Avatar />} action={<IconButton />} />, + () => ({ + classes, + inheritComponent: 'div', + render, + muiName: 'MuiCardHeader', + refInstanceof: window.HTMLDivElement, + testDeepOverrides: { slotName: 'content', slotClassName: classes.content }, + testComponentPropWith: 'span', + testVariantProps: { variant: 'foo' }, + slots: { + root: { + expectedClassName: classes.root, + }, + avatar: { + expectedClassName: classes.avatar, + }, + action: { + expectedClassName: classes.action, + }, + content: { + expectedClassName: classes.content, + }, + title: { + expectedClassName: classes.title, + }, + subheader: { + expectedClassName: classes.subheader, + }, + }, + skip: ['componentsProp'], + }), + ); describe('without an avatar', () => { it('should render the title as headline text', () => {