mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-03-02 23:37:04 +00:00
380 lines
12 KiB
JavaScript
380 lines
12 KiB
JavaScript
import _extends from 'babel-runtime/helpers/extends';
|
||
import _objectWithoutProperties from 'babel-runtime/helpers/objectWithoutProperties';
|
||
import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
|
||
import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn';
|
||
import _inherits from 'babel-runtime/helpers/inherits';
|
||
|
||
var _class, _temp;
|
||
|
||
import React, { Component, Children } from 'react';
|
||
import { findDOMNode } from 'react-dom';
|
||
import PropTypes from 'prop-types';
|
||
import { func, KEYCODE } from '../util';
|
||
import Overlay from './overlay';
|
||
|
||
var noop = func.noop,
|
||
makeChain = func.makeChain,
|
||
bindCtx = func.bindCtx;
|
||
|
||
/**
|
||
* Overlay.Popup
|
||
* @description 继承 Overlay 的 API,除非特别说明
|
||
* */
|
||
|
||
var Popup = (_temp = _class = function (_Component) {
|
||
_inherits(Popup, _Component);
|
||
|
||
function Popup(props) {
|
||
_classCallCheck(this, Popup);
|
||
|
||
var _this = _possibleConstructorReturn(this, _Component.call(this, props));
|
||
|
||
_this.state = {
|
||
visible: typeof props.visible === 'undefined' ? props.defaultVisible : props.visible
|
||
};
|
||
|
||
bindCtx(_this, ['handleTriggerClick', 'handleTriggerKeyDown', 'handleTriggerMouseEnter', 'handleTriggerMouseLeave', 'handleTriggerFocus', 'handleTriggerBlur', 'handleContentMouseEnter', 'handleContentMouseLeave', 'handleContentMouseDown', 'handleRequestClose', 'handleMaskMouseEnter', 'handleMaskMouseLeave']);
|
||
return _this;
|
||
}
|
||
|
||
Popup.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) {
|
||
if ('visible' in nextProps) {
|
||
this.setState({
|
||
visible: nextProps.visible
|
||
});
|
||
}
|
||
};
|
||
|
||
Popup.prototype.componentWillUnmount = function componentWillUnmount() {
|
||
var _this2 = this;
|
||
|
||
['_timer', '_hideTimer', '_showTimer'].forEach(function (time) {
|
||
_this2[time] && clearTimeout(_this2[time]);
|
||
});
|
||
};
|
||
|
||
Popup.prototype.handleVisibleChange = function handleVisibleChange(visible, type, e) {
|
||
if (!('visible' in this.props)) {
|
||
this.setState({
|
||
visible: visible
|
||
});
|
||
}
|
||
|
||
this.props.onVisibleChange(visible, type, e);
|
||
};
|
||
|
||
Popup.prototype.handleTriggerClick = function handleTriggerClick(e) {
|
||
if (this.state.visible && !this.props.canCloseByTrigger) {
|
||
return;
|
||
}
|
||
|
||
this.handleVisibleChange(!this.state.visible, 'fromTrigger', e);
|
||
};
|
||
|
||
Popup.prototype.handleTriggerKeyDown = function handleTriggerKeyDown(e) {
|
||
var triggerClickKeycode = this.props.triggerClickKeycode;
|
||
|
||
var keycodes = Array.isArray(triggerClickKeycode) ? triggerClickKeycode : [triggerClickKeycode];
|
||
if (keycodes.includes(e.keyCode)) {
|
||
e.preventDefault();
|
||
this.handleTriggerClick(e);
|
||
}
|
||
};
|
||
|
||
Popup.prototype.handleTriggerMouseEnter = function handleTriggerMouseEnter(e) {
|
||
var _this3 = this;
|
||
|
||
this._mouseNotFirstOnMask = false;
|
||
|
||
if (this._hideTimer) {
|
||
clearTimeout(this._hideTimer);
|
||
this._hideTimer = null;
|
||
}
|
||
if (this._showTimer) {
|
||
clearTimeout(this._showTimer);
|
||
this._showTimer = null;
|
||
}
|
||
if (!this.state.visible) {
|
||
this._showTimer = setTimeout(function () {
|
||
_this3.handleVisibleChange(true, 'fromTrigger', e);
|
||
}, this.props.delay);
|
||
}
|
||
};
|
||
|
||
Popup.prototype.handleTriggerMouseLeave = function handleTriggerMouseLeave(e, type) {
|
||
var _this4 = this;
|
||
|
||
if (this._showTimer) {
|
||
clearTimeout(this._showTimer);
|
||
this._showTimer = null;
|
||
}
|
||
if (this.state.visible) {
|
||
this._hideTimer = setTimeout(function () {
|
||
_this4.handleVisibleChange(false, type || 'fromTrigger', e);
|
||
}, this.props.delay);
|
||
}
|
||
};
|
||
|
||
Popup.prototype.handleTriggerFocus = function handleTriggerFocus(e) {
|
||
this.handleVisibleChange(true, 'fromTrigger', e);
|
||
};
|
||
|
||
Popup.prototype.handleTriggerBlur = function handleTriggerBlur(e) {
|
||
if (!this._isForwardContent) {
|
||
this.handleVisibleChange(false, 'fromTrigger', e);
|
||
}
|
||
this._isForwardContent = false;
|
||
};
|
||
|
||
Popup.prototype.handleContentMouseDown = function handleContentMouseDown() {
|
||
this._isForwardContent = true;
|
||
};
|
||
|
||
Popup.prototype.handleContentMouseEnter = function handleContentMouseEnter() {
|
||
clearTimeout(this._hideTimer);
|
||
};
|
||
|
||
Popup.prototype.handleContentMouseLeave = function handleContentMouseLeave(e) {
|
||
this.handleTriggerMouseLeave(e, 'fromContent');
|
||
};
|
||
|
||
Popup.prototype.handleMaskMouseEnter = function handleMaskMouseEnter() {
|
||
if (!this._mouseNotFirstOnMask) {
|
||
clearTimeout(this._hideTimer);
|
||
this._hideTimer = null;
|
||
this._mouseNotFirstOnMask = false;
|
||
}
|
||
};
|
||
|
||
Popup.prototype.handleMaskMouseLeave = function handleMaskMouseLeave() {
|
||
this._mouseNotFirstOnMask = true;
|
||
};
|
||
|
||
Popup.prototype.handleRequestClose = function handleRequestClose(type, e) {
|
||
this.handleVisibleChange(false, type, e);
|
||
};
|
||
|
||
Popup.prototype.renderTrigger = function renderTrigger() {
|
||
var _this5 = this;
|
||
|
||
var _props = this.props,
|
||
trigger = _props.trigger,
|
||
disabled = _props.disabled;
|
||
|
||
var props = {
|
||
key: 'trigger',
|
||
'aria-haspopup': true,
|
||
'aria-expanded': this.state.visible
|
||
};
|
||
|
||
if (!this.state.visible) {
|
||
props['aria-describedby'] = undefined;
|
||
}
|
||
|
||
if (!disabled) {
|
||
var triggerType = this.props.triggerType;
|
||
|
||
var triggerTypes = Array.isArray(triggerType) ? triggerType : [triggerType];
|
||
|
||
var _ref = trigger && trigger.props || {},
|
||
onClick = _ref.onClick,
|
||
onKeyDown = _ref.onKeyDown,
|
||
onMouseEnter = _ref.onMouseEnter,
|
||
onMouseLeave = _ref.onMouseLeave,
|
||
onFocus = _ref.onFocus,
|
||
onBlur = _ref.onBlur;
|
||
|
||
triggerTypes.forEach(function (triggerType) {
|
||
switch (triggerType) {
|
||
case 'click':
|
||
props.onClick = makeChain(_this5.handleTriggerClick, onClick);
|
||
props.onKeyDown = makeChain(_this5.handleTriggerKeyDown, onKeyDown);
|
||
break;
|
||
case 'hover':
|
||
props.onMouseEnter = makeChain(_this5.handleTriggerMouseEnter, onMouseEnter);
|
||
props.onMouseLeave = makeChain(_this5.handleTriggerMouseLeave, onMouseLeave);
|
||
break;
|
||
case 'focus':
|
||
props.onFocus = makeChain(_this5.handleTriggerFocus, onFocus);
|
||
props.onBlur = makeChain(_this5.handleTriggerBlur, onBlur);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
});
|
||
}
|
||
|
||
return trigger && React.cloneElement(trigger, props);
|
||
};
|
||
|
||
Popup.prototype.renderContent = function renderContent() {
|
||
var _this6 = this;
|
||
|
||
var _props2 = this.props,
|
||
children = _props2.children,
|
||
triggerType = _props2.triggerType;
|
||
|
||
var triggerTypes = Array.isArray(triggerType) ? triggerType : [triggerType];
|
||
var content = Children.only(children);
|
||
var _content$props = content.props,
|
||
onMouseDown = _content$props.onMouseDown,
|
||
onMouseEnter = _content$props.onMouseEnter,
|
||
onMouseLeave = _content$props.onMouseLeave;
|
||
|
||
var props = {
|
||
key: 'portal'
|
||
};
|
||
|
||
triggerTypes.forEach(function (triggerType) {
|
||
switch (triggerType) {
|
||
case 'focus':
|
||
props.onMouseDown = makeChain(_this6.handleContentMouseDown, onMouseDown);
|
||
break;
|
||
case 'hover':
|
||
props.onMouseEnter = makeChain(_this6.handleContentMouseEnter, onMouseEnter);
|
||
props.onMouseLeave = makeChain(_this6.handleContentMouseLeave, onMouseLeave);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
});
|
||
|
||
return React.cloneElement(content, props);
|
||
};
|
||
|
||
Popup.prototype.renderPortal = function renderPortal() {
|
||
var _this7 = this;
|
||
|
||
var _props3 = this.props,
|
||
target = _props3.target,
|
||
safeNode = _props3.safeNode,
|
||
followTrigger = _props3.followTrigger,
|
||
triggerType = _props3.triggerType,
|
||
hasMask = _props3.hasMask,
|
||
wrapperStyle = _props3.wrapperStyle,
|
||
others = _objectWithoutProperties(_props3, ['target', 'safeNode', 'followTrigger', 'triggerType', 'hasMask', 'wrapperStyle']);
|
||
|
||
var container = this.props.container;
|
||
|
||
var findTriggerNode = function findTriggerNode() {
|
||
return findDOMNode(_this7) || {};
|
||
};
|
||
var safeNodes = Array.isArray(safeNode) ? [].concat(safeNode) : [safeNode];
|
||
safeNodes.unshift(findTriggerNode);
|
||
|
||
var newWrapperStyle = wrapperStyle || {};
|
||
|
||
if (followTrigger) {
|
||
container = function container(trigger) {
|
||
return trigger && trigger.parentNode || trigger;
|
||
};
|
||
newWrapperStyle.position = 'relative';
|
||
}
|
||
|
||
if (triggerType === 'hover' && hasMask) {
|
||
others.onMaskMouseEnter = this.handleMaskMouseEnter;
|
||
others.onMaskMouseLeave = this.handleMaskMouseLeave;
|
||
}
|
||
|
||
return React.createElement(
|
||
Overlay,
|
||
_extends({}, others, {
|
||
key: 'overlay',
|
||
ref: function ref(overlay) {
|
||
return _this7.overlay = overlay;
|
||
},
|
||
visible: this.state.visible,
|
||
target: target || findTriggerNode,
|
||
container: container,
|
||
safeNode: safeNodes,
|
||
wrapperStyle: newWrapperStyle,
|
||
triggerType: triggerType,
|
||
hasMask: hasMask,
|
||
onRequestClose: this.handleRequestClose
|
||
}),
|
||
this.renderContent()
|
||
);
|
||
};
|
||
|
||
Popup.prototype.render = function render() {
|
||
return [this.renderTrigger(), this.renderPortal()];
|
||
};
|
||
|
||
return Popup;
|
||
}(Component), _class.propTypes = {
|
||
/**
|
||
* 弹层内容
|
||
*/
|
||
children: PropTypes.node,
|
||
/**
|
||
* 触发弹层显示或隐藏的元素
|
||
*/
|
||
trigger: PropTypes.element,
|
||
/**
|
||
* 触发弹层显示或隐藏的操作类型,可以是 'click','hover','focus',或者它们组成的数组,如 ['hover', 'focus']
|
||
*/
|
||
triggerType: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
|
||
/**
|
||
* 当 triggerType 为 click 时才生效,可自定义触发弹层显示的键盘码
|
||
*/
|
||
|
||
triggerClickKeycode: PropTypes.oneOfType([PropTypes.number, PropTypes.array]),
|
||
/**
|
||
* 弹层当前是否显示
|
||
*/
|
||
visible: PropTypes.bool,
|
||
/**
|
||
* 弹层默认是否显示
|
||
*/
|
||
defaultVisible: PropTypes.bool,
|
||
/**
|
||
* 弹层显示或隐藏时触发的回调函数
|
||
* @param {Boolean} visible 弹层是否显示
|
||
* @param {String} type 触发弹层显示或隐藏的来源 fromTrigger 表示由trigger的点击触发; docClick 表示由document的点击触发
|
||
* @param {Object} e DOM事件
|
||
*/
|
||
onVisibleChange: PropTypes.func,
|
||
/**
|
||
* 设置此属性,弹层无法显示或隐藏
|
||
*/
|
||
disabled: PropTypes.bool,
|
||
autoFit: PropTypes.bool,
|
||
/**
|
||
* 弹层显示或隐藏的延时时间(以毫秒为单位),在 triggerType 被设置为 hover 时生效
|
||
*/
|
||
delay: PropTypes.number,
|
||
/**
|
||
* trigger 是否可以关闭弹层
|
||
*/
|
||
canCloseByTrigger: PropTypes.bool,
|
||
/**
|
||
* 弹层定位的参照元素
|
||
* @default target 属性,即触发元素
|
||
*/
|
||
target: PropTypes.any,
|
||
safeNode: PropTypes.any,
|
||
/**
|
||
* 是否跟随trigger滚动
|
||
*/
|
||
followTrigger: PropTypes.bool,
|
||
container: PropTypes.any,
|
||
hasMask: PropTypes.bool,
|
||
wrapperStyle: PropTypes.object,
|
||
rtl: PropTypes.bool
|
||
}, _class.defaultProps = {
|
||
triggerType: 'hover',
|
||
triggerClickKeycode: [KEYCODE.SPACE, KEYCODE.ENTER],
|
||
defaultVisible: false,
|
||
onVisibleChange: noop,
|
||
disabled: false,
|
||
autoFit: false,
|
||
delay: 200,
|
||
canCloseByTrigger: true,
|
||
followTrigger: false,
|
||
container: function container() {
|
||
return document.body;
|
||
},
|
||
rtl: false
|
||
}, _temp);
|
||
Popup.displayName = 'Popup';
|
||
export { Popup as default }; |