import { describe, expect, it } from "vitest"; import { clampPanelPlacementToViewport, resolvePanelSnapPlacement, resolvePanelSnapPosition, } from "./panel-host-geometry"; import type { PanelViewport } from "./panel-host-types"; const viewport = { height: 500, offsetLeft: 0, offsetTop: 0, width: 800, } satisfies PanelViewport; const dimensions = { height: 100, width: 200, }; describe("resolvePanelSnapPosition", () => { it("returns semantic placement while preserving the position projection", () => { const input = { dimensions, edges: ["left", "right"] as const, position: { x: 12, y: 80 }, velocity: { x: 0, y: 0 }, viewport, }; expect(resolvePanelSnapPlacement(input)).toEqual({ offset: { x: 10, y: 80 }, snapEdge: "left", }); expect(resolvePanelSnapPosition(input)).toEqual({ x: 10, y: 80 }); }); it("snaps a side panel to the left edge", () => { expect( resolvePanelSnapPosition({ dimensions, edges: ["left", "right"], position: { x: 12, y: 80 }, velocity: { x: 0, y: 0 }, viewport, }), ).toEqual({ x: 10, y: 80 }); }); it("snaps a top or bottom panel to the bottom edge", () => { expect( resolvePanelSnapPosition({ dimensions, edges: ["top", "bottom"], position: { x: 160, y: 360 }, velocity: { x: 0, y: 0 }, viewport, }), ).toEqual({ x: 160, y: 390 }); }); it("returns null when the panel is outside the snap zone", () => { expect( resolvePanelSnapPosition({ dimensions, edges: ["left"], position: { x: 120, y: 80 }, velocity: { x: 0, y: 0 }, viewport, }), ).toBeNull(); }); it("clamps snapped panel positions inside the viewport", () => { expect( resolvePanelSnapPosition({ dimensions, edges: ["top"], position: { x: -100, y: 4 }, velocity: { x: 0, y: 0 }, viewport, }), ).toEqual({ x: 10, y: 10 }); }); it("clamps restored translation offsets to the current viewport", () => { expect( clampPanelPlacementToViewport({ dimensions, origin: { x: 100, y: 50 }, placement: { offset: { x: 900, y: -200 }, snapEdge: "right", }, viewport, }), ).toEqual({ offset: { x: 490, y: -40 }, snapEdge: "right", }); }); });