UNPKG

10.3 kBJavaScriptView Raw
1import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
2import _extends from "@babel/runtime/helpers/esm/extends";
3var _excluded = ["bsPrefix", "className", "style", "dialogClassName", "contentClassName", "children", "dialogAs", "aria-labelledby", "show", "animation", "backdrop", "keyboard", "onEscapeKeyDown", "onShow", "onHide", "container", "autoFocus", "enforceFocus", "restoreFocus", "restoreFocusOptions", "onEntered", "onExit", "onExiting", "onEnter", "onEntering", "onExited", "backdropClassName", "manager"];
4import classNames from 'classnames';
5import addEventListener from 'dom-helpers/addEventListener';
6import canUseDOM from 'dom-helpers/canUseDOM';
7import ownerDocument from 'dom-helpers/ownerDocument';
8import removeEventListener from 'dom-helpers/removeEventListener';
9import getScrollbarSize from 'dom-helpers/scrollbarSize';
10import useCallbackRef from '@restart/hooks/useCallbackRef';
11import useEventCallback from '@restart/hooks/useEventCallback';
12import useWillUnmount from '@restart/hooks/useWillUnmount';
13import transitionEnd from 'dom-helpers/transitionEnd';
14import React, { useCallback, useImperativeHandle, useMemo, useRef, useState } from 'react';
15import BaseModal from 'react-overlays/Modal';
16import warning from 'warning';
17import BootstrapModalManager from './BootstrapModalManager';
18import Fade from './Fade';
19import ModalBody from './ModalBody';
20import ModalContext from './ModalContext';
21import ModalDialog from './ModalDialog';
22import ModalFooter from './ModalFooter';
23import ModalHeader from './ModalHeader';
24import ModalTitle from './ModalTitle';
25import { useBootstrapPrefix } from './ThemeProvider';
26var manager;
27var defaultProps = {
28 show: false,
29 backdrop: true,
30 keyboard: true,
31 autoFocus: true,
32 enforceFocus: true,
33 restoreFocus: true,
34 animation: true,
35 dialogAs: ModalDialog
36};
37/* eslint-disable no-use-before-define, react/no-multi-comp */
38
39function DialogTransition(props) {
40 return /*#__PURE__*/React.createElement(Fade, _extends({}, props, {
41 timeout: null
42 }));
43}
44
45function BackdropTransition(props) {
46 return /*#__PURE__*/React.createElement(Fade, _extends({}, props, {
47 timeout: null
48 }));
49}
50/* eslint-enable no-use-before-define */
51
52
53var Modal = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
54 var bsPrefix = _ref.bsPrefix,
55 className = _ref.className,
56 style = _ref.style,
57 dialogClassName = _ref.dialogClassName,
58 contentClassName = _ref.contentClassName,
59 children = _ref.children,
60 Dialog = _ref.dialogAs,
61 ariaLabelledby = _ref['aria-labelledby'],
62 show = _ref.show,
63 animation = _ref.animation,
64 backdrop = _ref.backdrop,
65 keyboard = _ref.keyboard,
66 onEscapeKeyDown = _ref.onEscapeKeyDown,
67 onShow = _ref.onShow,
68 onHide = _ref.onHide,
69 container = _ref.container,
70 autoFocus = _ref.autoFocus,
71 enforceFocus = _ref.enforceFocus,
72 restoreFocus = _ref.restoreFocus,
73 restoreFocusOptions = _ref.restoreFocusOptions,
74 onEntered = _ref.onEntered,
75 onExit = _ref.onExit,
76 onExiting = _ref.onExiting,
77 onEnter = _ref.onEnter,
78 onEntering = _ref.onEntering,
79 onExited = _ref.onExited,
80 backdropClassName = _ref.backdropClassName,
81 propsManager = _ref.manager,
82 props = _objectWithoutPropertiesLoose(_ref, _excluded);
83
84 var _useState = useState({}),
85 modalStyle = _useState[0],
86 setStyle = _useState[1];
87
88 var _useState2 = useState(false),
89 animateStaticModal = _useState2[0],
90 setAnimateStaticModal = _useState2[1];
91
92 var waitingForMouseUpRef = useRef(false);
93 var ignoreBackdropClickRef = useRef(false);
94 var removeStaticModalAnimationRef = useRef(null); // TODO: what's this type
95
96 var _useCallbackRef = useCallbackRef(),
97 modal = _useCallbackRef[0],
98 setModalRef = _useCallbackRef[1];
99
100 var handleHide = useEventCallback(onHide);
101 bsPrefix = useBootstrapPrefix(bsPrefix, 'modal');
102 useImperativeHandle(ref, function () {
103 return {
104 get _modal() {
105 process.env.NODE_ENV !== "production" ? warning(false, 'Accessing `_modal` is not supported and will be removed in a future release') : void 0;
106 return modal;
107 }
108
109 };
110 }, [modal]);
111 var modalContext = useMemo(function () {
112 return {
113 onHide: handleHide
114 };
115 }, [handleHide]);
116
117 function getModalManager() {
118 if (propsManager) return propsManager;
119 if (!manager) manager = new BootstrapModalManager();
120 return manager;
121 }
122
123 function updateDialogStyle(node) {
124 if (!canUseDOM) return;
125 var containerIsOverflowing = getModalManager().isContainerOverflowing(modal);
126 var modalIsOverflowing = node.scrollHeight > ownerDocument(node).documentElement.clientHeight;
127 setStyle({
128 paddingRight: containerIsOverflowing && !modalIsOverflowing ? getScrollbarSize() : undefined,
129 paddingLeft: !containerIsOverflowing && modalIsOverflowing ? getScrollbarSize() : undefined
130 });
131 }
132
133 var handleWindowResize = useEventCallback(function () {
134 if (modal) {
135 updateDialogStyle(modal.dialog);
136 }
137 });
138 useWillUnmount(function () {
139 removeEventListener(window, 'resize', handleWindowResize);
140
141 if (removeStaticModalAnimationRef.current) {
142 removeStaticModalAnimationRef.current();
143 }
144 }); // We prevent the modal from closing during a drag by detecting where the
145 // the click originates from. If it starts in the modal and then ends outside
146 // don't close.
147
148 var handleDialogMouseDown = function handleDialogMouseDown() {
149 waitingForMouseUpRef.current = true;
150 };
151
152 var handleMouseUp = function handleMouseUp(e) {
153 if (waitingForMouseUpRef.current && modal && e.target === modal.dialog) {
154 ignoreBackdropClickRef.current = true;
155 }
156
157 waitingForMouseUpRef.current = false;
158 };
159
160 var handleStaticModalAnimation = function handleStaticModalAnimation() {
161 setAnimateStaticModal(true);
162 removeStaticModalAnimationRef.current = transitionEnd(modal.dialog, function () {
163 setAnimateStaticModal(false);
164 });
165 };
166
167 var handleStaticBackdropClick = function handleStaticBackdropClick(e) {
168 if (e.target !== e.currentTarget) {
169 return;
170 }
171
172 handleStaticModalAnimation();
173 };
174
175 var handleClick = function handleClick(e) {
176 if (backdrop === 'static') {
177 handleStaticBackdropClick(e);
178 return;
179 }
180
181 if (ignoreBackdropClickRef.current || e.target !== e.currentTarget) {
182 ignoreBackdropClickRef.current = false;
183 return;
184 }
185
186 onHide == null ? void 0 : onHide();
187 };
188
189 var handleEscapeKeyDown = function handleEscapeKeyDown(e) {
190 if (!keyboard && backdrop === 'static') {
191 // Call preventDefault to stop modal from closing in react-overlays,
192 // then play our animation.
193 e.preventDefault();
194 handleStaticModalAnimation();
195 } else if (keyboard && onEscapeKeyDown) {
196 onEscapeKeyDown(e);
197 }
198 };
199
200 var handleEnter = function handleEnter(node, isAppearing) {
201 if (node) {
202 node.style.display = 'block';
203 updateDialogStyle(node);
204 }
205
206 onEnter == null ? void 0 : onEnter(node, isAppearing);
207 };
208
209 var handleExit = function handleExit(node) {
210 removeStaticModalAnimationRef.current == null ? void 0 : removeStaticModalAnimationRef.current();
211 onExit == null ? void 0 : onExit(node);
212 };
213
214 var handleEntering = function handleEntering(node, isAppearing) {
215 onEntering == null ? void 0 : onEntering(node, isAppearing); // FIXME: This should work even when animation is disabled.
216
217 addEventListener(window, 'resize', handleWindowResize);
218 };
219
220 var handleExited = function handleExited(node) {
221 if (node) node.style.display = ''; // RHL removes it sometimes
222
223 onExited == null ? void 0 : onExited(node); // FIXME: This should work even when animation is disabled.
224
225 removeEventListener(window, 'resize', handleWindowResize);
226 };
227
228 var renderBackdrop = useCallback(function (backdropProps) {
229 return /*#__PURE__*/React.createElement("div", _extends({}, backdropProps, {
230 className: classNames(bsPrefix + "-backdrop", backdropClassName, !animation && 'show')
231 }));
232 }, [animation, backdropClassName, bsPrefix]);
233
234 var baseModalStyle = _extends({}, style, modalStyle); // Sets `display` always block when `animation` is false
235
236
237 if (!animation) {
238 baseModalStyle.display = 'block';
239 }
240
241 var renderDialog = function renderDialog(dialogProps) {
242 return /*#__PURE__*/React.createElement("div", _extends({
243 role: "dialog"
244 }, dialogProps, {
245 style: baseModalStyle,
246 className: classNames(className, bsPrefix, animateStaticModal && bsPrefix + "-static"),
247 onClick: backdrop ? handleClick : undefined,
248 onMouseUp: handleMouseUp,
249 "aria-labelledby": ariaLabelledby
250 }), /*#__PURE__*/React.createElement(Dialog, _extends({}, props, {
251 onMouseDown: handleDialogMouseDown,
252 className: dialogClassName,
253 contentClassName: contentClassName
254 }), children));
255 };
256
257 return /*#__PURE__*/React.createElement(ModalContext.Provider, {
258 value: modalContext
259 }, /*#__PURE__*/React.createElement(BaseModal, {
260 show: show,
261 ref: setModalRef,
262 backdrop: backdrop,
263 container: container,
264 keyboard: true // Always set true - see handleEscapeKeyDown
265 ,
266 autoFocus: autoFocus,
267 enforceFocus: enforceFocus,
268 restoreFocus: restoreFocus,
269 restoreFocusOptions: restoreFocusOptions,
270 onEscapeKeyDown: handleEscapeKeyDown,
271 onShow: onShow,
272 onHide: onHide,
273 onEnter: handleEnter,
274 onEntering: handleEntering,
275 onEntered: onEntered,
276 onExit: handleExit,
277 onExiting: onExiting,
278 onExited: handleExited,
279 manager: getModalManager(),
280 containerClassName: bsPrefix + "-open",
281 transition: animation ? DialogTransition : undefined,
282 backdropTransition: animation ? BackdropTransition : undefined,
283 renderBackdrop: renderBackdrop,
284 renderDialog: renderDialog
285 }));
286});
287Modal.displayName = 'Modal';
288Modal.defaultProps = defaultProps;
289Modal.Body = ModalBody;
290Modal.Header = ModalHeader;
291Modal.Title = ModalTitle;
292Modal.Footer = ModalFooter;
293Modal.Dialog = ModalDialog;
294Modal.TRANSITION_DURATION = 300;
295Modal.BACKDROP_TRANSITION_DURATION = 150;
296export default Modal;
\No newline at end of file