{
  "version": 3,
  "sources": ["/cdn/shop/t/8/assets/media-gallery.js?codex_gallery_fix=20260609b"],
  "sourcesContent": ["import { Component } from '@theme/component';\r\nimport { ThemeEvents, VariantUpdateEvent, ZoomMediaSelectedEvent } from '@theme/events';\r\n\r\n/**\r\n * A custom element that renders a media gallery.\r\n *\r\n * @typedef {object} Refs\r\n * @property {import('./zoom-dialog').ZoomDialog} [zoomDialogComponent] - The zoom dialog component.\r\n * @property {import('./slideshow').Slideshow} [slideshow] - The slideshow component.\r\n * @property {HTMLElement[]} [media] - The media elements.\r\n *\r\n * @extends Component<Refs>\r\n */\r\nexport class MediaGallery extends Component {\n  connectedCallback() {\n    super.connectedCallback();\n    this.#removeLowQualityGalleryMedia();\n\n    const { signal } = this.#controller;\n    const target = this.closest('.shopify-section, dialog');\n\r\n    target?.addEventListener(ThemeEvents.variantUpdate, this.#handleVariantUpdate, { signal });\n    this.refs.zoomDialogComponent?.addEventListener(ThemeEvents.zoomMediaSelected, this.#handleZoomMediaSelected, {\n      signal,\n    });\n    requestAnimationFrame(() => this.#selectInitialVariantMedia());\n  }\n\r\n  #controller = new AbortController();\n\n  #mediaSelectionRequest = 0;\n\r\n  disconnectedCallback() {\r\n    super.disconnectedCallback();\r\n\r\n    this.#controller.abort();\r\n  }\r\n\r\n  /**\n   * Handles a variant update event by selecting the variant media when possible.\n   *\n   * @param {VariantUpdateEvent} event - The variant update event.\n   */\n  #handleVariantUpdate = async (event) => {\n    const source = event.detail.data.html;\n    const variantMediaId = event.detail.resource?.featured_media?.id;\n\n    if (source) {\n      const newMediaGallery = source.querySelector('media-gallery');\n\n      if (newMediaGallery) {\n        this.replaceWith(newMediaGallery);\n        newMediaGallery.removeLowQualityMedia?.();\n        if (variantMediaId) {\n          this.#scheduleMediaSelection(newMediaGallery, String(variantMediaId));\n        }\n        return;\n      }\n    }\n\n    if (variantMediaId && !this.#isLowQualityMediaId(String(variantMediaId))) {\n      this.#selectMediaById(String(variantMediaId));\n      this.#scheduleMediaSelection(this, String(variantMediaId));\n    }\n  };\n\n  /**\n   * Public hook used after this element is inserted with replaceWith().\n   */\n  removeLowQualityMedia() {\n    this.#removeLowQualityGalleryMedia();\n  }\n\n  /**\n   * Selects a media item by Shopify media id.\n   * @param {string} mediaId - Shopify media ID.\n   * @returns {boolean}\n   */\n  selectMediaById(mediaId) {\n    return this.#selectMediaById(mediaId);\n  }\n\n  /**\n   * Selects a media item by Shopify media id.\n   * @param {string} mediaId - Shopify media ID.\n   * @returns {boolean}\n   */\n  #selectMediaById(mediaId) {\n    if (!mediaId) return false;\n    if (this.#isLowQualityMediaId(mediaId)) return false;\n\n    const slide = this.refs.slideshow?.refs.slides?.find((item) => item.getAttribute('slide-id') === mediaId);\n    if (slide) {\n      this.slideshow?.select({ id: mediaId }, undefined, { animate: false });\n      this.#syncSelectedSlide(mediaId);\n      return true;\n    }\n\n    const safeMediaId = globalThis.CSS?.escape ? CSS.escape(mediaId) : mediaId.replaceAll('\"', '\\\\\"');\n    const media = this.querySelector(`[data-media-id=\"${safeMediaId}\"]`);\n    const mediaContainer = media?.closest('[ref=\"media[]\"], .product-media-container, slideshow-slide');\n    if (!mediaContainer) return false;\n\n    mediaContainer.scrollIntoView({ block: 'nearest', inline: 'nearest', behavior: 'smooth' });\n    return true;\n  }\n\n  /**\n   * Keeps the visible slide and thumbnails in sync when media is selected before\n   * the slideshow internals finish reacting to a variant change.\n   * @param {string} mediaId - Shopify media ID.\n   */\n  #syncSelectedSlide(mediaId) {\n    this.#syncGalleryElementById(this, mediaId);\n  }\n\n  /**\n   * Keeps an arbitrary gallery element in sync. Useful immediately after\n   * replacing this element with Section Rendering API HTML.\n   * @param {Element} gallery\n   * @param {string} mediaId\n   */\n  #syncGalleryElementById(gallery, mediaId) {\n    const slides = Array.from(gallery.querySelectorAll('slideshow-slide'));\n    const selectedIndex = slides.findIndex((slide) => slide.getAttribute('slide-id') === mediaId);\n    if (selectedIndex < 0) return;\n\n    slides.forEach((slide) => {\n      const isSelected = slide.getAttribute('slide-id') === mediaId;\n      slide.setAttribute('aria-hidden', isSelected ? 'false' : 'true');\n      slide.toggleAttribute('active', isSelected);\n    });\n\n    gallery.querySelectorAll('slideshow-controls[thumbnails] .slideshow-controls__thumbnail').forEach((thumbnail, index) => {\n      const isSelected = index === selectedIndex;\n      thumbnail.setAttribute('aria-current', isSelected ? 'true' : 'false');\n      thumbnail.toggleAttribute('active', isSelected);\n    });\n  }\n\n  /**\n   * Re-applies the selected media after late variant/gallery rendering settles.\n   * @param {Element} gallery\n   * @param {string} mediaId\n   */\n  #scheduleMediaSelection(gallery, mediaId) {\n    const target = gallery.closest('.shopify-section, dialog') || document;\n    const requestId = `${Date.now()}-${++this.#mediaSelectionRequest}`;\n    target.__allbetterMediaSelectionRequest = requestId;\n    const isCurrentSelection = () => {\n      if (target.__allbetterMediaSelectionRequest !== requestId) return false;\n\n      const variantJson = target.querySelector('variant-picker script[type=\"application/json\"]')?.textContent;\n      if (!variantJson) return true;\n\n      try {\n        const variant = JSON.parse(variantJson);\n        const currentMediaId = variant?.featured_media?.id;\n        return !currentMediaId || String(currentMediaId) === mediaId;\n      } catch (error) {\n        return true;\n      }\n    };\n    const applyMedia = () => {\n      if (!isCurrentSelection()) return;\n      gallery.selectMediaById?.(mediaId);\n      this.#syncGalleryElementById(gallery, mediaId);\n    };\n\n    requestAnimationFrame(applyMedia);\n    [150, 750, 1800, 3600, 6200].forEach((delay) => {\n      window.setTimeout(applyMedia, delay);\n    });\n  }\n\n  /**\n   * Aligns the gallery with the variant selected in the picker on first load.\n   */\n  #selectInitialVariantMedia() {\n    const target = this.closest('.shopify-section, dialog') || document;\n    const variantJson = target.querySelector('variant-picker script[type=\"application/json\"]')?.textContent;\n    if (!variantJson) return;\n\n    try {\n      const variant = JSON.parse(variantJson);\n      const mediaId = variant?.featured_media?.id;\n      if (mediaId) this.#selectMediaById(String(mediaId));\n    } catch (error) {\n      // Ignore malformed variant JSON and keep the merchant-defined first image.\n    }\n  }\n\n  /**\n   * Removes imported swatch/thumbnail files from the main product gallery.\n   * Those files can be attached as variant media but are too small for the gallery.\n   */\n  #removeLowQualityGalleryMedia() {\n    const removedSlideIndexes = new Set();\n\n    this.querySelectorAll('slideshow-slide').forEach((slide, index) => {\n      if (!this.#elementHasLowQualityImage(slide)) return;\n\n      removedSlideIndexes.add(index);\n      slide.remove();\n    });\n\n    if (removedSlideIndexes.size) {\n      this.querySelectorAll('slideshow-controls[thumbnails]').forEach((controls) => {\n        controls\n          .querySelectorAll('.slideshow-controls__thumbnail')\n          .forEach((thumbnail, index) => {\n            if (removedSlideIndexes.has(index) || this.#elementHasLowQualityImage(thumbnail)) thumbnail.remove();\n          });\n      });\n    }\n\n    this.querySelectorAll('[ref=\"media[]\"], .dialog-thumbnails-list__thumbnail').forEach((item) => {\n      if (this.#elementHasLowQualityImage(item)) item.remove();\n    });\n\n    const firstSlide = this.refs.slideshow?.refs.slides?.[0] || this.querySelector('slideshow-slide');\n    firstSlide?.setAttribute('aria-hidden', 'false');\n  }\n\n  /**\n   * @param {string} mediaId\n   * @returns {boolean}\n   */\n  #isLowQualityMediaId(mediaId) {\n    const safeMediaId = globalThis.CSS?.escape ? CSS.escape(mediaId) : mediaId.replaceAll('\"', '\\\\\"');\n    const media = this.querySelector(`[data-media-id=\"${safeMediaId}\"], slideshow-slide[slide-id=\"${safeMediaId}\"]`);\n\n    return this.#elementHasLowQualityImage(media);\n  }\n\n  /**\n   * @param {Element | null | undefined} element\n   * @returns {boolean}\n   */\n  #elementHasLowQualityImage(element) {\n    if (!element) return false;\n\n    const src = [...element.querySelectorAll('img')]\n      .map((image) => image.currentSrc || image.src || image.getAttribute('src') || image.getAttribute('srcset') || '')\n      .join(' ')\n      .toLowerCase();\n\n    return src.includes('_ss64') || src.includes('_ac_sy550');\n  }\n\r\n  /**\r\n   * Handles the 'zoom-media:selected' event.\r\n   * @param {ZoomMediaSelectedEvent} event - The zoom-media:selected event.\r\n   */\r\n  #handleZoomMediaSelected = async (event) => {\r\n    this.slideshow?.select(event.detail.index, undefined, { animate: false });\r\n  };\r\n\r\n  /**\r\n   * Zooms the media gallery.\r\n   *\r\n   * @param {number} index - The index of the media to zoom.\r\n   * @param {PointerEvent} event - The pointer event.\r\n   */\r\n  zoom(index, event) {\r\n    this.refs.zoomDialogComponent?.open(index, event);\r\n  }\r\n\r\n  /**\r\n   * Preloads an image.\r\n   * @param {number} index - The index of the media to preload.\r\n   */\r\n  preloadImage(index) {\r\n    const zoomDialogMedia = this.refs.zoomDialogComponent?.refs.media[index];\r\n    if (!zoomDialogMedia) return;\r\n\r\n    this.refs.zoomDialogComponent?.loadHighResolutionImage(zoomDialogMedia);\r\n  }\r\n\r\n  get slideshow() {\r\n    return this.refs.slideshow;\r\n  }\r\n\r\n  get media() {\r\n    return this.refs.media;\r\n  }\r\n\r\n  get presentation() {\r\n    return this.dataset.presentation;\r\n  }\r\n}\r\n\r\nif (!customElements.get('media-gallery')) {\r\n  customElements.define('media-gallery', MediaGallery);\r\n}\r\n"],
  "mappings": "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",
  "names": []
}
