From 0fee0623980f4de193cf6a2c0976bd14192cba5b Mon Sep 17 00:00:00 2001 From: 07akioni <07akioni2@gmail.com> Date: Sun, 8 Nov 2020 21:46:26 +0800 Subject: [PATCH] feat(dropdown): animated prop --- .../dropdown/enUS/index.demo-entry.md | 1 + .../dropdown/zhCN/index.demo-entry.md | 1 + src/dropdown/src/Dropdown.js | 4 ++ src/dropdown/src/DropdownMenu.js | 2 +- src/dropdown/src/DropdownOption.js | 70 +++++++++++++++---- src/dropdown/src/styles/themed-base.cssr.js | 10 +-- 6 files changed, 67 insertions(+), 21 deletions(-) diff --git a/demo/documentation/components/dropdown/enUS/index.demo-entry.md b/demo/documentation/components/dropdown/enUS/index.demo-entry.md index 105fb5120..a454f3a3c 100644 --- a/demo/documentation/components/dropdown/enUS/index.demo-entry.md +++ b/demo/documentation/components/dropdown/enUS/index.demo-entry.md @@ -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`|`[]`|| |size|`'small'\|'medium'\|'large'\|'huge'`|`'medium'`|| diff --git a/demo/documentation/components/dropdown/zhCN/index.demo-entry.md b/demo/documentation/components/dropdown/zhCN/index.demo-entry.md index 9a6f4b567..4f5e11ec9 100644 --- a/demo/documentation/components/dropdown/zhCN/index.demo-entry.md +++ b/demo/documentation/components/dropdown/zhCN/index.demo-entry.md @@ -14,6 +14,7 @@ manual-position ## Props |名称|类型|默认值|说明| |-|-|-|-| +|animated|`boolean`|`true`|| |keyboard|`boolean`|`true`|是否支持键盘操作(注意和其他内容键盘操作可能的冲突)| |options|`Array`|`[]`|| |size|`'small'\|'medium'\|'large'\|'huge'`|`'medium'`|| diff --git a/src/dropdown/src/Dropdown.js b/src/dropdown/src/Dropdown.js index f46ed3e44..585e65959 100644 --- a/src/dropdown/src/Dropdown.js +++ b/src/dropdown/src/Dropdown.js @@ -24,6 +24,10 @@ const treemateOptions = { } const dropdownProps = { + animated: { + type: Boolean, + default: true + }, keyboard: { type: Boolean, default: true diff --git a/src/dropdown/src/DropdownMenu.js b/src/dropdown/src/DropdownMenu.js index aa5e549e8..5e9f5d319 100644 --- a/src/dropdown/src/DropdownMenu.js +++ b/src/dropdown/src/DropdownMenu.js @@ -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)) } }, diff --git a/src/dropdown/src/DropdownOption.js b/src/dropdown/src/DropdownOption.js index 35b230761..ace737e0f 100644 --- a/src/dropdown/src/DropdownOption.js +++ b/src/dropdown/src/DropdownOption.js @@ -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 diff --git a/src/dropdown/src/styles/themed-base.cssr.js b/src/dropdown/src/styles/themed-base.cssr.js index 264bdc5c8..87b932523 100644 --- a/src/dropdown/src/styles/themed-base.cssr.js +++ b/src/dropdown/src/styles/themed-base.cssr.js @@ -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' }) ])