refactor: remove rc-menu
							parent
							
								
									8179361803
								
							
						
					
					
						commit
						3d0edbc292
					
				|  | @ -134,8 +134,8 @@ export default defineComponent({ | |||
| 
 | ||||
|     watch( | ||||
|       () => props.selectedKeys, | ||||
|       (selectedKeys = mergedSelectedKeys.value) => { | ||||
|         mergedSelectedKeys.value = selectedKeys; | ||||
|       selectedKeys => { | ||||
|         mergedSelectedKeys.value = selectedKeys || mergedSelectedKeys.value; | ||||
|       }, | ||||
|       { immediate: true }, | ||||
|     ); | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| import classNames from '../../_util/classNames'; | ||||
| import { FunctionalComponent, provide } from 'vue'; | ||||
| import { FunctionalComponent } from 'vue'; | ||||
| import { useInjectMenu } from './hooks/useMenuContext'; | ||||
| const InternalSubMenuList: FunctionalComponent<any> = (_props, { slots, attrs }) => { | ||||
|   const { prefixCls, mode } = useInjectMenu(); | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| import { reactive, defineComponent, nextTick, computed, watch } from 'vue'; | ||||
| import FilterFilled from '@ant-design/icons-vue/FilterFilled'; | ||||
| import Menu, { SubMenu, Item as MenuItem } from '../vc-menu'; | ||||
| import Menu, { SubMenu, MenuItem } from '../menu'; | ||||
| import closest from '../_util/dom-closest'; | ||||
| import classNames from '../_util/classNames'; | ||||
| import shallowequal from '../_util/shallowequal'; | ||||
|  |  | |||
|  | @ -1,310 +0,0 @@ | |||
| import PropTypes from '../_util/vue-types'; | ||||
| import SubMenu from './SubMenu'; | ||||
| import BaseMixin from '../_util/BaseMixin'; | ||||
| import { getWidth, setStyle, menuAllProps } from './util'; | ||||
| import { cloneElement } from '../_util/vnode'; | ||||
| import { getAllProps, getSlot, findDOMNode } from '../_util/props-util'; | ||||
| 
 | ||||
| const MENUITEM_OVERFLOWED_CLASSNAME = 'menuitem-overflowed'; | ||||
| const FLOAT_PRECISION_ADJUST = 0.5; | ||||
| const MENUITEM_OVERFLOWED_UNI_KEY = 'MENUITEM_OVERFLOWED_UNI_KEY'; | ||||
| const MENUITEM_OVERFLOWED_UNI_KEYS = [MENUITEM_OVERFLOWED_UNI_KEY]; | ||||
| 
 | ||||
| const DOMWrap = { | ||||
|   name: 'DOMWrap', | ||||
|   mixins: [BaseMixin], | ||||
|   data() { | ||||
|     this.resizeObserver = null; | ||||
|     this.mutationObserver = null; | ||||
| 
 | ||||
|     // original scroll size of the list | ||||
|     this.originalTotalWidth = 0; | ||||
| 
 | ||||
|     // copy of overflowed items | ||||
|     this.overflowedItems = []; | ||||
| 
 | ||||
|     // cache item of the original items (so we can track the size and order) | ||||
|     this.menuItemSizes = []; | ||||
|     return { | ||||
|       lastVisibleIndex: undefined, | ||||
|     }; | ||||
|   }, | ||||
| 
 | ||||
|   mounted() { | ||||
|     this.$nextTick(() => { | ||||
|       this.setChildrenWidthAndResize(); | ||||
|       if (this.level === 1 && this.mode === 'horizontal') { | ||||
|         const menuUl = findDOMNode(this); | ||||
|         if (!menuUl) { | ||||
|           return; | ||||
|         } | ||||
|         this.resizeObserver = new ResizeObserver(entries => { | ||||
|           entries.forEach(this.setChildrenWidthAndResize); | ||||
|         }); | ||||
| 
 | ||||
|         [].slice | ||||
|           .call(menuUl.children) | ||||
|           .concat(menuUl) | ||||
|           .forEach(el => { | ||||
|             this.resizeObserver.observe(el); | ||||
|           }); | ||||
| 
 | ||||
|         if (typeof MutationObserver !== 'undefined') { | ||||
|           this.mutationObserver = new MutationObserver(() => { | ||||
|             this.resizeObserver.disconnect(); | ||||
|             [].slice | ||||
|               .call(menuUl.children) | ||||
|               .concat(menuUl) | ||||
|               .forEach(el => { | ||||
|                 this.resizeObserver.observe(el); | ||||
|               }); | ||||
|             this.setChildrenWidthAndResize(); | ||||
|           }); | ||||
|           this.mutationObserver.observe(menuUl, { | ||||
|             attributes: false, | ||||
|             childList: true, | ||||
|             subTree: false, | ||||
|           }); | ||||
|         } | ||||
|       } | ||||
|     }); | ||||
|   }, | ||||
| 
 | ||||
|   beforeUnmount() { | ||||
|     if (this.resizeObserver) { | ||||
|       this.resizeObserver.disconnect(); | ||||
|     } | ||||
|     if (this.mutationObserver) { | ||||
|       this.mutationObserver.disconnect(); | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     // get all valid menuItem nodes | ||||
|     getMenuItemNodes() { | ||||
|       const { prefixCls } = this.$props; | ||||
|       const ul = findDOMNode(this); | ||||
|       if (!ul) { | ||||
|         return []; | ||||
|       } | ||||
| 
 | ||||
|       // filter out all overflowed indicator placeholder | ||||
|       return [].slice | ||||
|         .call(ul.children) | ||||
|         .filter(node => node.className.split(' ').indexOf(`${prefixCls}-overflowed-submenu`) < 0); | ||||
|     }, | ||||
| 
 | ||||
|     getOverflowedSubMenuItem(keyPrefix, overflowedItems, renderPlaceholder) { | ||||
|       const { overflowedIndicator, level, mode, prefixCls, theme } = this.$props; | ||||
|       if (level !== 1 || mode !== 'horizontal') { | ||||
|         return null; | ||||
|       } | ||||
|       // put all the overflowed item inside a submenu | ||||
|       // with a title of overflow indicator ('...') | ||||
|       const copy = getSlot(this)[0]; | ||||
|       const allProps = getAllProps(copy) || {}; | ||||
|       const { title, extraProps, ...rest } = { ...allProps, ...allProps.extraProps }; // eslint-disable-line no-unused-vars | ||||
|       let style = {}; | ||||
|       let key = `${keyPrefix}-overflowed-indicator`; | ||||
|       let eventKey = `${keyPrefix}-overflowed-indicator`; | ||||
| 
 | ||||
|       if (overflowedItems.length === 0 && renderPlaceholder !== true) { | ||||
|         style = { | ||||
|           display: 'none', | ||||
|         }; | ||||
|       } else if (renderPlaceholder) { | ||||
|         style = { | ||||
|           visibility: 'hidden', | ||||
|           // prevent from taking normal dom space | ||||
|           position: 'absolute', | ||||
|         }; | ||||
|         key = `${key}-placeholder`; | ||||
|         eventKey = `${eventKey}-placeholder`; | ||||
|       } | ||||
| 
 | ||||
|       const popupClassName = theme ? `${prefixCls}-${theme}` : ''; | ||||
|       const props = {}; | ||||
|       menuAllProps.forEach(k => { | ||||
|         if (rest[k] !== undefined) { | ||||
|           props[k] = rest[k]; | ||||
|         } | ||||
|       }); | ||||
|       const subMenuProps = { | ||||
|         title: overflowedIndicator, | ||||
|         popupClassName, | ||||
|         ...props, | ||||
|         eventKey, | ||||
|         disabled: false, | ||||
|         class: `${prefixCls}-overflowed-submenu`, | ||||
|         key, | ||||
|         style, | ||||
|         isOverflowedSubMenu: true, | ||||
|       }; | ||||
|       return <SubMenu {...subMenuProps}>{overflowedItems}</SubMenu>; | ||||
|     }, | ||||
| 
 | ||||
|     // memorize rendered menuSize | ||||
|     setChildrenWidthAndResize() { | ||||
|       if (this.mode !== 'horizontal') { | ||||
|         return; | ||||
|       } | ||||
|       const ul = findDOMNode(this); | ||||
| 
 | ||||
|       if (!ul) { | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       const ulChildrenNodes = ul.children; | ||||
| 
 | ||||
|       if (!ulChildrenNodes || ulChildrenNodes.length === 0) { | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       const lastOverflowedIndicatorPlaceholder = ul.children[ulChildrenNodes.length - 1]; | ||||
| 
 | ||||
|       // need last overflowed indicator for calculating length; | ||||
|       setStyle(lastOverflowedIndicatorPlaceholder, 'display', 'inline-block'); | ||||
| 
 | ||||
|       const menuItemNodes = this.getMenuItemNodes(); | ||||
| 
 | ||||
|       // reset display attribute for all hidden elements caused by overflow to calculate updated width | ||||
|       // and then reset to original state after width calculation | ||||
| 
 | ||||
|       const overflowedItems = menuItemNodes.filter( | ||||
|         c => c.className.split(' ').indexOf(MENUITEM_OVERFLOWED_CLASSNAME) >= 0, | ||||
|       ); | ||||
| 
 | ||||
|       overflowedItems.forEach(c => { | ||||
|         setStyle(c, 'display', 'inline-block'); | ||||
|       }); | ||||
| 
 | ||||
|       this.menuItemSizes = menuItemNodes.map(c => getWidth(c)); | ||||
| 
 | ||||
|       overflowedItems.forEach(c => { | ||||
|         setStyle(c, 'display', 'none'); | ||||
|       }); | ||||
|       this.overflowedIndicatorWidth = getWidth(ul.children[ul.children.length - 1]); | ||||
|       this.originalTotalWidth = this.menuItemSizes.reduce((acc, cur) => acc + cur, 0); | ||||
|       this.handleResize(); | ||||
|       // prevent the overflowed indicator from taking space; | ||||
|       setStyle(lastOverflowedIndicatorPlaceholder, 'display', 'none'); | ||||
|     }, | ||||
| 
 | ||||
|     handleResize() { | ||||
|       if (this.mode !== 'horizontal') { | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       const ul = findDOMNode(this); | ||||
|       if (!ul) { | ||||
|         return; | ||||
|       } | ||||
|       const width = getWidth(ul); | ||||
| 
 | ||||
|       this.overflowedItems = []; | ||||
|       let currentSumWidth = 0; | ||||
| 
 | ||||
|       // index for last visible child in horizontal mode | ||||
|       let lastVisibleIndex; | ||||
| 
 | ||||
|       // float number comparison could be problematic | ||||
|       // e.g. 0.1 + 0.2 > 0.3 =====> true | ||||
|       // thus using FLOAT_PRECISION_ADJUST as buffer to help the situation | ||||
|       if (this.originalTotalWidth > width + FLOAT_PRECISION_ADJUST) { | ||||
|         lastVisibleIndex = -1; | ||||
| 
 | ||||
|         this.menuItemSizes.forEach(liWidth => { | ||||
|           currentSumWidth += liWidth; | ||||
|           if (currentSumWidth + this.overflowedIndicatorWidth <= width) { | ||||
|             lastVisibleIndex += 1; | ||||
|           } | ||||
|         }); | ||||
|       } | ||||
| 
 | ||||
|       this.setState({ lastVisibleIndex }); | ||||
|     }, | ||||
| 
 | ||||
|     renderChildren(children) { | ||||
|       // need to take care of overflowed items in horizontal mode | ||||
|       const { lastVisibleIndex } = this.$data; | ||||
|       const className = this.$attrs.class || ''; | ||||
|       return (children || []).reduce((acc, childNode, index) => { | ||||
|         let item = childNode; | ||||
|         const { extraProps = {} } = item.props || {}; | ||||
|         const { eventKey } = extraProps; | ||||
|         if (this.mode === 'horizontal') { | ||||
|           let overflowed = this.getOverflowedSubMenuItem(eventKey, []); | ||||
|           if ( | ||||
|             lastVisibleIndex !== undefined && | ||||
|             className.indexOf(`${this.prefixCls}-root`) !== -1 | ||||
|           ) { | ||||
|             if (index > lastVisibleIndex) { | ||||
|               item = cloneElement( | ||||
|                 childNode, | ||||
|                 // 这里修改 eventKey 是为了防止隐藏状态下还会触发 openkeys 事件 | ||||
|                 { | ||||
|                   extraProps: { | ||||
|                     ...extraProps, | ||||
|                     style: { display: 'none' }, | ||||
|                     eventKey: `${eventKey}-hidden`, | ||||
|                     class: MENUITEM_OVERFLOWED_CLASSNAME, | ||||
|                     parentUniKey: MENUITEM_OVERFLOWED_UNI_KEY, | ||||
|                     parentUniKeys: MENUITEM_OVERFLOWED_UNI_KEYS, | ||||
|                   }, | ||||
|                 }, | ||||
|               ); | ||||
|             } | ||||
|             if (index === lastVisibleIndex + 1) { | ||||
|               this.overflowedItems = children.slice(lastVisibleIndex + 1).map(c => { | ||||
|                 const { extraProps = {} } = c.props || {}; | ||||
|                 const { eventKey } = extraProps; | ||||
|                 return cloneElement( | ||||
|                   c, | ||||
|                   // children[index].key will become '.$key' in clone by default, | ||||
|                   // we have to overwrite with the correct key explicitly | ||||
|                   { | ||||
|                     extraProps: { | ||||
|                       ...extraProps, | ||||
|                       key: eventKey, | ||||
|                       mode: 'vertical-left', | ||||
|                       parentUniKey: MENUITEM_OVERFLOWED_UNI_KEY, | ||||
|                       parentUniKeys: MENUITEM_OVERFLOWED_UNI_KEYS, | ||||
|                     }, | ||||
|                   }, | ||||
|                 ); | ||||
|               }); | ||||
| 
 | ||||
|               overflowed = this.getOverflowedSubMenuItem(eventKey, this.overflowedItems); | ||||
|             } | ||||
|           } | ||||
| 
 | ||||
|           const ret = [...acc, overflowed, item]; | ||||
| 
 | ||||
|           if (index === children.length - 1) { | ||||
|             // need a placeholder for calculating overflowed indicator width | ||||
|             ret.push(this.getOverflowedSubMenuItem(eventKey, [], true)); | ||||
|           } | ||||
|           return ret; | ||||
|         } | ||||
|         return [...acc, item]; | ||||
|       }, []); | ||||
|     }, | ||||
|   }, | ||||
| 
 | ||||
|   render() { | ||||
|     const Tag = this.$props.tag; | ||||
|     return <Tag>{this.renderChildren(getSlot(this))}</Tag>; | ||||
|   }, | ||||
| }; | ||||
| 
 | ||||
| DOMWrap.props = { | ||||
|   mode: PropTypes.oneOf(['horizontal', 'vertical', 'vertical-left', 'vertical-right', 'inline']), | ||||
|   prefixCls: PropTypes.string, | ||||
|   level: PropTypes.number, | ||||
|   theme: PropTypes.string, | ||||
|   overflowedIndicator: PropTypes.any, | ||||
|   visible: PropTypes.looseBool, | ||||
|   hiddenClassName: PropTypes.string, | ||||
|   tag: PropTypes.string.def('div'), | ||||
| }; | ||||
| 
 | ||||
| export default DOMWrap; | ||||
|  | @ -1,23 +0,0 @@ | |||
| import { inject } from 'vue'; | ||||
| import { injectExtraPropsKey } from './FunctionProvider'; | ||||
| export default { | ||||
|   name: 'MenuDivider', | ||||
|   inheritAttrs: false, | ||||
|   props: { | ||||
|     disabled: { | ||||
|       type: Boolean, | ||||
|       default: true, | ||||
|     }, | ||||
|     rootPrefixCls: String, | ||||
|   }, | ||||
|   setup() { | ||||
|     return { | ||||
|       injectExtraProps: inject(injectExtraPropsKey, () => ({})), | ||||
|     }; | ||||
|   }, | ||||
|   render() { | ||||
|     const { rootPrefixCls } = { ...this.$props, ...this.injectExtraProps }; | ||||
|     const { class: className = '', style } = this.$attrs; | ||||
|     return <li class={[className, `${rootPrefixCls}-item-divider`]} style={style} />; | ||||
|   }, | ||||
| }; | ||||
|  | @ -1,20 +0,0 @@ | |||
| // import PropTypes from '../_util/vue-types'; | ||||
| import { computed, provide } from 'vue'; | ||||
| import { propTypes } from '../vc-progress/src/types'; | ||||
| export const injectExtraPropsKey = Symbol(); | ||||
| const FunctionProvider = { | ||||
|   inheritAttrs: false, | ||||
|   isMenuProvider: true, | ||||
|   props: { | ||||
|     extraProps: propTypes.object, | ||||
|   }, | ||||
|   setup(props, { slots }) { | ||||
|     provide( | ||||
|       injectExtraPropsKey, | ||||
|       computed(() => props.extraProps), | ||||
|     ); | ||||
|     return () => slots.default?.(); | ||||
|   }, | ||||
| }; | ||||
| 
 | ||||
| export default FunctionProvider; | ||||
|  | @ -1,46 +0,0 @@ | |||
| import { createVNode, defineComponent, inject, provide, watch } from 'vue'; | ||||
| import { injectExtraPropsKey } from './FunctionProvider'; | ||||
| 
 | ||||
| export default function wrapWithConnect(WrappedComponent) { | ||||
|   const tempProps = WrappedComponent.props || {}; | ||||
|   const props = {}; | ||||
|   Object.keys(tempProps).forEach(k => { | ||||
|     props[k] = { ...tempProps[k], required: false }; | ||||
|   }); | ||||
|   const Connect = { | ||||
|     name: `Connect_${WrappedComponent.name}`, | ||||
|     inheritAttrs: false, | ||||
|     props, | ||||
|     setup(props) { | ||||
|       provide(injectExtraPropsKey, undefined); // 断掉 injectExtraPropsKey 的依赖
 | ||||
|       const injectExtraProps = injectExtraPropsKey ? inject(injectExtraPropsKey, () => ({})) : {}; | ||||
|       watch(injectExtraProps, () => { | ||||
|         // 神奇的问题,vue 3.0.3 之后,没能正确响应式,暂时加个 watch hack 一下
 | ||||
|       }); | ||||
|       return { | ||||
|         props, | ||||
|         injectExtraProps, | ||||
|       }; | ||||
|     }, | ||||
|     methods: { | ||||
|       getWrappedInstance() { | ||||
|         return this.$refs.wrappedInstance; | ||||
|       }, | ||||
|     }, | ||||
|     render() { | ||||
|       const { $slots = {}, $attrs } = this; | ||||
|       const props = { ...this.props, ...this.injectExtraProps }; | ||||
|       const wrapProps = { | ||||
|         ...$attrs, | ||||
|         ...props, | ||||
|         ref: 'wrappedInstance', | ||||
|       }; | ||||
|       // const slots = {};
 | ||||
|       // for (let [key, value] of Object.entries($slots)) {
 | ||||
|       //   slots[key] = () => value();
 | ||||
|       // }
 | ||||
|       return createVNode(WrappedComponent, wrapProps, $slots); | ||||
|     }, | ||||
|   }; | ||||
|   return defineComponent(Connect); | ||||
| } | ||||
|  | @ -1,217 +0,0 @@ | |||
| import PropTypes from '../_util/vue-types'; | ||||
| import { default as SubPopupMenu } from './SubPopupMenu'; | ||||
| import BaseMixin from '../_util/BaseMixin'; | ||||
| import hasProp, { getOptionProps, getComponent } from '../_util/props-util'; | ||||
| import commonPropsType from './commonPropsType'; | ||||
| import { | ||||
|   computed, | ||||
|   defineComponent, | ||||
|   getCurrentInstance, | ||||
|   provide, | ||||
|   reactive, | ||||
|   ref, | ||||
|   toRaw, | ||||
|   watch, | ||||
| } from 'vue'; | ||||
| import isEqual from 'lodash-es/isEqual'; | ||||
| 
 | ||||
| const Menu = { | ||||
|   name: 'Menu', | ||||
|   inheritAttrs: false, | ||||
|   props: { | ||||
|     ...commonPropsType, | ||||
|     onClick: PropTypes.func, | ||||
|     selectable: PropTypes.looseBool.def(true), | ||||
|   }, | ||||
|   mixins: [BaseMixin], | ||||
|   setup(props) { | ||||
|     const menuChildrenInfo = reactive({}); | ||||
|     const selectedKeys = ref(props.selectedKeys || props.defaultSelectedKeys || []); | ||||
|     const openKeys = ref(props.openKeys || props.defaultOpenKeys || []); | ||||
|     //  computed(() => { | ||||
|     //   return props.openKeys || props.defaultOpenKeys || []; | ||||
|     // }); | ||||
|     watch( | ||||
|       () => props.selectedKeys, | ||||
|       () => { | ||||
|         selectedKeys.value = props.selectedKeys || []; | ||||
|       }, | ||||
|     ); | ||||
|     watch( | ||||
|       () => props.openKeys, | ||||
|       () => { | ||||
|         openKeys.value = props.openKeys || []; | ||||
|       }, | ||||
|     ); | ||||
|     const activeKey = reactive({ | ||||
|       '0-menu-': props.activeKey, | ||||
|     }); | ||||
|     const defaultActiveFirst = reactive({}); | ||||
|     const addChildrenInfo = (key, info) => { | ||||
|       menuChildrenInfo[key] = info; | ||||
|     }; | ||||
|     const removeChildrenInfo = key => { | ||||
|       delete menuChildrenInfo[key]; | ||||
|     }; | ||||
|     const getActiveKey = key => { | ||||
|       return key; | ||||
|     }; // TODO | ||||
|     const selectedParentUniKeys = ref([]); | ||||
|     watch(menuChildrenInfo, () => { | ||||
|       const keys = Object.values(menuChildrenInfo) | ||||
|         .filter(info => info.isSelected) | ||||
|         .reduce((allKeys, { parentUniKeys = [] }) => { | ||||
|           return [...allKeys, ...toRaw(parentUniKeys)]; | ||||
|         }, []); | ||||
|       if (!isEqual(selectedParentUniKeys.value, keys)) { | ||||
|         selectedParentUniKeys.value = keys || []; | ||||
|       } | ||||
|     }); | ||||
|     const store = reactive({ | ||||
|       selectedKeys, | ||||
|       openKeys, | ||||
|       activeKey, | ||||
|       defaultActiveFirst, | ||||
|       menuChildrenInfo, | ||||
|       selectedParentUniKeys, | ||||
|       addChildrenInfo, | ||||
|       removeChildrenInfo, | ||||
|       getActiveKey, | ||||
|     }); | ||||
|     const ins = getCurrentInstance(); | ||||
|     const getEl = () => { | ||||
|       return ins.vnode.el; | ||||
|     }; | ||||
|     provide('menuStore', store); | ||||
|     provide( | ||||
|       'parentMenu', | ||||
|       reactive({ | ||||
|         isRootMenu: computed(() => props.isRootMenu), | ||||
|         getPopupContainer: computed(() => props.getPopupContainer), | ||||
|         getEl, | ||||
|       }), | ||||
|     ); | ||||
|     return { | ||||
|       store, | ||||
|     }; | ||||
|   }, | ||||
|   methods: { | ||||
|     handleSelect(selectInfo) { | ||||
|       const props = this.$props; | ||||
|       if (props.selectable) { | ||||
|         // root menu | ||||
|         let selectedKeys = this.store.selectedKeys; | ||||
|         const selectedKey = selectInfo.key; | ||||
|         if (props.multiple) { | ||||
|           selectedKeys = selectedKeys.concat([selectedKey]); | ||||
|         } else { | ||||
|           selectedKeys = [selectedKey]; | ||||
|         } | ||||
|         if (!hasProp(this, 'selectedKeys')) { | ||||
|           this.store.selectedKeys = selectedKeys; | ||||
|         } | ||||
|         this.__emit('select', { | ||||
|           ...selectInfo, | ||||
|           selectedKeys, | ||||
|         }); | ||||
|       } | ||||
|     }, | ||||
| 
 | ||||
|     handleClick(e) { | ||||
|       this.__emit('click', e); | ||||
|     }, | ||||
|     // onKeyDown needs to be exposed as a instance method | ||||
|     // e.g., in rc-select, we need to navigate menu item while | ||||
|     // current active item is rc-select input box rather than the menu itself | ||||
|     onKeyDown(e, callback) { | ||||
|       this.innerMenu.getWrappedInstance().onKeyDown(e, callback); | ||||
|     }, | ||||
|     onOpenChange(event) { | ||||
|       const openKeys = this.store.openKeys.concat(); | ||||
|       let changed = false; | ||||
|       const processSingle = e => { | ||||
|         let oneChanged = false; | ||||
|         if (e.open) { | ||||
|           oneChanged = openKeys.indexOf(e.key) === -1; | ||||
|           if (oneChanged) { | ||||
|             openKeys.push(e.key); | ||||
|           } | ||||
|         } else { | ||||
|           const index = openKeys.indexOf(e.key); | ||||
|           oneChanged = index !== -1; | ||||
|           if (oneChanged) { | ||||
|             openKeys.splice(index, 1); | ||||
|           } | ||||
|         } | ||||
|         changed = changed || oneChanged; | ||||
|       }; | ||||
|       if (Array.isArray(event)) { | ||||
|         // batch change call | ||||
|         event.forEach(processSingle); | ||||
|       } else { | ||||
|         processSingle(event); | ||||
|       } | ||||
|       if (changed) { | ||||
|         if (!hasProp(this, 'openKeys')) { | ||||
|           this.store.openKeys = openKeys; | ||||
|         } | ||||
|         this.__emit('openChange', openKeys); | ||||
|       } | ||||
|     }, | ||||
| 
 | ||||
|     handleDeselect(selectInfo) { | ||||
|       const props = this.$props; | ||||
|       if (props.selectable) { | ||||
|         const selectedKeys = this.store.selectedKeys.concat(); | ||||
|         const selectedKey = selectInfo.key; | ||||
|         const index = selectedKeys.indexOf(selectedKey); | ||||
|         if (index !== -1) { | ||||
|           selectedKeys.splice(index, 1); | ||||
|         } | ||||
|         if (!hasProp(this, 'selectedKeys')) { | ||||
|           this.store.selectedKeys = selectedKeys; | ||||
|         } | ||||
|         this.__emit('deselect', { | ||||
|           ...selectInfo, | ||||
|           selectedKeys, | ||||
|         }); | ||||
|       } | ||||
|     }, | ||||
| 
 | ||||
|     getOpenTransitionName() { | ||||
|       const props = this.$props; | ||||
|       let transitionName = props.openTransitionName; | ||||
|       const animationName = props.openAnimation; | ||||
|       if (!transitionName && typeof animationName === 'string') { | ||||
|         transitionName = `${props.prefixCls}-open-${animationName}`; | ||||
|       } | ||||
|       return transitionName; | ||||
|     }, | ||||
|     saveInnerMenu(ref) { | ||||
|       this.innerMenu = ref; | ||||
|     }, | ||||
|   }, | ||||
| 
 | ||||
|   render() { | ||||
|     const props = { ...getOptionProps(this), ...this.$attrs }; | ||||
|     props.class = props.class | ||||
|       ? `${props.class} ${props.prefixCls}-root` | ||||
|       : `${props.prefixCls}-root`; | ||||
|     const subPopupMenuProps = { | ||||
|       ...props, | ||||
|       itemIcon: getComponent(this, 'itemIcon', props), | ||||
|       expandIcon: getComponent(this, 'expandIcon', props), | ||||
|       overflowedIndicator: getComponent(this, 'overflowedIndicator', props) || <span>···</span>, | ||||
|       openTransitionName: this.getOpenTransitionName(), | ||||
|       onClick: this.handleClick, | ||||
|       onOpenChange: this.onOpenChange, | ||||
|       onDeselect: this.handleDeselect, | ||||
|       onSelect: this.handleSelect, | ||||
|       ref: this.saveInnerMenu, | ||||
|       store: this.store, | ||||
|     }; | ||||
|     return <SubPopupMenu {...subPopupMenuProps} v-slots={this.$slots} />; | ||||
|   }, | ||||
| }; | ||||
| 
 | ||||
| export default defineComponent(Menu); | ||||
|  | @ -1,224 +0,0 @@ | |||
| import PropTypes from '../_util/vue-types'; | ||||
| import KeyCode from '../_util/KeyCode'; | ||||
| import BaseMixin from '../_util/BaseMixin'; | ||||
| import scrollIntoView from 'dom-scroll-into-view'; | ||||
| import { noop, menuAllProps } from './util'; | ||||
| import { getComponent, getSlot, findDOMNode } from '../_util/props-util'; | ||||
| import { computed, defineComponent, inject, onBeforeUnmount, onMounted, toRaw } from 'vue'; | ||||
| import InjectExtraProps from './InjectExtraProps'; | ||||
| const props = { | ||||
|   attribute: PropTypes.object, | ||||
|   rootPrefixCls: PropTypes.string, | ||||
|   eventKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), | ||||
|   active: PropTypes.looseBool, | ||||
|   selectedKeys: PropTypes.array, | ||||
|   disabled: PropTypes.looseBool, | ||||
|   title: PropTypes.any, | ||||
|   index: PropTypes.number, | ||||
|   inlineIndent: PropTypes.number.def(24), | ||||
|   level: PropTypes.number.def(1), | ||||
|   mode: PropTypes.oneOf(['horizontal', 'vertical', 'vertical-left', 'vertical-right', 'inline']), | ||||
|   multiple: PropTypes.looseBool, | ||||
|   value: PropTypes.any, | ||||
|   manualRef: PropTypes.func.def(noop), | ||||
|   role: PropTypes.any, | ||||
|   subMenuKey: PropTypes.string, | ||||
|   itemIcon: PropTypes.any, | ||||
|   parentUniKeys: PropTypes.array.def(() => []), | ||||
|   parentUniKey: PropTypes.string, | ||||
|   // clearSubMenuTimers: PropTypes.func.def(noop), | ||||
| }; | ||||
| let indexGuid = 0; | ||||
| const MenuItem = defineComponent({ | ||||
|   name: 'AMenuItem', | ||||
|   mixins: [BaseMixin], | ||||
|   inheritAttrs: false, | ||||
|   props, | ||||
|   isMenuItem: true, | ||||
|   setup(props) { | ||||
|     const uniKey = `menu_item_${++indexGuid}`; | ||||
|     const store = inject('menuStore', () => ({})); | ||||
|     const isSelected = computed( | ||||
|       () => store.selectedKeys && store.selectedKeys.indexOf(props.eventKey) !== -1, | ||||
|     ); | ||||
|     onMounted(() => { | ||||
|       store.addChildrenInfo( | ||||
|         uniKey, | ||||
|         computed(() => ({ | ||||
|           parentUniKeys: props.parentUniKeys, | ||||
|           parentUniKey: props.parentUniKey, | ||||
|           eventKey: props.eventKey, | ||||
|           isSelected: isSelected.value, | ||||
|           disabled: props.disabled, | ||||
|         })), | ||||
|       ); | ||||
|     }); | ||||
|     onBeforeUnmount(() => { | ||||
|       store.removeChildrenInfo(uniKey); | ||||
|     }); | ||||
| 
 | ||||
|     return { | ||||
|       parentMenu: inject('parentMenu', undefined), | ||||
|       isSelected, | ||||
|     }; | ||||
|   }, | ||||
|   created() { | ||||
|     this.prevActive = this.active; | ||||
|     // invoke customized ref to expose component to mixin | ||||
|     this.callRef(); | ||||
|   }, | ||||
|   updated() { | ||||
|     this.$nextTick(() => { | ||||
|       const { active, parentMenu, eventKey } = this; | ||||
|       if (!this.prevActive && active && (!parentMenu || !parentMenu[`scrolled-${eventKey}`])) { | ||||
|         scrollIntoView(findDOMNode(this.node), parentMenu.getEl(), { | ||||
|           onlyScrollIfNeeded: true, | ||||
|         }); | ||||
|         parentMenu[`scrolled-${eventKey}`] = true; | ||||
|       } else if (parentMenu && parentMenu[`scrolled-${eventKey}`]) { | ||||
|         delete parentMenu[`scrolled-${eventKey}`]; | ||||
|       } | ||||
|       this.prevActive = active; | ||||
|     }); | ||||
|     this.callRef(); | ||||
|   }, | ||||
|   methods: { | ||||
|     onKeyDown(e) { | ||||
|       const keyCode = e.keyCode; | ||||
|       if (keyCode === KeyCode.ENTER) { | ||||
|         this.onClick(e); | ||||
|         return true; | ||||
|       } | ||||
|     }, | ||||
| 
 | ||||
|     onMouseLeave(e) { | ||||
|       const { eventKey } = this.$props; | ||||
|       this.__emit('itemHover', { | ||||
|         key: eventKey, | ||||
|         hover: false, | ||||
|       }); | ||||
|       this.__emit('mouseleave', { | ||||
|         key: eventKey, | ||||
|         domEvent: e, | ||||
|       }); | ||||
|     }, | ||||
| 
 | ||||
|     onMouseEnter(e) { | ||||
|       const { eventKey } = this; | ||||
|       this.__emit('itemHover', { | ||||
|         key: eventKey, | ||||
|         hover: true, | ||||
|       }); | ||||
|       this.__emit('mouseenter', { | ||||
|         key: eventKey, | ||||
|         domEvent: e, | ||||
|       }); | ||||
|     }, | ||||
| 
 | ||||
|     onClick(e) { | ||||
|       const { eventKey, multiple } = this.$props; | ||||
|       const { isSelected } = this; | ||||
|       const info = { | ||||
|         key: eventKey, | ||||
|         keyPath: [eventKey], | ||||
|         item: { ...toRaw(this.$props), isSelected }, | ||||
|         domEvent: e, | ||||
|       }; | ||||
| 
 | ||||
|       this.__emit('click', info); | ||||
|       if (multiple) { | ||||
|         if (isSelected) { | ||||
|           this.__emit('deselect', info); | ||||
|         } else { | ||||
|           this.__emit('select', info); | ||||
|         } | ||||
|       } else if (!isSelected) { | ||||
|         this.__emit('select', info); | ||||
|       } | ||||
|     }, | ||||
| 
 | ||||
|     getPrefixCls() { | ||||
|       return `${this.$props.rootPrefixCls}-item`; | ||||
|     }, | ||||
| 
 | ||||
|     getActiveClassName() { | ||||
|       return `${this.getPrefixCls()}-active`; | ||||
|     }, | ||||
| 
 | ||||
|     getSelectedClassName() { | ||||
|       return `${this.getPrefixCls()}-selected`; | ||||
|     }, | ||||
| 
 | ||||
|     getDisabledClassName() { | ||||
|       return `${this.getPrefixCls()}-disabled`; | ||||
|     }, | ||||
|     saveNode(node) { | ||||
|       this.node = node; | ||||
|     }, | ||||
|     callRef() { | ||||
|       if (this.manualRef) { | ||||
|         this.manualRef(this); | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
| 
 | ||||
|   render() { | ||||
|     const { class: cls, style, ...props } = { ...this.$props, ...this.$attrs }; | ||||
| 
 | ||||
|     const className = { | ||||
|       [cls]: !!cls, | ||||
|       [this.getPrefixCls()]: true, | ||||
|       [this.getActiveClassName()]: !props.disabled && this.active, | ||||
|       [this.getSelectedClassName()]: this.isSelected, | ||||
|       [this.getDisabledClassName()]: props.disabled, | ||||
|     }; | ||||
|     let attrs = { | ||||
|       ...props.attribute, | ||||
|       title: props.title, | ||||
|       role: props.role || 'menuitem', | ||||
|       'aria-disabled': props.disabled, | ||||
|     }; | ||||
|     if (props.role === 'option') { | ||||
|       // overwrite to option | ||||
|       attrs = { | ||||
|         ...attrs, | ||||
|         role: 'option', | ||||
|         'aria-selected': this.isSelected, | ||||
|       }; | ||||
|     } else if (props.role === null || props.role === 'none') { | ||||
|       // sometimes we want to specify role inside <li/> element | ||||
|       // <li><a role='menuitem'>Link</a></li> would be a good example | ||||
|       // in this case the role on <li/> should be "none" to | ||||
|       // remove the implied listitem role. | ||||
|       // https://www.w3.org/TR/wai-aria-practices-1.1/examples/menubar/menubar-1/menubar-1.html | ||||
|       attrs.role = 'none'; | ||||
|     } | ||||
|     // In case that onClick/onMouseLeave/onMouseEnter is passed down from owner | ||||
|     const mouseEvent = { | ||||
|       onClick: props.disabled ? noop : this.onClick, | ||||
|       onMouseleave: props.disabled ? noop : this.onMouseLeave, | ||||
|       onMouseenter: props.disabled ? noop : this.onMouseEnter, | ||||
|     }; | ||||
| 
 | ||||
|     const styles = { ...(style || {}) }; | ||||
|     if (props.mode === 'inline') { | ||||
|       styles.paddingLeft = `${props.inlineIndent * props.level}px`; | ||||
|     } | ||||
|     menuAllProps.forEach(key => delete props[key]); | ||||
|     const liProps = { | ||||
|       ...props, | ||||
|       ...attrs, | ||||
|       ...mouseEvent, | ||||
|       ref: this.saveNode, | ||||
|     }; | ||||
|     return ( | ||||
|       <li {...liProps} style={styles} class={className}> | ||||
|         {getSlot(this)} | ||||
|         {getComponent(this, 'itemIcon', props)} | ||||
|       </li> | ||||
|     ); | ||||
|   }, | ||||
| }); | ||||
| 
 | ||||
| export default InjectExtraProps(MenuItem); | ||||
| export { props as menuItemProps }; | ||||
|  | @ -1,51 +0,0 @@ | |||
| import PropTypes from '../_util/vue-types'; | ||||
| import { getComponent, getSlot } from '../_util/props-util'; | ||||
| import { menuAllProps } from './util'; | ||||
| import { defineComponent, inject } from 'vue'; | ||||
| import classNames from '../_util/classNames'; | ||||
| import { injectExtraPropsKey } from './FunctionProvider'; | ||||
| const MenuItemGroup = { | ||||
|   name: 'MenuItemGroup', | ||||
|   inheritAttrs: false, | ||||
|   setup() { | ||||
|     return { | ||||
|       injectExtraProps: inject(injectExtraPropsKey, () => ({})), | ||||
|     }; | ||||
|   }, | ||||
|   props: { | ||||
|     renderMenuItem: PropTypes.func, | ||||
|     index: PropTypes.number, | ||||
|     className: PropTypes.string, | ||||
|     subMenuKey: PropTypes.string, | ||||
|     rootPrefixCls: PropTypes.string, | ||||
|     disabled: PropTypes.looseBool.def(true), | ||||
|     title: PropTypes.any, | ||||
|   }, | ||||
|   isMenuItemGroup: true, | ||||
|   methods: { | ||||
|     renderInnerMenuItem(item) { | ||||
|       const { renderMenuItem, index, subMenuKey } = { ...this.$props, ...this.injectExtraProps }; | ||||
|       return renderMenuItem(item, index, subMenuKey); | ||||
|     }, | ||||
|   }, | ||||
|   render() { | ||||
|     const props = { ...this.$props, ...this.injectExtraProps, ...this.$attrs }; | ||||
|     const { class: cls = '', rootPrefixCls, title } = props; | ||||
|     const titleClassName = `${rootPrefixCls}-item-group-title`; | ||||
|     const listClassName = `${rootPrefixCls}-item-group-list`; | ||||
|     menuAllProps.forEach(key => delete props[key]); | ||||
|     // Set onClick to null, to ignore propagated onClick event | ||||
|     delete props.onClick; | ||||
|     const children = getSlot(this); | ||||
|     return ( | ||||
|       <li {...props} class={classNames(cls, `${rootPrefixCls}-item-group`)}> | ||||
|         <div class={titleClassName} title={typeof title === 'string' ? title : undefined}> | ||||
|           {getComponent(this, 'title')} | ||||
|         </div> | ||||
|         <ul class={listClassName}>{children && children.map(this.renderInnerMenuItem)}</ul> | ||||
|       </li> | ||||
|     ); | ||||
|   }, | ||||
| }; | ||||
| 
 | ||||
| export default defineComponent(MenuItemGroup); | ||||
|  | @ -1,552 +0,0 @@ | |||
| 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'; | ||||
| 
 | ||||
| let guid = 0; | ||||
| const popupPlacementMap = { | ||||
|   horizontal: 'bottomLeft', | ||||
|   vertical: 'rightTop', | ||||
|   'vertical-left': 'rightTop', | ||||
|   'vertical-right': 'leftTop', | ||||
| }; | ||||
| 
 | ||||
| const updateDefaultActiveFirst = (store, eventKey, defaultActiveFirst) => { | ||||
|   const menuId = getMenuIdFromSubMenuEventKey(eventKey); | ||||
|   store.defaultActiveFirst[menuId] = defaultActiveFirst; | ||||
| }; | ||||
| let indexGuid = 0; | ||||
| const SubMenu = 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(() => ({})), | ||||
|     itemIcon: PropTypes.any, | ||||
|     expandIcon: PropTypes.any, | ||||
|     subMenuKey: PropTypes.string, | ||||
|     theme: PropTypes.string, | ||||
|     parentUniKeys: PropTypes.array.def(() => []), | ||||
|     parentUniKey: PropTypes.string, | ||||
|     isOverflowedSubMenu: PropTypes.looseBool.def(false), | ||||
|   }, | ||||
| 
 | ||||
|   isSubMenu: true, | ||||
|   setup(props) { | ||||
|     const uniKey = props.isOverflowedSubMenu | ||||
|       ? 'MENUITEM_OVERFLOWED_UNI_KEY' | ||||
|       : `sub_menu_${++indexGuid}`; | ||||
|     const store = inject('menuStore', () => ({})); | ||||
|     onMounted(() => { | ||||
|       store.addChildrenInfo( | ||||
|         uniKey, | ||||
|         computed(() => ({ | ||||
|           parentUniKeys: props.parentUniKeys, | ||||
|           parentUniKey: props.parentUniKey, | ||||
|           eventKey: props.eventKey, | ||||
|           disabled: props.disabled, | ||||
|         })), | ||||
|       ); | ||||
|     }); | ||||
|     onBeforeUnmount(() => { | ||||
|       store.removeChildrenInfo(uniKey); | ||||
|     }); | ||||
|     const isChildrenSelected = computed(() => { | ||||
|       return store.selectedParentUniKeys.indexOf(uniKey) !== -1; | ||||
|     }); | ||||
|     const ins = getCurrentInstance(); | ||||
|     const getEl = () => { | ||||
|       return ins.vnode.el; | ||||
|     }; | ||||
|     provide( | ||||
|       'parentMenu', | ||||
|       reactive({ | ||||
|         isRootMenu: computed(() => props.isRootMenu), | ||||
|         getPopupContainer: props.getPopupContainer, | ||||
|         getEl, | ||||
|       }), | ||||
|     ); | ||||
|     return { | ||||
|       parentMenu: inject('parentMenu', undefined), | ||||
|       store, | ||||
|       isChildrenSelected, | ||||
|       childrenUniKeys: [...props.parentUniKeys, uniKey], | ||||
|       uniKey, | ||||
|       isOpen: computed(() => store.openKeys.indexOf(props.eventKey) > -1), | ||||
|       active: computed(() => store.activeKey[props.subMenuKey] === props.eventKey), | ||||
|     }; | ||||
|   }, | ||||
|   data() { | ||||
|     const props = this.$props; | ||||
|     const store = this.store; | ||||
|     const eventKey = props.eventKey; | ||||
|     const defaultActiveFirst = store.defaultActiveFirst; | ||||
|     let value = false; | ||||
| 
 | ||||
|     if (defaultActiveFirst) { | ||||
|       value = defaultActiveFirst[eventKey]; | ||||
|     } | ||||
| 
 | ||||
|     updateDefaultActiveFirst(store, eventKey, value); | ||||
|     this.internalMenuId = undefined; | ||||
|     this.haveRendered = undefined; | ||||
|     this.haveOpened = undefined; | ||||
|     this.subMenuTitle = undefined; | ||||
|     return {}; | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.$nextTick(() => { | ||||
|       this.handleUpdated(); | ||||
|     }); | ||||
|   }, | ||||
| 
 | ||||
|   updated() { | ||||
|     this.$nextTick(() => { | ||||
|       this.handleUpdated(); | ||||
|     }); | ||||
|   }, | ||||
| 
 | ||||
|   beforeUnmount() { | ||||
|     const { eventKey } = this; | ||||
|     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; | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     isChildrenSelected2() { | ||||
|       if (this.haveOpened) return this.isChildrenSelected; | ||||
|       const ret = { find: false }; | ||||
|       loopMenuItemRecursively(getSlot(this), this.store.selectedKeys, ret); | ||||
|       return ret.find; | ||||
|     }, | ||||
|     handleUpdated() { | ||||
|       const { mode, manualRef } = this.$props; | ||||
|       // invoke customized ref to expose component to mixin | ||||
|       if (manualRef) { | ||||
|         manualRef(this); | ||||
|       } | ||||
|       if (mode !== 'horizontal' || !this.parentMenu.isRootMenu || !this.isOpen) { | ||||
|         return; | ||||
|       } | ||||
|       this.minWidthTimeout = requestAnimationTimeout(() => this.adjustWidth(), 0); | ||||
|     }, | ||||
| 
 | ||||
|     onKeyDown(e) { | ||||
|       const keyCode = e.keyCode; | ||||
|       const menu = this.menuInstance; | ||||
|       const { isOpen } = this; | ||||
|       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) { | ||||
|         let 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(visible) { | ||||
|       this.triggerOpenChange(visible, visible ? 'mouseenter' : 'mouseleave'); | ||||
|     }, | ||||
| 
 | ||||
|     onMouseEnter(e) { | ||||
|       const { eventKey: key } = this.$props; | ||||
|       updateDefaultActiveFirst(this.store, key, false); | ||||
|       this.__emit('mouseenter', { | ||||
|         key, | ||||
|         domEvent: e, | ||||
|       }); | ||||
|     }, | ||||
| 
 | ||||
|     onMouseLeave(e) { | ||||
|       const { eventKey } = this.$props; | ||||
|       this.__emit('mouseleave', { | ||||
|         key: eventKey, | ||||
|         domEvent: e, | ||||
|       }); | ||||
|     }, | ||||
| 
 | ||||
|     onTitleMouseEnter(domEvent) { | ||||
|       const { eventKey: key } = this.$props; | ||||
|       this.__emit('itemHover', { | ||||
|         key, | ||||
|         hover: true, | ||||
|       }); | ||||
|       this.__emit('titleMouseenter', { | ||||
|         key, | ||||
|         domEvent, | ||||
|       }); | ||||
|     }, | ||||
| 
 | ||||
|     onTitleMouseLeave(e) { | ||||
|       const { eventKey } = this.$props; | ||||
|       this.__emit('itemHover', { | ||||
|         key: eventKey, | ||||
|         hover: false, | ||||
|       }); | ||||
|       this.__emit('titleMouseleave', { | ||||
|         key: eventKey, | ||||
|         domEvent: e, | ||||
|       }); | ||||
|     }, | ||||
| 
 | ||||
|     onTitleClick(e) { | ||||
|       const { triggerSubMenuAction, eventKey } = this.$props; | ||||
|       this.__emit('titleClick', { | ||||
|         key: eventKey, | ||||
|         domEvent: e, | ||||
|       }); | ||||
|       if (triggerSubMenuAction === 'hover') { | ||||
|         return; | ||||
|       } | ||||
|       this.triggerOpenChange(!this.isOpen, 'click'); | ||||
|       updateDefaultActiveFirst(this.store, eventKey, false); | ||||
|     }, | ||||
| 
 | ||||
|     onSubMenuClick(info) { | ||||
|       this.__emit('click', this.addKeyPath(info)); | ||||
|     }, | ||||
| 
 | ||||
|     getPrefixCls() { | ||||
|       return `${this.$props.rootPrefixCls}-submenu`; | ||||
|     }, | ||||
| 
 | ||||
|     getActiveClassName() { | ||||
|       return `${this.getPrefixCls()}-active`; | ||||
|     }, | ||||
| 
 | ||||
|     getDisabledClassName() { | ||||
|       return `${this.getPrefixCls()}-disabled`; | ||||
|     }, | ||||
| 
 | ||||
|     getSelectedClassName() { | ||||
|       return `${this.getPrefixCls()}-selected`; | ||||
|     }, | ||||
| 
 | ||||
|     getOpenClassName() { | ||||
|       return `${this.$props.rootPrefixCls}-submenu-open`; | ||||
|     }, | ||||
| 
 | ||||
|     saveMenuInstance(c) { | ||||
|       // children menu instance | ||||
|       this.menuInstance = c; | ||||
|     }, | ||||
| 
 | ||||
|     addKeyPath(info) { | ||||
|       return { | ||||
|         ...info, | ||||
|         keyPath: (info.keyPath || []).concat(this.$props.eventKey), | ||||
|       }; | ||||
|     }, | ||||
|     triggerOpenChange(open, type) { | ||||
|       const key = this.$props.eventKey; | ||||
|       const openChange = () => { | ||||
|         this.__emit('openChange', { | ||||
|           key, | ||||
|           item: this.$props, | ||||
|           trigger: type, | ||||
|           open, | ||||
|         }); | ||||
|       }; | ||||
|       if (type === 'mouseenter') { | ||||
|         // make sure mouseenter happen after other menu item's mouseleave | ||||
|         this.mouseenterTimeout = requestAnimationTimeout(() => { | ||||
|           openChange(); | ||||
|         }, 0); | ||||
|       } else { | ||||
|         openChange(); | ||||
|       } | ||||
|     }, | ||||
|     adjustWidth() { | ||||
|       /* istanbul ignore if */ | ||||
|       if (!this.subMenuTitle || !this.menuInstance) { | ||||
|         return; | ||||
|       } | ||||
|       const popupMenu = findDOMNode(this.menuInstance); | ||||
|       if (popupMenu.offsetWidth >= this.subMenuTitle.offsetWidth) { | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       /* istanbul ignore next */ | ||||
|       popupMenu.style.minWidth = `${this.subMenuTitle.offsetWidth}px`; | ||||
|     }, | ||||
|     saveSubMenuTitle(subMenuTitle) { | ||||
|       this.subMenuTitle = subMenuTitle; | ||||
|     }, | ||||
|     renderChildren() { | ||||
|       const props = { ...this.$props, ...this.$attrs }; | ||||
| 
 | ||||
|       const subPopupMenuProps = { | ||||
|         mode: props.mode === 'horizontal' ? 'vertical' : props.mode, | ||||
|         visible: this.isOpen, | ||||
|         level: props.level + 1, | ||||
|         inlineIndent: props.inlineIndent, | ||||
|         focusable: false, | ||||
|         eventKey: `${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, | ||||
|       }; | ||||
|       const 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 <div />; | ||||
|       } | ||||
| 
 | ||||
|       // 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 | ||||
|       const transitionAppear = | ||||
|         haveRendered || !subPopupMenuProps.visible || !subPopupMenuProps.mode === 'inline'; | ||||
|       subPopupMenuProps.class = ` ${subPopupMenuProps.prefixCls}-sub`; | ||||
|       let transitionProps = { appear: transitionAppear, css: false }; | ||||
| 
 | ||||
|       if (subPopupMenuProps.openTransitionName) { | ||||
|         transitionProps = getTransitionProps(subPopupMenuProps.openTransitionName, { | ||||
|           appear: transitionAppear, | ||||
|         }); | ||||
|       } else if (typeof subPopupMenuProps.openAnimation === 'object') { | ||||
|         transitionProps = { ...transitionProps, ...(subPopupMenuProps.openAnimation || {}) }; | ||||
|         if (!transitionAppear) { | ||||
|           transitionProps.appear = false; | ||||
|         } | ||||
|       } else if (typeof subPopupMenuProps.openAnimation === 'string') { | ||||
|         transitionProps = getTransitionProps(subPopupMenuProps.openAnimation, { | ||||
|           appear: transitionAppear, | ||||
|         }); | ||||
|       } | ||||
|       return ( | ||||
|         <Transition {...transitionProps}> | ||||
|           <SubPopupMenu v-show={this.isOpen} {...subPopupMenuProps} v-slots={this.$slots} /> | ||||
|         </Transition> | ||||
|       ); | ||||
|     }, | ||||
|   }, | ||||
| 
 | ||||
|   render() { | ||||
|     const props = { ...this.$props, ...this.$attrs }; | ||||
|     const { onEvents } = splitAttrs(props); | ||||
|     const isOpen = this.isOpen; | ||||
|     const prefixCls = this.getPrefixCls(); | ||||
|     const isInlineMode = props.mode === 'inline'; | ||||
|     if (!this.internalMenuId) { | ||||
|       if (props.eventKey) { | ||||
|         this.internalMenuId = `${props.eventKey}$Menu`; | ||||
|       } else { | ||||
|         this.internalMenuId = `$__$${++guid}$Menu`; | ||||
|       } | ||||
|     } | ||||
|     const children = this.renderChildren(); | ||||
|     const className = { | ||||
|       [prefixCls]: true, | ||||
|       [`${prefixCls}-${props.mode}`]: true, | ||||
|       [props.class]: !!props.class, | ||||
|       [this.getOpenClassName()]: isOpen, | ||||
|       [this.getActiveClassName()]: this.active || (isOpen && !isInlineMode), | ||||
|       [this.getDisabledClassName()]: props.disabled, | ||||
|       [this.getSelectedClassName()]: this.isChildrenSelected || this.isChildrenSelected2(), | ||||
|     }; | ||||
|     let mouseEvents = {}; | ||||
|     let titleClickEvents = {}; | ||||
|     let 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, | ||||
|       }; | ||||
|     } | ||||
| 
 | ||||
|     const style = {}; | ||||
|     if (isInlineMode) { | ||||
|       style.paddingLeft = `${props.inlineIndent * props.level}px`; | ||||
|     } | ||||
|     let 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, | ||||
|       }; | ||||
|     } | ||||
|     const titleProps = { | ||||
|       'aria-expanded': isOpen, | ||||
|       ...ariaOwns, | ||||
|       'aria-haspopup': 'true', | ||||
|       title: typeof props.title === 'string' ? props.title : undefined, | ||||
|       ...titleMouseEvents, | ||||
|       ...titleClickEvents, | ||||
|       style, | ||||
|       class: `${prefixCls}-title`, | ||||
|       ref: this.saveSubMenuTitle, | ||||
|     }; | ||||
| 
 | ||||
|     // expand custom icon should NOT be displayed in menu with horizontal mode. | ||||
|     let icon = null; | ||||
|     if (props.mode !== 'horizontal') { | ||||
|       icon = getComponent(this, 'expandIcon', props); | ||||
|     } | ||||
|     const title = ( | ||||
|       <div {...titleProps}> | ||||
|         {getComponent(this, 'title')} | ||||
|         {icon || <i class={`${prefixCls}-arrow`} />} | ||||
|       </div> | ||||
|     ); | ||||
|     const getPopupContainer = this.parentMenu.isRootMenu | ||||
|       ? this.parentMenu.getPopupContainer | ||||
|       : triggerNode => triggerNode.parentNode; | ||||
|     const popupPlacement = popupPlacementMap[props.mode]; | ||||
|     const popupAlign = props.popupOffset ? { offset: props.popupOffset } : {}; | ||||
|     let popupClassName = props.mode === 'inline' ? '' : props.popupClassName || ''; | ||||
|     popupClassName = `${prefixCls}-popup ${popupClassName}`; | ||||
|     const liProps = { | ||||
|       ...omit(onEvents, ['onClick']), | ||||
|       ...mouseEvents, | ||||
|       class: className, | ||||
|       style: props.style, | ||||
|     }; | ||||
| 
 | ||||
|     return ( | ||||
|       <li {...liProps} role="menuitem"> | ||||
|         {isInlineMode && title} | ||||
|         {isInlineMode && children} | ||||
|         {!isInlineMode && ( | ||||
|           <Trigger | ||||
|             prefixCls={prefixCls} | ||||
|             popupClassName={popupClassName} | ||||
|             getPopupContainer={getPopupContainer} | ||||
|             builtinPlacements={placements} | ||||
|             builtinPlacements={Object.assign({}, placements, props.builtinPlacements)} | ||||
|             popupPlacement={popupPlacement} | ||||
|             popupVisible={isOpen} | ||||
|             popupAlign={popupAlign} | ||||
|             action={props.disabled ? [] : [props.triggerSubMenuAction]} | ||||
|             mouseEnterDelay={props.subMenuOpenDelay} | ||||
|             mouseLeaveDelay={props.subMenuCloseDelay} | ||||
|             onPopupVisibleChange={this.onPopupVisibleChange} | ||||
|             forceRender={props.forceSubMenuRender} | ||||
|             // popupTransitionName='rc-menu-open-slide-up' | ||||
|             // popupAnimation={transitionProps} | ||||
|             popup={children} | ||||
|           > | ||||
|             {title} | ||||
|           </Trigger> | ||||
|         )} | ||||
|       </li> | ||||
|     ); | ||||
|   }, | ||||
| }); | ||||
| 
 | ||||
| export default InjectExtraProps(SubMenu); | ||||
|  | @ -1,389 +0,0 @@ | |||
| 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 allDisabled(arr) { | ||||
|   if (!arr.length) { | ||||
|     return true; | ||||
|   } | ||||
|   return arr.every(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) { | ||||
|     const 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; | ||||
| // } | ||||
| 
 | ||||
| const 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(() => []), | ||||
|       parentUniKey: PropTypes.string, | ||||
|       theme: PropTypes.string, | ||||
|     }, | ||||
|     { | ||||
|       prefixCls: 'rc-menu', | ||||
|       mode: 'vertical', | ||||
|       level: 1, | ||||
|       inlineIndent: 24, | ||||
|       visible: true, | ||||
|       focusable: true, | ||||
|       manualRef: noop, | ||||
|     }, | ||||
|   ), | ||||
| 
 | ||||
|   mixins: [BaseMixin], | ||||
|   setup() { | ||||
|     const store = inject('menuStore', () => ({})); | ||||
|     return { store }; | ||||
|   }, | ||||
|   created() { | ||||
|     const props = getOptionProps(this); | ||||
|     this.prevProps = { ...props }; | ||||
|     this.store.activeKey[props.eventKey] = this.store.getActiveKey(props.activeKey); | ||||
|     this.instanceArray = []; | ||||
|   }, | ||||
|   mounted() { | ||||
|     // invoke customized ref to expose component to mixin | ||||
|     if (this.manualRef) { | ||||
|       this.manualRef(this); | ||||
|     } | ||||
|   }, | ||||
|   updated() { | ||||
|     const props = getOptionProps(this); | ||||
|     const prevProps = this.prevProps; | ||||
|     const originalActiveKey = | ||||
|       'activeKey' in props ? props.activeKey : this.store.activeKey[getEventKey(props)]; | ||||
|     const 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. | ||||
|       const prevActiveKey = this.store.getActiveKey(prevProps.activeKey); | ||||
|       if (activeKey !== prevActiveKey) { | ||||
|         updateActiveKey(this.store, getEventKey(props), activeKey); | ||||
|       } | ||||
|     } | ||||
|     this.prevProps = { ...props }; | ||||
|   }, | ||||
|   methods: { | ||||
|     // all keyboard events callbacks run from here at first | ||||
|     onKeyDown(e, callback) { | ||||
|       const keyCode = e.keyCode; | ||||
|       let handled; | ||||
|       this.getFlatInstanceArray().forEach(obj => { | ||||
|         if (obj && obj.active && obj.onKeyDown) { | ||||
|           handled = obj.onKeyDown(e); | ||||
|         } | ||||
|       }); | ||||
|       if (handled) { | ||||
|         return 1; | ||||
|       } | ||||
|       let 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(e) { | ||||
|       const { key, hover } = e; | ||||
|       updateActiveKey(this.store, getEventKey(this.$props), hover ? key : null); | ||||
|     }, | ||||
| 
 | ||||
|     onDeselect(selectInfo) { | ||||
|       this.__emit('deselect', selectInfo); | ||||
|     }, | ||||
| 
 | ||||
|     onSelect(selectInfo) { | ||||
|       this.__emit('select', selectInfo); | ||||
|     }, | ||||
| 
 | ||||
|     onClick(e) { | ||||
|       this.__emit('click', e); | ||||
|     }, | ||||
| 
 | ||||
|     onOpenChange(e) { | ||||
|       this.__emit('openChange', e); | ||||
|     }, | ||||
| 
 | ||||
|     onDestroy(key) { | ||||
|       this.__emit('destroy', key); | ||||
|     }, | ||||
| 
 | ||||
|     getFlatInstanceArray() { | ||||
|       return this.instanceArray; | ||||
|     }, | ||||
| 
 | ||||
|     getOpenTransitionName() { | ||||
|       return this.$props.openTransitionName; | ||||
|     }, | ||||
| 
 | ||||
|     step(direction) { | ||||
|       let children = this.getFlatInstanceArray(); | ||||
|       const activeKey = this.store.activeKey[getEventKey(this.$props)]; | ||||
|       const len = children.length; | ||||
|       if (!len) { | ||||
|         return null; | ||||
|       } | ||||
|       if (direction < 0) { | ||||
|         children = children.concat().reverse(); | ||||
|       } | ||||
|       // find current activeIndex | ||||
|       let activeIndex = -1; | ||||
|       children.every((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; | ||||
|       } | ||||
|       const start = (activeIndex + 1) % len; | ||||
|       let i = start; | ||||
| 
 | ||||
|       do { | ||||
|         const child = children[i]; | ||||
|         if (!child || child.disabled) { | ||||
|           i = (i + 1) % len; | ||||
|         } else { | ||||
|           return child; | ||||
|         } | ||||
|       } while (i !== start); | ||||
| 
 | ||||
|       return null; | ||||
|     }, | ||||
|     getIcon(instance, name) { | ||||
|       return getComponent(instance, name); | ||||
|     }, | ||||
|     renderCommonMenuItem(child, i, extraProps) { | ||||
|       if (child.type === Comment) { | ||||
|         return child; | ||||
|       } | ||||
|       const state = this.store; | ||||
|       const props = this.$props; | ||||
|       const key = getKeyFromChildrenIndex(child, props.eventKey, i); | ||||
|       const childProps = child.props || {}; // child.props 包含事件 | ||||
| 
 | ||||
|       const isActive = key === state.activeKey[getEventKey(this.$props)]; | ||||
|       if (!childProps.disabled) { | ||||
|         // manualRef的执行顺序不能保证,使用key映射ref在this.instanceArray中的位置 | ||||
|         this.instanceArrayKeyIndexMap[key] = Object.keys(this.instanceArrayKeyIndexMap).length; | ||||
|       } | ||||
|       const newChildProps = { | ||||
|         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: 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 <FunctionProvider extraProps={newChildProps}>{child}</FunctionProvider>; | ||||
|     }, | ||||
| 
 | ||||
|     renderMenuItem(c, i, subMenuKey) { | ||||
|       if (!c) { | ||||
|         return null; | ||||
|       } | ||||
|       const state = this.store; | ||||
|       const extraProps = { | ||||
|         openKeys: state.openKeys, | ||||
|         selectedKeys: state.selectedKeys, | ||||
|         triggerSubMenuAction: this.triggerSubMenuAction, | ||||
|         isRootMenu: false, | ||||
|         subMenuKey, | ||||
|       }; | ||||
|       return this.renderCommonMenuItem(c, i, extraProps); | ||||
|     }, | ||||
|   }, | ||||
|   render() { | ||||
|     const props = { ...this.$props }; | ||||
|     const { onEvents, extraAttrs } = splitAttrs(this.$attrs); | ||||
|     const { eventKey, prefixCls, visible, level, mode, theme } = props; | ||||
|     this.instanceArray = []; | ||||
|     this.instanceArrayKeyIndexMap = {}; | ||||
|     const className = classNames( | ||||
|       extraAttrs.class, | ||||
|       props.prefixCls, | ||||
|       `${props.prefixCls}-${props.mode}`, | ||||
|     ); | ||||
|     menuAllProps.forEach(key => delete props[key]); | ||||
|     // Otherwise, the propagated click event will trigger another onClick | ||||
|     delete onEvents.onClick; | ||||
|     const domWrapProps = { | ||||
|       ...props, | ||||
|       tag: 'ul', | ||||
|       // hiddenClassName: `${prefixCls}-hidden`, | ||||
|       visible, | ||||
|       prefixCls, | ||||
|       level, | ||||
|       mode, | ||||
|       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 */ | ||||
|       <DOMWrap {...domWrapProps}> | ||||
|         {getSlot(this).map((c, i) => this.renderMenuItem(c, i, eventKey || '0-menu-'))} | ||||
|       </DOMWrap> | ||||
|       /*eslint -enable */ | ||||
|     ); | ||||
|   }, | ||||
| }; | ||||
| 
 | ||||
| export default SubPopupMenu; | ||||
|  | @ -1,318 +0,0 @@ | |||
| @menuPrefixCls: rc-menu; | ||||
| 
 | ||||
| @font-face { | ||||
|   font-family: 'FontAwesome'; | ||||
|   src: url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/fonts/fontawesome-webfont.eot'); | ||||
|   src: url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/fonts/fontawesome-webfont.eot?#iefix') | ||||
|       format('embedded-opentype'), | ||||
|     url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/fonts/fontawesome-webfont.woff') | ||||
|       format('woff'), | ||||
|     url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/fonts/fontawesome-webfont.ttf') | ||||
|       format('truetype'), | ||||
|     url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/fonts/fontawesome-webfont.svg?#fontawesomeregular') | ||||
|       format('svg'); | ||||
|   font-weight: normal; | ||||
|   font-style: normal; | ||||
| } | ||||
| 
 | ||||
| .@{menuPrefixCls} { | ||||
|   outline: none; | ||||
|   margin-bottom: 0; | ||||
|   padding-left: 0; // Override default ul/ol | ||||
|   list-style: none; | ||||
|   border: 1px solid #d9d9d9; | ||||
|   box-shadow: 0 0 4px #d9d9d9; | ||||
|   border-radius: 3px; | ||||
|   color: #666; | ||||
| 
 | ||||
|   &-hidden { | ||||
|     display: none; | ||||
|   } | ||||
| 
 | ||||
|   &-collapse { | ||||
|     overflow: hidden; | ||||
|     &-active { | ||||
|       transition: height 0.3s ease-out; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   &-item-group-list { | ||||
|     margin: 0; | ||||
|     padding: 0; | ||||
|   } | ||||
| 
 | ||||
|   &-item-group-title { | ||||
|     color: #999; | ||||
|     line-height: 1.5; | ||||
|     padding: 8px 10px; | ||||
|     border-bottom: 1px solid #dedede; | ||||
|   } | ||||
| 
 | ||||
|   &-item-active, | ||||
|   &-submenu-active > &-submenu-title { | ||||
|     background-color: #eaf8fe; | ||||
|   } | ||||
| 
 | ||||
|   &-item-selected { | ||||
|     background-color: #eaf8fe; | ||||
|     // fix chrome render bug | ||||
|     transform: translateZ(0); | ||||
|   } | ||||
| 
 | ||||
|   &-submenu-selected { | ||||
|     background-color: #eaf8fe; | ||||
|   } | ||||
| 
 | ||||
|   & > li&-submenu { | ||||
|     padding: 0; | ||||
|   } | ||||
| 
 | ||||
|   &-horizontal&-sub, | ||||
|   &-vertical&-sub, | ||||
|   &-vertical-left&-sub, | ||||
|   &-vertical-right&-sub { | ||||
|     min-width: 160px; | ||||
|     margin-top: 0; | ||||
|   } | ||||
| 
 | ||||
|   &-item, | ||||
|   &-submenu-title { | ||||
|     margin: 0; | ||||
|     position: relative; | ||||
|     display: block; | ||||
|     padding: 7px 7px 7px 16px; | ||||
|     white-space: nowrap; | ||||
| 
 | ||||
|     // Disabled state sets text to gray and nukes hover/tab effects | ||||
|     &.@{menuPrefixCls}-item-disabled, | ||||
|     &.@{menuPrefixCls}-submenu-disabled { | ||||
|       color: #777 !important; | ||||
|     } | ||||
|   } | ||||
|   & > &-item-divider { | ||||
|     height: 1px; | ||||
|     margin: 1px 0; | ||||
|     overflow: hidden; | ||||
|     padding: 0; | ||||
|     line-height: 0; | ||||
|     background-color: #e5e5e5; | ||||
|   } | ||||
| 
 | ||||
|   &-submenu { | ||||
|     &-popup { | ||||
|       position: absolute; | ||||
| 
 | ||||
|       .submenu-title-wrapper { | ||||
|         padding-right: 20px; | ||||
|       } | ||||
|     } | ||||
|     > .@{menuPrefixCls} { | ||||
|       background-color: #fff; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   .@{menuPrefixCls}-submenu-title, | ||||
|   .@{menuPrefixCls}-item { | ||||
|     .anticon { | ||||
|       width: 14px; | ||||
|       height: 14px; | ||||
|       margin-right: 8px; | ||||
|       top: -1px; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   &-horizontal { | ||||
|     background-color: #f3f5f7; | ||||
|     border: none; | ||||
|     border-bottom: 1px solid #d9d9d9; | ||||
|     box-shadow: none; | ||||
|     white-space: nowrap; | ||||
|     overflow: hidden; | ||||
| 
 | ||||
|     & > .@{menuPrefixCls}-item, | ||||
|     & > .@{menuPrefixCls}-submenu > .@{menuPrefixCls}-submenu-title { | ||||
|       padding: 15px 20px; | ||||
|     } | ||||
| 
 | ||||
|     & > .@{menuPrefixCls}-submenu, | ||||
|     & > .@{menuPrefixCls}-item { | ||||
|       border-bottom: 2px solid transparent; | ||||
|       display: inline-block; | ||||
|       vertical-align: bottom; | ||||
| 
 | ||||
|       &-active { | ||||
|         border-bottom: 2px solid #2db7f5; | ||||
|         background-color: #f3f5f7; | ||||
|         color: #2baee9; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     &:after { | ||||
|       content: '\20'; | ||||
|       display: block; | ||||
|       height: 0; | ||||
|       clear: both; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   &-vertical, | ||||
|   &-vertical-left, | ||||
|   &-vertical-right, | ||||
|   &-inline { | ||||
|     padding: 12px 0; | ||||
|     & > .@{menuPrefixCls}-item, | ||||
|     & > .@{menuPrefixCls}-submenu > .@{menuPrefixCls}-submenu-title { | ||||
|       padding: 12px 8px 12px 24px; | ||||
|     } | ||||
|     .@{menuPrefixCls}-submenu-arrow { | ||||
|       display: inline-block; | ||||
|       font: normal normal normal 14px/1 FontAwesome; | ||||
|       font-size: inherit; | ||||
|       vertical-align: baseline; | ||||
|       text-align: center; | ||||
|       text-transform: none; | ||||
|       text-rendering: auto; | ||||
|       position: absolute; | ||||
|       right: 16px; | ||||
|       line-height: 1.5em; | ||||
|       &:before { | ||||
|         content: '\f0da'; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   &-inline { | ||||
|     .@{menuPrefixCls}-submenu-arrow { | ||||
|       transform: rotate(90deg); | ||||
|       transition: transform 0.3s; | ||||
|     } | ||||
|     & .@{menuPrefixCls}-submenu-open > .@{menuPrefixCls}-submenu-title { | ||||
|       .@{menuPrefixCls}-submenu-arrow { | ||||
|         transform: rotate(-90deg); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   &-vertical&-sub, | ||||
|   &-vertical-left&-sub, | ||||
|   &-vertical-right&-sub { | ||||
|     padding: 0; | ||||
|   } | ||||
| 
 | ||||
|   &-sub&-inline { | ||||
|     padding: 0; | ||||
|     border: none; | ||||
|     border-radius: 0; | ||||
|     box-shadow: none; | ||||
| 
 | ||||
|     & > .@{menuPrefixCls}-item, | ||||
|     & > .@{menuPrefixCls}-submenu > .@{menuPrefixCls}-submenu-title { | ||||
|       padding-top: 8px; | ||||
|       padding-bottom: 8px; | ||||
|       padding-right: 0; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   .effect() { | ||||
|     animation-duration: 0.3s; | ||||
|     animation-fill-mode: both; | ||||
|     transform-origin: 0 0; | ||||
|   } | ||||
| 
 | ||||
|   &-open { | ||||
|     &-slide-up-enter, | ||||
|     &-slide-up-appear { | ||||
|       .effect(); | ||||
|       opacity: 0; | ||||
|       animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1); | ||||
|       animation-play-state: paused; | ||||
|     } | ||||
| 
 | ||||
|     &-slide-up-leave { | ||||
|       .effect(); | ||||
|       opacity: 1; | ||||
|       animation-timing-function: cubic-bezier(0.6, 0.04, 0.98, 0.34); | ||||
|       animation-play-state: paused; | ||||
|     } | ||||
| 
 | ||||
|     &-slide-up-enter&-slide-up-enter-active, | ||||
|     &-slide-up-appear&-slide-up-appear-active { | ||||
|       animation-name: rcMenuOpenSlideUpIn; | ||||
|       animation-play-state: running; | ||||
|     } | ||||
| 
 | ||||
|     &-slide-up-leave&-slide-up-leave-active { | ||||
|       animation-name: rcMenuOpenSlideUpOut; | ||||
|       animation-play-state: running; | ||||
|     } | ||||
| 
 | ||||
|     @keyframes rcMenuOpenSlideUpIn { | ||||
|       0% { | ||||
|         opacity: 0; | ||||
|         transform-origin: 0% 0%; | ||||
|         transform: scaleY(0); | ||||
|       } | ||||
|       100% { | ||||
|         opacity: 1; | ||||
|         transform-origin: 0% 0%; | ||||
|         transform: scaleY(1); | ||||
|       } | ||||
|     } | ||||
|     @keyframes rcMenuOpenSlideUpOut { | ||||
|       0% { | ||||
|         opacity: 1; | ||||
|         transform-origin: 0% 0%; | ||||
|         transform: scaleY(1); | ||||
|       } | ||||
|       100% { | ||||
|         opacity: 0; | ||||
|         transform-origin: 0% 0%; | ||||
|         transform: scaleY(0); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     &-zoom-enter, | ||||
|     &-zoom-appear { | ||||
|       opacity: 0; | ||||
|       .effect(); | ||||
|       animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1); | ||||
|       animation-play-state: paused; | ||||
|     } | ||||
| 
 | ||||
|     &-zoom-leave { | ||||
|       .effect(); | ||||
|       animation-timing-function: cubic-bezier(0.6, 0.04, 0.98, 0.34); | ||||
|       animation-play-state: paused; | ||||
|     } | ||||
| 
 | ||||
|     &-zoom-enter&-zoom-enter-active, | ||||
|     &-zoom-appear&-zoom-appear-active { | ||||
|       animation-name: rcMenuOpenZoomIn; | ||||
|       animation-play-state: running; | ||||
|     } | ||||
| 
 | ||||
|     &-zoom-leave&-zoom-leave-active { | ||||
|       animation-name: rcMenuOpenZoomOut; | ||||
|       animation-play-state: running; | ||||
|     } | ||||
| 
 | ||||
|     @keyframes rcMenuOpenZoomIn { | ||||
|       0% { | ||||
|         opacity: 0; | ||||
|         transform: scale(0, 0); | ||||
|       } | ||||
|       100% { | ||||
|         opacity: 1; | ||||
|         transform: scale(1, 1); | ||||
|       } | ||||
|     } | ||||
|     @keyframes rcMenuOpenZoomOut { | ||||
|       0% { | ||||
|         transform: scale(1, 1); | ||||
|       } | ||||
|       100% { | ||||
|         opacity: 0; | ||||
|         transform: scale(0, 0); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | @ -1,42 +0,0 @@ | |||
| import PropTypes from '../_util/vue-types'; | ||||
| export default { | ||||
|   prefixCls: PropTypes.string.def('rc-menu'), | ||||
|   focusable: PropTypes.looseBool.def(true), | ||||
|   multiple: PropTypes.looseBool, | ||||
|   visible: PropTypes.looseBool.def(true), | ||||
|   activeKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), | ||||
|   selectedKeys: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number])), | ||||
|   defaultSelectedKeys: PropTypes.arrayOf( | ||||
|     PropTypes.oneOfType([PropTypes.string, PropTypes.number]), | ||||
|   ).def([]), | ||||
|   defaultOpenKeys: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number])).def( | ||||
|     [], | ||||
|   ), | ||||
|   openKeys: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number])), | ||||
|   openAnimation: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), | ||||
|   mode: PropTypes.oneOf([ | ||||
|     'horizontal', | ||||
|     'vertical', | ||||
|     'vertical-left', | ||||
|     'vertical-right', | ||||
|     'inline', | ||||
|   ]).def('vertical'), | ||||
|   triggerSubMenuAction: PropTypes.string.def('hover'), | ||||
|   subMenuOpenDelay: PropTypes.number.def(0.1), | ||||
|   subMenuCloseDelay: PropTypes.number.def(0.1), | ||||
|   level: PropTypes.number.def(1), | ||||
|   inlineIndent: PropTypes.number.def(24), | ||||
|   theme: PropTypes.oneOf(['light', 'dark']).def('light'), | ||||
|   getPopupContainer: PropTypes.func, | ||||
|   openTransitionName: PropTypes.string, | ||||
|   forceSubMenuRender: PropTypes.looseBool.def(false), | ||||
|   selectable: PropTypes.looseBool, | ||||
|   isRootMenu: PropTypes.looseBool.def(true), | ||||
|   builtinPlacements: PropTypes.object.def(() => ({})), | ||||
|   itemIcon: PropTypes.any, | ||||
|   expandIcon: PropTypes.any, | ||||
|   overflowedIndicator: PropTypes.any, | ||||
|   onClick: PropTypes.func, | ||||
|   onSelect: PropTypes.func, | ||||
|   onDeselect: PropTypes.func, | ||||
| }; | ||||
|  | @ -1,18 +0,0 @@ | |||
| // based on rc-menu 7.5.5
 | ||||
| import Menu from './Menu'; | ||||
| import SubMenu from './SubMenu'; | ||||
| import MenuItem, { menuItemProps } from './MenuItem'; | ||||
| import MenuItemGroup from './MenuItemGroup'; | ||||
| import Divider from './Divider'; | ||||
| 
 | ||||
| export { | ||||
|   SubMenu, | ||||
|   MenuItem as Item, | ||||
|   menuItemProps as itemProps, | ||||
|   MenuItem, | ||||
|   MenuItemGroup, | ||||
|   MenuItemGroup as ItemGroup, | ||||
|   Divider, | ||||
| }; | ||||
| 
 | ||||
| export default Menu; | ||||
|  | @ -1,29 +0,0 @@ | |||
| const autoAdjustOverflow = { | ||||
|   adjustX: 1, | ||||
|   adjustY: 1, | ||||
| }; | ||||
| 
 | ||||
| export const placements = { | ||||
|   topLeft: { | ||||
|     points: ['bl', 'tl'], | ||||
|     overflow: autoAdjustOverflow, | ||||
|     offset: [0, -7], | ||||
|   }, | ||||
|   bottomLeft: { | ||||
|     points: ['tl', 'bl'], | ||||
|     overflow: autoAdjustOverflow, | ||||
|     offset: [0, 7], | ||||
|   }, | ||||
|   leftTop: { | ||||
|     points: ['tr', 'tl'], | ||||
|     overflow: autoAdjustOverflow, | ||||
|     offset: [-4, 0], | ||||
|   }, | ||||
|   rightTop: { | ||||
|     points: ['tl', 'tr'], | ||||
|     overflow: autoAdjustOverflow, | ||||
|     offset: [4, 0], | ||||
|   }, | ||||
| }; | ||||
| 
 | ||||
| export default placements; | ||||
|  | @ -1,147 +0,0 @@ | |||
| import isMobile from './utils/isMobile'; | ||||
| import isObject from 'lodash-es/isObject'; | ||||
| 
 | ||||
| export function noop() {} | ||||
| 
 | ||||
| export function getKeyFromChildrenIndex(child, menuEventKey, index) { | ||||
|   const prefix = menuEventKey || ''; | ||||
|   return child.key === null ? `${prefix}item_${index}` : child.key; | ||||
| } | ||||
| 
 | ||||
| export function getMenuIdFromSubMenuEventKey(eventKey) { | ||||
|   return `${eventKey}-menu-`; | ||||
| } | ||||
| 
 | ||||
| // export function loopMenuItem(children, cb) {
 | ||||
| //   let index = -1;
 | ||||
| //   children.forEach(c => {
 | ||||
| //     index++;
 | ||||
| //     if (c && c.type && c.type.isMenuItemGroup) {
 | ||||
| //       c.children.default &&
 | ||||
| //         c.children.default().forEach(c2 => {
 | ||||
| //           index++;
 | ||||
| //           cb(c2, index);
 | ||||
| //         });
 | ||||
| //     } else {
 | ||||
| //       cb(c, index);
 | ||||
| //     }
 | ||||
| //   });
 | ||||
| // }
 | ||||
| 
 | ||||
| export function loopMenuItemRecursively(children, keys, ret) { | ||||
|   if (!children || ret.find) { | ||||
|     return; | ||||
|   } | ||||
|   children.forEach(c => { | ||||
|     if (ret.find) { | ||||
|       return; | ||||
|     } | ||||
|     const construct = c.type; | ||||
|     if (construct && isObject(construct)) { | ||||
|       if ( | ||||
|         !construct || | ||||
|         !( | ||||
|           construct.isSubMenu || | ||||
|           construct.isMenuItem || | ||||
|           construct.isMenuItemGroup || | ||||
|           construct.isMenuProvider | ||||
|         ) | ||||
|       ) { | ||||
|         return; | ||||
|       } | ||||
|       if (keys.indexOf(c.key) !== -1) { | ||||
|         ret.find = true; | ||||
|       } else if (c.children && c.children.default) { | ||||
|         loopMenuItemRecursively(c.children.default(), keys, ret); | ||||
|       } | ||||
|     } | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| export const menuAllProps = [ | ||||
|   'defaultSelectedKeys', | ||||
|   'selectedKeys', | ||||
|   'defaultOpenKeys', | ||||
|   'openKeys', | ||||
|   'mode', | ||||
|   'getPopupContainer', | ||||
|   'openTransitionName', | ||||
|   'openAnimation', | ||||
|   'subMenuOpenDelay', | ||||
|   'subMenuCloseDelay', | ||||
|   'forceSubMenuRender', | ||||
|   'triggerSubMenuAction', | ||||
|   'level', | ||||
|   'selectable', | ||||
|   'multiple', | ||||
|   'visible', | ||||
|   'focusable', | ||||
|   'defaultActiveFirst', | ||||
|   'prefixCls', | ||||
|   'inlineIndent', | ||||
|   'title', | ||||
|   'rootPrefixCls', | ||||
|   'eventKey', | ||||
|   'active', | ||||
|   'popupAlign', | ||||
|   'popupOffset', | ||||
|   'isOpen', | ||||
|   'renderMenuItem', | ||||
|   'manualRef', | ||||
|   'subMenuKey', | ||||
|   'disabled', | ||||
|   'index', | ||||
|   'isSelected', | ||||
|   'store', | ||||
|   'activeKey', | ||||
|   'builtinPlacements', | ||||
|   'overflowedIndicator', | ||||
| 
 | ||||
|   // the following keys found need to be removed from test regression
 | ||||
|   'attribute', | ||||
|   'value', | ||||
|   'popupClassName', | ||||
|   'inlineCollapsed', | ||||
|   'menu', | ||||
|   'theme', | ||||
|   'itemIcon', | ||||
|   'expandIcon', | ||||
| 
 | ||||
|   'onSelect', | ||||
|   'onDeselect', | ||||
|   'onDestroy', | ||||
|   'onOpenChange', | ||||
|   'onItemHover', | ||||
|   'onTitleMouseenter', | ||||
|   'onTitleMouseleave', | ||||
|   'onTitleClick', | ||||
|   'slots', | ||||
|   'ref', | ||||
|   'isRootMenu', | ||||
|   'parentUniKeys', | ||||
|   'parentUniKey', | ||||
| ]; | ||||
| 
 | ||||
| // ref: https://github.com/ant-design/ant-design/issues/14007
 | ||||
| // ref: https://bugs.chromium.org/p/chromium/issues/detail?id=360889
 | ||||
| // getBoundingClientRect return the full precision value, which is
 | ||||
| // not the same behavior as on chrome. Set the precision to 6 to
 | ||||
| // unify their behavior
 | ||||
| export const getWidth = elem => { | ||||
|   let width = | ||||
|     elem && typeof elem.getBoundingClientRect === 'function' && elem.getBoundingClientRect().width; | ||||
|   if (width) { | ||||
|     width = +width.toFixed(6); | ||||
|   } | ||||
|   return width || 0; | ||||
| }; | ||||
| 
 | ||||
| export const setStyle = (elem, styleProperty, value) => { | ||||
|   if (elem && typeof elem.style === 'object') { | ||||
|     elem.style[styleProperty] = value; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| export const isMobileDevice = () => { | ||||
|   return isMobile.any; | ||||
| }; | ||||
|  | @ -1,110 +0,0 @@ | |||
| // MIT License from https://github.com/kaimallea/isMobile
 | ||||
| 
 | ||||
| const applePhone = /iPhone/i; | ||||
| const appleIpod = /iPod/i; | ||||
| const appleTablet = /iPad/i; | ||||
| const androidPhone = /\bAndroid(?:.+)Mobile\b/i; // Match 'Android' AND 'Mobile'
 | ||||
| const androidTablet = /Android/i; | ||||
| const amazonPhone = /\bAndroid(?:.+)SD4930UR\b/i; | ||||
| const amazonTablet = /\bAndroid(?:.+)(?:KF[A-Z]{2,4})\b/i; | ||||
| const windowsPhone = /Windows Phone/i; | ||||
| const windowsTablet = /\bWindows(?:.+)ARM\b/i; // Match 'Windows' AND 'ARM'
 | ||||
| const otherBlackberry = /BlackBerry/i; | ||||
| const otherBlackberry10 = /BB10/i; | ||||
| const otherOpera = /Opera Mini/i; | ||||
| const otherChrome = /\b(CriOS|Chrome)(?:.+)Mobile/i; | ||||
| const otherFirefox = /Mobile(?:.+)Firefox\b/i; // Match 'Mobile' AND 'Firefox'
 | ||||
| 
 | ||||
| function match(regex, userAgent) { | ||||
|   return regex.test(userAgent); | ||||
| } | ||||
| 
 | ||||
| function isMobile(userAgent) { | ||||
|   let ua = userAgent || (typeof navigator !== 'undefined' ? navigator.userAgent : ''); | ||||
| 
 | ||||
|   // Facebook mobile app's integrated browser adds a bunch of strings that
 | ||||
|   // match everything. Strip it out if it exists.
 | ||||
|   let tmp = ua.split('[FBAN'); | ||||
|   if (typeof tmp[1] !== 'undefined') { | ||||
|     [ua] = tmp; | ||||
|   } | ||||
| 
 | ||||
|   // Twitter mobile app's integrated browser on iPad adds a "Twitter for
 | ||||
|   // iPhone" string. Same probably happens on other tablet platforms.
 | ||||
|   // This will confuse detection so strip it out if it exists.
 | ||||
|   tmp = ua.split('Twitter'); | ||||
|   if (typeof tmp[1] !== 'undefined') { | ||||
|     [ua] = tmp; | ||||
|   } | ||||
| 
 | ||||
|   const result = { | ||||
|     apple: { | ||||
|       phone: match(applePhone, ua) && !match(windowsPhone, ua), | ||||
|       ipod: match(appleIpod, ua), | ||||
|       tablet: !match(applePhone, ua) && match(appleTablet, ua) && !match(windowsPhone, ua), | ||||
|       device: | ||||
|         (match(applePhone, ua) || match(appleIpod, ua) || match(appleTablet, ua)) && | ||||
|         !match(windowsPhone, ua), | ||||
|     }, | ||||
|     amazon: { | ||||
|       phone: match(amazonPhone, ua), | ||||
|       tablet: !match(amazonPhone, ua) && match(amazonTablet, ua), | ||||
|       device: match(amazonPhone, ua) || match(amazonTablet, ua), | ||||
|     }, | ||||
|     android: { | ||||
|       phone: | ||||
|         (!match(windowsPhone, ua) && match(amazonPhone, ua)) || | ||||
|         (!match(windowsPhone, ua) && match(androidPhone, ua)), | ||||
|       tablet: | ||||
|         !match(windowsPhone, ua) && | ||||
|         !match(amazonPhone, ua) && | ||||
|         !match(androidPhone, ua) && | ||||
|         (match(amazonTablet, ua) || match(androidTablet, ua)), | ||||
|       device: | ||||
|         (!match(windowsPhone, ua) && | ||||
|           (match(amazonPhone, ua) || | ||||
|             match(amazonTablet, ua) || | ||||
|             match(androidPhone, ua) || | ||||
|             match(androidTablet, ua))) || | ||||
|         match(/\bokhttp\b/i, ua), | ||||
|     }, | ||||
|     windows: { | ||||
|       phone: match(windowsPhone, ua), | ||||
|       tablet: match(windowsTablet, ua), | ||||
|       device: match(windowsPhone, ua) || match(windowsTablet, ua), | ||||
|     }, | ||||
|     other: { | ||||
|       blackberry: match(otherBlackberry, ua), | ||||
|       blackberry10: match(otherBlackberry10, ua), | ||||
|       opera: match(otherOpera, ua), | ||||
|       firefox: match(otherFirefox, ua), | ||||
|       chrome: match(otherChrome, ua), | ||||
|       device: | ||||
|         match(otherBlackberry, ua) || | ||||
|         match(otherBlackberry10, ua) || | ||||
|         match(otherOpera, ua) || | ||||
|         match(otherFirefox, ua) || | ||||
|         match(otherChrome, ua), | ||||
|     }, | ||||
| 
 | ||||
|     // Additional
 | ||||
|     any: null, | ||||
|     phone: null, | ||||
|     tablet: null, | ||||
|   }; | ||||
|   result.any = | ||||
|     result.apple.device || result.android.device || result.windows.device || result.other.device; | ||||
| 
 | ||||
|   // excludes 'other' devices and ipods, targeting touchscreen phones
 | ||||
|   result.phone = result.apple.phone || result.android.phone || result.windows.phone; | ||||
|   result.tablet = result.apple.tablet || result.android.tablet || result.windows.tablet; | ||||
| 
 | ||||
|   return result; | ||||
| } | ||||
| 
 | ||||
| const defaultResult = { | ||||
|   ...isMobile(), | ||||
|   isMobile, | ||||
| }; | ||||
| 
 | ||||
| export default defaultResult; | ||||
		Loading…
	
		Reference in New Issue
	
	 tanjinzhou
						tanjinzhou