UNPKG

9.15 kBJavaScriptView Raw
1import _objectWithoutPropertiesLoose from "@babel/runtime-corejs2/helpers/esm/objectWithoutPropertiesLoose";
2import _inheritsLoose from "@babel/runtime-corejs2/helpers/esm/inheritsLoose";
3import _assertThisInitialized from "@babel/runtime-corejs2/helpers/esm/assertThisInitialized";
4import _extends from "@babel/runtime-corejs2/helpers/esm/extends";
5import classNames from 'classnames';
6import events from 'dom-helpers/events';
7import ownerDocument from 'dom-helpers/ownerDocument';
8import canUseDOM from 'dom-helpers/util/inDOM';
9import getScrollbarSize from 'dom-helpers/util/scrollbarSize';
10import React from 'react';
11import PropTypes from 'prop-types';
12import ReactDOM from 'react-dom';
13import BaseModal from 'react-overlays/lib/Modal';
14import isOverflowing from 'react-overlays/lib/utils/isOverflowing';
15import elementType from 'prop-types-extra/lib/elementType';
16import Fade from './Fade';
17import Body from './ModalBody';
18import ModalDialog from './ModalDialog';
19import Footer from './ModalFooter';
20import Header from './ModalHeader';
21import Title from './ModalTitle';
22import { bsClass, bsSizes, prefix } from './utils/bootstrapUtils';
23import createChainedFunction from './utils/createChainedFunction';
24import splitComponentProps from './utils/splitComponentProps';
25import { Size } from './utils/StyleConfig';
26
27var propTypes = _extends({}, BaseModal.propTypes, ModalDialog.propTypes, {
28 /**
29 * Include a backdrop component. Specify 'static' for a backdrop that doesn't
30 * trigger an "onHide" when clicked.
31 */
32 backdrop: PropTypes.oneOf(['static', true, false]),
33
34 /**
35 * Add an optional extra class name to .modal-backdrop
36 * It could end up looking like class="modal-backdrop foo-modal-backdrop in".
37 */
38 backdropClassName: PropTypes.string,
39
40 /**
41 * Close the modal when escape key is pressed
42 */
43 keyboard: PropTypes.bool,
44
45 /**
46 * Open and close the Modal with a slide and fade animation.
47 */
48 animation: PropTypes.bool,
49
50 /**
51 * A Component type that provides the modal content Markup. This is a useful
52 * prop when you want to use your own styles and markup to create a custom
53 * modal component.
54 */
55 dialogComponentClass: elementType,
56
57 /**
58 * When `true` The modal will automatically shift focus to itself when it
59 * opens, and replace it to the last focused element when it closes.
60 * Generally this should never be set to false as it makes the Modal less
61 * accessible to assistive technologies, like screen-readers.
62 */
63 autoFocus: PropTypes.bool,
64
65 /**
66 * When `true` The modal will prevent focus from leaving the Modal while
67 * open. Consider leaving the default value here, as it is necessary to make
68 * the Modal work well with assistive technologies, such as screen readers.
69 */
70 enforceFocus: PropTypes.bool,
71
72 /**
73 * When `true` The modal will restore focus to previously focused element once
74 * modal is hidden
75 */
76 restoreFocus: PropTypes.bool,
77
78 /**
79 * When `true` The modal will show itself.
80 */
81 show: PropTypes.bool,
82
83 /**
84 * A callback fired when the header closeButton or non-static backdrop is
85 * clicked. Required if either are specified.
86 */
87 onHide: PropTypes.func,
88
89 /**
90 * Callback fired before the Modal transitions in
91 */
92 onEnter: PropTypes.func,
93
94 /**
95 * Callback fired as the Modal begins to transition in
96 */
97 onEntering: PropTypes.func,
98
99 /**
100 * Callback fired after the Modal finishes transitioning in
101 */
102 onEntered: PropTypes.func,
103
104 /**
105 * Callback fired right before the Modal transitions out
106 */
107 onExit: PropTypes.func,
108
109 /**
110 * Callback fired as the Modal begins to transition out
111 */
112 onExiting: PropTypes.func,
113
114 /**
115 * Callback fired after the Modal finishes transitioning out
116 */
117 onExited: PropTypes.func,
118
119 /**
120 * @private
121 */
122 container: BaseModal.propTypes.container
123});
124
125var defaultProps = _extends({}, BaseModal.defaultProps, {
126 animation: true,
127 dialogComponentClass: ModalDialog
128});
129
130var childContextTypes = {
131 $bs_modal: PropTypes.shape({
132 onHide: PropTypes.func
133 })
134};
135/* eslint-disable no-use-before-define, react/no-multi-comp */
136
137function DialogTransition(props) {
138 return React.createElement(Fade, _extends({}, props, {
139 timeout: Modal.TRANSITION_DURATION
140 }));
141}
142
143function BackdropTransition(props) {
144 return React.createElement(Fade, _extends({}, props, {
145 timeout: Modal.BACKDROP_TRANSITION_DURATION
146 }));
147}
148/* eslint-enable no-use-before-define */
149
150
151var Modal =
152/*#__PURE__*/
153function (_React$Component) {
154 _inheritsLoose(Modal, _React$Component);
155
156 function Modal(props, context) {
157 var _this;
158
159 _this = _React$Component.call(this, props, context) || this;
160 _this.handleEntering = _this.handleEntering.bind(_assertThisInitialized(_assertThisInitialized(_this)));
161 _this.handleExited = _this.handleExited.bind(_assertThisInitialized(_assertThisInitialized(_this)));
162 _this.handleWindowResize = _this.handleWindowResize.bind(_assertThisInitialized(_assertThisInitialized(_this)));
163 _this.handleDialogClick = _this.handleDialogClick.bind(_assertThisInitialized(_assertThisInitialized(_this)));
164 _this.setModalRef = _this.setModalRef.bind(_assertThisInitialized(_assertThisInitialized(_this)));
165 _this.state = {
166 style: {}
167 };
168 return _this;
169 }
170
171 var _proto = Modal.prototype;
172
173 _proto.getChildContext = function getChildContext() {
174 return {
175 $bs_modal: {
176 onHide: this.props.onHide
177 }
178 };
179 };
180
181 _proto.componentWillUnmount = function componentWillUnmount() {
182 // Clean up the listener if we need to.
183 this.handleExited();
184 };
185
186 _proto.setModalRef = function setModalRef(ref) {
187 this._modal = ref;
188 };
189
190 _proto.handleDialogClick = function handleDialogClick(e) {
191 if (e.target !== e.currentTarget) {
192 return;
193 }
194
195 this.props.onHide();
196 };
197
198 _proto.handleEntering = function handleEntering() {
199 // FIXME: This should work even when animation is disabled.
200 events.on(window, 'resize', this.handleWindowResize);
201 this.updateStyle();
202 };
203
204 _proto.handleExited = function handleExited() {
205 // FIXME: This should work even when animation is disabled.
206 events.off(window, 'resize', this.handleWindowResize);
207 };
208
209 _proto.handleWindowResize = function handleWindowResize() {
210 this.updateStyle();
211 };
212
213 _proto.updateStyle = function updateStyle() {
214 if (!canUseDOM) {
215 return;
216 }
217
218 var dialogNode = this._modal.getDialogElement();
219
220 var dialogHeight = dialogNode.scrollHeight;
221 var document = ownerDocument(dialogNode);
222 var bodyIsOverflowing = isOverflowing(ReactDOM.findDOMNode(this.props.container || document.body));
223 var modalIsOverflowing = dialogHeight > document.documentElement.clientHeight;
224 this.setState({
225 style: {
226 paddingRight: bodyIsOverflowing && !modalIsOverflowing ? getScrollbarSize() : undefined,
227 paddingLeft: !bodyIsOverflowing && modalIsOverflowing ? getScrollbarSize() : undefined
228 }
229 });
230 };
231
232 _proto.render = function render() {
233 var _this$props = this.props,
234 backdrop = _this$props.backdrop,
235 backdropClassName = _this$props.backdropClassName,
236 animation = _this$props.animation,
237 show = _this$props.show,
238 Dialog = _this$props.dialogComponentClass,
239 className = _this$props.className,
240 style = _this$props.style,
241 children = _this$props.children,
242 onEntering = _this$props.onEntering,
243 onExited = _this$props.onExited,
244 props = _objectWithoutPropertiesLoose(_this$props, ["backdrop", "backdropClassName", "animation", "show", "dialogComponentClass", "className", "style", "children", "onEntering", "onExited"]);
245
246 var _splitComponentProps = splitComponentProps(props, BaseModal),
247 baseModalProps = _splitComponentProps[0],
248 dialogProps = _splitComponentProps[1];
249
250 var inClassName = show && !animation && 'in';
251 return React.createElement(BaseModal, _extends({}, baseModalProps, {
252 ref: this.setModalRef,
253 show: show,
254 containerClassName: prefix(props, 'open'),
255 transition: animation ? DialogTransition : undefined,
256 backdrop: backdrop,
257 backdropTransition: animation ? BackdropTransition : undefined,
258 backdropClassName: classNames(prefix(props, 'backdrop'), backdropClassName, inClassName),
259 onEntering: createChainedFunction(onEntering, this.handleEntering),
260 onExited: createChainedFunction(onExited, this.handleExited)
261 }), React.createElement(Dialog, _extends({}, dialogProps, {
262 style: _extends({}, this.state.style, style),
263 className: classNames(className, inClassName),
264 onClick: backdrop === true ? this.handleDialogClick : null
265 }), children));
266 };
267
268 return Modal;
269}(React.Component);
270
271Modal.propTypes = propTypes;
272Modal.defaultProps = defaultProps;
273Modal.childContextTypes = childContextTypes;
274Modal.Body = Body;
275Modal.Header = Header;
276Modal.Title = Title;
277Modal.Footer = Footer;
278Modal.Dialog = ModalDialog;
279Modal.TRANSITION_DURATION = 300;
280Modal.BACKDROP_TRANSITION_DURATION = 150;
281export default bsClass('modal', bsSizes([Size.LARGE, Size.SMALL], Modal));
\No newline at end of file