Skip to content

Commit

Permalink
[Popover] Migrate to emotion (#25197)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomasznguyen authored Mar 7, 2021
1 parent 59baefe commit fe2632d
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 49 deletions.
3 changes: 2 additions & 1 deletion docs/pages/api-docs/popover.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"type": { "name": "shape", "description": "{ component?: element type }" },
"default": "{}"
},
"sx": { "type": { "name": "object" } },
"transformOrigin": {
"type": {
"name": "shape",
Expand All @@ -55,6 +56,6 @@
"filename": "/packages/material-ui/src/Popover/Popover.js",
"inheritance": { "component": "Modal", "pathname": "/api/modal/" },
"demos": "<ul><li><a href=\"/components/menus/\">Menus</a></li>\n<li><a href=\"/components/popover/\">Popover</a></li></ul>",
"styledComponent": false,
"styledComponent": true,
"cssComponent": false
}
1 change: 1 addition & 0 deletions docs/translations/api-docs/popover/popover.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"onClose": "Callback fired when the component requests to be closed. The <code>reason</code> parameter can optionally be used to control the response to <code>onClose</code>.",
"open": "If <code>true</code>, the component is shown.",
"PaperProps": "Props applied to the <a href=\"/api/paper/\"><code>Paper</code></a> element.",
"sx": "The system prop that allows defining system overrides as well as additional CSS styles. See the <a href=\"/system/basics/#the-sx-prop\">`sx` page</a> for more details.",
"transformOrigin": "This is the point on the popover which will attach to the anchor&#39;s origin.<br>Options: vertical: [top, center, bottom, x(px)]; horizontal: [left, center, right, x(px)].",
"TransitionComponent": "The component used for the transition. <a href=\"/components/transitions/#transitioncomponent-prop\">Follow this guide</a> to learn more about the requirements for this component.",
"transitionDuration": "Set to &#39;auto&#39; to automatically calculate transition time based on height.",
Expand Down
6 changes: 6 additions & 0 deletions packages/material-ui/src/Popover/Popover.d.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -103,6 +105,10 @@ export interface PopoverProps
* @default {}
*/
PaperProps?: Partial<PaperProps>;
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx?: SxProps<Theme>;
/**
* This is the point on the popover which
* will attach to the anchor's origin.
Expand Down
113 changes: 83 additions & 30 deletions packages/material-ui/src/Popover/Popover.js
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -95,7 +129,6 @@ const Popover = React.forwardRef(function Popover(props, ref) {
anchorPosition,
anchorReference = 'anchorEl',
children,
classes,
className,
container: containerProp,
elevation = 8,
Expand All @@ -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(
Expand Down Expand Up @@ -379,31 +427,32 @@ const Popover = React.forwardRef(function Popover(props, ref) {
containerProp || (anchorEl ? ownerDocument(getAnchorEl(anchorEl)).body : undefined);

return (
<Modal
<PopoverRoot
BackdropProps={{ invisible: true }}
className={clsx(classes.root, className)}
container={container}
open={open}
ref={ref}
BackdropProps={{ invisible: true }}
className={clsx(classes.root, className)}
styleProps={styleProps}
{...other}
>
<TransitionComponent
appear
in={open}
timeout={transitionDuration}
onEntering={handleEntering}
timeout={transitionDuration}
{...TransitionProps}
>
<Paper
<PopoverPaper
elevation={elevation}
ref={paperRef}
{...PaperProps}
className={clsx(classes.paper, PaperProps.className)}
>
{children}
</Paper>
</PopoverPaper>
</TransitionComponent>
</Modal>
</PopoverRoot>
);
});

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -595,4 +648,4 @@ Popover.propTypes = {
TransitionProps: PropTypes.object,
};

export default withStyles(styles, { name: 'MuiPopover' })(Popover);
export default Popover;
41 changes: 23 additions & 18 deletions packages/material-ui/src/Popover/Popover.test.js
Original file line number Diff line number Diff line change
@@ -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 = () => {
Expand Down Expand Up @@ -49,27 +55,26 @@ const FakePaper = React.forwardRef(function FakeWidthPaper(props, ref) {
describe('<Popover />', () => {
// 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(
<Popover {...defaultProps}>
<div />
</Popover>,
);
});

describeConformance(<Popover {...defaultProps} open />, () => ({
describeConformanceV5(<Popover {...defaultProps} open />, () => ({
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',
],
Expand All @@ -83,7 +88,7 @@ describe('<Popover />', () => {
</Popover>,
);
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);
});

Expand Down Expand Up @@ -433,7 +438,7 @@ describe('<Popover />', () => {
it('should warn if anchorEl is not valid', () => {
expect(() => {
PropTypes.checkPropTypes(
Popover.Naked.propTypes,
Popover.propTypes,
{ classes: {}, open: true },
'prop',
'MockedPopover',
Expand All @@ -444,7 +449,7 @@ describe('<Popover />', () => {
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: () => <div />, elevation: 4 } },
'prop',
'MockedPopover',
Expand Down
3 changes: 3 additions & 0 deletions packages/material-ui/src/Popover/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
export { default } from './Popover';

export { default as popoverClasses } from './popoverClasses';
export * from './popoverClasses';
7 changes: 7 additions & 0 deletions packages/material-ui/src/Popover/popoverClasses.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { PopoverClassKey } from './Popover';

declare const popoverClasses: Record<PopoverClassKey, string>;

export function getPopoverUtilityClass(slot: string): string;

export default popoverClasses;
9 changes: 9 additions & 0 deletions packages/material-ui/src/Popover/popoverClasses.js
Original file line number Diff line number Diff line change
@@ -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;

0 comments on commit fe2632d

Please sign in to comment.