{
  "version": 3,
  "sources": ["/cdn/shop/t/6/assets/section-renderer.js?v=165897709872489896681790720035"],
  "sourcesContent": ["import { morph, MORPH_OPTIONS } from '@theme/morph';\n\n/**\n * A class to re-render sections using the Section Rendering API\n */\nclass SectionRenderer {\n  /**\n   * The cache of section HTML\n   * @type {Map<string, string>}\n   */\n  #cache = new Map();\n\n  /**\n   * The abort controllers by section ID\n   * @type {Map<string, AbortController>}\n   */\n  #abortControllersBySectionId = new Map();\n\n  /**\n   * The pending renders by section ID\n   * @type {Map<string, { abortController: AbortController, promise: Promise<string> }>}\n   */\n  #pendingRendersBySectionId = new Map();\n\n  /**\n   * The pending promises\n   * @type {Map<string, Promise<string>>}\n   */\n  #pendingPromises = new Map();\n\n  constructor() {\n    window.addEventListener('load', this.#cachePageSections.bind(this));\n  }\n\n  /**\n   * Renders a section\n   * @param {string} sectionId - The section ID\n   * @param {Object} [options] - The options\n   * @param {boolean} [options.cache] - Whether to use the cache\n   * @param {'hydration'|'full'} [options.mode] - Which parts of the section to morph into the DOM\n   * @param {boolean} [options.injectStylesheet=false] - When true, extracts\n   * `style[data-section-stylesheet]` from the response and injects it into the section wrapper.\n   * @param {URL} [options.url] - The URL to render the section from\n   * @param {(html: string) => boolean} [options.shouldRender] - Return false to preserve the current section.\n   * @returns {Promise<string>} The rendered section HTML\n   */\n  async renderSection(sectionId, options) {\n    const { cache = !Shopify.designMode, mode = 'full', injectStylesheet = false } = options ?? {};\n    const { url, shouldRender } = options ?? {};\n    this.#abortPendingMorph(sectionId);\n\n    const abortController = new AbortController();\n    this.#abortControllersBySectionId.set(sectionId, abortController);\n\n    const renderPromise = this.#renderSection(\n      sectionId,\n      { cache, mode, injectStylesheet, url, shouldRender },\n      abortController\n    );\n    this.#pendingRendersBySectionId.set(sectionId, { abortController, promise: renderPromise });\n\n    return renderPromise;\n  }\n\n  /**\n   * Cancels a pending render for a section.\n   * @param {string} sectionId - The section ID\n   */\n  abortRender(sectionId) {\n    this.#abortPendingMorph(sectionId);\n  }\n\n  /**\n   * Renders a section with an abort controller.\n   * @param {string} sectionId - The section ID\n   * @param {Object} options - The options\n   * @param {boolean} options.cache - Whether to use the cache\n   * @param {'hydration'|'full'} options.mode - Which parts of the section to morph into the DOM\n   * @param {boolean} options.injectStylesheet - When true, injects stylesheet from the response\n   * @param {URL} [options.url] - The URL to render the section from\n   * @param {(html: string) => boolean} [options.shouldRender] - Return false to preserve the current section.\n   * @param {AbortController} abortController - The abort controller for this render\n   * @returns {Promise<string>} The rendered section HTML\n   */\n  async #renderSection(sectionId, { cache, mode, injectStylesheet, url, shouldRender }, abortController) {\n    let sectionHTML = '';\n\n    try {\n      sectionHTML = await this.getSectionHTML(sectionId, cache, url, abortController.signal);\n    } catch (error) {\n      if (abortController.signal.aborted) {\n        const pendingRender = this.#pendingRendersBySectionId.get(sectionId);\n        if (pendingRender && pendingRender.abortController !== abortController) {\n          return pendingRender.promise;\n        }\n\n        return sectionHTML;\n      }\n\n      throw error;\n    } finally {\n      if (this.#abortControllersBySectionId.get(sectionId) === abortController) {\n        this.#abortControllersBySectionId.delete(sectionId);\n      }\n\n      const pendingRender = this.#pendingRendersBySectionId.get(sectionId);\n      if (pendingRender?.abortController === abortController) {\n        this.#pendingRendersBySectionId.delete(sectionId);\n      }\n    }\n\n    if (!abortController.signal.aborted && (shouldRender?.(sectionHTML) ?? true)) {\n      await morphSection(sectionId, sectionHTML, { mode, injectStylesheet });\n    }\n\n    return sectionHTML;\n  }\n\n  /**\n   * Aborts an existing render for a section\n   * @param {string} sectionId - The section ID\n   */\n  #abortPendingMorph(sectionId) {\n    const existingAbortController = this.#abortControllersBySectionId.get(sectionId);\n    if (existingAbortController) {\n      existingAbortController.abort();\n      this.#abortControllersBySectionId.delete(sectionId);\n    }\n  }\n\n  /**\n   * Gets the HTML for a section\n   * @param {string} sectionId - The section ID\n   * @param {boolean} useCache - Whether to use the cache\n   * @param {URL} url - The URL to render the section for\n   * @param {AbortSignal} [signal] - A signal that cancels the section render fetch\n   * @returns {Promise<string>} The rendered section HTML\n   */\n  async getSectionHTML(sectionId, useCache = true, url = new URL(window.location.href), signal) {\n    const sectionUrl = buildSectionRenderingURL(sectionId, url);\n\n    const shouldSharePendingPromise = !signal;\n    let pendingPromise = this.#pendingPromises.get(sectionUrl);\n    if (pendingPromise) return pendingPromise;\n\n    if (useCache) {\n      const cachedHTML = this.#cache.get(sectionUrl);\n\n      if (cachedHTML) return cachedHTML;\n    }\n\n    pendingPromise = fetch(sectionUrl, { signal }).then((response) => {\n      return response.text();\n    });\n\n    if (shouldSharePendingPromise) {\n      pendingPromise = pendingPromise.finally(() => {\n        this.#pendingPromises.delete(sectionUrl);\n      });\n\n      this.#pendingPromises.set(sectionUrl, pendingPromise);\n    }\n\n    const sectionHTML = await pendingPromise;\n\n    this.#cache.set(sectionUrl, sectionHTML);\n    return sectionHTML;\n  }\n\n  /**\n   * Caches the page sections\n   */\n  #cachePageSections() {\n    for (const section of document.querySelectorAll('.shopify-section')) {\n      const url = buildSectionRenderingURL(section.id);\n      if (this.#cache.get(url)) return;\n      if (containsShadowRoot(section)) return;\n\n      this.#cache.set(url, section.outerHTML);\n    }\n  }\n}\n\nconst SECTION_ID_PREFIX = 'shopify-section-';\n\n/**\n * Builds a section rendering URL\n * @param {string} sectionId - The section ID\n * @param {URL} url - The URL to render the section for\n * @returns {string} The section rendering URL\n */\nfunction buildSectionRenderingURL(sectionId, url = new URL(window.location.href)) {\n  url.searchParams.set('section_id', normalizeSectionId(sectionId));\n  url.searchParams.sort();\n\n  return url.toString();\n}\n\n/**\n * Builds a section selector\n * @param {string} sectionId - The section ID\n * @returns {string} The section selector\n */\nexport function buildSectionSelector(sectionId) {\n  return `${SECTION_ID_PREFIX}${sectionId}`;\n}\n\n/**\n * Normalizes a section ID\n * @param {string} sectionId - The section ID\n * @returns {string} The normalized section ID\n */\nexport function normalizeSectionId(sectionId) {\n  return sectionId.replace(new RegExp(`^${SECTION_ID_PREFIX}`), '');\n}\n\n/**\n * Checks if an element contains a shadow root\n * @param {Element} element - The element to check\n * @returns {boolean} Whether the element contains a shadow root\n */\nfunction containsShadowRoot(element) {\n  return !!element.shadowRoot || Array.from(element.children).some(containsShadowRoot);\n}\n\n/**\n * @typedef {(previousElement: HTMLElement, newElement: HTMLElement) => void} UpdateCallback\n */\n\n/**\n * Morphs the existing section element with the new section contents\n *\n * @param {string} sectionId - The section ID\n * @param {string} html - The new markup the section should morph into\n * @param {Object} [options] - Additional options\n * @param {'hydration'|'full'} [options.mode] - Which parts of the section to morph into the DOM. 'hydration' will only morph nodes with `data-hydration-key` attributes.\n * @param {boolean} [options.injectStylesheet=false] - When true, extracts\n * `style[data-section-stylesheet]` from the response and injects it into the section wrapper.\n */\nexport async function morphSection(sectionId, html, options = {}) {\n  const { mode = 'full', injectStylesheet = false } = options;\n  const fragment = new DOMParser().parseFromString(html, 'text/html');\n  const existingElement = document.getElementById(buildSectionSelector(sectionId));\n  const newElement = fragment.getElementById(buildSectionSelector(sectionId));\n\n  if (!existingElement) {\n    throw new Error(`Section ${sectionId} not found`);\n  }\n\n  if (!newElement) {\n    throw new Error(`Section ${sectionId} not found in the section rendering response`);\n  }\n\n  morph(existingElement, newElement, {\n    ...MORPH_OPTIONS,\n    hydrationMode: mode === 'hydration',\n  });\n\n  if (injectStylesheet) {\n    injectSectionStylesheet(fragment, existingElement);\n  }\n}\n\n/**\n * Injects a `<style data-section-stylesheet>` from the parsed SFR response\n * into the live section wrapper. Replaces the existing stylesheet, if it exists.\n *\n * @param {Document} fragment - The parsed response document\n * @param {HTMLElement} sectionElement - The live section wrapper element\n */\nfunction injectSectionStylesheet(fragment, sectionElement) {\n  const newStylesheet = fragment.querySelector('style[data-section-stylesheet]');\n  if (!newStylesheet) return;\n\n  const existingStylesheet = sectionElement.querySelector('style[data-section-stylesheet]');\n\n  if (existingStylesheet) {\n    existingStylesheet.textContent = newStylesheet.textContent;\n  } else {\n    sectionElement.prepend(newStylesheet);\n  }\n}\n\nexport const sectionRenderer = new SectionRenderer();\n"],
  "mappings": "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",
  "names": []
}
