@jekrch/react-viewport-lightbox 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +438 -273
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -2
- package/dist/index.d.ts +20 -2
- package/dist/index.js +438 -273
- package/dist/index.js.map +1 -1
- package/dist/styles.css +27 -2
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/math.ts","../src/hooks/useImageZoomPan.ts","../src/hooks/useSlideNavigation.ts","../src/hooks/useGestureHandler.ts","../src/hooks/useBarMeasure.ts","../src/hooks/useBodyScrollLock.ts","../src/hooks/useFocusTrap.ts","../src/components/icons.tsx","../src/components/cx.ts","../src/components/NavButton.tsx","../src/components/ImageViewer.tsx"],"names":["useRef","useState","useCallback","clampTranslate","useLayoutEffect","useEffect","sg","jsxs","jsx","useMemo"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Pure geometry/threshold helpers shared by the interaction hooks. Kept free of\n * React and DOM globals so they can be unit-tested in isolation.\n */\n\nexport interface Dims {\n width: number;\n height: number;\n}\n\n/**\n * Clamp a pan translation so the scaled image edge can't move past the\n * viewport edge. Returns `{ x: 0, y: 0 }` when not zoomed or when base\n * dimensions are unknown.\n */\nexport function clampTranslate(\n x: number,\n y: number,\n scale: number,\n baseDims: Dims,\n viewport: Dims,\n): { x: number; y: number } {\n if (scale <= 1) return { x: 0, y: 0 };\n const { width: baseW, height: baseH } = baseDims;\n if (baseW === 0 || baseH === 0) return { x: 0, y: 0 };\n\n const scaledHalfW = (baseW * scale) / 2;\n const scaledHalfH = (baseH * scale) / 2;\n const vpHalfW = viewport.width / 2;\n const vpHalfH = viewport.height / 2;\n\n const maxX = Math.max(0, scaledHalfW - vpHalfW);\n const maxY = Math.max(0, scaledHalfH - vpHalfH);\n\n return {\n x: Math.max(-maxX, Math.min(maxX, x)),\n y: Math.max(-maxY, Math.min(maxY, y)),\n };\n}\n\n/**\n * Compute the pan translation that keeps the content under a focal point\n * (cursor or pinch midpoint) anchored as the scale changes from `prevScale`\n * to `nextScale`.\n *\n * The viewer scales the wrapper about the viewport center, so the on-screen\n * position of a content point is `center + scale * (point - center) + t`.\n * Solving \"the content at `focal` before the zoom is still at `focal` after\"\n * for the new translate gives the closed form below. Pass `focal` in viewport\n * coordinates (e.g. `clientX`/`clientY`). The result is unclamped — feed it\n * through {@link clampTranslate} before applying.\n */\nexport function zoomToPoint(\n prevScale: number,\n nextScale: number,\n prev: { x: number; y: number },\n focal: { x: number; y: number },\n viewport: Dims,\n): { x: number; y: number } {\n const relX = focal.x - viewport.width / 2;\n const relY = focal.y - viewport.height / 2;\n const k = nextScale / prevScale;\n return {\n x: relX * (1 - k) + k * prev.x,\n y: relY * (1 - k) + k * prev.y,\n };\n}\n\nexport type SlideAction = \"prev\" | \"next\" | \"snap\";\n\nexport interface ResolveSlideArgs {\n /** Current horizontal swipe offset in px (positive = dragged right). */\n offset: number;\n /** Elapsed time of the gesture in ms (used for fling velocity). */\n elapsedMs: number;\n viewportWidth: number;\n hasPrev: boolean;\n hasNext: boolean;\n /** Fraction of viewport width past which a drag commits. Default 0.25. */\n distanceThreshold?: number;\n /** px/ms past which a fast fling commits regardless of distance. Default 0.4. */\n velocityThreshold?: number;\n}\n\n/**\n * Decide whether a released swipe should navigate `prev`/`next` or `snap` back,\n * based on distance and fling velocity.\n */\nexport function resolveSlideDirection({\n offset,\n elapsedMs,\n viewportWidth,\n hasPrev,\n hasNext,\n distanceThreshold = 0.25,\n velocityThreshold = 0.4,\n}: ResolveSlideArgs): SlideAction {\n const velocity = Math.abs(offset) / Math.max(elapsedMs, 1);\n const threshold = viewportWidth * distanceThreshold;\n const committed = Math.abs(offset) > threshold || velocity > velocityThreshold;\n\n if (offset > 0 && hasPrev && committed) return \"prev\";\n if (offset < 0 && hasNext && committed) return \"next\";\n return \"snap\";\n}\n","import { useCallback, useEffect, useLayoutEffect, useRef, useState, type RefObject } from \"react\";\nimport { clampTranslate as clampTranslatePure, zoomToPoint } from \"./math\";\n\nconst MIN_SCALE = 1;\nconst MAX_SCALE = 5;\n\nexport interface ImageTransform {\n scale: number;\n x: number;\n y: number;\n}\n\nexport interface ImageZoomPanState {\n imgRef: RefObject<HTMLImageElement | null>;\n displayScale: number;\n isZoomed: boolean;\n transformRef: React.MutableRefObject<ImageTransform>;\n\n /** Base (unscaled) image dimensions for clamp calculations */\n baseDimsRef: React.MutableRefObject<{ width: number; height: number }>;\n\n resetTransform: () => void;\n setTransform: (t: ImageTransform, animate?: boolean) => void;\n applyTransform: (t: ImageTransform, animate?: boolean) => void;\n clampTranslate: (x: number, y: number, scale: number) => { x: number; y: number };\n measureBaseDims: () => void;\n handleDoubleClick: (e: React.MouseEvent) => void;\n}\n\n/**\n * Manages zoom/pan state for an image viewer.\n *\n * Applies scale + translate transforms to the **wrapper** element rather\n * than the image itself. This avoids an iOS Safari compositing bug where\n * CSS scale() on an element clips its painted output to the element's\n * original layout bounds.\n *\n * When zoomed, the wrapper is positioned absolute inset-0 (full viewport),\n * so its layout bounds already match the viewport and scaling it won't clip.\n * The image stays at its natural constrained size, centered via flexbox.\n */\nexport function useImageZoomPan(\n imgWrapperRef: RefObject<HTMLDivElement | null>,\n currentIndex: number,\n /** When false, wheel-zoom and double-click-zoom are disabled. Default true. */\n enabled = true,\n /**\n * When true (default), wheel-zoom anchors on the cursor. When false, it zooms\n * about the viewport center.\n */\n zoomToCursor = true,\n): ImageZoomPanState {\n const imgRef = useRef<HTMLImageElement>(null);\n const [displayScale, setDisplayScale] = useState(1);\n const transformRef = useRef<ImageTransform>({ scale: 1, x: 0, y: 0 });\n const baseDimsRef = useRef<{ width: number; height: number }>({ width: 0, height: 0 });\n\n // Core helpers\n\n const applyTransform = useCallback(\n (t: ImageTransform, animate = false) => {\n const wrapper = imgWrapperRef.current;\n if (!wrapper) return;\n wrapper.style.transition = animate ? \"transform 0.2s ease-out\" : \"none\";\n\n if (t.scale <= 1) {\n wrapper.style.transform = \"none\";\n wrapper.style.position = \"\";\n wrapper.style.inset = \"\";\n wrapper.style.zIndex = \"\";\n wrapper.style.backgroundColor = \"\";\n wrapper.style.cursor = \"\";\n } else {\n wrapper.style.transform = `scale(${t.scale}) translate(${t.x / t.scale}px, ${t.y / t.scale}px)`;\n wrapper.style.position = \"absolute\";\n wrapper.style.inset = \"0\";\n wrapper.style.zIndex = \"30\";\n wrapper.style.backgroundColor = \"black\";\n wrapper.style.cursor = \"grab\";\n }\n\n // Keep React state in sync so isZoomed reflects reality\n setDisplayScale(t.scale);\n },\n [imgWrapperRef],\n );\n\n const setTransform = useCallback(\n (t: ImageTransform, animate = false) => {\n transformRef.current = t;\n applyTransform(t, animate);\n setDisplayScale(t.scale);\n },\n [applyTransform],\n );\n\n const resetTransform = useCallback(() => {\n setTransform({ scale: 1, x: 0, y: 0 }, true);\n }, [setTransform]);\n\n const measureBaseDims = useCallback(() => {\n const img = imgRef.current;\n if (!img) return;\n baseDimsRef.current = { width: img.offsetWidth, height: img.offsetHeight };\n }, []);\n\n /**\n * Clamp so the image edge can't pan past the viewport edge.\n */\n const clampTranslate = useCallback(\n (x: number, y: number, scale: number): { x: number; y: number } =>\n clampTranslatePure(x, y, scale, baseDimsRef.current, {\n width: window.innerWidth,\n height: window.innerHeight,\n }),\n [],\n );\n\n // Reset on navigation\n\n useLayoutEffect(() => {\n const wrapper = imgWrapperRef.current;\n if (wrapper) {\n wrapper.style.transition = \"none\";\n wrapper.style.transform = \"none\";\n wrapper.style.position = \"\";\n wrapper.style.inset = \"\";\n wrapper.style.zIndex = \"\";\n wrapper.style.backgroundColor = \"\";\n wrapper.style.cursor = \"\";\n }\n transformRef.current = { scale: 1, x: 0, y: 0 };\n }, [currentIndex, imgWrapperRef]);\n\n useEffect(() => {\n setDisplayScale(1);\n }, [currentIndex]);\n\n // Wheel zoom (desktop)\n\n useEffect(() => {\n if (!enabled) return;\n const wrapper = imgWrapperRef.current;\n if (!wrapper) return;\n\n const handleWheel = (e: WheelEvent) => {\n e.preventDefault();\n\n // Ensure base dims\n if (baseDimsRef.current.width === 0) {\n const img = imgRef.current;\n if (img) baseDimsRef.current = { width: img.offsetWidth, height: img.offsetHeight };\n }\n\n const t = transformRef.current;\n\n let dy = e.deltaY;\n if (e.deltaMode === 1) dy *= 16;\n if (e.deltaMode === 2) dy *= 100;\n\n const normalized = Math.max(-100, Math.min(100, dy));\n const step = -(normalized / 100) * 0.05;\n const factor = 1 + step;\n\n const nextScale = Math.min(MAX_SCALE, Math.max(MIN_SCALE, t.scale * factor));\n let clamped: { x: number; y: number };\n if (nextScale <= 1) {\n clamped = { x: 0, y: 0 };\n } else if (zoomToCursor) {\n const focal = zoomToPoint(\n t.scale,\n nextScale,\n { x: t.x, y: t.y },\n { x: e.clientX, y: e.clientY },\n { width: window.innerWidth, height: window.innerHeight },\n );\n clamped = clampTranslate(focal.x, focal.y, nextScale);\n } else {\n clamped = clampTranslate(t.x, t.y, nextScale);\n }\n setTransform({ scale: nextScale, ...clamped });\n };\n\n wrapper.addEventListener(\"wheel\", handleWheel, { passive: false });\n return () => wrapper.removeEventListener(\"wheel\", handleWheel);\n }, [imgWrapperRef, setTransform, clampTranslate, enabled, zoomToCursor]);\n\n // Double-click toggle\n\n const handleDoubleClick = useCallback(\n (e: React.MouseEvent) => {\n if (!enabled) return;\n e.stopPropagation();\n\n // Ensure base dims\n if (baseDimsRef.current.width === 0) {\n const img = imgRef.current;\n if (img) baseDimsRef.current = { width: img.offsetWidth, height: img.offsetHeight };\n }\n\n if (transformRef.current.scale > 1) {\n resetTransform();\n } else {\n setTransform({ scale: 1.8, x: 0, y: 0 }, true);\n }\n },\n [resetTransform, setTransform, enabled],\n );\n\n return {\n imgRef,\n displayScale,\n isZoomed: displayScale > 1,\n transformRef,\n baseDimsRef,\n resetTransform,\n setTransform,\n applyTransform,\n clampTranslate,\n measureBaseDims,\n handleDoubleClick,\n };\n}\n\nexport { MIN_SCALE, MAX_SCALE };\n","import { useCallback, useEffect, useLayoutEffect, useRef, useState } from \"react\";\nimport type { ViewerItem } from \"../types\";\nimport { resolveSlideDirection } from \"./math\";\n\nexport interface SlideNavigationState {\n slideTrackRef: React.RefObject<HTMLDivElement | null>;\n slideActive: boolean;\n slideAnimating: boolean;\n swipeOffset: number;\n swipeOffsetRef: React.MutableRefObject<number>;\n commitLockRef: React.MutableRefObject<boolean>;\n\n applySlideOffset: (offset: number, animate?: boolean) => void;\n commitSlide: (direction: \"prev\" | \"next\") => void;\n snapBack: () => void;\n resolveSlide: (gestureStartTime: number) => void;\n setSlideActive: React.Dispatch<React.SetStateAction<boolean>>;\n}\n\n/**\n * Manages the three-slot slide carousel: swipe offset tracking, animated\n * commit/snap-back, and DOM resets on navigation.\n *\n * `items[i].src` is treated as a final, ready-to-load url — the next image is\n * preloaded/decoded before navigation commits so the swipe lands on a painted\n * frame.\n */\nexport function useSlideNavigation(\n items: ViewerItem[],\n currentIndex: number,\n onNavigate: (index: number) => void,\n onSlideStart?: (direction: \"prev\" | \"next\") => void,\n /** When true, navigation wraps around the ends instead of stopping. */\n loop = false,\n): SlideNavigationState {\n const slideTrackRef = useRef<HTMLDivElement>(null);\n const swipeOffsetRef = useRef(0);\n const [swipeOffset, setSwipeOffset] = useState(0);\n const [slideAnimating, setSlideAnimating] = useState(false);\n const [slideActive, setSlideActive] = useState(false);\n const commitLockRef = useRef(false);\n\n // With loop on, every interior position has a neighbor in both directions as\n // long as there's more than one item to wrap to.\n const hasPrev = loop ? items.length > 1 : currentIndex > 0;\n const hasNext = loop ? items.length > 1 : currentIndex < items.length - 1;\n\n const applySlideOffset = useCallback((offset: number, animate = false) => {\n swipeOffsetRef.current = offset;\n const track = slideTrackRef.current;\n if (track) {\n track.style.transition = animate ? \"transform 0.28s cubic-bezier(0.2, 0, 0, 1)\" : \"none\";\n track.style.transform = `translateX(${offset}px)`;\n }\n setSwipeOffset(offset);\n }, []);\n\n const snapBack = useCallback(() => {\n setSlideAnimating(true);\n applySlideOffset(0, true);\n\n const track = slideTrackRef.current;\n let done = false;\n const onEnd = () => {\n if (done) return;\n done = true;\n track?.removeEventListener(\"transitionend\", onEnd);\n setSlideAnimating(false);\n setSlideActive(false);\n };\n if (track) {\n track.addEventListener(\"transitionend\", onEnd, { once: true });\n setTimeout(onEnd, 350);\n }\n }, [applySlideOffset]);\n\n const readyRef = useRef(true);\n\n const commitSlide = useCallback(\n (direction: \"prev\" | \"next\") => {\n if (commitLockRef.current || !readyRef.current) return;\n commitLockRef.current = true;\n readyRef.current = false;\n\n const vw = window.innerWidth;\n const targetOffset = direction === \"prev\" ? vw : -vw;\n setSlideActive(true);\n setSlideAnimating(true);\n // Fire at the START of the slide so overlays (info drawers) can animate\n // out in sync with the image — onNavigate only fires once it completes.\n onSlideStart?.(direction);\n\n requestAnimationFrame(() => {\n applySlideOffset(targetOffset, true);\n\n const track = slideTrackRef.current;\n let cleaned = false;\n\n const cleanup = () => {\n if (cleaned) return;\n cleaned = true;\n track?.removeEventListener(\"transitionend\", onTransitionEnd);\n\n let newIndex = direction === \"prev\" ? currentIndex - 1 : currentIndex + 1;\n // Wrap the index when looping so the slide that just played lands on\n // the far end (e.g. last → first) instead of bailing out of bounds.\n if (loop) newIndex = (newIndex + items.length) % items.length;\n if (newIndex < 0 || newIndex >= items.length) {\n commitLockRef.current = false;\n return;\n }\n\n const newItem = items[newIndex];\n const preload = new Image();\n preload.src = newItem.src;\n\n const doNavigate = () => onNavigate(newIndex);\n\n // Add a timeout so a stalled decode can't block navigation forever\n const timeout = setTimeout(doNavigate, 300);\n preload\n .decode()\n .then(() => {\n clearTimeout(timeout);\n doNavigate();\n })\n .catch(() => {\n clearTimeout(timeout);\n doNavigate();\n });\n };\n\n const onTransitionEnd = () => cleanup();\n if (track) {\n track.addEventListener(\"transitionend\", onTransitionEnd, { once: true });\n setTimeout(cleanup, 400);\n }\n });\n },\n [applySlideOffset, currentIndex, items, onNavigate, onSlideStart, loop],\n );\n\n const resolveSlide = useCallback(\n (gestureStartTime: number) => {\n const action = resolveSlideDirection({\n offset: swipeOffsetRef.current,\n elapsedMs: Date.now() - gestureStartTime,\n viewportWidth: window.innerWidth,\n hasPrev,\n hasNext,\n });\n\n if (action === \"prev\") commitSlide(\"prev\");\n else if (action === \"next\") commitSlide(\"next\");\n else snapBack();\n },\n [hasPrev, hasNext, commitSlide, snapBack],\n );\n\n // DOM resets on navigation (pre-paint)\n\n useLayoutEffect(() => {\n const track = slideTrackRef.current;\n if (track) {\n track.style.transition = \"none\";\n track.offsetHeight;\n track.style.transform = \"translateX(0px)\";\n }\n swipeOffsetRef.current = 0;\n commitLockRef.current = false;\n }, [currentIndex]);\n\n // React state cleanup — runs after paint\n useEffect(() => {\n setSwipeOffset(0);\n setSlideAnimating(false);\n setSlideActive(false);\n // Allow next commit only after React has painted the new panel\n readyRef.current = true;\n }, [currentIndex]);\n\n return {\n slideTrackRef,\n slideActive,\n slideAnimating,\n swipeOffset,\n swipeOffsetRef,\n commitLockRef,\n applySlideOffset,\n commitSlide,\n snapBack,\n resolveSlide,\n setSlideActive,\n };\n}\n","import { useCallback, useRef } from \"react\";\nimport { zoomToPoint } from \"./math\";\nimport type { ImageZoomPanState } from \"./useImageZoomPan\";\nimport type { SlideNavigationState } from \"./useSlideNavigation\";\n\ninterface GestureHandlers {\n handlePointerDown: (e: React.PointerEvent) => void;\n handlePointerMove: (e: React.PointerEvent) => void;\n handlePointerUp: (e: React.PointerEvent) => void;\n handleTouchStart: (e: React.TouchEvent) => void;\n handleTouchMove: (e: React.TouchEvent) => void;\n handleTouchEnd: (e: React.TouchEvent) => void;\n}\n\ninterface PanGesture {\n isDragging: boolean;\n pointerStart: { x: number; y: number };\n translateStart: { x: number; y: number };\n pinchStartDist: number | null;\n pinchStartScale: number;\n pinchMidpoint: { x: number; y: number } | null;\n lastTouchPos: { x: number; y: number } | null;\n}\n\ninterface SlideGesture {\n active: boolean;\n startX: number;\n startY: number;\n startTime: number;\n locked: boolean;\n rejected: boolean;\n}\n\n/**\n * Coordinates zoom/pan and slide gestures, routing pointer and touch events\n * to the appropriate behavior based on current zoom state.\n *\n * When zoomed (scale > 1): pointer/touch drags are pans.\n * When unzoomed (scale === 1): pointer/touch drags are slide-to-navigate.\n * Two-finger touch is always a pinch-zoom.\n */\nexport function useGestureHandler(\n zoomPan: ImageZoomPanState,\n slide: SlideNavigationState,\n hasPrev: boolean,\n hasNext: boolean,\n /** When false, pinch-zoom and double-tap-zoom are disabled. Default true. */\n zoomEnabled = true,\n /**\n * When true (default), pinch-zoom anchors on the gesture midpoint. When\n * false, it zooms about the viewport center.\n */\n zoomToCursor = true,\n): GestureHandlers {\n const { transformRef, clampTranslate, setTransform, applyTransform, resetTransform } = zoomPan;\n const { applySlideOffset, resolveSlide, snapBack, setSlideActive, swipeOffsetRef } = slide;\n\n const panRef = useRef<PanGesture>({\n isDragging: false,\n pointerStart: { x: 0, y: 0 },\n translateStart: { x: 0, y: 0 },\n pinchStartDist: null,\n pinchStartScale: 1,\n pinchMidpoint: null,\n lastTouchPos: null,\n });\n\n const slideRef = useRef<SlideGesture>({\n active: false,\n startX: 0,\n startY: 0,\n startTime: 0,\n locked: false,\n rejected: false,\n });\n\n // Double-tap detection for touch\n const lastTapRef = useRef<{ time: number; x: number; y: number }>({\n time: 0,\n x: 0,\n y: 0,\n });\n\n // Shared slide start helper\n\n const beginSlide = useCallback(\n (x: number, y: number) => {\n setSlideActive(true);\n const sg = slideRef.current;\n sg.active = true;\n sg.startX = x;\n sg.startY = y;\n sg.startTime = Date.now();\n sg.locked = false;\n sg.rejected = false;\n },\n [setSlideActive],\n );\n\n const updateSlide = useCallback(\n (clientX: number, clientY: number, lockThreshold: number, angleBias: number) => {\n const sg = slideRef.current;\n if (!sg.active || sg.rejected) return;\n\n const dx = clientX - sg.startX;\n const dy = clientY - sg.startY;\n\n if (!sg.locked) {\n const absDx = Math.abs(dx);\n const absDy = Math.abs(dy);\n if (absDx < lockThreshold && absDy < lockThreshold) return;\n if (absDy > absDx * angleBias) {\n sg.rejected = true;\n return;\n }\n sg.locked = true;\n }\n\n let offset = dx;\n if ((offset > 0 && !hasPrev) || (offset < 0 && !hasNext)) {\n offset *= 0.2; // rubber-band resistance at edges\n }\n applySlideOffset(offset);\n },\n [hasPrev, hasNext, applySlideOffset],\n );\n\n const endSlide = useCallback(\n (allowResolve: boolean) => {\n const sg = slideRef.current;\n if (sg.active && sg.locked && !sg.rejected && allowResolve) {\n const startTime = sg.startTime;\n sg.active = false;\n resolveSlide(startTime);\n } else {\n sg.active = false;\n if (swipeOffsetRef.current === 0) setSlideActive(false);\n }\n },\n [resolveSlide, setSlideActive, swipeOffsetRef],\n );\n\n // Pointer (mouse) handlers\n\n const handlePointerDown = useCallback(\n (e: React.PointerEvent) => {\n if (e.pointerType === \"touch\") return;\n\n if (transformRef.current.scale > 1) {\n e.preventDefault();\n const p = panRef.current;\n p.isDragging = true;\n p.pointerStart = { x: e.clientX, y: e.clientY };\n p.translateStart = { x: transformRef.current.x, y: transformRef.current.y };\n } else {\n beginSlide(e.clientX, e.clientY);\n }\n },\n [transformRef, beginSlide],\n );\n\n const handlePointerMove = useCallback(\n (e: React.PointerEvent) => {\n if (e.pointerType === \"touch\") return;\n\n const p = panRef.current;\n if (p.isDragging && transformRef.current.scale > 1) {\n const dx = e.clientX - p.pointerStart.x;\n const dy = e.clientY - p.pointerStart.y;\n const t = transformRef.current;\n const clamped = clampTranslate(p.translateStart.x + dx, p.translateStart.y + dy, t.scale);\n setTransform({ scale: t.scale, ...clamped });\n return;\n }\n\n // Mouse slide: lockThreshold=4, angleBias=1 (45° cutoff)\n updateSlide(e.clientX, e.clientY, 4, 1);\n },\n [transformRef, clampTranslate, setTransform, updateSlide],\n );\n\n const handlePointerUp = useCallback(\n (e: React.PointerEvent) => {\n if (e.pointerType === \"touch\") return;\n panRef.current.isDragging = false;\n endSlide(true);\n },\n [endSlide],\n );\n\n // Touch handlers\n\n const handleTouchStart = useCallback(\n (e: React.TouchEvent) => {\n const p = panRef.current;\n\n if (e.touches.length === 2 && zoomEnabled) {\n // Pinch start\n const dx = e.touches[0].clientX - e.touches[1].clientX;\n const dy = e.touches[0].clientY - e.touches[1].clientY;\n p.pinchStartDist = Math.hypot(dx, dy);\n p.pinchStartScale = transformRef.current.scale;\n p.pinchMidpoint = {\n x: (e.touches[0].clientX + e.touches[1].clientX) / 2,\n y: (e.touches[0].clientY + e.touches[1].clientY) / 2,\n };\n p.lastTouchPos = null;\n\n // Cancel any slide in progress\n if (slideRef.current.active) {\n slideRef.current.active = false;\n snapBack();\n }\n } else if (e.touches.length === 1) {\n if (transformRef.current.scale > 1) {\n p.lastTouchPos = {\n x: e.touches[0].clientX,\n y: e.touches[0].clientY,\n };\n } else {\n beginSlide(e.touches[0].clientX, e.touches[0].clientY);\n }\n }\n },\n [transformRef, snapBack, beginSlide, zoomEnabled],\n );\n\n const handleTouchMove = useCallback(\n (e: React.TouchEvent) => {\n const p = panRef.current;\n\n if (e.touches.length === 2 && p.pinchStartDist !== null) {\n // Pinch zoom\n const dx = e.touches[0].clientX - e.touches[1].clientX;\n const dy = e.touches[0].clientY - e.touches[1].clientY;\n const dist = Math.hypot(dx, dy);\n const ratio = dist / p.pinchStartDist;\n const nextScale = Math.min(5, Math.max(1, p.pinchStartScale * ratio));\n const t = transformRef.current;\n let clamped: { x: number; y: number };\n if (nextScale <= 1) {\n clamped = { x: 0, y: 0 };\n } else if (zoomToCursor) {\n const midX = (e.touches[0].clientX + e.touches[1].clientX) / 2;\n const midY = (e.touches[0].clientY + e.touches[1].clientY) / 2;\n const focal = zoomToPoint(\n t.scale,\n nextScale,\n { x: t.x, y: t.y },\n { x: midX, y: midY },\n { width: window.innerWidth, height: window.innerHeight },\n );\n clamped = clampTranslate(focal.x, focal.y, nextScale);\n } else {\n clamped = clampTranslate(t.x, t.y, nextScale);\n }\n\n const next = { scale: nextScale, ...clamped };\n transformRef.current = next;\n applyTransform(next);\n // Sync display state for UI\n // (We set displayScale indirectly through setTransform would cause extra work,\n // so we just write to transformRef + applyTransform, and let touchEnd sync.)\n } else if (e.touches.length === 1 && p.lastTouchPos && transformRef.current.scale > 1) {\n // Zoomed pan\n const touch = e.touches[0];\n const dx = touch.clientX - p.lastTouchPos.x;\n const dy = touch.clientY - p.lastTouchPos.y;\n p.lastTouchPos = { x: touch.clientX, y: touch.clientY };\n\n const t = transformRef.current;\n const clamped = clampTranslate(t.x + dx, t.y + dy, t.scale);\n const next = { scale: t.scale, ...clamped };\n transformRef.current = next;\n applyTransform(next);\n } else if (e.touches.length === 1) {\n // Touch slide: lockThreshold=6, angleBias=0.8\n const touch = e.touches[0];\n updateSlide(touch.clientX, touch.clientY, 6, 0.8);\n }\n },\n [transformRef, clampTranslate, applyTransform, updateSlide, zoomToCursor],\n );\n\n const handleTouchEnd = useCallback(\n (e: React.TouchEvent) => {\n const p = panRef.current;\n const wasPinch = p.pinchStartDist !== null;\n p.pinchStartDist = null;\n p.pinchMidpoint = null;\n\n if (e.touches.length === 0 && transformRef.current.scale <= 1) {\n // Resolve slide if active\n const sg = slideRef.current;\n if (sg.active && sg.locked && !sg.rejected) {\n const startTime = sg.startTime;\n sg.active = false;\n resolveSlide(startTime);\n transformRef.current = { scale: 1, x: 0, y: 0 };\n return;\n }\n sg.active = false;\n resetTransform();\n }\n\n // One finger remaining after pinch → start pan from that finger\n if (e.touches.length === 1 && transformRef.current.scale > 1) {\n p.lastTouchPos = {\n x: e.touches[0].clientX,\n y: e.touches[0].clientY,\n };\n } else {\n p.lastTouchPos = null;\n }\n\n // Double-tap detection (single finger, not after pinch, not after slide)\n const sg = slideRef.current;\n if (\n zoomEnabled &&\n e.touches.length === 0 &&\n e.changedTouches.length === 1 &&\n !wasPinch &&\n !sg.locked\n ) {\n const touch = e.changedTouches[0];\n const now = Date.now();\n const last = lastTapRef.current;\n const timeDelta = now - last.time;\n const distDelta = Math.hypot(touch.clientX - last.x, touch.clientY - last.y);\n\n if (timeDelta < 300 && distDelta < 30) {\n lastTapRef.current = { time: 0, x: 0, y: 0 };\n if (transformRef.current.scale > 1) {\n resetTransform();\n } else {\n setTransform({ scale: 2.5, x: 0, y: 0 }, true);\n }\n } else {\n lastTapRef.current = { time: now, x: touch.clientX, y: touch.clientY };\n }\n }\n\n // Cleanup slide if released without committing\n if (e.touches.length === 0 && sg.active && !sg.locked) {\n sg.active = false;\n if (swipeOffsetRef.current === 0) setSlideActive(false);\n }\n },\n [\n transformRef,\n resetTransform,\n setTransform,\n resolveSlide,\n setSlideActive,\n swipeOffsetRef,\n zoomEnabled,\n ],\n );\n\n return {\n handlePointerDown,\n handlePointerMove,\n handlePointerUp,\n handleTouchStart,\n handleTouchMove,\n handleTouchEnd,\n };\n}\n","import { useLayoutEffect, useState, type RefObject } from \"react\";\n\n/**\n * Measures the height of the top and bottom bars so the image area\n * can be constrained to fit between them.\n */\nexport function useBarMeasure(\n topBarRef: RefObject<HTMLDivElement | null>,\n bottomBarRef: RefObject<HTMLDivElement | null>,\n /** Re-measure whenever this key changes (e.g. currentIndex) */\n measureKey: unknown,\n) {\n const [topBarH, setTopBarH] = useState(0);\n const [bottomBarH, setBottomBarH] = useState(0);\n\n // Measured before paint so the image is constrained to its final height on the\n // very first frame — otherwise it lays out tall (bottomBarH = 0), then visibly\n // shrinks once the bar is measured, which shows up as a flutter on open.\n useLayoutEffect(() => {\n const measure = () => {\n if (topBarRef.current) setTopBarH(topBarRef.current.offsetHeight);\n if (bottomBarRef.current) setBottomBarH(bottomBarRef.current.offsetHeight);\n };\n measure();\n\n const ro = new ResizeObserver(measure);\n if (topBarRef.current) ro.observe(topBarRef.current);\n if (bottomBarRef.current) ro.observe(bottomBarRef.current);\n return () => ro.disconnect();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [measureKey]);\n\n return { topBarH, bottomBarH };\n}\n","import { useEffect } from \"react\";\n\n/**\n * Locks scrolling on the document body while `isLocked` is true (e.g. while the\n * lightbox is open), so content behind the overlay can't be scrolled. To\n * prevent the content from shifting when the scrollbar disappears, the width\n * the scrollbar occupied is added back as right padding while locked. Restores\n * the previous body styles on unlock/unmount, and reference-counts concurrent\n * locks so closing one overlay doesn't release a lock held by another.\n *\n * The page is pinned with `position: fixed` and `top: -scrollY` rather than a\n * plain `overflow: hidden`. Overflow-only locking leaves the restored scroll\n * offset at the mercy of the browser: when the page is scrolled to (or near)\n * the bottom, hiding overflow collapses the scrollable range and the browser\n * clamps the offset, so on unlock the content visibly \"skips\" to a different\n * position. Pinning records the exact offset and restores it explicitly via\n * `scrollTo`, so the page holds still no matter where it was scrolled.\n *\n * If the page already reserves the scrollbar's space with `scrollbar-gutter:\n * stable` on the root element, that gutter stays reserved while locked, so the\n * padding compensation is skipped — adding it on top would shift the page by a\n * scrollbar's width (the visible \"jump\" it's meant to prevent).\n *\n * SSR-safe: the effect only runs in the browser, so importing this on the\n * server is a no-op.\n */\nlet lockCount = 0;\nlet previousOverflow = \"\";\nlet previousPaddingRight = \"\";\nlet previousPosition = \"\";\nlet previousTop = \"\";\nlet previousWidth = \"\";\nlet lockedScrollY = 0;\n\nexport function useBodyScrollLock(isLocked: boolean): void {\n useEffect(() => {\n if (!isLocked) return;\n if (typeof document === \"undefined\") return;\n\n if (lockCount === 0) {\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n\n // When the root reserves a stable gutter, the space stays reserved while\n // locked, so compensating with padding would shift the page instead of\n // holding it still.\n const rootGutter = window.getComputedStyle(document.documentElement).scrollbarGutter;\n const reservesGutter = typeof rootGutter === \"string\" && rootGutter.includes(\"stable\");\n\n lockedScrollY = window.scrollY;\n previousOverflow = document.body.style.overflow;\n previousPaddingRight = document.body.style.paddingRight;\n previousPosition = document.body.style.position;\n previousTop = document.body.style.top;\n previousWidth = document.body.style.width;\n\n // Pin the page at its current offset. `width: 100%` keeps the body its\n // normal width once it's out of flow; `overflow: hidden` guards against a\n // stray scroll on the (now un-pinned) root.\n document.body.style.overflow = \"hidden\";\n document.body.style.position = \"fixed\";\n document.body.style.top = `-${lockedScrollY}px`;\n document.body.style.width = \"100%\";\n if (scrollbarWidth > 0 && !reservesGutter) {\n const currentPaddingRight =\n parseFloat(window.getComputedStyle(document.body).paddingRight) || 0;\n document.body.style.paddingRight = `${currentPaddingRight + scrollbarWidth}px`;\n }\n }\n lockCount += 1;\n\n return () => {\n lockCount -= 1;\n if (lockCount === 0) {\n document.body.style.overflow = previousOverflow;\n document.body.style.paddingRight = previousPaddingRight;\n document.body.style.position = previousPosition;\n document.body.style.top = previousTop;\n document.body.style.width = previousWidth;\n // Restore the exact offset the page was pinned at.\n window.scrollTo(0, lockedScrollY);\n }\n };\n }, [isLocked]);\n}\n","import { useEffect, type RefObject } from \"react\";\n\nconst FOCUSABLE =\n 'a[href], button:not([disabled]), textarea, input, select, [tabindex]:not([tabindex=\"-1\"])';\n\n/**\n * Traps Tab focus within `containerRef` while `active`, and restores focus to\n * the previously-focused element on deactivate/unmount. SSR-safe (effect only\n * runs in the browser).\n */\nexport function useFocusTrap(containerRef: RefObject<HTMLElement | null>, active: boolean): void {\n useEffect(() => {\n if (!active) return;\n if (typeof document === \"undefined\") return;\n\n const previouslyFocused = document.activeElement as HTMLElement | null;\n const container = containerRef.current;\n\n // Move focus into the dialog so screen readers/keyboard land inside it.\n container?.focus();\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key !== \"Tab\" || !container) return;\n const focusable = Array.from(container.querySelectorAll<HTMLElement>(FOCUSABLE)).filter(\n (el) => el.offsetParent !== null || el === document.activeElement,\n );\n if (focusable.length === 0) {\n e.preventDefault();\n container.focus();\n return;\n }\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n const activeEl = document.activeElement;\n\n if (e.shiftKey && (activeEl === first || activeEl === container)) {\n e.preventDefault();\n last.focus();\n } else if (!e.shiftKey && activeEl === last) {\n e.preventDefault();\n first.focus();\n }\n };\n\n document.addEventListener(\"keydown\", onKeyDown);\n return () => {\n document.removeEventListener(\"keydown\", onKeyDown);\n previouslyFocused?.focus?.();\n };\n }, [containerRef, active]);\n}\n","import type { SVGProps } from \"react\";\nimport type { ViewerIcons } from \"../types\";\n\n// Inline default icons so the package has no runtime icon dependency (e.g.\n// lucide-react). Each is a 24x24 stroked glyph that inherits `currentColor`.\n// Consumers can override any of them via the `icons` prop.\n\nfunction base(props: SVGProps<SVGSVGElement>) {\n return {\n width: 18,\n height: 18,\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: 1.75,\n strokeLinecap: \"round\" as const,\n strokeLinejoin: \"round\" as const,\n \"aria-hidden\": true,\n focusable: false,\n ...props,\n };\n}\n\nexport function CloseIcon(props: SVGProps<SVGSVGElement>) {\n return (\n <svg {...base(props)}>\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n );\n}\n\nexport function ZoomInIcon(props: SVGProps<SVGSVGElement>) {\n return (\n <svg {...base(props)}>\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.3-4.3\" />\n <path d=\"M11 8v6\" />\n <path d=\"M8 11h6\" />\n </svg>\n );\n}\n\nexport function ZoomOutIcon(props: SVGProps<SVGSVGElement>) {\n return (\n <svg {...base(props)}>\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.3-4.3\" />\n <path d=\"M8 11h6\" />\n </svg>\n );\n}\n\nexport function ChevronLeftIcon(props: SVGProps<SVGSVGElement>) {\n return (\n <svg {...base({ width: 36, height: 36, strokeWidth: 1.5, ...props })}>\n <path d=\"m15 18-6-6 6-6\" />\n </svg>\n );\n}\n\nexport function ChevronRightIcon(props: SVGProps<SVGSVGElement>) {\n return (\n <svg {...base({ width: 36, height: 36, strokeWidth: 1.5, ...props })}>\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n );\n}\n\n/** The full default icon set, merged with any consumer overrides. */\nexport const defaultIcons: ViewerIcons = {\n close: <CloseIcon />,\n zoomIn: <ZoomInIcon />,\n zoomOut: <ZoomOutIcon />,\n prev: <ChevronLeftIcon />,\n next: <ChevronRightIcon />,\n};\n","/** Tiny className joiner: drops falsy values and joins with a space. */\nexport function cx(...parts: Array<string | false | null | undefined>): string {\n return parts.filter(Boolean).join(\" \");\n}\n","import type { ReactNode } from \"react\";\nimport { cx } from \"./cx\";\n\ninterface NavButtonProps {\n direction: \"prev\" | \"next\";\n enabled: boolean;\n onClick: () => void;\n icon: ReactNode;\n className?: string;\n}\n\nexport function NavButton({ direction, enabled, onClick, icon, className }: NavButtonProps) {\n return (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n if (enabled) onClick();\n }}\n disabled={!enabled}\n className={cx(\"rvl-nav-btn\", className)}\n aria-label={direction === \"prev\" ? \"Previous image\" : \"Next image\"}\n >\n {icon}\n </button>\n );\n}\n","import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from \"react\";\nimport type { ImageViewerProps, ViewerContext, ViewerRect } from \"../types\";\nimport { useImageZoomPan, MIN_SCALE, MAX_SCALE } from \"../hooks/useImageZoomPan\";\nimport { useSlideNavigation } from \"../hooks/useSlideNavigation\";\nimport { useGestureHandler } from \"../hooks/useGestureHandler\";\nimport { useBarMeasure } from \"../hooks/useBarMeasure\";\nimport { useBodyScrollLock } from \"../hooks/useBodyScrollLock\";\nimport { useFocusTrap } from \"../hooks/useFocusTrap\";\nimport { defaultIcons } from \"./icons\";\nimport { NavButton } from \"./NavButton\";\nimport { cx } from \"./cx\";\n\nconst ANIM_MS = 250;\nconst IMG_PADDING = 44;\n// Decelerating ease for the shared-element zoom so it settles softly.\nconst ZOOM_EASE = \"cubic-bezier(0.22, 1, 0.36, 1)\";\n\nfunction prefersReducedMotion(): boolean {\n if (typeof window === \"undefined\" || !window.matchMedia) return false;\n return window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n}\n\n/**\n * CSS transform that maps `from` (the element's current rect) onto `to`,\n * assuming a `top left` transform-origin. Used for the FLIP-style thumbnail\n * zoom: place the full image where the thumbnail is, then animate the transform\n * away so it glides into its real position.\n */\nfunction flipTransform(from: ViewerRect, to: ViewerRect): string {\n const sx = to.width / from.width;\n const sy = to.height / from.height;\n const dx = to.left - from.left;\n const dy = to.top - from.top;\n return `translate(${dx}px, ${dy}px) scale(${sx}, ${sy})`;\n}\n\n/**\n * True when the Web Animations API is usable on `el`. jsdom (tests) and very old\n * browsers lack `Element.prototype.animate`, so callers fall back to no anim.\n */\nfunction canAnimate(el: HTMLElement | null): el is HTMLElement {\n return !!el && typeof el.animate === \"function\";\n}\n\n/**\n * True when `rect` overlaps the current viewport at all. A thumbnail scrolled\n * out of view returns its (offscreen) rect just the same, so collapsing into it\n * would fly the image off to nowhere — callers fall back to a plain fade in that\n * case.\n */\nfunction isRectInViewport(rect: ViewerRect): boolean {\n if (typeof window === \"undefined\") return true;\n return (\n rect.top < window.innerHeight &&\n rect.top + rect.height > 0 &&\n rect.left < window.innerWidth &&\n rect.left + rect.width > 0\n );\n}\n\n/**\n * Batteries-included fullscreen image viewer: zoom, pan, pinch, and swipe\n * navigation with themeable chrome and render slots. Controlled via `index` /\n * `onIndexChange`; mount it when open and it runs its own enter/exit animation,\n * calling `onClose` after the exit completes.\n */\nexport function ImageViewer<TData = unknown>({\n items,\n index,\n onIndexChange,\n onNavigate,\n onClose,\n onEscape,\n getOriginRect,\n zoom = true,\n zoomToCursor = true,\n showCounter = true,\n showZoomControls = true,\n disableNavigation = false,\n loop = false,\n closeOnBackdropClick = false,\n renderHeader,\n renderHeaderActions,\n renderNavStart,\n renderNavEnd,\n navSlotPlacement = \"edge\",\n navHeight,\n navInset,\n counterFontSize,\n renderFooter,\n renderOverlay,\n classNames,\n icons,\n ariaLabel,\n}: ImageViewerProps<TData>) {\n const [visible, setVisible] = useState(false);\n const [closing, setClosing] = useState(false);\n // True only while a thumbnail FLIP collapse is animating the image back into\n // its source. Keeps the track opaque for that flight; a close without a\n // collapse (zoomed, reduced motion, no origin rect) leaves it false so the\n // track fades out instead of vanishing on unmount.\n const [collapsing, setCollapsing] = useState(false);\n const [isTouchDevice, setIsTouchDevice] = useState(false);\n const [contentShift, setContentShiftState] = useState<{\n transform: string | null;\n animate: boolean;\n }>({ transform: null, animate: true });\n\n const containerRef = useRef<HTMLDivElement>(null);\n const imgWrapperRef = useRef<HTMLDivElement>(null);\n const topBarRef = useRef<HTMLDivElement>(null);\n const bottomBarRef = useRef<HTMLDivElement>(null);\n\n const [viewportWidth, setViewportWidth] = useState(() =>\n typeof window === \"undefined\" ? 0 : window.innerWidth,\n );\n\n const item = items[index];\n\n const hasPrevLinear = index > 0;\n const hasNextLinear = index < items.length - 1;\n const hasPrev = loop ? items.length > 1 : hasPrevLinear;\n const hasNext = loop ? items.length > 1 : hasNextLinear;\n\n const mergedIcons = useMemo(() => ({ ...defaultIcons, ...icons }), [icons]);\n const cn = (slot: keyof NonNullable<ImageViewerProps[\"classNames\"]>) => classNames?.[slot];\n\n useBodyScrollLock(true);\n useFocusTrap(containerRef, visible && !closing);\n const { topBarH, bottomBarH } = useBarMeasure(topBarRef, bottomBarRef, index);\n\n const zoomPan = useImageZoomPan(imgWrapperRef, index, zoom, zoomToCursor);\n const {\n imgRef,\n displayScale,\n isZoomed,\n transformRef,\n resetTransform,\n setTransform,\n clampTranslate,\n measureBaseDims,\n handleDoubleClick,\n } = zoomPan;\n\n const slide = useSlideNavigation(items, index, onIndexChange, onNavigate, loop);\n const { slideTrackRef, slideActive, slideAnimating, swipeOffset, commitSlide } = slide;\n\n const gestures = useGestureHandler(zoomPan, slide, hasPrev, hasNext, zoom, zoomToCursor);\n\n useEffect(() => {\n // Only suppress the hover-only zoom buttons on touch-PRIMARY devices\n // (phones/tablets). Merely being touch-capable (a touchscreen laptop or\n // 2-in-1 driven by a mouse) reports maxTouchPoints > 0, which would wrongly\n // hide the controls even though the pointer can click them. `(hover: none)\n // and (pointer: coarse)` matches only devices whose primary input is touch.\n if (typeof window === \"undefined\" || !window.matchMedia) {\n setIsTouchDevice(\"ontouchstart\" in window || navigator.maxTouchPoints > 0);\n return;\n }\n const mq = window.matchMedia(\"(hover: none) and (pointer: coarse)\");\n const update = () => setIsTouchDevice(mq.matches);\n update();\n mq.addEventListener(\"change\", update);\n return () => mq.removeEventListener(\"change\", update);\n }, []);\n\n useEffect(() => {\n const onResize = () => setViewportWidth(window.innerWidth);\n window.addEventListener(\"resize\", onResize);\n return () => window.removeEventListener(\"resize\", onResize);\n }, []);\n\n useEffect(() => {\n const raf = requestAnimationFrame(() => setVisible(true));\n return () => cancelAnimationFrame(raf);\n }, []);\n\n // --- Shared-element thumbnail zoom ---------------------------------------\n // When `getOriginRect` is supplied the image expands out of its source\n // thumbnail on open and collapses back into it on close. Driven by the Web\n // Animations API on the <img> itself (zoom/pan owns the wrapper): WAAPI plays\n // from an explicit start keyframe and owns the transform for the animation's\n // duration, so React re-renders / the zoom-reset layout effect / frame timing\n // can't clobber it mid-flight (the failure mode of a raw inline transition).\n // The FLIP only ever scales down to ≤ 1, sidestepping the iOS upscale-clip bug\n // noted in useImageZoomPan.\n const zoomTransition = !!getOriginRect;\n const reduceMotion = prefersReducedMotion();\n // For a thumbnail zoom, hold the image hidden until its full-size source has\n // decoded, then play the zoom from the thumbnail. Animating before the bytes\n // are ready lets the browser paint a full-size frame first, which reads as the\n // image \"expanding twice\" on the first (uncached) open.\n const gateEntry = zoomTransition && !reduceMotion;\n\n // Whether the opening image has finished loading + decoding.\n const [fullLoaded, setFullLoaded] = useState(false);\n // Set true only if the load runs long, so quick opens never flash a spinner.\n const [showSpinner, setShowSpinner] = useState(false);\n\n const entryStartedRef = useRef(false);\n // Tears down the in-flight entry zoom (clears the inline transform, restores\n // the wrapper clip, cancels the animation). Set while the zoom is playing so\n // a close mid-flight can settle the image before measuring its collapse.\n const entryCleanupRef = useRef<(() => void) | null>(null);\n\n // Plays the shared-element zoom once, from the source thumbnail to the resting\n // image box. Only ever invoked after the full image has decoded (see below),\n // so the picture is paint-ready and the zoom can't flash a full-size frame.\n const runZoomEntry = useCallback(() => {\n if (entryStartedRef.current) return;\n if (!getOriginRect || prefersReducedMotion()) return;\n const img = imgRef.current;\n const thumb = getOriginRect(index);\n if (!thumb || !canAnimate(img)) return;\n\n // Pin the image to its final constrained height before measuring. The bottom\n // bar is measured in a post-paint effect, so on the opening frame `bottomBarH`\n // is still 0 and the React-driven maxHeight is too tall; locking it here (read\n // straight from the bar's DOM) keeps a late bottomBarH measurement from\n // resizing the image mid-flight, which is what makes the open animation\n // visibly jump / re-expand. Held for the whole flight, then matched to React's\n // now-settled value on finish.\n const bottomH = bottomBarRef.current?.offsetHeight ?? 0;\n const lockedMaxHeight = `calc(100vh - ${bottomH + IMG_PADDING * 2}px)`;\n img.style.maxHeight = lockedMaxHeight;\n\n const imgRect = img.getBoundingClientRect();\n if (imgRect.width === 0 || imgRect.height === 0) {\n img.style.maxHeight = \"\";\n return;\n }\n entryStartedRef.current = true;\n\n const startTransform = flipTransform(imgRect, thumb);\n\n // Pin the image to the thumbnail pose *synchronously*, before the browser\n // can paint. On a first (uncached) open this handler fires the instant the\n // full image decodes; a WAAPI animation only composites its first frame on\n // the next frame, so without this inline transform the browser paints one\n // full-size frame first — the image flashes out to full size, then zooms in\n // again (\"expands twice\"). It only shows on the uncached load because the\n // cached path starts the zoom before the first paint. React never writes\n // `transform`, so it won't clobber this.\n img.style.transformOrigin = \"top left\";\n img.style.transform = startTransform;\n\n // The wrapper clips to its own (centered) box; while the image is translated\n // out to the thumbnail it would otherwise be sliced off. Lift the clip for\n // the flight, then restore it so zoom/pan clipping still works afterwards.\n const wrapper = imgWrapperRef.current;\n if (wrapper) wrapper.style.overflow = \"visible\";\n\n // Play from the thumbnail's box to the resting box. `fill: \"forwards\"` holds\n // the resting pose at the end so the inline start transform can't flash back\n // before cleanup swaps it out.\n const anim = img.animate(\n [\n { transformOrigin: \"top left\", transform: startTransform },\n { transformOrigin: \"top left\", transform: \"none\" },\n ],\n { duration: ANIM_MS, easing: ZOOM_EASE, fill: \"forwards\" },\n );\n const cleanup = () => {\n // Match the inline base to the held resting pose, then release the fill:\n // computed style stays \"none\" across the swap, so there's no flicker, and\n // the image is handed cleanly back to zoom/pan.\n img.style.transform = \"\";\n img.style.transformOrigin = \"\";\n if (wrapper) wrapper.style.overflow = \"\";\n // Keep the height pinned to the (by now settled) final value; releasing to\n // \"\" with no following render could briefly drop the constraint entirely.\n img.style.maxHeight = lockedMaxHeight;\n anim.cancel();\n entryCleanupRef.current = null;\n };\n entryCleanupRef.current = cleanup;\n anim.onfinish = cleanup;\n }, [getOriginRect, index, imgRef, imgWrapperRef, bottomBarRef]);\n\n // Mark the opening image ready once it has both loaded and decoded. `decode()`\n // forces the decode up front so revealing the image can't flash; fall back to\n // a plain reveal where it's unsupported or rejects (e.g. the src changed).\n const markFullLoaded = useCallback(() => {\n measureBaseDims();\n const img = imgRef.current;\n if (img && typeof img.decode === \"function\") {\n img.decode().then(\n () => setFullLoaded(true),\n () => setFullLoaded(true),\n );\n } else {\n setFullLoaded(true);\n }\n }, [measureBaseDims, imgRef]);\n\n // A cached image can already be `complete` before React wires up onLoad; pick\n // it up on mount so the open isn't stuck waiting for an event that won't fire.\n useLayoutEffect(() => {\n const img = imgRef.current;\n if (img && img.complete && img.naturalWidth > 0) markFullLoaded();\n // Mount-only: the opening image.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Once the image is decoded, play the entry zoom (a no-op for non-zoom opens,\n // reduced motion, or a repeat call — all guarded inside runZoomEntry).\n useLayoutEffect(() => {\n if (fullLoaded) runZoomEntry();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [fullLoaded]);\n\n // Reveal the spinner only after the wait crosses 500ms, then clear it the\n // moment the image is ready (or the gate no longer applies).\n useEffect(() => {\n if (!gateEntry || fullLoaded) {\n setShowSpinner(false);\n return;\n }\n const t = setTimeout(() => setShowSpinner(true), 500);\n return () => clearTimeout(t);\n }, [gateEntry, fullLoaded]);\n\n const handleClose = useCallback(() => {\n const reduce = prefersReducedMotion();\n // Collapse back into the source thumbnail when one exists, is still on\n // screen, and the image isn't zoomed (a zoomed image's box no longer\n // matches the thumbnail; an off-screen thumbnail would fly to nowhere, so\n // fall back to the plain fade).\n const origin = !reduce && !isZoomed ? (getOriginRect?.(index) ?? null) : null;\n const thumb = origin && isRectInViewport(origin) ? origin : null;\n const img = imgRef.current;\n\n // If the open zoom is still playing, settle the image to its resting pose\n // first so the collapse measures the real box, not a mid-flight transform.\n entryCleanupRef.current?.();\n\n setClosing(true);\n setVisible(false);\n\n if (thumb && canAnimate(img)) {\n const imgRect = img.getBoundingClientRect();\n // Lift the wrapper clip so the image isn't sliced as it flies back to the\n // thumbnail; the component unmounts at onClose, so no restore is needed.\n const wrapper = imgWrapperRef.current;\n if (wrapper) wrapper.style.overflow = \"visible\";\n setCollapsing(true);\n // fill \"forwards\" holds the collapsed pose until the component unmounts.\n img.animate(\n [\n { transformOrigin: \"top left\", transform: \"none\" },\n { transformOrigin: \"top left\", transform: flipTransform(imgRect, thumb) },\n ],\n { duration: ANIM_MS, easing: ZOOM_EASE, fill: \"forwards\" },\n );\n }\n // Otherwise the backdrop/bars/track simply fade out (default close).\n\n setTimeout(onClose, reduce ? 0 : ANIM_MS);\n }, [onClose, getOriginRect, index, isZoomed, imgRef, imgWrapperRef]);\n\n const navigate = useCallback(\n (dir: \"prev\" | \"next\") => {\n // commitSlide plays the three-slot slide and wraps the index itself when\n // looping, so boundary wraps animate in exactly like an interior move.\n if (dir === \"prev\") {\n if (hasPrev) commitSlide(\"prev\");\n } else {\n if (hasNext) commitSlide(\"next\");\n }\n },\n [hasPrev, hasNext, commitSlide],\n );\n\n useEffect(() => {\n const handler = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n // Let the consumer dismiss its own overlay first; only close when the\n // veto hook declines to handle the key.\n if (onEscape?.()) return;\n handleClose();\n return;\n }\n if (disableNavigation || displayScale > 1) return;\n if (e.key === \"ArrowLeft\" && hasPrev) navigate(\"prev\");\n if (e.key === \"ArrowRight\" && hasNext) navigate(\"next\");\n };\n window.addEventListener(\"keydown\", handler);\n return () => window.removeEventListener(\"keydown\", handler);\n }, [handleClose, hasPrev, hasNext, displayScale, navigate, onEscape, disableNavigation]);\n\n const setContentShift = useCallback((transform: string | null, animate = true) => {\n setContentShiftState({ transform, animate });\n }, []);\n\n const ctx: ViewerContext<TData> = {\n items,\n index,\n item: item!,\n total: items.length,\n closing,\n hasPrev,\n hasNext,\n goPrev: () => navigate(\"prev\"),\n goNext: () => navigate(\"next\"),\n goTo: (i: number) => {\n if (i !== index && i >= 0 && i < items.length) onIndexChange(i);\n },\n close: handleClose,\n isZoomed,\n displayScale,\n zoomIn: () => {\n const t = transformRef.current;\n const next = Math.min(MAX_SCALE, t.scale * 1.3);\n const clamped = clampTranslate(t.x, t.y, next);\n setTransform({ scale: next, ...clamped }, true);\n },\n zoomOut: () => {\n const t = transformRef.current;\n const next = Math.max(MIN_SCALE, t.scale / 1.3);\n const clamped = next <= 1 ? { x: 0, y: 0 } : clampTranslate(t.x, t.y, next);\n setTransform({ scale: next, ...clamped }, true);\n },\n resetZoom: resetTransform,\n isTouchDevice,\n topBarHeight: topBarH,\n bottomBarHeight: bottomBarH,\n setContentShift,\n };\n\n if (!item) return null;\n\n const reservedH = bottomBarH + IMG_PADDING * 2;\n const imgMaxHeight = `calc(100vh - ${reservedH}px)`;\n const imgStyle: React.CSSProperties = { maxHeight: imgMaxHeight };\n\n // Numbers become px; strings pass through (e.g. \"1.5rem\"). Only emit vars that\n // were supplied so the stylesheet defaults still apply otherwise.\n const dim = (v: number | string) => (typeof v === \"number\" ? `${v}px` : v);\n const rootStyle: React.CSSProperties = {\n ...(navHeight != null && { \"--rvl-nav-height\": dim(navHeight) }),\n ...(navInset != null && { \"--rvl-nav-inset\": dim(navInset) }),\n ...(counterFontSize != null && { \"--rvl-counter-font-size\": dim(counterFontSize) }),\n } as React.CSSProperties;\n // Keep the image hidden (but laid out, so the zoom can still measure its box)\n // until the full source has decoded, so the entry plays from the thumbnail\n // with no full-size flash. opacity, not display, to preserve the layout box.\n if (gateEntry && !fullLoaded) imgStyle.opacity = 0;\n\n const totalDigits = String(items.length).length;\n const counterMinWidth = `${totalDigits * 2 * 0.6 + 1.5}em`;\n\n // Three-slot carousel neighbors. When looping, the slots at the ends point at\n // the wrap-around items (last ↔ first) so the wrapping slide has a real image\n // to reveal instead of an empty panel.\n const prevIndex = hasPrevLinear ? index - 1 : hasPrev ? items.length - 1 : -1;\n const nextIndex = hasNextLinear ? index + 1 : hasNext ? 0 : -1;\n const prevItem = prevIndex >= 0 ? items[prevIndex] : null;\n const nextItem = nextIndex >= 0 ? items[nextIndex] : null;\n const showAdjacent = slideActive || slideAnimating || swipeOffset !== 0;\n const adjacentOpacity = Math.min(1, Math.abs(swipeOffset) / (viewportWidth * 0.8 || 1));\n\n // Never show the zoom controls while the image is shifted out of view (e.g. a\n // consumer-driven details/overlay pane pushed in via setContentShift): the\n // image isn't on screen, so zooming it makes no sense.\n const showZoomCtrls = zoom && !isTouchDevice && showZoomControls && !contentShift.transform;\n const headerActions = renderHeaderActions?.(ctx);\n const navStart = renderNavStart?.(ctx);\n const navEnd = renderNavEnd?.(ctx);\n const hasNavGroup = hasPrev || hasNext;\n const showNavRow = !isZoomed && (hasNavGroup || navStart != null || navEnd != null);\n\n return (\n <div\n ref={containerRef}\n className={cx(\"rvl-root\", visible && !closing && \"rvl-visible\", cn(\"root\"))}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={ariaLabel ?? item.alt ?? \"Image viewer\"}\n tabIndex={-1}\n style={rootStyle}\n >\n <div\n className={cx(\"rvl-backdrop\", cn(\"backdrop\"))}\n onClick={closeOnBackdropClick ? handleClose : undefined}\n aria-hidden=\"true\"\n />\n\n <div ref={topBarRef} className={cx(\"rvl-bar\", \"rvl-top-bar\", cn(\"topBar\"))}>\n <div className={cx(\"rvl-header\", cn(\"topBar\"))}>{renderHeader?.(ctx)}</div>\n\n <div className=\"rvl-header-actions\">\n {headerActions}\n\n {showZoomCtrls && isZoomed && (\n <button\n type=\"button\"\n className={cx(\"rvl-btn\", \"rvl-btn-scale\", cn(\"button\"))}\n onClick={(e) => {\n e.stopPropagation();\n resetTransform();\n }}\n title=\"Reset zoom\"\n aria-label=\"Reset zoom\"\n >\n {Math.round(displayScale * 100)}%\n </button>\n )}\n\n {showZoomCtrls && (\n <button\n type=\"button\"\n className={cx(\"rvl-btn\", cn(\"button\"))}\n onClick={(e) => {\n e.stopPropagation();\n ctx.zoomIn();\n }}\n title=\"Zoom in\"\n aria-label=\"Zoom in\"\n >\n {mergedIcons.zoomIn}\n </button>\n )}\n\n {showZoomCtrls && (\n <button\n type=\"button\"\n className={cx(\"rvl-btn\", cn(\"button\"))}\n onClick={(e) => {\n e.stopPropagation();\n ctx.zoomOut();\n }}\n title=\"Zoom out\"\n aria-label=\"Zoom out\"\n >\n {mergedIcons.zoomOut}\n </button>\n )}\n\n <button\n type=\"button\"\n className={cx(\"rvl-btn\", cn(\"button\"))}\n onClick={(e) => {\n e.stopPropagation();\n handleClose();\n }}\n title=\"Close (Esc)\"\n aria-label=\"Close\"\n >\n {mergedIcons.close}\n </button>\n </div>\n </div>\n\n <div\n className=\"rvl-stage\"\n // The stage (z-index 10) sits over the backdrop (z-index 0) and captures\n // its clicks, so the backdrop's own handler can't fire. Close from here\n // when the click lands on the stage itself — the image wrapper stops\n // propagation and the track/adjacent layers are pointer-events:none, so\n // only genuine background clicks reach this guard.\n onClick={\n closeOnBackdropClick\n ? (e) => {\n if (e.target === e.currentTarget) handleClose();\n }\n : undefined\n }\n style={{\n transform: contentShift.transform ?? \"translateY(0)\",\n // animate=false snaps with no transition (overrides the CSS transition)\n transition: contentShift.animate ? undefined : \"none\",\n }}\n >\n <div\n ref={slideTrackRef}\n className={cx(\n \"rvl-track\",\n // During a thumbnail zoom the track is opaque from the first frame\n // (the image itself is hidden until the zoom starts), so the picture\n // flies in crisply instead of cross-fading. On close it only stays\n // opaque while a FLIP collapse is animating the image back; otherwise\n // it fades out (so a zoomed close still animates instead of vanishing).\n (closing ? collapsing : zoomTransition || visible) && \"rvl-track-visible\",\n )}\n >\n {showAdjacent && prevItem && (\n <div\n className=\"rvl-adjacent\"\n style={{ transform: `translateX(-${viewportWidth}px)`, opacity: adjacentOpacity }}\n >\n <img\n src={prevItem.src}\n alt=\"\"\n className={cx(\"rvl-img\", cn(\"image\"))}\n style={imgStyle}\n draggable={false}\n />\n </div>\n )}\n\n <div\n ref={imgWrapperRef}\n className=\"rvl-img-wrapper\"\n onClick={(e) => e.stopPropagation()}\n onDoubleClick={handleDoubleClick}\n onPointerDown={gestures.handlePointerDown}\n onPointerMove={gestures.handlePointerMove}\n onPointerUp={gestures.handlePointerUp}\n onPointerLeave={gestures.handlePointerUp}\n onTouchStart={gestures.handleTouchStart}\n onTouchMove={gestures.handleTouchMove}\n onTouchEnd={gestures.handleTouchEnd}\n >\n <img\n ref={imgRef}\n src={item.src}\n alt={item.alt ?? \"\"}\n className={cx(\"rvl-img\", cn(\"image\"))}\n style={imgStyle}\n draggable={false}\n onLoad={markFullLoaded}\n // Don't strand the open on a broken image: reveal it (skipping the\n // zoom) so the spinner clears and the viewer stays usable.\n onError={() => setFullLoaded(true)}\n />\n </div>\n\n {gateEntry && showSpinner && !fullLoaded && (\n <div className={cx(\"rvl-spinner\", cn(\"spinner\"))} role=\"status\" aria-label=\"Loading\">\n <span className=\"rvl-spinner-ring\" aria-hidden=\"true\" />\n </div>\n )}\n\n {showAdjacent && nextItem && (\n <div\n className=\"rvl-adjacent\"\n style={{ transform: `translateX(${viewportWidth}px)`, opacity: adjacentOpacity }}\n >\n <img\n src={nextItem.src}\n alt=\"\"\n className={cx(\"rvl-img\", cn(\"image\"))}\n style={imgStyle}\n draggable={false}\n />\n </div>\n )}\n </div>\n </div>\n\n <div ref={bottomBarRef} className={cx(\"rvl-bar\", \"rvl-bottom-bar\", cn(\"bottomBar\"))}>\n {showNavRow && (\n <div className=\"rvl-nav-row\">\n <div className={cx(\"rvl-nav-inner\", navSlotPlacement === \"inline\" && \"rvl-nav-inline\")}>\n {navStart != null && (\n <div className={cx(\"rvl-nav-start\", cn(\"navStart\"))}>{navStart}</div>\n )}\n {hasNavGroup && (\n <div className=\"rvl-nav-group\">\n <NavButton\n direction=\"prev\"\n enabled={hasPrev}\n onClick={() => navigate(\"prev\")}\n icon={mergedIcons.prev}\n className={cn(\"navButton\")}\n />\n {showCounter && (\n <span\n className={cx(\"rvl-counter\", cn(\"counter\"))}\n style={{ minWidth: counterMinWidth }}\n >\n {index + 1} / {items.length}\n </span>\n )}\n <NavButton\n direction=\"next\"\n enabled={hasNext}\n onClick={() => navigate(\"next\")}\n icon={mergedIcons.next}\n className={cn(\"navButton\")}\n />\n </div>\n )}\n {navEnd != null && <div className={cx(\"rvl-nav-end\", cn(\"navEnd\"))}>{navEnd}</div>}\n </div>\n </div>\n )}\n\n {renderFooter && <div className=\"rvl-footer\">{renderFooter(ctx)}</div>}\n </div>\n\n {renderOverlay && (\n <div className={cx(\"rvl-overlay\", cn(\"overlay\"))}>{renderOverlay(ctx)}</div>\n )}\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/hooks/math.ts","../src/hooks/useImageZoomPan.ts","../src/hooks/useSlideNavigation.ts","../src/hooks/useGestureHandler.ts","../src/hooks/useBarMeasure.ts","../src/hooks/useBodyScrollLock.ts","../src/hooks/useFocusTrap.ts","../src/hooks/useSharedElementZoom.ts","../src/components/icons.tsx","../src/components/cx.ts","../src/components/NavButton.tsx","../src/components/ChromeButton.tsx","../src/components/ImageViewer.tsx"],"names":["useRef","useState","useCallback","clampTranslate","useLayoutEffect","useEffect","sg","jsxs","jsx","useMemo"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Pure geometry/threshold helpers shared by the interaction hooks. Kept free of\n * React and DOM globals so they can be unit-tested in isolation.\n */\n\nexport interface Dims {\n width: number;\n height: number;\n}\n\n/**\n * Clamp a pan translation so the scaled image edge can't move past the\n * viewport edge. Returns `{ x: 0, y: 0 }` when not zoomed or when base\n * dimensions are unknown.\n */\nexport function clampTranslate(\n x: number,\n y: number,\n scale: number,\n baseDims: Dims,\n viewport: Dims,\n): { x: number; y: number } {\n if (scale <= 1) return { x: 0, y: 0 };\n const { width: baseW, height: baseH } = baseDims;\n if (baseW === 0 || baseH === 0) return { x: 0, y: 0 };\n\n const scaledHalfW = (baseW * scale) / 2;\n const scaledHalfH = (baseH * scale) / 2;\n const vpHalfW = viewport.width / 2;\n const vpHalfH = viewport.height / 2;\n\n const maxX = Math.max(0, scaledHalfW - vpHalfW);\n const maxY = Math.max(0, scaledHalfH - vpHalfH);\n\n return {\n x: Math.max(-maxX, Math.min(maxX, x)),\n y: Math.max(-maxY, Math.min(maxY, y)),\n };\n}\n\n/**\n * Compute the pan translation that keeps the content under a focal point\n * (cursor or pinch midpoint) anchored as the scale changes from `prevScale`\n * to `nextScale`.\n *\n * The viewer scales the wrapper about the viewport center, so the on-screen\n * position of a content point is `center + scale * (point - center) + t`.\n * Solving \"the content at `focal` before the zoom is still at `focal` after\"\n * for the new translate gives the closed form below. Pass `focal` in viewport\n * coordinates (e.g. `clientX`/`clientY`). The result is unclamped — feed it\n * through {@link clampTranslate} before applying.\n */\nexport function zoomToPoint(\n prevScale: number,\n nextScale: number,\n prev: { x: number; y: number },\n focal: { x: number; y: number },\n viewport: Dims,\n): { x: number; y: number } {\n const relX = focal.x - viewport.width / 2;\n const relY = focal.y - viewport.height / 2;\n const k = nextScale / prevScale;\n return {\n x: relX * (1 - k) + k * prev.x,\n y: relY * (1 - k) + k * prev.y,\n };\n}\n\nexport interface ComputeZoomTransformArgs {\n prevScale: number;\n nextScale: number;\n /** Current translate. */\n prev: { x: number; y: number };\n /** Focal point in viewport coords (cursor / pinch midpoint). */\n focal: { x: number; y: number };\n viewport: Dims;\n baseDims: Dims;\n /** When true, anchor the zoom on `focal`; when false, zoom about the center. */\n zoomToCursor: boolean;\n /**\n * Extra translation added to the focal-anchored result before clamping. Used\n * by pinch to also pan by however far the midpoint drifted between frames.\n */\n focalPan?: { x: number; y: number };\n}\n\n/**\n * Resolve the clamped translate for a zoom step, sharing the wheel and pinch\n * branch logic: snaps to the origin when zooming back to ≤ 1, anchors on the\n * focal point when `zoomToCursor`, otherwise holds the current translate — then\n * clamps the result to the viewport.\n */\nexport function computeZoomTransform({\n prevScale,\n nextScale,\n prev,\n focal,\n viewport,\n baseDims,\n zoomToCursor,\n focalPan,\n}: ComputeZoomTransformArgs): { x: number; y: number } {\n if (nextScale <= 1) return { x: 0, y: 0 };\n if (zoomToCursor) {\n const f = zoomToPoint(prevScale, nextScale, prev, focal, viewport);\n return clampTranslate(\n f.x + (focalPan?.x ?? 0),\n f.y + (focalPan?.y ?? 0),\n nextScale,\n baseDims,\n viewport,\n );\n }\n return clampTranslate(prev.x, prev.y, nextScale, baseDims, viewport);\n}\n\nexport type SlideAction = \"prev\" | \"next\" | \"snap\";\n\nexport interface ResolveSlideArgs {\n /** Current horizontal swipe offset in px (positive = dragged right). */\n offset: number;\n /** Elapsed time of the gesture in ms (used for fling velocity). */\n elapsedMs: number;\n viewportWidth: number;\n hasPrev: boolean;\n hasNext: boolean;\n /** Fraction of viewport width past which a drag commits. Default 0.25. */\n distanceThreshold?: number;\n /** px/ms past which a fast fling commits regardless of distance. Default 0.4. */\n velocityThreshold?: number;\n}\n\n/**\n * Decide whether a released swipe should navigate `prev`/`next` or `snap` back,\n * based on distance and fling velocity.\n */\nexport function resolveSlideDirection({\n offset,\n elapsedMs,\n viewportWidth,\n hasPrev,\n hasNext,\n distanceThreshold = 0.25,\n velocityThreshold = 0.4,\n}: ResolveSlideArgs): SlideAction {\n const velocity = Math.abs(offset) / Math.max(elapsedMs, 1);\n const threshold = viewportWidth * distanceThreshold;\n const committed = Math.abs(offset) > threshold || velocity > velocityThreshold;\n\n if (offset > 0 && hasPrev && committed) return \"prev\";\n if (offset < 0 && hasNext && committed) return \"next\";\n return \"snap\";\n}\n","import { useCallback, useEffect, useLayoutEffect, useRef, useState, type RefObject } from \"react\";\nimport { clampTranslate as clampTranslatePure, computeZoomTransform } from \"./math\";\n\nconst MIN_SCALE = 1;\nconst MAX_SCALE = 5;\n/** Target scale for a desktop double-click zoom (a modest step-in). */\nconst DOUBLE_CLICK_ZOOM_SCALE = 1.8;\n\nexport interface ImageTransform {\n scale: number;\n x: number;\n y: number;\n}\n\n/**\n * Clears the inline styles the zoom applies to the wrapper, returning it to its\n * resting (unzoomed) state. Leaves `transition` alone so callers can control\n * whether the reset animates.\n */\nfunction resetWrapperStyles(wrapper: HTMLDivElement) {\n wrapper.style.transform = \"none\";\n wrapper.style.position = \"\";\n wrapper.style.inset = \"\";\n wrapper.style.zIndex = \"\";\n wrapper.style.backgroundColor = \"\";\n wrapper.style.cursor = \"\";\n // Release the compositing layer once the zoom settles back to 1.\n wrapper.style.willChange = \"\";\n}\n\nexport interface ImageZoomPanState {\n imgRef: RefObject<HTMLImageElement | null>;\n displayScale: number;\n isZoomed: boolean;\n transformRef: React.MutableRefObject<ImageTransform>;\n\n /** Base (unscaled) image dimensions for clamp calculations */\n baseDimsRef: React.MutableRefObject<{ width: number; height: number }>;\n\n resetTransform: () => void;\n /**\n * `animate` may be a boolean (true = default 0.2s ease-out) or an explicit\n * CSS transition string (e.g. a shorter one for smooth wheel-zoom stepping).\n */\n setTransform: (t: ImageTransform, animate?: boolean | string) => void;\n applyTransform: (t: ImageTransform, animate?: boolean | string) => void;\n clampTranslate: (x: number, y: number, scale: number) => { x: number; y: number };\n measureBaseDims: () => void;\n handleDoubleClick: (e: React.MouseEvent) => void;\n}\n\n/**\n * Manages zoom/pan state for an image viewer.\n *\n * Applies scale + translate transforms to the **wrapper** element rather\n * than the image itself. This avoids an iOS Safari compositing bug where\n * CSS scale() on an element clips its painted output to the element's\n * original layout bounds.\n *\n * When zoomed, the wrapper is positioned absolute inset-0 (full viewport),\n * so its layout bounds already match the viewport and scaling it won't clip.\n * The image stays at its natural constrained size, centered via flexbox.\n */\nexport function useImageZoomPan(\n imgWrapperRef: RefObject<HTMLDivElement | null>,\n currentIndex: number,\n /** When false, wheel-zoom and double-click-zoom are disabled. Default true. */\n enabled = true,\n /**\n * When true (default), wheel-zoom anchors on the cursor. When false, it zooms\n * about the viewport center.\n */\n zoomToCursor = true,\n): ImageZoomPanState {\n const imgRef = useRef<HTMLImageElement>(null);\n const [displayScale, setDisplayScale] = useState(1);\n const transformRef = useRef<ImageTransform>({ scale: 1, x: 0, y: 0 });\n const baseDimsRef = useRef<{ width: number; height: number }>({ width: 0, height: 0 });\n\n // Core helpers\n\n const applyTransform = useCallback(\n (t: ImageTransform, animate: boolean | string = false) => {\n const wrapper = imgWrapperRef.current;\n if (!wrapper) return;\n wrapper.style.transition =\n typeof animate === \"string\" ? animate : animate ? \"transform 0.2s ease-out\" : \"none\";\n\n if (t.scale <= 1) {\n resetWrapperStyles(wrapper);\n } else {\n wrapper.style.transform = `scale(${t.scale}) translate(${t.x / t.scale}px, ${t.y / t.scale}px)`;\n wrapper.style.position = \"absolute\";\n wrapper.style.inset = \"0\";\n wrapper.style.zIndex = \"30\";\n wrapper.style.backgroundColor = \"black\";\n wrapper.style.cursor = \"grab\";\n // Promote only while zoomed/panning; the wrapper is the element the\n // zoom transform lives on, so this is where the hint belongs.\n wrapper.style.willChange = \"transform\";\n }\n\n // Keep React state in sync so isZoomed reflects reality\n setDisplayScale(t.scale);\n },\n [imgWrapperRef],\n );\n\n const setTransform = useCallback(\n (t: ImageTransform, animate: boolean | string = false) => {\n transformRef.current = t;\n applyTransform(t, animate);\n setDisplayScale(t.scale);\n },\n [applyTransform],\n );\n\n const resetTransform = useCallback(() => {\n setTransform({ scale: 1, x: 0, y: 0 }, true);\n }, [setTransform]);\n\n const measureBaseDims = useCallback(() => {\n const img = imgRef.current;\n if (!img) return;\n baseDimsRef.current = { width: img.offsetWidth, height: img.offsetHeight };\n }, []);\n\n // Lazily populate base dims the first time a zoom gesture needs them (wheel /\n // double-click can fire before the load effect has measured).\n const ensureBaseDims = useCallback(() => {\n if (baseDimsRef.current.width === 0) measureBaseDims();\n }, [measureBaseDims]);\n\n /**\n * Clamp so the image edge can't pan past the viewport edge.\n */\n const clampTranslate = useCallback(\n (x: number, y: number, scale: number): { x: number; y: number } =>\n clampTranslatePure(x, y, scale, baseDimsRef.current, {\n width: window.innerWidth,\n height: window.innerHeight,\n }),\n [],\n );\n\n // Reset on navigation\n\n useLayoutEffect(() => {\n const wrapper = imgWrapperRef.current;\n if (wrapper) {\n wrapper.style.transition = \"none\";\n resetWrapperStyles(wrapper);\n }\n transformRef.current = { scale: 1, x: 0, y: 0 };\n }, [currentIndex, imgWrapperRef]);\n\n useEffect(() => {\n setDisplayScale(1);\n }, [currentIndex]);\n\n // Wheel zoom (desktop)\n\n useEffect(() => {\n if (!enabled) return;\n const wrapper = imgWrapperRef.current;\n if (!wrapper) return;\n\n const handleWheel = (e: WheelEvent) => {\n e.preventDefault();\n\n ensureBaseDims();\n\n const t = transformRef.current;\n\n let dy = e.deltaY;\n if (e.deltaMode === 1) dy *= 16;\n if (e.deltaMode === 2) dy *= 100;\n\n const normalized = Math.max(-100, Math.min(100, dy));\n const step = -(normalized / 100) * 0.05;\n const factor = 1 + step;\n\n const nextScale = Math.min(MAX_SCALE, Math.max(MIN_SCALE, t.scale * factor));\n const clamped = computeZoomTransform({\n prevScale: t.scale,\n nextScale,\n prev: { x: t.x, y: t.y },\n focal: { x: e.clientX, y: e.clientY },\n viewport: { width: window.innerWidth, height: window.innerHeight },\n baseDims: baseDimsRef.current,\n zoomToCursor,\n });\n // A short transition lets each discrete wheel tick glide into the next\n // instead of snapping, which smooths out the stepped look of scroll-zoom.\n // Rapid ticks restart the transition, producing continuous motion.\n setTransform({ scale: nextScale, ...clamped }, \"transform 0.1s ease-out\");\n };\n\n wrapper.addEventListener(\"wheel\", handleWheel, { passive: false });\n return () => wrapper.removeEventListener(\"wheel\", handleWheel);\n }, [imgWrapperRef, setTransform, enabled, zoomToCursor, ensureBaseDims]);\n\n // Double-click toggle\n\n const handleDoubleClick = useCallback(\n (e: React.MouseEvent) => {\n if (!enabled) return;\n e.stopPropagation();\n\n ensureBaseDims();\n\n if (transformRef.current.scale > 1) {\n resetTransform();\n } else {\n setTransform({ scale: DOUBLE_CLICK_ZOOM_SCALE, x: 0, y: 0 }, true);\n }\n },\n [resetTransform, setTransform, enabled, ensureBaseDims],\n );\n\n return {\n imgRef,\n displayScale,\n isZoomed: displayScale > 1,\n transformRef,\n baseDimsRef,\n resetTransform,\n setTransform,\n applyTransform,\n clampTranslate,\n measureBaseDims,\n handleDoubleClick,\n };\n}\n\nexport { MIN_SCALE, MAX_SCALE };\n","import { useCallback, useEffect, useLayoutEffect, useRef, useState } from \"react\";\nimport type { ViewerItem } from \"../types\";\nimport { resolveSlideDirection } from \"./math\";\n\n/**\n * Run `cb` exactly once when `el` finishes its transition, or after `fallbackMs`\n * if `transitionend` never fires (an interrupted transition, or none set). No-op\n * when `el` is null.\n */\n/**\n * Distance the track travels on a commit, in px. A letterboxed image sits\n * centered in a full-width track, so revealing a neighbor one *full* track\n * width away (translateX(±100%)) means the incoming image has to cross the\n * empty side margin before it even reaches the screen edge — in landscape,\n * with wide margins, it appears to lag far behind the outgoing image and then\n * rush to center. Sliding by the image width plus the near margin instead\n * (== vw − margin == (vw + imgW) / 2) starts the neighbor right at the screen\n * edge, so it enters immediately and both images travel the same distance at\n * the same speed. The neighbor panels are positioned at this same offset so the\n * committed slide lands them exactly centered.\n */\nfunction measureSlideDistance(track: HTMLElement | null): number {\n const vw = track?.clientWidth || window.innerWidth;\n const img = track?.querySelector<HTMLElement>(\".rvl-img-wrapper > img\");\n const imgW = img?.offsetWidth ?? 0;\n if (!imgW) return vw;\n // Never exceed the full track width (a near-full-bleed image ⇒ ~vw, i.e. the\n // classic full-width carousel slide).\n return Math.min(vw, (vw + imgW) / 2);\n}\n\n/**\n * Run `cb` exactly once when `el` finishes its transition, or after `fallbackMs`\n * if `transitionend` never fires (an interrupted transition, or none set). No-op\n * when `el` is null.\n */\nfunction onTransitionEndOnce(el: HTMLElement | null, cb: () => void, fallbackMs: number) {\n if (!el) return;\n let done = false;\n const run = () => {\n if (done) return;\n done = true;\n el.removeEventListener(\"transitionend\", run);\n cb();\n };\n el.addEventListener(\"transitionend\", run, { once: true });\n setTimeout(run, fallbackMs);\n}\n\nexport interface SlideNavigationState {\n slideTrackRef: React.RefObject<HTMLDivElement | null>;\n slideActive: boolean;\n slideAnimating: boolean;\n swipeOffset: number;\n swipeOffsetRef: React.MutableRefObject<number>;\n commitLockRef: React.MutableRefObject<boolean>;\n /**\n * Px distance the committed slide travels; also where the neighbor panels are\n * positioned so they land centered. See {@link measureSlideDistance}.\n */\n slideDistance: number;\n\n applySlideOffset: (offset: number, animate?: boolean) => void;\n commitSlide: (direction: \"prev\" | \"next\") => void;\n snapBack: () => void;\n resolveSlide: (gestureStartTime: number) => void;\n setSlideActive: React.Dispatch<React.SetStateAction<boolean>>;\n /** Measure the current image and refresh {@link slideDistance} (call at drag start). */\n refreshSlideDistance: () => void;\n}\n\n/**\n * Manages the three-slot slide carousel: swipe offset tracking, animated\n * commit/snap-back, and DOM resets on navigation.\n *\n * `items[i].src` is treated as a final, ready-to-load url — the next image is\n * preloaded/decoded before navigation commits so the swipe lands on a painted\n * frame.\n */\nexport function useSlideNavigation(\n items: ViewerItem[],\n currentIndex: number,\n onNavigate: (index: number) => void,\n onSlideStart?: (direction: \"prev\" | \"next\") => void,\n /** When true, navigation wraps around the ends instead of stopping. */\n loop = false,\n): SlideNavigationState {\n const slideTrackRef = useRef<HTMLDivElement>(null);\n const swipeOffsetRef = useRef(0);\n const [swipeOffset, setSwipeOffset] = useState(0);\n const [slideAnimating, setSlideAnimating] = useState(false);\n const [slideActive, setSlideActive] = useState(false);\n const [slideDistance, setSlideDistance] = useState(0);\n const commitLockRef = useRef(false);\n\n const refreshSlideDistance = useCallback(() => {\n setSlideDistance(measureSlideDistance(slideTrackRef.current));\n }, []);\n\n // With loop on, every interior position has a neighbor in both directions as\n // long as there's more than one item to wrap to.\n const hasPrev = loop ? items.length > 1 : currentIndex > 0;\n const hasNext = loop ? items.length > 1 : currentIndex < items.length - 1;\n\n const applySlideOffset = useCallback((offset: number, animate = false) => {\n swipeOffsetRef.current = offset;\n const track = slideTrackRef.current;\n if (track) {\n track.style.transition = animate ? \"transform 0.28s cubic-bezier(0.2, 0, 0, 1)\" : \"none\";\n track.style.transform = `translateX(${offset}px)`;\n }\n setSwipeOffset(offset);\n }, []);\n\n const snapBack = useCallback(() => {\n setSlideAnimating(true);\n applySlideOffset(0, true);\n\n onTransitionEndOnce(\n slideTrackRef.current,\n () => {\n setSlideAnimating(false);\n setSlideActive(false);\n },\n 350,\n );\n }, [applySlideOffset]);\n\n const readyRef = useRef(true);\n\n const commitSlide = useCallback(\n (direction: \"prev\" | \"next\") => {\n if (commitLockRef.current || !readyRef.current) return;\n commitLockRef.current = true;\n readyRef.current = false;\n\n // Slide by the image-relative distance (see measureSlideDistance), and\n // pin the neighbor panels to that same offset so the committed slide lands\n // them exactly centered. Measured fresh here so a button/keyboard nav (no\n // preceding drag to prime it) still gets the right distance.\n const distance = measureSlideDistance(slideTrackRef.current);\n setSlideDistance(distance);\n const targetOffset = direction === \"prev\" ? distance : -distance;\n setSlideActive(true);\n setSlideAnimating(true);\n // Fire at the START of the slide so overlays (info drawers) can animate\n // out in sync with the image — onNavigate only fires once it completes.\n onSlideStart?.(direction);\n\n requestAnimationFrame(() => {\n applySlideOffset(targetOffset, true);\n\n onTransitionEndOnce(\n slideTrackRef.current,\n () => {\n let newIndex = direction === \"prev\" ? currentIndex - 1 : currentIndex + 1;\n // Wrap the index when looping so the slide that just played lands on\n // the far end (e.g. last → first) instead of bailing out of bounds.\n if (loop) newIndex = (newIndex + items.length) % items.length;\n if (newIndex < 0 || newIndex >= items.length) {\n commitLockRef.current = false;\n return;\n }\n\n const newItem = items[newIndex];\n const preload = new Image();\n preload.src = newItem.src;\n\n const doNavigate = () => onNavigate(newIndex);\n\n // Add a timeout so a stalled decode can't block navigation forever\n const timeout = setTimeout(doNavigate, 300);\n preload\n .decode()\n .then(() => {\n clearTimeout(timeout);\n doNavigate();\n })\n .catch(() => {\n clearTimeout(timeout);\n doNavigate();\n });\n },\n 400,\n );\n });\n },\n [applySlideOffset, currentIndex, items, onNavigate, onSlideStart, loop],\n );\n\n const resolveSlide = useCallback(\n (gestureStartTime: number) => {\n const action = resolveSlideDirection({\n offset: swipeOffsetRef.current,\n elapsedMs: Date.now() - gestureStartTime,\n viewportWidth: window.innerWidth,\n hasPrev,\n hasNext,\n });\n\n if (action === \"prev\") commitSlide(\"prev\");\n else if (action === \"next\") commitSlide(\"next\");\n else snapBack();\n },\n [hasPrev, hasNext, commitSlide, snapBack],\n );\n\n // DOM + swipe-state resets on navigation, applied together pre-paint. The\n // imperative track reset and the React state reset (offset/active/animating)\n // MUST land in the same frame the new index paints. Splitting them — DOM here,\n // state in a post-paint effect — left one painted frame where the track had\n // already snapped to translateX(0) but swipeOffset still held the committed\n // ±viewportWidth. In that frame showAdjacent was still true and\n // adjacentOpacity computed to 1, so the just-left image rendered at full\n // opacity one viewport-width to the side: a blink on the far edge, worst in\n // landscape with wide letterbox margins. Resetting state here (a synchronous\n // pre-paint re-render) removes that frame.\n useLayoutEffect(() => {\n const track = slideTrackRef.current;\n if (track) {\n track.style.transition = \"none\";\n track.offsetHeight;\n track.style.transform = \"translateX(0px)\";\n }\n swipeOffsetRef.current = 0;\n commitLockRef.current = false;\n setSwipeOffset(0);\n setSlideAnimating(false);\n setSlideActive(false);\n }, [currentIndex]);\n\n // Allow the next commit only after React has painted the new panel.\n useEffect(() => {\n readyRef.current = true;\n }, [currentIndex]);\n\n return {\n slideTrackRef,\n slideActive,\n slideAnimating,\n swipeOffset,\n swipeOffsetRef,\n commitLockRef,\n slideDistance,\n applySlideOffset,\n commitSlide,\n snapBack,\n resolveSlide,\n setSlideActive,\n refreshSlideDistance,\n };\n}\n","import { useCallback, useRef } from \"react\";\nimport { computeZoomTransform } from \"./math\";\nimport { MIN_SCALE, MAX_SCALE, type ImageZoomPanState } from \"./useImageZoomPan\";\nimport type { SlideNavigationState } from \"./useSlideNavigation\";\n\n/** Target scale for a touch double-tap zoom (a larger step-in than desktop). */\nconst DOUBLE_TAP_ZOOM_SCALE = 2.5;\n\ninterface GestureHandlers {\n handlePointerDown: (e: React.PointerEvent) => void;\n handlePointerMove: (e: React.PointerEvent) => void;\n handlePointerUp: (e: React.PointerEvent) => void;\n handleTouchStart: (e: React.TouchEvent) => void;\n handleTouchMove: (e: React.TouchEvent) => void;\n handleTouchEnd: (e: React.TouchEvent) => void;\n /**\n * True when the most recent gesture involved real movement (a locked/rejected\n * swipe, a pan, or a pinch) rather than a stationary tap. Consumers use this\n * to tell a background swipe apart from a background tap so a swipe that ends\n * over empty space doesn't get mistaken for a tap-to-close.\n */\n gestureMovedRef: React.MutableRefObject<boolean>;\n}\n\ninterface PanGesture {\n isDragging: boolean;\n pointerStart: { x: number; y: number };\n translateStart: { x: number; y: number };\n pinchStartDist: number | null;\n pinchStartScale: number;\n pinchMidpoint: { x: number; y: number } | null;\n lastTouchPos: { x: number; y: number } | null;\n}\n\ninterface SlideGesture {\n active: boolean;\n startX: number;\n startY: number;\n startTime: number;\n locked: boolean;\n rejected: boolean;\n}\n\n/**\n * Coordinates zoom/pan and slide gestures, routing pointer and touch events\n * to the appropriate behavior based on current zoom state.\n *\n * When zoomed (scale > 1): pointer/touch drags are pans.\n * When unzoomed (scale === 1): pointer/touch drags are slide-to-navigate.\n * Two-finger touch is always a pinch-zoom.\n */\nexport function useGestureHandler(\n zoomPan: ImageZoomPanState,\n slide: SlideNavigationState,\n hasPrev: boolean,\n hasNext: boolean,\n /** When false, pinch-zoom and double-tap-zoom are disabled. Default true. */\n zoomEnabled = true,\n /**\n * When true (default), pinch-zoom anchors on the gesture midpoint. When\n * false, it zooms about the viewport center.\n */\n zoomToCursor = true,\n): GestureHandlers {\n const {\n transformRef,\n baseDimsRef,\n clampTranslate,\n setTransform,\n applyTransform,\n resetTransform,\n } = zoomPan;\n const {\n applySlideOffset,\n resolveSlide,\n snapBack,\n setSlideActive,\n swipeOffsetRef,\n refreshSlideDistance,\n } = slide;\n\n const panRef = useRef<PanGesture>({\n isDragging: false,\n pointerStart: { x: 0, y: 0 },\n translateStart: { x: 0, y: 0 },\n pinchStartDist: null,\n pinchStartScale: 1,\n pinchMidpoint: null,\n lastTouchPos: null,\n });\n\n const slideRef = useRef<SlideGesture>({\n active: false,\n startX: 0,\n startY: 0,\n startTime: 0,\n locked: false,\n rejected: false,\n });\n\n // Double-tap detection for touch\n const lastTapRef = useRef<{ time: number; x: number; y: number }>({\n time: 0,\n x: 0,\n y: 0,\n });\n\n // True once the current gesture moves past the tap threshold (swipe/pan/pinch).\n // Reset at the start of every fresh single-pointer gesture.\n const gestureMovedRef = useRef(false);\n\n // Shared slide start helper\n\n const beginSlide = useCallback(\n (x: number, y: number) => {\n setSlideActive(true);\n // Measure the current image now so the neighbor panels are positioned at\n // the right (image-relative) offset from the first drag frame.\n refreshSlideDistance();\n const sg = slideRef.current;\n sg.active = true;\n sg.startX = x;\n sg.startY = y;\n sg.startTime = Date.now();\n sg.locked = false;\n sg.rejected = false;\n },\n [setSlideActive, refreshSlideDistance],\n );\n\n const updateSlide = useCallback(\n (clientX: number, clientY: number, lockThreshold: number, angleBias: number) => {\n const sg = slideRef.current;\n if (!sg.active || sg.rejected) return;\n\n const dx = clientX - sg.startX;\n const dy = clientY - sg.startY;\n\n if (!sg.locked) {\n const absDx = Math.abs(dx);\n const absDy = Math.abs(dy);\n if (absDx < lockThreshold && absDy < lockThreshold) return;\n // Moved past the tap threshold in either axis — no longer a tap, even if\n // the drag is rejected as vertical below.\n gestureMovedRef.current = true;\n if (absDy > absDx * angleBias) {\n sg.rejected = true;\n return;\n }\n sg.locked = true;\n }\n\n let offset = dx;\n if ((offset > 0 && !hasPrev) || (offset < 0 && !hasNext)) {\n offset *= 0.2; // rubber-band resistance at edges\n }\n applySlideOffset(offset);\n },\n [hasPrev, hasNext, applySlideOffset],\n );\n\n const endSlide = useCallback(\n (allowResolve: boolean) => {\n const sg = slideRef.current;\n if (sg.active && sg.locked && !sg.rejected && allowResolve) {\n const startTime = sg.startTime;\n sg.active = false;\n resolveSlide(startTime);\n } else {\n sg.active = false;\n if (swipeOffsetRef.current === 0) setSlideActive(false);\n }\n },\n [resolveSlide, setSlideActive, swipeOffsetRef],\n );\n\n // Pointer (mouse) handlers\n\n const handlePointerDown = useCallback(\n (e: React.PointerEvent) => {\n if (e.pointerType === \"touch\") return;\n\n gestureMovedRef.current = false;\n if (transformRef.current.scale > 1) {\n e.preventDefault();\n const p = panRef.current;\n p.isDragging = true;\n p.pointerStart = { x: e.clientX, y: e.clientY };\n p.translateStart = { x: transformRef.current.x, y: transformRef.current.y };\n } else {\n beginSlide(e.clientX, e.clientY);\n }\n },\n [transformRef, beginSlide],\n );\n\n const handlePointerMove = useCallback(\n (e: React.PointerEvent) => {\n if (e.pointerType === \"touch\") return;\n\n const p = panRef.current;\n if (p.isDragging && transformRef.current.scale > 1) {\n const dx = e.clientX - p.pointerStart.x;\n const dy = e.clientY - p.pointerStart.y;\n if (Math.abs(dx) > 4 || Math.abs(dy) > 4) gestureMovedRef.current = true;\n const t = transformRef.current;\n const clamped = clampTranslate(p.translateStart.x + dx, p.translateStart.y + dy, t.scale);\n setTransform({ scale: t.scale, ...clamped });\n return;\n }\n\n // Mouse slide: lockThreshold=4, angleBias=1 (45° cutoff)\n updateSlide(e.clientX, e.clientY, 4, 1);\n },\n [transformRef, clampTranslate, setTransform, updateSlide],\n );\n\n const handlePointerUp = useCallback(\n (e: React.PointerEvent) => {\n if (e.pointerType === \"touch\") return;\n panRef.current.isDragging = false;\n endSlide(true);\n },\n [endSlide],\n );\n\n // Touch handlers\n\n const handleTouchStart = useCallback(\n (e: React.TouchEvent) => {\n const p = panRef.current;\n\n if (e.touches.length === 2 && zoomEnabled) {\n // Pinch start\n gestureMovedRef.current = true;\n const dx = e.touches[0].clientX - e.touches[1].clientX;\n const dy = e.touches[0].clientY - e.touches[1].clientY;\n p.pinchStartDist = Math.hypot(dx, dy);\n p.pinchStartScale = transformRef.current.scale;\n p.pinchMidpoint = {\n x: (e.touches[0].clientX + e.touches[1].clientX) / 2,\n y: (e.touches[0].clientY + e.touches[1].clientY) / 2,\n };\n p.lastTouchPos = null;\n\n // Cancel any slide in progress\n if (slideRef.current.active) {\n slideRef.current.active = false;\n snapBack();\n }\n } else if (e.touches.length === 1) {\n gestureMovedRef.current = false;\n if (transformRef.current.scale > 1) {\n p.lastTouchPos = {\n x: e.touches[0].clientX,\n y: e.touches[0].clientY,\n };\n } else {\n beginSlide(e.touches[0].clientX, e.touches[0].clientY);\n }\n }\n },\n [transformRef, snapBack, beginSlide, zoomEnabled],\n );\n\n const handleTouchMove = useCallback(\n (e: React.TouchEvent) => {\n const p = panRef.current;\n\n if (e.touches.length === 2 && p.pinchStartDist !== null) {\n // Pinch zoom\n const dx = e.touches[0].clientX - e.touches[1].clientX;\n const dy = e.touches[0].clientY - e.touches[1].clientY;\n const dist = Math.hypot(dx, dy);\n const ratio = dist / p.pinchStartDist;\n const nextScale = Math.min(MAX_SCALE, Math.max(MIN_SCALE, p.pinchStartScale * ratio));\n const t = transformRef.current;\n const midX = (e.touches[0].clientX + e.touches[1].clientX) / 2;\n const midY = (e.touches[0].clientY + e.touches[1].clientY) / 2;\n // Also translate by however far the midpoint itself moved since the last\n // frame, so sliding both fingers across the screen repositions the image\n // (standard pinch-to-pan behavior).\n const prevMid = p.pinchMidpoint;\n const focalPan = {\n x: prevMid ? midX - prevMid.x : 0,\n y: prevMid ? midY - prevMid.y : 0,\n };\n p.pinchMidpoint = { x: midX, y: midY };\n const clamped = computeZoomTransform({\n prevScale: t.scale,\n nextScale,\n prev: { x: t.x, y: t.y },\n focal: { x: midX, y: midY },\n viewport: { width: window.innerWidth, height: window.innerHeight },\n baseDims: baseDimsRef.current,\n zoomToCursor,\n focalPan,\n });\n\n const next = { scale: nextScale, ...clamped };\n transformRef.current = next;\n // applyTransform writes the wrapper style AND syncs displayScale, so the\n // UI (zoom %/controls) tracks each pinch frame. We call it directly rather\n // than setTransform to skip setTransform's redundant second setDisplayScale.\n applyTransform(next);\n } else if (e.touches.length === 1 && p.lastTouchPos && transformRef.current.scale > 1) {\n // Zoomed pan\n const touch = e.touches[0];\n const dx = touch.clientX - p.lastTouchPos.x;\n const dy = touch.clientY - p.lastTouchPos.y;\n if (Math.abs(dx) > 4 || Math.abs(dy) > 4) gestureMovedRef.current = true;\n p.lastTouchPos = { x: touch.clientX, y: touch.clientY };\n\n const t = transformRef.current;\n const clamped = clampTranslate(t.x + dx, t.y + dy, t.scale);\n const next = { scale: t.scale, ...clamped };\n transformRef.current = next;\n applyTransform(next);\n } else if (e.touches.length === 1) {\n // Touch slide: lockThreshold=6, angleBias=0.8\n const touch = e.touches[0];\n updateSlide(touch.clientX, touch.clientY, 6, 0.8);\n }\n },\n [transformRef, baseDimsRef, clampTranslate, applyTransform, updateSlide, zoomToCursor],\n );\n\n const handleTouchEnd = useCallback(\n (e: React.TouchEvent) => {\n const p = panRef.current;\n const wasPinch = p.pinchStartDist !== null;\n p.pinchStartDist = null;\n p.pinchMidpoint = null;\n\n if (e.touches.length === 0 && transformRef.current.scale <= 1) {\n // Resolve slide if active\n const sg = slideRef.current;\n if (sg.active && sg.locked && !sg.rejected) {\n const startTime = sg.startTime;\n sg.active = false;\n resolveSlide(startTime);\n transformRef.current = { scale: 1, x: 0, y: 0 };\n return;\n }\n sg.active = false;\n resetTransform();\n }\n\n // One finger remaining after pinch → start pan from that finger\n if (e.touches.length === 1 && transformRef.current.scale > 1) {\n p.lastTouchPos = {\n x: e.touches[0].clientX,\n y: e.touches[0].clientY,\n };\n } else {\n p.lastTouchPos = null;\n }\n\n // Double-tap detection (single finger, not after pinch, not after slide)\n const sg = slideRef.current;\n if (\n zoomEnabled &&\n e.touches.length === 0 &&\n e.changedTouches.length === 1 &&\n !wasPinch &&\n !sg.locked\n ) {\n const touch = e.changedTouches[0];\n const now = Date.now();\n const last = lastTapRef.current;\n const timeDelta = now - last.time;\n const distDelta = Math.hypot(touch.clientX - last.x, touch.clientY - last.y);\n\n if (timeDelta < 300 && distDelta < 30) {\n lastTapRef.current = { time: 0, x: 0, y: 0 };\n if (transformRef.current.scale > 1) {\n resetTransform();\n } else {\n setTransform({ scale: DOUBLE_TAP_ZOOM_SCALE, x: 0, y: 0 }, true);\n }\n } else {\n lastTapRef.current = { time: now, x: touch.clientX, y: touch.clientY };\n }\n }\n\n // Cleanup slide if released without committing\n if (e.touches.length === 0 && sg.active && !sg.locked) {\n sg.active = false;\n if (swipeOffsetRef.current === 0) setSlideActive(false);\n }\n },\n [\n transformRef,\n resetTransform,\n setTransform,\n resolveSlide,\n setSlideActive,\n swipeOffsetRef,\n zoomEnabled,\n ],\n );\n\n return {\n handlePointerDown,\n handlePointerMove,\n handlePointerUp,\n handleTouchStart,\n handleTouchMove,\n handleTouchEnd,\n gestureMovedRef,\n };\n}\n","import { useLayoutEffect, useState, type RefObject } from \"react\";\n\n/**\n * Measures the height of the top and bottom bars so the image area\n * can be constrained to fit between them.\n */\nexport function useBarMeasure(\n topBarRef: RefObject<HTMLDivElement | null>,\n bottomBarRef: RefObject<HTMLDivElement | null>,\n /** Re-measure whenever this key changes (e.g. currentIndex) */\n measureKey: unknown,\n) {\n const [topBarH, setTopBarH] = useState(0);\n const [bottomBarH, setBottomBarH] = useState(0);\n\n // Measured before paint so the image is constrained to its final height on the\n // very first frame — otherwise it lays out tall (bottomBarH = 0), then visibly\n // shrinks once the bar is measured, which shows up as a flutter on open.\n useLayoutEffect(() => {\n const measure = () => {\n if (topBarRef.current) setTopBarH(topBarRef.current.offsetHeight);\n if (bottomBarRef.current) setBottomBarH(bottomBarRef.current.offsetHeight);\n };\n measure();\n\n const ro = new ResizeObserver(measure);\n if (topBarRef.current) ro.observe(topBarRef.current);\n if (bottomBarRef.current) ro.observe(bottomBarRef.current);\n return () => ro.disconnect();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [measureKey]);\n\n return { topBarH, bottomBarH };\n}\n","import { useEffect } from \"react\";\n\n/**\n * Locks scrolling on the document body while `isLocked` is true (e.g. while the\n * lightbox is open), so content behind the overlay can't be scrolled. To\n * prevent the content from shifting when the scrollbar disappears, the width\n * the scrollbar occupied is added back as right padding while locked. Restores\n * the previous body styles on unlock/unmount, and reference-counts concurrent\n * locks so closing one overlay doesn't release a lock held by another.\n *\n * The page is pinned with `position: fixed` and `top: -scrollY` rather than a\n * plain `overflow: hidden`. Overflow-only locking leaves the restored scroll\n * offset at the mercy of the browser: when the page is scrolled to (or near)\n * the bottom, hiding overflow collapses the scrollable range and the browser\n * clamps the offset, so on unlock the content visibly \"skips\" to a different\n * position. Pinning records the exact offset and restores it explicitly via\n * `scrollTo`, so the page holds still no matter where it was scrolled.\n *\n * If the page already reserves the scrollbar's space with `scrollbar-gutter:\n * stable` on the root element, that gutter stays reserved while locked, so the\n * padding compensation is skipped — adding it on top would shift the page by a\n * scrollbar's width (the visible \"jump\" it's meant to prevent).\n *\n * SSR-safe: the effect only runs in the browser, so importing this on the\n * server is a no-op.\n */\nlet lockCount = 0;\nlet previousOverflow = \"\";\nlet previousPaddingRight = \"\";\nlet previousPosition = \"\";\nlet previousTop = \"\";\nlet previousWidth = \"\";\nlet lockedScrollY = 0;\n\nexport function useBodyScrollLock(isLocked: boolean): void {\n useEffect(() => {\n if (!isLocked) return;\n if (typeof document === \"undefined\") return;\n\n if (lockCount === 0) {\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n\n // When the root reserves a stable gutter, the space stays reserved while\n // locked, so compensating with padding would shift the page instead of\n // holding it still.\n const rootGutter = window.getComputedStyle(document.documentElement).scrollbarGutter;\n const reservesGutter = typeof rootGutter === \"string\" && rootGutter.includes(\"stable\");\n\n lockedScrollY = window.scrollY;\n previousOverflow = document.body.style.overflow;\n previousPaddingRight = document.body.style.paddingRight;\n previousPosition = document.body.style.position;\n previousTop = document.body.style.top;\n previousWidth = document.body.style.width;\n\n // Pin the page at its current offset. `width: 100%` keeps the body its\n // normal width once it's out of flow; `overflow: hidden` guards against a\n // stray scroll on the (now un-pinned) root.\n document.body.style.overflow = \"hidden\";\n document.body.style.position = \"fixed\";\n document.body.style.top = `-${lockedScrollY}px`;\n document.body.style.width = \"100%\";\n if (scrollbarWidth > 0 && !reservesGutter) {\n const currentPaddingRight =\n parseFloat(window.getComputedStyle(document.body).paddingRight) || 0;\n document.body.style.paddingRight = `${currentPaddingRight + scrollbarWidth}px`;\n }\n }\n lockCount += 1;\n\n return () => {\n lockCount -= 1;\n if (lockCount === 0) {\n document.body.style.overflow = previousOverflow;\n document.body.style.paddingRight = previousPaddingRight;\n document.body.style.position = previousPosition;\n document.body.style.top = previousTop;\n document.body.style.width = previousWidth;\n // Restore the exact offset the page was pinned at.\n window.scrollTo(0, lockedScrollY);\n }\n };\n }, [isLocked]);\n}\n","import { useEffect, type RefObject } from \"react\";\n\nconst FOCUSABLE =\n 'a[href], button:not([disabled]), textarea, input, select, [tabindex]:not([tabindex=\"-1\"])';\n\n/**\n * Traps Tab focus within `containerRef` while `active`, and restores focus to\n * the previously-focused element on deactivate/unmount. SSR-safe (effect only\n * runs in the browser).\n */\nexport function useFocusTrap(containerRef: RefObject<HTMLElement | null>, active: boolean): void {\n useEffect(() => {\n if (!active) return;\n if (typeof document === \"undefined\") return;\n\n const previouslyFocused = document.activeElement as HTMLElement | null;\n const container = containerRef.current;\n\n // Move focus into the dialog so screen readers/keyboard land inside it.\n container?.focus();\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key !== \"Tab\" || !container) return;\n const focusable = Array.from(container.querySelectorAll<HTMLElement>(FOCUSABLE)).filter(\n (el) => el.offsetParent !== null || el === document.activeElement,\n );\n if (focusable.length === 0) {\n e.preventDefault();\n container.focus();\n return;\n }\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n const activeEl = document.activeElement;\n\n if (e.shiftKey && (activeEl === first || activeEl === container)) {\n e.preventDefault();\n last.focus();\n } else if (!e.shiftKey && activeEl === last) {\n e.preventDefault();\n first.focus();\n }\n };\n\n document.addEventListener(\"keydown\", onKeyDown);\n return () => {\n document.removeEventListener(\"keydown\", onKeyDown);\n previouslyFocused?.focus?.();\n };\n }, [containerRef, active]);\n}\n","import { useCallback, useLayoutEffect, useEffect, useRef, useState, type RefObject } from \"react\";\nimport type { ViewerRect } from \"../types\";\n\n// Duration of the shared-element zoom (open expand / close collapse) in ms.\nexport const ANIM_MS = 250;\n// Vertical breathing room reserved around the image, per side, in px.\nexport const IMG_PADDING = 44;\n// Decelerating ease for the shared-element zoom so it settles softly.\nconst ZOOM_EASE = \"cubic-bezier(0.22, 1, 0.36, 1)\";\n\nexport function prefersReducedMotion(): boolean {\n if (typeof window === \"undefined\" || !window.matchMedia) return false;\n return window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n}\n\n/**\n * CSS transform that maps `from` (the element's current rect) onto `to`,\n * assuming a `top left` transform-origin. Used for the FLIP-style thumbnail\n * zoom: place the full image where the thumbnail is, then animate the transform\n * away so it glides into its real position.\n */\nfunction flipTransform(from: ViewerRect, to: ViewerRect): string {\n const sx = to.width / from.width;\n const sy = to.height / from.height;\n const dx = to.left - from.left;\n const dy = to.top - from.top;\n return `translate(${dx}px, ${dy}px) scale(${sx}, ${sy})`;\n}\n\n/**\n * True when the Web Animations API is usable on `el`. jsdom (tests) and very old\n * browsers lack `Element.prototype.animate`, so callers fall back to no anim.\n */\nfunction canAnimate(el: HTMLElement | null): el is HTMLElement {\n return !!el && typeof el.animate === \"function\";\n}\n\n/**\n * True when `rect` overlaps the current viewport at all. A thumbnail scrolled\n * out of view returns its (offscreen) rect just the same, so collapsing into it\n * would fly the image off to nowhere — callers fall back to a plain fade in that\n * case.\n */\nfunction isRectInViewport(rect: ViewerRect): boolean {\n if (typeof window === \"undefined\") return true;\n return (\n rect.top < window.innerHeight &&\n rect.top + rect.height > 0 &&\n rect.left < window.innerWidth &&\n rect.left + rect.width > 0\n );\n}\n\nexport interface SharedElementZoomArgs {\n getOriginRect?: (index: number) => ViewerRect | null;\n index: number;\n isZoomed: boolean;\n imgRef: RefObject<HTMLImageElement | null>;\n imgWrapperRef: RefObject<HTMLDivElement | null>;\n bottomBarRef: RefObject<HTMLDivElement | null>;\n measureBaseDims: () => void;\n}\n\nexport interface SharedElementZoomState {\n /** True when the open should hold the image hidden until it decodes, then play the zoom. */\n gateEntry: boolean;\n /** True when a shared-element (thumbnail) zoom is configured at all. */\n zoomTransition: boolean;\n /** Whether the opening image has finished loading + decoding. */\n fullLoaded: boolean;\n /** True once the load runs long enough to warrant a spinner. */\n showSpinner: boolean;\n /** True only while a close-collapse FLIP is animating the image back into its source. */\n collapsing: boolean;\n /** `<img onLoad>` handler: measures base dims and marks the image ready once decoded. */\n onImageLoad: () => void;\n /** `<img onError>` handler: reveal a broken image so the open isn't stranded. */\n onImageError: () => void;\n /** Settle an in-flight entry zoom to its resting pose (call before measuring a close). */\n settleEntry: () => void;\n /** Play the collapse-into-thumbnail FLIP on close, when one applies. No-op otherwise. */\n playCollapse: () => void;\n}\n\n/**\n * Drives the shared-element thumbnail zoom: the image expands out of its source\n * thumbnail on open and collapses back into it on close, when `getOriginRect` is\n * supplied. Also owns the load-gating (hold the image hidden until decoded so\n * the zoom plays from the thumbnail with no full-size flash) and the delayed\n * loading spinner.\n *\n * Driven by the Web Animations API on the <img> itself (zoom/pan owns the\n * wrapper): WAAPI plays from an explicit start keyframe and owns the transform\n * for the animation's duration, so React re-renders / the zoom-reset layout\n * effect / frame timing can't clobber it mid-flight (the failure mode of a raw\n * inline transition). The FLIP only ever scales down to ≤ 1, sidestepping the\n * iOS upscale-clip bug noted in useImageZoomPan.\n */\nexport function useSharedElementZoom({\n getOriginRect,\n index,\n isZoomed,\n imgRef,\n imgWrapperRef,\n bottomBarRef,\n measureBaseDims,\n}: SharedElementZoomArgs): SharedElementZoomState {\n const zoomTransition = !!getOriginRect;\n const reduceMotion = prefersReducedMotion();\n // For a thumbnail zoom, hold the image hidden until its full-size source has\n // decoded, then play the zoom from the thumbnail. Animating before the bytes\n // are ready lets the browser paint a full-size frame first, which reads as the\n // image \"expanding twice\" on the first (uncached) open.\n const gateEntry = zoomTransition && !reduceMotion;\n\n // Whether the opening image has finished loading + decoding.\n const [fullLoaded, setFullLoaded] = useState(false);\n // Set true only if the load runs long, so quick opens never flash a spinner.\n const [showSpinner, setShowSpinner] = useState(false);\n // True only while a thumbnail FLIP collapse is animating the image back into\n // its source. Keeps the track opaque for that flight; a close without a\n // collapse (zoomed, reduced motion, no origin rect) leaves it false so the\n // track fades out instead of vanishing on unmount.\n const [collapsing, setCollapsing] = useState(false);\n\n const entryStartedRef = useRef(false);\n // Tears down the in-flight entry zoom (clears the inline transform, restores\n // the wrapper clip, cancels the animation). Set while the zoom is playing so\n // a close mid-flight can settle the image before measuring its collapse.\n const entryCleanupRef = useRef<(() => void) | null>(null);\n\n // Plays the shared-element zoom once, from the source thumbnail to the resting\n // image box. Only ever invoked after the full image has decoded (see below),\n // so the picture is paint-ready and the zoom can't flash a full-size frame.\n const runZoomEntry = useCallback(() => {\n if (entryStartedRef.current) return;\n if (!getOriginRect || prefersReducedMotion()) return;\n const img = imgRef.current;\n const thumb = getOriginRect(index);\n if (!thumb || !canAnimate(img)) return;\n\n // Pin the image to its final constrained height before measuring. The bottom\n // bar is measured in a post-paint effect, so on the opening frame `bottomBarH`\n // is still 0 and the React-driven maxHeight is too tall; locking it here (read\n // straight from the bar's DOM) keeps a late bottomBarH measurement from\n // resizing the image mid-flight, which is what makes the open animation\n // visibly jump / re-expand. Held for the whole flight, then matched to React's\n // now-settled value on finish.\n const bottomH = bottomBarRef.current?.offsetHeight ?? 0;\n const lockedMaxHeight = `calc(100vh - ${bottomH + IMG_PADDING * 2}px)`;\n img.style.maxHeight = lockedMaxHeight;\n\n const imgRect = img.getBoundingClientRect();\n if (imgRect.width === 0 || imgRect.height === 0) {\n img.style.maxHeight = \"\";\n return;\n }\n entryStartedRef.current = true;\n\n const startTransform = flipTransform(imgRect, thumb);\n\n // Pin the image to the thumbnail pose *synchronously*, before the browser\n // can paint. On a first (uncached) open this handler fires the instant the\n // full image decodes; a WAAPI animation only composites its first frame on\n // the next frame, so without this inline transform the browser paints one\n // full-size frame first — the image flashes out to full size, then zooms in\n // again (\"expands twice\"). It only shows on the uncached load because the\n // cached path starts the zoom before the first paint. React never writes\n // `transform`, so it won't clobber this.\n img.style.transformOrigin = \"top left\";\n img.style.transform = startTransform;\n\n // The wrapper clips to its own (centered) box; while the image is translated\n // out to the thumbnail it would otherwise be sliced off. Lift the clip for\n // the flight, then restore it so zoom/pan clipping still works afterwards.\n const wrapper = imgWrapperRef.current;\n if (wrapper) wrapper.style.overflow = \"visible\";\n\n // Play from the thumbnail's box to the resting box. `fill: \"forwards\"` holds\n // the resting pose at the end so the inline start transform can't flash back\n // before cleanup swaps it out.\n const anim = img.animate(\n [\n { transformOrigin: \"top left\", transform: startTransform },\n { transformOrigin: \"top left\", transform: \"none\" },\n ],\n { duration: ANIM_MS, easing: ZOOM_EASE, fill: \"forwards\" },\n );\n const cleanup = () => {\n // Match the inline base to the held resting pose, then release the fill:\n // computed style stays \"none\" across the swap, so there's no flicker, and\n // the image is handed cleanly back to zoom/pan.\n img.style.transform = \"\";\n img.style.transformOrigin = \"\";\n if (wrapper) wrapper.style.overflow = \"\";\n // Keep the height pinned to the (by now settled) final value; releasing to\n // \"\" with no following render could briefly drop the constraint entirely.\n img.style.maxHeight = lockedMaxHeight;\n anim.cancel();\n entryCleanupRef.current = null;\n };\n entryCleanupRef.current = cleanup;\n anim.onfinish = cleanup;\n }, [getOriginRect, index, imgRef, imgWrapperRef, bottomBarRef]);\n\n // Mark the opening image ready once it has both loaded and decoded. `decode()`\n // forces the decode up front so revealing the image can't flash; fall back to\n // a plain reveal where it's unsupported or rejects (e.g. the src changed).\n const onImageLoad = useCallback(() => {\n measureBaseDims();\n const img = imgRef.current;\n if (img && typeof img.decode === \"function\") {\n img.decode().then(\n () => setFullLoaded(true),\n () => setFullLoaded(true),\n );\n } else {\n setFullLoaded(true);\n }\n }, [measureBaseDims, imgRef]);\n\n // Don't strand the open on a broken image: reveal it (skipping the zoom) so\n // the spinner clears and the viewer stays usable.\n const onImageError = useCallback(() => setFullLoaded(true), []);\n\n // A cached image can already be `complete` before React wires up onLoad; pick\n // it up on mount so the open isn't stuck waiting for an event that won't fire.\n useLayoutEffect(() => {\n const img = imgRef.current;\n if (img && img.complete && img.naturalWidth > 0) onImageLoad();\n // Mount-only: the opening image.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Once the image is decoded, play the entry zoom (a no-op for non-zoom opens,\n // reduced motion, or a repeat call — all guarded inside runZoomEntry).\n useLayoutEffect(() => {\n if (fullLoaded) runZoomEntry();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [fullLoaded]);\n\n // Reveal the spinner only after the wait crosses 500ms, then clear it the\n // moment the image is ready (or the gate no longer applies).\n useEffect(() => {\n if (!gateEntry || fullLoaded) {\n setShowSpinner(false);\n return;\n }\n const t = setTimeout(() => setShowSpinner(true), 500);\n return () => clearTimeout(t);\n }, [gateEntry, fullLoaded]);\n\n const settleEntry = useCallback(() => {\n entryCleanupRef.current?.();\n }, []);\n\n const playCollapse = useCallback(() => {\n const reduce = prefersReducedMotion();\n // Collapse back into the source thumbnail when one exists, is still on\n // screen, and the image isn't zoomed (a zoomed image's box no longer\n // matches the thumbnail; an off-screen thumbnail would fly to nowhere, so\n // fall back to the plain fade).\n const origin = !reduce && !isZoomed ? (getOriginRect?.(index) ?? null) : null;\n const thumb = origin && isRectInViewport(origin) ? origin : null;\n const img = imgRef.current;\n if (!thumb || !canAnimate(img)) return;\n\n const imgRect = img.getBoundingClientRect();\n // Lift the wrapper clip so the image isn't sliced as it flies back to the\n // thumbnail; the component unmounts at onClose, so no restore is needed.\n const wrapper = imgWrapperRef.current;\n if (wrapper) wrapper.style.overflow = \"visible\";\n setCollapsing(true);\n // fill \"forwards\" holds the collapsed pose until the component unmounts.\n img.animate(\n [\n { transformOrigin: \"top left\", transform: \"none\" },\n { transformOrigin: \"top left\", transform: flipTransform(imgRect, thumb) },\n ],\n { duration: ANIM_MS, easing: ZOOM_EASE, fill: \"forwards\" },\n );\n }, [getOriginRect, index, isZoomed, imgRef, imgWrapperRef]);\n\n return {\n gateEntry,\n zoomTransition,\n fullLoaded,\n showSpinner,\n collapsing,\n onImageLoad,\n onImageError,\n settleEntry,\n playCollapse,\n };\n}\n","import type { SVGProps } from \"react\";\nimport type { ViewerIcons } from \"../types\";\n\n// Inline default icons so the package has no runtime icon dependency (e.g.\n// lucide-react). Each is a 24x24 stroked glyph that inherits `currentColor`.\n// Consumers can override any of them via the `icons` prop.\n\nfunction base(props: SVGProps<SVGSVGElement>) {\n return {\n width: 18,\n height: 18,\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: 1.75,\n strokeLinecap: \"round\" as const,\n strokeLinejoin: \"round\" as const,\n \"aria-hidden\": true,\n focusable: false,\n ...props,\n };\n}\n\nexport function CloseIcon(props: SVGProps<SVGSVGElement>) {\n return (\n <svg {...base(props)}>\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n );\n}\n\nexport function ZoomInIcon(props: SVGProps<SVGSVGElement>) {\n return (\n <svg {...base(props)}>\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.3-4.3\" />\n <path d=\"M11 8v6\" />\n <path d=\"M8 11h6\" />\n </svg>\n );\n}\n\nexport function ZoomOutIcon(props: SVGProps<SVGSVGElement>) {\n return (\n <svg {...base(props)}>\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.3-4.3\" />\n <path d=\"M8 11h6\" />\n </svg>\n );\n}\n\nexport function ChevronLeftIcon(props: SVGProps<SVGSVGElement>) {\n return (\n <svg {...base({ width: 36, height: 36, strokeWidth: 1.5, ...props })}>\n <path d=\"m15 18-6-6 6-6\" />\n </svg>\n );\n}\n\nexport function ChevronRightIcon(props: SVGProps<SVGSVGElement>) {\n return (\n <svg {...base({ width: 36, height: 36, strokeWidth: 1.5, ...props })}>\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n );\n}\n\n/** The full default icon set, merged with any consumer overrides. */\nexport const defaultIcons: ViewerIcons = {\n close: <CloseIcon />,\n zoomIn: <ZoomInIcon />,\n zoomOut: <ZoomOutIcon />,\n prev: <ChevronLeftIcon />,\n next: <ChevronRightIcon />,\n};\n","/** Tiny className joiner: drops falsy values and joins with a space. */\nexport function cx(...parts: Array<string | false | null | undefined>): string {\n return parts.filter(Boolean).join(\" \");\n}\n","import type { ReactNode } from \"react\";\nimport { cx } from \"./cx\";\n\ninterface NavButtonProps {\n direction: \"prev\" | \"next\";\n enabled: boolean;\n onClick: () => void;\n icon: ReactNode;\n className?: string;\n}\n\nexport function NavButton({ direction, enabled, onClick, icon, className }: NavButtonProps) {\n return (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n if (enabled) onClick();\n }}\n disabled={!enabled}\n className={cx(\"rvl-nav-btn\", className)}\n aria-label={direction === \"prev\" ? \"Previous image\" : \"Next image\"}\n >\n {icon}\n </button>\n );\n}\n","import type { ReactNode } from \"react\";\nimport { cx } from \"./cx\";\n\ninterface ChromeButtonProps {\n onClick: () => void;\n title: string;\n ariaLabel: string;\n /** Extra class(es) appended after the base `rvl-btn` (e.g. a variant + the consumer override). */\n className?: string;\n children: ReactNode;\n}\n\n/**\n * A chrome toolbar button (zoom in/out, reset, close). Stops click propagation\n * so a press on the top bar never bubbles to the backdrop close handler, and\n * keeps `title`/`aria-label` in lockstep across every toolbar control.\n */\nexport function ChromeButton({\n onClick,\n title,\n ariaLabel,\n className,\n children,\n}: ChromeButtonProps) {\n return (\n <button\n type=\"button\"\n className={cx(\"rvl-btn\", className)}\n onClick={(e) => {\n e.stopPropagation();\n onClick();\n }}\n title={title}\n aria-label={ariaLabel}\n >\n {children}\n </button>\n );\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { ImageViewerProps, ViewerContext } from \"../types\";\nimport { useImageZoomPan, MIN_SCALE, MAX_SCALE } from \"../hooks/useImageZoomPan\";\nimport { useSlideNavigation } from \"../hooks/useSlideNavigation\";\nimport { useGestureHandler } from \"../hooks/useGestureHandler\";\nimport { useBarMeasure } from \"../hooks/useBarMeasure\";\nimport { useBodyScrollLock } from \"../hooks/useBodyScrollLock\";\nimport { useFocusTrap } from \"../hooks/useFocusTrap\";\nimport {\n useSharedElementZoom,\n prefersReducedMotion,\n ANIM_MS,\n IMG_PADDING,\n} from \"../hooks/useSharedElementZoom\";\nimport { defaultIcons } from \"./icons\";\nimport { NavButton } from \"./NavButton\";\nimport { ChromeButton } from \"./ChromeButton\";\nimport { cx } from \"./cx\";\n\n// Window after open during which synthesized mouse click/dblclick are ignored.\n// A tap (or double-tap) that opens the viewer fires iOS's synthesized `click` /\n// `dblclick` a few hundred ms LATER — by which point this viewer has mounted\n// under the finger, so they re-target onto it (the dblclick zooms the image,\n// the click hits the backdrop and closes it). See GHOST guards below.\nconst GHOST_CLICK_MS = 700;\n\n/**\n * Batteries-included fullscreen image viewer: zoom, pan, pinch, and swipe\n * navigation with themeable chrome and render slots. Controlled via `index` /\n * `onIndexChange`; mount it when open and it runs its own enter/exit animation,\n * calling `onClose` after the exit completes.\n */\nexport function ImageViewer<TData = unknown>({\n items,\n index,\n onIndexChange,\n onNavigate,\n onClose,\n onEscape,\n getOriginRect,\n zoom = true,\n zoomToCursor = true,\n showCounter = true,\n showZoomControls = true,\n disableNavigation = false,\n loop = false,\n closeOnBackdropClick = false,\n renderHeader,\n renderHeaderActions,\n renderNavStart,\n renderNavEnd,\n navSlotPlacement = \"edge\",\n navHeight,\n navInset,\n counterFontSize,\n renderFooter,\n renderOverlay,\n classNames,\n icons,\n ariaLabel,\n}: ImageViewerProps<TData>) {\n const [visible, setVisible] = useState(false);\n const [closing, setClosing] = useState(false);\n const [isTouchDevice, setIsTouchDevice] = useState(false);\n const [contentShift, setContentShiftState] = useState<{\n transform: string | null;\n animate: boolean;\n }>({ transform: null, animate: true });\n\n // Timestamp of this open, used to drop the iOS ghost click/dblclick that the\n // opening tap synthesizes onto the freshly mounted viewer (see GHOST_CLICK_MS).\n const openedAtRef = useRef(Date.now());\n const isGhostMouseEvent = useCallback(\n () => Date.now() - openedAtRef.current < GHOST_CLICK_MS,\n [],\n );\n\n const containerRef = useRef<HTMLDivElement>(null);\n const imgWrapperRef = useRef<HTMLDivElement>(null);\n const topBarRef = useRef<HTMLDivElement>(null);\n const bottomBarRef = useRef<HTMLDivElement>(null);\n\n const [viewportWidth, setViewportWidth] = useState(() =>\n typeof window === \"undefined\" ? 0 : window.innerWidth,\n );\n\n const item = items[index];\n\n const hasPrevLinear = index > 0;\n const hasNextLinear = index < items.length - 1;\n const hasPrev = loop ? items.length > 1 : hasPrevLinear;\n const hasNext = loop ? items.length > 1 : hasNextLinear;\n\n const mergedIcons = useMemo(() => ({ ...defaultIcons, ...icons }), [icons]);\n const cn = (slot: keyof NonNullable<ImageViewerProps[\"classNames\"]>) => classNames?.[slot];\n\n useBodyScrollLock(true);\n useFocusTrap(containerRef, visible && !closing);\n const { topBarH, bottomBarH } = useBarMeasure(topBarRef, bottomBarRef, index);\n\n const zoomPan = useImageZoomPan(imgWrapperRef, index, zoom, zoomToCursor);\n const {\n imgRef,\n displayScale,\n isZoomed,\n transformRef,\n resetTransform,\n setTransform,\n clampTranslate,\n measureBaseDims,\n handleDoubleClick,\n } = zoomPan;\n\n const slide = useSlideNavigation(items, index, onIndexChange, onNavigate, loop);\n const { slideTrackRef, slideActive, slideAnimating, swipeOffset, slideDistance, commitSlide } =\n slide;\n\n const gestures = useGestureHandler(zoomPan, slide, hasPrev, hasNext, zoom, zoomToCursor);\n\n // Shared-element thumbnail zoom: expand out of / collapse back into the source\n // thumbnail, plus load-gating + the delayed loading spinner. See the hook.\n const {\n gateEntry,\n zoomTransition,\n fullLoaded,\n showSpinner,\n collapsing,\n onImageLoad,\n onImageError,\n settleEntry,\n playCollapse,\n } = useSharedElementZoom({\n getOriginRect,\n index,\n isZoomed,\n imgRef,\n imgWrapperRef,\n bottomBarRef,\n measureBaseDims,\n });\n\n useEffect(() => {\n // Only suppress the hover-only zoom buttons on touch-PRIMARY devices\n // (phones/tablets). Merely being touch-capable (a touchscreen laptop or\n // 2-in-1 driven by a mouse) reports maxTouchPoints > 0, which would wrongly\n // hide the controls even though the pointer can click them. `(hover: none)\n // and (pointer: coarse)` matches only devices whose primary input is touch.\n if (typeof window === \"undefined\" || !window.matchMedia) {\n setIsTouchDevice(\"ontouchstart\" in window || navigator.maxTouchPoints > 0);\n return;\n }\n const mq = window.matchMedia(\"(hover: none) and (pointer: coarse)\");\n const update = () => setIsTouchDevice(mq.matches);\n update();\n mq.addEventListener(\"change\", update);\n return () => mq.removeEventListener(\"change\", update);\n }, []);\n\n useEffect(() => {\n const onResize = () => setViewportWidth(window.innerWidth);\n window.addEventListener(\"resize\", onResize);\n return () => window.removeEventListener(\"resize\", onResize);\n }, []);\n\n useEffect(() => {\n const raf = requestAnimationFrame(() => setVisible(true));\n return () => cancelAnimationFrame(raf);\n }, []);\n\n const handleClose = useCallback(() => {\n const reduce = prefersReducedMotion();\n // If the open zoom is still playing, settle the image to its resting pose\n // first so the collapse measures the real box, not a mid-flight transform.\n settleEntry();\n\n setClosing(true);\n setVisible(false);\n\n // Collapse back into the source thumbnail when one applies; otherwise the\n // backdrop/bars/track simply fade out (default close).\n playCollapse();\n\n setTimeout(onClose, reduce ? 0 : ANIM_MS);\n }, [onClose, settleEntry, playCollapse]);\n\n // Touch-tap close for the backdrop/stage. On iOS a tap that closes the viewer\n // via the synthesized `click` also fires synthesized mouse events (mouseover /\n // mousemove) straight after; once the backdrop unmounts those re-target to\n // whatever element now sits under the finger — a thumbnail on the page behind —\n // leaving it stuck in `:hover` (the tap \"falls through\"). Closing on touchend\n // and calling preventDefault suppresses those synthesized events *and* the\n // follow-up click, so the tap stays contained to the viewer. The\n // target===currentTarget guard keeps swipes/taps on the image (which bubble up\n // from the wrapper) from triggering a close.\n const handleBackdropTouchEnd = useCallback(\n (e: React.TouchEvent) => {\n if (e.target !== e.currentTarget) return;\n e.preventDefault();\n handleClose();\n },\n [handleClose],\n );\n\n // The track spans the whole viewport and owns every swipe/pan/pinch, so a\n // gesture registers wherever it starts — including the empty space around a\n // letterboxed image (the image wrapper only covers the picture itself). It\n // doubles as the backdrop hit target: a stationary tap on the background\n // closes, but a swipe that merely happens to end over empty space must not.\n // `gestureMovedRef` tells the two apart; `target===currentTarget` limits close\n // to the background (taps on the image bubble up from the wrapper).\n const handleTrackTouchEnd = useCallback(\n (e: React.TouchEvent) => {\n gestures.handleTouchEnd(e);\n if (!closeOnBackdropClick) return;\n if (e.target !== e.currentTarget) return;\n if (gestures.gestureMovedRef.current) return;\n e.preventDefault();\n handleClose();\n },\n [gestures, closeOnBackdropClick, handleClose],\n );\n\n const handleTrackClick = useCallback(\n (e: React.MouseEvent) => {\n if (e.target !== e.currentTarget) return;\n if (isGhostMouseEvent()) return;\n if (gestures.gestureMovedRef.current) return;\n handleClose();\n },\n [gestures, isGhostMouseEvent, handleClose],\n );\n\n // Mouse double-click zoom, minus the iOS ghost dblclick from the opening tap\n // (which would land here and pop the just-opened image into a zoom state).\n const handleDoubleClickGuarded = useCallback(\n (e: React.MouseEvent) => {\n if (isGhostMouseEvent()) return;\n handleDoubleClick(e);\n },\n [handleDoubleClick, isGhostMouseEvent],\n );\n\n // Backdrop/stage click-to-close, minus the iOS ghost click from the opening\n // tap (which would land here and close the viewer the instant it opened).\n const handleBackdropClick = useCallback(() => {\n if (isGhostMouseEvent()) return;\n handleClose();\n }, [handleClose, isGhostMouseEvent]);\n\n const navigate = useCallback(\n (dir: \"prev\" | \"next\") => {\n // commitSlide plays the three-slot slide and wraps the index itself when\n // looping, so boundary wraps animate in exactly like an interior move.\n if (dir === \"prev\") {\n if (hasPrev) commitSlide(\"prev\");\n } else {\n if (hasNext) commitSlide(\"next\");\n }\n },\n [hasPrev, hasNext, commitSlide],\n );\n\n useEffect(() => {\n const handler = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n // Let the consumer dismiss its own overlay first; only close when the\n // veto hook declines to handle the key.\n if (onEscape?.()) return;\n handleClose();\n return;\n }\n if (disableNavigation || displayScale > 1) return;\n if (e.key === \"ArrowLeft\" && hasPrev) navigate(\"prev\");\n if (e.key === \"ArrowRight\" && hasNext) navigate(\"next\");\n };\n window.addEventListener(\"keydown\", handler);\n return () => window.removeEventListener(\"keydown\", handler);\n }, [handleClose, hasPrev, hasNext, displayScale, navigate, onEscape, disableNavigation]);\n\n const setContentShift = useCallback((transform: string | null, animate = true) => {\n setContentShiftState({ transform, animate });\n }, []);\n\n const ctx: ViewerContext<TData> = {\n items,\n index,\n item: item!,\n total: items.length,\n closing,\n hasPrev,\n hasNext,\n goPrev: () => navigate(\"prev\"),\n goNext: () => navigate(\"next\"),\n goTo: (i: number) => {\n if (i !== index && i >= 0 && i < items.length) onIndexChange(i);\n },\n close: handleClose,\n isZoomed,\n displayScale,\n zoomIn: () => {\n const t = transformRef.current;\n const next = Math.min(MAX_SCALE, t.scale * 1.3);\n const clamped = clampTranslate(t.x, t.y, next);\n setTransform({ scale: next, ...clamped }, true);\n },\n zoomOut: () => {\n const t = transformRef.current;\n const next = Math.max(MIN_SCALE, t.scale / 1.3);\n const clamped = next <= 1 ? { x: 0, y: 0 } : clampTranslate(t.x, t.y, next);\n setTransform({ scale: next, ...clamped }, true);\n },\n resetZoom: resetTransform,\n isTouchDevice,\n topBarHeight: topBarH,\n bottomBarHeight: bottomBarH,\n setContentShift,\n };\n\n if (!item) return null;\n\n const reservedH = bottomBarH + IMG_PADDING * 2;\n const imgMaxHeight = `calc(100vh - ${reservedH}px)`;\n const imgStyle: React.CSSProperties = { maxHeight: imgMaxHeight };\n\n // Numbers become px; strings pass through (e.g. \"1.5rem\"). Only emit vars that\n // were supplied so the stylesheet defaults still apply otherwise.\n const dim = (v: number | string) => (typeof v === \"number\" ? `${v}px` : v);\n const rootStyle: React.CSSProperties = {\n ...(navHeight != null && { \"--rvl-nav-height\": dim(navHeight) }),\n ...(navInset != null && { \"--rvl-nav-inset\": dim(navInset) }),\n ...(counterFontSize != null && { \"--rvl-counter-font-size\": dim(counterFontSize) }),\n } as React.CSSProperties;\n // Keep the image hidden (but laid out, so the zoom can still measure its box)\n // until the full source has decoded, so the entry plays from the thumbnail\n // with no full-size flash. opacity, not display, to preserve the layout box.\n if (gateEntry && !fullLoaded) imgStyle.opacity = 0;\n\n const totalDigits = String(items.length).length;\n const counterMinWidth = `${totalDigits * 2 * 0.6 + 1.5}em`;\n\n // Three-slot carousel neighbors. When looping, the slots at the ends point at\n // the wrap-around items (last ↔ first) so the wrapping slide has a real image\n // to reveal instead of an empty panel.\n const prevIndex = hasPrevLinear ? index - 1 : hasPrev ? items.length - 1 : -1;\n const nextIndex = hasNextLinear ? index + 1 : hasNext ? 0 : -1;\n const prevItem = prevIndex >= 0 ? items[prevIndex] : null;\n const nextItem = nextIndex >= 0 ? items[nextIndex] : null;\n const showAdjacent = slideActive || slideAnimating || swipeOffset !== 0;\n // Neighbors sit `slideDistance` px to the side (see measureSlideDistance),\n // which starts their image right at the screen edge, so they slide in from the\n // edge as the track shifts. Falls back to the full viewport width before the\n // first measurement lands (classic full-width slot), matching the old\n // translateX(±100%) behavior.\n const adjacentOffset = slideDistance || viewportWidth;\n // The incoming neighbor also fades in as it's dragged toward center: opacity\n // ramps with the swipe distance and clamps to 1 shortly before the slide\n // fully commits, so the reveal is a crossfade rather than a hard slide.\n const adjacentOpacity = Math.min(1, Math.abs(swipeOffset) / (adjacentOffset * 0.8 || 1));\n // On commit/snap the offset jumps straight to its target, so the opacity would\n // snap 0→1 in one frame — a flash, worst on a fast flick that never dragged\n // far enough to raise the opacity much. Glide it over the slide's duration\n // while animating; during a live drag there's no transition, so it still\n // tracks the finger exactly.\n const adjacentTransition = slideAnimating ? \"opacity 0.28s cubic-bezier(0.2, 0, 0, 1)\" : \"none\";\n\n // Never show the zoom controls while the image is shifted out of view (e.g. a\n // consumer-driven details/overlay pane pushed in via setContentShift): the\n // image isn't on screen, so zooming it makes no sense.\n const showZoomCtrls = zoom && !isTouchDevice && showZoomControls && !contentShift.transform;\n const headerActions = renderHeaderActions?.(ctx);\n const navStart = renderNavStart?.(ctx);\n const navEnd = renderNavEnd?.(ctx);\n const hasNavGroup = hasPrev || hasNext;\n const showNavRow = !isZoomed && (hasNavGroup || navStart != null || navEnd != null);\n\n return (\n <div\n ref={containerRef}\n className={cx(\"rvl-root\", visible && !closing && \"rvl-visible\", cn(\"root\"))}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={ariaLabel ?? item.alt ?? \"Image viewer\"}\n tabIndex={-1}\n style={rootStyle}\n >\n <div\n className={cx(\"rvl-backdrop\", cn(\"backdrop\"))}\n onClick={closeOnBackdropClick ? handleBackdropClick : undefined}\n onTouchEnd={closeOnBackdropClick ? handleBackdropTouchEnd : undefined}\n aria-hidden=\"true\"\n />\n\n <div ref={topBarRef} className={cx(\"rvl-bar\", \"rvl-top-bar\", cn(\"topBar\"))}>\n <div className={cx(\"rvl-header\", cn(\"topBar\"))}>{renderHeader?.(ctx)}</div>\n\n <div className=\"rvl-header-actions\">\n {headerActions}\n\n {showZoomCtrls && isZoomed && (\n <ChromeButton\n className={cx(\"rvl-btn-scale\", cn(\"button\"))}\n onClick={resetTransform}\n title=\"Reset zoom\"\n ariaLabel=\"Reset zoom\"\n >\n {Math.round(displayScale * 100)}%\n </ChromeButton>\n )}\n\n {showZoomCtrls && (\n <ChromeButton\n className={cn(\"button\")}\n onClick={ctx.zoomIn}\n title=\"Zoom in\"\n ariaLabel=\"Zoom in\"\n >\n {mergedIcons.zoomIn}\n </ChromeButton>\n )}\n\n {showZoomCtrls && (\n <ChromeButton\n className={cn(\"button\")}\n onClick={ctx.zoomOut}\n title=\"Zoom out\"\n ariaLabel=\"Zoom out\"\n >\n {mergedIcons.zoomOut}\n </ChromeButton>\n )}\n\n <ChromeButton\n className={cn(\"button\")}\n onClick={handleClose}\n title=\"Close (Esc)\"\n ariaLabel=\"Close\"\n >\n {mergedIcons.close}\n </ChromeButton>\n </div>\n </div>\n\n <div\n className=\"rvl-stage\"\n style={{\n transform: contentShift.transform ?? \"translateY(0)\",\n // animate=false snaps with no transition (overrides the CSS transition)\n transition: contentShift.animate ? undefined : \"none\",\n }}\n >\n <div\n ref={slideTrackRef}\n // The track fills the whole stage and owns every gesture, so a swipe\n // registers no matter where it starts — including the empty space\n // around a letterboxed image. It's also the backdrop close target\n // (handleTrackTouchEnd / handleTrackClick), distinguishing a tap on the\n // background from a swipe that merely ends there.\n onPointerDown={gestures.handlePointerDown}\n onPointerMove={gestures.handlePointerMove}\n onPointerUp={gestures.handlePointerUp}\n onPointerLeave={gestures.handlePointerUp}\n onTouchStart={gestures.handleTouchStart}\n onTouchMove={gestures.handleTouchMove}\n onTouchEnd={handleTrackTouchEnd}\n onClick={closeOnBackdropClick ? handleTrackClick : undefined}\n className={cx(\n \"rvl-track\",\n // Promote the track only while a swipe is live (drag + commit/snap\n // animation), then release the layer. Matches `showAdjacent`.\n showAdjacent && \"rvl-track-swiping\",\n // During a thumbnail zoom the track is opaque from the first frame\n // (the image itself is hidden until the zoom starts), so the picture\n // flies in crisply instead of cross-fading. On close it only stays\n // opaque while a FLIP collapse is animating the image back; otherwise\n // it fades out (so a zoomed close still animates instead of vanishing).\n (closing ? collapsing : zoomTransition || visible) && \"rvl-track-visible\",\n )}\n >\n {showAdjacent && prevItem && (\n <div\n className=\"rvl-adjacent\"\n // Positioned `slideDistance` px to the left (the panel is centered\n // in the full-width track, so this places its image just past the\n // left screen edge) and shown only when swiping toward it (offset >\n // 0 reveals prev); the opposite neighbor stays hidden so it can\n // never flash in.\n style={{\n transform: `translateX(${-adjacentOffset}px)`,\n opacity: swipeOffset > 0 ? adjacentOpacity : 0,\n transition: adjacentTransition,\n }}\n >\n <img\n src={prevItem.src}\n alt=\"\"\n className={cx(\"rvl-img\", cn(\"image\"))}\n style={imgStyle}\n draggable={false}\n />\n </div>\n )}\n\n <div\n ref={imgWrapperRef}\n className=\"rvl-img-wrapper\"\n // Gestures live on the track (which spans the viewport); the wrapper\n // only stops a tap/click on the image itself from bubbling up to the\n // track's backdrop-close handler.\n onClick={(e) => e.stopPropagation()}\n onDoubleClick={handleDoubleClickGuarded}\n >\n <img\n ref={imgRef}\n src={item.src}\n alt={item.alt ?? \"\"}\n className={cx(\"rvl-img\", cn(\"image\"))}\n style={imgStyle}\n draggable={false}\n onLoad={onImageLoad}\n onError={onImageError}\n />\n </div>\n\n {gateEntry && showSpinner && !fullLoaded && (\n <div className={cx(\"rvl-spinner\", cn(\"spinner\"))} role=\"status\" aria-label=\"Loading\">\n <span className=\"rvl-spinner-ring\" aria-hidden=\"true\" />\n </div>\n )}\n\n {showAdjacent && nextItem && (\n <div\n className=\"rvl-adjacent\"\n // See prev panel above: positioned `slideDistance` px to the right\n // (image just past the right screen edge) and shown only when\n // swiping toward next (offset < 0) so prev never flashes on the far\n // edge.\n style={{\n transform: `translateX(${adjacentOffset}px)`,\n opacity: swipeOffset < 0 ? adjacentOpacity : 0,\n transition: adjacentTransition,\n }}\n >\n <img\n src={nextItem.src}\n alt=\"\"\n className={cx(\"rvl-img\", cn(\"image\"))}\n style={imgStyle}\n draggable={false}\n />\n </div>\n )}\n </div>\n </div>\n\n <div ref={bottomBarRef} className={cx(\"rvl-bar\", \"rvl-bottom-bar\", cn(\"bottomBar\"))}>\n {showNavRow && (\n <div className=\"rvl-nav-row\">\n <div className={cx(\"rvl-nav-inner\", navSlotPlacement === \"inline\" && \"rvl-nav-inline\")}>\n {navStart != null && (\n <div className={cx(\"rvl-nav-start\", cn(\"navStart\"))}>{navStart}</div>\n )}\n {hasNavGroup && (\n <div className=\"rvl-nav-group\">\n <NavButton\n direction=\"prev\"\n enabled={hasPrev}\n onClick={() => navigate(\"prev\")}\n icon={mergedIcons.prev}\n className={cn(\"navButton\")}\n />\n {showCounter && (\n <span\n className={cx(\"rvl-counter\", cn(\"counter\"))}\n style={{ minWidth: counterMinWidth }}\n >\n {index + 1} / {items.length}\n </span>\n )}\n <NavButton\n direction=\"next\"\n enabled={hasNext}\n onClick={() => navigate(\"next\")}\n icon={mergedIcons.next}\n className={cn(\"navButton\")}\n />\n </div>\n )}\n {navEnd != null && <div className={cx(\"rvl-nav-end\", cn(\"navEnd\"))}>{navEnd}</div>}\n </div>\n </div>\n )}\n\n {renderFooter && <div className=\"rvl-footer\">{renderFooter(ctx)}</div>}\n </div>\n\n {renderOverlay && (\n <div className={cx(\"rvl-overlay\", cn(\"overlay\"))}>{renderOverlay(ctx)}</div>\n )}\n </div>\n );\n}\n"]}
|