mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2025-01-18 12:34:25 +08:00
feat(menu): collapse
This commit is contained in:
parent
d5b259810e
commit
723a3b1b80
@ -13,62 +13,62 @@ Use `collapsed-width` and `width` to set sider's width.
|
||||
<n-layout>
|
||||
<n-layout-sider
|
||||
collapse-mode="width"
|
||||
:collapsed-width="80"
|
||||
:collapsed-width="48"
|
||||
:width="240"
|
||||
:collapsed="collapsed"
|
||||
show-toggle-button
|
||||
@collapse="collapsed = true"
|
||||
@expand="collapsed = false"
|
||||
>
|
||||
<n-menu :collapsed="collapsed" :collapsed-width="80" v-model="activeMenuItemName">
|
||||
<n-menu-item title="num1" name="num1">
|
||||
<n-menu :collapsed="collapsed" :collapsed-width="48" v-model="activeMenuItemName">
|
||||
<n-menu-item title="1800" name="1800">
|
||||
<template v-slot:icon>
|
||||
<n-icon>
|
||||
<ios-airplane />
|
||||
<md-notifications-outline />
|
||||
</n-icon>
|
||||
</template>
|
||||
</n-menu-item>
|
||||
<n-menu-item title="num2" name="num2">
|
||||
<n-menu-item title="1900" name="1900">
|
||||
<template v-slot:icon>
|
||||
<n-icon>
|
||||
<ios-airplane />
|
||||
<md-notifications-outline />
|
||||
</n-icon>
|
||||
</template>
|
||||
</n-menu-item>
|
||||
<n-menu-item title="num3" name="num3">
|
||||
<n-menu-item title="2000" name="2000">
|
||||
<template v-slot:icon>
|
||||
<n-icon>
|
||||
<ios-airplane />
|
||||
<md-notifications-outline />
|
||||
</n-icon>
|
||||
</template>
|
||||
</n-menu-item>
|
||||
<n-sub-menu title="subMenu" name="subMenu">
|
||||
<n-sub-menu title="2001" name="2001">
|
||||
<template v-slot:icon>
|
||||
<n-icon>
|
||||
<ios-airplane />
|
||||
<md-notifications-outline />
|
||||
</n-icon>
|
||||
</template>
|
||||
<n-menu-item title="sub1" name="sub1"></n-menu-item>
|
||||
<n-menu-item title="2002" name="2002"></n-menu-item>
|
||||
</n-sub-menu>
|
||||
<n-sub-menu title="subMenu2" name="subMenu2">
|
||||
<n-sub-menu title="2003" name="2003">
|
||||
<template v-slot:icon>
|
||||
<n-icon>
|
||||
<ios-airplane />
|
||||
<md-notifications-outline />
|
||||
</n-icon>
|
||||
</template>
|
||||
<n-sub-menu title="subMenu22" name="subMenu22">
|
||||
<n-menu-item title="sub222" name="sub222"></n-menu-item>
|
||||
<n-sub-menu title="2004" name="2004">
|
||||
<n-menu-item title="2005" name="2005"></n-menu-item>
|
||||
</n-sub-menu>
|
||||
</n-sub-menu>
|
||||
<n-sub-menu title="subMenu3" name="subMenu3">
|
||||
<n-sub-menu title="2006" name="2006">
|
||||
<template v-slot:icon>
|
||||
<n-icon>
|
||||
<ios-airplane />
|
||||
<md-notifications-outline />
|
||||
</n-icon>
|
||||
</template>
|
||||
<n-sub-menu title="group" name="subMenu4">
|
||||
<n-menu-item title="sub1" name="sub6"></n-menu-item>
|
||||
<n-menu-item title="sub1" name="sub7"></n-menu-item>
|
||||
<n-sub-menu title="2007" name="2007">
|
||||
<n-menu-item title="2008" name="2008"></n-menu-item>
|
||||
<n-menu-item title="2009" name="2009"></n-menu-item>
|
||||
</n-sub-menu>
|
||||
</n-sub-menu>
|
||||
</n-menu>
|
||||
@ -110,11 +110,11 @@ Use `collapsed-width` and `width` to set sider's width.
|
||||
```
|
||||
|
||||
```js
|
||||
import iosAirplane from 'naive-ui/lib/icons/ios-airplane'
|
||||
import mdNotificationsOutline from 'naive-ui/lib/icons/md-notifications-outline'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
iosAirplane
|
||||
mdNotificationsOutline
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
@ -19,7 +19,7 @@
|
||||
@scroll="handleMenuScroll"
|
||||
>
|
||||
<div class="n-base-select-menu-option-wrapper">
|
||||
<n-select-menu-light-bar ref="lightBar" />
|
||||
<n-select-menu-light-bar v-if="!withoutLightBar" ref="lightBar" />
|
||||
<template v-if="!loading">
|
||||
<template v-if="!useSlot">
|
||||
<n-select-option
|
||||
@ -32,10 +32,11 @@
|
||||
:mirror="false"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="!mirror">
|
||||
<n-render-options />
|
||||
</template>
|
||||
<template v-else>
|
||||
<n-render-options :mirror="mirror">
|
||||
<slot />
|
||||
</n-render-options>
|
||||
<slot />
|
||||
</template>
|
||||
</template>
|
||||
<div
|
||||
@ -89,6 +90,10 @@ export default {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
withoutLightBar: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
withoutScrollbar: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
|
@ -31,18 +31,24 @@ export default {
|
||||
},
|
||||
default: false
|
||||
},
|
||||
// payload: {
|
||||
// validator (value) {
|
||||
// return typeof value === 'string'
|
||||
// },
|
||||
// default: null
|
||||
// },
|
||||
isSelected: {
|
||||
validator (value) {
|
||||
return typeof value === 'boolean'
|
||||
},
|
||||
default: false
|
||||
},
|
||||
mirror: {
|
||||
validator (value) {
|
||||
return typeof value === 'boolean'
|
||||
},
|
||||
default: true
|
||||
}
|
||||
// mirror: {
|
||||
// validator (value) {
|
||||
// return typeof value === 'boolean'
|
||||
// },
|
||||
// default: true
|
||||
// }
|
||||
},
|
||||
render (h, context) {
|
||||
const option = {
|
||||
@ -53,11 +59,15 @@ export default {
|
||||
const selectMenu = context.injections.NBaseSelectMenu
|
||||
const disabled = context.props.disabled
|
||||
let selected = context.props.isSelected
|
||||
if (context.props.mirror) {
|
||||
if (selectMenu && selectMenu.isSelected && option) {
|
||||
selected = selectMenu.isSelected({ value: context.props.value })
|
||||
}
|
||||
}
|
||||
// if (context.props.mirror) {
|
||||
// if (selectMenu && selectMenu.isSelected && option) {
|
||||
// if (context.props.payload) {
|
||||
// selected = selectMenu.isSelected({ value: context.props.value, payload: context.props.payload })
|
||||
// } else {
|
||||
// selected = selectMenu.isSelected({ value: context.props.value })
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
const listeners = context.listeners || {}
|
||||
function handleClick (e) {
|
||||
if (disabled) return
|
||||
@ -92,7 +102,8 @@ export default {
|
||||
staticClass: 'n-base-select-option',
|
||||
class: {
|
||||
'n-base-select-option--selected': selected,
|
||||
'n-base-select-option--disabled': disabled
|
||||
'n-base-select-option--disabled': disabled,
|
||||
...context.data.class
|
||||
},
|
||||
key: context.props.value,
|
||||
attrs,
|
||||
|
@ -1,14 +1,10 @@
|
||||
<script>
|
||||
import {
|
||||
getDefaultSlotOf,
|
||||
getComponentNameOf,
|
||||
getOptionPropsDataOf
|
||||
getOptionPropsDataOf,
|
||||
isSelectOptionLikeComponent
|
||||
} from '../../../utils/component'
|
||||
|
||||
import {
|
||||
VALID_COMPONENT
|
||||
} from './config'
|
||||
|
||||
export default {
|
||||
name: 'NBaseSelectOptionCollector',
|
||||
provide () {
|
||||
@ -76,7 +72,7 @@ export default {
|
||||
* If component name is valid,
|
||||
* there must be data
|
||||
*/
|
||||
if (VALID_COMPONENT.includes(getComponentNameOf(child))) {
|
||||
if (isSelectOptionLikeComponent(child)) {
|
||||
const propsData = getOptionPropsDataOf(child)
|
||||
this.options.push({ ...propsData, children: child.children })
|
||||
}
|
||||
|
@ -7,36 +7,28 @@ export default {
|
||||
inject: {
|
||||
NBaseSelectMenu: {
|
||||
default: null
|
||||
},
|
||||
mirror: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
render (h, context) {
|
||||
if (context.props.mirror) {
|
||||
return context.children
|
||||
} else {
|
||||
const selectMenu = context.injections.NBaseSelectMenu
|
||||
const options = selectMenu && selectMenu.linkedOptions
|
||||
const isSelected = selectMenu.isSelected
|
||||
return options.map(option => {
|
||||
return h(SelectOption, {
|
||||
props: {
|
||||
label: option.label,
|
||||
value: option.value,
|
||||
disabled: option.disabled,
|
||||
isSelected: isSelected({ value: option.value }),
|
||||
mirror: false
|
||||
},
|
||||
scopedSlots: {
|
||||
default () {
|
||||
return option.children
|
||||
}
|
||||
const selectMenu = context.injections.NBaseSelectMenu
|
||||
const options = selectMenu && selectMenu.linkedOptions
|
||||
const isSelected = selectMenu.isSelected
|
||||
return options.map(option => {
|
||||
return h(SelectOption, {
|
||||
props: {
|
||||
label: option.label,
|
||||
value: option.value,
|
||||
disabled: option.disabled,
|
||||
isSelected: isSelected({ value: option.value }),
|
||||
mirror: false
|
||||
},
|
||||
scopedSlots: {
|
||||
default () {
|
||||
return option.children
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -1,5 +0,0 @@
|
||||
const VALID_COMPONENT = ['NBaseSelectOption', 'NDropdownItem', 'NDropdownSubmenu']
|
||||
|
||||
export {
|
||||
VALID_COMPONENT
|
||||
}
|
@ -69,6 +69,14 @@ export default {
|
||||
focusable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'dropdown'
|
||||
}
|
||||
},
|
||||
render (h, context) {
|
||||
@ -91,6 +99,7 @@ export default {
|
||||
arrow: false,
|
||||
raw: true,
|
||||
shadow: false,
|
||||
disabled: context.props.disabled,
|
||||
controller
|
||||
},
|
||||
scopedSlots: {
|
||||
@ -103,6 +112,7 @@ export default {
|
||||
tabindex: context.props.focusable ? '0' : '-1'
|
||||
},
|
||||
props: {
|
||||
type: context.props.type,
|
||||
autoFocus: context.props.autoFocus,
|
||||
size: context.props.size,
|
||||
controller,
|
||||
|
@ -18,6 +18,10 @@ export default {
|
||||
value: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
selected: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
inject: {
|
||||
@ -29,7 +33,12 @@ export default {
|
||||
return h(NBaseSelectOption, {
|
||||
props: {
|
||||
label: this.$scopedSlots.default ? '' : (this.label || this.name),
|
||||
value: this.value
|
||||
value: this.value,
|
||||
isSelected: this.selected
|
||||
},
|
||||
class: {
|
||||
'n-dropdown-item': true,
|
||||
'n-dropdown-item--as-submenu': this.asSubmenu
|
||||
},
|
||||
scopedSlots: { ...this.$scopedSlots },
|
||||
on: {
|
||||
|
@ -25,6 +25,10 @@ export default {
|
||||
}
|
||||
},
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: 'dropdown'
|
||||
},
|
||||
autoFocus: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
@ -63,6 +67,12 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
showAsMenuPopover () {
|
||||
if (this.NDropdownMenu) {
|
||||
return this.NDropdownMenu.showAsMenuPopover
|
||||
}
|
||||
return this.type === 'menu'
|
||||
},
|
||||
inheritedSubmenuWidth () {
|
||||
if (this.NDropdownMenu) {
|
||||
return this.NDropdownMenu.inheritedSubmenuWidth
|
||||
@ -95,6 +105,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
handleSelectItem (name) {
|
||||
console.log('handleSelectItem')
|
||||
/**
|
||||
* Can only be called at root level menu
|
||||
*/
|
||||
@ -177,6 +188,9 @@ export default {
|
||||
})
|
||||
return h('div', {
|
||||
staticClass: 'n-dropdown-menu',
|
||||
class: {
|
||||
'n-dropdown-menu--as-menu-popover': this.showAsMenuPopover
|
||||
},
|
||||
on: {
|
||||
keydown: this.handleKeyDown,
|
||||
mouseenter: this.handleMouseEnter,
|
||||
@ -194,15 +208,21 @@ export default {
|
||||
h(NBaseSelectMenu, {
|
||||
ref: 'selectMenu',
|
||||
props: {
|
||||
withoutLightBar: this.showAsMenuPopover,
|
||||
withoutScrollbar: true,
|
||||
useSlot: !!this.$scopedSlots.default,
|
||||
isSelected: () => false,
|
||||
options: this.options,
|
||||
size: this.size,
|
||||
isSelected: () => false,
|
||||
theme: this.synthesizedTheme,
|
||||
mirror: true
|
||||
},
|
||||
scopedSlots: {
|
||||
default () {
|
||||
return options
|
||||
}
|
||||
}
|
||||
}, options)
|
||||
})
|
||||
])
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,9 @@
|
||||
<n-dropdown-item
|
||||
ref="activator"
|
||||
:label="label"
|
||||
name="n-dropdown-submenu-item"
|
||||
:name="name"
|
||||
:value="value"
|
||||
:selected="selected"
|
||||
as-submenu
|
||||
@mouseenter="handleMouseEnter"
|
||||
@mouseleave="handleMouseLeave"
|
||||
@ -69,6 +70,10 @@ export default {
|
||||
}
|
||||
},
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
default: 'n-dropdown-submenu-item'
|
||||
},
|
||||
arrow: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
@ -104,6 +109,10 @@ export default {
|
||||
placement: {
|
||||
type: String,
|
||||
default: 'right-start'
|
||||
},
|
||||
selected: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
|
@ -6,6 +6,7 @@ import {
|
||||
export default {
|
||||
functional: true,
|
||||
render (h, context) {
|
||||
if (!context.scopedSlots.default) return []
|
||||
const defaultSlot = context.scopedSlots.default()
|
||||
let counter = 1
|
||||
defaultSlot.forEach((vNode, index) => {
|
||||
|
@ -65,6 +65,7 @@ export default {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
activeNames: [],
|
||||
internalOpenNames: this.openNames || this.defaultOpenNames || []
|
||||
}
|
||||
},
|
||||
|
@ -1,13 +1,48 @@
|
||||
<template>
|
||||
<li v-if="!shouldRenderAsDropItem & isFirstLevel" class="n-menu-item-wrapper">
|
||||
<n-tooltip trigger="hover" :disabled="!NMenu.collapsed" placement="right" :delay="300">
|
||||
<template v-slot:activator>
|
||||
<div
|
||||
class="n-menu-item"
|
||||
:style="{ paddingLeft: delayedPaddingLeft + 'px' }"
|
||||
:class="{
|
||||
'n-menu-item--selected': selected,
|
||||
'n-menu-item--disabled': synthesizedDisabled
|
||||
}"
|
||||
@click="handleClick"
|
||||
>
|
||||
<div
|
||||
v-if="$slots.icon"
|
||||
class="n-menu-item__icon"
|
||||
:style="{
|
||||
width: iconSize && (iconSize + 'px'),
|
||||
height: iconSize && (iconSize + 'px'),
|
||||
fontSize: iconSize && (iconSize + 'px'),
|
||||
}"
|
||||
>
|
||||
<slot name="icon" />
|
||||
</div>
|
||||
<div class="n-menu-item__header">
|
||||
<slot>
|
||||
<render :render="title" />
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<render :render="title" />
|
||||
</n-tooltip>
|
||||
</li>
|
||||
<li
|
||||
v-else-if="!shouldRenderAsDropItem"
|
||||
class="n-menu-item"
|
||||
:style="{ paddingLeft: paddingLeft + 'px' }"
|
||||
:style="{ paddingLeft: delayedPaddingLeft + 'px' }"
|
||||
:class="{
|
||||
'n-menu-item--selected': isSelected,
|
||||
'n-menu-item--selected': selected,
|
||||
'n-menu-item--disabled': synthesizedDisabled
|
||||
}"
|
||||
@click="handleClick"
|
||||
>
|
||||
<!-- identical part start -->
|
||||
<div
|
||||
v-if="$slots.icon"
|
||||
class="n-menu-item__icon"
|
||||
@ -19,26 +54,33 @@
|
||||
>
|
||||
<slot name="icon" />
|
||||
</div>
|
||||
<!-- identical part start end -->
|
||||
<div class="n-menu-item__header">
|
||||
<slot>
|
||||
<render :render="title" />
|
||||
</slot>
|
||||
</div>
|
||||
</li>
|
||||
<n-dropdown-item v-else :name="name" :label="title" :value="value" :selected="selected" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import registerable from '../../../mixins/registerable'
|
||||
import collectable from '../../../mixins/collectable'
|
||||
import withapp from '../../../mixins/withapp'
|
||||
import themeable from '../../../mixins/themeable'
|
||||
import render from '../../../utils/render'
|
||||
import NTooltip from '../../Tooltip'
|
||||
import NDropdownItem from '../../Dropdown/src/DropdownItem'
|
||||
|
||||
export default {
|
||||
name: 'NMenuItem',
|
||||
components: {
|
||||
NTooltip,
|
||||
NDropdownItem,
|
||||
render
|
||||
},
|
||||
mixins: [
|
||||
registerable('NMenu'),
|
||||
collectable('NSubMenu', 'menuItemNames', 'name', true),
|
||||
withapp,
|
||||
themeable
|
||||
],
|
||||
@ -51,11 +93,18 @@ export default {
|
||||
},
|
||||
NMenuItemGroup: {
|
||||
default: null
|
||||
},
|
||||
NMenuUl: {
|
||||
default: null
|
||||
}
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
title: {
|
||||
type: [String, Function],
|
||||
type: [ String, Function ],
|
||||
default: null
|
||||
},
|
||||
name: {
|
||||
@ -67,7 +116,19 @@ export default {
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
delayedPaddingLeft: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
disabledCollectable () {
|
||||
return this.shouldRenderAsDropItem
|
||||
},
|
||||
shouldRenderAsDropItem () {
|
||||
if (this.NMenuUl) return false
|
||||
return !this.isFirstLevel && this.NMenu.collapsed
|
||||
},
|
||||
iconSize () {
|
||||
return this.NMenu && this.NMenu.iconSize
|
||||
},
|
||||
@ -89,7 +150,7 @@ export default {
|
||||
synthesizedDisabled () {
|
||||
return ((this.NSubMenu && this.NSubMenu.synthesizedDisabled) || this.disabled)
|
||||
},
|
||||
isSelected () {
|
||||
selected () {
|
||||
if (this.NMenu.value === this.name) {
|
||||
return true
|
||||
} else {
|
||||
@ -97,6 +158,16 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
paddingLeft (value) {
|
||||
this.$nextTick().then(() => {
|
||||
this.delayedPaddingLeft = value
|
||||
})
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.delayedPaddingLeft = this.paddingLeft
|
||||
},
|
||||
methods: {
|
||||
handleClick () {
|
||||
if (!this.synthesizedDisabled) {
|
||||
|
@ -39,6 +39,11 @@ export default {
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
delayedPaddingLeft: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isFirstLevel () {
|
||||
return !this.NSubMenu && !this.NMenuItemGroup
|
||||
@ -52,6 +57,16 @@ export default {
|
||||
return (this.NMenu.rootIndent || this.NMenu.indent) / 2
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
paddingLeft (value) {
|
||||
this.$nextTick().then(() => {
|
||||
this.delayedPaddingLeft = value
|
||||
})
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.delayedPaddingLeft = this.paddingLeft
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
16
packages/common/Menu/src/MenuUl.vue
Normal file
16
packages/common/Menu/src/MenuUl.vue
Normal file
@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<ul>
|
||||
<slot />
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'NMenuUl',
|
||||
provide () {
|
||||
return {
|
||||
NMenuUl: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,10 +1,62 @@
|
||||
<template>
|
||||
<n-dropdown-submenu v-if="shouldBeRenderedAsDropdownSubmenu && !NMenuUl" :value="value" :label="title" :name="name" :selected="NMenu.activeNames.includes(name)">
|
||||
<template v-slot:activator>
|
||||
<render :render="title" />
|
||||
</template>
|
||||
<slot />
|
||||
</n-dropdown-submenu>
|
||||
<li
|
||||
v-else
|
||||
class="n-sub-menu"
|
||||
:class="{
|
||||
'n-sub-menu--selected-inside': selectedInside
|
||||
}"
|
||||
>
|
||||
<n-dropdown
|
||||
v-if="isFirstLevel"
|
||||
size="large"
|
||||
trigger="click"
|
||||
:focusable="false"
|
||||
:disabled="!isFirstLevel || !NMenu.collapsed"
|
||||
placement="right"
|
||||
type="menu"
|
||||
@select="handleDropdownSelect"
|
||||
>
|
||||
<template v-slot:activator>
|
||||
<div
|
||||
class="n-sub-menu-item n-dropdown"
|
||||
:style="{paddingLeft: delayedPaddingLeft + 'px'}"
|
||||
:class="{
|
||||
'n-sub-menu-item--collapsed': isCollapsed,
|
||||
'n-sub-menu-item--active': !isCollapsed,
|
||||
'n-sub-menu-item--disabled': disabled,
|
||||
}"
|
||||
@click="handleClick"
|
||||
>
|
||||
<div
|
||||
v-if="$slots.icon"
|
||||
class="n-sub-menu-item__icon"
|
||||
:style="{
|
||||
width: iconSize && (iconSize + 'px'),
|
||||
height: iconSize && (iconSize + 'px'),
|
||||
fontSize: iconSize && (iconSize + 'px'),
|
||||
}"
|
||||
>
|
||||
<slot name="icon" />
|
||||
</div>
|
||||
<div class="n-sub-menu-item__header">
|
||||
<slot name="header">
|
||||
<render :render="title" />
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<slot />
|
||||
</n-dropdown>
|
||||
<div
|
||||
class="n-sub-menu-item"
|
||||
:style="{paddingLeft: paddingLeft + 'px'}"
|
||||
v-else
|
||||
class="n-sub-menu-item n-dropdown"
|
||||
:style="{paddingLeft: delayedPaddingLeft + 'px'}"
|
||||
:class="{
|
||||
'n-sub-menu-item--collapsed': isCollapsed,
|
||||
'n-sub-menu-item--active': !isCollapsed,
|
||||
@ -30,31 +82,42 @@
|
||||
</div>
|
||||
</div>
|
||||
<fade-in-height-expand-transition>
|
||||
<ul
|
||||
v-if="!isCollapsed"
|
||||
<n-menu-ul
|
||||
v-show="!isCollapsed"
|
||||
class="n-sub-menu-content"
|
||||
>
|
||||
<slot />
|
||||
</ul>
|
||||
</n-menu-ul>
|
||||
</fade-in-height-expand-transition>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import collectable from '../../../mixins/collectable'
|
||||
import FadeInHeightExpandTransition from '../../../transition/FadeInHeightExpandTransition'
|
||||
import render from '../../../utils/render'
|
||||
import NDropdown from '../../Dropdown/src/Dropdown'
|
||||
import NDropdownSubmenu from '../../Dropdown/src/DropdownSubmenu'
|
||||
import NMenuUl from './MenuUl'
|
||||
|
||||
export default {
|
||||
name: 'NSubMenu',
|
||||
components: {
|
||||
FadeInHeightExpandTransition,
|
||||
NDropdown,
|
||||
NDropdownSubmenu,
|
||||
NMenuUl,
|
||||
render
|
||||
},
|
||||
mixins: [
|
||||
collectable('NSubMenu', 'menuItemNames', 'menuItemNames', true)
|
||||
],
|
||||
provide () {
|
||||
return {
|
||||
NSubMenu: this,
|
||||
NMenuItemGroup: null
|
||||
}
|
||||
},
|
||||
components: {
|
||||
FadeInHeightExpandTransition,
|
||||
render
|
||||
},
|
||||
inject: {
|
||||
NMenu: {
|
||||
default: null
|
||||
@ -64,9 +127,16 @@ export default {
|
||||
},
|
||||
NMenuItemGroup: {
|
||||
default: null
|
||||
},
|
||||
NMenuUl: {
|
||||
default: null
|
||||
}
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
title: {
|
||||
type: [String, Function],
|
||||
default: null
|
||||
@ -80,7 +150,22 @@ export default {
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
delayedPaddingLeft: null,
|
||||
menuItemNames: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
selectedInside () {
|
||||
return this.menuItemNames.includes(this.NMenu.value)
|
||||
},
|
||||
disabledCollectable () {
|
||||
return !this.shouldBeRenderedAsDropdownSubmenu
|
||||
},
|
||||
shouldBeRenderedAsDropdownSubmenu () {
|
||||
return this.NMenu.collapsed && !this.isFirstLevel
|
||||
},
|
||||
iconSize () {
|
||||
return this.NMenu && this.NMenu.iconSize
|
||||
},
|
||||
@ -106,7 +191,30 @@ export default {
|
||||
return this.NMenu.collapsed || !(this.NMenu.synthesizedOpenNames.includes(this.name))
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
selectedInside (value) {
|
||||
if (!value) {
|
||||
this.NMenu.activeNames = Array.from(new Set(this.NMenu.activeNames).delete(this.name))
|
||||
} else {
|
||||
this.NMenu.activeNames = Array.from(new Set(this.NMenu.activeNames).add(this.name))
|
||||
}
|
||||
},
|
||||
paddingLeft (value) {
|
||||
this.$nextTick().then(() => {
|
||||
this.delayedPaddingLeft = value
|
||||
})
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.delayedPaddingLeft = this.paddingLeft
|
||||
if (this.selectedInside) {
|
||||
this.NMenu.activeNames = Array.from(new Set(this.NMenu.activeNames).add(this.name))
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleDropdownSelect (value) {
|
||||
this.NMenu.handleSelect(value)
|
||||
},
|
||||
handleClick () {
|
||||
if (!this.disabled && !this.NMenu.collapsed) {
|
||||
this.NMenu.handleOpenNamesChange(this.name)
|
||||
|
@ -65,6 +65,7 @@ export default {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
activeNames: [],
|
||||
internalOpenNames: this.openNames || this.defaultOpenNames || []
|
||||
}
|
||||
},
|
||||
|
@ -1,13 +1,48 @@
|
||||
<template>
|
||||
<li v-if="!shouldRenderAsDropItem & isFirstLevel" class="n-menu-item-wrapper">
|
||||
<n-tooltip trigger="hover" :disabled="!NMenu.collapsed" placement="right" :delay="300">
|
||||
<template v-slot:activator>
|
||||
<div
|
||||
class="n-menu-item"
|
||||
:style="{ paddingLeft: delayedPaddingLeft + 'px' }"
|
||||
:class="{
|
||||
'n-menu-item--selected': selected,
|
||||
'n-menu-item--disabled': synthesizedDisabled
|
||||
}"
|
||||
@click="handleClick"
|
||||
>
|
||||
<div
|
||||
v-if="$slots.icon"
|
||||
class="n-menu-item__icon"
|
||||
:style="{
|
||||
width: iconSize && (iconSize + 'px'),
|
||||
height: iconSize && (iconSize + 'px'),
|
||||
fontSize: iconSize && (iconSize + 'px'),
|
||||
}"
|
||||
>
|
||||
<slot name="icon" />
|
||||
</div>
|
||||
<div class="n-menu-item__header">
|
||||
<slot>
|
||||
<render :render="title" />
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<render :render="title" />
|
||||
</n-tooltip>
|
||||
</li>
|
||||
<li
|
||||
v-else-if="!shouldRenderAsDropItem"
|
||||
class="n-menu-item"
|
||||
:style="{ paddingLeft: paddingLeft + 'px' }"
|
||||
:style="{ paddingLeft: delayedPaddingLeft + 'px' }"
|
||||
:class="{
|
||||
'n-menu-item--selected': isSelected,
|
||||
'n-menu-item--selected': selected,
|
||||
'n-menu-item--disabled': synthesizedDisabled
|
||||
}"
|
||||
@click="handleClick"
|
||||
>
|
||||
<!-- identical part start -->
|
||||
<div
|
||||
v-if="$slots.icon"
|
||||
class="n-menu-item__icon"
|
||||
@ -19,26 +54,33 @@
|
||||
>
|
||||
<slot name="icon" />
|
||||
</div>
|
||||
<!-- identical part start end -->
|
||||
<div class="n-menu-item__header">
|
||||
<slot>
|
||||
<render :render="title" />
|
||||
</slot>
|
||||
</div>
|
||||
</li>
|
||||
<n-dropdown-item v-else :name="name" :label="title" :value="value" :selected="selected" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import registerable from '../../../mixins/registerable'
|
||||
import collectable from '../../../mixins/collectable'
|
||||
import withapp from '../../../mixins/withapp'
|
||||
import themeable from '../../../mixins/themeable'
|
||||
import render from '../../../utils/render'
|
||||
import NTooltip from '../../Tooltip'
|
||||
import NDropdownItem from '../../Dropdown/src/DropdownItem'
|
||||
|
||||
export default {
|
||||
name: 'NMenuItem',
|
||||
components: {
|
||||
NTooltip,
|
||||
NDropdownItem,
|
||||
render
|
||||
},
|
||||
mixins: [
|
||||
registerable('NMenu'),
|
||||
collectable('NSubMenu', 'menuItemNames', 'name', true),
|
||||
withapp,
|
||||
themeable
|
||||
],
|
||||
@ -51,11 +93,18 @@ export default {
|
||||
},
|
||||
NMenuItemGroup: {
|
||||
default: null
|
||||
},
|
||||
NMenuUl: {
|
||||
default: null
|
||||
}
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
title: {
|
||||
type: [String, Function],
|
||||
type: [ String, Function ],
|
||||
default: null
|
||||
},
|
||||
name: {
|
||||
@ -67,7 +116,19 @@ export default {
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
delayedPaddingLeft: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
disabledCollectable () {
|
||||
return this.shouldRenderAsDropItem
|
||||
},
|
||||
shouldRenderAsDropItem () {
|
||||
if (this.NMenuUl) return false
|
||||
return !this.isFirstLevel && this.NMenu.collapsed
|
||||
},
|
||||
iconSize () {
|
||||
return this.NMenu && this.NMenu.iconSize
|
||||
},
|
||||
@ -89,7 +150,7 @@ export default {
|
||||
synthesizedDisabled () {
|
||||
return ((this.NSubMenu && this.NSubMenu.synthesizedDisabled) || this.disabled)
|
||||
},
|
||||
isSelected () {
|
||||
selected () {
|
||||
if (this.NMenu.value === this.name) {
|
||||
return true
|
||||
} else {
|
||||
@ -97,6 +158,16 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
paddingLeft (value) {
|
||||
this.$nextTick().then(() => {
|
||||
this.delayedPaddingLeft = value
|
||||
})
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.delayedPaddingLeft = this.paddingLeft
|
||||
},
|
||||
methods: {
|
||||
handleClick () {
|
||||
if (!this.synthesizedDisabled) {
|
||||
|
@ -1,10 +1,62 @@
|
||||
<template>
|
||||
<n-dropdown-submenu v-if="shouldBeRenderedAsDropdownSubmenu && !NMenuUl" :value="value" :label="title" :name="name" :selected="NMenu.activeNames.includes(name)">
|
||||
<template v-slot:activator>
|
||||
<render :render="title" />
|
||||
</template>
|
||||
<slot />
|
||||
</n-dropdown-submenu>
|
||||
<li
|
||||
v-else
|
||||
class="n-sub-menu"
|
||||
:class="{
|
||||
'n-sub-menu--selected-inside': selectedInside
|
||||
}"
|
||||
>
|
||||
<n-dropdown
|
||||
v-if="isFirstLevel"
|
||||
size="large"
|
||||
trigger="click"
|
||||
:focusable="false"
|
||||
:disabled="!isFirstLevel || !NMenu.collapsed"
|
||||
placement="right"
|
||||
type="menu"
|
||||
@select="handleDropdownSelect"
|
||||
>
|
||||
<template v-slot:activator>
|
||||
<div
|
||||
class="n-sub-menu-item n-dropdown"
|
||||
:style="{paddingLeft: delayedPaddingLeft + 'px'}"
|
||||
:class="{
|
||||
'n-sub-menu-item--collapsed': isCollapsed,
|
||||
'n-sub-menu-item--active': !isCollapsed,
|
||||
'n-sub-menu-item--disabled': disabled,
|
||||
}"
|
||||
@click="handleClick"
|
||||
>
|
||||
<div
|
||||
v-if="$slots.icon"
|
||||
class="n-sub-menu-item__icon"
|
||||
:style="{
|
||||
width: iconSize && (iconSize + 'px'),
|
||||
height: iconSize && (iconSize + 'px'),
|
||||
fontSize: iconSize && (iconSize + 'px'),
|
||||
}"
|
||||
>
|
||||
<slot name="icon" />
|
||||
</div>
|
||||
<div class="n-sub-menu-item__header">
|
||||
<slot name="header">
|
||||
<render :render="title" />
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<slot />
|
||||
</n-dropdown>
|
||||
<div
|
||||
class="n-sub-menu-item"
|
||||
:style="{paddingLeft: paddingLeft + 'px'}"
|
||||
v-else
|
||||
class="n-sub-menu-item n-dropdown"
|
||||
:style="{paddingLeft: delayedPaddingLeft + 'px'}"
|
||||
:class="{
|
||||
'n-sub-menu-item--collapsed': isCollapsed,
|
||||
'n-sub-menu-item--active': !isCollapsed,
|
||||
@ -30,31 +82,42 @@
|
||||
</div>
|
||||
</div>
|
||||
<fade-in-height-expand-transition>
|
||||
<ul
|
||||
v-if="!isCollapsed"
|
||||
<n-menu-ul
|
||||
v-show="!isCollapsed"
|
||||
class="n-sub-menu-content"
|
||||
>
|
||||
<slot />
|
||||
</ul>
|
||||
</n-menu-ul>
|
||||
</fade-in-height-expand-transition>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import collectable from '../../../mixins/collectable'
|
||||
import FadeInHeightExpandTransition from '../../../transition/FadeInHeightExpandTransition'
|
||||
import render from '../../../utils/render'
|
||||
import NDropdown from '../../Dropdown/src/Dropdown'
|
||||
import NDropdownSubmenu from '../../Dropdown/src/DropdownSubmenu'
|
||||
import NMenuUl from './MenuUl'
|
||||
|
||||
export default {
|
||||
name: 'NSubMenu',
|
||||
components: {
|
||||
FadeInHeightExpandTransition,
|
||||
NDropdown,
|
||||
NDropdownSubmenu,
|
||||
NMenuUl,
|
||||
render
|
||||
},
|
||||
mixins: [
|
||||
collectable('NSubMenu', 'menuItemNames', 'menuItemNames', true)
|
||||
],
|
||||
provide () {
|
||||
return {
|
||||
NSubMenu: this,
|
||||
NMenuItemGroup: null
|
||||
}
|
||||
},
|
||||
components: {
|
||||
FadeInHeightExpandTransition,
|
||||
render
|
||||
},
|
||||
inject: {
|
||||
NMenu: {
|
||||
default: null
|
||||
@ -64,9 +127,16 @@ export default {
|
||||
},
|
||||
NMenuItemGroup: {
|
||||
default: null
|
||||
},
|
||||
NMenuUl: {
|
||||
default: null
|
||||
}
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
title: {
|
||||
type: [String, Function],
|
||||
default: null
|
||||
@ -80,7 +150,22 @@ export default {
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
delayedPaddingLeft: null,
|
||||
menuItemNames: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
selectedInside () {
|
||||
return this.menuItemNames.includes(this.NMenu.value)
|
||||
},
|
||||
disabledCollectable () {
|
||||
return !this.shouldBeRenderedAsDropdownSubmenu
|
||||
},
|
||||
shouldBeRenderedAsDropdownSubmenu () {
|
||||
return this.NMenu.collapsed && !this.isFirstLevel
|
||||
},
|
||||
iconSize () {
|
||||
return this.NMenu && this.NMenu.iconSize
|
||||
},
|
||||
@ -106,7 +191,30 @@ export default {
|
||||
return this.NMenu.collapsed || !(this.NMenu.synthesizedOpenNames.includes(this.name))
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
selectedInside (value) {
|
||||
if (!value) {
|
||||
this.NMenu.activeNames = Array.from(new Set(this.NMenu.activeNames).delete(this.name))
|
||||
} else {
|
||||
this.NMenu.activeNames = Array.from(new Set(this.NMenu.activeNames).add(this.name))
|
||||
}
|
||||
},
|
||||
paddingLeft (value) {
|
||||
this.$nextTick().then(() => {
|
||||
this.delayedPaddingLeft = value
|
||||
})
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.delayedPaddingLeft = this.paddingLeft
|
||||
if (this.selectedInside) {
|
||||
this.NMenu.activeNames = Array.from(new Set(this.NMenu.activeNames).add(this.name))
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleDropdownSelect (value) {
|
||||
this.NMenu.handleSelect(value)
|
||||
},
|
||||
handleClick () {
|
||||
if (!this.disabled && !this.NMenu.collapsed) {
|
||||
this.NMenu.handleOpenNamesChange(this.name)
|
||||
|
@ -247,43 +247,42 @@ export default {
|
||||
}
|
||||
}
|
||||
}, [
|
||||
this.active
|
||||
? h('div', {
|
||||
attrs: {
|
||||
'n-placement': this.adjustedPlacement
|
||||
this.active ? h('div', {
|
||||
attrs: {
|
||||
'n-placement': this.adjustedPlacement
|
||||
},
|
||||
staticClass: 'n-popover-content',
|
||||
class: {
|
||||
'n-popover-content--without-arrow': !this.arrow,
|
||||
[`n-${this.synthesizedTheme}-theme`]: this.synthesizedTheme,
|
||||
'n-popover-content--without-shadow': !this.shadow,
|
||||
[this.contentClass]: this.contentClass,
|
||||
'n-popover-content--fix-width': this.width !== null || this.maxWidth !== null
|
||||
},
|
||||
style: this.style,
|
||||
directives: [
|
||||
// { name: 'show', rawName: 'v-show', value: this.active },
|
||||
{
|
||||
name: 'clickoutside',
|
||||
value: this.handleClickOutside
|
||||
},
|
||||
staticClass: 'n-popover-content',
|
||||
class: {
|
||||
'n-popover-content--without-arrow': !this.arrow,
|
||||
[`n-${this.synthesizedTheme}-theme`]: this.synthesizedTheme,
|
||||
'n-popover-content--without-shadow': !this.shadow,
|
||||
[this.contentClass]: this.contentClass,
|
||||
'n-popover-content--fix-width': this.width !== null || this.maxWidth !== null
|
||||
},
|
||||
style: this.style,
|
||||
directives: [
|
||||
{
|
||||
name: 'clickoutside',
|
||||
value: this.handleClickOutside
|
||||
},
|
||||
{
|
||||
name: 'mousemoveoutside',
|
||||
value: this.handleMouseMoveOutside
|
||||
}
|
||||
],
|
||||
on: {
|
||||
mouseenter: this.handleMouseEnter,
|
||||
mouseleave: this.handleMouseLeave
|
||||
{
|
||||
name: 'mousemoveoutside',
|
||||
value: this.handleMouseMoveOutside
|
||||
}
|
||||
}, [
|
||||
...this.$slots.default,
|
||||
this.arrow
|
||||
? h('div', {
|
||||
staticClass: 'n-popover-arrow'
|
||||
})
|
||||
: null
|
||||
])
|
||||
: null
|
||||
],
|
||||
on: {
|
||||
mouseenter: this.handleMouseEnter,
|
||||
mouseleave: this.handleMouseLeave
|
||||
}
|
||||
}, [
|
||||
...(this.$slots.default || []),
|
||||
this.arrow
|
||||
? h('div', {
|
||||
staticClass: 'n-popover-arrow'
|
||||
})
|
||||
: null
|
||||
]) : null
|
||||
])
|
||||
])
|
||||
])
|
||||
|
@ -33,6 +33,10 @@ export default {
|
||||
controller: {
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
created () {
|
||||
@ -87,6 +91,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
activate () {
|
||||
if (this.disabled) return
|
||||
const content = this.content()
|
||||
if (content && !content.active) {
|
||||
content.internalActive = true
|
||||
|
@ -84,6 +84,10 @@ export default {
|
||||
y: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
render (h, context) {
|
||||
|
@ -59,6 +59,10 @@ export default {
|
||||
controller: {
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
render (h, context) {
|
||||
|
@ -1,18 +1,19 @@
|
||||
export default function (
|
||||
inject,
|
||||
injectionName,
|
||||
collectionProperty,
|
||||
registerProperty = 'value'
|
||||
registerProperty = 'value',
|
||||
flatten = false
|
||||
) {
|
||||
return {
|
||||
computed: {
|
||||
activeInjection () {
|
||||
if (Array.isArray(inject)) {
|
||||
const activeInjectionIndex = inject.findIndex(key => this[key])
|
||||
if (Array.isArray(injectionName)) {
|
||||
const activeInjectionIndex = injectionName.findIndex(key => this[key])
|
||||
if (~activeInjectionIndex) {
|
||||
return this[inject[activeInjectionIndex]]
|
||||
return this[injectionName[activeInjectionIndex]]
|
||||
}
|
||||
} else {
|
||||
return this[inject]
|
||||
return this[injectionName]
|
||||
}
|
||||
return null
|
||||
}
|
||||
@ -36,12 +37,26 @@ export default function (
|
||||
},
|
||||
methods: {
|
||||
registerValue (value = undefined, oldValue = undefined) {
|
||||
if (this.disabledCollectable) {
|
||||
return
|
||||
}
|
||||
if (this.activeInjection) {
|
||||
const values = new Set(this.activeInjection[collectionProperty])
|
||||
if (oldValue !== undefined) values.delete(oldValue)
|
||||
if (value !== undefined) values.add(value)
|
||||
if (oldValue !== undefined) {
|
||||
if (flatten && Array.isArray(value)) {
|
||||
value.forEach(registeredValue => values.delete(registeredValue))
|
||||
} else {
|
||||
values.delete(oldValue)
|
||||
}
|
||||
}
|
||||
if (value !== undefined) {
|
||||
if (flatten && Array.isArray(value)) {
|
||||
value.forEach(valueToRegister => values.add(valueToRegister))
|
||||
} else {
|
||||
values.add(value)
|
||||
}
|
||||
}
|
||||
this.activeInjection[collectionProperty] = Array.from(values)
|
||||
// console.log(this.activeInjection[collectionProperty])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,22 +13,36 @@ import zIndexManager from '../utils/dom/zIndexManager'
|
||||
export default {
|
||||
mounted () {
|
||||
if (!this.detached) return
|
||||
zIndexManager.registerElement(this._getZindexableContent())
|
||||
if (this.active) this._initZindexable()
|
||||
},
|
||||
watch: {
|
||||
active (value) {
|
||||
if (!this.detached) return
|
||||
console.debug('[zindexable.watch.active]:', value)
|
||||
if (value) {
|
||||
this._initZindexable()
|
||||
zIndexManager.setNewZIndex(this._getZindexableContent())
|
||||
}
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
zindexableInitialized: false
|
||||
}
|
||||
},
|
||||
beforeDestroy () {
|
||||
if (!this.detached) return
|
||||
zIndexManager.unregisterElement(this._getZindexableContent())
|
||||
if (this.zindexableInitialized) {
|
||||
zIndexManager.unregisterElement(this._getZindexableContent())
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
_initZindexable () {
|
||||
if (!this.zindexableInitialized) {
|
||||
zIndexManager.registerElement(this._getZindexableContent())
|
||||
this.zindexableInitialized = true
|
||||
}
|
||||
},
|
||||
_getZindexableContent () {
|
||||
if (this.$refs.contentContainer) {
|
||||
return this.$refs.contentContainer
|
||||
|
@ -36,6 +36,11 @@ export default {
|
||||
this.$el.getBoundingClientRect()
|
||||
},
|
||||
handleAfterLeave () {
|
||||
if (this.width) {
|
||||
this.$el.style.maxWidth = null
|
||||
} else {
|
||||
this.$el.style.maxHeight = null
|
||||
}
|
||||
this.$emit('after-leave')
|
||||
},
|
||||
handleEnter () {
|
||||
|
@ -1,10 +1,12 @@
|
||||
const DROPDOWN_RELATED_COMPONENT = ['NDropdownItem', 'NDropdownSubmenu']
|
||||
const DROPDOWN_RELATED_COMPONENT = ['NDropdownItem', 'NDropdownSubmenu', 'NMenuItem', 'NSubMenu']
|
||||
const SELECT_OPTION_LIKE_COMPONENT = ['NBaseSelectOption', 'NDropdownItem', 'NDropdownSubmenu', 'NMenuItem', 'NSubMenu']
|
||||
|
||||
function isSelectOptionLikeComponent (vNode) {
|
||||
return SELECT_OPTION_LIKE_COMPONENT.includes(getComponentNameOf(vNode))
|
||||
}
|
||||
|
||||
function isDropdownRelatedComponent (vNode) {
|
||||
if (DROPDOWN_RELATED_COMPONENT.includes(getComponentNameOf(vNode))) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return DROPDOWN_RELATED_COMPONENT.includes(getComponentNameOf(vNode))
|
||||
}
|
||||
|
||||
function getComponentNameOf (vNode) {
|
||||
@ -30,8 +32,8 @@ function getDefaultSlotOf (componentInstance) {
|
||||
}
|
||||
|
||||
function getSlotOf (componentInstance, slotName) {
|
||||
if (componentInstance.$slots[slotName]) return componentInstance.$slots[slotName]
|
||||
if (componentInstance.$scopedSlots[slotName]) return componentInstance.$scopedSlots[slotName]()
|
||||
if (componentInstance.$slots[slotName]) return componentInstance.$slots[slotName] || []
|
||||
if (componentInstance.$scopedSlots[slotName]) return componentInstance.$scopedSlots[slotName]() || []
|
||||
return []
|
||||
}
|
||||
|
||||
@ -74,5 +76,6 @@ export {
|
||||
getDefaultSlotOf,
|
||||
getComponentNameOf,
|
||||
getOptionPropsDataOf,
|
||||
isDropdownRelatedComponent
|
||||
isDropdownRelatedComponent,
|
||||
isSelectOptionLikeComponent
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ class ZIndexManager {
|
||||
return this.elementZIndex.size
|
||||
}
|
||||
registerElement (el) {
|
||||
console.debug('[ZIndexManager.registerElement]: called')
|
||||
console.debug('[ZIndexManager.registerElement]: called', el)
|
||||
if (this.elementZIndex.has(el)) {
|
||||
console.debug('[ZIndexManager.registerElement]: do not register duplicate element')
|
||||
} else {
|
||||
|
@ -8,6 +8,30 @@
|
||||
fill: $--dropdown-item-suffix-fill;
|
||||
}
|
||||
}
|
||||
@include b(dropdown-menu) {
|
||||
@include m(as-menu-popover) {
|
||||
@include b(base-select-menu) {
|
||||
@include b(base-select-option) {
|
||||
&:hover {
|
||||
color: $--primary-6;
|
||||
@include b(dropdown-submenu-activator) {
|
||||
@include b(icon) {
|
||||
fill: $--primary-6;
|
||||
}
|
||||
}
|
||||
}
|
||||
@include m(selected) {
|
||||
background-color: $--base-select-menu-light-bar-background-color;
|
||||
}
|
||||
}
|
||||
@include b(dropdown-item) {
|
||||
@include m(as-submenu) {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@include once {
|
||||
position: relative;
|
||||
@include b(dropdown-submenu-activator) {
|
||||
@ -23,6 +47,8 @@
|
||||
@include b(dropdown-menu) {
|
||||
outline: none;
|
||||
@include b(base-select-menu) {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
@include m(small-size) {
|
||||
@include b(base-select-menu-option-wrapper) {
|
||||
padding-top: 4px;
|
||||
@ -93,6 +119,15 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
@include m(as-menu-popover) {
|
||||
@include b(base-select-menu) {
|
||||
min-width: 132px;
|
||||
@include b(base-select-menu-option-wrapper) {
|
||||
padding-top: 0 !important;
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@include b(dropdown-divider) {
|
||||
margin: 2px 0;
|
||||
|
107
styles/Menu.scss
107
styles/Menu.scss
@ -15,17 +15,33 @@
|
||||
@include m(collapsed) {
|
||||
@include b(menu-list) {
|
||||
@include b(menu-item) {
|
||||
@include m(selected) {
|
||||
&::before {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@include e(header) {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@include b(sub-menu) {
|
||||
@include m(selected-inside) {
|
||||
@include b(sub-menu-item) {
|
||||
@include e(icon) {
|
||||
fill: $--primary-6;
|
||||
}
|
||||
}
|
||||
}
|
||||
@include b(sub-menu-item) {
|
||||
@include e(icon) {
|
||||
fill: $--n-text-color;
|
||||
}
|
||||
@include e(header) {
|
||||
opacity: 0;
|
||||
}
|
||||
&::after {
|
||||
transition: transform 0.2s $--n-ease-in-out-cubic-bezier, opacity 0.2s $--n-ease-in-out-cubic-bezier, border-color 0.3s $--n-ease-in-out-cubic-bezier;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@ -37,11 +53,13 @@
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
@include b(menu-item-wrapper) {
|
||||
list-style: none;
|
||||
}
|
||||
@include b(menu-item) {
|
||||
color: $--menu-item-text-color;
|
||||
@include once {
|
||||
cursor: pointer;
|
||||
transition: color .3s $--n-ease-in-out-cubic-bezier, padding-left .3s $--n-ease-in-out-cubic-bezier;
|
||||
transition: background-color .3s $--n-ease-in-out-cubic-bezier, padding-left .3s $--n-ease-in-out-cubic-bezier;
|
||||
position: relative;
|
||||
height: 48px;
|
||||
display: flex;
|
||||
@ -57,7 +75,7 @@
|
||||
display: inline-flex;
|
||||
}
|
||||
@include e(header) {
|
||||
transition: opacity .3s $--n-ease-in-out-cubic-bezier;
|
||||
transition: color .3s $--n-ease-in-out-cubic-bezier, opacity .3s $--n-ease-in-out-cubic-bezier;
|
||||
opacity: 1;
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
@ -72,25 +90,58 @@
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
&::before {
|
||||
background-image: $--menu-item-background-image;
|
||||
background-position: $--menu-item-background-position;
|
||||
@include once {
|
||||
content: "";
|
||||
background-size: 300%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: 0;
|
||||
transition: opacity 0.3s $--n-ease-in-out-cubic-bezier, background-position .3s $--n-ease-in-out-cubic-bezier;
|
||||
opacity: 0;
|
||||
@include e(icon) {
|
||||
fill: $--n-secondary-text-color;
|
||||
}
|
||||
@include e(header) {
|
||||
color: $--n-secondary-text-color;
|
||||
}
|
||||
&:hover {
|
||||
@include e(icon) {
|
||||
fill: $--primary-6;
|
||||
}
|
||||
@include e(header) {
|
||||
color: $--primary-6;
|
||||
}
|
||||
}
|
||||
@include m(selected) {
|
||||
background-color: $--menu-item-background-color;
|
||||
@include e(icon) {
|
||||
fill: $--primary-6;
|
||||
}
|
||||
@include e(header) {
|
||||
color: $--primary-6;
|
||||
}
|
||||
}
|
||||
// &::before {
|
||||
// background-image: $--menu-item-background-image;
|
||||
// background-position: $--menu-item-background-position;
|
||||
// @include once {
|
||||
// content: "";
|
||||
// background-size: 300%;
|
||||
// position: absolute;
|
||||
// left: 0;
|
||||
// right: 0;
|
||||
// top: 0;
|
||||
// bottom: 0;
|
||||
// z-index: 0;
|
||||
// transition: opacity 0.3s $--n-ease-in-out-cubic-bezier, background-position .3s $--n-ease-in-out-cubic-bezier;
|
||||
// opacity: 0;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
@include b(sub-menu) {
|
||||
@include m(selected-inside) {
|
||||
@include b(sub-menu-item) {
|
||||
@include e(header) {
|
||||
color: $--primary-6
|
||||
}
|
||||
@include e(icon) {
|
||||
fill: $--primary-6
|
||||
}
|
||||
}
|
||||
}
|
||||
@include once {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
@ -101,7 +152,12 @@
|
||||
}
|
||||
}
|
||||
@include b(sub-menu-item) {
|
||||
color: $--menu-sub-menu-text-color;
|
||||
@include e(header) {
|
||||
color: $--n-text-color;
|
||||
}
|
||||
@include e(icon) {
|
||||
fill: $--n-text-color;
|
||||
}
|
||||
@include once {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
@ -120,7 +176,7 @@
|
||||
display: inline-flex;
|
||||
}
|
||||
@include e(header) {
|
||||
transition: opacity .3s $--n-ease-in-out-cubic-bezier;
|
||||
transition: color .3s $--n-ease-in-out-cubic-bezier, opacity .3s $--n-ease-in-out-cubic-bezier;
|
||||
opacity: 1;
|
||||
flex-grow: 1;
|
||||
opacity: 1;
|
||||
@ -135,7 +191,16 @@
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
&::after { // down arrow
|
||||
&:hover {
|
||||
@include e(icon) {
|
||||
fill: $--primary-6;
|
||||
}
|
||||
@include e(header) {
|
||||
color: $--primary-6;
|
||||
}
|
||||
}
|
||||
/** ::after is the arrow of submenu */
|
||||
&::after {
|
||||
border-left: 2px solid $--menu-sub-menu-arrow-color;
|
||||
border-top: 2px solid $--menu-sub-menu-arrow-color;
|
||||
@include once {
|
||||
@ -148,7 +213,7 @@
|
||||
transform: rotate(45deg) ;
|
||||
transform-origin: 25% 25%;
|
||||
opacity: 1;
|
||||
transition: transform 0.2s $--n-ease-in-out-cubic-bezier, opacity 0.3s $--n-ease-in-out-cubic-bezier, border-color 0.3s $--n-ease-in-out-cubic-bezier;
|
||||
transition: transform 0.2s $--n-ease-in-out-cubic-bezier, opacity 0.2s $--n-ease-in-out-cubic-bezier .1s, border-color 0.3s $--n-ease-in-out-cubic-bezier;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,5 +5,5 @@
|
||||
'hover': $--n-primary-color,
|
||||
'active': $--n-primary-color
|
||||
) !global;
|
||||
$--anchor-link-background-color: change-color($color: $--primary-6, $alpha: .2) !global;
|
||||
$--anchor-link-background-color: change-color($color: $--primary-6, $alpha: .15) !global;
|
||||
}
|
@ -9,5 +9,5 @@
|
||||
$--base-select-menu-option-check-mark-color: $--n-primary-color !global;
|
||||
$--base-select-menu-background-color: $--n-popover-color !global;
|
||||
$--base-select-menu-box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.18) !global;
|
||||
$--base-select-menu-light-bar-background-color: change-color($--primary-6, $alpha: .2) !global;
|
||||
$--base-select-menu-light-bar-background-color: change-color($--primary-6, $alpha: .15) !global;
|
||||
}
|
@ -1,8 +1,9 @@
|
||||
@mixin setup-dark-menu {
|
||||
$--menu-item-background-image: linear-gradient(90deg, rgba(255, 255, 255, .3) 0%, rgba(255, 255, 255, .03) 40%, rgba(0, 0, 0, .09) 60%, rgba(0, 0, 0, .09) 100%) !global;
|
||||
$--menu-item-background-image: linear-gradient(90deg, rgba(255, 255, 255, .3) 0%, rgba(255, 255, 255, .03) 40%, rgba(0, 0, 0, .04) 60%, rgba(0, 0, 0, .04) 100%) !global;
|
||||
$--menu-item-background-position: 0% !global;
|
||||
$--menu-item-group-text-color: $--n-meta-text-color !global;
|
||||
$--menu-item-text-color: $--n-secondary-text-color !global;
|
||||
$--menu-sub-menu-text-color: $--n-text-color !global;
|
||||
$--menu-sub-menu-arrow-color: $--n-primary-color !global;
|
||||
$--menu-item-background-color: change-color($--primary-6, $alpha: .15) !global;
|
||||
}
|
@ -5,5 +5,5 @@
|
||||
'hover': $--n-primary-color,
|
||||
'active': $--n-primary-color
|
||||
) !global;
|
||||
$--anchor-link-background-color: change-color($color: $--primary-6, $alpha: .2) !global;
|
||||
$--anchor-link-background-color: change-color($color: $--primary-6, $alpha: .1) !global;
|
||||
}
|
@ -9,5 +9,5 @@
|
||||
$--base-select-menu-option-check-mark-color: $--n-primary-color !global;
|
||||
$--base-select-menu-background-color: white !global;
|
||||
$--base-select-menu-box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.18) !global;
|
||||
$--base-select-menu-light-bar-background-color: change-color($--primary-6, $alpha: .15) !global;
|
||||
$--base-select-menu-light-bar-background-color: change-color($--primary-6, $alpha: .1) !global;
|
||||
}
|
@ -1,8 +1,9 @@
|
||||
@mixin setup-light-menu {
|
||||
$--menu-item-background-image: linear-gradient(90deg, rgba(255, 255, 255, .3) 0%, rgba(255, 255, 255, .03) 40%, rgba(0, 0, 0, .09) 60%, rgba(0, 0, 0, .09) 100%) !global;
|
||||
$--menu-item-background-image: linear-gradient(90deg, rgba(255, 255, 255, .3) 0%, rgba(255, 255, 255, .03) 40%, rgba(0, 0, 0, .04) 60%, rgba(0, 0, 0, .04) 100%) !global;
|
||||
$--menu-item-background-position: 100% !global;
|
||||
$--menu-item-group-text-color: $--n-meta-text-color !global;
|
||||
$--menu-item-text-color: $--n-secondary-text-color !global;
|
||||
$--menu-sub-menu-text-color: $--n-text-color !global;
|
||||
$--menu-sub-menu-arrow-color: $--n-primary-color !global;
|
||||
$--menu-item-background-color: change-color($--primary-6, $alpha: .1) !global;
|
||||
}
|
Loading…
Reference in New Issue
Block a user