{"version":3,"file":"variant-selector-elements-section-xxxxxxxxxxxxxxxxxxxx.min.js","mappings":"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","sources":["webpack://lange/./scripts/sections/variant-selector-elements/variant-category/index.ts","webpack://lange/./scripts/sections/variant-selector-elements/variant-selector-option/index.ts","webpack://lange/webpack/bootstrap","webpack://lange/./scripts/sections/variant-selector-elements/variant-selector/index.ts"],"sourcesContent":["/**\n * This is a placeholder element that carries data properties for a variant category. It has no\n * functionality, just for semantic mark-up. Used to group product variants in the variant selector\n * under categories.\n */\nclass VariantCategory extends HTMLElement {\n  declare readonly dataset: {\n    /**\n     * Product description for the category. When the user select a variant from this category, this\n     * description will be shown instead of the main product description.\n     */\n    description?: string;\n\n    /**\n     * Unique ID for the category. Used to match variants to their categories.\n     */\n    id: string;\n\n    /**\n     * Title of the category. Category title shown to the user on the page.\n     */\n    title: string;\n  };\n}\n\ndeclare global {\n  interface HTMLElementTagNameMap {\n    'variant-category': VariantCategory;\n  }\n}\n\nif (!customElements.get('variant-category')) {\n  customElements.define('variant-category', VariantCategory);\n}\n","/**\n * This is a placeholder element that carries product variant option data, needed for the variant\n * selector functionality. It has no functionality itself.\n */\nclass VariantSelectorOption extends HTMLElement {\n  declare readonly dataset: {\n    /**\n     * Boolean represented as string representing product availability\n     */\n    available: 'false' | 'true';\n\n    /**\n     * CSS class to set a color associated with variant option as a background for the color swatch\n     */\n    backgroundClass: string;\n\n    /**\n     * Color swatch badge label, e.g. \"New\"\n     */\n    badge: string;\n\n    /**\n     * Badge style, only \"default\", \"highlighted\" are supported now\n     */\n    badgeStyle: string;\n\n    /**\n     * Option group name of a subproduct's bundle product. The name is a combination of the product\n     * title and option group name in parentheses to ensure uniqueness among multiple bundle options\n     * with the same option group name, e.g. \"ELATION (Shade)\"\n     */\n    bundleOptionGroup: string;\n\n    /**\n     * Category ID this variant option belongs to. Categories are used to group product variants in\n     * the variant selector. Passing category ID here allows to match variant options to their\n     * categories.\n     */\n    categoryId: string;\n\n    /**\n     * Variant's compare at price, a stringified integer representing cents, e.g. \"1200\" means $12\n     */\n    compareAtPrice: string;\n\n    /**\n     * Content to be displayed in the compare at price modal for a particular variant\n     */\n    compareAtPriceModalContent: string;\n\n    /**\n     * Variant additional short description\n     */\n    description: string;\n\n    /**\n     * Discount offer message\n     */\n    discountMessage: string;\n\n    /**\n     * List of filter groups this variant option belongs to, separated by \"|\", e.g.\n     * \"Light|Bright|Warm\". It's optional and used for some products for filtering variant options\n     * in the variant selector.\n     */\n    filterGroup: string;\n\n    /**\n     * Options group name, e.g. \"Color\", \"Shade\"\n     */\n    group: string;\n\n    /**\n     * Variant image src\n     */\n    image: string;\n\n    /**\n     * Variant's price, a stringified integer representing cents, e.g. \"1200\" means $12\n     */\n    price: string;\n\n    /**\n     * Top badge label, e.g. \"50% off\", \"Sale\"\n     */\n    topBadge: string;\n\n    /**\n     * Top badge style (black or red color), e.g. \"default\", \"highlighted\"\n     */\n    topBadgeStyle: 'default' | 'highlighted';\n\n    /**\n     * Variant associated option name\n     */\n    value: string;\n\n    /**\n     * Variant ID, a stringified integer\n     */\n    variantId: string;\n  };\n}\n\ndeclare global {\n  interface HTMLElementTagNameMap {\n    'variant-selector-option': VariantSelectorOption;\n  }\n}\n\nif (!customElements.get('variant-selector-option')) {\n  customElements.define('variant-selector-option', VariantSelectorOption);\n}\n","// The module cache\nlet __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tlet cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tlet module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","import type { CustomElement } from '@integrabeauty/custom-elements';\nimport html from './index.html';\nimport styles from './index.scss';\n\n/**\n * A custom element for selecting product variants. Includes list of selectable options and the\n * title and description of the selected variant.\n *\n * The data for all variants are stored as `<variant-selector-option>` elements. Each element\n * contains data-attributes, which store the values needed to handle the variant selector's\n * functionality.\n *\n * This component can optionally group variants into categories using `<variant-category>` elements.\n * Each category can have its own title and alternative product description that should be displayed\n * when a variant from that category is selected.\n *\n * TODO: Check accessibility. Since we change the description dynamically, there might be\n * accessibility issues or improvements we need to make.\n *\n * This custom element doesn't gather all variants data to an object. It's easily accessible via\n * `querySelector`, we don't need to access it frequently, nor process this data. The selected\n * variant is also not stored as a class property and taken via `querySelector('input:checked')`.\n *\n * Currently, only one option group is used for products, but technically a Shopify product can have\n * multiple options, e.g. \"Color\", \"Size\" etc.\n */\nclass VariantSelector extends HTMLElement implements CustomElement {\n  declare readonly dataset: {\n    /**\n     * Boolean represented as string that indicates whether the element is expandable or not. If\n     * categories are used, expandable must be false.\n     */\n    expandable: 'false' | 'true';\n\n    /**\n     * Set the horizontal alignment of the component on desktop. Depending on where it's placed we\n     * need to make the elements of the component centered.\n     */\n    horizontalAlignmentDesktop: 'center';\n\n    /**\n     * Set the horizontal alignment of the component on mobile. Depending on where it's placed we\n     * need to make the elements of the component centered.\n     */\n    horizontalAlignmentMobile: 'center';\n\n    /**\n     * The ID of the initially selected product variant, a stringified integer\n     */\n    initSelectedVariantId: string;\n\n    /**\n     * A string representing a boolean that indicates whether the component is being used for a gift\n     * card product.\n     *\n     * Depending on whether this is a basic product or a gift card, the component should be rendered\n     * and styled differently.\n     */\n    isGiftCard: 'false' | 'true';\n\n    /**\n     * Product ID, a stringified integer\n     */\n    productId: string;\n\n    /**\n     * Set the size of the component. We need the variant selector component in different sizes\n     * depending on where it's placed. It affects only styles.\n     *\n     * TODO: The `lagre` option is not in use for now and most likely we won't need it. I'll keep it\n     * here for now and remove later if really not needed.\n     */\n    size: 'large' | 'medium' | 'small';\n\n    /**\n     * Represents the possible variants for the title style.\n     *\n     * <strong>Berry</strong> - Muted Plum with Cool Undertones\" Default: variant name + variant\n     * short description, e.g.\"Berry - Muted Plum with Cool Undertones\" Condensed: variant name,\n     * e.g. \"Berry\"\n     */\n    titleFormat: 'condensed' | 'default' | 'none';\n  };\n\n  private onInputChangedBound = this.onInputChanged.bind(this);\n  private onExpandButtonClickedBound = this.onExpandButtonClicked.bind(this);\n  private onFilterClickedBound = this.onFilterClicked.bind(this);\n  private onSlotChangeBound = this.onSlotChange.bind(this);\n\n  public connectedCallback() {\n    this.initializeShadowRoot();\n    this.render();\n  }\n\n  public disconnectedCallback() {\n    const slot = this.shadowRoot.querySelector('slot');\n    slot.removeEventListener('slotchange', this.onSlotChangeBound);\n\n    this.shadowRoot.removeEventListener('change', this.onInputChangedBound);\n\n    const expandButton = this.shadowRoot.querySelector('.expand');\n    if (expandButton) {\n      // Checking this condition is important. The expand buttons are added only if the attribute\n      // data-expandable=\"true\" is set and the variant selector contains more than 4 options. Also,\n      // we remove it after clicking.\n      expandButton.removeEventListener('click', this.onExpandButtonClickedBound);\n    }\n\n    const filters = this.shadowRoot.querySelectorAll('.filters button');\n    for (const filter of filters) {\n      filter.removeEventListener('click', this.onFilterClickedBound);\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 render() {\n    const slot = this.shadowRoot.querySelector('slot');\n    slot.addEventListener('slotchange', this.onSlotChangeBound);\n  }\n\n  /**\n   * Handles the `slotchange` event. When the slot is populated with `<variant-selector-option>`\n   * elements, it calls the `onSlotReady` method to proceed with rendering and event setup.\n   * DOMContentLoaded is not reliable for cases when this component is slotted into another\n   * component, like in the upsell modal.\n   */\n  private onSlotChange(e: Event) {\n    const slot = <HTMLSlotElement>e.target;\n    const assignedElements = slot.assignedElements();\n    if (assignedElements.length > 0) {\n      this.onSlotReady();\n    }\n  }\n\n  /**\n   * Renders the variant selector options when the default slot is populated with child elements.\n   */\n  private onSlotReady() {\n    this.renderFilters();\n\n    // Checking for categories\n    const categories =\n      this.querySelectorAll<HTMLElementTagNameMap['variant-category']>('variant-category');\n\n    // Having categories affects some logic later, so we store this info\n    const hasCategories = categories.length > 0;\n\n    if (hasCategories) {\n      // Rendering categories if they exist. Creating a document fragment which will be appended to\n      // the DOM in one operation for better performance.\n      const categoriesFragment = document.createDocumentFragment();\n\n      for (const category of categories) {\n        const categoryContainer = document.createElement('div');\n        categoryContainer.classList.add('category');\n\n        const title = document.createElement('h3');\n        title.classList.add('category-title');\n        title.textContent = category.dataset.title;\n        categoryContainer.appendChild(title);\n\n        categoriesFragment.appendChild(categoryContainer);\n\n        // Rendering options container. We don't need to check if there are options, because\n        // category data is stored in the variant metafield, which means that if there are\n        // categories, there will be options for each category.\n        const optionsContainer = document.createElement('div');\n        optionsContainer.classList.add('options');\n        categoryContainer.appendChild(optionsContainer);\n\n        // Searching for options that belong to this category, rendering and appending them to the\n        // options container.\n        const options = this.querySelectorAll<HTMLElementTagNameMap['variant-selector-option']>(\n          `variant-selector-option[data-category-id=\"${category.dataset.id}\"]`);\n        for (const variant of options) {\n          const optionElement = this.createOptionElement(variant);\n          optionsContainer.appendChild(optionElement);\n        }\n      }\n\n      // All categories elements are created, appending them to the shadow DOM\n      const categoriesContainer = this.shadowRoot.querySelector('.categories');\n      categoriesContainer.appendChild(categoriesFragment);\n    }\n\n    // Rendering the remaining variant options that don't belong to any category based on data\n    // stored in `<variant-selector-option>` elements. These options will be rendered in the main\n    // options container. Creating a document fragment to improve performance.\n    //\n    // We don't expect to have options that don't belong to any category when categories are used,\n    // but just in case we handle this scenario too.\n    const options = this.querySelectorAll<HTMLElementTagNameMap['variant-selector-option']>(\n      'variant-selector-option:not([data-category-id])');\n    if (options.length > 0) {\n      const optionsFragment = document.createDocumentFragment();\n      for (const variant of options) {\n        const optionElement = this.createOptionElement(variant);\n        optionsFragment.appendChild(optionElement);\n      }\n\n      const optionsContainer = this.shadowRoot.querySelector('.options');\n\n      // Handling expandable variant selector. It's turned on via the `data-expandable=\"true\"`\n      // attribute but only if there are more than 4 options.\n      //\n      // Also, we need to force-disable it if there are categories, categories are designed to be\n      // used on the PDP only, while expandable variant selector is for product cards, but just for\n      // safety we add this check.\n      if (this.dataset.expandable === 'true' && options.length > 4 && !hasCategories) {\n        optionsContainer.classList.add('collapsed');\n\n        // Creating expand button and add it to the options container. We store the button HTML in a\n        // template element in the shadow DOM to keep the code clean and not create the button via\n        // explicit DOM methods.\n        const expandButtonTemplate =\n          this.shadowRoot.querySelector<HTMLTemplateElement>('#expand-button');\n        optionsFragment.appendChild(expandButtonTemplate.content.cloneNode(true));\n\n        // The HTMLTemplateElement.content.cloneNode() method returns a DocumentFragment, so we\n        // can't attach any event listener directly to it. We need to query the button after\n        // appending the fragment. Hovever, optionsFragment is a DocumentFragment too it's possible\n        // to add the event listener before appending to the DOM to any element inside but not to\n        // the fragment itself.\n        const expandButton = optionsFragment.querySelector('.expand');\n        expandButton.addEventListener('click', this.onExpandButtonClickedBound);\n      }\n\n      // Appending remaining options to the main options container.\n      optionsContainer.appendChild(optionsFragment);\n    }\n\n    this.renderTitle();\n\n    // attaching event listeners\n    this.shadowRoot.addEventListener('change', this.onInputChangedBound);\n\n    // Sending initial event\n    const selector =\n      `variant-selector-option[data-variant-id=\"${this.dataset.initSelectedVariantId}\"]`;\n    type VariantSelectorOptionType = HTMLElementTagNameMap['variant-selector-option'];\n    let initialVariant = this.querySelector<VariantSelectorOptionType>(selector);\n    if (!initialVariant) {\n      // There's a strange error in Sentry. I cannot reproduce so trying to catch it. I assume that\n      // `this.dataset.initSelectedVariantId` is not passed sometimes. If it helps we will\n      // investigate more why it happens.\n      const variantOptions = this.querySelectorAll('variant-selector-option');\n      const options = [];\n      for (const variantOption of variantOptions) {\n        options.push({\n          variantId: variantOption.dataset.variantId,\n          value: variantOption.dataset.value,\n          available: variantOption.dataset.available\n        });\n      }\n\n      Sentry.captureMessage('Variant selector initial variant not found', {\n        level: 'warning',\n        extra: {\n          initSelectedVariantId: this.dataset.initSelectedVariantId,\n          productId: this.dataset.productId,\n          parentElement: this.parentElement,\n          options\n        }\n      });\n\n      // Fallback to the first variant\n      initialVariant = this.querySelector<VariantSelectorOptionType>('variant-selector-option');\n    }\n\n    const category = this.findCategoryForVariant(initialVariant);\n\n    const variantChangedEvent = new CustomEvent<VariantChangedEvent['detail']>('variant-changed', {\n      cancelable: false,\n      bubbles: true,\n      detail: {\n        initial: true,\n        source: 'variant-selector',\n        variant: {\n          available: initialVariant.dataset.available === 'true',\n          description: initialVariant.dataset.description,\n          id: parseInt(initialVariant.dataset.variantId, 10),\n          product_id: parseInt(this.dataset.productId, 10),\n          coming_soon: false,\n          bundleOptionGroup: initialVariant.dataset.bundleOptionGroup,\n          option: initialVariant.dataset.value,\n          price: parseInt(initialVariant.dataset.price, 10),\n          compareAtPrice: initialVariant.dataset.compareAtPrice,\n          compareAtPriceModalContent: initialVariant.dataset.compareAtPriceModalContent,\n          image: initialVariant.dataset.image ?? '',\n          color: this.getVariantColor(initialVariant.dataset.backgroundClass),\n          discountMessage: initialVariant.dataset.discountMessage ?? '',\n          topBadge: initialVariant.dataset.topBadge ?? '',\n          topBadgeStyle: initialVariant.dataset.topBadgeStyle ?? 'default',\n          categoryDescription: category?.dataset.description ?? null\n        }\n      }\n    });\n    this.dispatchEvent(variantChangedEvent);\n  }\n\n  private onInputChanged(_event: Event) {\n    this.renderTitle();\n\n    const input = this.shadowRoot.querySelector('input:checked');\n    type Variant = HTMLElementTagNameMap['variant-selector-option'];\n    const selector = `variant-selector-option[data-variant-id=\"${input.id}\"]`;\n    const variant = this.querySelector<Variant>(selector);\n    const category = this.findCategoryForVariant(variant);\n\n    const variantChangedEvent = new CustomEvent<VariantChangedEvent['detail']>('variant-changed', {\n      cancelable: false,\n      bubbles: true,\n      detail: {\n        initial: false,\n        source: 'variant-selector',\n        variant: {\n          available: variant.dataset.available === 'true',\n          description: variant.dataset.description,\n          id: parseInt(variant.dataset.variantId, 10),\n          product_id: parseInt(this.dataset.productId, 10),\n          coming_soon: false,\n          bundleOptionGroup: variant.dataset.bundleOptionGroup,\n          option: variant.dataset.value,\n          price: parseInt(variant.dataset.price, 10),\n          compareAtPrice: variant.dataset.compareAtPrice,\n          compareAtPriceModalContent: variant.dataset.compareAtPriceModalContent,\n          image: variant.dataset.image ?? '',\n          color: this.getVariantColor(variant.dataset.backgroundClass),\n          discountMessage: variant.dataset.discountMessage,\n          topBadge: variant.dataset.topBadge ?? '',\n          topBadgeStyle: variant.dataset.topBadgeStyle ?? 'default',\n          categoryDescription: category?.dataset.description ?? null\n        }\n      }\n    });\n    this.dispatchEvent(variantChangedEvent);\n  }\n\n  private onExpandButtonClicked(event: Event) {\n    const button = <HTMLElement>event.currentTarget;\n    button.remove();\n\n    const options = this.shadowRoot.querySelector('.options');\n    options.classList.remove('collapsed');\n  }\n\n  private onFilterClicked(event: Event) {\n    const filter = <HTMLButtonElement>event.currentTarget;\n    const activeFilter = this.shadowRoot.querySelector('.filters button[aria-pressed=\"true\"]');\n\n    if (activeFilter === filter) {\n      return;\n    }\n\n    if (activeFilter) {\n      activeFilter.setAttribute('aria-pressed', 'false');\n    }\n\n    filter.setAttribute('aria-pressed', 'true');\n\n    const name = filter.textContent.toLowerCase();\n    const optionContainers = this.shadowRoot.querySelectorAll<HTMLElement>('.options>div');\n    for (const optionContainer of optionContainers) {\n      const filterGroup = optionContainer.dataset.filterGroup;\n      if (name === 'all' || filterGroup?.includes(name)) {\n        optionContainer.classList.remove('hidden');\n      } else {\n        optionContainer.classList.add('hidden');\n      }\n    }\n  }\n\n  /**\n   * Renders the title and short description based on the selected variant.\n   */\n  private renderTitle() {\n    const titleElement = this.shadowRoot.querySelector('.title');\n    if (this.dataset.titleFormat === 'none') {\n      if (titleElement) {\n        titleElement.remove();\n      }\n\n      return;\n    }\n\n    let checkedInput = this.shadowRoot.querySelector('input:checked');\n    if (!checkedInput) {\n      // This is a fallback, it should not happen normally. Trying to fix a strange Sentry error\n      checkedInput = this.shadowRoot.querySelector('input');\n    }\n\n    type Variant = HTMLElementTagNameMap['variant-selector-option'];\n    const selector = `variant-selector-option[data-variant-id=\"${checkedInput.id}\"]`;\n    const selectedVariant = this.querySelector<Variant>(selector);\n    const { value, description } = selectedVariant.dataset;\n\n    let title = '';\n\n    if (value) {\n      if (this.dataset.isGiftCard === 'true') {\n        title += `<strong>${removeDecimals(value)}</strong>`;\n      } else {\n        title += `<strong>${value}</strong>`;\n      }\n    }\n\n    if (this.dataset.titleFormat !== 'condensed' && description) {\n      title += ` - ${description}`;\n    }\n\n    titleElement.innerHTML = title;\n  }\n\n  private renderFilters() {\n    const options = this.querySelectorAll<HTMLElementTagNameMap['variant-selector-option']>(\n      'variant-selector-option[data-filter-group]');\n    if (options.length === 0) {\n      return;\n    }\n\n    // Gather filters from all variants\n    const allFilters = new Set<string>();\n\n    // We need to always render 'All' filter as the first one, so adding it to the set in advance\n    allFilters.add('all');\n\n    for (const option of options) {\n      const filtersString = option.dataset.filterGroup;\n      if (!filtersString) {\n        continue;\n      }\n\n      const filters = filtersString.split('|');\n      for (const filter of filters) {\n        allFilters.add(filter);\n      }\n    }\n\n    // `size` 1 means that we have only \"All\" filter, which is not really a filter, but just a way\n    // to show all options. So if it's the only filter we have, we don't render the filters section\n    // at all.\n    if (allFilters.size === 1) {\n      return;\n    }\n\n    // render filters\n    const container = this.shadowRoot.querySelector('.filters');\n    for (const filter of allFilters) {\n      const element = document.createElement('button');\n      element.textContent = filter;\n\n      if (filter === 'all') {\n        element.setAttribute('aria-pressed', 'true');\n      } else {\n        element.setAttribute('aria-pressed', 'false');\n      }\n\n      element.addEventListener('click', this.onFilterClickedBound);\n      container.appendChild(element);\n    }\n\n    // Show filters container when we have filters. By default, it's hidden via CSS\n    container.classList.remove('hidden');\n\n    const wrapper = this.shadowRoot.querySelector('.wrapper');\n    wrapper.classList.add('has-filters');\n  }\n\n  /**\n   * Creates an element containing a radio input and label element for a given variant option. We\n   * need to create option elements from different places, so it's separated into its own method.\n   */\n  private createOptionElement(variant: HTMLElementTagNameMap['variant-selector-option']) {\n    // Creating a radia input representing the variant option. It's visually hidden, the label\n    // element is styled to look like the option swatch.\n    const input = document.createElement('input');\n    input.id = variant.dataset.variantId;\n    input.type = 'radio';\n    input.name = variant.dataset.group;\n    input.value = variant.dataset.value;\n    input.classList.add('visually-hidden');\n    if (variant.dataset.available !== 'true') {\n      input.classList.add('unavailable');\n    }\n\n    input.checked = variant.dataset.variantId === this.dataset.initSelectedVariantId;\n\n    // Creating the label element associated with the input. This is the visible part of the option\n    // swatch that the user interacts with.\n    const label = document.createElement('label');\n    label.setAttribute('for', variant.dataset.variantId);\n    label.setAttribute('title', variant.dataset.value);\n    if (variant.dataset.backgroundClass) {\n      label.classList.add(variant.dataset.backgroundClass);\n    }\n\n    // Preparing label inner HTML. We add conditionally different content and then set it to the\n    // label element in one operation.\n    let labelHtml = '';\n\n    // Adding a text label inside the label element. For gift cards, we show the price directly. For\n    // regular products, we add a visually hidden span for screen readers.\n    if (this.dataset.isGiftCard === 'true') {\n      labelHtml = removeDecimals(variant.dataset.value);\n    } else {\n      labelHtml = `<span class=\"visually-hidden\">${variant.dataset.value}</span>`;\n    }\n\n    // Adding badge if exists. It's a small marketing label shown on the color swatch, e.g. \"New\"\n    if (variant.dataset.badge) {\n      const badgeStyleClass = variant.dataset.badgeStyle ?? '';\n      labelHtml += `<span class=\"badge ${badgeStyleClass}\">${variant.dataset.badge}</span>`;\n    }\n\n    // Adding prepared HTML to the label element\n    label.innerHTML = labelHtml;\n\n    // Creating a container for the input and label to return as a single element. We need to wrap\n    // them in a container to keep the structure clean and easier to style.\n    const container = document.createElement('div');\n\n    // If the variant has a filter group, we add this information to the container's dataset. It\n    // will be used later to show/hide options when a filter is applied.\n    if (variant.dataset.filterGroup) {\n      container.dataset.filterGroup = variant.dataset.filterGroup;\n    }\n\n    container.appendChild(input);\n    container.appendChild(label);\n\n    return container;\n  }\n\n  /**\n   * Finds the category element associated with a given variant\n   */\n  private findCategoryForVariant(variant: HTMLElementTagNameMap['variant-selector-option']) {\n    let category: HTMLElementTagNameMap['variant-category'];\n    const categoryId = variant.dataset.categoryId;\n    if (categoryId) {\n      category = this.querySelector<HTMLElementTagNameMap['variant-category']>(\n        `variant-category[data-id=\"${categoryId}\"]`);\n    }\n\n    return category;\n  }\n\n  /**\n   * Retrieves the background color defined in the CSS for a variant color swatch.\n   *\n   * @todo This approach isn't ideal, but it's set up like this for now to get things working. We\n   * need to start discussing a better way to handle variant colors. One idea is to store them in\n   * Shopify so the content team can manage them directly, but this would require more investigation\n   */\n  private getVariantColor(backgroundClass: string) {\n    // e.g., gift card\n    if (!backgroundClass) {\n      return '';\n    }\n\n    const style = this.shadowRoot.querySelector('style');\n    const rules: CSSRuleList = style.sheet.cssRules;\n\n    // Escape exclamation marks and other common problematic characters\n    const escapedBackgroundClass = backgroundClass\n      .replace(/[!\"#$%&'()*+,.:;?@^`{|}~]/g, '\\\\$&');\n\n    for (const rule of rules) {\n      if (rule instanceof CSSStyleRule && rule.selectorText === `.${escapedBackgroundClass}`) {\n        const backgroundColor = rule.style.backgroundColor;\n        if (backgroundColor) {\n          return backgroundColor;\n        }\n      }\n    }\n\n    return '';\n  }\n}\n\n/**\n * Removes the decimal part from a price string if it ends with \".00\".\n *\n * @param priceString - e.g. \"$10.00\"\n */\nfunction removeDecimals(priceString: string): string {\n  return priceString.replace(/\\.00$/, '');\n}\n\n// TODO The detail of the event should be refactored, it's very old and tends to copy the structure\n// and key names of some Shopify object, but there's no sense to do that, we don't need all these\n// values. This object has to be reviewed and only the parameters we need for the variant selector\n// functionality should stay. For now, I leave them as optional for compatibility until the old\n// variant selector is replaced with this custom element for all places.\ntype VariantChangedEvent = CustomEvent<{\n  initial: boolean;\n  source: string;\n  variant: {\n    /**\n     * Indicates whether the variant is available or not.\n     */\n    available: boolean;\n\n    /**\n     * Option group name of a subproduct's bundle product. The name is a combination of the product\n     * title and option group name in parentheses to ensure uniqueness among multiple bundle options\n     * with the same option group name, e.g. \"ELATION (Shade)\"\n     */\n    bundleOptionGroup: string;\n\n    /**\n     * The category description for the variant's category. It's null if no category description is\n     * set or if the variant doesn't belong to any category.\n     */\n    categoryDescription: string | null;\n\n    /**\n     * The variant's color in CSS RGB format, used in the UI to display color swatches. Returns an\n     * empty string if no color is found.\n     *\n     * @example \"rgb(51, 47, 33)\"\n     */\n    color: string;\n\n    /**\n     * Indicates whether the coming soon variant.\n     */\n    coming_soon: boolean | null;\n\n    /**\n     * Variant compare at price. It's possible, that's different variants will have each own compare\n     * at price. Represented as string with currency symbol, e.g. \"$12\"\n     */\n    compareAtPrice: string;\n\n    /**\n     * Content to be displayed in the compare at price modal for a particular variant\n     */\n    compareAtPriceModalContent: string;\n\n    /**\n     * Variant additional short description\n     */\n    description: string | null;\n\n    /**\n     * Discount offer message\n     */\n    discountMessage: string;\n\n    /**\n     * Product variant ID\n     */\n    id: number;\n\n    /**\n     * Variant image src\n     */\n    image: string;\n\n    /**\n     * Variant main media ID\n     *\n     * @todo check if we need it anywhere\n     */\n    media_id?: number | null;\n\n    /**\n     * Variant associated option name\n     */\n    option?: string;\n\n    /**\n     * List of all variant options\n     *\n     * @todo check if we need it anywhere\n     */\n    options?: string[];\n\n    /**\n     * Variant price. It's possible, that's different variants will have each own price, e.g. the\n     * gift card. Represented as cents, e.g. \"1200\" means $12\n     */\n    price?: number;\n\n    /**\n     * Variant product ID\n     */\n    product_id: number;\n\n    /**\n     * Top badge label, e.g. \"50% off\", \"Sale\"\n     */\n    topBadge: string;\n\n    /**\n     * Top badge style (black or red color), e.g. \"default\", \"highlighted\"\n     */\n    topBadgeStyle: 'default' | 'highlighted';\n  };\n}>;\n\ndeclare global {\n  interface HTMLElementTagNameMap {\n    'variant-selector': VariantSelector;\n  }\n\n  interface WindowEventMap {\n    'variant-changed': VariantChangedEvent;\n  }\n\n  interface HTMLElementEventMap {\n    'variant-changed': VariantChangedEvent;\n  }\n}\n\nif (!customElements.get('variant-selector')) {\n  customElements.define('variant-selector', VariantSelector);\n}\n"],"names":["VariantCategory","HTMLElement","customElements","get","define","VariantSelectorOption","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","exports","module","__webpack_modules__","VariantSelector","onInputChangedBound","this","onInputChanged","bind","onExpandButtonClickedBound","onExpandButtonClicked","onFilterClickedBound","onFilterClicked","onSlotChangeBound","onSlotChange","connectedCallback","initializeShadowRoot","render","disconnectedCallback","shadowRoot","querySelector","removeEventListener","expandButton","filters","querySelectorAll","filter","attachShadow","mode","innerHTML","addEventListener","e","target","assignedElements","length","onSlotReady","_initialVariant$datas","_initialVariant$datas2","_initialVariant$datas3","_initialVariant$datas4","_category$dataset$des","renderFilters","categories","hasCategories","categoriesFragment","document","createDocumentFragment","category","categoryContainer","createElement","classList","add","title","textContent","dataset","appendChild","optionsContainer","options","id","variant","optionElement","createOptionElement","optionsFragment","expandable","expandButtonTemplate","content","cloneNode","renderTitle","selector","initSelectedVariantId","initialVariant","variantOptions","variantOption","push","variantId","value","available","Sentry","captureMessage","level","extra","productId","parentElement","findCategoryForVariant","variantChangedEvent","CustomEvent","cancelable","bubbles","detail","initial","source","description","parseInt","product_id","coming_soon","bundleOptionGroup","option","price","compareAtPrice","compareAtPriceModalContent","image","color","getVariantColor","backgroundClass","discountMessage","topBadge","topBadgeStyle","categoryDescription","dispatchEvent","_event","_variant$dataset$imag","_variant$dataset$topB","_variant$dataset$topB2","_category$dataset$des2","event","currentTarget","remove","activeFilter","setAttribute","name","toLowerCase","optionContainers","optionContainer","filterGroup","includes","titleElement","titleFormat","checkedInput","selectedVariant","isGiftCard","removeDecimals","allFilters","Set","filtersString","split","size","container","element","input","type","group","checked","label","labelHtml","badge","_variant$dataset$badg","badgeStyle","categoryId","rules","sheet","cssRules","escapedBackgroundClass","replace","rule","CSSStyleRule","selectorText","backgroundColor","style","priceString"],"sourceRoot":""}