choerodon-ui
Version:
An enterprise-class UI design language and React-based implementation
739 lines (624 loc) • 20.8 kB
JavaScript
import _extends from "@babel/runtime/helpers/extends";
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
import _objectSpread from "@babel/runtime/helpers/objectSpread2";
import _regeneratorRuntime from "@babel/runtime/regenerator";
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
import _createClass from "@babel/runtime/helpers/createClass";
import _inherits from "@babel/runtime/helpers/inherits";
import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
function _createSuper(Derived) {
function isNativeReflectConstruct() {
if (typeof Reflect === "undefined" || !Reflect.construct) return false;
if (Reflect.construct.sham) return false;
if (typeof Proxy === "function") return true;
try {
Date.prototype.toString.call(Reflect.construct(Date, [], function () {}));
return true;
} catch (e) {
return false;
}
}
return function () {
var Super = _getPrototypeOf(Derived),
result;
if (isNativeReflectConstruct()) {
var NewTarget = _getPrototypeOf(this).constructor;
result = Reflect.construct(Super, arguments, NewTarget);
} else {
result = Super.apply(this, arguments);
}
return _possibleConstructorReturn(this, result);
};
}
import { __decorate } from "tslib";
import React, { Component } from 'react';
import { createPortal, render } from 'react-dom';
import { action, computed, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import findLast from 'lodash/findLast';
import noop from 'lodash/noop';
import EventManager from '../../../es/_util/EventManager';
import measureScrollbar from '../../../es/_util/measureScrollbar';
import { pxToRem } from '../../../es/_util/UnitConvertor';
import warning from '../../../es/_util/warning';
import { getConfig, getProPrefixCls } from '../../../es/configure';
import ModalManager from '../modal-manager';
import Modal from '../modal/Modal';
import Animate from '../animate';
import Mask from './Mask';
import { stopEvent } from '../_util/EventManager';
import { suffixCls } from '../modal/utils';
import { getDocument, getMousePosition } from '../_util/DocumentUtils';
var containerInstances = ModalManager.containerInstances;
function getArrayIndex(array, index) {
if (array.length > index) {
return array[index];
}
return 0;
}
function getRoot() {
var root = ModalManager.root;
if (typeof window !== 'undefined') {
var doc = getDocument(window);
if (root) {
if (!root.parentNode) {
doc.body.appendChild(root);
}
} else {
root = doc.createElement('div');
root.className = "".concat(getProPrefixCls(suffixCls), "-container");
doc.body.appendChild(root);
ModalManager.root = root;
}
}
return root;
}
/**
* 判断body是否有滚动条
*
* @returns {boolean}
*/
function hasScrollBar(body) {
var scrollHeight = body.scrollHeight,
clientHeight = body.clientHeight;
return scrollHeight > clientHeight;
}
function hideBodyScrollBar(body) {
var style = body.style;
if (!ModalManager.defaultBodyStyle) {
ModalManager.defaultBodyStyle = {
overflow: style.overflow,
paddingRight: style.paddingRight
};
style.overflow = 'hidden';
if (hasScrollBar(body)) {
style.paddingRight = pxToRem(measureScrollbar()) || '';
}
}
}
function showBodyScrollBar(body) {
var style = body.style;
if (ModalManager.defaultBodyStyle) {
var _ModalManager$default = ModalManager.defaultBodyStyle,
overflow = _ModalManager$default.overflow,
paddingRight = _ModalManager$default.paddingRight;
ModalManager.defaultBodyStyle = undefined;
style.overflow = overflow;
style.paddingRight = paddingRight;
}
}
var ModalContainer =
/*#__PURE__*/
function (_Component) {
_inherits(ModalContainer, _Component);
var _super = _createSuper(ModalContainer);
function ModalContainer(props, context) {
var _this;
_classCallCheck(this, ModalContainer);
_this = _super.call(this, props, context);
_this.state = {
modals: []
};
_this.saveMount = function (mount) {
if (mount) {
_this.setState({
mount: mount
});
}
};
_this.handleAnimationEnd = function (modalKey, isEnter) {
if (!isEnter) {
var modals = _this.state.modals;
var index = _this.findIndex(modalKey);
if (index !== -1) {
var _props = modals[index];
modals.splice(index, 1);
if (!_props.destroyOnClose) {
modals.unshift(_props);
}
if (_props.afterClose) {
_props.afterClose();
}
_this.updateModals(modals);
}
}
};
_this.handleMaskClick =
/*#__PURE__*/
_asyncToGenerator(
/*#__PURE__*/
_regeneratorRuntime.mark(function _callee() {
var modals, modal, _modal$close, close, _modal$onCancel, onCancel, _modal$maskClosable, maskClosable, ret;
return _regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
modals = _this.state.modals;
modal = findLast(modals, function (_ref2) {
var hidden = _ref2.hidden;
return !hidden;
});
if (!modal) {
_context.next = 9;
break;
}
_modal$close = modal.close, close = _modal$close === void 0 ? noop : _modal$close, _modal$onCancel = modal.onCancel, onCancel = _modal$onCancel === void 0 ? noop : _modal$onCancel, _modal$maskClosable = modal.maskClosable, maskClosable = _modal$maskClosable === void 0 ? getConfig('modalMaskClosable') : _modal$maskClosable;
if (!maskClosable) {
_context.next = 9;
break;
}
_context.next = 7;
return onCancel();
case 7:
ret = _context.sent;
if (ret !== false) {
close();
}
case 9:
case "end":
return _context.stop();
}
}
}, _callee);
}));
runInAction(function () {
_this.maskHidden = true;
_this.drawerOffsets = {
'slide-up': [],
'slide-right': [],
'slide-down': [],
'slide-left': []
};
_this.top();
var doc = typeof window === 'undefined' ? undefined : document;
if (doc && !ModalManager.mousePositionEventBound.has(doc)) {
new EventManager(doc).addEventListener('click', function (e) {
ModalManager.mousePosition = getMousePosition(e.clientX, e.clientY, window); // 100ms 内发生过点击事件,则从点击位置动画展示
// 否则直接 zoom 展示
// 这样可以兼容非点击方式展开
setTimeout(function () {
return ModalManager.mousePosition = undefined;
}, 100);
}, true);
ModalManager.mousePositionEventBound.add(doc);
}
});
return _this;
}
_createClass(ModalContainer, [{
key: "top",
value: function top() {
ModalManager.addInstance(this);
return this;
}
}, {
key: "componentDidUpdate",
value: function componentDidUpdate(prevProps) {
var location = prevProps.location;
var currentLocation = this.props.location;
if (location && currentLocation && location.pathname !== currentLocation.pathname) {
ModalManager.clear(true);
}
}
}, {
key: "componentWillUnmount",
value: function componentWillUnmount() {
var modals = this.state.modals;
ModalManager.removeInstance(this);
var current = ModalManager.containerInstances[0];
if (current && modals.length) {
current.mergeModals(modals.reduce(function (list, modal) {
return modal.__deprecate__ && (!modal.hidden || !modal.destroyOnClose) ? list.concat(_objectSpread({}, modal, {
transitionAppear: false
})) : list;
}, []));
}
}
}, {
key: "updateModals",
value: function updateModals(modals) {
this.top();
var maskHidden = true;
var drawerOffsets = {
'slide-up': [],
'slide-right': [],
'slide-down': [],
'slide-left': []
};
modals.slice().reverse().forEach(function (_ref3) {
var hidden = _ref3.hidden,
drawer = _ref3.drawer,
drawerOffset = _ref3.drawerOffset,
drawerTransitionName = _ref3.drawerTransitionName;
if (!hidden) {
maskHidden = false;
if (drawer && drawerTransitionName) {
var offsets = drawerOffsets[drawerTransitionName];
var offset = offsets[0] || 0;
offsets.unshift(offset + (drawerOffset || 0));
}
}
});
this.drawerOffsets = drawerOffsets;
this.maskHidden = maskHidden; // modals.every(({ hidden }) => hidden);
this.setState({
modals: modals
});
}
}, {
key: "mergeModals",
value: function mergeModals(newModals) {
var modals = this.state.modals;
var map = new Map();
modals.forEach(function (modal) {
if (modal.key) {
map.set(modal.key, modal);
}
});
newModals.forEach(function (modal) {
if (modal.key) {
map.set(modal.key, modal);
}
});
this.updateModals(_toConsumableArray(map.values()));
}
}, {
key: "findIndex",
value: function findIndex(modalKey) {
var modals = this.state.modals;
return modals.findIndex(function (_ref4) {
var key = _ref4.key;
return key === modalKey;
});
}
}, {
key: "open",
value: function open(props) {
var modals = this.state.modals;
if (!props.key) {
props.key = ModalManager.getKey();
warning(!!props.destroyOnClose, "The modal which opened has no key, please provide a key or set the `destroyOnClose` as true.");
} else {
var index = this.findIndex(props.key);
if (index !== -1) {
modals.splice(index, 1);
}
}
modals.push(_objectSpread({}, props, {
hidden: false
}));
this.updateModals(modals);
}
}, {
key: "close",
value: function close(props) {
var modals = this.state.modals;
var target = modals.find(function (_ref5) {
var key = _ref5.key;
return key === props.key;
});
if (target) {
_extends(target, props, {
hidden: true
});
this.updateModals(modals);
}
}
}, {
key: "update",
value: function update(props) {
var originModals = this.state.modals;
var modals = _toConsumableArray(originModals);
if (props.key) {
var index = this.findIndex(props.key);
if (index !== -1) {
modals[index] = _objectSpread({}, modals[index], {}, props);
this.updateModals(modals);
}
}
}
}, {
key: "clear",
value: function clear(closeByLocationChange) {
var modals = this.state.modals;
this.updateModals(modals.map(function (modal) {
return closeByLocationChange && !modal.closeOnLocationChange ? modal : _objectSpread({}, modal, {
destroyOnClose: true,
hidden: true
});
}));
}
}, {
key: "getModalWidth",
value: function getModalWidth(modal) {
return modal && modal.style && modal.style.width || 520;
}
}, {
key: "getComponent",
value: function getComponent(mount) {
var _this2 = this;
var hidden = this.maskHidden,
isTop = this.isTop,
drawerOffsets = this.drawerOffsets,
baseOffsets = this.baseOffsets;
var modals = this.state.modals;
var indexes = {
'slide-up': 1,
'slide-right': 1,
'slide-down': 1,
'slide-left': 1
};
var activeModal;
var maskTransition = true;
var items = modals.map(function (props, index) {
var _props$drawerTransiti = props.drawerTransitionName,
drawerTransitionName = _props$drawerTransiti === void 0 ? getConfig('drawerTransitionName') : _props$drawerTransiti,
drawer = props.drawer,
key = props.key,
_props$transitionAppe = props.transitionAppear,
transitionAppear = _props$transitionAppe === void 0 ? true : _props$transitionAppe;
var style = _objectSpread({}, props.style);
if (drawer && drawerTransitionName) {
var i = indexes[drawerTransitionName];
indexes[drawerTransitionName] += 1;
var offset = getArrayIndex(drawerOffsets[drawerTransitionName], i) + baseOffsets[drawerTransitionName];
if (offset) {
switch (drawerTransitionName) {
case 'slide-up':
style.marginTop = offset;
break;
case 'slide-down':
style.marginBottom = offset;
break;
case 'slide-left':
style.marginLeft = offset;
break;
default:
style.marginRight = offset;
}
}
}
var active = isTop && index === modals.length - 1;
if (active) {
activeModal = props;
}
if (transitionAppear === false) {
maskTransition = false;
}
return React.createElement(Animate, {
key: key,
component: "div",
// UED 用类名判断
className: props.drawer ? "".concat(getProPrefixCls(suffixCls), "-container-drawer") : "".concat(getProPrefixCls(suffixCls), "-container-pristine"),
transitionAppear: transitionAppear,
transitionName: drawer ? drawerTransitionName : 'zoom',
hiddenProp: "hidden",
onEnd: _this2.handleAnimationEnd
}, React.createElement(Modal, _extends({
key: key,
mousePosition: ModalManager.mousePosition
}, props, {
style: style,
active: active
})));
});
var animationProps = {};
if (mount && mount.ownerDocument) {
var body = mount.ownerDocument.body;
if (containerInstances.every(function (instance) {
return instance.maskHidden;
})) {
animationProps.onEnd = function () {
return showBodyScrollBar(body);
};
} else {
hideBodyScrollBar(body);
}
}
var eventProps = {};
if (activeModal && activeModal.mask) {
var _activeModal = activeModal,
_activeModal$maskClos = _activeModal.maskClosable,
maskClosable = _activeModal$maskClos === void 0 ? getConfig('modalMaskClosable') : _activeModal$maskClos;
if (maskClosable === 'dblclick') {
eventProps.onDoubleClick = this.handleMaskClick;
} else {
eventProps.onClick = this.handleMaskClick;
}
}
return React.createElement(React.Fragment, null, React.createElement(Animate, _extends({
component: "",
transitionAppear: true,
transitionName: maskTransition ? 'fade' : undefined,
hiddenProp: "hidden"
}, animationProps), activeModal && activeModal.mask ? React.createElement(Mask, _extends({
style: activeModal.maskStyle,
className: activeModal.maskClassName,
hidden: hidden
}, eventProps, {
onMouseDown: stopEvent
})) : React.createElement("div", {
hidden: hidden
})), items, !mount && React.createElement("span", {
ref: this.saveMount
}));
}
}, {
key: "getContainer",
value: function getContainer() {
var getModalContainer = this.props.getContainer;
if (typeof getModalContainer === 'function') {
return getModalContainer();
}
return getModalContainer;
}
}, {
key: "render",
value: function render() {
var getModalContainer = this.props.getContainer;
if (getModalContainer === false) {
var _mount = this.state.mount;
return this.getComponent(_mount);
}
var mount = this.getContainer();
if (mount) {
return createPortal(this.getComponent(mount), mount);
}
return null;
}
}, {
key: "baseOffsets",
get: function get() {
var _this3 = this;
var offsets = {
'slide-up': 0,
'slide-right': 0,
'slide-down': 0,
'slide-left': 0
};
containerInstances.some(function (instance) {
if (instance === _this3) {
return true;
}
var drawerOffsets = instance.drawerOffsets,
maskHidden = instance.maskHidden;
if (!maskHidden) {
offsets['slide-up'] += getArrayIndex(drawerOffsets['slide-up'], 0);
offsets['slide-right'] += getArrayIndex(drawerOffsets['slide-right'], 0);
offsets['slide-down'] += getArrayIndex(drawerOffsets['slide-down'], 0);
offsets['slide-left'] += getArrayIndex(drawerOffsets['slide-left'], 0);
}
return false;
});
return offsets;
}
}, {
key: "isTop",
get: function get() {
var _this4 = this;
var is = true;
containerInstances.some(function (instance) {
if (instance !== _this4 && !instance.maskHidden) {
is = false;
return true;
}
if (instance === _this4) {
return true;
}
return false;
});
return is;
}
}]);
return ModalContainer;
}(Component);
ModalContainer.displayName = 'ModalContainer';
ModalContainer.defaultProps = {
getContainer: getRoot
};
__decorate([observable], ModalContainer.prototype, "maskHidden", void 0);
__decorate([observable], ModalContainer.prototype, "drawerOffsets", void 0);
__decorate([computed], ModalContainer.prototype, "baseOffsets", null);
__decorate([computed], ModalContainer.prototype, "isTop", null);
__decorate([action], ModalContainer.prototype, "top", null);
__decorate([action], ModalContainer.prototype, "updateModals", null);
ModalContainer = __decorate([observer], ModalContainer);
export default ModalContainer;
export function getContainer(loop) {
var length = containerInstances.length;
if (length) {
return containerInstances[0];
}
if (loop !== true) {
var root = getRoot();
if (root) {
render(React.createElement(ModalContainer, null), root);
}
return getContainer(true);
}
}
export function open(props) {
var container = getContainer();
function getCurrentContainer() {
return containerInstances.includes(container) ? container : getContainer();
}
function close(_x) {
return _close.apply(this, arguments);
}
function _close() {
_close = _asyncToGenerator(
/*#__PURE__*/
_regeneratorRuntime.mark(function _callee2(destroy) {
var _props2, _props2$onClose, onClose;
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
_props2 = props, _props2$onClose = _props2.onClose, onClose = _props2$onClose === void 0 ? noop : _props2$onClose;
_context2.next = 3;
return onClose();
case 3:
_context2.t0 = _context2.sent;
if (!(_context2.t0 !== false)) {
_context2.next = 6;
break;
}
if (destroy) {
getCurrentContainer().close(_objectSpread({}, props, {
destroyOnClose: true
}));
} else {
getCurrentContainer().close(props);
}
case 6:
case "end":
return _context2.stop();
}
}
}, _callee2);
}));
return _close.apply(this, arguments);
}
function update(newProps) {
getCurrentContainer().update(_objectSpread({}, newProps, {
key: props.key
}));
}
props = _objectSpread({
__deprecate__: true,
close: close,
update: update
}, Modal.defaultProps, {}, props);
container.open(props);
function show(newProps) {
getCurrentContainer().open(_objectSpread({}, props, {}, newProps));
}
return {
close: close,
open: show,
update: update
};
}
//# sourceMappingURL=ModalContainer.js.map