zarm-web
Version:
基于 React 的桌面端UI库
547 lines (450 loc) • 20.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _react = _interopRequireDefault(require("react"));
var _reactDom = require("react-dom");
var _classnames2 = _interopRequireDefault(require("classnames"));
var _events = _interopRequireDefault(require("../utils/events"));
var _throttle = _interopRequireDefault(require("../utils/throttle"));
var _dom = _interopRequireDefault(require("../utils/dom"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
function getOffsetElem(elem) {
var parentElem = elem.parentNode;
while (parentElem) {
if (parentElem instanceof HTMLElement) {
if (parentElem.style.position === 'fixed' || window.getComputedStyle(parentElem).position === 'fixed' || parentElem === document.body) {
return parentElem;
}
parentElem = parentElem.parentNode;
} else {
break;
}
}
return document.body;
} // 获取元素坐标
function getElemPosition(elem) {
var relativeElem = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document.body;
var parentElem = elem.offsetParent;
var position = {
top: elem.offsetTop,
left: elem.offsetLeft
};
while (relativeElem.contains(parentElem)) {
if (parentElem instanceof HTMLElement) {
if (relativeElem === parentElem) {
return position;
}
position.top += parentElem.offsetTop;
position.left += parentElem.offsetLeft;
parentElem = parentElem.offsetParent;
}
}
return position;
} // todo [首次不创建]
var placementMap = {
bottomLeft: 5,
bottomCenter: 9,
bottomRight: 17,
topLeft: 6,
topCenter: 10,
topRight: 18
};
var defaultProps = {
visible: false,
isRadius: false,
hideOnClick: true,
prefixCls: 'ui-dropdown',
placement: 'bottomLeft',
trigger: 'click',
disabled: false,
zIndex: 2018
};
var mountedInstance = new Set();
var Dropdown =
/*#__PURE__*/
function (_React$Component) {
_inherits(Dropdown, _React$Component);
_createClass(Dropdown, null, [{
key: "hide",
// 隐藏全部的Dropdown
value: function hide() {
mountedInstance.forEach(function (instance) {
instance.props.onVisibleChange(false);
});
} // 显示全部的Dropdown 除了disable
}, {
key: "show",
value: function show() {
mountedInstance.forEach(function (instance) {
instance.props.onVisibleChange(true);
});
} // 重新计算Dropdown定位
}, {
key: "reposition",
value: function reposition() {
mountedInstance.forEach(function (instance) {
instance.reposition();
});
} // 用于存储已生成的全部实例的Set
// private static mountedInstance: Set<Dropdown> = new Set();
// 根据定位点计算定位信息
}, {
key: "calcPosition",
value: function calcPosition() {
var placement = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'bottomLeft';
var width = arguments.length > 1 ? arguments[1] : undefined;
var height = arguments.length > 2 ? arguments[2] : undefined;
var dropWidth = arguments.length > 3 ? arguments[3] : undefined;
var dropHeight = arguments.length > 4 ? arguments[4] : undefined;
var top = 0;
var left = 0;
var placementCode = placementMap[placement];
if (placementCode & 1) {
top = height;
} else if (placementCode & 2) {
top = -dropHeight;
}
if (placementCode & 8) {
left = (width - dropWidth) / 2;
} else if (placementCode & 16) {
left = width - dropWidth;
}
return {
top: top,
left: left
};
}
}, {
key: "createDivBox",
value: function createDivBox() {
var div = document.createElement('div');
div.style.setProperty('position', 'absolute');
div.style.setProperty('left', '0');
div.style.setProperty('top', '0');
div.style.setProperty('width', 'auto');
return div;
}
}]);
function Dropdown(props) {
var _this;
_classCallCheck(this, Dropdown);
_this = _possibleConstructorReturn(this, _getPrototypeOf(Dropdown).call(this, props));
_this.state = {
visible: _this.props.visible,
positionInfo: {
left: 0,
top: 0
},
animationState: null,
// eslint-disable-next-line react/no-unused-state
animationProps: null
};
_this.DropdownContentEvent = {};
_this.triggerEvent = {};
_this.onWindowResize = void 0;
_this.onParentScroll = void 0;
_this.div = Dropdown.createDivBox();
_this.triggerBox = void 0;
_this.DropdownContent = void 0;
_this.popContainer = void 0;
_this.scrollParent = void 0;
_this.isHoverOnDropContent = false;
_this.hiddenTimer = void 0;
_this.triggerBoxOffsetHeight = void 0;
_this.setEventObject = function (triggerType) {
if (triggerType === 'hover') {
_this.DropdownContentEvent.onMouseLeave = _this.onDropdownContentMouseLeave;
_this.DropdownContentEvent.onMouseEnter = _this.onDropdownContentMouseEnter;
_this.triggerEvent.onMouseEnter = _this.onTrigger;
_this.triggerEvent.onMouseLeave = _this.onTrigger;
} else if (triggerType === 'click') {
_this.triggerEvent.onClick = _this.onTrigger;
} else if (triggerType === 'contextMenu') {
_this.triggerEvent.onContextMenu = _this.onTrigger;
}
};
_this.onTrigger = function (e) {
// 禁用状态不做任何处理
if (_this.props.disabled === true) {
return;
}
var type = e.type;
if (type === 'click') {
_this.props.onVisibleChange(!_this.props.visible);
} else if (type === 'contextmenu') {
e.preventDefault();
_this.props.onVisibleChange(!_this.props.visible);
} else if (type === 'mouseenter') {
if (_this.props.visible === false) {
_this.props.onVisibleChange(true);
} else if (_this.hiddenTimer) {
clearTimeout(_this.hiddenTimer);
}
} else if (type === 'mouseleave') {
// 缓冲一点一时间给间隙
_this.hiddenTimer = setTimeout(function () {
// 若当前鼠标在弹出层上 则不消失
if (_this.isHoverOnDropContent === false) {
_this.props.onVisibleChange(false);
}
}, 300);
}
};
_this.onDropdownContentMouseEnter = function () {
// 重新放置时候取消隐藏
if (_this.hiddenTimer) {
clearTimeout(_this.hiddenTimer);
}
if (_this.isHoverOnDropContent === false) {
_this.isHoverOnDropContent = true;
}
};
_this.onDropdownContentMouseLeave = function () {
_this.isHoverOnDropContent = false; // 给消失一点缓冲时间
_this.hiddenTimer = setTimeout(function () {
_this.props.onVisibleChange(false);
}, 300);
};
_this.onDocumentClick = function (e) {
var _this$props = _this.props,
hideOnClick = _this$props.hideOnClick,
onVisibleChange = _this$props.onVisibleChange;
if (_this.props.disabled === true || _this.state.visible === false) {
return;
}
var target = e.target; // eslint-disable-next-line no-empty
if (_this.div.contains(target) || _this.triggerBox.contains(target)) {} else {
// eslint-disable-next-line no-lonely-if
if (hideOnClick) {
onVisibleChange(false);
}
}
};
_this.reposition = function () {
if (!_this.state.visible || _this.props.disabled) {
return;
}
var _this$getDropdownPosi = _this.getDropdownPosition(_this.props.placement),
left = _this$getDropdownPosi.left,
top = _this$getDropdownPosi.top;
if (left === _this.state.positionInfo.left && top === _this.state.positionInfo.top) {
return;
}
_this.setState({
positionInfo: {
left: left,
top: top
}
});
};
_this.onAniEnd = function (e) {
if (e.type.toLowerCase().endsWith('animationend')) {
_this.setState({
visible: _this.props.visible,
animationState: null
});
}
};
_this.setEventObject(props.trigger);
_this.onWindowResize = (0, _throttle.default)(_this.reposition, 300);
_this.onParentScroll = _this.reposition;
return _this;
}
_createClass(Dropdown, [{
key: "componentDidMount",
value: function componentDidMount() {
var _this$props2 = this.props,
getPopupContainer = _this$props2.getPopupContainer,
visible = _this$props2.visible,
placement = _this$props2.placement;
if (typeof getPopupContainer === 'function') {
this.popContainer = getPopupContainer();
this.popContainer.style.position = 'relative';
} else {
this.popContainer = getOffsetElem(this.triggerBox);
}
this.popContainer.appendChild(this.div);
if (visible) {
var _this$getDropdownPosi2 = this.getDropdownPosition(placement),
left = _this$getDropdownPosi2.left,
top = _this$getDropdownPosi2.top;
this.setState({
positionInfo: {
left: left,
top: top
}
});
}
this.scrollParent = _dom.default.getScrollParent(this.triggerBox);
_events.default.on(document, 'click', this.onDocumentClick);
_events.default.on(window, 'resize', this.onWindowResize);
_events.default.on(this.scrollParent, 'scroll', this.onParentScroll); // 存储当前实例,方便静态方法统一处理
mountedInstance.add(this);
this.triggerBoxOffsetHeight = this.triggerBox.offsetHeight;
}
}, {
key: "componentWillReceiveProps",
value: function componentWillReceiveProps(nextProps) {
var _this2 = this;
var _this$props3 = this.props,
visible = _this$props3.visible,
trigger = _this$props3.trigger;
if (nextProps.visible === visible) {
return;
}
if (nextProps.trigger !== trigger) {
this.setEventObject(nextProps.trigger);
}
if (nextProps.visible) {
this.enter(function () {
if (nextProps.visible) {
_this2.setState({
positionInfo: _this2.getDropdownPosition(nextProps.placement)
});
}
});
} else {
this.leave();
}
}
}, {
key: "componentDidUpdate",
value: function componentDidUpdate() {
var height = this.triggerBox.offsetHeight;
if (height !== this.triggerBoxOffsetHeight) {
this.reposition();
this.triggerBoxOffsetHeight = height;
}
}
}, {
key: "componentWillUnmount",
value: function componentWillUnmount() {
var _this3 = this;
_events.default.off(document, 'click', this.onDocumentClick);
_events.default.off(window, 'click', this.onWindowResize);
_events.default.off(this.scrollParent, 'scroll', this.onParentScroll);
mountedInstance.delete(this);
setTimeout(function () {
_this3.popContainer.removeChild(_this3.div);
});
} // 根据trigger方式不同绑定事件
}, {
key: "getDropdownPosition",
// 获取元素的定位信息
value: function getDropdownPosition() {
var placement = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'bottomLeft';
var rectInfo = getElemPosition(this.triggerBox, this.popContainer);
var _this$DropdownContent = this.DropdownContent,
offsetWidth = _this$DropdownContent.offsetWidth,
offsetHeight = _this$DropdownContent.offsetHeight;
var computerStyle = window.getComputedStyle(this.DropdownContent);
var marginTop = parseFloat(this.DropdownContent.style.marginTop || computerStyle.marginTop || '0');
var marginLeft = parseFloat(this.DropdownContent.style.marginLeft || computerStyle.marginLeft || '0');
var _Dropdown$calcPositio = Dropdown.calcPosition(placement, this.triggerBox.offsetWidth, this.triggerBox.offsetHeight, offsetWidth, offsetHeight),
top = _Dropdown$calcPositio.top,
left = _Dropdown$calcPositio.left;
var offset = placement.startsWith('bottom') ? 5 : -5;
var scrollLeft = 0;
var scrollTop = 0;
if (this.scrollParent !== this.popContainer && this.popContainer.contains(this.scrollParent)) {
scrollLeft = _dom.default.getScrollLeftValue(this.scrollParent);
scrollTop = _dom.default.getScrollTopValue(this.scrollParent);
}
return {
left: rectInfo.left + left - marginLeft - scrollLeft,
top: rectInfo.top + top - marginTop + offset - scrollTop
};
}
}, {
key: "enter",
value: function enter(callback) {
this.setState({
visible: true,
animationState: 'enter'
}, callback);
}
}, {
key: "leave",
value: function leave() {
this.setState({
visible: true,
animationState: 'leave'
});
}
}, {
key: "render",
value: function render() {
var _classnames,
_this4 = this;
var _this$props4 = this.props,
disabled = _this$props4.disabled,
children = _this$props4.children,
overlay = _this$props4.overlay,
className = _this$props4.className,
trigger = _this$props4.trigger,
prefixCls = _this$props4.prefixCls,
style = _this$props4.style,
isRadius = _this$props4.isRadius,
_this$props4$placemen = _this$props4.placement,
placement = _this$props4$placemen === void 0 ? 'bottomLeft' : _this$props4$placemen,
zIndex = _this$props4.zIndex,
notRenderInDisabledMode = _this$props4.notRenderInDisabledMode,
visible = _this$props4.visible,
hideOnClick = _this$props4.hideOnClick,
onVisibleChange = _this$props4.onVisibleChange,
getPopupContainer = _this$props4.getPopupContainer,
triggerBoxStyle = _this$props4.triggerBoxStyle,
others = _objectWithoutProperties(_this$props4, ["disabled", "children", "overlay", "className", "trigger", "prefixCls", "style", "isRadius", "placement", "zIndex", "notRenderInDisabledMode", "visible", "hideOnClick", "onVisibleChange", "getPopupContainer", "triggerBoxStyle"]);
var _this$state = this.state,
positionInfo = _this$state.positionInfo,
animationState = _this$state.animationState,
stateVisible = _this$state.visible; // 根据placement判断向上动画还是向下动画
var animationProps = placementMap[placement] & 1 ? 'scaleDown' : 'scaleUp';
var cls = (0, _classnames2.default)((_classnames = {}, _defineProperty(_classnames, prefixCls, true), _defineProperty(_classnames, "radius", 'radius' in this.props || isRadius), _defineProperty(_classnames, className, !!className), _defineProperty(_classnames, "".concat(animationProps, "-").concat(animationState), !!animationState), _classnames));
var dropdownBoxStyle = _objectSpread({
minWidth: this.triggerBox && this.triggerBox.offsetWidth || 0
}, style, {}, positionInfo, {
position: 'absolute',
animationDuration: '300ms',
// eslint-disable-next-line no-nested-ternary
display: disabled ? 'none' : stateVisible ? 'block' : 'none',
overflow: 'hidden',
zIndex: zIndex
});
return _react.default.createElement(_react.default.Fragment, null, _react.default.createElement("div", _extends({
className: "".concat(prefixCls, "-trigger-box"),
style: triggerBoxStyle,
ref: function ref(e) {
_this4.triggerBox = e;
}
}, this.triggerEvent), children), (0, _reactDom.createPortal)(_react.default.createElement("div", _extends({
onAnimationEnd: this.onAniEnd,
className: cls,
ref: function ref(e) {
_this4.DropdownContent = e;
},
style: dropdownBoxStyle
}, others, this.DropdownContentEvent), notRenderInDisabledMode && disabled ? null : overlay), this.div));
}
}]);
return Dropdown;
}(_react.default.Component);
exports.default = Dropdown;
Dropdown.defaultProps = defaultProps;