From 2277cf026f6cc8397041936d220d6d19ca7c1fa4 Mon Sep 17 00:00:00 2001 From: danranvm Date: Fri, 29 Jul 2022 16:21:21 +0800 Subject: [PATCH] feat(comp:form): support message in tooltip --- packages/cdk/popper/docs/Index.zh.md | 6 +- packages/cdk/popper/src/hooks.ts | 9 +- packages/cdk/popper/src/types.ts | 6 +- packages/cdk/popper/src/usePopper.ts | 33 +++--- .../_private/overlay/src/Overlay.tsx | 20 +++- .../_private/overlay/style/index.less | 8 +- .../style/themes/default.variable.less | 2 +- packages/components/dropdown/style/index.less | 2 +- .../form/demo/CustomizedValidation.vue | 6 +- .../components/form/demo/MessageTooltip.md | 14 +++ .../components/form/demo/MessageTooltip.vue | 100 ++++++++++++++++ packages/components/form/docs/Index.zh.md | 2 + packages/components/form/src/FormItem.tsx | 112 ++++++++++++++---- .../form/src/composables/useFormItem.ts | 33 +++--- packages/components/form/src/types.ts | 17 ++- packages/components/form/style/index.less | 15 +-- packages/components/form/style/mixin.less | 11 +- packages/components/form/style/status.less | 32 ++--- packages/components/style/motion/fade.less | 22 ++++ packages/components/tooltip/src/types.ts | 1 + .../tooltip/src/useTooltipOverlay.ts | 2 +- packages/components/tooltip/style/index.less | 4 - 22 files changed, 333 insertions(+), 124 deletions(-) create mode 100644 packages/components/form/demo/MessageTooltip.md create mode 100644 packages/components/form/demo/MessageTooltip.vue diff --git a/packages/cdk/popper/docs/Index.zh.md b/packages/cdk/popper/docs/Index.zh.md index 4aa14ab7f..7b06f1c71 100644 --- a/packages/cdk/popper/docs/Index.zh.md +++ b/packages/cdk/popper/docs/Index.zh.md @@ -48,11 +48,11 @@ export type PopperTrigger = 'click' | 'hover' | 'focus' | 'contextmenu' | 'manua | `destroy` | 销毁浮层 | `(): void` | - | - | - | | `visibility` | 浮层显示状态 | `ComputedRef` | -| - | - | | `placement` | 浮层位置 | `ComputedRef` | - | - | - | -| `triggerRef` | 浮层的触发元素 | `Ref` | - | - | +| `triggerRef` | 浮层的触发元素 | `Ref` | - | - | | `triggerEvents` | 浮层触发元素的事件 | `ComputedRef` | - | - | 需要手动绑定到触发元素上 | -| `popperRef` | 浮层的容器元素 | `Ref` | - | - | +| `popperRef` | 浮层的容器元素 | `Ref` | - | - | | `popperEvents` | 浮层容器容器的事件 | `ComputedRef` | - | - | 需要手动绑定到浮层容器元素上 | -| `arrowRef` | 浮层的箭头元素 | `Ref` | - | - | - | +| `arrowRef` | 浮层的箭头元素 | `Ref` | - | - | - | ```ts diff --git a/packages/cdk/popper/src/hooks.ts b/packages/cdk/popper/src/hooks.ts index 1fa6d8742..08e18a239 100644 --- a/packages/cdk/popper/src/hooks.ts +++ b/packages/cdk/popper/src/hooks.ts @@ -6,20 +6,15 @@ */ import type { PopperEvents, PopperOptions, PopperPlacement, PopperTriggerEvents } from './types' -import type { ComputedRef, Ref } from 'vue' +import type { ComputedRef } from 'vue' import { computed, reactive, ref, watch } from 'vue' import { NoopFunction, NoopObject } from '@idux/cdk/utils' -export function useElement(): Ref { - const element: Ref = ref(null) - return element -} - const defaultDelay = 0 -export function useState(options: PopperOptions): Required { +export function useReactiveOptions(options: PopperOptions): Required { const { allowEnter = true, autoAdjust = true, diff --git a/packages/cdk/popper/src/types.ts b/packages/cdk/popper/src/types.ts index 1fed1ab87..90f0037d1 100644 --- a/packages/cdk/popper/src/types.ts +++ b/packages/cdk/popper/src/types.ts @@ -136,7 +136,7 @@ export interface PopperInstance + triggerRef: Ref /** * Manually bind to the event on the trigger. */ @@ -145,7 +145,7 @@ export interface PopperInstance + popperRef: Ref /** * Manually bind to events on the popper. */ @@ -154,5 +154,5 @@ export interface PopperInstance + arrowRef: Ref } diff --git a/packages/cdk/popper/src/usePopper.ts b/packages/cdk/popper/src/usePopper.ts index 36d4f5bf2..16bb12173 100644 --- a/packages/cdk/popper/src/usePopper.ts +++ b/packages/cdk/popper/src/usePopper.ts @@ -5,12 +5,9 @@ * found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE */ -import type { PopperElement, PopperInstance, PopperOptions } from './types' -import type { Instance } from '@popperjs/core' +import { type WatchStopHandle, ref, watch } from 'vue' -import { WatchStopHandle, watch } from 'vue' - -import { createPopper } from '@popperjs/core' +import { type Instance, createPopper } from '@popperjs/core' import { isEqual } from 'lodash-es' import { convertElement } from '@idux/cdk/utils' @@ -18,14 +15,14 @@ import { convertElement } from '@idux/cdk/utils' import { useBaseOptions, useDelay, - useElement, usePlacement, usePopperEvents, - useState, + useReactiveOptions, useTimer, useTriggerEvents, useVisibility, } from './hooks' +import { type PopperElement, type PopperInstance, type PopperOptions } from './types' import { convertOptions } from './utils' export function usePopper( @@ -33,11 +30,11 @@ export function usePopper { let popperInstance: Instance | null = null - const triggerRef = useElement() - const popperRef = useElement() - const arrowRef = useElement() + const triggerRef = ref() + const popperRef = ref() + const arrowRef = ref() - const state = useState(options) + const state = useReactiveOptions(options) const baseOptions = useBaseOptions(state) const visibility = useVisibility(state) const { placement, updatePlacement } = usePlacement(state) @@ -126,11 +123,15 @@ export function usePopper { - popperInstance?.setOptions( - convertOptions(currBaseOptions, { arrowElement: convertElement(arrowElement), updatePlacement }), - ) - }) + watch( + [baseOptions, arrowRef], + ([currBaseOptions, arrowElement]) => { + popperInstance?.setOptions( + convertOptions(currBaseOptions, { arrowElement: convertElement(arrowElement), updatePlacement }), + ) + }, + { flush: 'post' }, + ) return { visibility, diff --git a/packages/components/_private/overlay/src/Overlay.tsx b/packages/components/_private/overlay/src/Overlay.tsx index c0209733b..5dcc31566 100644 --- a/packages/components/_private/overlay/src/Overlay.tsx +++ b/packages/components/_private/overlay/src/Overlay.tsx @@ -92,16 +92,24 @@ export default defineComponent({ } return () => { - const triggerNode = getFirstValidNode(slots.default?.()) - if (!triggerNode) { + const triggerNodes = slots.default?.() + const triggerNode = getFirstValidNode(triggerNodes) + if (!triggerNode || triggerNodes!.length > 1) { __DEV__ && Logger.warn('components/overlay', 'Trigger must is single rooted node') return null } + const trigger = renderTrigger(props, triggerNode, { ref: triggerRef, ...triggerEvents.value }, handleClickOutside) const contentNode = slots.content?.() if (!getFirstValidNode(contentNode)) { - return triggerNode + // 避免没有 content 时, trigger 被重新创建 + return ( + <> + {trigger} + + + ) } - const trigger = renderTrigger(props, triggerNode, { ref: triggerRef, ...triggerEvents.value }, handleClickOutside) + const content = renderContent( props, mergedPrefixCls, @@ -141,8 +149,8 @@ function renderContent( visibility: ComputedRef, currentZIndex: ComputedRef, contentNode: VNode[], - arrowRef: Ref, - popperRef: Ref, + arrowRef: Ref, + popperRef: Ref, popperEvents: ComputedRef, attrs: Record, ) { diff --git a/packages/components/_private/overlay/style/index.less b/packages/components/_private/overlay/style/index.less index 899c5bc20..31cd9c461 100644 --- a/packages/components/_private/overlay/style/index.less +++ b/packages/components/_private/overlay/style/index.less @@ -17,7 +17,7 @@ bottom: 0; &::before { - bottom: -@overlay-arrow-size + 1px; + bottom: -@overlay-arrow-size; left: 0; border-width: @overlay-arrow-size @overlay-arrow-size 0; border-top-color: initial; @@ -31,7 +31,7 @@ top: 0; &::before { - top: -@overlay-arrow-size + 1px; + top: -@overlay-arrow-size; left: 0; border-width: 0 @overlay-arrow-size @overlay-arrow-size; border-bottom-color: initial; @@ -47,7 +47,7 @@ &::before { border-width: @overlay-arrow-size 0 @overlay-arrow-size @overlay-arrow-size; border-left-color: initial; - right: -@overlay-arrow-size + 1px; + right: -@overlay-arrow-size; transform-origin: center left; } } @@ -58,7 +58,7 @@ left: 0; &::before { - left: -@overlay-arrow-size + 1px; + left: -@overlay-arrow-size; border-width: @overlay-arrow-size @overlay-arrow-size @overlay-arrow-size 0; border-right-color: initial; transform-origin: center right; diff --git a/packages/components/_private/overlay/style/themes/default.variable.less b/packages/components/_private/overlay/style/themes/default.variable.less index 47480a3fb..f22e3dd48 100644 --- a/packages/components/_private/overlay/style/themes/default.variable.less +++ b/packages/components/_private/overlay/style/themes/default.variable.less @@ -1 +1 @@ -@overlay-arrow-size: 8px; +@overlay-arrow-size: 6px; diff --git a/packages/components/dropdown/style/index.less b/packages/components/dropdown/style/index.less index 9cc33cde5..fd2134504 100644 --- a/packages/components/dropdown/style/index.less +++ b/packages/components/dropdown/style/index.less @@ -14,7 +14,7 @@ cursor: pointer; } - .@{idux-prefix}-overlay-arrow { + .@{overlay-prefix}-arrow { color: @dropdown-overlay-arrow-color; } } diff --git a/packages/components/form/demo/CustomizedValidation.vue b/packages/components/form/demo/CustomizedValidation.vue index 85166fd12..8017d9d7f 100644 --- a/packages/components/form/demo/CustomizedValidation.vue +++ b/packages/components/form/demo/CustomizedValidation.vue @@ -1,12 +1,12 @@