UNPKG

ant-design-vue

Version:

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

580 lines (495 loc) 21.7 kB
var _defineComponent; import { isVNode as _isVNode, withDirectives as _withDirectives, resolveDirective as _resolveDirective, vShow as _vShow, createVNode as _createVNode } from "vue"; 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(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(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 _typeof(obj) { "@babel/helpers - typeof"; 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 _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } import { computed, defineComponent, getCurrentInstance, inject, onBeforeUnmount, onMounted, provide, reactive } from 'vue'; import omit from 'omit.js'; import PropTypes from '../_util/vue-types'; import Trigger from '../vc-trigger'; import KeyCode from '../_util/KeyCode'; import SubPopupMenu from './SubPopupMenu'; import placements from './placements'; import BaseMixin from '../_util/BaseMixin'; import { getComponent, splitAttrs, findDOMNode, getSlot } from '../_util/props-util'; import { requestAnimationTimeout, cancelAnimationTimeout } from '../_util/requestAnimationTimeout'; import { noop, getMenuIdFromSubMenuEventKey, loopMenuItemRecursively } from './util'; import { getTransitionProps, Transition } from '../_util/transition'; import InjectExtraProps from './InjectExtraProps'; function _isSlot(s) { return typeof s === 'function' || Object.prototype.toString.call(s) === '[object Object]' && !_isVNode(s); } 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); store.defaultActiveFirst[menuId] = defaultActiveFirst; }; var indexGuid = 0; var SubMenu = defineComponent((_defineComponent = { name: 'SubMenu', mixins: [BaseMixin], inheritAttrs: false, isSubMenu: true, props: { title: PropTypes.any, openKeys: PropTypes.array.def([]), openChange: PropTypes.func.def(noop), rootPrefixCls: PropTypes.string, eventKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), multiple: PropTypes.looseBool, isRootMenu: PropTypes.looseBool.def(false), index: PropTypes.number, triggerSubMenuAction: PropTypes.string, popupClassName: PropTypes.string, getPopupContainer: PropTypes.func, forceSubMenuRender: PropTypes.looseBool.def(false), openAnimation: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), disabled: PropTypes.looseBool, subMenuOpenDelay: PropTypes.number.def(0.1), subMenuCloseDelay: PropTypes.number.def(0.1), level: PropTypes.number.def(1), inlineIndent: PropTypes.number.def(24), openTransitionName: PropTypes.string, popupOffset: PropTypes.array, mode: PropTypes.oneOf(['horizontal', 'vertical', 'vertical-left', 'vertical-right', 'inline']).def('vertical'), manualRef: PropTypes.func.def(noop), builtinPlacements: PropTypes.object.def(function () { return {}; }), itemIcon: PropTypes.any, expandIcon: PropTypes.any, subMenuKey: PropTypes.string, theme: PropTypes.string, parentUniKeys: PropTypes.array.def(function () { return []; }), parentUniKey: PropTypes.string, isOverflowedSubMenu: PropTypes.looseBool.def(false) } }, _defineProperty(_defineComponent, "isSubMenu", true), _defineProperty(_defineComponent, "setup", function setup(props) { var uniKey = props.isOverflowedSubMenu ? 'MENUITEM_OVERFLOWED_UNI_KEY' : "sub_menu_".concat(++indexGuid); var store = inject('menuStore', function () { return {}; }); onMounted(function () { store.addChildrenInfo(uniKey, computed(function () { return { parentUniKeys: props.parentUniKeys, parentUniKey: props.parentUniKey, eventKey: props.eventKey, disabled: props.disabled }; })); }); onBeforeUnmount(function () { store.removeChildrenInfo(uniKey); }); var isChildrenSelected = computed(function () { return store.selectedParentUniKeys.indexOf(uniKey) !== -1; }); var ins = getCurrentInstance(); var getEl = function getEl() { return ins.vnode.el; }; provide('parentMenu', reactive({ isRootMenu: computed(function () { return props.isRootMenu; }), getPopupContainer: props.getPopupContainer, getEl: getEl })); return { parentMenu: inject('parentMenu', undefined), store: store, isChildrenSelected: isChildrenSelected, childrenUniKeys: [].concat(_toConsumableArray(props.parentUniKeys), [uniKey]), uniKey: uniKey, isOpen: computed(function () { return store.openKeys.indexOf(props.eventKey) > -1; }), active: computed(function () { return store.activeKey[props.subMenuKey] === props.eventKey; }) }; }), _defineProperty(_defineComponent, "data", function data() { var props = this.$props; var store = this.store; var eventKey = props.eventKey; var defaultActiveFirst = store.defaultActiveFirst; var value = false; if (defaultActiveFirst) { value = defaultActiveFirst[eventKey]; } updateDefaultActiveFirst(store, eventKey, value); this.internalMenuId = undefined; this.haveRendered = undefined; this.haveOpened = undefined; this.subMenuTitle = undefined; return {}; }), _defineProperty(_defineComponent, "mounted", function mounted() { var _this = this; this.$nextTick(function () { _this.handleUpdated(); }); }), _defineProperty(_defineComponent, "updated", function updated() { var _this2 = this; this.$nextTick(function () { _this2.handleUpdated(); }); }), _defineProperty(_defineComponent, "beforeUnmount", function beforeUnmount() { var eventKey = this.eventKey; this.__emit('destroy', eventKey); /* istanbul ignore if */ if (this.minWidthTimeout) { cancelAnimationTimeout(this.minWidthTimeout); this.minWidthTimeout = null; } /* istanbul ignore if */ if (this.mouseenterTimeout) { cancelAnimationTimeout(this.mouseenterTimeout); this.mouseenterTimeout = null; } }), _defineProperty(_defineComponent, "methods", { isChildrenSelected2: function isChildrenSelected2() { if (this.haveOpened) return this.isChildrenSelected; var ret = { find: false }; loopMenuItemRecursively(getSlot(this), this.store.selectedKeys, ret); return ret.find; }, handleUpdated: function handleUpdated() { var _this3 = this; var _this$$props = this.$props, mode = _this$$props.mode, manualRef = _this$$props.manualRef; // invoke customized ref to expose component to mixin if (manualRef) { manualRef(this); } if (mode !== 'horizontal' || !this.parentMenu.isRootMenu || !this.isOpen) { return; } this.minWidthTimeout = requestAnimationTimeout(function () { return _this3.adjustWidth(); }, 0); }, onKeyDown: function onKeyDown(e) { var keyCode = e.keyCode; var menu = this.menuInstance; var isOpen = this.isOpen; if (keyCode === KeyCode.ENTER) { this.onTitleClick(e); updateDefaultActiveFirst(this.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(this.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); } return undefined; }, onPopupVisibleChange: function onPopupVisibleChange(visible) { this.triggerOpenChange(visible, visible ? 'mouseenter' : 'mouseleave'); }, onMouseEnter: function onMouseEnter(e) { var key = this.$props.eventKey; updateDefaultActiveFirst(this.store, key, false); this.__emit('mouseenter', { key: key, domEvent: e }); }, onMouseLeave: function onMouseLeave(e) { var eventKey = this.$props.eventKey; this.__emit('mouseleave', { key: eventKey, domEvent: e }); }, onTitleMouseEnter: function onTitleMouseEnter(domEvent) { var key = this.$props.eventKey; this.__emit('itemHover', { key: key, hover: true }); this.__emit('titleMouseenter', { key: key, domEvent: domEvent }); }, onTitleMouseLeave: function onTitleMouseLeave(e) { var eventKey = this.$props.eventKey; this.__emit('itemHover', { key: eventKey, hover: false }); this.__emit('titleMouseleave', { key: eventKey, domEvent: e }); }, onTitleClick: function onTitleClick(e) { var _this$$props2 = this.$props, triggerSubMenuAction = _this$$props2.triggerSubMenuAction, eventKey = _this$$props2.eventKey; this.__emit('titleClick', { key: eventKey, domEvent: e }); if (triggerSubMenuAction === 'hover') { return; } this.triggerOpenChange(!this.isOpen, 'click'); updateDefaultActiveFirst(this.store, eventKey, false); }, onSubMenuClick: function onSubMenuClick(info) { this.__emit('click', this.addKeyPath(info)); }, getPrefixCls: function getPrefixCls() { return "".concat(this.$props.rootPrefixCls, "-submenu"); }, getActiveClassName: function getActiveClassName() { return "".concat(this.getPrefixCls(), "-active"); }, getDisabledClassName: function getDisabledClassName() { return "".concat(this.getPrefixCls(), "-disabled"); }, getSelectedClassName: function getSelectedClassName() { return "".concat(this.getPrefixCls(), "-selected"); }, getOpenClassName: function getOpenClassName() { return "".concat(this.$props.rootPrefixCls, "-submenu-open"); }, saveMenuInstance: function saveMenuInstance(c) { // children menu instance this.menuInstance = c; }, addKeyPath: function addKeyPath(info) { return _extends(_extends({}, info), { keyPath: (info.keyPath || []).concat(this.$props.eventKey) }); }, triggerOpenChange: function triggerOpenChange(open, type) { var _this4 = this; var key = this.$props.eventKey; var openChange = function openChange() { _this4.__emit('openChange', { key: key, item: _this4.$props, trigger: type, open: open }); }; if (type === 'mouseenter') { // make sure mouseenter happen after other menu item's mouseleave this.mouseenterTimeout = requestAnimationTimeout(function () { openChange(); }, 0); } else { openChange(); } }, adjustWidth: function adjustWidth() { /* 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"); }, saveSubMenuTitle: function saveSubMenuTitle(subMenuTitle) { this.subMenuTitle = subMenuTitle; }, renderChildren: function renderChildren() { var _slot; var props = _extends(_extends({}, this.$props), this.$attrs); var subPopupMenuProps = { mode: props.mode === 'horizontal' ? 'vertical' : props.mode, visible: this.isOpen, level: props.level + 1, inlineIndent: props.inlineIndent, focusable: false, eventKey: "".concat(props.eventKey, "-menu-"), openKeys: props.openKeys, openTransitionName: props.openTransitionName, openAnimation: props.openAnimation, subMenuOpenDelay: props.subMenuOpenDelay, subMenuCloseDelay: props.subMenuCloseDelay, forceSubMenuRender: props.forceSubMenuRender, triggerSubMenuAction: props.triggerSubMenuAction, builtinPlacements: props.builtinPlacements, multiple: props.multiple, prefixCls: props.rootPrefixCls, manualRef: this.saveMenuInstance, itemIcon: getComponent(this, 'itemIcon'), expandIcon: getComponent(this, 'expandIcon'), onClick: this.onSubMenuClick, onSelect: props.onSelect || noop, onDeselect: props.onDeselect || noop, onOpenChange: props.onOpenChange || noop, id: this.internalMenuId, parentUniKeys: this.childrenUniKeys, parentUniKey: this.uniKey }; var haveRendered = this.haveRendered; this.haveRendered = true; this.haveOpened = this.haveOpened || subPopupMenuProps.visible || subPopupMenuProps.forceSubMenuRender; // never rendered not planning to, don't render if (!this.haveOpened) { return _createVNode("div", null, null); } // don't show transition on first rendering (no animation for opened menu) // show appear transition if it's not visible (not sure why) // show appear transition if it's not inline mode var transitionAppear = haveRendered || !subPopupMenuProps.visible || !subPopupMenuProps.mode === 'inline'; subPopupMenuProps.class = " ".concat(subPopupMenuProps.prefixCls, "-sub"); var transitionProps = { appear: transitionAppear, css: false }; if (subPopupMenuProps.openTransitionName) { transitionProps = getTransitionProps(subPopupMenuProps.openTransitionName, { appear: transitionAppear }); } else if (_typeof(subPopupMenuProps.openAnimation) === 'object') { transitionProps = _extends(_extends({}, transitionProps), subPopupMenuProps.openAnimation || {}); if (!transitionAppear) { transitionProps.appear = false; } } else if (typeof subPopupMenuProps.openAnimation === 'string') { transitionProps = getTransitionProps(subPopupMenuProps.openAnimation, { appear: transitionAppear }); } return _createVNode(Transition, transitionProps, _isSlot(_slot = _withDirectives(_createVNode(SubPopupMenu, subPopupMenuProps, _objectSpread({}, this.$slots)), [[_vShow, this.isOpen]])) ? _slot : { default: function _default() { return [_slot]; } }); } }), _defineProperty(_defineComponent, "render", function render() { var _className, _createVNode2; var props = _extends(_extends({}, this.$props), this.$attrs); var _splitAttrs = splitAttrs(props), onEvents = _splitAttrs.onEvents; var isOpen = this.isOpen; var prefixCls = this.getPrefixCls(); var isInlineMode = props.mode === 'inline'; if (!this.internalMenuId) { if (props.eventKey) { this.internalMenuId = "".concat(props.eventKey, "$Menu"); } else { this.internalMenuId = "$__$".concat(++guid, "$Menu"); } } var children = this.renderChildren(); var className = (_className = {}, _defineProperty(_className, prefixCls, true), _defineProperty(_className, "".concat(prefixCls, "-").concat(props.mode), true), _defineProperty(_className, props.class, !!props.class), _defineProperty(_className, this.getOpenClassName(), isOpen), _defineProperty(_className, this.getActiveClassName(), this.active || isOpen && !isInlineMode), _defineProperty(_className, this.getDisabledClassName(), props.disabled), _defineProperty(_className, this.getSelectedClassName(), this.isChildrenSelected || this.isChildrenSelected2()), _className); 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 = "".concat(props.inlineIndent * props.level, "px"); } 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 (isOpen) { ariaOwns = { 'aria-owns': this.internalMenuId }; } var titleProps = _extends(_extends(_extends(_extends(_extends({ 'aria-expanded': isOpen }, ariaOwns), { 'aria-haspopup': 'true', title: typeof props.title === 'string' ? props.title : undefined }), titleMouseEvents), titleClickEvents), { style: style, class: "".concat(prefixCls, "-title"), ref: this.saveSubMenuTitle }); // expand custom icon should NOT be displayed in menu with horizontal mode. var icon = null; if (props.mode !== 'horizontal') { icon = getComponent(this, 'expandIcon', props); } var title = _createVNode("div", titleProps, [getComponent(this, 'title'), icon || _createVNode("i", { "class": "".concat(prefixCls, "-arrow") }, null)]); var getPopupContainer = this.parentMenu.isRootMenu ? this.parentMenu.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 || ''; popupClassName = "".concat(prefixCls, "-popup ").concat(popupClassName); var liProps = _extends(_extends(_extends({}, omit(onEvents, ['onClick'])), mouseEvents), { class: className, style: props.style }); return _createVNode("li", _objectSpread(_objectSpread({}, liProps), {}, { "role": "menuitem" }), [isInlineMode && title, isInlineMode && children, !isInlineMode && _createVNode(Trigger, (_createVNode2 = { "prefixCls": prefixCls, "popupClassName": popupClassName, "getPopupContainer": getPopupContainer, "builtinPlacements": placements }, _defineProperty(_createVNode2, "builtinPlacements", _extends({}, placements, props.builtinPlacements)), _defineProperty(_createVNode2, "popupPlacement", popupPlacement), _defineProperty(_createVNode2, "popupVisible", isOpen), _defineProperty(_createVNode2, "popupAlign", popupAlign), _defineProperty(_createVNode2, "action", props.disabled ? [] : [props.triggerSubMenuAction]), _defineProperty(_createVNode2, "mouseEnterDelay", props.subMenuOpenDelay), _defineProperty(_createVNode2, "mouseLeaveDelay", props.subMenuCloseDelay), _defineProperty(_createVNode2, "onPopupVisibleChange", this.onPopupVisibleChange), _defineProperty(_createVNode2, "forceRender", props.forceSubMenuRender), _defineProperty(_createVNode2, "popup", children), _createVNode2), _isSlot(title) ? title : { default: function _default() { return [title]; } })]); }), _defineComponent)); export default InjectExtraProps(SubMenu);