Page MenuHomec4science

Modal.js
No OneTemporary

File Metadata

Created
Wed, Feb 19, 01:12

Modal.js

const _excluded = ["show", "role", "className", "style", "children", "backdrop", "keyboard", "onBackdropClick", "onEscapeKeyDown", "transition", "backdropTransition", "autoFocus", "enforceFocus", "restoreFocus", "restoreFocusOptions", "renderDialog", "renderBackdrop", "manager", "container", "onShow", "onHide", "onExit", "onExited", "onExiting", "onEnter", "onEntering", "onEntered"];
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; }
/* eslint-disable @typescript-eslint/no-use-before-define, react/prop-types */
import activeElement from 'dom-helpers/activeElement';
import contains from 'dom-helpers/contains';
import canUseDOM from 'dom-helpers/canUseDOM';
import listen from 'dom-helpers/listen';
import { useState, useRef, useCallback, useImperativeHandle, forwardRef, useEffect } from 'react';
import * as React from 'react';
import ReactDOM from 'react-dom';
import useMounted from '@restart/hooks/useMounted';
import useWillUnmount from '@restart/hooks/useWillUnmount';
import usePrevious from '@restart/hooks/usePrevious';
import useEventCallback from '@restart/hooks/useEventCallback';
import ModalManager from './ModalManager';
import useWaitForDOMRef from './useWaitForDOMRef';
import useWindow from './useWindow';
import { jsx as _jsx } from "react/jsx-runtime";
import { Fragment as _Fragment } from "react/jsx-runtime";
import { jsxs as _jsxs } from "react/jsx-runtime";
let manager;
function getManager(window) {
if (!manager) manager = new ModalManager({
ownerDocument: window == null ? void 0 : window.document
});
return manager;
}
function useModalManager(provided) {
const window = useWindow();
const modalManager = provided || getManager(window);
const modal = useRef({
dialog: null,
backdrop: null
});
return Object.assign(modal.current, {
add: () => modalManager.add(modal.current),
remove: () => modalManager.remove(modal.current),
isTopModal: () => modalManager.isTopModal(modal.current),
setDialogRef: useCallback(ref => {
modal.current.dialog = ref;
}, []),
setBackdropRef: useCallback(ref => {
modal.current.backdrop = ref;
}, [])
});
}
const Modal = /*#__PURE__*/forwardRef((_ref, ref) => {
let {
show = false,
role = 'dialog',
className,
style,
children,
backdrop = true,
keyboard = true,
onBackdropClick,
onEscapeKeyDown,
transition,
backdropTransition,
autoFocus = true,
enforceFocus = true,
restoreFocus = true,
restoreFocusOptions,
renderDialog,
renderBackdrop = props => /*#__PURE__*/_jsx("div", Object.assign({}, props)),
manager: providedManager,
container: containerRef,
onShow,
onHide = () => {},
onExit,
onExited,
onExiting,
onEnter,
onEntering,
onEntered
} = _ref,
rest = _objectWithoutPropertiesLoose(_ref, _excluded);
const container = useWaitForDOMRef(containerRef);
const modal = useModalManager(providedManager);
const isMounted = useMounted();
const prevShow = usePrevious(show);
const [exited, setExited] = useState(!show);
const lastFocusRef = useRef(null);
useImperativeHandle(ref, () => modal, [modal]);
if (canUseDOM && !prevShow && show) {
lastFocusRef.current = activeElement();
}
if (!transition && !show && !exited) {
setExited(true);
} else if (show && exited) {
setExited(false);
}
const handleShow = useEventCallback(() => {
modal.add();
removeKeydownListenerRef.current = listen(document, 'keydown', handleDocumentKeyDown);
removeFocusListenerRef.current = listen(document, 'focus', // the timeout is necessary b/c this will run before the new modal is mounted
// and so steals focus from it
() => 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) {
const currentActiveElement = activeElement(document);
if (modal.dialog && currentActiveElement && !contains(modal.dialog, currentActiveElement)) {
lastFocusRef.current = currentActiveElement;
modal.dialog.focus();
}
}
});
const handleHide = useEventCallback(() => {
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
useEffect(() => {
if (!show || !container) return;
handleShow();
}, [show, container,
/* should never change: */
handleShow]); // Hide cleanup logic when:
// - `exited` switches to true
// - component unmounts;
useEffect(() => {
if (!exited) return;
handleHide();
}, [exited, handleHide]);
useWillUnmount(() => {
handleHide();
}); // --------------------------------
const handleEnforceFocus = useEventCallback(() => {
if (!enforceFocus || !isMounted() || !modal.isTopModal()) {
return;
}
const currentActiveElement = activeElement();
if (modal.dialog && currentActiveElement && !contains(modal.dialog, currentActiveElement)) {
modal.dialog.focus();
}
});
const handleBackdropClick = useEventCallback(e => {
if (e.target !== e.currentTarget) {
return;
}
onBackdropClick == null ? void 0 : onBackdropClick(e);
if (backdrop === true) {
onHide();
}
});
const handleDocumentKeyDown = useEventCallback(e => {
if (keyboard && e.keyCode === 27 && modal.isTopModal()) {
onEscapeKeyDown == null ? void 0 : onEscapeKeyDown(e);
if (!e.defaultPrevented) {
onHide();
}
}
});
const removeFocusListenerRef = useRef();
const removeKeydownListenerRef = useRef();
const handleHidden = (...args) => {
setExited(true);
onExited == null ? void 0 : onExited(...args);
};
const Transition = transition;
if (!container || !(show || Transition && !exited)) {
return null;
}
const dialogProps = Object.assign({
role,
ref: modal.setDialogRef,
// apparently only works on the dialog role element
'aria-modal': role === 'dialog' ? true : undefined
}, rest, {
style,
className,
tabIndex: -1
});
let dialog = renderDialog ? renderDialog(dialogProps) : /*#__PURE__*/_jsx("div", Object.assign({}, dialogProps, {
children: /*#__PURE__*/React.cloneElement(children, {
role: 'document'
})
}));
if (Transition) {
dialog = /*#__PURE__*/_jsx(Transition, {
appear: true,
unmountOnExit: true,
in: !!show,
onExit: onExit,
onExiting: onExiting,
onExited: handleHidden,
onEnter: onEnter,
onEntering: onEntering,
onEntered: onEntered,
children: dialog
});
}
let backdropElement = null;
if (backdrop) {
const BackdropTransition = backdropTransition;
backdropElement = renderBackdrop({
ref: modal.setBackdropRef,
onClick: handleBackdropClick
});
if (BackdropTransition) {
backdropElement = /*#__PURE__*/_jsx(BackdropTransition, {
appear: true,
in: !!show,
children: backdropElement
});
}
}
return /*#__PURE__*/_jsx(_Fragment, {
children: /*#__PURE__*/ReactDOM.createPortal( /*#__PURE__*/_jsxs(_Fragment, {
children: [backdropElement, dialog]
}), container)
});
});
Modal.displayName = 'Modal';
export default Object.assign(Modal, {
Manager: ModalManager
});

Event Timeline