@dropins/storefront-pdp 3.2.0-beta.0 → 3.2.0-beta.1
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/CHANGELOG.md +10 -5
- package/api.js +216 -3
- package/api.js.map +1 -1
- package/chunks/components.js +4 -0
- package/chunks/components.js.map +1 -0
- package/components/Swatches/Swatches.d.ts +3 -8
- package/containers/ProductAttributes.js +1 -1
- package/containers/ProductAttributes.js.map +1 -1
- package/containers/ProductDescription.js +1 -1
- package/containers/ProductDescription.js.map +1 -1
- package/containers/ProductDetails.js +1 -1
- package/containers/ProductDetails.js.map +1 -1
- package/containers/ProductDownloadableOptions.js +1 -1
- package/containers/ProductDownloadableOptions.js.map +1 -1
- package/containers/ProductGallery.js +1 -1
- package/containers/ProductGallery.js.map +1 -1
- package/containers/ProductGiftCardOptions.js +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 +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 +1 -1
- package/containers/ProductQuantity.js.map +1 -1
- package/containers/ProductShortDescription.js +1 -1
- package/containers/ProductShortDescription.js.map +1 -1
- package/fragments.js +1 -171
- package/fragments.js.map +1 -1
- package/lib/product-option-selection.d.ts +27 -0
- package/package.json +2 -2
- package/render.js +3 -5
- package/render.js.map +1 -1
- package/chunks/DownloadableOptions2.js +0 -4
- package/chunks/DownloadableOptions2.js.map +0 -1
- package/chunks/GiftCardOptions2.js +0 -4
- package/chunks/GiftCardOptions2.js.map +0 -1
- package/chunks/PriceRange.js +0 -4
- package/chunks/PriceRange.js.map +0 -1
- package/chunks/Swatches.js +0 -4
- package/chunks/Swatches.js.map +0 -1
- package/chunks/Zoom.js +0 -4
- package/chunks/Zoom.js.map +0 -1
- package/chunks/fetchProductData.js +0 -47
- package/chunks/fetchProductData.js.map +0 -1
- package/chunks/getFetchedProductData.js +0 -4
- package/chunks/getFetchedProductData.js.map +0 -1
- package/chunks/getProductConfigurationValues.js +0 -4
- package/chunks/getProductConfigurationValues.js.map +0 -1
- package/chunks/isProductConfigurationValid.js +0 -4
- package/chunks/isProductConfigurationValid.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProductDetails.js","sources":["/@dropins/storefront-pdp/src/components/Product/Product.tsx","/@dropins/storefront-pdp/src/components/GalleryGrid/GalleryGrid.tsx","/@dropins/storefront-pdp/src/containers/ProductDetails/ProductDetails.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 { HTMLAttributes, useState } from 'preact/compat';\nimport { classes, VComponent } from '@adobe-commerce/elsie/lib';\nimport { useText } from '@adobe-commerce/elsie/i18n';\n\nimport { Carousel, GalleryGrid, Overlay, Zoom } from '@/pdp/components';\nimport '@/pdp/components/Product/Product.css';\n\nimport { CarouselConfig } from '@/pdp/containers';\n\ninterface ProductCarouselConfig extends CarouselConfig {\n thumbnails: VNode[];\n}\n\nexport interface ProductProps\n extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n title?: VNode;\n breadcrumbs?: VNode;\n galleryContent?: VNode;\n infoContent?: VNode;\n productContent?: VNode;\n shortDescription?: VNode;\n description?: VNode;\n attributes?: VNode;\n images: VNode[];\n options?: VNode;\n giftCardOptions?: VNode;\n downloadableOptions?: VNode;\n sku?: VNode;\n price?: VNode;\n specialPrice?: VNode;\n outOfStock: boolean;\n actions?: VNode;\n quantity?: VNode;\n carouselConfig?: ProductCarouselConfig;\n zoomType?: 'zoom' | 'overlay';\n closeButton?: boolean;\n}\n\nexport const Product: FunctionComponent<ProductProps> = ({\n title,\n breadcrumbs,\n galleryContent,\n infoContent,\n productContent,\n sku,\n outOfStock,\n shortDescription,\n description,\n attributes,\n images,\n options,\n giftCardOptions,\n downloadableOptions,\n price,\n specialPrice,\n className,\n children,\n quantity,\n actions,\n carouselConfig,\n zoomType = 'overlay',\n closeButton = true,\n ...props\n}) => {\n // i18n\n const RegularPriceLabel = useText('PDP.Product.RegularPrice.label').label;\n const SpecialPriceLabel = useText('PDP.Product.SpecialPrice.label').label;\n const OutOfStockLabel = useText('PDP.Product.OutOfStock.label').label;\n const ImagesLabel = useText('PDP.Product.Image.label').label;\n\n const [zoom, setZoom] = useState<number | null>(null);\n\n const galleryImages = images?.length ? (\n images.map((image, key) => {\n const alt =\n title?.props?.children &&\n ImagesLabel?.replace('{product}', title.props.children.toString())\n .replace('{key}', String(key + 1))\n .replace('{total}', String(images.length));\n return zoomType === 'zoom' ? (\n <Zoom closeButton={closeButton}>\n <VComponent\n key={key}\n node={image}\n loading={key === 0 ? 'eager' : 'lazy'}\n alt={alt}\n />\n </Zoom>\n ) : (\n <VComponent\n key={key}\n node={image}\n loading={key === 0 ? 'eager' : 'lazy'}\n alt={alt}\n onClick={() => setZoom(key)}\n />\n );\n })\n ) : (\n <img\n src=\"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\"\n className=\"pdp-product__images__placeholder\"\n aria-hidden\n />\n );\n\n const localThumbnailsImages = carouselConfig?.thumbnails?.length ? (\n carouselConfig.thumbnails.map((image, key) => (\n <VComponent\n key={key}\n node={image}\n loading={carouselConfig?.thumbnailsLoadingMode || 'lazy'}\n alt={\n title?.props?.children &&\n ImagesLabel?.replace('{product}', title.props.children.toString())\n .replace('{key}', String(key + 1))\n .replace('{total}', String(images.length))\n }\n />\n ))\n ) : (\n <img\n src=\"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\"\n className=\"pdp-product__images__placeholder\"\n aria-hidden\n />\n );\n\n return (\n <div {...props} className={classes(['pdp-product', className])}>\n {breadcrumbs && (\n <VComponent node={breadcrumbs} className=\"pdp-product__breadcrumbs\" />\n )}\n <div className=\"pdp-product__column-container pdp-product__gallery-column\">\n <div className=\"pdp-product__column-body\">\n {carouselConfig?.controls?.desktop ? (\n <Carousel\n className=\"pdp-product__overlay__carousel\"\n arrows={images?.length > 1}\n controls={\n images?.length > 1 ? carouselConfig.controls.desktop : 'dots'\n }\n arrowsOnMainImage={carouselConfig?.arrowsOnMainImage}\n loop={carouselConfig?.loopable && images?.length > 1}\n peak={\n (carouselConfig?.thumbnails?.length > 1 &&\n carouselConfig?.peak?.desktop) ||\n false\n }\n gap={carouselConfig?.gap || null}\n width=\"100%\"\n height=\"100%\"\n defaultIndex={zoom || 0}\n thumbnails={localThumbnailsImages}\n >\n {galleryImages}\n </Carousel>\n ) : (\n <GalleryGrid className=\"pdp-product__images\" gap=\"small\">\n {galleryImages}\n </GalleryGrid>\n )}\n </div>\n {galleryContent && (\n <VComponent\n node={galleryContent}\n className=\"pdp-product__gallery-content\"\n />\n )}\n </div>\n\n <div className=\"pdp-product__column-container pdp-product__content-column\">\n <div className=\"pdp-product__column-body\">\n <div className=\"pdp-product__header\">\n {title && (\n <VComponent node={title} className=\"pdp-product__title\" />\n )}\n\n {sku && <VComponent node={sku} className=\"pdp-product__sku\" />}\n </div>\n\n <div className=\"pdp-product__prices\">\n {specialPrice && (\n <VComponent\n node={specialPrice}\n className={classes([\n 'pdp-product__price-special',\n 'pdp-product__price',\n ])}\n aria-label={SpecialPriceLabel}\n role=\"text\"\n />\n )}\n {price && (\n <VComponent\n node={price}\n className={classes([\n 'pdp-product__price-regular',\n 'pdp-product__price--grey',\n ])}\n aria-label={RegularPriceLabel}\n role=\"text\"\n />\n )}\n </div>\n\n {/* Small Screen Gallery */}\n {carouselConfig?.controls?.mobile &&\n carouselConfig?.controls?.mobile === 'thumbnailsRow' ? (\n <Carousel\n className=\"pdp-product__images pdp-product__images--carousel pdp-product__images--carousel--thumbnails\"\n width=\"100%\"\n height=\"auto\"\n arrows={images?.length > 1}\n controls={images?.length > 1 ? 'thumbnailsRow' : null}\n loop={carouselConfig?.loopable && images?.length > 1}\n peak={\n (carouselConfig?.thumbnails?.length > 1 &&\n carouselConfig?.peak?.mobile) ||\n false\n }\n gap={carouselConfig?.gap || null}\n thumbnails={localThumbnailsImages}\n >\n {galleryImages}\n </Carousel>\n ) : (\n <Carousel\n className=\"pdp-product__images pdp-product__images--carousel\"\n peak={carouselConfig?.peak?.mobile && images?.length > 1}\n gap={carouselConfig?.gap || null}\n width=\"100%\"\n height=\"auto\"\n arrows={images?.length > 1}\n controls={images?.length > 1 ? 'dots' : null}\n loop={carouselConfig?.loopable && images?.length > 1}\n >\n {galleryImages}\n </Carousel>\n )}\n\n <div\n className={classes([\n 'pdp-product__actions',\n [`pdp-product__actions--out-of-stock`, outOfStock],\n ])}\n >\n {outOfStock && (\n <div className=\"pdp-product__out-of-stock__text\">\n {OutOfStockLabel}\n </div>\n )}\n\n {options && (\n <VComponent\n node={options}\n className={classes(['pdp-product__options'])}\n />\n )}\n\n {giftCardOptions && (\n <VComponent\n node={giftCardOptions}\n className={classes(['pdp-product__gift-card-options'])}\n />\n )}\n\n {downloadableOptions && (\n <VComponent\n node={downloadableOptions}\n className={classes(['pdp-product__downloadable-options'])}\n />\n )}\n\n {quantity && (\n <div className=\"pdp-product__quantity\">\n <VComponent node={quantity} />\n </div>\n )}\n\n {actions && (\n <VComponent\n node={actions}\n className={classes(['pdp-product__buttons'])}\n />\n )}\n </div>\n\n {shortDescription && (\n <VComponent\n node={shortDescription}\n className={classes(['pdp-product__short_description'])}\n />\n )}\n\n {description && (\n <VComponent\n node={description}\n className={classes(['pdp-product__description'])}\n />\n )}\n\n {attributes ? (\n <div className=\"pdp-product__attributes\">{attributes}</div>\n ) : null}\n </div>\n {infoContent && (\n <VComponent\n node={infoContent}\n className=\"pdp-product__info-content\"\n />\n )}\n </div>\n\n {productContent && (\n <VComponent node={productContent} className=\"pdp-product__content\" />\n )}\n\n {/* Zoom Overlay */}\n {zoom === null ? null : (\n <Overlay\n className=\"pdp-product__overlay\"\n onClose={() => setZoom(null)}\n centered\n >\n <Carousel\n className=\"pdp-product__overlay__carousel\"\n arrows={images?.length > 1}\n width=\"100%\"\n height=\"100%\"\n defaultIndex={zoom || 0}\n loop={carouselConfig?.loopable && images?.length > 1}\n controls={images?.length > 1 ? 'dots' : null}\n isZoomed\n >\n {galleryImages}\n </Carousel>\n </Overlay>\n )}\n </div>\n );\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, VNode } from 'preact';\nimport { HTMLAttributes, Children } from 'preact/compat';\nimport { classes, VComponent } from '@adobe-commerce/elsie/lib';\nimport '@/pdp/components/GalleryGrid/GalleryGrid.css';\n\nexport interface GalleryGridProps extends HTMLAttributes<HTMLDivElement> {\n children: VNode[] | VNode;\n gap?: 'small' | 'medium' | 'large' | null;\n style?: Record<string, string | number>;\n}\n\nexport const GalleryGrid: FunctionComponent<GalleryGridProps> = ({\n children,\n gap = null,\n className,\n style,\n ...props\n}) => {\n const count = Children.count(children);\n\n return (\n <div\n {...props}\n className={classes(['pdp-gallery-grid', className])}\n style={{\n '--gap': gap ? `var(--spacing-${gap})` : '0px',\n ...style,\n }}\n >\n {Children.map(\n children,\n (child: VNode<HTMLAttributes<HTMLElement>>, key) => (\n <div key={count + key} className=\"pdp-gallery-grid__item\">\n <VComponent\n key={child.props.src}\n node={child}\n loading={key === 0 ? 'eager' : 'lazy'}\n />\n </div>\n )\n )}\n </div>\n );\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 {\n HTMLAttributes,\n useEffect,\n useState,\n useCallback,\n useMemo,\n} from 'preact/compat';\n\nimport {\n Container,\n toLanguageTag,\n SlotProps,\n SlotMethod,\n Slot,\n ResolveImageUrlOptions,\n} from '@adobe-commerce/elsie/lib';\n\nimport {\n Button,\n Icon,\n ButtonProps,\n Image,\n Incrementer,\n Breadcrumbs,\n} from '@adobe-commerce/elsie/components';\nimport {\n Product,\n Swatches,\n PriceRange,\n Option,\n GiftCardOptions,\n DownloadableOptions,\n} from '@/pdp/components';\nimport { config, fetchProductData } from '@/pdp/api';\nimport { events } from '@adobe-commerce/event-bus';\nimport { Lang, useText } from '@adobe-commerce/elsie/i18n';\nimport { isDateValid, toDateString } from '@/pdp/lib/date';\nimport {\n setUrlParams,\n getValidatedQuantityFromUrl,\n} from '@/pdp/lib/url-params';\nimport { publishProductPageViewEvent } from '@/pdp/lib/acdl';\nimport { ProductModel, Option as ProductOption } from '@/pdp/data/models';\nimport { transformProductData } from '@/pdp/data/transforms/product-transform';\n\ntype IconType = keyof typeof import('@adobe-commerce/elsie/icons');\n\n/** @deprecated This type is part of the deprecated ProductDetails component. */\nexport type Values = {\n sku: string;\n quantity: number;\n optionsUIDs?: string[];\n enteredOptions?: Array<{ uid: string; value: string }>;\n};\n\n/** @deprecated This type is part of the deprecated ProductDetails component. */\ntype DefaultSlotContext = {\n data: ProductModel | null;\n values: Values;\n valid: boolean;\n};\n\n/** @deprecated This type is part of the deprecated ProductDetails component. */\nexport type CarouselConfig = {\n controls?: {\n desktop?: 'thumbnailsRow' | 'thumbnailsColumn' | 'dots' | null;\n mobile?: 'dots' | 'thumbnailsRow' | null;\n };\n arrowsOnMainImage?: boolean;\n loopable?: boolean;\n peak?: {\n desktop: boolean;\n mobile: boolean;\n };\n gap?: 'small' | 'medium' | 'large' | null;\n thumbnailsLoadingMode?: 'lazy' | 'eager';\n imageParams?: ResolveImageUrlOptions;\n thumbnailParams?: ResolveImageUrlOptions;\n};\n\n/** @deprecated This type is part of the deprecated ProductDetails component. */\nexport type OptionsConfig = {\n anchorOptions?: string[];\n};\n\n/** @deprecated This interface is part of the deprecated ProductDetails component. */\nexport interface ProductDetailsProps extends HTMLAttributes<HTMLDivElement> {\n sku: string;\n productData?: ProductModel;\n hideSku?: boolean;\n hideQuantity?: boolean;\n hideShortDescription?: boolean;\n hideDescription?: boolean;\n hideAttributes?: boolean;\n hideSelectedOptionValue?: boolean;\n hideURLParams?: boolean;\n slots?: {\n Title?: SlotProps<DefaultSlotContext>;\n\n SKU?: SlotProps<DefaultSlotContext>;\n\n RegularPrice?: SlotProps<DefaultSlotContext>;\n\n SpecialPrice?: SlotProps<DefaultSlotContext>;\n\n Options?: SlotProps<DefaultSlotContext>;\n\n Quantity?: SlotProps<DefaultSlotContext>;\n\n Actions?: SlotProps<\n DefaultSlotContext & {\n appendButton: SlotMethod<\n Omit<ButtonProps, 'icon'> & {\n text?: string;\n icon?: IconType;\n }\n >;\n }\n >;\n\n ShortDescription?: SlotProps<DefaultSlotContext>;\n\n Description?: SlotProps<DefaultSlotContext>;\n\n Attributes?: SlotProps<DefaultSlotContext>;\n\n Breadcrumbs?: SlotProps<\n DefaultSlotContext & {\n setSeparator: SlotMethod<IconType>;\n\n appendLink: SlotMethod<\n HTMLAttributes<HTMLAnchorElement> & { text?: string }\n >;\n\n appendHTMLElement: SlotMethod<HTMLElement>;\n }\n >;\n\n GalleryContent?: SlotProps<DefaultSlotContext>;\n\n InfoContent?: SlotProps<DefaultSlotContext>;\n\n Content?: SlotProps<DefaultSlotContext>;\n };\n carousel?: CarouselConfig;\n optionsConfig?: OptionsConfig;\n useACDL?: boolean;\n onAddToCart?: (values: Values) => void;\n zoomType?: 'zoom' | 'overlay';\n closeButton?: boolean;\n disableDropdownPreselection?: boolean;\n}\n\n/**\n * @deprecated This container has been deprecated and will be removed in a future release.\n * Please use the different composable containers to build your product details page.xs\n */\nexport const ProductDetails: Container<\n ProductDetailsProps,\n ProductModel | null\n> = ({\n sku,\n hideSku,\n hideQuantity,\n hideShortDescription,\n hideDescription,\n hideAttributes,\n hideURLParams,\n hideSelectedOptionValue,\n slots,\n children,\n initialData,\n carousel,\n optionsConfig,\n useACDL,\n onAddToCart,\n zoomType,\n closeButton = true,\n disableDropdownPreselection,\n ...props\n}) => {\n // i18n\n const AddToCartLabel = useText('PDP.Product.AddToCart.label').label;\n const IncrementerLabel = useText('PDP.Product.Incrementer.label').label;\n const DetailsLabel = useText('PDP.Product.Details.label').label;\n const ChooseOptionLabel = useText('PDP.Swatches.ChooseOption.label').label;\n\n // TODO: Investigate if the \"|| 'en-US' \" is really necessary\n const [locale, setLocale] = useState<Lang>(\n (config.getConfig().defaultLocale as Lang) || 'en-US'\n );\n\n const [selectionsToUpdate, setSelectionsToUpdate] = useState<Option[]>();\n\n const [data = null, setData] = useState(initialData);\n\n const [values, setValues] = useState<Values>(() => {\n const initialQuantity = getValidatedQuantityFromUrl(1); // Default quantity to 1\n\n const defaultValues: Values = {\n sku,\n quantity: initialQuantity,\n };\n\n if (data?.optionUIDs) {\n defaultValues.optionsUIDs = data.optionUIDs;\n }\n return defaultValues;\n });\n\n // the context is invalid for a configurable product that doesn't have all the options selected\n const [valid, setValid] = useState(() => {\n return !(\n data?.options &&\n data?.options?.length > 0 &&\n data?.optionUIDs?.length !== data?.options.length\n );\n });\n const defaultSlotContext: DefaultSlotContext = { data, values, valid };\n\n function hasProductViewOptionValueProduct(options: ProductOption[]) {\n return options?.some(\n (option) => option?.typename === 'ProductViewOptionValueProduct'\n );\n }\n\n useEffect(() => {\n const dataEvent = events.on('pdp/data', (payload) => {\n if (payload) {\n setData(payload);\n // Preserve the current quantity value when updating from pdp/data event\n setValues((prev: Values) => ({\n ...prev,\n sku: payload.sku,\n optionsUIDs: payload.optionUIDs,\n }));\n }\n });\n\n // @ts-ignore - Type error with event bus events\n const updateDataEvent = events.on(\n 'pdp/setValues',\n (payload: Partial<Values>) => {\n setValues((prev: Values) => ({ ...prev, ...payload }));\n }\n );\n\n return () => {\n updateDataEvent?.off();\n dataEvent?.off();\n };\n }, []);\n\n // Locale\n useEffect(() => {\n const localeEvent = events.on('locale', (payload: string) => {\n if (payload === locale) return;\n\n setLocale(payload as Lang);\n\n fetchProductData(sku, {\n preselectFirstOption: !disableDropdownPreselection,\n anchors: optionsConfig?.anchorOptions,\n }).then(setData);\n });\n return () => {\n localeEvent?.off();\n };\n }, [disableDropdownPreselection, locale, optionsConfig?.anchorOptions, sku]);\n\n useEffect(() => {\n if (useACDL && initialData && Object.keys(initialData).length > 0) {\n publishProductPageViewEvent(initialData);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [initialData]);\n\n // Callbacks\n const handleOnValues = useCallback((newValues: Partial<Values>) => {\n setValues((prev) => ({ ...prev, ...newValues }));\n }, []);\n\n useEffect(() => {\n events.emit('pdp/values', values);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [JSON.stringify(values)]);\n\n const handleOptionSelected = useCallback(\n async (selections: { [id: string]: { label: string; value: string } }) => {\n // options Selected\n let optionsUIDs = Object.entries(selections)\n .filter(([_, value]) => value.label !== ChooseOptionLabel) // eslint-disable-line no-unused-vars\n .map(([id, _]) => selections[id].value) // eslint-disable-line no-unused-vars\n .filter((element) => element !== undefined);\n\n // set optionUIDs to URL params\n // ?optionsUIDs=1,2,3\n // only set the URL params if the hideURLParams is not set to true and the product is not a bundle type\n if (\n !hideURLParams &&\n data?.options &&\n !hasProductViewOptionValueProduct(data.options)\n ) {\n setUrlParams({ optionsUIDs: optionsUIDs.join(',') });\n }\n\n // update state\n handleOnValues({ optionsUIDs });\n setValid(optionsUIDs?.length === data?.options?.length);\n\n // get refined product data and update state\n const next = await fetchProductData(sku, {\n anchors: optionsConfig?.anchorOptions,\n isBundle: data?.isBundle,\n optionsUIDs,\n preselectFirstOption: !disableDropdownPreselection,\n });\n\n setData(next);\n\n // special processing for anchor options (options that should not be refined when other options are selected)\n if (optionsConfig?.anchorOptions?.length) {\n processUpdates(next, optionsUIDs);\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [sku]\n );\n\n const processUpdates = useCallback(\n (next: ProductModel | null, previousOptionsUIDs: string[]) => {\n const updatedOptionsUIDs = next?.optionUIDs ?? [];\n const haveSameValues = previousOptionsUIDs.every((item) =>\n updatedOptionsUIDs.includes(item)\n );\n if (!haveSameValues) {\n setSelectionsToUpdate(next?.options);\n handleOnValues({ optionsUIDs: updatedOptionsUIDs });\n setValid(updatedOptionsUIDs?.length === next?.options?.length);\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [sku]\n );\n\n const handleOnErrors = useCallback((_errors: { [id: string]: string }) => {\n if (Object.keys(_errors).length !== 0) setValid(false);\n }, []);\n\n // Product Attributes\n const attributes = useMemo(() => {\n return data?.attributes?.map(({ label, value, id }, key: number) => {\n // Return empty string for gift card attributes\n if (id === 'ac_giftcard') {\n return '';\n }\n\n const __html = isDateValid(value)\n ? toDateString(value, locale)\n : value.toString();\n\n return (\n <li key={key}>\n {/* eslint-disable-next-line react/no-danger */}\n {label}: <span dangerouslySetInnerHTML={{ __html }} />\n </li>\n );\n });\n }, [data?.attributes, locale]);\n\n const quantity =\n !hideQuantity && data?.inStock ? (\n <Slot\n name=\"Quantity\"\n slot={slots?.Quantity}\n context={{ ...defaultSlotContext }}\n >\n <Incrementer\n key=\"quantity\"\n name=\"quantity\"\n defaultValue={values.quantity.toString()}\n value={values.quantity.toString()}\n min={1}\n aria-label={IncrementerLabel}\n className=\"pdp-product__quantity\"\n onValue={(quantity) => {\n const quantityValue = Number(quantity);\n handleOnValues({ quantity: quantityValue });\n\n // Add quantity to URL parameters if not set to hide\n if (!hideURLParams && data?.options) {\n // Only update URL if the product is not a bundle type\n if (!hasProductViewOptionValueProduct(data.options)) {\n setUrlParams({ quantity: quantityValue });\n }\n }\n }}\n />\n </Slot>\n ) : undefined;\n\n const renderOptions = () => {\n if (data?.options) {\n return (\n <Slot\n name=\"Options\"\n slot={slots?.Options}\n context={{ ...defaultSlotContext }}\n >\n <Swatches\n selectedUIDs={values.optionsUIDs}\n options={data.options}\n defaultOptions={values.optionsUIDs}\n selectionsToUpdate={selectionsToUpdate}\n hideSelectedValue={hideSelectedOptionValue}\n disablePreselections={disableDropdownPreselection}\n onValues={handleOptionSelected}\n onErrors={handleOnErrors}\n />\n </Slot>\n );\n }\n };\n\n const renderGiftCardOptions = () => {\n if (data?.attributes) {\n const giftCardAttributes = data.attributes.filter(\n (attr) => attr.id === 'ac_giftcard'\n );\n\n if (giftCardAttributes.length > 0) {\n const giftCardElements = giftCardAttributes.map(\n (giftCardAttr, index) => {\n try {\n const giftCardData = JSON.parse(giftCardAttr.value);\n const prevOptions = values.enteredOptions || [];\n const optionValues =\n giftCardData.options?.map((option: any) => {\n const existingOption = prevOptions.find(\n (opt: { uid: string; value: string }) =>\n opt.uid === option.uid\n );\n return {\n id: option.uid,\n value: existingOption?.value || '',\n };\n }) || [];\n\n return (\n <GiftCardOptions\n key={`giftcard-${index}`}\n options={giftCardData.options || []}\n optionValues={optionValues}\n onOptionChange={(uid: string, value: string) => {\n const prevOptions = values.enteredOptions || [];\n const idx = prevOptions.findIndex(\n (field: { uid: string; value: string }) =>\n field.uid === uid\n );\n let newEnteredOptions;\n if (idx !== -1) {\n newEnteredOptions = prevOptions.map(\n (field: { uid: string; value: string }) =>\n field.uid === uid ? { ...field, value } : field\n );\n } else {\n newEnteredOptions = [...prevOptions, { uid, value }];\n }\n\n handleOnValues({ enteredOptions: newEnteredOptions });\n\n if (data) {\n const updatedData = { ...data };\n const giftCardAttributes =\n updatedData.attributes?.map((attr) => {\n if (attr.id === 'ac_giftcard') {\n try {\n const giftCardData = JSON.parse(attr.value);\n const updatedOptions =\n giftCardData.options?.map((option: any) => {\n if (option.uid === uid) {\n return { ...option, value };\n }\n return option;\n }) || [];\n return {\n ...attr,\n value: JSON.stringify({\n ...giftCardData,\n options: updatedOptions,\n }),\n };\n } catch (error) {\n return attr;\n }\n }\n return attr;\n }) || [];\n updatedData.attributes = giftCardAttributes;\n setData(updatedData);\n }\n }}\n onValidationChange={(valid: boolean) => {\n if (!valid) {\n handleOnErrors({ giftCard: 'Invalid gift card data' });\n }\n\n setValid(valid);\n }}\n className=\"pdp-product__gift-card-options\"\n />\n );\n } catch (error) {\n console.warn('Invalid gift card data format:', error);\n return null;\n }\n }\n );\n\n // Filter out null values and return a single element\n const validElements = giftCardElements.filter(\n (element) => element !== null\n );\n return validElements.length > 0 ? (\n <div className=\"pdp-product__gift-card-options-container\">\n {validElements}\n </div>\n ) : undefined;\n }\n }\n return undefined;\n };\n\n const renderDownloadableOptions = () => {\n if (data?.attributes) {\n const downloadableAttributes = data.attributes.filter(\n (attr) =>\n attr.id === 'ac_downloadable' &&\n attr.roles?.includes('visible_in_pdp')\n );\n\n if (downloadableAttributes.length > 0) {\n const downloadableElements = downloadableAttributes.map(\n (downloadableAttr, index) => {\n try {\n const downloadableValue =\n typeof downloadableAttr.value === 'string'\n ? JSON.parse(downloadableAttr.value)\n : downloadableAttr.value;\n\n return (\n <DownloadableOptions\n key={`downloadable-${index}`}\n label={downloadableAttr.label}\n value={downloadableValue}\n onLinkChange={(uid: string, selected: boolean) => {\n const prevUIDs = values.optionsUIDs || [];\n let newOptionsUIDs;\n\n if (selected) {\n if (!prevUIDs.includes(uid)) {\n newOptionsUIDs = [...prevUIDs, uid];\n } else {\n newOptionsUIDs = prevUIDs;\n }\n } else {\n newOptionsUIDs = prevUIDs.filter(\n (id: string) => id !== uid\n );\n }\n\n handleOnValues({ optionsUIDs: newOptionsUIDs });\n }}\n currency={data.prices?.final?.currency}\n className=\"pdp-product__downloadable-options\"\n />\n );\n } catch (error) {\n console.warn('Invalid downloadable data format:', error);\n return null;\n }\n }\n );\n\n // Filter out null values and return a wrapper div\n const validElements = downloadableElements.filter(\n (element) => element !== null\n );\n return validElements.length > 0 ? (\n <div className=\"pdp-product__downloadable-options-container\">\n {validElements}\n </div>\n ) : undefined;\n }\n }\n return undefined;\n };\n\n return (\n <div {...props}>\n <Product\n title={\n <Slot\n name=\"Title\"\n slot={slots?.Title}\n context={{ ...defaultSlotContext }}\n >\n {data?.name}\n </Slot>\n }\n sku={\n !hideSku ? (\n <Slot\n name=\"SKU\"\n slot={slots?.SKU}\n context={{ ...defaultSlotContext }}\n >\n {data?.sku}\n </Slot>\n ) : undefined\n }\n options={renderOptions()}\n giftCardOptions={renderGiftCardOptions()}\n downloadableOptions={renderDownloadableOptions()}\n breadcrumbs={\n slots?.Breadcrumbs && (\n <Slot\n name=\"Breadcrumbs\"\n slot={slots?.Breadcrumbs}\n context={{\n ...defaultSlotContext,\n\n setSeparator(callback) {\n this._registerMethod((...attrs) => {\n const nextSeparator = callback(...attrs);\n\n const separator = nextSeparator && (\n <Icon source={nextSeparator} />\n );\n\n this._setProps((prev: any) => {\n return {\n ...prev,\n separator,\n children: [\n // eslint-disable-next-line react/jsx-key\n <Breadcrumbs\n separator={separator}\n categories={prev.categories}\n />,\n ],\n };\n });\n });\n },\n\n appendLink(callback) {\n this._registerMethod((...attrs) => {\n const { text, ...p } = callback(...attrs);\n\n const link = <a {...p}>{text}</a>;\n\n this._setProps((prev: any) => {\n const categories = [...(prev.categories || []), link];\n return {\n ...prev,\n categories,\n children: [\n // eslint-disable-next-line react/jsx-key\n <Breadcrumbs\n separator={prev.separator}\n categories={categories}\n />,\n ],\n };\n });\n });\n },\n\n appendHTMLElement(callback) {\n this._registerMethod((...attrs) => {\n const domElement = callback(...attrs);\n\n const vnode = this._htmlElementToVNode(domElement);\n\n this._setProps((prev: any) => {\n const categories = [...(prev.categories || []), vnode];\n\n return {\n ...prev,\n categories,\n children: [\n // eslint-disable-next-line react/jsx-key\n <Breadcrumbs\n separator={prev.separator}\n categories={categories}\n />,\n ],\n };\n });\n });\n },\n }}\n />\n )\n }\n quantity={quantity}\n actions={\n <Slot\n name=\"Actions\"\n slot={slots?.Actions}\n context={{\n ...defaultSlotContext,\n\n appendButton(callback) {\n this._registerMethod((...attrs) => {\n const _button = callback(...attrs);\n\n if (!_button) return;\n\n const { text, icon, ...buttonProps } = _button;\n\n const button = (\n <Button\n type=\"button\"\n {...buttonProps}\n icon={icon && <Icon source={icon} />}\n >\n {text}\n </Button>\n );\n\n this._setProps((prev: any) => ({\n children: [...(prev.children || []), button],\n }));\n });\n },\n }}\n >\n {\n // Default Add to Cart button if no slot is provided\n !slots?.Actions && (\n <Button\n size=\"medium\"\n type=\"submit\"\n icon={<Icon source=\"Cart\" />}\n disabled={!data?.inStock || !valid}\n aria-label={AddToCartLabel}\n onClick={() => {\n return onAddToCart?.(values);\n }}\n >\n {AddToCartLabel}\n </Button>\n )\n }\n </Slot>\n }\n shortDescription={\n !hideShortDescription ? (\n <Slot\n name=\"ShortDescription\"\n slot={slots?.ShortDescription}\n context={{ ...defaultSlotContext }}\n >\n <div\n // eslint-disable-next-line react/no-danger\n dangerouslySetInnerHTML={{\n __html: data?.shortDescription ?? '',\n }}\n />\n </Slot>\n ) : undefined\n }\n description={\n !hideDescription ? (\n <Slot\n name=\"Description\"\n slot={slots?.Description}\n context={{ ...defaultSlotContext }}\n >\n <div\n // eslint-disable-next-line react/no-danger\n dangerouslySetInnerHTML={{ __html: data?.description ?? '' }}\n />\n </Slot>\n ) : undefined\n }\n images={\n data?.images?.map(({ label, url }) => (\n <Image\n key={url}\n title={label}\n alt={label}\n src={url}\n // TODO: change width/height for image aspect ratio\n // pending https://jira.corp.adobe.com/browse/DATA-5122\n width={carousel?.imageParams?.width ?? 960}\n height={carousel?.imageParams?.height ?? 1191}\n params={carousel?.imageParams ?? { width: 960 }}\n />\n )) ?? []\n }\n specialPrice={\n data?.prices?.visible ? (\n <Slot\n name=\"SpecialPrice\"\n slot={slots?.SpecialPrice}\n context={{ ...defaultSlotContext }}\n >\n <PriceRange\n {...data.prices?.final}\n locale={toLanguageTag(locale)}\n />\n </Slot>\n ) : undefined\n }\n price={\n data?.prices?.visible &&\n data?.prices?.regular &&\n data?.prices?.final?.amount !== data?.prices?.regular?.amount ? (\n <Slot\n name=\"RegularPrice\"\n slot={slots?.RegularPrice}\n context={{ ...defaultSlotContext }}\n >\n <PriceRange\n {...data.prices?.regular}\n locale={toLanguageTag(locale)}\n />\n </Slot>\n ) : undefined\n }\n zoomType={zoomType}\n closeButton={closeButton}\n carouselConfig={{\n ...carousel,\n thumbnails:\n carousel && Object.keys(carousel).length\n ? data?.images?.map(({ label, url }) => (\n <Image\n key={url}\n title={label}\n alt={label}\n src={url}\n // TODO: change width/height for image aspect ratio\n // pending https://jira.corp.adobe.com/browse/DATA-5122\n width={carousel?.thumbnailParams?.width ?? 200}\n height={carousel?.thumbnailParams?.height ?? 248}\n params={carousel?.thumbnailParams ?? { width: 200 }}\n />\n )) ?? []\n : [],\n }}\n outOfStock={!data?.inStock}\n attributes={\n !hideAttributes ? (\n <Slot\n name=\"Attributes\"\n slot={slots?.Attributes}\n context={{ ...defaultSlotContext }}\n >\n {attributes?.length ? (\n <>\n {DetailsLabel}\n <ul>{attributes}</ul>\n </>\n ) : null}\n </Slot>\n ) : undefined\n }\n galleryContent={\n slots?.GalleryContent && (\n <Slot\n name=\"GalleryContent\"\n slot={slots.GalleryContent}\n context={{ ...defaultSlotContext }}\n />\n )\n }\n infoContent={\n slots?.InfoContent && (\n <Slot\n name=\"InfoContent\"\n slot={slots.InfoContent}\n context={{ ...defaultSlotContext }}\n />\n )\n }\n productContent={\n slots?.Content && (\n <Slot\n name=\"Content\"\n slot={slots.Content}\n context={{ ...defaultSlotContext }}\n />\n )\n }\n />\n </div>\n );\n};\n\n/** @deprecated This method is part of the deprecated ProductDetails component. */\nProductDetails.getInitialData = async function ({\n sku,\n disableDropdownPreselection = false,\n optionsConfig,\n}) {\n const initialData = config.getConfig().models?.ProductDetails?.initialData;\n\n return initialData\n ? transformProductData(initialData)\n : fetchProductData(sku, {\n preselectFirstOption: !disableDropdownPreselection,\n anchors: optionsConfig?.anchorOptions,\n });\n};\n"],"names":["Product","title","breadcrumbs","galleryContent","infoContent","productContent","sku","outOfStock","shortDescription","description","attributes","images","options","giftCardOptions","downloadableOptions","price","specialPrice","className","children","quantity","actions","carouselConfig","zoomType","closeButton","props","RegularPriceLabel","useText","SpecialPriceLabel","OutOfStockLabel","ImagesLabel","zoom","setZoom","useState","galleryImages","image","key","alt","_a","jsx","Zoom","VComponent","localThumbnailsImages","jsxs","classes","_b","Carousel","_c","_d","GalleryGrid","_e","_f","_g","_h","_i","Overlay","gap","style","count","Children","child","ProductDetails","hideSku","hideQuantity","hideShortDescription","hideDescription","hideAttributes","hideURLParams","hideSelectedOptionValue","slots","initialData","carousel","optionsConfig","useACDL","onAddToCart","disableDropdownPreselection","AddToCartLabel","IncrementerLabel","DetailsLabel","ChooseOptionLabel","locale","setLocale","config","selectionsToUpdate","setSelectionsToUpdate","data","setData","values","setValues","initialQuantity","getValidatedQuantityFromUrl","defaultValues","valid","setValid","defaultSlotContext","hasProductViewOptionValueProduct","option","useEffect","dataEvent","events","payload","prev","updateDataEvent","localeEvent","fetchProductData","publishProductPageViewEvent","handleOnValues","useCallback","newValues","handleOptionSelected","selections","optionsUIDs","_","value","id","element","setUrlParams","next","processUpdates","previousOptionsUIDs","updatedOptionsUIDs","item","handleOnErrors","_errors","useMemo","label","__html","isDateValid","toDateString","Slot","Incrementer","quantityValue","renderOptions","Swatches","renderGiftCardOptions","giftCardAttributes","attr","validElements","giftCardAttr","index","giftCardData","prevOptions","optionValues","existingOption","opt","GiftCardOptions","uid","idx","field","newEnteredOptions","updatedData","updatedOptions","error","renderDownloadableOptions","downloadableAttributes","downloadableAttr","downloadableValue","DownloadableOptions","selected","prevUIDs","newOptionsUIDs","callback","attrs","nextSeparator","separator","Icon","Breadcrumbs","text","p","link","categories","domElement","vnode","_button","icon","buttonProps","button","Button","url","Image","PriceRange","toLanguageTag","_j","_k","Fragment","transformProductData"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ProductDetails.js","sources":["/@dropins/storefront-pdp/src/containers/ProductDetails/ProductDetails.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 {\n HTMLAttributes,\n useEffect,\n useState,\n useCallback,\n useMemo,\n} from 'preact/compat';\n\nimport {\n Container,\n toLanguageTag,\n SlotProps,\n SlotMethod,\n Slot,\n ResolveImageUrlOptions,\n} from '@adobe-commerce/elsie/lib';\n\nimport {\n Button,\n Icon,\n ButtonProps,\n Image,\n Incrementer,\n Breadcrumbs,\n} from '@adobe-commerce/elsie/components';\nimport {\n Product,\n Swatches,\n PriceRange,\n Option,\n GiftCardOptions,\n DownloadableOptions,\n} from '@/pdp/components';\nimport { config, fetchProductData } from '@/pdp/api';\nimport { events } from '@adobe-commerce/event-bus';\nimport { Lang, useText } from '@adobe-commerce/elsie/i18n';\nimport { isDateValid, toDateString } from '@/pdp/lib/date';\nimport {\n isProductOptionsSelectionComplete,\n selectionMapToOptionUIDs,\n type ProductOptionSelectionMap,\n} from '@/pdp/lib/product-option-selection';\nimport {\n setUrlParams,\n getValidatedQuantityFromUrl,\n} from '@/pdp/lib/url-params';\nimport { publishProductPageViewEvent } from '@/pdp/lib/acdl';\nimport { ProductModel, Option as ProductOption } from '@/pdp/data/models';\nimport { transformProductData } from '@/pdp/data/transforms/product-transform';\n\ntype IconType = keyof typeof import('@adobe-commerce/elsie/icons');\n\n/** @deprecated This type is part of the deprecated ProductDetails component. */\nexport type Values = {\n sku: string;\n quantity: number;\n optionsUIDs?: string[];\n enteredOptions?: Array<{ uid: string; value: string }>;\n};\n\n/** @deprecated This type is part of the deprecated ProductDetails component. */\ntype DefaultSlotContext = {\n data: ProductModel | null;\n values: Values;\n valid: boolean;\n};\n\n/** @deprecated This type is part of the deprecated ProductDetails component. */\nexport type CarouselConfig = {\n controls?: {\n desktop?: 'thumbnailsRow' | 'thumbnailsColumn' | 'dots' | null;\n mobile?: 'dots' | 'thumbnailsRow' | null;\n };\n arrowsOnMainImage?: boolean;\n loopable?: boolean;\n peak?: {\n desktop: boolean;\n mobile: boolean;\n };\n gap?: 'small' | 'medium' | 'large' | null;\n thumbnailsLoadingMode?: 'lazy' | 'eager';\n imageParams?: ResolveImageUrlOptions;\n thumbnailParams?: ResolveImageUrlOptions;\n};\n\n/** @deprecated This type is part of the deprecated ProductDetails component. */\nexport type OptionsConfig = {\n anchorOptions?: string[];\n};\n\n/** @deprecated This interface is part of the deprecated ProductDetails component. */\nexport interface ProductDetailsProps extends HTMLAttributes<HTMLDivElement> {\n sku: string;\n productData?: ProductModel;\n hideSku?: boolean;\n hideQuantity?: boolean;\n hideShortDescription?: boolean;\n hideDescription?: boolean;\n hideAttributes?: boolean;\n hideSelectedOptionValue?: boolean;\n hideURLParams?: boolean;\n slots?: {\n Title?: SlotProps<DefaultSlotContext>;\n\n SKU?: SlotProps<DefaultSlotContext>;\n\n RegularPrice?: SlotProps<DefaultSlotContext>;\n\n SpecialPrice?: SlotProps<DefaultSlotContext>;\n\n Options?: SlotProps<DefaultSlotContext>;\n\n Quantity?: SlotProps<DefaultSlotContext>;\n\n Actions?: SlotProps<\n DefaultSlotContext & {\n appendButton: SlotMethod<\n Omit<ButtonProps, 'icon'> & {\n text?: string;\n icon?: IconType;\n }\n >;\n }\n >;\n\n ShortDescription?: SlotProps<DefaultSlotContext>;\n\n Description?: SlotProps<DefaultSlotContext>;\n\n Attributes?: SlotProps<DefaultSlotContext>;\n\n Breadcrumbs?: SlotProps<\n DefaultSlotContext & {\n setSeparator: SlotMethod<IconType>;\n\n appendLink: SlotMethod<\n HTMLAttributes<HTMLAnchorElement> & { text?: string }\n >;\n\n appendHTMLElement: SlotMethod<HTMLElement>;\n }\n >;\n\n GalleryContent?: SlotProps<DefaultSlotContext>;\n\n InfoContent?: SlotProps<DefaultSlotContext>;\n\n Content?: SlotProps<DefaultSlotContext>;\n };\n carousel?: CarouselConfig;\n optionsConfig?: OptionsConfig;\n useACDL?: boolean;\n onAddToCart?: (values: Values) => void;\n zoomType?: 'zoom' | 'overlay';\n closeButton?: boolean;\n disableDropdownPreselection?: boolean;\n}\n\n/**\n * @deprecated This container has been deprecated and will be removed in a future release.\n * Please use the different composable containers to build your product details page.xs\n */\nexport const ProductDetails: Container<\n ProductDetailsProps,\n ProductModel | null\n> = ({\n sku,\n hideSku,\n hideQuantity,\n hideShortDescription,\n hideDescription,\n hideAttributes,\n hideURLParams,\n hideSelectedOptionValue,\n slots,\n children,\n initialData,\n carousel,\n optionsConfig,\n useACDL,\n onAddToCart,\n zoomType,\n closeButton = true,\n disableDropdownPreselection,\n ...props\n}) => {\n // i18n\n const AddToCartLabel = useText('PDP.Product.AddToCart.label').label;\n const IncrementerLabel = useText('PDP.Product.Incrementer.label').label;\n const DetailsLabel = useText('PDP.Product.Details.label').label;\n const ChooseOptionLabel = useText('PDP.Swatches.ChooseOption.label').label;\n\n // TODO: Investigate if the \"|| 'en-US' \" is really necessary\n const [locale, setLocale] = useState<Lang>(\n (config.getConfig().defaultLocale as Lang) || 'en-US'\n );\n\n const [selectionsToUpdate, setSelectionsToUpdate] = useState<Option[]>();\n\n const [data = null, setData] = useState(initialData);\n\n const [values, setValues] = useState<Values>(() => {\n const initialQuantity = getValidatedQuantityFromUrl(1); // Default quantity to 1\n\n const defaultValues: Values = {\n sku,\n quantity: initialQuantity,\n };\n\n if (data?.optionUIDs) {\n defaultValues.optionsUIDs = data.optionUIDs;\n }\n return defaultValues;\n });\n\n // the context is invalid for a configurable product that doesn't have all the options selected\n const [valid, setValid] = useState(() => {\n if (!data?.options?.length) {\n return true;\n }\n return isProductOptionsSelectionComplete(\n data.options,\n data.optionUIDs,\n data.isBundle\n );\n });\n const defaultSlotContext: DefaultSlotContext = { data, values, valid };\n\n function hasProductViewOptionValueProduct(options: ProductOption[]) {\n return options?.some(\n (option) => option?.typename === 'ProductViewOptionValueProduct'\n );\n }\n\n useEffect(() => {\n const dataEvent = events.on('pdp/data', (payload) => {\n if (payload) {\n setData(payload);\n // Preserve the current quantity value when updating from pdp/data event\n setValues((prev: Values) => ({\n ...prev,\n sku: payload.sku,\n optionsUIDs: payload.optionUIDs,\n }));\n }\n });\n\n // @ts-ignore - Type error with event bus events\n const updateDataEvent = events.on(\n 'pdp/setValues',\n (payload: Partial<Values>) => {\n setValues((prev: Values) => ({ ...prev, ...payload }));\n }\n );\n\n return () => {\n updateDataEvent?.off();\n dataEvent?.off();\n };\n }, []);\n\n // Locale\n useEffect(() => {\n const localeEvent = events.on('locale', (payload: string) => {\n if (payload === locale) return;\n\n setLocale(payload as Lang);\n\n fetchProductData(sku, {\n preselectFirstOption: !disableDropdownPreselection,\n anchors: optionsConfig?.anchorOptions,\n }).then(setData);\n });\n return () => {\n localeEvent?.off();\n };\n }, [disableDropdownPreselection, locale, optionsConfig?.anchorOptions, sku]);\n\n useEffect(() => {\n if (useACDL && initialData && Object.keys(initialData).length > 0) {\n publishProductPageViewEvent(initialData);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [initialData]);\n\n // Callbacks\n const handleOnValues = useCallback((newValues: Partial<Values>) => {\n setValues((prev) => ({ ...prev, ...newValues }));\n }, []);\n\n useEffect(() => {\n events.emit('pdp/values', values);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [JSON.stringify(values)]);\n\n const handleOptionSelected = useCallback(\n async (selections: ProductOptionSelectionMap) => {\n // options Selected\n const sanitizedSelections = Object.fromEntries(\n Object.entries(selections).filter(\n ([, value]) => value.label !== ChooseOptionLabel\n )\n ) as ProductOptionSelectionMap;\n\n let optionsUIDs = selectionMapToOptionUIDs(\n sanitizedSelections,\n data?.options\n );\n\n // set optionUIDs to URL params\n // ?optionsUIDs=1,2,3\n // only set the URL params if the hideURLParams is not set to true and the product is not a bundle type\n if (\n !hideURLParams &&\n data?.options &&\n !hasProductViewOptionValueProduct(data.options)\n ) {\n setUrlParams({ optionsUIDs: optionsUIDs.join(',') });\n }\n\n // update state\n handleOnValues({ optionsUIDs });\n\n // get refined product data and update state\n const next = await fetchProductData(sku, {\n anchors: optionsConfig?.anchorOptions,\n isBundle: data?.isBundle,\n optionsUIDs,\n preselectFirstOption: !disableDropdownPreselection,\n });\n\n setData(next);\n setValid(\n isProductOptionsSelectionComplete(\n next?.options,\n next?.optionUIDs ?? optionsUIDs,\n next?.isBundle\n )\n );\n\n // special processing for anchor options (options that should not be refined when other options are selected)\n if (optionsConfig?.anchorOptions?.length) {\n processUpdates(next, optionsUIDs);\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [sku]\n );\n\n const processUpdates = useCallback(\n (next: ProductModel | null, previousOptionsUIDs: string[]) => {\n const updatedOptionsUIDs = next?.optionUIDs ?? [];\n const haveSameValues = previousOptionsUIDs.every((item) =>\n updatedOptionsUIDs.includes(item)\n );\n if (!haveSameValues) {\n setSelectionsToUpdate(next?.options);\n handleOnValues({ optionsUIDs: updatedOptionsUIDs });\n setValid(\n isProductOptionsSelectionComplete(\n next?.options,\n updatedOptionsUIDs,\n next?.isBundle\n )\n );\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [sku]\n );\n\n const handleOnErrors = useCallback((_errors: { [id: string]: string }) => {\n if (Object.keys(_errors).length !== 0) setValid(false);\n }, []);\n\n // Product Attributes\n const attributes = useMemo(() => {\n return data?.attributes?.map(({ label, value, id }, key: number) => {\n // Return empty string for gift card attributes\n if (id === 'ac_giftcard') {\n return '';\n }\n\n const __html = isDateValid(value)\n ? toDateString(value, locale)\n : value.toString();\n\n return (\n <li key={key}>\n {/* eslint-disable-next-line react/no-danger */}\n {label}: <span dangerouslySetInnerHTML={{ __html }} />\n </li>\n );\n });\n }, [data?.attributes, locale]);\n\n const quantity =\n !hideQuantity && data?.inStock ? (\n <Slot\n name=\"Quantity\"\n slot={slots?.Quantity}\n context={{ ...defaultSlotContext }}\n >\n <Incrementer\n key=\"quantity\"\n name=\"quantity\"\n defaultValue={values.quantity.toString()}\n value={values.quantity.toString()}\n min={1}\n aria-label={IncrementerLabel}\n className=\"pdp-product__quantity\"\n onValue={(quantity) => {\n const quantityValue = Number(quantity);\n handleOnValues({ quantity: quantityValue });\n\n // Add quantity to URL parameters if not set to hide\n if (!hideURLParams && data?.options) {\n // Only update URL if the product is not a bundle type\n if (!hasProductViewOptionValueProduct(data.options)) {\n setUrlParams({ quantity: quantityValue });\n }\n }\n }}\n />\n </Slot>\n ) : undefined;\n\n const renderOptions = () => {\n if (data?.options) {\n return (\n <Slot\n name=\"Options\"\n slot={slots?.Options}\n context={{ ...defaultSlotContext }}\n >\n <Swatches\n selectedUIDs={values.optionsUIDs}\n options={data.options}\n defaultOptions={values.optionsUIDs}\n selectionsToUpdate={selectionsToUpdate}\n hideSelectedValue={hideSelectedOptionValue}\n disablePreselections={disableDropdownPreselection}\n onValues={handleOptionSelected}\n onErrors={handleOnErrors}\n />\n </Slot>\n );\n }\n };\n\n const renderGiftCardOptions = () => {\n if (data?.attributes) {\n const giftCardAttributes = data.attributes.filter(\n (attr) => attr.id === 'ac_giftcard'\n );\n\n if (giftCardAttributes.length > 0) {\n const giftCardElements = giftCardAttributes.map(\n (giftCardAttr, index) => {\n try {\n const giftCardData = JSON.parse(giftCardAttr.value);\n const prevOptions = values.enteredOptions || [];\n const optionValues =\n giftCardData.options?.map((option: any) => {\n const existingOption = prevOptions.find(\n (opt: { uid: string; value: string }) =>\n opt.uid === option.uid\n );\n return {\n id: option.uid,\n value: existingOption?.value || '',\n };\n }) || [];\n\n return (\n <GiftCardOptions\n key={`giftcard-${index}`}\n options={giftCardData.options || []}\n optionValues={optionValues}\n onOptionChange={(uid: string, value: string) => {\n const prevOptions = values.enteredOptions || [];\n const idx = prevOptions.findIndex(\n (field: { uid: string; value: string }) =>\n field.uid === uid\n );\n let newEnteredOptions;\n if (idx !== -1) {\n newEnteredOptions = prevOptions.map(\n (field: { uid: string; value: string }) =>\n field.uid === uid ? { ...field, value } : field\n );\n } else {\n newEnteredOptions = [...prevOptions, { uid, value }];\n }\n\n handleOnValues({ enteredOptions: newEnteredOptions });\n\n if (data) {\n const updatedData = { ...data };\n const giftCardAttributes =\n updatedData.attributes?.map((attr) => {\n if (attr.id === 'ac_giftcard') {\n try {\n const giftCardData = JSON.parse(attr.value);\n const updatedOptions =\n giftCardData.options?.map((option: any) => {\n if (option.uid === uid) {\n return { ...option, value };\n }\n return option;\n }) || [];\n return {\n ...attr,\n value: JSON.stringify({\n ...giftCardData,\n options: updatedOptions,\n }),\n };\n } catch (error) {\n return attr;\n }\n }\n return attr;\n }) || [];\n updatedData.attributes = giftCardAttributes;\n setData(updatedData);\n }\n }}\n onValidationChange={(valid: boolean) => {\n if (!valid) {\n handleOnErrors({ giftCard: 'Invalid gift card data' });\n }\n\n setValid(valid);\n }}\n className=\"pdp-product__gift-card-options\"\n />\n );\n } catch (error) {\n console.warn('Invalid gift card data format:', error);\n return null;\n }\n }\n );\n\n // Filter out null values and return a single element\n const validElements = giftCardElements.filter(\n (element) => element !== null\n );\n return validElements.length > 0 ? (\n <div className=\"pdp-product__gift-card-options-container\">\n {validElements}\n </div>\n ) : undefined;\n }\n }\n return undefined;\n };\n\n const renderDownloadableOptions = () => {\n if (data?.attributes) {\n const downloadableAttributes = data.attributes.filter(\n (attr) =>\n attr.id === 'ac_downloadable' &&\n attr.roles?.includes('visible_in_pdp')\n );\n\n if (downloadableAttributes.length > 0) {\n const downloadableElements = downloadableAttributes.map(\n (downloadableAttr, index) => {\n try {\n const downloadableValue =\n typeof downloadableAttr.value === 'string'\n ? JSON.parse(downloadableAttr.value)\n : downloadableAttr.value;\n\n return (\n <DownloadableOptions\n key={`downloadable-${index}`}\n label={downloadableAttr.label}\n value={downloadableValue}\n onLinkChange={(uid: string, selected: boolean) => {\n const prevUIDs = values.optionsUIDs || [];\n let newOptionsUIDs;\n\n if (selected) {\n if (!prevUIDs.includes(uid)) {\n newOptionsUIDs = [...prevUIDs, uid];\n } else {\n newOptionsUIDs = prevUIDs;\n }\n } else {\n newOptionsUIDs = prevUIDs.filter(\n (id: string) => id !== uid\n );\n }\n\n handleOnValues({ optionsUIDs: newOptionsUIDs });\n }}\n currency={data.prices?.final?.currency}\n className=\"pdp-product__downloadable-options\"\n />\n );\n } catch (error) {\n console.warn('Invalid downloadable data format:', error);\n return null;\n }\n }\n );\n\n // Filter out null values and return a wrapper div\n const validElements = downloadableElements.filter(\n (element) => element !== null\n );\n return validElements.length > 0 ? (\n <div className=\"pdp-product__downloadable-options-container\">\n {validElements}\n </div>\n ) : undefined;\n }\n }\n return undefined;\n };\n\n return (\n <div {...props}>\n <Product\n title={\n <Slot\n name=\"Title\"\n slot={slots?.Title}\n context={{ ...defaultSlotContext }}\n >\n {data?.name}\n </Slot>\n }\n sku={\n !hideSku ? (\n <Slot\n name=\"SKU\"\n slot={slots?.SKU}\n context={{ ...defaultSlotContext }}\n >\n {data?.sku}\n </Slot>\n ) : undefined\n }\n options={renderOptions()}\n giftCardOptions={renderGiftCardOptions()}\n downloadableOptions={renderDownloadableOptions()}\n breadcrumbs={\n slots?.Breadcrumbs && (\n <Slot\n name=\"Breadcrumbs\"\n slot={slots?.Breadcrumbs}\n context={{\n ...defaultSlotContext,\n\n setSeparator(callback) {\n this._registerMethod((...attrs) => {\n const nextSeparator = callback(...attrs);\n\n const separator = nextSeparator && (\n <Icon source={nextSeparator} />\n );\n\n this._setProps((prev: any) => {\n return {\n ...prev,\n separator,\n children: [\n // eslint-disable-next-line react/jsx-key\n <Breadcrumbs\n separator={separator}\n categories={prev.categories}\n />,\n ],\n };\n });\n });\n },\n\n appendLink(callback) {\n this._registerMethod((...attrs) => {\n const { text, ...p } = callback(...attrs);\n\n const link = <a {...p}>{text}</a>;\n\n this._setProps((prev: any) => {\n const categories = [...(prev.categories || []), link];\n return {\n ...prev,\n categories,\n children: [\n // eslint-disable-next-line react/jsx-key\n <Breadcrumbs\n separator={prev.separator}\n categories={categories}\n />,\n ],\n };\n });\n });\n },\n\n appendHTMLElement(callback) {\n this._registerMethod((...attrs) => {\n const domElement = callback(...attrs);\n\n const vnode = this._htmlElementToVNode(domElement);\n\n this._setProps((prev: any) => {\n const categories = [...(prev.categories || []), vnode];\n\n return {\n ...prev,\n categories,\n children: [\n // eslint-disable-next-line react/jsx-key\n <Breadcrumbs\n separator={prev.separator}\n categories={categories}\n />,\n ],\n };\n });\n });\n },\n }}\n />\n )\n }\n quantity={quantity}\n actions={\n <Slot\n name=\"Actions\"\n slot={slots?.Actions}\n context={{\n ...defaultSlotContext,\n\n appendButton(callback) {\n this._registerMethod((...attrs) => {\n const _button = callback(...attrs);\n\n if (!_button) return;\n\n const { text, icon, ...buttonProps } = _button;\n\n const button = (\n <Button\n type=\"button\"\n {...buttonProps}\n icon={icon && <Icon source={icon} />}\n >\n {text}\n </Button>\n );\n\n this._setProps((prev: any) => ({\n children: [...(prev.children || []), button],\n }));\n });\n },\n }}\n >\n {\n // Default Add to Cart button if no slot is provided\n !slots?.Actions && (\n <Button\n size=\"medium\"\n type=\"submit\"\n icon={<Icon source=\"Cart\" />}\n disabled={!data?.inStock || !valid}\n aria-label={AddToCartLabel}\n onClick={() => {\n return onAddToCart?.(values);\n }}\n >\n {AddToCartLabel}\n </Button>\n )\n }\n </Slot>\n }\n shortDescription={\n !hideShortDescription ? (\n <Slot\n name=\"ShortDescription\"\n slot={slots?.ShortDescription}\n context={{ ...defaultSlotContext }}\n >\n <div\n // eslint-disable-next-line react/no-danger\n dangerouslySetInnerHTML={{\n __html: data?.shortDescription ?? '',\n }}\n />\n </Slot>\n ) : undefined\n }\n description={\n !hideDescription ? (\n <Slot\n name=\"Description\"\n slot={slots?.Description}\n context={{ ...defaultSlotContext }}\n >\n <div\n // eslint-disable-next-line react/no-danger\n dangerouslySetInnerHTML={{ __html: data?.description ?? '' }}\n />\n </Slot>\n ) : undefined\n }\n images={\n data?.images?.map(({ label, url }) => (\n <Image\n key={url}\n title={label}\n alt={label}\n src={url}\n // TODO: change width/height for image aspect ratio\n // pending https://jira.corp.adobe.com/browse/DATA-5122\n width={carousel?.imageParams?.width ?? 960}\n height={carousel?.imageParams?.height ?? 1191}\n params={carousel?.imageParams ?? { width: 960 }}\n />\n )) ?? []\n }\n specialPrice={\n data?.prices?.visible ? (\n <Slot\n name=\"SpecialPrice\"\n slot={slots?.SpecialPrice}\n context={{ ...defaultSlotContext }}\n >\n <PriceRange\n {...data.prices?.final}\n locale={toLanguageTag(locale)}\n />\n </Slot>\n ) : undefined\n }\n price={\n data?.prices?.visible &&\n data?.prices?.regular &&\n data?.prices?.final?.amount !== data?.prices?.regular?.amount ? (\n <Slot\n name=\"RegularPrice\"\n slot={slots?.RegularPrice}\n context={{ ...defaultSlotContext }}\n >\n <PriceRange\n {...data.prices?.regular}\n locale={toLanguageTag(locale)}\n />\n </Slot>\n ) : undefined\n }\n zoomType={zoomType}\n closeButton={closeButton}\n carouselConfig={{\n ...carousel,\n thumbnails:\n carousel && Object.keys(carousel).length\n ? data?.images?.map(({ label, url }) => (\n <Image\n key={url}\n title={label}\n alt={label}\n src={url}\n // TODO: change width/height for image aspect ratio\n // pending https://jira.corp.adobe.com/browse/DATA-5122\n width={carousel?.thumbnailParams?.width ?? 200}\n height={carousel?.thumbnailParams?.height ?? 248}\n params={carousel?.thumbnailParams ?? { width: 200 }}\n />\n )) ?? []\n : [],\n }}\n outOfStock={!data?.inStock}\n attributes={\n !hideAttributes ? (\n <Slot\n name=\"Attributes\"\n slot={slots?.Attributes}\n context={{ ...defaultSlotContext }}\n >\n {attributes?.length ? (\n <>\n {DetailsLabel}\n <ul>{attributes}</ul>\n </>\n ) : null}\n </Slot>\n ) : undefined\n }\n galleryContent={\n slots?.GalleryContent && (\n <Slot\n name=\"GalleryContent\"\n slot={slots.GalleryContent}\n context={{ ...defaultSlotContext }}\n />\n )\n }\n infoContent={\n slots?.InfoContent && (\n <Slot\n name=\"InfoContent\"\n slot={slots.InfoContent}\n context={{ ...defaultSlotContext }}\n />\n )\n }\n productContent={\n slots?.Content && (\n <Slot\n name=\"Content\"\n slot={slots.Content}\n context={{ ...defaultSlotContext }}\n />\n )\n }\n />\n </div>\n );\n};\n\n/** @deprecated This method is part of the deprecated ProductDetails component. */\nProductDetails.getInitialData = async function ({\n sku,\n disableDropdownPreselection = false,\n optionsConfig,\n}) {\n const initialData = config.getConfig().models?.ProductDetails?.initialData;\n\n return initialData\n ? transformProductData(initialData)\n : fetchProductData(sku, {\n preselectFirstOption: !disableDropdownPreselection,\n anchors: optionsConfig?.anchorOptions,\n });\n};\n"],"names":["ProductDetails","sku","hideSku","hideQuantity","hideShortDescription","hideDescription","hideAttributes","hideURLParams","hideSelectedOptionValue","slots","children","initialData","carousel","optionsConfig","useACDL","onAddToCart","zoomType","closeButton","disableDropdownPreselection","props","AddToCartLabel","useText","IncrementerLabel","DetailsLabel","ChooseOptionLabel","locale","setLocale","useState","config","selectionsToUpdate","setSelectionsToUpdate","data","setData","values","setValues","initialQuantity","getValidatedQuantityFromUrl","defaultValues","valid","setValid","_a","isProductOptionsSelectionComplete","defaultSlotContext","hasProductViewOptionValueProduct","options","option","useEffect","dataEvent","events","payload","prev","updateDataEvent","localeEvent","fetchProductData","publishProductPageViewEvent","handleOnValues","useCallback","newValues","handleOptionSelected","selections","sanitizedSelections","value","optionsUIDs","selectionMapToOptionUIDs","setUrlParams","next","processUpdates","previousOptionsUIDs","updatedOptionsUIDs","item","handleOnErrors","_errors","attributes","useMemo","label","id","key","__html","isDateValid","toDateString","jsx","quantity","Slot","Incrementer","quantityValue","renderOptions","Swatches","renderGiftCardOptions","giftCardAttributes","attr","validElements","giftCardAttr","index","giftCardData","prevOptions","optionValues","existingOption","opt","GiftCardOptions","uid","idx","field","newEnteredOptions","updatedData","updatedOptions","error","element","renderDownloadableOptions","downloadableAttributes","downloadableAttr","downloadableValue","DownloadableOptions","selected","prevUIDs","newOptionsUIDs","_b","Product","callback","attrs","nextSeparator","separator","Icon","Breadcrumbs","text","p","link","categories","domElement","vnode","_button","icon","buttonProps","button","Button","url","Image","PriceRange","_c","toLanguageTag","_d","_e","_g","_f","_i","_h","_j","_k","jsxs","Fragment","transformProductData"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/*! Copyright 2026 Adobe
|
|
2
2
|
All Rights Reserved. */
|
|
3
|
-
import{jsx as r}from"@dropins/tools/preact-jsx-runtime.js";import{classes as
|
|
3
|
+
import{jsx as r}from"@dropins/tools/preact-jsx-runtime.js";import{classes as d}from"@dropins/tools/lib.js";import{setProductConfigurationValues as f,getFetchedProductData as D}from"../api.js";import"@dropins/tools/event-bus.js";import{D as b}from"../chunks/components.js";import{u as g,g as h}from"../chunks/useProductData.js";import"@dropins/tools/fetch-graphql.js";import"@dropins/tools/i18n.js";import"@dropins/tools/preact-compat.js";import"@dropins/tools/components.js";import"@dropins/tools/preact.js";import"@dropins/tools/preact-hooks.js";const I=({initialData:c=null,scope:m,children:w,...a})=>{const{data:l,values:u}=g({scope:m,initialData:c,initialValues:{optionsUIDs:[]}}),p=(o,s)=>{const t=u.optionsUIDs||[];let e;s?t.includes(o)?e=t:e=[...t,o]:e=t.filter(n=>n!==o),f(n=>({...n,optionsUIDs:e}))},i=h(l,"ac_downloadable");return!l||i.length===0?null:r("div",{...a,className:d(["pdp-downloadable-options",a.className]),children:i.map((o,s)=>{var t,e;return r(b,{label:o.label,value:o.value,onLinkChange:p,currency:(e=(t=l.prices)==null?void 0:t.final)==null?void 0:e.currency,className:a.className},`downloadable-${s}`)})})};I.getInitialData=D;export{I as ProductDownloadableOptions,I as default};
|
|
4
4
|
//# sourceMappingURL=ProductDownloadableOptions.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProductDownloadableOptions.js","sources":["/@dropins/storefront-pdp/src/containers/ProductDownloadableOptions/ProductDownloadableOptions.tsx"],"sourcesContent":["/**\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 */\n\nimport { HTMLAttributes } from 'preact/compat';\nimport { Container, classes } from '@adobe-commerce/elsie/lib';\nimport { ProductModel } from '@/pdp/data/models';\nimport {\n getFetchedProductData,\n setProductConfigurationValues,\n} from '@/pdp/api';\nimport { DownloadableOptions } from '@/pdp/components/DownloadableOptions';\nimport { useProductData, getAttributesById } from '@/pdp/lib/useProductData';\n\nexport interface ProductDownloadableOptionsProps\n extends HTMLAttributes<HTMLDivElement> {\n scope?: string;\n}\n\nexport const ProductDownloadableOptions: Container<\n ProductDownloadableOptionsProps,\n ProductModel | null\n> = ({ initialData = null, scope, children, ...props }) => {\n const { data, values } = useProductData({\n scope,\n initialData,\n initialValues: { optionsUIDs: [] },\n });\n\n const handleLinkChange = (uid: string, selected: boolean) => {\n const prevUIDs = values.optionsUIDs || [];\n let newOptionsUIDs;\n\n if (!selected) {\n newOptionsUIDs = prevUIDs.filter((id) => id !== uid);\n } else if (prevUIDs.includes(uid)) {\n newOptionsUIDs = prevUIDs;\n } else {\n newOptionsUIDs = [...prevUIDs, uid];\n }\n\n setProductConfigurationValues((prev) => ({\n ...prev,\n optionsUIDs: newOptionsUIDs,\n }));\n };\n\n const downloadableAttributes = getAttributesById(data, 'ac_downloadable');\n\n if (!data) return null;\n\n if (downloadableAttributes.length === 0) return null;\n\n return (\n <div\n {...props}\n className={classes(['pdp-downloadable-options', props.className])}\n >\n {downloadableAttributes.map((downloadable, index) => (\n <DownloadableOptions\n key={`downloadable-${index}`}\n label={downloadable.label}\n value={downloadable.value}\n onLinkChange={handleLinkChange}\n currency={data.prices?.final?.currency}\n className={props.className}\n />\n ))}\n </div>\n );\n};\n\nProductDownloadableOptions.getInitialData = getFetchedProductData;\n"],"names":["ProductDownloadableOptions","initialData","scope","children","props","data","values","useProductData","handleLinkChange","uid","selected","prevUIDs","newOptionsUIDs","id","setProductConfigurationValues","prev","downloadableAttributes","getAttributesById","jsx","classes","downloadable","index","DownloadableOptions","_b","_a","getFetchedProductData"],"mappings":"
|
|
1
|
+
{"version":3,"file":"ProductDownloadableOptions.js","sources":["/@dropins/storefront-pdp/src/containers/ProductDownloadableOptions/ProductDownloadableOptions.tsx"],"sourcesContent":["/**\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 */\n\nimport { HTMLAttributes } from 'preact/compat';\nimport { Container, classes } from '@adobe-commerce/elsie/lib';\nimport { ProductModel } from '@/pdp/data/models';\nimport {\n getFetchedProductData,\n setProductConfigurationValues,\n} from '@/pdp/api';\nimport { DownloadableOptions } from '@/pdp/components/DownloadableOptions';\nimport { useProductData, getAttributesById } from '@/pdp/lib/useProductData';\n\nexport interface ProductDownloadableOptionsProps\n extends HTMLAttributes<HTMLDivElement> {\n scope?: string;\n}\n\nexport const ProductDownloadableOptions: Container<\n ProductDownloadableOptionsProps,\n ProductModel | null\n> = ({ initialData = null, scope, children, ...props }) => {\n const { data, values } = useProductData({\n scope,\n initialData,\n initialValues: { optionsUIDs: [] },\n });\n\n const handleLinkChange = (uid: string, selected: boolean) => {\n const prevUIDs = values.optionsUIDs || [];\n let newOptionsUIDs;\n\n if (!selected) {\n newOptionsUIDs = prevUIDs.filter((id) => id !== uid);\n } else if (prevUIDs.includes(uid)) {\n newOptionsUIDs = prevUIDs;\n } else {\n newOptionsUIDs = [...prevUIDs, uid];\n }\n\n setProductConfigurationValues((prev) => ({\n ...prev,\n optionsUIDs: newOptionsUIDs,\n }));\n };\n\n const downloadableAttributes = getAttributesById(data, 'ac_downloadable');\n\n if (!data) return null;\n\n if (downloadableAttributes.length === 0) return null;\n\n return (\n <div\n {...props}\n className={classes(['pdp-downloadable-options', props.className])}\n >\n {downloadableAttributes.map((downloadable, index) => (\n <DownloadableOptions\n key={`downloadable-${index}`}\n label={downloadable.label}\n value={downloadable.value}\n onLinkChange={handleLinkChange}\n currency={data.prices?.final?.currency}\n className={props.className}\n />\n ))}\n </div>\n );\n};\n\nProductDownloadableOptions.getInitialData = getFetchedProductData;\n"],"names":["ProductDownloadableOptions","initialData","scope","children","props","data","values","useProductData","handleLinkChange","uid","selected","prevUIDs","newOptionsUIDs","id","setProductConfigurationValues","prev","downloadableAttributes","getAttributesById","jsx","classes","downloadable","index","DownloadableOptions","_b","_a","getFetchedProductData"],"mappings":"miBA+BO,MAAMA,EAGT,CAAC,CAAE,YAAAC,EAAc,KAAM,MAAAC,EAAO,SAAAC,EAAU,GAAGC,KAAY,CACzD,KAAM,CAAE,KAAAC,EAAM,OAAAC,CAAA,EAAWC,EAAe,CACtC,MAAAL,EACA,YAAAD,EACA,cAAe,CAAE,YAAa,CAAA,CAAC,CAAE,CAClC,EAEKO,EAAmB,CAACC,EAAaC,IAAsB,CAC3D,MAAMC,EAAWL,EAAO,aAAe,CAAA,EACvC,IAAIM,EAECF,EAEMC,EAAS,SAASF,CAAG,EAC9BG,EAAiBD,EAEjBC,EAAiB,CAAC,GAAGD,EAAUF,CAAG,EAJlCG,EAAiBD,EAAS,OAAQE,GAAOA,IAAOJ,CAAG,EAOrDK,EAA+BC,IAAU,CACvC,GAAGA,EACH,YAAaH,CAAA,EACb,CACJ,EAEMI,EAAyBC,EAAkBZ,EAAM,iBAAiB,EAIxE,MAFI,CAACA,GAEDW,EAAuB,SAAW,EAAU,KAG9CE,EAAC,MAAA,CACE,GAAGd,EACJ,UAAWe,EAAQ,CAAC,2BAA4Bf,EAAM,SAAS,CAAC,EAE/D,SAAAY,EAAuB,IAAI,CAACI,EAAcC,IAAA,SACzC,OAAAH,EAACI,EAAA,CAEC,MAAOF,EAAa,MACpB,MAAOA,EAAa,MACpB,aAAcZ,EACd,UAAUe,GAAAC,EAAAnB,EAAK,SAAL,YAAAmB,EAAa,QAAb,YAAAD,EAAoB,SAC9B,UAAWnB,EAAM,SAAA,EALZ,gBAAgBiB,CAAK,EAAA,EAO7B,CAAA,CAAA,CAGP,EAEArB,EAA2B,eAAiByB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/*! Copyright 2026 Adobe
|
|
2
2
|
All Rights Reserved. */
|
|
3
|
-
import{jsxs as O,jsx as i}from"@dropins/tools/preact-jsx-runtime.js";import{useState as M,useEffect as D,useRef as G,useMemo as S}from"@dropins/tools/preact-compat.js";import{Slot as K}from"@dropins/tools/lib.js";import{Image as W}from"@dropins/tools/components.js";import{events as L}from"@dropins/tools/event-bus.js";import{
|
|
3
|
+
import{jsxs as O,jsx as i}from"@dropins/tools/preact-jsx-runtime.js";import{useState as M,useEffect as D,useRef as G,useMemo as S}from"@dropins/tools/preact-compat.js";import{Slot as K}from"@dropins/tools/lib.js";import{Image as W}from"@dropins/tools/components.js";import{events as L}from"@dropins/tools/event-bus.js";import{getFetchedProductData as a}from"../api.js";import{C as k,O as b,Z as m}from"../chunks/components.js";import"@dropins/tools/preact-hooks.js";import{useText as P}from"@dropins/tools/i18n.js";import"@dropins/tools/fetch-graphql.js";import"@dropins/tools/preact.js";const z=[".mp4",".webm",".ogg",".mov",".avi",".mkv"],ee={".mp4":"video/mp4",".webm":"video/webm",".ogg":"video/ogg",".mov":"video/quicktime",".avi":"video/x-msvideo",".mkv":"video/x-matroska"};function te(r){if(!r)return"video/mp4";const l=r.toLowerCase(),t=z.find(e=>l.endsWith(e));return t?ee[t]:"video/mp4"}function re(r){if(!r)return!1;const l=r.toLowerCase();return z.some(t=>l.endsWith(t))}function x(r,l){if(l)return l;if(r!=null&&r.includes("adobeaemcloud.com")&&r.endsWith("/play"))return r.replace(/\/play$/,"/as/thumbnail.png")}function oe(r){if(!r)return"";const l=r.match(/(?:youtube\.com\/(?:watch\?v=|embed\/)|youtu\.be\/)([a-zA-Z0-9_-]+)/);if(l)return`https://www.youtube.com/embed/${l[1]}?rel=0`;const t=r.match(/vimeo\.com\/(?:video\/)?(\d+)/);return t?`https://player.vimeo.com/video/${t[1]}`:r}const ne=3e3;function le(r,{enabled:l=!0,timeoutMs:t=ne}={}){const e=r.join("\0"),p=!l||r.length===0,[d,c]=M(null),[u,h]=M(null);return D(()=>{if(p){c(e),h(null);return}let w=!1,n=r.length,y=!1;const g=()=>{w||(w=!0,y&&h(e),c(e))},A=window.setTimeout(()=>{y=!0,g()},t),s=v=>{w||(v&&(y=!0),n-=1,n<=0&&(window.clearTimeout(A),g()))};return r.forEach(v=>{const f=new Image;f.src=v,typeof f.decode=="function"?f.decode().then(()=>s(!1)).catch(()=>s(!0)):(f.onload=()=>s(!1),f.onerror=()=>s(!0))}),()=>{w=!0,window.clearTimeout(A)}},[e,l,t,p]),{ready:p||d===e,error:u===e}}const de=200,ce=(r,l)=>{var d,c;const t=((d=r==null?void 0:r.images)==null?void 0:d.map(u=>({type:"image",url:u.url,label:u.label})))??[];if(!l)return t;const e=((c=r==null?void 0:r.videos)==null?void 0:c.map(u=>({type:"video",url:u.url,label:u.title??"",preview:u.preview})))??[];return(typeof l=="object"?l.position:"last")==="first"?[...e,...t]:[...t,...e]},ie=(r,l)=>{if(!r)return[];const t=(r.images??[]).map(e=>e.url);return l&&(r.videos??[]).forEach(e=>{var d;const p=x(e.url,(d=e.preview)==null?void 0:d.url);p&&t.push(p)}),t},ue=(r,l,t)=>{var u,h;if(r===l)return!0;if(!r||!l)return!1;const e=r.images??[],p=l.images??[];if(e.length!==p.length)return!1;for(let o=0;o<e.length;o+=1)if(e[o].url!==p[o].url)return!1;if(!t)return!0;const d=r.videos??[],c=l.videos??[];if(d.length!==c.length)return!1;for(let o=0;o<d.length;o+=1){if(d[o].url!==c[o].url)return!1;const _=x(d[o].url,(u=d[o].preview)==null?void 0:u.url),w=x(c[o].url,(h=c[o].preview)==null?void 0:h.url);if(_!==w)return!1}return!0},pe=()=>typeof window<"u"&&typeof window.matchMedia=="function"&&window.matchMedia("(prefers-reduced-motion: reduce)").matches,q=({data:r,videos:l,imageParams:t,thumbnailParams:e,zoom:p,slots:d,ImagesLabel:c,onZoom:u})=>{const h=S(()=>({data:r}),[r]),o=S(()=>ce(r,l),[r,l]),_=S(()=>o.length>0?o.map((n,y)=>{const g=({...A})=>{var f;const s={title:n.label,src:n.url,alt:c==null?void 0:c.replace("{product}",n.label).replace("{key}",String(y+1)).replace("{total}",String(o.length)),width:(t==null?void 0:t.width)??960,height:(t==null?void 0:t.height)??1191,params:t??{width:960},loading:y===0?"eager":"lazy",...A},v=n.type==="video"?x(n.url,(f=n.preview)==null?void 0:f.url):void 0;return i(K,{name:"CarouselMainImage",slot:d==null?void 0:d.CarouselMainImage,context:{...h,defaultImageProps:s,mediaType:n.type,previewUrl:v},children:n.type==="video"?re(n.url)?O("video",{className:"pdp-product-gallery__video",controls:!0,preload:"metadata",poster:v,width:(t==null?void 0:t.width)??960,height:(t==null?void 0:t.height)??1191,children:[i("source",{src:n.url,type:te(n.url)}),"Your browser does not support the video tag."]}):i("iframe",{className:"pdp-product-gallery__video-iframe",src:oe(n.url),title:n.label||"Product video",width:(t==null?void 0:t.width)??960,height:(t==null?void 0:t.height)??1191,loading:"lazy",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",allowFullScreen:!0}):i(W,{...s})})};return p&&n.type==="image"?i(m,{closeButton:typeof p=="object"?p.closeButton:!1,children:i(g,{})},n.url):i(g,{onClick:()=>u==null?void 0:u(y)},n.url)}):i("img",{src:"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",className:"pdp-product-gallery__images__placeholder",width:(t==null?void 0:t.width)??960,height:(t==null?void 0:t.height)??1191,"aria-hidden":!0},"pleaceholder"),[c,o,t,p,h,d==null?void 0:d.CarouselMainImage,u]),w=S(()=>o.length>0?o.map((n,y)=>{var s;const g={title:n.label,src:n.url,alt:c==null?void 0:c.replace("{product}",n.label).replace("{key}",String(y+1)).replace("{total}",String(o.length)),width:(e==null?void 0:e.width)??200,height:(e==null?void 0:e.height)??248,params:e??{width:200},loading:"lazy"},A=n.type==="video"?x(n.url,(s=n.preview)==null?void 0:s.url):void 0;return i(K,{name:"CarouselThumbnail",slotTag:"span",contentTag:"span",slot:d==null?void 0:d.CarouselThumbnail,context:{...h,defaultImageProps:g,mediaType:n.type,previewUrl:A},children:n.type==="video"?O("span",{className:"pdp-product-gallery__video-thumbnail",role:"img","aria-label":`Play video: ${n.label||"Product video"}`,children:[A?i("img",{src:A,alt:"",width:(e==null?void 0:e.width)??200,height:(e==null?void 0:e.height)??248,loading:"lazy","aria-hidden":"true"}):i("span",{className:"pdp-product-gallery__video-thumbnail-placeholder",style:{width:(e==null?void 0:e.width)??200,height:(e==null?void 0:e.height)??248},"aria-hidden":"true"}),i("span",{className:"pdp-product-gallery__video-icon","aria-hidden":"true",children:"▶"})]}):i(W,{...g})},n.url)}):i("img",{src:"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",className:"pdp-product-gallery__thumbnail__placeholder",width:(e==null?void 0:e.width)??200,height:(e==null?void 0:e.height)??248,"aria-hidden":!0},"pleaceholder"),[c,o,e,h,d==null?void 0:d.CarouselThumbnail]);return{mediaItems:o,galleryItems:_,thumbnails:w}},fe=({initialData:r=null,scope:l,controls:t="dots",loop:e=!0,peak:p=!1,gap:d=null,arrows:c=!0,arrowsOnMainImage:u=!1,zoom:h=!1,videos:o=!1,imageParams:_,thumbnailParams:w,children:n,slots:y,...g})=>{const A=P("PDP.Product.Image.label").label,[s,v]=M(r),[f,B]=M(null),[H,N]=M(!1),[R,j]=M(null),F=G(r);D(()=>{F.current=s},[s]);const V=G(o);V.current=o,D(()=>{const E=L.on("pdp/data",C=>{if(!C){v(null),B(null),N(!1);return}if(ue(F.current,C,V.current)){v(C),B(null),N(!1);return}B(C),N(!1)},{scope:l});return()=>{E==null||E.off()}},[l]);const Q=S(()=>ie(f,o),[f,o]),{ready:U}=le(Q,{enabled:!!f});D(()=>{if(!f||!U)return;const E=()=>{v(f),B(null),N(!1)};if(pe()){E();return}const C=window.requestAnimationFrame(()=>N(!0)),J=window.setTimeout(E,de+50);return()=>{window.cancelAnimationFrame(C),window.clearTimeout(J)}},[U,f]);const{mediaItems:I,galleryItems:$,thumbnails:Y}=q({data:s,videos:o,imageParams:_,thumbnailParams:w,zoom:h,slots:y,ImagesLabel:A,onZoom:j}),T=q({data:f,videos:o,imageParams:_,thumbnailParams:w,zoom:h,slots:y,ImagesLabel:A});if(!s)return null;const X=["pdp-product-gallery__stack",g.className].filter(Boolean).join(" "),Z=["pdp-product-gallery__layer","pdp-product-gallery__layer--pending",H?"pdp-product-gallery__layer--entering":""].filter(Boolean).join(" ");return O("div",{...g,className:X,children:[i("div",{className:"pdp-product-gallery__layer",children:i(k,{arrows:!!I.length&&c,arrowsOnMainImage:u,controls:I.length?t:void 0,loop:e&&!!I.length,peak:!!I.length&&p,gap:d,defaultIndex:R||0,thumbnails:Y,children:$})}),f?i("div",{className:Z,"aria-hidden":"true",children:i(k,{arrows:!!T.mediaItems.length&&c,arrowsOnMainImage:u,controls:T.mediaItems.length?t:void 0,loop:e&&!!T.mediaItems.length,peak:!!T.mediaItems.length&&p,gap:d,defaultIndex:0,thumbnails:T.thumbnails,children:T.galleryItems})}):null,R===null?null:i(b,{onClose:()=>j(null),centered:!0,children:i(k,{arrows:!!I.length,width:"100%",height:"100%",defaultIndex:R,loop:e&&!!I.length,controls:"dots",isZoomed:!0,children:$})})]})};fe.getInitialData=a;export{fe as ProductGallery,fe as default};
|
|
4
4
|
//# sourceMappingURL=ProductGallery.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProductGallery.js","sources":["/@dropins/storefront-pdp/src/lib/videoUtils.ts","/@dropins/storefront-pdp/src/lib/usePreloadImages.ts","/@dropins/storefront-pdp/src/containers/ProductGallery/ProductGallery.tsx"],"sourcesContent":["/**\n * Video utility functions for ProductGallery\n */\n\nconst VIDEO_EXTENSIONS = ['.mp4', '.webm', '.ogg', '.mov', '.avi', '.mkv'];\n\nconst VIDEO_MIME_TYPES: Record<string, string> = {\n '.mp4': 'video/mp4',\n '.webm': 'video/webm',\n '.ogg': 'video/ogg',\n '.mov': 'video/quicktime',\n '.avi': 'video/x-msvideo',\n '.mkv': 'video/x-matroska',\n};\n\n/**\n * Gets the MIME type for a video URL based on file extension\n * @param url - The video URL\n * @returns The MIME type string, defaults to 'video/mp4' if unknown\n */\nexport function getVideoMimeType(url: string): string {\n if (!url) return 'video/mp4';\n const lowerUrl = url.toLowerCase();\n const ext = VIDEO_EXTENSIONS.find((e) => lowerUrl.endsWith(e));\n return ext ? VIDEO_MIME_TYPES[ext] : 'video/mp4';\n}\n\n/**\n * Checks if URL is a direct video file based on extension\n * @param url - The video URL\n * @returns true if direct video file\n */\nexport function isDirectVideoFile(url: string): boolean {\n if (!url) return false;\n const lowerUrl = url.toLowerCase();\n return VIDEO_EXTENSIONS.some((ext) => lowerUrl.endsWith(ext));\n}\n\n/**\n * Gets the preview image URL for a video.\n * Uses provided preview URL if available, otherwise tries to derive from video URL.\n * @param videoUrl - The video URL\n * @param previewUrl - The preview URL from data (if available)\n * @returns The preview image URL or undefined\n */\nexport function getVideoPreviewUrl(\n videoUrl: string,\n previewUrl?: string\n): string | undefined {\n // Use provided preview URL if available\n if (previewUrl) return previewUrl;\n\n // Fallback: Derive thumbnail for AEM Assets URLs\n // Pattern: .../urn:aaid:aem:.../play -> .../urn:aaid:aem:.../as/thumbnail.png\n if (videoUrl?.includes('adobeaemcloud.com') && videoUrl.endsWith('/play')) {\n return videoUrl.replace(/\\/play$/, '/as/thumbnail.png');\n }\n\n return undefined;\n}\n\n/**\n * Converts YouTube/Vimeo URLs to embeddable URLs.\n * Returns original URL for other video sources.\n * @param url - The original video URL\n * @returns The embed URL\n */\nexport function getEmbedUrl(url: string): string {\n if (!url) return '';\n\n // YouTube: various formats\n // https://www.youtube.com/watch?v=VIDEO_ID\n // https://youtu.be/VIDEO_ID\n // https://www.youtube.com/embed/VIDEO_ID\n const youtubeMatch = url.match(\n /(?:youtube\\.com\\/(?:watch\\?v=|embed\\/)|youtu\\.be\\/)([a-zA-Z0-9_-]+)/\n );\n if (youtubeMatch) {\n return `https://www.youtube.com/embed/${youtubeMatch[1]}?rel=0`;\n }\n\n // Vimeo: various formats\n // https://vimeo.com/VIDEO_ID\n // https://player.vimeo.com/video/VIDEO_ID\n const vimeoMatch = url.match(/vimeo\\.com\\/(?:video\\/)?(\\d+)/);\n if (vimeoMatch) {\n return `https://player.vimeo.com/video/${vimeoMatch[1]}`;\n }\n\n // Return original URL for other sources (AEM, etc.)\n return url;\n}\n","/**\n * ADOBE CONFIDENTIAL\n * __________________\n * Copyright 2026 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 { useEffect, useState } from 'preact/compat';\n\nexport interface UsePreloadImagesOptions {\n /** Skip the preload entirely; ready resolves to true synchronously. */\n enabled?: boolean;\n /**\n * Maximum time to wait for all images before giving up and reporting ready=true\n * with error=true. Prevents a single broken URL from soft-locking consumers.\n */\n timeoutMs?: number;\n}\n\nexport interface UsePreloadImagesResult {\n ready: boolean;\n error: boolean;\n}\n\nconst DEFAULT_TIMEOUT_MS = 3000;\n\n/**\n * Preloads a list of image URLs in the background and reports when all are\n * decoded and ready to paint. Used to avoid visible flicker when a gallery\n * needs to swap to a new set of images.\n *\n * - Calls img.decode() when available (guarantees paint readiness); falls\n * back to onload otherwise.\n * - Cancels stale state updates when the URL list changes; the underlying\n * network requests continue in the background and are left to the browser.\n * - Always resolves ready=true after timeoutMs as a safety fallback.\n *\n * `ready` is derived synchronously from the URL list, so a transition to a\n * new non-empty url set immediately reports ready=false in the same render —\n * avoiding races where consumers would otherwise see a stale ready=true.\n */\nexport function usePreloadImages(\n urls: string[],\n {\n enabled = true,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n }: UsePreloadImagesOptions = {}\n): UsePreloadImagesResult {\n // \\0 cannot appear in a URL, so this avoids collisions with URLs that\n // contain spaces or other delimiter-like characters.\n const key = urls.join('\\0');\n const trivial = !enabled || urls.length === 0;\n\n const [loadedKey, setLoadedKey] = useState<string | null>(null);\n const [errorKey, setErrorKey] = useState<string | null>(null);\n\n useEffect(() => {\n if (trivial) {\n setLoadedKey(key);\n setErrorKey(null);\n return undefined;\n }\n\n let cancelled = false;\n let remaining = urls.length;\n let hadError = false;\n\n const finish = () => {\n if (cancelled) return;\n cancelled = true;\n if (hadError) setErrorKey(key);\n setLoadedKey(key);\n };\n\n const timeoutId = window.setTimeout(() => {\n hadError = true;\n finish();\n }, timeoutMs);\n\n const onOne = (failed: boolean) => {\n if (cancelled) return;\n if (failed) hadError = true;\n remaining -= 1;\n if (remaining <= 0) {\n window.clearTimeout(timeoutId);\n finish();\n }\n };\n\n urls.forEach((url) => {\n const img = new Image();\n img.src = url;\n if (typeof img.decode === 'function') {\n img\n .decode()\n .then(() => onOne(false))\n .catch(() => onOne(true));\n } else {\n img.onload = () => onOne(false);\n img.onerror = () => onOne(true);\n }\n });\n\n return () => {\n cancelled = true;\n window.clearTimeout(timeoutId);\n };\n // key intentionally drives the effect; urls is its source.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [key, enabled, timeoutMs, trivial]);\n\n const ready = trivial || loadedKey === key;\n const error = errorKey === key;\n return { ready, error };\n}\n","import {\n HTMLAttributes,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'preact/compat';\nimport {\n Container,\n ResolveImageUrlOptions,\n Slot,\n SlotProps,\n} from '@adobe-commerce/elsie/lib';\n\nimport { Image, ImageProps } from '@adobe-commerce/elsie/components';\nimport { events } from '@adobe-commerce/event-bus';\nimport { ProductModel } from '@/pdp/data/models/product-model';\nimport { getFetchedProductData } from '@/pdp/api';\nimport { useText } from '@adobe-commerce/elsie/i18n';\nimport { Carousel, Overlay, Zoom } from '@/pdp/components';\nimport {\n isDirectVideoFile,\n getEmbedUrl,\n getVideoPreviewUrl,\n getVideoMimeType,\n} from '@/pdp/lib/videoUtils';\nimport { usePreloadImages } from '@/pdp/lib/usePreloadImages';\nimport '@/pdp/containers/ProductGallery/ProductGallery.css';\n\n// Total time we hold the pending layer before promoting it. Must exceed the\n// CSS transition duration in ProductGallery.css (currently 180ms). If you\n// change one, update the other.\nconst CROSSFADE_MS = 200;\n\ntype DefaultSlotContext = {\n data: ProductModel | null;\n};\n\ntype VideosProp = boolean | { position: 'first' | 'last' };\n\nexport interface ProductGalleryProps\n extends Omit<HTMLAttributes<HTMLDivElement>, 'controls'> {\n scope?: string;\n controls?: 'thumbnailsRow' | 'thumbnailsColumn' | 'dots' | null;\n loop?: boolean;\n peak?: boolean;\n gap?: 'small' | 'medium' | 'large' | null;\n arrows?: boolean;\n arrowsOnMainImage?: boolean;\n imageParams?: ResolveImageUrlOptions;\n thumbnailParams?: ResolveImageUrlOptions;\n zoom?: { closeButton: boolean } | boolean;\n videos?: VideosProp;\n slots?: {\n CarouselThumbnail?: SlotProps<\n DefaultSlotContext & {\n defaultImageProps: ImageProps;\n mediaType?: 'image' | 'video';\n previewUrl?: string;\n }\n >;\n CarouselMainImage?: SlotProps<\n DefaultSlotContext & {\n defaultImageProps: ImageProps;\n mediaType?: 'image' | 'video';\n previewUrl?: string;\n }\n >;\n };\n}\n\ntype MediaItem =\n | { type: 'image'; url: string; label: string }\n | {\n type: 'video';\n url: string;\n label: string;\n preview?: { url: string; label?: string };\n };\n\nconst buildMediaItems = (\n data: ProductModel | null,\n videos: VideosProp\n): MediaItem[] => {\n const imageItems: MediaItem[] =\n data?.images?.map((img) => ({\n type: 'image' as const,\n url: img.url,\n label: img.label,\n })) ?? [];\n\n if (!videos) return imageItems;\n\n const videoItems: MediaItem[] =\n data?.videos?.map((video) => ({\n type: 'video' as const,\n url: video.url,\n label: video.title ?? '',\n preview: video.preview,\n })) ?? [];\n\n const position = typeof videos === 'object' ? videos.position : 'last';\n return position === 'first'\n ? [...videoItems, ...imageItems]\n : [...imageItems, ...videoItems];\n};\n\nconst collectPreloadUrls = (\n data: ProductModel | null,\n videos: VideosProp\n): string[] => {\n if (!data) return [];\n const urls: string[] = (data.images ?? []).map((img) => img.url);\n if (videos) {\n (data.videos ?? []).forEach((video) => {\n const previewUrl = getVideoPreviewUrl(video.url, video.preview?.url);\n if (previewUrl) urls.push(previewUrl);\n });\n }\n return urls;\n};\n\nconst sameMediaUrls = (\n a: ProductModel | null,\n b: ProductModel | null,\n videos: VideosProp\n): boolean => {\n if (a === b) return true;\n if (!a || !b) return false;\n\n const aImages = a.images ?? [];\n const bImages = b.images ?? [];\n if (aImages.length !== bImages.length) return false;\n for (let i = 0; i < aImages.length; i += 1) {\n if (aImages[i].url !== bImages[i].url) return false;\n }\n\n if (!videos) return true;\n\n const aVideos = a.videos ?? [];\n const bVideos = b.videos ?? [];\n if (aVideos.length !== bVideos.length) return false;\n for (let i = 0; i < aVideos.length; i += 1) {\n if (aVideos[i].url !== bVideos[i].url) return false;\n // Mirror collectPreloadUrls: a video preview thumbnail change should\n // also trigger the buffered swap, not the fast path.\n const aPreview = getVideoPreviewUrl(\n aVideos[i].url,\n aVideos[i].preview?.url\n );\n const bPreview = getVideoPreviewUrl(\n bVideos[i].url,\n bVideos[i].preview?.url\n );\n if (aPreview !== bPreview) return false;\n }\n return true;\n};\n\nconst prefersReducedMotion = (): boolean =>\n typeof window !== 'undefined' &&\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n\ninterface GalleryContentArgs {\n data: ProductModel | null;\n videos: VideosProp;\n imageParams?: ResolveImageUrlOptions;\n thumbnailParams?: ResolveImageUrlOptions;\n zoom: ProductGalleryProps['zoom'];\n slots: ProductGalleryProps['slots'];\n ImagesLabel?: string;\n onZoom?: (key: number) => void;\n}\n\nconst useGalleryContent = ({\n data,\n videos,\n imageParams,\n thumbnailParams,\n zoom,\n slots,\n ImagesLabel,\n onZoom,\n}: GalleryContentArgs) => {\n const defaultSlotContext: DefaultSlotContext = useMemo(\n () => ({ data }),\n [data]\n );\n\n const mediaItems = useMemo(\n () => buildMediaItems(data, videos),\n [data, videos]\n );\n\n const galleryItems = useMemo(\n () =>\n mediaItems.length > 0 ? (\n mediaItems.map((item, key) => {\n const Item = ({ ...itemProps }) => {\n const defaultProps = {\n title: item.label,\n src: item.url,\n alt: ImagesLabel?.replace('{product}', item.label)\n .replace('{key}', String(key + 1))\n .replace('{total}', String(mediaItems.length)),\n\n // TODO: change width/height for image aspect ratio\n // pending https://jira.corp.adobe.com/browse/DATA-5122\n width: imageParams?.width ?? 960,\n height: imageParams?.height ?? 1191,\n params: imageParams ?? { width: 960 },\n loading: key === 0 ? 'eager' : 'lazy',\n ...itemProps,\n } as const;\n\n const previewUrl =\n item.type === 'video'\n ? getVideoPreviewUrl(item.url, item.preview?.url)\n : undefined;\n\n return (\n <Slot\n name=\"CarouselMainImage\"\n slot={slots?.CarouselMainImage}\n context={{\n ...defaultSlotContext,\n defaultImageProps: defaultProps,\n mediaType: item.type,\n previewUrl,\n }}\n >\n {item.type === 'video' ? (\n isDirectVideoFile(item.url) ? (\n <video\n className=\"pdp-product-gallery__video\"\n controls\n preload=\"metadata\"\n poster={previewUrl}\n width={imageParams?.width ?? 960}\n height={imageParams?.height ?? 1191}\n >\n <source\n src={item.url}\n type={getVideoMimeType(item.url)}\n />\n Your browser does not support the video tag.\n </video>\n ) : (\n <iframe\n className=\"pdp-product-gallery__video-iframe\"\n src={getEmbedUrl(item.url)}\n title={item.label || 'Product video'}\n width={imageParams?.width ?? 960}\n height={imageParams?.height ?? 1191}\n loading=\"lazy\"\n allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\"\n allowFullScreen\n />\n )\n ) : (\n <Image {...defaultProps} />\n )}\n </Slot>\n );\n };\n\n return zoom && item.type === 'image' ? (\n <Zoom\n key={item.url}\n closeButton={typeof zoom === 'object' ? zoom.closeButton : false}\n >\n <Item />\n </Zoom>\n ) : (\n <Item key={item.url} onClick={() => onZoom?.(key)} />\n );\n })\n ) : (\n <img\n key=\"pleaceholder\"\n src=\"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\"\n className=\"pdp-product-gallery__images__placeholder\"\n width={imageParams?.width ?? 960}\n height={imageParams?.height ?? 1191}\n aria-hidden\n />\n ),\n [\n ImagesLabel,\n mediaItems,\n imageParams,\n zoom,\n defaultSlotContext,\n slots?.CarouselMainImage,\n onZoom,\n ]\n );\n\n const thumbnails = useMemo(() => {\n return mediaItems.length > 0 ? (\n mediaItems.map((item, key) => {\n const defaultProps = {\n title: item.label,\n src: item.url,\n alt: ImagesLabel?.replace('{product}', item.label)\n .replace('{key}', String(key + 1))\n .replace('{total}', String(mediaItems.length)),\n\n // TODO: change width/height for image aspect ratio\n // pending https://jira.corp.adobe.com/browse/DATA-5122\n width: thumbnailParams?.width ?? 200,\n height: thumbnailParams?.height ?? 248,\n params: thumbnailParams ?? { width: 200 },\n loading: 'lazy',\n } as const;\n\n const previewUrl =\n item.type === 'video'\n ? getVideoPreviewUrl(item.url, item.preview?.url)\n : undefined;\n\n return (\n <Slot\n key={item.url}\n name=\"CarouselThumbnail\"\n slotTag=\"span\"\n contentTag=\"span\"\n slot={slots?.CarouselThumbnail}\n context={{\n ...defaultSlotContext,\n defaultImageProps: defaultProps,\n mediaType: item.type,\n previewUrl,\n }}\n >\n {item.type === 'video' ? (\n <span\n className=\"pdp-product-gallery__video-thumbnail\"\n role=\"img\"\n aria-label={`Play video: ${item.label || 'Product video'}`}\n >\n {previewUrl ? (\n <img\n src={previewUrl}\n alt=\"\"\n width={thumbnailParams?.width ?? 200}\n height={thumbnailParams?.height ?? 248}\n loading=\"lazy\"\n aria-hidden=\"true\"\n />\n ) : (\n <span\n className=\"pdp-product-gallery__video-thumbnail-placeholder\"\n style={{\n width: thumbnailParams?.width ?? 200,\n height: thumbnailParams?.height ?? 248,\n }}\n aria-hidden=\"true\"\n />\n )}\n <span\n className=\"pdp-product-gallery__video-icon\"\n aria-hidden=\"true\"\n >\n ▶\n </span>\n </span>\n ) : (\n <Image {...defaultProps} />\n )}\n </Slot>\n );\n })\n ) : (\n <img\n key=\"pleaceholder\"\n src=\"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\"\n className=\"pdp-product-gallery__thumbnail__placeholder\"\n width={thumbnailParams?.width ?? 200}\n height={thumbnailParams?.height ?? 248}\n aria-hidden\n />\n );\n }, [\n ImagesLabel,\n mediaItems,\n thumbnailParams,\n defaultSlotContext,\n slots?.CarouselThumbnail,\n ]);\n\n return { mediaItems, galleryItems, thumbnails };\n};\n\nexport const ProductGallery: Container<\n ProductGalleryProps,\n ProductModel | null\n> = ({\n initialData = null,\n scope,\n controls = 'dots',\n loop = true,\n peak = false,\n gap = null,\n arrows = true,\n arrowsOnMainImage = false,\n zoom = false,\n videos = false,\n imageParams,\n thumbnailParams,\n children,\n slots,\n ...props\n}) => {\n const ImagesLabel = useText('PDP.Product.Image.label').label;\n\n const [displayedData, setDisplayedData] = useState<ProductModel | null>(\n initialData\n );\n const [pendingData, setPendingData] = useState<ProductModel | null>(null);\n const [entering, setEntering] = useState(false);\n const [zoomTo, setZoomTo] = useState<number | null>(null);\n\n const displayedRef = useRef<ProductModel | null>(initialData);\n useEffect(() => {\n displayedRef.current = displayedData;\n }, [displayedData]);\n\n // videosRef avoids re-subscribing the event listener when a consumer passes\n // an inline object for `videos` (a fresh reference on every parent render).\n const videosRef = useRef(videos);\n videosRef.current = videos;\n\n useEffect(() => {\n const dataEvent = events.on(\n 'pdp/data',\n (newData: ProductModel | null) => {\n if (!newData) {\n setDisplayedData(null);\n setPendingData(null);\n setEntering(false);\n return;\n }\n\n if (sameMediaUrls(displayedRef.current, newData, videosRef.current)) {\n // Same media set — fast path, skip buffering and crossfade.\n setDisplayedData(newData);\n setPendingData(null);\n setEntering(false);\n return;\n }\n\n setPendingData(newData);\n setEntering(false);\n },\n { scope }\n );\n return () => {\n dataEvent?.off();\n };\n }, [scope]);\n\n const pendingUrls = useMemo(\n () => collectPreloadUrls(pendingData, videos),\n [pendingData, videos]\n );\n\n const { ready: pendingReady } = usePreloadImages(pendingUrls, {\n enabled: !!pendingData,\n });\n\n useEffect(() => {\n if (!pendingData || !pendingReady) return undefined;\n\n const promote = () => {\n setDisplayedData(pendingData);\n setPendingData(null);\n setEntering(false);\n };\n\n if (prefersReducedMotion()) {\n promote();\n return undefined;\n }\n\n // Mount pending layer in opacity:0, flip to 1 on the next frame so the\n // browser commits the initial style before the transition starts.\n const raf = window.requestAnimationFrame(() => setEntering(true));\n const timer = window.setTimeout(promote, CROSSFADE_MS + 50);\n\n return () => {\n window.cancelAnimationFrame(raf);\n window.clearTimeout(timer);\n };\n }, [pendingReady, pendingData]);\n\n const { mediaItems, galleryItems, thumbnails } = useGalleryContent({\n data: displayedData,\n videos,\n imageParams,\n thumbnailParams,\n zoom,\n slots,\n ImagesLabel,\n onZoom: setZoomTo,\n });\n\n const pendingContent = useGalleryContent({\n data: pendingData,\n videos,\n imageParams,\n thumbnailParams,\n zoom,\n slots,\n ImagesLabel,\n // No onZoom: pending layer is non-interactive.\n });\n\n if (!displayedData) return null;\n\n const stackClassName = ['pdp-product-gallery__stack', props.className]\n .filter(Boolean)\n .join(' ');\n\n const pendingLayerClassName = [\n 'pdp-product-gallery__layer',\n 'pdp-product-gallery__layer--pending',\n entering ? 'pdp-product-gallery__layer--entering' : '',\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <div {...props} className={stackClassName}>\n <div className=\"pdp-product-gallery__layer\">\n <Carousel\n arrows={!!mediaItems.length && arrows}\n arrowsOnMainImage={arrowsOnMainImage}\n controls={mediaItems.length ? controls : undefined}\n loop={loop && !!mediaItems.length}\n peak={!!mediaItems.length && peak}\n gap={gap}\n defaultIndex={zoomTo || 0}\n thumbnails={thumbnails}\n >\n {galleryItems}\n </Carousel>\n </div>\n\n {pendingData ? (\n <div className={pendingLayerClassName} aria-hidden=\"true\">\n <Carousel\n arrows={!!pendingContent.mediaItems.length && arrows}\n arrowsOnMainImage={arrowsOnMainImage}\n controls={pendingContent.mediaItems.length ? controls : undefined}\n loop={loop && !!pendingContent.mediaItems.length}\n peak={!!pendingContent.mediaItems.length && peak}\n gap={gap}\n defaultIndex={0}\n thumbnails={pendingContent.thumbnails}\n >\n {pendingContent.galleryItems}\n </Carousel>\n </div>\n ) : null}\n\n {/* Zoom Overlay (always uses displayed data) */}\n {zoomTo === null ? null : (\n <Overlay onClose={() => setZoomTo(null)} centered>\n <Carousel\n arrows={!!mediaItems.length}\n width=\"100%\"\n height=\"100%\"\n defaultIndex={zoomTo}\n loop={loop && !!mediaItems.length}\n controls=\"dots\"\n isZoomed\n >\n {galleryItems}\n </Carousel>\n </Overlay>\n )}\n </div>\n );\n};\n\nProductGallery.getInitialData = getFetchedProductData;\n"],"names":["VIDEO_EXTENSIONS","VIDEO_MIME_TYPES","getVideoMimeType","url","lowerUrl","ext","isDirectVideoFile","getVideoPreviewUrl","videoUrl","previewUrl","getEmbedUrl","youtubeMatch","vimeoMatch","DEFAULT_TIMEOUT_MS","usePreloadImages","urls","enabled","timeoutMs","key","trivial","loadedKey","setLoadedKey","useState","errorKey","setErrorKey","useEffect","cancelled","remaining","hadError","finish","timeoutId","onOne","failed","img","CROSSFADE_MS","buildMediaItems","data","videos","imageItems","_a","videoItems","_b","video","collectPreloadUrls","sameMediaUrls","a","b","aImages","bImages","i","aVideos","bVideos","aPreview","bPreview","prefersReducedMotion","useGalleryContent","imageParams","thumbnailParams","zoom","slots","ImagesLabel","onZoom","defaultSlotContext","useMemo","mediaItems","galleryItems","item","Item","itemProps","defaultProps","jsx","Slot","jsxs","Image","Zoom","thumbnails","ProductGallery","initialData","scope","controls","loop","peak","gap","arrows","arrowsOnMainImage","children","props","useText","displayedData","setDisplayedData","pendingData","setPendingData","entering","setEntering","zoomTo","setZoomTo","displayedRef","useRef","videosRef","dataEvent","events","newData","pendingUrls","pendingReady","promote","raf","timer","pendingContent","stackClassName","pendingLayerClassName","Carousel","Overlay","getFetchedProductData"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ProductGallery.js","sources":["/@dropins/storefront-pdp/src/lib/videoUtils.ts","/@dropins/storefront-pdp/src/lib/usePreloadImages.ts","/@dropins/storefront-pdp/src/containers/ProductGallery/ProductGallery.tsx"],"sourcesContent":["/**\n * Video utility functions for ProductGallery\n */\n\nconst VIDEO_EXTENSIONS = ['.mp4', '.webm', '.ogg', '.mov', '.avi', '.mkv'];\n\nconst VIDEO_MIME_TYPES: Record<string, string> = {\n '.mp4': 'video/mp4',\n '.webm': 'video/webm',\n '.ogg': 'video/ogg',\n '.mov': 'video/quicktime',\n '.avi': 'video/x-msvideo',\n '.mkv': 'video/x-matroska',\n};\n\n/**\n * Gets the MIME type for a video URL based on file extension\n * @param url - The video URL\n * @returns The MIME type string, defaults to 'video/mp4' if unknown\n */\nexport function getVideoMimeType(url: string): string {\n if (!url) return 'video/mp4';\n const lowerUrl = url.toLowerCase();\n const ext = VIDEO_EXTENSIONS.find((e) => lowerUrl.endsWith(e));\n return ext ? VIDEO_MIME_TYPES[ext] : 'video/mp4';\n}\n\n/**\n * Checks if URL is a direct video file based on extension\n * @param url - The video URL\n * @returns true if direct video file\n */\nexport function isDirectVideoFile(url: string): boolean {\n if (!url) return false;\n const lowerUrl = url.toLowerCase();\n return VIDEO_EXTENSIONS.some((ext) => lowerUrl.endsWith(ext));\n}\n\n/**\n * Gets the preview image URL for a video.\n * Uses provided preview URL if available, otherwise tries to derive from video URL.\n * @param videoUrl - The video URL\n * @param previewUrl - The preview URL from data (if available)\n * @returns The preview image URL or undefined\n */\nexport function getVideoPreviewUrl(\n videoUrl: string,\n previewUrl?: string\n): string | undefined {\n // Use provided preview URL if available\n if (previewUrl) return previewUrl;\n\n // Fallback: Derive thumbnail for AEM Assets URLs\n // Pattern: .../urn:aaid:aem:.../play -> .../urn:aaid:aem:.../as/thumbnail.png\n if (videoUrl?.includes('adobeaemcloud.com') && videoUrl.endsWith('/play')) {\n return videoUrl.replace(/\\/play$/, '/as/thumbnail.png');\n }\n\n return undefined;\n}\n\n/**\n * Converts YouTube/Vimeo URLs to embeddable URLs.\n * Returns original URL for other video sources.\n * @param url - The original video URL\n * @returns The embed URL\n */\nexport function getEmbedUrl(url: string): string {\n if (!url) return '';\n\n // YouTube: various formats\n // https://www.youtube.com/watch?v=VIDEO_ID\n // https://youtu.be/VIDEO_ID\n // https://www.youtube.com/embed/VIDEO_ID\n const youtubeMatch = url.match(\n /(?:youtube\\.com\\/(?:watch\\?v=|embed\\/)|youtu\\.be\\/)([a-zA-Z0-9_-]+)/\n );\n if (youtubeMatch) {\n return `https://www.youtube.com/embed/${youtubeMatch[1]}?rel=0`;\n }\n\n // Vimeo: various formats\n // https://vimeo.com/VIDEO_ID\n // https://player.vimeo.com/video/VIDEO_ID\n const vimeoMatch = url.match(/vimeo\\.com\\/(?:video\\/)?(\\d+)/);\n if (vimeoMatch) {\n return `https://player.vimeo.com/video/${vimeoMatch[1]}`;\n }\n\n // Return original URL for other sources (AEM, etc.)\n return url;\n}\n","/**\n * ADOBE CONFIDENTIAL\n * __________________\n * Copyright 2026 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 { useEffect, useState } from 'preact/compat';\n\nexport interface UsePreloadImagesOptions {\n /** Skip the preload entirely; ready resolves to true synchronously. */\n enabled?: boolean;\n /**\n * Maximum time to wait for all images before giving up and reporting ready=true\n * with error=true. Prevents a single broken URL from soft-locking consumers.\n */\n timeoutMs?: number;\n}\n\nexport interface UsePreloadImagesResult {\n ready: boolean;\n error: boolean;\n}\n\nconst DEFAULT_TIMEOUT_MS = 3000;\n\n/**\n * Preloads a list of image URLs in the background and reports when all are\n * decoded and ready to paint. Used to avoid visible flicker when a gallery\n * needs to swap to a new set of images.\n *\n * - Calls img.decode() when available (guarantees paint readiness); falls\n * back to onload otherwise.\n * - Cancels stale state updates when the URL list changes; the underlying\n * network requests continue in the background and are left to the browser.\n * - Always resolves ready=true after timeoutMs as a safety fallback.\n *\n * `ready` is derived synchronously from the URL list, so a transition to a\n * new non-empty url set immediately reports ready=false in the same render —\n * avoiding races where consumers would otherwise see a stale ready=true.\n */\nexport function usePreloadImages(\n urls: string[],\n {\n enabled = true,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n }: UsePreloadImagesOptions = {}\n): UsePreloadImagesResult {\n // \\0 cannot appear in a URL, so this avoids collisions with URLs that\n // contain spaces or other delimiter-like characters.\n const key = urls.join('\\0');\n const trivial = !enabled || urls.length === 0;\n\n const [loadedKey, setLoadedKey] = useState<string | null>(null);\n const [errorKey, setErrorKey] = useState<string | null>(null);\n\n useEffect(() => {\n if (trivial) {\n setLoadedKey(key);\n setErrorKey(null);\n return undefined;\n }\n\n let cancelled = false;\n let remaining = urls.length;\n let hadError = false;\n\n const finish = () => {\n if (cancelled) return;\n cancelled = true;\n if (hadError) setErrorKey(key);\n setLoadedKey(key);\n };\n\n const timeoutId = window.setTimeout(() => {\n hadError = true;\n finish();\n }, timeoutMs);\n\n const onOne = (failed: boolean) => {\n if (cancelled) return;\n if (failed) hadError = true;\n remaining -= 1;\n if (remaining <= 0) {\n window.clearTimeout(timeoutId);\n finish();\n }\n };\n\n urls.forEach((url) => {\n const img = new Image();\n img.src = url;\n if (typeof img.decode === 'function') {\n img\n .decode()\n .then(() => onOne(false))\n .catch(() => onOne(true));\n } else {\n img.onload = () => onOne(false);\n img.onerror = () => onOne(true);\n }\n });\n\n return () => {\n cancelled = true;\n window.clearTimeout(timeoutId);\n };\n // key intentionally drives the effect; urls is its source.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [key, enabled, timeoutMs, trivial]);\n\n const ready = trivial || loadedKey === key;\n const error = errorKey === key;\n return { ready, error };\n}\n","import {\n HTMLAttributes,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'preact/compat';\nimport {\n Container,\n ResolveImageUrlOptions,\n Slot,\n SlotProps,\n} from '@adobe-commerce/elsie/lib';\n\nimport { Image, ImageProps } from '@adobe-commerce/elsie/components';\nimport { events } from '@adobe-commerce/event-bus';\nimport { ProductModel } from '@/pdp/data/models/product-model';\nimport { getFetchedProductData } from '@/pdp/api';\nimport { useText } from '@adobe-commerce/elsie/i18n';\nimport { Carousel, Overlay, Zoom } from '@/pdp/components';\nimport {\n isDirectVideoFile,\n getEmbedUrl,\n getVideoPreviewUrl,\n getVideoMimeType,\n} from '@/pdp/lib/videoUtils';\nimport { usePreloadImages } from '@/pdp/lib/usePreloadImages';\nimport '@/pdp/containers/ProductGallery/ProductGallery.css';\n\n// Total time we hold the pending layer before promoting it. Must exceed the\n// CSS transition duration in ProductGallery.css (currently 180ms). If you\n// change one, update the other.\nconst CROSSFADE_MS = 200;\n\ntype DefaultSlotContext = {\n data: ProductModel | null;\n};\n\ntype VideosProp = boolean | { position: 'first' | 'last' };\n\nexport interface ProductGalleryProps\n extends Omit<HTMLAttributes<HTMLDivElement>, 'controls'> {\n scope?: string;\n controls?: 'thumbnailsRow' | 'thumbnailsColumn' | 'dots' | null;\n loop?: boolean;\n peak?: boolean;\n gap?: 'small' | 'medium' | 'large' | null;\n arrows?: boolean;\n arrowsOnMainImage?: boolean;\n imageParams?: ResolveImageUrlOptions;\n thumbnailParams?: ResolveImageUrlOptions;\n zoom?: { closeButton: boolean } | boolean;\n videos?: VideosProp;\n slots?: {\n CarouselThumbnail?: SlotProps<\n DefaultSlotContext & {\n defaultImageProps: ImageProps;\n mediaType?: 'image' | 'video';\n previewUrl?: string;\n }\n >;\n CarouselMainImage?: SlotProps<\n DefaultSlotContext & {\n defaultImageProps: ImageProps;\n mediaType?: 'image' | 'video';\n previewUrl?: string;\n }\n >;\n };\n}\n\ntype MediaItem =\n | { type: 'image'; url: string; label: string }\n | {\n type: 'video';\n url: string;\n label: string;\n preview?: { url: string; label?: string };\n };\n\nconst buildMediaItems = (\n data: ProductModel | null,\n videos: VideosProp\n): MediaItem[] => {\n const imageItems: MediaItem[] =\n data?.images?.map((img) => ({\n type: 'image' as const,\n url: img.url,\n label: img.label,\n })) ?? [];\n\n if (!videos) return imageItems;\n\n const videoItems: MediaItem[] =\n data?.videos?.map((video) => ({\n type: 'video' as const,\n url: video.url,\n label: video.title ?? '',\n preview: video.preview,\n })) ?? [];\n\n const position = typeof videos === 'object' ? videos.position : 'last';\n return position === 'first'\n ? [...videoItems, ...imageItems]\n : [...imageItems, ...videoItems];\n};\n\nconst collectPreloadUrls = (\n data: ProductModel | null,\n videos: VideosProp\n): string[] => {\n if (!data) return [];\n const urls: string[] = (data.images ?? []).map((img) => img.url);\n if (videos) {\n (data.videos ?? []).forEach((video) => {\n const previewUrl = getVideoPreviewUrl(video.url, video.preview?.url);\n if (previewUrl) urls.push(previewUrl);\n });\n }\n return urls;\n};\n\nconst sameMediaUrls = (\n a: ProductModel | null,\n b: ProductModel | null,\n videos: VideosProp\n): boolean => {\n if (a === b) return true;\n if (!a || !b) return false;\n\n const aImages = a.images ?? [];\n const bImages = b.images ?? [];\n if (aImages.length !== bImages.length) return false;\n for (let i = 0; i < aImages.length; i += 1) {\n if (aImages[i].url !== bImages[i].url) return false;\n }\n\n if (!videos) return true;\n\n const aVideos = a.videos ?? [];\n const bVideos = b.videos ?? [];\n if (aVideos.length !== bVideos.length) return false;\n for (let i = 0; i < aVideos.length; i += 1) {\n if (aVideos[i].url !== bVideos[i].url) return false;\n // Mirror collectPreloadUrls: a video preview thumbnail change should\n // also trigger the buffered swap, not the fast path.\n const aPreview = getVideoPreviewUrl(\n aVideos[i].url,\n aVideos[i].preview?.url\n );\n const bPreview = getVideoPreviewUrl(\n bVideos[i].url,\n bVideos[i].preview?.url\n );\n if (aPreview !== bPreview) return false;\n }\n return true;\n};\n\nconst prefersReducedMotion = (): boolean =>\n typeof window !== 'undefined' &&\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n\ninterface GalleryContentArgs {\n data: ProductModel | null;\n videos: VideosProp;\n imageParams?: ResolveImageUrlOptions;\n thumbnailParams?: ResolveImageUrlOptions;\n zoom: ProductGalleryProps['zoom'];\n slots: ProductGalleryProps['slots'];\n ImagesLabel?: string;\n onZoom?: (key: number) => void;\n}\n\nconst useGalleryContent = ({\n data,\n videos,\n imageParams,\n thumbnailParams,\n zoom,\n slots,\n ImagesLabel,\n onZoom,\n}: GalleryContentArgs) => {\n const defaultSlotContext: DefaultSlotContext = useMemo(\n () => ({ data }),\n [data]\n );\n\n const mediaItems = useMemo(\n () => buildMediaItems(data, videos),\n [data, videos]\n );\n\n const galleryItems = useMemo(\n () =>\n mediaItems.length > 0 ? (\n mediaItems.map((item, key) => {\n const Item = ({ ...itemProps }) => {\n const defaultProps = {\n title: item.label,\n src: item.url,\n alt: ImagesLabel?.replace('{product}', item.label)\n .replace('{key}', String(key + 1))\n .replace('{total}', String(mediaItems.length)),\n\n // TODO: change width/height for image aspect ratio\n // pending https://jira.corp.adobe.com/browse/DATA-5122\n width: imageParams?.width ?? 960,\n height: imageParams?.height ?? 1191,\n params: imageParams ?? { width: 960 },\n loading: key === 0 ? 'eager' : 'lazy',\n ...itemProps,\n } as const;\n\n const previewUrl =\n item.type === 'video'\n ? getVideoPreviewUrl(item.url, item.preview?.url)\n : undefined;\n\n return (\n <Slot\n name=\"CarouselMainImage\"\n slot={slots?.CarouselMainImage}\n context={{\n ...defaultSlotContext,\n defaultImageProps: defaultProps,\n mediaType: item.type,\n previewUrl,\n }}\n >\n {item.type === 'video' ? (\n isDirectVideoFile(item.url) ? (\n <video\n className=\"pdp-product-gallery__video\"\n controls\n preload=\"metadata\"\n poster={previewUrl}\n width={imageParams?.width ?? 960}\n height={imageParams?.height ?? 1191}\n >\n <source\n src={item.url}\n type={getVideoMimeType(item.url)}\n />\n Your browser does not support the video tag.\n </video>\n ) : (\n <iframe\n className=\"pdp-product-gallery__video-iframe\"\n src={getEmbedUrl(item.url)}\n title={item.label || 'Product video'}\n width={imageParams?.width ?? 960}\n height={imageParams?.height ?? 1191}\n loading=\"lazy\"\n allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\"\n allowFullScreen\n />\n )\n ) : (\n <Image {...defaultProps} />\n )}\n </Slot>\n );\n };\n\n return zoom && item.type === 'image' ? (\n <Zoom\n key={item.url}\n closeButton={typeof zoom === 'object' ? zoom.closeButton : false}\n >\n <Item />\n </Zoom>\n ) : (\n <Item key={item.url} onClick={() => onZoom?.(key)} />\n );\n })\n ) : (\n <img\n key=\"pleaceholder\"\n src=\"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\"\n className=\"pdp-product-gallery__images__placeholder\"\n width={imageParams?.width ?? 960}\n height={imageParams?.height ?? 1191}\n aria-hidden\n />\n ),\n [\n ImagesLabel,\n mediaItems,\n imageParams,\n zoom,\n defaultSlotContext,\n slots?.CarouselMainImage,\n onZoom,\n ]\n );\n\n const thumbnails = useMemo(() => {\n return mediaItems.length > 0 ? (\n mediaItems.map((item, key) => {\n const defaultProps = {\n title: item.label,\n src: item.url,\n alt: ImagesLabel?.replace('{product}', item.label)\n .replace('{key}', String(key + 1))\n .replace('{total}', String(mediaItems.length)),\n\n // TODO: change width/height for image aspect ratio\n // pending https://jira.corp.adobe.com/browse/DATA-5122\n width: thumbnailParams?.width ?? 200,\n height: thumbnailParams?.height ?? 248,\n params: thumbnailParams ?? { width: 200 },\n loading: 'lazy',\n } as const;\n\n const previewUrl =\n item.type === 'video'\n ? getVideoPreviewUrl(item.url, item.preview?.url)\n : undefined;\n\n return (\n <Slot\n key={item.url}\n name=\"CarouselThumbnail\"\n slotTag=\"span\"\n contentTag=\"span\"\n slot={slots?.CarouselThumbnail}\n context={{\n ...defaultSlotContext,\n defaultImageProps: defaultProps,\n mediaType: item.type,\n previewUrl,\n }}\n >\n {item.type === 'video' ? (\n <span\n className=\"pdp-product-gallery__video-thumbnail\"\n role=\"img\"\n aria-label={`Play video: ${item.label || 'Product video'}`}\n >\n {previewUrl ? (\n <img\n src={previewUrl}\n alt=\"\"\n width={thumbnailParams?.width ?? 200}\n height={thumbnailParams?.height ?? 248}\n loading=\"lazy\"\n aria-hidden=\"true\"\n />\n ) : (\n <span\n className=\"pdp-product-gallery__video-thumbnail-placeholder\"\n style={{\n width: thumbnailParams?.width ?? 200,\n height: thumbnailParams?.height ?? 248,\n }}\n aria-hidden=\"true\"\n />\n )}\n <span\n className=\"pdp-product-gallery__video-icon\"\n aria-hidden=\"true\"\n >\n ▶\n </span>\n </span>\n ) : (\n <Image {...defaultProps} />\n )}\n </Slot>\n );\n })\n ) : (\n <img\n key=\"pleaceholder\"\n src=\"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\"\n className=\"pdp-product-gallery__thumbnail__placeholder\"\n width={thumbnailParams?.width ?? 200}\n height={thumbnailParams?.height ?? 248}\n aria-hidden\n />\n );\n }, [\n ImagesLabel,\n mediaItems,\n thumbnailParams,\n defaultSlotContext,\n slots?.CarouselThumbnail,\n ]);\n\n return { mediaItems, galleryItems, thumbnails };\n};\n\nexport const ProductGallery: Container<\n ProductGalleryProps,\n ProductModel | null\n> = ({\n initialData = null,\n scope,\n controls = 'dots',\n loop = true,\n peak = false,\n gap = null,\n arrows = true,\n arrowsOnMainImage = false,\n zoom = false,\n videos = false,\n imageParams,\n thumbnailParams,\n children,\n slots,\n ...props\n}) => {\n const ImagesLabel = useText('PDP.Product.Image.label').label;\n\n const [displayedData, setDisplayedData] = useState<ProductModel | null>(\n initialData\n );\n const [pendingData, setPendingData] = useState<ProductModel | null>(null);\n const [entering, setEntering] = useState(false);\n const [zoomTo, setZoomTo] = useState<number | null>(null);\n\n const displayedRef = useRef<ProductModel | null>(initialData);\n useEffect(() => {\n displayedRef.current = displayedData;\n }, [displayedData]);\n\n // videosRef avoids re-subscribing the event listener when a consumer passes\n // an inline object for `videos` (a fresh reference on every parent render).\n const videosRef = useRef(videos);\n videosRef.current = videos;\n\n useEffect(() => {\n const dataEvent = events.on(\n 'pdp/data',\n (newData: ProductModel | null) => {\n if (!newData) {\n setDisplayedData(null);\n setPendingData(null);\n setEntering(false);\n return;\n }\n\n if (sameMediaUrls(displayedRef.current, newData, videosRef.current)) {\n // Same media set — fast path, skip buffering and crossfade.\n setDisplayedData(newData);\n setPendingData(null);\n setEntering(false);\n return;\n }\n\n setPendingData(newData);\n setEntering(false);\n },\n { scope }\n );\n return () => {\n dataEvent?.off();\n };\n }, [scope]);\n\n const pendingUrls = useMemo(\n () => collectPreloadUrls(pendingData, videos),\n [pendingData, videos]\n );\n\n const { ready: pendingReady } = usePreloadImages(pendingUrls, {\n enabled: !!pendingData,\n });\n\n useEffect(() => {\n if (!pendingData || !pendingReady) return undefined;\n\n const promote = () => {\n setDisplayedData(pendingData);\n setPendingData(null);\n setEntering(false);\n };\n\n if (prefersReducedMotion()) {\n promote();\n return undefined;\n }\n\n // Mount pending layer in opacity:0, flip to 1 on the next frame so the\n // browser commits the initial style before the transition starts.\n const raf = window.requestAnimationFrame(() => setEntering(true));\n const timer = window.setTimeout(promote, CROSSFADE_MS + 50);\n\n return () => {\n window.cancelAnimationFrame(raf);\n window.clearTimeout(timer);\n };\n }, [pendingReady, pendingData]);\n\n const { mediaItems, galleryItems, thumbnails } = useGalleryContent({\n data: displayedData,\n videos,\n imageParams,\n thumbnailParams,\n zoom,\n slots,\n ImagesLabel,\n onZoom: setZoomTo,\n });\n\n const pendingContent = useGalleryContent({\n data: pendingData,\n videos,\n imageParams,\n thumbnailParams,\n zoom,\n slots,\n ImagesLabel,\n // No onZoom: pending layer is non-interactive.\n });\n\n if (!displayedData) return null;\n\n const stackClassName = ['pdp-product-gallery__stack', props.className]\n .filter(Boolean)\n .join(' ');\n\n const pendingLayerClassName = [\n 'pdp-product-gallery__layer',\n 'pdp-product-gallery__layer--pending',\n entering ? 'pdp-product-gallery__layer--entering' : '',\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <div {...props} className={stackClassName}>\n <div className=\"pdp-product-gallery__layer\">\n <Carousel\n arrows={!!mediaItems.length && arrows}\n arrowsOnMainImage={arrowsOnMainImage}\n controls={mediaItems.length ? controls : undefined}\n loop={loop && !!mediaItems.length}\n peak={!!mediaItems.length && peak}\n gap={gap}\n defaultIndex={zoomTo || 0}\n thumbnails={thumbnails}\n >\n {galleryItems}\n </Carousel>\n </div>\n\n {pendingData ? (\n <div className={pendingLayerClassName} aria-hidden=\"true\">\n <Carousel\n arrows={!!pendingContent.mediaItems.length && arrows}\n arrowsOnMainImage={arrowsOnMainImage}\n controls={pendingContent.mediaItems.length ? controls : undefined}\n loop={loop && !!pendingContent.mediaItems.length}\n peak={!!pendingContent.mediaItems.length && peak}\n gap={gap}\n defaultIndex={0}\n thumbnails={pendingContent.thumbnails}\n >\n {pendingContent.galleryItems}\n </Carousel>\n </div>\n ) : null}\n\n {/* Zoom Overlay (always uses displayed data) */}\n {zoomTo === null ? null : (\n <Overlay onClose={() => setZoomTo(null)} centered>\n <Carousel\n arrows={!!mediaItems.length}\n width=\"100%\"\n height=\"100%\"\n defaultIndex={zoomTo}\n loop={loop && !!mediaItems.length}\n controls=\"dots\"\n isZoomed\n >\n {galleryItems}\n </Carousel>\n </Overlay>\n )}\n </div>\n );\n};\n\nProductGallery.getInitialData = getFetchedProductData;\n"],"names":["VIDEO_EXTENSIONS","VIDEO_MIME_TYPES","getVideoMimeType","url","lowerUrl","ext","isDirectVideoFile","getVideoPreviewUrl","videoUrl","previewUrl","getEmbedUrl","youtubeMatch","vimeoMatch","DEFAULT_TIMEOUT_MS","usePreloadImages","urls","enabled","timeoutMs","key","trivial","loadedKey","setLoadedKey","useState","errorKey","setErrorKey","useEffect","cancelled","remaining","hadError","finish","timeoutId","onOne","failed","img","CROSSFADE_MS","buildMediaItems","data","videos","imageItems","_a","videoItems","_b","video","collectPreloadUrls","sameMediaUrls","a","b","aImages","bImages","i","aVideos","bVideos","aPreview","bPreview","prefersReducedMotion","useGalleryContent","imageParams","thumbnailParams","zoom","slots","ImagesLabel","onZoom","defaultSlotContext","useMemo","mediaItems","galleryItems","item","Item","itemProps","defaultProps","jsx","Slot","jsxs","Image","Zoom","thumbnails","ProductGallery","initialData","scope","controls","loop","peak","gap","arrows","arrowsOnMainImage","children","props","useText","displayedData","setDisplayedData","pendingData","setPendingData","entering","setEntering","zoomTo","setZoomTo","displayedRef","useRef","videosRef","dataEvent","events","newData","pendingUrls","pendingReady","promote","raf","timer","pendingContent","stackClassName","pendingLayerClassName","Carousel","Overlay","getFetchedProductData"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/*! Copyright 2026 Adobe
|
|
2
2
|
All Rights Reserved. */
|
|
3
|
-
import{jsx as p}from"@dropins/tools/preact-jsx-runtime.js";import{classes as g}from"@dropins/tools/lib.js";import{
|
|
3
|
+
import{jsx as p}from"@dropins/tools/preact-jsx-runtime.js";import{classes as g}from"@dropins/tools/lib.js";import{setProductConfigurationValid as h,setProductConfigurationValues as O,getFetchedProductData as C}from"../api.js";import"@dropins/tools/event-bus.js";import{G as V}from"../chunks/components.js";import{u as v,g as x}from"../chunks/useProductData.js";import"@dropins/tools/fetch-graphql.js";import"@dropins/tools/i18n.js";import"@dropins/tools/preact-compat.js";import"@dropins/tools/components.js";import"@dropins/tools/preact.js";import"@dropins/tools/preact-hooks.js";const P=({initialData:l=null,scope:u,children:N,...e})=>{const{data:r,values:d}=v({scope:u,initialData:l,initialValues:{enteredOptions:[]}}),m=(i,a)=>{const n=d.enteredOptions||[],o=n.findIndex(t=>t.uid===i)!==-1?n.map(t=>t.uid===i?{...t,value:a}:t):[...n,{uid:i,value:a}];O(t=>({...t,enteredOptions:o}))},f=i=>{h(()=>i)};if(!r)return null;const c=x(r,"ac_giftcard");return c.length===0?null:p("div",{...e,className:g(["pdp-gift-card-options",e.className]),children:c.map((i,a)=>{var n,s,o;return p(V,{options:((n=i.value)==null?void 0:n.options)||[],className:e.className,optionValues:(d.enteredOptions||[]).map(t=>({id:t.uid,value:t.value})),currency:(o=(s=r.prices)==null?void 0:s.final)==null?void 0:o.currency,onOptionChange:m,onValidationChange:f},`giftcard-${a}`)})})};P.getInitialData=C;export{P as ProductGiftCardOptions,P as default};
|
|
4
4
|
//# sourceMappingURL=ProductGiftCardOptions.js.map
|