ant-design-vue/components/vc-menu/MenuMixin.js

263 lines
7.2 KiB
JavaScript
Raw Normal View History

2018-02-24 10:12:24 +00:00
import { hasProp, getComponentName } from '../_util/props-util'
2018-02-06 09:22:36 +00:00
import KeyCode from '../_util/KeyCode'
2017-12-08 06:31:53 +00:00
import scrollIntoView from 'dom-scroll-into-view'
import { getKeyFromChildrenIndex, loopMenuItem } from './util'
2018-02-24 10:12:24 +00:00
import { cloneElement } from '../_util/vnode'
2017-12-08 06:31:53 +00:00
import DOMWrap from './DOMWrap'
2018-02-06 09:22:36 +00:00
import warning from '../_util/warning'
2017-12-08 06:31:53 +00:00
function allDisabled (arr) {
if (!arr.length) {
return true
}
2018-01-02 11:05:02 +00:00
return arr.every(c => {
2018-01-09 06:21:15 +00:00
return !!c.disabled
2018-01-02 11:05:02 +00:00
})
2017-12-08 06:31:53 +00:00
}
2018-01-03 10:30:12 +00:00
export default {
2017-12-12 05:49:02 +00:00
data () {
const props = this.$props
2017-12-08 06:31:53 +00:00
return {
2018-01-04 11:06:54 +00:00
sActiveKey: this.getActiveKey(props.activeKey),
2017-12-08 06:31:53 +00:00
}
},
2018-01-08 10:31:04 +00:00
provide () {
return {
parentMenuContext: this,
}
},
2018-01-02 11:05:02 +00:00
watch: {
'$props': {
handler: function (nextProps) {
let props
if (hasProp(this, 'activeKey')) {
props = {
2018-01-04 11:06:54 +00:00
sActiveKey: this.getActiveKey(nextProps.activeKey),
2018-01-02 11:05:02 +00:00
}
} else {
const originalActiveKey = this.$data.sActiveKey
2018-01-04 11:06:54 +00:00
const sActiveKey = this.getActiveKey(originalActiveKey)
2018-01-02 11:05:02 +00:00
// fix: this.setState(), parent.render(),
if (sActiveKey !== originalActiveKey) {
props = {
sActiveKey,
}
}
2017-12-08 06:31:53 +00:00
}
2018-01-02 11:05:02 +00:00
if (props) {
this.setState(props)
}
},
deep: true,
},
2017-12-08 06:31:53 +00:00
},
2017-12-12 05:49:02 +00:00
methods: {
2018-01-04 11:06:54 +00:00
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
},
2017-12-12 05:49:02 +00:00
// all keyboard events callbacks run from here at first
2018-01-09 06:21:15 +00:00
onKeyDown (e) {
2017-12-12 05:49:02 +00:00
const keyCode = e.keyCode
let handled
this.getFlatInstanceArray().forEach((obj) => {
2018-01-09 06:21:15 +00:00
if (obj && obj.active) {
handled = obj.onKeyDown(e)
2017-12-08 06:31:53 +00:00
}
})
2017-12-12 05:49:02 +00:00
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({
2018-01-09 06:21:15 +00:00
sActiveKey: activeItem.eventKey,
2017-12-12 05:49:02 +00:00
}, () => {
scrollIntoView(activeItem.$el, this.$el, {
onlyScrollIfNeeded: true,
})
})
return 1
} else if (activeItem === undefined) {
e.preventDefault()
this.setState({
2018-01-02 11:05:02 +00:00
sActiveKey: null,
2017-12-12 05:49:02 +00:00
})
return 1
}
},
onItemHover (e) {
const { key, hover } = e
2017-12-08 06:31:53 +00:00
this.setState({
2018-01-02 11:05:02 +00:00
sActiveKey: hover ? key : null,
2017-12-08 06:31:53 +00:00
})
2017-12-12 05:49:02 +00:00
},
2017-12-08 06:31:53 +00:00
2017-12-12 05:49:02 +00:00
getFlatInstanceArray () {
2018-01-09 06:21:15 +00:00
let instance = []
try {
instance = this.$children[0].$children || []
} catch (error) {
2017-12-12 05:49:02 +00:00
}
2018-01-09 06:21:15 +00:00
return instance
2017-12-12 05:49:02 +00:00
},
2017-12-08 06:31:53 +00:00
2017-12-12 05:49:02 +00:00
renderCommonMenuItem (child, i, subIndex, extraProps) {
2018-01-16 11:15:07 +00:00
if (child.tag === undefined) { return child }
2018-01-30 09:17:40 +00:00
warning(['MenuItem', 'MenuItemGroup', 'SubMenu', 'MenuDivider'].includes(getComponentName(child.componentOptions)),
2018-01-30 08:52:56 +00:00
`Menu children not support ${getComponentName(child.componentOptions)}`,
2018-01-16 11:15:07 +00:00
)
2018-01-02 11:05:02 +00:00
const state = this.$data
const props = this.$props
2017-12-12 05:49:02 +00:00
const key = getKeyFromChildrenIndex(child, props.eventKey, i)
2018-01-02 11:05:02 +00:00
const childProps = child.componentOptions.propsData || {}
const isActive = key === state.sActiveKey
2017-12-12 05:49:02 +00:00
const newChildProps = {
2018-01-02 11:05:02 +00:00
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,
},
2018-01-25 09:40:46 +00:00
on: {
2018-01-02 11:05:02 +00:00
click: this.onClick,
itemHover: this.onItemHover,
2018-01-04 02:35:45 +00:00
openChange: this.onOpenChange,
2018-01-02 11:05:02 +00:00
deselect: this.onDeselect,
2018-01-17 08:12:53 +00:00
// destroy: this.onDestroy,
2018-01-02 11:05:02 +00:00
select: this.onSelect,
},
2017-12-12 05:49:02 +00:00
}
if (props.mode === 'inline') {
2018-01-02 11:05:02 +00:00
newChildProps.props.triggerSubMenuAction = 'click'
2017-12-12 05:49:02 +00:00
}
2018-01-17 08:12:53 +00:00
// if (!extraProps.isRootMenu) {
// newChildProps.props.clearSubMenuTimers = this.clearSubMenuTimers
// }
2018-01-02 11:05:02 +00:00
return cloneElement(child, newChildProps)
2017-12-12 05:49:02 +00:00
},
2017-12-08 06:31:53 +00:00
2018-01-03 10:30:12 +00:00
renderRoot (props, children = []) {
2017-12-12 05:49:02 +00:00
const className = {
[props.prefixCls]: true,
2018-01-02 11:05:02 +00:00
[props.class]: true,
2017-12-12 05:49:02 +00:00
[`${props.prefixCls}-${props.mode}`]: true,
}
const domProps = {
2018-01-02 11:05:02 +00:00
attrs: {
role: 'menu',
'aria-activedescendant': '',
},
props: {
tag: 'ul',
2018-01-04 11:06:54 +00:00
// hiddenClassName: `${props.prefixCls}-hidden`,
// visible: props.visible,
2018-01-02 11:05:02 +00:00
},
class: className,
2018-02-28 11:07:04 +00:00
on: {},
}
if (this.$listeners.popupScroll) {
domProps.on.scroll = this.$listeners.popupScroll
2017-12-12 05:49:02 +00:00
}
if (props.id) {
domProps.id = props.id
}
if (props.focusable) {
2018-01-02 11:05:02 +00:00
domProps.attrs.tabIndex = '0'
domProps.on.keydown = this.onKeyDown
2017-12-12 05:49:02 +00:00
}
2018-01-09 06:21:15 +00:00
const newChildren = children.map((c, i) => this.renderMenuItem(c, i))
2017-12-12 05:49:02 +00:00
return (
2018-01-04 11:06:54 +00:00
<DOMWrap
2017-12-12 05:49:02 +00:00
{...domProps}
>
2018-01-03 10:30:12 +00:00
{newChildren}
2018-01-04 11:06:54 +00:00
</DOMWrap>
2017-12-12 05:49:02 +00:00
)
},
2017-12-08 06:31:53 +00:00
2017-12-12 05:49:02 +00:00
step (direction) {
let children = this.getFlatInstanceArray()
2018-01-02 11:05:02 +00:00
const sActiveKey = this.$data.sActiveKey
2017-12-12 05:49:02 +00:00
const len = children.length
if (!len) {
return null
2017-12-08 06:31:53 +00:00
}
2017-12-12 05:49:02 +00:00
if (direction < 0) {
children = children.concat().reverse()
2017-12-08 06:31:53 +00:00
}
2017-12-12 05:49:02 +00:00
// find current activeIndex
let activeIndex = -1
children.every((c, ci) => {
2018-01-09 06:21:15 +00:00
if (c && c.eventKey === sActiveKey) {
2017-12-12 05:49:02 +00:00
activeIndex = ci
return false
}
return true
})
2018-01-02 11:05:02 +00:00
if (!this.$props.defaultActiveFirst && activeIndex !== -1) {
2017-12-12 05:49:02 +00:00
if (allDisabled(children.slice(activeIndex, len - 1))) {
return undefined
2017-12-08 06:31:53 +00:00
}
}
2017-12-12 05:49:02 +00:00
const start = (activeIndex + 1) % len
let i = start
for (; ;) {
const child = children[i]
2018-01-09 06:21:15 +00:00
if (!child || child.disabled) {
2017-12-12 05:49:02 +00:00
i = (i + 1 + len) % len
// complete a loop
if (i === start) {
return null
}
} else {
return child
}
}
},
2017-12-08 06:31:53 +00:00
},
}