diff --git a/docs/pages/api-docs/popover.json b/docs/pages/api-docs/popover.json
index 4c034015a04250..b4bb01dffceee3 100644
--- a/docs/pages/api-docs/popover.json
+++ b/docs/pages/api-docs/popover.json
@@ -31,6 +31,7 @@
"type": { "name": "shape", "description": "{ component?: element type }" },
"default": "{}"
},
+ "sx": { "type": { "name": "object" } },
"transformOrigin": {
"type": {
"name": "shape",
@@ -55,6 +56,6 @@
"filename": "/packages/material-ui/src/Popover/Popover.js",
"inheritance": { "component": "Modal", "pathname": "/api/modal/" },
"demos": "
",
- "styledComponent": false,
+ "styledComponent": true,
"cssComponent": false
}
diff --git a/docs/translations/api-docs/popover/popover.json b/docs/translations/api-docs/popover/popover.json
index 169f18cde52cb6..de0491a8b129e1 100644
--- a/docs/translations/api-docs/popover/popover.json
+++ b/docs/translations/api-docs/popover/popover.json
@@ -15,6 +15,7 @@
"onClose": "Callback fired when the component requests to be closed. The reason
parameter can optionally be used to control the response to onClose
.",
"open": "If true
, the component is shown.",
"PaperProps": "Props applied to the Paper
element.",
+ "sx": "The system prop that allows defining system overrides as well as additional CSS styles. See the `sx` page for more details.",
"transformOrigin": "This is the point on the popover which will attach to the anchor's origin.
Options: vertical: [top, center, bottom, x(px)]; horizontal: [left, center, right, x(px)].",
"TransitionComponent": "The component used for the transition. Follow this guide to learn more about the requirements for this component.",
"transitionDuration": "Set to 'auto' to automatically calculate transition time based on height.",
diff --git a/packages/material-ui/src/Popover/Popover.d.ts b/packages/material-ui/src/Popover/Popover.d.ts
index 7e572794f99f7b..ce77cbf7559c3d 100644
--- a/packages/material-ui/src/Popover/Popover.d.ts
+++ b/packages/material-ui/src/Popover/Popover.d.ts
@@ -1,7 +1,9 @@
import * as React from 'react';
+import { SxProps } from '@material-ui/system';
import { InternalStandardProps as StandardProps } from '..';
import { PaperProps } from '../Paper';
import { ModalProps } from '../Modal';
+import { Theme } from '../styles';
import { TransitionHandlerProps, TransitionProps } from '../transitions/transition';
export interface PopoverOrigin {
@@ -103,6 +105,10 @@ export interface PopoverProps
* @default {}
*/
PaperProps?: Partial;
+ /**
+ * The system prop that allows defining system overrides as well as additional CSS styles.
+ */
+ sx?: SxProps;
/**
* This is the point on the popover which
* will attach to the anchor's origin.
diff --git a/packages/material-ui/src/Popover/Popover.js b/packages/material-ui/src/Popover/Popover.js
index d403c77fd0d245..42cbefd237fe1b 100644
--- a/packages/material-ui/src/Popover/Popover.js
+++ b/packages/material-ui/src/Popover/Popover.js
@@ -1,19 +1,23 @@
import * as React from 'react';
import PropTypes from 'prop-types';
+import clsx from 'clsx';
+import { unstable_composeClasses as composeClasses } from '@material-ui/unstyled';
import {
chainPropTypes,
+ deepmerge,
elementTypeAcceptingRef,
refType,
HTMLElementType,
} from '@material-ui/utils';
-import clsx from 'clsx';
+import experimentalStyled from '../styles/experimentalStyled';
+import useThemeProps from '../styles/useThemeProps';
import debounce from '../utils/debounce';
import ownerDocument from '../utils/ownerDocument';
import ownerWindow from '../utils/ownerWindow';
-import withStyles from '../styles/withStyles';
-import Modal from '../Modal';
import Grow from '../Grow';
+import Modal from '../Modal';
import Paper from '../Paper';
+import popoverClasses, { getPopoverUtilityClass } from './popoverClasses';
export function getOffsetTop(rect, vertical) {
let offset = 0;
@@ -65,26 +69,56 @@ function getAnchorEl(anchorEl) {
return typeof anchorEl === 'function' ? anchorEl() : anchorEl;
}
-export const styles = {
- /* Styles applied to the root element. */
- root: {},
- /* Styles applied to the Paper component. */
- paper: {
- position: 'absolute',
- overflowY: 'auto',
- overflowX: 'hidden',
- // So we see the popover when it's empty.
- // It's most likely on issue on userland.
- minWidth: 16,
- minHeight: 16,
- maxWidth: 'calc(100% - 32px)',
- maxHeight: 'calc(100% - 32px)',
- // We disable the focus ring for mouse, touch and keyboard users.
- outline: 0,
- },
+const overridesResolver = (props, styles) => {
+ return deepmerge(styles.root || {}, {
+ [`& .${popoverClasses.paper}`]: styles.paper,
+ });
};
-const Popover = React.forwardRef(function Popover(props, ref) {
+const useUtilityClasses = (styleProps) => {
+ const { classes } = styleProps;
+
+ const slots = {
+ root: ['root'],
+ paper: ['paper'],
+ };
+
+ return composeClasses(slots, getPopoverUtilityClass, classes);
+};
+
+const PopoverRoot = experimentalStyled(
+ Modal,
+ {},
+ {
+ name: 'MuiPopover',
+ slot: 'Root',
+ overridesResolver,
+ },
+)({});
+
+const PopoverPaper = experimentalStyled(
+ Paper,
+ {},
+ {
+ name: 'MuiPopover',
+ slot: 'Paper',
+ },
+)({
+ position: 'absolute',
+ overflowY: 'auto',
+ overflowX: 'hidden',
+ // So we see the popover when it's empty.
+ // It's most likely on issue on userland.
+ minWidth: 16,
+ minHeight: 16,
+ maxWidth: 'calc(100% - 32px)',
+ maxHeight: 'calc(100% - 32px)',
+ // We disable the focus ring for mouse, touch and keyboard users.
+ outline: 0,
+});
+
+const Popover = React.forwardRef(function Popover(inProps, ref) {
+ const props = useThemeProps({ props: inProps, name: 'MuiPopover' });
const {
action,
anchorEl,
@@ -95,7 +129,6 @@ const Popover = React.forwardRef(function Popover(props, ref) {
anchorPosition,
anchorReference = 'anchorEl',
children,
- classes,
className,
container: containerProp,
elevation = 8,
@@ -114,6 +147,21 @@ const Popover = React.forwardRef(function Popover(props, ref) {
} = props;
const paperRef = React.useRef();
+ const styleProps = {
+ ...props,
+ anchorOrigin,
+ anchorReference,
+ elevation,
+ marginThreshold,
+ PaperProps,
+ transformOrigin,
+ TransitionComponent,
+ transitionDuration: transitionDurationProp,
+ TransitionProps,
+ };
+
+ const classes = useUtilityClasses(styleProps);
+
// Returns the top/left offset of the position
// to attach to on the anchor element (or body if none is provided)
const getAnchorOffset = React.useCallback(
@@ -379,31 +427,32 @@ const Popover = React.forwardRef(function Popover(props, ref) {
containerProp || (anchorEl ? ownerDocument(getAnchorEl(anchorEl)).body : undefined);
return (
-
-
{children}
-
+
-
+
);
});
@@ -548,6 +597,10 @@ Popover.propTypes = {
PaperProps: PropTypes /* @typescript-to-proptypes-ignore */.shape({
component: elementTypeAcceptingRef,
}),
+ /**
+ * The system prop that allows defining system overrides as well as additional CSS styles.
+ */
+ sx: PropTypes.object,
/**
* This is the point on the popover which
* will attach to the anchor's origin.
@@ -595,4 +648,4 @@ Popover.propTypes = {
TransitionProps: PropTypes.object,
};
-export default withStyles(styles, { name: 'MuiPopover' })(Popover);
+export default Popover;
diff --git a/packages/material-ui/src/Popover/Popover.test.js b/packages/material-ui/src/Popover/Popover.test.js
index 92ed380077c614..697838a8188445 100644
--- a/packages/material-ui/src/Popover/Popover.test.js
+++ b/packages/material-ui/src/Popover/Popover.test.js
@@ -1,12 +1,18 @@
import * as React from 'react';
import { expect } from 'chai';
import { spy, stub, useFakeTimers } from 'sinon';
-import { findOutermostIntrinsic, getClasses, createMount, describeConformance } from 'test/utils';
+import {
+ findOutermostIntrinsic,
+ createMount,
+ createClientRender,
+ describeConformanceV5,
+} from 'test/utils';
import PropTypes from 'prop-types';
-import Grow from '../Grow';
-import Modal from '../Modal';
-import Paper from '../Paper';
-import Popover, { getOffsetLeft, getOffsetTop } from './Popover';
+import Grow from '@material-ui/core/Grow';
+import Modal from '@material-ui/core/Modal';
+import Paper from '@material-ui/core/Paper';
+import Popover, { popoverClasses as classes } from '@material-ui/core/Popover';
+import { getOffsetLeft, getOffsetTop } from './Popover';
import useForkRef from '../utils/useForkRef';
const mockedAnchorEl = () => {
@@ -49,27 +55,26 @@ const FakePaper = React.forwardRef(function FakeWidthPaper(props, ref) {
describe('', () => {
// StrictModeViolation: Not using act(), prefer using createClientRender from test/utils
const mount = createMount({ strict: false });
- let classes;
+ const render = createClientRender();
const defaultProps = {
open: false,
anchorEl: () => document.createElement('svg'),
};
- before(() => {
- classes = getClasses(
-
-
- ,
- );
- });
-
- describeConformance(, () => ({
+ describeConformanceV5(, () => ({
classes,
inheritComponent: Modal,
+ render,
mount,
+ muiName: 'MuiPopover',
refInstanceof: window.HTMLDivElement,
+ testDeepOverrides: { slotName: 'paper', slotClassName: classes.paper },
skip: [
'componentProp',
+ 'componentsProp',
+ 'themeDefaultProps',
+ 'themeStyleOverrides',
+ 'themeVariants',
// react-transition-group issue
'reactTestRenderer',
],
@@ -83,7 +88,7 @@ describe('', () => {
,
);
const root = wrapper.find('ForwardRef(Popover) > [data-root-node]').first();
- expect(root.type()).to.equal(Modal);
+ expect(root.find(Modal).exists()).to.equal(true);
expect(root.props().BackdropProps.invisible).to.equal(true);
});
@@ -433,7 +438,7 @@ describe('', () => {
it('should warn if anchorEl is not valid', () => {
expect(() => {
PropTypes.checkPropTypes(
- Popover.Naked.propTypes,
+ Popover.propTypes,
{ classes: {}, open: true },
'prop',
'MockedPopover',
@@ -444,7 +449,7 @@ describe('', () => {
it('warns if a component for the Paper is used that cant hold a ref', () => {
expect(() => {
PropTypes.checkPropTypes(
- Popover.Naked.propTypes,
+ Popover.propTypes,
{ ...defaultProps, classes: {}, PaperProps: { component: () => , elevation: 4 } },
'prop',
'MockedPopover',
diff --git a/packages/material-ui/src/Popover/index.js b/packages/material-ui/src/Popover/index.js
index 44c04deafa71ff..210824f52648b8 100644
--- a/packages/material-ui/src/Popover/index.js
+++ b/packages/material-ui/src/Popover/index.js
@@ -1 +1,4 @@
export { default } from './Popover';
+
+export { default as popoverClasses } from './popoverClasses';
+export * from './popoverClasses';
diff --git a/packages/material-ui/src/Popover/popoverClasses.d.ts b/packages/material-ui/src/Popover/popoverClasses.d.ts
new file mode 100644
index 00000000000000..dba3bff5ed8ab9
--- /dev/null
+++ b/packages/material-ui/src/Popover/popoverClasses.d.ts
@@ -0,0 +1,7 @@
+import { PopoverClassKey } from './Popover';
+
+declare const popoverClasses: Record;
+
+export function getPopoverUtilityClass(slot: string): string;
+
+export default popoverClasses;
diff --git a/packages/material-ui/src/Popover/popoverClasses.js b/packages/material-ui/src/Popover/popoverClasses.js
new file mode 100644
index 00000000000000..c7d09eada0eff2
--- /dev/null
+++ b/packages/material-ui/src/Popover/popoverClasses.js
@@ -0,0 +1,9 @@
+import { generateUtilityClass, generateUtilityClasses } from '@material-ui/unstyled';
+
+export function getPopoverUtilityClass(slot) {
+ return generateUtilityClass('MuiPopover', slot);
+}
+
+const popoverClasses = generateUtilityClasses('MuiPopover', ['root', 'paper']);
+
+export default popoverClasses;