UNPKG

@material-ui/core

Version:

React components that implement Google's Material Design.

317 lines (255 loc) 10 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties")); var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized")); var _react = _interopRequireDefault(require("react")); var _reactDom = _interopRequireDefault(require("react-dom")); var _propTypes = _interopRequireDefault(require("prop-types")); var _popper = _interopRequireDefault(require("popper.js")); var _withTheme = _interopRequireDefault(require("../styles/withTheme")); var _Portal = _interopRequireDefault(require("../Portal")); function flipPlacement(theme, placement) { if (theme.direction !== 'rtl') { return placement; } switch (placement) { case 'bottom-end': return 'bottom-start'; case 'bottom-start': return 'bottom-end'; case 'top-end': return 'top-start'; case 'top-start': return 'top-end'; default: return placement; } } function getAnchorEl(anchorEl) { return typeof anchorEl === 'function' ? anchorEl() : anchorEl; } /** * Poppers rely on the 3rd party library [Popper.js](https://github.com/FezVrasta/popper.js) for positioning. */ var Popper = /*#__PURE__*/ function (_React$Component) { (0, _inherits2.default)(Popper, _React$Component); function Popper(props) { var _this; (0, _classCallCheck2.default)(this, Popper); _this = (0, _possibleConstructorReturn2.default)(this, (0, _getPrototypeOf2.default)(Popper).call(this)); _this.handleOpen = function () { var _this$props = _this.props, anchorEl = _this$props.anchorEl, modifiers = _this$props.modifiers, open = _this$props.open, placement = _this$props.placement, _this$props$popperOpt = _this$props.popperOptions, popperOptions = _this$props$popperOpt === void 0 ? {} : _this$props$popperOpt, theme = _this$props.theme, disablePortal = _this$props.disablePortal; var popperNode = _reactDom.default.findDOMNode((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this))); if (!popperNode || !anchorEl || !open) { return; } if (_this.popper) { _this.popper.destroy(); _this.popper = null; } _this.popper = new _popper.default(getAnchorEl(anchorEl), popperNode, (0, _extends2.default)({ placement: flipPlacement(theme, placement) }, popperOptions, { modifiers: (0, _extends2.default)({}, disablePortal ? {} : { // It's using scrollParent by default, we can use the viewport when using a portal. preventOverflow: { boundariesElement: 'window' } }, modifiers, popperOptions.modifiers), // We could have been using a custom modifier like react-popper is doing. // But it seems this is the best public API for this use case. onCreate: _this.handlePopperUpdate, onUpdate: _this.handlePopperUpdate })); }; _this.handlePopperUpdate = function (data) { if (data.placement !== _this.state.placement) { _this.setState({ placement: data.placement }); } }; _this.handleExited = function () { _this.setState({ exited: true }); _this.handleClose(); }; _this.handleClose = function () { if (!_this.popper) { return; } _this.popper.destroy(); _this.popper = null; }; _this.state = { exited: !props.open }; return _this; } (0, _createClass2.default)(Popper, [{ key: "componentDidUpdate", value: function componentDidUpdate(prevProps) { if (prevProps.open !== this.props.open && !this.props.open && !this.props.transition) { // Otherwise handleExited will call this. this.handleClose(); } // Let's update the popper position. if (prevProps.open !== this.props.open || prevProps.anchorEl !== this.props.anchorEl || prevProps.popperOptions !== this.props.popperOptions || prevProps.modifiers !== this.props.modifiers || prevProps.disablePortal !== this.props.disablePortal || prevProps.placement !== this.props.placement) { this.handleOpen(); } } }, { key: "componentWillUnmount", value: function componentWillUnmount() { this.handleClose(); } }, { key: "render", value: function render() { var _this$props2 = this.props, anchorEl = _this$props2.anchorEl, children = _this$props2.children, container = _this$props2.container, disablePortal = _this$props2.disablePortal, keepMounted = _this$props2.keepMounted, modifiers = _this$props2.modifiers, open = _this$props2.open, placementProps = _this$props2.placement, popperOptions = _this$props2.popperOptions, theme = _this$props2.theme, transition = _this$props2.transition, other = (0, _objectWithoutProperties2.default)(_this$props2, ["anchorEl", "children", "container", "disablePortal", "keepMounted", "modifiers", "open", "placement", "popperOptions", "theme", "transition"]); var _this$state = this.state, exited = _this$state.exited, placement = _this$state.placement; if (!keepMounted && !open && (!transition || exited)) { return null; } var childProps = { placement: placement || flipPlacement(theme, placementProps) }; if (transition) { childProps.TransitionProps = { in: open, onExited: this.handleExited }; } return _react.default.createElement(_Portal.default, { onRendered: this.handleOpen, disablePortal: disablePortal, container: container }, _react.default.createElement("div", (0, _extends2.default)({ role: "tooltip", style: { // Prevents scroll issue, waiting for Popper.js to add this style once initiated. position: 'absolute' } }, other), typeof children === 'function' ? children(childProps) : children)); } }], [{ key: "getDerivedStateFromProps", value: function getDerivedStateFromProps(nextProps) { if (nextProps.open) { return { exited: false }; } if (!nextProps.transition) { // Otherwise let handleExited take care of marking exited. return { exited: true }; } return null; } }]); return Popper; }(_react.default.Component); Popper.propTypes = process.env.NODE_ENV !== "production" ? { /** * This is the DOM element, or a function that returns the DOM element, * that may be used to set the position of the popover. * The return value will passed as the reference object of the Popper * instance. */ anchorEl: _propTypes.default.oneOfType([_propTypes.default.object, _propTypes.default.func]), /** * Popper render function or node. */ children: _propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.func]).isRequired, /** * A node, component instance, or function that returns either. * The `container` will passed to the Modal component. * By default, it uses the body of the anchorEl's top-level document object, * so it's simply `document.body` most of the time. */ container: _propTypes.default.oneOfType([_propTypes.default.object, _propTypes.default.func]), /** * Disable the portal behavior. * The children stay within it's parent DOM hierarchy. */ disablePortal: _propTypes.default.bool, /** * Always keep the children in the DOM. * This property can be useful in SEO situation or * when you want to maximize the responsiveness of the Popper. */ keepMounted: _propTypes.default.bool, /** * Popper.js is based on a "plugin-like" architecture, * most of its features are fully encapsulated "modifiers". * * A modifier is a function that is called each time Popper.js needs to * compute the position of the popper. * For this reason, modifiers should be very performant to avoid bottlenecks. * To learn how to create a modifier, [read the modifiers documentation](https://github.com/FezVrasta/popper.js/blob/master/docs/_includes/popper-documentation.md#modifiers--object). */ modifiers: _propTypes.default.object, /** * If `true`, the popper is visible. */ open: _propTypes.default.bool.isRequired, /** * Popper placement. */ placement: _propTypes.default.oneOf(['bottom-end', 'bottom-start', 'bottom', 'left-end', 'left-start', 'left', 'right-end', 'right-start', 'right', 'top-end', 'top-start', 'top']), /** * Options provided to the [`popper.js`](https://github.com/FezVrasta/popper.js) instance. */ popperOptions: _propTypes.default.object, /** * @ignore */ theme: _propTypes.default.object.isRequired, /** * Help supporting a react-transition-group/Transition component. */ transition: _propTypes.default.bool } : {}; Popper.defaultProps = { disablePortal: false, placement: 'bottom', transition: false }; var _default = (0, _withTheme.default)()(Popper); exports.default = _default;