123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509 |
- "use strict";
-
- exports.__esModule = true;
- exports.default = void 0;
-
- var _activeElement = _interopRequireDefault(require("dom-helpers/activeElement"));
-
- var _contains = _interopRequireDefault(require("dom-helpers/query/contains"));
-
- var _inDOM = _interopRequireDefault(require("dom-helpers/util/inDOM"));
-
- var _listen = _interopRequireDefault(require("dom-helpers/events/listen"));
-
- var _propTypes = _interopRequireDefault(require("prop-types"));
-
- var _componentOrElement = _interopRequireDefault(require("prop-types-extra/lib/componentOrElement"));
-
- var _elementType = _interopRequireDefault(require("prop-types-extra/lib/elementType"));
-
- var _react = _interopRequireDefault(require("react"));
-
- var _reactDom = _interopRequireDefault(require("react-dom"));
-
- var _ModalManager = _interopRequireDefault(require("./ModalManager"));
-
- var _Portal = _interopRequireDefault(require("./Portal"));
-
- var _getContainer = _interopRequireDefault(require("./utils/getContainer"));
-
- var _ownerDocument = _interopRequireDefault(require("./utils/ownerDocument"));
-
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
- function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
-
- function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
-
- function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
-
- function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
-
- var modalManager = new _ModalManager.default();
-
- function omitProps(props, propTypes) {
- var keys = Object.keys(props);
- var newProps = {};
- keys.map(function (prop) {
- if (!Object.prototype.hasOwnProperty.call(propTypes, prop)) {
- newProps[prop] = props[prop];
- }
- });
- return newProps;
- }
- /**
- * Love them or hate them, `<Modal />` provides a solid foundation for creating dialogs, lightboxes, or whatever else.
- * The Modal component renders its `children` node in front of a backdrop component.
- *
- * The Modal offers a few helpful features over using just a `<Portal/>` component and some styles:
- *
- * - Manages dialog stacking when one-at-a-time just isn't enough.
- * - Creates a backdrop, for disabling interaction below the modal.
- * - It properly manages focus; moving to the modal content, and keeping it there until the modal is closed.
- * - It disables scrolling of the page content while open.
- * - Adds the appropriate ARIA roles are automatically.
- * - Easily pluggable animations via a `<Transition/>` component.
- *
- * Note that, in the same way the backdrop element prevents users from clicking or interacting
- * with the page content underneath the Modal, Screen readers also need to be signaled to not to
- * interact with page content while the Modal is open. To do this, we use a common technique of applying
- * the `aria-hidden='true'` attribute to the non-Modal elements in the Modal `container`. This means that for
- * a Modal to be truly modal, it should have a `container` that is _outside_ your app's
- * React hierarchy (such as the default: document.body).
- */
-
-
- var Modal =
- /*#__PURE__*/
- function (_React$Component) {
- _inheritsLoose(Modal, _React$Component);
-
- function Modal() {
- var _this;
-
- for (var _len = arguments.length, _args = new Array(_len), _key = 0; _key < _len; _key++) {
- _args[_key] = arguments[_key];
- }
-
- _this = _React$Component.call.apply(_React$Component, [this].concat(_args)) || this;
- _this.state = {
- exited: !_this.props.show
- };
-
- _this.onPortalRendered = function () {
- if (_this.props.onShow) {
- _this.props.onShow();
- } // autofocus after onShow, to not trigger a focus event for previous
- // modals before this one is shown.
-
-
- _this.autoFocus();
- };
-
- _this.onShow = function () {
- var doc = (0, _ownerDocument.default)(_assertThisInitialized(_assertThisInitialized(_this)));
- var container = (0, _getContainer.default)(_this.props.container, doc.body);
-
- _this.props.manager.add(_assertThisInitialized(_assertThisInitialized(_this)), container, _this.props.containerClassName);
-
- _this.removeKeydownListener = (0, _listen.default)(doc, 'keydown', _this.handleDocumentKeyDown);
- _this.removeFocusListener = (0, _listen.default)(doc, 'focus', // the timeout is necessary b/c this will run before the new modal is mounted
- // and so steals focus from it
- function () {
- return setTimeout(_this.enforceFocus);
- }, true);
- };
-
- _this.onHide = function () {
- _this.props.manager.remove(_assertThisInitialized(_assertThisInitialized(_this)));
-
- _this.removeKeydownListener();
-
- _this.removeFocusListener();
-
- if (_this.props.restoreFocus) {
- _this.restoreLastFocus();
- }
- };
-
- _this.setDialogRef = function (ref) {
- _this.dialog = ref;
- };
-
- _this.setBackdropRef = function (ref) {
- _this.backdrop = ref && _reactDom.default.findDOMNode(ref);
- };
-
- _this.handleHidden = function () {
- _this.setState({
- exited: true
- });
-
- _this.onHide();
-
- if (_this.props.onExited) {
- var _this$props;
-
- (_this$props = _this.props).onExited.apply(_this$props, arguments);
- }
- };
-
- _this.handleBackdropClick = function (e) {
- if (e.target !== e.currentTarget) {
- return;
- }
-
- if (_this.props.onBackdropClick) {
- _this.props.onBackdropClick(e);
- }
-
- if (_this.props.backdrop === true) {
- _this.props.onHide();
- }
- };
-
- _this.handleDocumentKeyDown = function (e) {
- if (_this.props.keyboard && e.keyCode === 27 && _this.isTopModal()) {
- if (_this.props.onEscapeKeyDown) {
- _this.props.onEscapeKeyDown(e);
- }
-
- _this.props.onHide();
- }
- };
-
- _this.enforceFocus = function () {
- if (!_this.props.enforceFocus || !_this._isMounted || !_this.isTopModal()) {
- return;
- }
-
- var currentActiveElement = (0, _activeElement.default)((0, _ownerDocument.default)(_assertThisInitialized(_assertThisInitialized(_this))));
-
- if (_this.dialog && !(0, _contains.default)(_this.dialog, currentActiveElement)) {
- _this.dialog.focus();
- }
- };
-
- _this.renderBackdrop = function () {
- var _this$props2 = _this.props,
- renderBackdrop = _this$props2.renderBackdrop,
- Transition = _this$props2.backdropTransition;
- var backdrop = renderBackdrop({
- ref: _this.setBackdropRef,
- onClick: _this.handleBackdropClick
- });
-
- if (Transition) {
- backdrop = _react.default.createElement(Transition, {
- appear: true,
- in: _this.props.show
- }, backdrop);
- }
-
- return backdrop;
- };
-
- return _this;
- }
-
- Modal.getDerivedStateFromProps = function getDerivedStateFromProps(nextProps) {
- if (nextProps.show) {
- return {
- exited: false
- };
- } else if (!nextProps.transition) {
- // Otherwise let handleHidden take care of marking exited.
- return {
- exited: true
- };
- }
-
- return null;
- };
-
- var _proto = Modal.prototype;
-
- _proto.getSnapshotBeforeUpdate = function getSnapshotBeforeUpdate(prevProps) {
- if (_inDOM.default && !prevProps.show && this.props.show) {
- this.lastFocus = (0, _activeElement.default)();
- }
-
- return null;
- };
-
- _proto.componentDidMount = function componentDidMount() {
- this._isMounted = true;
-
- if (this.props.show) {
- this.onShow();
- }
- };
-
- _proto.componentDidUpdate = function componentDidUpdate(prevProps) {
- var transition = this.props.transition;
-
- if (prevProps.show && !this.props.show && !transition) {
- // Otherwise handleHidden will call this.
- this.onHide();
- } else if (!prevProps.show && this.props.show) {
- this.onShow();
- }
- };
-
- _proto.componentWillUnmount = function componentWillUnmount() {
- var _this$props3 = this.props,
- show = _this$props3.show,
- transition = _this$props3.transition;
- this._isMounted = false;
-
- if (show || transition && !this.state.exited) {
- this.onHide();
- }
- };
-
- _proto.autoFocus = function autoFocus() {
- if (!this.props.autoFocus) return;
- var currentActiveElement = (0, _activeElement.default)((0, _ownerDocument.default)(this));
-
- if (this.dialog && !(0, _contains.default)(this.dialog, currentActiveElement)) {
- this.lastFocus = currentActiveElement;
- this.dialog.focus();
- }
- };
-
- _proto.restoreLastFocus = function restoreLastFocus() {
- // Support: <=IE11 doesn't support `focus()` on svg elements (RB: #917)
- if (this.lastFocus && this.lastFocus.focus) {
- this.lastFocus.focus();
- this.lastFocus = null;
- }
- };
-
- _proto.isTopModal = function isTopModal() {
- return this.props.manager.isTopModal(this);
- };
-
- _proto.render = function render() {
- var _this$props4 = this.props,
- show = _this$props4.show,
- container = _this$props4.container,
- children = _this$props4.children,
- renderDialog = _this$props4.renderDialog,
- _this$props4$role = _this$props4.role,
- role = _this$props4$role === void 0 ? 'dialog' : _this$props4$role,
- Transition = _this$props4.transition,
- backdrop = _this$props4.backdrop,
- className = _this$props4.className,
- style = _this$props4.style,
- onExit = _this$props4.onExit,
- onExiting = _this$props4.onExiting,
- onEnter = _this$props4.onEnter,
- onEntering = _this$props4.onEntering,
- onEntered = _this$props4.onEntered,
- props = _objectWithoutPropertiesLoose(_this$props4, ["show", "container", "children", "renderDialog", "role", "transition", "backdrop", "className", "style", "onExit", "onExiting", "onEnter", "onEntering", "onEntered"]);
-
- if (!(show || Transition && !this.state.exited)) {
- return null;
- }
-
- var dialogProps = _extends({
- role: role,
- ref: this.setDialogRef,
- // apparently only works on the dialog role element
- 'aria-modal': role === 'dialog' ? true : undefined
- }, omitProps(props, Modal.propTypes), {
- style: style,
- className: className,
- tabIndex: '-1'
- });
-
- var dialog = renderDialog ? renderDialog(dialogProps) : _react.default.createElement("div", dialogProps, _react.default.cloneElement(children, {
- role: 'document'
- }));
-
- if (Transition) {
- dialog = _react.default.createElement(Transition, {
- appear: true,
- unmountOnExit: true,
- in: show,
- onExit: onExit,
- onExiting: onExiting,
- onExited: this.handleHidden,
- onEnter: onEnter,
- onEntering: onEntering,
- onEntered: onEntered
- }, dialog);
- }
-
- return _react.default.createElement(_Portal.default, {
- container: container,
- onRendered: this.onPortalRendered
- }, _react.default.createElement(_react.default.Fragment, null, backdrop && this.renderBackdrop(), dialog));
- };
-
- return Modal;
- }(_react.default.Component);
-
- Modal.propTypes = {
- /**
- * Set the visibility of the Modal
- */
- show: _propTypes.default.bool,
-
- /**
- * A Node, Component instance, or function that returns either. The Modal is appended to it's container element.
- *
- * For the sake of assistive technologies, the container should usually be the document body, so that the rest of the
- * page content can be placed behind a virtual backdrop as well as a visual one.
- */
- container: _propTypes.default.oneOfType([_componentOrElement.default, _propTypes.default.func]),
-
- /**
- * A callback fired when the Modal is opening.
- */
- onShow: _propTypes.default.func,
-
- /**
- * A callback fired when either the backdrop is clicked, or the escape key is pressed.
- *
- * The `onHide` callback only signals intent from the Modal,
- * you must actually set the `show` prop to `false` for the Modal to close.
- */
- onHide: _propTypes.default.func,
-
- /**
- * Include a backdrop component.
- */
- backdrop: _propTypes.default.oneOfType([_propTypes.default.bool, _propTypes.default.oneOf(['static'])]),
-
- /**
- * A function that returns the dialog component. Useful for custom
- * rendering. **Note:** the component should make sure to apply the provided ref.
- *
- * ```js
- * renderDialog={props => <MyDialog {...props} />}
- * ```
- */
- renderDialog: _propTypes.default.func,
-
- /**
- * A function that returns a backdrop component. Useful for custom
- * backdrop rendering.
- *
- * ```js
- * renderBackdrop={props => <MyBackdrop {...props} />}
- * ```
- */
- renderBackdrop: _propTypes.default.func,
-
- /**
- * A callback fired when the escape key, if specified in `keyboard`, is pressed.
- */
- onEscapeKeyDown: _propTypes.default.func,
-
- /**
- * A callback fired when the backdrop, if specified, is clicked.
- */
- onBackdropClick: _propTypes.default.func,
-
- /**
- * A css class or set of classes applied to the modal container when the modal is open,
- * and removed when it is closed.
- */
- containerClassName: _propTypes.default.string,
-
- /**
- * Close the modal when escape key is pressed
- */
- keyboard: _propTypes.default.bool,
-
- /**
- * A `react-transition-group@2.0.0` `<Transition/>` component used
- * to control animations for the dialog component.
- */
- transition: _elementType.default,
-
- /**
- * A `react-transition-group@2.0.0` `<Transition/>` component used
- * to control animations for the backdrop components.
- */
- backdropTransition: _elementType.default,
-
- /**
- * When `true` The modal will automatically shift focus to itself when it opens, and
- * replace it to the last focused element when it closes. This also
- * works correctly with any Modal children that have the `autoFocus` prop.
- *
- * Generally this should never be set to `false` as it makes the Modal less
- * accessible to assistive technologies, like screen readers.
- */
- autoFocus: _propTypes.default.bool,
-
- /**
- * When `true` The modal will prevent focus from leaving the Modal while open.
- *
- * Generally this should never be set to `false` as it makes the Modal less
- * accessible to assistive technologies, like screen readers.
- */
- enforceFocus: _propTypes.default.bool,
-
- /**
- * When `true` The modal will restore focus to previously focused element once
- * modal is hidden
- */
- restoreFocus: _propTypes.default.bool,
-
- /**
- * Callback fired before the Modal transitions in
- */
- onEnter: _propTypes.default.func,
-
- /**
- * Callback fired as the Modal begins to transition in
- */
- onEntering: _propTypes.default.func,
-
- /**
- * Callback fired after the Modal finishes transitioning in
- */
- onEntered: _propTypes.default.func,
-
- /**
- * Callback fired right before the Modal transitions out
- */
- onExit: _propTypes.default.func,
-
- /**
- * Callback fired as the Modal begins to transition out
- */
- onExiting: _propTypes.default.func,
-
- /**
- * Callback fired after the Modal finishes transitioning out
- */
- onExited: _propTypes.default.func,
-
- /**
- * A ModalManager instance used to track and manage the state of open
- * Modals. Useful when customizing how modals interact within a container
- */
- manager: _propTypes.default.object.isRequired
- };
- Modal.defaultProps = {
- show: false,
- role: 'dialog',
- backdrop: true,
- keyboard: true,
- autoFocus: true,
- enforceFocus: true,
- restoreFocus: true,
- onHide: function onHide() {},
- manager: modalManager,
- renderBackdrop: function renderBackdrop(props) {
- return _react.default.createElement("div", props);
- }
- };
- Modal.Manager = _ModalManager.default;
- var _default = Modal;
- exports.default = _default;
- module.exports = exports.default;
|