@alifd/next
Version:
A configurable component library for web built on React.
431 lines (360 loc) • 15.2 kB
JavaScript
'use strict';
exports.__esModule = true;
var _extends2 = require('babel-runtime/helpers/extends');
var _extends3 = _interopRequireDefault(_extends2);
var _objectWithoutProperties2 = require('babel-runtime/helpers/objectWithoutProperties');
var _objectWithoutProperties3 = _interopRequireDefault(_objectWithoutProperties2);
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _reactDom = require('react-dom');
var _reactDom2 = _interopRequireDefault(_reactDom);
var _classnames = require('classnames');
var _classnames2 = _interopRequireDefault(_classnames);
var _overlay = require('@alifd/overlay');
var _overlay2 = _interopRequireDefault(_overlay);
var _inner = require('./inner');
var _inner2 = _interopRequireDefault(_inner);
var _animate = require('../animate');
var _animate2 = _interopRequireDefault(_animate);
var _zhCn = require('../locale/zh-cn');
var _zhCn2 = _interopRequireDefault(_zhCn);
var _util = require('../util');
var _scrollLocker = require('./scroll-locker');
var _scrollLocker2 = _interopRequireDefault(_scrollLocker);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var OverlayContext = _overlay2.default.OverlayContext; /* istanbul ignore file */
var noop = _util.func.noop;
var Dialog = function Dialog(props) {
var _classNames, _classNames2, _classNames3;
if (!_react.useState || !_react.useRef || !_react.useEffect) {
_util.log.warning('need react version > 16.8.0');
return null;
}
var _props$prefix = props.prefix,
prefix = _props$prefix === undefined ? 'next-' : _props$prefix,
_props$afterClose = props.afterClose,
afterClose = _props$afterClose === undefined ? noop : _props$afterClose,
_props$hasMask = props.hasMask,
hasMask = _props$hasMask === undefined ? true : _props$hasMask,
_props$autoFocus = props.autoFocus,
autoFocus = _props$autoFocus === undefined ? false : _props$autoFocus,
className = props.className,
title = props.title,
children = props.children,
footer = props.footer,
footerAlign = props.footerAlign,
footerActions = props.footerActions,
_props$onOk = props.onOk,
onOk = _props$onOk === undefined ? noop : _props$onOk,
onCancel = props.onCancel,
okProps = props.okProps,
cancelProps = props.cancelProps,
_props$locale = props.locale,
locale = _props$locale === undefined ? _zhCn2.default.Dialog : _props$locale,
rtl = props.rtl,
pvisible = props.visible,
_props$closeMode = props.closeMode,
closeMode = _props$closeMode === undefined ? ['close', 'esc'] : _props$closeMode,
closeIcon = props.closeIcon,
_props$animation = props.animation,
animation = _props$animation === undefined ? { in: 'fadeInUp', out: 'fadeOutUp' } : _props$animation,
cache = props.cache,
wrapperStyle = props.wrapperStyle,
_props$popupContainer = props.popupContainer,
popupContainer = _props$popupContainer === undefined ? document.body : _props$popupContainer,
dialogRender = props.dialogRender,
centered = props.centered,
_props$top = props.top,
top = _props$top === undefined ? centered ? 40 : 100 : _props$top,
_props$bottom = props.bottom,
bottom = _props$bottom === undefined ? 40 : _props$bottom,
_props$width = props.width,
width = _props$width === undefined ? 520 : _props$width,
height = props.height,
isFullScreen = props.isFullScreen,
_props$overflowScroll = props.overflowScroll,
overflowScroll = _props$overflowScroll === undefined ? !isFullScreen : _props$overflowScroll,
minMargin = props.minMargin,
onClose = props.onClose,
style = props.style,
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']);
if ('isFullScreen' in props) {
_util.log.deprecated('isFullScreen', 'overflowScroll', 'Dialog v2');
}
if ('minMargin' in props) {
_util.log.deprecated('minMargin', 'top/bottom', 'Dialog v2');
}
var _useState = (0, _react.useState)(pvisible || false),
firstVisible = _useState[0],
setFirst = _useState[1];
var _useState2 = (0, _react.useState)(pvisible),
visible = _useState2[0],
setVisible = _useState2[1];
var getContainer = typeof popupContainer === 'string' ? function () {
return document.getElementById(popupContainer);
} : typeof popupContainer !== 'function' ? function () {
return popupContainer;
} : popupContainer;
var _useState3 = (0, _react.useState)(getContainer()),
container = _useState3[0],
setContainer = _useState3[1];
var dialogRef = (0, _react.useRef)(null);
var wrapperRef = (0, _react.useRef)(null);
var lastFocus = (0, _react.useRef)(null);
var locker = (0, _react.useRef)(null);
var _useState4 = (0, _react.useState)((0, _util.guid)()),
uuid = _useState4[0];
var _useContext = (0, _react.useContext)(OverlayContext),
setVisibleOverlayToParent = _useContext.setVisibleOverlayToParent,
otherContext = (0, _objectWithoutProperties3.default)(_useContext, ['setVisibleOverlayToParent']);
var childIDMap = (0, _react.useRef)(new Map());
var isAnimationEnd = (0, _react.useRef)(false);
var _useState5 = (0, _react.useState)(),
forceUpdate = _useState5[1];
var markAnimationEnd = function markAnimationEnd(state) {
isAnimationEnd.current = state;
forceUpdate({});
};
var canCloseByEsc = false;
var canCloseByMask = false;
var closeable = false;
var closeModeArray = Array.isArray(closeMode) ? closeMode : [closeMode];
closeModeArray.forEach(function (mode) {
switch (mode) {
case 'esc':
canCloseByEsc = true;
break;
case 'mask':
canCloseByMask = true;
break;
case 'close':
closeable = true;
break;
}
});
// visible 受控
(0, _react.useEffect)(function () {
if ('visible' in props) {
setVisible(pvisible);
}
}, [pvisible]);
// 打开遮罩后 document.body 滚动处理
(0, _react.useEffect)(function () {
if (visible && hasMask) {
var _style = {
overflow: 'hidden'
};
if (_util.dom.hasScroll(document.body)) {
var scrollWidth = _util.dom.scrollbar().width;
if (scrollWidth) {
_style.paddingRight = _util.dom.getStyle(document.body, 'paddingRight') + _util.dom.scrollbar().width + 'px';
}
}
locker.current = _scrollLocker2.default.lock(document.body, _style);
}
}, [visible && hasMask]);
var handleClose = function handleClose(targetType, e) {
setVisibleOverlayToParent(uuid, null);
typeof onClose === 'function' && onClose(targetType, e);
};
var keydownEvent = function keydownEvent(e) {
if (e.keyCode === 27 && canCloseByEsc && !childIDMap.current.size) {
handleClose('esc', e);
}
};
// esc 键盘事件处理
(0, _react.useEffect)(function () {
if (visible && canCloseByEsc) {
document.body.addEventListener('keydown', keydownEvent, false);
return function () {
document.body.removeEventListener('keydown', keydownEvent, false);
};
}
}, [visible && canCloseByEsc]);
// 优化: 第一次加载并且 visible=false 的情况不挂载弹窗
(0, _react.useEffect)(function () {
!firstVisible && visible && setFirst(true);
}, [visible]);
// container 异步加载情况
(0, _react.useEffect)(function () {
if (!container) {
setTimeout(function () {
setContainer(getContainer());
});
}
}, [container]);
var handleExited = function handleExited() {
if (!isAnimationEnd.current) {
markAnimationEnd(true);
_util.dom.setStyle(wrapperRef.current, 'display', 'none');
_scrollLocker2.default.unlock(document.body, locker.current);
if (autoFocus && lastFocus.current) {
try {
lastFocus.current.focus();
} finally {
// ignore ...
}
lastFocus.current = null;
}
afterClose();
}
};
(0, _react.useEffect)(function () {
return function () {
handleExited();
};
}, []);
if (firstVisible === false || !container) {
return null;
}
if (!visible && !cache && isAnimationEnd.current) {
return null;
}
var handleCancel = function handleCancel(e) {
if (typeof onCancel === 'function') {
onCancel(e);
} else {
handleClose('cancelBtn', e);
}
};
var handleMaskClick = function handleMaskClick(e) {
if (!canCloseByMask) {
return;
}
if (e.type === 'click' && dialogRef.current) {
var dialogNode = _reactDom2.default.findDOMNode(dialogRef.current);
if (dialogNode && dialogNode.contains(e.target)) {
return;
}
}
handleClose('maskClick', e);
};
var handleEnter = function handleEnter() {
markAnimationEnd(false);
_util.dom.setStyle(wrapperRef.current, 'display', '');
};
var handleEntered = function handleEntered() {
if (autoFocus && dialogRef.current && dialogRef.current.bodyNode) {
var focusableNodes = _util.focus.getFocusNodeList(dialogRef.current.bodyNode);
if (focusableNodes.length > 0 && focusableNodes[0]) {
lastFocus.current = document.activeElement;
focusableNodes[0].focus();
}
}
setVisibleOverlayToParent(uuid, wrapperRef.current);
};
var wrapperCls = (0, _classnames2.default)((_classNames = {}, _classNames[prefix + 'overlay-wrapper'] = true, _classNames.opened = visible, _classNames));
var dialogCls = (0, _classnames2.default)((_classNames2 = {}, _classNames2[prefix + 'dialog-v2'] = true, _classNames2[className] = !!className, _classNames2));
var topStyle = {};
if (centered) {
// 兼容 minMargin
if (!top && !bottom && minMargin) {
topStyle.marginTop = minMargin;
topStyle.marginBottom = minMargin;
} else {
top && (topStyle.marginTop = top);
bottom && (topStyle.marginBottom = bottom);
}
} else {
top && (topStyle.top = top);
bottom && (topStyle.paddingBottom = bottom);
}
var maxHeight = void 0;
if (overflowScroll) {
maxHeight = 'calc(100vh - ' + (top + bottom) + 'px)';
}
var timeout = {
appear: 300,
enter: 300,
exit: 250
};
var inner = _react2.default.createElement(
_animate2.default.OverlayAnimate,
{
visible: visible,
animation: animation,
timeout: timeout,
onEnter: handleEnter,
onEntered: handleEntered,
onExited: handleExited
},
_react2.default.createElement(
_inner2.default,
(0, _extends3.default)({}, others, {
style: centered ? (0, _extends3.default)({}, topStyle, style) : style,
v2: true,
ref: dialogRef,
prefix: prefix,
className: dialogCls,
title: title,
footer: footer,
footerAlign: footerAlign,
footerActions: footerActions,
onOk: visible ? onOk : noop,
onCancel: visible ? handleCancel : noop,
okProps: okProps,
cancelProps: cancelProps,
locale: locale,
closeable: closeable,
rtl: rtl,
onClose: function onClose() {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return handleClose.apply(undefined, ['closeClick'].concat(args));
},
closeIcon: closeIcon,
height: height,
maxHeight: maxHeight,
width: width
}),
children
)
);
if (typeof dialogRender === 'function') {
inner = dialogRender(inner);
}
var innerWrapperCls = (0, _classnames2.default)((_classNames3 = {}, _classNames3[prefix + 'overlay-inner'] = true, _classNames3[prefix + 'dialog-wrapper'] = true, _classNames3[prefix + 'dialog-centered'] = centered, _classNames3));
var getVisibleOverlayFromChild = function getVisibleOverlayFromChild(id, node) {
if (node) {
childIDMap.current.set(id, node);
} else {
childIDMap.current.delete(id);
}
// 让父级也感知
setVisibleOverlayToParent(id, node);
};
return _react2.default.createElement(
OverlayContext.Provider,
{
value: (0, _extends3.default)({}, otherContext, {
setVisibleOverlayToParent: getVisibleOverlayFromChild
})
},
_reactDom2.default.createPortal(_react2.default.createElement(
'div',
{ className: wrapperCls, style: wrapperStyle, ref: wrapperRef },
hasMask ? _react2.default.createElement(
_animate2.default.OverlayAnimate,
{
visible: visible,
animation: animation ? { in: 'fadeIn', out: 'fadeOut' } : false,
timeout: timeout,
unmountOnExit: true
},
_react2.default.createElement('div', { className: prefix + 'overlay-backdrop' })
) : null,
_react2.default.createElement(
'div',
{ className: innerWrapperCls, onClick: handleMaskClick },
centered ? inner : _react2.default.createElement(
'div',
{ style: topStyle, className: prefix + 'dialog-inner-wrapper' },
inner
)
)
), container)
);
};
exports.default = Dialog;
module.exports = exports['default'];