From 9919e0a8678331f7a540f5fe283a7922da07d32a Mon Sep 17 00:00:00 2001 From: JeremyWuuuuu <15975785+JeremyWuuuuu@users.noreply.github.com> Date: Sat, 26 Mar 2022 13:33:24 +0800 Subject: [PATCH] feat(components): [tooltip-v2] add new component (#6838) * feat(components): [tooltip-v2] add new component - Init component * Implement trigger and only child * Fix typing issue --- packages/components/tooltip-v2/index.ts | 0 packages/components/tooltip-v2/src/arrow.ts | 0 packages/components/tooltip-v2/src/arrow.vue | 0 packages/components/tooltip-v2/src/content.ts | 0 .../components/tooltip-v2/src/content.vue | 0 .../components/tooltip-v2/src/only-child.tsx | 38 +++++++++++++++++++ packages/components/tooltip-v2/src/root.ts | 0 packages/components/tooltip-v2/src/root.vue | 0 packages/components/tooltip-v2/src/tooltip.ts | 0 .../components/tooltip-v2/src/tooltip.vue | 9 +++++ packages/components/tooltip-v2/src/trigger.ts | 11 ++++++ .../components/tooltip-v2/src/trigger.vue | 20 ++++++++++ packages/utils/vue/refs.ts | 16 +++++++- packages/utils/vue/vnode.ts | 15 +++++++- 14 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 packages/components/tooltip-v2/index.ts create mode 100644 packages/components/tooltip-v2/src/arrow.ts create mode 100644 packages/components/tooltip-v2/src/arrow.vue create mode 100644 packages/components/tooltip-v2/src/content.ts create mode 100644 packages/components/tooltip-v2/src/content.vue create mode 100644 packages/components/tooltip-v2/src/only-child.tsx create mode 100644 packages/components/tooltip-v2/src/root.ts create mode 100644 packages/components/tooltip-v2/src/root.vue create mode 100644 packages/components/tooltip-v2/src/tooltip.ts create mode 100644 packages/components/tooltip-v2/src/tooltip.vue create mode 100644 packages/components/tooltip-v2/src/trigger.ts create mode 100644 packages/components/tooltip-v2/src/trigger.vue diff --git a/packages/components/tooltip-v2/index.ts b/packages/components/tooltip-v2/index.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/components/tooltip-v2/src/arrow.ts b/packages/components/tooltip-v2/src/arrow.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/components/tooltip-v2/src/arrow.vue b/packages/components/tooltip-v2/src/arrow.vue new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/components/tooltip-v2/src/content.ts b/packages/components/tooltip-v2/src/content.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/components/tooltip-v2/src/content.vue b/packages/components/tooltip-v2/src/content.vue new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/components/tooltip-v2/src/only-child.tsx b/packages/components/tooltip-v2/src/only-child.tsx new file mode 100644 index 0000000000..0cfaf22d4e --- /dev/null +++ b/packages/components/tooltip-v2/src/only-child.tsx @@ -0,0 +1,38 @@ +import { Fragment, defineComponent, ref } from 'vue' +import { + buildProps, + composeRefs, + definePropType, + ensureOnlyChild, +} from '@element-plus/utils' + +import type { ExtractPropTypes, VNodeArrayChildren } from 'vue' + +export type RefSetter = (el: HTMLElement | null) => void + +export const forwardRefProps = buildProps({ + setRef: { type: definePropType(Function), required: true }, +} as const) + +export type ForwardRefProps = ExtractPropTypes + +// TODO: consider make this component a reusable component without the only child feature. +export default defineComponent({ + props: forwardRefProps, + setup(props, { slots }) { + const fragmentRef = ref() + const setRef = composeRefs(fragmentRef, (el) => { + // vue fragments is represented as a text element. + // The first element sibling should be the first element children of fragment. + // This is how we get the element. + props.setRef((el as HTMLElement).nextElementSibling as HTMLElement | null) + }) + return () => { + const [firstChild] = slots.default?.() || [] + const child = ensureOnlyChild(firstChild.children as VNodeArrayChildren) + // Dunno why the ref for jsx complains about the typing issue which was not + // in template + return {child} + } + }, +}) diff --git a/packages/components/tooltip-v2/src/root.ts b/packages/components/tooltip-v2/src/root.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/components/tooltip-v2/src/root.vue b/packages/components/tooltip-v2/src/root.vue new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/components/tooltip-v2/src/tooltip.ts b/packages/components/tooltip-v2/src/tooltip.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/components/tooltip-v2/src/tooltip.vue b/packages/components/tooltip-v2/src/tooltip.vue new file mode 100644 index 0000000000..b38ce8c7d8 --- /dev/null +++ b/packages/components/tooltip-v2/src/tooltip.vue @@ -0,0 +1,9 @@ + + + diff --git a/packages/components/tooltip-v2/src/trigger.ts b/packages/components/tooltip-v2/src/trigger.ts new file mode 100644 index 0000000000..18227849db --- /dev/null +++ b/packages/components/tooltip-v2/src/trigger.ts @@ -0,0 +1,11 @@ +import { buildProps } from '@element-plus/utils' + +import type { ExtractPropTypes } from 'vue' + +export const tooltipTriggerV2Props = buildProps({ + asChild: Boolean, +} as const) + +export type TooltipTriggerV2Props = ExtractPropTypes< + typeof tooltipTriggerV2Props +> diff --git a/packages/components/tooltip-v2/src/trigger.vue b/packages/components/tooltip-v2/src/trigger.vue new file mode 100644 index 0000000000..d2814977b3 --- /dev/null +++ b/packages/components/tooltip-v2/src/trigger.vue @@ -0,0 +1,20 @@ + + + diff --git a/packages/utils/vue/refs.ts b/packages/utils/vue/refs.ts index eae59f571c..e7edeebd11 100644 --- a/packages/utils/vue/refs.ts +++ b/packages/utils/vue/refs.ts @@ -1,9 +1,21 @@ +import { isFunction } from '@element-plus/utils' + import type { ComponentPublicInstance, Ref } from 'vue' -export const composeRefs = (...refs: Ref[]) => { +export type RefSetter = ( + el: Element | ComponentPublicInstance | undefined +) => void + +export const composeRefs = ( + ...refs: (Ref | RefSetter)[] +) => { return (el: Element | ComponentPublicInstance | null) => { refs.forEach((ref) => { - ref.value = el as HTMLElement | undefined + if (isFunction(ref)) { + ref(el as Element | ComponentPublicInstance) + } else { + ref.value = el as HTMLElement | undefined + } }) } } diff --git a/packages/utils/vue/vnode.ts b/packages/utils/vue/vnode.ts index c9e2cca113..8743ccd5ce 100644 --- a/packages/utils/vue/vnode.ts +++ b/packages/utils/vue/vnode.ts @@ -8,9 +8,15 @@ import { isVNode, openBlock, } from 'vue' +import { isArray } from '@vue/shared' import { hasOwn } from '../objects' import { debugWarn } from '../error' -import type { VNode, VNodeChild, VNodeNormalizedChildren } from 'vue' +import type { + VNode, + VNodeArrayChildren, + VNodeChild, + VNodeNormalizedChildren, +} from 'vue' const SCOPE = 'utils/vue/vnode' @@ -125,3 +131,10 @@ export const getNormalizedProps = (node: VNode) => { return props } + +export const ensureOnlyChild = (children: VNodeArrayChildren | undefined) => { + if (!isArray(children) || children.length > 1) { + throw new Error('expect to receive a single Vue element child') + } + return children[0] +}