You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ant-design-vue/components/vc-menu/MenuMixin.js

260 lines
7.0 KiB

7 years ago
import { hasProp, getComponentName } from '../_util/props-util'
7 years ago
import KeyCode from '../_util/KeyCode'
7 years ago
import scrollIntoView from 'dom-scroll-into-view'
import { getKeyFromChildrenIndex, loopMenuItem } from './util'
7 years ago
import { cloneElement } from '../_util/vnode'
7 years ago
import DOMWrap from './DOMWrap'
7 years ago
import warning from '../_util/warning'
7 years ago
function allDisabled (arr) {
if (!arr.length) {
return true
}
7 years ago
return arr.every(c => {
7 years ago
return !!c.disabled
7 years ago
})
7 years ago
}
7 years ago
export default {
7 years ago
data () {
const props = this.$props
7 years ago
return {
7 years ago
sActiveKey: this.getActiveKey(props.activeKey),
7 years ago
}
},
7 years ago
provide () {
return {
parentMenuContext: this,
}
},
7 years ago
watch: {
'$props': {
handler: function (nextProps) {
let props
if (hasProp(this, 'activeKey')) {
props = {
7 years ago
sActiveKey: this.getActiveKey(nextProps.activeKey),
7 years ago
}
} else {
const originalActiveKey = this.$data.sActiveKey
7 years ago
const sActiveKey = this.getActiveKey(originalActiveKey)
7 years ago
// fix: this.setState(), parent.render(),
if (sActiveKey !== originalActiveKey) {
props = {
sActiveKey,
}
}
7 years ago
}
7 years ago
if (props) {
this.setState(props)
}
},
deep: true,
},
7 years ago
},
7 years ago
methods: {
7 years ago
getActiveKey (originalActiveKey) {
let activeKey = originalActiveKey
const { eventKey, defaultActiveFirst } = this.$props
const children = this.$slots.default
if (activeKey) {
let found
loopMenuItem(children, (c, i) => {
const propsData = c.componentOptions.propsData || {}
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 = c.componentOptions.propsData || {}
if (!activeKey && c && !propsData.disabled) {
activeKey = getKeyFromChildrenIndex(c, eventKey, i)
}
})
return activeKey
}
return activeKey
},
7 years ago
// all keyboard events callbacks run from here at first
7 years ago
onKeyDown (e) {
7 years ago
const keyCode = e.keyCode
let handled
this.getFlatInstanceArray().forEach((obj) => {
7 years ago
if (obj && obj.active) {
handled = obj.onKeyDown(e)
7 years ago
}
})
7 years ago
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()
this.setState({
7 years ago
sActiveKey: activeItem.eventKey,
7 years ago
}, () => {
scrollIntoView(activeItem.$el, this.$el, {
onlyScrollIfNeeded: true,
})
})
return 1
} else if (activeItem === undefined) {
e.preventDefault()
this.setState({
7 years ago
sActiveKey: null,
7 years ago
})
return 1
}
},
onItemHover (e) {
const { key, hover } = e
7 years ago
this.setState({
7 years ago
sActiveKey: hover ? key : null,
7 years ago
})
7 years ago
},
7 years ago
7 years ago
getFlatInstanceArray () {
7 years ago
let instance = []
try {
instance = this.$children[0].$children || []
} catch (error) {
7 years ago
}
7 years ago
return instance
7 years ago
},
7 years ago
7 years ago
renderCommonMenuItem (child, i, subIndex, extraProps) {
7 years ago
if (child.tag === undefined) { return child }
7 years ago
warning(['MenuItem', 'MenuItemGroup', 'SubMenu', 'MenuDivider'].includes(getComponentName(child.componentOptions)),
7 years ago
`Menu children not support ${getComponentName(child.componentOptions)}`,
7 years ago
)
7 years ago
const state = this.$data
const props = this.$props
7 years ago
const key = getKeyFromChildrenIndex(child, props.eventKey, i)
7 years ago
const childProps = child.componentOptions.propsData || {}
const isActive = key === state.sActiveKey
7 years ago
const newChildProps = {
7 years ago
props: {
mode: props.mode,
level: props.level,
inlineIndent: props.inlineIndent,
renderMenuItem: this.renderMenuItem,
rootPrefixCls: props.prefixCls,
index: i,
eventKey: key,
active: !childProps.disabled && isActive,
multiple: props.multiple,
openTransitionName: this.getOpenTransitionName(),
openAnimation: props.openAnimation,
subMenuOpenDelay: props.subMenuOpenDelay,
subMenuCloseDelay: props.subMenuCloseDelay,
forceSubMenuRender: props.forceSubMenuRender,
...extraProps,
openChange: this.onOpenChange,
},
7 years ago
on: {
7 years ago
click: this.onClick,
itemHover: this.onItemHover,
7 years ago
openChange: this.onOpenChange,
7 years ago
deselect: this.onDeselect,
7 years ago
// destroy: this.onDestroy,
7 years ago
select: this.onSelect,
},
7 years ago
}
if (props.mode === 'inline') {
7 years ago
newChildProps.props.triggerSubMenuAction = 'click'
7 years ago
}
7 years ago
// if (!extraProps.isRootMenu) {
// newChildProps.props.clearSubMenuTimers = this.clearSubMenuTimers
// }
7 years ago
return cloneElement(child, newChildProps)
7 years ago
},
7 years ago
7 years ago
renderRoot (props, children = []) {
7 years ago
const className = {
[props.prefixCls]: true,
7 years ago
[props.class]: true,
7 years ago
[`${props.prefixCls}-${props.mode}`]: true,
}
const domProps = {
7 years ago
attrs: {
role: 'menu',
'aria-activedescendant': '',
},
props: {
tag: 'ul',
7 years ago
// hiddenClassName: `${props.prefixCls}-hidden`,
// visible: props.visible,
7 years ago
},
class: className,
on: {},
7 years ago
}
if (props.id) {
domProps.id = props.id
}
if (props.focusable) {
7 years ago
domProps.attrs.tabIndex = '0'
domProps.on.keydown = this.onKeyDown
7 years ago
}
7 years ago
const newChildren = children.map((c, i) => this.renderMenuItem(c, i))
7 years ago
return (
7 years ago
<DOMWrap
7 years ago
{...domProps}
>
7 years ago
{newChildren}
7 years ago
</DOMWrap>
7 years ago
)
},
7 years ago
7 years ago
step (direction) {
let children = this.getFlatInstanceArray()
7 years ago
const sActiveKey = this.$data.sActiveKey
7 years ago
const len = children.length
if (!len) {
return null
7 years ago
}
7 years ago
if (direction < 0) {
children = children.concat().reverse()
7 years ago
}
7 years ago
// find current activeIndex
let activeIndex = -1
children.every((c, ci) => {
7 years ago
if (c && c.eventKey === sActiveKey) {
7 years ago
activeIndex = ci
return false
}
return true
})
7 years ago
if (!this.$props.defaultActiveFirst && activeIndex !== -1) {
7 years ago
if (allDisabled(children.slice(activeIndex, len - 1))) {
return undefined
7 years ago
}
}
7 years ago
const start = (activeIndex + 1) % len
let i = start
for (; ;) {
const child = children[i]
7 years ago
if (!child || child.disabled) {
7 years ago
i = (i + 1 + len) % len
// complete a loop
if (i === start) {
return null
}
} else {
return child
}
}
},
7 years ago
},
}