rsuite
Version:
A suite of react components
267 lines (265 loc) • 11.5 kB
JavaScript
'use client';
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
exports.__esModule = true;
exports.modalPropTypes = exports.default = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
var _react = _interopRequireWildcard(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _classnames = _interopRequireDefault(require("classnames"));
var _contains = _interopRequireDefault(require("dom-lib/contains"));
var _on = _interopRequireDefault(require("dom-lib/on"));
var _constants = require("../constants");
var _hooks = require("../hooks");
var _utils = require("../utils");
var _ModalManager = _interopRequireDefault(require("./ModalManager"));
var _Fade = _interopRequireDefault(require("../../Animation/Fade"));
var _utils2 = require("../../Animation/utils");
var _OverlayContext = _interopRequireDefault(require("./OverlayContext"));
var _excluded = ["as", "children", "transition", "dialogTransitionTimeout", "style", "className", "container", "animationProps", "containerClassName", "keyboard", "enforceFocus", "backdrop", "backdropTransitionTimeout", "backdropStyle", "backdropClassName", "open", "autoFocus", "onEsc", "onExit", "onExiting", "onExited", "onEnter", "onEntering", "onEntered", "onClose", "onOpen"],
_excluded2 = ["className"];
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
var manager;
function getManager() {
if (!manager) manager = new _ModalManager.default();
return manager;
}
var useModalManager = function useModalManager() {
var modalManager = getManager();
var modal = (0, _react.useRef)({
dialog: null,
backdrop: null
});
return {
get dialog() {
var _modal$current;
return (_modal$current = modal.current) === null || _modal$current === void 0 ? void 0 : _modal$current.dialog;
},
add: function add(containerElement, containerClassName) {
return modalManager.add(modal.current, containerElement, containerClassName);
},
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__*/_react.default.forwardRef(function (props, ref) {
var _props$as = props.as,
Component = _props$as === void 0 ? 'div' : _props$as,
children = props.children,
Transition = props.transition,
dialogTransitionTimeout = props.dialogTransitionTimeout,
style = props.style,
className = props.className,
container = props.container,
animationProps = props.animationProps,
containerClassName = props.containerClassName,
_props$keyboard = props.keyboard,
keyboard = _props$keyboard === void 0 ? true : _props$keyboard,
_props$enforceFocus = props.enforceFocus,
enforceFocus = _props$enforceFocus === void 0 ? true : _props$enforceFocus,
_props$backdrop = props.backdrop,
backdrop = _props$backdrop === void 0 ? true : _props$backdrop,
backdropTransitionTimeout = props.backdropTransitionTimeout,
backdropStyle = props.backdropStyle,
backdropClassName = props.backdropClassName,
open = props.open,
_props$autoFocus = props.autoFocus,
autoFocus = _props$autoFocus === void 0 ? true : _props$autoFocus,
onEsc = props.onEsc,
onExit = props.onExit,
onExiting = props.onExiting,
onExited = props.onExited,
onEnter = props.onEnter,
onEntering = props.onEntering,
onEntered = props.onEntered,
onClose = props.onClose,
onOpen = props.onOpen,
rest = (0, _objectWithoutPropertiesLoose2.default)(props, _excluded);
var _useState = (0, _react.useState)(!open),
exited = _useState[0],
setExited = _useState[1];
var _usePortal = (0, _hooks.usePortal)({
container: container
}),
Portal = _usePortal.Portal,
containerElement = _usePortal.target;
var modal = useModalManager();
if (open) {
if (exited) setExited(false);
} else if (!Transition && !exited) {
setExited(true);
}
var mountModal = open || Transition && !exited;
var lastFocus = (0, _react.useRef)(null);
var handleDocumentKeyDown = (0, _hooks.useEventCallback)(function (event) {
if (keyboard && event.key === _constants.KEY_VALUES.ESC && modal.isTopModal()) {
onEsc === null || onEsc === void 0 || onEsc(event);
onClose === null || onClose === void 0 || onClose(event);
}
});
var restoreLastFocus = (0, _react.useCallback)(function () {
if (lastFocus.current) {
var _lastFocus$current$fo, _lastFocus$current;
(_lastFocus$current$fo = (_lastFocus$current = lastFocus.current).focus) === null || _lastFocus$current$fo === void 0 || _lastFocus$current$fo.call(_lastFocus$current);
lastFocus.current = null;
}
}, []);
/**
* Determines if the currently focused element is inside the dialog,
* and if not, returns the focus to the dialog.
*
*/
var handleFocusDialog = (0, _hooks.useEventCallback)(function (onBeforeFocusCallback) {
var currentActiveElement = document.activeElement;
var dialog = modal.dialog;
if (dialog && currentActiveElement && !(0, _contains.default)(dialog, currentActiveElement)) {
onBeforeFocusCallback === null || onBeforeFocusCallback === void 0 || onBeforeFocusCallback();
dialog.focus();
}
});
var handleEnforceFocus = (0, _hooks.useEventCallback)(function () {
if (!enforceFocus || !modal.isTopModal()) {
return;
}
handleFocusDialog();
});
var documentKeyDownListener = (0, _react.useRef)();
var documentFocusListener = (0, _react.useRef)();
var handleOpen = (0, _hooks.useEventCallback)(function () {
if (containerElement) {
modal.add(containerElement, containerClassName);
}
if (!documentKeyDownListener.current) {
documentKeyDownListener.current = (0, _on.default)(document, 'keydown', handleDocumentKeyDown);
}
if (!documentFocusListener.current) {
documentFocusListener.current = (0, _on.default)(document, 'focus', handleEnforceFocus, true);
}
if (autoFocus) {
handleFocusDialog(function () {
lastFocus.current = document.activeElement;
});
}
onOpen === null || onOpen === void 0 || onOpen();
});
var handleClose = (0, _hooks.useEventCallback)(function () {
var _documentKeyDownListe, _documentFocusListene;
modal.remove();
(_documentKeyDownListe = documentKeyDownListener.current) === null || _documentKeyDownListe === void 0 || _documentKeyDownListe.off();
documentKeyDownListener.current = null;
(_documentFocusListene = documentFocusListener.current) === null || _documentFocusListene === void 0 || _documentFocusListene.off();
documentFocusListener.current = null;
restoreLastFocus();
});
(0, _react.useEffect)(function () {
if (!open) {
return;
}
handleOpen();
}, [open, handleOpen]);
(0, _react.useEffect)(function () {
if (!exited) {
return;
}
handleClose();
}, [exited, handleClose]);
(0, _hooks.useWillUnmount)(function () {
handleClose();
});
var handleExited = (0, _react.useCallback)(function () {
setExited(true);
}, []);
var contextValue = (0, _react.useMemo)(function () {
return {
overlayContainer: function overlayContainer() {
return modal.dialog;
}
};
}, [modal.dialog]);
if (!mountModal) {
return null;
}
var renderBackdrop = function renderBackdrop() {
if (Transition) {
return /*#__PURE__*/_react.default.createElement(_Fade.default, {
transitionAppear: true,
in: open,
timeout: backdropTransitionTimeout
}, function (fadeProps, ref) {
var className = fadeProps.className,
rest = (0, _objectWithoutPropertiesLoose2.default)(fadeProps, _excluded2);
return /*#__PURE__*/_react.default.createElement("div", (0, _extends2.default)({
"aria-hidden": true,
"data-testid": "backdrop"
}, rest, {
style: backdropStyle,
ref: (0, _utils.mergeRefs)(modal.setBackdropRef, ref),
className: (0, _classnames.default)(backdropClassName, className)
}));
});
}
return /*#__PURE__*/_react.default.createElement("div", {
"aria-hidden": true,
style: backdropStyle,
className: backdropClassName
});
};
var dialogElement = Transition ? /*#__PURE__*/_react.default.createElement(Transition, (0, _extends2.default)({}, animationProps, {
transitionAppear: true,
unmountOnExit: true,
in: open,
timeout: dialogTransitionTimeout,
onExit: onExit,
onExiting: onExiting,
onExited: (0, _utils.createChainedFunction)(handleExited, onExited),
onEnter: onEnter,
onEntering: onEntering,
onEntered: onEntered
}), children) : children;
return /*#__PURE__*/_react.default.createElement(_OverlayContext.default.Provider, {
value: contextValue
}, /*#__PURE__*/_react.default.createElement(Portal, null, backdrop && renderBackdrop(), /*#__PURE__*/_react.default.createElement(Component, (0, _extends2.default)({}, rest, {
ref: (0, _utils.mergeRefs)(modal.setDialogRef, ref),
style: style,
className: className,
tabIndex: -1
}), dialogElement)));
});
var modalPropTypes = exports.modalPropTypes = {
as: _propTypes.default.elementType,
className: _propTypes.default.string,
backdropClassName: _propTypes.default.string,
style: _propTypes.default.object,
backdropStyle: _propTypes.default.object,
open: _propTypes.default.bool,
backdrop: _propTypes.default.oneOfType([_propTypes.default.bool, _propTypes.default.string]),
keyboard: _propTypes.default.bool,
autoFocus: _propTypes.default.bool,
enforceFocus: _propTypes.default.bool,
animationProps: _propTypes.default.object,
onOpen: _propTypes.default.func,
onClose: _propTypes.default.func
};
Modal.displayName = 'OverlayModal';
Modal.propTypes = (0, _extends2.default)({}, _utils2.animationPropTypes, modalPropTypes, {
children: _propTypes.default.func,
container: _propTypes.default.any,
containerClassName: _propTypes.default.string,
dialogTransitionTimeout: _propTypes.default.number,
backdropTransitionTimeout: _propTypes.default.number,
transition: _propTypes.default.any,
onEsc: _propTypes.default.func
});
var _default = exports.default = Modal;