diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md index 4d6e76071..63de6fe31 100644 --- a/CHANGELOG.en-US.md +++ b/CHANGELOG.en-US.md @@ -29,6 +29,7 @@ - Fix `n-date-picker`'s `date` type of `action` validate error. - Fix `n-data-table` throws error when using `selection` and `summary` together, closes [#1276](https://github.com/TuSimple/naive-ui/issues/1276). - Fix `n-data-table` selection column's width is collapsed when it is set to fixed, closes [#1283](https://github.com/TuSimple/naive-ui/issues/1283). +- Fix `n-popconfirm` can't be nested in `n-tooltip`, closes [#872](https://github.com/TuSimple/naive-ui/issues/872). ## 2.19.3 (2021-09-28) diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index 11da9b04c..1f461fdb3 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -29,6 +29,7 @@ - 修复 `n-date-picker` 的 `date` 类型的 `action` 验证错误 - 修复 `n-data-table` 在 `selection` 和 `summary` 一起使用时报错,关闭 [#1276](https://github.com/TuSimple/naive-ui/issues/1276) - 修复 `n-data-table` 勾选列的宽度在设为 fixed 时候塌陷,关闭 [#1283](https://github.com/TuSimple/naive-ui/issues/1283) +- 修复 `n-popconfirm` 不能被嵌套于 `n-tooltip` 内,关闭 [#872](https://github.com/TuSimple/naive-ui/issues/872). ## 2.19.3 (2021-09-28) diff --git a/package.json b/package.json index 8e0c6c09b..0dcf701d0 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "vdirs": "^0.1.4", "vfonts": "^0.1.0", "vooks": "^0.2.6", - "vueuc": "^0.4.12" + "vueuc": "^0.4.13" }, "sideEffects": false, "homepage": "https://www.naiveui.com", diff --git a/src/popconfirm/src/Popconfirm.ts b/src/popconfirm/src/Popconfirm.ts index 0fb38ff38..38d08ffab 100644 --- a/src/popconfirm/src/Popconfirm.ts +++ b/src/popconfirm/src/Popconfirm.ts @@ -37,6 +37,7 @@ export type PopconfirmProps = ExtractPublicPropTypes export default defineComponent({ name: 'Popconfirm', props: popconfirmProps, + __popover__: true, setup (props) { const { mergedClsPrefixRef } = useConfig() const themeRef = useTheme( diff --git a/src/popover/demos/zhCN/index.demo-entry.md b/src/popover/demos/zhCN/index.demo-entry.md index f7f8941d9..670be7fb0 100644 --- a/src/popover/demos/zhCN/index.demo-entry.md +++ b/src/popover/demos/zhCN/index.demo-entry.md @@ -20,6 +20,7 @@ manual-position header hoist-debug nested-debug +nested2-debug ``` ## API diff --git a/src/popover/demos/zhCN/nested2-debug.demo.md b/src/popover/demos/zhCN/nested2-debug.demo.md new file mode 100644 index 000000000..b9bc03e28 --- /dev/null +++ b/src/popover/demos/zhCN/nested2-debug.demo.md @@ -0,0 +1,27 @@ +# Nested Debug + +```html + + + Tooltip + + + + + 如果它长得像鸭子,走起来像鸭子,叫起来也像鸭子,那它一定是个鸭子。 + +``` diff --git a/src/popover/src/Popover.ts b/src/popover/src/Popover.tsx similarity index 70% rename from src/popover/src/Popover.ts rename to src/popover/src/Popover.tsx index b354e358a..4482fea25 100644 --- a/src/popover/src/Popover.ts +++ b/src/popover/src/Popover.tsx @@ -14,7 +14,7 @@ import { cloneVNode, watchEffect } from 'vue' -import { VBinder, VTarget, FollowerPlacement } from 'vueuc' +import { VBinder, VTarget, FollowerPlacement, BinderInst } from 'vueuc' import { useMergedState, useCompitable, useIsMounted, useMemo } from 'vooks' import { call, keep, getFirstSlotVNode, warnOnce } from '../../_utils' import type { @@ -36,19 +36,22 @@ const triggerEventMap = { focus: ['onFocus', 'onBlur'], click: ['onClick'], hover: ['onMouseenter', 'onMouseleave'], - manual: [] + manual: [], + nested: ['onFocus', 'onBlur', 'onMouseenter', 'onMouseleave', 'onClick'] } as const +export interface TriggerEventHandlers { + onClick: (e: MouseEvent) => void + onMouseenter: (e: MouseEvent) => void + onMouseleave: (e: MouseEvent) => void + onFocus: (e: FocusEvent) => void + onBlur: (e: FocusEvent) => void +} + function appendEvents ( vNode: VNode, - trigger: PopoverTrigger, - events: { - onClick: (e: MouseEvent) => void - onMouseenter: (e: MouseEvent) => void - onMouseleave: (e: MouseEvent) => void - onFocus: (e: FocusEvent) => void - onBlur: (e: FocusEvent) => void - } + trigger: PopoverTrigger | 'nested', + events: TriggerEventHandlers ): void { triggerEventMap[trigger].forEach((eventName) => { if (!vNode.props) vNode.props = {} @@ -151,6 +154,11 @@ export const popoverBaseProps = { MaybeArray<(value: boolean) => void> >, zIndex: Number, + internalSyncTargetWithParent: Boolean, + internalInheritedEventHandlers: { + type: Array as PropType, + default: () => [] + }, /** @deprecated */ onShow: [Function, Array] as PropType< MaybeArray<(value: boolean) => void> | undefined @@ -183,6 +191,7 @@ export default defineComponent({ name: 'Popover', inheritAttrs: false, props: popoverProps, + __popover__: true, setup (props) { if (__DEV__) { watchEffect(() => { @@ -219,6 +228,7 @@ export default defineComponent({ }) } const isMountedRef = useIsMounted() + const binderInstRef = ref(null) // setup show const controlledShowRef = computed(() => props.show) const uncontrolledShowRef = ref(props.defaultShow) @@ -246,8 +256,6 @@ export default defineComponent({ if (props.overlap) return false return compatibleShowArrowRef.value }) - // trigger - let triggerVNode: VNode | null = null // bodyInstance let bodyInstance: BodyInstance | null = null const showTimerIdRef = ref(null) @@ -372,7 +380,7 @@ export default defineComponent({ uncontrolledShowRef.value = value } function getTriggerElement (): HTMLElement { - return triggerVNode?.el as HTMLElement + return binderInstRef.value?.targetRef as HTMLElement } function setBodyInstance (value: BodyInstance | null): void { bodyInstance = value @@ -391,6 +399,7 @@ export default defineComponent({ internalRenderBodyRef: toRef(props, 'internalRenderBody') }) return { + binderInstRef, positionManually: positionManuallyRef, mergedShowConsideringDisabledProp: mergedShowConsideringDisabledPropRef, // if to show popover body @@ -403,65 +412,127 @@ export default defineComponent({ handleMouseLeave, handleFocus, handleBlur, - setTriggerVNode (v: VNode | null) { - triggerVNode = v - }, syncPosition } }, render () { - return h(VBinder, null, { - default: () => { - const { positionManually, $slots: slots } = this - let triggerVNode: VNode | null - if (!positionManually) { - if (slots.activator) { - triggerVNode = getFirstSlotVNode(slots, 'activator') - } else { - triggerVNode = getFirstSlotVNode(slots, 'trigger') - } - if (triggerVNode) { - triggerVNode = cloneVNode(triggerVNode) - triggerVNode = - triggerVNode.type === textVNodeType - ? h('span', [triggerVNode]) - : triggerVNode - appendEvents( - triggerVNode, - positionManually ? 'manual' : this.trigger, - { - onClick: this.handleClick, - onMouseenter: this.handleMouseEnter, - onMouseleave: this.handleMouseLeave, - onFocus: this.handleFocus, - onBlur: this.handleBlur - } - ) - } - this.setTriggerVNode(triggerVNode) - } - // We need to subscribe it. Sometimes rerender won't ge triggered. - // `mergedShowConsideringDisabledProp` is not the final disabled status. - // In ellpisis it's dynamic. - void this.mergedShowConsideringDisabledProp - const mergedShow = this.getMergedShow() - return [ - positionManually - ? null - : h(VTarget, null, { - default: () => triggerVNode - }), - h( - NPopoverBody, - keep(this.$props, bodyPropKeys, { - ...this.$attrs, - showArrow: this.mergedShowArrow, - show: mergedShow - }), - slots - ) - ] + const { positionManually, $slots: slots } = this + let triggerVNode: VNode | null + let popoverInside = false + if (!positionManually) { + if (slots.activator) { + triggerVNode = getFirstSlotVNode(slots, 'activator') + } else { + triggerVNode = getFirstSlotVNode(slots, 'trigger') } - }) + if (triggerVNode) { + triggerVNode = cloneVNode(triggerVNode) + triggerVNode = + triggerVNode.type === textVNodeType + ? h('span', [triggerVNode]) + : triggerVNode + const handlers = { + onClick: this.handleClick, + onMouseenter: this.handleMouseEnter, + onMouseleave: this.handleMouseLeave, + onFocus: this.handleFocus, + onBlur: this.handleBlur + } + if ((triggerVNode.type as any)?.__popover__) { + popoverInside = true + // We assume that there's no DOM event handlers on popover element + if (!triggerVNode.props) { + triggerVNode.props = { + internalSyncTargetWithParent: true, + internalInheritedEventHandlers: [] + } + } + triggerVNode.props.internalSyncTargetWithParent = true + if (!triggerVNode.props.internalInheritedEventHandlers) { + triggerVNode.props.internalInheritedEventHandlers = [handlers] + } else { + triggerVNode.props.internalInheritedEventHandlers = [ + handlers, + ...triggerVNode.props.internalInheritedEventHandlers + ] + } + } else { + const { internalInheritedEventHandlers } = this + const ascendantAndCurrentHandlers: TriggerEventHandlers[] = [ + handlers, + ...internalInheritedEventHandlers + ] + const mergedHandlers: TriggerEventHandlers = { + onBlur: (e: FocusEvent) => { + ascendantAndCurrentHandlers.forEach((_handlers) => { + _handlers.onBlur(e) + }) + }, + onFocus: (e: FocusEvent) => { + ascendantAndCurrentHandlers.forEach((_handlers) => { + _handlers.onBlur(e) + }) + }, + onClick: (e: MouseEvent) => { + ascendantAndCurrentHandlers.forEach((_handlers) => { + _handlers.onClick(e) + }) + }, + onMouseenter: (e: MouseEvent) => { + ascendantAndCurrentHandlers.forEach((_handlers) => { + _handlers.onMouseenter(e) + }) + }, + onMouseleave: (e: MouseEvent) => { + ascendantAndCurrentHandlers.forEach((_handlers) => { + _handlers.onMouseleave(e) + }) + } + } + appendEvents( + triggerVNode, + internalInheritedEventHandlers + ? 'nested' + : positionManually + ? 'manual' + : this.trigger, + mergedHandlers + ) + } + } + } + return ( + + {{ + default: () => { + // We need to subscribe it. Sometimes rerender won't ge triggered. + // `mergedShowConsideringDisabledProp` is not the final disabled status. + // In ellpisis it's dynamic. + void this.mergedShowConsideringDisabledProp + const mergedShow = this.getMergedShow() + return [ + positionManually + ? null + : h(VTarget, null, { + default: () => triggerVNode + }), + h( + NPopoverBody, + keep(this.$props, bodyPropKeys, { + ...this.$attrs, + showArrow: this.mergedShowArrow, + show: mergedShow + }), + slots + ) + ] + } + }} + + ) } }) diff --git a/src/popselect/src/Popselect.tsx b/src/popselect/src/Popselect.tsx index 0d06cbd6f..3d67a07c4 100644 --- a/src/popselect/src/Popselect.tsx +++ b/src/popselect/src/Popselect.tsx @@ -32,6 +32,7 @@ export type PopselectProps = ExtractPublicPropTypes export default defineComponent({ name: 'Popselect', props: popselectProps, + __popover__: true, setup (props) { const themeRef = useTheme( 'Popselect', diff --git a/src/tooltip/src/Tooltip.ts b/src/tooltip/src/Tooltip.ts index a19b9e2aa..8daee46c4 100644 --- a/src/tooltip/src/Tooltip.ts +++ b/src/tooltip/src/Tooltip.ts @@ -21,6 +21,7 @@ export type TooltipProps = ExtractPublicPropTypes export default defineComponent({ name: 'Tooltip', props: tooltipProps, + __popover__: true, setup (props) { const themeRef = useTheme( 'Tooltip',