fix(sidebar): keep tooltips within the viewport
This commit is contained in:
3 files changed
+76
-3
No files matched your search
@@ -0,0 +1,22 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { floatingArrowOffset, floatingViewportShift } from "@/lib/common/floatingViewportPosition";
|
||||
|
||||
describe("floating viewport position", () => {
|
||||
it("moves a floating element inside each viewport edge", () => {
|
||||
expect(floatingViewportShift({ left: -24, right: 296, top: 40, bottom: 80 }, { width: 800, height: 600 })).toEqual({ x: 32, y: 0 });
|
||||
expect(floatingViewportShift({ left: 600, right: 840, top: 40, bottom: 80 }, { width: 800, height: 600 })).toEqual({ x: -48, y: 0 });
|
||||
expect(floatingViewportShift({ left: 40, right: 240, top: -12, bottom: 28 }, { width: 800, height: 600 })).toEqual({ x: 0, y: 20 });
|
||||
expect(floatingViewportShift({ left: 40, right: 240, top: 570, bottom: 620 }, { width: 800, height: 600 })).toEqual({ x: 0, y: -28 });
|
||||
});
|
||||
|
||||
it("does not move an element that already fits", () => {
|
||||
expect(floatingViewportShift({ left: 8, right: 792, top: 8, bottom: 592 }, { width: 800, height: 600 })).toEqual({ x: 0, y: 0 });
|
||||
});
|
||||
|
||||
it("keeps the arrow pointing at the trigger after shifting the floating element", () => {
|
||||
expect(floatingArrowOffset(320, 32)).toBe(128);
|
||||
expect(floatingArrowOffset(320, -48)).toBe(208);
|
||||
expect(floatingArrowOffset(40, 100)).toBe(8);
|
||||
expect(floatingArrowOffset(40, -100)).toBe(32);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
export interface FloatingRect {
|
||||
left: number;
|
||||
right: number;
|
||||
top: number;
|
||||
bottom: number;
|
||||
}
|
||||
|
||||
export interface FloatingViewport {
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
export function floatingViewportShift(rect: FloatingRect, viewport: FloatingViewport, margin = 8): { x: number; y: number } {
|
||||
let x = 0;
|
||||
let y = 0;
|
||||
|
||||
if (rect.left < margin) x = margin - rect.left;
|
||||
else if (rect.right > viewport.width - margin) x = viewport.width - margin - rect.right;
|
||||
|
||||
if (rect.top < margin) y = margin - rect.top;
|
||||
else if (rect.bottom > viewport.height - margin) y = viewport.height - margin - rect.bottom;
|
||||
|
||||
return { x, y };
|
||||
}
|
||||
|
||||
export function floatingArrowOffset(length: number, shift: number, padding = 8): number {
|
||||
const maximum = Math.max(padding, length - padding);
|
||||
return Math.min(Math.max(padding, length / 2 - shift), maximum);
|
||||
}
|
||||
Reference in new issue
Block a user