mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2025-03-31 14:20:53 +08:00
feat(dropdown): animated prop
This commit is contained in:
parent
2a1b7b63cd
commit
0fee062398
demo/documentation/components/dropdown
src/dropdown/src
@ -14,6 +14,7 @@ manual-position
|
||||
## Props
|
||||
|Name|Type|Default|Description|
|
||||
|-|-|-|-|
|
||||
|animated|`boolean`|`true`||
|
||||
|keyboard|`boolean`|`true`|Whether is supports keyboard operation. (Be careful about the potential conflicts with other components keyboard operations)|
|
||||
|options|`Array<DropdownOption \| DropdownDivider \| DropdownSubmenu>`|`[]`||
|
||||
|size|`'small'\|'medium'\|'large'\|'huge'`|`'medium'`||
|
||||
|
@ -14,6 +14,7 @@ manual-position
|
||||
## Props
|
||||
|名称|类型|默认值|说明|
|
||||
|-|-|-|-|
|
||||
|animated|`boolean`|`true`||
|
||||
|keyboard|`boolean`|`true`|是否支持键盘操作(注意和其他内容键盘操作可能的冲突)|
|
||||
|options|`Array<DropdownOption \| DropdownDivider \| DropdownSubmenu>`|`[]`||
|
||||
|size|`'small'\|'medium'\|'large'\|'huge'`|`'medium'`||
|
||||
|
@ -24,6 +24,10 @@ const treemateOptions = {
|
||||
}
|
||||
|
||||
const dropdownProps = {
|
||||
animated: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
keyboard: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
|
@ -25,7 +25,7 @@ export default {
|
||||
showIcon () {
|
||||
return this.tmNodes.some(tmNode => tmNode.rawNode.icon)
|
||||
},
|
||||
showSubmenu () {
|
||||
hasSubmenu () {
|
||||
return this.tmNodes.some(tmNode => isSubmenuNode(tmNode.rawNode))
|
||||
}
|
||||
},
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { h, computed, inject, ref } from 'vue'
|
||||
import { h, computed, inject, ref, Transition } from 'vue'
|
||||
import { render } from '../../_utils/vue'
|
||||
import { placeable } from '../../_mixins'
|
||||
import { ChevronRightIcon } from '../../_base/icons'
|
||||
@ -10,8 +10,18 @@ import { isSubmenuNode } from './utils'
|
||||
|
||||
export default {
|
||||
name: 'DropdownOption',
|
||||
inject: ['NDropdown', 'NDropdownMenu'],
|
||||
mixins: [placeable],
|
||||
mixins: [
|
||||
placeable
|
||||
],
|
||||
provide () {
|
||||
return {
|
||||
NDropdownOption: this
|
||||
}
|
||||
},
|
||||
inject: [
|
||||
'NDropdown',
|
||||
'NDropdownMenu'
|
||||
],
|
||||
props: {
|
||||
tmNode: {
|
||||
type: Object,
|
||||
@ -28,6 +38,7 @@ export default {
|
||||
},
|
||||
setup (props) {
|
||||
const NDropdown = inject('NDropdown')
|
||||
const NDropdownOption = inject('NDropdownOption', null)
|
||||
const rawNodeRef = computed(() => props.tmNode.rawNode)
|
||||
const hasSubmenuRef = computed(() => {
|
||||
return isSubmenuNode(props.tmNode.rawNode)
|
||||
@ -51,11 +62,20 @@ export default {
|
||||
if (lastToggledSubmenuKey !== null) return activeKeyPath.includes(key)
|
||||
return false
|
||||
})
|
||||
const shouldDelayRef = computed(() => NDropdown.keyboardKey === null)
|
||||
const shouldDelayRef = computed(() => {
|
||||
return NDropdown.keyboardKey === null && NDropdown.animated === false
|
||||
})
|
||||
const delayedSubmenuRef = useDelayedTrue(showSubmenuRef, 300, shouldDelayRef)
|
||||
const parentEnteringSubmenuRef = computed(() => {
|
||||
return !!(NDropdownOption && NDropdownOption.enteringSubmenu)
|
||||
})
|
||||
return {
|
||||
enteringSubmenu: ref(false),
|
||||
mergedShowSubmenu: computed(() => {
|
||||
return delayedSubmenuRef.value && !parentEnteringSubmenuRef.value
|
||||
}),
|
||||
rawNode: rawNodeRef,
|
||||
hasSubmenu: hasSubmenuRef,
|
||||
showSubmenu: useDelayedTrue(showSubmenuRef, 300, shouldDelayRef),
|
||||
pending: useMemo(() => {
|
||||
const {
|
||||
activeKeyPath
|
||||
@ -66,12 +86,13 @@ export default {
|
||||
// placeable
|
||||
trackingRef: ref(null),
|
||||
offsetContainerRef: ref(null),
|
||||
bodyRef: ref(null)
|
||||
bodyRef: ref(null),
|
||||
NDropdownOption
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
__placeableEnabled () {
|
||||
return this.showSubmenu
|
||||
return this.mergedShowSubmenu
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -87,6 +108,12 @@ export default {
|
||||
__placeableBody () {
|
||||
return this.bodyRef
|
||||
},
|
||||
handleSubmenuBeforeEnter () {
|
||||
this.enteringSubmenu = true
|
||||
},
|
||||
handleSubmenuAfterEnter () {
|
||||
this.enteringSubmenu = false
|
||||
},
|
||||
handleMouseEnter () {
|
||||
const {
|
||||
NDropdown,
|
||||
@ -136,6 +163,19 @@ export default {
|
||||
}
|
||||
},
|
||||
render () {
|
||||
const {
|
||||
NDropdown: {
|
||||
animated
|
||||
},
|
||||
mergedShowSubmenu
|
||||
} = this
|
||||
const submenuVNode = mergedShowSubmenu
|
||||
? h(NDropdownMenu, {
|
||||
ref: 'bodyRef',
|
||||
tmNodes: this.tmNode.children,
|
||||
parentKey: this.tmNode.key
|
||||
})
|
||||
: null
|
||||
return h('div', {
|
||||
class: 'n-dropdown-option'
|
||||
}, [
|
||||
@ -172,7 +212,7 @@ export default {
|
||||
class: [
|
||||
'n-dropdown-option-body__suffix',
|
||||
{
|
||||
'n-dropdown-option-body__suffix--show-submenu': this.NDropdownMenu.showSubmenu
|
||||
'n-dropdown-option-body__suffix--has-submenu': this.NDropdownMenu.hasSubmenu
|
||||
}
|
||||
],
|
||||
'n-dropdown-option': true
|
||||
@ -193,13 +233,13 @@ export default {
|
||||
class: 'n-dropdown-menu-wrapper'
|
||||
},
|
||||
[
|
||||
this.showSubmenu
|
||||
? h(NDropdownMenu, {
|
||||
ref: 'bodyRef',
|
||||
tmNodes: this.tmNode.children,
|
||||
parentKey: this.tmNode.key
|
||||
})
|
||||
: null
|
||||
animated ? h(Transition, {
|
||||
onBeforeEnter: this.handleSubmenuBeforeEnter,
|
||||
onAfterEnter: this.handleSubmenuAfterEnter,
|
||||
name: 'n-fade-in-scale-up-transition'
|
||||
}, {
|
||||
default: () => submenuVNode
|
||||
}) : submenuVNode
|
||||
]
|
||||
)
|
||||
]) : null
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { c, cTB, cB, cM, cE, createKey } from '../../../_utils/cssr'
|
||||
import fadeInScaleUpTransition from '../../../_styles/transitions/fade-in-scale-up'
|
||||
|
||||
export default c([
|
||||
({ props }) => {
|
||||
@ -19,6 +20,7 @@ export default c([
|
||||
borderRadius,
|
||||
boxShadow
|
||||
}, [
|
||||
fadeInScaleUpTransition(),
|
||||
[
|
||||
'small',
|
||||
'medium',
|
||||
@ -42,8 +44,7 @@ export default c([
|
||||
width: local[createKey('optionIconPrefixWidth', size)]
|
||||
}),
|
||||
cB('icon', {
|
||||
fill: prefixColor,
|
||||
stroke: prefixColor,
|
||||
color: prefixColor,
|
||||
fontSize: '16px'
|
||||
})
|
||||
]),
|
||||
@ -60,12 +61,11 @@ export default c([
|
||||
minWidth: local[createKey('optionSuffixWidth', size)],
|
||||
padding: '0 8px'
|
||||
}, [
|
||||
cM('show-submenu', {
|
||||
cM('has-submenu', {
|
||||
width: local[createKey('optionIconSuffixWidth', size)]
|
||||
}),
|
||||
cB('icon', {
|
||||
fill: suffixColor,
|
||||
stroke: suffixColor,
|
||||
color: suffixColor,
|
||||
fontSize: '16px'
|
||||
})
|
||||
])
|
||||
|
Loading…
x
Reference in New Issue
Block a user