UNPKG

19 kBJavaScriptView Raw
1'use strict';
2
3exports.__esModule = true;
4exports.default = undefined;
5
6var _objectWithoutProperties2 = require('babel-runtime/helpers/objectWithoutProperties');
7
8var _objectWithoutProperties3 = _interopRequireDefault(_objectWithoutProperties2);
9
10var _extends2 = require('babel-runtime/helpers/extends');
11
12var _extends3 = _interopRequireDefault(_extends2);
13
14var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
15
16var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
17
18var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
19
20var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
21
22var _inherits2 = require('babel-runtime/helpers/inherits');
23
24var _inherits3 = _interopRequireDefault(_inherits2);
25
26var _class, _temp;
27
28var _react = require('react');
29
30var _react2 = _interopRequireDefault(_react);
31
32var _propTypes = require('prop-types');
33
34var _propTypes2 = _interopRequireDefault(_propTypes);
35
36var _overlay = require('../overlay');
37
38var _overlay2 = _interopRequireDefault(_overlay);
39
40var _zhCn = require('../locale/zh-cn');
41
42var _zhCn2 = _interopRequireDefault(_zhCn);
43
44var _util = require('../util');
45
46var _inner = require('./inner');
47
48var _inner2 = _interopRequireDefault(_inner);
49
50function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
51
52var noop = function noop() {};
53var limitTabRange = _util.focus.limitTabRange;
54var bindCtx = _util.func.bindCtx;
55var pickOthers = _util.obj.pickOthers;
56var getStyle = _util.dom.getStyle,
57 setStyle = _util.dom.setStyle;
58
59// [fix issue #1609](https://github.com/alibaba-fusion/next/issues/1609)
60// https://stackoverflow.com/questions/19717907/getcomputedstyle-reporting-different-heights-between-chrome-safari-firefox-and-i
61
62function _getSize(dom, name) {
63 var boxSizing = getStyle(dom, 'boxSizing');
64
65 if (_util.env.ieVersion && ['width', 'height'].indexOf(name) !== -1 && boxSizing === 'border-box') {
66 return parseFloat(dom.getBoundingClientRect()[name].toFixed(1));
67 } else {
68 return getStyle(dom, name);
69 }
70}
71
72/**
73 * Dialog
74 */
75var Dialog = (_temp = _class = function (_Component) {
76 (0, _inherits3.default)(Dialog, _Component);
77
78 function Dialog(props, context) {
79 (0, _classCallCheck3.default)(this, Dialog);
80
81 var _this = (0, _possibleConstructorReturn3.default)(this, _Component.call(this, props, context));
82
83 bindCtx(_this, ['onKeyDown', 'beforePosition', 'adjustPosition', 'getOverlayRef']);
84 return _this;
85 }
86
87 Dialog.prototype.componentDidMount = function componentDidMount() {
88 _util.events.on(document, 'keydown', this.onKeyDown);
89 if (!this.useCSSToPosition()) {
90 this.adjustPosition();
91 }
92 };
93
94 Dialog.prototype.componentWillUnmount = function componentWillUnmount() {
95 _util.events.off(document, 'keydown', this.onKeyDown);
96 };
97
98 Dialog.prototype.useCSSToPosition = function useCSSToPosition() {
99 var _props = this.props,
100 align = _props.align,
101 isFullScreen = _props.isFullScreen;
102
103 return align === 'cc cc' && isFullScreen;
104 };
105
106 Dialog.prototype.onKeyDown = function onKeyDown(e) {
107 var node = this.getInnerNode();
108 if (node) {
109 limitTabRange(node, e);
110 }
111 };
112
113 Dialog.prototype.beforePosition = function beforePosition() {
114 if (this.props.visible && this.overlay) {
115 var inner = this.getInner();
116 if (inner) {
117 var node = this.getInnerNode();
118 if (this._lastDialogHeight !== _getSize(node, 'height')) {
119 this.revertSize(inner.bodyNode);
120 }
121 }
122 }
123 };
124
125 Dialog.prototype.adjustPosition = function adjustPosition() {
126 if (this.props.visible && this.overlay) {
127 var inner = this.getInner();
128 if (inner) {
129 var node = this.getInnerNode();
130
131 var top = getStyle(node, 'top');
132 var minMargin = this.props.minMargin;
133 if (top < minMargin) {
134 top = minMargin;
135 setStyle(node, 'top', minMargin + 'px');
136 }
137
138 var height = _getSize(node, 'height');
139 var viewportHeight = window.innerHeight || document.documentElement.clientHeight;
140
141 if (viewportHeight < height + top * 2 - 1 || // 分辨率和精确度的原因 高度计算的时候 可能会有1px内的偏差
142 this.props.height) {
143 this.adjustSize(inner, node, Math.min(height, viewportHeight - top * 2));
144 } else {
145 this.revertSize(inner.bodyNode);
146 }
147
148 this._lastDialogHeight = height;
149 }
150 }
151 };
152
153 Dialog.prototype.adjustSize = function adjustSize(inner, node, expectHeight) {
154 var headerNode = inner.headerNode,
155 bodyNode = inner.bodyNode,
156 footerNode = inner.footerNode;
157
158 var _map = [headerNode, footerNode].map(function (node) {
159 return node ? _getSize(node, 'height') : 0;
160 }),
161 headerHeight = _map[0],
162 footerHeight = _map[1];
163
164 var padding = ['padding-top', 'padding-bottom'].reduce(function (sum, attr) {
165 return sum + getStyle(node, attr);
166 }, 0);
167
168 var maxBodyHeight = expectHeight - headerHeight - footerHeight - padding;
169
170 if (maxBodyHeight < 0) {
171 maxBodyHeight = 1;
172 }
173
174 if (bodyNode) {
175 this.dialogBodyStyleMaxHeight = bodyNode.style.maxHeight;
176 this.dialogBodyStyleOverflowY = bodyNode.style.overflowY;
177
178 setStyle(bodyNode, {
179 'max-height': maxBodyHeight + 'px',
180 'overflow-y': 'auto'
181 });
182 }
183 };
184
185 Dialog.prototype.revertSize = function revertSize(bodyNode) {
186 setStyle(bodyNode, {
187 'max-height': this.dialogBodyStyleMaxHeight,
188 'overflow-y': this.dialogBodyStyleOverflowY
189 });
190 };
191
192 Dialog.prototype.mapcloseableToConfig = function mapcloseableToConfig(closeable) {
193 return ['esc', 'close', 'mask'].reduce(function (ret, option) {
194 var key = option.charAt(0).toUpperCase() + option.substr(1);
195 var value = typeof closeable === 'boolean' ? closeable : closeable.split(',').indexOf(option) > -1;
196
197 if (option === 'esc' || option === 'mask') {
198 ret['canCloseBy' + key] = value;
199 } else {
200 ret['canCloseBy' + key + 'Click'] = value;
201 }
202
203 return ret;
204 }, {});
205 };
206
207 Dialog.prototype.getOverlayRef = function getOverlayRef(ref) {
208 this.overlay = ref;
209 };
210
211 Dialog.prototype.getInner = function getInner() {
212 return this.overlay.getInstance().getContent();
213 };
214
215 Dialog.prototype.getInnerNode = function getInnerNode() {
216 return this.overlay.getInstance().getContentNode();
217 };
218
219 Dialog.prototype.renderInner = function renderInner(closeable) {
220 var _props2 = this.props,
221 prefix = _props2.prefix,
222 className = _props2.className,
223 title = _props2.title,
224 children = _props2.children,
225 footer = _props2.footer,
226 footerAlign = _props2.footerAlign,
227 footerActions = _props2.footerActions,
228 onOk = _props2.onOk,
229 onCancel = _props2.onCancel,
230 okProps = _props2.okProps,
231 cancelProps = _props2.cancelProps,
232 onClose = _props2.onClose,
233 locale = _props2.locale,
234 visible = _props2.visible,
235 rtl = _props2.rtl,
236 height = _props2.height;
237
238 var others = pickOthers(Object.keys(Dialog.propTypes), this.props);
239
240 return _react2.default.createElement(
241 _inner2.default,
242 (0, _extends3.default)({
243 prefix: prefix,
244 className: className,
245 title: title,
246 footer: footer,
247 footerAlign: footerAlign,
248 footerActions: footerActions,
249 onOk: visible ? onOk : noop,
250 onCancel: visible ? onCancel : noop,
251 okProps: okProps,
252 cancelProps: cancelProps,
253 locale: locale,
254 closeable: closeable,
255 rtl: rtl,
256 onClose: onClose.bind(this, 'closeClick'),
257 height: height
258 }, others),
259 children
260 );
261 };
262
263 Dialog.prototype.render = function render() {
264 var _props3 = this.props,
265 prefix = _props3.prefix,
266 visible = _props3.visible,
267 hasMask = _props3.hasMask,
268 animation = _props3.animation,
269 autoFocus = _props3.autoFocus,
270 closeable = _props3.closeable,
271 closeMode = _props3.closeMode,
272 onClose = _props3.onClose,
273 afterClose = _props3.afterClose,
274 shouldUpdatePosition = _props3.shouldUpdatePosition,
275 align = _props3.align,
276 popupContainer = _props3.popupContainer,
277 cache = _props3.cache,
278 overlayProps = _props3.overlayProps,
279 rtl = _props3.rtl;
280
281
282 var useCSS = this.useCSSToPosition();
283 var newCloseable = 'closeMode' in this.props ? Array.isArray(closeMode) ? closeMode.join(',') : closeMode : closeable;
284
285 var _mapcloseableToConfig = this.mapcloseableToConfig(newCloseable),
286 canCloseByCloseClick = _mapcloseableToConfig.canCloseByCloseClick,
287 closeConfig = (0, _objectWithoutProperties3.default)(_mapcloseableToConfig, ['canCloseByCloseClick']);
288
289 var newOverlayProps = (0, _extends3.default)({
290 disableScroll: true,
291 container: popupContainer,
292 cache: cache
293 }, overlayProps, {
294 prefix: prefix,
295 visible: visible,
296 animation: animation,
297 hasMask: hasMask,
298 autoFocus: autoFocus,
299 afterClose: afterClose
300 }, closeConfig, {
301 canCloseByOutSideClick: false,
302 align: useCSS ? false : align,
303 onRequestClose: onClose,
304 needAdjust: false,
305 ref: this.getOverlayRef,
306 rtl: rtl,
307 maskClass: useCSS ? prefix + 'dialog-container' : '',
308 isChildrenInMask: useCSS && hasMask
309 });
310 if (!useCSS) {
311 newOverlayProps.beforePosition = this.beforePosition;
312 newOverlayProps.onPosition = this.adjustPosition;
313 newOverlayProps.shouldUpdatePosition = shouldUpdatePosition;
314 }
315
316 var inner = this.renderInner(canCloseByCloseClick);
317
318 // useCSS && hasMask : isFullScreen 并且 有mask的模式下,为了解决 next-overlay-backdrop 覆盖mask,使得点击mask关闭页面的功能不生效的问题,需要开启 Overlay 的 isChildrenInMask 功能,并且把 next-dialog-container 放到 next-overlay-backdrop上
319 // useCSS && !hasMask : isFullScreen 并且 没有mask的情况下,需要关闭 isChildrenInMask 功能,以防止children不渲染
320 // 其他模式下维持 mask 与 children 同级的关系
321 return _react2.default.createElement(
322 _overlay2.default,
323 newOverlayProps,
324 useCSS && !hasMask ? _react2.default.createElement(
325 'div',
326 { className: prefix + 'dialog-container', dir: rtl ? 'rtl' : undefined },
327 inner
328 ) : inner
329 );
330 };
331
332 return Dialog;
333}(_react.Component), _class.propTypes = {
334 prefix: _propTypes2.default.string,
335 pure: _propTypes2.default.bool,
336 rtl: _propTypes2.default.bool,
337 className: _propTypes2.default.string,
338 /**
339 * 是否显示
340 */
341 visible: _propTypes2.default.bool,
342 /**
343 * 标题
344 */
345 title: _propTypes2.default.node,
346 /**
347 * 内容
348 */
349 children: _propTypes2.default.node,
350 /**
351 * 底部内容,设置为 false,则不进行显示
352 * @default [<Button type="primary">确定</Button>, <Button>取消</Button>]
353 */
354 footer: _propTypes2.default.oneOfType([_propTypes2.default.bool, _propTypes2.default.node]),
355 /**
356 * 底部按钮的对齐方式
357 */
358 footerAlign: _propTypes2.default.oneOf(['left', 'center', 'right']),
359 /**
360 * 指定确定按钮和取消按钮是否存在以及如何排列,<br><br>**可选值**:
361 * ['ok', 'cancel'](确认取消按钮同时存在,确认按钮在左)
362 * ['cancel', 'ok'](确认取消按钮同时存在,确认按钮在右)
363 * ['ok'](只存在确认按钮)
364 * ['cancel'](只存在取消按钮)
365 */
366 footerActions: _propTypes2.default.array,
367 /**
368 * 在点击确定按钮时触发的回调函数
369 * @param {Object} event 点击事件对象
370 */
371 onOk: _propTypes2.default.func,
372 /**
373 * 在点击取消/关闭按钮时触发的回调函数
374 * @param {Object} event 点击事件对象, event.triggerType=esc|closeIcon 可区分点击来源
375 */
376 onCancel: _propTypes2.default.func,
377 /**
378 * 应用于确定按钮的属性对象
379 */
380 okProps: _propTypes2.default.object,
381 /**
382 * 应用于取消按钮的属性对象
383 */
384 cancelProps: _propTypes2.default.object,
385 /**
386 * [推荐]1.21.x 支持控制对话框关闭的方式,值可以为字符串或者数组,其中字符串、数组均为以下值的枚举:
387 * **close** 表示点击关闭按钮可以关闭对话框
388 * **mask** 表示点击遮罩区域可以关闭对话框
389 * **esc** 表示按下 esc 键可以关闭对话框
390 * 如 'close' 或 ['close','esc','mask'], []
391 * @version 1.21
392 */
393 closeMode: _propTypes2.default.oneOfType([_propTypes2.default.arrayOf(_propTypes2.default.oneOf(['close', 'mask', 'esc'])), _propTypes2.default.oneOf(['close', 'mask', 'esc'])]),
394 /**
395 * 隐藏时是否保留子节点,不销毁 (低版本通过 overlayProps 实现)
396 * @version 1.23
397 */
398 cache: _propTypes2.default.bool,
399 /**
400 * 对话框关闭后触发的回调函数, 如果有动画,则在动画结束后触发
401 */
402 afterClose: _propTypes2.default.func,
403 /**
404 * 是否显示遮罩
405 */
406 hasMask: _propTypes2.default.bool,
407 /**
408 * 显示隐藏时动画的播放方式,支持 { in: 'enter-class', out: 'leave-class' } 的对象参数,如果设置为 false,则不播放动画。 请参考 Animate 组件的文档获取可用的动画名
409 * @default { in: 'expandInDown', out: 'expandOutUp' }
410 */
411 animation: _propTypes2.default.oneOfType([_propTypes2.default.object, _propTypes2.default.bool]),
412 /**
413 * 对话框弹出时是否自动获得焦点
414 */
415 autoFocus: _propTypes2.default.bool,
416 /**
417 * [v2废弃] 透传到弹层组件的属性对象
418 */
419 overlayProps: _propTypes2.default.object,
420 /**
421 * 自定义国际化文案对象
422 * @property {String} ok 确认按钮文案
423 * @property {String} cancel 取消按钮文案
424 */
425 locale: _propTypes2.default.object,
426 // Do not remove this, it's for <ConfigProvider popupContainer={} />
427 // see https://github.com/alibaba-fusion/next/issues/1508
428 /**
429 * 自定义弹窗挂载位置
430 */
431 popupContainer: _propTypes2.default.any,
432 /**
433 * 对话框的高度样式属性
434 */
435 height: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.number]),
436 /**
437 * 开启 v2 版本弹窗
438 */
439 v2: _propTypes2.default.bool,
440 /**
441 * [v2] 弹窗宽度
442 * @version 1.25
443 */
444 width: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.number]),
445 /**
446 * [v2] 弹窗上边距。默认 100,设置 centered=true 后默认 40
447 * @version 1.25
448 */
449 top: _propTypes2.default.number,
450 /**
451 * [v2] 弹窗下边距
452 * @version 1.25
453 */
454 bottom: _propTypes2.default.number,
455 /**
456 * [v2] 定制关闭按钮 icon
457 * @version 1.25
458 */
459 closeIcon: _propTypes2.default.node,
460 /**
461 * [v2] 弹窗居中对齐
462 * @version 1.25
463 */
464 centered: _propTypes2.default.bool,
465 /**
466 * [v2] 对话框高度超过浏览器视口高度时,对话框是否展示滚动条。关闭此功后对话框会随高度撑开页面
467 * @version 1.25
468 */
469 overflowScroll: _propTypes2.default.bool,
470 /**
471 * [废弃]同closeMode, 控制对话框关闭的方式,值可以为字符串或者布尔值,其中字符串是由以下值组成:
472 * **close** 表示点击关闭按钮可以关闭对话框
473 * **mask** 表示点击遮罩区域可以关闭对话框
474 * **esc** 表示按下 esc 键可以关闭对话框
475 * 如 'close' 或 'close,esc,mask'
476 * 如果设置为 true,则以上关闭方式全部生效
477 * 如果设置为 false,则以上关闭方式全部失效
478 */
479 closeable: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.bool]),
480 /**
481 * 点击对话框关闭按钮时触发的回调函数
482 * @param {String} trigger 关闭触发行为的描述字符串
483 * @param {Object} event 关闭时事件对象
484 */
485 onClose: _propTypes2.default.func,
486 /**
487 * [v2废弃] 对话框对齐方式, 具体见Overlay文档
488 */
489 align: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.bool]),
490 /**
491 * [v2废弃] 是否撑开页面。 v2 改用 overflowScroll
492 */
493 isFullScreen: _propTypes2.default.bool,
494 /**
495 * [v2废弃] 是否在对话框重新渲染时及时更新对话框位置,一般用于对话框高度变化后依然能保证原来的对齐方式
496 */
497 shouldUpdatePosition: _propTypes2.default.bool,
498 /**
499 * [v2废弃] 对话框距离浏览器顶部和底部的最小间距,align 被设置为 'cc cc' 并且 isFullScreen 被设置为 true 时不生效
500 */
501 minMargin: _propTypes2.default.number
502}, _class.defaultProps = {
503 prefix: 'next-',
504 pure: false,
505 visible: false,
506 footerAlign: 'right',
507 footerActions: ['ok', 'cancel'],
508 onOk: noop,
509 onCancel: noop,
510 cache: false,
511 okProps: {},
512 cancelProps: {},
513 closeable: 'esc,close',
514 onClose: noop,
515 afterClose: noop,
516 centered: false,
517 hasMask: true,
518 animation: {
519 in: 'fadeInUp',
520 out: 'fadeOutUp'
521 },
522 autoFocus: false,
523 align: 'cc cc',
524 isFullScreen: false,
525 overflowScroll: true,
526 shouldUpdatePosition: false,
527 minMargin: 40,
528 bottom: 40,
529 overlayProps: {},
530 locale: _zhCn2.default.Dialog
531}, _temp);
532Dialog.displayName = 'Dialog';
533exports.default = Dialog;
534module.exports = exports['default'];
\No newline at end of file