import { GestureEngine } from "./gesture.mjs"; import type { Haptics } from "./haptics.mjs"; import type { Transform2D } from "./transform.mjs"; export interface MotionControllerOptions { /** Root element of the dialog; read for opacity writes + rect. */ root: HTMLElement; /** Stage element; GestureEngine + swipe/wheel listeners attach here. */ stage: HTMLElement; /** Read current at gesture time (may be null for non-image slides). */ getCurrentImg: () => HTMLImageElement | null; /** Read current writing direction (LTR / RTL flips swipe). */ getDirection: () => "ltr" | "rtl"; /** Shared haptics engine — MotionController fires doubleTap / snap / dismiss. */ haptics: Haptics; /** Navigation + dismissal callbacks into core. */ onNext: () => void; onPrev: () => void; onDismiss: () => void; } /** * Coordinates GestureEngine, SwipeNavigator and momentum so the * viewer doesn't have to juggle boolean flags across pointerdown / * move / up listeners. Replaces ~300 LOC of state machine scattered * across `viewer.ts` during Phase 1 of the refactor. * * State transitions: * idle → swipeActive (pointerdown at scale=1 over non-interactive) * swipeActive → idle (pointerup / cancel / released) * idle → momentumRunning (release with "cancel" + non-zero delta) * momentumRunning → idle (runMomentum resolves or cancelled) * * The viewer retains ownership of the image element, toolbars and * keyboard routing — it calls `panBy` / `zoomBy` / `zoomReset` from * its own handleKeyDown. */ export declare class MotionController { readonly gesture: GestureEngine; private readonly swipe; private swipeActivePointer; private momentumCancel; private zoomAnimCancel; private readonly opts; constructor(options: MotionControllerOptions); /** * Wire pointer + wheel listeners. Must be called once after * construction — listeners are scoped to the supplied signal so * `destroy()` (which aborts the signal) tears them all down. */ attach(signal: AbortSignal): void; /** Enable GestureEngine pointer tracking — called on viewer open. */ engage(): void; /** Disengage gesture tracking + cancel any running momentum/zoom. */ disengage(): void; [Symbol.dispose](): void; /** Reset gesture transform (used between slides). */ reset(): void; /** Write a transform onto the current image via CSS custom prop. */ writeImgTransform(t: Transform2D): void; /** Write a raw transform string (used by swipe controller). */ writeImgTransformRaw(css: string): void; /** Apply current gesture transform onto a freshly-mounted image. */ applyCurrentTransform(img: HTMLImageElement): void; /** Cancel any in-flight momentum animation. */ cancelMomentum(): void; /** * WCAG 2.5.7 dragging alternative — shift pan translation by a * pixel vector. Called from the viewer's keyboard handler so * users who cannot drag can still reach every corner of a zoomed * image (#25). */ panBy(dx: number, dy: number): void; /** Zoom by a multiplicative factor around the image center. */ zoomBy(factor: number): void; zoomReset(): void; /** Current scale — read by the viewer's keyboard handler for pan branch. */ get scale(): number; /** * Animate a zoom transition using the van Wijk (2003) optimal * zoom-pan curve (#47). Cancels any in-flight zoom animation. * Skips animation when `prefers-reduced-motion: reduce` is active * or when `requestAnimationFrame` is unavailable (SSR / jsdom). */ private animateZoomTo; private handleDoubleTap; private onWheelZoom; private isSwipeEligible; private onSwipeDown; private onSwipeMove; private onSwipeUp; private onSwipeCancel; private resetSwipeVisual; }