1 | import _extends from 'babel-runtime/helpers/extends';
|
2 | import _objectWithoutProperties from 'babel-runtime/helpers/objectWithoutProperties';
|
3 |
|
4 | import React, { useState, useRef, useEffect, useContext } from 'react';
|
5 | import ReactDOM from 'react-dom';
|
6 | import classNames from 'classnames';
|
7 | import Overlay from '@alifd/overlay';
|
8 |
|
9 | import Inner from './inner';
|
10 | import Animate from '../animate';
|
11 | import zhCN from '../locale/zh-cn';
|
12 | import { log, func, dom, focus, guid } from '../util';
|
13 | import scrollLocker from './scroll-locker';
|
14 |
|
15 | var OverlayContext = Overlay.OverlayContext;
|
16 |
|
17 | var noop = func.noop;
|
18 |
|
19 | var Dialog = function Dialog(props) {
|
20 | var _classNames, _classNames2, _classNames3;
|
21 |
|
22 | if (!useState || !useRef || !useEffect) {
|
23 | log.warning('need react version > 16.8.0');
|
24 | return null;
|
25 | }
|
26 |
|
27 | var _props$prefix = props.prefix,
|
28 | prefix = _props$prefix === undefined ? 'next-' : _props$prefix,
|
29 | _props$afterClose = props.afterClose,
|
30 | afterClose = _props$afterClose === undefined ? noop : _props$afterClose,
|
31 | _props$hasMask = props.hasMask,
|
32 | hasMask = _props$hasMask === undefined ? true : _props$hasMask,
|
33 | _props$autoFocus = props.autoFocus,
|
34 | autoFocus = _props$autoFocus === undefined ? false : _props$autoFocus,
|
35 | className = props.className,
|
36 | title = props.title,
|
37 | children = props.children,
|
38 | footer = props.footer,
|
39 | footerAlign = props.footerAlign,
|
40 | footerActions = props.footerActions,
|
41 | _props$onOk = props.onOk,
|
42 | onOk = _props$onOk === undefined ? noop : _props$onOk,
|
43 | onCancel = props.onCancel,
|
44 | okProps = props.okProps,
|
45 | cancelProps = props.cancelProps,
|
46 | _props$locale = props.locale,
|
47 | locale = _props$locale === undefined ? zhCN.Dialog : _props$locale,
|
48 | rtl = props.rtl,
|
49 | pvisible = props.visible,
|
50 | _props$closeMode = props.closeMode,
|
51 | closeMode = _props$closeMode === undefined ? ['close', 'esc'] : _props$closeMode,
|
52 | closeIcon = props.closeIcon,
|
53 | _props$animation = props.animation,
|
54 | animation = _props$animation === undefined ? { in: 'fadeInUp', out: 'fadeOutUp' } : _props$animation,
|
55 | cache = props.cache,
|
56 | wrapperStyle = props.wrapperStyle,
|
57 | _props$popupContainer = props.popupContainer,
|
58 | popupContainer = _props$popupContainer === undefined ? document.body : _props$popupContainer,
|
59 | dialogRender = props.dialogRender,
|
60 | centered = props.centered,
|
61 | _props$top = props.top,
|
62 | top = _props$top === undefined ? centered ? 40 : 100 : _props$top,
|
63 | _props$bottom = props.bottom,
|
64 | bottom = _props$bottom === undefined ? 40 : _props$bottom,
|
65 | _props$width = props.width,
|
66 | width = _props$width === undefined ? 520 : _props$width,
|
67 | height = props.height,
|
68 | isFullScreen = props.isFullScreen,
|
69 | _props$overflowScroll = props.overflowScroll,
|
70 | overflowScroll = _props$overflowScroll === undefined ? !isFullScreen : _props$overflowScroll,
|
71 | minMargin = props.minMargin,
|
72 | onClose = props.onClose,
|
73 | style = props.style,
|
74 | others = _objectWithoutProperties(props, ['prefix', 'afterClose', 'hasMask', 'autoFocus', 'className', 'title', 'children', 'footer', 'footerAlign', 'footerActions', 'onOk', 'onCancel', 'okProps', 'cancelProps', 'locale', 'rtl', 'visible', 'closeMode', 'closeIcon', 'animation', 'cache', 'wrapperStyle', 'popupContainer', 'dialogRender', 'centered', 'top', 'bottom', 'width', 'height', 'isFullScreen', 'overflowScroll', 'minMargin', 'onClose', 'style']);
|
75 |
|
76 | if ('isFullScreen' in props) {
|
77 | log.deprecated('isFullScreen', 'overflowScroll', 'Dialog v2');
|
78 | }
|
79 | if ('minMargin' in props) {
|
80 | log.deprecated('minMargin', 'top/bottom', 'Dialog v2');
|
81 | }
|
82 |
|
83 | var _useState = useState(pvisible || false),
|
84 | firstVisible = _useState[0],
|
85 | setFirst = _useState[1];
|
86 |
|
87 | var _useState2 = useState(pvisible),
|
88 | visible = _useState2[0],
|
89 | setVisible = _useState2[1];
|
90 |
|
91 | var getContainer = typeof popupContainer === 'string' ? function () {
|
92 | return document.getElementById(popupContainer);
|
93 | } : typeof popupContainer !== 'function' ? function () {
|
94 | return popupContainer;
|
95 | } : popupContainer;
|
96 |
|
97 | var _useState3 = useState(getContainer()),
|
98 | container = _useState3[0],
|
99 | setContainer = _useState3[1];
|
100 |
|
101 | var dialogRef = useRef(null);
|
102 | var wrapperRef = useRef(null);
|
103 | var lastFocus = useRef(null);
|
104 | var locker = useRef(null);
|
105 |
|
106 | var _useState4 = useState(guid()),
|
107 | uuid = _useState4[0];
|
108 |
|
109 | var _useContext = useContext(OverlayContext),
|
110 | setVisibleOverlayToParent = _useContext.setVisibleOverlayToParent,
|
111 | otherContext = _objectWithoutProperties(_useContext, ['setVisibleOverlayToParent']);
|
112 |
|
113 | var childIDMap = useRef(new Map());
|
114 | var isAnimationEnd = useRef(false);
|
115 |
|
116 | var _useState5 = useState(),
|
117 | forceUpdate = _useState5[1];
|
118 |
|
119 | var markAnimationEnd = function markAnimationEnd(state) {
|
120 | isAnimationEnd.current = state;
|
121 | forceUpdate({});
|
122 | };
|
123 |
|
124 | var canCloseByEsc = false;
|
125 | var canCloseByMask = false;
|
126 | var closeable = false;
|
127 |
|
128 | var closeModeArray = Array.isArray(closeMode) ? closeMode : [closeMode];
|
129 | closeModeArray.forEach(function (mode) {
|
130 | switch (mode) {
|
131 | case 'esc':
|
132 | canCloseByEsc = true;
|
133 | break;
|
134 | case 'mask':
|
135 | canCloseByMask = true;
|
136 | break;
|
137 | case 'close':
|
138 | closeable = true;
|
139 | break;
|
140 | }
|
141 | });
|
142 |
|
143 |
|
144 | useEffect(function () {
|
145 | if ('visible' in props) {
|
146 | setVisible(pvisible);
|
147 | }
|
148 | }, [pvisible]);
|
149 |
|
150 |
|
151 | useEffect(function () {
|
152 | if (visible && hasMask) {
|
153 | var _style = {
|
154 | overflow: 'hidden'
|
155 | };
|
156 |
|
157 | if (dom.hasScroll(document.body)) {
|
158 | var scrollWidth = dom.scrollbar().width;
|
159 | if (scrollWidth) {
|
160 | _style.paddingRight = dom.getStyle(document.body, 'paddingRight') + dom.scrollbar().width + 'px';
|
161 | }
|
162 | }
|
163 | locker.current = scrollLocker.lock(document.body, _style);
|
164 | }
|
165 | }, [visible && hasMask]);
|
166 |
|
167 | var handleClose = function handleClose(targetType, e) {
|
168 | setVisibleOverlayToParent(uuid, null);
|
169 | typeof onClose === 'function' && onClose(targetType, e);
|
170 | };
|
171 |
|
172 | var keydownEvent = function keydownEvent(e) {
|
173 | if (e.keyCode === 27 && canCloseByEsc && !childIDMap.current.size) {
|
174 | handleClose('esc', e);
|
175 | }
|
176 | };
|
177 |
|
178 |
|
179 | useEffect(function () {
|
180 | if (visible && canCloseByEsc) {
|
181 | document.body.addEventListener('keydown', keydownEvent, false);
|
182 | return function () {
|
183 | document.body.removeEventListener('keydown', keydownEvent, false);
|
184 | };
|
185 | }
|
186 | }, [visible && canCloseByEsc]);
|
187 |
|
188 |
|
189 | useEffect(function () {
|
190 | !firstVisible && visible && setFirst(true);
|
191 | }, [visible]);
|
192 |
|
193 |
|
194 | useEffect(function () {
|
195 | if (!container) {
|
196 | setTimeout(function () {
|
197 | setContainer(getContainer());
|
198 | });
|
199 | }
|
200 | }, [container]);
|
201 |
|
202 | var handleExited = function handleExited() {
|
203 | if (!isAnimationEnd.current) {
|
204 | markAnimationEnd(true);
|
205 | dom.setStyle(wrapperRef.current, 'display', 'none');
|
206 | scrollLocker.unlock(document.body, locker.current);
|
207 |
|
208 | if (autoFocus && lastFocus.current) {
|
209 | try {
|
210 | lastFocus.current.focus();
|
211 | } finally {
|
212 |
|
213 | }
|
214 | lastFocus.current = null;
|
215 | }
|
216 | afterClose();
|
217 | }
|
218 | };
|
219 |
|
220 | useEffect(function () {
|
221 | return function () {
|
222 | handleExited();
|
223 | };
|
224 | }, []);
|
225 |
|
226 | if (firstVisible === false || !container) {
|
227 | return null;
|
228 | }
|
229 |
|
230 | if (!visible && !cache && isAnimationEnd.current) {
|
231 | return null;
|
232 | }
|
233 |
|
234 | var handleCancel = function handleCancel(e) {
|
235 | if (typeof onCancel === 'function') {
|
236 | onCancel(e);
|
237 | } else {
|
238 | handleClose('cancelBtn', e);
|
239 | }
|
240 | };
|
241 |
|
242 | var handleMaskClick = function handleMaskClick(e) {
|
243 | if (!canCloseByMask) {
|
244 | return;
|
245 | }
|
246 |
|
247 | if (e.type === 'click' && dialogRef.current) {
|
248 | var dialogNode = ReactDOM.findDOMNode(dialogRef.current);
|
249 | if (dialogNode && dialogNode.contains(e.target)) {
|
250 | return;
|
251 | }
|
252 | }
|
253 |
|
254 | handleClose('maskClick', e);
|
255 | };
|
256 |
|
257 | var handleEnter = function handleEnter() {
|
258 | markAnimationEnd(false);
|
259 | dom.setStyle(wrapperRef.current, 'display', '');
|
260 | };
|
261 | var handleEntered = function handleEntered() {
|
262 | if (autoFocus && dialogRef.current && dialogRef.current.bodyNode) {
|
263 | var focusableNodes = focus.getFocusNodeList(dialogRef.current.bodyNode);
|
264 | if (focusableNodes.length > 0 && focusableNodes[0]) {
|
265 | lastFocus.current = document.activeElement;
|
266 | focusableNodes[0].focus();
|
267 | }
|
268 | }
|
269 | setVisibleOverlayToParent(uuid, wrapperRef.current);
|
270 | };
|
271 |
|
272 | var wrapperCls = classNames((_classNames = {}, _classNames[prefix + 'overlay-wrapper'] = true, _classNames.opened = visible, _classNames));
|
273 | var dialogCls = classNames((_classNames2 = {}, _classNames2[prefix + 'dialog-v2'] = true, _classNames2[className] = !!className, _classNames2));
|
274 |
|
275 | var topStyle = {};
|
276 | if (centered) {
|
277 |
|
278 | if (!top && !bottom && minMargin) {
|
279 | topStyle.marginTop = minMargin;
|
280 | topStyle.marginBottom = minMargin;
|
281 | } else {
|
282 | top && (topStyle.marginTop = top);
|
283 | bottom && (topStyle.marginBottom = bottom);
|
284 | }
|
285 | } else {
|
286 | top && (topStyle.top = top);
|
287 | bottom && (topStyle.paddingBottom = bottom);
|
288 | }
|
289 |
|
290 | var maxHeight = void 0;
|
291 | if (overflowScroll) {
|
292 | maxHeight = 'calc(100vh - ' + (top + bottom) + 'px)';
|
293 | }
|
294 |
|
295 | var timeout = {
|
296 | appear: 300,
|
297 | enter: 300,
|
298 | exit: 250
|
299 | };
|
300 |
|
301 | var inner = React.createElement(
|
302 | Animate.OverlayAnimate,
|
303 | {
|
304 | visible: visible,
|
305 | animation: animation,
|
306 | timeout: timeout,
|
307 | onEnter: handleEnter,
|
308 | onEntered: handleEntered,
|
309 | onExited: handleExited
|
310 | },
|
311 | React.createElement(
|
312 | Inner,
|
313 | _extends({}, others, {
|
314 | style: centered ? _extends({}, topStyle, style) : style,
|
315 | v2: true,
|
316 | ref: dialogRef,
|
317 | prefix: prefix,
|
318 | className: dialogCls,
|
319 | title: title,
|
320 | footer: footer,
|
321 | footerAlign: footerAlign,
|
322 | footerActions: footerActions,
|
323 | onOk: visible ? onOk : noop,
|
324 | onCancel: visible ? handleCancel : noop,
|
325 | okProps: okProps,
|
326 | cancelProps: cancelProps,
|
327 | locale: locale,
|
328 | closeable: closeable,
|
329 | rtl: rtl,
|
330 | onClose: function onClose() {
|
331 | for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
|
332 | args[_key] = arguments[_key];
|
333 | }
|
334 |
|
335 | return handleClose.apply(undefined, ['closeClick'].concat(args));
|
336 | },
|
337 | closeIcon: closeIcon,
|
338 | height: height,
|
339 | maxHeight: maxHeight,
|
340 | width: width
|
341 | }),
|
342 | children
|
343 | )
|
344 | );
|
345 |
|
346 | if (typeof dialogRender === 'function') {
|
347 | inner = dialogRender(inner);
|
348 | }
|
349 |
|
350 | var innerWrapperCls = classNames((_classNames3 = {}, _classNames3[prefix + 'overlay-inner'] = true, _classNames3[prefix + 'dialog-wrapper'] = true, _classNames3[prefix + 'dialog-centered'] = centered, _classNames3));
|
351 |
|
352 | var getVisibleOverlayFromChild = function getVisibleOverlayFromChild(id, node) {
|
353 | if (node) {
|
354 | childIDMap.current.set(id, node);
|
355 | } else {
|
356 | childIDMap.current.delete(id);
|
357 | }
|
358 |
|
359 | setVisibleOverlayToParent(id, node);
|
360 | };
|
361 |
|
362 | return React.createElement(
|
363 | OverlayContext.Provider,
|
364 | {
|
365 | value: _extends({}, otherContext, {
|
366 | setVisibleOverlayToParent: getVisibleOverlayFromChild
|
367 | })
|
368 | },
|
369 | ReactDOM.createPortal(React.createElement(
|
370 | 'div',
|
371 | { className: wrapperCls, style: wrapperStyle, ref: wrapperRef },
|
372 | hasMask ? React.createElement(
|
373 | Animate.OverlayAnimate,
|
374 | {
|
375 | visible: visible,
|
376 | animation: animation ? { in: 'fadeIn', out: 'fadeOut' } : false,
|
377 | timeout: timeout,
|
378 | unmountOnExit: true
|
379 | },
|
380 | React.createElement('div', { className: prefix + 'overlay-backdrop' })
|
381 | ) : null,
|
382 | React.createElement(
|
383 | 'div',
|
384 | { className: innerWrapperCls, onClick: handleMaskClick },
|
385 | centered ? inner : React.createElement(
|
386 | 'div',
|
387 | { style: topStyle, className: prefix + 'dialog-inner-wrapper' },
|
388 | inner
|
389 | )
|
390 | )
|
391 | ), container)
|
392 | );
|
393 | };
|
394 |
|
395 | export default Dialog; |
\ | No newline at end of file |