feat: update vc-menu to 7.4.19
parent
2bf65a4828
commit
2cce6a5f55
|
@ -88,19 +88,19 @@ const getOptionProps = (instance) => {
|
|||
return filterProps($props, $options.propsData)
|
||||
}
|
||||
|
||||
const getComponentFromProp = (instance, prop) => {
|
||||
const getComponentFromProp = (instance, prop, options) => {
|
||||
if (instance.$createElement) {
|
||||
const h = instance.$createElement
|
||||
const temp = instance[prop]
|
||||
if (temp !== undefined) {
|
||||
return typeof temp === 'function' ? temp(h) : temp
|
||||
return typeof temp === 'function' ? temp(h, options) : temp
|
||||
}
|
||||
return instance.$slots[prop]
|
||||
return instance.$slots[prop] || (instance.$scopedSlots[prop] && instance.$scopedSlots[prop](options)) || undefined
|
||||
} else {
|
||||
const h = instance.context.$createElement
|
||||
const temp = getPropsData(instance)[prop]
|
||||
if (temp !== undefined) {
|
||||
return typeof temp === 'function' ? temp(h) : temp
|
||||
return typeof temp === 'function' ? temp(h, options) : temp
|
||||
}
|
||||
const slotsProp = []
|
||||
const componentOptions = instance.componentOptions || {};
|
||||
|
|
|
@ -1,41 +1,304 @@
|
|||
import PropTypes from '../_util/vue-types'
|
||||
import ResizeObserver from 'resize-observer-polyfill'
|
||||
import SubMenu from './SubMenu'
|
||||
import BaseMixin from '../_util/BaseMixin'
|
||||
import { getWidth, setStyle, menuAllProps } from './util'
|
||||
import { cloneElement } from '../_util/vnode'
|
||||
import { getClass, getPropsData, filterEmpty } from '../_util/props-util'
|
||||
|
||||
import omit from 'omit.js'
|
||||
export default {
|
||||
const canUseDOM = !!(
|
||||
typeof window !== 'undefined' &&
|
||||
window.document &&
|
||||
window.document.createElement
|
||||
)
|
||||
|
||||
const MENUITEM_OVERFLOWED_CLASSNAME = 'menuitem-overflowed'
|
||||
|
||||
// Fix ssr
|
||||
if (canUseDOM) {
|
||||
require('mutationobserver-shim')
|
||||
}
|
||||
|
||||
const DOMWrap = {
|
||||
name: 'DOMWrap',
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
tag: {
|
||||
type: String,
|
||||
default: 'div',
|
||||
},
|
||||
hiddenClassName: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
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,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
class () {
|
||||
const { visible, hiddenClassName } = this.$props
|
||||
return {
|
||||
// [hiddenClassName]: !visible,
|
||||
|
||||
mounted () {
|
||||
this.$nextTick(() => {
|
||||
this.setChildrenWidthAndResize()
|
||||
if (this.level === 1 && this.mode === 'horizontal') {
|
||||
const menuUl = this.$el
|
||||
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 }
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
beforeDestroy () {
|
||||
if (this.resizeObserver) {
|
||||
this.resizeObserver.disconnect()
|
||||
}
|
||||
if (this.mutationObserver) {
|
||||
this.resizeObserver.disconnect()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// get all valid menuItem nodes
|
||||
getMenuItemNodes () {
|
||||
const { prefixCls } = this.$props
|
||||
const ul = this.$el
|
||||
if (!ul) {
|
||||
return []
|
||||
}
|
||||
|
||||
// filter out all overflowed indicator placeholder
|
||||
return [].slice.call(ul.children)
|
||||
.filter(node => {
|
||||
return 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 = this.$slots.default[0]
|
||||
const { title, eventKey, ...rest } = getPropsData(copy)
|
||||
|
||||
let style = {}
|
||||
let key = `${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`
|
||||
}
|
||||
|
||||
const popupClassName = theme ? `${prefixCls}-${theme}` : ''
|
||||
const subMenuProps = {
|
||||
props: {
|
||||
title,
|
||||
overflowedIndicator,
|
||||
popupClassName,
|
||||
eventKey: `${keyPrefix}-overflowed-indicator`,
|
||||
disabled: false,
|
||||
},
|
||||
class: `${prefixCls}-overflowed-submenu`,
|
||||
key,
|
||||
style,
|
||||
on: copy.$listeners,
|
||||
}
|
||||
menuAllProps.props.forEach(k => {
|
||||
if (rest[k] !== undefined) {
|
||||
subMenuProps.props[k] = rest[k]
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<SubMenu
|
||||
{...subMenuProps}
|
||||
>
|
||||
{overflowedItems}
|
||||
</SubMenu>
|
||||
)
|
||||
},
|
||||
|
||||
// memorize rendered menuSize
|
||||
setChildrenWidthAndResize () {
|
||||
if (this.mode !== 'horizontal') {
|
||||
return
|
||||
}
|
||||
const ul = this.$el
|
||||
|
||||
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 = this.$el
|
||||
if (!ul) {
|
||||
return
|
||||
}
|
||||
const width = getWidth(ul)
|
||||
|
||||
this.overflowedItems = []
|
||||
let currentSumWidth = 0
|
||||
|
||||
// index for last visible child in horizontal mode
|
||||
let lastVisibleIndex
|
||||
|
||||
if (this.originalTotalWidth > width) {
|
||||
lastVisibleIndex = -1
|
||||
|
||||
this.menuItemSizes.forEach(liWidth => {
|
||||
currentSumWidth += liWidth
|
||||
if (currentSumWidth + this.overflowedIndicatorWidth <= width) {
|
||||
lastVisibleIndex++
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.setState({ lastVisibleIndex })
|
||||
},
|
||||
|
||||
renderChildren (children) {
|
||||
// need to take care of overflowed items in horizontal mode
|
||||
const { lastVisibleIndex } = this.$data
|
||||
const className = getClass(this)
|
||||
return (children || []).reduce((acc, childNode, index) => {
|
||||
let item = childNode
|
||||
const eventKey = getPropsData(childNode).eventKey
|
||||
if (this.mode === 'horizontal') {
|
||||
let overflowed = this.getOverflowedSubMenuItem(eventKey, [])
|
||||
if (lastVisibleIndex !== undefined &&
|
||||
className[`${this.prefixCls}-root`]
|
||||
) {
|
||||
if (index > lastVisibleIndex) {
|
||||
item = cloneElement(
|
||||
childNode,
|
||||
// 这里修改 eventKey 是为了防止隐藏状态下还会触发 openkeys 事件
|
||||
{
|
||||
style: { display: 'none' },
|
||||
props: { eventKey: `${eventKey}-hidden` },
|
||||
class: { ...getClass(childNode), [MENUITEM_OVERFLOWED_CLASSNAME]: true },
|
||||
},
|
||||
)
|
||||
}
|
||||
if (index === lastVisibleIndex + 1) {
|
||||
this.overflowedItems = children.slice(lastVisibleIndex + 1).map(c => {
|
||||
return cloneElement(
|
||||
c,
|
||||
// children[index].key will become '.$key' in clone by default,
|
||||
// we have to overwrite with the correct key explicitly
|
||||
{ key: getPropsData(c).eventKey, props: { mode: 'vertical-left' }},
|
||||
)
|
||||
})
|
||||
|
||||
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 otherProps = omit(this.$props, [
|
||||
'tag',
|
||||
'hiddenClassName',
|
||||
'visible',
|
||||
])
|
||||
const Tag = this.$props.tag
|
||||
const tagProps = {
|
||||
attr: { ...otherProps, ...this.$attrs },
|
||||
on: this.$listeners,
|
||||
}
|
||||
return <Tag {...tagProps} class={this.class}>{this.$slots.default}</Tag>
|
||||
return <Tag {...tagProps}>{this.renderChildren(filterEmpty(this.$slots.default))}</Tag>
|
||||
},
|
||||
}
|
||||
|
||||
DOMWrap.props = {
|
||||
mode: PropTypes.oneOf(['horizontal', 'vertical', 'vertical-left', 'vertical-right', 'inline']),
|
||||
prefixCls: PropTypes.string,
|
||||
level: PropTypes.number,
|
||||
theme: PropTypes.string,
|
||||
overflowedIndicator: PropTypes.node,
|
||||
visible: PropTypes.bool,
|
||||
hiddenClassName: PropTypes.string,
|
||||
tag: PropTypes.string.def('div'),
|
||||
}
|
||||
|
||||
export default DOMWrap
|
||||
|
|
|
@ -2,7 +2,7 @@ import PropTypes from '../_util/vue-types'
|
|||
import { Provider, create } from '../_util/store'
|
||||
import { default as SubPopupMenu, getActiveKey } from './SubPopupMenu'
|
||||
import BaseMixin from '../_util/BaseMixin'
|
||||
import hasProp, { getOptionProps } from '../_util/props-util'
|
||||
import hasProp, { getOptionProps, getComponentFromProp } from '../_util/props-util'
|
||||
import commonPropsType from './commonPropsType'
|
||||
|
||||
const Menu = {
|
||||
|
@ -33,47 +33,13 @@ const Menu = {
|
|||
// this.isRootMenu = true // 声明在props上
|
||||
return {}
|
||||
},
|
||||
watch: {
|
||||
selectedKeys (val) {
|
||||
this.store.setState({
|
||||
selectedKeys: val || [],
|
||||
})
|
||||
},
|
||||
openKeys (val) {
|
||||
this.store.setState({
|
||||
openKeys: val || [],
|
||||
})
|
||||
},
|
||||
// '$props': {
|
||||
// handler: function (nextProps) {
|
||||
// if (hasProp(this, 'selectedKeys')) {
|
||||
// this.setState({
|
||||
// sSelectedKeys: nextProps.selectedKeys || [],
|
||||
// })
|
||||
// }
|
||||
// if (hasProp(this, 'openKeys')) {
|
||||
// this.setState({
|
||||
// sOpenKeys: nextProps.openKeys || [],
|
||||
// })
|
||||
// }
|
||||
// },
|
||||
// deep: true,
|
||||
// },
|
||||
mounted () {
|
||||
this.updateMiniStore()
|
||||
},
|
||||
updated () {
|
||||
this.updateMiniStore()
|
||||
},
|
||||
methods: {
|
||||
// onDestroy (key) {
|
||||
// const state = this.$data
|
||||
// const sSelectedKeys = state.sSelectedKeys
|
||||
// const sOpenKeys = state.sOpenKeys
|
||||
// let index = sSelectedKeys.indexOf(key)
|
||||
// if (!hasProp(this, 'selectedKeys') && index !== -1) {
|
||||
// sSelectedKeys.splice(index, 1)
|
||||
// }
|
||||
// index = sOpenKeys.indexOf(key)
|
||||
// if (!hasProp(this, 'openKeys') && index !== -1) {
|
||||
// sOpenKeys.splice(index, 1)
|
||||
// }
|
||||
// },
|
||||
|
||||
onSelect (selectInfo) {
|
||||
const props = this.$props
|
||||
|
@ -170,35 +136,19 @@ const Menu = {
|
|||
}
|
||||
return transitionName
|
||||
},
|
||||
|
||||
// isInlineMode () {
|
||||
// return this.$props.mode === 'inline'
|
||||
// },
|
||||
|
||||
// lastOpenSubMenu () {
|
||||
// let lastOpen = []
|
||||
// const { sOpenKeys } = this.$data
|
||||
// if (sOpenKeys.length) {
|
||||
// lastOpen = this.getFlatInstanceArray().filter((c) => {
|
||||
// return c && sOpenKeys.indexOf(c.eventKey) !== -1
|
||||
// })
|
||||
// }
|
||||
// return lastOpen[0]
|
||||
// },
|
||||
|
||||
// renderMenuItem (c, i, subIndex) {
|
||||
// if (!c) {
|
||||
// return null
|
||||
// }
|
||||
// const state = this.$data
|
||||
// const extraProps = {
|
||||
// openKeys: state.sOpenKeys,
|
||||
// selectedKeys: state.sSelectedKeys,
|
||||
// triggerSubMenuAction: this.$props.triggerSubMenuAction,
|
||||
// isRootMenu: this.isRootMenu,
|
||||
// }
|
||||
// return this.renderCommonMenuItem(c, i, subIndex, extraProps)
|
||||
// },
|
||||
updateMiniStore () {
|
||||
const props = getOptionProps(this)
|
||||
if ('selectedKeys' in props) {
|
||||
this.store.setState({
|
||||
selectedKeys: props.selectedKeys || [],
|
||||
})
|
||||
}
|
||||
if ('openKeys' in props) {
|
||||
this.store.setState({
|
||||
openKeys: props.openKeys || [],
|
||||
})
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
render () {
|
||||
|
@ -206,6 +156,9 @@ const Menu = {
|
|||
const subPopupMenuProps = {
|
||||
props: {
|
||||
...props,
|
||||
itemIcon: getComponentFromProp(this, 'itemIcon', props),
|
||||
expandIcon: getComponentFromProp(this, 'expandIcon', props),
|
||||
overflowedIndicator: getComponentFromProp(this, 'overflowedIndicator', props),
|
||||
openTransitionName: this.getOpenTransitionName(),
|
||||
parentMenu: this,
|
||||
children: this.$slots.default || [],
|
||||
|
|
|
@ -5,6 +5,7 @@ import BaseMixin from '../_util/BaseMixin'
|
|||
import scrollIntoView from 'dom-scroll-into-view'
|
||||
import { connect } from '../_util/store'
|
||||
import { noop, menuAllProps } from './util'
|
||||
import { getComponentFromProp } from '../_util/props-util'
|
||||
|
||||
const props = {
|
||||
attribute: PropTypes.object,
|
||||
|
@ -25,6 +26,7 @@ const props = {
|
|||
manualRef: PropTypes.func.def(noop),
|
||||
role: PropTypes.any,
|
||||
subMenuKey: PropTypes.string,
|
||||
itemIcon: PropTypes.any,
|
||||
// clearSubMenuTimers: PropTypes.func.def(noop),
|
||||
}
|
||||
const MenuItem = {
|
||||
|
@ -138,7 +140,7 @@ const MenuItem = {
|
|||
let attrs = {
|
||||
...props.attribute,
|
||||
title: props.title,
|
||||
role: 'menuitem',
|
||||
role: props.role || 'menuitem',
|
||||
'aria-disabled': props.disabled,
|
||||
}
|
||||
if (props.role === 'option') {
|
||||
|
@ -148,10 +150,13 @@ const MenuItem = {
|
|||
role: 'option',
|
||||
'aria-selected': props.isSelected,
|
||||
}
|
||||
} else if (props.role === null) {
|
||||
} 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
|
||||
delete attrs.role
|
||||
// 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 = {
|
||||
|
@ -184,6 +189,7 @@ const MenuItem = {
|
|||
class={className}
|
||||
>
|
||||
{this.$slots.default}
|
||||
{getComponentFromProp(this, 'itemIcon', props)}
|
||||
</li>
|
||||
)
|
||||
},
|
||||
|
|
|
@ -66,6 +66,9 @@ const SubMenu = {
|
|||
store: PropTypes.object,
|
||||
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,
|
||||
},
|
||||
mixins: [BaseMixin],
|
||||
isSubMenu: true,
|
||||
|
@ -350,11 +353,14 @@ const SubMenu = {
|
|||
subMenuCloseDelay: props.subMenuCloseDelay,
|
||||
forceSubMenuRender: props.forceSubMenuRender,
|
||||
triggerSubMenuAction: props.triggerSubMenuAction,
|
||||
builtinPlacements: props.builtinPlacements,
|
||||
defaultActiveFirst: props.store.getState()
|
||||
.defaultActiveFirst[getMenuIdFromSubMenuEventKey(props.eventKey)],
|
||||
multiple: props.multiple,
|
||||
prefixCls: props.rootPrefixCls,
|
||||
manualRef: this.saveMenuInstance,
|
||||
itemIcon: getComponentFromProp(this, 'itemIcon'),
|
||||
expandIcon: getComponentFromProp(this, 'expandIcon'),
|
||||
children,
|
||||
__propsSymbol__: Symbol(),
|
||||
},
|
||||
|
@ -475,10 +481,15 @@ const SubMenu = {
|
|||
class: `${prefixCls}-title`,
|
||||
ref: 'subMenuTitle',
|
||||
}
|
||||
// expand custom icon should NOT be displayed in menu with horizontal mode.
|
||||
let icon = null
|
||||
if (props.mode !== 'horizontal') {
|
||||
icon = getComponentFromProp(this, 'expandIcon', props)
|
||||
}
|
||||
const title = (
|
||||
<div {...titleProps}>
|
||||
{getComponentFromProp(this, 'title')}
|
||||
<i class={`${prefixCls}-arrow`} />
|
||||
{icon || <i class={`${prefixCls}-arrow`} />}
|
||||
</div>
|
||||
)
|
||||
const children = this.renderChildren(this.$slots.default)
|
||||
|
@ -503,6 +514,7 @@ const SubMenu = {
|
|||
popupClassName={`${prefixCls}-popup ${rootPrefixCls}-${parentMenu.theme} ${popupClassName || ''}`}
|
||||
getPopupContainer={getPopupContainer}
|
||||
builtinPlacements={placements}
|
||||
builtinPlacements={Object.assign({}, placements, props.builtinPlacements)}
|
||||
popupPlacement={popupPlacement}
|
||||
popupVisible={isOpen}
|
||||
popupAlign={popupAlign}
|
||||
|
|
|
@ -7,7 +7,7 @@ import classNames from 'classnames'
|
|||
import { getKeyFromChildrenIndex, loopMenuItem, noop } from './util'
|
||||
import DOMWrap from './DOMWrap'
|
||||
import { cloneElement } from '../_util/vnode'
|
||||
import { initDefaultProps, getOptionProps, getEvents } from '../_util/props-util'
|
||||
import { initDefaultProps, getOptionProps, getPropsData, getEvents, getComponentFromProp } from '../_util/props-util'
|
||||
|
||||
function allDisabled (arr) {
|
||||
if (!arr.length) {
|
||||
|
@ -28,6 +28,11 @@ function updateActiveKey (store, 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]
|
||||
|
@ -100,6 +105,8 @@ const SubPopupMenu = {
|
|||
triggerSubMenuAction: PropTypes.oneOf(['click', 'hover']),
|
||||
inlineIndent: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
||||
manualRef: PropTypes.func,
|
||||
itemIcon: PropTypes.any,
|
||||
expandIcon: PropTypes.any,
|
||||
children: PropTypes.any.def([]),
|
||||
__propsSymbol__: PropTypes.any, // mock componentWillReceiveProps
|
||||
}, {
|
||||
|
@ -129,18 +136,27 @@ const SubPopupMenu = {
|
|||
this.manualRef(this)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
__propsSymbol__ () {
|
||||
const props = getOptionProps(this)
|
||||
const storeActiveKey = this.getStore().getState().activeKey[this.getEventKey()]
|
||||
const originalActiveKey = 'activeKey' in props ? props.activeKey
|
||||
: storeActiveKey
|
||||
const activeKey = getActiveKey(props, originalActiveKey)
|
||||
if (activeKey !== originalActiveKey || storeActiveKey !== activeKey) {
|
||||
updateActiveKey(this.getStore(), this.getEventKey(), activeKey)
|
||||
}
|
||||
},
|
||||
updated () {
|
||||
const props = getOptionProps(this)
|
||||
const originalActiveKey = 'activeKey' in props ? props.activeKey
|
||||
: props.store.getState().activeKey[getEventKey(props)]
|
||||
const activeKey = getActiveKey(props, originalActiveKey)
|
||||
if (activeKey !== originalActiveKey) {
|
||||
updateActiveKey(props.store, getEventKey(props), activeKey)
|
||||
}
|
||||
},
|
||||
// watch: {
|
||||
// __propsSymbol__ () {
|
||||
// const props = getOptionProps(this)
|
||||
// const storeActiveKey = this.getStore().getState().activeKey[this.getEventKey()]
|
||||
// const originalActiveKey = 'activeKey' in props ? props.activeKey
|
||||
// : storeActiveKey
|
||||
// const activeKey = getActiveKey(props, originalActiveKey)
|
||||
// if (activeKey !== originalActiveKey || storeActiveKey !== activeKey) {
|
||||
// updateActiveKey(this.getStore(), this.getEventKey(), activeKey)
|
||||
// }
|
||||
// },
|
||||
// },
|
||||
methods: {
|
||||
// all keyboard events callbacks run from here at first
|
||||
onKeyDown (e, callback) {
|
||||
|
@ -160,7 +176,7 @@ const SubPopupMenu = {
|
|||
}
|
||||
if (activeItem) {
|
||||
e.preventDefault()
|
||||
updateActiveKey(this.getStore(), this.getEventKey(), activeItem.eventKey)
|
||||
updateActiveKey(this.$props.store, getEventKey(this.$props), activeItem.eventKey)
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback(activeItem)
|
||||
|
@ -172,7 +188,7 @@ const SubPopupMenu = {
|
|||
|
||||
onItemHover (e) {
|
||||
const { key, hover } = e
|
||||
updateActiveKey(this.getStore(), this.getEventKey(), hover ? key : null)
|
||||
updateActiveKey(this.$props.store, getEventKey(this.$props), hover ? key : null)
|
||||
},
|
||||
|
||||
onDeselect (selectInfo) {
|
||||
|
@ -199,22 +215,13 @@ const SubPopupMenu = {
|
|||
return this.instanceArray
|
||||
},
|
||||
|
||||
getStore () {
|
||||
return this.store
|
||||
},
|
||||
|
||||
getEventKey () {
|
||||
// when eventKey not available ,it's menu and return menu id '0-menu-'
|
||||
return this.eventKey !== undefined ? this.eventKey : '0-menu-'
|
||||
},
|
||||
|
||||
getOpenTransitionName () {
|
||||
return this.$props.openTransitionName
|
||||
},
|
||||
|
||||
step (direction) {
|
||||
let children = this.getFlatInstanceArray()
|
||||
const activeKey = this.getStore().getState().activeKey[this.getEventKey()]
|
||||
const activeKey = this.$props.store.getState().activeKey[this.getEventKey(this.$props)]
|
||||
const len = children.length
|
||||
if (!len) {
|
||||
return null
|
||||
|
@ -251,14 +258,39 @@ const SubPopupMenu = {
|
|||
|
||||
return null
|
||||
},
|
||||
|
||||
getIcon (instance, name) {
|
||||
if (instance.$createElement) {
|
||||
const temp = instance[name]
|
||||
if (temp !== undefined) {
|
||||
return temp
|
||||
}
|
||||
return instance.$slots[name] || instance.$scopedSlots[name]
|
||||
} else {
|
||||
const temp = getPropsData(instance)[name]
|
||||
if (temp !== undefined) {
|
||||
return temp
|
||||
}
|
||||
const slotsProp = []
|
||||
const componentOptions = instance.componentOptions || {};
|
||||
(componentOptions.children || []).forEach((child) => {
|
||||
if (child.data && child.data.slot === name) {
|
||||
if (child.tag === 'template') {
|
||||
slotsProp.push(child.children)
|
||||
} else {
|
||||
slotsProp.push(child)
|
||||
}
|
||||
}
|
||||
})
|
||||
return slotsProp.length ? slotsProp : undefined
|
||||
}
|
||||
},
|
||||
renderCommonMenuItem (child, i, extraProps) {
|
||||
if (child.tag === undefined) { return child }
|
||||
const state = this.getStore().getState()
|
||||
const state = this.$props.store.getState()
|
||||
const props = this.$props
|
||||
const key = getKeyFromChildrenIndex(child, props.eventKey, i)
|
||||
const childProps = child.componentOptions.propsData || {}
|
||||
const isActive = key === state.activeKey[this.getEventKey()]
|
||||
const isActive = key === state.activeKey
|
||||
if (!childProps.disabled) {
|
||||
// manualRef的执行顺序不能保证,使用key映射ref在this.instanceArray中的位置
|
||||
this.instanceArrayKeyIndexMap[key] = Object.keys(this.instanceArrayKeyIndexMap).length
|
||||
|
@ -266,7 +298,7 @@ const SubPopupMenu = {
|
|||
const childListeners = getEvents(child)
|
||||
const newChildProps = {
|
||||
props: {
|
||||
mode: props.mode,
|
||||
mode: childProps.mode || props.mode,
|
||||
level: props.level,
|
||||
inlineIndent: props.inlineIndent,
|
||||
renderMenuItem: this.renderMenuItem,
|
||||
|
@ -283,6 +315,9 @@ const SubPopupMenu = {
|
|||
subMenuOpenDelay: props.subMenuOpenDelay,
|
||||
subMenuCloseDelay: props.subMenuCloseDelay,
|
||||
forceSubMenuRender: props.forceSubMenuRender,
|
||||
builtinPlacements: props.builtinPlacements,
|
||||
itemIcon: this.getIcon(child, 'itemIcon') || this.getIcon(this, 'itemIcon'),
|
||||
expandIcon: this.getIcon(child, 'expandIcon') || this.getIcon(this, 'expandIcon'),
|
||||
...extraProps,
|
||||
},
|
||||
on: {
|
||||
|
@ -307,7 +342,7 @@ const SubPopupMenu = {
|
|||
if (!c) {
|
||||
return null
|
||||
}
|
||||
const state = this.getStore().getState()
|
||||
const state = this.$props.store.getState()
|
||||
const extraProps = {
|
||||
openKeys: state.openKeys,
|
||||
selectedKeys: state.selectedKeys,
|
||||
|
@ -320,7 +355,7 @@ const SubPopupMenu = {
|
|||
},
|
||||
render () {
|
||||
const { ...props } = this.$props
|
||||
const { eventKey, visible } = props
|
||||
const { eventKey, visible, level, mode, theme } = props
|
||||
this.instanceArray = []
|
||||
this.instanceArrayKeyIndexMap = {}
|
||||
const className = classNames(
|
||||
|
@ -332,6 +367,8 @@ const SubPopupMenu = {
|
|||
tag: 'ul',
|
||||
// hiddenClassName: `${prefixCls}-hidden`,
|
||||
visible,
|
||||
level, mode, theme,
|
||||
overflowedIndicator: getComponentFromProp(this, 'overflowedIndicator'),
|
||||
},
|
||||
attrs: {
|
||||
role: props.role || 'menu',
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
@font-face {
|
||||
font-family: 'FontAwesome';
|
||||
src: url('https://cdn.bootcss.com/font-awesome/4.2.0/fonts/fontawesome-webfont.eot?v=4.2.0');
|
||||
src: url('https://cdn.bootcss.com/font-awesome/4.2.0/fonts/fontawesome-webfont.eot?#iefix&v=4.2.0') format('embedded-opentype'), url('https://cdn.bootcss.com/font-awesome/4.2.0/fonts/fontawesome-webfont.woff?v=4.2.0') format('woff'), url('https://cdn.bootcss.com/font-awesome/4.2.0/fonts/fontawesome-webfont.ttf?v=4.2.0') format('truetype'), url('https://cdn.bootcss.com/font-awesome/4.2.0/fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular') format('svg');
|
||||
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;
|
||||
}
|
||||
|
@ -92,6 +92,10 @@
|
|||
&-submenu {
|
||||
&-popup {
|
||||
position: absolute;
|
||||
|
||||
.submenu-title-wrapper {
|
||||
padding-right: 20px;
|
||||
}
|
||||
}
|
||||
> .@{menuPrefixCls} {
|
||||
background-color: #fff;
|
||||
|
@ -110,17 +114,19 @@
|
|||
&-horizontal {
|
||||
background-color: #F3F5F7;
|
||||
border: none;
|
||||
border-bottom: 1px solid transparent;
|
||||
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 {
|
||||
float: left;
|
||||
border-bottom: 2px solid transparent;
|
||||
display: inline-block;
|
||||
vertical-align: bottom;
|
||||
|
||||
&-active {
|
||||
border-bottom: 2px solid #2db7f5;
|
||||
|
|
|
@ -23,4 +23,8 @@ export default {
|
|||
forceSubMenuRender: PropTypes.bool,
|
||||
selectable: PropTypes.bool,
|
||||
isRootMenu: PropTypes.bool.def(true),
|
||||
builtinPlacements: PropTypes.object.def({}),
|
||||
itemIcon: PropTypes.any,
|
||||
expandIcon: PropTypes.any,
|
||||
overflowedIndicator: PropTypes.any,
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// based on rc-menu 7.0.5
|
||||
// based on rc-menu 7.4.19
|
||||
import Menu from './Menu'
|
||||
import SubMenu from './SubMenu'
|
||||
import MenuItem, { menuItemProps } from './MenuItem'
|
||||
|
|
|
@ -77,6 +77,7 @@ export const menuAllProps = {
|
|||
'rootPrefixCls',
|
||||
'eventKey',
|
||||
'active',
|
||||
'popupAlign',
|
||||
'popupOffset',
|
||||
'isOpen',
|
||||
'renderMenuItem',
|
||||
|
@ -87,6 +88,8 @@ export const menuAllProps = {
|
|||
'isSelected',
|
||||
'store',
|
||||
'activeKey',
|
||||
'builtinPlacements',
|
||||
'overflowedIndicator',
|
||||
|
||||
// the following keys found need to be removed from test regression
|
||||
'attribute',
|
||||
|
@ -95,6 +98,8 @@ export const menuAllProps = {
|
|||
'inlineCollapsed',
|
||||
'menu',
|
||||
'theme',
|
||||
'itemIcon',
|
||||
'expandIcon',
|
||||
],
|
||||
on: [
|
||||
'select',
|
||||
|
@ -107,3 +112,15 @@ export const menuAllProps = {
|
|||
'titleClick',
|
||||
],
|
||||
}
|
||||
|
||||
export const getWidth = (elem) => (
|
||||
elem &&
|
||||
typeof elem.getBoundingClientRect === 'function' &&
|
||||
elem.getBoundingClientRect().width
|
||||
) || 0
|
||||
|
||||
export const setStyle = (elem, styleProperty, value) => {
|
||||
if (elem && typeof elem.style === 'object') {
|
||||
elem.style[styleProperty] = value
|
||||
}
|
||||
}
|
||||
|
|
|
@ -172,6 +172,7 @@
|
|||
"json2mq": "^0.2.0",
|
||||
"lodash": "^4.17.5",
|
||||
"moment": "^2.21.0",
|
||||
"mutationobserver-shim": "^0.3.2",
|
||||
"omit.js": "^1.0.0",
|
||||
"raf": "^3.4.0",
|
||||
"resize-observer-polyfill": "^1.5.0",
|
||||
|
|
Loading…
Reference in New Issue