diff --git a/docs/pages/api-docs/card-media.json b/docs/pages/api-docs/card-media.json
index 6d6a6a01c294fc..528452a3976a72 100644
--- a/docs/pages/api-docs/card-media.json
+++ b/docs/pages/api-docs/card-media.json
@@ -4,7 +4,8 @@
"classes": { "type": { "name": "object" } },
"component": { "type": { "name": "elementType" } },
"image": { "type": { "name": "string" } },
- "src": { "type": { "name": "string" } }
+ "src": { "type": { "name": "string" } },
+ "sx": { "type": { "name": "object" } }
},
"name": "CardMedia",
"styles": { "classes": ["root", "media", "img"], "globalClasses": {}, "name": "MuiCardMedia" },
@@ -13,6 +14,6 @@
"filename": "/packages/material-ui/src/CardMedia/CardMedia.js",
"inheritance": null,
"demos": "
",
- "styledComponent": false,
+ "styledComponent": true,
"cssComponent": false
}
diff --git a/docs/translations/api-docs/card-media/card-media.json b/docs/translations/api-docs/card-media/card-media.json
index 549ce3ec7b894f..92515bce5e0bfc 100644
--- a/docs/translations/api-docs/card-media/card-media.json
+++ b/docs/translations/api-docs/card-media/card-media.json
@@ -5,7 +5,8 @@
"classes": "Override or extend the styles applied to the component. See CSS API below for more details.",
"component": "The component used for the root node. Either a string to use a HTML element or a component.",
"image": "Image to be displayed as a background image. Either image
or src
prop must be specified. Note that caller must specify height otherwise the image will not be visible.",
- "src": "An alias for image
property. Available only with media components. Media components: video
, audio
, picture
, iframe
, img
."
+ "src": "An alias for image
property. Available only with media components. Media components: video
, audio
, picture
, iframe
, img
.",
+ "sx": "The system prop that allows defining system overrides as well as additional CSS styles. See the `sx` page for more details."
},
"classDescriptions": {
"root": { "description": "Styles applied to the root element." },
diff --git a/packages/material-ui/src/CardMedia/CardMedia.d.ts b/packages/material-ui/src/CardMedia/CardMedia.d.ts
index 7d5a6299c820fb..3ec63fbf834e55 100644
--- a/packages/material-ui/src/CardMedia/CardMedia.d.ts
+++ b/packages/material-ui/src/CardMedia/CardMedia.d.ts
@@ -1,4 +1,6 @@
+import { SxProps } from '@material-ui/system';
import * as React from 'react';
+import { Theme } from '..';
import { OverridableComponent, OverrideProps } from '../OverridableComponent';
export interface CardMediaTypeMap {
@@ -30,6 +32,10 @@ export interface CardMediaTypeMap
{
* Media components: `video`, `audio`, `picture`, `iframe`, `img`.
*/
src?: string;
+ /**
+ * The system prop that allows defining system overrides as well as additional CSS styles.
+ */
+ sx?: SxProps;
};
defaultComponent: D;
}
diff --git a/packages/material-ui/src/CardMedia/CardMedia.js b/packages/material-ui/src/CardMedia/CardMedia.js
index d28619ff1980e4..8e6e2fbd35bceb 100644
--- a/packages/material-ui/src/CardMedia/CardMedia.js
+++ b/packages/material-ui/src/CardMedia/CardMedia.js
@@ -1,63 +1,89 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
-import { chainPropTypes } from '@material-ui/utils';
-import withStyles from '../styles/withStyles';
+import { chainPropTypes, deepmerge } from '@material-ui/utils';
+import { unstable_composeClasses as composeClasses } from '@material-ui/unstyled';
+import useThemeProps from '../styles/useThemeProps';
+import experimentalStyled from '../styles/experimentalStyled';
+import { getCardMediaUtilityClass } from './cardMediaClasses';
-export const styles = {
- /* Styles applied to the root element. */
- root: {
- display: 'block',
- backgroundSize: 'cover',
- backgroundRepeat: 'no-repeat',
- backgroundPosition: 'center',
+const overridesResolver = (props, styles) => {
+ const { styleProps } = props;
+ const { isMediaComponent, isImageComponent } = styleProps;
+
+ return deepmerge(styles.root || {}, {
+ ...(isMediaComponent && styles.media),
+ ...(isImageComponent && styles.img),
+ });
+};
+
+const useUtilityClasses = (styleProps) => {
+ const { classes, isMediaComponent, isImageComponent } = styleProps;
+
+ const slots = {
+ root: ['root', isMediaComponent && 'media', isImageComponent && 'img'],
+ };
+
+ return composeClasses(slots, getCardMediaUtilityClass, classes);
+};
+
+const CardMediaRoot = experimentalStyled(
+ 'div',
+ {},
+ {
+ name: 'MuiCardMedia',
+ slot: 'Root',
+ overridesResolver,
},
+)(({ styleProps }) => ({
+ /* Styles applied to the root element. */
+ display: 'block',
+ backgroundSize: 'cover',
+ backgroundRepeat: 'no-repeat',
+ backgroundPosition: 'center',
/* Styles applied to the root element if `component="video, audio, picture, iframe, or img"`. */
- media: {
+ ...(styleProps.isMediaComponent && {
width: '100%',
- },
+ }),
/* Styles applied to the root element if `component="picture or img"`. */
- img: {
+ ...(styleProps.isImageComponent && {
// ⚠️ object-fit is not supported by IE11.
objectFit: 'cover',
- },
-};
+ }),
+}));
const MEDIA_COMPONENTS = ['video', 'audio', 'picture', 'iframe', 'img'];
+const IMAGE_COMPONENTS = ['picture', 'img'];
-const CardMedia = React.forwardRef(function CardMedia(props, ref) {
- const {
- children,
- classes,
- className,
- component: Component = 'div',
- image,
- src,
- style,
- ...other
- } = props;
+const CardMedia = React.forwardRef(function CardMedia(inProps, ref) {
+ const props = useThemeProps({ props: inProps, name: 'MuiCardMedia' });
+ const { children, className, component = 'div', image, src, style, ...other } = props;
- const isMediaComponent = MEDIA_COMPONENTS.indexOf(Component) !== -1;
+ const isMediaComponent = MEDIA_COMPONENTS.indexOf(component) !== -1;
const composedStyle =
!isMediaComponent && image ? { backgroundImage: `url("${image}")`, ...style } : style;
+ const styleProps = {
+ ...props,
+ component,
+ isMediaComponent,
+ isImageComponent: IMAGE_COMPONENTS.indexOf(component) !== -1,
+ };
+
+ const classes = useUtilityClasses(styleProps);
+
return (
-
{children}
-
+
);
});
@@ -106,6 +132,10 @@ CardMedia.propTypes = {
* @ignore
*/
style: PropTypes.object,
+ /**
+ * The system prop that allows defining system overrides as well as additional CSS styles.
+ */
+ sx: PropTypes.object,
};
-export default withStyles(styles, { name: 'MuiCardMedia' })(CardMedia);
+export default CardMedia;
diff --git a/packages/material-ui/src/CardMedia/CardMedia.test.js b/packages/material-ui/src/CardMedia/CardMedia.test.js
index 2d6e8c93306dda..8cbba8334d5094 100644
--- a/packages/material-ui/src/CardMedia/CardMedia.test.js
+++ b/packages/material-ui/src/CardMedia/CardMedia.test.js
@@ -1,23 +1,23 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import { expect } from 'chai';
-import { getClasses, createMount, createClientRender, describeConformance } from 'test/utils';
+import { createMount, createClientRender, describeConformanceV5 } from 'test/utils';
import CardMedia from './CardMedia';
+import classes from './cardMediaClasses';
describe('', () => {
const mount = createMount();
- let classes;
const render = createClientRender();
- before(() => {
- classes = getClasses();
- });
- describeConformance(, () => ({
+ describeConformanceV5(, () => ({
classes,
inheritComponent: 'div',
mount,
+ muiName: 'MuiCardMedia',
refInstanceof: window.HTMLDivElement,
testComponentPropWith: 'span',
+ testVariantProps: { variant: 'foo' },
+ skip: ['componentsProp'],
}));
it('should have the backgroundImage specified', () => {
@@ -79,7 +79,7 @@ describe('', () => {
it('warns when neither `children`, nor `image`, nor `src`, nor `component` are provided', () => {
expect(() => {
- PropTypes.checkPropTypes(CardMedia.Naked.propTypes, { classes: {} }, 'prop', 'MockedName');
+ PropTypes.checkPropTypes(CardMedia.propTypes, { classes: {} }, 'prop', 'MockedName');
}).toErrorDev(
'Material-UI: Either `children`, `image`, `src` or `component` prop must be specified.',
);
diff --git a/packages/material-ui/src/CardMedia/cardMediaClasses.d.ts b/packages/material-ui/src/CardMedia/cardMediaClasses.d.ts
new file mode 100644
index 00000000000000..4bf7f3f94b9a98
--- /dev/null
+++ b/packages/material-ui/src/CardMedia/cardMediaClasses.d.ts
@@ -0,0 +1,11 @@
+export interface CardMediaClasses {
+ root: string;
+ media: string;
+ img: string;
+}
+
+declare const cardMediaClasses: CardMediaClasses;
+
+export function getCardMediaUtilityClass(slot: string): string;
+
+export default cardMediaClasses;
diff --git a/packages/material-ui/src/CardMedia/cardMediaClasses.js b/packages/material-ui/src/CardMedia/cardMediaClasses.js
new file mode 100644
index 00000000000000..5a1f4587377c8b
--- /dev/null
+++ b/packages/material-ui/src/CardMedia/cardMediaClasses.js
@@ -0,0 +1,9 @@
+import { generateUtilityClass, generateUtilityClasses } from '@material-ui/unstyled';
+
+export function getCardMediaUtilityClass(slot) {
+ return generateUtilityClass('MuiCardMedia', slot);
+}
+
+const cardMediaClasses = generateUtilityClasses('MuiCardMedia', ['root', 'media', 'img']);
+
+export default cardMediaClasses;
diff --git a/packages/material-ui/src/CardMedia/index.d.ts b/packages/material-ui/src/CardMedia/index.d.ts
index e01400dab1b601..c61f21cc6b4d84 100644
--- a/packages/material-ui/src/CardMedia/index.d.ts
+++ b/packages/material-ui/src/CardMedia/index.d.ts
@@ -1,2 +1,5 @@
export { default } from './CardMedia';
export * from './CardMedia';
+
+export { default as cardMediaClasses } from './cardMediaClasses';
+export * from './cardMediaClasses';
diff --git a/packages/material-ui/src/CardMedia/index.js b/packages/material-ui/src/CardMedia/index.js
index 52c81c17a543a3..b20f3170c16b8a 100644
--- a/packages/material-ui/src/CardMedia/index.js
+++ b/packages/material-ui/src/CardMedia/index.js
@@ -1 +1,4 @@
export { default } from './CardMedia';
+
+export { default as cardMediaClasses } from './cardMediaClasses';
+export * from './cardMediaClasses';