@dropins/storefront-pdp 3.0.4-beta2 → 3.1.0-alpha-20260513114245
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/api.js +1 -1
- package/api.js.map +1 -1
- package/chunks/DownloadableOptions2.js.map +1 -1
- package/chunks/GiftCardOptions2.js.map +1 -1
- package/chunks/PriceRange.js.map +1 -1
- package/chunks/Swatches.js.map +1 -1
- package/chunks/Zoom.js.map +1 -1
- package/chunks/date.js.map +1 -1
- package/chunks/fetchProductData.js +1 -1
- package/chunks/fetchProductData.js.map +1 -1
- package/chunks/getFetchedProductData.js.map +1 -1
- package/chunks/getProductConfigurationValues.js.map +1 -1
- package/chunks/isProductConfigurationValid.js.map +1 -1
- package/chunks/useProductData.js.map +1 -1
- package/containers/ProductAttributes.js +1 -1
- package/containers/ProductAttributes.js.map +1 -1
- package/containers/ProductDescription.js.map +1 -1
- package/containers/ProductDetails.js.map +1 -1
- package/containers/ProductDownloadableOptions.js.map +1 -1
- package/containers/ProductGallery.js.map +1 -1
- package/containers/ProductGiftCardOptions.js.map +1 -1
- package/containers/ProductHeader.js +1 -1
- package/containers/ProductHeader.js.map +1 -1
- package/containers/ProductOptions.js.map +1 -1
- package/containers/ProductPrice.js +1 -1
- package/containers/ProductPrice.js.map +1 -1
- package/containers/ProductQuantity.js.map +1 -1
- package/containers/ProductShortDescription.js.map +1 -1
- package/package.json +6 -1
- package/render.js.map +1 -1
package/api.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*! Copyright 2026 Adobe
|
|
2
2
|
All Rights Reserved. */
|
|
3
|
-
import{a as i,t as c}from"./chunks/fetchProductData.js";import{c as m,f as C,
|
|
3
|
+
import{a as i,t as c}from"./chunks/fetchProductData.js";import{c as m,f as C,b as F,d as k,e as R,h as U,i as A,r as E,j as _,k as x,l as Q}from"./chunks/fetchProductData.js";import{PRODUCT_FRAGMENT as p}from"./fragments.js";import"@dropins/tools/event-bus.js";import{g as V,s as I}from"./chunks/getProductConfigurationValues.js";import{i as O,s as S}from"./chunks/isProductConfigurationValid.js";import{g as b}from"./chunks/getFetchedProductData.js";import"@dropins/tools/lib.js";import"@dropins/tools/fetch-graphql.js";const d=`
|
|
4
4
|
query GET_PRODUCTS_DATA($skus: [String]) {
|
|
5
5
|
products(skus: $skus) {
|
|
6
6
|
...PRODUCT_FRAGMENT
|
package/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sources":["/@dropins/storefront-pdp/src/api/getProductsData/graphql/getProductsData.graphql.ts","/@dropins/storefront-pdp/src/api/getProductsData/getProductsData.ts"],"sourcesContent":["/**\n * ADOBE CONFIDENTIAL\n * __________________\n * Copyright 2023 Adobe\n * All Rights Reserved.\n * __________________\n * NOTICE: All information contained herein is, and remains\n * the property of Adobe and its suppliers, if any. The intellectual\n * and technical concepts contained herein are proprietary to Adobe\n * and its suppliers and are protected by all applicable intellectual\n * property laws, including trade secret and copyright laws.\n * Dissemination of this information or reproduction of this material\n * is strictly forbidden unless prior written permission is obtained\n * from Adobe.\n */\n\nimport { PRODUCT_FRAGMENT } from '@/pdp/api/graphql/ProductFragment.graphql';\n\nexport const GET_PRODUCTS_DATA = `\nquery GET_PRODUCTS_DATA($skus: [String]) {\n products(skus: $skus) {\n ...PRODUCT_FRAGMENT\n }\n}\n\n${PRODUCT_FRAGMENT}\n`;\n","/**\n * ADOBE CONFIDENTIAL\n * __________________\n * Copyright 2023 Adobe\n * All Rights Reserved.\n * __________________\n * NOTICE: All information contained herein is, and remains\n * the property of Adobe and its suppliers, if any. The intellectual\n * and technical concepts contained herein are proprietary to Adobe\n * and its suppliers and are protected by all applicable intellectual\n * property laws, including trade secret and copyright laws.\n * Dissemination of this information or reproduction of this material\n * is strictly forbidden unless prior written permission is obtained\n * from Adobe.\n */\n\nimport { fetchGraphQl } from '@/pdp/api';\nimport { ProductModel } from '@/pdp/data/models';\nimport { transformProductData } from '@/pdp/data/transforms';\nimport { GET_PRODUCTS_DATA } from './graphql/getProductsData.graphql';\n\nexport interface ProductDataItem {\n sku: string;\n optionsUIDs?: string[];\n preselectFirstOption?: boolean;\n}\n\n/**\n * Fetches multiple products by SKUs with optional per-product configuration.\n *\n * @example\n * // Basic usage\n * const products = await getProductsData([\n * { sku: 'SKU001' },\n * { sku: 'SKU002' }\n * ]);\n *\n * @example\n * // With options\n * const products = await getProductsData([\n * { sku: 'SKU001', optionsUIDs: ['option1'], preselectFirstOption: true },\n * { sku: 'SKU002', optionsUIDs: ['option2'] }\n * ]);\n *\n * @example\n * // Get raw data without transformation\n * const rawProducts = await getProductsData([{ sku: 'SKU001' }], true);\n */\nexport const getProductsData = async (\n items: ProductDataItem[],\n raw?: boolean\n): Promise<ProductModel[] | null> => {\n if (!items || items.length === 0) {\n return null;\n }\n\n const skus = items.map((item) => item.sku);\n const { data } = await fetchGraphQl(GET_PRODUCTS_DATA, {\n method: 'GET',\n variables: { skus },\n });\n const products = data?.products;\n\n if (!products || products.length === 0) {\n return null;\n }\n\n // Create a map for quick lookup of options by SKU\n const optionsMap = items.reduce((acc, item) => {\n acc[item.sku] = item;\n return acc;\n }, {} as Record<string, ProductDataItem>);\n\n return raw\n ? products\n : products.map((product: any) => {\n const itemOptions = optionsMap[product.sku];\n\n // If optionsUIDs are provided, override the optionsUIDs from the response\n if (itemOptions?.optionsUIDs) {\n product.optionUIDs = itemOptions.optionsUIDs;\n }\n\n return transformProductData(product, {\n preselectFirstOption: itemOptions?.preselectFirstOption,\n });\n });\n};\n"],"names":["GET_PRODUCTS_DATA","PRODUCT_FRAGMENT","getProductsData","items","raw","skus","item","data","fetchGraphQl","products","optionsMap","acc","product","itemOptions","transformProductData"],"mappings":"ygBAkBO,MAAMA,EAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO/BC,CAAgB;AAAA,ECuBLC,EAAkB,MAC7BC,EACAC,IACmC,CACnC,GAAI,CAACD,GAASA,EAAM,SAAW,
|
|
1
|
+
{"version":3,"file":"api.js","sources":["/@dropins/storefront-pdp/src/api/getProductsData/graphql/getProductsData.graphql.ts","/@dropins/storefront-pdp/src/api/getProductsData/getProductsData.ts"],"sourcesContent":["/**\n * ADOBE CONFIDENTIAL\n * __________________\n * Copyright 2023 Adobe\n * All Rights Reserved.\n * __________________\n * NOTICE: All information contained herein is, and remains\n * the property of Adobe and its suppliers, if any. The intellectual\n * and technical concepts contained herein are proprietary to Adobe\n * and its suppliers and are protected by all applicable intellectual\n * property laws, including trade secret and copyright laws.\n * Dissemination of this information or reproduction of this material\n * is strictly forbidden unless prior written permission is obtained\n * from Adobe.\n */\n\nimport { PRODUCT_FRAGMENT } from '@/pdp/api/graphql/ProductFragment.graphql';\n\nexport const GET_PRODUCTS_DATA = `\nquery GET_PRODUCTS_DATA($skus: [String]) {\n products(skus: $skus) {\n ...PRODUCT_FRAGMENT\n }\n}\n\n${PRODUCT_FRAGMENT}\n`;\n","/**\n * ADOBE CONFIDENTIAL\n * __________________\n * Copyright 2023 Adobe\n * All Rights Reserved.\n * __________________\n * NOTICE: All information contained herein is, and remains\n * the property of Adobe and its suppliers, if any. The intellectual\n * and technical concepts contained herein are proprietary to Adobe\n * and its suppliers and are protected by all applicable intellectual\n * property laws, including trade secret and copyright laws.\n * Dissemination of this information or reproduction of this material\n * is strictly forbidden unless prior written permission is obtained\n * from Adobe.\n */\n\nimport { fetchGraphQl } from '@/pdp/api';\nimport { ProductModel } from '@/pdp/data/models';\nimport { transformProductData } from '@/pdp/data/transforms';\nimport { GET_PRODUCTS_DATA } from './graphql/getProductsData.graphql';\n\nexport interface ProductDataItem {\n sku: string;\n optionsUIDs?: string[];\n preselectFirstOption?: boolean;\n}\n\n/**\n * Fetches multiple products by SKUs with optional per-product configuration.\n *\n * @example\n * // Basic usage\n * const products = await getProductsData([\n * { sku: 'SKU001' },\n * { sku: 'SKU002' }\n * ]);\n *\n * @example\n * // With options\n * const products = await getProductsData([\n * { sku: 'SKU001', optionsUIDs: ['option1'], preselectFirstOption: true },\n * { sku: 'SKU002', optionsUIDs: ['option2'] }\n * ]);\n *\n * @example\n * // Get raw data without transformation\n * const rawProducts = await getProductsData([{ sku: 'SKU001' }], true);\n */\nexport const getProductsData = async (\n items: ProductDataItem[],\n raw?: boolean\n): Promise<ProductModel[] | null> => {\n if (!items || items.length === 0) {\n return null;\n }\n\n const skus = items.map((item) => item.sku);\n const { data } = await fetchGraphQl(GET_PRODUCTS_DATA, {\n method: 'GET',\n variables: { skus },\n });\n const products = data?.products;\n\n if (!products || products.length === 0) {\n return null;\n }\n\n // Create a map for quick lookup of options by SKU\n const optionsMap = items.reduce((acc, item) => {\n acc[item.sku] = item;\n return acc;\n }, {} as Record<string, ProductDataItem>);\n\n return raw\n ? products\n : products.map((product: any) => {\n const itemOptions = optionsMap[product.sku];\n\n // If optionsUIDs are provided, override the optionsUIDs from the response\n if (itemOptions?.optionsUIDs) {\n product.optionUIDs = itemOptions.optionsUIDs;\n }\n\n return transformProductData(product, {\n preselectFirstOption: itemOptions?.preselectFirstOption,\n });\n });\n};\n"],"names":["GET_PRODUCTS_DATA","PRODUCT_FRAGMENT","getProductsData","items","raw","skus","item","data","fetchGraphQl","products","optionsMap","acc","product","itemOptions","transformProductData"],"mappings":"ygBAkBO,MAAMA,EAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO/BC,CAAgB;AAAA,ECuBLC,EAAkB,MAC7BC,EACAC,IACmC,CACnC,GAAI,CAACD,GAASA,EAAM,SAAW,EAC7B,OAAO,KAGT,MAAME,EAAOF,EAAM,IAAKG,GAASA,EAAK,GAAG,EACnC,CAAE,KAAAC,CAAA,EAAS,MAAMC,EAAaR,EAAmB,CACrD,OAAQ,MACR,UAAW,CAAE,KAAAK,CAAA,CAAK,CACnB,EACKI,EAAWF,GAAA,YAAAA,EAAM,SAEvB,GAAI,CAACE,GAAYA,EAAS,SAAW,EACnC,OAAO,KAIT,MAAMC,EAAaP,EAAM,OAAO,CAACQ,EAAKL,KACpCK,EAAIL,EAAK,GAAG,EAAIA,EACTK,GACN,CAAA,CAAqC,EAExC,OAAOP,EACHK,EACAA,EAAS,IAAKG,GAAiB,CAC7B,MAAMC,EAAcH,EAAWE,EAAQ,GAAG,EAG1C,OAAIC,GAAA,MAAAA,EAAa,cACfD,EAAQ,WAAaC,EAAY,aAG5BC,EAAqBF,EAAS,CACnC,qBAAsBC,GAAA,YAAAA,EAAa,oBAAA,CACpC,CACH,CAAC,CACP"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DownloadableOptions2.js","sources":["/@dropins/storefront-pdp/src/components/DownloadableOptions/DownloadableOptions.tsx"],"sourcesContent":["/**\n * ADOBE CONFIDENTIAL\n * __________________\n * Copyright 2023 Adobe\n * All Rights Reserved.\n * __________________\n * NOTICE: All information contained herein is, and remains\n * the property of Adobe and its suppliers, if any. The intellectual\n * and technical concepts contained herein are proprietary to Adobe\n * and its suppliers and are protected by all applicable intellectual\n * property laws, including trade secret and copyright laws.\n * Dissemination of this information or reproduction of this material\n * is strictly forbidden unless prior written permission is obtained\n * from Adobe.\n */\n\nimport { FunctionComponent } from 'preact';\nimport { HTMLAttributes, useState, useCallback } from 'preact/compat';\nimport { classes } from '@adobe-commerce/elsie/lib';\nimport { useText } from '@adobe-commerce/elsie/i18n';\nimport { Price } from '@adobe-commerce/elsie/components';\n\nimport '@/pdp/components/DownloadableOptions/DownloadableOptions.css';\n\nexport type DownloadableLink = {\n uid: string;\n price: number;\n sample_url: string | null;\n label: string;\n number_of_downloads: number;\n};\n\nexport type DownloadableSample = {\n uid: string;\n label: string;\n url: string;\n};\n\nexport type DownloadableValue = {\n links: DownloadableLink[];\n samples: DownloadableSample[];\n purchaseSeparately: boolean;\n};\n\nexport interface DownloadableOptionsProps\n extends Omit<HTMLAttributes<HTMLDivElement>, 'value'> {\n label: string;\n value: DownloadableValue;\n onLinkChange?: (uid: string, selected: boolean) => void;\n currency?: string;\n locale?: string;\n}\n\nexport const DownloadableOptions: FunctionComponent<\n DownloadableOptionsProps\n> = ({ label, value, onLinkChange, currency, locale, className, ...props }) => {\n const SampleLabel = useText('PDP.DownloadableOptions.Sample.label').label;\n const ViewSampleLabel = useText('PDP.DownloadableOptions.ViewSample.label');\n\n const { links, samples, purchaseSeparately } = value;\n\n const initialSelected = purchaseSeparately\n ? new Set<string>()\n : new Set(links.map((link) => link.uid));\n\n const [selected, setSelected] = useState<Set<string>>(initialSelected);\n\n const handleToggle = useCallback(\n (uid: string, isSelected: boolean, isDisabled: boolean) => {\n if (!purchaseSeparately || isDisabled) {\n return;\n }\n\n setSelected((prev) => {\n const next = new Set(prev);\n if (isSelected) {\n next.add(uid);\n } else {\n next.delete(uid);\n }\n return next;\n });\n onLinkChange?.(uid, isSelected);\n },\n [onLinkChange, purchaseSeparately]\n );\n\n const renderLink = (link: DownloadableLink) => {\n const isSelected = purchaseSeparately && selected.has(link.uid);\n\n return (\n <div\n key={link.uid}\n className={`pdp-downloadable-options__item ${\n isSelected ? 'pdp-downloadable-options__item--selected' : ''\n } ${\n !purchaseSeparately ? 'pdp-downloadable-options__item--disabled' : ''\n }`}\n >\n <button\n type=\"button\"\n className=\"pdp-downloadable-options__clickable\"\n aria-pressed={isSelected}\n disabled={!purchaseSeparately}\n onClick={() =>\n purchaseSeparately &&\n handleToggle(link.uid, !isSelected, !purchaseSeparately)\n }\n onKeyDown={(e) => {\n if (purchaseSeparately && (e.key === 'Enter' || e.key === ' ')) {\n e.preventDefault();\n handleToggle(link.uid, !isSelected, !purchaseSeparately);\n }\n }}\n >\n <div className=\"pdp-downloadable-options__content\">\n <div className=\"pdp-downloadable-options__header\">\n <span className=\"pdp-downloadable-options__title\">\n {link.label}\n </span>\n <Price\n amount={link.price}\n currency={currency}\n locale={locale}\n className=\"pdp-downloadable-options__price\"\n />\n </div>\n </div>\n </button>\n {link.sample_url && (\n <a\n href={link.sample_url}\n className=\"pdp-downloadable-options__sample-button\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={ViewSampleLabel.label.replace('{label}', link.label)}\n >\n {SampleLabel}\n </a>\n )}\n </div>\n );\n };\n\n const renderSample = (sample: DownloadableSample) => {\n return (\n <div\n key={sample.uid}\n className=\"pdp-downloadable-options__item pdp-downloadable-options__item--sample\"\n >\n <button\n type=\"button\"\n className=\"pdp-downloadable-options__clickable\"\n aria-pressed={false}\n disabled={true}\n >\n <div className=\"pdp-downloadable-options__content\">\n <div className=\"pdp-downloadable-options__header\">\n <span className=\"pdp-downloadable-options__title\">\n {sample.label}\n </span>\n </div>\n </div>\n </button>\n <a\n href={sample.url}\n className=\"pdp-downloadable-options__sample-button\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={`${SampleLabel} ${sample.label}`}\n >\n {SampleLabel}\n </a>\n </div>\n );\n };\n\n return (\n <div\n {...props}\n className={classes(['pdp-downloadable-options', className])}\n data-slot-key=\"product-downloadable-options\"\n >\n <div className=\"pdp-downloadable-options__field\">\n <div className=\"pdp-downloadable-options__field__label\">{label}</div>\n\n <div className=\"pdp-downloadable-options__list\">\n {links.map((link) => renderLink(link))}\n {samples.map((sample) => renderSample(sample))}\n </div>\n </div>\n </div>\n );\n};\n"],"names":["DownloadableOptions","label","value","onLinkChange","currency","locale","className","props","SampleLabel","useText","ViewSampleLabel","links","samples","purchaseSeparately","initialSelected","link","selected","setSelected","useState","handleToggle","useCallback","uid","isSelected","isDisabled","prev","next","renderLink","jsxs","jsx","e","Price","renderSample","sample","classes"],"mappings":"
|
|
1
|
+
{"version":3,"file":"DownloadableOptions2.js","sources":["/@dropins/storefront-pdp/src/components/DownloadableOptions/DownloadableOptions.tsx"],"sourcesContent":["/**\n * ADOBE CONFIDENTIAL\n * __________________\n * Copyright 2023 Adobe\n * All Rights Reserved.\n * __________________\n * NOTICE: All information contained herein is, and remains\n * the property of Adobe and its suppliers, if any. The intellectual\n * and technical concepts contained herein are proprietary to Adobe\n * and its suppliers and are protected by all applicable intellectual\n * property laws, including trade secret and copyright laws.\n * Dissemination of this information or reproduction of this material\n * is strictly forbidden unless prior written permission is obtained\n * from Adobe.\n */\n\nimport { FunctionComponent } from 'preact';\nimport { HTMLAttributes, useState, useCallback } from 'preact/compat';\nimport { classes } from '@adobe-commerce/elsie/lib';\nimport { useText } from '@adobe-commerce/elsie/i18n';\nimport { Price } from '@adobe-commerce/elsie/components';\n\nimport '@/pdp/components/DownloadableOptions/DownloadableOptions.css';\n\nexport type DownloadableLink = {\n uid: string;\n price: number;\n sample_url: string | null;\n label: string;\n number_of_downloads: number;\n};\n\nexport type DownloadableSample = {\n uid: string;\n label: string;\n url: string;\n};\n\nexport type DownloadableValue = {\n links: DownloadableLink[];\n samples: DownloadableSample[];\n purchaseSeparately: boolean;\n};\n\nexport interface DownloadableOptionsProps\n extends Omit<HTMLAttributes<HTMLDivElement>, 'value'> {\n label: string;\n value: DownloadableValue;\n onLinkChange?: (uid: string, selected: boolean) => void;\n currency?: string;\n locale?: string;\n}\n\nexport const DownloadableOptions: FunctionComponent<\n DownloadableOptionsProps\n> = ({ label, value, onLinkChange, currency, locale, className, ...props }) => {\n const SampleLabel = useText('PDP.DownloadableOptions.Sample.label').label;\n const ViewSampleLabel = useText('PDP.DownloadableOptions.ViewSample.label');\n\n const { links, samples, purchaseSeparately } = value;\n\n const initialSelected = purchaseSeparately\n ? new Set<string>()\n : new Set(links.map((link) => link.uid));\n\n const [selected, setSelected] = useState<Set<string>>(initialSelected);\n\n const handleToggle = useCallback(\n (uid: string, isSelected: boolean, isDisabled: boolean) => {\n if (!purchaseSeparately || isDisabled) {\n return;\n }\n\n setSelected((prev) => {\n const next = new Set(prev);\n if (isSelected) {\n next.add(uid);\n } else {\n next.delete(uid);\n }\n return next;\n });\n onLinkChange?.(uid, isSelected);\n },\n [onLinkChange, purchaseSeparately]\n );\n\n const renderLink = (link: DownloadableLink) => {\n const isSelected = purchaseSeparately && selected.has(link.uid);\n\n return (\n <div\n key={link.uid}\n className={`pdp-downloadable-options__item ${\n isSelected ? 'pdp-downloadable-options__item--selected' : ''\n } ${\n !purchaseSeparately ? 'pdp-downloadable-options__item--disabled' : ''\n }`}\n >\n <button\n type=\"button\"\n className=\"pdp-downloadable-options__clickable\"\n aria-pressed={isSelected}\n disabled={!purchaseSeparately}\n onClick={() =>\n purchaseSeparately &&\n handleToggle(link.uid, !isSelected, !purchaseSeparately)\n }\n onKeyDown={(e) => {\n if (purchaseSeparately && (e.key === 'Enter' || e.key === ' ')) {\n e.preventDefault();\n handleToggle(link.uid, !isSelected, !purchaseSeparately);\n }\n }}\n >\n <div className=\"pdp-downloadable-options__content\">\n <div className=\"pdp-downloadable-options__header\">\n <span className=\"pdp-downloadable-options__title\">\n {link.label}\n </span>\n <Price\n amount={link.price}\n currency={currency}\n locale={locale}\n className=\"pdp-downloadable-options__price\"\n />\n </div>\n </div>\n </button>\n {link.sample_url && (\n <a\n href={link.sample_url}\n className=\"pdp-downloadable-options__sample-button\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={ViewSampleLabel.label.replace('{label}', link.label)}\n >\n {SampleLabel}\n </a>\n )}\n </div>\n );\n };\n\n const renderSample = (sample: DownloadableSample) => {\n return (\n <div\n key={sample.uid}\n className=\"pdp-downloadable-options__item pdp-downloadable-options__item--sample\"\n >\n <button\n type=\"button\"\n className=\"pdp-downloadable-options__clickable\"\n aria-pressed={false}\n disabled={true}\n >\n <div className=\"pdp-downloadable-options__content\">\n <div className=\"pdp-downloadable-options__header\">\n <span className=\"pdp-downloadable-options__title\">\n {sample.label}\n </span>\n </div>\n </div>\n </button>\n <a\n href={sample.url}\n className=\"pdp-downloadable-options__sample-button\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={`${SampleLabel} ${sample.label}`}\n >\n {SampleLabel}\n </a>\n </div>\n );\n };\n\n return (\n <div\n {...props}\n className={classes(['pdp-downloadable-options', className])}\n data-slot-key=\"product-downloadable-options\"\n >\n <div className=\"pdp-downloadable-options__field\">\n <div className=\"pdp-downloadable-options__field__label\">{label}</div>\n\n <div className=\"pdp-downloadable-options__list\">\n {links.map((link) => renderLink(link))}\n {samples.map((sample) => renderSample(sample))}\n </div>\n </div>\n </div>\n );\n};\n"],"names":["DownloadableOptions","label","value","onLinkChange","currency","locale","className","props","SampleLabel","useText","ViewSampleLabel","links","samples","purchaseSeparately","initialSelected","link","selected","setSelected","useState","handleToggle","useCallback","uid","isSelected","isDisabled","prev","next","renderLink","jsxs","jsx","e","Price","renderSample","sample","classes"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GiftCardOptions2.js","sources":["/@dropins/storefront-pdp/src/components/GiftCardOptions/GiftCardOptions.tsx"],"sourcesContent":["import { FunctionComponent } from 'preact';\nimport { useState, useEffect, useMemo, useCallback } from 'preact/hooks';\nimport { HTMLAttributes } from 'preact/compat';\nimport { useText } from '@adobe-commerce/elsie/i18n';\nimport {\n Field,\n Input,\n TextArea,\n Picker,\n PickerOption,\n} from '@adobe-commerce/elsie/components';\nimport { classes } from '@adobe-commerce/elsie/lib';\nimport { Option, OptionField } from '@/pdp/data/models/values-model';\nimport './GiftCardOptions.css';\n\nenum ComponentType {\n INPUT = 'input',\n TEXTAREA = 'textarea',\n PICKER = 'picker',\n}\n\nexport interface GiftCardOptionsProps extends HTMLAttributes<HTMLDivElement> {\n options: Option[];\n currency?: string;\n optionValues: OptionField[];\n onOptionChange: (uid: string, value: string) => void;\n onValidationChange: (valid: boolean) => void;\n}\n\n// Utility functions\nconst getInputType = (validationType: string): string => {\n switch (validationType) {\n case 'number':\n return 'number';\n case 'email':\n return 'email';\n default:\n return 'text';\n }\n};\n\nconst getComponentType = (option: Option): ComponentType => {\n if (option.name === 'giftcard/giftcard_message') {\n return ComponentType.TEXTAREA;\n }\n\n if (option.name === 'giftcard/giftcard_amount') {\n return ComponentType.PICKER;\n }\n\n return ComponentType.INPUT;\n};\n\nconst mapToPickerOptions = (\n values: (string | number)[],\n hasCustomAmountField: boolean,\n chooseAmountText: string,\n otherAmountText: string\n): PickerOption[] => {\n const options: PickerOption[] = [\n {\n text: chooseAmountText,\n value: '0',\n disabled: false,\n },\n ...values.map((value) => ({\n text: value.toString(),\n value: value.toString(),\n disabled: false,\n })),\n ...(hasCustomAmountField\n ? [\n {\n text: otherAmountText,\n value: 'other',\n disabled: false,\n },\n ]\n : []),\n ];\n return options;\n};\n\nconst validate = (\n option: Option,\n value: string,\n errorMessages: {\n RequiredFieldError: string;\n NumberError: string;\n MinError: string;\n MaxError: string;\n MinLengthError: string;\n MaxLengthError: string;\n EmailError: string;\n InvalidValueError: string;\n }\n) => {\n const { validationRule } = option;\n\n if (option.name === 'giftcard/giftcard_amount') {\n if (\n validationRule.required &&\n (value === '0' || !value || value.trim() === '')\n ) {\n return errorMessages.RequiredFieldError;\n }\n if (value === '0') {\n return errorMessages.RequiredFieldError;\n }\n if (value === 'other') {\n return '';\n }\n } else if (validationRule.required && (!value || value.trim() === '')) {\n return errorMessages.RequiredFieldError;\n }\n\n if (!value || value.trim() === '') {\n return '';\n }\n\n switch (validationRule.type) {\n case 'email': {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n if (!emailRegex.test(value)) {\n return errorMessages.EmailError;\n }\n break;\n }\n\n case 'number': {\n const num = Number(value);\n if (isNaN(num)) {\n return errorMessages.NumberError;\n }\n\n // Check min value\n if (validationRule.min !== undefined && num < validationRule.min) {\n return errorMessages.MinError.replace(\n '{min}',\n validationRule.min.toString()\n );\n }\n\n // Check max value\n if (validationRule.max !== undefined && num > validationRule.max) {\n return errorMessages.MaxError.replace(\n '{max}',\n validationRule.max.toString()\n );\n }\n\n // Check allowed values\n if (validationRule.values) {\n const isValidValue = validationRule.values.some((val) =>\n typeof val === 'number' ? val === num : val === value\n );\n if (!isValidValue) {\n return errorMessages.InvalidValueError.replace(\n '{values}',\n validationRule.values.join(', ')\n );\n }\n }\n break;\n }\n\n case 'string': {\n const length = value.length;\n\n // Check min length\n if (\n validationRule.minLength !== undefined &&\n length < validationRule.minLength\n ) {\n return errorMessages.MinLengthError.replace(\n '{min_length}',\n validationRule.minLength.toString()\n );\n }\n\n // Check max length\n if (\n validationRule.maxLength !== undefined &&\n length > validationRule.maxLength\n ) {\n return errorMessages.MaxLengthError.replace(\n '{max_length}',\n validationRule.maxLength.toString()\n );\n }\n break;\n }\n }\n\n return '';\n};\n\nexport const GiftCardOptions: FunctionComponent<GiftCardOptionsProps> = ({\n options,\n currency,\n optionValues,\n onOptionChange,\n onValidationChange,\n}) => {\n const ChooseAmount = useText(\n 'PDP.Product.GiftCardOptions.ChooseAmount.label'\n ).label;\n const OtherAmount = useText(\n 'PDP.Product.GiftCardOptions.OtherAmount.label'\n ).label;\n const RequiredFieldError = useText(\n 'PDP.Product.GiftCardOptions.RequiredFieldError.label'\n ).label;\n const NumberError = useText(\n 'PDP.Product.GiftCardOptions.NumberError.label'\n ).label;\n const MinError = useText('PDP.Product.GiftCardOptions.MinError.label').label;\n const MaxError = useText('PDP.Product.GiftCardOptions.MaxError.label').label;\n const MinLengthError = useText(\n 'PDP.Product.GiftCardOptions.MinLengthError.label'\n ).label;\n const MaxLengthError = useText(\n 'PDP.Product.GiftCardOptions.MaxLengthError.label'\n ).label;\n const EmailError = useText(\n 'PDP.Product.GiftCardOptions.EmailError.label'\n ).label;\n const InvalidValueError = useText(\n 'PDP.Product.GiftCardOptions.InvalidValueError.label'\n ).label;\n\n const [errors, setErrors] = useState<Record<string, string>>({});\n const [showCustomAmount, setShowCustomAmount] = useState(false);\n\n // Helper function to find option by name\n const findOptionByName = useCallback(\n (name: string): Option | undefined => {\n return options.find((option) => option.name === name);\n },\n [options]\n );\n\n // Memoize error messages to avoid recreating them on every render\n const errorMessages = useMemo(\n () => ({\n RequiredFieldError,\n NumberError,\n MinError,\n MaxError,\n MinLengthError,\n MaxLengthError,\n EmailError,\n InvalidValueError,\n }),\n [\n RequiredFieldError,\n NumberError,\n MinError,\n MaxError,\n MinLengthError,\n MaxLengthError,\n EmailError,\n InvalidValueError,\n ]\n );\n\n // Run initial validation only when options or optionValues change\n useEffect(() => {\n const valid = options.every((option) => {\n // Skip validation for custom gift card amount when it's not shown\n if (\n option.name === 'giftcard/custom_giftcard_amount' &&\n !showCustomAmount\n ) {\n return true;\n }\n\n const field = optionValues.find((f) => f.id === option.uid);\n const value = field?.value || '';\n return validate(option, value, errorMessages) === '';\n });\n\n onValidationChange(valid);\n }, [\n options,\n optionValues,\n onValidationChange,\n errorMessages,\n showCustomAmount,\n ]);\n\n useEffect(() => {\n const giftCardAmountOption = findOptionByName('giftcard/giftcard_amount');\n const customAmountOption = findOptionByName(\n 'giftcard/custom_giftcard_amount'\n );\n\n const giftCardAmountField = optionValues.find(\n (f) => f.id === giftCardAmountOption?.uid\n );\n\n const selectedValue = giftCardAmountField?.value || '';\n const wasShowingCustomAmount = showCustomAmount;\n\n // If there's no gift card amount option, always show custom amount\n // Otherwise, show custom amount only when \"other\" is selected\n const willShowCustomAmount = giftCardAmountOption\n ? selectedValue === 'other'\n : !!customAmountOption;\n\n setShowCustomAmount(willShowCustomAmount);\n\n // Reset custom amount value when switching away from \"other\"\n if (wasShowingCustomAmount && !willShowCustomAmount && customAmountOption) {\n onOptionChange(customAmountOption.uid, '');\n }\n }, [optionValues, findOptionByName, showCustomAmount, onOptionChange]);\n\n const handleChange = (option: Option, value: string) => {\n const error = validate(option, value, errorMessages);\n setErrors((prev: Record<string, string>) => ({\n ...prev,\n [option.uid]: error,\n }));\n\n onOptionChange(option.uid, value);\n };\n\n const handleBlur = (option: Option, value: string) => {\n const error = validate(option, value, errorMessages);\n setErrors((prev: Record<string, string>) => ({\n ...prev,\n [option.uid]: error,\n }));\n };\n\n const handlePickerSelect = (option: Option, event: any) => {\n const selectedValue = event.target.value;\n handleChange(option, selectedValue);\n };\n\n const renderField = (option: Option) => {\n const field = optionValues.find((f) => f.id === option.uid);\n const value = field?.value;\n const error = errors[option.uid];\n const componentType = getComponentType(option);\n const hasCustomAmountField = !!findOptionByName(\n 'giftcard/custom_giftcard_amount'\n );\n\n // Add currency to custom gift card amount label\n let label = option.label;\n if (option.name === 'giftcard/custom_giftcard_amount' && currency) {\n label = `${option.label} ${currency}`;\n }\n\n return (\n <Field\n key={option.uid}\n label={label}\n className={classes([\n 'pdp-gift-card-options__option-field',\n componentType === ComponentType.TEXTAREA &&\n 'pdp-gift-card-options__option-field--full-width',\n ])}\n error={error}\n >\n {(() => {\n if (componentType === ComponentType.TEXTAREA) {\n return (\n <TextArea\n value={value}\n label={option.label}\n onChange={(e: any) =>\n handleChange(option, (e.target as HTMLTextAreaElement).value)\n }\n onBlur={(e: any) =>\n handleBlur(option, (e.target as HTMLTextAreaElement).value)\n }\n aria-invalid={!!error}\n />\n );\n }\n\n if (componentType === ComponentType.PICKER) {\n return (\n <Picker\n aria-label={option.label}\n label={option.label}\n handleSelect={(event) => handlePickerSelect(option, event)}\n options={mapToPickerOptions(\n option.validationRule.values || [],\n hasCustomAmountField,\n ChooseAmount,\n OtherAmount\n )}\n value={value}\n aria-invalid={!!error}\n />\n );\n }\n\n return (\n <Input\n type={getInputType(option.validationRule.type)}\n value={value}\n onChange={(e) =>\n handleChange(option, (e.target as HTMLInputElement).value)\n }\n onBlur={(e) =>\n handleBlur(option, (e.target as HTMLInputElement).value)\n }\n aria-invalid={!!error}\n />\n );\n })()}\n </Field>\n );\n };\n\n return (\n <div className=\"pdp-gift-card-options__grid\">\n {/* Row 1: Gift card amount and custom amount */}\n <div className=\"pdp-gift-card-options__row\">\n {findOptionByName('giftcard/giftcard_amount') &&\n renderField(findOptionByName('giftcard/giftcard_amount')!)}\n {findOptionByName('giftcard/custom_giftcard_amount') &&\n showCustomAmount &&\n renderField(findOptionByName('giftcard/custom_giftcard_amount')!)}\n </div>\n\n {/* Row 2: Sender name and email */}\n <div className=\"pdp-gift-card-options__row\">\n {findOptionByName('giftcard/giftcard_sender_name') &&\n renderField(findOptionByName('giftcard/giftcard_sender_name')!)}\n {findOptionByName('giftcard/giftcard_sender_email') &&\n renderField(findOptionByName('giftcard/giftcard_sender_email')!)}\n </div>\n\n {/* Row 3: Recipient name and email */}\n <div className=\"pdp-gift-card-options__row\">\n {findOptionByName('giftcard/giftcard_recipient_name') &&\n renderField(findOptionByName('giftcard/giftcard_recipient_name')!)}\n {findOptionByName('giftcard/giftcard_recipient_email') &&\n renderField(findOptionByName('giftcard/giftcard_recipient_email')!)}\n </div>\n\n {/* Row 4: Gift card message */}\n <div className=\"pdp-gift-card-options__row\">\n {findOptionByName('giftcard/giftcard_message') &&\n renderField(findOptionByName('giftcard/giftcard_message')!)}\n </div>\n </div>\n );\n};\n"],"names":["getInputType","validationType","getComponentType","option","mapToPickerOptions","values","hasCustomAmountField","chooseAmountText","otherAmountText","value","validate","errorMessages","validationRule","num","val","length","GiftCardOptions","options","currency","optionValues","onOptionChange","onValidationChange","ChooseAmount","useText","OtherAmount","RequiredFieldError","NumberError","MinError","MaxError","MinLengthError","MaxLengthError","EmailError","InvalidValueError","errors","setErrors","useState","showCustomAmount","setShowCustomAmount","findOptionByName","useCallback","name","useMemo","useEffect","valid","field","giftCardAmountOption","customAmountOption","giftCardAmountField","f","selectedValue","wasShowingCustomAmount","willShowCustomAmount","handleChange","error","prev","handleBlur","handlePickerSelect","event","renderField","componentType","label","jsx","Field","classes","TextArea","e","Picker","Input","jsxs"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"GiftCardOptions2.js","sources":["/@dropins/storefront-pdp/src/components/GiftCardOptions/GiftCardOptions.tsx"],"sourcesContent":["import { FunctionComponent } from 'preact';\nimport { useState, useEffect, useMemo, useCallback } from 'preact/hooks';\nimport { HTMLAttributes } from 'preact/compat';\nimport { useText } from '@adobe-commerce/elsie/i18n';\nimport {\n Field,\n Input,\n TextArea,\n Picker,\n PickerOption,\n} from '@adobe-commerce/elsie/components';\nimport { classes } from '@adobe-commerce/elsie/lib';\nimport { Option, OptionField } from '@/pdp/data/models/values-model';\nimport './GiftCardOptions.css';\n\nenum ComponentType {\n INPUT = 'input',\n TEXTAREA = 'textarea',\n PICKER = 'picker',\n}\n\nexport interface GiftCardOptionsProps extends HTMLAttributes<HTMLDivElement> {\n options: Option[];\n currency?: string;\n optionValues: OptionField[];\n onOptionChange: (uid: string, value: string) => void;\n onValidationChange: (valid: boolean) => void;\n}\n\n// Utility functions\nconst getInputType = (validationType: string): string => {\n switch (validationType) {\n case 'number':\n return 'number';\n case 'email':\n return 'email';\n default:\n return 'text';\n }\n};\n\nconst getComponentType = (option: Option): ComponentType => {\n if (option.name === 'giftcard/giftcard_message') {\n return ComponentType.TEXTAREA;\n }\n\n if (option.name === 'giftcard/giftcard_amount') {\n return ComponentType.PICKER;\n }\n\n return ComponentType.INPUT;\n};\n\nconst mapToPickerOptions = (\n values: (string | number)[],\n hasCustomAmountField: boolean,\n chooseAmountText: string,\n otherAmountText: string\n): PickerOption[] => {\n const options: PickerOption[] = [\n {\n text: chooseAmountText,\n value: '0',\n disabled: false,\n },\n ...values.map((value) => ({\n text: value.toString(),\n value: value.toString(),\n disabled: false,\n })),\n ...(hasCustomAmountField\n ? [\n {\n text: otherAmountText,\n value: 'other',\n disabled: false,\n },\n ]\n : []),\n ];\n return options;\n};\n\nconst validate = (\n option: Option,\n value: string,\n errorMessages: {\n RequiredFieldError: string;\n NumberError: string;\n MinError: string;\n MaxError: string;\n MinLengthError: string;\n MaxLengthError: string;\n EmailError: string;\n InvalidValueError: string;\n }\n) => {\n const { validationRule } = option;\n\n if (option.name === 'giftcard/giftcard_amount') {\n if (\n validationRule.required &&\n (value === '0' || !value || value.trim() === '')\n ) {\n return errorMessages.RequiredFieldError;\n }\n if (value === '0') {\n return errorMessages.RequiredFieldError;\n }\n if (value === 'other') {\n return '';\n }\n } else if (validationRule.required && (!value || value.trim() === '')) {\n return errorMessages.RequiredFieldError;\n }\n\n if (!value || value.trim() === '') {\n return '';\n }\n\n switch (validationRule.type) {\n case 'email': {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n if (!emailRegex.test(value)) {\n return errorMessages.EmailError;\n }\n break;\n }\n\n case 'number': {\n const num = Number(value);\n if (isNaN(num)) {\n return errorMessages.NumberError;\n }\n\n // Check min value\n if (validationRule.min !== undefined && num < validationRule.min) {\n return errorMessages.MinError.replace(\n '{min}',\n validationRule.min.toString()\n );\n }\n\n // Check max value\n if (validationRule.max !== undefined && num > validationRule.max) {\n return errorMessages.MaxError.replace(\n '{max}',\n validationRule.max.toString()\n );\n }\n\n // Check allowed values\n if (validationRule.values) {\n const isValidValue = validationRule.values.some((val) =>\n typeof val === 'number' ? val === num : val === value\n );\n if (!isValidValue) {\n return errorMessages.InvalidValueError.replace(\n '{values}',\n validationRule.values.join(', ')\n );\n }\n }\n break;\n }\n\n case 'string': {\n const length = value.length;\n\n // Check min length\n if (\n validationRule.minLength !== undefined &&\n length < validationRule.minLength\n ) {\n return errorMessages.MinLengthError.replace(\n '{min_length}',\n validationRule.minLength.toString()\n );\n }\n\n // Check max length\n if (\n validationRule.maxLength !== undefined &&\n length > validationRule.maxLength\n ) {\n return errorMessages.MaxLengthError.replace(\n '{max_length}',\n validationRule.maxLength.toString()\n );\n }\n break;\n }\n }\n\n return '';\n};\n\nexport const GiftCardOptions: FunctionComponent<GiftCardOptionsProps> = ({\n options,\n currency,\n optionValues,\n onOptionChange,\n onValidationChange,\n}) => {\n const ChooseAmount = useText(\n 'PDP.Product.GiftCardOptions.ChooseAmount.label'\n ).label;\n const OtherAmount = useText(\n 'PDP.Product.GiftCardOptions.OtherAmount.label'\n ).label;\n const RequiredFieldError = useText(\n 'PDP.Product.GiftCardOptions.RequiredFieldError.label'\n ).label;\n const NumberError = useText(\n 'PDP.Product.GiftCardOptions.NumberError.label'\n ).label;\n const MinError = useText('PDP.Product.GiftCardOptions.MinError.label').label;\n const MaxError = useText('PDP.Product.GiftCardOptions.MaxError.label').label;\n const MinLengthError = useText(\n 'PDP.Product.GiftCardOptions.MinLengthError.label'\n ).label;\n const MaxLengthError = useText(\n 'PDP.Product.GiftCardOptions.MaxLengthError.label'\n ).label;\n const EmailError = useText(\n 'PDP.Product.GiftCardOptions.EmailError.label'\n ).label;\n const InvalidValueError = useText(\n 'PDP.Product.GiftCardOptions.InvalidValueError.label'\n ).label;\n\n const [errors, setErrors] = useState<Record<string, string>>({});\n const [showCustomAmount, setShowCustomAmount] = useState(false);\n\n // Helper function to find option by name\n const findOptionByName = useCallback(\n (name: string): Option | undefined => {\n return options.find((option) => option.name === name);\n },\n [options]\n );\n\n // Memoize error messages to avoid recreating them on every render\n const errorMessages = useMemo(\n () => ({\n RequiredFieldError,\n NumberError,\n MinError,\n MaxError,\n MinLengthError,\n MaxLengthError,\n EmailError,\n InvalidValueError,\n }),\n [\n RequiredFieldError,\n NumberError,\n MinError,\n MaxError,\n MinLengthError,\n MaxLengthError,\n EmailError,\n InvalidValueError,\n ]\n );\n\n // Run initial validation only when options or optionValues change\n useEffect(() => {\n const valid = options.every((option) => {\n // Skip validation for custom gift card amount when it's not shown\n if (\n option.name === 'giftcard/custom_giftcard_amount' &&\n !showCustomAmount\n ) {\n return true;\n }\n\n const field = optionValues.find((f) => f.id === option.uid);\n const value = field?.value || '';\n return validate(option, value, errorMessages) === '';\n });\n\n onValidationChange(valid);\n }, [\n options,\n optionValues,\n onValidationChange,\n errorMessages,\n showCustomAmount,\n ]);\n\n useEffect(() => {\n const giftCardAmountOption = findOptionByName('giftcard/giftcard_amount');\n const customAmountOption = findOptionByName(\n 'giftcard/custom_giftcard_amount'\n );\n\n const giftCardAmountField = optionValues.find(\n (f) => f.id === giftCardAmountOption?.uid\n );\n\n const selectedValue = giftCardAmountField?.value || '';\n const wasShowingCustomAmount = showCustomAmount;\n\n // If there's no gift card amount option, always show custom amount\n // Otherwise, show custom amount only when \"other\" is selected\n const willShowCustomAmount = giftCardAmountOption\n ? selectedValue === 'other'\n : !!customAmountOption;\n\n setShowCustomAmount(willShowCustomAmount);\n\n // Reset custom amount value when switching away from \"other\"\n if (wasShowingCustomAmount && !willShowCustomAmount && customAmountOption) {\n onOptionChange(customAmountOption.uid, '');\n }\n }, [optionValues, findOptionByName, showCustomAmount, onOptionChange]);\n\n const handleChange = (option: Option, value: string) => {\n const error = validate(option, value, errorMessages);\n setErrors((prev: Record<string, string>) => ({\n ...prev,\n [option.uid]: error,\n }));\n\n onOptionChange(option.uid, value);\n };\n\n const handleBlur = (option: Option, value: string) => {\n const error = validate(option, value, errorMessages);\n setErrors((prev: Record<string, string>) => ({\n ...prev,\n [option.uid]: error,\n }));\n };\n\n const handlePickerSelect = (option: Option, event: any) => {\n const selectedValue = event.target.value;\n handleChange(option, selectedValue);\n };\n\n const renderField = (option: Option) => {\n const field = optionValues.find((f) => f.id === option.uid);\n const value = field?.value;\n const error = errors[option.uid];\n const componentType = getComponentType(option);\n const hasCustomAmountField = !!findOptionByName(\n 'giftcard/custom_giftcard_amount'\n );\n\n // Add currency to custom gift card amount label\n let label = option.label;\n if (option.name === 'giftcard/custom_giftcard_amount' && currency) {\n label = `${option.label} ${currency}`;\n }\n\n return (\n <Field\n key={option.uid}\n label={label}\n className={classes([\n 'pdp-gift-card-options__option-field',\n componentType === ComponentType.TEXTAREA &&\n 'pdp-gift-card-options__option-field--full-width',\n ])}\n error={error}\n >\n {(() => {\n if (componentType === ComponentType.TEXTAREA) {\n return (\n <TextArea\n value={value}\n label={option.label}\n onChange={(e: any) =>\n handleChange(option, (e.target as HTMLTextAreaElement).value)\n }\n onBlur={(e: any) =>\n handleBlur(option, (e.target as HTMLTextAreaElement).value)\n }\n aria-invalid={!!error}\n />\n );\n }\n\n if (componentType === ComponentType.PICKER) {\n return (\n <Picker\n aria-label={option.label}\n label={option.label}\n handleSelect={(event) => handlePickerSelect(option, event)}\n options={mapToPickerOptions(\n option.validationRule.values || [],\n hasCustomAmountField,\n ChooseAmount,\n OtherAmount\n )}\n value={value}\n aria-invalid={!!error}\n />\n );\n }\n\n return (\n <Input\n type={getInputType(option.validationRule.type)}\n value={value}\n onChange={(e) =>\n handleChange(option, (e.target as HTMLInputElement).value)\n }\n onBlur={(e) =>\n handleBlur(option, (e.target as HTMLInputElement).value)\n }\n aria-invalid={!!error}\n />\n );\n })()}\n </Field>\n );\n };\n\n return (\n <div className=\"pdp-gift-card-options__grid\">\n {/* Row 1: Gift card amount and custom amount */}\n <div className=\"pdp-gift-card-options__row\">\n {findOptionByName('giftcard/giftcard_amount') &&\n renderField(findOptionByName('giftcard/giftcard_amount')!)}\n {findOptionByName('giftcard/custom_giftcard_amount') &&\n showCustomAmount &&\n renderField(findOptionByName('giftcard/custom_giftcard_amount')!)}\n </div>\n\n {/* Row 2: Sender name and email */}\n <div className=\"pdp-gift-card-options__row\">\n {findOptionByName('giftcard/giftcard_sender_name') &&\n renderField(findOptionByName('giftcard/giftcard_sender_name')!)}\n {findOptionByName('giftcard/giftcard_sender_email') &&\n renderField(findOptionByName('giftcard/giftcard_sender_email')!)}\n </div>\n\n {/* Row 3: Recipient name and email */}\n <div className=\"pdp-gift-card-options__row\">\n {findOptionByName('giftcard/giftcard_recipient_name') &&\n renderField(findOptionByName('giftcard/giftcard_recipient_name')!)}\n {findOptionByName('giftcard/giftcard_recipient_email') &&\n renderField(findOptionByName('giftcard/giftcard_recipient_email')!)}\n </div>\n\n {/* Row 4: Gift card message */}\n <div className=\"pdp-gift-card-options__row\">\n {findOptionByName('giftcard/giftcard_message') &&\n renderField(findOptionByName('giftcard/giftcard_message')!)}\n </div>\n </div>\n );\n};\n"],"names":["getInputType","validationType","getComponentType","option","mapToPickerOptions","values","hasCustomAmountField","chooseAmountText","otherAmountText","value","validate","errorMessages","validationRule","num","val","length","GiftCardOptions","options","currency","optionValues","onOptionChange","onValidationChange","ChooseAmount","useText","OtherAmount","RequiredFieldError","NumberError","MinError","MaxError","MinLengthError","MaxLengthError","EmailError","InvalidValueError","errors","setErrors","useState","showCustomAmount","setShowCustomAmount","findOptionByName","useCallback","name","useMemo","useEffect","valid","field","giftCardAmountOption","customAmountOption","giftCardAmountField","f","selectedValue","wasShowingCustomAmount","willShowCustomAmount","handleChange","error","prev","handleBlur","handlePickerSelect","event","renderField","componentType","label","jsx","Field","classes","TextArea","e","Picker","Input","jsxs"],"mappings":"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"}
|
package/chunks/PriceRange.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PriceRange.js","sources":["/@dropins/storefront-pdp/src/components/PriceRange/PriceRange.tsx"],"sourcesContent":["/**\n * ADOBE CONFIDENTIAL\n * __________________\n * Copyright 2023 Adobe\n * All Rights Reserved.\n * __________________\n * NOTICE: All information contained herein is, and remains\n * the property of Adobe and its suppliers, if any. The intellectual\n * and technical concepts contained herein are proprietary to Adobe\n * and its suppliers and are protected by all applicable intellectual\n * property laws, including trade secret and copyright laws.\n * Dissemination of this information or reproduction of this material\n * is strictly forbidden unless prior written permission is obtained\n * from Adobe.\n */\n\nimport { HTMLAttributes } from 'preact/compat';\nimport '@/pdp/components/PriceRange/PriceRange.css';\nimport { FunctionalComponent } from 'preact';\nimport { Price } from '@adobe-commerce/elsie/components';\n\nexport interface PriceRangeProps extends HTMLAttributes<HTMLDivElement> {\n locale?: string;\n variant?: 'default' | 'strikethrough';\n currency?: string;\n\n // Simple product\n amount?: number;\n sale?: boolean;\n\n // Complex product (range)\n minimumAmount?: number;\n maximumAmount?: number;\n}\n\nexport const PriceRange: FunctionalComponent<PriceRangeProps> = ({\n amount,\n currency,\n locale,\n variant,\n sale,\n minimumAmount,\n maximumAmount,\n className,\n ...props\n}) => {\n return (\n <>\n {amount || minimumAmount === maximumAmount ? (\n <div className={'pdp-price-range'} {...props}>\n <Price\n amount={amount ? amount : minimumAmount}\n currency={currency}\n locale={locale}\n variant={variant}\n sale={sale}\n className={className}\n />\n </div>\n ) : (\n <div className={'pdp-price-range'} {...props}>\n <Price\n amount={minimumAmount}\n currency={currency}\n locale={locale}\n className={className}\n />\n <span className=\"pdp-price-range__label\">{'-'}</span>\n <Price\n amount={maximumAmount}\n currency={currency}\n locale={locale}\n className={className}\n />\n </div>\n )}\n </>\n );\n};\n"],"names":["PriceRange","amount","currency","locale","variant","sale","minimumAmount","maximumAmount","className","props","jsx","Fragment","Price","jsxs"],"mappings":"gKAmCO,MAAMA,EAAmD,CAAC,CAC/D,OAAAC,EACA,SAAAC,EACA,OAAAC,EACA,QAAAC,EACA,KAAAC,EACA,cAAAC,EACA,cAAAC,EACA,UAAAC,EACA,GAAGC,CACL,IAEIC,EAAAC,EAAA,CACG,YAAUL,IAAkBC,IAC1B,
|
|
1
|
+
{"version":3,"file":"PriceRange.js","sources":["/@dropins/storefront-pdp/src/components/PriceRange/PriceRange.tsx"],"sourcesContent":["/**\n * ADOBE CONFIDENTIAL\n * __________________\n * Copyright 2023 Adobe\n * All Rights Reserved.\n * __________________\n * NOTICE: All information contained herein is, and remains\n * the property of Adobe and its suppliers, if any. The intellectual\n * and technical concepts contained herein are proprietary to Adobe\n * and its suppliers and are protected by all applicable intellectual\n * property laws, including trade secret and copyright laws.\n * Dissemination of this information or reproduction of this material\n * is strictly forbidden unless prior written permission is obtained\n * from Adobe.\n */\n\nimport { HTMLAttributes } from 'preact/compat';\nimport '@/pdp/components/PriceRange/PriceRange.css';\nimport { FunctionalComponent } from 'preact';\nimport { Price } from '@adobe-commerce/elsie/components';\n\nexport interface PriceRangeProps extends HTMLAttributes<HTMLDivElement> {\n locale?: string;\n variant?: 'default' | 'strikethrough';\n currency?: string;\n\n // Simple product\n amount?: number;\n sale?: boolean;\n\n // Complex product (range)\n minimumAmount?: number;\n maximumAmount?: number;\n}\n\nexport const PriceRange: FunctionalComponent<PriceRangeProps> = ({\n amount,\n currency,\n locale,\n variant,\n sale,\n minimumAmount,\n maximumAmount,\n className,\n ...props\n}) => {\n return (\n <>\n {amount || minimumAmount === maximumAmount ? (\n <div className={'pdp-price-range'} {...props}>\n <Price\n amount={amount ? amount : minimumAmount}\n currency={currency}\n locale={locale}\n variant={variant}\n sale={sale}\n className={className}\n />\n </div>\n ) : (\n <div className={'pdp-price-range'} {...props}>\n <Price\n amount={minimumAmount}\n currency={currency}\n locale={locale}\n className={className}\n />\n <span className=\"pdp-price-range__label\">{'-'}</span>\n <Price\n amount={maximumAmount}\n currency={currency}\n locale={locale}\n className={className}\n />\n </div>\n )}\n </>\n );\n};\n"],"names":["PriceRange","amount","currency","locale","variant","sale","minimumAmount","maximumAmount","className","props","jsx","Fragment","Price","jsxs"],"mappings":"gKAmCO,MAAMA,EAAmD,CAAC,CAC/D,OAAAC,EACA,SAAAC,EACA,OAAAC,EACA,QAAAC,EACA,KAAAC,EACA,cAAAC,EACA,cAAAC,EACA,UAAAC,EACA,GAAGC,CACL,IAEIC,EAAAC,EAAA,CACG,YAAUL,IAAkBC,IAC1B,MAAA,CAAI,UAAW,kBAAoB,GAAGE,EACrC,SAAAC,EAACE,EAAA,CACC,OAAQX,GAAkBK,EAC1B,SAAAJ,EACA,OAAAC,EACA,QAAAC,EACA,KAAAC,EACA,UAAAG,CAAA,CAAA,EAEJ,EAEAK,EAAC,OAAI,UAAW,kBAAoB,GAAGJ,EACrC,SAAA,CAAAC,EAACE,EAAA,CACC,OAAQN,EACR,SAAAJ,EACA,OAAAC,EACA,UAAAK,CAAA,CAAA,EAEFE,EAAC,OAAA,CAAK,UAAU,yBAA0B,SAAA,IAAI,EAC9CA,EAACE,EAAA,CACC,OAAQL,EACR,SAAAL,EACA,OAAAC,EACA,UAAAK,CAAA,CAAA,CACF,CAAA,CACF,CAAA,CAEJ"}
|
package/chunks/Swatches.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Swatches.js","sources":["/@dropins/storefront-pdp/src/components/Swatches/Swatches.tsx"],"sourcesContent":["/**\n * ADOBE CONFIDENTIAL\n * __________________\n * Copyright 2023 Adobe\n * All Rights Reserved.\n * __________________\n * NOTICE: All information contained herein is, and remains\n * the property of Adobe and its suppliers, if any. The intellectual\n * and technical concepts contained herein are proprietary to Adobe\n * and its suppliers and are protected by all applicable intellectual\n * property laws, including trade secret and copyright laws.\n * Dissemination of this information or reproduction of this material\n * is strictly forbidden unless prior written permission is obtained\n * from Adobe.\n */\n\nimport { FunctionComponent, VNode } from 'preact';\nimport {\n HTMLAttributes,\n useState,\n useMemo,\n useCallback,\n useEffect,\n JSX,\n} from 'preact/compat';\nimport { classes } from '@adobe-commerce/elsie/lib';\nimport { useText } from '@adobe-commerce/elsie/i18n';\nimport {\n ColorSwatch,\n ImageSwatch,\n TextSwatch,\n Picker,\n PickerOption,\n ImageNodeRenderProps,\n} from '@adobe-commerce/elsie/components';\n\nimport '@/pdp/components/Swatches/Swatches.css';\n\nconst supportedTypes = ['text', 'image', 'color', 'dropdown'];\n\nconst mapToPickerOptions = (items: OptionValue[]): PickerOption[] => {\n return items.map((item: OptionValue) => ({\n ...item,\n text: item.label,\n disabled: !item.inStock,\n }));\n};\n\ntype OptionValue = {\n id: string;\n label: string;\n inStock: boolean;\n value: string;\n selected?: boolean;\n};\n\nexport type Option = {\n id: string;\n type: (typeof supportedTypes)[number];\n label: string;\n required?: boolean;\n multiple?: boolean;\n items: OptionValue[];\n};\n\ntype Selection = { [id: string]: { label: string; value: string } };\n\nfunction optionUIDsToSelection(\n optionUIDs: string[],\n options: Array<Option>\n): Selection {\n return optionUIDs.reduce((accum, optionUID) => {\n const option = options?.find((option) =>\n option.items.find((item) => item.id === optionUID)\n );\n if (!option) return accum;\n\n const item = option.items.find((item) => item.id === optionUID);\n\n return {\n ...accum,\n [option.id]: {\n label: item!.label,\n value: item!.id,\n },\n };\n }, {});\n}\n\nexport interface SwatchesProps extends HTMLAttributes<HTMLDivElement> {\n options: Array<Option>;\n hideSelectedValue?: boolean;\n disablePreselections?: boolean;\n defaultOptions?: string[];\n selectionsToUpdate?: Option[];\n onValues?: (uids: Selection, current: string) => void;\n onErrors?: (errors: { [id: string]: string }) => void;\n selectedUIDs?: string[];\n imageSwatchNode?: VNode | ((props: ImageNodeRenderProps) => JSX.Element);\n}\n\nexport const Swatches: FunctionComponent<SwatchesProps> = ({\n options,\n hideSelectedValue,\n disablePreselections,\n selectedUIDs,\n onValues,\n onErrors,\n defaultOptions,\n selectionsToUpdate,\n className,\n children,\n imageSwatchNode,\n ...props\n}) => {\n // i18n\n const RequiredLabel = useText('PDP.Swatches.Required.label').label;\n const ChooseOptionLabel = useText('PDP.Swatches.ChooseOption.label').label;\n\n const [selections, setSelections] = useState<Selection>(() => {\n const initial = options?.reduce((accum, option) => {\n const { items } = option;\n const defaultSelection = items?.find((item) =>\n defaultOptions?.includes(item.id)\n );\n const selected = items?.find((item) => item.selected);\n if (defaultSelection) {\n return {\n ...accum,\n [option.id]: {\n label: defaultSelection.label,\n value: defaultSelection.id,\n },\n };\n } else if (selected) {\n return {\n ...accum,\n [option.id]: { label: selected.label, value: selected.id },\n };\n }\n return accum;\n }, {} as Selection);\n\n return initial;\n });\n\n // set selected options from props\n useEffect(() => {\n if (selectedUIDs) {\n const selection = optionUIDsToSelection(selectedUIDs, options);\n // if the internal state is already the same as the props, do nothing\n if (JSON.stringify(selection) === JSON.stringify(selections)) return;\n\n setSelections((prev) => {\n let next = {\n ...prev,\n ...selection,\n };\n onValues?.(next);\n return next;\n });\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedUIDs]);\n\n // this only applies for the case with anchor options\n // update selections in the swatches if they are updated in the parent component\n useEffect(() => {\n selectionsToUpdate?.forEach((selectionToUpdate) => {\n setSelections((prev) => {\n const selectedItem = selectionToUpdate?.items?.find(\n (item) => item.selected\n );\n if (!selectedItem) return prev;\n\n const next = {\n ...prev,\n [selectionToUpdate.id]: {\n label: selectedItem?.label,\n value: selectedItem?.id,\n },\n };\n return next;\n });\n });\n }, [selectionsToUpdate, setSelections]);\n\n // Update invalid options\n useMemo(() => {\n const errors = options?.reduce((accum, option) => {\n let valueSelected = false;\n option?.items?.forEach((item) => {\n const selected = selections[option.id]?.value === item.id;\n if (selected) {\n valueSelected = true;\n }\n });\n\n // Validate required\n if (option.required && !valueSelected) {\n accum[option.id] = RequiredLabel;\n }\n return accum;\n }, {} as { [id: string]: string });\n\n // Call the callback\n onErrors?.(errors);\n\n return errors;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selections]);\n\n const handleOnSelection = useCallback(\n (id: string, label: string, optionId: string) => {\n setSelections((prev) => {\n let next = {\n ...prev,\n ...(id && { [id]: { label, value: optionId } }),\n };\n\n if (label === ChooseOptionLabel) {\n delete next[id];\n }\n\n // Call the callback\n onValues?.(next, optionId);\n\n // Return the next state\n return next;\n });\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [onValues]\n );\n\n // Function to handle the picker selection\n const handlePickerSelect = useCallback(\n (optionId: string, selection: any) => {\n const label = selection.selectedOptions[0]?.label ?? '';\n handleOnSelection(optionId, label, selection.value);\n },\n [handleOnSelection]\n );\n\n const Swatches = useCallback(\n ({ items, id, required, type, selected, label }: any) => {\n const uniqueId = `pdp-swatch-${id}=${Math.random().toString(36)}`;\n\n return (\n items?.length > 0 && (\n <div className={classes(['pdp-swatches__options'])}>\n {type?.toLowerCase() === 'dropdown' ? (\n <Picker\n id={uniqueId}\n name={id}\n aria-label={label}\n placeholder={\n disablePreselections ? ChooseOptionLabel : undefined\n }\n handleSelect={(event) => handlePickerSelect(id, event.target)}\n options={mapToPickerOptions(items)}\n value={selected}\n />\n ) : (\n items?.map((option: any) => {\n const common = {\n key: option.id,\n id: `${uniqueId}-${option.id}`,\n name: id,\n value: option.value,\n label: option.label,\n groupAriaLabel: label,\n selected: selected === option.id,\n outOfStock: !option.inStock,\n // API may return null, we default to true as all swatches are required.\n // we still comply to this in case the api return \"false\".\n required: required === null ? true : required,\n onValue: () => {\n handleOnSelection(id, option.label, option.id);\n },\n };\n\n switch (type) {\n case 'text':\n return <TextSwatch {...common} label={option.label} />;\n\n case 'image':\n return (\n <ImageSwatch\n {...common}\n src={option.value}\n alt={option.label}\n imageNode={imageSwatchNode}\n />\n );\n\n case 'color':\n return (\n <ColorSwatch\n {...common}\n size=\"large\"\n color={option.value}\n />\n );\n\n default:\n console.warn(`Invalid swatch type ${type}`);\n return null;\n }\n })\n )}\n </div>\n )\n );\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [ChooseOptionLabel, handleOnSelection, handlePickerSelect]\n );\n\n return (\n <div {...props} className={classes(['pdp-swatches', className])}>\n {options?.map(({ type, label, id, multiple, required, items }) => {\n // Only render supported types\n if (!supportedTypes.includes(type)) {\n console.warn(`Invalid swatch type ${type}`);\n }\n\n if (multiple) {\n console.warn(\n 'Multiple selection swatches are not currently supported.'\n );\n }\n\n return (\n <div\n key={`swatch-item-${id}`}\n id={`swatch-item-${id}`}\n data-slot-key={`product-swatch--${id}`}\n className=\"pdp-swatches__field\"\n >\n <div className=\"pdp-swatches__field__label\">\n {selections[id]\n ? hideSelectedValue\n ? `${label}`\n : `${label}: ${selections[id].label}`\n : label}\n </div>\n\n <Swatches\n id={id}\n type={type}\n required={required}\n items={items}\n label={label} //label referring to the name of the swatchGroup\n selected={selections[id]?.value}\n />\n </div>\n );\n })}\n </div>\n );\n};\n"],"names":["supportedTypes","mapToPickerOptions","items","item","optionUIDsToSelection","optionUIDs","options","accum","optionUID","option","Swatches","hideSelectedValue","disablePreselections","selectedUIDs","onValues","onErrors","defaultOptions","selectionsToUpdate","className","children","imageSwatchNode","props","RequiredLabel","useText","ChooseOptionLabel","selections","setSelections","useState","defaultSelection","selected","useEffect","selection","prev","next","selectionToUpdate","selectedItem","_a","useMemo","errors","valueSelected","handleOnSelection","useCallback","id","label","optionId","handlePickerSelect","required","type","uniqueId","jsx","classes","Picker","event","common","TextSwatch","ImageSwatch","ColorSwatch","multiple","jsxs"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Swatches.js","sources":["/@dropins/storefront-pdp/src/components/Swatches/Swatches.tsx"],"sourcesContent":["/**\n * ADOBE CONFIDENTIAL\n * __________________\n * Copyright 2023 Adobe\n * All Rights Reserved.\n * __________________\n * NOTICE: All information contained herein is, and remains\n * the property of Adobe and its suppliers, if any. The intellectual\n * and technical concepts contained herein are proprietary to Adobe\n * and its suppliers and are protected by all applicable intellectual\n * property laws, including trade secret and copyright laws.\n * Dissemination of this information or reproduction of this material\n * is strictly forbidden unless prior written permission is obtained\n * from Adobe.\n */\n\nimport { FunctionComponent, VNode } from 'preact';\nimport {\n HTMLAttributes,\n useState,\n useMemo,\n useCallback,\n useEffect,\n JSX,\n} from 'preact/compat';\nimport { classes } from '@adobe-commerce/elsie/lib';\nimport { useText } from '@adobe-commerce/elsie/i18n';\nimport {\n ColorSwatch,\n ImageSwatch,\n TextSwatch,\n Picker,\n PickerOption,\n ImageNodeRenderProps,\n} from '@adobe-commerce/elsie/components';\n\nimport '@/pdp/components/Swatches/Swatches.css';\n\nconst supportedTypes = ['text', 'image', 'color', 'dropdown'];\n\nconst mapToPickerOptions = (items: OptionValue[]): PickerOption[] => {\n return items.map((item: OptionValue) => ({\n ...item,\n text: item.label,\n disabled: !item.inStock,\n }));\n};\n\ntype OptionValue = {\n id: string;\n label: string;\n inStock: boolean;\n value: string;\n selected?: boolean;\n};\n\nexport type Option = {\n id: string;\n type: (typeof supportedTypes)[number];\n label: string;\n required?: boolean;\n multiple?: boolean;\n items: OptionValue[];\n};\n\ntype Selection = { [id: string]: { label: string; value: string } };\n\nfunction optionUIDsToSelection(\n optionUIDs: string[],\n options: Array<Option>\n): Selection {\n return optionUIDs.reduce((accum, optionUID) => {\n const option = options?.find((option) =>\n option.items.find((item) => item.id === optionUID)\n );\n if (!option) return accum;\n\n const item = option.items.find((item) => item.id === optionUID);\n\n return {\n ...accum,\n [option.id]: {\n label: item!.label,\n value: item!.id,\n },\n };\n }, {});\n}\n\nexport interface SwatchesProps extends HTMLAttributes<HTMLDivElement> {\n options: Array<Option>;\n hideSelectedValue?: boolean;\n disablePreselections?: boolean;\n defaultOptions?: string[];\n selectionsToUpdate?: Option[];\n onValues?: (uids: Selection, current: string) => void;\n onErrors?: (errors: { [id: string]: string }) => void;\n selectedUIDs?: string[];\n imageSwatchNode?: VNode | ((props: ImageNodeRenderProps) => JSX.Element);\n}\n\nexport const Swatches: FunctionComponent<SwatchesProps> = ({\n options,\n hideSelectedValue,\n disablePreselections,\n selectedUIDs,\n onValues,\n onErrors,\n defaultOptions,\n selectionsToUpdate,\n className,\n children,\n imageSwatchNode,\n ...props\n}) => {\n // i18n\n const RequiredLabel = useText('PDP.Swatches.Required.label').label;\n const ChooseOptionLabel = useText('PDP.Swatches.ChooseOption.label').label;\n\n const [selections, setSelections] = useState<Selection>(() => {\n const initial = options?.reduce((accum, option) => {\n const { items } = option;\n const defaultSelection = items?.find((item) =>\n defaultOptions?.includes(item.id)\n );\n const selected = items?.find((item) => item.selected);\n if (defaultSelection) {\n return {\n ...accum,\n [option.id]: {\n label: defaultSelection.label,\n value: defaultSelection.id,\n },\n };\n } else if (selected) {\n return {\n ...accum,\n [option.id]: { label: selected.label, value: selected.id },\n };\n }\n return accum;\n }, {} as Selection);\n\n return initial;\n });\n\n // set selected options from props\n useEffect(() => {\n if (selectedUIDs) {\n const selection = optionUIDsToSelection(selectedUIDs, options);\n // if the internal state is already the same as the props, do nothing\n if (JSON.stringify(selection) === JSON.stringify(selections)) return;\n\n setSelections((prev) => {\n let next = {\n ...prev,\n ...selection,\n };\n onValues?.(next);\n return next;\n });\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedUIDs]);\n\n // this only applies for the case with anchor options\n // update selections in the swatches if they are updated in the parent component\n useEffect(() => {\n selectionsToUpdate?.forEach((selectionToUpdate) => {\n setSelections((prev) => {\n const selectedItem = selectionToUpdate?.items?.find(\n (item) => item.selected\n );\n if (!selectedItem) return prev;\n\n const next = {\n ...prev,\n [selectionToUpdate.id]: {\n label: selectedItem?.label,\n value: selectedItem?.id,\n },\n };\n return next;\n });\n });\n }, [selectionsToUpdate, setSelections]);\n\n // Update invalid options\n useMemo(() => {\n const errors = options?.reduce((accum, option) => {\n let valueSelected = false;\n option?.items?.forEach((item) => {\n const selected = selections[option.id]?.value === item.id;\n if (selected) {\n valueSelected = true;\n }\n });\n\n // Validate required\n if (option.required && !valueSelected) {\n accum[option.id] = RequiredLabel;\n }\n return accum;\n }, {} as { [id: string]: string });\n\n // Call the callback\n onErrors?.(errors);\n\n return errors;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selections]);\n\n const handleOnSelection = useCallback(\n (id: string, label: string, optionId: string) => {\n setSelections((prev) => {\n let next = {\n ...prev,\n ...(id && { [id]: { label, value: optionId } }),\n };\n\n if (label === ChooseOptionLabel) {\n delete next[id];\n }\n\n // Call the callback\n onValues?.(next, optionId);\n\n // Return the next state\n return next;\n });\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [onValues]\n );\n\n // Function to handle the picker selection\n const handlePickerSelect = useCallback(\n (optionId: string, selection: any) => {\n const label = selection.selectedOptions[0]?.label ?? '';\n handleOnSelection(optionId, label, selection.value);\n },\n [handleOnSelection]\n );\n\n const Swatches = useCallback(\n ({ items, id, required, type, selected, label }: any) => {\n const uniqueId = `pdp-swatch-${id}=${Math.random().toString(36)}`;\n\n return (\n items?.length > 0 && (\n <div className={classes(['pdp-swatches__options'])}>\n {type?.toLowerCase() === 'dropdown' ? (\n <Picker\n id={uniqueId}\n name={id}\n aria-label={label}\n placeholder={\n disablePreselections ? ChooseOptionLabel : undefined\n }\n handleSelect={(event) => handlePickerSelect(id, event.target)}\n options={mapToPickerOptions(items)}\n value={selected}\n />\n ) : (\n items?.map((option: any) => {\n const common = {\n key: option.id,\n id: `${uniqueId}-${option.id}`,\n name: id,\n value: option.value,\n label: option.label,\n groupAriaLabel: label,\n selected: selected === option.id,\n outOfStock: !option.inStock,\n // API may return null, we default to true as all swatches are required.\n // we still comply to this in case the api return \"false\".\n required: required === null ? true : required,\n onValue: () => {\n handleOnSelection(id, option.label, option.id);\n },\n };\n\n switch (type) {\n case 'text':\n return <TextSwatch {...common} label={option.label} />;\n\n case 'image':\n return (\n <ImageSwatch\n {...common}\n src={option.value}\n alt={option.label}\n imageNode={imageSwatchNode}\n />\n );\n\n case 'color':\n return (\n <ColorSwatch\n {...common}\n size=\"large\"\n color={option.value}\n />\n );\n\n default:\n console.warn(`Invalid swatch type ${type}`);\n return null;\n }\n })\n )}\n </div>\n )\n );\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [ChooseOptionLabel, handleOnSelection, handlePickerSelect]\n );\n\n return (\n <div {...props} className={classes(['pdp-swatches', className])}>\n {options?.map(({ type, label, id, multiple, required, items }) => {\n // Only render supported types\n if (!supportedTypes.includes(type)) {\n console.warn(`Invalid swatch type ${type}`);\n }\n\n if (multiple) {\n console.warn(\n 'Multiple selection swatches are not currently supported.'\n );\n }\n\n return (\n <div\n key={`swatch-item-${id}`}\n id={`swatch-item-${id}`}\n data-slot-key={`product-swatch--${id}`}\n className=\"pdp-swatches__field\"\n >\n <div className=\"pdp-swatches__field__label\">\n {selections[id]\n ? hideSelectedValue\n ? `${label}`\n : `${label}: ${selections[id].label}`\n : label}\n </div>\n\n <Swatches\n id={id}\n type={type}\n required={required}\n items={items}\n label={label} //label referring to the name of the swatchGroup\n selected={selections[id]?.value}\n />\n </div>\n );\n })}\n </div>\n );\n};\n"],"names":["supportedTypes","mapToPickerOptions","items","item","optionUIDsToSelection","optionUIDs","options","accum","optionUID","option","Swatches","hideSelectedValue","disablePreselections","selectedUIDs","onValues","onErrors","defaultOptions","selectionsToUpdate","className","children","imageSwatchNode","props","RequiredLabel","useText","ChooseOptionLabel","selections","setSelections","useState","defaultSelection","selected","useEffect","selection","prev","next","selectionToUpdate","selectedItem","_a","useMemo","errors","valueSelected","handleOnSelection","useCallback","id","label","optionId","handlePickerSelect","required","type","uniqueId","jsx","classes","Picker","event","common","TextSwatch","ImageSwatch","ColorSwatch","multiple","jsxs"],"mappings":"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"}
|
package/chunks/Zoom.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Zoom.js","sources":["../../node_modules/@adobe-commerce/elsie/src/icons/ChevronDown.svg","../../node_modules/@adobe-commerce/elsie/src/icons/Close.svg","/@dropins/storefront-pdp/src/components/Carousel/Carousel.tsx","/@dropins/storefront-pdp/src/components/Overlay/Overlay.tsx","/@dropins/storefront-pdp/src/components/Zoom/Zoom.tsx"],"sourcesContent":["import * as React from \"react\";\nconst SvgChevronDown = (props) => /* @__PURE__ */ React.createElement(\"svg\", { width: 24, height: 24, viewBox: \"0 0 24 24\", fill: \"none\", xmlns: \"http://www.w3.org/2000/svg\", ...props }, /* @__PURE__ */ React.createElement(\"path\", { d: \"M7.74512 9.87701L12.0001 14.132L16.2551 9.87701\", stroke: \"currentColor\", strokeWidth: 1.5, strokeLinecap: \"square\", strokeLinejoin: \"round\" }));\nexport default SvgChevronDown;\n","import * as React from \"react\";\nconst SvgClose = (props) => /* @__PURE__ */ React.createElement(\"svg\", { width: 24, height: 24, viewBox: \"0 0 24 24\", fill: \"none\", xmlns: \"http://www.w3.org/2000/svg\", ...props }, /* @__PURE__ */ React.createElement(\"path\", { vectorEffect: \"non-scaling-stroke\", d: \"M18.3599 5.64001L5.62988 18.37\", stroke: \"currentColor\" }), /* @__PURE__ */ React.createElement(\"path\", { vectorEffect: \"non-scaling-stroke\", d: \"M18.3599 18.37L5.62988 5.64001\", stroke: \"currentColor\" }));\nexport default SvgClose;\n","/**\n * ADOBE CONFIDENTIAL\n * __________________\n * Copyright 2023 Adobe\n * All Rights Reserved.\n * __________________\n * NOTICE: All information contained herein is, and remains\n * the property of Adobe and its suppliers, if any. The intellectual\n * and technical concepts contained herein are proprietary to Adobe\n * and its suppliers and are protected by all applicable intellectual\n * property laws, including trade secret and copyright laws.\n * Dissemination of this information or reproduction of this material\n * is strictly forbidden unless prior written permission is obtained\n * from Adobe.\n */\n\nimport { FunctionComponent, VNode } from 'preact';\nimport {\n HTMLAttributes,\n Children,\n useState,\n useRef,\n useEffect,\n useMemo,\n useCallback,\n useLayoutEffect,\n} from 'preact/compat';\nimport { classes, debounce } from '@adobe-commerce/elsie/lib';\nimport { Button, Icon } from '@adobe-commerce/elsie/components';\nimport { ChevronDown } from '@adobe-commerce/elsie/icons';\nimport { useText } from '@adobe-commerce/elsie/i18n';\n\nimport '@/pdp/components/Carousel/Carousel.css';\n\ntype Show = number;\n\nconst PEAK_WIDTH = 24;\nconst THUMB_GAP = 16;\nconst ICON_SIZE = '32';\n\nenum GapSize {\n small = 16,\n medium = 24,\n large = 64,\n}\n\nexport interface CarouselProps\n extends Omit<HTMLAttributes<HTMLDivElement>, 'controls'> {\n children: VNode[] | VNode;\n thumbnails?: VNode[] | VNode;\n show?: Show | { small: Show; medium: Show; large: Show };\n gap?: 'small' | 'medium' | 'large' | null;\n scrollbar?: boolean;\n peak?: boolean;\n arrows?: boolean;\n controls?: 'thumbnailsRow' | 'thumbnailsColumn' | 'dots' | null;\n arrowsOnMainImage?: boolean;\n loop?: boolean;\n direction?: 'horizontal';\n style?: Record<string, string | number>;\n width?: string;\n height?: string;\n defaultIndex?: number;\n infinite?: boolean;\n isZoomed?: boolean;\n}\n\nexport const Carousel: FunctionComponent<CarouselProps> = ({\n show = 1,\n scrollbar = false,\n peak = false,\n arrows = false,\n controls = 'dots',\n arrowsOnMainImage = false,\n loop = false,\n gap = null,\n direction = 'horizontal',\n width = '100%',\n height = '100%',\n defaultIndex = 0,\n className,\n children,\n thumbnails = null,\n isZoomed,\n ...props\n}) => {\n // i18n\n const Label = useText('PDP.Carousel.label').label;\n const SlideLabel = useText('PDP.Carousel.Slide.label').label;\n const PreviousLabel = useText('PDP.Carousel.Previous.label').label;\n const NextLabel = useText('PDP.Carousel.Next.label').label;\n const ControlsLabel = useText('PDP.Carousel.Controls.label').label;\n const ControlsBtnLabel = useText('PDP.Carousel.Controls.Button.label').label;\n\n // States\n const [perPage, setPerPage] = useState(() => getPerPageFromBreakpoint(show));\n\n // Constants\n const length = Math.ceil(Children.count(children) / perPage);\n\n const peakWidth = peak ? PEAK_WIDTH : 0;\n const gapWidth = gap ? GapSize[gap] : 0;\n const rest = Children.count(children) % perPage;\n\n // States\n const [current, setCurrent] = useState(\n loop ? (isRTL() ? defaultIndex - 1 : defaultIndex + 1) : defaultIndex\n );\n\n // Thumbnails (refs for each thumbnail item)\n const thumbnailsRefs = useRef<HTMLLabelElement[]>([]);\n const [thumbWidth, setThumbWidth] = useState(0);\n const [thumbHeight, setThumbHeight] = useState(0);\n\n // VNodes\n const thumbnailSlides = useMemo<VNode[]>(() => {\n return Children.toArray(thumbnails);\n }, [thumbnails]);\n\n // Slides\n const slides = useMemo<VNode[][]>(() => {\n const returnValue = Children.toArray(children).reduce((acc, child, i) => {\n if (i % perPage === 0) {\n return [...acc, [child]];\n }\n\n return [...acc.slice(0, -1), [...acc[acc.length - 1], child]];\n }, [] as VNode[][]);\n\n if (!loop || returnValue.length === 1) {\n return returnValue;\n }\n\n if (loop && !(Children.count(children) % perPage !== 0)) {\n return [returnValue[length - 1]]\n .concat(returnValue)\n .concat([returnValue[0], returnValue[1]]);\n }\n\n return [Children.toArray(children).slice(-perPage)]\n .concat(returnValue)\n .concat([returnValue[0], returnValue[1]]);\n }, [children, perPage, length, loop]);\n\n // Wrapper\n const wrapperRef = useRef<HTMLDivElement>(null);\n const thumbnailsWrapperRef = useRef<HTMLDivElement>(null);\n\n const thumbnailControls =\n controls === 'thumbnailsRow' || controls === 'thumbnailsColumn';\n\n // Observe Resize (responsive)\n useEffect(() => {\n const wrapper = wrapperRef.current;\n\n if (!wrapper) return; // Guard clause in case the ref is not set yet\n\n const handleResize = debounce(() => {\n setThumbWidth(wrapper.offsetWidth ?? 0);\n setThumbHeight(wrapper.offsetHeight ?? 0);\n const width = window.innerWidth;\n const newPerPage = getPerPageFromBreakpoint(show, width);\n\n if (newPerPage !== perPage) {\n setPerPage(newPerPage);\n }\n }, 50);\n\n const observer = new ResizeObserver(handleResize);\n observer.observe(wrapper);\n\n return () => {\n observer.unobserve(wrapper);\n };\n }, [perPage, show]);\n\n // Scrolling logic controls\n const handleThumbnailsScroll = useCallback(\n (nextSlideIndex: number) => {\n const nextItem = loop ? nextSlideIndex - 1 : nextSlideIndex;\n const thumbnailRef = thumbnailsRefs?.current[0];\n const oneItemWidth = thumbnailRef?.offsetWidth + THUMB_GAP;\n const oneItemHeight = thumbnailRef?.offsetHeight + THUMB_GAP;\n const thumbnailsWrapper = thumbnailsWrapperRef.current!;\n\n const isRow = controls === 'thumbnailsRow';\n const isColumn = controls === 'thumbnailsColumn';\n const offset = isRow\n ? thumbnailsWrapper?.offsetWidth\n : thumbnailsWrapper?.offsetHeight;\n const oneItemSize = isRow ? oneItemWidth : oneItemHeight;\n\n if ((isRow || isColumn) && offset) {\n const visibleThumbnails = Math.floor(\n (isRow\n ? thumbnailsWrapper.clientWidth\n : thumbnailsWrapper.clientHeight) / oneItemSize\n );\n const centerOffset = Math.floor(visibleThumbnails / 2);\n const targetScrollPosition = (nextItem - centerOffset) * oneItemSize;\n thumbnailsWrapper.style.scrollBehavior = 'smooth';\n\n if (isRow) {\n thumbnailsWrapper.scrollLeft = isRTL()\n ? -(\n thumbnailsWrapper.scrollWidth -\n thumbnailsWrapper.clientWidth -\n targetScrollPosition\n )\n : targetScrollPosition;\n } else {\n thumbnailsWrapper.scrollTop = targetScrollPosition;\n }\n }\n },\n [controls, loop]\n );\n\n useEffect(() => {\n handleThumbnailsScroll(current);\n }, [current, handleThumbnailsScroll]);\n\n // Navigation\n const handleScrollTo = useCallback(\n (nextSlideIndex: number, smooth?: boolean, reset?: boolean) => {\n if (thumbnailControls) {\n handleThumbnailsScroll(nextSlideIndex);\n }\n\n const wrapper = wrapperRef.current!;\n const realWidth = peakWidth\n ? wrapper.offsetWidth - peakWidth\n : wrapper.offsetWidth - peakWidth + gapWidth;\n\n const items = Array.from(wrapper.querySelectorAll('[data-index]')).filter(\n (element) => {\n const dataIndex = Number(element.getAttribute('data-index')!);\n return !isNaN(dataIndex) && dataIndex > -1;\n }\n );\n\n const item = items[nextSlideIndex];\n\n if (!item) {\n return;\n }\n\n if (reset) {\n const futureIndex = nextSlideIndex === 0 ? length : 0;\n const scrollWidth =\n realWidth * (length + (rest ? rest : perPage) / perPage);\n\n if (isRTL()) {\n if (\n wrapper.scrollLeft <= 0 &&\n wrapper.scrollLeft > -(realWidth - 5)\n ) {\n handleScrollTo(1, true);\n return;\n }\n if (\n wrapper.scrollLeft < realWidth - scrollWidth &&\n wrapper.scrollLeft >= -scrollWidth\n ) {\n handleScrollTo(length, true);\n return;\n }\n\n wrapper.style.scrollBehavior = 'auto';\n wrapper.scrollLeft = futureIndex === 0 ? 0 : -scrollWidth;\n handleScrollTo(futureIndex === 0 ? 1 : length, true);\n } else {\n if (wrapper.scrollLeft >= 0 && wrapper.scrollLeft < realWidth - 5) {\n handleScrollTo(1, true);\n return;\n }\n\n if (\n wrapper.scrollLeft > scrollWidth - realWidth &&\n wrapper.scrollLeft <= scrollWidth\n ) {\n handleScrollTo(length, true);\n return;\n }\n\n wrapper.style.scrollBehavior = 'auto';\n wrapper.scrollLeft = futureIndex === 0 ? 0 : scrollWidth;\n handleScrollTo(futureIndex === 0 ? 1 : length, true);\n return;\n }\n }\n\n const diff =\n ((wrapper.offsetWidth - gapWidth) / perPage) *\n slides[nextSlideIndex].length -\n peakWidth;\n\n wrapper.style.scrollBehavior = smooth ? 'smooth' : 'auto';\n wrapper.scrollLeft = isRTL()\n ? -(slides[nextSlideIndex].length === perPage\n ? realWidth * nextSlideIndex\n : realWidth * (nextSlideIndex - 1) - diff)\n : slides[nextSlideIndex].length === perPage\n ? realWidth * nextSlideIndex\n : realWidth * (nextSlideIndex - 1) + diff;\n return;\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n gapWidth,\n length,\n peakWidth,\n perPage,\n rest,\n slides,\n handleThumbnailsScroll,\n controls,\n ]\n );\n\n const handleGoToPrev = useCallback(() => {\n if (loop) {\n const nextSlideIndex = current - 1;\n handleScrollTo(\n nextSlideIndex,\n true,\n isRTL() ? current === length - 1 : current === 1\n );\n return;\n }\n\n const nextSlideIndex = current <= 0 ? 0 : current - 1;\n handleScrollTo(nextSlideIndex, true);\n }, [current, handleScrollTo, loop]); //eslint-disable-line react-hooks/exhaustive-deps\n\n const handleGoToNext = useCallback(() => {\n const lastSlideIndex = slides.length - 1;\n\n if (loop) {\n const nextSlideIndex = current + 1;\n handleScrollTo(\n nextSlideIndex,\n true,\n isRTL() ? current === 0 : current === length\n );\n return;\n }\n\n const nextSlideIndex =\n current >= lastSlideIndex ? lastSlideIndex : current + 1;\n\n handleScrollTo(nextSlideIndex, true);\n }, [slides.length, loop, current, handleScrollTo, length]);\n\n // Navigate with keyboard\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'ArrowLeft') {\n isRTL() ? handleGoToNext() : handleGoToPrev();\n }\n\n if (event.key === 'ArrowRight') {\n isRTL() ? handleGoToPrev() : handleGoToNext();\n }\n };\n\n window.addEventListener('keydown', handleKeyDown);\n\n return () => {\n window.removeEventListener('keydown', handleKeyDown);\n };\n }, [handleGoToNext, handleGoToPrev]);\n\n // Set default index\n useLayoutEffect(() => {\n handleScrollTo(loop ? defaultIndex + 1 : defaultIndex, false);\n }, [defaultIndex, handleScrollTo, loop, thumbWidth]);\n\n // Track scrolling (swipes)\n const handleOnScroll = debounce(() => {\n const wrapper = wrapperRef.current!;\n const realWidth = peakWidth\n ? wrapper.offsetWidth - peakWidth\n : wrapper.offsetWidth - peakWidth + gapWidth;\n\n const dividing = Math.abs(wrapper.scrollLeft) / realWidth;\n const nextSlideIndex = Math.abs(\n Math.round(dividing) - dividing < 1\n ? Math.round(dividing)\n : Math.ceil(dividing)\n );\n\n if (thumbnailControls) {\n handleThumbnailsScroll(nextSlideIndex);\n }\n\n if (loop) {\n const totalWidth =\n realWidth * (length + (rest ? rest : perPage) / perPage);\n const scrollOffset = isRTL() ? -wrapper.scrollLeft : wrapper.scrollLeft;\n\n if (Math.ceil(Math.abs(scrollOffset)) >= Math.ceil(totalWidth) - 5) {\n wrapper.style.scrollBehavior = 'auto';\n wrapper.scrollLeft = isRTL()\n ? -wrapper.offsetWidth +\n (Math.ceil(scrollOffset) - Math.ceil(totalWidth) - peakWidth)\n : wrapper.offsetWidth +\n (Math.ceil(scrollOffset) - Math.ceil(totalWidth) - peakWidth);\n return;\n }\n\n if (Math.abs(scrollOffset) === 0) {\n wrapper.style.scrollBehavior = 'auto';\n\n wrapper.scrollLeft = isRTL()\n ? -(totalWidth - wrapper.offsetWidth + peakWidth)\n : totalWidth - wrapper.offsetWidth + peakWidth;\n return;\n }\n }\n\n if (current !== nextSlideIndex) {\n setCurrent(nextSlideIndex);\n }\n }, 100);\n\n useEffect(() => {\n const wrapper = wrapperRef.current;\n wrapper?.addEventListener('scroll', handleOnScroll);\n\n return () => {\n wrapper?.removeEventListener('scroll', handleOnScroll);\n };\n }, [handleOnScroll]);\n\n // thumbnails is column -> container is row reverse, controls is column\n // thumbnails is row -> container is column, controls is row\n const getArrow = (\n forThumbnails: boolean,\n direction: string,\n callback: () => void\n ) => {\n return (\n <Button\n className={classes([\n ['pdp-carousel__button', !forThumbnails],\n [`pdp-carousel__button--${direction}`, !forThumbnails],\n [`pdp-carousel__button--${controls}`, forThumbnails],\n ])}\n style={{\n '--height': `${thumbHeight}px`,\n }}\n variant=\"tertiary\"\n aria-label={direction === 'next' ? NextLabel : PreviousLabel}\n onClick={callback}\n disabled={\n loop\n ? false\n : direction === 'next'\n ? current >= slides.length - 1\n : current < 1\n }\n >\n <Icon\n className={classes([\n ['pdp-carousel__button__icon', !forThumbnails],\n [`pdp-carousel__button__icon--${direction}`, !forThumbnails],\n [\n `pdp-carousel__button__icon--${controls}--${direction}`,\n forThumbnails,\n ],\n ])}\n size={ICON_SIZE}\n source={ChevronDown}\n />\n </Button>\n );\n };\n\n const prevArrow =\n arrows &&\n slides.length != 1 &&\n getArrow(thumbnailControls, 'prev', handleGoToPrev);\n\n const nextArrow =\n arrows &&\n slides.length != 1 &&\n getArrow(thumbnailControls, 'next', handleGoToNext);\n\n const prevArrowMainImage =\n arrows && slides.length != 1 && getArrow(false, 'prev', handleGoToPrev);\n\n const nextArrowMainImage =\n arrows && slides.length != 1 && getArrow(false, 'next', handleGoToNext);\n\n return (\n <div\n role=\"region\"\n aria-roledescription={Label}\n className={classes([\n 'pdp-carousel',\n ['pdp-carousel--main-image-controls', arrowsOnMainImage],\n ['pdp-carousel--arrows', arrows && !thumbnailControls],\n [`pdp-carousel--${controls}`, thumbnailControls],\n className,\n ])}\n style={{\n '--flex-carousel':\n controls === 'thumbnailsColumn' ? 'row-reverse' : 'column',\n '--gap': thumbnailControls ? '0' : 'var(--spacing-small)',\n '--width': width,\n }}\n {...props}\n >\n {/* Slideshow */}\n <div\n ref={wrapperRef}\n className={classes([\n 'pdp-carousel__wrapper',\n `pdp-carousel__wrapper--${direction}`,\n ['pdp-carousel__wrapper--scrollbar', scrollbar],\n ['pdp-carousel__wrapper--peak', peak],\n ])}\n style={{\n '--total-width': controls === 'thumbnailsColumn' ? `81.6%` : `100%`,\n '--height': controls === 'thumbnailsColumn' ? 'auto' : height,\n '--gap': gap ? `var(--spacing-${gap})` : '0px',\n '--per-page': perPage,\n }}\n tabIndex={0}\n >\n {slides.map((page, index) => {\n const orphan = page.length < perPage;\n\n return (\n <div\n key={index}\n role=\"group\"\n aria-roledescription={SlideLabel}\n data-index={index}\n className={classes([\n 'pdp-carousel__slide',\n `pdp-carousel__slide--${direction}`,\n ['pdp-carousel__slide--active', current === index],\n ['pdp-carousel__slide--orphan', orphan],\n ['pdp-carousel__slide--hidden', thumbWidth === 0],\n ])}\n style={{\n '--length': page.length,\n }}\n >\n {page}\n </div>\n );\n })}\n </div>\n\n {/* Previous and next arrows for Carousel without thumbnails */}\n {!thumbnailControls && (\n <>\n {prevArrow}\n {nextArrow}\n </>\n )}\n\n {thumbnailControls && arrowsOnMainImage && (\n <>\n {prevArrowMainImage}\n {nextArrowMainImage}\n </>\n )}\n\n {/* Controls */}\n {controls && slides.length != 1 && (\n <div\n className={classes([\n [\n `pdp-carousel__controls__container--${controls}`,\n thumbnailControls,\n ],\n [\n 'pdp-carousel__controls__container--no-arrows',\n !arrows || arrowsOnMainImage,\n ],\n ])}\n style={{\n '--width': controls === 'thumbnailsRow' ? `${thumbWidth}px` : width,\n '--height': `${thumbHeight}px`,\n '--nr-thumbnails': thumbnailSlides.length,\n }}\n >\n {(thumbnailControls || isZoomed) && !arrowsOnMainImage && prevArrow}\n\n <div\n ref={thumbnailsWrapperRef}\n className={classes([\n [\n `pdp-carousel__controls__wrapper--${controls}`,\n thumbnailControls,\n ],\n [`pdp-carousel__controls__wrapper`, thumbnailControls],\n ])}\n >\n <div\n role=\"group\"\n aria-label={ControlsLabel}\n className={classes([\n 'pdp-carousel__controls',\n [`pdp-carousel__controls--${controls}`, thumbnailControls],\n ])}\n >\n {(loop ? slides.slice(0, length) : slides).map((_, key) => {\n const buttonsLength = loop ? length : slides.length;\n const active = loop ? current - 1 === key : current === key;\n\n if (!thumbnailControls) {\n return (\n <button\n key={key}\n aria-label={ControlsBtnLabel.replace(\n '{key}',\n String(key + 1)\n ).replace('{total}', String(buttonsLength))}\n onClick={() => {\n handleScrollTo(loop ? key + 1 : key, true);\n }}\n className={classes([\n 'pdp-carousel__controls__button',\n ['pdp-carousel__controls__button--active', active],\n ])}\n />\n );\n }\n return (\n <label\n className={classes(['pdp-carousel__thumbnail__container'])}\n key={key}\n ref={(el: HTMLLabelElement | null) => {\n if (el) {\n thumbnailsRefs.current[key] = el;\n }\n }}\n >\n <input\n type=\"radio\"\n name={'carousel-thumbnails'}\n aria-label={ControlsBtnLabel.replace(\n '{key}',\n String(key + 1)\n ).replace('{total}', String(buttonsLength))}\n checked={active && thumbWidth !== 0}\n onChange={() => {\n handleScrollTo(loop ? key + 1 : key, true);\n }}\n {...props}\n className={classes([\n 'pdp-carousel__thumbnail',\n [\n 'pdp-carousel__thumbnail--selected',\n active && thumbWidth !== 0,\n ],\n ])}\n />\n\n <span\n className={classes(['pdp-carousel__thumbnail__span'])}\n >\n {thumbnailSlides[key]}\n </span>\n </label>\n );\n })}\n </div>\n </div>\n\n {(thumbnailControls || isZoomed) && !arrowsOnMainImage && nextArrow}\n </div>\n )}\n </div>\n );\n};\n\n// Utilities\nfunction getPerPageFromBreakpoint(\n breakpoints: { small: number; medium: number; large: number } | number,\n width = 0\n) {\n if (typeof breakpoints === 'number') return breakpoints;\n\n const { small, medium, large } = breakpoints;\n const breakpointsMap = [\n { breakpoint: 1024, value: large },\n { breakpoint: 786, value: medium },\n { breakpoint: 0, value: small },\n ];\n\n const matchingBreakpoint = breakpointsMap.find(\n ({ breakpoint }) => width > breakpoint\n );\n\n return matchingBreakpoint ? matchingBreakpoint.value : small;\n}\n\nfunction isRTL() {\n return document.documentElement.dir === 'rtl';\n}\n","/**\n * ADOBE CONFIDENTIAL\n * __________________\n * Copyright 2023 Adobe\n * All Rights Reserved.\n * __________________\n * NOTICE: All information contained herein is, and remains\n * the property of Adobe and its suppliers, if any. The intellectual\n * and technical concepts contained herein are proprietary to Adobe\n * and its suppliers and are protected by all applicable intellectual\n * property laws, including trade secret and copyright laws.\n * Dissemination of this information or reproduction of this material\n * is strictly forbidden unless prior written permission is obtained\n * from Adobe.\n */\n\nimport { FunctionComponent } from 'preact';\nimport { HTMLAttributes, useCallback, useEffect, useRef } from 'preact/compat';\nimport { classes } from '@adobe-commerce/elsie/lib';\nimport { useText } from '@adobe-commerce/elsie/i18n';\nimport { Close as CloseSVG } from '@adobe-commerce/elsie/icons';\nimport { Button } from '@adobe-commerce/elsie/components';\n\nimport '@/pdp/components/Overlay/Overlay.css';\n\nexport interface OverlayProps extends HTMLAttributes<HTMLDivElement> {\n centered?: boolean;\n onClose?: () => void;\n}\n\nexport const Overlay: FunctionComponent<OverlayProps> = ({\n centered,\n onClose,\n className,\n children,\n ...props\n}) => {\n // i18n\n const CloseLabel = useText('PDP.Overlay.Close.label').label;\n const overlayRef = useRef<HTMLInputElement>(null);\n const handleOnClose = useCallback(() => {\n onClose?.();\n }, [onClose]);\n\n // Close on ESC\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n handleOnClose();\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n };\n }, [handleOnClose]);\n\n // Prevent document scrolling\n useEffect(() => {\n const input = overlayRef.current;\n input?.focus();\n\n const scrollingElement = document.scrollingElement as HTMLElement;\n\n const defaultOverflowValue = scrollingElement.style.overflow;\n\n scrollingElement.style.overflow = 'hidden';\n\n return () => {\n scrollingElement.style.overflow = defaultOverflowValue;\n };\n }, []);\n\n return (\n <div\n {...props}\n className={classes([\n 'pdp-overlay',\n ['pdp-overlay--centered', centered],\n className,\n ])}\n ref={overlayRef}\n role=\"dialog\"\n aria-describedby=\"overlay-content\"\n tabindex={0}\n >\n <div className=\"pdp-overlay__content\" id=\"overlay-content\">\n {children}\n </div>\n <Button\n aria-label={CloseLabel}\n variant=\"tertiary\"\n className=\"pdp-overlay__close-button\"\n onClick={handleOnClose}\n icon={<CloseSVG />}\n />\n </div>\n );\n};\n","/**\n * ADOBE CONFIDENTIAL\n * __________________\n * Copyright 2024 Adobe\n * All Rights Reserved.\n * __________________\n * NOTICE: All information contained herein is, and remains\n * the property of Adobe and its suppliers, if any. The intellectual\n * and technical concepts contained herein are proprietary to Adobe\n * and its suppliers and are protected by all applicable intellectual\n * property laws, including trade secret and copyright laws.\n * Dissemination of this information or reproduction of this material\n * is strictly forbidden unless prior written permission is obtained\n * from Adobe.\n */\nimport { cloneElement, FunctionComponent, VNode } from 'preact';\nimport {\n Children,\n useEffect,\n useState,\n useRef,\n useCallback,\n} from 'preact/compat';\n\nimport '@/pdp/components/Zoom/Zoom.css';\nimport { Button } from '@adobe-commerce/elsie/components';\nimport { Close as CloseSVG } from '@adobe-commerce/elsie/icons';\nimport { useText } from '@adobe-commerce/elsie/i18n';\n\nexport interface ZoomProps {\n children: VNode[] | VNode;\n scale?: number;\n closeButton?: boolean;\n}\n\nexport const Zoom: FunctionComponent<ZoomProps> = ({\n children,\n scale = 2.0,\n closeButton = true,\n}) => {\n const [zoomed, setZoomed] = useState(false);\n const [figureClassName, setFigureClassName] = useState('pdp-zoom');\n const [drag, setDrag] = useState(false);\n const [dragStart, setDragStart] = useState({ x: 0, y: 0 });\n const [dragStartPosition, setDragStartPosition] = useState({ x: 0, y: 0 });\n const [position, setPosition] = useState({ x: 0, y: 0 });\n\n const containerRef = useRef<HTMLElement>(null);\n const cachedBoundsRef = useRef<DOMRect | null>(null);\n const animationFrameRef = useRef<number | null>(null);\n const lastTransformRef = useRef<string>('none');\n\n const touchStartRef = useRef<{ x: number; y: number; time: number } | null>(\n null\n );\n const isSwipingRef = useRef<boolean>(false);\n const lastValidTouchRef = useRef<{ clientX: number; clientY: number } | null>(\n null\n );\n\n const updatePosition = useCallback(\n (event: MouseEvent | TouchEvent) => {\n const updatePositionLogic = () => {\n let zoomer: DOMRect;\n\n if (cachedBoundsRef.current && containerRef.current) {\n zoomer = cachedBoundsRef.current;\n } else if (containerRef.current) {\n zoomer = containerRef.current.getBoundingClientRect();\n cachedBoundsRef.current = zoomer;\n } else {\n zoomer = (\n event.currentTarget as HTMLElement\n )?.getBoundingClientRect();\n }\n\n const overlap = (100 - 100 / scale) / 2;\n let coordinates: { clientX: number; clientY: number } | null = null;\n\n if ('touches' in event) {\n if (event.touches.length > 0) {\n coordinates = event.touches[0];\n lastValidTouchRef.current = {\n clientX: coordinates.clientX,\n clientY: coordinates.clientY,\n };\n } else if (event.type === 'touchend' && touchStartRef.current) {\n coordinates = {\n clientX: touchStartRef.current.x,\n clientY: touchStartRef.current.y,\n };\n } else if (lastValidTouchRef.current) {\n coordinates = lastValidTouchRef.current;\n } else {\n return;\n }\n } else if (event instanceof MouseEvent) {\n coordinates = event;\n } else {\n return;\n }\n\n const relativeX =\n ((coordinates.clientX - zoomer.left) / zoomer.width) * 100;\n const relativeY =\n ((coordinates.clientY - zoomer.top) / zoomer.height) * 100;\n\n const x = ((50 - relativeX) * (scale - 1)) / scale;\n const y = ((50 - relativeY) * (scale - 1)) / scale;\n\n setPosition({\n x: Math.max(-overlap, Math.min(x, overlap)) || 0,\n y: Math.max(-overlap, Math.min(y, overlap)) || 0,\n });\n };\n\n if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'test') {\n updatePositionLogic();\n } else {\n if (animationFrameRef.current) {\n cancelAnimationFrame(animationFrameRef.current);\n }\n animationFrameRef.current = requestAnimationFrame(updatePositionLogic);\n }\n },\n [scale]\n );\n\n useEffect(() => {\n cachedBoundsRef.current = null;\n }, [zoomed]);\n\n const startDrag = (event: TouchEvent) => {\n if (!zoomed || event.type !== 'touchstart') return;\n setDragStart({ x: event.touches[0].clientX, y: event.touches[0].clientY });\n setDragStartPosition({ x: position.x, y: position.y });\n setDrag(true);\n };\n\n const dragMove = (event: TouchEvent) => {\n if (!drag || event.type !== 'touchmove') return;\n const zoomer = (\n event.currentTarget as HTMLElement\n )?.getBoundingClientRect();\n const overlap = (100 - 100 / scale) / 2;\n const movedX = event.touches[0].clientX - dragStart.x;\n const movedY = event.touches[0].clientY - dragStart.y;\n const movedXPercent = (movedX * 100) / (zoomer.width * scale);\n const movedYPercent = (movedY * 100) / (zoomer.height * scale);\n const x = dragStartPosition.x + movedXPercent;\n const y = dragStartPosition.y + movedYPercent;\n setPosition({\n x: Math.max(-overlap, Math.min(x, overlap)) || 0,\n y: Math.max(-overlap, Math.min(y, overlap)) || 0,\n });\n event.preventDefault();\n };\n\n const handleTouchStart = (event: TouchEvent) => {\n if (closeButton) {\n touchStartRef.current = {\n x: event.touches[0].clientX,\n y: event.touches[0].clientY,\n time: Date.now(),\n };\n\n lastValidTouchRef.current = {\n clientX: event.touches[0].clientX,\n clientY: event.touches[0].clientY,\n };\n\n isSwipingRef.current = false;\n\n if (zoomed) {\n startDrag(event);\n }\n } else {\n if (drag) return;\n\n !zoomed && updatePosition(event);\n\n setZoomed(!zoomed);\n\n event.preventDefault();\n }\n };\n\n const handleTouchMove = (event: TouchEvent) => {\n if (event.touches.length === 0) return;\n\n lastValidTouchRef.current = {\n clientX: event.touches[0].clientX,\n clientY: event.touches[0].clientY,\n };\n\n if (closeButton) {\n if (!touchStartRef.current) return;\n\n if (drag) {\n dragMove(event);\n return;\n }\n\n const touchX = event.touches[0].clientX;\n const touchY = event.touches[0].clientY;\n const deltaX = Math.abs(touchX - touchStartRef.current.x);\n const deltaY = Math.abs(touchY - touchStartRef.current.y);\n\n if (deltaX > 10 || deltaY > 10) {\n isSwipingRef.current = true;\n }\n }\n\n if (zoomed) {\n updatePosition(event);\n }\n };\n\n const handleTouchEnd = (event: TouchEvent) => {\n if (closeButton) {\n if (!touchStartRef.current) return;\n\n const tapDuration = Date.now() - touchStartRef.current.time;\n\n if (!isSwipingRef.current && tapDuration < 300 && !drag) {\n setZoomed(true);\n updatePosition(event);\n event.preventDefault();\n }\n\n setDrag(false);\n touchStartRef.current = null;\n } else {\n setZoomed(false);\n }\n };\n\n const handleClick = (event: MouseEvent) => {\n if ('touches' in event) return;\n\n if (drag) return;\n\n if (zoomed) {\n !closeButton && setZoomed(false);\n } else {\n setZoomed(true);\n updatePosition(event);\n }\n event.preventDefault();\n };\n\n const handleMove = (event: MouseEvent) => {\n if ('touches' in event) return;\n\n if (zoomed) {\n updatePosition(event);\n }\n };\n\n const handleLeave = (event: MouseEvent) => {\n if ('touches' in event) return;\n\n if (closeButton) {\n setDrag(false);\n return;\n }\n setZoomed(false);\n };\n\n const closeButtonClick = (event: MouseEvent | TouchEvent) => {\n setZoomed(false);\n event.stopPropagation();\n };\n\n const transformStyle = zoomed\n ? `scale(${scale}) translateX(${position.x}%) translateY(${position.y}%)`\n : 'none';\n\n const CloseLabel = useText('PDP.Zoom.Close.label').label;\n const child = Children.only(children) as any;\n\n useEffect(() => {\n const handleGalleryChange = () => {\n if (zoomed) {\n setZoomed(false);\n setPosition({ x: 0, y: 0 });\n setDrag(false);\n }\n };\n\n const gallery = document.querySelector('#gallery');\n if (gallery) {\n gallery.addEventListener('click', handleGalleryChange);\n return () => gallery.removeEventListener('click', handleGalleryChange);\n }\n }, [zoomed]);\n\n const ImageClone = cloneElement(child, {\n ...child.props,\n draggable: false,\n style: {\n ...child.props?.style,\n '--transform': transformStyle,\n },\n });\n\n useEffect(() => {\n const className = zoomed\n ? `pdp-zoom ${closeButton ? 'pdp-zoom--no-effects' : 'pdp-zoom--zoomed'}`\n : 'pdp-zoom';\n setFigureClassName(className);\n }, [zoomed, closeButton]);\n\n useEffect(() => {\n if (lastTransformRef.current === transformStyle) return;\n lastTransformRef.current = transformStyle;\n\n const updateTransforms = () => {\n if (!containerRef.current) return;\n\n const images = containerRef.current.querySelectorAll('img');\n images.forEach((img) => {\n if (zoomed && transformStyle !== 'none') {\n img.style.setProperty('transform', transformStyle, 'important');\n } else {\n img.style.removeProperty('transform');\n }\n });\n };\n\n requestAnimationFrame(updateTransforms);\n }, [transformStyle, zoomed]);\n\n useEffect(() => {\n return () => {\n if (animationFrameRef.current) {\n cancelAnimationFrame(animationFrameRef.current);\n }\n };\n }, []);\n\n return (\n <figure\n ref={containerRef}\n className={figureClassName}\n onClick={handleClick}\n onMouseMove={handleMove}\n onMouseLeave={handleLeave}\n onTouchStart={handleTouchStart}\n onTouchMove={handleTouchMove}\n onTouchEnd={handleTouchEnd}\n >\n {ImageClone}\n {closeButton && zoomed && (\n <Button\n aria-label={CloseLabel}\n variant=\"tertiary\"\n className=\"pdp-zoom__close-button\"\n icon={<CloseSVG />}\n onClick={closeButtonClick}\n />\n )}\n </figure>\n );\n};\n"],"names":["SvgChevronDown","props","React","SvgClose","PEAK_WIDTH","THUMB_GAP","ICON_SIZE","GapSize","Carousel","show","scrollbar","peak","arrows","controls","arrowsOnMainImage","loop","gap","direction","width","height","defaultIndex","className","children","thumbnails","isZoomed","Label","useText","SlideLabel","PreviousLabel","NextLabel","ControlsLabel","ControlsBtnLabel","perPage","setPerPage","useState","getPerPageFromBreakpoint","length","Children","peakWidth","gapWidth","rest","current","setCurrent","isRTL","thumbnailsRefs","useRef","thumbWidth","setThumbWidth","thumbHeight","setThumbHeight","thumbnailSlides","useMemo","slides","returnValue","acc","child","i","wrapperRef","thumbnailsWrapperRef","thumbnailControls","useEffect","wrapper","handleResize","debounce","newPerPage","observer","handleThumbnailsScroll","useCallback","nextSlideIndex","nextItem","thumbnailRef","oneItemWidth","oneItemHeight","thumbnailsWrapper","isRow","isColumn","offset","oneItemSize","visibleThumbnails","centerOffset","targetScrollPosition","handleScrollTo","smooth","reset","realWidth","element","dataIndex","futureIndex","scrollWidth","diff","handleGoToPrev","handleGoToNext","lastSlideIndex","handleKeyDown","event","useLayoutEffect","handleOnScroll","dividing","totalWidth","scrollOffset","getArrow","forThumbnails","callback","jsx","Button","classes","Icon","ChevronDown","prevArrow","nextArrow","prevArrowMainImage","nextArrowMainImage","jsxs","page","index","orphan","Fragment","_","key","buttonsLength","active","el","breakpoints","small","medium","large","matchingBreakpoint","breakpoint","Overlay","centered","onClose","CloseLabel","overlayRef","handleOnClose","input","scrollingElement","defaultOverflowValue","CloseSVG","Zoom","scale","closeButton","zoomed","setZoomed","figureClassName","setFigureClassName","drag","setDrag","dragStart","setDragStart","dragStartPosition","setDragStartPosition","position","setPosition","containerRef","cachedBoundsRef","animationFrameRef","lastTransformRef","touchStartRef","isSwipingRef","lastValidTouchRef","updatePosition","updatePositionLogic","zoomer","_a","overlap","coordinates","relativeX","relativeY","x","y","startDrag","dragMove","movedX","movedY","movedXPercent","movedYPercent","handleTouchStart","handleTouchMove","touchX","touchY","deltaX","deltaY","handleTouchEnd","tapDuration","handleClick","handleMove","handleLeave","closeButtonClick","transformStyle","handleGalleryChange","gallery","ImageClone","cloneElement","img"],"mappings":"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","x_google_ignoreList":[0,1]}
|
|
1
|
+
{"version":3,"file":"Zoom.js","sources":["../../node_modules/@adobe-commerce/elsie/src/icons/ChevronDown.svg","../../node_modules/@adobe-commerce/elsie/src/icons/Close.svg","/@dropins/storefront-pdp/src/components/Carousel/Carousel.tsx","/@dropins/storefront-pdp/src/components/Overlay/Overlay.tsx","/@dropins/storefront-pdp/src/components/Zoom/Zoom.tsx"],"sourcesContent":["import * as React from \"react\";\nconst SvgChevronDown = (props) => /* @__PURE__ */ React.createElement(\"svg\", { width: 24, height: 24, viewBox: \"0 0 24 24\", fill: \"none\", xmlns: \"http://www.w3.org/2000/svg\", ...props }, /* @__PURE__ */ React.createElement(\"path\", { d: \"M7.74512 9.87701L12.0001 14.132L16.2551 9.87701\", stroke: \"currentColor\", strokeWidth: 1.5, strokeLinecap: \"square\", strokeLinejoin: \"round\" }));\nexport default SvgChevronDown;\n","import * as React from \"react\";\nconst SvgClose = (props) => /* @__PURE__ */ React.createElement(\"svg\", { width: 24, height: 24, viewBox: \"0 0 24 24\", fill: \"none\", xmlns: \"http://www.w3.org/2000/svg\", ...props }, /* @__PURE__ */ React.createElement(\"path\", { vectorEffect: \"non-scaling-stroke\", d: \"M18.3599 5.64001L5.62988 18.37\", stroke: \"currentColor\" }), /* @__PURE__ */ React.createElement(\"path\", { vectorEffect: \"non-scaling-stroke\", d: \"M18.3599 18.37L5.62988 5.64001\", stroke: \"currentColor\" }));\nexport default SvgClose;\n","/**\n * ADOBE CONFIDENTIAL\n * __________________\n * Copyright 2023 Adobe\n * All Rights Reserved.\n * __________________\n * NOTICE: All information contained herein is, and remains\n * the property of Adobe and its suppliers, if any. The intellectual\n * and technical concepts contained herein are proprietary to Adobe\n * and its suppliers and are protected by all applicable intellectual\n * property laws, including trade secret and copyright laws.\n * Dissemination of this information or reproduction of this material\n * is strictly forbidden unless prior written permission is obtained\n * from Adobe.\n */\n\nimport { FunctionComponent, VNode } from 'preact';\nimport {\n HTMLAttributes,\n Children,\n useState,\n useRef,\n useEffect,\n useMemo,\n useCallback,\n useLayoutEffect,\n} from 'preact/compat';\nimport { classes, debounce } from '@adobe-commerce/elsie/lib';\nimport { Button, Icon } from '@adobe-commerce/elsie/components';\nimport { ChevronDown } from '@adobe-commerce/elsie/icons';\nimport { useText } from '@adobe-commerce/elsie/i18n';\n\nimport '@/pdp/components/Carousel/Carousel.css';\n\ntype Show = number;\n\nconst PEAK_WIDTH = 24;\nconst THUMB_GAP = 16;\nconst ICON_SIZE = '32';\n\nenum GapSize {\n small = 16,\n medium = 24,\n large = 64,\n}\n\nexport interface CarouselProps\n extends Omit<HTMLAttributes<HTMLDivElement>, 'controls'> {\n children: VNode[] | VNode;\n thumbnails?: VNode[] | VNode;\n show?: Show | { small: Show; medium: Show; large: Show };\n gap?: 'small' | 'medium' | 'large' | null;\n scrollbar?: boolean;\n peak?: boolean;\n arrows?: boolean;\n controls?: 'thumbnailsRow' | 'thumbnailsColumn' | 'dots' | null;\n arrowsOnMainImage?: boolean;\n loop?: boolean;\n direction?: 'horizontal';\n style?: Record<string, string | number>;\n width?: string;\n height?: string;\n defaultIndex?: number;\n infinite?: boolean;\n isZoomed?: boolean;\n}\n\nexport const Carousel: FunctionComponent<CarouselProps> = ({\n show = 1,\n scrollbar = false,\n peak = false,\n arrows = false,\n controls = 'dots',\n arrowsOnMainImage = false,\n loop = false,\n gap = null,\n direction = 'horizontal',\n width = '100%',\n height = '100%',\n defaultIndex = 0,\n className,\n children,\n thumbnails = null,\n isZoomed,\n ...props\n}) => {\n // i18n\n const Label = useText('PDP.Carousel.label').label;\n const SlideLabel = useText('PDP.Carousel.Slide.label').label;\n const PreviousLabel = useText('PDP.Carousel.Previous.label').label;\n const NextLabel = useText('PDP.Carousel.Next.label').label;\n const ControlsLabel = useText('PDP.Carousel.Controls.label').label;\n const ControlsBtnLabel = useText('PDP.Carousel.Controls.Button.label').label;\n\n // States\n const [perPage, setPerPage] = useState(() => getPerPageFromBreakpoint(show));\n\n // Constants\n const length = Math.ceil(Children.count(children) / perPage);\n\n const peakWidth = peak ? PEAK_WIDTH : 0;\n const gapWidth = gap ? GapSize[gap] : 0;\n const rest = Children.count(children) % perPage;\n\n // States\n const [current, setCurrent] = useState(\n loop ? (isRTL() ? defaultIndex - 1 : defaultIndex + 1) : defaultIndex\n );\n\n // Thumbnails (refs for each thumbnail item)\n const thumbnailsRefs = useRef<HTMLLabelElement[]>([]);\n const [thumbWidth, setThumbWidth] = useState(0);\n const [thumbHeight, setThumbHeight] = useState(0);\n\n // VNodes\n const thumbnailSlides = useMemo<VNode[]>(() => {\n return Children.toArray(thumbnails);\n }, [thumbnails]);\n\n // Slides\n const slides = useMemo<VNode[][]>(() => {\n const returnValue = Children.toArray(children).reduce((acc, child, i) => {\n if (i % perPage === 0) {\n return [...acc, [child]];\n }\n\n return [...acc.slice(0, -1), [...acc[acc.length - 1], child]];\n }, [] as VNode[][]);\n\n if (!loop || returnValue.length === 1) {\n return returnValue;\n }\n\n if (loop && !(Children.count(children) % perPage !== 0)) {\n return [returnValue[length - 1]]\n .concat(returnValue)\n .concat([returnValue[0], returnValue[1]]);\n }\n\n return [Children.toArray(children).slice(-perPage)]\n .concat(returnValue)\n .concat([returnValue[0], returnValue[1]]);\n }, [children, perPage, length, loop]);\n\n // Wrapper\n const wrapperRef = useRef<HTMLDivElement>(null);\n const thumbnailsWrapperRef = useRef<HTMLDivElement>(null);\n\n const thumbnailControls =\n controls === 'thumbnailsRow' || controls === 'thumbnailsColumn';\n\n // Observe Resize (responsive)\n useEffect(() => {\n const wrapper = wrapperRef.current;\n\n if (!wrapper) return; // Guard clause in case the ref is not set yet\n\n const handleResize = debounce(() => {\n setThumbWidth(wrapper.offsetWidth ?? 0);\n setThumbHeight(wrapper.offsetHeight ?? 0);\n const width = window.innerWidth;\n const newPerPage = getPerPageFromBreakpoint(show, width);\n\n if (newPerPage !== perPage) {\n setPerPage(newPerPage);\n }\n }, 50);\n\n const observer = new ResizeObserver(handleResize);\n observer.observe(wrapper);\n\n return () => {\n observer.unobserve(wrapper);\n };\n }, [perPage, show]);\n\n // Scrolling logic controls\n const handleThumbnailsScroll = useCallback(\n (nextSlideIndex: number) => {\n const nextItem = loop ? nextSlideIndex - 1 : nextSlideIndex;\n const thumbnailRef = thumbnailsRefs?.current[0];\n const oneItemWidth = thumbnailRef?.offsetWidth + THUMB_GAP;\n const oneItemHeight = thumbnailRef?.offsetHeight + THUMB_GAP;\n const thumbnailsWrapper = thumbnailsWrapperRef.current!;\n\n const isRow = controls === 'thumbnailsRow';\n const isColumn = controls === 'thumbnailsColumn';\n const offset = isRow\n ? thumbnailsWrapper?.offsetWidth\n : thumbnailsWrapper?.offsetHeight;\n const oneItemSize = isRow ? oneItemWidth : oneItemHeight;\n\n if ((isRow || isColumn) && offset) {\n const visibleThumbnails = Math.floor(\n (isRow\n ? thumbnailsWrapper.clientWidth\n : thumbnailsWrapper.clientHeight) / oneItemSize\n );\n const centerOffset = Math.floor(visibleThumbnails / 2);\n const targetScrollPosition = (nextItem - centerOffset) * oneItemSize;\n thumbnailsWrapper.style.scrollBehavior = 'smooth';\n\n if (isRow) {\n thumbnailsWrapper.scrollLeft = isRTL()\n ? -(\n thumbnailsWrapper.scrollWidth -\n thumbnailsWrapper.clientWidth -\n targetScrollPosition\n )\n : targetScrollPosition;\n } else {\n thumbnailsWrapper.scrollTop = targetScrollPosition;\n }\n }\n },\n [controls, loop]\n );\n\n useEffect(() => {\n handleThumbnailsScroll(current);\n }, [current, handleThumbnailsScroll]);\n\n // Navigation\n const handleScrollTo = useCallback(\n (nextSlideIndex: number, smooth?: boolean, reset?: boolean) => {\n if (thumbnailControls) {\n handleThumbnailsScroll(nextSlideIndex);\n }\n\n const wrapper = wrapperRef.current!;\n const realWidth = peakWidth\n ? wrapper.offsetWidth - peakWidth\n : wrapper.offsetWidth - peakWidth + gapWidth;\n\n const items = Array.from(wrapper.querySelectorAll('[data-index]')).filter(\n (element) => {\n const dataIndex = Number(element.getAttribute('data-index')!);\n return !isNaN(dataIndex) && dataIndex > -1;\n }\n );\n\n const item = items[nextSlideIndex];\n\n if (!item) {\n return;\n }\n\n if (reset) {\n const futureIndex = nextSlideIndex === 0 ? length : 0;\n const scrollWidth =\n realWidth * (length + (rest ? rest : perPage) / perPage);\n\n if (isRTL()) {\n if (\n wrapper.scrollLeft <= 0 &&\n wrapper.scrollLeft > -(realWidth - 5)\n ) {\n handleScrollTo(1, true);\n return;\n }\n if (\n wrapper.scrollLeft < realWidth - scrollWidth &&\n wrapper.scrollLeft >= -scrollWidth\n ) {\n handleScrollTo(length, true);\n return;\n }\n\n wrapper.style.scrollBehavior = 'auto';\n wrapper.scrollLeft = futureIndex === 0 ? 0 : -scrollWidth;\n handleScrollTo(futureIndex === 0 ? 1 : length, true);\n } else {\n if (wrapper.scrollLeft >= 0 && wrapper.scrollLeft < realWidth - 5) {\n handleScrollTo(1, true);\n return;\n }\n\n if (\n wrapper.scrollLeft > scrollWidth - realWidth &&\n wrapper.scrollLeft <= scrollWidth\n ) {\n handleScrollTo(length, true);\n return;\n }\n\n wrapper.style.scrollBehavior = 'auto';\n wrapper.scrollLeft = futureIndex === 0 ? 0 : scrollWidth;\n handleScrollTo(futureIndex === 0 ? 1 : length, true);\n return;\n }\n }\n\n const diff =\n ((wrapper.offsetWidth - gapWidth) / perPage) *\n slides[nextSlideIndex].length -\n peakWidth;\n\n wrapper.style.scrollBehavior = smooth ? 'smooth' : 'auto';\n wrapper.scrollLeft = isRTL()\n ? -(slides[nextSlideIndex].length === perPage\n ? realWidth * nextSlideIndex\n : realWidth * (nextSlideIndex - 1) - diff)\n : slides[nextSlideIndex].length === perPage\n ? realWidth * nextSlideIndex\n : realWidth * (nextSlideIndex - 1) + diff;\n return;\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n gapWidth,\n length,\n peakWidth,\n perPage,\n rest,\n slides,\n handleThumbnailsScroll,\n controls,\n ]\n );\n\n const handleGoToPrev = useCallback(() => {\n if (loop) {\n const nextSlideIndex = current - 1;\n handleScrollTo(\n nextSlideIndex,\n true,\n isRTL() ? current === length - 1 : current === 1\n );\n return;\n }\n\n const nextSlideIndex = current <= 0 ? 0 : current - 1;\n handleScrollTo(nextSlideIndex, true);\n }, [current, handleScrollTo, loop]); //eslint-disable-line react-hooks/exhaustive-deps\n\n const handleGoToNext = useCallback(() => {\n const lastSlideIndex = slides.length - 1;\n\n if (loop) {\n const nextSlideIndex = current + 1;\n handleScrollTo(\n nextSlideIndex,\n true,\n isRTL() ? current === 0 : current === length\n );\n return;\n }\n\n const nextSlideIndex =\n current >= lastSlideIndex ? lastSlideIndex : current + 1;\n\n handleScrollTo(nextSlideIndex, true);\n }, [slides.length, loop, current, handleScrollTo, length]);\n\n // Navigate with keyboard\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'ArrowLeft') {\n isRTL() ? handleGoToNext() : handleGoToPrev();\n }\n\n if (event.key === 'ArrowRight') {\n isRTL() ? handleGoToPrev() : handleGoToNext();\n }\n };\n\n window.addEventListener('keydown', handleKeyDown);\n\n return () => {\n window.removeEventListener('keydown', handleKeyDown);\n };\n }, [handleGoToNext, handleGoToPrev]);\n\n // Set default index\n useLayoutEffect(() => {\n handleScrollTo(loop ? defaultIndex + 1 : defaultIndex, false);\n }, [defaultIndex, handleScrollTo, loop, thumbWidth]);\n\n // Track scrolling (swipes)\n const handleOnScroll = debounce(() => {\n const wrapper = wrapperRef.current!;\n const realWidth = peakWidth\n ? wrapper.offsetWidth - peakWidth\n : wrapper.offsetWidth - peakWidth + gapWidth;\n\n const dividing = Math.abs(wrapper.scrollLeft) / realWidth;\n const nextSlideIndex = Math.abs(\n Math.round(dividing) - dividing < 1\n ? Math.round(dividing)\n : Math.ceil(dividing)\n );\n\n if (thumbnailControls) {\n handleThumbnailsScroll(nextSlideIndex);\n }\n\n if (loop) {\n const totalWidth =\n realWidth * (length + (rest ? rest : perPage) / perPage);\n const scrollOffset = isRTL() ? -wrapper.scrollLeft : wrapper.scrollLeft;\n\n if (Math.ceil(Math.abs(scrollOffset)) >= Math.ceil(totalWidth) - 5) {\n wrapper.style.scrollBehavior = 'auto';\n wrapper.scrollLeft = isRTL()\n ? -wrapper.offsetWidth +\n (Math.ceil(scrollOffset) - Math.ceil(totalWidth) - peakWidth)\n : wrapper.offsetWidth +\n (Math.ceil(scrollOffset) - Math.ceil(totalWidth) - peakWidth);\n return;\n }\n\n if (Math.abs(scrollOffset) === 0) {\n wrapper.style.scrollBehavior = 'auto';\n\n wrapper.scrollLeft = isRTL()\n ? -(totalWidth - wrapper.offsetWidth + peakWidth)\n : totalWidth - wrapper.offsetWidth + peakWidth;\n return;\n }\n }\n\n if (current !== nextSlideIndex) {\n setCurrent(nextSlideIndex);\n }\n }, 100);\n\n useEffect(() => {\n const wrapper = wrapperRef.current;\n wrapper?.addEventListener('scroll', handleOnScroll);\n\n return () => {\n wrapper?.removeEventListener('scroll', handleOnScroll);\n };\n }, [handleOnScroll]);\n\n // thumbnails is column -> container is row reverse, controls is column\n // thumbnails is row -> container is column, controls is row\n const getArrow = (\n forThumbnails: boolean,\n direction: string,\n callback: () => void\n ) => {\n return (\n <Button\n className={classes([\n ['pdp-carousel__button', !forThumbnails],\n [`pdp-carousel__button--${direction}`, !forThumbnails],\n [`pdp-carousel__button--${controls}`, forThumbnails],\n ])}\n style={{\n '--height': `${thumbHeight}px`,\n }}\n variant=\"tertiary\"\n aria-label={direction === 'next' ? NextLabel : PreviousLabel}\n onClick={callback}\n disabled={\n loop\n ? false\n : direction === 'next'\n ? current >= slides.length - 1\n : current < 1\n }\n >\n <Icon\n className={classes([\n ['pdp-carousel__button__icon', !forThumbnails],\n [`pdp-carousel__button__icon--${direction}`, !forThumbnails],\n [\n `pdp-carousel__button__icon--${controls}--${direction}`,\n forThumbnails,\n ],\n ])}\n size={ICON_SIZE}\n source={ChevronDown}\n />\n </Button>\n );\n };\n\n const prevArrow =\n arrows &&\n slides.length != 1 &&\n getArrow(thumbnailControls, 'prev', handleGoToPrev);\n\n const nextArrow =\n arrows &&\n slides.length != 1 &&\n getArrow(thumbnailControls, 'next', handleGoToNext);\n\n const prevArrowMainImage =\n arrows && slides.length != 1 && getArrow(false, 'prev', handleGoToPrev);\n\n const nextArrowMainImage =\n arrows && slides.length != 1 && getArrow(false, 'next', handleGoToNext);\n\n return (\n <div\n role=\"region\"\n aria-roledescription={Label}\n className={classes([\n 'pdp-carousel',\n ['pdp-carousel--main-image-controls', arrowsOnMainImage],\n ['pdp-carousel--arrows', arrows && !thumbnailControls],\n [`pdp-carousel--${controls}`, thumbnailControls],\n className,\n ])}\n style={{\n '--flex-carousel':\n controls === 'thumbnailsColumn' ? 'row-reverse' : 'column',\n '--gap': thumbnailControls ? '0' : 'var(--spacing-small)',\n '--width': width,\n }}\n {...props}\n >\n {/* Slideshow */}\n <div\n ref={wrapperRef}\n className={classes([\n 'pdp-carousel__wrapper',\n `pdp-carousel__wrapper--${direction}`,\n ['pdp-carousel__wrapper--scrollbar', scrollbar],\n ['pdp-carousel__wrapper--peak', peak],\n ])}\n style={{\n '--total-width': controls === 'thumbnailsColumn' ? `81.6%` : `100%`,\n '--height': controls === 'thumbnailsColumn' ? 'auto' : height,\n '--gap': gap ? `var(--spacing-${gap})` : '0px',\n '--per-page': perPage,\n }}\n tabIndex={0}\n >\n {slides.map((page, index) => {\n const orphan = page.length < perPage;\n\n return (\n <div\n key={index}\n role=\"group\"\n aria-roledescription={SlideLabel}\n data-index={index}\n className={classes([\n 'pdp-carousel__slide',\n `pdp-carousel__slide--${direction}`,\n ['pdp-carousel__slide--active', current === index],\n ['pdp-carousel__slide--orphan', orphan],\n ['pdp-carousel__slide--hidden', thumbWidth === 0],\n ])}\n style={{\n '--length': page.length,\n }}\n >\n {page}\n </div>\n );\n })}\n </div>\n\n {/* Previous and next arrows for Carousel without thumbnails */}\n {!thumbnailControls && (\n <>\n {prevArrow}\n {nextArrow}\n </>\n )}\n\n {thumbnailControls && arrowsOnMainImage && (\n <>\n {prevArrowMainImage}\n {nextArrowMainImage}\n </>\n )}\n\n {/* Controls */}\n {controls && slides.length != 1 && (\n <div\n className={classes([\n [\n `pdp-carousel__controls__container--${controls}`,\n thumbnailControls,\n ],\n [\n 'pdp-carousel__controls__container--no-arrows',\n !arrows || arrowsOnMainImage,\n ],\n ])}\n style={{\n '--width': controls === 'thumbnailsRow' ? `${thumbWidth}px` : width,\n '--height': `${thumbHeight}px`,\n '--nr-thumbnails': thumbnailSlides.length,\n }}\n >\n {(thumbnailControls || isZoomed) && !arrowsOnMainImage && prevArrow}\n\n <div\n ref={thumbnailsWrapperRef}\n className={classes([\n [\n `pdp-carousel__controls__wrapper--${controls}`,\n thumbnailControls,\n ],\n [`pdp-carousel__controls__wrapper`, thumbnailControls],\n ])}\n >\n <div\n role=\"group\"\n aria-label={ControlsLabel}\n className={classes([\n 'pdp-carousel__controls',\n [`pdp-carousel__controls--${controls}`, thumbnailControls],\n ])}\n >\n {(loop ? slides.slice(0, length) : slides).map((_, key) => {\n const buttonsLength = loop ? length : slides.length;\n const active = loop ? current - 1 === key : current === key;\n\n if (!thumbnailControls) {\n return (\n <button\n key={key}\n aria-label={ControlsBtnLabel.replace(\n '{key}',\n String(key + 1)\n ).replace('{total}', String(buttonsLength))}\n onClick={() => {\n handleScrollTo(loop ? key + 1 : key, true);\n }}\n className={classes([\n 'pdp-carousel__controls__button',\n ['pdp-carousel__controls__button--active', active],\n ])}\n />\n );\n }\n return (\n <label\n className={classes(['pdp-carousel__thumbnail__container'])}\n key={key}\n ref={(el: HTMLLabelElement | null) => {\n if (el) {\n thumbnailsRefs.current[key] = el;\n }\n }}\n >\n <input\n type=\"radio\"\n name={'carousel-thumbnails'}\n aria-label={ControlsBtnLabel.replace(\n '{key}',\n String(key + 1)\n ).replace('{total}', String(buttonsLength))}\n checked={active && thumbWidth !== 0}\n onChange={() => {\n handleScrollTo(loop ? key + 1 : key, true);\n }}\n {...props}\n className={classes([\n 'pdp-carousel__thumbnail',\n [\n 'pdp-carousel__thumbnail--selected',\n active && thumbWidth !== 0,\n ],\n ])}\n />\n\n <span\n className={classes(['pdp-carousel__thumbnail__span'])}\n >\n {thumbnailSlides[key]}\n </span>\n </label>\n );\n })}\n </div>\n </div>\n\n {(thumbnailControls || isZoomed) && !arrowsOnMainImage && nextArrow}\n </div>\n )}\n </div>\n );\n};\n\n// Utilities\nfunction getPerPageFromBreakpoint(\n breakpoints: { small: number; medium: number; large: number } | number,\n width = 0\n) {\n if (typeof breakpoints === 'number') return breakpoints;\n\n const { small, medium, large } = breakpoints;\n const breakpointsMap = [\n { breakpoint: 1024, value: large },\n { breakpoint: 786, value: medium },\n { breakpoint: 0, value: small },\n ];\n\n const matchingBreakpoint = breakpointsMap.find(\n ({ breakpoint }) => width > breakpoint\n );\n\n return matchingBreakpoint ? matchingBreakpoint.value : small;\n}\n\nfunction isRTL() {\n return document.documentElement.dir === 'rtl';\n}\n","/**\n * ADOBE CONFIDENTIAL\n * __________________\n * Copyright 2023 Adobe\n * All Rights Reserved.\n * __________________\n * NOTICE: All information contained herein is, and remains\n * the property of Adobe and its suppliers, if any. The intellectual\n * and technical concepts contained herein are proprietary to Adobe\n * and its suppliers and are protected by all applicable intellectual\n * property laws, including trade secret and copyright laws.\n * Dissemination of this information or reproduction of this material\n * is strictly forbidden unless prior written permission is obtained\n * from Adobe.\n */\n\nimport { FunctionComponent } from 'preact';\nimport { HTMLAttributes, useCallback, useEffect, useRef } from 'preact/compat';\nimport { classes } from '@adobe-commerce/elsie/lib';\nimport { useText } from '@adobe-commerce/elsie/i18n';\nimport { Close as CloseSVG } from '@adobe-commerce/elsie/icons';\nimport { Button } from '@adobe-commerce/elsie/components';\n\nimport '@/pdp/components/Overlay/Overlay.css';\n\nexport interface OverlayProps extends HTMLAttributes<HTMLDivElement> {\n centered?: boolean;\n onClose?: () => void;\n}\n\nexport const Overlay: FunctionComponent<OverlayProps> = ({\n centered,\n onClose,\n className,\n children,\n ...props\n}) => {\n // i18n\n const CloseLabel = useText('PDP.Overlay.Close.label').label;\n const overlayRef = useRef<HTMLInputElement>(null);\n const handleOnClose = useCallback(() => {\n onClose?.();\n }, [onClose]);\n\n // Close on ESC\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n handleOnClose();\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n };\n }, [handleOnClose]);\n\n // Prevent document scrolling\n useEffect(() => {\n const input = overlayRef.current;\n input?.focus();\n\n const scrollingElement = document.scrollingElement as HTMLElement;\n\n const defaultOverflowValue = scrollingElement.style.overflow;\n\n scrollingElement.style.overflow = 'hidden';\n\n return () => {\n scrollingElement.style.overflow = defaultOverflowValue;\n };\n }, []);\n\n return (\n <div\n {...props}\n className={classes([\n 'pdp-overlay',\n ['pdp-overlay--centered', centered],\n className,\n ])}\n ref={overlayRef}\n role=\"dialog\"\n aria-describedby=\"overlay-content\"\n tabindex={0}\n >\n <div className=\"pdp-overlay__content\" id=\"overlay-content\">\n {children}\n </div>\n <Button\n aria-label={CloseLabel}\n variant=\"tertiary\"\n className=\"pdp-overlay__close-button\"\n onClick={handleOnClose}\n icon={<CloseSVG />}\n />\n </div>\n );\n};\n","/**\n * ADOBE CONFIDENTIAL\n * __________________\n * Copyright 2024 Adobe\n * All Rights Reserved.\n * __________________\n * NOTICE: All information contained herein is, and remains\n * the property of Adobe and its suppliers, if any. The intellectual\n * and technical concepts contained herein are proprietary to Adobe\n * and its suppliers and are protected by all applicable intellectual\n * property laws, including trade secret and copyright laws.\n * Dissemination of this information or reproduction of this material\n * is strictly forbidden unless prior written permission is obtained\n * from Adobe.\n */\nimport { cloneElement, FunctionComponent, VNode } from 'preact';\nimport {\n Children,\n useEffect,\n useState,\n useRef,\n useCallback,\n} from 'preact/compat';\n\nimport '@/pdp/components/Zoom/Zoom.css';\nimport { Button } from '@adobe-commerce/elsie/components';\nimport { Close as CloseSVG } from '@adobe-commerce/elsie/icons';\nimport { useText } from '@adobe-commerce/elsie/i18n';\n\nexport interface ZoomProps {\n children: VNode[] | VNode;\n scale?: number;\n closeButton?: boolean;\n}\n\nexport const Zoom: FunctionComponent<ZoomProps> = ({\n children,\n scale = 2.0,\n closeButton = true,\n}) => {\n const [zoomed, setZoomed] = useState(false);\n const [figureClassName, setFigureClassName] = useState('pdp-zoom');\n const [drag, setDrag] = useState(false);\n const [dragStart, setDragStart] = useState({ x: 0, y: 0 });\n const [dragStartPosition, setDragStartPosition] = useState({ x: 0, y: 0 });\n const [position, setPosition] = useState({ x: 0, y: 0 });\n\n const containerRef = useRef<HTMLElement>(null);\n const cachedBoundsRef = useRef<DOMRect | null>(null);\n const animationFrameRef = useRef<number | null>(null);\n const lastTransformRef = useRef<string>('none');\n\n const touchStartRef = useRef<{ x: number; y: number; time: number } | null>(\n null\n );\n const isSwipingRef = useRef<boolean>(false);\n const lastValidTouchRef = useRef<{ clientX: number; clientY: number } | null>(\n null\n );\n\n const updatePosition = useCallback(\n (event: MouseEvent | TouchEvent) => {\n const updatePositionLogic = () => {\n let zoomer: DOMRect;\n\n if (cachedBoundsRef.current && containerRef.current) {\n zoomer = cachedBoundsRef.current;\n } else if (containerRef.current) {\n zoomer = containerRef.current.getBoundingClientRect();\n cachedBoundsRef.current = zoomer;\n } else {\n zoomer = (\n event.currentTarget as HTMLElement\n )?.getBoundingClientRect();\n }\n\n const overlap = (100 - 100 / scale) / 2;\n let coordinates: { clientX: number; clientY: number } | null = null;\n\n if ('touches' in event) {\n if (event.touches.length > 0) {\n coordinates = event.touches[0];\n lastValidTouchRef.current = {\n clientX: coordinates.clientX,\n clientY: coordinates.clientY,\n };\n } else if (event.type === 'touchend' && touchStartRef.current) {\n coordinates = {\n clientX: touchStartRef.current.x,\n clientY: touchStartRef.current.y,\n };\n } else if (lastValidTouchRef.current) {\n coordinates = lastValidTouchRef.current;\n } else {\n return;\n }\n } else if (event instanceof MouseEvent) {\n coordinates = event;\n } else {\n return;\n }\n\n const relativeX =\n ((coordinates.clientX - zoomer.left) / zoomer.width) * 100;\n const relativeY =\n ((coordinates.clientY - zoomer.top) / zoomer.height) * 100;\n\n const x = ((50 - relativeX) * (scale - 1)) / scale;\n const y = ((50 - relativeY) * (scale - 1)) / scale;\n\n setPosition({\n x: Math.max(-overlap, Math.min(x, overlap)) || 0,\n y: Math.max(-overlap, Math.min(y, overlap)) || 0,\n });\n };\n\n if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'test') {\n updatePositionLogic();\n } else {\n if (animationFrameRef.current) {\n cancelAnimationFrame(animationFrameRef.current);\n }\n animationFrameRef.current = requestAnimationFrame(updatePositionLogic);\n }\n },\n [scale]\n );\n\n useEffect(() => {\n cachedBoundsRef.current = null;\n }, [zoomed]);\n\n const startDrag = (event: TouchEvent) => {\n if (!zoomed || event.type !== 'touchstart') return;\n setDragStart({ x: event.touches[0].clientX, y: event.touches[0].clientY });\n setDragStartPosition({ x: position.x, y: position.y });\n setDrag(true);\n };\n\n const dragMove = (event: TouchEvent) => {\n if (!drag || event.type !== 'touchmove') return;\n const zoomer = (\n event.currentTarget as HTMLElement\n )?.getBoundingClientRect();\n const overlap = (100 - 100 / scale) / 2;\n const movedX = event.touches[0].clientX - dragStart.x;\n const movedY = event.touches[0].clientY - dragStart.y;\n const movedXPercent = (movedX * 100) / (zoomer.width * scale);\n const movedYPercent = (movedY * 100) / (zoomer.height * scale);\n const x = dragStartPosition.x + movedXPercent;\n const y = dragStartPosition.y + movedYPercent;\n setPosition({\n x: Math.max(-overlap, Math.min(x, overlap)) || 0,\n y: Math.max(-overlap, Math.min(y, overlap)) || 0,\n });\n event.preventDefault();\n };\n\n const handleTouchStart = (event: TouchEvent) => {\n if (closeButton) {\n touchStartRef.current = {\n x: event.touches[0].clientX,\n y: event.touches[0].clientY,\n time: Date.now(),\n };\n\n lastValidTouchRef.current = {\n clientX: event.touches[0].clientX,\n clientY: event.touches[0].clientY,\n };\n\n isSwipingRef.current = false;\n\n if (zoomed) {\n startDrag(event);\n }\n } else {\n if (drag) return;\n\n !zoomed && updatePosition(event);\n\n setZoomed(!zoomed);\n\n event.preventDefault();\n }\n };\n\n const handleTouchMove = (event: TouchEvent) => {\n if (event.touches.length === 0) return;\n\n lastValidTouchRef.current = {\n clientX: event.touches[0].clientX,\n clientY: event.touches[0].clientY,\n };\n\n if (closeButton) {\n if (!touchStartRef.current) return;\n\n if (drag) {\n dragMove(event);\n return;\n }\n\n const touchX = event.touches[0].clientX;\n const touchY = event.touches[0].clientY;\n const deltaX = Math.abs(touchX - touchStartRef.current.x);\n const deltaY = Math.abs(touchY - touchStartRef.current.y);\n\n if (deltaX > 10 || deltaY > 10) {\n isSwipingRef.current = true;\n }\n }\n\n if (zoomed) {\n updatePosition(event);\n }\n };\n\n const handleTouchEnd = (event: TouchEvent) => {\n if (closeButton) {\n if (!touchStartRef.current) return;\n\n const tapDuration = Date.now() - touchStartRef.current.time;\n\n if (!isSwipingRef.current && tapDuration < 300 && !drag) {\n setZoomed(true);\n updatePosition(event);\n event.preventDefault();\n }\n\n setDrag(false);\n touchStartRef.current = null;\n } else {\n setZoomed(false);\n }\n };\n\n const handleClick = (event: MouseEvent) => {\n if ('touches' in event) return;\n\n if (drag) return;\n\n if (zoomed) {\n !closeButton && setZoomed(false);\n } else {\n setZoomed(true);\n updatePosition(event);\n }\n event.preventDefault();\n };\n\n const handleMove = (event: MouseEvent) => {\n if ('touches' in event) return;\n\n if (zoomed) {\n updatePosition(event);\n }\n };\n\n const handleLeave = (event: MouseEvent) => {\n if ('touches' in event) return;\n\n if (closeButton) {\n setDrag(false);\n return;\n }\n setZoomed(false);\n };\n\n const closeButtonClick = (event: MouseEvent | TouchEvent) => {\n setZoomed(false);\n event.stopPropagation();\n };\n\n const transformStyle = zoomed\n ? `scale(${scale}) translateX(${position.x}%) translateY(${position.y}%)`\n : 'none';\n\n const CloseLabel = useText('PDP.Zoom.Close.label').label;\n const child = Children.only(children) as any;\n\n useEffect(() => {\n const handleGalleryChange = () => {\n if (zoomed) {\n setZoomed(false);\n setPosition({ x: 0, y: 0 });\n setDrag(false);\n }\n };\n\n const gallery = document.querySelector('#gallery');\n if (gallery) {\n gallery.addEventListener('click', handleGalleryChange);\n return () => gallery.removeEventListener('click', handleGalleryChange);\n }\n }, [zoomed]);\n\n const ImageClone = cloneElement(child, {\n ...child.props,\n draggable: false,\n style: {\n ...child.props?.style,\n '--transform': transformStyle,\n },\n });\n\n useEffect(() => {\n const className = zoomed\n ? `pdp-zoom ${closeButton ? 'pdp-zoom--no-effects' : 'pdp-zoom--zoomed'}`\n : 'pdp-zoom';\n setFigureClassName(className);\n }, [zoomed, closeButton]);\n\n useEffect(() => {\n if (lastTransformRef.current === transformStyle) return;\n lastTransformRef.current = transformStyle;\n\n const updateTransforms = () => {\n if (!containerRef.current) return;\n\n const images = containerRef.current.querySelectorAll('img');\n images.forEach((img) => {\n if (zoomed && transformStyle !== 'none') {\n img.style.setProperty('transform', transformStyle, 'important');\n } else {\n img.style.removeProperty('transform');\n }\n });\n };\n\n requestAnimationFrame(updateTransforms);\n }, [transformStyle, zoomed]);\n\n useEffect(() => {\n return () => {\n if (animationFrameRef.current) {\n cancelAnimationFrame(animationFrameRef.current);\n }\n };\n }, []);\n\n return (\n <figure\n ref={containerRef}\n className={figureClassName}\n onClick={handleClick}\n onMouseMove={handleMove}\n onMouseLeave={handleLeave}\n onTouchStart={handleTouchStart}\n onTouchMove={handleTouchMove}\n onTouchEnd={handleTouchEnd}\n >\n {ImageClone}\n {closeButton && zoomed && (\n <Button\n aria-label={CloseLabel}\n variant=\"tertiary\"\n className=\"pdp-zoom__close-button\"\n icon={<CloseSVG />}\n onClick={closeButtonClick}\n />\n )}\n </figure>\n );\n};\n"],"names":["SvgChevronDown","props","React","SvgClose","PEAK_WIDTH","THUMB_GAP","ICON_SIZE","GapSize","Carousel","show","scrollbar","peak","arrows","controls","arrowsOnMainImage","loop","gap","direction","width","height","defaultIndex","className","children","thumbnails","isZoomed","Label","useText","SlideLabel","PreviousLabel","NextLabel","ControlsLabel","ControlsBtnLabel","perPage","setPerPage","useState","getPerPageFromBreakpoint","length","Children","peakWidth","gapWidth","rest","current","setCurrent","isRTL","thumbnailsRefs","useRef","thumbWidth","setThumbWidth","thumbHeight","setThumbHeight","thumbnailSlides","useMemo","slides","returnValue","acc","child","i","wrapperRef","thumbnailsWrapperRef","thumbnailControls","useEffect","wrapper","handleResize","debounce","newPerPage","observer","handleThumbnailsScroll","useCallback","nextSlideIndex","nextItem","thumbnailRef","oneItemWidth","oneItemHeight","thumbnailsWrapper","isRow","isColumn","offset","oneItemSize","visibleThumbnails","centerOffset","targetScrollPosition","handleScrollTo","smooth","reset","realWidth","element","dataIndex","futureIndex","scrollWidth","diff","handleGoToPrev","handleGoToNext","lastSlideIndex","handleKeyDown","event","useLayoutEffect","handleOnScroll","dividing","totalWidth","scrollOffset","getArrow","forThumbnails","callback","jsx","Button","classes","Icon","ChevronDown","prevArrow","nextArrow","prevArrowMainImage","nextArrowMainImage","jsxs","page","index","orphan","Fragment","_","key","buttonsLength","active","el","breakpoints","small","medium","large","matchingBreakpoint","breakpoint","Overlay","centered","onClose","CloseLabel","overlayRef","handleOnClose","input","scrollingElement","defaultOverflowValue","CloseSVG","Zoom","scale","closeButton","zoomed","setZoomed","figureClassName","setFigureClassName","drag","setDrag","dragStart","setDragStart","dragStartPosition","setDragStartPosition","position","setPosition","containerRef","cachedBoundsRef","animationFrameRef","lastTransformRef","touchStartRef","isSwipingRef","lastValidTouchRef","updatePosition","updatePositionLogic","zoomer","_a","overlap","coordinates","relativeX","relativeY","x","y","startDrag","dragMove","movedX","movedY","movedXPercent","movedYPercent","handleTouchStart","handleTouchMove","touchX","touchY","deltaX","deltaY","handleTouchEnd","tapDuration","handleClick","handleMove","handleLeave","closeButtonClick","transformStyle","handleGalleryChange","gallery","ImageClone","cloneElement","img"],"mappings":"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","x_google_ignoreList":[0,1]}
|