{"version":3,"file":"product-card-element-section-xxxxxxxxxxxxxxxxxxxx.min.js","mappings":"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","sources":["webpack://lange/./scripts/sections/product-card-element/product-card-simple/index.ts","webpack://lange/./scripts/sections/product-card-element/product-card-simple/index.scss","webpack://lange/./scripts/sections/product-card-element/product-card-simple/index.html","webpack://lange/./scripts/sections/product-card-element/product-card/index.ts","webpack://lange/./scripts/sections/product-card-element/product-card/index.scss","webpack://lange/./scripts/sections/product-card-element/product-card/index.html"],"sourcesContent":["import type { CustomElement } from '@integrabeauty/custom-elements';\nimport html from './index.html';\nimport styles from './index.scss';\n\n/**\n * A simplified product card displaying image, title, subtitle, rating, and add to bag CTA. No\n * variant selector, price, or top badge. Used for the paired products.\n */\nclass ProductCardSimple extends HTMLElement implements CustomElement {\n  readonly dataset!: {\n    /**\n     * Product URL used for the card link.\n     */\n    url: string;\n  };\n\n  public shadowRoot!: ShadowRoot;\n\n  public constructor() {\n    super();\n    this.attachShadow({ mode: 'open' });\n    this.shadowRoot.innerHTML = `<style>${styles}</style>${html}`;\n  }\n\n  public connectedCallback() {\n    this.render();\n  }\n\n  private render() {\n    if (this.dataset.url) {\n      const anchor = this.shadowRoot.querySelector('a');\n      anchor.setAttribute('href', this.dataset.url);\n    }\n  }\n}\n\ndeclare global {\n  interface HTMLElementTagNameMap {\n    'product-card-simple': ProductCardSimple;\n  }\n}\n\nif (!customElements.get('product-card-simple')) {\n  customElements.define('product-card-simple', ProductCardSimple);\n}\n","export default \":host{background-color:#f5f5f5;display:flex;height:100%;max-width:520px;width:100%}a,slot{display:block}a{color:inherit;text-decoration:none}slot[name=image]{align-items:center;display:flex;justify-content:center;padding:10px;width:110px}@media only screen and (min-width:768px){slot[name=image]{width:140px}}.main{align-items:flex-start;display:flex;flex-direction:column;justify-content:space-between;padding:12px 24px 14px 14px}h3{font-size:.875rem;font-weight:600;letter-spacing:.07em;line-height:1;margin-bottom:4px;margin-top:0;text-transform:uppercase}@media only screen and (min-width:1280px){h3{font-size:1rem}}::slotted([slot=subtitle]){font-size:.625rem;letter-spacing:.07em;line-height:1.5;margin-bottom:8px!important;text-transform:uppercase}@media only screen and (min-width:1280px){::slotted([slot=subtitle]){font-size:.75rem}}slot[name=rating]{margin-bottom:auto}slot[name=action]{display:inline-block;margin-top:10px}::slotted([slot=action]){font-size:.75rem;min-height:40px}\";","// Module\nvar code = \"<slot name=\\\"image\\\"></slot><div class=\\\"main\\\"><a href=\\\"\\\"><h3><slot name=\\\"title\\\"></slot></h3><slot name=\\\"subtitle\\\"></slot></a><slot name=\\\"rating\\\"></slot><slot name=\\\"action\\\"></slot></div>\";\n// Exports\nexport default code;","import type { CustomElement } from '@integrabeauty/custom-elements';\nimport html from './index.html';\nimport styles from './index.scss';\n\n/**\n * A custom web component for displaying product card on PLP, predictable search, in product\n * carousels, etc.\n */\nclass ProductCard extends HTMLElement implements CustomElement {\n  readonly dataset: {\n    /**\n     * Initial value for the top badge.\n     *\n     * For products that don't have the variant selector and have a top badge, this value will be\n     * used. For products with variant selector, the top badge will be updated based on the selected\n     * variant by initial variant-changed event.\n     */\n    initTopBadge: string;\n\n    /**\n     * Initial style for the top badge.\n     */\n    initTopBadgeStyle: string;\n\n    /**\n     * Boolean represented as string, whether the product is an upsell product\n     */\n    isUpsell: 'false' | 'true';\n\n    /**\n     * Defines the size variant for the component\n     */\n    size: 'default' | 'small';\n\n    /**\n     * Defines the style variant for the component\n     */\n    styleVariant: 'upsell';\n\n    /**\n     * Product url without variant\n     */\n    url: string;\n  };\n\n  public shadowRoot!: ShadowRoot;\n\n  private onVariantChangedBound = this.onVariantChanged.bind(this);\n\n  public constructor() {\n    super();\n    this.attachShadow({ mode: 'open' });\n    this.shadowRoot.innerHTML = `<style>${styles}</style>${html}`;\n  }\n\n  public connectedCallback() {\n    this.render();\n  }\n\n  public disconnectedCallback() {\n    this.removeEventListener('variant-changed', this.onVariantChangedBound);\n  }\n\n  private render() {\n    this.renderLinks(this.dataset.url);\n\n    if (this.dataset.initTopBadge) {\n      const topBadge = this.shadowRoot.querySelector('product-top-badge');\n      topBadge.dataset.value = this.dataset.initTopBadge;\n      topBadge.dataset.style = this.dataset.initTopBadgeStyle || 'default';\n    }\n\n    this.addEventListener('variant-changed', this.onVariantChangedBound);\n  }\n\n  private onVariantChanged(event: WindowEventMap['variant-changed']) {\n    // After variant is changed, we need to update the products url to have the selected variant\n    const variantUrl = `${this.dataset.url}?variant=${event.detail.variant.id}`;\n    this.renderLinks(variantUrl);\n\n    const variantImages = this.querySelectorAll<HTMLElement>('.variant-image');\n\n    // update image\n    for (const image of variantImages) {\n      if (image.dataset.variantId === event.detail.variant.id.toString()) {\n        image.classList.remove('hidden');\n      } else {\n        image.classList.add('hidden');\n      }\n    }\n\n    // update top badge\n    const topBadge = this.shadowRoot.querySelector('product-top-badge');\n    topBadge.dataset.value = event.detail.variant.topBadge;\n    topBadge.dataset.style = event.detail.variant.topBadgeStyle;\n\n    const priceElement = this.querySelector('.product-card-final-price');\n    const previousPrice = priceElement.textContent || '';\n    const newPrice = event.detail.variant.price / 100;\n    let newPriceText = '';\n    if (Number.isInteger(newPrice)) {\n      newPriceText = newPrice.toString();\n    } else {\n      newPriceText = newPrice.toFixed(2);\n    }\n\n    // Regex to replace the price in the format of $XX.XX or $XX\n    priceElement.textContent = previousPrice.replace(/\\d+(?:\\.\\d+)?/g, newPriceText);\n\n    // Update compare at price. Compare at price is formatted string already, so we can just replace\n    // the number in the string with the new compare at price\n    const compareAtPriceElement = this.querySelector('.price__compare-at');\n    compareAtPriceElement.textContent = event.detail.variant.compareAtPrice || '';\n\n    if (this.dataset.isUpsell !== 'true') {\n      // Create a compare at price info button if needed. We don't show it for upsell products\n      if (event.detail.variant.compareAtPriceModalContent) {\n        const compareAtPriceInfo = document.createElement('compare-at-price-info');\n        compareAtPriceInfo.dataset.content = event.detail.variant.compareAtPriceModalContent;\n        compareAtPriceElement.appendChild(compareAtPriceInfo);\n      }\n    }\n\n    // Update discount message. It's a big formatted box with a promo message. It doesn't exist for\n    // upsell products, so we need this check.\n    const discountMessage = this.querySelector('discount-message');\n    if (discountMessage) {\n      discountMessage.dataset.message = event.detail.variant.discountMessage;\n    }\n  }\n\n  /**\n   * Update the url for all the links in both shadow DOM and light DOM, including the clickable area\n   */\n  private renderLinks(url: string) {\n    // there's some links in the light DOM, updating them first\n    const productLinks = this.querySelectorAll<HTMLAnchorElement>('a[slot=\"action\"]');\n    for (const productLink of productLinks) {\n      productLink.setAttribute('href', url);\n    }\n\n    // updating the shadow DOM link url as well\n    const anchor = this.shadowRoot.querySelector('a');\n    anchor.setAttribute('href', url);\n\n    // clickable area is a custom element that provides a clickable area but not an anchor tag, url\n    // is passed through dataset attribute\n    const clickableArea = this.querySelector('clickable-area');\n    clickableArea.dataset.url = url;\n  }\n}\n\ndeclare global {\n  interface HTMLElementTagNameMap {\n    'product-card': ProductCard;\n  }\n}\n\nif (!customElements.get('product-card')) {\n  customElements.define('product-card', ProductCard);\n}\n","export default \":host{display:flex;flex-direction:column;height:100%;position:relative;width:100%}:host([data-size=small]) .title{font-size:1rem}:host([data-size=small]) ::slotted([slot=subtitle]){font-size:.875rem}:host([data-size=small]) ::slotted([slot=discount-message]){font-size:.75rem;line-height:1.3;padding:6px 12px}:host([data-size=small]) ::slotted([slot=action]){font-size:.875rem!important;min-height:36px!important}:host([data-size=small]) ::slotted(.cta[slot=action]){height:36px!important}:host([data-is-upsell=true]){background-color:#fff;padding:0 10px 12px}:host([data-is-upsell=true]) .title{font-size:1rem;margin-top:8px}:host([data-is-upsell=true]) ::slotted([slot=subtitle]){font-size:.75rem}:host([data-is-upsell=true]) slot[name=price]{order:-2}:host([data-is-upsell=true]) ::slotted([slot=price]){margin-bottom:8px}:host([data-is-upsell=true]) slot[name=discount-message]{margin-bottom:8px;order:-1}:host([data-is-upsell=true]) ::slotted([slot=discount-message]){font-size:.75rem;line-height:1.3;padding:0;text-align:left}:host([data-is-upsell=true]) ::slotted([slot=action]){font-size:.875rem!important;min-height:36px!important}:host([data-is-upsell=true]) ::slotted(.cta[slot=action]){height:36px!important}slot{display:block}slot[name=image]{margin-left:auto;margin-right:auto}a{color:inherit;display:block;text-decoration:none}.title{font-size:1rem;font-weight:600;letter-spacing:.07em;line-height:1;margin-bottom:4px;text-transform:uppercase}@media only screen and (min-width:1280px){.title{font-size:1.375rem}}::slotted([slot=subtitle]){font-size:.75rem;letter-spacing:.07em;line-height:1.5;margin-bottom:8px!important;text-transform:uppercase}@media only screen and (min-width:1280px){::slotted([slot=subtitle]){font-size:.875rem}}::slotted([slot=rating]){display:block;margin-bottom:18px}product-top-badge{left:0;position:absolute;top:18px}@media only screen and (min-width:768px){product-top-badge{top:30px}}::slotted([slot=price]){margin-bottom:12px}footer{display:flex;flex-direction:column;flex-grow:1}::slotted([slot=discount-message]){font-size:.75rem;margin-bottom:14px;padding:8px 10px}@media only screen and (min-width:768px){::slotted([slot=discount-message]){font-size:1rem;padding-bottom:20px;padding-top:20px}}slot[name=variant-selector]{flex-grow:1}::slotted([slot=variant-selector]){margin-bottom:22px}slot[name=action]{font-size:.75rem;margin-top:auto}::slotted([slot=action]){font-size:.875rem}@media only screen and (min-width:768px){::slotted([slot=action]){font-size:1rem}}\";","// Module\nvar code = \"<slot name=\\\"image\\\"></slot><a href=\\\"\\\"><h3 class=\\\"title\\\"><slot name=\\\"title\\\"></slot></h3><slot name=\\\"subtitle\\\"></slot></a><slot name=\\\"rating\\\"></slot><product-top-badge></product-top-badge><footer><slot name=\\\"price\\\"></slot><slot name=\\\"variant-selector\\\"></slot><slot name=\\\"discount-message\\\"></slot><slot name=\\\"action\\\"></slot></footer>\";\n// Exports\nexport default code;"],"names":["ProductCardSimple","HTMLElement","constructor","super","this","attachShadow","mode","shadowRoot","innerHTML","concat","connectedCallback","render","dataset","url","querySelector","setAttribute","customElements","get","define","ProductCard","onVariantChangedBound","onVariantChanged","bind","disconnectedCallback","removeEventListener","renderLinks","initTopBadge","topBadge","value","style","initTopBadgeStyle","addEventListener","event","variantUrl","detail","variant","id","variantImages","querySelectorAll","image","variantId","toString","classList","remove","add","topBadgeStyle","priceElement","previousPrice","textContent","newPrice","price","newPriceText","Number","isInteger","toFixed","replace","compareAtPriceElement","compareAtPrice","isUpsell","compareAtPriceModalContent","compareAtPriceInfo","document","createElement","content","appendChild","discountMessage","message","productLinks","productLink"],"sourceRoot":""}