{"version":3,"file":"lightbox.mjs","names":[],"sources":["../../../../package/common/lightbox/lightbox.tsx"],"sourcesContent":["import {\n  useCallback,\n  useContext,\n  useEffect,\n  useLayoutEffect,\n  useRef,\n  useState,\n  type CSSProperties,\n  type KeyboardEvent as ReactKeyboardEvent,\n  type PointerEvent as ReactPointerEvent,\n  type Ref,\n  type RefCallback,\n  type RefObject,\n} from 'react';\nimport cx from 'classnames';\nimport { faMagnifyingGlassMinus, faMagnifyingGlassPlus, faXmark } from '@fortawesome/free-solid-svg-icons';\n\nimport ActionIcon from '../actionIcon';\nimport BodyEnd from '../bodyEnd';\nimport Carousel from '../carousel';\nimport Image from '../image';\nimport Loader from '../loader';\nimport { CarouselSlideContext } from '../carousel/carouselSlideContext';\nimport PanZoom from '../panZoom';\nimport type { PanZoomHandle } from '../panZoom/panZoom.types';\nimport { useComponentDefaults, useLabels } from '../configProvider';\nimport { useOverlay } from '../hooks/useOverlay';\nimport { useSwipeDismiss } from '../hooks/useSwipeDismiss';\nimport type { LightboxImage, LightboxLabels, LightboxProps, LightboxSlots } from './lightbox.types';\nimport { flightKeyframes, flungFrame, hideThumbnail, pictureFrame, thumbnailFrame } from './lightbox.flight';\nimport type { SlotClassNames, SlotStyles } from '../types/slots.types';\nimport styles from './lightbox.module.pcss';\n\nconst DEFAULT_LABELS: Required<LightboxLabels> = {\n  dialog: 'Image viewer',\n  close: 'Close',\n  previous: 'Previous image',\n  next: 'Next image',\n  zoomIn: 'Zoom in',\n  zoomOut: 'Zoom out',\n  loadError: 'This image could not be loaded.',\n  counter: (position, count) => `${position} / ${count}`,\n};\n\n/** The closing animation's length in lightbox.module.pcss, and the flight back into a thumbnail. */\nconst CLOSE_MS = 250;\nconst OPEN_FLIGHT_MS = 300;\nconst FLIGHT_EASING = 'cubic-bezier(0.2, 0, 0, 1)';\n\n/** Controls that use the left and right arrow keys themselves. */\nconst OWNS_ARROW_KEYS = 'input, textarea, select, [contenteditable=\"\"], [contenteditable=\"true\"], [role=\"slider\"]';\n\nfunction Lightbox(props: LightboxProps) {\n  const { isOpen = false, ...rest } = useComponentDefaults('Lightbox', props);\n  const [isRendered, setRendered] = useState(isOpen);\n\n  // The dialog's key, so a reopening mid-close mounts fresh too: on `defaultIndex`, without a swipe's offset.\n  const [opening, setOpening] = useState(0);\n  const [wasOpen, setWasOpen] = useState(isOpen);\n  if (isOpen !== wasOpen) {\n    setWasOpen(isOpen);\n    if (isOpen) setOpening(opening + 1);\n  }\n\n  useEffect(() => {\n    if (isOpen) {\n      setRendered(true);\n      return;\n    }\n    const id = setTimeout(() => setRendered(false), CLOSE_MS);\n    return () => clearTimeout(id);\n  }, [isOpen]);\n\n  if (!(isOpen || isRendered) || rest.images.length === 0) return null;\n  return <LightboxDialog key={opening} {...rest} isClosing={!isOpen} />;\n}\n\nfunction LightboxDialog({\n  images,\n  onClose = () => {},\n  currentIndex,\n  defaultIndex = 0,\n  onChange,\n  actions,\n  getThumbnail,\n  glow = false,\n  className,\n  style,\n  classNames,\n  styles: slotStyles,\n  labels,\n  onKeyDown,\n  isClosing,\n  ...rest\n}: Omit<LightboxProps, 'isOpen'> & { isClosing: boolean }) {\n  const text = useLabels('Lightbox', labels, DEFAULT_LABELS);\n  const dialogRef = useRef<HTMLDivElement>(null);\n  const count = images.length;\n  const [internalIndex, setInternalIndex] = useState(defaultIndex);\n  const index = wrapIndex(currentIndex ?? internalIndex, count);\n  const panZoomRef = useRef<PanZoomHandle>(null);\n  // With its index: the next image always comes in fitted.\n  const [zoomedIndex, setZoomedIndex] = useState<number | null>(null);\n  const isZoomed = zoomedIndex === index;\n  // By source: a neighbour loads before it is on show.\n  const [loadedSources, setLoadedSources] = useState<ReadonlySet<string>>(() => new Set());\n  const canZoom = loadedSources.has(images[index].src);\n  const [isClear, setClear] = useState(false);\n\n  // Released at the start of closing, not after the animation.\n  useOverlay({ isActive: !isClosing, containerRef: dialogRef, onEscape: onClose });\n\n  // The backdrop and the controls have faded out by twice the distance that closes it.\n  const swipeThreshold = Math.round(window.innerHeight / 5);\n  const swipeOffset = useRef(0);\n  // The image stays opaque and where it was let go: it shrinks instead, and the flight takes it from there.\n  const { ref: swipeRef, isDragging } = useSwipeDismiss<HTMLElement>({\n    onDismiss: onClose,\n    axis: 'y',\n    distanceThreshold: swipeThreshold,\n    mobileOnly: false,\n    fade: false,\n    animateExit: false,\n    disabled: isClosing,\n    onDrag: (offset) => {\n      swipeOffset.current = offset;\n      dialogRef.current?.style.setProperty(\n        '--custom-lightbox-fade',\n        String(Math.min(1, Math.abs(offset) / (swipeThreshold * 2))),\n      );\n    },\n  });\n\n  const shownFigure = useRef<HTMLElement | null>(null);\n  const figureRef = useCallback(\n    (figure: HTMLElement | null) => {\n      swipeRef(figure);\n      shownFigure.current = figure;\n    },\n    [swipeRef],\n  );\n  const { flyerRef, isFlying } = useThumbnailFlight({\n    isClosing,\n    thumbnail: () => getThumbnail?.(images[index], index),\n    figureRef: shownFigure,\n    swipeOffset,\n  });\n\n  // Lifted out of the grid while on show, so it never shows twice: behind a backdrop a swipe fades.\n  useLayoutEffect(() => {\n    const thumbnail = isClosing ? null : getThumbnail?.(images[index], index);\n    return thumbnail ? hideThumbnail(thumbnail) : undefined;\n  }, [isClosing, getThumbnail, images, index]);\n\n  // A slide that left is `inert`, which drops its focus to the body, out of the arrow keys' reach.\n  // Chromium has dropped it before this runs, hence the body check.\n  useLayoutEffect(() => {\n    const active = document.activeElement;\n    if (!active || active === document.body || active.closest('[inert]')) dialogRef.current?.focus();\n  }, [index]);\n\n  function goTo(next: number) {\n    const wrapped = wrapIndex(next, count);\n    setInternalIndex(wrapped);\n    onChange?.(wrapped);\n  }\n\n  // Carousel answers the arrow keys on its own buttons only.\n  function handleKeyDown(event: ReactKeyboardEvent<HTMLDivElement>) {\n    onKeyDown?.(event);\n    // A key means a keyboard, which needs the controls it moves to.\n    setClear(false);\n    if (event.defaultPrevented || count < 2) return;\n    // Alt + left is the browser's Back, and a field in a caption needs its own arrows.\n    if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) return;\n    if ((event.target as Element).closest(OWNS_ARROW_KEYS)) return;\n    if (event.key === 'ArrowLeft') goTo(index - 1);\n    else if (event.key === 'ArrowRight') goTo(index + 1);\n    else return;\n    event.preventDefault();\n  }\n\n  const isNamed = rest['aria-label'] !== undefined || rest['aria-labelledby'] !== undefined;\n\n  return (\n    <BodyEnd>\n      <div\n        {...rest}\n        ref={dialogRef}\n        role='dialog'\n        aria-modal='true'\n        aria-label={isNamed ? rest['aria-label'] : text.dialog}\n        tabIndex={-1}\n        inert={isClosing || undefined}\n        className={cx(\n          styles.lightbox,\n          isClosing && styles.lightboxClosing,\n          isDragging && styles.lightboxDragging,\n          isFlying && styles.lightboxFlying,\n          isClear && styles.lightboxClear,\n          className,\n          classNames?.root,\n        )}\n        style={{ ...style, ...slotStyles?.root }}\n        onKeyDown={handleKeyDown}\n      >\n        <div className={cx(styles.lightboxToolbar, classNames?.toolbar)} style={slotStyles?.toolbar}>\n          <span className={cx(styles.lightboxCounter, classNames?.counter)} style={slotStyles?.counter}>\n            {count > 1 ? text.counter(index + 1, count) : null}\n          </span>\n          {actions && (\n            <div className={cx(styles.lightboxActions, classNames?.actions)} style={slotStyles?.actions}>\n              {actions(images[index], index)}\n            </div>\n          )}\n          <ActionIcon\n            icon={isZoomed ? faMagnifyingGlassMinus : faMagnifyingGlassPlus}\n            title={isZoomed ? text.zoomOut : text.zoomIn}\n            aria-label={isZoomed ? text.zoomOut : text.zoomIn}\n            aria-disabled={!canZoom || undefined}\n            onClick={() => {\n              if (canZoom) panZoomRef.current?.toggle();\n            }}\n            className={cx(!canZoom && styles.lightboxUnavailable, classNames?.zoomButton)}\n            style={slotStyles?.zoomButton}\n          />\n          <ActionIcon\n            icon={faXmark}\n            title={text.close}\n            aria-label={text.close}\n            onClick={onClose}\n            className={classNames?.closeButton}\n            style={slotStyles?.closeButton}\n          />\n        </div>\n\n        {/* Every prop set, or the app's Carousel defaults would reach it: autoplay, no arrows. */}\n        <Carousel\n          className={styles.lightboxCarousel}\n          classNames={{\n            track: styles.lightboxTrack,\n            prevButton: styles.lightboxArrow,\n            nextButton: styles.lightboxArrow,\n          }}\n          currentIndex={index}\n          onChange={goTo}\n          loop\n          autoPlay={false}\n          showArrows\n          showDots={false}\n          swipeable\n          lazyRender\n          adaptiveHeight={false}\n          labels={{ previous: text.previous, next: text.next }}\n        >\n          {images.map((image, i) => (\n            <LightboxSlide\n              // With the source, so a replaced image starts loading afresh.\n              key={`${i}:${image.src}`}\n              image={image}\n              loadError={text.loadError}\n              glow={glow}\n              isCurrent={i === index}\n              hasLoaded={loadedSources.has(image.src)}\n              onLoad={() =>\n                setLoadedSources((current) => (current.has(image.src) ? current : new Set(current).add(image.src)))\n              }\n              panZoomRef={panZoomRef}\n              figureRef={figureRef}\n              onScaleChange={(scale) => setZoomedIndex(scale > 1 ? index : null)}\n              // A mouse has the controls in reach and no screen to clear: a click would only lose them.\n              onTap={(event) => {\n                if (event.pointerType !== 'mouse') setClear((clear) => !clear);\n              }}\n              classNames={classNames}\n              styles={slotStyles}\n            />\n          ))}\n        </Carousel>\n      </div>\n      {/* Outside the dialog, whose fades would take it along. */}\n      {isFlying && <img ref={flyerRef} className={styles.lightboxFlyer} alt='' aria-hidden='true' />}\n    </BodyEnd>\n  );\n}\n\ninterface Flight {\n  direction: 'in' | 'out';\n  thumbnail: HTMLElement | null;\n  /** How far a swipe to close had moved the image, which flies on that way with no thumbnail to land in. */\n  swipe: number;\n}\n\ninterface ThumbnailFlightArgs {\n  isClosing: boolean;\n  /** The thumbnail of the image on show. */\n  thumbnail: () => HTMLElement | null | undefined;\n  figureRef: RefObject<HTMLElement | null>;\n  swipeOffset: RefObject<number>;\n}\n\n/**\n * Flies the image out of its thumbnail as the viewer opens, and into the thumbnail of the image on\n * show as it closes. A copy flies: the Carousel and the PanZoom both clip the image itself.\n */\nfunction useThumbnailFlight({ isClosing, thumbnail, figureRef, swipeOffset }: ThumbnailFlightArgs) {\n  const [flight, setFlight] = useState<Flight | null>(null);\n  const flyerRef = useRef<HTMLImageElement>(null);\n\n  useLayoutEffect(() => {\n    const element = thumbnail() ?? null;\n    const swipe = isClosing ? swipeOffset.current : 0;\n    if (!(element || swipe) || window.matchMedia?.('(prefers-reduced-motion: reduce)').matches) return;\n    setFlight({ direction: isClosing ? 'out' : 'in', thumbnail: element, swipe });\n    // As it opens and as it starts closing, with the image on show then.\n    // oxlint-disable-next-line react-hooks/exhaustive-deps\n  }, [isClosing]);\n\n  // A commit after the one above: on opening, the first in which the Image has put up its picture.\n  useLayoutEffect(() => {\n    const flyer = flyerRef.current;\n    const figure = figureRef.current;\n    if (!flight || !flyer || !figure) return;\n    const picture = pictureFrame(figure);\n    const home = picture && flight.thumbnail ? thumbnailFrame(flight.thumbnail, picture.aspect) : null;\n    const away = home ?? (picture && flight.swipe ? flungFrame(picture.frame, flight.swipe) : null);\n    const [from, to] = flight.direction === 'in' ? [home, picture?.frame] : [picture?.frame, away];\n    if (!picture || !from || !to) {\n      setFlight(null);\n      return;\n    }\n\n    // At the larger end, so it is scaled down rather than blurred up. Inline, against an app's\n    // `img { max-width: 100% }`, which wins over a layered stylesheet: a zoomed-in image is wider.\n    const layout = from.box.width > to.box.width ? from.box : to.box;\n    Object.assign(flyer.style, {\n      left: `${layout.left}px`,\n      top: `${layout.top}px`,\n      width: `${layout.width}px`,\n      height: `${layout.height}px`,\n      maxWidth: 'none',\n      maxHeight: 'none',\n    });\n    flyer.src = picture.src;\n    const show = home && flight.thumbnail ? hideThumbnail(flight.thumbnail) : undefined;\n\n    const animation = flyer.animate(flightKeyframes(from, to, layout), {\n      duration: flight.direction === 'in' ? OPEN_FLIGHT_MS : CLOSE_MS,\n      easing: FLIGHT_EASING,\n      fill: 'both',\n    });\n    animation.finished.then(\n      () => setFlight(null),\n      () => {},\n    );\n    return () => {\n      animation.cancel();\n      show?.();\n    };\n  }, [flight, figureRef]);\n\n  return { flyerRef, isFlying: flight !== null };\n}\n\ninterface LightboxSlideProps {\n  image: LightboxImage;\n  loadError: string;\n  glow: boolean;\n  /** For every instance of the image on show, its looping copy included, unlike the slide context. */\n  isCurrent: boolean;\n  hasLoaded: boolean;\n  onLoad: () => void;\n  panZoomRef: Ref<PanZoomHandle>;\n  figureRef: RefCallback<HTMLElement>;\n  onScaleChange: (scale: number) => void;\n  onTap: (event: ReactPointerEvent<HTMLDivElement>) => void;\n  classNames?: SlotClassNames<LightboxSlots>;\n  styles?: SlotStyles<LightboxSlots>;\n}\n\n/** Only the instance on show takes the refs: a looping Carousel also renders inert copies. */\nfunction LightboxSlide({\n  image,\n  loadError,\n  glow,\n  isCurrent,\n  hasLoaded,\n  onLoad,\n  panZoomRef,\n  figureRef,\n  onScaleChange,\n  onTap,\n  classNames,\n  styles: slotStyles,\n}: LightboxSlideProps) {\n  const isOnShow = useContext(CarouselSlideContext);\n  const [hasFailed, setFailed] = useState(false);\n\n  return (\n    // What a swipe to close moves, the caption with it.\n    <figure\n      ref={isOnShow ? figureRef : undefined}\n      className={cx(styles.lightboxFigure, classNames?.figure)}\n      style={slotStyles?.figure}\n    >\n      {/* Disabled off screen, which zooms an image back out as it leaves. */}\n      <PanZoom\n        ref={isOnShow ? panZoomRef : undefined}\n        className={styles.lightboxPanZoom}\n        scrollToZoom\n        showControls={false}\n        disabled={!isOnShow || hasFailed}\n        onScaleChange={isOnShow ? onScaleChange : undefined}\n        onTap={isOnShow ? onTap : undefined}\n      >\n        {/* A spinner: a skeleton would need the image's shape, unknown until it loads. */}\n        <Image\n          src={image.src}\n          alt={image.alt}\n          thumbnail={image.thumbnail}\n          placeholder={<Loader className={styles.lightboxLoader} />}\n          onLoad={onLoad}\n          onError={() => setFailed(true)}\n          fallback={<p className={styles.lightboxError}>{loadError}</p>}\n          className={classNames?.image}\n          style={slotStyles?.image}\n          classNames={{ placeholder: styles.lightboxThumbnail }}\n          // Not as `width` and `height`, which would become the image's attributes and size it.\n          styles={image.width && image.height ? { placeholder: knownSize(image.width, image.height) } : undefined}\n        />\n      </PanZoom>\n      {/* After the PanZoom, which the flight finds first in the figure. Lit once the image is in, and only\n          for the image on show: it reaches past its slide, and a neighbour's would shine in at the edge of\n          the screen. Its looping copy too, which is what a wrap from the last image to the first slides in. */}\n      {glow && (\n        <img\n          src={image.src}\n          alt=''\n          aria-hidden='true'\n          className={cx(styles.lightboxGlow, hasLoaded && isCurrent && styles.lightboxGlowLit, classNames?.glow)}\n          style={slotStyles?.glow}\n        />\n      )}\n      {image.caption != null && (\n        <figcaption className={cx(styles.lightboxCaption, classNames?.caption)} style={slotStyles?.caption}>\n          {image.caption}\n        </figcaption>\n      )}\n    </figure>\n  );\n}\n\nfunction knownSize(width: number, height: number): CSSProperties {\n  return { '--custom-image-width': `${width}px`, '--custom-image-ratio': `${width} / ${height}` } as CSSProperties;\n}\n\nfunction wrapIndex(index: number, count: number): number {\n  return ((index % count) + count) % count;\n}\n\nexport default Lightbox;\n"],"mappings":"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"}