fix(FloatingBubble): should handle negative gap values (#13544)

This commit is contained in:
inottn
2025-07-05 13:43:43 +08:00
committed by GitHub
parent c1afa74945
commit a61ed0e61d
2 changed files with 89 additions and 59 deletions

View File

@@ -44,16 +44,13 @@ import {
export const floatingBubbleProps = {
gap: {
type: [Number, Object] as unknown as PropType<FloatingBubbleGap>,
type: [Number, Object] as PropType<FloatingBubbleGap>,
default: 24,
},
icon: String,
axis: makeStringProp<FloatingBubbleAxis>('y'),
magnetic: String as PropType<FloatingBubbleMagnetic>,
offset: {
type: Object as unknown as PropType<FloatingBubbleOffset>,
default: () => ({ x: -1, y: -1 }),
},
offset: Object as PropType<FloatingBubbleOffset>,
teleport: {
type: [String, Object] as PropType<TeleportProps['to']>,
default: 'body',
@@ -120,8 +117,8 @@ export default defineComponent({
const { width, height } = useRect(rootRef.value!);
const { offset } = props;
state.value = {
x: offset.x > -1 ? offset.x : windowWidth.value - width - gapX.value,
y: offset.y > -1 ? offset.y : windowHeight.value - height - gapY.value,
x: offset ? offset.x : windowWidth.value - width - gapX.value,
y: offset ? offset.y : windowHeight.value - height - gapY.value,
width,
height,
};

View File

@@ -9,9 +9,16 @@ import {
triggerDrag,
} from '../../../test';
const bubbleWidth = 48;
const bubbleHeight = 48;
const defaultGap = 24;
test('should render correctly when all props set', async () => {
useWindowSize();
const restore = mockGetBoundingClientRect({ width: 48, height: 48 });
const restore = mockGetBoundingClientRect({
width: bubbleWidth,
height: bubbleHeight,
});
const root = document.createElement('div');
const wrapper = mount(FloatingBubble, {
@@ -27,8 +34,8 @@ test('should render correctly when all props set', async () => {
await later();
expect(floatingBubbleEl.style.transform).toEqual(
`translate3d(${window.innerWidth - 48 - 24}px, ${
window.innerHeight - 48 - 24
`translate3d(${window.innerWidth - bubbleWidth - defaultGap}px, ${
window.innerHeight - bubbleHeight - defaultGap
}px, 0)`,
);
@@ -37,8 +44,8 @@ test('should render correctly when all props set', async () => {
});
expect(floatingBubbleEl.style.transform).toEqual(
`translate3d(${window.innerWidth - 48 - 50}px, ${
window.innerHeight - 48 - 50
`translate3d(${window.innerWidth - bubbleWidth - 50}px, ${
window.innerHeight - bubbleHeight - 50
}px, 0)`,
);
@@ -64,7 +71,10 @@ test('should render correctly when all props set', async () => {
test('should render with xy gaps', async () => {
useWindowSize();
const restore = mockGetBoundingClientRect({ width: 48, height: 48 });
const restore = mockGetBoundingClientRect({
width: bubbleWidth,
height: bubbleHeight,
});
const root = document.createElement('div');
mount(FloatingBubble, {
@@ -81,8 +91,8 @@ test('should render with xy gaps', async () => {
await later();
expect(floatingBubbleEl.style.transform).toEqual(
`translate3d(${window.innerWidth - 48 - 50}px, ${
window.innerHeight - 48 - 27
`translate3d(${window.innerWidth - bubbleWidth - 50}px, ${
window.innerHeight - bubbleHeight - 27
}px, 0)`,
);
@@ -90,7 +100,10 @@ test('should render with xy gaps', async () => {
});
test('should only y axis direction move when axis is default', async () => {
const restore = mockGetBoundingClientRect({ width: 48, height: 48 });
const restore = mockGetBoundingClientRect({
width: bubbleWidth,
height: bubbleHeight,
});
const root = document.createElement('div');
mount(FloatingBubble, {
@@ -106,16 +119,19 @@ test('should only y axis direction move when axis is default', async () => {
await triggerDrag(floatingBubbleEl, -100, -100);
expect(floatingBubbleEl.style.transform).toEqual(
`translate3d(${window.innerWidth - 48 - 24}px, ${
window.innerHeight - 48 - 24 - 100
`translate3d(${window.innerWidth - bubbleWidth - defaultGap}px, ${
window.innerHeight - bubbleHeight - defaultGap - 100
}px, 0)`,
);
restore();
});
test('should only x axis direction adn emit offsetChange move when axis is "x" ', async () => {
const restore = mockGetBoundingClientRect({ width: 48, height: 48 });
test('should only x axis direction and emit offsetChange move when axis is "x"', async () => {
const restore = mockGetBoundingClientRect({
width: bubbleWidth,
height: bubbleHeight,
});
const root = document.createElement('div');
const wrapper = mount(FloatingBubble, {
@@ -132,8 +148,8 @@ test('should only x axis direction adn emit offsetChange move when axis is "x" '
await triggerDrag(floatingBubbleEl, -100, -100);
expect(floatingBubbleEl.style.transform).toEqual(
`translate3d(${window.innerWidth - 48 - 24 - 100}px, ${
window.innerHeight - 48 - 24
`translate3d(${window.innerWidth - bubbleWidth - defaultGap - 100}px, ${
window.innerHeight - bubbleHeight - defaultGap
}px, 0)`,
);
@@ -145,8 +161,11 @@ test('should only x axis direction adn emit offsetChange move when axis is "x" '
restore();
});
test('should free direction move when axis is "xy" ', async () => {
const restore = mockGetBoundingClientRect({ width: 48, height: 48 });
test('should free direction move when axis is "xy"', async () => {
const restore = mockGetBoundingClientRect({
width: bubbleWidth,
height: bubbleHeight,
});
const root = document.createElement('div');
mount(FloatingBubble, {
@@ -163,44 +182,21 @@ test('should free direction move when axis is "xy" ', async () => {
await triggerDrag(floatingBubbleEl, -100, -100);
expect(floatingBubbleEl.style.transform).toEqual(
`translate3d(${window.innerWidth - 48 - 24 - 100}px, ${
window.innerHeight - 48 - 24 - 100
`translate3d(${window.innerWidth - bubbleWidth - defaultGap - 100}px, ${
window.innerHeight - bubbleHeight - defaultGap - 100
}px, 0)`,
);
restore();
});
test('should free direction move when axis is "xy" ', async () => {
const restore = mockGetBoundingClientRect({ width: 48, height: 48 });
const root = document.createElement('div');
mount(FloatingBubble, {
props: {
teleport: root,
axis: 'xy',
},
});
const floatingBubbleEl = root.querySelector<HTMLDivElement>(
'.van-floating-bubble',
)!;
await triggerDrag(floatingBubbleEl, -100, -100);
expect(floatingBubbleEl.style.transform).toEqual(
`translate3d(${window.innerWidth - 48 - 24 - 100}px, ${
window.innerHeight - 48 - 24 - 100
}px, 0)`,
);
restore();
});
test('should free direction move and magnetic to x axios when magnetic is "x" ', async () => {
test('should free direction move and magnetic to x axis when magnetic is "x" ', async () => {
vi.useFakeTimers();
const restore = mockGetBoundingClientRect({ width: 48, height: 48 });
const restore = mockGetBoundingClientRect({
width: bubbleWidth,
height: bubbleHeight,
});
const root = document.createElement('div');
mount(FloatingBubble, {
props: {
@@ -218,8 +214,8 @@ test('should free direction move and magnetic to x axios when magnetic is "x" '
await vi.advanceTimersByTimeAsync(400);
expect(floatingBubbleEl.style.transform).toEqual(
`translate3d(${window.innerWidth - 48 - 24}px, ${
window.innerHeight - 48 - 24 - 100
`translate3d(${window.innerWidth - bubbleWidth - defaultGap}px, ${
window.innerHeight - bubbleHeight - defaultGap - 100
}px, 0)`,
);
@@ -227,17 +223,20 @@ test('should free direction move and magnetic to x axios when magnetic is "x" '
await vi.advanceTimersByTimeAsync(400);
expect(floatingBubbleEl.style.transform).toEqual(
`translate3d(${24}px, ${window.innerHeight - 48 - 24 - 200}px, 0)`,
`translate3d(${defaultGap}px, ${window.innerHeight - bubbleHeight - defaultGap - 200}px, 0)`,
);
restore();
vi.useRealTimers();
});
test('should offset control positioning when use v-model:offset ', async () => {
test('should offset control positioning when use v-model:offset', async () => {
vi.useFakeTimers();
const restore = mockGetBoundingClientRect({ width: 48, height: 48 });
const restore = mockGetBoundingClientRect({
width: bubbleWidth,
height: bubbleHeight,
});
const root = document.createElement('div');
const wrapper = mount(FloatingBubble, {
props: {
@@ -290,3 +289,37 @@ test('should emit click when click wrapper', async () => {
expect(wrapper.emitted('click')).toBeFalsy();
});
test('should handle negative gap values', async () => {
const restore = mockGetBoundingClientRect({
width: bubbleWidth,
height: bubbleHeight,
});
const root = document.createElement('div');
mount(FloatingBubble, {
props: {
teleport: root,
axis: 'xy',
gap: -10,
},
});
const floatingBubbleEl = root.querySelector<HTMLDivElement>(
'.van-floating-bubble',
)!;
await triggerDrag(floatingBubbleEl, -1000, -1000);
expect(floatingBubbleEl.style.transform).toEqual(
`translate3d(-10px, -10px, 0)`,
);
await triggerDrag(floatingBubbleEl, 1000, 1000);
expect(floatingBubbleEl.style.transform).toEqual(
`translate3d(${window.innerWidth - bubbleWidth + 10}px, ${window.innerHeight - bubbleHeight + 10}px, 0)`,
);
restore();
});