'use strict'; exports.__esModule = true; var _extends2 = require('babel-runtime/helpers/extends'); var _extends3 = _interopRequireDefault(_extends2); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _inherits2 = require('babel-runtime/helpers/inherits'); var _inherits3 = _interopRequireDefault(_inherits2); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _propTypes = require('prop-types'); var _propTypes2 = _interopRequireDefault(_propTypes); var _reactDom = require('react-dom'); var _reactLifecyclesCompat = require('react-lifecycles-compat'); var _contains = require('rc-util/lib/Dom/contains'); var _contains2 = _interopRequireDefault(_contains); var _addEventListener = require('rc-util/lib/Dom/addEventListener'); var _addEventListener2 = _interopRequireDefault(_addEventListener); var _ContainerRender = require('rc-util/lib/ContainerRender'); var _ContainerRender2 = _interopRequireDefault(_ContainerRender); var _Portal = require('rc-util/lib/Portal'); var _Portal2 = _interopRequireDefault(_Portal); var _classnames = require('classnames'); var _classnames2 = _interopRequireDefault(_classnames); var _utils = require('./utils'); var _Popup = require('./Popup'); var _Popup2 = _interopRequireDefault(_Popup); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } function noop() {} function returnEmptyString() { return ''; } function returnDocument() { return window.document; } var ALL_HANDLERS = ['onClick', 'onMouseDown', 'onTouchStart', 'onMouseEnter', 'onMouseLeave', 'onFocus', 'onBlur', 'onContextMenu']; var IS_REACT_16 = !!_reactDom.createPortal; var contextTypes = { rcTrigger: _propTypes2['default'].shape({ onPopupMouseDown: _propTypes2['default'].func }) }; var Trigger = function (_React$Component) { (0, _inherits3['default'])(Trigger, _React$Component); function Trigger(props) { (0, _classCallCheck3['default'])(this, Trigger); var _this = (0, _possibleConstructorReturn3['default'])(this, _React$Component.call(this, props)); _initialiseProps.call(_this); var popupVisible = void 0; if ('popupVisible' in props) { popupVisible = !!props.popupVisible; } else { popupVisible = !!props.defaultPopupVisible; } _this.state = { prevPopupVisible: popupVisible, popupVisible: popupVisible }; ALL_HANDLERS.forEach(function (h) { _this['fire' + h] = function (e) { _this.fireEvents(h, e); }; }); return _this; } Trigger.prototype.getChildContext = function getChildContext() { return { rcTrigger: { onPopupMouseDown: this.onPopupMouseDown } }; }; Trigger.prototype.componentDidMount = function componentDidMount() { this.componentDidUpdate({}, { popupVisible: this.state.popupVisible }); }; Trigger.prototype.componentDidUpdate = function componentDidUpdate(_, prevState) { var props = this.props; var state = this.state; var triggerAfterPopupVisibleChange = function triggerAfterPopupVisibleChange() { if (prevState.popupVisible !== state.popupVisible) { props.afterPopupVisibleChange(state.popupVisible); } }; if (!IS_REACT_16) { this.renderComponent(null, triggerAfterPopupVisibleChange); } // We must listen to `mousedown` or `touchstart`, edge case: // https://github.com/ant-design/ant-design/issues/5804 // https://github.com/react-component/calendar/issues/250 // https://github.com/react-component/trigger/issues/50 if (state.popupVisible) { var currentDocument = void 0; if (!this.clickOutsideHandler && (this.isClickToHide() || this.isContextMenuToShow())) { currentDocument = props.getDocument(); this.clickOutsideHandler = (0, _addEventListener2['default'])(currentDocument, 'mousedown', this.onDocumentClick); } // always hide on mobile if (!this.touchOutsideHandler) { currentDocument = currentDocument || props.getDocument(); this.touchOutsideHandler = (0, _addEventListener2['default'])(currentDocument, 'touchstart', this.onDocumentClick); } // close popup when trigger type contains 'onContextMenu' and document is scrolling. if (!this.contextMenuOutsideHandler1 && this.isContextMenuToShow()) { currentDocument = currentDocument || props.getDocument(); this.contextMenuOutsideHandler1 = (0, _addEventListener2['default'])(currentDocument, 'scroll', this.onContextMenuClose); } // close popup when trigger type contains 'onContextMenu' and window is blur. if (!this.contextMenuOutsideHandler2 && this.isContextMenuToShow()) { this.contextMenuOutsideHandler2 = (0, _addEventListener2['default'])(window, 'blur', this.onContextMenuClose); } return; } this.clearOutsideHandler(); }; Trigger.prototype.componentWillUnmount = function componentWillUnmount() { this.clearDelayTimer(); this.clearOutsideHandler(); clearTimeout(this.mouseDownTimeout); }; Trigger.getDerivedStateFromProps = function getDerivedStateFromProps(_ref, prevState) { var popupVisible = _ref.popupVisible; var newState = {}; if (popupVisible !== undefined && prevState.popupVisible !== popupVisible) { newState.popupVisible = popupVisible; newState.prevPopupVisible = prevState.popupVisible; } return newState; }; Trigger.prototype.getPopupDomNode = function getPopupDomNode() { // for test if (this._component && this._component.getPopupDomNode) { return this._component.getPopupDomNode(); } return null; }; Trigger.prototype.getPopupAlign = function getPopupAlign() { var props = this.props; var popupPlacement = props.popupPlacement, popupAlign = props.popupAlign, builtinPlacements = props.builtinPlacements; if (popupPlacement && builtinPlacements) { return (0, _utils.getAlignFromPlacement)(builtinPlacements, popupPlacement, popupAlign); } return popupAlign; }; /** * @param popupVisible Show or not the popup element * @param event SyntheticEvent, used for `pointAlign` */ Trigger.prototype.setPopupVisible = function setPopupVisible(popupVisible, event) { var alignPoint = this.props.alignPoint; var prevPopupVisible = this.state.popupVisible; this.clearDelayTimer(); if (prevPopupVisible !== popupVisible) { if (!('popupVisible' in this.props)) { this.setState({ popupVisible: popupVisible, prevPopupVisible: prevPopupVisible }); } this.props.onPopupVisibleChange(popupVisible); } // Always record the point position since mouseEnterDelay will delay the show if (alignPoint && event) { this.setPoint(event); } }; Trigger.prototype.delaySetPopupVisible = function delaySetPopupVisible(visible, delayS, event) { var _this2 = this; var delay = delayS * 1000; this.clearDelayTimer(); if (delay) { var point = event ? { pageX: event.pageX, pageY: event.pageY } : null; this.delayTimer = setTimeout(function () { _this2.setPopupVisible(visible, point); _this2.clearDelayTimer(); }, delay); } else { this.setPopupVisible(visible, event); } }; Trigger.prototype.clearDelayTimer = function clearDelayTimer() { if (this.delayTimer) { clearTimeout(this.delayTimer); this.delayTimer = null; } }; Trigger.prototype.clearOutsideHandler = function clearOutsideHandler() { if (this.clickOutsideHandler) { this.clickOutsideHandler.remove(); this.clickOutsideHandler = null; } if (this.contextMenuOutsideHandler1) { this.contextMenuOutsideHandler1.remove(); this.contextMenuOutsideHandler1 = null; } if (this.contextMenuOutsideHandler2) { this.contextMenuOutsideHandler2.remove(); this.contextMenuOutsideHandler2 = null; } if (this.touchOutsideHandler) { this.touchOutsideHandler.remove(); this.touchOutsideHandler = null; } }; Trigger.prototype.createTwoChains = function createTwoChains(event) { var childPros = this.props.children.props; var props = this.props; if (childPros[event] && props[event]) { return this['fire' + event]; } return childPros[event] || props[event]; }; Trigger.prototype.isClickToShow = function isClickToShow() { var _props = this.props, action = _props.action, showAction = _props.showAction; return action.indexOf('click') !== -1 || showAction.indexOf('click') !== -1; }; Trigger.prototype.isContextMenuToShow = function isContextMenuToShow() { var _props2 = this.props, action = _props2.action, showAction = _props2.showAction; return action.indexOf('contextMenu') !== -1 || showAction.indexOf('contextMenu') !== -1; }; Trigger.prototype.isClickToHide = function isClickToHide() { var _props3 = this.props, action = _props3.action, hideAction = _props3.hideAction; return action.indexOf('click') !== -1 || hideAction.indexOf('click') !== -1; }; Trigger.prototype.isMouseEnterToShow = function isMouseEnterToShow() { var _props4 = this.props, action = _props4.action, showAction = _props4.showAction; return action.indexOf('hover') !== -1 || showAction.indexOf('mouseEnter') !== -1; }; Trigger.prototype.isMouseLeaveToHide = function isMouseLeaveToHide() { var _props5 = this.props, action = _props5.action, hideAction = _props5.hideAction; return action.indexOf('hover') !== -1 || hideAction.indexOf('mouseLeave') !== -1; }; Trigger.prototype.isFocusToShow = function isFocusToShow() { var _props6 = this.props, action = _props6.action, showAction = _props6.showAction; return action.indexOf('focus') !== -1 || showAction.indexOf('focus') !== -1; }; Trigger.prototype.isBlurToHide = function isBlurToHide() { var _props7 = this.props, action = _props7.action, hideAction = _props7.hideAction; return action.indexOf('focus') !== -1 || hideAction.indexOf('blur') !== -1; }; Trigger.prototype.forcePopupAlign = function forcePopupAlign() { if (this.state.popupVisible && this._component && this._component.alignInstance) { this._component.alignInstance.forceAlign(); } }; Trigger.prototype.fireEvents = function fireEvents(type, e) { var childCallback = this.props.children.props[type]; if (childCallback) { childCallback(e); } var callback = this.props[type]; if (callback) { callback(e); } }; Trigger.prototype.close = function close() { this.setPopupVisible(false); }; Trigger.prototype.render = function render() { var _this3 = this; var popupVisible = this.state.popupVisible; var _props8 = this.props, children = _props8.children, forceRender = _props8.forceRender, alignPoint = _props8.alignPoint, className = _props8.className; var child = _react2['default'].Children.only(children); var newChildProps = { key: 'trigger' }; if (this.isContextMenuToShow()) { newChildProps.onContextMenu = this.onContextMenu; } else { newChildProps.onContextMenu = this.createTwoChains('onContextMenu'); } if (this.isClickToHide() || this.isClickToShow()) { newChildProps.onClick = this.onClick; newChildProps.onMouseDown = this.onMouseDown; newChildProps.onTouchStart = this.onTouchStart; } else { newChildProps.onClick = this.createTwoChains('onClick'); newChildProps.onMouseDown = this.createTwoChains('onMouseDown'); newChildProps.onTouchStart = this.createTwoChains('onTouchStart'); } if (this.isMouseEnterToShow()) { newChildProps.onMouseEnter = this.onMouseEnter; if (alignPoint) { newChildProps.onMouseMove = this.onMouseMove; } } else { newChildProps.onMouseEnter = this.createTwoChains('onMouseEnter'); } if (this.isMouseLeaveToHide()) { newChildProps.onMouseLeave = this.onMouseLeave; } else { newChildProps.onMouseLeave = this.createTwoChains('onMouseLeave'); } if (this.isFocusToShow() || this.isBlurToHide()) { newChildProps.onFocus = this.onFocus; newChildProps.onBlur = this.onBlur; } else { newChildProps.onFocus = this.createTwoChains('onFocus'); newChildProps.onBlur = this.createTwoChains('onBlur'); } var childrenClassName = (0, _classnames2['default'])(child && child.props && child.props.className, className); if (childrenClassName) { newChildProps.className = childrenClassName; } var trigger = _react2['default'].cloneElement(child, newChildProps); if (!IS_REACT_16) { return _react2['default'].createElement( _ContainerRender2['default'], { parent: this, visible: popupVisible, autoMount: false, forceRender: forceRender, getComponent: this.getComponent, getContainer: this.getContainer }, function (_ref2) { var renderComponent = _ref2.renderComponent; _this3.renderComponent = renderComponent; return trigger; } ); } var portal = void 0; // prevent unmounting after it's rendered if (popupVisible || this._component || forceRender) { portal = _react2['default'].createElement( _Portal2['default'], { key: 'portal', getContainer: this.getContainer, didUpdate: this.handlePortalUpdate }, this.getComponent() ); } return [trigger, portal]; }; return Trigger; }(_react2['default'].Component); Trigger.propTypes = { children: _propTypes2['default'].any, action: _propTypes2['default'].oneOfType([_propTypes2['default'].string, _propTypes2['default'].arrayOf(_propTypes2['default'].string)]), showAction: _propTypes2['default'].any, hideAction: _propTypes2['default'].any, getPopupClassNameFromAlign: _propTypes2['default'].any, onPopupVisibleChange: _propTypes2['default'].func, afterPopupVisibleChange: _propTypes2['default'].func, popup: _propTypes2['default'].oneOfType([_propTypes2['default'].node, _propTypes2['default'].func]).isRequired, popupStyle: _propTypes2['default'].object, prefixCls: _propTypes2['default'].string, popupClassName: _propTypes2['default'].string, className: _propTypes2['default'].string, popupPlacement: _propTypes2['default'].string, builtinPlacements: _propTypes2['default'].object, popupTransitionName: _propTypes2['default'].oneOfType([_propTypes2['default'].string, _propTypes2['default'].object]), popupAnimation: _propTypes2['default'].any, mouseEnterDelay: _propTypes2['default'].number, mouseLeaveDelay: _propTypes2['default'].number, zIndex: _propTypes2['default'].number, focusDelay: _propTypes2['default'].number, blurDelay: _propTypes2['default'].number, getPopupContainer: _propTypes2['default'].func, getDocument: _propTypes2['default'].func, forceRender: _propTypes2['default'].bool, destroyPopupOnHide: _propTypes2['default'].bool, mask: _propTypes2['default'].bool, maskClosable: _propTypes2['default'].bool, onPopupAlign: _propTypes2['default'].func, popupAlign: _propTypes2['default'].object, popupVisible: _propTypes2['default'].bool, defaultPopupVisible: _propTypes2['default'].bool, maskTransitionName: _propTypes2['default'].oneOfType([_propTypes2['default'].string, _propTypes2['default'].object]), maskAnimation: _propTypes2['default'].string, stretch: _propTypes2['default'].string, alignPoint: _propTypes2['default'].bool // Maybe we can support user pass position in the future }; Trigger.contextTypes = contextTypes; Trigger.childContextTypes = contextTypes; Trigger.defaultProps = { prefixCls: 'rc-trigger-popup', getPopupClassNameFromAlign: returnEmptyString, getDocument: returnDocument, onPopupVisibleChange: noop, afterPopupVisibleChange: noop, onPopupAlign: noop, popupClassName: '', mouseEnterDelay: 0, mouseLeaveDelay: 0.1, focusDelay: 0, blurDelay: 0.15, popupStyle: {}, destroyPopupOnHide: false, popupAlign: {}, defaultPopupVisible: false, mask: false, maskClosable: true, action: [], showAction: [], hideAction: [] }; var _initialiseProps = function _initialiseProps() { var _this4 = this; this.onMouseEnter = function (e) { var mouseEnterDelay = _this4.props.mouseEnterDelay; _this4.fireEvents('onMouseEnter', e); _this4.delaySetPopupVisible(true, mouseEnterDelay, mouseEnterDelay ? null : e); }; this.onMouseMove = function (e) { _this4.fireEvents('onMouseMove', e); _this4.setPoint(e); }; this.onMouseLeave = function (e) { _this4.fireEvents('onMouseLeave', e); _this4.delaySetPopupVisible(false, _this4.props.mouseLeaveDelay); }; this.onPopupMouseEnter = function () { _this4.clearDelayTimer(); }; this.onPopupMouseLeave = function (e) { // https://github.com/react-component/trigger/pull/13 // react bug? if (e.relatedTarget && !e.relatedTarget.setTimeout && _this4._component && _this4._component.getPopupDomNode && (0, _contains2['default'])(_this4._component.getPopupDomNode(), e.relatedTarget)) { return; } _this4.delaySetPopupVisible(false, _this4.props.mouseLeaveDelay); }; this.onFocus = function (e) { _this4.fireEvents('onFocus', e); // incase focusin and focusout _this4.clearDelayTimer(); if (_this4.isFocusToShow()) { _this4.focusTime = Date.now(); _this4.delaySetPopupVisible(true, _this4.props.focusDelay); } }; this.onMouseDown = function (e) { _this4.fireEvents('onMouseDown', e); _this4.preClickTime = Date.now(); }; this.onTouchStart = function (e) { _this4.fireEvents('onTouchStart', e); _this4.preTouchTime = Date.now(); }; this.onBlur = function (e) { _this4.fireEvents('onBlur', e); _this4.clearDelayTimer(); if (_this4.isBlurToHide()) { _this4.delaySetPopupVisible(false, _this4.props.blurDelay); } }; this.onContextMenu = function (e) { e.preventDefault(); _this4.fireEvents('onContextMenu', e); _this4.setPopupVisible(true, e); }; this.onContextMenuClose = function () { if (_this4.isContextMenuToShow()) { _this4.close(); } }; this.onClick = function (event) { _this4.fireEvents('onClick', event); // focus will trigger click if (_this4.focusTime) { var preTime = void 0; if (_this4.preClickTime && _this4.preTouchTime) { preTime = Math.min(_this4.preClickTime, _this4.preTouchTime); } else if (_this4.preClickTime) { preTime = _this4.preClickTime; } else if (_this4.preTouchTime) { preTime = _this4.preTouchTime; } if (Math.abs(preTime - _this4.focusTime) < 20) { return; } _this4.focusTime = 0; } _this4.preClickTime = 0; _this4.preTouchTime = 0; // Only prevent default when all the action is click. // https://github.com/ant-design/ant-design/issues/17043 // https://github.com/ant-design/ant-design/issues/17291 if (_this4.isClickToShow() && (_this4.isClickToHide() || _this4.isBlurToHide()) && event && event.preventDefault) { event.preventDefault(); } var nextVisible = !_this4.state.popupVisible; if (_this4.isClickToHide() && !nextVisible || nextVisible && _this4.isClickToShow()) { _this4.setPopupVisible(!_this4.state.popupVisible, event); } }; this.onPopupMouseDown = function () { var _context$rcTrigger = _this4.context.rcTrigger, rcTrigger = _context$rcTrigger === undefined ? {} : _context$rcTrigger; _this4.hasPopupMouseDown = true; clearTimeout(_this4.mouseDownTimeout); _this4.mouseDownTimeout = setTimeout(function () { _this4.hasPopupMouseDown = false; }, 0); if (rcTrigger.onPopupMouseDown) { rcTrigger.onPopupMouseDown.apply(rcTrigger, arguments); } }; this.onDocumentClick = function (event) { if (_this4.props.mask && !_this4.props.maskClosable) { return; } var target = event.target; var root = (0, _reactDom.findDOMNode)(_this4); if (!(0, _contains2['default'])(root, target) && !_this4.hasPopupMouseDown) { _this4.close(); } }; this.getRootDomNode = function () { return (0, _reactDom.findDOMNode)(_this4); }; this.getPopupClassNameFromAlign = function (align) { var className = []; var _props9 = _this4.props, popupPlacement = _props9.popupPlacement, builtinPlacements = _props9.builtinPlacements, prefixCls = _props9.prefixCls, alignPoint = _props9.alignPoint, getPopupClassNameFromAlign = _props9.getPopupClassNameFromAlign; if (popupPlacement && builtinPlacements) { className.push((0, _utils.getAlignPopupClassName)(builtinPlacements, prefixCls, align, alignPoint)); } if (getPopupClassNameFromAlign) { className.push(getPopupClassNameFromAlign(align)); } return className.join(' '); }; this.getComponent = function () { var _props10 = _this4.props, prefixCls = _props10.prefixCls, destroyPopupOnHide = _props10.destroyPopupOnHide, popupClassName = _props10.popupClassName, action = _props10.action, onPopupAlign = _props10.onPopupAlign, popupAnimation = _props10.popupAnimation, popupTransitionName = _props10.popupTransitionName, popupStyle = _props10.popupStyle, mask = _props10.mask, maskAnimation = _props10.maskAnimation, maskTransitionName = _props10.maskTransitionName, zIndex = _props10.zIndex, popup = _props10.popup, stretch = _props10.stretch, alignPoint = _props10.alignPoint; var _state = _this4.state, popupVisible = _state.popupVisible, point = _state.point; var align = _this4.getPopupAlign(); var mouseProps = {}; if (_this4.isMouseEnterToShow()) { mouseProps.onMouseEnter = _this4.onPopupMouseEnter; } if (_this4.isMouseLeaveToHide()) { mouseProps.onMouseLeave = _this4.onPopupMouseLeave; } mouseProps.onMouseDown = _this4.onPopupMouseDown; mouseProps.onTouchStart = _this4.onPopupMouseDown; return _react2['default'].createElement( _Popup2['default'], (0, _extends3['default'])({ prefixCls: prefixCls, destroyPopupOnHide: destroyPopupOnHide, visible: popupVisible, point: alignPoint && point, className: popupClassName, action: action, align: align, onAlign: onPopupAlign, animation: popupAnimation, getClassNameFromAlign: _this4.getPopupClassNameFromAlign }, mouseProps, { stretch: stretch, getRootDomNode: _this4.getRootDomNode, style: popupStyle, mask: mask, zIndex: zIndex, transitionName: popupTransitionName, maskAnimation: maskAnimation, maskTransitionName: maskTransitionName, ref: _this4.savePopup }), typeof popup === 'function' ? popup() : popup ); }; this.getContainer = function () { var props = _this4.props; var popupContainer = document.createElement('div'); // Make sure default popup container will never cause scrollbar appearing // https://github.com/react-component/trigger/issues/41 popupContainer.style.position = 'absolute'; popupContainer.style.top = '0'; popupContainer.style.left = '0'; popupContainer.style.width = '100%'; var mountNode = props.getPopupContainer ? props.getPopupContainer((0, _reactDom.findDOMNode)(_this4)) : props.getDocument().body; mountNode.appendChild(popupContainer); return popupContainer; }; this.setPoint = function (point) { var alignPoint = _this4.props.alignPoint; if (!alignPoint || !point) return; _this4.setState({ point: { pageX: point.pageX, pageY: point.pageY } }); }; this.handlePortalUpdate = function () { if (_this4.state.prevPopupVisible !== _this4.state.popupVisible) { _this4.props.afterPopupVisibleChange(_this4.state.popupVisible); } }; this.savePopup = function (node) { _this4._component = node; }; }; (0, _reactLifecyclesCompat.polyfill)(Trigger); exports['default'] = Trigger; module.exports = exports['default'];