import type { Transform2D } from "./transform.mjs"; export type GestureEventType = "start" | "pan" | "pinch" | "end" | "tap" | "doubleTap"; export interface GestureSnapshot { type: GestureEventType; transform: Transform2D; delta?: { dx: number; dy: number; }; swipe?: { direction: "up" | "down" | "left" | "right"; velocity: number; }; } export interface GestureEngineOptions { /** Clamp the output scale to this range. Default [1, 8]. */ minScale?: number; maxScale?: number; /** Tap threshold in pixels. Default 8. */ tapThreshold?: number; /** Tap timeout in ms. Default 250. */ tapTimeout?: number; /** Double-tap window in ms. Default 300. */ doubleTapWindow?: number; /** Emit callback with every gesture update. */ onUpdate?: (snapshot: GestureSnapshot) => void; } /** * A small Pointer Events-based gesture engine shared by the lightbox. * * Responsibilities: * - unify mouse/touch/pen into a single pipeline via Pointer Events * - pan with one pointer * - pinch-zoom around the centroid with two pointers * - tap / double-tap detection with configurable thresholds * * Swipe / drag-to-dismiss / momentum live in a higher-level controller * (next commit) so this class stays focused and testable. */ export declare class GestureEngine { private readonly el; private readonly opts; private readonly pointers; private transform; private lastPinchDistance; private lastTap; /** * rAF throttle state (#34). pointermove fires at the device sample * rate — on modern iPads that can be 120 Hz while the display only * commits at 60 Hz, wasting ~half of the transform work. We coalesce * all moves received within one frame into a single emit. */ private rafId; private pendingEmit; private readonly onPointerDown; private readonly onPointerMove; private readonly onPointerUp; private readonly onPointerCancel; constructor(el: HTMLElement, opts?: GestureEngineOptions); private attached; private detachController; attach(): void; detach(): void; [Symbol.dispose](): void; reset(): void; /** Visible for tests: force-drain the rAF queue synchronously. */ flushPendingEmit(): void; get current(): Transform2D; /** * Programmatically set the transform (used by wheel zoom, double-tap * zoom, and other non-pointer sources). Emits a synthetic pinch event * so the viewer can repaint. */ setTransform(t: Transform2D): void; /** Public for tests: inject synthetic pointer events. */ handleDown(e: PointerEvent): void; handleMove(e: PointerEvent): void; /** * Schedule a single emit on the next animation frame. Subsequent * pointermove events that arrive inside the same frame overwrite * the pending snapshot (pinch) or accumulate the delta (pan), so * the caller always sees the freshest transform per display commit. */ private queueEmit; private cancelPendingEmit; handleUp(e: PointerEvent): void; private emit; }