choerodon-ui
Version:
An enterprise-class UI design language and React-based implementation
568 lines (475 loc) • 18.8 kB
JavaScript
import _extends from "@babel/runtime/helpers/extends";
import _typeof from "@babel/runtime/helpers/typeof";
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
import _createClass from "@babel/runtime/helpers/createClass";
import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized";
import _inherits from "@babel/runtime/helpers/inherits";
import _createSuper from "@babel/runtime/helpers/createSuper";
import _defineProperty from "@babel/runtime/helpers/defineProperty";
import _objectSpread from "@babel/runtime/helpers/objectSpread2";
import React, { Component, createElement } from 'react';
import { findDOMNode } from 'react-dom';
import noop from 'lodash/noop';
import classNames from 'classnames';
import { connect } from 'mini-store';
import Trigger from '../trigger';
import KeyCode from '../../_util/KeyCode';
import SubPopupMenu from './SubPopupMenu';
import placements from './placements';
import Animate from '../../animate';
import { getMenuIdFromSubMenuEventKey, loopMenuItemRecursively, menuAllProps } from './util';
var guid = 0;
var popupPlacementMap = {
horizontal: 'bottomLeft',
vertical: 'rightTop',
'vertical-left': 'rightTop',
'vertical-right': 'leftTop'
};
var updateDefaultActiveFirst = function updateDefaultActiveFirst(store, eventKey, defaultActiveFirst) {
var menuId = getMenuIdFromSubMenuEventKey(eventKey);
var state = store.getState();
store.setState({
defaultActiveFirst: _objectSpread(_objectSpread({}, state.defaultActiveFirst), {}, _defineProperty({}, menuId, defaultActiveFirst))
});
};
export var SubMenu = /*#__PURE__*/function (_Component) {
_inherits(SubMenu, _Component);
var _super = _createSuper(SubMenu);
function SubMenu(_props) {
var _this;
_classCallCheck(this, SubMenu);
_this = _super.call(this, _props);
_defineProperty(_assertThisInitialized(_this), "onDestroy", function (key) {
_this.props.onDestroy(key);
});
_defineProperty(_assertThisInitialized(_this), "onKeyDown", function (e) {
var keyCode = e.keyCode;
var menu = _this.menuInstance;
var _this$props = _this.props,
isOpen = _this$props.isOpen,
store = _this$props.store;
if (keyCode === KeyCode.ENTER) {
_this.onTitleClick(e);
updateDefaultActiveFirst(store, _this.props.eventKey, true);
return true;
}
if (keyCode === KeyCode.RIGHT) {
if (isOpen) {
menu.onKeyDown(e);
} else {
_this.triggerOpenChange(true); // need to update current menu's defaultActiveFirst value
updateDefaultActiveFirst(store, _this.props.eventKey, true);
}
return true;
}
if (keyCode === KeyCode.LEFT) {
var handled;
if (isOpen) {
handled = menu.onKeyDown(e);
} else {
return undefined;
}
if (!handled) {
_this.triggerOpenChange(false);
handled = true;
}
return handled;
}
if (isOpen && (keyCode === KeyCode.UP || keyCode === KeyCode.DOWN)) {
return menu.onKeyDown(e);
}
});
_defineProperty(_assertThisInitialized(_this), "onOpenChange", function (e) {
_this.props.onOpenChange(e);
});
_defineProperty(_assertThisInitialized(_this), "onPopupVisibleChange", function (visible) {
_this.triggerOpenChange(visible, visible ? 'mouseenter' : 'mouseleave');
});
_defineProperty(_assertThisInitialized(_this), "onMouseEnter", function (e) {
var _this$props2 = _this.props,
key = _this$props2.eventKey,
onMouseEnter = _this$props2.onMouseEnter,
store = _this$props2.store;
updateDefaultActiveFirst(store, _this.props.eventKey, false);
onMouseEnter({
key: key,
domEvent: e
});
});
_defineProperty(_assertThisInitialized(_this), "onMouseLeave", function (e) {
var _this$props3 = _this.props,
parentMenu = _this$props3.parentMenu,
eventKey = _this$props3.eventKey,
onMouseLeave = _this$props3.onMouseLeave;
parentMenu.subMenuInstance = _assertThisInitialized(_this);
onMouseLeave({
key: eventKey,
domEvent: e
});
});
_defineProperty(_assertThisInitialized(_this), "onTitleMouseEnter", function (domEvent) {
var _this$props4 = _this.props,
key = _this$props4.eventKey,
onItemHover = _this$props4.onItemHover,
onTitleMouseEnter = _this$props4.onTitleMouseEnter;
onItemHover({
key: key,
hover: true
});
onTitleMouseEnter({
key: key,
domEvent: domEvent
});
});
_defineProperty(_assertThisInitialized(_this), "onTitleMouseLeave", function (e) {
var _this$props5 = _this.props,
parentMenu = _this$props5.parentMenu,
eventKey = _this$props5.eventKey,
onItemHover = _this$props5.onItemHover,
onTitleMouseLeave = _this$props5.onTitleMouseLeave;
parentMenu.subMenuInstance = _assertThisInitialized(_this);
onItemHover({
key: eventKey,
hover: false
});
onTitleMouseLeave({
key: eventKey,
domEvent: e
});
});
_defineProperty(_assertThisInitialized(_this), "onTitleClick", function (e) {
var _assertThisInitialize = _assertThisInitialized(_this),
props = _assertThisInitialize.props;
props.onTitleClick({
key: props.eventKey,
domEvent: e
});
if (props.triggerSubMenuAction === 'hover') {
return;
}
_this.triggerOpenChange(!props.isOpen, 'click');
updateDefaultActiveFirst(props.store, _this.props.eventKey, false);
});
_defineProperty(_assertThisInitialized(_this), "onSubMenuClick", function (info) {
// in the case of overflowed submenu
// onClick is not copied over
if (typeof _this.props.onClick === 'function') {
_this.props.onClick(_this.addKeyPath(info));
}
});
_defineProperty(_assertThisInitialized(_this), "onSelect", function (info) {
_this.props.onSelect(info);
});
_defineProperty(_assertThisInitialized(_this), "onDeselect", function (info) {
_this.props.onDeselect(info);
});
_defineProperty(_assertThisInitialized(_this), "getPrefixCls", function () {
return "".concat(_this.props.rootPrefixCls, "-submenu");
});
_defineProperty(_assertThisInitialized(_this), "getActiveClassName", function () {
return "".concat(_this.getPrefixCls(), "-active");
});
_defineProperty(_assertThisInitialized(_this), "getDisabledClassName", function () {
return "".concat(_this.getPrefixCls(), "-disabled");
});
_defineProperty(_assertThisInitialized(_this), "getSelectedClassName", function () {
return "".concat(_this.getPrefixCls(), "-selected");
});
_defineProperty(_assertThisInitialized(_this), "getOpenClassName", function () {
return "".concat(_this.props.rootPrefixCls, "-submenu-open");
});
_defineProperty(_assertThisInitialized(_this), "saveMenuInstance", function (c) {
// children menu instance
_this.menuInstance = c;
});
_defineProperty(_assertThisInitialized(_this), "addKeyPath", function (info) {
return _objectSpread(_objectSpread({}, info), {}, {
keyPath: (info.keyPath || []).concat(_this.props.eventKey)
});
});
_defineProperty(_assertThisInitialized(_this), "triggerOpenChange", function (open, type) {
var key = _this.props.eventKey;
var openChange = function openChange() {
_this.onOpenChange({
key: key,
item: _assertThisInitialized(_this),
trigger: type,
open: open
});
};
if (type === 'mouseenter') {
// make sure mouseenter happen after other menu item's mouseleave
_this.mouseenterTimeout = setTimeout(function () {
openChange();
}, 0);
} else {
openChange();
}
});
_defineProperty(_assertThisInitialized(_this), "isChildrenSelected", function () {
var ret = {
find: false
};
loopMenuItemRecursively(_this.props.children, _this.props.selectedKeys, ret);
return ret.find;
});
_defineProperty(_assertThisInitialized(_this), "isOpen", function () {
return _this.props.openKeys.indexOf(_this.props.eventKey) !== -1;
});
_defineProperty(_assertThisInitialized(_this), "adjustWidth", function () {
/* istanbul ignore if */
if (!_this.subMenuTitle || !_this.menuInstance) {
return;
}
var popupMenu = findDOMNode(_this.menuInstance);
if (popupMenu.offsetWidth >= _this.subMenuTitle.offsetWidth) {
return;
}
/* istanbul ignore next */
popupMenu.style.minWidth = "".concat(_this.subMenuTitle.offsetWidth, "px");
});
_defineProperty(_assertThisInitialized(_this), "saveSubMenuTitle", function (subMenuTitle) {
_this.subMenuTitle = subMenuTitle;
});
var _store = _props.store;
var _eventKey = _props.eventKey;
var defaultActiveFirst = _store.getState().defaultActiveFirst;
_this.isRootMenu = false;
var value = false;
if (defaultActiveFirst) {
value = defaultActiveFirst[_eventKey];
}
updateDefaultActiveFirst(_store, _eventKey, value);
return _this;
}
_createClass(SubMenu, [{
key: "componentDidMount",
value: function componentDidMount() {
this.componentDidUpdate();
}
}, {
key: "componentDidUpdate",
value: function componentDidUpdate() {
var _this2 = this;
var _this$props6 = this.props,
mode = _this$props6.mode,
parentMenu = _this$props6.parentMenu,
manualRef = _this$props6.manualRef; // invoke customized ref to expose component to mixin
if (manualRef) {
manualRef(this);
}
if (mode !== 'horizontal' || !parentMenu.isRootMenu || !this.props.isOpen) {
return;
}
this.minWidthTimeout = setTimeout(function () {
return _this2.adjustWidth();
}, 0);
}
}, {
key: "componentWillUnmount",
value: function componentWillUnmount() {
var _this$props7 = this.props,
onDestroy = _this$props7.onDestroy,
eventKey = _this$props7.eventKey;
if (onDestroy) {
onDestroy(eventKey);
}
/* istanbul ignore if */
if (this.minWidthTimeout) {
clearTimeout(this.minWidthTimeout);
}
/* istanbul ignore if */
if (this.mouseenterTimeout) {
clearTimeout(this.mouseenterTimeout);
}
}
}, {
key: "renderChildren",
value: function renderChildren(children) {
var props = this.props;
var baseProps = {
mode: props.mode === 'horizontal' ? 'vertical' : props.mode,
hidden: !this.props.isOpen,
level: props.level + 1,
inlineIndent: props.inlineIndent,
focusable: false,
onClick: this.onSubMenuClick,
onSelect: this.onSelect,
onDeselect: this.onDeselect,
onDestroy: this.onDestroy,
selectedKeys: props.selectedKeys,
eventKey: "".concat(props.eventKey, "-menu-"),
openKeys: props.openKeys,
openTransitionName: props.openTransitionName,
openAnimation: props.openAnimation,
onOpenChange: this.onOpenChange,
subMenuOpenDelay: props.subMenuOpenDelay,
parentMenu: this,
subMenuCloseDelay: props.subMenuCloseDelay,
forceSubMenuRender: props.forceSubMenuRender,
triggerSubMenuAction: props.triggerSubMenuAction,
builtinPlacements: props.builtinPlacements,
defaultActiveFirst: props.store.getState().defaultActiveFirst[getMenuIdFromSubMenuEventKey(props.eventKey)],
multiple: props.multiple,
prefixCls: props.rootPrefixCls,
id: this._menuId,
manualRef: this.saveMenuInstance,
itemIcon: props.itemIcon,
expandIcon: props.expandIcon
};
var haveRendered = this.haveRendered;
this.haveRendered = true;
this.haveOpened = this.haveOpened || !baseProps.hidden || baseProps.forceSubMenuRender; // never rendered not planning to, don't render
if (!this.haveOpened) {
return /*#__PURE__*/React.createElement("div", null);
} // don't show transition on first rendering (no animation for opened menu)
// show appear transition if it's hidden (not sure why)
// show appear transition if it's not inline mode
var transitionAppear = haveRendered || baseProps.hidden || !baseProps.mode === 'inline';
baseProps.className = " ".concat(baseProps.prefixCls, "-sub");
var animProps = {};
if (baseProps.openTransitionName) {
animProps.transitionName = baseProps.openTransitionName;
} else if (_typeof(baseProps.openAnimation) === 'object') {
animProps.animation = _objectSpread({}, baseProps.openAnimation);
if (!transitionAppear) {
delete animProps.animation.appear;
}
}
return /*#__PURE__*/React.createElement(Animate, _extends({}, animProps, {
hiddenProp: "hidden",
component: "",
transitionAppear: transitionAppear
}), /*#__PURE__*/React.createElement(SubPopupMenu, _extends({}, baseProps, {
id: this._menuId
}), children));
}
}, {
key: "render",
value: function render() {
var _classNames;
var props = _objectSpread({}, this.props);
var isOpen = props.isOpen;
var prefixCls = this.getPrefixCls();
var isInlineMode = props.mode === 'inline';
var className = classNames(prefixCls, "".concat(prefixCls, "-").concat(props.mode), (_classNames = {}, _defineProperty(_classNames, props.className, !!props.className), _defineProperty(_classNames, this.getOpenClassName(), isOpen), _defineProperty(_classNames, this.getActiveClassName(), props.active || isOpen && !isInlineMode), _defineProperty(_classNames, this.getDisabledClassName(), props.disabled), _defineProperty(_classNames, this.getSelectedClassName(), this.isChildrenSelected()), _classNames));
if (!this._menuId) {
if (props.eventKey) {
this._menuId = "".concat(props.eventKey, "$Menu");
} else {
this._menuId = "$__$".concat(++guid, "$Menu");
}
}
var mouseEvents = {};
var titleClickEvents = {};
var titleMouseEvents = {};
if (!props.disabled) {
mouseEvents = {
onMouseLeave: this.onMouseLeave,
onMouseEnter: this.onMouseEnter
}; // only works in title, not outer li
titleClickEvents = {
onClick: this.onTitleClick
};
titleMouseEvents = {
onMouseEnter: this.onTitleMouseEnter,
onMouseLeave: this.onTitleMouseLeave
};
}
var style = {};
if (isInlineMode) {
style.paddingLeft = props.inlineIndent * props.level;
}
var ariaOwns = {}; // only set aria-owns when menu is open
// otherwise it would be an invalid aria-owns value
// since corresponding node cannot be found
if (this.props.isOpen) {
ariaOwns = {
'aria-owns': this._menuId
};
} // expand custom icon should NOT be displayed in menu with horizontal mode.
var icon = null;
if (props.mode !== 'horizontal') {
icon = this.props.expandIcon; // ReactNode
if (typeof this.props.expandIcon === 'function') {
icon = /*#__PURE__*/createElement(this.props.expandIcon, _objectSpread({}, this.props));
}
}
var title = /*#__PURE__*/React.createElement("div", _extends({
ref: this.saveSubMenuTitle,
style: style,
className: "".concat(prefixCls, "-title")
}, titleMouseEvents, titleClickEvents, {
"aria-expanded": isOpen
}, ariaOwns, {
"aria-haspopup": "true",
title: typeof props.title === 'string' ? props.title : undefined
}), props.title, icon || /*#__PURE__*/React.createElement("i", {
className: "".concat(prefixCls, "-arrow")
}));
var children = this.renderChildren(props.children);
var getPopupContainer = props.parentMenu.isRootMenu ? props.parentMenu.props.getPopupContainer : function (triggerNode) {
return triggerNode.parentNode;
};
var popupPlacement = popupPlacementMap[props.mode];
var popupAlign = props.popupOffset ? {
offset: props.popupOffset
} : {};
var popupClassName = props.mode === 'inline' ? '' : props.popupClassName;
var disabled = props.disabled,
triggerSubMenuAction = props.triggerSubMenuAction,
subMenuOpenDelay = props.subMenuOpenDelay,
forceSubMenuRender = props.forceSubMenuRender,
subMenuCloseDelay = props.subMenuCloseDelay,
builtinPlacements = props.builtinPlacements;
menuAllProps.forEach(function (key) {
return delete props[key];
}); // Set onClick to null, to ignore propagated onClick event
delete props.onClick;
return /*#__PURE__*/React.createElement("li", _extends({}, props, mouseEvents, {
className: className,
role: "menuitem"
}), isInlineMode && title, isInlineMode && children, !isInlineMode && /*#__PURE__*/React.createElement(Trigger, {
prefixCls: prefixCls,
popupClassName: "".concat(prefixCls, "-popup ").concat(popupClassName),
getPopupContainer: getPopupContainer,
builtinPlacements: _extends({}, placements, builtinPlacements),
popupPlacement: popupPlacement,
popupVisible: isOpen,
popupAlign: popupAlign,
popup: children,
action: disabled ? [] : [triggerSubMenuAction],
mouseEnterDelay: subMenuOpenDelay,
mouseLeaveDelay: subMenuCloseDelay,
onPopupVisibleChange: this.onPopupVisibleChange,
forceRender: forceSubMenuRender
}, title));
}
}]);
return SubMenu;
}(Component);
_defineProperty(SubMenu, "defaultProps", {
onMouseEnter: noop,
onMouseLeave: noop,
onTitleMouseEnter: noop,
onTitleMouseLeave: noop,
onTitleClick: noop,
manualRef: noop,
mode: 'vertical',
title: ''
});
var connected = connect(function (_ref, _ref2) {
var openKeys = _ref.openKeys,
activeKey = _ref.activeKey,
selectedKeys = _ref.selectedKeys;
var eventKey = _ref2.eventKey,
subMenuKey = _ref2.subMenuKey;
return {
isOpen: openKeys.indexOf(eventKey) > -1,
active: activeKey[subMenuKey] === eventKey,
selectedKeys: selectedKeys
};
})(SubMenu);
connected.isSubMenu = true;
export default connected;
//# sourceMappingURL=SubMenu.js.map