{"version":3,"file":"useRefitTransition.mjs","names":[],"sources":["../../../src/Image/viewer/useRefitTransition.ts"],"sourcesContent":["import type { MotionValue } from 'motion/react';\nimport { animate } from 'motion/react';\nimport { useLayoutEffect, useRef } from 'react';\n\nimport { computeFit, type Rotation, type Size } from './geometry';\nimport { OPEN_SPRING } from './useFlipTransition';\n\nexport interface UseRefitTransitionOptions {\n  animated: boolean;\n  fillViewport?: boolean;\n  isTransitioning: () => boolean;\n  natural: Size;\n  rotation: Rotation;\n  scale: MotionValue<number>;\n  viewport: Size;\n  x: MotionValue<number>;\n  y: MotionValue<number>;\n}\n\nexport const useRefitTransition = ({\n  animated,\n  fillViewport,\n  isTransitioning,\n  natural,\n  rotation,\n  scale,\n  viewport,\n  x,\n  y,\n}: UseRefitTransitionOptions): void => {\n  const naturalRef = useRef(natural);\n\n  useLayoutEffect(() => {\n    const previousNatural = naturalRef.current;\n    naturalRef.current = natural;\n    if (previousNatural.width === natural.width && previousNatural.height === natural.height)\n      return;\n    if (!animated) return;\n    // A FLIP open/close spring or a gallery switch is already animating these\n    // same scale/x/y values. Calling animate() on them here would silently\n    // cancel that in-flight animation (motion's animate() stops the prior one\n    // without firing its onComplete), which can park the viewer mid-transform\n    // on open or, worse, permanently wedge an invisible dialog open on close.\n    // Skip outright: the open spring always targets identity relative to the\n    // *current* fit rect, so it self-corrects once it settles; a switch resets\n    // the transform itself, and instant re-fit is correct there.\n    if (isTransitioning()) return;\n\n    const previousFit = computeFit(previousNatural, viewport, rotation, fillViewport);\n    const nextFit = computeFit(natural, viewport, rotation, fillViewport);\n    if (\n      previousFit.width === nextFit.width &&\n      previousFit.height === nextFit.height &&\n      previousFit.x === nextFit.x &&\n      previousFit.y === nextFit.y\n    )\n      return;\n\n    const ratio = nextFit.width > 0 ? previousFit.width / nextFit.width : 1;\n    if (!Number.isFinite(ratio) || ratio <= 0) return;\n\n    const previousCenterX = previousFit.x + previousFit.width / 2;\n    const previousCenterY = previousFit.y + previousFit.height / 2;\n    const nextCenterX = nextFit.x + nextFit.width / 2;\n    const nextCenterY = nextFit.y + nextFit.height / 2;\n\n    const targetScale = scale.get();\n    const targetX = x.get();\n    const targetY = y.get();\n\n    scale.set(targetScale * ratio);\n    x.set(targetX + (previousCenterX - nextCenterX));\n    y.set(targetY + (previousCenterY - nextCenterY));\n\n    animate(scale, targetScale, OPEN_SPRING);\n    animate(x, targetX, OPEN_SPRING);\n    animate(y, targetY, OPEN_SPRING);\n  }, [animated, fillViewport, isTransitioning, natural, rotation, scale, viewport, x, y]);\n};\n"],"mappings":";;;;;AAmBA,MAAa,sBAAsB,EACjC,UACA,cACA,iBACA,SACA,UACA,OACA,UACA,GACA,QACqC;CACrC,MAAM,aAAa,OAAO,OAAO;CAEjC,sBAAsB;EACpB,MAAM,kBAAkB,WAAW;EACnC,WAAW,UAAU;EACrB,IAAI,gBAAgB,UAAU,QAAQ,SAAS,gBAAgB,WAAW,QAAQ,QAChF;EACF,IAAI,CAAC,UAAU;EASf,IAAI,gBAAgB,GAAG;EAEvB,MAAM,cAAc,WAAW,iBAAiB,UAAU,UAAU,YAAY;EAChF,MAAM,UAAU,WAAW,SAAS,UAAU,UAAU,YAAY;EACpE,IACE,YAAY,UAAU,QAAQ,SAC9B,YAAY,WAAW,QAAQ,UAC/B,YAAY,MAAM,QAAQ,KAC1B,YAAY,MAAM,QAAQ,GAE1B;EAEF,MAAM,QAAQ,QAAQ,QAAQ,IAAI,YAAY,QAAQ,QAAQ,QAAQ;EACtE,IAAI,CAAC,OAAO,SAAS,KAAK,KAAK,SAAS,GAAG;EAE3C,MAAM,kBAAkB,YAAY,IAAI,YAAY,QAAQ;EAC5D,MAAM,kBAAkB,YAAY,IAAI,YAAY,SAAS;EAC7D,MAAM,cAAc,QAAQ,IAAI,QAAQ,QAAQ;EAChD,MAAM,cAAc,QAAQ,IAAI,QAAQ,SAAS;EAEjD,MAAM,cAAc,MAAM,IAAI;EAC9B,MAAM,UAAU,EAAE,IAAI;EACtB,MAAM,UAAU,EAAE,IAAI;EAEtB,MAAM,IAAI,cAAc,KAAK;EAC7B,EAAE,IAAI,WAAW,kBAAkB,YAAY;EAC/C,EAAE,IAAI,WAAW,kBAAkB,YAAY;EAE/C,QAAQ,OAAO,aAAa,WAAW;EACvC,QAAQ,GAAG,SAAS,WAAW;EAC/B,QAAQ,GAAG,SAAS,WAAW;CACjC,GAAG;EAAC;EAAU;EAAc;EAAiB;EAAS;EAAU;EAAO;EAAU;EAAG;CAAC,CAAC;AACxF"}