GoScrobble/web/node_modules/react-overlays/cjs/Modal.js

456 lines
15 KiB
JavaScript
Raw Normal View History

2022-04-25 02:47:15 +00:00
"use strict";
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
exports.__esModule = true;
exports["default"] = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
var _activeElement = _interopRequireDefault(require("dom-helpers/activeElement"));
var _contains = _interopRequireDefault(require("dom-helpers/contains"));
var _canUseDOM = _interopRequireDefault(require("dom-helpers/canUseDOM"));
var _listen = _interopRequireDefault(require("dom-helpers/listen"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _react = _interopRequireWildcard(require("react"));
var _reactDom = _interopRequireDefault(require("react-dom"));
var _useMounted = _interopRequireDefault(require("@restart/hooks/useMounted"));
var _useWillUnmount = _interopRequireDefault(require("@restart/hooks/useWillUnmount"));
var _usePrevious = _interopRequireDefault(require("@restart/hooks/usePrevious"));
var _useEventCallback = _interopRequireDefault(require("@restart/hooks/useEventCallback"));
var _ModalManager = _interopRequireDefault(require("./ModalManager"));
var _useWaitForDOMRef = _interopRequireDefault(require("./useWaitForDOMRef"));
/* eslint-disable @typescript-eslint/no-use-before-define, react/prop-types */
var manager;
function getManager() {
if (!manager) manager = new _ModalManager["default"]();
return manager;
}
function useModalManager(provided) {
var modalManager = provided || getManager();
var modal = (0, _react.useRef)({
dialog: null,
backdrop: null
});
return Object.assign(modal.current, {
add: function add(container, className) {
return modalManager.add(modal.current, container, className);
},
remove: function remove() {
return modalManager.remove(modal.current);
},
isTopModal: function isTopModal() {
return modalManager.isTopModal(modal.current);
},
setDialogRef: (0, _react.useCallback)(function (ref) {
modal.current.dialog = ref;
}, []),
setBackdropRef: (0, _react.useCallback)(function (ref) {
modal.current.backdrop = ref;
}, [])
});
}
var Modal = /*#__PURE__*/(0, _react.forwardRef)(function (_ref, ref) {
var _ref$show = _ref.show,
show = _ref$show === void 0 ? false : _ref$show,
_ref$role = _ref.role,
role = _ref$role === void 0 ? 'dialog' : _ref$role,
className = _ref.className,
style = _ref.style,
children = _ref.children,
_ref$backdrop = _ref.backdrop,
backdrop = _ref$backdrop === void 0 ? true : _ref$backdrop,
_ref$keyboard = _ref.keyboard,
keyboard = _ref$keyboard === void 0 ? true : _ref$keyboard,
onBackdropClick = _ref.onBackdropClick,
onEscapeKeyDown = _ref.onEscapeKeyDown,
transition = _ref.transition,
backdropTransition = _ref.backdropTransition,
_ref$autoFocus = _ref.autoFocus,
autoFocus = _ref$autoFocus === void 0 ? true : _ref$autoFocus,
_ref$enforceFocus = _ref.enforceFocus,
enforceFocus = _ref$enforceFocus === void 0 ? true : _ref$enforceFocus,
_ref$restoreFocus = _ref.restoreFocus,
restoreFocus = _ref$restoreFocus === void 0 ? true : _ref$restoreFocus,
restoreFocusOptions = _ref.restoreFocusOptions,
renderDialog = _ref.renderDialog,
_ref$renderBackdrop = _ref.renderBackdrop,
renderBackdrop = _ref$renderBackdrop === void 0 ? function (props) {
return /*#__PURE__*/_react["default"].createElement("div", props);
} : _ref$renderBackdrop,
providedManager = _ref.manager,
containerRef = _ref.container,
containerClassName = _ref.containerClassName,
onShow = _ref.onShow,
_ref$onHide = _ref.onHide,
onHide = _ref$onHide === void 0 ? function () {} : _ref$onHide,
onExit = _ref.onExit,
onExited = _ref.onExited,
onExiting = _ref.onExiting,
onEnter = _ref.onEnter,
onEntering = _ref.onEntering,
onEntered = _ref.onEntered,
rest = (0, _objectWithoutPropertiesLoose2["default"])(_ref, ["show", "role", "className", "style", "children", "backdrop", "keyboard", "onBackdropClick", "onEscapeKeyDown", "transition", "backdropTransition", "autoFocus", "enforceFocus", "restoreFocus", "restoreFocusOptions", "renderDialog", "renderBackdrop", "manager", "container", "containerClassName", "onShow", "onHide", "onExit", "onExited", "onExiting", "onEnter", "onEntering", "onEntered"]);
var container = (0, _useWaitForDOMRef["default"])(containerRef);
var modal = useModalManager(providedManager);
var isMounted = (0, _useMounted["default"])();
var prevShow = (0, _usePrevious["default"])(show);
var _useState = (0, _react.useState)(!show),
exited = _useState[0],
setExited = _useState[1];
var lastFocusRef = (0, _react.useRef)(null);
(0, _react.useImperativeHandle)(ref, function () {
return modal;
}, [modal]);
if (_canUseDOM["default"] && !prevShow && show) {
lastFocusRef.current = (0, _activeElement["default"])();
}
if (!transition && !show && !exited) {
setExited(true);
} else if (show && exited) {
setExited(false);
}
var handleShow = (0, _useEventCallback["default"])(function () {
modal.add(container, containerClassName);
removeKeydownListenerRef.current = (0, _listen["default"])(document, 'keydown', handleDocumentKeyDown);
removeFocusListenerRef.current = (0, _listen["default"])(document, '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(handleEnforceFocus);
}, true);
if (onShow) {
onShow();
} // autofocus after onShow to not trigger a focus event for previous
// modals before this one is shown.
if (autoFocus) {
var currentActiveElement = (0, _activeElement["default"])(document);
if (modal.dialog && currentActiveElement && !(0, _contains["default"])(modal.dialog, currentActiveElement)) {
lastFocusRef.current = currentActiveElement;
modal.dialog.focus();
}
}
});
var handleHide = (0, _useEventCallback["default"])(function () {
modal.remove();
removeKeydownListenerRef.current == null ? void 0 : removeKeydownListenerRef.current();
removeFocusListenerRef.current == null ? void 0 : removeFocusListenerRef.current();
if (restoreFocus) {
var _lastFocusRef$current;
// Support: <=IE11 doesn't support `focus()` on svg elements (RB: #917)
(_lastFocusRef$current = lastFocusRef.current) == null ? void 0 : _lastFocusRef$current.focus == null ? void 0 : _lastFocusRef$current.focus(restoreFocusOptions);
lastFocusRef.current = null;
}
}); // TODO: try and combine these effects: https://github.com/react-bootstrap/react-overlays/pull/794#discussion_r409954120
// Show logic when:
// - show is `true` _and_ `container` has resolved
(0, _react.useEffect)(function () {
if (!show || !container) return;
handleShow();
}, [show, container,
/* should never change: */
handleShow]); // Hide cleanup logic when:
// - `exited` switches to true
// - component unmounts;
(0, _react.useEffect)(function () {
if (!exited) return;
handleHide();
}, [exited, handleHide]);
(0, _useWillUnmount["default"])(function () {
handleHide();
}); // --------------------------------
var handleEnforceFocus = (0, _useEventCallback["default"])(function () {
if (!enforceFocus || !isMounted() || !modal.isTopModal()) {
return;
}
var currentActiveElement = (0, _activeElement["default"])();
if (modal.dialog && currentActiveElement && !(0, _contains["default"])(modal.dialog, currentActiveElement)) {
modal.dialog.focus();
}
});
var handleBackdropClick = (0, _useEventCallback["default"])(function (e) {
if (e.target !== e.currentTarget) {
return;
}
onBackdropClick == null ? void 0 : onBackdropClick(e);
if (backdrop === true) {
onHide();
}
});
var handleDocumentKeyDown = (0, _useEventCallback["default"])(function (e) {
if (keyboard && e.keyCode === 27 && modal.isTopModal()) {
onEscapeKeyDown == null ? void 0 : onEscapeKeyDown(e);
if (!e.defaultPrevented) {
onHide();
}
}
});
var removeFocusListenerRef = (0, _react.useRef)();
var removeKeydownListenerRef = (0, _react.useRef)();
var handleHidden = function handleHidden() {
setExited(true);
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
onExited == null ? void 0 : onExited.apply(void 0, args);
};
var Transition = transition;
if (!container || !(show || Transition && !exited)) {
return null;
}
var dialogProps = (0, _extends2["default"])({
role: role,
ref: modal.setDialogRef,
// apparently only works on the dialog role element
'aria-modal': role === 'dialog' ? true : undefined
}, rest, {
style: style,
className: className,
tabIndex: -1
});
var dialog = renderDialog ? renderDialog(dialogProps) : /*#__PURE__*/_react["default"].createElement("div", dialogProps, /*#__PURE__*/_react["default"].cloneElement(children, {
role: 'document'
}));
if (Transition) {
dialog = /*#__PURE__*/_react["default"].createElement(Transition, {
appear: true,
unmountOnExit: true,
"in": !!show,
onExit: onExit,
onExiting: onExiting,
onExited: handleHidden,
onEnter: onEnter,
onEntering: onEntering,
onEntered: onEntered
}, dialog);
}
var backdropElement = null;
if (backdrop) {
var BackdropTransition = backdropTransition;
backdropElement = renderBackdrop({
ref: modal.setBackdropRef,
onClick: handleBackdropClick
});
if (BackdropTransition) {
backdropElement = /*#__PURE__*/_react["default"].createElement(BackdropTransition, {
appear: true,
"in": !!show
}, backdropElement);
}
}
return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, /*#__PURE__*/_reactDom["default"].createPortal( /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, backdropElement, dialog), container));
});
var propTypes = {
/**
* Set the visibility of the Modal
*/
show: _propTypes["default"].bool,
/**
* A DOM element, a `ref` to an element, 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"].any,
/**
* 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 static
* 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.
*
* If preventDefault() is called on the keyboard event, closing the modal will be cancelled.
*/
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: _propTypes["default"].elementType,
/**
* A `react-transition-group@2.0.0` `<Transition/>` component used
* to control animations for the backdrop components.
*/
backdropTransition: _propTypes["default"].elementType,
/**
* 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,
/**
* Options passed to focus function when `restoreFocus` is set to `true`
*
* @link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus#Parameters
*/
restoreFocusOptions: _propTypes["default"].shape({
preventScroll: _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"].instanceOf(_ModalManager["default"])
};
Modal.displayName = 'Modal';
Modal.propTypes = propTypes;
var _default = Object.assign(Modal, {
Manager: _ModalManager["default"]
});
exports["default"] = _default;
module.exports = exports.default;