{"version":3,"file":"useZoomPan.mjs","names":[],"sources":["../../../src/Image/viewer/useZoomPan.ts"],"sourcesContent":["import type { MotionValue } from 'motion/react';\nimport { animate, motionValue } from 'motion/react';\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\nimport type { Point, Rect, Rotation, Size, TransformState, ZoomPolicy } from './geometry';\nimport {\n  anchoredZoom,\n  clampPan,\n  clampScale,\n  computeFit,\n  DEFAULT_AUTO_ZOOM_THRESHOLD,\n  DEFAULT_MAX_SCALE,\n  doubleClickTarget,\n  MIN_SCALE,\n  naturalScale,\n  normalizeRotation,\n  normalizeWheelDelta,\n  panBounds,\n  resolveInitialScale,\n  rubberBand,\n  wheelZoomFactor,\n} from './geometry';\n\nconst WHEEL_CLOSE_THRESHOLD = 100;\nconst WHEEL_IDLE_MS = 300;\nconst ZOOM_STEP = 1.5;\nconst RESET_TRANSITION = { damping: 30, stiffness: 300, type: 'spring' as const };\nconst CLEAN_EPSILON = 0.01;\n\nexport interface WheelLikeEvent {\n  clientX: number;\n  clientY: number;\n  ctrlKey?: boolean;\n  deltaMode?: number;\n  deltaY: number;\n  metaKey?: boolean;\n  preventDefault?: () => void;\n}\n\nexport interface UseZoomPanOptions {\n  autoZoomThreshold?: number;\n  defaultZoom?: ZoomPolicy;\n  fillViewport?: boolean;\n  isClosing?: () => boolean;\n  isTransitioning?: () => boolean;\n  maxScale?: number;\n  natural: Size;\n  onCloseRequest?: () => void;\n  viewport: Size;\n}\n\nexport interface UseZoomPanResult {\n  canZoomIn: boolean;\n  canZoomOut: boolean;\n  dragBy: (delta: Point) => void;\n  dragEnd: () => void;\n  escIntent: () => 'reset' | 'close';\n  flipHorizontal: () => void;\n  flipVertical: () => void;\n  flipX: MotionValue<boolean>;\n  flipY: MotionValue<boolean>;\n  getInitialScale: () => number;\n  handleDoubleClick: (point: Point) => void;\n  handleWheel: (event: WheelLikeEvent) => void;\n  isClean: boolean;\n  isZoomed: boolean;\n  reset: () => void;\n  resetCloseTracking: () => void;\n  rotate: MotionValue<number>;\n  rotateLeft: () => void;\n  rotateRight: () => void;\n  rotation: Rotation;\n  scale: MotionValue<number>;\n  setNatural: (natural: Size) => void;\n  setViewport: (viewport: Size) => void;\n  toggleActualSize: () => void;\n  x: MotionValue<number>;\n  y: MotionValue<number>;\n  zoomIn: () => void;\n  zoomOut: () => void;\n}\n\ninterface DerivedState {\n  canZoomIn: boolean;\n  canZoomOut: boolean;\n  isClean: boolean;\n  isZoomed: boolean;\n  rotation: Rotation;\n}\n\nexport const useZoomPan = ({\n  natural,\n  viewport,\n  maxScale,\n  onCloseRequest,\n  isClosing,\n  isTransitioning,\n  fillViewport,\n  defaultZoom,\n  autoZoomThreshold,\n}: UseZoomPanOptions): UseZoomPanResult => {\n  const naturalRef = useRef(natural);\n  const viewportRef = useRef(viewport);\n  const maxScaleRef = useRef(maxScale ?? DEFAULT_MAX_SCALE);\n  maxScaleRef.current = maxScale ?? DEFAULT_MAX_SCALE;\n  const fillViewportRef = useRef(fillViewport ?? false);\n  fillViewportRef.current = fillViewport ?? false;\n  const policyRef = useRef(defaultZoom ?? 'auto');\n  policyRef.current = defaultZoom ?? 'auto';\n  const thresholdRef = useRef(autoZoomThreshold ?? DEFAULT_AUTO_ZOOM_THRESHOLD);\n  thresholdRef.current = autoZoomThreshold ?? DEFAULT_AUTO_ZOOM_THRESHOLD;\n\n  const computeInitialScale = useCallback((rotation: Rotation = 0) => {\n    const fitRect = computeFit(\n      naturalRef.current,\n      viewportRef.current,\n      rotation,\n      fillViewportRef.current,\n    );\n    return resolveInitialScale(\n      policyRef.current,\n      naturalRef.current,\n      fitRect,\n      rotation,\n      thresholdRef.current,\n    );\n  }, []);\n\n  const [initialScaleSeed] = useState(computeInitialScale);\n  const initialScaleRef = useRef(initialScaleSeed);\n  const getInitialScale = useCallback(() => initialScaleRef.current, []);\n\n  const [{ scale, x, y, rotate, flipX, flipY }] = useState(() => ({\n    flipX: motionValue(false),\n    flipY: motionValue(false),\n    rotate: motionValue(0),\n    scale: motionValue(initialScaleRef.current),\n    x: motionValue(0),\n    y: motionValue(0),\n  }));\n\n  // The ceiling has to clear the opening scale, otherwise a very large image\n  // (naturalScale > maxScale) is clamped below the 100% it was asked to open at.\n  const effectiveMaxScale = useCallback(\n    () => Math.max(maxScaleRef.current, initialScaleRef.current),\n    [],\n  );\n\n  const onCloseRequestRef = useRef(onCloseRequest);\n  onCloseRequestRef.current = onCloseRequest;\n\n  const isClosingRef = useRef(isClosing);\n  isClosingRef.current = isClosing;\n\n  const isTransitioningRef = useRef(isTransitioning);\n  isTransitioningRef.current = isTransitioning;\n\n  const closeAccumRef = useRef(0);\n  const disarmedRef = useRef(false);\n  const idleTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n  const resetCloseTracking = useCallback(() => {\n    if (idleTimerRef.current !== null) {\n      clearTimeout(idleTimerRef.current);\n      idleTimerRef.current = null;\n    }\n    closeAccumRef.current = 0;\n    disarmedRef.current = false;\n  }, []);\n\n  // The close FLIP spring animates these same scale/x/y values. Any of\n  // these entry points still firing during the ~300ms close window would\n  // either fight that spring visually or, for wheel/reset specifically,\n  // race escIntent()/isCleanState() into cancelling the close outright.\n  const closing = useCallback(() => isClosingRef.current?.() ?? false, []);\n\n  // Three questions that used to share one answer, and stop sharing it the\n  // moment the viewer can open at something other than fit:\n  //   isAtFitFloor       — no zoom-out left, so a further scroll down has\n  //                        nowhere to go and becomes the dismiss gesture.\n  //   isOrientationClean — no rotation/flip to lose, so dismissing is safe.\n  //                        Guards the wheel the same way layered Esc does:\n  //                        state the user built is never thrown away by a\n  //                        gesture that merely ran out of room.\n  //   isCleanState       — both of the above *and* untouched zoom, i.e. \"the\n  //                        user hasn't changed anything at all\", which is what\n  //                        lets Esc/click close outright and lets the close\n  //                        animation FLIP back to the thumbnail instead of fade.\n  // All three coincide only while initialScale === MIN_SCALE.\n  const isAtFitFloor = useCallback(() => scale.get() <= MIN_SCALE + CLEAN_EPSILON, [scale]);\n\n  const isOrientationClean = useCallback(\n    () => Math.abs(rotate.get()) < CLEAN_EPSILON && !flipX.get() && !flipY.get(),\n    [flipX, flipY, rotate],\n  );\n\n  const isCleanState = useCallback(\n    () => Math.abs(scale.get() - initialScaleRef.current) < CLEAN_EPSILON && isOrientationClean(),\n    [isOrientationClean, scale],\n  );\n\n  const computeDerived = useCallback((): DerivedState => {\n    const currentScale = scale.get();\n    return {\n      canZoomIn: currentScale < effectiveMaxScale(),\n      canZoomOut: currentScale > MIN_SCALE,\n      isClean: isCleanState(),\n      isZoomed: currentScale > MIN_SCALE,\n      rotation: normalizeRotation(rotate.get()),\n    };\n  }, [effectiveMaxScale, isCleanState, rotate, scale]);\n\n  const [derived, setDerived] = useState<DerivedState>(computeDerived);\n\n  const syncDerived = useCallback(() => {\n    setDerived((prev) => {\n      const next = computeDerived();\n      if (\n        prev.canZoomIn === next.canZoomIn &&\n        prev.canZoomOut === next.canZoomOut &&\n        prev.isClean === next.isClean &&\n        prev.isZoomed === next.isZoomed &&\n        prev.rotation === next.rotation\n      ) {\n        return prev;\n      }\n      return next;\n    });\n  }, [computeDerived]);\n\n  useEffect(() => {\n    const unsubscribers = [scale, rotate, flipX, flipY].map((value) =>\n      value.on('change', syncDerived),\n    );\n    syncDerived();\n    return () => {\n      for (const unsubscribe of unsubscribers) unsubscribe();\n    };\n  }, [flipX, flipY, rotate, scale, syncDerived]);\n\n  const getFitRect = useCallback(\n    () =>\n      computeFit(\n        naturalRef.current,\n        viewportRef.current,\n        normalizeRotation(rotate.get()),\n        fillViewportRef.current,\n      ),\n    [rotate],\n  );\n\n  const applyTransform = useCallback(\n    (next: TransformState, fitRect: Rect) => {\n      const clamped = clampPan(next, fitRect, viewportRef.current);\n      // .jump(), not .set(): a surviving spring on these same values (e.g. a\n      // dragEnd clamp-back or wheel snap-back still in flight) would otherwise\n      // keep animating toward its own target and silently overwrite this\n      // instant write on its next tick — motion's set() never stops an\n      // active animation, only jump() does.\n      scale.jump(next.scale);\n      x.jump(clamped.x);\n      y.jump(clamped.y);\n    },\n    [scale, x, y],\n  );\n\n  // Wheel/pinch stays on the instant applyTransform for 1:1 gesture tracking;\n  // stepped inputs (toolbar/keyboard zoom, double-click) animate instead.\n  const animateTransform = useCallback(\n    (next: TransformState, fitRect: Rect) => {\n      const clamped = clampPan(next, fitRect, viewportRef.current);\n      animate(scale, next.scale, RESET_TRANSITION);\n      animate(x, clamped.x, RESET_TRANSITION);\n      animate(y, clamped.y, RESET_TRANSITION);\n    },\n    [scale, x, y],\n  );\n\n  const zoomBy = useCallback(\n    (factor: number) => {\n      if (closing()) return;\n      const currentScale = scale.get();\n      const targetScale = clampScale(currentScale * factor, effectiveMaxScale());\n      const fitRect = getFitRect();\n      const anchor: Point = { x: viewportRef.current.width / 2, y: viewportRef.current.height / 2 };\n      const next = anchoredZoom(\n        { scale: currentScale, x: x.get(), y: y.get() },\n        targetScale,\n        anchor,\n        fitRect,\n      );\n      animateTransform(next, fitRect);\n    },\n    [animateTransform, closing, effectiveMaxScale, getFitRect, scale, x, y],\n  );\n\n  const zoomIn = useCallback(() => zoomBy(ZOOM_STEP), [zoomBy]);\n  const zoomOut = useCallback(() => zoomBy(1 / ZOOM_STEP), [zoomBy]);\n\n  const handleDoubleClick = useCallback(\n    (point: Point) => {\n      if (closing()) return;\n      const currentScale = scale.get();\n      const fitRect = getFitRect();\n      const target = doubleClickTarget(\n        currentScale,\n        naturalRef.current,\n        fitRect,\n        normalizeRotation(rotate.get()),\n      );\n      const targetScale = clampScale(target, effectiveMaxScale());\n      const next = anchoredZoom(\n        { scale: currentScale, x: x.get(), y: y.get() },\n        targetScale,\n        point,\n        fitRect,\n      );\n      animateTransform(next, fitRect);\n    },\n    [animateTransform, closing, effectiveMaxScale, getFitRect, rotate, scale, x, y],\n  );\n\n  const toggleActualSize = useCallback(() => {\n    if (closing()) return;\n    const currentScale = scale.get();\n    const fitRect = getFitRect();\n    const actual = naturalScale(naturalRef.current, fitRect, normalizeRotation(rotate.get()));\n    const atActual = Math.abs(currentScale - actual) < CLEAN_EPSILON;\n    const targetScale = clampScale(atActual ? MIN_SCALE : actual, effectiveMaxScale());\n    const anchor: Point = { x: viewportRef.current.width / 2, y: viewportRef.current.height / 2 };\n    const next = anchoredZoom(\n      { scale: currentScale, x: x.get(), y: y.get() },\n      targetScale,\n      anchor,\n      fitRect,\n    );\n    animateTransform(next, fitRect);\n  }, [animateTransform, closing, effectiveMaxScale, getFitRect, rotate, scale, x, y]);\n\n  const handleWheel = useCallback(\n    (event: WheelLikeEvent) => {\n      event.preventDefault?.();\n      if (closing()) return;\n\n      if (idleTimerRef.current !== null) clearTimeout(idleTimerRef.current);\n      idleTimerRef.current = setTimeout(() => {\n        idleTimerRef.current = null;\n        closeAccumRef.current = 0;\n        disarmedRef.current = false;\n      }, WHEEL_IDLE_MS);\n\n      const delta = normalizeWheelDelta(event.deltaY, event.deltaMode, viewportRef.current.height);\n\n      const currentScale = scale.get();\n      const isPinch = !!(event.ctrlKey || event.metaKey);\n      // Zooming in is never gated on the current scale: gating it was what made\n      // a plain wheel inert at the zoom floor, which reads as enormous damping.\n      // Only scrolling *down* while already at the floor has nowhere left to go,\n      // and that is precisely where the dismiss gesture takes over.\n      const zoomingIn = delta < 0;\n\n      if (isPinch || zoomingIn || !isAtFitFloor()) {\n        disarmedRef.current = true;\n        closeAccumRef.current = 0;\n\n        const rawTarget = currentScale * wheelZoomFactor(delta);\n\n        if (rawTarget <= MIN_SCALE) {\n          animate(scale, MIN_SCALE, RESET_TRANSITION);\n          animate(x, 0, RESET_TRANSITION);\n          animate(y, 0, RESET_TRANSITION);\n          return;\n        }\n\n        const targetScale = clampScale(rawTarget, effectiveMaxScale());\n        const fitRect = getFitRect();\n        const anchor: Point = { x: event.clientX, y: event.clientY };\n        const next = anchoredZoom(\n          { scale: currentScale, x: x.get(), y: y.get() },\n          targetScale,\n          anchor,\n          fitRect,\n        );\n        applyTransform(next, fitRect);\n        return;\n      }\n\n      // Deliberately not isCleanState(): an image that opened at 100% and was\n      // scrolled back down to fit has \"changed\" by that measure, yet it is\n      // exactly where the dismiss gesture belongs. Only orientation is worth\n      // protecting here.\n      if (disarmedRef.current || !isOrientationClean()) return;\n\n      closeAccumRef.current += Math.abs(delta);\n      if (closeAccumRef.current >= WHEEL_CLOSE_THRESHOLD) {\n        closeAccumRef.current = 0;\n        onCloseRequestRef.current?.();\n      }\n    },\n    [\n      applyTransform,\n      closing,\n      effectiveMaxScale,\n      getFitRect,\n      isAtFitFloor,\n      isOrientationClean,\n      scale,\n      x,\n      y,\n    ],\n  );\n\n  const rotateBy = useCallback(\n    (delta: 90 | -90) => {\n      if (closing()) return;\n      rotate.jump(normalizeRotation(rotate.get() + delta));\n      scale.jump(1);\n      x.jump(0);\n      y.jump(0);\n    },\n    [closing, rotate, scale, x, y],\n  );\n\n  const rotateLeft = useCallback(() => rotateBy(-90), [rotateBy]);\n  const rotateRight = useCallback(() => rotateBy(90), [rotateBy]);\n\n  const flipHorizontal = useCallback(() => {\n    if (closing()) return;\n    flipX.set(!flipX.get());\n  }, [closing, flipX]);\n\n  const flipVertical = useCallback(() => {\n    if (closing()) return;\n    flipY.set(!flipY.get());\n  }, [closing, flipY]);\n\n  const reset = useCallback(() => {\n    if (closing()) return;\n    // Back to how the viewer opened, which is not necessarily fit.\n    animate(scale, initialScaleRef.current, RESET_TRANSITION);\n    animate(x, 0, RESET_TRANSITION);\n    animate(y, 0, RESET_TRANSITION);\n    animate(rotate, 0, RESET_TRANSITION);\n    flipX.set(false);\n    flipY.set(false);\n  }, [closing, flipX, flipY, rotate, scale, x, y]);\n\n  const dragBy = useCallback(\n    (delta: Point) => {\n      // A pointer can still be down when close starts (e.g. pinch to just\n      // over 1x — inside isClean's epsilon, so Esc/wheel reads 'close' —\n      // while the same gesture is still panning). Gated for consistency\n      // with the other entry points even though .set() here can't cancel\n      // the close spring outright, only cause a self-correcting flicker.\n      if (closing()) return;\n      const fitRect = getFitRect();\n      const bounds = panBounds({ scale: scale.get(), x: 0, y: 0 }, fitRect, viewportRef.current);\n      x.set(rubberBand(x.get() + delta.x, bounds.x.min, bounds.x.max));\n      y.set(rubberBand(y.get() + delta.y, bounds.y.min, bounds.y.max));\n    },\n    [closing, getFitRect, scale, x, y],\n  );\n\n  const dragEnd = useCallback(() => {\n    if (closing()) return;\n    const fitRect = getFitRect();\n    const clamped = clampPan(\n      { scale: scale.get(), x: x.get(), y: y.get() },\n      fitRect,\n      viewportRef.current,\n    );\n    animate(x, clamped.x, RESET_TRANSITION);\n    animate(y, clamped.y, RESET_TRANSITION);\n  }, [closing, getFitRect, scale, x, y]);\n\n  const escIntent = useCallback(\n    (): 'reset' | 'close' => (isCleanState() ? 'close' : 'reset'),\n    [isCleanState],\n  );\n\n  const setViewport = useCallback(\n    (next: Size) => {\n      viewportRef.current = next;\n      const fitRect = computeFit(\n        naturalRef.current,\n        next,\n        normalizeRotation(rotate.get()),\n        fillViewportRef.current,\n      );\n      const clamped = clampPan({ scale: scale.get(), x: x.get(), y: y.get() }, fitRect, next);\n      x.set(clamped.x);\n      y.set(clamped.y);\n    },\n    [rotate, scale, x, y],\n  );\n\n  const setNatural = useCallback(\n    (next: Size) => {\n      const wasClean = isCleanState();\n      naturalRef.current = next;\n      const rotation = normalizeRotation(rotate.get());\n      initialScaleRef.current = computeInitialScale(rotation);\n\n      // A dual-source entry opens on the thumbnail's intrinsic size and only\n      // learns the hi-res one here, which can move the opening scale (a 400px\n      // stand-in is fit-sized; the 2000px original it becomes is not). Re-land\n      // only if the user hasn't taken over — and never mid-transition, where\n      // .jump() would kill the open FLIP's spring instead of joining it.\n      if (wasClean && !closing() && !isTransitioningRef.current?.()) {\n        scale.jump(initialScaleRef.current);\n      }\n\n      const fitRect = computeFit(next, viewportRef.current, rotation, fillViewportRef.current);\n      const clamped = clampPan(\n        { scale: scale.get(), x: x.get(), y: y.get() },\n        fitRect,\n        viewportRef.current,\n      );\n      x.set(clamped.x);\n      y.set(clamped.y);\n    },\n    [closing, computeInitialScale, isCleanState, rotate, scale, x, y],\n  );\n\n  return {\n    canZoomIn: derived.canZoomIn,\n    canZoomOut: derived.canZoomOut,\n    dragBy,\n    dragEnd,\n    escIntent,\n    flipHorizontal,\n    flipVertical,\n    flipX,\n    flipY,\n    getInitialScale,\n    handleDoubleClick,\n    handleWheel,\n    isClean: derived.isClean,\n    isZoomed: derived.isZoomed,\n    reset,\n    resetCloseTracking,\n    rotate,\n    rotateLeft,\n    rotateRight,\n    rotation: derived.rotation,\n    scale,\n    setNatural,\n    setViewport,\n    toggleActualSize,\n    x,\n    y,\n    zoomIn,\n    zoomOut,\n  };\n};\n\nexport type { Point, Rotation, Size, ZoomPolicy } from './geometry';\n"],"mappings":"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"}