UNPKG

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