fix
parent
baec906d5c
commit
f8be36593d
|
@ -0,0 +1,298 @@
|
||||||
|
@menuPrefixCls: rc-menu;
|
||||||
|
|
||||||
|
@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');
|
||||||
|
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 .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;
|
||||||
|
}
|
||||||
|
> .@{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 transparent;
|
||||||
|
border-bottom: 1px solid #d9d9d9;
|
||||||
|
box-shadow: none;
|
||||||
|
|
||||||
|
& > .@{menuPrefixCls}-item, & > .@{menuPrefixCls}-submenu .@{menuPrefixCls}-submenu-title {
|
||||||
|
padding: 15px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .@{menuPrefixCls}-submenu, & > .@{menuPrefixCls}-item {
|
||||||
|
float: left;
|
||||||
|
border-bottom: 2px solid transparent;
|
||||||
|
|
||||||
|
&-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 .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: .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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,132 @@
|
||||||
|
<script>
|
||||||
|
import { cloneElement } from '../../_util/vnode'
|
||||||
|
import Menu, { SubMenu, Item as MenuItem, Divider } from '../src/index'
|
||||||
|
import '../assets/index.less'
|
||||||
|
import animate from 'css-animation'
|
||||||
|
|
||||||
|
function handleSelect (info) {
|
||||||
|
console.log(info)
|
||||||
|
console.log(`selected ${info.key}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const animation = {
|
||||||
|
enter (node, done) {
|
||||||
|
let height
|
||||||
|
return animate(node, 'rc-menu-collapse', {
|
||||||
|
start () {
|
||||||
|
height = node.offsetHeight
|
||||||
|
node.style.height = 0
|
||||||
|
},
|
||||||
|
active () {
|
||||||
|
node.style.height = `${height}px`
|
||||||
|
},
|
||||||
|
end () {
|
||||||
|
node.style.height = ''
|
||||||
|
done()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
appear () {
|
||||||
|
return this.enter.apply(this, arguments)
|
||||||
|
},
|
||||||
|
|
||||||
|
leave (node, done) {
|
||||||
|
return animate(node, 'rc-menu-collapse', {
|
||||||
|
start () {
|
||||||
|
node.style.height = `${node.offsetHeight}px`
|
||||||
|
},
|
||||||
|
active () {
|
||||||
|
node.style.height = 0
|
||||||
|
},
|
||||||
|
end () {
|
||||||
|
node.style.height = ''
|
||||||
|
done()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
export default {
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
},
|
||||||
|
render () {
|
||||||
|
// const nestSubMenu = (<SubMenu title={<span>sub menu 2</span>} key='4'>
|
||||||
|
// <MenuItem key='4-1'>inner inner</MenuItem>
|
||||||
|
// <Divider/>
|
||||||
|
// <SubMenu
|
||||||
|
// key='4-2'
|
||||||
|
// title={<span>sub menu 3</span>}
|
||||||
|
// >
|
||||||
|
// <SubMenu title='sub 4-2-0' key='4-2-0'>
|
||||||
|
// <MenuItem key='4-2-0-1'>inner inner</MenuItem>
|
||||||
|
// <MenuItem key='4-2-0-2'>inner inner2</MenuItem>
|
||||||
|
// </SubMenu>
|
||||||
|
// <MenuItem key='4-2-1'>inn</MenuItem>
|
||||||
|
// <SubMenu title={<span>sub menu 4</span>} key='4-2-2'>
|
||||||
|
// <MenuItem key='4-2-2-1'>inner inner</MenuItem>
|
||||||
|
// <MenuItem key='4-2-2-2'>inner inner2</MenuItem>
|
||||||
|
// </SubMenu>
|
||||||
|
// <SubMenu title='sub 4-2-3' key='4-2-3'>
|
||||||
|
// <MenuItem key='4-2-3-1'>inner inner</MenuItem>
|
||||||
|
// <MenuItem key='4-2-3-2'>inner inner2</MenuItem>
|
||||||
|
// </SubMenu>
|
||||||
|
// </SubMenu>
|
||||||
|
// </SubMenu>)
|
||||||
|
|
||||||
|
function onOpenChange (value) {
|
||||||
|
console.log('onOpenChange', value)
|
||||||
|
}
|
||||||
|
const commonMenu = (<Menu class='test' onSelect={handleSelect} onOpenChange={onOpenChange}>
|
||||||
|
<SubMenu key='1'>
|
||||||
|
<template slot='title'><span>sub menu</span></template>
|
||||||
|
<MenuItem key='1-1'>0-1</MenuItem>
|
||||||
|
<MenuItem key='1-2'>0-2</MenuItem>
|
||||||
|
</SubMenu>
|
||||||
|
</Menu>)
|
||||||
|
const horizontalMenu = cloneElement(commonMenu, { props: {
|
||||||
|
mode: 'horizontal',
|
||||||
|
// use openTransition for antd
|
||||||
|
openAnimation: 'slide-up',
|
||||||
|
}})
|
||||||
|
|
||||||
|
// const horizontalMenu2 = cloneElement(commonMenu, { props: {
|
||||||
|
// mode: 'horizontal',
|
||||||
|
// openAnimation: 'slide-up',
|
||||||
|
// triggerSubMenuAction: 'click',
|
||||||
|
// }})
|
||||||
|
|
||||||
|
// const verticalMenu = cloneElement(commonMenu, { props: {
|
||||||
|
// mode: 'vertical',
|
||||||
|
// openAnimation: 'zoom',
|
||||||
|
// }})
|
||||||
|
|
||||||
|
// const inlineMenu = cloneElement(commonMenu, { props: {
|
||||||
|
// mode: 'inline',
|
||||||
|
// defaultOpenKeys: ['1'],
|
||||||
|
// openAnimation: animation,
|
||||||
|
// }})
|
||||||
|
return (
|
||||||
|
<div style={{ margin: '20px' }}>
|
||||||
|
<h2>antd menu</h2>
|
||||||
|
<div>
|
||||||
|
<h3>horizontal</h3>
|
||||||
|
|
||||||
|
<div style={{ margin: '20px', width: '800px' }}>{horizontalMenu}</div>
|
||||||
|
<h3>horizontal and click</h3>
|
||||||
|
{/*
|
||||||
|
<div style={{ margin: '20px', width: '800px' }}>{horizontalMenu2}</div>
|
||||||
|
<h3>vertical</h3>
|
||||||
|
|
||||||
|
<div style={{ margin: '20px', width: '200px' }}>{verticalMenu}</div>
|
||||||
|
<h3>inline</h3>
|
||||||
|
|
||||||
|
<div style={{ margin: '20px', width: '400px' }}>{inlineMenu}</div>
|
||||||
|
*/}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
|
@ -0,0 +1 @@
|
||||||
|
module.exports = require('./src/')
|
|
@ -11,7 +11,10 @@ export default {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'div',
|
default: 'div',
|
||||||
},
|
},
|
||||||
hiddenClassName: String,
|
hiddenClassName: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
class () {
|
class () {
|
||||||
|
@ -31,7 +34,7 @@ export default {
|
||||||
const tagProps = {
|
const tagProps = {
|
||||||
attr: { ...otherProps, ...this.$attrs },
|
attr: { ...otherProps, ...this.$attrs },
|
||||||
}
|
}
|
||||||
return <Tag {...tagProps} class={this.class} />
|
return <Tag {...tagProps} class={this.class}>{this.$slots.default}</Tag>
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import PropTypes from '../../_util/vue-types'
|
import PropTypes from '../../_util/vue-types'
|
||||||
import MenuMixin from './MenuMixin'
|
import MenuMixin from './MenuMixin'
|
||||||
import StateMixin from '../../_util/StateMixin'
|
import StateMixin from '../../_util/StateMixin'
|
||||||
|
import hasProp from '../../_util/hasProp'
|
||||||
|
|
||||||
const Menu = {
|
const Menu = {
|
||||||
name: 'Menu',
|
name: 'Menu',
|
||||||
|
@ -27,14 +28,14 @@ const Menu = {
|
||||||
|
|
||||||
data () {
|
data () {
|
||||||
const props = this.$props
|
const props = this.$props
|
||||||
let selectedKeys = props.defaultSelectedKeys
|
let sSelectedKeys = props.defaultSelectedKeys
|
||||||
let openKeys = props.defaultOpenKeys
|
let sOpenKeys = props.defaultOpenKeys
|
||||||
selectedKeys = props.selectedKeys || []
|
sSelectedKeys = props.selectedKeys || []
|
||||||
openKeys = props.openKeys || []
|
sOpenKeys = props.openKeys || []
|
||||||
this.isRootMenu = true
|
this.isRootMenu = true
|
||||||
return {
|
return {
|
||||||
selectedKeys,
|
sSelectedKeys,
|
||||||
openKeys,
|
sOpenKeys,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -42,10 +43,10 @@ const Menu = {
|
||||||
handler: function (nextProps) {
|
handler: function (nextProps) {
|
||||||
const props = {}
|
const props = {}
|
||||||
if (nextProps.selectedKeys === undefined) {
|
if (nextProps.selectedKeys === undefined) {
|
||||||
props.selectedKeys = nextProps.selectedKeys || []
|
props.sSelectedKeys = nextProps.selectedKeys || []
|
||||||
}
|
}
|
||||||
if (nextProps.openKeys === undefined) {
|
if (nextProps.openKeys === undefined) {
|
||||||
props.openKeys = nextProps.openKeys || []
|
props.sOpenKeys = nextProps.openKeys || []
|
||||||
}
|
}
|
||||||
this.setState(props)
|
this.setState(props)
|
||||||
},
|
},
|
||||||
|
@ -55,16 +56,15 @@ const Menu = {
|
||||||
methods: {
|
methods: {
|
||||||
onDestroy (key) {
|
onDestroy (key) {
|
||||||
const state = this.$data
|
const state = this.$data
|
||||||
const props = this.$props
|
const sSelectedKeys = state.sSelectedKeys
|
||||||
const selectedKeys = state.selectedKeys
|
const sOpenKeys = state.sOpenKeys
|
||||||
const openKeys = state.openKeys
|
let index = sSelectedKeys.indexOf(key)
|
||||||
let index = selectedKeys.indexOf(key)
|
if (!hasProp(this, 'selectedKeys') && index !== -1) {
|
||||||
if (!('selectedKeys' in props) && index !== -1) {
|
sSelectedKeys.splice(index, 1)
|
||||||
selectedKeys.splice(index, 1)
|
|
||||||
}
|
}
|
||||||
index = openKeys.indexOf(key)
|
index = sOpenKeys.indexOf(key)
|
||||||
if (!('openKeys' in props) && index !== -1) {
|
if (!hasProp(this, 'openKeys') && index !== -1) {
|
||||||
openKeys.splice(index, 1)
|
sOpenKeys.splice(index, 1)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -72,21 +72,21 @@ const Menu = {
|
||||||
const props = this.$props
|
const props = this.$props
|
||||||
if (props.selectable) {
|
if (props.selectable) {
|
||||||
// root menu
|
// root menu
|
||||||
let selectedKeys = this.$data.selectedKeys
|
let sSelectedKeys = this.$data.sSelectedKeys
|
||||||
const selectedKey = selectInfo.key
|
const selectedKey = selectInfo.key
|
||||||
if (props.multiple) {
|
if (props.multiple) {
|
||||||
selectedKeys = selectedKeys.concat([selectedKey])
|
sSelectedKeys = sSelectedKeys.concat([selectedKey])
|
||||||
} else {
|
} else {
|
||||||
selectedKeys = [selectedKey]
|
sSelectedKeys = [selectedKey]
|
||||||
}
|
}
|
||||||
if (!('selectedKeys' in props)) {
|
if (!hasProp(this, 'selectedKeys')) {
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedKeys,
|
sSelectedKeys,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.$emit('select', {
|
this.$emit('select', {
|
||||||
...selectInfo,
|
...selectInfo,
|
||||||
selectedKeys,
|
sSelectedKeys,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -96,20 +96,20 @@ const Menu = {
|
||||||
},
|
},
|
||||||
|
|
||||||
onOpenChange (e_) {
|
onOpenChange (e_) {
|
||||||
const openKeys = this.$data.openKeys.concat()
|
const sOpenKeys = this.$data.sOpenKeys.concat()
|
||||||
let changed = false
|
let changed = false
|
||||||
const processSingle = (e) => {
|
const processSingle = (e) => {
|
||||||
let oneChanged = false
|
let oneChanged = false
|
||||||
if (e.open) {
|
if (e.open) {
|
||||||
oneChanged = openKeys.indexOf(e.key) === -1
|
oneChanged = sOpenKeys.indexOf(e.key) === -1
|
||||||
if (oneChanged) {
|
if (oneChanged) {
|
||||||
openKeys.push(e.key)
|
sOpenKeys.push(e.key)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const index = openKeys.indexOf(e.key)
|
const index = sOpenKeys.indexOf(e.key)
|
||||||
oneChanged = index !== -1
|
oneChanged = index !== -1
|
||||||
if (oneChanged) {
|
if (oneChanged) {
|
||||||
openKeys.splice(index, 1)
|
sOpenKeys.splice(index, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
changed = changed || oneChanged
|
changed = changed || oneChanged
|
||||||
|
@ -121,30 +121,30 @@ const Menu = {
|
||||||
processSingle(e_)
|
processSingle(e_)
|
||||||
}
|
}
|
||||||
if (changed) {
|
if (changed) {
|
||||||
if (this.$props.openKeys === undefined) {
|
if (!hasProp(this, 'openKeys')) {
|
||||||
this.setState({ openKeys })
|
this.setState({ sOpenKeys })
|
||||||
}
|
}
|
||||||
this.$emit('openChange', openKeys)
|
this.$emit('openChange', sOpenKeys)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onDeselect (selectInfo) {
|
onDeselect (selectInfo) {
|
||||||
const props = this.$props
|
const props = this.$props
|
||||||
if (props.selectable) {
|
if (props.selectable) {
|
||||||
const selectedKeys = this.$data.selectedKeys.concat()
|
const sSelectedKeys = this.$data.sSelectedKeys.concat()
|
||||||
const selectedKey = selectInfo.key
|
const selectedKey = selectInfo.key
|
||||||
const index = selectedKeys.indexOf(selectedKey)
|
const index = sSelectedKeys.indexOf(selectedKey)
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
selectedKeys.splice(index, 1)
|
sSelectedKeys.splice(index, 1)
|
||||||
}
|
}
|
||||||
if (!('selectedKeys' in props)) {
|
if (!hasProp(this, 'selectedKeys')) {
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedKeys,
|
sSelectedKeys,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.$emit('deselect', {
|
this.$emit('deselect', {
|
||||||
...selectInfo,
|
...selectInfo,
|
||||||
selectedKeys,
|
sSelectedKeys,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -165,10 +165,10 @@ const Menu = {
|
||||||
|
|
||||||
lastOpenSubMenu () {
|
lastOpenSubMenu () {
|
||||||
let lastOpen = []
|
let lastOpen = []
|
||||||
const { openKeys } = this.$data
|
const { sOpenKeys } = this.$data
|
||||||
if (openKeys.length) {
|
if (sOpenKeys.length) {
|
||||||
lastOpen = this.getFlatInstanceArray().filter((c) => {
|
lastOpen = this.getFlatInstanceArray().filter((c) => {
|
||||||
return c && openKeys.indexOf(c.props.eventKey) !== -1
|
return c && sOpenKeys.indexOf(c.props.eventKey) !== -1
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return lastOpen[0]
|
return lastOpen[0]
|
||||||
|
@ -180,8 +180,8 @@ const Menu = {
|
||||||
}
|
}
|
||||||
const state = this.$data
|
const state = this.$data
|
||||||
const extraProps = {
|
const extraProps = {
|
||||||
openKeys: state.openKeys,
|
openKeys: state.sOpenKeys,
|
||||||
selectedKeys: state.selectedKeys,
|
selectedKeys: state.sSelectedKeys,
|
||||||
triggerSubMenuAction: this.$props.triggerSubMenuAction,
|
triggerSubMenuAction: this.$props.triggerSubMenuAction,
|
||||||
}
|
}
|
||||||
return this.renderCommonMenuItem(c, i, subIndex, extraProps)
|
return this.renderCommonMenuItem(c, i, subIndex, extraProps)
|
||||||
|
@ -190,7 +190,7 @@ const Menu = {
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const props = { ...this.$props }
|
const props = { ...this.$props }
|
||||||
props.className += ` ${props.prefixCls}-root`
|
props.class = ` ${props.prefixCls}-root`
|
||||||
return this.renderRoot(props)
|
return this.renderRoot(props)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ const MenuItemGroup = {
|
||||||
className: PropTypes.string,
|
className: PropTypes.string,
|
||||||
rootPrefixCls: PropTypes.string,
|
rootPrefixCls: PropTypes.string,
|
||||||
disabled: PropTypes.bool.def(true),
|
disabled: PropTypes.bool.def(true),
|
||||||
|
title: PropTypes.any.def(''),
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
@ -1,14 +1,21 @@
|
||||||
import PropTypes from 'vue-types'
|
import PropTypes from '../../_util/vue-types'
|
||||||
|
import hasProp from '../../_util/hasProp'
|
||||||
import KeyCode from '../../_util/KeyCode'
|
import KeyCode from '../../_util/KeyCode'
|
||||||
import scrollIntoView from 'dom-scroll-into-view'
|
import scrollIntoView from 'dom-scroll-into-view'
|
||||||
import { getKeyFromChildrenIndex, loopMenuItem } from './util'
|
import { getKeyFromChildrenIndex, loopMenuItem } from './util'
|
||||||
|
import StateMixin from '../../_util/StateMixin'
|
||||||
|
import { cloneElement, cloneVNode } from '../../_util/vnode'
|
||||||
import DOMWrap from './DOMWrap'
|
import DOMWrap from './DOMWrap'
|
||||||
|
|
||||||
function allDisabled (arr) {
|
function allDisabled (arr) {
|
||||||
if (!arr.length) {
|
if (!arr.length) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return arr.every(c => !!c.props.disabled)
|
|
||||||
|
return arr.every(c => {
|
||||||
|
const propsData = c.componentOptions.propsData || {}
|
||||||
|
return !!propsData.disabled
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function getActiveKey (props, originalActiveKey) {
|
function getActiveKey (props, originalActiveKey) {
|
||||||
|
@ -17,7 +24,8 @@ function getActiveKey (props, originalActiveKey) {
|
||||||
if (activeKey) {
|
if (activeKey) {
|
||||||
let found
|
let found
|
||||||
loopMenuItem(children, (c, i) => {
|
loopMenuItem(children, (c, i) => {
|
||||||
if (c && !c.props.disabled && activeKey === getKeyFromChildrenIndex(c, eventKey, i)) {
|
const propsData = c.componentOptions.propsData || {}
|
||||||
|
if (c && !propsData.disabled && activeKey === getKeyFromChildrenIndex(c, eventKey, i)) {
|
||||||
found = true
|
found = true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -28,7 +36,8 @@ function getActiveKey (props, originalActiveKey) {
|
||||||
activeKey = null
|
activeKey = null
|
||||||
if (props.defaultActiveFirst) {
|
if (props.defaultActiveFirst) {
|
||||||
loopMenuItem(children, (c, i) => {
|
loopMenuItem(children, (c, i) => {
|
||||||
if (!activeKey && c && !c.props.disabled) {
|
const propsData = c.componentOptions.propsData || {}
|
||||||
|
if (!activeKey && c && !propsData.disabled) {
|
||||||
activeKey = getKeyFromChildrenIndex(c, eventKey, i)
|
activeKey = getKeyFromChildrenIndex(c, eventKey, i)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -37,24 +46,12 @@ function getActiveKey (props, originalActiveKey) {
|
||||||
return activeKey
|
return activeKey
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveRef (index, subIndex, c) {
|
|
||||||
if (c) {
|
|
||||||
if (subIndex !== undefined) {
|
|
||||||
this.instanceArray[index] = this.instanceArray[index] || []
|
|
||||||
this.instanceArray[index][subIndex] = c
|
|
||||||
} else {
|
|
||||||
this.instanceArray[index] = c
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const MenuMixin = {
|
const MenuMixin = {
|
||||||
props: {
|
props: {
|
||||||
prefixCls: PropTypes.string.def('ant-menu'),
|
prefixCls: PropTypes.string.def('rc-menu'),
|
||||||
inlineIndent: PropTypes.number.def(24),
|
inlineIndent: PropTypes.number.def(24),
|
||||||
focusable: PropTypes.bool.def(true),
|
focusable: PropTypes.bool.def(true),
|
||||||
multiple: PropTypes.bool,
|
multiple: PropTypes.bool,
|
||||||
style: PropTypes.object,
|
|
||||||
defaultActiveFirst: PropTypes.bool,
|
defaultActiveFirst: PropTypes.bool,
|
||||||
visible: PropTypes.bool.def(true),
|
visible: PropTypes.bool.def(true),
|
||||||
activeKey: PropTypes.string,
|
activeKey: PropTypes.string,
|
||||||
|
@ -63,45 +60,60 @@ const MenuMixin = {
|
||||||
defaultOpenKeys: PropTypes.arrayOf(PropTypes.string),
|
defaultOpenKeys: PropTypes.arrayOf(PropTypes.string),
|
||||||
openKeys: PropTypes.arrayOf(PropTypes.string),
|
openKeys: PropTypes.arrayOf(PropTypes.string),
|
||||||
},
|
},
|
||||||
|
mixin: [StateMixin],
|
||||||
data () {
|
data () {
|
||||||
const props = this.$props
|
const props = this.$props
|
||||||
return {
|
return {
|
||||||
activeKey: getActiveKey(props, props.activeKey),
|
sActiveKey: getActiveKey(props, props.activeKey),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
componentWillReceiveProps (nextProps) {
|
'$props': {
|
||||||
let props
|
handler: function (nextProps) {
|
||||||
if ('activeKey' in nextProps) {
|
let props
|
||||||
props = {
|
if (hasProp(this, 'activeKey')) {
|
||||||
activeKey: getActiveKey(nextProps, nextProps.activeKey),
|
props = {
|
||||||
}
|
sActiveKey: getActiveKey(nextProps, nextProps.activeKey),
|
||||||
} else {
|
}
|
||||||
const originalActiveKey = this.state.activeKey
|
} else {
|
||||||
const activeKey = getActiveKey(nextProps, originalActiveKey)
|
const originalActiveKey = this.$data.sActiveKey
|
||||||
// fix: this.setState(), parent.render(),
|
const sActiveKey = getActiveKey(nextProps, originalActiveKey)
|
||||||
if (activeKey !== originalActiveKey) {
|
// fix: this.setState(), parent.render(),
|
||||||
props = {
|
if (sActiveKey !== originalActiveKey) {
|
||||||
activeKey,
|
props = {
|
||||||
|
sActiveKey,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
if (props) {
|
||||||
}
|
this.setState(props)
|
||||||
if (props) {
|
}
|
||||||
this.setState(props)
|
},
|
||||||
}
|
deep: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
created () {
|
created () {
|
||||||
this.instanceArray = []
|
this.instanceArray = []
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
saveRef (index, subIndex, c) {
|
||||||
|
if (c) {
|
||||||
|
if (subIndex !== undefined) {
|
||||||
|
this.instanceArray[index] = this.instanceArray[index] || []
|
||||||
|
this.instanceArray[index][subIndex] = c
|
||||||
|
} else {
|
||||||
|
this.instanceArray[index] = c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
// all keyboard events callbacks run from here at first
|
// all keyboard events callbacks run from here at first
|
||||||
onKeyDown (e, callback) {
|
onKeyDown (e, callback) {
|
||||||
const keyCode = e.keyCode
|
const keyCode = e.keyCode
|
||||||
let handled
|
let handled
|
||||||
this.getFlatInstanceArray().forEach((obj) => {
|
this.getFlatInstanceArray().forEach((obj) => {
|
||||||
if (obj && obj.props.active && obj.onKeyDown) {
|
if (obj && obj.$props.active) {
|
||||||
handled = obj.onKeyDown(e)
|
handled = this.$emit('keydown', e)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (handled) {
|
if (handled) {
|
||||||
|
@ -114,7 +126,7 @@ const MenuMixin = {
|
||||||
if (activeItem) {
|
if (activeItem) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
this.setState({
|
this.setState({
|
||||||
activeKey: activeItem.$props.eventKey,
|
sActiveKey: activeItem.$props.eventKey,
|
||||||
}, () => {
|
}, () => {
|
||||||
scrollIntoView(activeItem.$el, this.$el, {
|
scrollIntoView(activeItem.$el, this.$el, {
|
||||||
onlyScrollIfNeeded: true,
|
onlyScrollIfNeeded: true,
|
||||||
|
@ -128,7 +140,7 @@ const MenuMixin = {
|
||||||
} else if (activeItem === undefined) {
|
} else if (activeItem === undefined) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
this.setState({
|
this.setState({
|
||||||
activeKey: null,
|
sActiveKey: null,
|
||||||
})
|
})
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
@ -137,7 +149,7 @@ const MenuMixin = {
|
||||||
onItemHover (e) {
|
onItemHover (e) {
|
||||||
const { key, hover } = e
|
const { key, hover } = e
|
||||||
this.setState({
|
this.setState({
|
||||||
activeKey: hover ? key : null,
|
sActiveKey: hover ? key : null,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -161,72 +173,83 @@ const MenuMixin = {
|
||||||
},
|
},
|
||||||
|
|
||||||
renderCommonMenuItem (child, i, subIndex, extraProps) {
|
renderCommonMenuItem (child, i, subIndex, extraProps) {
|
||||||
const state = this.state
|
const state = this.$data
|
||||||
const props = this.props
|
const props = this.$props
|
||||||
const key = getKeyFromChildrenIndex(child, props.eventKey, i)
|
const key = getKeyFromChildrenIndex(child, props.eventKey, i)
|
||||||
const childProps = child.props
|
const childProps = child.componentOptions.propsData || {}
|
||||||
const isActive = key === state.activeKey
|
const isActive = key === state.sActiveKey
|
||||||
const newChildProps = {
|
const newChildProps = {
|
||||||
mode: props.mode,
|
props: {
|
||||||
level: props.level,
|
mode: props.mode,
|
||||||
inlineIndent: props.inlineIndent,
|
level: props.level,
|
||||||
renderMenuItem: this.renderMenuItem,
|
inlineIndent: props.inlineIndent,
|
||||||
rootPrefixCls: props.prefixCls,
|
renderMenuItem: this.renderMenuItem,
|
||||||
index: i,
|
rootPrefixCls: props.prefixCls,
|
||||||
parentMenu: this,
|
index: i,
|
||||||
ref: child.ref,
|
parentMenu: this,
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
on: {
|
||||||
|
click: this.onClick,
|
||||||
|
itemHover: this.onItemHover,
|
||||||
|
// openChange: () => { console.log('openChange') },
|
||||||
|
deselect: this.onDeselect,
|
||||||
|
destroy: this.onDestroy,
|
||||||
|
select: this.onSelect,
|
||||||
|
},
|
||||||
|
|
||||||
|
ref: childProps.disabled ? undefined : child.ref,
|
||||||
// ref: childProps.disabled ? undefined
|
// ref: childProps.disabled ? undefined
|
||||||
// : createChainedFunction(child.ref, saveRef.bind(this, i, subIndex)),
|
// : createChainedFunction(child.ref, saveRef.bind(this, i, subIndex)),
|
||||||
eventKey: key,
|
|
||||||
active: !childProps.disabled && isActive,
|
|
||||||
multiple: props.multiple,
|
|
||||||
onClick: this.onClick,
|
|
||||||
onItemHover: this.onItemHover,
|
|
||||||
openTransitionName: this.getOpenTransitionName(),
|
|
||||||
openAnimation: props.openAnimation,
|
|
||||||
subMenuOpenDelay: props.subMenuOpenDelay,
|
|
||||||
subMenuCloseDelay: props.subMenuCloseDelay,
|
|
||||||
forceSubMenuRender: props.forceSubMenuRender,
|
|
||||||
onOpenChange: this.onOpenChange,
|
|
||||||
onDeselect: this.onDeselect,
|
|
||||||
onDestroy: this.onDestroy,
|
|
||||||
onSelect: this.onSelect,
|
|
||||||
...extraProps,
|
|
||||||
}
|
}
|
||||||
|
!childProps.disabled && this.saveRef(i, subIndex, child.ref)
|
||||||
if (props.mode === 'inline') {
|
if (props.mode === 'inline') {
|
||||||
newChildProps.triggerSubMenuAction = 'click'
|
newChildProps.props.triggerSubMenuAction = 'click'
|
||||||
}
|
}
|
||||||
return child
|
return cloneElement(child, newChildProps)
|
||||||
// return React.cloneElement(child, newChildProps)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
renderRoot (props) {
|
renderRoot (props) {
|
||||||
this.instanceArray = []
|
this.instanceArray = []
|
||||||
const className = {
|
const className = {
|
||||||
[props.prefixCls]: true,
|
[props.prefixCls]: true,
|
||||||
[props.className]: true,
|
[props.class]: true,
|
||||||
[`${props.prefixCls}-${props.mode}`]: true,
|
[`${props.prefixCls}-${props.mode}`]: true,
|
||||||
}
|
}
|
||||||
const domProps = {
|
const domProps = {
|
||||||
className,
|
attrs: {
|
||||||
role: 'menu',
|
role: 'menu',
|
||||||
'aria-activedescendant': '',
|
'aria-activedescendant': '',
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
tag: 'ul',
|
||||||
|
hiddenClassName: `${props.prefixCls}-hidden`,
|
||||||
|
visible: props.visible,
|
||||||
|
},
|
||||||
|
class: className,
|
||||||
|
on: {},
|
||||||
|
// style:props.style,
|
||||||
}
|
}
|
||||||
if (props.id) {
|
if (props.id) {
|
||||||
domProps.id = props.id
|
domProps.id = props.id
|
||||||
}
|
}
|
||||||
if (props.focusable) {
|
if (props.focusable) {
|
||||||
domProps.tabIndex = '0'
|
domProps.attrs.tabIndex = '0'
|
||||||
domProps.onKeyDown = this.onKeyDown
|
domProps.on.keydown = this.onKeyDown
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
// ESLint is not smart enough to know that the type of `children` was checked.
|
// ESLint is not smart enough to know that the type of `children` was checked.
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
<DOMWrap
|
<DOMWrap
|
||||||
style={props.style}
|
|
||||||
tag="ul"
|
|
||||||
hiddenClassName={`${props.prefixCls}-hidden`}
|
|
||||||
visible={props.visible}
|
|
||||||
{...domProps}
|
{...domProps}
|
||||||
>
|
>
|
||||||
{this.$slots.default.map(this.renderMenuItem)}
|
{this.$slots.default.map(this.renderMenuItem)}
|
||||||
|
@ -237,7 +260,7 @@ const MenuMixin = {
|
||||||
|
|
||||||
step (direction) {
|
step (direction) {
|
||||||
let children = this.getFlatInstanceArray()
|
let children = this.getFlatInstanceArray()
|
||||||
const activeKey = this.state.activeKey
|
const sActiveKey = this.$data.sActiveKey
|
||||||
const len = children.length
|
const len = children.length
|
||||||
if (!len) {
|
if (!len) {
|
||||||
return null
|
return null
|
||||||
|
@ -248,13 +271,14 @@ const MenuMixin = {
|
||||||
// find current activeIndex
|
// find current activeIndex
|
||||||
let activeIndex = -1
|
let activeIndex = -1
|
||||||
children.every((c, ci) => {
|
children.every((c, ci) => {
|
||||||
if (c && c.props.eventKey === activeKey) {
|
const propsData = c.componentOptions.propsData || {}
|
||||||
|
if (c && propsData.eventKey === sActiveKey) {
|
||||||
activeIndex = ci
|
activeIndex = ci
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
if (!this.props.defaultActiveFirst && activeIndex !== -1) {
|
if (!this.$props.defaultActiveFirst && activeIndex !== -1) {
|
||||||
if (allDisabled(children.slice(activeIndex, len - 1))) {
|
if (allDisabled(children.slice(activeIndex, len - 1))) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
@ -263,7 +287,8 @@ const MenuMixin = {
|
||||||
let i = start
|
let i = start
|
||||||
for (; ;) {
|
for (; ;) {
|
||||||
const child = children[i]
|
const child = children[i]
|
||||||
if (!child || child.props.disabled) {
|
const propsData = child.componentOptions.propsData || {}
|
||||||
|
if (!child || propsData.disabled) {
|
||||||
i = (i + 1 + len) % len
|
i = (i + 1 + len) % len
|
||||||
// complete a loop
|
// complete a loop
|
||||||
if (i === start) {
|
if (i === start) {
|
||||||
|
|
|
@ -4,7 +4,8 @@ import Trigger from '../../trigger'
|
||||||
import KeyCode from '../../_util/KeyCode'
|
import KeyCode from '../../_util/KeyCode'
|
||||||
import SubPopupMenu from './SubPopupMenu'
|
import SubPopupMenu from './SubPopupMenu'
|
||||||
import placements from './placements'
|
import placements from './placements'
|
||||||
import { noop, loopMenuItemRecusively } from './util'
|
import { loopMenuItemRecusively } from './util'
|
||||||
|
import StateMixin from '../../_util/StateMixin'
|
||||||
|
|
||||||
let guid = 0
|
let guid = 0
|
||||||
|
|
||||||
|
@ -20,335 +21,326 @@ const SubMenu = {
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
parentMenu: PropTypes.object,
|
parentMenu: PropTypes.object,
|
||||||
title: PropTypes.node,
|
mode: PropTypes.oneOf(['horizontal', 'vertical', 'vertical-left', 'vertical-right', 'inline']).def('vertical'),
|
||||||
|
title: PropTypes.any.def(''),
|
||||||
children: PropTypes.any,
|
children: PropTypes.any,
|
||||||
selectedKeys: PropTypes.array,
|
selectedKeys: PropTypes.array,
|
||||||
openKeys: PropTypes.array,
|
openKeys: PropTypes.array,
|
||||||
onClick: PropTypes.func,
|
// onClick: PropTypes.func,
|
||||||
onOpenChange: PropTypes.func,
|
openChange: PropTypes.func,
|
||||||
rootPrefixCls: PropTypes.string,
|
rootPrefixCls: PropTypes.string,
|
||||||
eventKey: PropTypes.string,
|
eventKey: PropTypes.string,
|
||||||
multiple: PropTypes.bool,
|
multiple: PropTypes.bool,
|
||||||
active: PropTypes.bool, // TODO: remove
|
active: PropTypes.bool, // TODO: remove
|
||||||
onItemHover: PropTypes.func,
|
// onItemHover: PropTypes.func,
|
||||||
onSelect: PropTypes.func,
|
// onSelect: PropTypes.func,
|
||||||
triggerSubMenuAction: PropTypes.string,
|
triggerSubMenuAction: PropTypes.string,
|
||||||
onDeselect: PropTypes.func,
|
popupClassName: PropTypes.string,
|
||||||
onDestroy: PropTypes.func,
|
// onDeselect: PropTypes.func,
|
||||||
onMouseEnter: PropTypes.func,
|
// onDestroy: PropTypes.func,
|
||||||
onMouseLeave: PropTypes.func,
|
// onMouseEnter: PropTypes.func,
|
||||||
onTitleMouseEnter: PropTypes.func,
|
// onMouseLeave: PropTypes.func,
|
||||||
onTitleMouseLeave: PropTypes.func,
|
// onTitleMouseEnter: PropTypes.func,
|
||||||
onTitleClick: PropTypes.func,
|
// onTitleMouseLeave: PropTypes.func,
|
||||||
|
// onTitleClick: PropTypes.func,
|
||||||
},
|
},
|
||||||
|
mixins: [StateMixin],
|
||||||
isRootMenu: false,
|
data () {
|
||||||
|
|
||||||
getDefaultProps () {
|
|
||||||
return {
|
|
||||||
onMouseEnter: noop,
|
|
||||||
onMouseLeave: noop,
|
|
||||||
onTitleMouseEnter: noop,
|
|
||||||
onTitleMouseLeave: noop,
|
|
||||||
onTitleClick: noop,
|
|
||||||
title: '',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
getInitialState () {
|
|
||||||
this.isSubMenu = 1
|
this.isSubMenu = 1
|
||||||
|
this.isRootMenu = false
|
||||||
return {
|
return {
|
||||||
defaultActiveFirst: false,
|
defaultActiveFirst: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount () {
|
mounted () {
|
||||||
this.componentDidUpdate()
|
this.handleUpdated()
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidUpdate () {
|
updated () {
|
||||||
const { mode, parentMenu } = this.props
|
this.handleUpdated()
|
||||||
if (mode !== 'horizontal' || !parentMenu.isRootMenu || !this.isOpen()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
setTimeout(() => {
|
|
||||||
if (!this.subMenuTitle || !this.menuInstance) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const popupMenu = this.$refs.menuInstance.$el
|
|
||||||
if (popupMenu.offsetWidth >= this.subMenuTitle.offsetWidth) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
popupMenu.style.minWidth = `${this.subMenuTitle.offsetWidth}px`
|
|
||||||
}, 0)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillUnmount () {
|
beforeDestroy () {
|
||||||
const { onDestroy, eventKey, parentMenu } = this.props
|
const { eventKey, parentMenu } = this.$props
|
||||||
if (onDestroy) {
|
this.$emit('destroy', eventKey)
|
||||||
onDestroy(eventKey)
|
|
||||||
}
|
|
||||||
if (parentMenu.subMenuInstance === this) {
|
if (parentMenu.subMenuInstance === this) {
|
||||||
this.clearSubMenuTimers()
|
this.clearSubMenuTimers()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
handleUpdated () {
|
||||||
|
const { mode, parentMenu } = this.$props
|
||||||
|
if (mode !== 'horizontal' || !parentMenu.isRootMenu || !this.isOpen()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!this.subMenuTitle || !this.menuInstance) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const popupMenu = this.$refs.menuInstance.$el
|
||||||
|
if (popupMenu.offsetWidth >= this.subMenuTitle.offsetWidth) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
popupMenu.style.minWidth = `${this.subMenuTitle.offsetWidth}px`
|
||||||
|
}, 0)
|
||||||
|
},
|
||||||
|
onDestroy (key) {
|
||||||
|
this.$emit('destroy', key)
|
||||||
|
},
|
||||||
|
|
||||||
onDestroy (key) {
|
onKeyDown (e) {
|
||||||
this.props.onDestroy(key)
|
const keyCode = e.keyCode
|
||||||
},
|
const menu = this.menuInstance
|
||||||
|
const isOpen = this.isOpen()
|
||||||
|
|
||||||
onKeyDown (e) {
|
if (keyCode === KeyCode.ENTER) {
|
||||||
const keyCode = e.keyCode
|
this.onTitleClick(e)
|
||||||
const menu = this.menuInstance
|
|
||||||
const isOpen = this.isOpen()
|
|
||||||
|
|
||||||
if (keyCode === KeyCode.ENTER) {
|
|
||||||
this.onTitleClick(e)
|
|
||||||
this.setState({
|
|
||||||
defaultActiveFirst: true,
|
|
||||||
})
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keyCode === KeyCode.RIGHT) {
|
|
||||||
if (isOpen) {
|
|
||||||
menu.onKeyDown(e)
|
|
||||||
} else {
|
|
||||||
this.triggerOpenChange(true)
|
|
||||||
this.setState({
|
this.setState({
|
||||||
defaultActiveFirst: true,
|
defaultActiveFirst: true,
|
||||||
})
|
})
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
}
|
if (keyCode === KeyCode.RIGHT) {
|
||||||
if (keyCode === KeyCode.LEFT) {
|
if (isOpen) {
|
||||||
let handled
|
menu.onKeyDown(e)
|
||||||
if (isOpen) {
|
} else {
|
||||||
handled = menu.onKeyDown(e)
|
this.triggerOpenChange(true)
|
||||||
} else {
|
this.setState({
|
||||||
return undefined
|
defaultActiveFirst: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
if (!handled) {
|
if (keyCode === KeyCode.LEFT) {
|
||||||
this.triggerOpenChange(false)
|
let handled
|
||||||
handled = true
|
if (isOpen) {
|
||||||
|
handled = menu.onKeyDown(e)
|
||||||
|
} else {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
if (!handled) {
|
||||||
|
this.triggerOpenChange(false)
|
||||||
|
handled = true
|
||||||
|
}
|
||||||
|
return handled
|
||||||
}
|
}
|
||||||
return handled
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isOpen && (keyCode === KeyCode.UP || keyCode === KeyCode.DOWN)) {
|
if (isOpen && (keyCode === KeyCode.UP || keyCode === KeyCode.DOWN)) {
|
||||||
return menu.onKeyDown(e)
|
return menu.onKeyDown(e)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onOpenChange (e) {
|
onOpenChange (e) {
|
||||||
this.props.onOpenChange(e)
|
this.$emit('openChange', e)
|
||||||
},
|
this.$props.openChange(e)
|
||||||
|
},
|
||||||
|
|
||||||
onPopupVisibleChange (visible) {
|
onPopupVisibleChange (visible) {
|
||||||
this.triggerOpenChange(visible, visible ? 'mouseenter' : 'mouseleave')
|
this.triggerOpenChange(visible, visible ? 'mouseenter' : 'mouseleave')
|
||||||
},
|
},
|
||||||
|
|
||||||
onMouseEnter (e) {
|
onMouseEnter (e) {
|
||||||
const { eventKey: key, onMouseEnter } = this.props
|
const { eventKey: key } = this.$props
|
||||||
this.clearSubMenuLeaveTimer()
|
this.clearSubMenuLeaveTimer()
|
||||||
this.setState({
|
this.setState({
|
||||||
defaultActiveFirst: false,
|
defaultActiveFirst: false,
|
||||||
})
|
})
|
||||||
onMouseEnter({
|
this.$emit('mouseenter', {
|
||||||
key,
|
key,
|
||||||
domEvent: e,
|
domEvent: e,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
onMouseLeave (e) {
|
onMouseLeave (e) {
|
||||||
const {
|
const {
|
||||||
parentMenu,
|
parentMenu,
|
||||||
eventKey,
|
eventKey,
|
||||||
onMouseLeave,
|
} = this.$props
|
||||||
} = this.props
|
parentMenu.subMenuInstance = this
|
||||||
parentMenu.subMenuInstance = this
|
parentMenu.subMenuLeaveFn = () => {
|
||||||
parentMenu.subMenuLeaveFn = () => {
|
|
||||||
// trigger mouseleave
|
// trigger mouseleave
|
||||||
onMouseLeave({
|
this.$emit('mouseleave', {
|
||||||
|
key: eventKey,
|
||||||
|
domEvent: e,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// prevent popup menu and submenu gap
|
||||||
|
parentMenu.subMenuLeaveTimer = setTimeout(parentMenu.subMenuLeaveFn, 100)
|
||||||
|
},
|
||||||
|
|
||||||
|
onTitleMouseEnter (domEvent) {
|
||||||
|
const { eventKey: key } = this.$props
|
||||||
|
this.clearSubMenuTitleLeaveTimer()
|
||||||
|
this.$emit('itemHover', {
|
||||||
|
key,
|
||||||
|
hover: true,
|
||||||
|
})
|
||||||
|
this.$emit('titleMouseenter', {
|
||||||
|
key,
|
||||||
|
domEvent,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
onTitleMouseLeave (e) {
|
||||||
|
const { parentMenu, eventKey } = this.$props
|
||||||
|
parentMenu.subMenuInstance = this
|
||||||
|
parentMenu.subMenuTitleLeaveFn = () => {
|
||||||
|
this.$emit('itemHover', {
|
||||||
|
key: eventKey,
|
||||||
|
hover: false,
|
||||||
|
})
|
||||||
|
this.$emit('titleMouseleave', {
|
||||||
|
key: eventKey,
|
||||||
|
domEvent: e,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
parentMenu.subMenuTitleLeaveTimer = setTimeout(parentMenu.subMenuTitleLeaveFn, 100)
|
||||||
|
},
|
||||||
|
|
||||||
|
onTitleClick (e) {
|
||||||
|
const { triggerSubMenuAction, eventKey } = this.$props
|
||||||
|
|
||||||
|
this.$emit('itemClick', {
|
||||||
key: eventKey,
|
key: eventKey,
|
||||||
domEvent: e,
|
domEvent: e,
|
||||||
|
test: 111,
|
||||||
})
|
})
|
||||||
}
|
if (triggerSubMenuAction === 'hover') {
|
||||||
// prevent popup menu and submenu gap
|
return
|
||||||
parentMenu.subMenuLeaveTimer = setTimeout(parentMenu.subMenuLeaveFn, 100)
|
}
|
||||||
},
|
this.triggerOpenChange(!this.isOpen(), 'click')
|
||||||
|
this.setState({
|
||||||
onTitleMouseEnter (domEvent) {
|
defaultActiveFirst: false,
|
||||||
const { eventKey: key, onItemHover, onTitleMouseEnter } = this.props
|
|
||||||
this.clearSubMenuTitleLeaveTimer()
|
|
||||||
onItemHover({
|
|
||||||
key,
|
|
||||||
hover: true,
|
|
||||||
})
|
|
||||||
onTitleMouseEnter({
|
|
||||||
key,
|
|
||||||
domEvent,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
onTitleMouseLeave (e) {
|
|
||||||
const { parentMenu, eventKey, onItemHover, onTitleMouseLeave } = this.props
|
|
||||||
parentMenu.subMenuInstance = this
|
|
||||||
parentMenu.subMenuTitleLeaveFn = () => {
|
|
||||||
onItemHover({
|
|
||||||
key: eventKey,
|
|
||||||
hover: false,
|
|
||||||
})
|
})
|
||||||
onTitleMouseLeave({
|
},
|
||||||
key: eventKey,
|
|
||||||
domEvent: e,
|
onSubMenuClick (info) {
|
||||||
|
this.$emit('click', this.addKeyPath(info))
|
||||||
|
},
|
||||||
|
|
||||||
|
onSelect (info) {
|
||||||
|
this.$emit('select', info)
|
||||||
|
},
|
||||||
|
|
||||||
|
onDeselect (info) {
|
||||||
|
this.$emit('deselect', 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`
|
||||||
|
},
|
||||||
|
|
||||||
|
addKeyPath (info) {
|
||||||
|
return {
|
||||||
|
...info,
|
||||||
|
keyPath: (info.keyPath || []).concat(this.$props.eventKey),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
triggerOpenChange (open, type) {
|
||||||
|
const key = this.$props.eventKey
|
||||||
|
this.onOpenChange({
|
||||||
|
key,
|
||||||
|
item: this,
|
||||||
|
trigger: type,
|
||||||
|
open,
|
||||||
})
|
})
|
||||||
}
|
},
|
||||||
parentMenu.subMenuTitleLeaveTimer = setTimeout(parentMenu.subMenuTitleLeaveFn, 100)
|
|
||||||
|
clearSubMenuTimers () {
|
||||||
|
this.clearSubMenuLeaveTimer()
|
||||||
|
this.clearSubMenuTitleLeaveTimer()
|
||||||
|
},
|
||||||
|
|
||||||
|
clearSubMenuTitleLeaveTimer () {
|
||||||
|
const parentMenu = this.$props.parentMenu
|
||||||
|
if (parentMenu.subMenuTitleLeaveTimer) {
|
||||||
|
clearTimeout(parentMenu.subMenuTitleLeaveTimer)
|
||||||
|
parentMenu.subMenuTitleLeaveTimer = null
|
||||||
|
parentMenu.subMenuTitleLeaveFn = null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
clearSubMenuLeaveTimer () {
|
||||||
|
const parentMenu = this.$props.parentMenu
|
||||||
|
if (parentMenu.subMenuLeaveTimer) {
|
||||||
|
clearTimeout(parentMenu.subMenuLeaveTimer)
|
||||||
|
parentMenu.subMenuLeaveTimer = null
|
||||||
|
parentMenu.subMenuLeaveFn = null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
isChildrenSelected () {
|
||||||
|
const ret = { find: false }
|
||||||
|
loopMenuItemRecusively(this.$slots.default, this.$props.selectedKeys, ret)
|
||||||
|
return ret.find
|
||||||
|
},
|
||||||
|
isOpen () {
|
||||||
|
return this.$props.openKeys.indexOf(this.$props.eventKey) !== -1
|
||||||
|
},
|
||||||
|
|
||||||
|
renderChildren (children) {
|
||||||
|
const props = this.$props
|
||||||
|
const subPopupMenuProps = {
|
||||||
|
props: {
|
||||||
|
mode: props.mode === 'horizontal' ? 'vertical' : props.mode,
|
||||||
|
visible: this.isOpen(),
|
||||||
|
level: props.level + 1,
|
||||||
|
inlineIndent: props.inlineIndent,
|
||||||
|
focusable: false,
|
||||||
|
selectedKeys: props.selectedKeys,
|
||||||
|
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,
|
||||||
|
defaultActiveFirst: this.$data.defaultActiveFirst,
|
||||||
|
multiple: props.multiple,
|
||||||
|
prefixCls: props.rootPrefixCls,
|
||||||
|
},
|
||||||
|
on: {
|
||||||
|
click: this.onSubMenuClick,
|
||||||
|
select: this.onSelect,
|
||||||
|
deselect: this.onDeselect,
|
||||||
|
destroy: this.onDestroy,
|
||||||
|
openChange: this.onOpenChange,
|
||||||
|
},
|
||||||
|
id: this._menuId,
|
||||||
|
ref: 'menuInstance',
|
||||||
|
}
|
||||||
|
return <SubPopupMenu {...subPopupMenuProps}>{children}</SubPopupMenu>
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
onTitleClick (e) {
|
render (h) {
|
||||||
const { props } = this
|
|
||||||
props.onTitleClick({
|
|
||||||
key: props.eventKey,
|
|
||||||
domEvent: e,
|
|
||||||
})
|
|
||||||
if (props.triggerSubMenuAction === 'hover') {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.triggerOpenChange(!this.isOpen(), 'click')
|
|
||||||
this.setState({
|
|
||||||
defaultActiveFirst: false,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
onSubMenuClick (info) {
|
|
||||||
this.props.onClick(this.addKeyPath(info))
|
|
||||||
},
|
|
||||||
|
|
||||||
onSelect (info) {
|
|
||||||
this.props.onSelect(info)
|
|
||||||
},
|
|
||||||
|
|
||||||
onDeselect (info) {
|
|
||||||
this.props.onDeselect(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) {
|
|
||||||
this.menuInstance = c
|
|
||||||
},
|
|
||||||
|
|
||||||
addKeyPath (info) {
|
|
||||||
return {
|
|
||||||
...info,
|
|
||||||
keyPath: (info.keyPath || []).concat(this.props.eventKey),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
triggerOpenChange (open, type) {
|
|
||||||
const key = this.props.eventKey
|
|
||||||
this.onOpenChange({
|
|
||||||
key,
|
|
||||||
item: this,
|
|
||||||
trigger: type,
|
|
||||||
open,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
clearSubMenuTimers () {
|
|
||||||
this.clearSubMenuLeaveTimer()
|
|
||||||
this.clearSubMenuTitleLeaveTimer()
|
|
||||||
},
|
|
||||||
|
|
||||||
clearSubMenuTitleLeaveTimer () {
|
|
||||||
const parentMenu = this.props.parentMenu
|
|
||||||
if (parentMenu.subMenuTitleLeaveTimer) {
|
|
||||||
clearTimeout(parentMenu.subMenuTitleLeaveTimer)
|
|
||||||
parentMenu.subMenuTitleLeaveTimer = null
|
|
||||||
parentMenu.subMenuTitleLeaveFn = null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
clearSubMenuLeaveTimer () {
|
|
||||||
const parentMenu = this.props.parentMenu
|
|
||||||
if (parentMenu.subMenuLeaveTimer) {
|
|
||||||
clearTimeout(parentMenu.subMenuLeaveTimer)
|
|
||||||
parentMenu.subMenuLeaveTimer = null
|
|
||||||
parentMenu.subMenuLeaveFn = null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
isChildrenSelected () {
|
|
||||||
const ret = { find: false }
|
|
||||||
loopMenuItemRecusively(this.props.children, this.props.selectedKeys, ret)
|
|
||||||
return ret.find
|
|
||||||
},
|
|
||||||
isOpen () {
|
|
||||||
return this.props.openKeys.indexOf(this.props.eventKey) !== -1
|
|
||||||
},
|
|
||||||
|
|
||||||
renderChildren (children) {
|
|
||||||
const props = this.$props
|
|
||||||
const baseProps = {
|
|
||||||
mode: props.mode === 'horizontal' ? 'vertical' : props.mode,
|
|
||||||
visible: this.isOpen(),
|
|
||||||
level: props.level + 1,
|
|
||||||
inlineIndent: props.inlineIndent,
|
|
||||||
focusable: false,
|
|
||||||
onClick: this.onSubMenuClick,
|
|
||||||
onSelect: this.onSelect,
|
|
||||||
onDeselect: this.onDeselect,
|
|
||||||
onDestroy: this.onDestroy,
|
|
||||||
selectedKeys: props.selectedKeys,
|
|
||||||
eventKey: `${props.eventKey}-menu-`,
|
|
||||||
openKeys: props.openKeys,
|
|
||||||
openTransitionName: props.openTransitionName,
|
|
||||||
openAnimation: props.openAnimation,
|
|
||||||
onOpenChange: this.onOpenChange,
|
|
||||||
subMenuOpenDelay: props.subMenuOpenDelay,
|
|
||||||
subMenuCloseDelay: props.subMenuCloseDelay,
|
|
||||||
forceSubMenuRender: props.forceSubMenuRender,
|
|
||||||
triggerSubMenuAction: props.triggerSubMenuAction,
|
|
||||||
defaultActiveFirst: this.state.defaultActiveFirst,
|
|
||||||
multiple: props.multiple,
|
|
||||||
prefixCls: props.rootPrefixCls,
|
|
||||||
id: this._menuId,
|
|
||||||
ref: this.saveMenuInstance,
|
|
||||||
}
|
|
||||||
return <SubPopupMenu {...baseProps}>{children}</SubPopupMenu>
|
|
||||||
},
|
|
||||||
|
|
||||||
saveSubMenuTitle (subMenuTitle) {
|
|
||||||
this.subMenuTitle = subMenuTitle
|
|
||||||
},
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const props = this.$props
|
const props = this.$props
|
||||||
const isOpen = this.isOpen()
|
const isOpen = this.isOpen()
|
||||||
const prefixCls = this.getPrefixCls()
|
const prefixCls = this.getPrefixCls()
|
||||||
const isInlineMode = props.mode === 'inline'
|
const isInlineMode = props.mode === 'inline'
|
||||||
const className = {
|
const className = {
|
||||||
prefixCls: true,
|
[prefixCls]: true,
|
||||||
[`${prefixCls}-${props.mode}`]: true,
|
[`${prefixCls}-${props.mode}`]: true,
|
||||||
[this.getOpenClassName()]: isOpen,
|
[this.getOpenClassName()]: isOpen,
|
||||||
[this.getActiveClassName()]: props.active || (isOpen && !isInlineMode),
|
[this.getActiveClassName()]: props.active || (isOpen && !isInlineMode),
|
||||||
|
@ -369,65 +361,79 @@ const SubMenu = {
|
||||||
let titleMouseEvents = {}
|
let titleMouseEvents = {}
|
||||||
if (!props.disabled) {
|
if (!props.disabled) {
|
||||||
mouseEvents = {
|
mouseEvents = {
|
||||||
onMouseLeave: this.onMouseLeave,
|
mouseleave: this.onMouseLeave,
|
||||||
onMouseEnter: this.onMouseEnter,
|
mouseenter: this.onMouseEnter,
|
||||||
}
|
}
|
||||||
|
|
||||||
// only works in title, not outer li
|
// only works in title, not outer li
|
||||||
titleClickEvents = {
|
titleClickEvents = {
|
||||||
onClick: this.onTitleClick,
|
click: this.onTitleClick,
|
||||||
}
|
}
|
||||||
titleMouseEvents = {
|
titleMouseEvents = {
|
||||||
onMouseEnter: this.onTitleMouseEnter,
|
mouseenter: this.onTitleMouseEnter,
|
||||||
onMouseLeave: this.onTitleMouseLeave,
|
mouseleave: this.onTitleMouseLeave,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const style = {}
|
const style = {}
|
||||||
if (isInlineMode) {
|
if (isInlineMode) {
|
||||||
style.paddingLeft = props.inlineIndent * props.level
|
style.paddingLeft = `${props.inlineIndent * props.level}px`
|
||||||
|
}
|
||||||
|
const titleProps = {
|
||||||
|
attrs: {
|
||||||
|
'aria-expanded': isOpen,
|
||||||
|
'aria-owns': this._menuId,
|
||||||
|
'aria-haspopup': 'true',
|
||||||
|
title: typeof props.title === 'string' ? props.title : undefined,
|
||||||
|
},
|
||||||
|
on: {
|
||||||
|
...titleMouseEvents,
|
||||||
|
...titleClickEvents,
|
||||||
|
},
|
||||||
|
style,
|
||||||
|
class: `${prefixCls}-title`,
|
||||||
|
ref: 'subMenuTitle',
|
||||||
}
|
}
|
||||||
const title = (
|
const title = (
|
||||||
<div
|
<div
|
||||||
ref='subMenuTitle'
|
{...titleProps}
|
||||||
style={style}
|
|
||||||
class={`${prefixCls}-title`}
|
|
||||||
{...titleMouseEvents}
|
|
||||||
{...titleClickEvents}
|
|
||||||
aria-expanded={isOpen}
|
|
||||||
aria-owns={this._menuId}
|
|
||||||
aria-haspopup='true'
|
|
||||||
title={typeof props.title === 'string' ? props.title : undefined}
|
|
||||||
>
|
>
|
||||||
{props.title}
|
{this.$slots.title}
|
||||||
<i class={`${prefixCls}-arrow`} />
|
<i class={`${prefixCls}-arrow`} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
const children = this.renderChildren(props.children)
|
const children = this.renderChildren(this.$slots.default)
|
||||||
|
|
||||||
const getPopupContainer = props.parentMenu.isRootMenu
|
const getPopupContainer = props.parentMenu.isRootMenu
|
||||||
? props.parentMenu.props.getPopupContainer : triggerNode => triggerNode.parentNode
|
? props.parentMenu.getPopupContainer : triggerNode => triggerNode.parentNode
|
||||||
const popupPlacement = popupPlacementMap[props.mode]
|
const popupPlacement = popupPlacementMap[props.mode]
|
||||||
const popupClassName = props.mode === 'inline' ? '' : props.popupClassName
|
const popupClassName = props.mode === 'inline' ? '' : props.popupClassName
|
||||||
|
const liProps = {
|
||||||
|
on: { ...mouseEvents },
|
||||||
|
class: className,
|
||||||
|
}
|
||||||
|
console.log(isOpen)
|
||||||
return (
|
return (
|
||||||
<li {...mouseEvents} class={className}>
|
<li {...liProps}>
|
||||||
{isInlineMode && title}
|
{isInlineMode && title}
|
||||||
{isInlineMode && children}
|
{isInlineMode && children}
|
||||||
{!isInlineMode && (
|
{!isInlineMode && (
|
||||||
<Trigger
|
<Trigger
|
||||||
prefixCls={prefixCls}
|
prefixCls={prefixCls}
|
||||||
popupClassName={`${prefixCls}-popup ${popupClassName}`}
|
popupClassName={`${prefixCls}-popup ${popupClassName}`}
|
||||||
getPopupContainer={getPopupContainer}
|
// getPopupContainer={getPopupContainer}
|
||||||
builtinPlacements={placements}
|
builtinPlacements={placements}
|
||||||
popupPlacement={popupPlacement}
|
popupPlacement={popupPlacement}
|
||||||
popupVisible={isOpen}
|
popupVisible={isOpen}
|
||||||
popup={children}
|
|
||||||
action={props.disabled ? [] : [props.triggerSubMenuAction]}
|
action={props.disabled ? [] : [props.triggerSubMenuAction]}
|
||||||
mouseEnterDelay={props.subMenuOpenDelay}
|
mouseEnterDelay={props.subMenuOpenDelay}
|
||||||
mouseLeaveDelay={props.subMenuCloseDelay}
|
mouseLeaveDelay={props.subMenuCloseDelay}
|
||||||
onPopupVisibleChange={this.onPopupVisibleChange}
|
onPopupVisibleChange={this.onPopupVisibleChange}
|
||||||
forceRender={props.forceSubMenuRender}
|
forceRender={props.forceSubMenuRender}
|
||||||
>
|
>
|
||||||
|
<template slot='popup'>
|
||||||
|
{children}
|
||||||
|
</template>
|
||||||
{title}
|
{title}
|
||||||
</Trigger>
|
</Trigger>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -79,16 +79,13 @@ export default {
|
||||||
delete animProps.animation.appear
|
delete animProps.animation.appear
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Animate
|
<transition
|
||||||
{...animProps}
|
appear
|
||||||
showProp='visible'
|
name={animProps.transitionName}
|
||||||
component=''
|
|
||||||
transitionAppear={transitionAppear}
|
|
||||||
>
|
>
|
||||||
{this.renderRoot(props)}
|
{this.renderRoot(props)}
|
||||||
</Animate>
|
</transition>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,25 +7,25 @@ export function getKeyFromChildrenIndex (child, menuEventKey, index) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loopMenuItem (children, cb) {
|
export function loopMenuItem (children, cb) {
|
||||||
// let index = -1
|
let index = -1
|
||||||
// React.Children.forEach(children, (c) => {
|
children.forEach((c) => {
|
||||||
// index++
|
index++
|
||||||
// if (c && c.type && c.type.isMenuItemGroup) {
|
if (c && c.type && c.type.isMenuItemGroup) {
|
||||||
// React.Children.forEach(c.props.children, (c2) => {
|
c.$slots.default.forEach((c2) => {
|
||||||
// index++
|
index++
|
||||||
// cb(c2, index)
|
cb(c2, index)
|
||||||
// })
|
})
|
||||||
// } else {
|
} else {
|
||||||
// cb(c, index)
|
cb(c, index)
|
||||||
// }
|
}
|
||||||
// })
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loopMenuItemRecusively (children, keys, ret) {
|
export function loopMenuItemRecusively (children, keys, ret) {
|
||||||
if (!children || ret.find) {
|
if (!children || ret.find) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
React.Children.forEach(children, (c) => {
|
children.forEach((c) => {
|
||||||
if (ret.find) {
|
if (ret.find) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -36,8 +36,8 @@ export function loopMenuItemRecusively (children, keys, ret) {
|
||||||
}
|
}
|
||||||
if (keys.indexOf(c.key) !== -1) {
|
if (keys.indexOf(c.key) !== -1) {
|
||||||
ret.find = true
|
ret.find = true
|
||||||
} else if (c.props.children) {
|
} else if (c.$slots.default) {
|
||||||
loopMenuItemRecusively(c.props.children, keys, ret)
|
loopMenuItemRecusively(c.$slots.default, keys, ret)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -77,6 +77,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"add-dom-event-listener": "^1.0.2",
|
"add-dom-event-listener": "^1.0.2",
|
||||||
"css-animation": "^1.4.1",
|
"css-animation": "^1.4.1",
|
||||||
|
"dom-scroll-into-view": "^1.2.1",
|
||||||
"eslint-plugin-vue": "^3.13.0",
|
"eslint-plugin-vue": "^3.13.0",
|
||||||
"lodash.clonedeep": "^4.5.0",
|
"lodash.clonedeep": "^4.5.0",
|
||||||
"lodash.debounce": "^4.0.8",
|
"lodash.debounce": "^4.0.8",
|
||||||
|
|
Loading…
Reference in New Issue