From d739f678b48b49da16235d351267270397578371 Mon Sep 17 00:00:00 2001 From: Wei-Liang Liou Date: Sun, 13 Apr 2025 17:20:59 +0800 Subject: [PATCH] feat(FloatingBubble): allow gap xy to be set separately (#13297) (#13429) Co-authored-by: neverland --- .../src/floating-bubble/FloatingBubble.tsx | 28 +++++++++++++------ packages/vant/src/floating-bubble/README.md | 2 +- .../vant/src/floating-bubble/README.zh-CN.md | 2 +- .../src/floating-bubble/test/index.spec.ts | 27 ++++++++++++++++++ packages/vant/src/floating-bubble/types.ts | 7 +++++ 5 files changed, 55 insertions(+), 11 deletions(-) diff --git a/packages/vant/src/floating-bubble/FloatingBubble.tsx b/packages/vant/src/floating-bubble/FloatingBubble.tsx index 52e859c86..d2441f38e 100644 --- a/packages/vant/src/floating-bubble/FloatingBubble.tsx +++ b/packages/vant/src/floating-bubble/FloatingBubble.tsx @@ -20,7 +20,7 @@ import { addUnit, closest, createNamespace, - makeNumberProp, + isObject, makeStringProp, windowWidth, windowHeight, @@ -38,11 +38,15 @@ import { FloatingBubbleAxis, FloatingBubbleMagnetic, FloatingBubbleOffset, + FloatingBubbleGap, FloatingBubbleBoundary, } from './types'; export const floatingBubbleProps = { - gap: makeNumberProp(24), + gap: { + type: [Number, Object] as unknown as PropType, + default: 24, + }, icon: String, axis: makeStringProp('y'), magnetic: String as PropType, @@ -79,11 +83,17 @@ export default defineComponent({ height: 0, }); + const gapX = computed(() => + isObject(props.gap) ? props.gap.x : props.gap, + ); + const gapY = computed(() => + isObject(props.gap) ? props.gap.y : props.gap, + ); const boundary = computed(() => ({ - top: props.gap, - right: windowWidth.value - state.value.width - props.gap, - bottom: windowHeight.value - state.value.height - props.gap, - left: props.gap, + top: gapY.value, + right: windowWidth.value - state.value.width - gapX.value, + bottom: windowHeight.value - state.value.height - gapY.value, + left: gapX.value, })); const dragging = ref(false); @@ -110,8 +120,8 @@ export default defineComponent({ const { width, height } = useRect(rootRef.value!); const { offset } = props; state.value = { - x: offset.x > -1 ? offset.x : windowWidth.value - width - props.gap, - y: offset.y > -1 ? offset.y : windowHeight.value - height - props.gap, + x: offset.x > -1 ? offset.x : windowWidth.value - width - gapX.value, + y: offset.y > -1 ? offset.y : windowHeight.value - height - gapY.value, width, height, }; @@ -203,7 +213,7 @@ export default defineComponent({ }); watch( - [windowWidth, windowHeight, () => props.gap, () => props.offset], + [windowWidth, windowHeight, gapX, gapY, () => props.offset], updateState, { deep: true }, ); diff --git a/packages/vant/src/floating-bubble/README.md b/packages/vant/src/floating-bubble/README.md index 2b4fa65c1..25d05ca9b 100644 --- a/packages/vant/src/floating-bubble/README.md +++ b/packages/vant/src/floating-bubble/README.md @@ -94,7 +94,7 @@ export default { | axis | Drag direction, `xy` stands for free drag, `lock` stands for disable drag | _'x' \| 'y' \| 'xy' \| 'lock'_ | `y` | | magnetic | Direction of automatic magnetic absorption | _'x' \| 'y'_ | - | | icon | Bubble icon | _string_ | - | -| gap | Minimum gap between the bubble and the window, unit `px` | _number_ | `24` | +| gap | Minimum gap between the bubble and the window, unit `px` | _number \| { x: number, y: number }_ | `24` | | teleport | Specifies a target element where BackTop will be mounted | _string \| Element_ | `body` | ### Events diff --git a/packages/vant/src/floating-bubble/README.zh-CN.md b/packages/vant/src/floating-bubble/README.zh-CN.md index 7098cc7f4..f252d932e 100644 --- a/packages/vant/src/floating-bubble/README.zh-CN.md +++ b/packages/vant/src/floating-bubble/README.zh-CN.md @@ -94,7 +94,7 @@ export default { | axis | 拖拽的方向,`xy` 代表自由拖拽,`lock` 代表禁止拖拽 | _'x' \| 'y' \| 'xy' \| 'lock'_ | `y` | | magnetic | 自动磁吸的方向 | _'x' \| 'y'_ | - | | icon | 气泡图标名称或图片链接,等同于 Icon 组件的 [name 属性](#/zh-CN/icon#props) | _string_ | - | -| gap | 气泡与窗口的最小间距,单位为 `px` | _number_ | `24` | +| gap | 气泡与窗口的最小间距,单位为 `px` | _number \| { x: number, y: number }_ | `24` | | teleport | 指定挂载的节点,等同于 Teleport 组件的 [to 属性](https://cn.vuejs.org/api/built-in-components.html#teleport) | _string \| Element_ | `body` | ### Events diff --git a/packages/vant/src/floating-bubble/test/index.spec.ts b/packages/vant/src/floating-bubble/test/index.spec.ts index 40a06c2f8..c51c105d2 100644 --- a/packages/vant/src/floating-bubble/test/index.spec.ts +++ b/packages/vant/src/floating-bubble/test/index.spec.ts @@ -62,6 +62,33 @@ test('should render correctly when all props set', async () => { restore(); }); +test('should render with xy gaps', async () => { + useWindowSize(); + const restore = mockGetBoundingClientRect({ width: 48, height: 48 }); + + const root = document.createElement('div'); + mount(FloatingBubble, { + props: { + teleport: root, + gap: { x: 50, y: 27 }, + }, + }); + + const floatingBubbleEl = root.querySelector( + '.van-floating-bubble', + )!; + + await later(); + + expect(floatingBubbleEl.style.transform).toEqual( + `translate3d(${window.innerWidth - 48 - 50}px, ${ + window.innerHeight - 48 - 27 + }px, 0)`, + ); + + restore(); +}); + test('should only y axis direction move when axis is default', async () => { const restore = mockGetBoundingClientRect({ width: 48, height: 48 }); diff --git a/packages/vant/src/floating-bubble/types.ts b/packages/vant/src/floating-bubble/types.ts index 852ccaa7e..4b63ebd26 100644 --- a/packages/vant/src/floating-bubble/types.ts +++ b/packages/vant/src/floating-bubble/types.ts @@ -16,6 +16,13 @@ export type FloatingBubbleOffset = { y: number; }; +export type FloatingBubbleGap = + | number + | { + x: number; + y: number; + }; + export type FloatingBubbleBoundary = { top: number; right: number;