ant-design-vue
Version:
An enterprise-class UI design language and Vue-based implementation
418 lines (367 loc) • 13.5 kB
JavaScript
import { createVNode as _createVNode, isVNode as _isVNode } from "vue";
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); }
import { Comment, inject } from 'vue';
import PropTypes from '../_util/vue-types';
import BaseMixin from '../_util/BaseMixin';
import KeyCode from '../_util/KeyCode';
import classNames from '../_util/classNames';
import { getKeyFromChildrenIndex, noop, isMobileDevice, menuAllProps } from './util';
import DOMWrap from './DOMWrap';
import { initDefaultProps, getOptionProps, getComponent, splitAttrs, getSlot } from '../_util/props-util';
import FunctionProvider from './FunctionProvider'; // import { getActiveKey } from '../vc-tabs/src/utils';
function _isSlot(s) {
return typeof s === 'function' || Object.prototype.toString.call(s) === '[object Object]' && !_isVNode(s);
}
function allDisabled(arr) {
if (!arr.length) {
return true;
}
return arr.every(function (c) {
return !!c.disabled;
});
}
function updateActiveKey(store, menuId, activeKey) {
store.activeKey[menuId] = activeKey;
}
function getEventKey(props) {
// when eventKey not available ,it's menu and return menu id '0-menu-'
return props.eventKey || '0-menu-';
}
export function saveRef(key, c) {
if (c) {
var index = this.instanceArrayKeyIndexMap[key];
this.instanceArray[index] = c;
}
} // export function getActiveKey(props, originalActiveKey) {
// let activeKey = originalActiveKey;
// const { eventKey, defaultActiveFirst, children } = props;
// if (activeKey !== undefined && activeKey !== null) {
// let found;
// loopMenuItem(children, (c, i) => {
// const propsData = getPropsData(c);
// if (c && !propsData.disabled && activeKey === getKeyFromChildrenIndex(c, eventKey, i)) {
// found = true;
// }
// });
// if (found) {
// return activeKey;
// }
// }
// activeKey = null;
// if (defaultActiveFirst) {
// loopMenuItem(children, (c, i) => {
// const propsData = getPropsData(c);
// const noActiveKey = activeKey === null || activeKey === undefined;
// if (noActiveKey && c && !propsData.disabled) {
// activeKey = getKeyFromChildrenIndex(c, eventKey, i);
// }
// });
// return activeKey;
// }
// return activeKey;
// }
var SubPopupMenu = {
name: 'SubPopupMenu',
inheritAttrs: false,
props: initDefaultProps({
// onSelect: PropTypes.func,
// onClick: PropTypes.func,
// onDeselect: PropTypes.func,
// onOpenChange: PropTypes.func,
// onDestroy: PropTypes.func,
prefixCls: PropTypes.string,
openTransitionName: PropTypes.string,
openAnimation: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
openKeys: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number])),
visible: PropTypes.looseBool,
eventKey: PropTypes.string,
// adding in refactor
focusable: PropTypes.looseBool,
multiple: PropTypes.looseBool,
defaultActiveFirst: PropTypes.looseBool,
activeKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
defaultSelectedKeys: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number])),
defaultOpenKeys: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number])),
level: PropTypes.number,
mode: PropTypes.oneOf(['horizontal', 'vertical', 'vertical-left', 'vertical-right', 'inline']),
triggerSubMenuAction: PropTypes.oneOf(['click', 'hover']),
inlineIndent: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
manualRef: PropTypes.func,
itemIcon: PropTypes.any,
expandIcon: PropTypes.any,
overflowedIndicator: PropTypes.any,
children: PropTypes.any.def([]),
subMenuOpenDelay: PropTypes.number.def(0.1),
subMenuCloseDelay: PropTypes.number.def(0.1),
forceSubMenuRender: PropTypes.looseBool.def(false),
parentUniKeys: PropTypes.array.def(function () {
return [];
}),
parentUniKey: PropTypes.string,
theme: PropTypes.string
}, {
prefixCls: 'rc-menu',
mode: 'vertical',
level: 1,
inlineIndent: 24,
visible: true,
focusable: true,
manualRef: noop
}),
mixins: [BaseMixin],
setup: function setup() {
var store = inject('menuStore', function () {
return {};
});
return {
store: store
};
},
created: function created() {
var props = getOptionProps(this);
this.prevProps = _extends({}, props);
this.store.activeKey[props.eventKey] = this.store.getActiveKey(props.activeKey);
this.instanceArray = [];
},
mounted: function mounted() {
// invoke customized ref to expose component to mixin
if (this.manualRef) {
this.manualRef(this);
}
},
updated: function updated() {
var props = getOptionProps(this);
var prevProps = this.prevProps;
var originalActiveKey = 'activeKey' in props ? props.activeKey : this.store.activeKey[getEventKey(props)];
var activeKey = this.store.getActiveKey(originalActiveKey);
if (activeKey !== originalActiveKey) {
updateActiveKey(this.store, getEventKey(props), activeKey);
} else if ('activeKey' in prevProps) {
// If prev activeKey is not same as current activeKey,
// we should set it.
var prevActiveKey = this.store.getActiveKey(prevProps.activeKey);
if (activeKey !== prevActiveKey) {
updateActiveKey(this.store, getEventKey(props), activeKey);
}
}
this.prevProps = _extends({}, props);
},
methods: {
// all keyboard events callbacks run from here at first
onKeyDown: function onKeyDown(e, callback) {
var keyCode = e.keyCode;
var handled;
this.getFlatInstanceArray().forEach(function (obj) {
if (obj && obj.active && obj.onKeyDown) {
handled = obj.onKeyDown(e);
}
});
if (handled) {
return 1;
}
var activeItem = null;
if (keyCode === KeyCode.UP || keyCode === KeyCode.DOWN) {
activeItem = this.step(keyCode === KeyCode.UP ? -1 : 1);
}
if (activeItem) {
e.preventDefault();
updateActiveKey(this.store, getEventKey(this.$props), activeItem.eventKey);
if (typeof callback === 'function') {
callback(activeItem);
}
return 1;
}
return undefined;
},
onItemHover: function onItemHover(e) {
var key = e.key,
hover = e.hover;
updateActiveKey(this.store, getEventKey(this.$props), hover ? key : null);
},
onDeselect: function onDeselect(selectInfo) {
this.__emit('deselect', selectInfo);
},
onSelect: function onSelect(selectInfo) {
this.__emit('select', selectInfo);
},
onClick: function onClick(e) {
this.__emit('click', e);
},
onOpenChange: function onOpenChange(e) {
this.__emit('openChange', e);
},
onDestroy: function onDestroy(key) {
this.__emit('destroy', key);
},
getFlatInstanceArray: function getFlatInstanceArray() {
return this.instanceArray;
},
getOpenTransitionName: function getOpenTransitionName() {
return this.$props.openTransitionName;
},
step: function step(direction) {
var children = this.getFlatInstanceArray();
var activeKey = this.store.activeKey[getEventKey(this.$props)];
var len = children.length;
if (!len) {
return null;
}
if (direction < 0) {
children = children.concat().reverse();
} // find current activeIndex
var activeIndex = -1;
children.every(function (c, ci) {
if (c && c.eventKey === activeKey) {
activeIndex = ci;
return false;
}
return true;
});
if (!this.defaultActiveFirst && activeIndex !== -1 && allDisabled(children.slice(activeIndex, len - 1))) {
return undefined;
}
var start = (activeIndex + 1) % len;
var i = start;
do {
var child = children[i];
if (!child || child.disabled) {
i = (i + 1) % len;
} else {
return child;
}
} while (i !== start);
return null;
},
getIcon: function getIcon(instance, name) {
return getComponent(instance, name);
},
renderCommonMenuItem: function renderCommonMenuItem(child, i, extraProps) {
var _this = this;
if (child.type === Comment) {
return child;
}
var state = this.store;
var props = this.$props;
var key = getKeyFromChildrenIndex(child, props.eventKey, i);
var childProps = child.props || {}; // child.props 包含事件
var isActive = key === state.activeKey[getEventKey(this.$props)];
if (!childProps.disabled) {
// manualRef的执行顺序不能保证,使用key映射ref在this.instanceArray中的位置
this.instanceArrayKeyIndexMap[key] = Object.keys(this.instanceArrayKeyIndexMap).length;
}
var newChildProps = _extends(_extends({
mode: childProps.mode || props.mode,
level: props.level,
inlineIndent: props.inlineIndent,
renderMenuItem: this.renderMenuItem,
rootPrefixCls: props.prefixCls,
index: i,
// customized ref function, need to be invoked manually in child's componentDidMount
manualRef: childProps.disabled ? noop : saveRef.bind(this, key),
eventKey: key,
active: !childProps.disabled && isActive,
multiple: props.multiple,
openTransitionName: this.getOpenTransitionName(),
openAnimation: props.openAnimation,
subMenuOpenDelay: props.subMenuOpenDelay,
subMenuCloseDelay: props.subMenuCloseDelay,
builtinPlacements: props.builtinPlacements,
itemIcon: this.getIcon(child, 'itemIcon') || this.getIcon(this, 'itemIcon'),
expandIcon: this.getIcon(child, 'expandIcon') || this.getIcon(this, 'expandIcon')
}, extraProps), {
onClick: function onClick(e) {
(childProps.onClick || noop)(e);
_this.onClick(e);
},
onItemHover: this.onItemHover,
onOpenChange: this.onOpenChange,
onDeselect: this.onDeselect,
// destroy: this.onDestroy,
onSelect: this.onSelect,
parentUniKeys: this.parentUniKeys,
parentUniKey: this.parentUniKey
});
if (props.forceSubMenuRender !== undefined) {
newChildProps.forceSubMenuRender = props.forceSubMenuRender;
} // ref: https://github.com/ant-design/ant-design/issues/13943
if (props.mode === 'inline' || isMobileDevice()) {
newChildProps.triggerSubMenuAction = 'click';
}
return _createVNode(FunctionProvider, {
"extraProps": newChildProps
}, _isSlot(child) ? child : {
default: function _default() {
return [child];
}
});
},
renderMenuItem: function renderMenuItem(c, i, subMenuKey) {
if (!c) {
return null;
}
var state = this.store;
var extraProps = {
openKeys: state.openKeys,
selectedKeys: state.selectedKeys,
triggerSubMenuAction: this.triggerSubMenuAction,
isRootMenu: false,
subMenuKey: subMenuKey
};
return this.renderCommonMenuItem(c, i, extraProps);
}
},
render: function render() {
var _slot;
var _this2 = this;
var props = _extends({}, this.$props);
var _splitAttrs = splitAttrs(this.$attrs),
onEvents = _splitAttrs.onEvents,
extraAttrs = _splitAttrs.extraAttrs;
var eventKey = props.eventKey,
prefixCls = props.prefixCls,
visible = props.visible,
level = props.level,
mode = props.mode,
theme = props.theme;
this.instanceArray = [];
this.instanceArrayKeyIndexMap = {};
var className = classNames(extraAttrs.class, props.prefixCls, "".concat(props.prefixCls, "-").concat(props.mode));
menuAllProps.forEach(function (key) {
return delete props[key];
}); // Otherwise, the propagated click event will trigger another onClick
delete onEvents.onClick;
var domWrapProps = _extends(_extends(_extends({}, props), {
tag: 'ul',
// hiddenClassName: `${prefixCls}-hidden`,
visible: visible,
prefixCls: prefixCls,
level: level,
mode: mode,
theme: theme,
overflowedIndicator: getComponent(this, 'overflowedIndicator'),
role: props.role || 'menu',
class: className,
style: extraAttrs.style
}), onEvents);
if (extraAttrs.id !== undefined) {
domWrapProps.id = extraAttrs.id;
}
if (props.focusable) {
domWrapProps.tabindex = '0';
domWrapProps.onKeydown = this.onKeyDown;
}
delete domWrapProps.children;
return (// ESLint is not smart enough to know that the type of `children` was checked.
/* eslint-disable */
_createVNode(DOMWrap, domWrapProps, _isSlot(_slot = getSlot(this).map(function (c, i) {
return _this2.renderMenuItem(c, i, eventKey || '0-menu-');
})) ? _slot : {
default: function _default() {
return [_slot];
}
})
/*eslint -enable */
);
}
};
export default SubPopupMenu;