UNPKG

choerodon-ui

Version:

An enterprise-class UI design language and React-based implementation

862 lines (742 loc) 27.8 kB
import _slicedToArray from "@babel/runtime/helpers/slicedToArray"; import _extends from "@babel/runtime/helpers/extends"; import _classCallCheck from "@babel/runtime/helpers/classCallCheck"; import _createClass from "@babel/runtime/helpers/createClass"; import _inherits from "@babel/runtime/helpers/inherits"; import _createSuper from "@babel/runtime/helpers/createSuper"; import _objectSpread from "@babel/runtime/helpers/objectSpread2"; import { __decorate } from "tslib"; import React, { Children, Component, isValidElement } from 'react'; import { findDOMNode } from 'react-dom'; import classNames from 'classnames'; import raf from 'raf'; import { action as mobxAction, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import noop from 'lodash/noop'; import isEqual from 'lodash/isEqual'; import isFragment from '../../pro/es/_util/isFragment'; import autobind from '../../pro/es/_util/autobind'; import focusable, { findFocusableParent } from '../../pro/es/_util/focusable'; import { getIf } from '../../pro/es/data-set/utils'; import { isChrome, isIE, isSafari, isWeChat } from '../_util/browser'; import KeyCode from '../_util/KeyCode'; import TaskRunner from '../_util/TaskRunner'; import Popup from './Popup'; import EventManager from '../_util/EventManager'; import { Action, HideAction, ShowAction } from './enum'; import TriggerChild from './TriggerChild'; function isHTMLInputElement(target) { return target.tagName.toLowerCase() === 'input'; } function isButton(target) { return target.tagName.toLowerCase() === 'button' || isHTMLInputElement(target) && target.type === 'button'; } function isPointsEq(a1, a2) { return a1[0] === a2[0] && a1[1] === a2[1]; } function _getPopupClassNameFromAlign(builtinPlacements, prefixCls, align) { var points = align.points; var found = Object.keys(builtinPlacements).find(function (placement) { return {}.hasOwnProperty.call(builtinPlacements, placement) && isPointsEq(builtinPlacements[placement].points, points); }); return found ? "".concat(prefixCls, "-popup-placement-").concat(found) : ''; } function getAlignFromPlacement(builtinPlacements, placementStr, align) { var baseAlign = builtinPlacements[placementStr] || {}; return _objectSpread(_objectSpread({}, baseAlign), align); } function getPopupAlign(props) { var popupPlacement = props.popupPlacement, popupAlign = props.popupAlign, builtinPlacements = props.builtinPlacements; if (popupPlacement && builtinPlacements) { return getAlignFromPlacement(builtinPlacements, popupPlacement, popupAlign); } return popupAlign; } function contains(root, n) { if (root) { var node = n; while (node) { if (node === root || root.contains && root.contains(node)) { return true; } node = node.parentNode; } } return false; } function isChildrenFunction(fn) { return typeof fn === 'function'; } var Trigger = /*#__PURE__*/function (_Component) { _inherits(Trigger, _Component); var _super = _createSuper(Trigger); function Trigger(props, context) { var _this; _classCallCheck(this, Trigger); _this = _super.call(this, props, context); _this.focusTime = 0; _this.preClickTime = 0; _this.animateFrameId = 0; runInAction(function () { _this.popupHidden = 'popupHidden' in props ? props.popupHidden : props.defaultPopupHidden; _this.align = getPopupAlign(props); }); return _this; } _createClass(Trigger, [{ key: "saveRef", value: function saveRef(node) { this.popup = node; } }, { key: "setActiveElement", value: function setActiveElement(activeElement) { var _this2 = this; this.activeElement = activeElement; var activeElementEvent = getIf(this, 'activeElementEvent', function () { return new EventManager(); }); if (activeElement) { if (this.relatedTarget) { var target = this.target; if (target && document.activeElement === document.body) { this.activeElement = null; target.focus(); } this.relatedTarget = null; } else { activeElementEvent.clear().setTarget(activeElement).addEventListener('blur', function () { var target = _this2.target; if (target && document.activeElement === document.body) { _this2.setActiveElement(null); target.focus(); } }, { once: true }); } } else { activeElementEvent.clear(); } } }, { key: "getFocusableElements", value: function getFocusableElements(elements) { this.focusElements = elements; var target = this.target, activeElement = this.activeElement; if (target && activeElement && (!elements || !elements.includes(activeElement))) { if (!elements || !elements.length) { this.setActiveElement(null); target.focus(); } } } }, { key: "renderTriggerChild", value: function renderTriggerChild(child) { var _this3 = this; if (child) { if (isFragment(child)) { var children = child.props.children; return Children.map(children, function (fragmentChild) { return _this3.renderTriggerChild(fragmentChild); }); } if ( /*#__PURE__*/isValidElement(child)) { var newChildProps = { key: child.key }; if (this.isContextMenuToShow()) { newChildProps.onContextMenu = this.handleEvent; } if (this.isClickToHide() || this.isClickToShow()) { newChildProps.onClick = this.handleEvent; newChildProps.onMouseDown = this.handleEvent; } if (this.isMouseEnterToShow()) { newChildProps.onMouseEnter = this.handleEvent; var mouseEnterDelay = this.props.mouseEnterDelay; if (mouseEnterDelay && !this.isMouseLeaveToHide()) { newChildProps.onMouseLeave = this.cancelPopupTask; } } if (this.isMouseLeaveToHide()) { newChildProps.onMouseLeave = this.handleEvent; var mouseLeaveDelay = this.props.mouseLeaveDelay; if (mouseLeaveDelay && !this.isMouseEnterToShow()) { newChildProps.onMouseEnter = this.cancelPopupTask; } } if (this.isFocusToShow() || this.isBlurToHide()) { newChildProps.onFocus = this.handleEvent; newChildProps.onBlur = this.handleEvent; } newChildProps.onKeyDown = this.handleEvent; newChildProps.popupHidden = this.popupHidden; return /*#__PURE__*/React.createElement(TriggerChild, _extends({}, newChildProps), child); } } return child; } }, { key: "render", value: function render() { var _this4 = this; var _this$props = this.props, children = _this$props.children, childrenProps = _this$props.childrenProps; var popup = this.getPopup(); var newChildren = isChildrenFunction(children) ? children(this.renderTriggerChild, childrenProps) : Children.map(children, function (child) { return _this4.renderTriggerChild(child); }); return [newChildren, popup]; } }, { key: "componentWillReceiveProps", value: function componentWillReceiveProps(nextProps) { var popupHidden = nextProps.popupHidden; if (popupHidden !== this.popupHidden && popupHidden !== undefined) { this.popupHidden = popupHidden; } var newAlign = getPopupAlign(nextProps); if (!isEqual(this.align, newAlign)) { this.align = newAlign; } } }, { key: "componentDidMount", value: function componentDidMount() { var _this5 = this; this.mounted = true; if (!isChrome() && (isSafari() || isWeChat())) { this.mouseDownEvent = new EventManager(document).addEventListener('mousedown', function (e) { if (!_this5.popupHidden) { var target = e.target; if (isButton(target)) { _this5.relatedTarget = target; } else { var parent = findFocusableParent(target); if (parent && isButton(parent)) { _this5.relatedTarget = parent; } } } }); } } }, { key: "componentDidUpdate", value: function componentDidUpdate() { var popupHidden = this.popupHidden; if (this.documentEvent) { this.documentEvent.clear(); } if (!popupHidden) { var documentEvent = getIf(this, 'documentEvent', function () { return new EventManager(typeof window === 'undefined' ? undefined : document); }); documentEvent.addEventListener('scroll', this.handleDocumentScroll, true); if ((this.isClickToHide() || this.isContextMenuToShow()) && !this.isBlurToHide()) { documentEvent.addEventListener('mousedown', this.handleDocumentMouseDown); } } } }, { key: "componentWillUnmount", value: function componentWillUnmount() { this.cancelPopupTask(); if (this.documentEvent) { this.documentEvent.clear(); } if (this.activeElementEvent) { this.activeElementEvent.clear(); } if (this.mouseDownEvent) { this.mouseDownEvent.clear(); } } }, { key: "cancelPopupTask", value: function cancelPopupTask() { if (this.popupTask) { this.popupTask.cancel(); } } }, { key: "handlePopupKeyDown", value: function handlePopupKeyDown(e) { var focusTarget = this.focusTarget, activeElement = this.activeElement; if (activeElement && focusTarget && e.keyCode === KeyCode.TAB) { var focusElements = this.focusElements; var shiftKey = e.shiftKey; if (focusElements && focusElements.indexOf(activeElement) === (shiftKey ? 0 : focusElements.length - 1)) { if (shiftKey) { e.preventDefault(); } focusTarget.focus(); } } } }, { key: "handleTargetBlur", value: function handleTargetBlur(e, child) { var popup = this.popup, focusTarget = this.focusTarget; var relatedTarget = isIE() ? document.activeElement : e.relatedTarget || this.relatedTarget; if (popup && relatedTarget && popup.element.contains(relatedTarget)) { e.stopPropagation(); this.setActiveElement(relatedTarget); this.currentTriggerChild = child; if (!focusTarget) { this.focusTarget = e.target; } return false; } if (focusTarget) { this.focusTarget = null; this.setActiveElement(null); this.currentTriggerChild = null; if (focusTarget !== relatedTarget) { this.handleTriggerEvent('Blur', child, e); } } return true; } }, { key: "handleTriggerEvent", value: function handleTriggerEvent(eventName, child, e) { var handle = this.props["on".concat(eventName)]; var childHandle = child.props["on".concat(eventName)]; if (childHandle) { childHandle(e); } if (!e.isDefaultPrevented()) { if (handle) { handle(e); } if (!e.isDefaultPrevented()) { this["handle".concat(eventName)].call(this, e); } } } }, { key: "handleEvent", value: function handleEvent(eventName, child, e) { if (this.isBlurToHide() && eventName === 'Blur' && !this.handleTargetBlur(e, child)) { if (!this.target) { this.target = e.target; } } else { this.handleTriggerEvent(eventName, child, e); } } }, { key: "handlePopupMouseDown", value: function handlePopupMouseDown(e) { var fix = false; var popup = this.popup; var popupElement = popup && popup.element; var target = e.target; if (!e.isDefaultPrevented()) { var element = focusable(target) ? target : findFocusableParent(target, popupElement); if (element) { e.stopPropagation(); } else { fix = true; } } else { fix = true; } if (fix && this.isBlurToHide()) { var ownerDocument = target.ownerDocument; if (ownerDocument) { var activeElement = ownerDocument.activeElement; if (activeElement && activeElement !== ownerDocument.body) { var el = findDOMNode(this); if (el && el.contains(activeElement)) { e.preventDefault(); } } } } } }, { key: "handlePopupBlur", value: function handlePopupBlur(e) { if (this.isBlurToHide()) { var activeElement = this.activeElement, currentTriggerChild = this.currentTriggerChild; if (activeElement && currentTriggerChild) { this.handleTargetBlur(e, currentTriggerChild); } } } }, { key: "handleContextMenu", value: function handleContextMenu(e) { e.preventDefault(); this.setPopupHidden(false); } }, { key: "handleKeyDown", value: function handleKeyDown(e) { var tabIntoPopupContent = this.props.tabIntoPopupContent; if (!this.popupHidden && tabIntoPopupContent && this.focusElements && e.keyCode === KeyCode.TAB && !e.shiftKey) { var _this$focusElements = _slicedToArray(this.focusElements, 1), firstFocusElement = _this$focusElements[0]; if (firstFocusElement) { e.preventDefault(); firstFocusElement.focus(); } } } }, { key: "handleFocus", value: function handleFocus() { if (this.isFocusToShow()) { var focusDelay = this.props.focusDelay; this.focusTime = Date.now(); this.delaySetPopupHidden(false, focusDelay); } } }, { key: "handleBlur", value: function handleBlur() { if (this.isBlurToHide()) { var blurDelay = this.props.blurDelay; this.delaySetPopupHidden(true, blurDelay); } } }, { key: "handleDocumentMouseDown", value: function handleDocumentMouseDown(e) { if (this.popup) { var target = e.target; if (!contains(findDOMNode(this), target) && !contains(findDOMNode(this.popup), target)) { this.setPopupHidden(true); } } } }, { key: "handleDocumentScroll", value: function handleDocumentScroll(_ref) { var target = _ref.target; if (this.popup && target !== document && !contains(findDOMNode(this.popup), target)) { if (this.animateFrameId) { raf.cancel(this.animateFrameId); } this.animateFrameId = raf(this.forcePopupAlign); } } }, { key: "handleMouseDown", value: function handleMouseDown() { this.preClickTime = Date.now(); } }, { key: "handleClick", value: function handleClick(e) { var popupHidden = this.popupHidden; if (this.focusTime) { if (Math.abs(this.preClickTime - this.focusTime) < 20) { return; } this.focusTime = 0; } this.preClickTime = 0; if (this.isClickToHide() && !popupHidden || popupHidden && this.isClickToShow()) { e.preventDefault(); this.setPopupHidden(!popupHidden); } } }, { key: "handleMouseEnter", value: function handleMouseEnter() { var mouseEnterDelay = this.props.mouseEnterDelay; this.delaySetPopupHidden(false, mouseEnterDelay); } }, { key: "handleMouseLeave", value: function handleMouseLeave() { var mouseLeaveDelay = this.props.mouseLeaveDelay; this.delaySetPopupHidden(true, mouseLeaveDelay); } }, { key: "handlePopupMouseEnter", value: function handlePopupMouseEnter(e) { this.cancelPopupTask(); var onPopupMouseEnter = this.props.onPopupMouseEnter; if (onPopupMouseEnter) { onPopupMouseEnter(e); } } }, { key: "handlePopupMouseLeave", value: function handlePopupMouseLeave(e) { var _this$props2 = this.props, mouseLeaveDelay = _this$props2.mouseLeaveDelay, onPopupMouseLeave = _this$props2.onPopupMouseLeave; this.delaySetPopupHidden(true, mouseLeaveDelay); if (onPopupMouseLeave) { onPopupMouseLeave(e); } } }, { key: "getPopup", value: function getPopup() { var _this$props3 = this.props, prefixCls = _this$props3.prefixCls, popupCls = _this$props3.popupCls, popupStyle = _this$props3.popupStyle, popupClassName = _this$props3.popupClassName, onPopupAnimateAppear = _this$props3.onPopupAnimateAppear, onPopupAnimateEnter = _this$props3.onPopupAnimateEnter, onPopupAnimateLeave = _this$props3.onPopupAnimateLeave, onPopupAnimateEnd = _this$props3.onPopupAnimateEnd, onPopupAlign = _this$props3.onPopupAlign, onPopupMouseEnter = _this$props3.onPopupMouseEnter, onPopupMouseLeave = _this$props3.onPopupMouseLeave, getPopupStyleFromAlign = _this$props3.getPopupStyleFromAlign, _this$props3$getRootD = _this$props3.getRootDomNode, getRootDomNode = _this$props3$getRootD === void 0 ? this.getRootDomNode : _this$props3$getRootD, transitionName = _this$props3.transitionName, getPopupContainer = _this$props3.getPopupContainer, forceRender = _this$props3.forceRender; if (this.mounted || !getPopupContainer) { var hidden = this.popupHidden; if (!hidden || this.popup || forceRender) { var mouseProps = { onMouseEnter: this.isMouseEnterToShow() ? this.handlePopupMouseEnter : onPopupMouseEnter, onMouseLeave: this.isMouseLeaveToHide() ? this.handlePopupMouseLeave : onPopupMouseLeave }; return /*#__PURE__*/React.createElement(Popup, _extends({ key: "popup", ref: this.saveRef, transitionName: transitionName, className: classNames("".concat(prefixCls, "-popup"), popupCls, popupClassName), style: popupStyle, hidden: hidden, align: this.align, onAlign: onPopupAlign, onMouseDown: this.handlePopupMouseDown, onKeyDown: this.handlePopupKeyDown, onBlur: this.handlePopupBlur, getFocusableElements: this.getFocusableElements, getRootDomNode: getRootDomNode, onAnimateAppear: onPopupAnimateAppear, onAnimateEnter: onPopupAnimateEnter, onAnimateLeave: onPopupAnimateLeave, onAnimateEnd: onPopupAnimateEnd, getStyleFromAlign: getPopupStyleFromAlign, getClassNameFromAlign: this.getPopupClassNameFromAlign, getPopupContainer: getPopupContainer, forceRender: forceRender }, mouseProps), this.getPopupContent()); } } } }, { key: "getRootDomNode", value: function getRootDomNode() { return findDOMNode(this); } }, { key: "getPopupClassNameFromAlign", value: function getPopupClassNameFromAlign(align) { var className = []; var _this$props4 = this.props, popupPlacement = _this$props4.popupPlacement, builtinPlacements = _this$props4.builtinPlacements, prefixCls = _this$props4.prefixCls, getCls = _this$props4.getPopupClassNameFromAlign; if (popupPlacement && builtinPlacements) { className.push(_getPopupClassNameFromAlign(builtinPlacements, prefixCls, align)); } if (getCls) { var cls = getCls(align); if (cls) { className.push(cls); } } return className.join(' '); } }, { key: "forcePopupAlign", value: function forcePopupAlign() { if (!this.popupHidden && this.popup) { this.popup.forceAlign(); } } }, { key: "getPopupWrapper", value: function getPopupWrapper() { if (!this.popupHidden && this.popup) { return this.popup.wrapper; } } }, { key: "getPopupContent", value: function getPopupContent() { var _this$props5 = this.props, popupContent = _this$props5.popupContent, children = _this$props5.children; return typeof popupContent === 'function' ? popupContent({ trigger: children }) : popupContent; } }, { key: "popupHiddenBeforeChange", value: function popupHiddenBeforeChange(hidden) { var _this$props$onPopupHi = this.props.onPopupHiddenBeforeChange, onPopupHiddenBeforeChange = _this$props$onPopupHi === void 0 ? noop : _this$props$onPopupHi; if (onPopupHiddenBeforeChange(hidden) === false) { return false; } // if (hidden === false) { // return !isEmpty(this.getPopupContent()); // } return true; } }, { key: "setPopupHidden", value: function setPopupHidden(hidden) { this.cancelPopupTask(); if (this.popupHidden !== hidden) { var _this$props6 = this.props, popupHidden = _this$props6.popupHidden, _this$props6$onPopupH = _this$props6.onPopupHiddenChange, onPopupHiddenChange = _this$props6$onPopupH === void 0 ? noop : _this$props6$onPopupH; if (this.popupHiddenBeforeChange(hidden) !== false) { if (popupHidden === undefined) { this.popupHidden = hidden; } onPopupHiddenChange(hidden); } } } }, { key: "delaySetPopupHidden", value: function delaySetPopupHidden(popupHidden, delay) { var _this6 = this; this.cancelPopupTask(); if (delay) { getIf(this, 'popupTask', function () { return new TaskRunner(); }).delay(delay, function () { _this6.setPopupHidden(popupHidden); }); } else { this.setPopupHidden(popupHidden); } } }, { key: "isClickToShow", value: function isClickToShow() { var _this$props7 = this.props, _this$props7$action = _this$props7.action, action = _this$props7$action === void 0 ? [] : _this$props7$action, _this$props7$showActi = _this$props7.showAction, showAction = _this$props7$showActi === void 0 ? [] : _this$props7$showActi; return action.indexOf(Action.click) !== -1 || showAction.indexOf(ShowAction.click) !== -1; } }, { key: "isContextMenuToShow", value: function isContextMenuToShow() { var _this$props8 = this.props, _this$props8$action = _this$props8.action, action = _this$props8$action === void 0 ? [] : _this$props8$action, _this$props8$showActi = _this$props8.showAction, showAction = _this$props8$showActi === void 0 ? [] : _this$props8$showActi; return action.indexOf(Action.contextMenu) !== -1 || showAction.indexOf(ShowAction.contextMenu) !== -1; } }, { key: "isClickToHide", value: function isClickToHide() { var _this$props9 = this.props, _this$props9$action = _this$props9.action, action = _this$props9$action === void 0 ? [] : _this$props9$action, _this$props9$hideActi = _this$props9.hideAction, hideAction = _this$props9$hideActi === void 0 ? [] : _this$props9$hideActi; return action.indexOf(Action.click) !== -1 || hideAction.indexOf(HideAction.click) !== -1; } }, { key: "isMouseEnterToShow", value: function isMouseEnterToShow() { var _this$props10 = this.props, _this$props10$action = _this$props10.action, action = _this$props10$action === void 0 ? [] : _this$props10$action, _this$props10$showAct = _this$props10.showAction, showAction = _this$props10$showAct === void 0 ? [] : _this$props10$showAct; return action.indexOf(Action.hover) !== -1 || showAction.indexOf(ShowAction.mouseEnter) !== -1; } }, { key: "isMouseLeaveToHide", value: function isMouseLeaveToHide() { var _this$props11 = this.props, _this$props11$action = _this$props11.action, action = _this$props11$action === void 0 ? [] : _this$props11$action, _this$props11$hideAct = _this$props11.hideAction, hideAction = _this$props11$hideAct === void 0 ? [] : _this$props11$hideAct; return action.indexOf(Action.hover) !== -1 || hideAction.indexOf(HideAction.mouseLeave) !== -1; } }, { key: "isFocusToShow", value: function isFocusToShow() { var _this$props12 = this.props, _this$props12$action = _this$props12.action, action = _this$props12$action === void 0 ? [] : _this$props12$action, _this$props12$showAct = _this$props12.showAction, showAction = _this$props12$showAct === void 0 ? [] : _this$props12$showAct; return action.indexOf(Action.focus) !== -1 || showAction.indexOf(ShowAction.focus) !== -1; } }, { key: "isBlurToHide", value: function isBlurToHide() { var _this$props13 = this.props, _this$props13$action = _this$props13.action, action = _this$props13$action === void 0 ? [] : _this$props13$action, _this$props13$hideAct = _this$props13.hideAction, hideAction = _this$props13$hideAct === void 0 ? [] : _this$props13$hideAct, getContextConfig = _this$props13.getContextConfig; var formAutoFocus = getContextConfig ? getContextConfig('formAutoFocus') : false; return action.indexOf(Action.focus) !== -1 || hideAction.indexOf(HideAction.blur) !== -1 || formAutoFocus; } }]); return Trigger; }(Component); Trigger.displayName = 'Trigger'; Trigger.defaultProps = { focusDelay: 150, blurDelay: 0, mouseEnterDelay: 100, mouseLeaveDelay: 100, transitionName: 'slide-up', defaultPopupHidden: true }; __decorate([observable], Trigger.prototype, "popupHidden", void 0); __decorate([observable], Trigger.prototype, "mounted", void 0); __decorate([autobind], Trigger.prototype, "saveRef", null); __decorate([autobind], Trigger.prototype, "getFocusableElements", null); __decorate([autobind], Trigger.prototype, "renderTriggerChild", null); __decorate([mobxAction], Trigger.prototype, "componentWillReceiveProps", null); __decorate([mobxAction], Trigger.prototype, "componentDidMount", null); __decorate([autobind], Trigger.prototype, "cancelPopupTask", null); __decorate([autobind], Trigger.prototype, "handlePopupKeyDown", null); __decorate([autobind], Trigger.prototype, "handleTargetBlur", null); __decorate([autobind], Trigger.prototype, "handleEvent", null); __decorate([autobind], Trigger.prototype, "handlePopupMouseDown", null); __decorate([autobind], Trigger.prototype, "handlePopupBlur", null); __decorate([autobind], Trigger.prototype, "handleDocumentMouseDown", null); __decorate([autobind], Trigger.prototype, "handleDocumentScroll", null); __decorate([autobind], Trigger.prototype, "handlePopupMouseEnter", null); __decorate([autobind], Trigger.prototype, "handlePopupMouseLeave", null); __decorate([autobind], Trigger.prototype, "getRootDomNode", null); __decorate([autobind], Trigger.prototype, "getPopupClassNameFromAlign", null); __decorate([autobind], Trigger.prototype, "forcePopupAlign", null); __decorate([mobxAction], Trigger.prototype, "setPopupHidden", null); Trigger = __decorate([observer], Trigger); export default Trigger; //# sourceMappingURL=Trigger.js.map