From add208aefbe1356b257e43dd5e9a109fe48f0349 Mon Sep 17 00:00:00 2001 From: tangjinzhou <415800467@qq.com> Date: Fri, 3 Mar 2023 16:58:47 +0800 Subject: [PATCH] refactor: float-button --- components/back-top/index.tsx | 2 +- components/components.ts | 11 +-- components/float-button/BackTop.tsx | 15 +++-- components/float-button/FloatButton.tsx | 57 +++++----------- .../float-button/FloatButtonContent.tsx | 27 +++----- components/float-button/FloatButtonGroup.tsx | 67 ++++++++++--------- components/float-button/context.ts | 36 ++++------ components/float-button/demo/back-top.vue | 2 - components/float-button/demo/group.vue | 4 +- components/float-button/index.en-US.md | 17 +++-- components/float-button/index.ts | 2 +- components/float-button/index.zh-CN.md | 23 +++++-- components/float-button/interface.ts | 4 +- components/qrcode/index.en-US.md | 4 +- components/qrcode/index.tsx | 4 +- components/qrcode/index.zh-CN.md | 4 +- components/qrcode/interface.ts | 3 +- 17 files changed, 136 insertions(+), 146 deletions(-) diff --git a/components/back-top/index.tsx b/components/back-top/index.tsx index e7660b0ad..9d9af2526 100644 --- a/components/back-top/index.tsx +++ b/components/back-top/index.tsx @@ -33,7 +33,7 @@ export type BackTopProps = Partial>; const BackTop = defineComponent({ compatConfig: { MODE: 3 }, - name: 'ABackTop', + name: 'ABackTopLegacy', inheritAttrs: false, props: backTopProps(), // emits: ['click'], diff --git a/components/components.ts b/components/components.ts index 0d7040516..bcd3dfeca 100644 --- a/components/components.ts +++ b/components/components.ts @@ -13,9 +13,6 @@ export { default as Alert } from './alert'; export type { AvatarProps } from './avatar'; export { default as Avatar, AvatarGroup } from './avatar'; -export type { BackTopProps } from './back-top'; -export { default as BackTop } from './back-top'; - export type { BadgeProps } from './badge'; export { default as Badge, BadgeRibbon } from './badge'; @@ -76,8 +73,12 @@ export { default as Drawer } from './drawer'; export type { EmptyProps } from './empty'; export { default as Empty } from './empty'; -export type { FloatButtonProps, FloatButtonGroupProps } from './float-button/interface'; -export { default as FloatButton, FloatButtonGroup } from './float-button'; +export type { + FloatButtonProps, + FloatButtonGroupProps, + BackTopProps, +} from './float-button/interface'; +export { default as FloatButton, FloatButtonGroup, BackTop } from './float-button'; export type { FormProps, FormItemProps, FormInstance, FormItemInstance } from './form'; export { default as Form, FormItem, FormItemRest } from './form'; diff --git a/components/float-button/BackTop.tsx b/components/float-button/BackTop.tsx index 3e231cec2..55e0b5466 100644 --- a/components/float-button/BackTop.tsx +++ b/components/float-button/BackTop.tsx @@ -11,16 +11,16 @@ import { watch, onDeactivated, } from 'vue'; -import FloatButton from './FloatButton'; +import FloatButton, { floatButtonPrefixCls } from './FloatButton'; import useConfigInject from '../config-provider/hooks/useConfigInject'; import getScroll from '../_util/getScroll'; import scrollTo from '../_util/scrollTo'; import throttleByAnimationFrame from '../_util/throttleByAnimationFrame'; import { initDefaultProps } from '../_util/props-util'; import { backTopProps } from './interface'; -import { floatButtonPrefixCls } from './FloatButton'; import useStyle from './style'; +import { useInjectFloatButtonGroupContext } from './context'; const BackTop = defineComponent({ compatConfig: { MODE: 3 }, @@ -30,6 +30,8 @@ const BackTop = defineComponent({ visibilityHeight: 400, target: () => window, duration: 450, + type: 'default', + shape: 'circle', }), // emits: ['click'], setup(props, { slots, attrs, emit }) { @@ -39,7 +41,7 @@ const BackTop = defineComponent({ const domRef = ref(); const state = reactive({ - visible: false, + visible: props.visibilityHeight === 0, scrollEvent: null, }); @@ -106,7 +108,7 @@ const BackTop = defineComponent({ onBeforeUnmount(() => { scrollRemove(); }); - + const floatButtonGroupContext = useInjectFloatButtonGroupContext(); return () => { const defaultElement = (
@@ -115,8 +117,9 @@ const BackTop = defineComponent({
); - const divProps = { + const floatButtonProps = { ...attrs, + shape: floatButtonGroupContext?.shape.value || props.shape, onClick: scrollToTop, class: { [`${prefixCls.value}`]: true, @@ -128,7 +131,7 @@ const BackTop = defineComponent({ const transitionProps = getTransitionProps('fade'); return wrapSSR( - + {{ icon: () => , default: () => slots.default?.() || defaultElement, diff --git a/components/float-button/FloatButton.tsx b/components/float-button/FloatButton.tsx index a0f440452..228a4a454 100644 --- a/components/float-button/FloatButton.tsx +++ b/components/float-button/FloatButton.tsx @@ -1,10 +1,9 @@ import classNames from '../_util/classNames'; -import { defineComponent, computed, CSSProperties, ref } from 'vue'; +import { defineComponent, computed, ref } from 'vue'; import Tooltip from '../tooltip'; import Content from './FloatButtonContent'; -import type { FloatButtonContentProps } from './interface'; import useConfigInject from '../config-provider/hooks/useConfigInject'; -import FloatButtonGroupContext from './context'; +import { useInjectFloatButtonGroupContext } from './context'; import warning from '../_util/warning'; import { initDefaultProps } from '../_util/props-util'; import { floatButtonProps } from './interface'; @@ -20,39 +19,30 @@ const FloatButton = defineComponent({ name: 'AFloatButton', inheritAttrs: false, props: initDefaultProps(floatButtonProps(), { type: 'default', shape: 'circle' }), - setup(props, { attrs, slots, expose }) { + setup(props, { attrs, slots }) { const { prefixCls, direction } = useConfigInject(floatButtonPrefixCls, props); const [wrapSSR, hashId] = useStyle(prefixCls); - const { shape: groupShape } = FloatButtonGroupContext.useInject(); + const { shape: groupShape } = useInjectFloatButtonGroupContext(); - const floatButtonRef = ref(null); + const floatButtonRef = ref(null); const mergeShape = computed(() => { return groupShape?.value || props.shape; }); - expose({ - floatButtonEl: floatButtonRef, - }); - return () => { const { prefixCls: customPrefixCls, type = 'default', shape = 'circle', - description, + description = slots.description?.(), tooltip, ...restProps } = props; - const contentProps: FloatButtonContentProps = { - prefixCls: prefixCls.value, - description, - }; - const classString = classNames( prefixCls.value, - `${prefixCls.value}-${props.type}`, + `${prefixCls.value}-${type}`, `${prefixCls.value}-${mergeShape.value}`, { [`${prefixCls.value}-rtl`]: direction.value === 'rtl', @@ -62,24 +52,26 @@ const FloatButton = defineComponent({ ); const buttonNode = ( - - {{ + (slots.tooltip && slots.tooltip()) || tooltip : undefined, default: () => (
- - {{ + description, }} - + >
), }} -
+ >
); if (process.env.NODE_ENV !== 'production') { @@ -92,24 +84,11 @@ const FloatButton = defineComponent({ return wrapSSR( props.href ? ( - + {buttonNode} ) : ( - ), diff --git a/components/float-button/FloatButtonContent.tsx b/components/float-button/FloatButtonContent.tsx index 67a5591ac..699de578f 100644 --- a/components/float-button/FloatButtonContent.tsx +++ b/components/float-button/FloatButtonContent.tsx @@ -1,7 +1,7 @@ import { defineComponent } from 'vue'; import FileTextOutlined from '@ant-design/icons-vue/FileTextOutlined'; -import classNames from '../_util/classNames'; import { floatButtonContentProps } from './interface'; +import { filterEmpty } from '../_util/props-util'; const FloatButtonContent = defineComponent({ compatConfig: { MODE: 3 }, @@ -10,27 +10,22 @@ const FloatButtonContent = defineComponent({ props: floatButtonContentProps(), setup(props, { attrs, slots }) { return () => { - const { description, prefixCls } = props; - - const defaultElement = ( -
- -
- ); + const { prefixCls } = props; + const description = filterEmpty(slots.description?.()); return ( -
- {slots.icon || description ? ( +
+ {slots.icon || description.length ? ( <> {slots.icon &&
{slots.icon()}
} - {(slots.description || description) && ( -
- {(slots.description && slots.description()) || description} -
- )} + {description.length ? ( +
{description}
+ ) : null} ) : ( - defaultElement +
+ +
)}
); diff --git a/components/float-button/FloatButtonGroup.tsx b/components/float-button/FloatButtonGroup.tsx index f80c6bc94..12c18e6f6 100644 --- a/components/float-button/FloatButtonGroup.tsx +++ b/components/float-button/FloatButtonGroup.tsx @@ -1,17 +1,18 @@ -import { defineComponent, ref, computed, watch } from 'vue'; +import { defineComponent, ref, computed, watch, onBeforeUnmount } from 'vue'; import CloseOutlined from '@ant-design/icons-vue/CloseOutlined'; import FileTextOutlined from '@ant-design/icons-vue/FileTextOutlined'; import classNames from '../_util/classNames'; import { getTransitionProps, Transition } from '../_util/transition'; import FloatButton, { floatButtonPrefixCls } from './FloatButton'; import useConfigInject from '../config-provider/hooks/useConfigInject'; -import FloatButtonGroupContext from './context'; -import { initDefaultProps } from '../_util/props-util'; +import { useProvideFloatButtonGroupContext } from './context'; +import { findDOMNode, initDefaultProps } from '../_util/props-util'; import { floatButtonGroupProps } from './interface'; import type { FloatButtonGroupProps } from './interface'; // CSSINJS import useStyle from './style'; +import useMergedState from '../_util/hooks/useMergedState'; const FloatButtonGroup = defineComponent({ compatConfig: { MODE: 3 }, @@ -21,63 +22,68 @@ const FloatButtonGroup = defineComponent({ type: 'default', shape: 'circle', } as FloatButtonGroupProps), - setup(props, { attrs, slots }) { + setup(props, { attrs, slots, emit }) { const { prefixCls, direction } = useConfigInject(floatButtonPrefixCls, props); // style const [wrapSSR, hashId] = useStyle(prefixCls); - const open = ref(props.open); + const [open, setOpen] = useMergedState(false, { value: computed(() => props.open) }); const floatButtonGroupRef = ref(null); const floatButtonRef = ref(null); - FloatButtonGroupContext.useProvide({ + useProvideFloatButtonGroupContext({ shape: computed(() => props.shape), }); - + const hoverTypeAction = { + onMouseenter() { + setOpen(true); + emit('update:open', true); + props.onOpenChange?.(true); + }, + onMouseleave() { + setOpen(false); + emit('update:open', false); + props.onOpenChange?.(false); + }, + }; const hoverAction = computed(() => { - const hoverTypeAction = { - onMouseenter() { - open.value = true; - props.onOpenChange?.(true); - }, - onMouseleave() { - open.value = false; - props.onOpenChange?.(false); - }, - }; return props.trigger === 'hover' ? hoverTypeAction : {}; }); const handleOpenChange = () => { - open.value = !open.value; - props.onOpenChange?.(!open.value); + const nextOpen = !open.value; + emit('update:open', nextOpen); + props.onOpenChange?.(nextOpen); + setOpen(nextOpen); }; const onClick = (e: MouseEvent) => { if (floatButtonGroupRef.value?.contains(e.target as Node)) { - if ((floatButtonRef.value as any)?.floatButtonEl?.contains(e.target as Node)) { + if (findDOMNode(floatButtonRef.value)?.contains(e.target as Node)) { handleOpenChange(); } return; } - open.value = false; + setOpen(false); + emit('update:open', false); props.onOpenChange?.(false); }; watch( computed(() => props.trigger), value => { + document.removeEventListener('click', onClick); if (value === 'click') { document.addEventListener('click', onClick); - return () => { - document.removeEventListener('click', onClick); - }; } }, { immediate: true }, ); + onBeforeUnmount(() => { + document.removeEventListener('click', onClick); + }); return () => { const { shape = 'circle', type = 'default', tooltip, description, trigger } = props; @@ -99,7 +105,7 @@ const FloatButtonGroup = defineComponent({ {trigger && ['click', 'hover'].includes(trigger) ? ( <> -
+
{slots.default && slots.default()}
@@ -109,19 +115,18 @@ const FloatButtonGroup = defineComponent({ shape={shape} tooltip={tooltip} description={description} - > - {{ + v-slots={{ icon: () => open.value - ? (slots.closeIcon && slots.closeIcon()) || - : (slots.icon && slots.icon()) || , + ? slots.closeIcon?.() || + : slots.icon?.() || , tooltip: slots.tooltip, description: slots.description, }} - + > ) : ( - slots.default && slots.default() + slots.default?.() )}
, ); diff --git a/components/float-button/context.ts b/components/float-button/context.ts index ef9aeeeb1..3882a9d65 100644 --- a/components/float-button/context.ts +++ b/components/float-button/context.ts @@ -1,29 +1,19 @@ -import type { Ref } from 'vue'; -import { inject, provide } from 'vue'; +import type { Ref, InjectionKey } from 'vue'; +import { inject, provide, ref } from 'vue'; import type { FloatButtonShape } from './interface'; -function createContext>(defaultValue?: T) { - const contextKey = Symbol('floatButtonGroupContext'); - - const useProvide = (props: T) => { - provide(contextKey, props); - - return props; - }; - - const useInject = () => { - return inject(contextKey, defaultValue as T) || ({} as T); - }; - - return { - useProvide, - useInject, - }; +interface FloatButtonGroupContext { + shape: Ref; } +const contextKey: InjectionKey = Symbol('floatButtonGroupContext'); -const FloatButtonGroupContext = createContext<{ shape: Ref } | undefined>( - undefined, -); +export const useProvideFloatButtonGroupContext = (props: FloatButtonGroupContext) => { + provide(contextKey, props); -export default FloatButtonGroupContext; + return props; +}; + +export const useInjectFloatButtonGroupContext = () => { + return inject(contextKey, { shape: ref() } as FloatButtonGroupContext); +}; diff --git a/components/float-button/demo/back-top.vue b/components/float-button/demo/back-top.vue index f0befadd5..61846bd16 100644 --- a/components/float-button/demo/back-top.vue +++ b/components/float-button/demo/back-top.vue @@ -32,10 +32,8 @@ title: