import { describe, expect, test } from "bun:test"; import { commandIds } from "@commands/ids"; import { toolCommands } from "@commands/tool"; import { viewportCommands } from "@commands/viewport"; import { createCommandRegistry } from "@commands/registry"; import { createInitialAppState } from "@editor/initial-state"; import { createAppStore } from "@editor/store"; import type { PointerInputEvent } from "./pointer"; import { createViewportPanInputController } from "./viewport-pan"; const registry = createCommandRegistry([...toolCommands, ...viewportCommands]); describe("viewport pan store integration", () => { test("space key input updates actual store tool mode", () => { const store = createAppStore(createInitialAppState("Test"), registry); const controller = createController(store); expect(controller.keyDown(keyEvent("Space"))).toBe(true); expect(store.getState().editor.tools.interactionMode).toEqual({ type: "temporary-pan", previousTool: "select" }); expect(controller.keyUp(keyEvent("Space"))).toBe(true); expect(store.getState().editor.tools.interactionMode).toEqual({ type: "tool", tool: "select" }); }); test("left-drag only pans while temporary pan is active", () => { const store = createAppStore(createInitialAppState("Test"), registry); const controller = createController(store); expect(controller.pointerDown(pointerEvent({ buttons: 1, position: { x: 0, y: 0 } }))).toBe(false); expect(controller.pointerMove(pointerEvent({ buttons: 1, position: { x: 10, y: 0 } }))).toBe(false); expect(store.getState().editor.viewport.center).toEqual({ x: 0, y: 0 }); store.dispatch(commandIds.toolEnterTemporaryPan, undefined); expect(controller.pointerDown(pointerEvent({ buttons: 1, position: { x: 0, y: 0 } }))).toBe(true); expect(controller.pointerMove(pointerEvent({ buttons: 1, position: { x: 10, y: 0 } }))).toBe(true); expect(store.getState().editor.viewport.center).toEqual({ x: -10, y: 0 }); }); test("left-drag pans while pan tool is active", () => { const store = createAppStore(createInitialAppState("Test"), registry); const controller = createController(store); store.dispatch(commandIds.toolSetActive, { tool: "pan" }); expect(controller.pointerDown(pointerEvent({ buttons: 1, position: { x: 0, y: 0 } }))).toBe(true); expect(controller.pointerMove(pointerEvent({ buttons: 1, position: { x: 4, y: -2 } }))).toBe(true); expect(store.getState().editor.viewport.center).toEqual({ x: -4, y: 2 }); }); }); function createController(store: ReturnType) { return createViewportPanInputController({ globalKeyConsumer: () => false, globalPointerConsumer: () => false, getCurrentZoom: () => store.getState().editor.viewport.zoom, isPanMode: () => { const mode = store.getState().editor.tools.interactionMode; return mode.type === "temporary-pan" || (mode.type === "tool" && mode.tool === "pan"); }, dispatch: store.dispatch, }); } function keyEvent(code: string) { return { key: code === "Space" ? " " : code, code, altKey: false, ctrlKey: false, metaKey: false, shiftKey: false }; } function pointerEvent(overrides: Partial): PointerInputEvent { return { pointerId: 1, pointerType: "mouse", position: { x: 0, y: 0 }, buttons: 0, altKey: false, ctrlKey: false, metaKey: false, shiftKey: false, ...overrides, }; }