{"version":3,"file":"product-comparison-complex-section.min.js","mappings":"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","sources":["webpack://lange/./sections/product-comparison-complex/product-comparison-chart/index.ts","webpack://lange/./lib/dom-ready.ts","webpack://lange/./lib/cart-event-queue.ts","webpack://lange/./sections/product-comparison-complex/select-option-button/index.ts","webpack://lange/./lib/css-dom.ts","webpack://lange/./sections/product-comparison-complex/index.ts"],"sourcesContent":["import type { CustomElement } from '@integrabeauty/custom-elements';\nimport { ready, type ReleaseHandle } from '../../../lib/dom-ready.js';\nimport html from './index.html';\nimport styles from './index.scss';\n\n/**\n * Comparison table for products/variants.\n *\n * This component displays products as columns and features as rows. The mobile version shows only 2\n * products at a time with dropdown selectors that allow users to choose which products to compare.\n */\nclass ProductComparisonChart extends HTMLElement implements CustomElement {\n  declare readonly dataset: {\n    /**\n     * Whether to show the ratings in the last row of the table.\n     */\n    showRatings: 'false' | 'true';\n  };\n\n  private variants = new Map<string, string>();\n  private selectedVariants: string[] = [];\n  private featureNames = new Map<string, string>();\n\n  private isSticky = false;\n  private rafId = 0;\n  private isVisible = false;\n  private declare observer: IntersectionObserver;\n\n  private colored = false;\n  private declare releaseReady: ReleaseHandle;\n  private onScrollBound = this.onScroll.bind(this);\n  private onProductSelectorChangedBound = this.onProductSelectorChanged.bind(this);\n  private onReadyBound = this.onReady.bind(this);\n\n  private onReady() {\n    if (this.isConnected) {\n      this.readTableDefinition();\n      this.render();\n    }\n  }\n\n  public connectedCallback() {\n    this.initializeShadowRoot();\n\n    this.observer = new IntersectionObserver(entries => {\n      this.isVisible = entries[0].isIntersecting;\n    });\n    this.observer.observe(this);\n\n    addEventListener('scroll', this.onScrollBound, { passive: true });\n\n    this.releaseReady = ready(this.onReadyBound);\n  }\n\n  public disconnectedCallback() {\n    this.observer.disconnect();\n    removeEventListener('scroll', this.onScrollBound);\n    cancelAnimationFrame(this.rafId);\n    this.rafId = 0;\n\n    if (this.releaseReady) {\n      this.releaseReady();\n    }\n\n    const productSelectorElements = this.shadowRoot.querySelectorAll<HTMLSelectElement>(\n      '.product-selectors select');\n    for (const productSelector of productSelectorElements) {\n      productSelector.removeEventListener('change', this.onProductSelectorChangedBound);\n    }\n  }\n\n  private initializeShadowRoot() {\n    if (!this.shadowRoot) {\n      this.attachShadow({ mode: 'open' });\n      this.shadowRoot.innerHTML = `<style>${styles}</style>${html}`;\n    }\n  }\n\n  private readTableDefinition() {\n    this.variants.clear();\n\n    const variantsEl = this.querySelectorAll<HTMLElement>('[slot=\"variants\"] [data-variant-id]');\n    for (const variantEl of variantsEl) {\n      this.variants.set(variantEl.dataset.variantId, variantEl.textContent?.trim() ?? '');\n    }\n\n    this.selectedVariants = Array.from(this.variants.keys()).slice(0, getCurrentProductLimit());\n\n    const featuresEl = this.querySelectorAll<HTMLElement>('[slot=\"features\"] [data-feature-no]');\n    for (const featureEl of featuresEl) {\n      this.featureNames.set(featureEl.dataset.featureNo, featureEl.textContent?.trim() ?? '');\n    }\n  }\n\n  private onProductSelectorChanged(_event: Event) {\n    this.selectedVariants = [];\n\n    const productSelectorElements = this.shadowRoot.querySelectorAll<HTMLSelectElement>(\n      '.product-selectors select');\n    for (const productSelectorEl of productSelectorElements) {\n      const selectedVariantId = productSelectorEl.value;\n      this.selectedVariants.push(selectedVariantId);\n    }\n\n    this.render();\n  }\n\n  private render() {\n    this.colored = false;\n\n    const thead = this.shadowRoot.querySelector('thead');\n    thead.innerHTML = '';\n\n    this.renderProductSelectors();\n    this.renderProductCards();\n\n    const tbody = this.shadowRoot.querySelector('tbody');\n    tbody.innerHTML = '';\n\n    this.renderCtaRow();\n    this.renderViewDetailsRow();\n    this.renderFeatureRows();\n\n    if (this.dataset.showRatings === 'true') {\n      this.renderRatingsRow();\n    }\n  }\n\n  private renderProductSelectors() {\n    const productSelectors = document.createElement('tr');\n    productSelectors.classList.add('product-selectors');\n\n    let i = 1;\n    for (const variantId of this.selectedVariants) {\n      const cell = document.createElement('td');\n      cell.setAttribute('headers', 'comparison-col' + i++);\n\n      const selector = document.createElement('select');\n      selector.setAttribute('aria-label', 'Select a product to compare');\n      selector.dataset.clickTrack = 'Comparison Chart Product Selector';\n      for (const [id, name] of this.variants.entries()) {\n        const option = document.createElement('option');\n        option.setAttribute('value', id);\n        option.textContent = name;\n        if (id === variantId) {\n          option.selected = true;\n        }\n\n        selector.appendChild(option);\n      }\n\n      cell.appendChild(selector);\n\n      productSelectors.appendChild(cell);\n    }\n\n    const thead = this.shadowRoot.querySelector('thead');\n    thead.appendChild(productSelectors);\n\n    const productSelectorElements = this.shadowRoot.querySelectorAll<HTMLSelectElement>(\n      '.product-selectors select');\n    for (const productSelector of productSelectorElements) {\n      productSelector.addEventListener('change', this.onProductSelectorChangedBound);\n    }\n  }\n\n  private renderProductCards() {\n    const productCards = document.createElement('tr');\n    productCards.classList.add('product-cards');\n\n    let i = 1;\n    for (const variantId of this.selectedVariants) {\n      const cell = document.createElement('th');\n      cell.setAttribute('scope', 'col');\n      cell.setAttribute('id', 'comparison-col' + i++);\n\n      const productCard = this.querySelector(\n        '[slot=\"product-cards\"] [data-variant-id=\"' + variantId + '\"]');\n      if (productCard) {\n        cell.innerHTML = productCard.innerHTML;\n      }\n\n      productCards.appendChild(cell);\n    }\n\n    const thead = this.shadowRoot.querySelector('thead');\n    thead.appendChild(productCards);\n  }\n\n  private renderCtaRow() {\n    const ctaRow = document.createElement('tr');\n    ctaRow.classList.add('cta-row');\n\n    let i = 1;\n    for (const variantId of this.selectedVariants) {\n      const cell = document.createElement('td');\n      cell.setAttribute('headers', 'comparison-col' + i++);\n\n      const addToCart = this.querySelector(\n        '[slot=\"add-to-cart-row\"] [data-variant-id=\"' + variantId + '\"]');\n      if (addToCart) {\n        cell.innerHTML = addToCart.innerHTML;\n      }\n\n      ctaRow.appendChild(cell);\n    }\n\n    const tbody = this.shadowRoot.querySelector('tbody');\n    tbody.appendChild(ctaRow);\n  }\n\n  private renderFeatureRows() {\n    const tbody = this.shadowRoot.querySelector('tbody');\n\n    for (const featureNo of this.featureNames.keys()) {\n      this.colored = !this.colored;\n\n      const headingRow = document.createElement('tr');\n      headingRow.classList.add('chart-heading');\n      if (this.colored) {\n        headingRow.classList.add('colored');\n      }\n\n      const heading = document.createElement('td');\n      heading.setAttribute('colspan', this.selectedVariants.length.toString());\n      heading.textContent = this.featureNames.get(featureNo) ?? '';\n\n      headingRow.appendChild(heading);\n\n      tbody.appendChild(headingRow);\n\n      const row = document.createElement('tr');\n      if (this.colored) {\n        row.classList.add('colored');\n      }\n\n      let i = 1;\n      for (const variantId of this.selectedVariants) {\n        const cell = document.createElement('td');\n        cell.setAttribute('headers', 'comparison-col' + i++);\n\n        const feature = this.querySelector(\n          '[slot=\"feature-rows\"] ' +\n          '[data-variant-id=\"' + variantId + '\"] ' +\n          '[data-feature-no=\"' + featureNo + '\"]');\n        if (feature) {\n          cell.innerHTML = feature.innerHTML;\n        }\n\n        row.appendChild(cell);\n      }\n\n      tbody.appendChild(row);\n    }\n  }\n\n  private renderViewDetailsRow() {\n    const viewDetailsRow = document.createElement('tr');\n    viewDetailsRow.classList.add('view-details-row');\n\n    let i = 1;\n    for (const variantId of this.selectedVariants) {\n      const cell = document.createElement('td');\n      cell.setAttribute('headers', 'comparison-col' + i++);\n\n      const viewDetails = this.querySelector(\n        '[slot=\"view-details-row\"] [data-variant-id=\"' + variantId + '\"]');\n      if (viewDetails) {\n        cell.innerHTML = viewDetails.innerHTML;\n      }\n\n      viewDetailsRow.appendChild(cell);\n    }\n\n    const tbody = this.shadowRoot.querySelector('tbody');\n    tbody.appendChild(viewDetailsRow);\n  }\n\n  private renderRatingsRow() {\n    const tbody = this.shadowRoot.querySelector('tbody');\n    this.colored = !this.colored;\n\n    const headingRow = document.createElement('tr');\n    headingRow.classList.add('chart-heading');\n    if (this.colored) {\n      headingRow.classList.add('colored');\n    }\n\n    const heading = document.createElement('td');\n    heading.setAttribute('colspan', this.selectedVariants.length.toString());\n    heading.textContent = 'Ratings';\n\n    headingRow.appendChild(heading);\n    tbody.appendChild(headingRow);\n\n    const ratingsRow = document.createElement('tr');\n    if (this.colored) {\n      ratingsRow.classList.add('colored');\n    }\n\n    let i = 1;\n    for (const variantId of this.selectedVariants) {\n      const cell = document.createElement('td');\n      cell.setAttribute('headers', 'comparison-col' + i++);\n\n      const wrapper = document.createElement('div');\n      wrapper.classList.add('rating');\n\n      const rating = this.querySelector(\n        '[slot=\"rating-stars\"] [data-variant-id=\"' + variantId + '\"]');\n      if (rating) {\n        wrapper.innerHTML = rating.innerHTML;\n      }\n\n      cell.appendChild(wrapper);\n\n      ratingsRow.appendChild(cell);\n    }\n\n    tbody.appendChild(ratingsRow);\n  }\n\n  /**\n   * Defers the sticky header update to the next animation frame. Skips the update entirely when the\n   * chart is not visible, so scrolling elsewhere on the page does no work here.\n   */\n  private onScroll(_event: Event) {\n    if (!this.isVisible || this.rafId) {\n      return;\n    }\n\n    this.rafId = requestAnimationFrame(() => {\n      this.rafId = 0;\n      this.updateStickyHeader();\n    });\n  }\n\n  /**\n   * Keeps the CTA row pinned just below the header as the user scrolls through the chart. The row\n   * is translated rather than made `position: sticky` because `border-collapse: collapse` on the\n   * table prevents sticky from working on table cells in browsers. Looks like it's not a bug but\n   * how things should work according to the specification.\n   *\n   * @see https://issues.chromium.org/issues/40511425\n   *\n   * The header bottom position comes from `getHeaderBottom`, which reads the header element's\n   * bounding rect so the offset tracks the header correctly when the promo banner hides or shows.\n   */\n  private updateStickyHeader() {\n    const tbody = this.shadowRoot.querySelector('tbody');\n    const row = tbody.querySelector<HTMLElement>('.cta-row');\n    if (!row) {\n      return;\n    }\n\n    const chartRect = tbody.getBoundingClientRect();\n    const headerBottom = getHeaderBottom();\n\n    if (chartRect.top < headerBottom && !this.isSticky) {\n      this.isSticky = true;\n      tbody.classList.add('sticky');\n    }\n\n    if (!this.isSticky) {\n      return;\n    }\n\n    const offset = headerBottom - chartRect.top;\n    const maxOffset = chartRect.height - row.offsetHeight;\n    if (offset <= 0 || maxOffset <= 0) {\n      row.style.transform = '';\n      tbody.classList.remove('sticky');\n      this.isSticky = false;\n      return;\n    }\n\n    row.style.transform = `translateY(${Math.min(offset, maxOffset)}px)`;\n  }\n}\n\nfunction getHeaderBottom() {\n  const headerWrapper = document.querySelector<HTMLElement>('header .wrapper');\n  if (!headerWrapper) {\n    return 0;\n  }\n\n  return headerWrapper.getBoundingClientRect().bottom;\n}\n\nfunction getCurrentProductLimit() {\n  const screenWidth = innerWidth;\n  if (screenWidth > 960) {\n    return 4;\n  }\n\n  if (screenWidth > 640) {\n    return 3;\n  }\n\n  return 2;\n}\n\ndeclare global {\n  interface HTMLElementTagNameMap {\n    'product-comparison-chart': ProductComparisonChart;\n  }\n}\n\nif (!customElements.get('product-comparison-chart')) {\n  customElements.define('product-comparison-chart', ProductComparisonChart);\n}\n","/**\n * Releases the handle returned from the ready() function.\n *\n * This is idempotent. Additional calls are pointless but harmless.\n */\nexport type ReleaseHandle = () => void;\n\n/**\n * A subset of events that pertain to document ready state.\n */\ntype LoadingEventMap = Pick<DocumentEventMap, 'DOMContentLoaded' | 'load'>;\n\n/**\n * Calls the provided callback when the document is ready. This works both when the document is\n * already ready and when it is not, so callers do not have to care. This exists because it ensures\n * that each caller consistently expresses its dependency on document readiness, and to save a bit\n * of boilerplate.\n *\n * A document is considered ready when it has been parsed. This corresponds to the ready state of\n * 'interactive'. When the document has been fully loaded, the ready state is 'complete'. The\n * callback runs either way, so callers do not have to check which one they are in.\n *\n * Ready means the html is parsed and the DOM is there to query. It does not mean the page's other\n * scripts have run. Deferred scripts and module scripts run after the ready state turns\n * 'interactive' and before DOMContentLoaded fires, so a callback here can run before them. When a\n * caller needs some other script to have run already, this is the wrong tool, and it should wait on\n * whatever that script produces instead.\n *\n * That remedy has a catch of its own when the calling bundle is loaded with async. An async bundle\n * can execute after DOMContentLoaded has already fired, so a plain listener for that event never\n * runs and the work silently never happens. Nothing here can detect that, because by the time this\n * file executes the event is long gone. Catching it needs something registered at parse time,\n * before any bundle loads.\n *\n * There is a second trap right next to that one, and it applies only when waiting for\n * DOMContentLoaded. The ready state stays 'interactive' after DOMContentLoaded has fired, all the\n * way until 'complete', so the ready state cannot tell you whether DOMContentLoaded is still coming\n * or has already gone. Waiting for load is not exposed to this, because the ready state turns\n * 'complete' and load fires in the same task, so seeing 'complete' means load has fired too.\n *\n * When the document is already ready, the callback is invoked via setTimeout. This way, if the\n * callback throws, the error surfaces to the global error handler in a way that is similar to what\n * happens when an event listener throws.\n *\n * We might one day want to move this to an NPM library.\n *\n * Beware of a quirk here. setTimeout yields, and the busier the frontend, the longer it takes to\n * fire. Page load is exactly when the frontend is busiest. The timeout is a floor and not a\n * guarantee, so there is no real bound on how long that yield lasts. What this means is that using\n * this library can introduce more delay than you might expect. Compare code that runs on async load\n * and checks ready state and invokes immediately to code that runs after setTimeout. The former\n * runs in the same tick, the latter runs in \"some later tick\". That later tick can be surprisingly\n * much later. That can cause initial paint issues.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/DOMContentLoaded_event\n * @see https://html.spec.whatwg.org/multipage/parsing.html#the-end\n */\nexport function ready(callback: (event?: Event) => void,\n  type: keyof LoadingEventMap = 'DOMContentLoaded') {\n  if (document.readyState === 'complete' || (type === 'DOMContentLoaded' &&\n    document.readyState === 'interactive')) {\n    const timer = setTimeout(callback, 0);\n    const handle: ReleaseHandle = () => clearTimeout(timer);\n    return handle;\n  } else {\n    addEventListener(type, callback);\n    const handle: ReleaseHandle = () => removeEventListener(type, callback);\n    return handle;\n  }\n}\n","// Accessors for the ambient cart event queue seeded and filled by the always-on cart lifecycle\n// snippet. The snippet registers a parse-time listener that buffers every cart event into the\n// queue, so a section whose bundle loads later can replay what it missed. Reaching the queue\n// through this lib, rather than the global directly, keeps the coupling to the ambient layer\n// explicit. The buffered events come off the queue untyped, so the guards here narrow each one\n// during replay.\n\ntype CartUpdatedEvent = GlobalEventHandlersEventMap['cart-updated'];\ntype CartUpdateErredEvent = GlobalEventHandlersEventMap['cart-update-erred'];\n\n/**\n * Returns the ambient queue of buffered cart events. A consumer replays this as it initializes,\n * then listens live for further events.\n */\nexport function getEventQueue() {\n  return cart_lifecycle.queue;\n}\n\n/**\n * Whether the value is a cart updated event. A consumer replaying the queue narrows each buffered\n * event with this before handling it.\n */\nexport function isCartUpdatedEvent(value: any): value is CartUpdatedEvent {\n  return value instanceof Event && value.type === 'cart-updated';\n}\n\n/**\n * Whether the value is a cart update erred event.\n */\nexport function isCartUpdateErredEvent(value: any): value is CartUpdateErredEvent {\n  return value instanceof Event && value.type === 'cart-update-erred';\n}\n","import type { CustomElement } from '@integrabeauty/custom-elements';\nimport { getEventQueue, isCartUpdatedEvent } from '../../../lib/cart-event-queue.js';\nimport html from './index.html';\nimport styles from './index.scss';\n\n/**\n * The per-column call to action in the product comparison chart for products that have more than\n * one variant. Single-variant products use the plain add to cart button instead.\n *\n * This exists so a shopper can pick a variant straight from the comparison chart without first\n * going to the product page.\n *\n * Product data is gathered from nested product elements.\n *\n * On click it broadcasts a request for the variant selector to open for this product.\n */\nclass SelectOptionButton extends HTMLElement implements CustomElement {\n  declare readonly dataset: {\n    /**\n     * Selected Shopify country code, it is used by the add to cart button.\n     */\n    countryCode: string;\n\n    /**\n     * Currency ISO Code. Required.\n     */\n    currencyCode: string;\n  };\n\n  private onSelectOptionClickBound = this.onSelectOptionClick.bind(this);\n  private onCartUpdatedBound = this.onCartUpdated.bind(this);\n  private product: Partial<Product> = {};\n\n  public connectedCallback() {\n    this.initializeShadowRoot();\n\n    for (const event of getEventQueue()) {\n      if (isCartUpdatedEvent(event)) {\n        try {\n          this.onCartUpdatedBound(event);\n        } catch (error) {\n          console.warn(error);\n        }\n      }\n    }\n\n    addEventListener('cart-updated', this.onCartUpdatedBound);\n\n    this.addEventListener('click', this.onSelectOptionClickBound);\n    this.ingestProduct();\n  }\n\n  public disconnectedCallback() {\n    this.removeEventListener('click', this.onSelectOptionClickBound);\n\n    removeEventListener('cart-updated', this.onCartUpdatedBound);\n  }\n\n  private initializeShadowRoot() {\n    if (!this.shadowRoot) {\n      this.attachShadow({ mode: 'open' });\n      this.shadowRoot.innerHTML = `<style>${styles}</style>${html}`;\n    }\n  }\n\n  private onCartUpdated(event: GlobalEventHandlersEventMap['cart-updated']) {\n    if (event.detail.is_initial) {\n      const button = this.shadowRoot.querySelector('button');\n      button.disabled = false;\n    }\n  }\n\n  private ingestProduct() {\n    type VariantElement = HTMLElementTagNameMap['variant-element'];\n\n    const productElement = this.querySelector<HTMLElementTagNameMap['product-element']>(\n      'product-element[slot=\"data\"]');\n    if (!productElement) {\n      return;\n    }\n\n    this.product.available = productElement.dataset.available === 'true';\n    this.product.id = parseInt(productElement.dataset.id, 10);\n    this.product.metafields_title = productElement.dataset.metafieldsTitle;\n    this.product.metafields_subtitle = productElement.dataset.metafieldsSubtitle;\n    this.product.selected_variant_id = parseInt(productElement.dataset.selectedVariantId, 10);\n    this.product.title = productElement.dataset.title;\n    this.product.type = productElement.dataset.type;\n    this.product.url = productElement.dataset.url;\n    this.product.metafields_discount_code = productElement.dataset.discountCode;\n    this.product.metafields_discount_percentage =\n      parseFloat(productElement.dataset.discountPercentage);\n    this.product.metafields_discount_override = productElement.dataset.discountOverride;\n    this.product.reviews_average = productElement.dataset.reviewsAverage ?\n      parseFloat(productElement.dataset.reviewsAverage) : 0;\n    this.product.reviews_count = productElement.dataset.reviewsCount ?\n      parseInt(productElement.dataset.reviewsCount, 10) : 0;\n    this.product.tags = productElement.dataset.tags;\n    this.product.option_groups = [];\n\n    const optionGroupElements = productElement.querySelectorAll('product-option-group');\n    for (const optionGroupElement of optionGroupElements) {\n      const optionGroup = <Product['option_groups'][0]>{};\n      optionGroup.name = optionGroupElement.dataset.name;\n      optionGroup.selected_option = optionGroupElement.dataset.selectedOption;\n      if (optionGroupElement.dataset.position) {\n        optionGroup.position = parseInt(optionGroupElement.dataset.position, 10);\n      }\n\n      optionGroup.options = [];\n\n      type ProductOption = HTMLElementTagNameMap['product-option'];\n      const productOptionElements = optionGroupElement.querySelectorAll<ProductOption>(\n        'product-option[data-value]');\n\n      for (const productOptionElement of productOptionElements) {\n        const productOption = <Product['option_groups'][0]['options'][0]>{};\n        productOption.value = productOptionElement.dataset.value;\n        productOption.variants = [];\n\n        const variantElements = productOptionElement.querySelectorAll<VariantElement>(\n          'variant-element[data-id]');\n\n        for (const variantElement of variantElements) {\n          const variant = <ProductVariant>{};\n          variant.available = variantElement.dataset.available === 'true';\n          variant.backorder = variantElement.dataset.backorder;\n          variant.backorder_selling_plan_id = variantElement.dataset.backorderSellingPlanId ?\n            parseInt(variantElement.dataset.backorderSellingPlanId, 10) : null;\n          variant.compare_at_price = variantElement.dataset.compareAtPrice ?\n            parseInt(variantElement.dataset.compareAtPrice, 10) : null;\n          variant.id = parseInt(variantElement.dataset.id, 10);\n          variant.price = parseInt(variantElement.dataset.price, 10);\n          variant.selected = variantElement.dataset.selected === 'true';\n          variant.sku = variantElement.dataset.sku;\n          variant.title = variantElement.dataset.title || productElement.dataset.title || '';\n\n          productOption.variants.push(variant);\n        }\n\n        optionGroup.options.push(productOption);\n      }\n\n      this.product.option_groups.push(optionGroup);\n    }\n\n    this.product.variants = [];\n    const variantElements = this.querySelectorAll<VariantElement>(\n      'product-element[slot=\"data\"] > variant-element[data-id]');\n    for (const variantElement of variantElements) {\n      const variant = <ProductVariant>{};\n      variant.available = variantElement.dataset.available === 'true';\n      variant.compare_at_price = variantElement.dataset.compareAtPrice ?\n        parseInt(variantElement.dataset.compareAtPrice, 10) : null;\n      variant.currency_code = this.dataset.currencyCode;\n      variant.hide_backorder_in_collection = variantElement.dataset.hideBackorderInCollection;\n      variant.id = parseInt(variantElement.dataset.id, 10);\n      variant.image_src = variantElement.dataset.imageSrc || '';\n      variant.option1 = variantElement.dataset.option1;\n      variant.option2 = variantElement.dataset.option2;\n      variant.option3 = variantElement.dataset.option3;\n      variant.price = parseInt(variantElement.dataset.price, 10);\n      variant.selected = variantElement.dataset.selected === 'true';\n      variant.sku = variantElement.dataset.sku;\n      variant.title = variantElement.dataset.title || productElement.dataset.title || '';\n      this.product.variants.push(variant);\n    }\n  }\n\n  private onSelectOptionClick(_event: MouseEvent) {\n    type Detail = WindowEventMap['select-option-requested']['detail'];\n    const requestEvent = new CustomEvent<Detail>('select-option-requested', {\n      bubbles: true,\n      composed: true,\n      detail: {\n        country: this.dataset.countryCode,\n        product: this.product\n      }\n    });\n\n    this.dispatchEvent(requestEvent);\n  }\n}\n\n/**\n * Represents a Shopify product variant\n */\ninterface ProductVariant {\n  /**\n   * Whether the variant is in stock\n   */\n  available: boolean;\n\n  /**\n   * Whether the variant is on backorder\n   */\n  backorder: string;\n\n  /**\n   * The \"Pre-Order\" deferred payment selling plan ID associated with a backordered variant.\n   */\n  backorder_selling_plan_id: number | null;\n\n  /**\n   * The MSRP, or original sales price before discounts, per unit\n   */\n  compare_at_price: number;\n\n  /**\n   * The currency code associated with the price\n   */\n  currency_code: string;\n\n  /**\n   * Boolean as a string to indicate whether to hide any backorder message if the product card is\n   * being viewed in a collection context.\n   */\n  hide_backorder_in_collection: string;\n\n  /**\n   * Variant id\n   *\n   * @example 12345568943\n   */\n  id: number;\n\n  /**\n   * The URL for the variant image\n   */\n  image_src: string;\n\n  /**\n   * The value of the variant for the first product option. If there's no first product option, then\n   * nil is returned.\n   */\n  option1: string;\n\n  /**\n   * The value of the variant for the second product option. If there's no second product option,\n   * then nil is returned.\n   */\n  option2: string;\n\n  /**\n   * The value of the variant for the third product option. If there's no third product option, then\n   * nil is returned.\n   */\n  option3: string;\n\n  /**\n   * The price of the variant in the currency's subunit.\n   *\n   * @see https://shopify.dev/docs/api/liquid/objects/variant#variant-price\n   */\n  price: number;\n\n  /**\n   * Whether this variant is the currently selected variant out of all the variants for the product\n   */\n  selected: boolean;\n\n  /**\n   * The Stock Keeping Unit associated with the variant. This is another kind of product id.\n   */\n  sku: string;\n\n  /**\n   * The title of the variant.\n   */\n  title: string;\n}\n\n/**\n * The complete product shape this section assembles before dispatching, recovered from the shared\n * event contract so the canonical definition lives in one place. The event carries a partial\n * product, so the optional wrapper is stripped here to describe the fully built product.\n */\ntype Product = Required<WindowEventMap['select-option-requested']['detail']['product']>;\n\ndeclare global {\n  interface HTMLElementTagNameMap {\n    'select-option-button': SelectOptionButton;\n  }\n}\n\nif (!customElements.get('select-option-button')) {\n  customElements.define('select-option-button', SelectOptionButton);\n}\n","/**\n * Generates a style element containing the given content and appends it to the dom.\n *\n * This is an alternative to the webpack style-loader that circumvents the overly complex webpack\n * configuration and plugin behavior. This intentionally avoids using CSSStyleSheet or any other\n * kind of feature that is not broadly supported or accurately polyfilled.\n *\n * This is safe to call before the dom has loaded.\n *\n * This is safe to call on platforms where document.head is not defined.\n *\n * This annotates appended style elements with a data-lazy attribute so that it is trivial to\n * identify which elements were appended to the dom in this manner. This extra annotation is not\n * expected to have a material performance impact.\n */\nexport function appendCSSText(content: string) {\n  const style = document.createElement('style');\n  style.dataset.lazy = 'true';\n  const node = document.createTextNode(content);\n  style.appendChild(node);\n  const parent = document.head || document.body || document.documentElement;\n  parent.appendChild(style);\n}\n","import './product-comparison-chart/index.js';\nimport './select-option-button/index.js';\nimport { appendCSSText } from '../../lib/css-dom.js';\nimport styles from './index.scss';\n\nappendCSSText(styles);\n"],"names":["ProductComparisonChart","HTMLElement","variants","Map","selectedVariants","featureNames","isSticky","rafId","isVisible","colored","onScrollBound","this","onScroll","bind","onProductSelectorChangedBound","onProductSelectorChanged","onReadyBound","onReady","isConnected","readTableDefinition","render","connectedCallback","initializeShadowRoot","observer","IntersectionObserver","entries","isIntersecting","observe","addEventListener","passive","releaseReady","callback","type","document","readyState","timer","setTimeout","clearTimeout","removeEventListener","ready","disconnectedCallback","disconnect","cancelAnimationFrame","productSelectorElements","shadowRoot","querySelectorAll","productSelector","attachShadow","mode","innerHTML","clear","variantsEl","variantEl","_variantEl$textConten","_variantEl$textConten2","set","dataset","variantId","textContent","trim","Array","from","keys","slice","screenWidth","innerWidth","getCurrentProductLimit","featuresEl","featureEl","_featureEl$textConten","_featureEl$textConten2","featureNo","_event","productSelectorEl","selectedVariantId","value","push","querySelector","renderProductSelectors","renderProductCards","renderCtaRow","renderViewDetailsRow","renderFeatureRows","showRatings","renderRatingsRow","productSelectors","createElement","classList","add","i","cell","setAttribute","selector","clickTrack","id","name","option","selected","appendChild","productCards","productCard","ctaRow","addToCart","tbody","_this$featureNames$ge","headingRow","heading","length","toString","get","row","feature","viewDetailsRow","viewDetails","ratingsRow","wrapper","rating","requestAnimationFrame","updateStickyHeader","chartRect","getBoundingClientRect","headerBottom","headerWrapper","bottom","getHeaderBottom","top","offset","maxOffset","height","offsetHeight","style","transform","remove","Math","min","isCartUpdatedEvent","Event","customElements","define","SelectOptionButton","onSelectOptionClickBound","onSelectOptionClick","onCartUpdatedBound","onCartUpdated","product","event","cart_lifecycle","queue","error","console","warn","ingestProduct","detail","is_initial","disabled","productElement","available","parseInt","metafields_title","metafieldsTitle","metafields_subtitle","metafieldsSubtitle","selected_variant_id","title","url","metafields_discount_code","discountCode","metafields_discount_percentage","parseFloat","discountPercentage","metafields_discount_override","discountOverride","reviews_average","reviewsAverage","reviews_count","reviewsCount","tags","option_groups","optionGroupElements","optionGroupElement","optionGroup","selected_option","selectedOption","position","options","productOptionElements","productOptionElement","productOption","variantElements","variantElement","variant","backorder","backorder_selling_plan_id","backorderSellingPlanId","compare_at_price","compareAtPrice","price","sku","currency_code","currencyCode","hide_backorder_in_collection","hideBackorderInCollection","image_src","imageSrc","option1","option2","option3","requestEvent","CustomEvent","bubbles","composed","country","countryCode","dispatchEvent","content","lazy","node","createTextNode","head","body","documentElement","appendCSSText"],"sourceRoot":""}