diff --git a/express/code/blocks/print-product-detail-sdk/components/Contexts.js b/express/code/blocks/print-product-detail-sdk/components/Contexts.js
new file mode 100644
index 000000000..49c90f51c
--- /dev/null
+++ b/express/code/blocks/print-product-detail-sdk/components/Contexts.js
@@ -0,0 +1,72 @@
+import { html, createContext, useContext, useMemo, useSyncExternalStore, useEffect, useCallback, useState } from '../../../scripts/vendors/htm-preact.min.js';
+
+export const StoreContext = createContext(null);
+
+export function StoreProvider({ children, sdkStore }) {
+ const state = useSyncExternalStore(
+ sdkStore.subscribe.bind(sdkStore),
+ sdkStore.getSnapshot.bind(sdkStore),
+ );
+
+ const actions = useMemo(() => sdkStore, [sdkStore]);
+
+ const value = useMemo(() => ({
+ state,
+ actions,
+ env: sdkStore.env,
+ sdk: sdkStore,
+ }), [state, actions, sdkStore]);
+
+ return html`
+ <${StoreContext.Provider} value=${value}>
+ ${children}
+ ${StoreContext.Provider}>
+ `;
+}
+
+export function useStore() {
+ const value = useContext(StoreContext);
+ if (!value) {
+ throw new Error('useStore must be used within a StoreProvider');
+ }
+ return value;
+}
+const DrawerContext = createContext(null);
+
+export function DrawerProvider({ children }) {
+ const [drawerState, setDrawerState] = useState({ open: false, type: null, payload: null });
+
+ const openDrawer = useCallback((nextState) => {
+ setDrawerState({ open: true, ...nextState });
+ document.body.classList.add('disable-scroll');
+ }, []);
+
+ const closeDrawer = useCallback(() => {
+ setDrawerState({ open: false, type: null, payload: null });
+ document.body.classList.remove('disable-scroll');
+ }, []);
+
+ const value = useMemo(() => ({
+ state: drawerState,
+ openDrawer,
+ closeDrawer,
+ }), [drawerState, openDrawer, closeDrawer]);
+
+ useEffect(() => () => {
+ document.body.classList.remove('disable-scroll');
+ }, []);
+
+ return html`
+ <${DrawerContext.Provider} value=${value}>
+ ${children}
+ ${DrawerContext.Provider}>
+ `;
+}
+
+export function useDrawer() {
+ const ctx = useContext(DrawerContext);
+ if (!ctx) {
+ throw new Error('useDrawer must be used within a DrawerProvider');
+ }
+ return ctx;
+}
diff --git a/express/code/blocks/print-product-detail-sdk/components/CustomizationInputs.js b/express/code/blocks/print-product-detail-sdk/components/CustomizationInputs.js
new file mode 100644
index 000000000..4aed7fd16
--- /dev/null
+++ b/express/code/blocks/print-product-detail-sdk/components/CustomizationInputs.js
@@ -0,0 +1,857 @@
+import {
+ html,
+ useEffect,
+ useRef,
+} from '../../../scripts/vendors/htm-preact.min.js';
+import { useStore } from './Contexts.js';
+import createSimpleCarousel from '../../../scripts/widgets/simple-carousel.js';
+import { createPicker } from '../../../scripts/widgets/picker.js';
+import { trackPrintAddonOptionSelect } from '../../../scripts/instrument.js';
+import { debounce } from '../../../scripts/utils/hofs.js';
+import { sanitizeHtml } from '../utilities/utility-functions.js';
+
+const debouncedTrackOptionSelect = debounce((payload) => {
+ trackPrintAddonOptionSelect(payload).catch(() => { });
+}, 250);
+
+function toDomIdPart(value) {
+ return String(value || '')
+ .toLowerCase()
+ .replace(/[^a-z0-9_-]+/g, '-')
+ .replace(/^-+|-+$/g, '');
+}
+
+function positionTooltip(target, tooltipText) {
+ const pill = target.getBoundingClientRect();
+ const pillTop = pill.top;
+ const tooltipWidth = (tooltipText.length * 3) + 12;
+ const pillCenter = pill.left + (pill.width / 2);
+ const drawer = target.closest('.pdpx-drawer');
+ const drawerOffsetLeft = drawer ? drawer.getBoundingClientRect().left : 0;
+ target.style.setProperty('--tooltip-top', `${pillTop - 42}px`);
+ target.style.setProperty('--tooltip-left', `${pillCenter - tooltipWidth - drawerOffsetLeft}px`);
+ target.style.setProperty('--arrow-top', `${pillTop - 6}px`);
+ target.style.setProperty('--arrow-left', `${pillCenter - drawerOffsetLeft}px`);
+}
+
+function getNextRadioIndex(currentIndex, key, maxIndex) {
+ switch (key) {
+ case 'ArrowRight':
+ case 'ArrowDown':
+ return currentIndex + 1 > maxIndex ? 0 : currentIndex + 1;
+ case 'ArrowLeft':
+ case 'ArrowUp':
+ return currentIndex - 1 < 0 ? maxIndex : currentIndex - 1;
+ case 'Home':
+ return 0;
+ case 'End':
+ return maxIndex;
+ default:
+ return currentIndex;
+ }
+}
+
+export function CheckboxSelector({ attribute }) {
+ const { actions } = useStore();
+ const { selector, selectedOptionValue, name } = attribute;
+ const isChecked = selectedOptionValue === selector.checkedValue;
+ const checkboxId = `pdpx-checkbox-${toDomIdPart(name)}`;
+
+ const handleChange = () => {
+ const nextValue = isChecked
+ ? selector.uncheckedValue
+ : selector.checkedValue;
+ actions.selectOption(name, nextValue);
+ };
+
+ return html`
+
+
+
+ ${selector.title}${selector.priceDelta ? ` ${selector.priceDelta}` : ''}
+
+
+ `;
+}
+
+export function DropdownSelector({ attribute, onRequestDrawer, productType }) {
+ const { actions } = useStore();
+ const { selector, selectedOptionValue, title, helpLink } = attribute;
+ const pickerHostRef = useRef(null);
+ const pickerRef = useRef(null);
+ const pickerIdRef = useRef(`pdpx-picker-${attribute.name}`);
+ const options = selector.options || [];
+ const optionsSignature = options
+ .map((option) => `${option.value}:${option.title}:${option.priceDelta || ''}`)
+ .join('|');
+ useEffect(() => {
+ let cancelled = false;
+ async function mountPicker() {
+ if (!pickerHostRef.current) {
+ return;
+ }
+ if (pickerRef.current?.destroy) {
+ pickerRef.current.destroy();
+ pickerRef.current = null;
+ }
+ pickerHostRef.current.innerHTML = '';
+ const pickerOptions = options.map((option) => ({
+ value: option.value,
+ text: `${option.title}${option.priceDelta ? ` ${option.priceDelta}` : ''}`,
+ }));
+ const picker = await createPicker({
+ id: pickerIdRef.current,
+ name: attribute.name,
+ label: title,
+ labelPosition: 'side',
+ options: pickerOptions,
+ defaultValue: selectedOptionValue,
+ onChange: (value) => {
+ actions.selectOption(attribute.name, value);
+ debouncedTrackOptionSelect({
+ attributeName: attribute.name,
+ actionValue: value,
+ productType,
+ });
+ },
+ });
+ if (cancelled || !pickerHostRef.current) {
+ picker?.destroy?.();
+ return;
+ }
+ pickerHostRef.current.appendChild(picker);
+ pickerRef.current = picker;
+ }
+ mountPicker();
+ return () => {
+ cancelled = true;
+ if (pickerRef.current?.destroy) {
+ pickerRef.current.destroy();
+ pickerRef.current = null;
+ }
+ if (pickerHostRef.current) {
+ pickerHostRef.current.innerHTML = '';
+ }
+ };
+ }, [attribute.name, title, optionsSignature]);
+ useEffect(() => {
+ if (!pickerRef.current?.getPicker || !pickerRef.current?.setPicker) {
+ return;
+ }
+ if (String(pickerRef.current.getPicker()) !== String(selectedOptionValue)) {
+ pickerRef.current.setPicker(selectedOptionValue);
+ }
+ }, [selectedOptionValue]);
+ const hasDrawerLink = typeof onRequestDrawer === 'function'
+ && helpLink?.type === 'dialog'
+ && helpLink.dialogType;
+
+ const triggerDrawer = () => {
+ if (hasDrawerLink) {
+ onRequestDrawer({
+ type: helpLink.dialogType,
+ payload: { attribute, helpLink },
+ });
+ }
+ };
+
+ return html`
+
+
+
+ ${hasDrawerLink && html`
+
+ ${helpLink.label}
+
+ `}
+
+ ${selector.message
+ && html`
+
${selector.message}
+ `}
+
+ `;
+}
+
+export function QuantitySelector() {
+ const { state, actions } = useStore();
+ const pickerHostRef = useRef(null);
+ const pickerRef = useRef(null);
+ const pickerIdRef = useRef('pdpx-picker-qty');
+
+ if (!state) {
+ return null;
+ }
+
+ const { quantity, quantityOptions, productType } = state;
+ const optionsSignature = quantityOptions
+ .map((option) => `${option.quantity}:${option.label}:${option.discount || ''}`)
+ .join('|');
+
+ useEffect(() => {
+ let cancelled = false;
+
+ async function mountPicker() {
+ if (!pickerHostRef.current) {
+ return;
+ }
+
+ if (pickerRef.current?.destroy) {
+ pickerRef.current.destroy();
+ pickerRef.current = null;
+ }
+
+ pickerHostRef.current.innerHTML = '';
+ const pickerOptions = quantityOptions.map((option) => ({
+ value: String(option.quantity),
+ text: `${option.label}${option.discount ? ` (Save ${option.discount})` : ''}`,
+ }));
+
+ const picker = await createPicker({
+ id: pickerIdRef.current,
+ name: 'qty',
+ label: 'Quantity',
+ labelPosition: 'side',
+ options: pickerOptions,
+ defaultValue: String(quantity),
+ onChange: (value) => {
+ const nextQuantity = parseInt(value, 10);
+ if (!Number.isNaN(nextQuantity)) {
+ actions.selectQuantity(nextQuantity);
+ debouncedTrackOptionSelect({
+ attributeName: 'qty',
+ actionValue: value,
+ productType,
+ });
+ }
+ },
+ });
+
+ if (cancelled || !pickerHostRef.current) {
+ picker?.destroy?.();
+ return;
+ }
+
+ pickerHostRef.current.appendChild(picker);
+ pickerRef.current = picker;
+ }
+
+ mountPicker();
+
+ return () => {
+ cancelled = true;
+ if (pickerRef.current?.destroy) {
+ pickerRef.current.destroy();
+ pickerRef.current = null;
+ }
+ if (pickerHostRef.current) {
+ pickerHostRef.current.innerHTML = '';
+ }
+ };
+ }, [optionsSignature]);
+
+ useEffect(() => {
+ if (!pickerRef.current?.getPicker || !pickerRef.current?.setPicker) {
+ return;
+ }
+ if (String(pickerRef.current.getPicker()) !== String(quantity)) {
+ pickerRef.current.setPicker(String(quantity));
+ }
+ }, [quantity]);
+
+ return html`
+
+ `;
+}
+
+export function RadioSelector({ attribute }) {
+ const { actions } = useStore();
+ const { selector, selectedOptionValue, name, title } = attribute;
+ const groupLabelId = `pdpx-radio-group-label-${toDomIdPart(name)}`;
+
+ const handleChange = (value) => {
+ if (value !== selectedOptionValue) {
+ actions.selectOption(name, value);
+ }
+ };
+
+ return html`
+
+
${title}
+
+ ${selector.options.map(
+ (option) => html`
+
+ handleChange(option.value)}
+ />
+ ${option.title}${option.priceDelta
+ ? ` ${option.priceDelta}`
+ : ''}
+
+ `,
+ )}
+
+
+ `;
+}
+
+function updateImageUrl(url, maxDim = 54) {
+ try {
+ const urlObj = new URL(url);
+ urlObj.searchParams.set('max_dim', String(maxDim));
+ return urlObj.toString();
+ } catch {
+ return url;
+ }
+}
+
+function flattenOptionGroups(selector) {
+ if (!selector.optionGroups || !Array.isArray(selector.optionGroups)) {
+ return [];
+ }
+ return selector.optionGroups.flatMap((group) => (group.options || []).map((option) => ({
+ ...option,
+ groupTitle: group.title,
+ })));
+}
+
+function buildPillElement(option, isSelected, index, setSize, activeIndex, handlers) {
+ const { handleOptionClick, handleMiniPillKeyDown } = handlers;
+ const thumbnailUrl = updateImageUrl(option.imageUrl, 48);
+
+ const pillContainer = document.createElement('div');
+ pillContainer.className = 'pdpx-mini-pill-container';
+
+ const button = document.createElement('button');
+ button.type = 'button';
+ button.className = `pdpx-mini-pill-image-container ${isSelected ? 'selected' : ''}`;
+ button.setAttribute('data-name', option.value);
+ button.setAttribute('data-title', option.title);
+ button.setAttribute('role', 'radio');
+ button.setAttribute('aria-current', isSelected ? 'true' : 'false');
+ button.setAttribute('aria-checked', isSelected ? 'true' : 'false');
+ button.setAttribute('aria-pressed', isSelected ? 'true' : 'false');
+ button.setAttribute('aria-posinset', String(index + 1));
+ button.setAttribute('aria-setsize', String(setSize));
+ button.setAttribute('aria-label', `${option.title}${option.priceDelta ? ` ${option.priceDelta}` : ''}`);
+ button.setAttribute('tabindex', index === activeIndex ? '0' : '-1');
+ button.addEventListener('click', () => handleOptionClick(option));
+ button.addEventListener('keydown', handleMiniPillKeyDown);
+
+ const img = document.createElement('img');
+ img.className = 'pdpx-mini-pill-image';
+ img.src = thumbnailUrl;
+ img.alt = '';
+ img.setAttribute('aria-hidden', 'true');
+ button.appendChild(img);
+
+ pillContainer.addEventListener('mouseenter', (event) => {
+ positionTooltip(event.currentTarget, option.title);
+ });
+
+ const textContainer = document.createElement('div');
+ textContainer.className = 'pdpx-mini-pill-text-container';
+ if (option.priceDelta) {
+ const priceSpan = document.createElement('span');
+ priceSpan.className = 'pdpx-mini-pill-price';
+ priceSpan.textContent = option.priceDelta;
+ textContainer.appendChild(priceSpan);
+ }
+
+ pillContainer.appendChild(button);
+ pillContainer.appendChild(textContainer);
+ return pillContainer;
+}
+
+/**
+ * Mini-pill carousel built imperatively to work with createSimpleCarousel.
+ * The carousel mutates the DOM (moves children into a platform, adds faders),
+ * which conflicts with Preact's reconciliation. By building the pills in useEffect
+ * and not rendering them via Preact, we avoid reconciliation conflicts.
+ */
+function MiniPillCarousel({ attribute, onRequestDrawer, productType }) {
+ const containerRef = useRef(null);
+ const carouselCleanupsRef = useRef([]);
+ const handlersRef = useRef({});
+ const { actions } = useStore();
+ const { selector, selectedOptionValue, title } = attribute;
+ let { helpLink } = attribute;
+ const allOptions = flattenOptionGroups(selector);
+ const isSegmented = selector.optionGroups?.length > 1;
+ const selectedOption = allOptions.find((option) => option.value === selectedOptionValue)
+ || allOptions[0];
+ const selectedOptionTitle = isSegmented && selectedOption?.groupTitle
+ ? `${selectedOption.title} (${selectedOption.groupTitle})`
+ : (selectedOption?.title || '');
+ const groupLabelId = `pdpx-mini-pill-label-${toDomIdPart(attribute.name)}`;
+ const groupValueId = `pdpx-mini-pill-selected-value-${toDomIdPart(attribute.name)}`;
+ const isBusinessCardMediaAttribute = attribute.name === 'media' && productType === 'zazzle_businesscard';
+ if (isBusinessCardMediaAttribute) {
+ helpLink = {
+ type: 'dialog',
+ dialogType: 'paperType',
+ label: 'Compare Paper Types',
+ };
+ }
+ const isShirtColorAttribute = attribute.name === 'color'
+ && (productType === 'zazzle_shirt' || productType === 'zazzle_hoodie');
+ if (isShirtColorAttribute) {
+ helpLink = {
+ type: 'dialog',
+ dialogType: 'printingProcess',
+ label: 'Learn More',
+ };
+ }
+ handlersRef.current = {
+ handleOptionClick: (option) => {
+ actions.selectOption(attribute.name, option.value);
+ debouncedTrackOptionSelect({
+ attributeName: attribute.name,
+ actionValue: option.value,
+ productType,
+ });
+ },
+ handleMiniPillKeyDown: (event) => {
+ const { key, currentTarget } = event;
+ if (!['ArrowRight', 'ArrowLeft', 'ArrowDown', 'ArrowUp', 'Home', 'End'].includes(key)) {
+ return;
+ }
+ const buttons = Array.from(
+ containerRef.current?.querySelectorAll('.pdpx-mini-pill-image-container') || [],
+ );
+ if (!buttons.length) {
+ return;
+ }
+ const currentIndex = buttons.indexOf(currentTarget);
+ if (currentIndex < 0) {
+ return;
+ }
+ event.preventDefault();
+ const nextIndex = getNextRadioIndex(currentIndex, key, buttons.length - 1);
+ const nextButton = buttons[nextIndex];
+ nextButton?.focus();
+ nextButton?.click();
+ },
+ };
+
+ const triggerDrawer = () => {
+ if (helpLink) {
+ onRequestDrawer({
+ type: helpLink.dialogType,
+ payload: { attribute, helpLink },
+ });
+ }
+ };
+
+ // Build pills imperatively and initialize carousel (avoids Preact reconciliation conflict)
+ useEffect(() => {
+ if (!containerRef.current || !allOptions.length) {
+ return undefined;
+ }
+
+ const container = containerRef.current;
+ container.innerHTML = '';
+ const handlers = {
+ handleOptionClick: (option) => handlersRef.current.handleOptionClick(option),
+ handleMiniPillKeyDown: (event) => handlersRef.current.handleMiniPillKeyDown(event),
+ };
+
+ if (isSegmented) {
+ const sectionsWrapper = document.createElement('div');
+ sectionsWrapper.className = 'pdpx-mini-pill-sections-container';
+
+ const carouselTargets = [];
+ selector.optionGroups.forEach((group) => {
+ const sectionContainer = document.createElement('div');
+ sectionContainer.className = 'pdpx-mini-pill-section-container';
+
+ if (group.title) {
+ const sectionLabel = document.createElement('span');
+ sectionLabel.className = 'pdpx-pill-selector-section-label';
+ sectionLabel.textContent = group.title;
+ sectionContainer.appendChild(sectionLabel);
+ }
+
+ const sectionOptions = document.createElement('div');
+ sectionOptions.className = 'pdpx-mini-pill-section-options-container';
+ sectionOptions.setAttribute('role', 'radiogroup');
+ sectionOptions.setAttribute('aria-orientation', 'horizontal');
+ sectionOptions.setAttribute('aria-label', group.title || `${title} options`);
+
+ const groupOptions = group.options || [];
+ const groupSelectedIndex = groupOptions.findIndex(
+ (option) => option.value === selectedOptionValue,
+ );
+ const groupActiveIndex = groupSelectedIndex >= 0 ? groupSelectedIndex : 0;
+
+ groupOptions.forEach((option, index) => {
+ const isSelected = option.value === selectedOptionValue;
+ const pill = buildPillElement(
+ option,
+ isSelected,
+ index,
+ groupOptions.length,
+ groupActiveIndex,
+ handlers,
+ );
+ sectionOptions.appendChild(pill);
+ });
+
+ sectionContainer.appendChild(sectionOptions);
+ sectionsWrapper.appendChild(sectionContainer);
+ carouselTargets.push(sectionOptions);
+ });
+
+ container.appendChild(sectionsWrapper);
+
+ Promise.all(
+ carouselTargets.map((target) => createSimpleCarousel(
+ '.pdpx-mini-pill-container',
+ target,
+ { ariaLabel: `${title} options`, centerActive: true, activeClass: 'selected' },
+ )),
+ ).then((carousels) => {
+ carouselCleanupsRef.current = carousels.filter(Boolean).map((c) => c.cleanup);
+ });
+ } else {
+ const selectedIndex = allOptions.findIndex(
+ (option) => option.value === selectedOptionValue,
+ );
+ const activeIndex = selectedIndex >= 0 ? selectedIndex : 0;
+
+ allOptions.forEach((option, index) => {
+ const isSelected = option.value === selectedOptionValue;
+ const pill = buildPillElement(
+ option,
+ isSelected,
+ index,
+ allOptions.length,
+ activeIndex,
+ handlers,
+ );
+ container.appendChild(pill);
+ });
+
+ createSimpleCarousel('.pdpx-mini-pill-container', container, {
+ ariaLabel: `${title} options`,
+ centerActive: true,
+ activeClass: 'selected',
+ }).then((carousel) => {
+ if (carousel) {
+ carouselCleanupsRef.current = [carousel.cleanup];
+ }
+ });
+ }
+
+ return () => {
+ carouselCleanupsRef.current.forEach((fn) => fn());
+ carouselCleanupsRef.current = [];
+ };
+ }, [
+ attribute.name,
+ title,
+ selector.optionGroups?.map((g) => (g.options || []).map((o) => o.value).join(',')).join('|'),
+ ]);
+
+ // Update selected state when selection changes
+ useEffect(() => {
+ if (!containerRef.current) return;
+ const buttons = containerRef.current.querySelectorAll('.pdpx-mini-pill-image-container');
+ let hasSelected = false;
+ buttons.forEach((btn) => {
+ const value = btn.getAttribute('data-name');
+ const isSelected = value === selectedOptionValue;
+ if (isSelected) {
+ hasSelected = true;
+ }
+ btn.classList.toggle('selected', isSelected);
+ btn.setAttribute('aria-current', isSelected ? 'true' : 'false');
+ btn.setAttribute('aria-checked', isSelected ? 'true' : 'false');
+ btn.setAttribute('aria-pressed', isSelected ? 'true' : 'false');
+ btn.setAttribute('tabindex', isSelected ? '0' : '-1');
+ });
+ if (!hasSelected && buttons.length > 0) {
+ buttons[0].setAttribute('tabindex', '0');
+ }
+ }, [selectedOptionValue]);
+
+ return html`
+
+
+
+ ${title}:
+ ${selectedOptionTitle}
+
+ ${helpLink
+ && html`
+
+ ${helpLink.label}
+
+ `}
+
+
+
+ `;
+}
+
+export function ThumbnailSelector({ attribute, onRequestDrawer, productType }) {
+ const { actions } = useStore();
+ const { selector, selectedOptionValue, title, helpLink } = attribute;
+ const groupLabelId = `pdpx-pill-label-${toDomIdPart(attribute.name)}`;
+
+ const allOptions = flattenOptionGroups(selector);
+
+ if (!allOptions.length) {
+ return null;
+ }
+
+ const isMiniPill = attribute.name === 'color' || attribute.name === 'media';
+
+ const handleOptionClick = (option) => {
+ if (option.value !== selectedOptionValue) {
+ actions.selectOption(attribute.name, option.value);
+ debouncedTrackOptionSelect({
+ attributeName: attribute.name,
+ actionValue: option.value,
+ productType,
+ });
+ }
+ };
+
+ const selectedIndex = allOptions.findIndex((option) => option.value === selectedOptionValue);
+ const activeIndex = selectedIndex >= 0 ? selectedIndex : 0;
+ const handleThumbnailKeyDown = (event) => {
+ const { key, currentTarget } = event;
+ if (!['ArrowRight', 'ArrowLeft', 'ArrowDown', 'ArrowUp', 'Home', 'End'].includes(key)) {
+ return;
+ }
+ const currentIndex = Number(currentTarget.getAttribute('data-index'));
+ if (Number.isNaN(currentIndex) || !allOptions.length) {
+ return;
+ }
+ event.preventDefault();
+ const nextIndex = getNextRadioIndex(currentIndex, key, allOptions.length - 1);
+ const nextOption = allOptions[nextIndex];
+ if (!nextOption) {
+ return;
+ }
+ const radioGroup = currentTarget.closest('[role="radiogroup"]');
+ const nextButton = radioGroup?.querySelector(`[data-index="${nextIndex}"]`);
+ handleOptionClick(nextOption);
+ nextButton?.focus();
+ };
+
+ const triggerDrawer = () => {
+ if (helpLink && typeof onRequestDrawer === 'function') {
+ onRequestDrawer({
+ type: helpLink.dialogType,
+ payload: { attribute, helpLink },
+ });
+ }
+ };
+
+ if (isMiniPill) {
+ return html`<${MiniPillCarousel} attribute=${attribute} onRequestDrawer=${onRequestDrawer} productType=${productType} />`;
+ }
+
+ return html`
+
+
+ ${title}
+ ${helpLink?.type === 'dialog' && helpLink.dialogType && html`
+
+ ${helpLink.label}
+
+ `}
+
+
+ ${selector.optionGroups?.map(
+ (group) => html`
+
+ ${group.title
+ && html`
${group.title}
`}
+ ${(group.options || []).map((option) => {
+ const thumbnailUrl = updateImageUrl(option.imageUrl);
+ const isSelected = option.value === selectedOptionValue;
+ const optionIndex = allOptions.findIndex((candidate) => candidate.value === option.value);
+ return html`
+
handleOptionClick(option)}
+ onKeyDown=${handleThumbnailKeyDown}
+ >
+
+
+
+
+ ${option.title}
+ ${option.priceDelta
+ && html`
+ ${option.priceDelta}
+ `}
+
+
+ `;
+ })}
+
+ `,
+ )}
+
+ ${selector.preview
+ && html`
+
+
+
+
+ `}
+
+ `;
+}
+
+function renderAttribute(attribute, onRequestDrawer, key, productType) {
+ switch (attribute.selector.type) {
+ case 'thumbnails':
+ return html`<${ThumbnailSelector}
+ key=${key}
+ attribute=${attribute}
+ onRequestDrawer=${onRequestDrawer}
+ productType=${productType}
+ />`;
+ case 'dropdown':
+ return html`<${DropdownSelector}
+ key=${key}
+ attribute=${attribute}
+ onRequestDrawer=${onRequestDrawer}
+ productType=${productType}
+ />`;
+ case 'radio':
+ return html`<${RadioSelector}
+ key=${key}
+ attribute=${attribute}
+ />`;
+ case 'checkbox':
+ return html`<${CheckboxSelector}
+ key=${key}
+ attribute=${attribute}
+ />`;
+ default:
+ return null;
+ }
+}
+
+const ATTRIBUTE_ORDER = {
+ zazzle_businesscard: ['style', 'cornerstyle', 'media'],
+ zazzle_shirt: ['style', 'color', 'size'],
+};
+
+function sortAttributes(attributes, productType) {
+ const order = ATTRIBUTE_ORDER[productType];
+ if (!order) return attributes;
+ return [...attributes].sort((a, b) => {
+ const indexA = order.indexOf(a.name);
+ const indexB = order.indexOf(b.name);
+ const posA = indexA >= 0 ? indexA : order.length;
+ const posB = indexB >= 0 ? indexB : order.length;
+ return posA - posB;
+ });
+}
+
+export function CustomizationInputs({ onRequestDrawer, productType }) {
+ const { state } = useStore();
+ if (!state) {
+ return null;
+ }
+ const productAttributes = sortAttributes(
+ (state.attributes || []).filter((attribute) => attribute.name !== 'quantity'),
+ productType,
+ );
+ return html`
+
+
+
+ `;
+}
diff --git a/express/code/blocks/print-product-detail-sdk/components/ProductComponents.js b/express/code/blocks/print-product-detail-sdk/components/ProductComponents.js
new file mode 100644
index 000000000..ac95e9f7f
--- /dev/null
+++ b/express/code/blocks/print-product-detail-sdk/components/ProductComponents.js
@@ -0,0 +1,825 @@
+import {
+ html,
+ useEffect,
+ useRef,
+ useState,
+ Fragment,
+ useCallback,
+} from '../../../scripts/vendors/htm-preact.min.js';
+import { useStore, useDrawer } from './Contexts.js';
+import axAccordionDecorate from '../../ax-accordion/ax-accordion.js';
+import { formatLargeNumberToK, sanitizeHtml } from '../utilities/utility-functions.js';
+import createSimpleCarousel from '../../../scripts/widgets/simple-carousel.js';
+
+function mapToAccordionFormat(descriptions) {
+ if (!descriptions || !Array.isArray(descriptions)) {
+ return [];
+ }
+ return descriptions.map((item) => ({
+ title: item.attributeTitle,
+ content: item.descriptionHTML,
+ }));
+}
+
+export function ProductDetails() {
+ const { state } = useStore();
+ const accordionRef = useRef(null);
+ const previousDescriptionsRef = useRef(null);
+ useEffect(() => {
+ if (!state || !accordionRef.current) {
+ return;
+ }
+ const descriptions = state.descriptionComponents;
+ if (!descriptions) {
+ return;
+ }
+ const accordionData = mapToAccordionFormat(descriptions);
+ if (!accordionRef.current.accordionData) {
+ accordionRef.current.accordionData = accordionData;
+ axAccordionDecorate(accordionRef.current);
+ } else {
+ const previousDescriptions = previousDescriptionsRef.current;
+ if (previousDescriptions !== descriptions && accordionRef.current.updateAccordion) {
+ let forceExpandTitle = null;
+ if (previousDescriptions && Array.isArray(previousDescriptions)) {
+ const prevTitles = previousDescriptions.map((entry) => entry.attributeTitle);
+ const currentTitles = descriptions.map((entry) => entry.attributeTitle);
+ const changedIndex = currentTitles
+ .findIndex((title, index) => prevTitles[index] !== title);
+ if (changedIndex >= 0) {
+ forceExpandTitle = descriptions[changedIndex].attributeTitle;
+ }
+ }
+ accordionRef.current.updateAccordion(accordionData, forceExpandTitle);
+ }
+ }
+ previousDescriptionsRef.current = descriptions;
+ }, [state]);
+
+ if (!state) {
+ return null;
+ }
+
+ return html`
+
+
+ Product Details
+
+
+
+ `;
+}
+
+export function ProductHeader() {
+ const { state } = useStore();
+ const [tooltipVisible, setTooltipVisible] = useState(false);
+ const showTooltip = useCallback(() => setTooltipVisible(true), []);
+ const hideTooltip = useCallback(() => setTooltipVisible(false), []);
+
+ if (!state) {
+ return null;
+ }
+
+ const { title, pricing, shippingEstimate, reviewsStats } = state;
+ const reviewsCount = reviewsStats?.count || 0;
+ const reviewsRating = reviewsStats?.rating || 0;
+ const formattedRating = reviewsRating ? Math.round(reviewsRating * 10) / 10 : '';
+ const formattedCount = reviewsCount ? formatLargeNumberToK(reviewsCount) : '';
+
+ return html`
+
+
+
+
+
${title}
+
+ ${reviewsRating > 0 && html`
+
+
+ ${Array.from({ length: 5 }).map(() => html`
+
+ `)}
+
+
+ ${formattedRating}
+
+
+ ${formattedCount}
+
+
+ `}
+
+
+
+
${pricing.totalPrice}
+ ${pricing.originalTotalPrice !== pricing.totalPrice && html`
+
${pricing.originalTotalPrice}
+ `}
+ ${pricing.showCompValue && html`
+
Comp. value
+
+
+
+
+ ${tooltipVisible && html`
+
+
Compare Value
+
+ The compare value is the estimated retail value of a similar product purchased elsewhere.
+
+
+ Your price may vary based on the options you select.
+
+
+ `}
+
+ `}
+
+ ${pricing.discountLabel && html`
+
${pricing.discountLabel}
+ `}
+
+
+ ${shippingEstimate && html`
+
+
+
Estimated Delivery
+
${shippingEstimate}
+
+ `}
+
+ `;
+}
+
+function updateImageUrl(url, maxDim = 644) {
+ try {
+ const urlObj = new URL(url);
+ urlObj.searchParams.set('max_dim', String(maxDim));
+ return urlObj.toString();
+ } catch {
+ return url;
+ }
+}
+
+export function ProductImages() {
+ const { state, actions } = useStore();
+ const containerRef = useRef(null);
+ const carouselCleanupRef = useRef(null);
+
+ if (!state || !state.selectedRealview) {
+ return null;
+ }
+
+ const { realviews = [], selectedRealview } = state;
+ const heroImageUrl = updateImageUrl(selectedRealview.url, 644);
+
+ const handleThumbnailClick = (realview) => {
+ actions.selectRealview(realview.id);
+ };
+
+ // Build thumbnails imperatively to work with createSimpleCarousel
+ useEffect(() => {
+ if (!containerRef.current || !realviews.length) return undefined;
+
+ const container = containerRef.current;
+ container.innerHTML = '';
+
+ realviews.forEach((realview) => {
+ const thumbnailUrl = updateImageUrl(realview.url, 76);
+ const isSelected = realview.id === selectedRealview.id;
+
+ const button = document.createElement('button');
+ button.type = 'button';
+ button.className = `pdpx-image-thumbnail-carousel-item ${isSelected ? 'selected' : ''}`;
+ button.setAttribute('data-image-type', realview.id);
+ button.addEventListener('click', () => handleThumbnailClick(realview));
+
+ const img = document.createElement('img');
+ img.className = 'pdpx-image-thumbnail-carousel-item-image';
+ img.src = thumbnailUrl;
+ img.alt = realview.title;
+ img.setAttribute('data-image-type', realview.id);
+ button.appendChild(img);
+
+ container.appendChild(button);
+ });
+
+ createSimpleCarousel('.pdpx-image-thumbnail-carousel-item', container, {
+ ariaLabel: 'Product image thumbnails',
+ centerActive: true,
+ activeClass: 'selected',
+ }).then((carousel) => {
+ if (carousel) {
+ carouselCleanupRef.current = carousel.cleanup;
+ }
+ });
+
+ return () => {
+ if (carouselCleanupRef.current) {
+ carouselCleanupRef.current();
+ carouselCleanupRef.current = null;
+ }
+ };
+ }, [realviews.map((r) => `${r.id}:${r.url}`).join(',')]);
+
+ // Update selected state when selection changes
+ useEffect(() => {
+ if (!containerRef.current) return;
+ const buttons = containerRef.current.querySelectorAll('.pdpx-image-thumbnail-carousel-item');
+ buttons.forEach((btn) => {
+ const id = btn.getAttribute('data-image-type');
+ const isSelected = id === selectedRealview.id;
+ btn.classList.toggle('selected', isSelected);
+ });
+ }, [selectedRealview.id]);
+
+ return html`
+
+
+
+
+
+
+
+ `;
+}
+
+const TASK_ID_MAP = {
+ zazzle_shirt: 'tshirt',
+ zazzle_businesscard: 'businesscard',
+};
+
+function buildCheckoutUrl(templateId, expressProductSettings, productType) {
+ const taskId = TASK_ID_MAP[productType] || '';
+ const baseUrl = `https://new.express.adobe.com/design-remix/template/${templateId}`;
+ const params = new URLSearchParams({
+ category: 'templates',
+ taskId,
+ loadPrintAddon: 'true',
+ print: 'true',
+ action: 'customize-and-print-zazzle-iframe',
+ source: 'a.com-print-and-deliver-seo',
+ entryPoint: 'a.com-print-and-deliver-seo',
+ mv: 'other',
+ url: 'express/print',
+ });
+ const encodedProductSettings = encodeURIComponent(expressProductSettings);
+ return `${baseUrl}?${params.toString()}&productSettings=${encodedProductSettings}`;
+}
+
+const VALID_COUNTRIES = ['us', 'gb'];
+const OUT_OF_REGION_TEXT = 'Print with Adobe Express isn\u2019t available yet in your region. Check back soon!';
+
+export function CheckoutButton({ templateId }) {
+ const { state } = useStore();
+ const [outOfRegion, setOutOfRegion] = useState(null);
+ const promoBarRef = useRef(null);
+
+ useEffect(() => {
+ let active = true;
+ import('../../../scripts/utils/location-utils.js')
+ .then(({ getCountry }) => getCountry())
+ .then((country) => {
+ if (active) setOutOfRegion(!VALID_COUNTRIES.includes(country));
+ })
+ .catch((err) => {
+ window.lana?.log(`print-product-detail-sdk: country detection failed: ${err.message}`, { tags: 'print-product-detail-sdk', severity: 'warning' });
+ if (active) setOutOfRegion(false);
+ });
+ return () => { active = false; };
+ }, []);
+
+ useEffect(() => {
+ if (!outOfRegion || !promoBarRef.current) return;
+ const container = promoBarRef.current;
+
+ const promoBar = document.createElement('div');
+ promoBar.className = 'sticky-promo-bar rounded';
+
+ const textWrapper = document.createElement('div');
+ const textSpan = document.createElement('span');
+ textSpan.className = 'pdpx-checkout-button-cta-text-container';
+ textSpan.textContent = OUT_OF_REGION_TEXT;
+ textWrapper.appendChild(textSpan);
+ promoBar.appendChild(textWrapper);
+
+ container.appendChild(promoBar);
+
+ import('../../../scripts/utils.js').then(({ getLibs }) => import(`${getLibs()}/utils/utils.js`)).then(({ loadStyle, getConfig }) => {
+ const { codeRoot } = getConfig();
+ loadStyle(`${codeRoot}/blocks/sticky-promo-bar/sticky-promo-bar.css`, () => {
+ import('../../sticky-promo-bar/sticky-promo-bar.js').then(({ default: stickyPromoBar }) => {
+ stickyPromoBar(promoBar);
+ });
+ });
+ }).catch((error) => {
+ window.lana?.log(`Failed to load sticky-promo-bar: ${error}`, { tags: 'print-product-detail-sdk', severity: 'warning' });
+ });
+ }, [outOfRegion]);
+
+ if (outOfRegion === null) return null;
+
+ const defaultUrl = `https://new.express.adobe.com/design-remix/template/${templateId}`;
+ const checkoutUrl = state?.expressProductSettings
+ ? buildCheckoutUrl(templateId, state.expressProductSettings, state.productType)
+ : defaultUrl;
+
+ if (outOfRegion) {
+ return html`
+
+
+ `;
+ }
+
+ return html`
+
+ `;
+}
+
+function SizeChartTable({ measurementTypes, attributeValues }) {
+ if (!measurementTypes?.length || !attributeValues?.length) {
+ return null;
+ }
+
+ const headerLabel = measurementTypes[0]?.key?.startsWith('garment')
+ ? 'Garment (IN)' : 'Body (IN)';
+
+ return html`
+
+
+ ${headerLabel} size chart
+
+
+
+ ${measurementTypes.map((type) => html`
+ ${type.label}
+ `)}
+
+
+
+ ${attributeValues.map((row) => html`
+
+ ${row.attributeValueLabel}
+ ${measurementTypes.map((type) => {
+ const measurement = row.measurements?.[type.key];
+ return html`
+ ${measurement?.imperial || '—'}
+ `;
+ })}
+
+ `)}
+
+
+
+ `;
+}
+
+function SizeChartContent() {
+ const { actions } = useStore();
+ const [chart, setChart] = useState(null);
+ const [error, setError] = useState(null);
+ const { fetchSizeChart } = actions;
+ useEffect(() => {
+ let active = true;
+ fetchSizeChart()
+ .then((data) => {
+ if (active) {
+ setChart(data);
+ }
+ })
+ .catch((err) => {
+ if (active) {
+ setError(err);
+ }
+ window.reportError?.(err);
+ });
+ return () => {
+ active = false;
+ };
+ }, [fetchSizeChart]);
+
+ if (error) {
+ return html`Unable to load size chart. Please try again later.
`;
+ }
+
+ if (!chart) {
+ return html`
`;
+ }
+
+ const { measurementTypes = [], attributeValues = [] } = chart.sizeChart || {};
+ const bodyTypes = measurementTypes.filter((t) => t.key.startsWith('body'));
+ const garmentTypes = measurementTypes.filter((t) => !t.key.startsWith('body'));
+
+ return html`
+
+
${chart.title || 'Size Chart'}
+
+
+ ${bodyTypes.length > 0 && html`
+ <${SizeChartTable}
+ measurementTypes=${bodyTypes}
+ attributeValues=${attributeValues}
+ />
+ `}
+ ${garmentTypes.length > 0 && html`
+ <${SizeChartTable}
+ measurementTypes=${garmentTypes}
+ attributeValues=${attributeValues}
+ />
+ `}
+
+
+
+ ${bodyTypes.length > 0 && html`
+
+
Body
+ ${bodyTypes.map((type) => html`
+
+ ${type.extraDescription || type.label}
+
+ `)}
+
+ `}
+ ${garmentTypes.length > 0 && html`
+
+
Garment
+ ${garmentTypes.map((type) => html`
+
+ ${type.extraDescription || type.label}
+
+ `)}
+
+ `}
+ ${chart.fitStyle && html`
+
+
Fit
+
${chart.fitStyle}
+
+ `}
+
+
+ `;
+}
+
+function PrintingProcessContent() {
+ return html`
+
+
+
+
+
+
+
+
Classic printing: no underbase
+
+ Best for lighter colored garments. The design is printed directly onto the garment using CMYK inks only.
+
+
+
+
+
+
+
+
+
+
Vivid printing: with underbase
+
+ Best for darker colored garments. A white underbase is printed first, then the design is printed on top using CMYK inks for vivid color reproduction.
+
+
+
+
+
+
+
+ CMYK + White
+
+
+
+
+
+ `;
+}
+
+function flattenOptionGroups(selector) {
+ if (!selector?.optionGroups || !Array.isArray(selector.optionGroups)) {
+ return [];
+ }
+ return selector.optionGroups.flatMap(
+ (group) => (group.options || []).map((option) => ({ ...option, groupTitle: group.title })),
+ );
+}
+
+function PaperTypeContent({ onClose }) {
+ const { state, actions } = useStore();
+ const { state: drawerState } = useDrawer();
+ const pillContainerRef = useRef(null);
+ const carouselCleanupRef = useRef(null);
+ const actionsRef = useRef(actions);
+ actionsRef.current = actions;
+ const attrName = drawerState.payload?.attribute?.name;
+ const attribute = (state?.attributes || []).find((a) => a.name === attrName);
+ if (!attribute) return null;
+ const { selector, selectedOptionValue } = attribute;
+ const { preview } = selector;
+ const allOptions = flattenOptionGroups(selector);
+ const selectedOption = allOptions.find((o) => o.value === selectedOptionValue) || allOptions[0];
+ const heroImageUrl = preview?.imageUrl ? updateImageUrl(preview.imageUrl, 1000) : '';
+ const isRecommended = selectedOptionValue === '175ptmatte';
+
+ // Build pills imperatively and initialize carousel (avoids Preact reconciliation conflict)
+ useEffect(() => {
+ if (!pillContainerRef.current || !allOptions.length) return undefined;
+
+ const container = pillContainerRef.current;
+ container.innerHTML = '';
+
+ allOptions.forEach((option) => {
+ const isSelected = option.value === selectedOptionValue;
+ const thumbUrl = updateImageUrl(option.imageUrl, 48);
+
+ const pillContainer = document.createElement('div');
+ pillContainer.className = 'pdpx-mini-pill-container';
+
+ const button = document.createElement('button');
+ button.type = 'button';
+ button.className = `pdpx-mini-pill-image-container ${isSelected ? 'selected' : ''}`;
+ button.setAttribute('data-name', option.value);
+ button.setAttribute('data-title', option.title);
+ button.setAttribute('aria-label', option.title);
+ button.setAttribute('aria-current', isSelected ? 'true' : 'false');
+ button.setAttribute('aria-checked', isSelected ? 'true' : 'false');
+ button.setAttribute('aria-pressed', isSelected ? 'true' : 'false');
+ button.addEventListener('click', () => {
+ actionsRef.current.selectOption(attribute.name, option.value);
+ });
+
+ const img = document.createElement('img');
+ img.className = 'pdpx-mini-pill-image';
+ img.src = thumbUrl;
+ img.alt = '';
+ img.setAttribute('aria-hidden', 'true');
+ button.appendChild(img);
+
+ pillContainer.addEventListener('mouseenter', (event) => {
+ const pill = event.currentTarget.getBoundingClientRect();
+ const tooltipWidth = (option.title.length * 3) + 12;
+ const pillCenter = pill.left + (pill.width / 2);
+ const drawer = event.currentTarget.closest('.pdpx-drawer');
+ const drawerOffsetLeft = drawer ? drawer.getBoundingClientRect().left : 0;
+ event.currentTarget.style.setProperty('--tooltip-top', `${pill.top - 42}px`);
+ event.currentTarget.style.setProperty('--tooltip-left', `${pillCenter - tooltipWidth - drawerOffsetLeft}px`);
+ event.currentTarget.style.setProperty('--arrow-top', `${pill.top - 6}px`);
+ event.currentTarget.style.setProperty('--arrow-left', `${pillCenter - drawerOffsetLeft}px`);
+ });
+
+ const textContainer = document.createElement('div');
+ textContainer.className = 'pdpx-mini-pill-text-container';
+ if (option.priceDelta) {
+ const priceSpan = document.createElement('span');
+ priceSpan.className = 'pdpx-mini-pill-price';
+ priceSpan.textContent = option.priceDelta;
+ textContainer.appendChild(priceSpan);
+ }
+
+ pillContainer.appendChild(button);
+ pillContainer.appendChild(textContainer);
+ container.appendChild(pillContainer);
+ });
+
+ createSimpleCarousel('.pdpx-mini-pill-container', container, {
+ ariaLabel: `${attribute.title} options`,
+ centerActive: true,
+ activeClass: 'selected',
+ }).then((carousel) => {
+ if (carousel) {
+ carouselCleanupRef.current = carousel.cleanup;
+ }
+ });
+
+ return () => {
+ if (carouselCleanupRef.current) {
+ carouselCleanupRef.current();
+ carouselCleanupRef.current = null;
+ }
+ };
+ }, [attribute.name, attribute.title, allOptions.map((o) => o.value).join(',')]);
+
+ // Update selected state when selection changes
+ useEffect(() => {
+ if (!pillContainerRef.current) return;
+ const buttons = pillContainerRef.current.querySelectorAll('.pdpx-mini-pill-image-container');
+ buttons.forEach((btn) => {
+ const value = btn.getAttribute('data-name');
+ const isSelected = value === selectedOptionValue;
+ btn.classList.toggle('selected', isSelected);
+ btn.setAttribute('aria-current', isSelected ? 'true' : 'false');
+ btn.setAttribute('aria-checked', isSelected ? 'true' : 'false');
+ btn.setAttribute('aria-pressed', isSelected ? 'true' : 'false');
+ });
+ }, [selectedOptionValue]);
+
+ return html`
+ <${Fragment}>
+
+ ${heroImageUrl && html`
+
+
+
+ `}
+
+ ${selectedOption?.title || ''}
+ Recommended
+
+ ${preview?.descriptionHTML && html`
+
+ ${preview.descriptionHTML
+ .split(/
/i)[0]
+ .replace(/[<>]/g, '')
+ .split('/')
+ .filter(Boolean)
+ .map((spec) => html`
+
+
+
${spec.trim()}
+
+ `)}
+
+ `}
+
+
+
+ ${attribute.title}:
+ ${selectedOption?.title || ''}
+
+
+
+
+ ${state?.descriptionComponents?.[1]?.descriptionHTML && html`
+
+ `}
+
+
+ ${Fragment}>
+ `;
+}
+
+export function Drawer() {
+ const { state, closeDrawer } = useDrawer();
+ const drawerRef = useRef(null);
+ const triggerRef = useRef(null);
+
+ useEffect(() => {
+ if (!state.open) return undefined;
+
+ // Capture the element that triggered the drawer so we can return focus
+ triggerRef.current = document.activeElement;
+
+ const handleKeyDown = (e) => {
+ if (e.key === 'Escape') {
+ closeDrawer();
+ return;
+ }
+ // Focus trap: keep Tab within the drawer
+ if (e.key === 'Tab' && drawerRef.current) {
+ const focusable = drawerRef.current.querySelectorAll(
+ 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])',
+ );
+ if (!focusable.length) return;
+ const first = focusable[0];
+ const last = focusable[focusable.length - 1];
+ if (e.shiftKey && document.activeElement === first) {
+ e.preventDefault();
+ last.focus();
+ } else if (!e.shiftKey && document.activeElement === last) {
+ e.preventDefault();
+ first.focus();
+ }
+ }
+ };
+ document.addEventListener('keydown', handleKeyDown);
+
+ // Move focus into the drawer
+ let active = true;
+ setTimeout(() => {
+ if (!active || !drawerRef.current) return;
+ const firstFocusable = drawerRef.current.querySelector('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
+ if (firstFocusable) firstFocusable.focus();
+ }, 0);
+
+ return () => {
+ active = false;
+ document.removeEventListener('keydown', handleKeyDown);
+ // Return focus to the triggering element
+ if (triggerRef.current?.focus) {
+ triggerRef.current.focus();
+ triggerRef.current = null;
+ }
+ };
+ }, [state.open, closeDrawer]);
+
+ const drawerLabels = {
+ sizeChart: state.payload?.helpLink?.label || 'Size Chart',
+ paperType: 'Select Paper Type',
+ printingProcess: 'Printing Process',
+ };
+ const drawerLabel = drawerLabels[state.type] || '';
+
+ return html`
+ <${Fragment}>
+
+
+
+
${drawerLabel}
+
+
+
+
+ ${state.type === 'sizeChart' && html`<${SizeChartContent} onClose=${closeDrawer} />`}
+ ${state.type === 'paperType' && html`<${PaperTypeContent} onClose=${closeDrawer} />`}
+ ${state.type === 'printingProcess' && html`<${PrintingProcessContent} onClose=${closeDrawer} />`}
+
+ ${Fragment}>
+ `;
+}
diff --git a/express/code/blocks/print-product-detail-sdk/components/useSeo.js b/express/code/blocks/print-product-detail-sdk/components/useSeo.js
new file mode 100644
index 000000000..8f558fa6e
--- /dev/null
+++ b/express/code/blocks/print-product-detail-sdk/components/useSeo.js
@@ -0,0 +1,198 @@
+import { useEffect } from '../../../scripts/vendors/htm-preact.min.js';
+import { useStore } from './Contexts.js';
+
+export function getCanonicalUrl() {
+ const existing = document.querySelector('link[rel="canonical"]');
+ const href = existing?.getAttribute('href');
+ return href && href.trim() ? href : window.location.href;
+}
+
+export function getAuthoredOverrides(doc = document) {
+ const overrides = {};
+ const titleEl = doc.querySelector('title');
+ const metaDescEl = doc.querySelector('meta[name="description"]');
+ const ogImgEl = doc.querySelector('meta[property="og:image"]');
+ if (titleEl && titleEl.textContent && titleEl.textContent.trim()) {
+ overrides.name = titleEl.textContent.trim();
+ }
+ if (metaDescEl && metaDescEl.content && metaDescEl.content.trim()) {
+ overrides.description = metaDescEl.content.trim();
+ }
+ if (ogImgEl && ogImgEl.content && ogImgEl.content.trim()) {
+ overrides.image = ogImgEl.content.trim();
+ }
+ return overrides;
+}
+
+export function upsertLdJson(id, data) {
+ let script = document.getElementById(id);
+ if (!script) {
+ script = document.createElement('script');
+ script.type = 'application/ld+json';
+ script.id = id;
+ document.head.appendChild(script);
+ }
+ script.textContent = JSON.stringify(data);
+}
+
+function stripHtml(input) {
+ if (!input) return '';
+ const doc = new DOMParser().parseFromString(input, 'text/html');
+ return (doc.body.textContent || '').replace(/\s+/g, ' ').trim();
+}
+
+async function getCurrencyCode() {
+ const { getCurrency } = await import('../../../scripts/utils/pricing.js');
+ const { getCountry } = await import('../../../scripts/utils/location-utils.js');
+ const country = await getCountry();
+ const currency = await getCurrency(country);
+ return currency;
+}
+
+export async function buildProductJsonLd(apiData, overrides, canonicalUrl) {
+ const name = overrides?.name || apiData.productTitle || '';
+ const descriptionSource = overrides?.description
+ || (Array.isArray(apiData.productDescriptions) && apiData.productDescriptions[0]?.description)
+ || '';
+ const description = stripHtml(descriptionSource);
+ const image = overrides?.image || apiData.heroImage || '';
+ const sku = apiData.id || apiData.templateId || '';
+
+ const json = {
+ '@context': 'https://schema.org/',
+ '@type': 'Product',
+ name,
+ description,
+ image,
+ brand: {
+ '@type': 'Brand',
+ name: 'Adobe Express',
+ },
+ };
+
+ if (sku) json.sku = String(sku);
+
+ // Offers (if pricing available)
+ if (apiData.productPrice) {
+ const priceCurrency = await getCurrencyCode();
+ json.offers = {
+ '@type': 'Offer',
+ price: Number(apiData.productPrice).toFixed(2),
+ priceCurrency,
+ availability: 'https://schema.org/InStock',
+ url: canonicalUrl,
+ };
+ }
+
+ return json;
+}
+
+export function upsertTitleAndDescriptionRespectingAuthored(apiData) {
+ const authored = getAuthoredOverrides(document);
+ if (!authored.name && apiData.productTitle) {
+ let titleEl = document.querySelector('title');
+ if (!titleEl) {
+ titleEl = document.createElement('title');
+ document.head.appendChild(titleEl);
+ }
+ titleEl.textContent = apiData.productTitle;
+ }
+ if (!authored.description) {
+ const descriptionSource = (Array.isArray(apiData.productDescriptions) && apiData.productDescriptions[0]?.description) || '';
+ const description = stripHtml(descriptionSource).slice(0, 160);
+ if (description) {
+ let metaDesc = document.querySelector('meta[name="description"]');
+ if (!metaDesc) {
+ metaDesc = document.createElement('meta');
+ metaDesc.setAttribute('name', 'description');
+ document.head.appendChild(metaDesc);
+ }
+ metaDesc.setAttribute('content', description);
+ }
+ }
+}
+
+export function buildBreadcrumbsJsonLdFromDom() {
+ const nav = document.querySelector('nav.feds-breadcrumbs');
+ if (!nav) return null;
+ const items = [];
+ const lis = nav.querySelectorAll('ul > li');
+ let position = 1;
+ lis.forEach((li) => {
+ const a = li.querySelector('a');
+ const name = (a ? a.textContent : li.textContent) || '';
+ const item = { '@type': 'ListItem', position, name: name.trim() };
+ if (a && a.getAttribute('href')) {
+ try {
+ const href = new URL(a.getAttribute('href'), window.location.origin).toString();
+ item.item = href;
+ } catch (e) {
+ // ignore malformed hrefs
+ }
+ }
+ items.push(item);
+ position += 1;
+ });
+ if (!items.length) return null;
+ return {
+ '@context': 'https://schema.org',
+ '@type': 'BreadcrumbList',
+ itemListElement: items,
+ };
+}
+
+function mapStateToSeoPayload(state, templateId) {
+ const descriptionComponents = Array.isArray(state.descriptionComponents)
+ ? state.descriptionComponents.map((item) => ({ description: item.descriptionHTML }))
+ : [];
+
+ const numericPrice = (() => {
+ const priceString = state.pricing?.unitPrice || state.pricing?.totalPrice || '';
+ const normalized = priceString.replace(/[^0-9.,]/g, '').replace(',', '.');
+ const parsed = Number.parseFloat(normalized);
+ return Number.isFinite(parsed) ? parsed : undefined;
+ })();
+
+ return {
+ productTitle: state.title,
+ productDescriptions: descriptionComponents,
+ heroImage: state.selectedRealview?.url,
+ productPrice: numericPrice,
+ id: templateId,
+ templateId,
+ };
+}
+
+export default function useSeo(templateId) {
+ const { state } = useStore();
+
+ useEffect(() => {
+ if (!state) {
+ return undefined;
+ }
+
+ let active = true;
+ const payload = mapStateToSeoPayload(state, templateId);
+ upsertTitleAndDescriptionRespectingAuthored(payload);
+
+ const canonicalUrl = getCanonicalUrl();
+ const overrides = getAuthoredOverrides(document);
+
+ buildProductJsonLd(payload, overrides, canonicalUrl)
+ .then((json) => {
+ if (active && json) {
+ upsertLdJson('pdp-product-jsonld', json);
+ }
+ })
+ .catch((error) => {
+ window.reportError?.(error);
+ });
+
+ const breadcrumbs = buildBreadcrumbsJsonLdFromDom();
+ if (breadcrumbs) {
+ upsertLdJson('pdp-breadcrumbs-jsonld', breadcrumbs);
+ }
+
+ return () => { active = false; };
+ }, [state, templateId]);
+}
diff --git a/express/code/blocks/print-product-detail-sdk/print-product-detail-sdk.css b/express/code/blocks/print-product-detail-sdk/print-product-detail-sdk.css
new file mode 100644
index 000000000..1427da1dd
--- /dev/null
+++ b/express/code/blocks/print-product-detail-sdk/print-product-detail-sdk.css
@@ -0,0 +1,1195 @@
+.print-product-detail-sdk {
+ --standard-transition-hover-in-border-color: opacity 80ms ease-out 20ms;
+ --standard-transition-hover-out-border-color: opacity 80ms ease-out 220ms;
+ --standard-transition-hover-in-opacity: opacity 80ms ease-out 20ms;
+ --standard-transition-hover-out-opacity: opacity 80ms ease-out 220ms;
+ --global-container-margin: 16px;
+ --font-size-header: 24px;
+
+
+
+ @media (min-width: 600px) {
+ --global-container-margin: 32px;
+
+ }
+ @media (min-width: 1200px) {
+ --global-container-margin: 40px;
+ --font-size-header: 28px;
+ }
+ span {
+ font-family: var(--body-font-family)
+ }
+ .global-Typography-Size-Headings-Heading-L {
+ font-size: var(--font-size-header);
+ font-weight: var(--heading-font-weight-extra);
+ line-height: 104%;
+ color: var(--color-gray-950);
+ }
+ .picker-with-link {
+ width: fit-content;
+ }
+ .picker-container.side {
+ width: fit-content;
+ }
+ .picker-current-value {
+ min-width: 65px;
+ }
+ .picker-container:not(.picker-with-link .picker-container) {
+ margin-bottom: var(--spacing-300);
+ }
+}
+
+.print-product-detail-sdk .hidden {
+ display: none;
+ visibility: hidden;
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 0;
+ height: 0;
+ opacity: 0;
+ pointer-events: none;
+ z-index: -1;
+ overflow: hidden;
+ border: none;
+ outline: none;
+ box-shadow: none;
+ background: transparent;
+ cursor: pointer;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+}
+.print-product-detail-sdk [data-skeleton='true'] {
+ background: linear-gradient(90deg, #eee 25%, #f5f5f5 37%, #eee 63%);
+ background-size: 400% 100%;
+ animation: skeleton-shimmer 1.2s ease-in-out infinite;
+ border-radius: 4px;
+ min-height: 16px;
+}
+@keyframes skeleton-shimmer {
+ 0% {
+ background-position: 100% 0;
+ }
+ 100% {
+ background-position: -100% 0;
+ }
+}
+.pdpx-global-container {
+ max-width: var(--block-wd-max-width);
+ margin: 0 auto;
+ padding: var(--global-container-margin);
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-300);
+ align-items: flex-start;
+}
+.pdpx-product-info-wrapper {
+ display: contents;
+ flex-direction: column;
+ width: 100%;
+ order: 3;
+}
+.pdpx-product-info-section-container {
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ order: 3;
+ .pdpx-product-info-section {
+ width: 100%;
+ order: 3;
+ }
+}
+/* HEADER SECTION CONTENT */
+.pdpx-product-info-heading-section-wrapper {
+ width: 100%;
+ order: 1;
+}
+.pdpx-product-info-heading-section-container {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ gap: var(--spacing-100);
+ align-items: baseline;
+ margin-bottom: var(--spacing-200);
+}
+.pdpx-product-title {
+ font-size: var(--ax-heading-xl-size);
+}
+.pdpx-customization-inputs-container {
+ padding-bottom: var(--spacing-400);
+}
+.pdpx-customization-inputs-container .picker-container.opened {
+ position: relative;
+ z-index: 19;
+}
+.pdpx-customization-inputs-container .picker-container.opened .picker-options-wrapper::after {
+ content: '';
+ position: absolute;
+ bottom: -16px;
+ left: 0;
+ width: 1px;
+ height: 16px;
+ pointer-events: none;
+}
+.pdpx-price-info-container {
+ display: flex;
+ flex-direction: column;
+ .pdpx-price-info-row {
+ display: flex;
+ align-items: baseline;
+ gap: var(--spacing-75);
+ .pdpx-price-label {
+ font-size: var(--ax-body-l-size);
+ font-weight: var(--ax-detail-weight);
+ }
+ .pdpx-compare-price-label {
+ text-decoration: line-through;
+ font-size: var(--ax-body-xs-size);
+ }
+ .pdpx-compare-price-info-label {
+ font-size: var(--ax-body-xs-size);
+ text-align: end;
+ white-space: nowrap;
+ }
+ }
+ .pdpx-compare-price-info-icon-container {
+ position: relative;
+ .pdpx-compare-price-info-icon-button {
+ background: transparent;
+ border: none;
+ padding: 0;
+ margin: 0;
+ align-self: end;
+ cursor: pointer;
+ width: max-content;
+ .pdpx-compare-price-info-icon {
+ width: var(--spacing-200);
+ }
+ }
+ .pdpx-info-tooltip-content {
+ position: absolute;
+ display: none;
+ right: -100px;
+ background-color: #323232;
+ color: var(--color-white);
+ padding: 15px;
+ border-radius: 8px;
+ width: max-content;
+ max-width: 250px;
+ text-align: center;
+ z-index: 1;
+ .pdpx-info-tooltip-content-title {
+ font-size: var(--ax-body-xs-size);
+ font-weight: var(--ax-detail-weight);
+ color: var(--color-white);
+ margin: 0;
+ }
+ .pdpx-info-tooltip-content-description {
+ font-size: var(--ax-body-xxs-size);
+ margin: 0;
+ padding: 0;
+ padding-top: 10px;
+ }
+ }
+ }
+ .pdpx-savings-text {
+ font-size: var(--ax-body-xxs-size);
+ font-weight: var(--ax-detail-weight);
+ color: #05834e;
+ }
+}
+.pdpx-product-ratings-lockup-container {
+ display: flex;
+ flex-direction: row;
+ align-items: baseline;
+ gap: var(--spacing-75);
+ .pdpx-product-info-header-ratings-star {
+ width: 17px;
+ }
+ .pdpx-star-ratings {
+ display: flex;
+ align-self: anchor-center;
+ gap: 2px;
+ }
+ .pdpx-star-ratings .pdpx-star-icon {
+ width: 17px;
+ height: 17px;
+ display: block;
+ flex-shrink: 0;
+ }
+ .pdpx-star-ratings .pdpx-star-icon-wrapper {
+ width: 17px;
+ height: 17px;
+ flex-shrink: 0;
+ }
+ .pdpx-star-ratings .pdpx-star-icon-half-wrapper {
+ position: relative;
+ overflow: hidden;
+ }
+ .pdpx-star-ratings .pdpx-star-icon-half-filled {
+ position: absolute;
+ left: 0;
+ top: 0;
+ clip-path: inset(0 50% 0 0);
+ -webkit-clip-path: inset(0 50% 0 0);
+ }
+ .pdpx-star-ratings .pdpx-star-icon-half-empty {
+ position: absolute;
+ left: 0;
+ top: 0;
+ clip-path: inset(0 0 0 50%);
+ -webkit-clip-path: inset(0 0 0 50%);
+ }
+ .pdpx-ratings-number {
+ font-size: var(--ax-body-xs-size);
+ font-weight: var(--ax-detail-weight);
+ line-height: 1.5;
+ color: var(--body-color);
+ }
+ .pdpx-ratings-amount {
+ background: transparent;
+ font-size: var(--ax-body-xs-size);
+ line-height: 1.5;
+ font-weight: var(--ax-body-weight);
+ color: var(--body-color);
+ border: none;
+ padding: 0;
+ margin: 0;
+ cursor: default;
+ }
+}
+.pdpx-delivery-estimate-pill {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ background-color: var(--palette-indigo-200);
+ border-radius: 8px;
+ width: fit-content;
+ padding: var(--spacing-100);
+ gap: var(--spacing-75);
+ margin-bottom: 0;
+}
+/* END HEADER SECTION CONTENT */
+/* PRODUCT IMAGES SECTION CONTENT */
+.pdpx-product-images-container {
+ width: 100%;
+ order: 2;
+ .pdpx-product-hero-image-container {
+ margin-bottom: var(--spacing-100);
+ aspect-ratio: 1/1;
+ border-radius: var(--spacing-200);
+ overflow: hidden;
+ object-fit: contain;
+ object-position: center;
+ .pdpx-product-hero-image {
+ width: 100%;
+ border-radius: var(--spacing-200);
+ }
+ }
+ .pdpx-image-thumbnail-carousel-container {
+ position: relative;
+ width: 100%;
+ }
+ .pdpx-image-thumbnail-carousel-item {
+ border-radius: 8px;
+ overflow: hidden;
+ flex-shrink: 0;
+ width: var(--spacing-700);
+ height: var(--spacing-700);
+ border: 1px solid transparent;
+ background-color: transparent;
+ padding: 0;
+ cursor: pointer;
+ transition: border-color 0.2s ease;
+ }
+ .pdpx-image-thumbnail-carousel-item:hover {
+ border-color: var(--color-gray-300);
+ }
+ .pdpx-image-thumbnail-carousel-item.selected {
+ border: 1px solid var(--color-background-accent-default);
+ }
+ .pdpx-image-thumbnail-carousel-item-image {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ }
+}
+/* SIMPLE CAROUSEL */
+.simple-carousel-fader-left {
+ pointer-events: none;
+ width: 88px;
+ background: linear-gradient(
+ to right,
+ rgba(255, 255, 255, 1) 0%,
+ rgba(255, 255, 255, 1) 20%,
+ rgba(255, 255, 255, 0) 100%
+ );
+ .simple-carousel-arrow-left {
+ pointer-events: all;
+ left: 5px;
+ }
+}
+.simple-carousel-fader-right {
+ pointer-events: none;
+ width: 88px;
+ background: linear-gradient(
+ to left,
+ rgba(255, 255, 255, 1) 0%,
+ rgba(255, 255, 255, 1) 20%,
+ rgba(255, 255, 255, 0) 100%
+ );
+ .simple-carousel-arrow-right {
+ pointer-events: all;
+ }
+}
+
+/* CHECKOUT BUTTON */
+.pdpx-checkout-button-container {
+ position: fixed;
+ bottom: -1px;
+ left: 0;
+ background: var(--color-white);
+ width: 100%;
+ margin-top: var(--spacing-200);
+ order: 4;
+ z-index: 18;
+ a.pdpx-checkout-button {
+ width: calc(100% - (var(--global-container-margin) * 2));
+ margin-left: auto;
+ margin-right: auto;
+ box-sizing: border-box;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ gap: 10px;
+ margin-bottom: var(--spacing-100);
+ background-color: var(--color-background-accent-default);
+ color: var(--color-white);
+ border: none;
+ border-radius: 24px;
+ padding: 13px;
+ cursor: pointer;
+ }
+}
+
+.pdpx-checkout-button-text {
+ font-size: var(--ax-body-m-size);
+ font-weight: var(--ax-detail-weight);
+}
+.pdpx-checkout-button-subhead {
+ width: calc(100% - (var(--global-container-margin) * 2));
+ margin-left: auto;
+ margin-right: auto;
+ display: flex;
+ flex-direction: row;
+ align-items: end;
+ flex-wrap: wrap;
+ justify-content: center;
+ gap: var(--spacing-75);
+ font-size: var(--ax-body-xs-size);
+ margin-bottom: var(--spacing-300);
+}
+.pdpx-checkout-button-subhead-image {
+ margin-bottom: 1px;
+}
+main .pdpx-checkout-button-subhead a.pdpx-checkout-button-subhead-link {
+ white-space: nowrap;
+ color: var(--color-black);
+ font-weight: var(--ax-body-weight);
+ text-decoration: underline;
+}
+.pdpx-checkout-button-subhead-text {
+ text-align: right;
+}
+.pdpx-checkout-button-disabled a.pdpx-checkout-button {
+ background-color: var(--color-dark-gray);
+ border-radius: 10px;
+ cursor: not-allowed;
+ pointer-events: none;
+ font-weight: var(--ax-body-weight);
+ span.pdpx-checkout-button-text {
+ font-size: var(--ax-body-s-size);
+ font-weight: var(--ax-body-weight);
+ }
+}
+.pdpx-assurance-lockup-container {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: var(--spacing-300);
+ margin-bottom: var(--spacing-400);
+ .pdpx-assurance-lockup-item {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: var(--spacing-100);
+ width: 100%;
+ justify-content: center;
+ padding: var(--spacing-100) 0;
+ background-color: var(--color-gray-100);
+ border-radius: 8px;
+ }
+}
+/* PILL SELECTOR */
+.pdpx-pill-selector-container {
+ margin-bottom: var(--spacing-400);
+ overflow: visible;
+ .pdpx-pill-selector-label-container {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ margin-bottom: var(--spacing-100);
+ .pdpx-pill-selector-label-label {
+ font-weight: var(--ax-detail-weight);
+ }
+ }
+}
+.pdpx-standard-selector-container {
+ margin-bottom: 1rem;
+}
+.pdpx-pill-selector-label {
+ display: block;
+ font-weight: var(--ax-detail-weight);
+ margin-bottom: var(--spacing-100);
+}
+.pdpx-pill-selector-options-container {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ gap: var(--spacing-100);
+ overflow: visible;
+}
+.pdpx-pill-container {
+ position: relative;
+ display: flex;
+ flex-direction: row;
+ min-width: 150px;
+ background-color: white;
+ overflow: hidden;
+ border-radius: 8px;
+ border: 1px solid var(--color-gray-300-variant);
+ padding: 0px;
+ cursor: pointer;
+}
+.pdpx-pill-container.selected {
+ border: 1px solid var(--color-background-accent-default);
+}
+.pdpx-pill-image-container {
+ width: 54px;
+ height: 100%;
+ flex-shrink: 0;
+ aspect-ratio: 1/1;
+}
+.pdpx-pill-image {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+}
+.pdpx-pill-text-container {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ justify-content: center;
+ min-width: 92px;
+ gap: var(--spacing-75);
+ padding: var(--spacing-100);
+ padding-right: var(--spacing-400);
+}
+.pdpx-pill-text-name {
+ font-size: var(--ax-body-xs-size);
+ font-weight: var(--ax-detail-weight);
+ color: black;
+ text-align: left;
+}
+.pdpx-pill-text-price {
+ font-size: var(--ax-body-xs-size);
+ font-weight: var(--ax-body-weight);
+ color: var(--color-dark-gray);
+}
+/* MINI PILL SELECTOR */
+.pdpx-mini-pill-container {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ gap: 0px;
+ overflow: visible;
+}
+.pdpx-pill-selector-label-compare-link {
+ background: transparent;
+ font-family: var(--body-font-family);
+ font-size: var(--ax-body-xs-size);
+ font-weight: 500;
+ border: none;
+ padding: 0;
+ margin: 0;
+ text-decoration: underline;
+ cursor: pointer;
+}
+
+.pdpx-mini-pill-sections-container {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ gap: var(--spacing-200);
+ overflow: visible;
+ position: relative;
+}
+.pdpx-mini-pill-image-container {
+ border-radius: 4px;
+ border: 1px solid transparent;
+ width: 48px;
+ height: 48px;
+ padding: 0;
+ background-color: transparent;
+ display: inline-block;
+ overflow: hidden;
+ position: relative;
+ line-height: 0;
+ cursor: pointer;
+ transition: var(--standard-transition-hover-out-border-color);
+ font-family: var(--body-font-family);
+ font-weight: var(--ax-body-weight);
+ font-size: var(--ax-body-xs-size);
+ .pdpx-mini-pill-image {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ object-position: center;
+ display: block;
+ pointer-events: none;
+ }
+}
+.pdpx-mini-pill-price {
+ font-size: var(--ax-body-xxs-size);
+ font-weight: var(--ax-body-weight);
+ color: var(--color-gray-950);
+}
+.pdpx-mini-pill-image-container.selected {
+ border: 1px solid var(--color-background-accent-default);
+}
+.pdpx-mini-pill-image-container:hover:not(.selected),
+.pdpx-image-thumbnail-carousel-item:hover:not(.selected) {
+ border-color: var(--color-black);
+ transition: var(--standard-transition-hover-in-border-color);
+}
+@media (hover: hover) {
+ .pdpx-mini-pill-image-container::after {
+ content: attr(aria-label);
+ position: fixed;
+ font-size: var(--ax-body-xs-size);
+ padding: var(--spacing-325) var(--spacing-200);
+ top: var(--tooltip-top);
+ left: var(--tooltip-left);
+ background: var(--color-gray-800);
+ color: var(--color-white);
+ border-radius: 6px;
+ white-space: nowrap;
+ pointer-events: none;
+ opacity: 0;
+ visibility: hidden;
+ transition: var(--standard-transition-hover-out-opacity);
+ z-index: 200;
+ }
+ .pdpx-mini-pill-image-container::before {
+ content: '';
+ position: fixed;
+ top: var(--arrow-top);
+ left: var(--arrow-left);
+ bottom: 100%;
+ transform: translate(-50%, -4px) rotate(45deg);
+ width: 8px;
+ height: 8px;
+ background: var(--color-gray-800);
+ pointer-events: none;
+ opacity: 0;
+ visibility: hidden;
+ transition: var(--standard-transition-hover-out-opacity);
+ z-index: 199;
+ }
+ .pdpx-mini-pill-image-container:hover::after,
+ .pdpx-mini-pill-image-container:hover::before {
+ opacity: 1;
+ visibility: visible;
+ transition: var(--standard-transition-hover-in-opacity);
+ }
+}
+.pdpx-mini-pill-text-container {
+ display: none;
+}
+.pdpx-pill-selector-section-label {
+ display: block;
+ margin-bottom: var(--spacing-100);
+}
+.pdpx-mini-pill-section-container,
+.pdpx-mini-pill-section-options-container {
+ position: relative;
+ width: 100%;
+}
+/* PRODUCT DETAILS SECTION */
+.pdpx-product-details-section {
+ margin-bottom: var(--spacing-400);
+}
+.pdpx-product-details-section-title-container {
+ padding-bottom: var(--spacing-300);
+}
+.pdpx-product-details-section-title {
+ font-size: var(--ax-body-s-size);
+ font-weight: var(--ax-detail-weight);
+}
+.pdpx-mini-pill-selector-options-container {
+ position: relative;
+}
+#pdpx-checkout-button-sentinel-div {
+ height: 1px;
+ width: 1px;
+ opacity: 0;
+ background-color: transparent;
+ visibility: hidden;
+ pointer-events: none;
+ position: absolute;
+ bottom: 0;
+ left: 0;
+}
+/*DRAWER*/
+.pdpx-drawer-body {
+ padding: var(--spacing-300) var(--spacing-300) 0 var(--spacing-300);
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ overflow-y: auto;
+ overflow-x: visible;
+ scrollbar-width: thin;
+
+}
+.pdpx-drawer-hero-image-container {
+ aspect-ratio: 3 / 2;
+ width: 100%;
+ min-height: 200px;
+ overflow: hidden;
+ flex-shrink: 0;
+ margin-bottom: var(--spacing-400);
+ .pdpx-drawer-hero-image {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ object-position: bottom;
+ border-radius: 8px;
+ display: block;
+ transition: opacity 0.2s ease;
+ }
+}
+.pdpx-drawer-title-row {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: var(--spacing-100);
+ .pdpx-drawer-title {
+ font-size: var(--ax-body-l-size);
+ font-weight: var(--ax-detail-weight);
+ }
+ .pdpx-recommended-badge {
+ font-size: var(--body-font-size-xs);
+ color: white;
+ padding: 4px 9px;
+ line-height: 1.3;
+ border-radius: 7px;
+ background-color: #3b63fb;
+ }
+}
+.pdpx-drawer-pills-container {
+ display: flex;
+ gap: var(--spacing-100);
+ margin-bottom: var(--spacing-300);
+ .pdpx-drawer-pill {
+ border-radius: 8px;
+ padding: var(--spacing-75) var(--spacing-100);
+ background-color: var(--color-gray-150);
+ display: flex;
+ align-items: center;
+ font-size: var(--body-font-size-s);
+ gap: 4px;
+ }
+}
+main .section .pdpx-drawer-description {
+ font-size: var(--ax-body-xs-size);
+ font-weight: var(--ax-body-weight);
+ margin-bottom: var(--spacing-300);
+ p {
+ margin: 0;
+ margin-top: 0px;
+ margin-bottom: 0px;
+ padding: 0;
+ }
+ p, ul, ol {
+ font-size: var(--ax-body-xs-size);
+ font-weight: var(--ax-body-weight);
+ }
+}
+.ax-accordion-item-description ul,
+.ax-accordion-item-description ol,
+.ax-accordion-item-description p {
+ font-size: var(--ax-body-s-size);
+}
+main .section .ax-accordion-item-description p {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+.pdpx-drawer-foot {
+ display: flex;
+ border-top: 1px solid var(--color-gray-325);
+ padding: var(--spacing-200) var(--spacing-300);
+ justify-content: space-between;
+ background-color: var(--color-white);
+ flex-shrink: 0;
+ .pdpx-drawer-foot-info-container {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-200);
+ }
+ .pdpx-drawer-foot-info-container img {
+ width: 48px;
+ border-radius: 4px;
+ }
+ .pdpx-drawer-foot-info-name {
+ font-weight: var(--ax-detail-weight);
+ line-height: 1.3;
+ padding-bottom: 2px;
+ }
+ .pdpx-drawer-foot-info-price {
+ font-size: var(--body-font-size-s);
+ line-height: 1.3;
+ }
+ .pdpx-drawer-foot-select-button {
+ color: var(--color-white);
+ background-color: var(--color-background-accent-default);
+ padding: var(--spacing-200) var(--spacing-400);
+ border-radius: 24px;
+ border: none;
+ font-family: var(--body-font-family);
+ font-weight: var(--ax-detail-weight);
+ font-size: var(--body-font-size-l);
+ cursor: pointer;
+ }
+}
+.pdpx-printing-process-options-container {
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-300);
+ .pdpx-printing-process-option-container {
+ display: flex;
+ flex-direction: row;
+ gap: var(--spacing-500);
+ .pdpx-printing-process-option-image-container {
+ max-width: 40%;
+ .pdpx-printing-process-option-image {
+ aspect-ratio: 1/1;
+ object-fit: cover;
+ object-position: center;
+ border-radius: 8px;
+ }
+ }
+ .pdpx-printing-process-option-info-container {
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-300);
+
+ .pdpx-printing-process-option-info-title {
+ font-size: var(--ax-body-l-size);
+ font-weight: var(--ax-detail-weight);
+ }
+ p.pdpx-printing-process-option-info-description {
+ font-size: var(--ax-body-xs-size);
+ font-weight: var(--ax-body-weight);
+ color: var(--color-gray-900);
+ line-height: 1.3;
+ margin: 0;
+ padding: 0;
+ }
+ .pdpx-printing-process-option-color-lockup {
+ display: flex;
+ align-items: center;
+ padding: var(--spacing-75) var(--spacing-100);
+ border-radius: 8px;
+ background-color: var(--color-gray-150);
+ font-size: var(--body-font-size-s);
+ width: fit-content;
+ img:last-of-type {
+ margin-right: 4px;
+ }
+ }
+ }
+ }
+}
+.pdpx-drawer {
+ position: fixed;
+ left: 0;
+ bottom: 0;
+ z-index: 102;
+ border-radius: 16px 16px 0 0;
+ background-color: var(--color-white);
+ height: 600px;
+ width: 100%;
+ transform: translateY(0);
+ transition: transform 300ms ease;
+ display: flex;
+ flex-direction: column;
+}
+.pdpx-drawer.hidden {
+ transform: translateY(100%);
+}
+.pdpx-drawer-head {
+ display: flex;
+ position: sticky;
+ top: 0;
+ z-index: 1;
+ justify-content: space-between;
+ border-radius: 16px 16px 0 0;
+ border-bottom: 1px solid var(--color-gray-325);
+ padding: var(--spacing-400) var(--spacing-300);
+ background-color: var(--color-white);
+}
+.pdpx-drawer-head-label {
+ font-size: var(--ax-body-xl-size);
+ font-weight: var(--ax-detail-weight);
+ line-height: 1.3;
+}
+.pdpx-drawer-head button {
+ cursor: pointer;
+ background: none;
+ border: none;
+}
+.pdpx-drawer-body .pdpx-mini-pill-sections-container {
+ overflow: visible;
+}
+.pdpx-curtain {
+ z-index: 101;
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ background: rgb(0 0 0 / 40%);
+}
+/* SIZE CHART */
+.print-product-detail-sdk .size-chart-product-name {
+ font-size: var(--body-font-size-l);
+ font-weight: var(--subheading-font-weight);
+ color: var(--color-gray-950);
+ margin: 0;
+ margin-bottom: var(--spacing-100);
+}
+.print-product-detail-sdk .size-chart-table-container {
+ border-radius: 16px;
+ border: 1px solid var(--color-gray-325);
+ padding: var(--spacing-400);
+ color: var(--color-gray-900);
+ margin-bottom: var(--spacing-400);
+}
+.print-product-detail-sdk .size-chart-table-section {
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-100);
+}
+.print-product-detail-sdk .size-chart-table thead .size-chart-table-header {
+ font-size: var(--body-font-size-s);
+ font-weight: var(--subheading-font-weight);
+ color: var(--color-gray-950);
+ text-align: left;
+ padding: var(--spacing-100);
+ white-space: nowrap;
+}
+.print-product-detail-sdk .size-chart-table {
+ width: 100%;
+ border-collapse: separate;
+ border-spacing: 0 var(--spacing-100);
+ table-layout: fixed;
+}
+.print-product-detail-sdk .size-chart-table thead th {
+ font-size: var(--body-font-size-s);
+ font-weight: normal;
+ color: var(--color-gray-800);
+ text-align: left;
+ padding: var(--spacing-100);
+ padding-top: 0px;
+}
+.print-product-detail-sdk .size-chart-table thead th:nth-child(2),
+.print-product-detail-sdk .size-chart-table thead th:nth-child(3) {
+ padding-left: var(--spacing-400);
+ text-align: right;
+}
+.print-product-detail-sdk .size-chart-table tbody tr {
+ background: var(--color-white);
+}
+.print-product-detail-sdk .size-chart-table tbody tr:nth-child(odd) {
+ background: #ebebeb;
+}
+.print-product-detail-sdk .size-chart-table tbody tr:nth-child(odd) td:first-child {
+ border-top-left-radius: 8px;
+ border-bottom-left-radius: 8px;
+}
+.print-product-detail-sdk .size-chart-table tbody tr:nth-child(odd) td:last-child {
+ border-top-right-radius: 8px;
+ border-bottom-right-radius: 8px;
+}
+.print-product-detail-sdk .size-chart-table tbody td {
+ font-size: var(--body-font-size-xs);
+ color: var(--color-gray-950);
+ padding: var(--spacing-100) var(--spacing-200);
+ word-break: break-word;
+ line-height: 1.3;
+}
+.print-product-detail-sdk .size-chart-table tbody td:nth-child(2),
+.print-product-detail-sdk .size-chart-table tbody td:nth-child(3) {
+ padding-left: var(--spacing-400);
+ text-align: right;
+}
+.print-product-detail-sdk .size-chart-instructions {
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-300);
+ margin-bottom: 80px;
+}
+.print-product-detail-sdk .size-chart-instruction-section h3 {
+ font-size: var(--body-font-size-m);
+ font-weight: var(--subheading-font-weight);
+ color: var(--color-gray-950);
+ margin: 0 0 var(--spacing-100) 0;
+}
+.print-product-detail-sdk .size-chart-instructions .size-chart-instruction-text {
+ font-size: var(--body-font-size-s);
+ font-style: normal;
+ font-weight: var(--ax-body-weight);
+ line-height: 130%;
+ margin: 0;
+}
+.pdpx-checkout-button-container:not(.hide-gradient)::before {
+ content: '';
+ position: absolute;
+ bottom: 100%;
+ left: 0;
+ right: 0;
+ height: var(--spacing-900);
+ pointer-events: none;
+ background: linear-gradient(to top, white 20%, rgba(255, 255, 255, 0) 100%);
+}
+
+
+/*TABLET*/
+@media (min-width: 600px) {
+ .pdpx-global-container {
+ flex-direction: row;
+ }
+ .pdpx-price-info-container {
+ .pdpx-compare-price-info-icon-container {
+ .pdpx-info-tooltip-content {
+ right: 0px;
+ width: 175px;
+ }
+ }
+ }
+ .pdpx-product-images-container {
+ order: 1;
+ width: calc(50% - 8px);
+ }
+ .pdpx-product-info-wrapper {
+ order: 2;
+ width: calc(50% - 8px);
+ display: flex;
+ flex-direction: column;
+ flex: 1 1 auto;
+ height: 75vh;
+ overflow-x: visible;
+ overflow-y: scroll;
+ scrollbar-gutter: stable;
+ padding-right: var(--spacing-400);
+ }
+ .pdpx-product-info-heading-section-wrapper {
+ order: 1;
+ }
+ .pdpx-product-info-section-container {
+ display: flex;
+ flex-direction: column;
+ order: 2;
+ }
+ .pdpx-product-info-heading-section-container {
+ flex-direction: column;
+ order: 1;
+ }
+ .pdpx-product-info-section {
+ order: 2;
+ }
+ .pdpx-checkout-button-subhead {
+ display: flex;
+ }
+ .pdpx-delivery-estimate-pill {
+ margin-bottom: var(--spacing-400);
+ }
+ .size-chart-tables {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: var(--spacing-400);
+ }
+ .pdpx-mini-pill-text-container {
+ display: block;
+ }
+ .pdpx-drawer-body {
+ padding: var(--spacing-500);
+ }
+ .pdpx-drawer-foot {
+ padding: var(--spacing-200) var(--spacing-500);
+ }
+ .pdpx-checkout-button-container:not(.hide-gradient)::before {
+ content: '';
+ position: absolute;
+ bottom: 100%;
+ left: 0;
+ right: 0;
+ height: var(--spacing-900);
+ pointer-events: none;
+ background: linear-gradient(to top, white 20%, rgba(255, 255, 255, 0) 100%);
+ }
+ .pdpx-checkout-button-container {
+ position: sticky;
+ width: 100%;
+ a.pdpx-checkout-button {
+ width: 100%;
+ }
+ }
+}
+/*DESKTOP*/
+@media (min-width: 1200px) {
+ .pdpx-global-container {
+ gap: var(--spacing-400);
+ }
+ .pdpx-price-info-container {
+ .pdpx-compare-price-info-icon-container {
+ .pdpx-info-tooltip-content {
+ right: 0;
+ width: 250px;
+ }
+ }
+ }
+ .pdpx-product-info-heading-section-container {
+ flex-direction: row;
+ margin-bottom: var(--spacing-400);
+ gap: var(--spacing-400);
+ .pdpx-price-info-container {
+ align-items: flex-end;
+ }
+ }
+ .pdpx-title-and-ratings-container {
+ max-width: 64%;
+ }
+ .pdpx-product-images-container,
+ .pdpx-product-info-wrapper {
+ width: calc(50% - 12px);
+ }
+ .pdpx-savings-text {
+ text-align: end;
+ }
+ .pdpx-drawer {
+ bottom: initial;
+ top: 0;
+ right: 0;
+ left: initial;
+ width: 50%;
+ height: 100%;
+ border-radius: initial;
+ transform: translateX(0);
+ }
+ .pdpx-drawer.hidden {
+ transform: translateX(100%);
+ }
+ .pdpx-drawer-title {
+ font-size: var(--body-font-size-xl);
+ }
+ .pdpx-assurance-lockup-container {
+ flex-direction: row;
+ .pdpx-assurance-lockup-item {
+ width: 50%;
+ }
+ }
+ .pdpx-product-images-container .pdpx-product-hero-image-container {
+ margin-bottom: var(--spacing-200);
+ }
+ .pdpx-product-images-container .pdpx-image-thumbnail-carousel-item {
+ width: 76px;
+ height: 76px;
+ }
+ .pdpx-mini-pill-sections-container {
+ .simple-carousel-platform {
+ flex-wrap: wrap;
+ overflow: visible;
+ }
+ .simple-carousel-fader-left,
+ .simple-carousel-fader-right {
+ pointer-events: none;
+ display: none;
+ }
+ }
+ .pdpx-drawer-head {
+ padding: var(--spacing-400) var(--spacing-600);
+ }
+ .pdpx-drawer-body {
+ padding: var(--spacing-600) var(--spacing-600) 0 var(--spacing-600);
+ }
+ .pdpx-drawer-foot {
+ padding: var(--spacing-200) var(--spacing-600);
+ }
+}
+
+/* Accessibility: screen-reader-only utility */
+.print-product-detail-sdk .sr-only {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ white-space: nowrap;
+ border: 0;
+}
+
+/* Accessibility: focus indicators */
+.print-product-detail-sdk a:focus-visible,
+.print-product-detail-sdk button:focus-visible,
+.print-product-detail-sdk input:focus-visible,
+.print-product-detail-sdk select:focus-visible {
+ outline: 3px solid var(--color-background-accent-default);
+ outline-offset: 2px;
+}
+
+.print-product-detail-sdk .pdpx-mini-pill-image-container:focus-visible {
+ outline: 3px solid var(--color-background-accent-default);
+ outline-offset: 2px;
+ border-radius: 50%;
+}
+
+.print-product-detail-sdk .pdpx-pill-container:focus-visible {
+ outline: 3px solid var(--color-background-accent-default);
+ outline-offset: 2px;
+ border-radius: var(--spacing-100);
+}
+
+.print-product-detail-sdk a.pdpx-checkout-button:focus-visible {
+ outline: 3px solid var(--color-white);
+ outline-offset: -3px;
+}
+
+/* Accessibility: reduced motion */
+@media (prefers-reduced-motion: reduce) {
+ .print-product-detail-sdk [data-skeleton='true'] {
+ animation: none;
+ }
+
+ .print-product-detail-sdk .pdpx-curtain,
+ .print-product-detail-sdk .pdpx-drawer,
+ .print-product-detail-sdk .pdpx-mini-pill-image-container::after,
+ .print-product-detail-sdk .pdpx-mini-pill-image-container::before {
+ transition-duration: 0.01ms;
+ }
+}
diff --git a/express/code/blocks/print-product-detail-sdk/print-product-detail-sdk.js b/express/code/blocks/print-product-detail-sdk/print-product-detail-sdk.js
new file mode 100644
index 000000000..c952f2d24
--- /dev/null
+++ b/express/code/blocks/print-product-detail-sdk/print-product-detail-sdk.js
@@ -0,0 +1,158 @@
+import { createZazzleStore, extractTemplateId } from './utilities/utility-functions.js';
+import { getLibs } from '../../scripts/utils.js';
+import {
+ html,
+ render,
+ useEffect,
+ useRef,
+ useState,
+ Fragment,
+} from '../../scripts/vendors/htm-preact.min.js';
+import { StoreProvider, useStore, DrawerProvider, useDrawer } from './components/Contexts.js';
+import { ProductImages, ProductDetails, ProductHeader, CheckoutButton, Drawer } from './components/ProductComponents.js';
+import { CustomizationInputs } from './components/CustomizationInputs.js';
+import { trackViewTemplatePage } from '../../scripts/instrument.js';
+import useSeo from './components/useSeo.js';
+
+function LoadingSkeleton() {
+ return html`
+
+ `;
+}
+
+function PDPContent({ templateId }) {
+ const store = useStore();
+ const { state, actions } = store;
+ const { openDrawer } = useDrawer();
+ const { fetchProduct } = actions;
+ const containerRef = useRef(null);
+ const hasTrackedPageView = useRef(false);
+ const [fetchError, setFetchError] = useState(false);
+
+ useSeo(templateId);
+
+ useEffect(() => {
+ if (!templateId) {
+ return;
+ }
+ fetchProduct(templateId).catch((err) => {
+ window.lana?.log(`print-product-detail-sdk: fetchProduct failed: ${err.message}`, { tags: 'print-product-detail-sdk', severity: 'error' });
+ setFetchError(true);
+ });
+ }, [templateId, fetchProduct]);
+
+ useEffect(() => {
+ if (!state || hasTrackedPageView.current) return;
+ hasTrackedPageView.current = true;
+ try {
+ const attributeObject = Object.fromEntries(
+ (state.attributes || []).map((attr) => [attr.name, attr.selectedOptionValue]),
+ );
+ trackViewTemplatePage(
+ 'pdp',
+ state.productType,
+ templateId,
+ 'print',
+ true,
+ attributeObject,
+ true,
+ );
+ } catch (error) {
+ window.lana?.log(`Failed to track PDP pageload: ${error}`, { tags: 'print-product-detail-sdk', severity: 'warning' });
+ }
+ }, [state, templateId]);
+
+ useEffect(() => {
+ if (!containerRef.current || !state) return;
+ import(`${getLibs()}/martech/attributes.js`).then(({ decorateDefaultLinkAnalytics }) => {
+ import(`${getLibs()}/utils/utils.js`).then(({ getConfig }) => {
+ decorateDefaultLinkAnalytics(containerRef.current, getConfig());
+ });
+ });
+ }, [state]);
+
+ const handleDrawerRequest = (request) => {
+ if (!request) {
+ return;
+ }
+ openDrawer({ type: request.type, payload: request.payload });
+ };
+
+ if (fetchError) {
+ return html`
+
+
+
Something went wrong loading this product. Please try refreshing the page.
+
+
+ `;
+ }
+
+ if (!state) {
+ return html`
+ <${Fragment}>
+ <${LoadingSkeleton} />
+ <${Drawer} />
+ ${Fragment}>
+ `;
+ }
+
+ return html`
+
+ <${ProductImages} />
+
+ <${ProductHeader} />
+
+
+ <${CustomizationInputs} onRequestDrawer=${handleDrawerRequest} productType=${state.productType} />
+ <${ProductDetails} />
+ <${Drawer} />
+
+ <${CheckoutButton} templateId=${templateId} />
+
+
+
+ `;
+}
+
+export function PDPApp({ sdkStore, templateId }) {
+ return html`
+ <${StoreProvider} sdkStore=${sdkStore}>
+ <${DrawerProvider}>
+ <${PDPContent} templateId=${templateId} />
+ ${DrawerProvider}>
+ ${StoreProvider}>
+ `;
+}
+
+export default async function decorate(block) {
+ const templateId = extractTemplateId(block);
+ block.innerHTML = '';
+ const mountPoint = document.createElement('div');
+ block.append(mountPoint);
+ const store = await createZazzleStore();
+ render(html`<${PDPApp} sdkStore=${store.sdk} templateId=${templateId} />`, mountPoint);
+ const { loadStyle, getConfig } = await import(`${getLibs()}/utils/utils.js`);
+ const { codeRoot } = getConfig();
+ await Promise.all([
+ new Promise((resolve) => {
+ loadStyle(`${codeRoot}/scripts/widgets/simple-carousel.css`, resolve);
+ }),
+ new Promise((resolve) => {
+ loadStyle(`${codeRoot}/scripts/widgets/picker.css`, resolve);
+ }),
+ ]);
+}
diff --git a/express/code/blocks/print-product-detail-sdk/sdk/index.d.ts b/express/code/blocks/print-product-detail-sdk/sdk/index.d.ts
new file mode 100644
index 000000000..bf0d53531
--- /dev/null
+++ b/express/code/blocks/print-product-detail-sdk/sdk/index.d.ts
@@ -0,0 +1,418 @@
+export type PDPState = {
+ /**
+ * All data needed to render the product attribute UI (titles, selectors, values, etc.).
+ */
+ attributes: Attribute[];
+ /**
+ * The components that make up the product description, one for each attribute with a description.
+ */
+ descriptionComponents: DescriptionComponent[];
+ /**
+ * The `?productSettings` string to add to the Express URL, which facilitates state transfer to the add-on.
+ */
+ expressProductSettings: string;
+ /**
+ * Pricing info for the currently selected options and quantity.
+ */
+ pricing: PricingInfo;
+ /**
+ * The Zazzle-centric product type (e.g. `zazzle_shirt`).
+ */
+ productType: AdobeKnownZazzleProductType;
+ /**
+ * The currently selected quantity.
+ */
+ quantity: number;
+ /**
+ * The list of quantity options to show in the quantity selector.
+ */
+ quantityOptions: QuantityOption[];
+ /**
+ * All views (known to Zazzle as realviews) showcasing the product. Images and videos may be present.
+ * @see selectedRealview
+ * @see selectRealview
+ */
+ realviews: Realview[];
+ /**
+ * Overall reviews statistics.
+ */
+ reviewsStats?: ReviewsStats | undefined;
+ /**
+ * The currently selected realview.
+ * @see realviews
+ * @see selectRealview
+ */
+ selectedRealview: Realview;
+ /**
+ * The range of possible worst-case delivery dates (e.g. 'Nov 23 - 27')
+ */
+ shippingEstimate: string;
+ /**
+ * The title of the product.
+ */
+ title: string;
+ /**
+ * The unit label that's applicable to the current quantity (e.g. 'shirt' or 'shirts').
+ * @see quantity
+ */
+ unitLabel: string;
+};
+export type Attribute = {
+ /**
+ * When present, render a help link alongside the attribute title, which will show more info when clicked.
+ */
+ helpLink: AttributeHelpLink | undefined;
+ /**
+ * The attribute's internal name (e.g. 'color').
+ * Use this as the first parameter when selecting an option.
+ *
+ * @see selectOption
+ */
+ name: string;
+ /** The currently selected option's value, or internal name (e.g. 'red'). */
+ selectedOptionValue: string;
+ /** The human readable title of the currently selected option (e.g. 'Red'). */
+ selectedOptionTitle: string;
+ /**
+ * Data powering the actual UI selector (thumbnails, radio buttons, dropdown, etc.).
+ * Each selector type has its own data structure. See the associated types for details.
+ */
+ selector: AttributeSelectorThumbnails | AttributeSelectorRadio | AttributeSelectorCheckbox | AttributeSelectorDropdown;
+ /** The human readable title of the attribute (e.g. 'Color'). */
+ title: string;
+};
+export type AttributeHelpLink = {
+ /**
+ * For now, size chart is the only supported help link dialog type.
+ * @see fetchSizeChart
+ */
+ dialogType: 'sizeChart';
+ /** The label of the link that should open the dialog. */
+ label: string;
+ type: 'dialog';
+};
+/** This selector type doesn't appear to currently be in use :/ */
+export type AttributeSelectorCheckbox = {
+ /**
+ * The value, or internal name, of the option that represents the checked state.
+ * (Under the hood, a checkbox is really a semantic UI element that selects between two underlying options.)
+ * Use this as the second parameter when selecting an option.
+ * @see selectOption
+ */
+ checkedValue: string;
+ /** Will only be set when configured to show and non-zero. */
+ priceDelta?: string;
+ /** The human readable title of the checkbox (e.g. 'High Definition'). */
+ title: string;
+ type: 'checkbox';
+ /**
+ * The value, or internal name, of the option that represents the unchecked state.
+ * (Under the hood, a checkbox is really a semantic UI element that selects between two underlying options.)
+ * Use this as the second parameter when selecting an option.
+ * @see selectOption
+ */
+ uncheckedValue: string;
+};
+export type AttributeSelectorDropdown = {
+ /** An optional message to display beneath the dropdown (e.g. 'Unisex sizing') */
+ message?: string;
+ options: {
+ /** Will only be set when configured to show and non-zero. */
+ priceDelta?: string;
+ /** The human readable title of the option (e.g. 'Red'). */
+ title: string;
+ /**
+ * The value, or internal name, of the option.
+ * Use this as the second parameter when selecting an option.
+ * @see selectOption
+ */
+ value: string;
+ }[];
+ type: 'dropdown';
+};
+export type AttributeSelectorRadio = {
+ options: {
+ /** Will only be set when configured to show and non-zero. */
+ priceDelta?: string;
+ /** The human readable title of the option (e.g. 'Red'). */
+ title: string;
+ /**
+ * The value, or internal name, of the option.
+ * Use this as the second parameter when selecting an option.
+ * @see selectOption
+ */
+ value: string;
+ }[];
+ type: 'radio';
+};
+export type AttributeSelectorThumbnails = {
+ /**
+ * In most cases, there will be only one group.
+ * But in cases like shirts, there will be multiple, with unique labels.
+ */
+ optionGroups: {
+ options: {
+ /** Replace the `max_dim` param value with whatever resolution you'd like to use. */
+ imageUrl: string;
+ /** Will only be set when configured to show and non-zero. */
+ priceDelta?: string;
+ /** The human readable title of the option (e.g. 'Red'). */
+ title: string;
+ /**
+ * The value, or internal name, of the option.
+ * Use this as the second parameter when selecting an option.
+ * @see selectOption
+ */
+ value: string;
+ }[];
+ /** The human readable title of the option group (e.g. 'Classic printing: no underbase'). */
+ title?: string;
+ }[];
+ /**
+ * When present, show a larger preview of the currently selected option, along with a description of the option.
+ */
+ preview?: {
+ /** Will likely contain HTML elements, like ``. */
+ descriptionHTML: string;
+ /** Replace the `max_dim` param value with whatever resolution you'd like to use. */
+ imageUrl: string;
+ /**
+ * The human readable title of the option, primarily for a11y (equivalent to `attribute.selectedOptionTitle`).
+ */
+ optionTitle: string;
+ };
+ type: 'thumbnails';
+};
+export type DescriptionComponent = {
+ /** The human readable title of the attribute (e.g. 'Color'). */
+ attributeTitle: string;
+ /**
+ * The description contextual to the currently selected option.
+ * Will likely contain HTML elements, like ` `.
+ */
+ descriptionHTML: string;
+ /** The human readable title of the currently selected option (e.g. 'Red'). */
+ selectedValueTitle: string;
+};
+export type QuantityOption = {
+ /**
+ * Will only be set when the discount on this quantity is better than the currently applied discount (e.g. '50%').
+ */
+ discount: string | undefined;
+ /** The label for the quantity option (e.g. '1 shirt') */
+ label: string;
+ quantity: number;
+};
+export type PricingInfo = {
+ /**
+ * The label for the currently applied discount. For example,
+ * 'You save 40% (LETZCELEBRATE)' or 'You save 55% (Volume Discount)'
+ */
+ discountLabel: string | undefined;
+ /** The total price (respecting quantity), before any discounts */
+ originalTotalPrice: string;
+ /** The unit price, before any discounts */
+ originalUnitPrice: string;
+ /** The currently active promo code, iff that's what driving the current price */
+ promoCode: string | undefined;
+ /** Whether to show the "Comp Value" UI */
+ showCompValue: boolean;
+ /** The total price (respecting quantity), including any discounts */
+ totalPrice: string;
+ /** The unit price, including any discounts */
+ unitPrice: string;
+};
+export type Realview = RealviewImage | RealviewVideo;
+export type RealviewBase = {
+ /** The unique identifier for the realview. Use this for determining which realview is selected. */
+ id: string;
+ title: string;
+ /**
+ * The URL for the image (or video thumbnnail).
+ * Replace the `max_dim` param value with whatever resolution you'd like to use.
+ */
+ url: string;
+};
+export type RealviewImage = RealviewBase & {
+ type: 'image';
+};
+export type RealviewVideo = RealviewBase & {
+ /**
+ * The source URL for the video in MP4 format (i.e. use `type="video/mp4"`).
+ * For some video types, there will be a `max_dim` param in the URL. If so, replace that value with whatever resolution you'd like to use.
+ */
+ mp4Source: string;
+ type: 'video';
+};
+export type ReviewsStats = {
+ /** The total number of reviews for the product */
+ count: number;
+ /** The average rating for the product, from 1 to 5 */
+ rating: number;
+};
+/**
+ * Zazzle product types that the Adobe world knows about.
+ */
+export type AdobeKnownZazzleProductType = 'mojo_throwpillow' | 'zazzle_bag' | 'zazzle_businesscard' | 'zazzle_flyer' | 'zazzle_foldedthankyoucard' | 'zazzle_invitation3' | 'zazzle_mug' | 'zazzle_print' | 'zazzle_shirt' | 'zazzle_sticker';
+export declare namespace SizeChart {
+ interface ISizeChart {
+ defaultToMetric?: boolean;
+ fitStyle?: string;
+ imageRealViewUrl?: string;
+ isUnisex: boolean;
+ modelInfo?: SizeChart.ISizeMeasurement[];
+ sizeChart?: SizeChart.IChart;
+ title?: string;
+ }
+ interface IModelInfo {
+ bodyMeasurements: ISizeMeasurement[];
+ wearingMeasurements: ISizeMeasurement[];
+ }
+ interface IChart {
+ /** an array of measurement types in the size chart, defining the order of columns from left to right */
+ measurementTypes: IMeasurementType[];
+ /** an array of attribute value rows */
+ attributeValues: IAttributeValueSizeMeasurement[];
+ }
+ interface IMeasurementType {
+ label: string;
+ key: TMeasurementKey;
+ extraDescription: string;
+ }
+ type TMeasurementKey = 'bodyChest' | 'bodyWaist' | 'bodyHip' | 'bodyWeight' | 'bodyAge' | 'garmentWidth' | 'garmentHeight' | 'inseam';
+ type TMeasurementTypeCategory = 'body' | 'garment';
+ interface IAttributeValueSizeMeasurement {
+ attributeValueLabel: string;
+ measurements: {
+ [key in TMeasurementKey]: ISizeMeasurement;
+ };
+ }
+ interface ISizeMeasurement {
+ label?: string;
+ metric: string;
+ imperial: string;
+ }
+}
+/**
+ * # createZazzlePDPStore
+ *
+ * Creates a Zazzle PDP store, which has several key responsibilities:
+ * 1) Abstract away Zazzle API calls, so you only have to deal with high-level methods like `fetchProduct` and `selectOption`.
+ * 2) Maintain an immutable data store representing the current state of the PDP.
+ * 3) Translate raw API data into a more convenient format for rendering the PDP.
+ *
+ * ## Usage
+ *
+ * 1) Create a store instance.
+ * ```ts
+ * const store = createZazzlePDPStore({ region: 'us', language: 'en' });
+ * ```
+ * 2) Fetch product data.
+ * ```ts
+ * await store.fetchProduct('template123');
+ * ```
+ * 3) Subscribe to data changes so you can update your UI. (Unsubscribe by calling the function returned from `subscribe`.)
+ * ```ts
+ * const unsubscribe = store.subscribe(() => {
+ * const newState = store.getSnapshot();
+ * // Update your UI based on the new state
+ * });
+ * ```
+ *
+ * ## Reactive optimistic data model
+ *
+ * The store interaction/update loop assumes that the UI is fully driven by the state. User input responsiveness is solved with optimistic updates.
+ * As such, the UI should not be remembering any of the state on its own, and should instead fully defer to the state.
+ *
+ * For example, calling `selectOption('color', 'red')` will result in several state updates, all of which will trigger the subscription callback. This is the flow.
+ * 1) Update the state immediately with the newly selected color option (`attributes` will change).
+ * 2) Fetch the new state of the attributes from the API and update the state again (`attributes` will change, potentially with a different set of options).
+ * 3) Fetch new pricing and shipping estimate data concurrently, and update the state when each one returns.
+ *
+ * This approach results in immediate optimistic user feedback and async state updates as new data is received, just like on zazzle.com.
+ *
+ * ## Immutability
+ *
+ * The state is maintained immutably, so you can use `===` to compare previous and current state (at any level of the tree) to optimize re-renders.
+ * ```ts
+ * const shouldRerenderAttributesUi = previousState.attributes !== currentState.attributes;
+ * ```
+ *
+ * ## useSyncExternalStore support
+ *
+ * This store directly integrates with the `useSyncExternalStore` API in UI frameworks like React and Preact.
+ * ```ts
+ * const [zazzlePDP] = useState(() => createZazzlePDPStore({ language: 'en', region: 'us' }));
+ * const pdpState = useSyncExternalStore(zazzlePDP.subscribe, zazzlePDP.getSnapshot);
+ * ```
+ */
+export declare function createZazzlePDPStore(options: {
+ /**
+ * ISO 639-1 language code
+ * @example "en"
+ *
+ * If not provided, we use the default language for the given `region`.
+ */
+ language?: string;
+ /**
+ * ISO 3166-1 country code
+ * @example "us"
+ */
+ region: string;
+}): {
+ /** Constants */
+ env: {
+ /**
+ * ISO 4217 currency code
+ * @example "USD"
+ */
+ currency: ZUIBase.ZCurrency;
+ /**
+ * ISO 639-1 language code
+ * @example "en"
+ *
+ * If not provided, we use the default language for the given `region`.
+ */
+ language: "en" | "de" | "es" | "fr" | "ja" | "ko" | "nl" | "pt" | "sv";
+ /**
+ * ISO 3166-1 country code
+ * @example "us"
+ */
+ region: "at" | "br" | "us" | "au" | "ca" | "gb" | "nz" | "de" | "ch" | "es" | "fr" | "be" | "jp" | "kr" | "nl" | "pt" | "se";
+ };
+ /**
+ * Subscribes to changes in the data
+ * @param callback Function that will be called when the data changes
+ * @returns A function to unsubscribe the callback
+ */
+ subscribe: (callback: () => void) => () => void;
+ /**
+ * Gets the current state (you likely want to call this inside a subscription callback)
+ * @see subscribe
+ */
+ getSnapshot: () => Readonly;
+ /**
+ * Fetches product (and accompanying) data for the given `templateId`.
+ * This should be called once during page init, and then likely never again.
+ */
+ fetchProduct(templateId: string): Promise;
+ /**
+ * Fetches size chart data for the current product state.
+ * (This data is not stored in the state, since it's only needed on user action, and will be stale with any option change.)
+ * @see AttributeHelpLink
+ */
+ fetchSizeChart(): Promise;
+ /**
+ * Optimistically updates the selected option, then syncs with the API.
+ */
+ selectOption(attributeName: string, value: string): Promise;
+ /**
+ * Optimistically updates the quantity, then syncs with the API.
+ */
+ selectQuantity(quantity: number): Promise;
+ /**
+ * Optimistically updates the selected realview, then syncs with the API.
+ */
+ selectRealview(realviewId: string): Promise;
+};
+export default createZazzlePDPStore;
diff --git a/express/code/blocks/print-product-detail-sdk/sdk/index.min.js b/express/code/blocks/print-product-detail-sdk/sdk/index.min.js
new file mode 100644
index 000000000..8cf4e4490
--- /dev/null
+++ b/express/code/blocks/print-product-detail-sdk/sdk/index.min.js
@@ -0,0 +1,6 @@
+var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),s=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;li[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},c=(n,r,a)=>(a=n==null?{}:e(i(n)),s(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));function l(e){return Array.isArray(e)?e:Array.from(e)}function u(e){return Number.isSafeInteger(e)&&e>=0}function d(e){return e!=null&&typeof e!=`function`&&u(e.length)}function f(e,t=1){let n=[],r=Math.floor(t),i=(e,t)=>{for(let a=0;a0?E(e,{...t},n,r):w(e,t);default:return S(e)?typeof t==`string`?t===``:!0:w(e,t)}}function D(e,t,n,r){if(t==null)return!0;if(Array.isArray(t))return k(e,t,n,r);if(t instanceof Map)return O(e,t,n,r);if(t instanceof Set)return A(e,t,n,r);let i=Object.keys(t);if(e==null)return i.length===0;if(i.length===0)return!0;if(r&&r.has(t))return r.get(t)===e;r&&r.set(t,e);try{for(let a=0;avoid 0)}function M(e){return Object.getOwnPropertySymbols(e).filter(t=>Object.prototype.propertyIsEnumerable.call(e,t))}function N(e){return e==null?e===void 0?`[object Undefined]`:`[object Null]`:Object.prototype.toString.call(e)}var P=`[object RegExp]`,F=`[object String]`,I=`[object Number]`,L=`[object Boolean]`,R=`[object Arguments]`,z=`[object Symbol]`,B=`[object Date]`,V=`[object Map]`,H=`[object Set]`,U=`[object Array]`,ee=`[object ArrayBuffer]`,te=`[object Object]`,ne=`[object DataView]`,re=`[object Uint8Array]`,ie=`[object Uint8ClampedArray]`,ae=`[object Uint16Array]`,oe=`[object Uint32Array]`,se=`[object Int8Array]`,W=`[object Int16Array]`,G=`[object Int32Array]`,ce=`[object Float32Array]`,le=`[object Float64Array]`;function ue(e){return ArrayBuffer.isView(e)&&!(e instanceof DataView)}function de(e,t){return K(e,void 0,e,new Map,t)}function K(e,t,n,r=new Map,i=void 0){let a=i?.(e,t,n,r);if(a!==void 0)return a;if(C(e))return e;if(r.has(e))return r.get(e);if(Array.isArray(e)){let t=Array(e.length);r.set(e,t);for(let a=0;aj(t,e)}function he(e,t){return de(e,(n,r,i,a)=>{let o=t?.(n,r,i,a);if(o!==void 0)return o;if(typeof e==`object`)switch(Object.prototype.toString.call(e)){case I:case F:case L:{let t=new e.constructor(e?.valueOf());return q(t,e),t}case R:{let t={};return q(t,e),t.length=e.length,t[Symbol.iterator]=e[Symbol.iterator],t}default:return}})}function J(e){return he(e)}var ge=/^(?:0|[1-9]\d*)$/;function _e(e,t=2**53-1){switch(typeof e){case`number`:return Number.isInteger(e)&&e>=0&&e!t(e,n,r));return n===-1?[]:e.slice(n)}function De(e,t=p){return d(e)?Oe(l(e),t):[]}function Oe(e,t){switch(typeof t){case`function`:return X(e,(e,n,r)=>!!t(e,n,r));case`object`:if(Array.isArray(t)&&t.length===2){let n=t[0],r=t[1];return X(e,be(n,r))}else return X(e,me(t));case`number`:case`symbol`:case`string`:return X(e,x(t))}}function ke(e,t,n=1){if(t??(t=e,e=0),!Number.isInteger(n)||n===0)throw Error(`The step value must be a non-zero integer.`);let r=Math.max(Math.ceil((t-e)/n),0),i=Array(r);for(let t=0;t{for(let a=0;an.has(e))}function Re(e){return[...new Set(e)]}function ze(...e){if(e.length===0||!Se(e[0]))return[];let t=Re(Array.from(e[0]));for(let n=1;n{if(e!==t){let r=Ve(e),i=Ve(t);if(r===i&&r===0){if(et)return n===`desc`?-1:1}return n===`desc`?i-r:r-i}return 0},Ue=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,We=/^\w*$/;function Ge(e,t){return Array.isArray(e)?!1:typeof e==`number`||typeof e==`boolean`||e==null||Ce(e)?!0:typeof e==`string`&&(We.test(e)||!Ue.test(e))||t!=null&&Object.hasOwn(t,e)}function Ke(e,t,n,r){if(e==null)return[];n=r?void 0:n,Array.isArray(e)||(e=Object.values(e)),Array.isArray(t)||(t=t==null?[null]:[t]),t.length===0&&(t=[null]),Array.isArray(n)||(n=n==null?[]:[n]),n=n.map(e=>String(e));let i=(e,t)=>{let n=e;for(let e=0;et==null||e==null?t:typeof e==`object`&&`key`in e?Object.hasOwn(t,e.key)?t[e.key]:i(t,e.path):typeof e==`function`?e(t):Array.isArray(e)?i(t,e):typeof t==`object`?t[e]:t,o=t.map(e=>(Array.isArray(e)&&e.length===1&&(e=e[0]),e==null||typeof e==`function`||Array.isArray(e)||Ge(e)?e:{key:e,path:v(e)}));return e.map(e=>({original:e,criteria:o.map(t=>a(t,e))})).slice().sort((e,t)=>{for(let r=0;re.original)}function qe(e,t){if(e==null)return!0;switch(typeof t){case`symbol`:case`number`:case`object`:if(Array.isArray(t))return Je(e,t);if(typeof t==`number`?t=g(t):typeof t==`object`&&(t=Object.is(t?.valueOf(),-0)?`-0`:String(t)),m(t))return!1;if(e?.[t]===void 0)return!0;try{return delete e[t],!0}catch{return!1}case`string`:if(e?.[t]===void 0&&h(t))return Je(e,v(t));if(m(t))return!1;try{return delete e[t],!0}catch{return!1}}}function Je(e,t){let n=t.length===1?e:y(e,t.slice(0,-1)),r=t[t.length-1];if(n?.[r]===void 0)return!0;if(m(r))return!1;try{return delete n[r],!0}catch{return!1}}function Ye(e,t,n){return n==null?Math.min(e,t):Math.min(Math.max(e,t),n)}function Xe(e,t,n){return Number.isNaN(t)&&(t=0),Number.isNaN(n)&&(n=0),Ye(e,t,n)}function Ze(e){return e==null}function Qe(e,...t){let n=t.length;return n>1&&je(e,t[0],t[1])?t=[]:n>2&&je(t[0],t[1],t[2])&&(t=[t[0]]),Ke(e,f(t),[`asc`])}function $e(e){return e}var et=(e,t,n)=>{let r=e[t];(!(Object.hasOwn(e,t)&&w(r,n))||n===void 0&&!(t in e))&&(e[t]=n)};function tt(e,t,n,r){if(e==null&&!S(e))return e;let i=Ge(t,e)?[t]:Array.isArray(t)?t:typeof t==`string`?v(t):[t],a=e;for(let t=0;tn,()=>void 0)}function rt(){}function it(e){return typeof Buffer<`u`&&Buffer.isBuffer(e)}function at(e){let t=e?.constructor;return e===(typeof t==`function`?t.prototype:Object.prototype)}function ot(e){return ue(e)}function st(e,t){if(e=Ee(e),e<1||!Number.isSafeInteger(e))return[];let n=Array(e);for(let r=0;re!==`constructor`):t}function lt(e){let t=st(e.length,e=>`${e}`),n=new Set(t);return it(e)&&(n.add(`offset`),n.add(`parent`)),ot(e)&&(n.add(`buffer`),n.add(`byteLength`),n.add(`byteOffset`)),[...t,...Object.keys(e).filter(e=>!n.has(e))]}function ut(e){if(e==null)return[];switch(typeof e){case`object`:case`function`:return d(e)?pt(e):at(e)?ft(e):dt(e);default:return dt(Object(e))}}function dt(e){let t=[];for(let n in e)t.push(n);return t}function ft(e){return dt(e).filter(e=>e!==`constructor`)}function pt(e){let t=st(e.length,e=>`${e}`),n=new Set(t);return it(e)&&(n.add(`offset`),n.add(`parent`)),ot(e)&&(n.add(`buffer`),n.add(`byteLength`),n.add(`byteOffset`)),[...t,...dt(e).filter(e=>!n.has(e))]}function mt(e){if(typeof e!=`object`||!e)return!1;if(Object.getPrototypeOf(e)===null)return!0;if(Object.prototype.toString.call(e)!==`[object Object]`){let t=e[Symbol.toStringTag];return t==null||!Object.getOwnPropertyDescriptor(e,Symbol.toStringTag)?.writable?!1:e.toString()===`[object ${t}]`}let t=e;for(;Object.getPrototypeOf(t)!==null;)t=Object.getPrototypeOf(t);return Object.getPrototypeOf(e)===t}function ht(e,...t){e=Object(e);for(let n=0;nArray.isArray(e)||h(e))?jt(e):At(e)}function At(e){let t={},n=[...ut(e),...Dt(e)];for(let r=0;r{if(!mt(e))return e})}return t}function Mt(e,...t){if(Ze(e))return{};let n={};for(let r=0;r`u`||!Buffer.isBuffer(e))&&!ot(e)&&!ve(e)?!1:e.length===0;if(typeof e==`object`){if(e instanceof Map||e instanceof Set)return e.size===0;let t=Object.keys(e);return at(e)?t.filter(e=>e!==`constructor`).length===0:t.length===0}return!0}function Ft(e){return N(e)===`[object Error]`}function It(e,t,n){return _(e).split(t,n)}var Lt=.1,Rt=1,zt=99999,Bt=1;function Vt(e,t,n,r){t??=Rt,n??=zt,r??=Bt;let i=Xe(e,t,n);return Math.round(Math.ceil(i/r)*r)}function Ht(e,t,n){let r=[];if(e=De(e,e=>!e.hasDiscount),e.length>0){if(n)r=Ut(e,t);else{let n;for(let i=0,a=0;i1){let e,t;for(let n=0;n({quantity:e}))}function Ut(e,t){let n=[];for(let r=0,i=0;ro.maxQuantity?i++:(n.push({quantity:a,discount:o}),r++)}return n}var Wt=o(((e,t)=>{(function(n){var r=typeof e==`object`&&e&&!e.nodeType&&e,i=typeof t==`object`&&t&&!t.nodeType&&t,a=typeof global==`object`&&global;(a.global===a||a.window===a||a.self===a)&&(n=a);var o,s=2147483647,c=36,l=1,u=26,d=38,f=700,p=72,m=128,h=`-`,g=/^xn--/,_=/[^\x20-\x7E]/,v=/[\x2E\u3002\uFF0E\uFF61]/g,y={overflow:`Overflow: input needs wider integers to process`,"not-basic":`Illegal input >= 0x80 (not a basic code point)`,"invalid-input":`Invalid input`},b=c-l,x=Math.floor,S=String.fromCharCode,C;function w(e){throw RangeError(y[e])}function T(e,t){for(var n=e.length,r=[];n--;)r[n]=t(e[n]);return r}function E(e,t){var n=e.split(`@`),r=``;n.length>1&&(r=n[0]+`@`,e=n[1]),e=e.replace(v,`.`);var i=T(e.split(`.`),t).join(`.`);return r+i}function D(e){for(var t=[],n=0,r=e.length,i,a;n=55296&&i<=56319&&n65535&&(e-=65536,t+=S(e>>>10&1023|55296),e=56320|e&1023),t+=S(e),t}).join(``)}function k(e){return e-48<10?e-22:e-65<26?e-65:e-97<26?e-97:c}function A(e,t){return e+22+75*(e<26)-((t!=0)<<5)}function j(e,t,n){var r=0;for(e=n?x(e/f):e>>1,e+=x(e/t);e>b*u>>1;r+=c)e=x(e/b);return x(r+(b+1)*e/(e+d))}function M(e){var t=[],n=e.length,r,i=0,a=m,o=p,d=e.lastIndexOf(h),f,g,_,v,y,b,S,C;for(d<0&&(d=0),f=0;f=128&&w(`not-basic`),t.push(e.charCodeAt(f));for(g=d>0?d+1:0;g=n&&w(`invalid-input`),b=k(e.charCodeAt(g++)),(b>=c||b>x((s-i)/v))&&w(`overflow`),i+=b*v,S=y<=o?l:y>=o+u?u:y-o,!(bx(s/C)&&w(`overflow`),v*=C;r=t.length+1,o=j(i-_,r,_==0),x(i/r)>s-a&&w(`overflow`),a+=x(i/r),i%=r,t.splice(i++,0,a)}return O(t)}function N(e){var t,n,r,i,a,o,d,f,g,_,v,y=[],b,C,T,E;for(e=D(e),b=e.length,t=m,n=0,a=p,o=0;o=t&&vx((s-n)/C)&&w(`overflow`),n+=(d-t)*C,t=d,o=0;os&&w(`overflow`),v==t){for(f=n,g=c;_=g<=a?l:g>=a+u?u:g-a,!(f<_);g+=c)E=f-_,T=c-_,y.push(S(A(_+E%T,0))),f=x(E/T);y.push(S(A(f,0))),a=j(n,C,r==i),n=0,++r}++n,++t}return y.join(``)}function P(e){return E(e,function(e){return g.test(e)?M(e.slice(4).toLowerCase()):e})}function F(e){return E(e,function(e){return _.test(e)?`xn--`+N(e):e})}if(o={version:`1.4.1`,ucs2:{decode:D,encode:O},decode:M,encode:N,toASCII:F,toUnicode:P},typeof define==`function`&&typeof define.amd==`object`&&define.amd)define(`punycode`,function(){return o});else if(r&&i)if(t.exports==r)i.exports=o;else for(C in o)o.hasOwnProperty(C)&&(r[C]=o[C]);else n.punycode=o})(e)})),Gt=o(((e,t)=>{t.exports=TypeError})),Kt=o(((e,t)=>{t.exports={}})),qt=o(((e,t)=>{var n=typeof Map==`function`&&Map.prototype,r=Object.getOwnPropertyDescriptor&&n?Object.getOwnPropertyDescriptor(Map.prototype,`size`):null,i=n&&r&&typeof r.get==`function`?r.get:null,a=n&&Map.prototype.forEach,o=typeof Set==`function`&&Set.prototype,s=Object.getOwnPropertyDescriptor&&o?Object.getOwnPropertyDescriptor(Set.prototype,`size`):null,c=o&&s&&typeof s.get==`function`?s.get:null,l=o&&Set.prototype.forEach,u=typeof WeakMap==`function`&&WeakMap.prototype?WeakMap.prototype.has:null,d=typeof WeakSet==`function`&&WeakSet.prototype?WeakSet.prototype.has:null,f=typeof WeakRef==`function`&&WeakRef.prototype?WeakRef.prototype.deref:null,p=Boolean.prototype.valueOf,m=Object.prototype.toString,h=Function.prototype.toString,g=String.prototype.match,_=String.prototype.slice,v=String.prototype.replace,y=String.prototype.toUpperCase,b=String.prototype.toLowerCase,x=RegExp.prototype.test,S=Array.prototype.concat,C=Array.prototype.join,w=Array.prototype.slice,T=Math.floor,E=typeof BigInt==`function`?BigInt.prototype.valueOf:null,D=Object.getOwnPropertySymbols,O=typeof Symbol==`function`&&typeof Symbol.iterator==`symbol`?Symbol.prototype.toString:null,k=typeof Symbol==`function`&&typeof Symbol.iterator==`object`,A=typeof Symbol==`function`&&Symbol.toStringTag&&(typeof Symbol.toStringTag===k||`symbol`)?Symbol.toStringTag:null,j=Object.prototype.propertyIsEnumerable,M=(typeof Reflect==`function`?Reflect.getPrototypeOf:Object.getPrototypeOf)||([].__proto__===Array.prototype?function(e){return e.__proto__}:null);function N(e,t){if(e===1/0||e===-1/0||e!==e||e&&e>-1e3&&e<1e3||x.call(/e/,t))return t;var n=/[0-9](?=(?:[0-9]{3})+(?![0-9]))/g;if(typeof e==`number`){var r=e<0?-T(-e):T(e);if(r!==e){var i=String(r),a=_.call(t,i.length+1);return v.call(i,n,`$&_`)+`.`+v.call(v.call(a,/([0-9]{3})/g,`$&_`),/_$/,``)}}return v.call(t,n,`$&_`)}var P=Kt(),F=P.custom,I=ae(F)?F:null,L={__proto__:null,double:`"`,single:`'`},R={__proto__:null,double:/(["\\])/g,single:/(['\\])/g};t.exports=function e(t,n,r,o){var s=n||{};if(W(s,`quoteStyle`)&&!W(L,s.quoteStyle))throw TypeError(`option "quoteStyle" must be "single" or "double"`);if(W(s,`maxStringLength`)&&(typeof s.maxStringLength==`number`?s.maxStringLength<0&&s.maxStringLength!==1/0:s.maxStringLength!==null))throw TypeError('option "maxStringLength", if provided, must be a positive integer, Infinity, or `null`');var u=W(s,`customInspect`)?s.customInspect:!0;if(typeof u!=`boolean`&&u!==`symbol`)throw TypeError("option \"customInspect\", if provided, must be `true`, `false`, or `'symbol'`");if(W(s,`indent`)&&s.indent!==null&&s.indent!==` `&&!(parseInt(s.indent,10)===s.indent&&s.indent>0))throw TypeError('option "indent" must be "\\t", an integer > 0, or `null`');if(W(s,`numericSeparator`)&&typeof s.numericSeparator!=`boolean`)throw TypeError('option "numericSeparator", if provided, must be `true` or `false`');var d=s.numericSeparator;if(t===void 0)return`undefined`;if(t===null)return`null`;if(typeof t==`boolean`)return t?`true`:`false`;if(typeof t==`string`)return me(t,s);if(typeof t==`number`){if(t===0)return 1/0/t>0?`0`:`-0`;var f=String(t);return d?N(t,f):f}if(typeof t==`bigint`){var m=String(t)+`n`;return d?N(t,m):m}var h=s.depth===void 0?5:s.depth;if(r===void 0&&(r=0),r>=h&&h>0&&typeof t==`object`)return H(t)?`[Array]`:`[Object]`;var g=ye(s,r);if(o===void 0)o=[];else if(le(o,t)>=0)return`[Circular]`;function y(t,n,i){if(n&&(o=w.call(o),o.push(n)),i){var a={depth:s.depth};return W(s,`quoteStyle`)&&(a.quoteStyle=s.quoteStyle),e(t,a,r+1,o)}return e(t,s,r+1,o)}if(typeof t==`function`&&!ee(t)){var x=ce(t),T=Y(t,y);return`[Function`+(x?`: `+x:` (anonymous)`)+`]`+(T.length>0?` { `+C.call(T,`, `)+` }`:``)}if(ae(t)){var D=k?v.call(String(t),/^(Symbol\(.*\))_[^)]*$/,`$1`):O.call(t);return typeof t==`object`&&!k?J(D):D}if(pe(t)){for(var F=`<`+b.call(String(t.nodeName)),R=t.attributes||[],V=0;V`,t.childNodes&&t.childNodes.length&&(F+=`...`),F+=``+b.call(String(t.nodeName))+`>`,F}if(H(t)){if(t.length===0)return`[]`;var se=Y(t,y);return g&&!ve(se)?`[`+be(se,g)+`]`:`[ `+C.call(se,`, `)+` ]`}if(te(t)){var he=Y(t,y);return!(`cause`in Error.prototype)&&`cause`in t&&!j.call(t,`cause`)?`{ [`+String(t)+`] `+C.call(S.call(`[cause]: `+y(t.cause),he),`, `)+` }`:he.length===0?`[`+String(t)+`]`:`{ [`+String(t)+`] `+C.call(he,`, `)+` }`}if(typeof t==`object`&&u){if(I&&typeof t[I]==`function`&&P)return P(t,{depth:h-r});if(u!==`symbol`&&typeof t.inspect==`function`)return t.inspect()}if(ue(t)){var xe=[];return a&&a.call(t,function(e,n){xe.push(y(n,t,!0)+` => `+y(e,t))}),_e(`Map`,i.call(t),xe,g)}if(q(t)){var Se=[];return l&&l.call(t,function(e){Se.push(y(e,t))}),_e(`Set`,c.call(t),Se,g)}if(de(t))return ge(`WeakMap`);if(fe(t))return ge(`WeakSet`);if(K(t))return ge(`WeakRef`);if(re(t))return J(y(Number(t)));if(oe(t))return J(y(E.call(t)));if(ie(t))return J(p.call(t));if(ne(t))return J(y(String(t)));if(typeof window<`u`&&t===window)return`{ [object Window] }`;if(typeof globalThis<`u`&&t===globalThis||typeof global<`u`&&t===global)return`{ [object globalThis] }`;if(!U(t)&&!ee(t)){var Ce=Y(t,y),we=M?M(t)===Object.prototype:t instanceof Object||t.constructor===Object,Te=t instanceof Object?``:`null prototype`,Ee=!we&&A&&Object(t)===t&&A in t?_.call(G(t),8,-1):Te?`Object`:``,X=(we||typeof t.constructor!=`function`?``:t.constructor.name?t.constructor.name+` `:``)+(Ee||Te?`[`+C.call(S.call([],Ee||[],Te||[]),`: `)+`] `:``);return Ce.length===0?X+`{}`:g?X+`{`+be(Ce,g)+`}`:X+`{ `+C.call(Ce,`, `)+` }`}return String(t)};function z(e,t,n){var r=L[n.quoteStyle||t];return r+e+r}function B(e){return v.call(String(e),/"/g,`"`)}function V(e){return!A||!(typeof e==`object`&&(A in e||e[A]!==void 0))}function H(e){return G(e)===`[object Array]`&&V(e)}function U(e){return G(e)===`[object Date]`&&V(e)}function ee(e){return G(e)===`[object RegExp]`&&V(e)}function te(e){return G(e)===`[object Error]`&&V(e)}function ne(e){return G(e)===`[object String]`&&V(e)}function re(e){return G(e)===`[object Number]`&&V(e)}function ie(e){return G(e)===`[object Boolean]`&&V(e)}function ae(e){if(k)return e&&typeof e==`object`&&e instanceof Symbol;if(typeof e==`symbol`)return!0;if(!e||typeof e!=`object`||!O)return!1;try{return O.call(e),!0}catch{}return!1}function oe(e){if(!e||typeof e!=`object`||!E)return!1;try{return E.call(e),!0}catch{}return!1}var se=Object.prototype.hasOwnProperty||function(e){return e in this};function W(e,t){return se.call(e,t)}function G(e){return m.call(e)}function ce(e){if(e.name)return e.name;var t=g.call(h.call(e),/^function\s*([\w$]+)/);return t?t[1]:null}function le(e,t){if(e.indexOf)return e.indexOf(t);for(var n=0,r=e.length;nt.maxStringLength){var n=e.length-t.maxStringLength,r=`... `+n+` more character`+(n>1?`s`:``);return me(_.call(e,0,t.maxStringLength),t)+r}var i=R[t.quoteStyle||`single`];return i.lastIndex=0,z(v.call(v.call(e,i,`\\$1`),/[\x00-\x1f]/g,he),`single`,t)}function he(e){var t=e.charCodeAt(0),n={8:`b`,9:`t`,10:`n`,12:`f`,13:`r`}[t];return n?`\\`+n:`\\x`+(t<16?`0`:``)+y.call(t.toString(16))}function J(e){return`Object(`+e+`)`}function ge(e){return e+` { ? }`}function _e(e,t,n,r){var i=r?be(n,r):C.call(n,`, `);return e+` (`+t+`) {`+i+`}`}function ve(e){for(var t=0;t=0)return!1;return!0}function ye(e,t){var n;if(e.indent===` `)n=` `;else if(typeof e.indent==`number`&&e.indent>0)n=C.call(Array(e.indent+1),` `);else return null;return{base:n,prev:C.call(Array(t+1),n)}}function be(e,t){if(e.length===0)return``;var n=`
+`+t.prev+t.base;return n+C.call(e,`,`+n)+`
+`+t.prev}function Y(e,t){var n=H(e),r=[];if(n){r.length=e.length;for(var i=0;i{var n=qt(),r=Gt(),i=function(e,t,n){for(var r=e,i;(i=r.next)!=null;r=i)if(i.key===t)return r.next=i.next,n||(i.next=e.next,e.next=i),i},a=function(e,t){if(e){var n=i(e,t);return n&&n.value}},o=function(e,t,n){var r=i(e,t);r?r.value=n:e.next={key:t,next:e.next,value:n}},s=function(e,t){return e?!!i(e,t):!1},c=function(e,t){if(e)return i(e,t,!0)};t.exports=function(){var e,t={assert:function(e){if(!t.has(e))throw new r(`Side channel does not contain `+n(e))},delete:function(t){var n=e&&e.next,r=c(e,t);return r&&n&&n===r&&(e=void 0),!!r},get:function(t){return a(e,t)},has:function(t){return s(e,t)},set:function(t,n){e||={next:void 0},o(e,t,n)}};return t}})),Yt=o(((e,t)=>{t.exports=Object})),Xt=o(((e,t)=>{t.exports=Error})),Zt=o(((e,t)=>{t.exports=EvalError})),Qt=o(((e,t)=>{t.exports=RangeError})),$t=o(((e,t)=>{t.exports=ReferenceError})),en=o(((e,t)=>{t.exports=SyntaxError})),tn=o(((e,t)=>{t.exports=URIError})),nn=o(((e,t)=>{t.exports=Math.abs})),rn=o(((e,t)=>{t.exports=Math.floor})),an=o(((e,t)=>{t.exports=Math.max})),on=o(((e,t)=>{t.exports=Math.min})),sn=o(((e,t)=>{t.exports=Math.pow})),cn=o(((e,t)=>{t.exports=Math.round})),ln=o(((e,t)=>{t.exports=Number.isNaN||function(e){return e!==e}})),un=o(((e,t)=>{var n=ln();t.exports=function(e){return n(e)||e===0?e:e<0?-1:1}})),dn=o(((e,t)=>{t.exports=Object.getOwnPropertyDescriptor})),fn=o(((e,t)=>{var n=dn();if(n)try{n([],`length`)}catch{n=null}t.exports=n})),pn=o(((e,t)=>{var n=Object.defineProperty||!1;if(n)try{n({},`a`,{value:1})}catch{n=!1}t.exports=n})),mn=o(((e,t)=>{t.exports=function(){if(typeof Symbol!=`function`||typeof Object.getOwnPropertySymbols!=`function`)return!1;if(typeof Symbol.iterator==`symbol`)return!0;var e={},t=Symbol(`test`),n=Object(t);if(typeof t==`string`||Object.prototype.toString.call(t)!==`[object Symbol]`||Object.prototype.toString.call(n)!==`[object Symbol]`)return!1;var r=42;for(var i in e[t]=r,e)return!1;if(typeof Object.keys==`function`&&Object.keys(e).length!==0||typeof Object.getOwnPropertyNames==`function`&&Object.getOwnPropertyNames(e).length!==0)return!1;var a=Object.getOwnPropertySymbols(e);if(a.length!==1||a[0]!==t||!Object.prototype.propertyIsEnumerable.call(e,t))return!1;if(typeof Object.getOwnPropertyDescriptor==`function`){var o=Object.getOwnPropertyDescriptor(e,t);if(o.value!==r||o.enumerable!==!0)return!1}return!0}})),hn=o(((e,t)=>{var n=typeof Symbol<`u`&&Symbol,r=mn();t.exports=function(){return typeof n!=`function`||typeof Symbol!=`function`||typeof n(`foo`)!=`symbol`||typeof Symbol(`bar`)!=`symbol`?!1:r()}})),gn=o(((e,t)=>{t.exports=typeof Reflect<`u`&&Reflect.getPrototypeOf||null})),_n=o(((e,t)=>{t.exports=Yt().getPrototypeOf||null})),vn=o(((e,t)=>{var n=`Function.prototype.bind called on incompatible `,r=Object.prototype.toString,i=Math.max,a=`[object Function]`,o=function(e,t){for(var n=[],r=0;r{var n=vn();t.exports=Function.prototype.bind||n})),bn=o(((e,t)=>{t.exports=Function.prototype.call})),xn=o(((e,t)=>{t.exports=Function.prototype.apply})),Sn=o(((e,t)=>{t.exports=typeof Reflect<`u`&&Reflect&&Reflect.apply})),Cn=o(((e,t)=>{var n=yn(),r=xn(),i=bn();t.exports=Sn()||n.call(i,r)})),wn=o(((e,t)=>{var n=yn(),r=Gt(),i=bn(),a=Cn();t.exports=function(e){if(e.length<1||typeof e[0]!=`function`)throw new r(`a function is required`);return a(n,i,e)}})),Tn=o(((e,t)=>{var n=wn(),r=fn(),i;try{i=[].__proto__===Array.prototype}catch(e){if(!e||typeof e!=`object`||!(`code`in e)||e.code!==`ERR_PROTO_ACCESS`)throw e}var a=!!i&&r&&r(Object.prototype,`__proto__`),o=Object,s=o.getPrototypeOf;t.exports=a&&typeof a.get==`function`?n([a.get]):typeof s==`function`?function(e){return s(e==null?e:o(e))}:!1})),En=o(((e,t)=>{var n=gn(),r=_n(),i=Tn();t.exports=n?function(e){return n(e)}:r?function(e){if(!e||typeof e!=`object`&&typeof e!=`function`)throw TypeError(`getProto: not an object`);return r(e)}:i?function(e){return i(e)}:null})),Dn=o(((e,t)=>{var n=Function.prototype.call,r=Object.prototype.hasOwnProperty;t.exports=yn().call(n,r)})),On=o(((e,t)=>{var n,r=Yt(),i=Xt(),a=Zt(),o=Qt(),s=$t(),c=en(),l=Gt(),u=tn(),d=nn(),f=rn(),p=an(),m=on(),h=sn(),g=cn(),_=un(),v=Function,y=function(e){try{return v(`"use strict"; return (`+e+`).constructor;`)()}catch{}},b=fn(),x=pn(),S=function(){throw new l},C=b?function(){try{return arguments.callee,S}catch{try{return b(arguments,`callee`).get}catch{return S}}}():S,w=hn()(),T=En(),E=_n(),D=gn(),O=xn(),k=bn(),A={},j=typeof Uint8Array>`u`||!T?n:T(Uint8Array),M={__proto__:null,"%AggregateError%":typeof AggregateError>`u`?n:AggregateError,"%Array%":Array,"%ArrayBuffer%":typeof ArrayBuffer>`u`?n:ArrayBuffer,"%ArrayIteratorPrototype%":w&&T?T([][Symbol.iterator]()):n,"%AsyncFromSyncIteratorPrototype%":n,"%AsyncFunction%":A,"%AsyncGenerator%":A,"%AsyncGeneratorFunction%":A,"%AsyncIteratorPrototype%":A,"%Atomics%":typeof Atomics>`u`?n:Atomics,"%BigInt%":typeof BigInt>`u`?n:BigInt,"%BigInt64Array%":typeof BigInt64Array>`u`?n:BigInt64Array,"%BigUint64Array%":typeof BigUint64Array>`u`?n:BigUint64Array,"%Boolean%":Boolean,"%DataView%":typeof DataView>`u`?n:DataView,"%Date%":Date,"%decodeURI%":decodeURI,"%decodeURIComponent%":decodeURIComponent,"%encodeURI%":encodeURI,"%encodeURIComponent%":encodeURIComponent,"%Error%":i,"%eval%":eval,"%EvalError%":a,"%Float16Array%":typeof Float16Array>`u`?n:Float16Array,"%Float32Array%":typeof Float32Array>`u`?n:Float32Array,"%Float64Array%":typeof Float64Array>`u`?n:Float64Array,"%FinalizationRegistry%":typeof FinalizationRegistry>`u`?n:FinalizationRegistry,"%Function%":v,"%GeneratorFunction%":A,"%Int8Array%":typeof Int8Array>`u`?n:Int8Array,"%Int16Array%":typeof Int16Array>`u`?n:Int16Array,"%Int32Array%":typeof Int32Array>`u`?n:Int32Array,"%isFinite%":isFinite,"%isNaN%":isNaN,"%IteratorPrototype%":w&&T?T(T([][Symbol.iterator]())):n,"%JSON%":typeof JSON==`object`?JSON:n,"%Map%":typeof Map>`u`?n:Map,"%MapIteratorPrototype%":typeof Map>`u`||!w||!T?n:T(new Map()[Symbol.iterator]()),"%Math%":Math,"%Number%":Number,"%Object%":r,"%Object.getOwnPropertyDescriptor%":b,"%parseFloat%":parseFloat,"%parseInt%":parseInt,"%Promise%":typeof Promise>`u`?n:Promise,"%Proxy%":typeof Proxy>`u`?n:Proxy,"%RangeError%":o,"%ReferenceError%":s,"%Reflect%":typeof Reflect>`u`?n:Reflect,"%RegExp%":RegExp,"%Set%":typeof Set>`u`?n:Set,"%SetIteratorPrototype%":typeof Set>`u`||!w||!T?n:T(new Set()[Symbol.iterator]()),"%SharedArrayBuffer%":typeof SharedArrayBuffer>`u`?n:SharedArrayBuffer,"%String%":String,"%StringIteratorPrototype%":w&&T?T(``[Symbol.iterator]()):n,"%Symbol%":w?Symbol:n,"%SyntaxError%":c,"%ThrowTypeError%":C,"%TypedArray%":j,"%TypeError%":l,"%Uint8Array%":typeof Uint8Array>`u`?n:Uint8Array,"%Uint8ClampedArray%":typeof Uint8ClampedArray>`u`?n:Uint8ClampedArray,"%Uint16Array%":typeof Uint16Array>`u`?n:Uint16Array,"%Uint32Array%":typeof Uint32Array>`u`?n:Uint32Array,"%URIError%":u,"%WeakMap%":typeof WeakMap>`u`?n:WeakMap,"%WeakRef%":typeof WeakRef>`u`?n:WeakRef,"%WeakSet%":typeof WeakSet>`u`?n:WeakSet,"%Function.prototype.call%":k,"%Function.prototype.apply%":O,"%Object.defineProperty%":x,"%Object.getPrototypeOf%":E,"%Math.abs%":d,"%Math.floor%":f,"%Math.max%":p,"%Math.min%":m,"%Math.pow%":h,"%Math.round%":g,"%Math.sign%":_,"%Reflect.getPrototypeOf%":D};if(T)try{null.error}catch(e){M[`%Error.prototype%`]=T(T(e))}var N=function e(t){var n;if(t===`%AsyncFunction%`)n=y(`async function () {}`);else if(t===`%GeneratorFunction%`)n=y(`function* () {}`);else if(t===`%AsyncGeneratorFunction%`)n=y(`async function* () {}`);else if(t===`%AsyncGenerator%`){var r=e(`%AsyncGeneratorFunction%`);r&&(n=r.prototype)}else if(t===`%AsyncIteratorPrototype%`){var i=e(`%AsyncGenerator%`);i&&T&&(n=T(i.prototype))}return M[t]=n,n},P={__proto__:null,"%ArrayBufferPrototype%":[`ArrayBuffer`,`prototype`],"%ArrayPrototype%":[`Array`,`prototype`],"%ArrayProto_entries%":[`Array`,`prototype`,`entries`],"%ArrayProto_forEach%":[`Array`,`prototype`,`forEach`],"%ArrayProto_keys%":[`Array`,`prototype`,`keys`],"%ArrayProto_values%":[`Array`,`prototype`,`values`],"%AsyncFunctionPrototype%":[`AsyncFunction`,`prototype`],"%AsyncGenerator%":[`AsyncGeneratorFunction`,`prototype`],"%AsyncGeneratorPrototype%":[`AsyncGeneratorFunction`,`prototype`,`prototype`],"%BooleanPrototype%":[`Boolean`,`prototype`],"%DataViewPrototype%":[`DataView`,`prototype`],"%DatePrototype%":[`Date`,`prototype`],"%ErrorPrototype%":[`Error`,`prototype`],"%EvalErrorPrototype%":[`EvalError`,`prototype`],"%Float32ArrayPrototype%":[`Float32Array`,`prototype`],"%Float64ArrayPrototype%":[`Float64Array`,`prototype`],"%FunctionPrototype%":[`Function`,`prototype`],"%Generator%":[`GeneratorFunction`,`prototype`],"%GeneratorPrototype%":[`GeneratorFunction`,`prototype`,`prototype`],"%Int8ArrayPrototype%":[`Int8Array`,`prototype`],"%Int16ArrayPrototype%":[`Int16Array`,`prototype`],"%Int32ArrayPrototype%":[`Int32Array`,`prototype`],"%JSONParse%":[`JSON`,`parse`],"%JSONStringify%":[`JSON`,`stringify`],"%MapPrototype%":[`Map`,`prototype`],"%NumberPrototype%":[`Number`,`prototype`],"%ObjectPrototype%":[`Object`,`prototype`],"%ObjProto_toString%":[`Object`,`prototype`,`toString`],"%ObjProto_valueOf%":[`Object`,`prototype`,`valueOf`],"%PromisePrototype%":[`Promise`,`prototype`],"%PromiseProto_then%":[`Promise`,`prototype`,`then`],"%Promise_all%":[`Promise`,`all`],"%Promise_reject%":[`Promise`,`reject`],"%Promise_resolve%":[`Promise`,`resolve`],"%RangeErrorPrototype%":[`RangeError`,`prototype`],"%ReferenceErrorPrototype%":[`ReferenceError`,`prototype`],"%RegExpPrototype%":[`RegExp`,`prototype`],"%SetPrototype%":[`Set`,`prototype`],"%SharedArrayBufferPrototype%":[`SharedArrayBuffer`,`prototype`],"%StringPrototype%":[`String`,`prototype`],"%SymbolPrototype%":[`Symbol`,`prototype`],"%SyntaxErrorPrototype%":[`SyntaxError`,`prototype`],"%TypedArrayPrototype%":[`TypedArray`,`prototype`],"%TypeErrorPrototype%":[`TypeError`,`prototype`],"%Uint8ArrayPrototype%":[`Uint8Array`,`prototype`],"%Uint8ClampedArrayPrototype%":[`Uint8ClampedArray`,`prototype`],"%Uint16ArrayPrototype%":[`Uint16Array`,`prototype`],"%Uint32ArrayPrototype%":[`Uint32Array`,`prototype`],"%URIErrorPrototype%":[`URIError`,`prototype`],"%WeakMapPrototype%":[`WeakMap`,`prototype`],"%WeakSetPrototype%":[`WeakSet`,`prototype`]},F=yn(),I=Dn(),L=F.call(k,Array.prototype.concat),R=F.call(O,Array.prototype.splice),z=F.call(k,String.prototype.replace),B=F.call(k,String.prototype.slice),V=F.call(k,RegExp.prototype.exec),H=/[^%.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|%$))/g,U=/\\(\\)?/g,ee=function(e){var t=B(e,0,1),n=B(e,-1);if(t===`%`&&n!==`%`)throw new c("invalid intrinsic syntax, expected closing `%`");if(n===`%`&&t!==`%`)throw new c("invalid intrinsic syntax, expected opening `%`");var r=[];return z(e,H,function(e,t,n,i){r[r.length]=n?z(i,U,`$1`):t||e}),r},te=function(e,t){var n=e,r;if(I(P,n)&&(r=P[n],n=`%`+r[0]+`%`),I(M,n)){var i=M[n];if(i===A&&(i=N(n)),i===void 0&&!t)throw new l(`intrinsic `+e+` exists, but is not available. Please file an issue!`);return{alias:r,name:n,value:i}}throw new c(`intrinsic `+e+` does not exist!`)};t.exports=function(e,t){if(typeof e!=`string`||e.length===0)throw new l(`intrinsic name must be a non-empty string`);if(arguments.length>1&&typeof t!=`boolean`)throw new l(`"allowMissing" argument must be a boolean`);if(V(/^%?[^%]*%?$/,e)===null)throw new c("`%` may not be present anywhere but at the beginning and end of the intrinsic name");var n=ee(e),r=n.length>0?n[0]:``,i=te(`%`+r+`%`,t),a=i.name,o=i.value,s=!1,u=i.alias;u&&(r=u[0],R(n,L([0,1],u)));for(var d=1,f=!0;d=n.length){var g=b(o,p);f=!!g,o=f&&`get`in g&&!(`originalValue`in g.get)?g.get:o[p]}else f=I(o,p),o=o[p];f&&!s&&(M[a]=o)}}return o}})),kn=o(((e,t)=>{var n=On(),r=wn(),i=r([n(`%String.prototype.indexOf%`)]);t.exports=function(e,t){var a=n(e,!!t);return typeof a==`function`&&i(e,`.prototype.`)>-1?r([a]):a}})),An=o(((e,t)=>{var n=On(),r=kn(),i=qt(),a=Gt(),o=n(`%Map%`,!0),s=r(`Map.prototype.get`,!0),c=r(`Map.prototype.set`,!0),l=r(`Map.prototype.has`,!0),u=r(`Map.prototype.delete`,!0),d=r(`Map.prototype.size`,!0);t.exports=!!o&&function(){var e,t={assert:function(e){if(!t.has(e))throw new a(`Side channel does not contain `+i(e))},delete:function(t){if(e){var n=u(e,t);return d(e)===0&&(e=void 0),n}return!1},get:function(t){if(e)return s(e,t)},has:function(t){return e?l(e,t):!1},set:function(t,n){e||=new o,c(e,t,n)}};return t}})),jn=o(((e,t)=>{var n=On(),r=kn(),i=qt(),a=An(),o=Gt(),s=n(`%WeakMap%`,!0),c=r(`WeakMap.prototype.get`,!0),l=r(`WeakMap.prototype.set`,!0),u=r(`WeakMap.prototype.has`,!0),d=r(`WeakMap.prototype.delete`,!0);t.exports=s?function(){var e,t,n={assert:function(e){if(!n.has(e))throw new o(`Side channel does not contain `+i(e))},delete:function(n){if(s&&n&&(typeof n==`object`||typeof n==`function`)){if(e)return d(e,n)}else if(a&&t)return t.delete(n);return!1},get:function(n){return s&&n&&(typeof n==`object`||typeof n==`function`)&&e?c(e,n):t&&t.get(n)},has:function(n){return s&&n&&(typeof n==`object`||typeof n==`function`)&&e?u(e,n):!!t&&t.has(n)},set:function(n,r){s&&n&&(typeof n==`object`||typeof n==`function`)?(e||=new s,l(e,n,r)):a&&(t||=a(),t.set(n,r))}};return n}:a})),Mn=o(((e,t)=>{var n=Gt(),r=qt(),i=Jt(),a=An(),o=jn()||a||i;t.exports=function(){var e,t={assert:function(e){if(!t.has(e))throw new n(`Side channel does not contain `+r(e))},delete:function(t){return!!e&&e.delete(t)},get:function(t){return e&&e.get(t)},has:function(t){return!!e&&e.has(t)},set:function(t,n){e||=o(),e.set(t,n)}};return t}})),Nn=o(((e,t)=>{var n=String.prototype.replace,r=/%20/g,i={RFC1738:`RFC1738`,RFC3986:`RFC3986`};t.exports={default:i.RFC3986,formatters:{RFC1738:function(e){return n.call(e,r,`+`)},RFC3986:function(e){return String(e)}},RFC1738:i.RFC1738,RFC3986:i.RFC3986}})),Pn=o(((e,t)=>{var n=Nn(),r=Object.prototype.hasOwnProperty,i=Array.isArray,a=function(){for(var e=[],t=0;t<256;++t)e.push(`%`+((t<16?`0`:``)+t.toString(16)).toUpperCase());return e}(),o=function(e){for(;e.length>1;){var t=e.pop(),n=t.obj[t.prop];if(i(n)){for(var r=[],a=0;a=d?s.slice(l,l+d):s,f=[],p=0;p=48&&m<=57||m>=65&&m<=90||m>=97&&m<=122||o===n.RFC1738&&(m===40||m===41)){f[f.length]=u.charAt(p);continue}if(m<128){f[f.length]=a[m];continue}if(m<2048){f[f.length]=a[192|m>>6]+a[128|m&63];continue}if(m<55296||m>=57344){f[f.length]=a[224|m>>12]+a[128|m>>6&63]+a[128|m&63];continue}p+=1,m=65536+((m&1023)<<10|u.charCodeAt(p)&1023),f[f.length]=a[240|m>>18]+a[128|m>>12&63]+a[128|m>>6&63]+a[128|m&63]}c+=f.join(``)}return c},isBuffer:function(e){return!e||typeof e!=`object`?!1:!!(e.constructor&&e.constructor.isBuffer&&e.constructor.isBuffer(e))},isRegExp:function(e){return Object.prototype.toString.call(e)===`[object RegExp]`},maybeMap:function(e,t){if(i(e)){for(var n=[],r=0;r{var n=Mn(),r=Pn(),i=Nn(),a=Object.prototype.hasOwnProperty,o={brackets:function(e){return e+`[]`},comma:`comma`,indices:function(e,t){return e+`[`+t+`]`},repeat:function(e){return e}},s=Array.isArray,c=Array.prototype.push,l=function(e,t){c.apply(e,s(t)?t:[t])},u=Date.prototype.toISOString,d=i.default,f={addQueryPrefix:!1,allowDots:!1,allowEmptyArrays:!1,arrayFormat:`indices`,charset:`utf-8`,charsetSentinel:!1,commaRoundTrip:!1,delimiter:`&`,encode:!0,encodeDotInKeys:!1,encoder:r.encode,encodeValuesOnly:!1,filter:void 0,format:d,formatter:i.formatters[d],indices:!1,serializeDate:function(e){return u.call(e)},skipNulls:!1,strictNullHandling:!1},p=function(e){return typeof e==`string`||typeof e==`number`||typeof e==`boolean`||typeof e==`symbol`||typeof e==`bigint`},m={},h=function e(t,i,a,o,c,u,d,h,g,_,v,y,b,x,S,C,w,T){for(var E=t,D=T,O=0,k=!1;(D=D.get(m))!==void 0&&!k;){var A=D.get(t);if(O+=1,A!==void 0){if(A===O)throw RangeError(`Cyclic object value`);k=!0}D.get(m)===void 0&&(O=0)}if(typeof _==`function`?E=_(i,E):E instanceof Date?E=b(E):a===`comma`&&s(E)&&(E=r.maybeMap(E,function(e){return e instanceof Date?b(e):e})),E===null){if(u)return g&&!C?g(i,f.encoder,w,`key`,x):i;E=``}if(p(E)||r.isBuffer(E))return g?[S(C?i:g(i,f.encoder,w,`key`,x))+`=`+S(g(E,f.encoder,w,`value`,x))]:[S(i)+`=`+S(String(E))];var j=[];if(E===void 0)return j;var M;if(a===`comma`&&s(E))C&&g&&(E=r.maybeMap(E,g)),M=[{value:E.length>0?E.join(`,`)||null:void 0}];else if(s(_))M=_;else{var N=Object.keys(E);M=v?N.sort(v):N}var P=h?String(i).replace(/\./g,`%2E`):String(i),F=o&&s(E)&&E.length===1?P+`[]`:P;if(c&&s(E)&&E.length===0)return F+`[]`;for(var I=0;I0?b+y:``}})),In=o(((e,t)=>{var n=Pn(),r=Object.prototype.hasOwnProperty,i=Array.isArray,a={allowDots:!1,allowEmptyArrays:!1,allowPrototypes:!1,allowSparse:!1,arrayLimit:20,charset:`utf-8`,charsetSentinel:!1,comma:!1,decodeDotInKeys:!1,decoder:n.decode,delimiter:`&`,depth:5,duplicates:`combine`,ignoreQueryPrefix:!1,interpretNumericEntities:!1,parameterLimit:1e3,parseArrays:!0,plainObjects:!1,strictDepth:!1,strictNullHandling:!1,throwOnLimitExceeded:!1},o=function(e){return e.replace(/(\d+);/g,function(e,t){return String.fromCharCode(parseInt(t,10))})},s=function(e,t,n){if(e&&typeof e==`string`&&t.comma&&e.indexOf(`,`)>-1)return e.split(`,`);if(t.throwOnLimitExceeded&&n>=t.arrayLimit)throw RangeError(`Array limit exceeded. Only `+t.arrayLimit+` element`+(t.arrayLimit===1?``:`s`)+` allowed in an array.`);return e},c=`utf8=%26%2310003%3B`,l=`utf8=%E2%9C%93`,u=function(e,t){var u={__proto__:null},d=t.ignoreQueryPrefix?e.replace(/^\?/,``):e;d=d.replace(/%5B/gi,`[`).replace(/%5D/gi,`]`);var f=t.parameterLimit===1/0?void 0:t.parameterLimit,p=d.split(t.delimiter,t.throwOnLimitExceeded?f+1:f);if(t.throwOnLimitExceeded&&p.length>f)throw RangeError(`Parameter limit exceeded. Only `+f+` parameter`+(f===1?``:`s`)+` allowed.`);var m=-1,h,g=t.charset;if(t.charsetSentinel)for(h=0;h-1&&(x=i(x)?[x]:x);var S=r.call(u,b);S&&t.duplicates===`combine`?u[b]=n.combine(u[b],x):(!S||t.duplicates===`last`)&&(u[b]=x)}return u},d=function(e,t,r,i){var a=0;if(e.length>0&&e[e.length-1]===`[]`){var o=e.slice(0,-1).join(``);a=Array.isArray(t)&&t[o]?t[o].length:0}for(var c=i?t:s(t,r,a),l=e.length-1;l>=0;--l){var u,d=e[l];if(d===`[]`&&r.parseArrays)u=r.allowEmptyArrays&&(c===``||r.strictNullHandling&&c===null)?[]:n.combine([],c);else{u=r.plainObjects?{__proto__:null}:{};var f=d.charAt(0)===`[`&&d.charAt(d.length-1)===`]`?d.slice(1,-1):d,p=r.decodeDotInKeys?f.replace(/%2E/g,`.`):f,m=parseInt(p,10);!r.parseArrays&&p===``?u={0:c}:!isNaN(m)&&d!==p&&String(m)===p&&m>=0&&r.parseArrays&&m<=r.arrayLimit?(u=[],u[m]=c):p!==`__proto__`&&(u[p]=c)}c=u}return c},f=function(e,t,n,i){if(e){var a=n.allowDots?e.replace(/\.([^.[]+)/g,`[$1]`):e,o=/(\[[^[\]]*])/,s=/(\[[^[\]]*])/g,c=n.depth>0&&o.exec(a),l=c?a.slice(0,c.index):a,u=[];if(l){if(!n.plainObjects&&r.call(Object.prototype,l)&&!n.allowPrototypes)return;u.push(l)}for(var f=0;n.depth>0&&(c=s.exec(a))!==null&&f{var n=Fn(),r=In();t.exports={formats:Nn(),parse:r,stringify:n}})),Rn=o((e=>{var t=Wt();function n(){this.protocol=null,this.slashes=null,this.auth=null,this.host=null,this.port=null,this.hostname=null,this.hash=null,this.search=null,this.query=null,this.pathname=null,this.path=null,this.href=null}var r=/^([a-z0-9.+-]+:)/i,i=/:[0-9]*$/,a=/^(\/\/?(?!\/)[^?\s]*)(\?[^\s]*)?$/,o=[`'`,`{`,`}`,`|`,`\\`,`^`,"`",`<`,`>`,`"`,"`",` `,`\r`,`
+`,` `],s=[`%`,`/`,`?`,`;`,`#`].concat(o),c=[`/`,`?`,`#`],l=255,u=/^[+a-z0-9A-Z_-]{0,63}$/,d=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,f={javascript:!0,"javascript:":!0},p={javascript:!0,"javascript:":!0},m={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0},h=Ln();function g(e,t,r){if(e&&typeof e==`object`&&e instanceof n)return e;var i=new n;return i.parse(e,t,r),i}n.prototype.parse=function(e,n,i){if(typeof e!=`string`)throw TypeError(`Parameter 'url' must be a string, not `+typeof e);var g=e.indexOf(`?`),_=g!==-1&&g127?N+=`x`:N+=M[P];if(!N.match(u)){var I=A.slice(0,T),L=A.slice(T+1),R=M.match(d);R&&(I.push(R[1]),L.unshift(R[2])),L.length&&(y=`/`+L.join(`.`)+y),this.hostname=I.join(`.`);break}}}this.hostname.length>l?this.hostname=``:this.hostname=this.hostname.toLowerCase(),k||(this.hostname=t.toASCII(this.hostname));var z=this.port?`:`+this.port:``;this.host=(this.hostname||``)+z,this.href+=this.host,k&&(this.hostname=this.hostname.substr(1,this.hostname.length-2),y[0]!==`/`&&(y=`/`+y))}if(!f[S])for(var T=0,j=o.length;T0?r.host.split(`@`):!1;S&&(r.auth=S.shift(),r.hostname=S.shift(),r.host=r.hostname)}return r.search=e.search,r.query=e.query,(r.pathname!==null||r.search!==null)&&(r.path=(r.pathname?r.pathname:``)+(r.search?r.search:``)),r.href=r.format(),r}if(!b.length)return r.pathname=null,r.search?r.path=`/`+r.search:r.path=null,r.href=r.format(),r;for(var C=b.slice(-1)[0],w=(r.host||e.host||b.length>1)&&(C===`.`||C===`..`)||C===``,T=0,E=b.length;E>=0;E--)C=b[E],C===`.`?b.splice(E,1):C===`..`?(b.splice(E,1),T++):T&&(b.splice(E,1),T--);if(!v&&!y)for(;T--;)b.unshift(`..`);v&&b[0]!==``&&(!b[0]||b[0].charAt(0)!==`/`)&&b.unshift(``),w&&b.join(`/`).substr(-1)!==`/`&&b.push(``);var D=b[0]===``||b[0]&&b[0].charAt(0)===`/`;if(x){r.hostname=D?``:b.length?b.shift():``,r.host=r.hostname;var S=r.host&&r.host.indexOf(`@`)>0?r.host.split(`@`):!1;S&&(r.auth=S.shift(),r.hostname=S.shift(),r.host=r.hostname)}return v||=r.host&&b.length,v&&!D&&b.unshift(``),b.length>0?r.pathname=b.join(`/`):(r.pathname=null,r.path=null),(r.pathname!==null||r.search!==null)&&(r.path=(r.pathname?r.pathname:``)+(r.search?r.search:``)),r.auth=e.auth||r.auth,r.slashes=r.slashes||e.slashes,r.href=r.format(),r},n.prototype.parseHost=function(){var e=this.host,t=i.exec(e);t&&(t=t[0],t!==`:`&&(this.port=t.substr(1)),e=e.substr(0,e.length-t.length)),e&&(this.hostname=e)},e.parse=g,e.format=_})),zn=c(Rn());function Bn(e,t){if(Object.is(e,t))return!0;if(typeof e!=`object`||!e||typeof t!=`object`||!t)return!1;let n=Object.keys(e),r=Object.keys(t);if(n.length!==r.length)return!1;for(let r=0;re),t.length===0)return e;let n=zn.parse(e,!0),r=Object.assign({},n.query,...t);return n.query=Ot(r,Object.keys(r).filter(e=>{let t=r[e];return t==null||t===``})),delete n.search,zn.format(n)}function Hn(e){let t=zn.parse(e,!0).query;if(t){for(let e in t){let n=t[e];t[e]=Array.isArray(n)?n[n.length-1]:n}return t}}function Un(e){return Hn(`?${e}`)}function Wn(e,t=!1){if(t){let t=Object.keys(e).filter(t=>{let n=e[t];return n==null||n===``});e=Ot(e,t)}return zn.format({query:e}).slice(1)}function Q(e){return typeof DEBUG>`u`||!DEBUG||!e||typeof e!=`object`?e:(Object.getOwnPropertyNames(e).forEach(t=>{let n=e[t];typeof n==`object`&&n&&Q(n)}),Object.freeze(e),e)}var Gn=class e{static toString(e){let t=``;return e&&bt(e,function(e,n){e!=null&&(t.length>0&&(t+=`&`),t+=n+`=`+e.toString())}),t}static fromString(e){let t={};if(e)for(let n of It(e,`&`)){let e=It(n,`=`,2);t[e[0]]=e[1]}return t}static equals(t,n){return Bn(e.fromString(t),e.fromString(n))}};function Kn(e=0){return new Promise(t=>{setTimeout(t,e)})}const qn=e=>e!==void 0,Jn=e=>!!e;function Yn(e){let t=document.createElement(`div`);return t.innerHTML=e,t.querySelectorAll(`li`).forEach(e=>{e.textContent?.toLowerCase().includes(`designer tip`)&&e.remove()}),t.innerHTML}const Xn=new Set([`STANDARDWEEKEND`,`ZIP`,`ZIPPLUS`]);var $=!0,Zn=new Set;function Qn(e){if($!==e){$=e;for(let e of Zn)try{e($)}catch(e){setTimeout(()=>{throw e})}}}typeof window<`u`&&(document.addEventListener(`visibilitychange`,()=>{document.visibilityState===`visible`&&!$&&navigator.onLine&&Qn(!0)}),window.addEventListener(`online`,()=>{Qn(!0)}),window.addEventListener(`offline`,()=>{Qn(!1)}));function $n(e){return Zn.add(e),()=>{Zn.delete(e)}}async function er(){!$&&navigator.onLine&&Qn(!0),!$&&await new Promise(e=>{let t=$n(()=>{$&&(t(),e($))})})}var tr=o(((e,t)=>{function n(e,t){return Object.prototype.hasOwnProperty.call(e,t)}t.exports=function(e,t,r,i){t||=`&`,r||=`=`;var a={};if(typeof e!=`string`||e.length===0)return a;var o=/\+/g;e=e.split(t);var s=1e3;i&&typeof i.maxKeys==`number`&&(s=i.maxKeys);var c=e.length;s>0&&c>s&&(c=s);for(var l=0;l=0?(f=u.substr(0,d),p=u.substr(d+1)):(f=u,p=``),m=decodeURIComponent(f),h=decodeURIComponent(p),n(a,m)?Array.isArray(a[m])?a[m].push(h):a[m]=[a[m],h]:a[m]=h}return a}})),nr=o(((e,t)=>{var n=function(e){switch(typeof e){case`string`:return e;case`boolean`:return e?`true`:`false`;case`number`:return isFinite(e)?e:``;default:return``}};t.exports=function(e,t,r,i){return t||=`&`,r||=`=`,e===null&&(e=void 0),typeof e==`object`?Object.keys(e).map(function(i){var a=encodeURIComponent(n(i))+r;return Array.isArray(e[i])?e[i].map(function(e){return a+encodeURIComponent(n(e))}).join(t):a+encodeURIComponent(n(e[i]))}).filter(Boolean).join(t):i?encodeURIComponent(n(i))+r+encodeURIComponent(n(e)):``}})),rr=c(o((e=>{e.decode=e.parse=tr(),e.encode=e.stringify=nr()}))());function ir(e){"@babel/helpers - typeof";return ir=typeof Symbol==`function`&&typeof Symbol.iterator==`symbol`?function(e){return typeof e}:function(e){return e&&typeof Symbol==`function`&&e.constructor===Symbol&&e!==Symbol.prototype?`symbol`:typeof e},ir(e)}function ar(e,t){if(ir(e)!=`object`||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var r=n.call(e,t||`default`);if(ir(r)!=`object`)return r;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(t===`string`?String:Number)(e)}function or(e){var t=ar(e,`string`);return ir(t)==`symbol`?t:t+``}function sr(e,t,n){return(t=or(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var cr=c(Rn()),lr=8e3,ur=8e3,dr=Q({credentials:`include`,enableCsrf:!1,fallbackToPostMethod:!0,headers:{},includeCacheVersion:!0,includeClientParam:!0,includeI18NParams:!1,method:`GET`,retryOnNetworkError:!1});function fr(...e){let t=[...e].reverse();return t.push(dr),ht({},...t)}var pr=class extends Error{constructor(e,t,n,r){t&&(e+=`\nmethod:${t}`),n&&(e+=`\nurl:${n}`),super(e),sr(this,`name`,`ZFetchError`),sr(this,`response`,void 0),this.response=r}};function mr(e){return typeof e==`object`&&!!e&&`error`in e}function hr(e){return mr(e)&&typeof e.error==`object`&&!!e.error&&`id`in e.error&&e.error.id===`auth_token_invalid`}function gr(e){return mr(e)&&typeof e.error==`object`&&!!e.error&&`csrf`in e.error}async function _r(e,t,n,r){n={enableCsrf:!0,...n,headers:{Accept:`application/json`,...n?.headers}},{url:e,data:t,init:n}=yr(e,t,n,r);let i,a=n.retryOnNetworkError?2:1;for(let t=1;t<=a;t++){let o,s;try{if(o=await vr(e,n),s=await o.json(),n.enableCsrf&&gr(s)&&r&&(r.csrf=s.error.csrf,n.headers||={},n.headers[`X-Csrf-Token`]=r.csrf,o=await vr(e,n),s=await o.json(),gr(s)))throw new pr(`Invalid CSRF token on fetch retry.`,n.method,e,o);if(r?.access_token&&hr(s))throw new pr(`Invalid access token`,n.method,e,o);if(n.throwSoftJsonErrors&&mr(s))throw new pr(JSON.stringify(s.error),n.method,e,o);i=s;break}catch(r){await br(r,n.method,e,o,t=200&&n.status<300)return n;throw new pr(`Unsuccessful status: ${n.status} - ${n.statusText}`,t.method,e,n)}function yr(e,t,n,r){n=fr(n);function i(n,r){typeof t==`string`||typeof Blob<`u`&&t instanceof Blob||typeof FormData<`u`&&t instanceof FormData?e=Z(e,{[n]:r}):t={...t,[n]:r}}let a={};if(r&&(r.access_token&&(a.access_token=r.access_token),n.includeI18NParams&&(r.currency&&(a.zcur=r.currency),r.language&&(a.lang=r.language),r.region&&(a.region=r.region)),r.sessionParams&&Object.assign(a,r.sessionParams),Pt(a)||(e=Z(e,a))),n.enableCsrf&&(n.headers||={},n.headers[`X-Csrf-Token`]=r?.csrf??``),n.includeClientParam&&i(`client`,`js`),n.includeCacheVersion&&n.method===`GET`&&r?.httpCacheVersion&&(e=Z(e,{cv:r.httpCacheVersion})),(n.method===`GET`||n.method===`DELETE`)&&(e=Z(e,t),delete n.body,n.fallbackToPostMethod)){let r=cr.parse(e,!0);if(e.length>lr||r.search&&r.search.length>ur){if(n.method=`POST`,Pt(a))t=r.query,delete r.query;else{let e=Object.keys(a);t=Ot(r.query,e),r.query=Mt(r.query,e)}delete r.search,e=cr.format(r)}}if(!(n.method===`GET`||n.method===`DELETE`))if(typeof t==`string`||t instanceof Blob||t instanceof FormData){if(n.body=t,DEBUG&&!(typeof t!=`string`||n.headers&&Object.keys(n.headers).find(e=>e.toLowerCase()===`content-type`)))throw new pr(`You provided a raw payload to zfetch but failed to specify a Content-Type header.`,n.method,e,void 0)}else if(n.postAsFormUrlEncoded){let e=Nt(t,e=>e!==void 0);n.body=rr.stringify(e),n.headers||={},n.headers[`Content-Type`]=`application/x-www-form-urlencoded; charset=UTF-8`}else n.headers||={},n.headers[`Content-Type`]=`application/json`,n.body=JSON.stringify(t);return{url:e,data:t,init:n}}async function br(e,t,n,r,i){let a=e;if(a instanceof pr)throw a;if(i&&xr(a))await Kn(1e3);else throw new pr(`${a.name}: ${a.message}`,t,n,r)}function xr(e){return Ft(e)&&e.name===`TypeError`&&typeof e.message==`string`&&Sr.has(e.message)}var Sr=new Set([`network error`,`Failed to fetch`,`The Internet connection appears to be offline.`,`Load failed`,`NetworkError when attempting to fetch resource.`,`Network request failed`]);function Cr(e,t,n,r){return wr(e,t,{method:`GET`,...n},r)}async function wr(e,t,n,r){return await er(),{init:n,env:r}=Tr(n,r),_r(e,t,n,r)}function Tr(e,t){let n=e?.method??`GET`;return e={...e,credentials:`omit`,enableCsrf:!1,retryOnNetworkError:n===`GET`},t?.region&&(e.includeI18NParams=!0),{init:e,env:t}}function Er(e){return{async wwwGetProductFromTemplate(t){return(await Cr(e.wwwPag(`svc/partner/adobeexpress/v1/getproductfromtemplate`),{templateId:t},{throwSoftJsonErrors:!0})).data},async wwwChangeOptions(t){return(await Cr(e.wwwPag(`svc/partner/adobeexpress/v1/changeoptions`),t,{throwSoftJsonErrors:!0})).data.product},async wwwGetHelpDialog(t){let n=await Cr(e.wwwPag(`svc/z3/product/productattributehelp/gethelpdialog`),t);if(!n.success)throw n.error;return n.data},async wwwGetPricing(t){return(await Cr(e.wwwPag(`svc/partner/adobeexpress/v1/getproductpricing`),t,{throwSoftJsonErrors:!0})).data},async wwwGetShippingEstimates(t){let n=await Cr(e.wwwPag(`svc/partner/adobeexpress/v1/getshippingestimates`),t,{throwSoftJsonErrors:!0});return n?.data?.estimates&&(n.data.estimates=n.data.estimates.filter(e=>!Xn.has(e.method))),n.data}}}const Dr={mojo_throwpillow:{},zazzle_bag:{},zazzle_businesscard:{attributeValueFilter:{"*":``,"en-au":`std={iso}`,"en-ca":`std={iso}`,"en-gb":`std={iso}`,"en-us":`std={na}`,"es-us":`std={na}`,"fr-ca":`std={iso}`}},zazzle_flyer:{attributeValueFilter:{"*":``,"en-au":`std={iso}`,"en-ca":`std={iso}`,"en-gb":`std={iso}`,"en-us":`std={na}`,"es-us":`std={na}`,"fr-ca":`std={iso}`}},zazzle_foldedthankyoucard:{attributeValueFilter:{"*":``,"en-au":`std={iso}`,"en-ca":`std={iso}`,"en-gb":`std={iso}`,"en-us":`std={na}`,"es-us":`std={na}`,"fr-ca":`std={iso}`}},zazzle_invitation3:{attributeValueFilter:{"*":``,"en-au":`std={iso}`,"en-ca":`std={iso}`,"en-gb":`std={iso}`,"en-us":`std={na}`,"es-us":`std={na}`,"fr-ca":`std={iso}`}},zazzle_mug:{},zazzle_print:{attributeValueFilter:{"*":``,"en-au":`std={iso}`,"en-ca":`*`,"en-gb":`*`,"en-us":`std={na}`,"es-us":`std={na}`,"fr-ca":`*`}},zazzle_shirt:{attributeValueFilter:{"en-gb":``}},zazzle_sticker:{}};var Or=class e{constructor(e){sr(this,`zMatchExpression`,void 0),this.zMatchExpression=(e||``).toLowerCase()}evaluate(e){if(!this.zMatchExpression)return 0;let t=``;typeof e==`string`?t=e:typeof e==`object`&&(t=Wn(e)||``),t=t.toLowerCase();let n=this.lookupEvaluation(this.zMatchExpression,t);if(n!==void 0)return n;let r=this.zMatchExpression.split(`&`).map(e=>this.scoreExpressionAtom(e,t)),i=r.includes(-1)?-1:r.reduce((e,t)=>e+t,0);return this.cacheEvaluation(this.zMatchExpression,t,i),i}matches(e){return this.evaluate(e)>-1}expressionAtomValueMatchesAttributeSetAtomValue(e,t){let n=this.getAtomValueAsSet(t),r=e.startsWith(`!`),i=ze(n,this.getAtomValueAsSet(e.replace(/^!/,``)));return r?i.length===0:i.length>0}getAtomValueAsSet(e){return e=e.replace(/[{\[}\]}]/g,``),e.split(`,`).filter(e=>!!e)}scoreExpressionAtom(e,t){let n=e.includes(`:=`)?`:=`:`=`,[r,i]=e.split(n),a=Un(t)||{},o=a[r];return Object.keys(a).includes(r)?this.expressionAtomValueMatchesAttributeSetAtomValue(i,o)?1:-1:n===`=`?0:-1}cacheEvaluation(t,n,r){let i=this.generateCacheKey(t,n);e.cache[i]=r}static clearCache(){e.cache={}}generateCacheKey(e,t){return[e,t].join(`|`)}lookupEvaluation(t,n){let r=this.generateCacheKey(t,n);if(r in e.cache)return e.cache[r]}};sr(Or,`cache`,{});function kr(e,t,n=!1){let r=new Or(e),i=[],a=[];return t.forEach(e=>{r.matches(e.properties)?a.push(e):i.push(e)}),n?[...a,...i]:a}function Ar(e,t,n){if(!t)return e.values;let r=[];if(r=t[n]?kr(t[n],e.values):t[`*`]?kr(t[`*`],e.values):e.values,!r.find(t=>t.name===e.value)){let t=e.values.find(t=>t.name===e.value);t&&r.unshift(t)}return r}function jr(e,t){let n={};switch(t){case`firstProductRealview`:n=e.firstProductRealviewParams;break;case`realview`:n=e.realviewParams;break;case`swatch`:n=e.swatchParams;break}return Pt(n)&&(n=e.realviewParams),n}const Mr={AISparkle:`쓑`,Account:``,AccountFill22:`쑟`,AccountStroke22:`쑠`,AccountWIZ:`쑜`,Add22:`쑰`,AddFill22:`쒇`,AddImage:`쎗`,AddShape:``,AddText:`쎓`,AddToList:``,AddedToList:``,AddressBook22:`쑸`,AddressBookWIZ:`쑕`,Advanced:``,Album:``,Albums:``,AlignLayersBottom:`쎺`,AlignLayersHorzCenter:`쎸`,AlignLayersLeft:`쎻`,AlignLayersRight:`쎼`,AlignLayersTop:`쎹`,AlignLayersVertCenter:`쎷`,AllWhites:`쏓`,Animation:`쒢`,AppsEndWIZ:`쑌`,AppsStartWIZ:`쑋`,AroundClock:``,Arrange22:`쑱`,ArrowDown:``,ArrowNw:``,ArrowRight:``,ArrowSw:``,ArtView:``,Asciicircum:`^`,AspectRatio:`쒝`,AspectRatio22:`쒜`,AttAccent:``,AttAccentOpen:``,AttAge:``,AttColorOpen:``,AttDesignSizeOpen:``,AttFeaturesOpen:``,AttImage:``,AttImageOpen:``,AttLaptopSizeOpen:``,AttMetalOpen:``,AttOptionsOpen:``,AttOrientationOpen:``,AttOutputOpen:``,AttSignedOpen:``,AttSizeOpen:``,AttStoneOpen:``,AttStyle:``,AttStyleOpen:``,AttText:``,AttTextOpen:``,AttUpholsteryFabricOpen:``,Background:`쏠`,BackgroundWhite:`쏕`,Boundaries:`쎔`,Burger22:`쒏`,BurgerEndWIZ:`쑐`,BurgerStartWIZ:`쑏`,BurgerWideStartWIZ:`쑑`,Camera:``,CameraStroke:``,CaretDown:``,CaretDownSmallZ4:`썠`,CaretDownZ4:`썖`,CaretUpSmallZ4:`썟`,CaretUpZ4:`썕`,CartEmpty:`Á`,CartFill22:`쑡`,CartFull:`Â`,CartStroke22:`쑢`,CartWIZ:``,CartWIZ2:`쑙`,Change22:`쑲`,CharacterSpacing:``,ChatFill22:`쑣`,ChatFilled:`쐙`,ChatMonostroke:`쐘`,ChatStroke22:`쑤`,ChatWIZ:`쑚`,Check:`✓`,CheckStamp:``,Checkmark:`쎕`,ChevronDown:``,ChevronUp:``,Circle:``,CircleOutline:``,ClipMaskOff:`쏗`,ClipMaskOn:`쏘`,ClockStroke:``,CloseStamp:``,CloseStroke:`╳`,Collections22:`쑹`,ColorDropper:``,ColorPickerDroplet:``,Connect:``,ContourDynamicSizing:`쏙`,Copy:``,Create22:`쒐`,CreateEndWIZ:`쑎`,CreateStartWIZ:`쑍`,CreateVertical:`쐛`,Crop:``,Crop22:`쑪`,CropZ4:`쏏`,Customers:``,Cut:``,DatePicker:``,Delete22:`쑴`,DeleteTrashcan:`쎤`,DeliveryTruck:``,Designers:``,Designs22:`쑺`,DirectionDown:`쒡`,DirectionLeft:`쒞`,DirectionRight:`쒠`,DirectionUp:`쒟`,DistributeHorz:``,DistributeVert:``,Download22:`쒙`,DownloadCircle22:`쒚`,DragDrop:`쏬`,Droplet:``,Duplicate22:`쑳`,Earnings22:`쑻`,EarningsWIZ:`쑘`,Edit:``,EditBox:``,EditText22:`쒈`,Editor22:`쑶`,EditorsPick:``,Elements:`쏢`,Email:``,Envelope:`쓒`,ErrorCA:`썢`,Expand:``,Expand22:`쑼`,ExpandWindow:``,EyeDropper:``,FacebookCircle:``,FacebookOutline:`썻`,FileBitmap:``,FilePdfai:``,FileScreenprint:``,FileStitch:``,FileVideo:``,Fill:`쏐`,Fill22:`쑮`,Filter:`쏑`,Filter22:`쑭`,FilterImage:``,Fit:`쏒`,Fit22:`쑩`,FitBest:``,FitFill:``,FitFit:``,Flag:``,Flip22:`쑬`,FlipX:`쐁`,FlipY:`쐀`,Followed22:`쑷`,FollowedDesignersWIZ:`쑖`,Font:``,Font22:`쒍`,Fraction:`⁄`,Friends22:`쑽`,GdArrowGetStarted:``,Gift22:`쒑`,GiftBox:``,GiftsEndWIZ:`쑞`,GiftsStartWIZ:`쑝`,Globe:``,GoogleCircle:``,Greater:`쎃`,Grid:`쐠`,GridView:``,Gridlines:`쎖`,Grippy:``,Group:`쐄`,Group24:`쓔`,GroupEdit:`쓓`,GroupLayers:`쏵`,Guillemotleft:`«`,Guillemotright:`»`,HamburgerMenuCaret:`Å`,Heart:``,Heart22:`쑾`,HeartFill22:`쒄`,HeartOpen:``,Help:`쏞`,Hidden:``,History:``,HolidayGift:`ñ`,Home:``,HorizontalText:`쏀`,Hotspot:``,IdeasVertical:`쐞`,Images22:`쑿`,ImagesVertical:`쐜`,Info:``,InfoBg:``,InfoStamp:``,InfoStamp24:`쓙`,InfoStampFill24:`쓚`,InstagramCircle:``,InstagramOutline:`썹`,IntercharacterSpacing:`쎱`,InviteShapes:``,IsolatedZ:``,LaptopStroke:``,LargerImage:``,Layout:`쐡`,Less:`쎂`,Line:``,LineWeight:``,Link:``,List:``,Live22:`쒒`,LiveEndWIZ:`쑊`,LiveStartWIZ:`쑉`,LiveVertical:`쐝`,Location:``,Lock:``,Logo:``,LogoBigZ:``,LogoLetterform:``,MagnifyDecrease:``,MagnifyIncrease:``,MakeTools:``,Maker22:`쒀`,MakerProCheckmark:``,MakerStroke:``,MakerVertical:`쐟`,MarketplaceVertical:`쐚`,Mask:`쓖`,MaskEdit:`쓗`,Message:``,MicrophoneOff:`쐤`,MicrophoneOn:`쐣`,MinimizeWindow:``,MobileClose:`쀁`,MobileDevice:``,More:`쏄`,MoveBackward:``,MoveBackwardZ4:`쎾`,MoveForward:``,MoveForwardZ4:`쎽`,MoveToBack:``,MoveToBackZ4:`쏼`,MoveToFront:``,MoveToFrontZ4:`쏻`,MultipleSelected:``,Multiply:`×`,MultiplyLight:`Ö`,Mute:``,MyAccountWIZ:`쑒`,MyEndWIZ:`쑈`,MyOrdersWIZ:`쑓`,MyStartWIZ:`쑇`,MyStoresWIZ:`쑗`,NoWhites:`쏔`,NotSelected:``,NotVisible:`썝`,NotificationFill22:`쑥`,NotificationStroke22:`쑦`,ObjectAlignBottom:``,ObjectAlignHorzCenter:``,ObjectAlignLeft:``,ObjectAlignRight:``,ObjectAlignTop:``,ObjectAlignVertCenter:``,OffCanvasLeft:`Ä`,OffCanvasRight:``,Orders22:`쒁`,PaintPalette:``,PaperStack:``,Paste:``,Pause:``,PaymentAmericanexpress:``,PaymentApplepay:`쐎`,PaymentBankTransfer:``,PaymentBankTransferJapan:``,PaymentBankeinzug:``,PaymentBoletoBancario:``,PaymentGiropay:``,PaymentGooglepay:`쐏`,PaymentIdeal:``,PaymentIncasso:``,PaymentMastercard:``,PaymentOverboeking:``,PaymentOverboekingBancare:``,PaymentPaypal:``,PaymentSofort:``,PaymentTransferenciaBancaria:``,PaymentTransferenciaBancaria2:``,PaymentUberweisung:``,PaymentVirementBancare:``,PaymentVisa:``,PaymentVorkasse:``,Pencil:``,Phone:``,PhoneOff:`쐨`,PhoneOn:`쐧`,PicFrame:``,PiggyBankStroke:``,Pin:``,PinterestCircle:``,PinterestOutline:`썺`,Play:``,PlayCircle:`Æ`,Plus:``,Popup:``,PositionBottom:``,PositionHorzCenter:``,PositionLeft:``,PositionRight:``,PositionTop:``,PositionVertCenter:``,Print:``,Prints22:`쒘`,Product22:`쒓`,ProductBox:``,Profile22:`쒂`,ProsellerBadge:``,QRCode:`쏣`,QRCodeLarge:`쏤`,QuestionStamp:``,Radius:`쏛`,Redo:``,RedoZ4:`쎘`,RemoveWhite:`쏖`,Resize:``,RetailerCart:``,RevisedErrorIcon:``,Robot:``,Rotate:``,Rotate22:`쑫`,RotateCcw:``,RotateCw:``,RotateZ4:`쎥`,RoundedRectangle:`쏚`,Save:``,SaveRibbon:``,Saved22:`쒔`,SavedDesignsWIZ:`쑔`,Scale22:`쑨`,Search:`Ã`,Sell22:`쒕`,SellStartWIZ:`쑛`,Send:`쓜`,SendFill:`쓛`,SettingsGear:`쐢`,ShapeFill:``,Share:``,Share22:`쒅`,ShareFill22:`쒆`,ShareUp22:`쒎`,Shared:`쏡`,ShoppingBag:`쒛`,Show:``,SizeDecrease:``,SizeIncrease:``,SizeNonApparel:`썐`,Sliders:`쒣`,Smiley:``,SocialBlogger:``,SocialEmail:``,SocialEmailIso:``,SocialFacebook:``,SocialFacebookIso:``,SocialFlickr:``,SocialFlickrSquare:``,SocialGoogleplus:``,SocialGoogleplusIso:``,SocialInstagram:``,SocialInstagramBare:``,SocialLinkedin:``,SocialLinkedinSquare:``,SocialPinterest:``,SocialPinterestBare:``,SocialPinterestIso:``,SocialRss:``,SocialShare:``,SocialTumblr:``,SocialTumblrIso:``,SocialTwitter:``,SocialTwitterIso:``,SocialWaneloIso:``,SocialWordpress:``,SocialYoutube:``,SocialYoutubeIso:``,SocialZazzleBlog:``,SocialZazzleForum:``,SourceAccount:``,SourceComputer:``,SourceGoogleDrive:``,SourceInstagram:``,SpaceEvenlyHorz:`쎵`,SpaceEvenlyVert:`쎶`,SpeechBubble:``,SquareOutline:``,Star:``,StickerShapes:``,Store22:`쒃`,StoreOpen:``,Stroke:``,TShirt:``,TabArea:``,TabFilter:``,TabFit:``,TabFonts:``,TabInfo:``,TabLayers:``,TabModify:``,TabMore:``,TabOptions:``,TabPersonalize:``,TabTemplates:``,TabTextalign:``,Templates:`썓`,Text:``,TextAlignCenter:``,TextAlignCenterZ4:`쎴`,TextAlignLeft:``,TextAlignLeftZ4:`쎲`,TextAlignRight:``,TextAlignRightZ4:`쎳`,TextAlignVertBottom:``,TextAlignVertCenter:``,TextAlignVertTop:``,TextCurve22:`쒉`,TextDropShadow:`쐇`,TextHeight22:`쒌`,TextLineHeight:`쏸`,TextOnPath:`쎿`,TextOrientation22:`쒊`,TextPathHorz:``,TextPathHorzCurveDown:``,TextPathHorzCurveUp:``,TextPathVert:``,TextSize:``,TextSizeZ4:`쎰`,TextSpacing22:`쒋`,TextStroke:`쐆`,ThumbsDown:``,ThumbsUp:``,TikTokStroke:`썾`,Tile22:`쑯`,Tiling:``,Tools22:`쒖`,Transfer22:`쑧`,Transparency:``,TransparencyMobile:``,Trash:``,Trending22:`쒗`,TrendingEndWIZ:`쑆`,TrendingStartWIZ:`쑅`,Triangle:`쐍`,TwitterCircle:``,TwitterOutline:`썼`,Undo:``,UndoZ4:`쎙`,Ungroup:`쐅`,Ungroup24:`쓕`,Unlink:``,UnlinkZ4:`쐃`,Unmask:`쓘`,Uploads:`쏟`,Verified22:`쑵`,VerifiedCollectionStar:``,VerticalText:`쏁`,VideoOff:`쐦`,VideoOn:`쐥`,ViewGrid:``,ViewImage:``,ViewList:``,Volume:``,WarehouseStroke:``,Warning:`썗`,WarningStamp:``,YoutubeCircle:``,YoutubeOutline:`썽`,ZazzleHeart:``,ZazzleSelect:`쐗`},Nr=e=>e,Pr=e=>e in Mr,Fr=Q({type:`thumbnails`,showTitle:!0,thumbnailSize:`m`}),Ir=Q({type:`thumbnails`,thumbnailRows:1}),Lr=Q({type:`thumbnailsWithPreview`,thumbnailRows:1}),Rr=Q({fullSelection:{type:`thumbnails`,enabled:!0},hideWhen:0,includeDesign:!0,includeDesignWhenCustomizing:!0,inlineSelection:{type:`none`},name:``,showPriceDelta:!0,shown:!0,thumbnailType:`realview`}),zr=Q({hideWhen:0,includeDesign:!0,includeDesignWhenCustomizing:!0,inlineSelection:{type:`thumbnails`},name:``,showPriceDelta:!0,shown:!0,thumbnailShape:`square`,thumbnailType:`realview`}),Br=Q({actionable:!1,astSlug:``,descriptionLabel:``,dismissable:!0,flair:!1,flairLabel:`product.ui.config.new[title]`,skuFilter:``,titleLabel:``}),Vr=Q({ads:[],attributeGroups:[{attributes:[]}],mobileAttributeGroups:[{attributes:[]}]});function Hr(e,t,n=!1,r=!1,i,a,o){let s,c=n?t.mobileAttributeGroups:t.attributeGroups,l={};if(c.forEach(e=>{e.attributes.forEach(e=>{l[e.name]=e})}),r){let r=[],o=[];function c(e){if(n){let n=l[e];if(!n){let r=Xr(t,e);n=Gr({name:e},r)}return Jr(n)}else{let t=l[e];return t||=Wr({name:e}),qr(t)}}let u={};(i||[]).forEach(e=>{switch(e.type){case`area`:o.push({attributes:[],defaulted:!0,vizLiteAreaGroupName:e.areaGroup});break;case`optiongroup`:if(e.attributes.length){let t=e.attributes.map(e=>(u[e]=!0,c(e))),n=t.filter(e=>e.forceSelection),i=t.filter(e=>!e.forceSelection),s=`product.annotation.${a}.optiongroup.${e.name}[title]`;n.length&&r.push({attributes:n,defaulted:!0,label:s}),i.length&&o.push({attributes:i,defaulted:!0,label:s})}break;case`option`:{u[e.attribute]=!0;let t=c(e.attribute),n={attributes:[t],defaulted:!0};t.forceSelection?r.push(n):o.push(n);break}}}),Ae(e,e=>{if(!u[e.name]){let t=c(e.name),n={attributes:[t],defaulted:!0};t.forceSelection?r.push(n):o.push(n)}});let d=[...r,...o];if(d.some(e=>!!e.label)){let t=[];d.forEach(n=>{n.label||n.vizLiteAreaGroupName?t.push(n):n.attributes.forEach(r=>{e[r.name]&&t.push({attributes:[r],defaulted:!0,isAccessoryGroup:n.isAccessoryGroup,label:e[r.name].title})})}),s=t}else s=d}else{let r=[...c],i=[];if(Ae(e,e=>{if(!l[e.name]){let r;if(n){let n=Xr(t,e.name);r=Gr({name:e.name},n)}else r=Wr({name:e.name});i.push(r)}}),i.length){let e={attributes:i,defaulted:!0};r.push(e)}s=r}return o&&(s=J(s),s.forEach(e=>{e.attributes.forEach(e=>{e.showPriceDelta=!1})})),s}function Ur(e,t,n=!1,r,i,a){return Hr(e,t,!1,n,r,i,a)}function Wr(e){let t=Et({},Rr,e,{defaulted:!0});e.heroThumbnailType||(t.heroThumbnailType=t.thumbnailType),t.name===`size`&&(e.heroThumbnailType||(t.heroThumbnailType=`zazzicon`),t.heroThumbnailType===`zazzicon`&&!e.heroThumbnailIconName&&(t.heroThumbnailIconName=Nr(`AttDesignSizeOpen`))),t.heroThumbnailIconName&&!Pr(t.heroThumbnailIconName)&&(t.heroThumbnailIconName=Nr(`Robot`));let n=t.inlineSelection;n.type===`thumbnails`?t.inlineSelection=n={...Ir,...n}:n.type===`thumbnailsWithPreview`&&(t.inlineSelection=n={...Lr,...n});let r=t.fullSelection;return n.type===`droplist`&&(!e.fullSelection||!e.fullSelection.type)&&(r.type=`radio`),r.type===`thumbnails`&&(t.fullSelection=r={...Fr,...r}),t.helpLink&&Zr(t.helpLink),t}function Gr(e,t){let n=Et({},zr,t,e,{defaulted:!0});n.helpLink&&Zr(n.helpLink);let r=t.inlineSelection&&t.inlineSelection.type===`radio`,i=!e||!e.inlineSelection||!e.inlineSelection.type;return r&&i&&(n.inlineSelection.type=`droplist`),n}function Kr(e){let t=Et({},Br,e,{defaulted:!0});return t.helpLink&&Zr(t.helpLink),t}function qr(e){let t={...e,heroThumbnailType:`swatch`,hideWhen:1,includeDesignWhenCustomizing:!1,thumbnailType:`swatch`};return t.fullSelection.type===`thumbnails`&&(t.fullSelection.thumbnailSize=`l`),t}function Jr(e){return{...e,hideWhen:1,includeDesignWhenCustomizing:!1,thumbnailType:`swatch`}}function Yr(e){e=Et({},Vr,e);let t=e.ads.map(Kr),n=e.attributeGroups.map(e=>{let t=(e.attributes||[]).map(Wr);return{...e,attributes:t,defaulted:!0}}),r=Ie(e.attributeGroups,e=>e.attributes),i=Ie(e.mobileAttributeGroups,e=>e.attributes),a=[{attributes:Be([...i.map(e=>e.name),...r.map(e=>e.name)]).map(e=>{let t=r.find(t=>t.name===e)??Wr({name:e});return Gr(i.find(t=>t.name===e)??{},t)}),defaulted:!0}];return{...e,ads:t,attributeGroups:n,defaulted:!0,mobileAttributeGroups:a}}function Xr(e,t){for(let n of e.attributeGroups)for(let e of n.attributes)if(e.name===t)return e;return Wr({name:t})}function Zr(e){e.iconName&&!Pr(e.iconName)&&(e.iconName=Nr(`Robot`))}function Qr(e,t,n){if(e.subtitle){let r=e.subtitle.map(e=>new Or(e.filter).evaluate(t.properties)),i=Math.max(...r);if(i>0){let t=r.findIndex(e=>e===i),a=e.subtitle[t];return n(a.label)}}}function $r(e){return e?.find(e=>e.discountIsApplied&&(e.isDiscountOnItem||e.isDiscountOnPrice))||void 0}function ei(e,t){let{discountProductItems:n=[]}=e;return n.find(e=>e.isDiscountOnPrice||e.discountIsApplied||!!t&&e.discountCode===t)}function ti(e,t){let n=ei(e,t);return n?n.priceAdjusted:e.unitPrice}function ni(e,t,n={},r=!1){return Z(t,r&&e.videoParams?e.videoParams:e.realviewParams,n)}const ri=(e,t)=>{if(!e?.length)return``;let n=Qe(e,e=>new Date(e.maxDeliveryDate)),r=new Date(n[0].maxDeliveryDate),i=new Date(n[n.length-1].maxDeliveryDate),a=``;if(r.getUTCMonth()===i.getUTCMonth())a=r.getUTCDate()===i.getUTCDate()?t(i,{day:`numeric`,month:`short`,timeZone:`UTC`}):`${t(r,{day:`numeric`,month:`short`,timeZone:`UTC`})} - ${t(i,{day:`numeric`,timeZone:`UTC`})}`;else{let e={day:`numeric`,month:`short`,timeZone:`UTC`};a=`${t(r,e)} - ${t(i,e)}`}return a};function ii(e){let t=e;function n(e){if(e===t)return t;t=e;for(let e of r)try{e()}catch(e){window.reportError(e)}return e}let r=new Set;function i(e){return r.add(e),()=>{r.delete(e)}}return{getSnapshot:()=>t,setState:n,subscribe:i}}function ai(e,t){let n=oi(e,t),r={},i=ii(r),a=ii(n(r));return i.subscribe(()=>{let e=n(i.getSnapshot());a.setState(e)}),{external:a,internal:i}}function oi(e,t){function n(t){let n=e.culture;n===`en-ca`?n=`en-us`:n===`fr-ca`&&(n=`fr-fr`);let r={style:`currency`,currency:e.currency};return t.toLocaleString(n,r)}function r(e){if(e!==0)return`${e>0?`+`:`-`}${n(Math.abs(e))}`}let i=Vn((e,t,n)=>{let r=Yr({...e,...Dr[t]});return{pbj:r,pbjAttributeGroups:Ur(n,r,!1,void 0,t,!1)}}),a=si(e=>{let{pbj:t,pbjAttributeGroups:n}=i(e.product.pbjOverrides,e.product.productType,e.product.attributes);return[t,n,e.entities.dbStrings,e.product.attributes]},(n,i,a,o)=>i.flatMap(e=>e.attributes).map(i=>{let s=o[i.name];if(!s||!i.shown)return;let c=Ar(s,n.attributeValueFilter,e.culture).filter(e=>e.isInStock||e.name===s.value),l=c.find(e=>e.name===s.value);if(c.length<=i.hideWhen)return;let u=(()=>{let e=i.helpLink;if(e?.type===`dialog`&&e.dialogType===`sizeChart`&&e.label&&a[e.label])return{dialogType:`sizeChart`,label:a[e.label],type:`dialog`}})(),d=(()=>{switch(i.inlineSelection.type){case`thumbnails`:case`thumbnailsWithPreview`:{let e=i.includeDesign&&(i.thumbnailType===`realview`||i.thumbnailType===`firstProductRealview`),n=i.inlineSelection,o=n.groups||[{filter:``}],s=o.map(e=>kr(e.filter,c,n.allowGroupBackfill));return{optionGroups:o.map((n,o)=>{let c=s[o];if(c.length===0)return;let l=n.label?a[n.label]:``;return{options:c.map(n=>{let a=jr(n,i.thumbnailType);return{imageUrl:Z(t.staticRealviewUrlBase(),{...a,max_dim:48},!e&&{design:void 0}),priceDelta:i.showPriceDelta&&n.priceDifferential?r(n.priceDifferential):void 0,title:n.title,value:n.name}}),title:l}}).filter(qn),preview:(()=>{if(i.inlineSelection.type!==`thumbnailsWithPreview`||!l)return;let n=jr(l,i.thumbnailType),r=Z(t.staticRealviewUrlBase(),{...n,max_dim:192},!e&&{design:void 0});return{descriptionHTML:l.descriptionBrief,imageUrl:r,optionTitle:l.title}})(),type:`thumbnails`}}case`radio`:return{options:c.map(e=>({priceDelta:i.showPriceDelta?r(e.priceDifferential):void 0,title:e.title,value:e.name})),type:`radio`};case`toggle`:{let e=s.values.indexOf(l),t=e===0?1:0,n=s.values[t].priceDifferential;return{checkedValue:s.values[e].name,priceDelta:i.showPriceDelta?r(n):void 0,title:s.values[1].title,type:`checkbox`,uncheckedValue:s.values[t].name}}}return{message:(l?Qr(i.inlineSelection,l,e=>a[e]):``)||void 0,options:c.map(e=>({title:e.title,value:e.name,priceDelta:i.showPriceDelta?r(e.priceDifferential):void 0})),type:`dropdown`}})();return{helpLink:u,name:s.name,selectedOptionValue:s.value,selectedOptionTitle:l?.title??``,selector:d,title:s.title}}).filter(qn)),o=si(e=>[e.product.attributes],e=>Object.values(e).map(e=>{let t=e.values.find(t=>t.name===e.value)??e.values[0];if(t?.description)return{attributeTitle:e.title,descriptionHTML:Yn(t.description),selectedValueTitle:t.titleLong}}).filter(Jn));function s(e){let t={designAreasSizes:e.designAreasSizes,qty:1,...St(e.product.attributes,e=>e.value)};return JSON.stringify(t)}let c=si(e=>[e.product.quantity,e.product.pricing],(t,r)=>{let i=r.unitPrice,a=i*t,o=ti(r),s=o*t,c=ei(r),l=c?.discountCode;return{discountLabel:c?.discountString,originalTotalPrice:n(a),originalUnitPrice:n(i),promoCode:l,showCompValue:e.region===`us`,totalPrice:n(s),unitPrice:n(o)}});function l(e){return e.product.productType}function u(e){return e.product.quantity}let d=si(e=>[e.product.pricing.discountProductItems,e.product.pricing,e.product.quantities,e.product.hasForcedQuantities,e.product.singularUnitLabel,e.product.pluralUnitLabel],(e,t,n,r,i,a)=>{let o=$r(e)?.discountPercent??0;return Ht(t.volumeDiscountTiers,n,r).map(e=>{let t=e.discount?.discountPercent&&(!o||o[e.product.realviews],e=>e.filter(e=>e.type===`Product`&&(e.media===`image`||e.media===`video`)).map(e=>{let n={id:e.id,title:e.title,url:ni(e,t.staticRealviewUrlBase(),{max_dim:128})};if(e.media===`image`)return{...n,type:`image`};{let r=(()=>{if(e.videoId)return Z(t.videoPag(`${e.videoId}_hd.mp4`));if(e.videoParams)return ni(e,t.staticRealviewUrlBase(),{max_dim:128},!0)})();return r?{...n,mp4Source:r,type:`video`}:void 0}}).filter(qn)),p=si(e=>[e.reviews?.stats.totalReviews,e.reviews?.stats.averageRating],(e,t)=>{if(!(e===void 0||t===void 0))return{count:e,rating:t}});function m(e){let t=f(e);return t.find(t=>t.id===e.product.preferredRealviewId)??t[0]}function h(t){return t.shippingEstimates?ri(t.shippingEstimates.estimates,(t,n)=>t.toLocaleDateString(e.culture,n)):``}function g(e){return e.product.title}function _(e){let t=e.product;return t.quantity===1?t.singularUnitLabel:t.pluralUnitLabel}return Vn(e=>{if(e.product)return{attributes:a(e),descriptionComponents:o(e),expressProductSettings:s(e),pricing:c(e),productType:l(e),quantity:u(e),quantityOptions:d(e),realviews:f(e),reviewsStats:p(e),selectedRealview:m(e),shippingEstimate:h(e),title:g(e),unitLabel:_(e)}})}function si(e,t){let n=Vn(t);return(...t)=>n(...e(...t))}var ci={at:`.at`,au:`.com.au`,be:`.be`,br:`.com.br`,ca:`.ca`,ch:`.ch`,de:`.de`,es:`.es`,fr:`.fr`,gb:`.co.uk`,jp:`.co.jp`,kr:`.co.kr`,nl:`.nl`,nz:`.co.nz`,pt:`.pt`,se:`.se`,us:`.com`},li={at:`EUR`,au:`AUD`,be:`EUR`,br:`BRL`,ca:`CAD`,ch:`CHF`,de:`EUR`,es:`EUR`,fr:`EUR`,gb:`GBP`,jp:`JPY`,kr:`KRW`,nl:`EUR`,nz:`NZD`,pt:`EUR`,se:`SEK`,us:`USD`},ui={at:`de`,au:`en`,be:`fr`,br:`pt`,ca:`en`,ch:`de`,de:`de`,es:`de`,fr:`fr`,gb:`en`,jp:`ja`,kr:`ko`,nl:`nl`,nz:`en`,pt:`pt`,se:`sv`,us:`en`},di={at:`Europe/Vienna`,au:`Australia/Sydney`,be:`Europe/Brussels`,br:`America/Sao_Paulo`,ca:`America/Toronto`,ch:`Europe/Zurich`,de:`Europe/Berlin`,es:`Europe/Madrid`,fr:`Europe/Paris`,gb:`Europe/London`,jp:`Asia/Tokyo`,kr:`Asia/Seoul`,nl:`Europe/Amsterdam`,nz:`Pacific/Auckland`,pt:`Europe/Lisbon`,se:`Europe/Stockholm`,us:`America/Los_Angeles`},fi={at:`metric`,au:`metric`,be:`metric`,br:`metric`,ca:`metric`,ch:`metric`,de:`metric`,es:`metric`,fr:`metric`,gb:`metric`,jp:`metric`,kr:`metric`,nl:`metric`,nz:`metric`,pt:`metric`,se:`metric`,us:`imperial`},pi=[`en-us`,`en-au`,`en-ca`,`en-gb`,`en-nz`,`de-at`,`de-ch`,`de-de`,`es-es`,`es-us`,`fr-be`,`fr-ca`,`fr-ch`,`fr-fr`,`ja-jp`,`nl-be`,`nl-nl`,`pt-br`,`pt-pt`,`sv-se`],mi=`en`,hi=`us`;function gi(e,t){let n=e?e.toLowerCase():hi,r=t?t.toLowerCase():mi,i=`${r}-${n}`;if(vi(i))return i;if(_i(n)){let e=ui[n];if(e){let t=`${e}-${n}`.toLowerCase();if(vi(t))return t}}return i=`${r}-${hi}`.toLowerCase(),vi(i)?i:`en-us`}function _i(e){return e in ui}function vi(e){return pi.includes(e)}function yi(e,t){return e.replace(`.*`,`${ci[t]}`)}function bi(e,t){let n=gi(e,t),[r,i]=n.split(`-`),a=yi(`rlv.zcache.*`,i),o=yi(`asset.zcache.*/vcc`,i),s=yi(`asset.zcache.*/assets/graphics`,i),c=yi(`www.zazzle.*`,i);return{culture:n,currency:li[i],language:r,region:i,staticRlvUrlBase:a,timezone:di[i],unit:fi[i],videoUrlBase:o,wwwAstBase:s,wwwUrlBase:c}}function xi(e){return{zcur:e.currency,lang:e.language,region:e.region}}function Si(e){function t(t,n,r,i=!0){return n=Ci(n),Z(`https://${t}/${n}`,{...i?xi(e):void 0,...r})}let n=(e=!0)=>o(`svc/getimage`,void 0,e),r=(e=!0)=>a(`svc/view`,void 0,e),i=(e=!0)=>o(`svc/view`,void 0,e);function a(e,t,n=!0){return e=Ci(e),c(`rlv/${e}`,t,n)}function o(n,r,i=!0){return t(e.staticRlvUrlBase,n,r,i)}function s(n,r,i=!0){return t(e.wwwAstBase,n,r,i)}function c(n,r,i=!0){return t(e.wwwUrlBase,n,r,i)}function l(n,r){return t(e.videoUrlBase,n,r,!1)}return{dynamicRealviewUrlBase:r,rlvPag:a,sRlvPag:o,staticRealviewGetImageBase:n,staticRealviewUrlBase:i,videoPag:l,wwwAst:s,wwwPag:c}}function Ci(e){return e.startsWith(`/`)?e.substring(1):e}function wi(e){let t=bi(e.region,e.language),n=Si(t),r=Er(n),i=ai(t,n),a=()=>i.internal.getSnapshot(),o=e=>i.internal.setState(e);return{env:{currency:t.currency,language:t.language,region:t.region},subscribe:e=>i.external.subscribe(e),getSnapshot:()=>i.external.getSnapshot(),async fetchProduct(e){let{designAreasSizes:t,entities:n,product:i}=await r.wwwGetProductFromTemplate(e);i.pricing=await r.wwwGetPricing({productId:i.id,productOptions:i.productOption}),o({designAreasSizes:t,entities:n,product:i,shippingEstimates:await r.wwwGetShippingEstimates({productId:i.id,productOptions:i.productOption,qty:i.quantity})})},async fetchSizeChart(){let e=a();if(!e.product)throw Error(`Product data is not available`);return await r.wwwGetHelpDialog({att:`size`,dialogType:`sizeChart`,po:e.product.productOption,pt:e.product.productType})},async selectOption(e,n){let i=a();if(!i.product)throw Error(`Product data is not available`);let s=i.product.attributes[e];if(!s||s.value===n||!s.values.some(e=>e.name===n))return;i=o({...i,product:{...i.product,attributes:{...i.product.attributes,[e]:{...s,value:n}}}});let c={...Gn.fromString(i.product.productOption),[e]:n},l=await r.wwwChangeOptions({preferredViewId:i.product.preferredRealviewId,productId:i.product.id,productOptions:Gn.toString(c)});i=a(),i=o({...i,product:{...i.product,...l}}),await Promise.all([(async()=>{let e=await r.wwwGetPricing({productId:i.product.id,productOptions:i.product.productOption,qty:i.product.quantity}),t=a();o({...t,product:{...t.product,pricing:e}})})(),(async()=>{if(!(t.region!==`us`&&t.region!==`gb`))try{let e=await r.wwwGetShippingEstimates({productId:i.product.rootProductId,productOptions:i.product.productOption,qty:i.product.quantity,zip:``});o({...a(),shippingEstimates:e})}catch(e){window.reportError(e)}})()])},async selectQuantity(e){let t=a();if(!t.product)throw Error(`Product data is not available`);e=Vt(e,t.product.minQuantity,t.product.maxQuantity,t.product.quantityIncrement);let{product:n}=t,i=n.pricing.volumeDiscountTiers?.find(e=>e.minQuantity<=n.quantity&&n.quantity<=e.maxQuantity),s=n.pricing.volumeDiscountTiers?.find(t=>t.minQuantity<=e&&e<=t.maxQuantity);(i===s||!i?.hasDiscount&&!s?.hasDiscount)&&(t=o({...t,product:{...t.product,quantity:e}}));let c=await r.wwwGetPricing({productId:t.product.id,productOptions:t.product.productOption,qty:e});t=a(),o({...t,product:{...t.product,pricing:c,quantity:e}})},async selectRealview(e){let t=a();if(!t.product)throw Error(`Product data is not available`);if(t.product.preferredRealviewId===e||!t.product.realviews.some(t=>t.id===e))return;t=a(),t=o({...t,product:{...t.product,preferredRealviewId:e}});let n=await r.wwwChangeOptions({preferredViewId:t.product.preferredRealviewId,productId:t.product.id,productOptions:t.product.productOption});t=a(),o({...t,product:{...t.product,...n}})}}}var Ti=wi;export{wi as createZazzlePDPStore,Ti as default};
+//# sourceMappingURL=index.js.map
\ No newline at end of file
diff --git a/express/code/blocks/print-product-detail-sdk/utilities/sample_state.json b/express/code/blocks/print-product-detail-sdk/utilities/sample_state.json
new file mode 100644
index 000000000..71c5360a3
--- /dev/null
+++ b/express/code/blocks/print-product-detail-sdk/utilities/sample_state.json
@@ -0,0 +1,275 @@
+{
+ "state": {
+ "attributes": [
+ {
+ "name": "cornerstyle",
+ "selectedOptionValue": "normal",
+ "selectedOptionTitle": "Squared",
+ "selector": {
+ "optionGroups": [
+ {
+ "options": [
+ {
+ "imageUrl": "https://rlv.zcache.com/svc/view?zcur=USD&lang=en®ion=us&rlvnet=1&realview=113474916875736696&cornerstyle=normal&max_dim=48",
+ "title": "Squared",
+ "value": "normal"
+ },
+ {
+ "imageUrl": "https://rlv.zcache.com/svc/view?zcur=USD&lang=en®ion=us&rlvnet=1&realview=113474916875736696&cornerstyle=allrounded&max_dim=48",
+ "priceDelta": "+$5.35",
+ "title": "Rounded",
+ "value": "allrounded"
+ }
+ ],
+ "title": ""
+ }
+ ],
+ "type": "thumbnails"
+ },
+ "title": "Corner Style"
+ },
+ {
+ "name": "media",
+ "selectedOptionValue": "175ptmatte",
+ "selectedOptionTitle": "Signature Matte",
+ "selector": {
+ "optionGroups": [
+ {
+ "options": [
+ {
+ "imageUrl": "https://rlv.zcache.com/svc/view?zcur=USD&lang=en®ion=us&rlvnet=1&realview=113055797571919632&media=175ptmatte&max_dim=48",
+ "title": "Signature Matte",
+ "value": "175ptmatte"
+ },
+ {
+ "imageUrl": "https://rlv.zcache.com/svc/view?zcur=USD&lang=en®ion=us&rlvnet=1&realview=113055797571919632&media=16ptsemi&max_dim=48",
+ "title": "Standard Semi-Gloss",
+ "value": "16ptsemi"
+ },
+ {
+ "imageUrl": "https://rlv.zcache.com/svc/view?zcur=USD&lang=en®ion=us&rlvnet=1&realview=113055797571919632&media=18ptsemi_gloss&max_dim=48",
+ "priceDelta": "+$4.50",
+ "title": "Signature UV Gloss",
+ "value": "18ptsemi_gloss"
+ },
+ {
+ "imageUrl": "https://rlv.zcache.com/svc/view?zcur=USD&lang=en®ion=us&rlvnet=1&realview=113055797571919632&media=18ptsemi_matte&max_dim=48",
+ "priceDelta": "+$4.50",
+ "title": "Signature UV Matte",
+ "value": "18ptsemi_matte"
+ },
+ {
+ "imageUrl": "https://rlv.zcache.com/svc/view?zcur=USD&lang=en®ion=us&rlvnet=1&realview=113055797571919632&media=16ptcream&max_dim=48",
+ "priceDelta": "+$4.50",
+ "title": "Signature Cream",
+ "value": "16ptcream"
+ },
+ {
+ "imageUrl": "https://rlv.zcache.com/svc/view?zcur=USD&lang=en®ion=us&rlvnet=1&realview=113055797571919632&media=18ptsemi_softtouch&max_dim=48",
+ "priceDelta": "+$8.95",
+ "title": "Premium Silk",
+ "value": "18ptsemi_softtouch"
+ },
+ {
+ "imageUrl": "https://rlv.zcache.com/svc/view?zcur=USD&lang=en®ion=us&rlvnet=1&realview=113055797571919632&media=16ptlinen&max_dim=48",
+ "priceDelta": "+$8.95",
+ "title": "Premium Linen",
+ "value": "16ptlinen"
+ },
+ {
+ "imageUrl": "https://rlv.zcache.com/svc/view?zcur=USD&lang=en®ion=us&rlvnet=1&realview=113055797571919632&media=16ptpearl&max_dim=48",
+ "priceDelta": "+$8.95",
+ "title": "Premium Pearl",
+ "value": "16ptpearl"
+ },
+ {
+ "imageUrl": "https://rlv.zcache.com/svc/view?zcur=USD&lang=en®ion=us&rlvnet=1&realview=113055797571919632&media=18ptkraft&max_dim=48",
+ "priceDelta": "+$8.95",
+ "title": "Premium Kraft",
+ "value": "18ptkraft"
+ },
+ {
+ "imageUrl": "https://rlv.zcache.com/svc/view?zcur=USD&lang=en®ion=us&rlvnet=1&realview=113055797571919632&media=16ptpewtergray&max_dim=48",
+ "priceDelta": "+$8.95",
+ "title": "Premium Grey",
+ "value": "16ptpewtergray"
+ },
+ {
+ "imageUrl": "https://rlv.zcache.com/svc/view?zcur=USD&lang=en®ion=us&rlvnet=1&realview=113055797571919632&media=16ptblack&max_dim=48",
+ "priceDelta": "+$8.95",
+ "title": "Premium Black",
+ "value": "16ptblack"
+ },
+ {
+ "imageUrl": "https://rlv.zcache.com/svc/view?zcur=USD&lang=en®ion=us&rlvnet=1&realview=113055797571919632&media=32ptultrathick&max_dim=48",
+ "priceDelta": "+$16.90",
+ "title": "Premium Thick",
+ "value": "32ptultrathick"
+ }
+ ],
+ "title": ""
+ }
+ ],
+ "preview": {
+ "descriptionHTML": "18 pt thickness / 120 lb weight Light eggshell white, uncoated matte finish
",
+ "imageUrl": "https://rlv.zcache.com/svc/view?zcur=USD&lang=en®ion=us&rlvnet=1&realview=113055797571919632&media=175ptmatte&max_dim=192",
+ "optionTitle": "Signature Matte"
+ },
+ "type": "thumbnails"
+ },
+ "title": "Paper"
+ }
+ ],
+ "descriptionComponents": [
+ {
+ "attributeTitle": "Size",
+ "descriptionHTML": "When it comes to your business, don't wait for opportunity, create it! Make a lasting impression with quality cards that WOW.
\n\nDimensions: 3.5\" x 2.0\" \nFull color CMYK print process \nDouble sided printing for no additional cost \n100% satisfaction guarantee \n ",
+ "selectedValueTitle": "Standard, 3.5\" x 2.0\""
+ },
+ {
+ "attributeTitle": "Paper",
+ "descriptionHTML": "Signature Matte is our best-selling paper—timeless, elegant, and crafted for a premium feel. With its softly textured, uncoated matte finish and sturdy 18 point thickness, it delivers a refined look and lasting impression. Made exclusively for Zazzle by Neenah, it blends print clarity, sustainability, and elevated style.
Light white, uncoated matte finish with an eggshell texture Thick, premium-quality stock with a substantial feel (18 pt) Ideal for writing—won't smudge or smear Made with 30% post-consumer waste Made and printed in the USA ",
+ "selectedValueTitle": "Signature Matte"
+ }
+ ],
+ "expressProductSettings": "{\"designAreasSizes\":\"[3.5,2,3.5,2]\",\"qty\":1,\"style\":\"3.5x2\",\"cornerstyle\":\"normal\",\"media\":\"175ptmatte\",\"printquality\":\"4color\",\"envelopes\":\"none\"}",
+ "pricing": {
+ "discountLabel": "You save 15%",
+ "originalTotalPrice": "$23.15",
+ "originalUnitPrice": "$23.15",
+ "promoCode": "ZCLASSOF2026",
+ "showCompValue": true,
+ "totalPrice": "$19.68",
+ "unitPrice": "$19.68"
+ },
+ "productType": "zazzle_businesscard",
+ "quantity": 1,
+ "quantityOptions": [
+ {
+ "label": "1 pack of 100",
+ "quantity": 1
+ },
+ {
+ "discount": "20%",
+ "label": "2 packs of 100",
+ "quantity": 2
+ },
+ {
+ "discount": "30%",
+ "label": "3 packs of 100",
+ "quantity": 3
+ },
+ {
+ "discount": "40%",
+ "label": "4 packs of 100",
+ "quantity": 4
+ },
+ {
+ "discount": "50%",
+ "label": "5 packs of 100",
+ "quantity": 5
+ },
+ {
+ "discount": "55%",
+ "label": "6 packs of 100",
+ "quantity": 6
+ },
+ {
+ "discount": "65%",
+ "label": "10 packs of 100",
+ "quantity": 10
+ },
+ {
+ "discount": "68%",
+ "label": "20 packs of 100",
+ "quantity": 20
+ },
+ {
+ "discount": "68%",
+ "label": "50 packs of 100",
+ "quantity": 50
+ },
+ {
+ "discount": "68%",
+ "label": "100 packs of 100",
+ "quantity": 100
+ },
+ {
+ "discount": "68%",
+ "label": "200 packs of 100",
+ "quantity": 200
+ },
+ {
+ "discount": "68%",
+ "label": "500 packs of 100",
+ "quantity": 500
+ }
+ ],
+ "realviews": [
+ {
+ "id": "113335724526596936",
+ "title": "Front",
+ "url": "https://rlv.zcache.com/svc/view?zcur=USD&lang=en®ion=us&realview=113335724526596936&design=62f85318-d828-459c-9801-c31232b624b5&style=3.5x2&media=175ptmatte&cornerstyle=normal&envelopes=none&max_dim=128&zattribution=none",
+ "type": "image"
+ },
+ {
+ "id": "113466622742179623",
+ "title": "Back",
+ "url": "https://rlv.zcache.com/svc/view?zcur=USD&lang=en®ion=us&realview=113466622742179623&design=62f85318-d828-459c-9801-c31232b624b5&style=3.5x2&media=175ptmatte&cornerstyle=normal&envelopes=none&max_dim=128&zattribution=none",
+ "type": "image"
+ },
+ {
+ "id": "113337099578326473",
+ "title": "Standing Front",
+ "url": "https://rlv.zcache.com/svc/view?zcur=USD&lang=en®ion=us&realview=113337099578326473&design=62f85318-d828-459c-9801-c31232b624b5&style=3.5x2&media=175ptmatte&cornerstyle=normal&envelopes=none&max_dim=128&zattribution=none",
+ "type": "image"
+ },
+ {
+ "id": "113908836188368045",
+ "title": "Front/Back",
+ "url": "https://rlv.zcache.com/svc/view?zcur=USD&lang=en®ion=us&realview=113908836188368045&design=62f85318-d828-459c-9801-c31232b624b5&style=3.5x2&media=175ptmatte&cornerstyle=normal&envelopes=none&max_dim=128&zattribution=none",
+ "type": "image"
+ },
+ {
+ "id": "113643097329661494",
+ "title": "Front/Back In Situ",
+ "url": "https://rlv.zcache.com/svc/view?zcur=USD&lang=en®ion=us&realview=113643097329661494&design=62f85318-d828-459c-9801-c31232b624b5&style=3.5x2&media=175ptmatte&cornerstyle=normal&envelopes=none&istype=lightwood_pprclip_black&max_dim=128&zattribution=none",
+ "type": "image"
+ },
+ {
+ "id": "113099207059102382",
+ "title": "Paper Corner",
+ "url": "https://rlv.zcache.com/svc/view?zcur=USD&lang=en®ion=us&realview=113099207059102382&design=62f85318-d828-459c-9801-c31232b624b5&rlvnet=1&max_dim=128",
+ "type": "image"
+ }
+ ],
+ "selectedRealview": {
+ "id": "113335724526596936",
+ "title": "Front",
+ "url": "https://rlv.zcache.com/svc/view?zcur=USD&lang=en®ion=us&realview=113335724526596936&design=62f85318-d828-459c-9801-c31232b624b5&style=3.5x2&media=175ptmatte&cornerstyle=normal&envelopes=none&max_dim=128&zattribution=none",
+ "type": "image"
+ },
+ "shippingEstimate": "Apr 6 - 10",
+ "title": "Black and Gold Designer Business Card",
+ "unitLabel": "pack of 100"
+ },
+ "actions": {
+ "env": {
+ "currency": "USD",
+ "language": "en",
+ "region": "us"
+ }
+ },
+ "env": {
+ "currency": "USD",
+ "language": "en",
+ "region": "us"
+ },
+ "sdk": {
+ "env": {
+ "currency": "USD",
+ "language": "en",
+ "region": "us"
+ }
+ }
+}
diff --git a/express/code/blocks/print-product-detail-sdk/utilities/utility-functions.js b/express/code/blocks/print-product-detail-sdk/utilities/utility-functions.js
new file mode 100644
index 000000000..0687d6563
--- /dev/null
+++ b/express/code/blocks/print-product-detail-sdk/utilities/utility-functions.js
@@ -0,0 +1,183 @@
+import { getLibs, createTag } from '../../../scripts/utils.js';
+
+export function formatPaperThickness(thickness) {
+ const thicknessFormatted = `${thickness.replace('_', '.')}pt thickness`;
+ return thicknessFormatted;
+}
+
+export function formatPaperWeight(weight) {
+ const [weightValue, gsmValue] = weight.split('lb');
+ const weightFormatted = `${weightValue}lb weight`;
+ const gsmFormatted = gsmValue?.replace('gsm', ' GSM');
+ return { weight: weightFormatted, gsm: gsmFormatted };
+}
+
+export function extractTemplateId(block) {
+ const templateIdBlock = block.children[0].children[1].textContent;
+ const urlParams = new URLSearchParams(window.location.search);
+ const templateIdURL = urlParams.get('templateId');
+ const templateId = templateIdURL || templateIdBlock;
+ return templateId;
+}
+
+export function formatDeliveryEstimateDateRange(minDate, maxDate) {
+ const options = { month: 'short', day: 'numeric' };
+ const minFormatted = new Date(minDate).toLocaleDateString('en-US', options);
+ const maxFormatted = new Date(maxDate).toLocaleDateString('en-US', options);
+ return `${minFormatted} - ${maxFormatted}`;
+}
+
+export function formatLargeNumberToK(totalReviews) {
+ if (totalReviews > 1000) {
+ const hundreds = Math.round((totalReviews % 1000) / 100);
+ if (hundreds === 0) {
+ return `${Math.round(totalReviews / 1000)}k`;
+ }
+ return `${Math.round(totalReviews / 1000)}.${Math.round((totalReviews % 1000) / 100)}k`;
+ }
+ return String(totalReviews);
+}
+
+export function exchangeRegionForTopLevelDomain(region) {
+ const urlParams = new URLSearchParams(window.location.search);
+ const regionURL = urlParams.get('region');
+ const regionFinal = regionURL || region;
+ const regionToTopLevelDomainMap = {
+ 'en-GB': 'co.uk',
+ 'en-US': 'com',
+ 'en-CA': 'ca',
+ 'en-AU': 'au',
+ 'en-NZ': 'nz',
+ };
+ const topLevelDomain = regionToTopLevelDomainMap[regionFinal] || 'com';
+ return topLevelDomain;
+}
+
+export async function formatPriceZazzle(price, differential = false) {
+ const { getCountry } = await import('../../../scripts/utils/location-utils.js');
+ const country = await getCountry();
+ const { getCurrency, formatPrice } = await import('../../../scripts/utils/pricing.js');
+ const currency = await getCurrency(country);
+ const urlParams = new URLSearchParams(window.location.search);
+ const region = urlParams.get('region');
+ const currencyMap = {
+ 'en-GB': 'GBP',
+ 'en-US': 'USD',
+ 'en-CA': 'CAD',
+ 'en-AU': 'AUD',
+ 'en-NZ': 'NZD',
+ };
+ const currencyFinal = currencyMap[region] || currency;
+ let priceDifferentialOperator;
+ const localizedPrice = await formatPrice(price, currencyFinal);
+ if (differential) {
+ priceDifferentialOperator = price >= 0 ? '+' : '';
+ } else {
+ priceDifferentialOperator = '';
+ }
+ const formattedPrice = priceDifferentialOperator + localizedPrice;
+ return formattedPrice;
+}
+
+const ALLOWED_TAGS = new Set([
+ 'p', 'br', 'strong', 'em', 'b', 'i', 'u', 'ul', 'ol', 'li', 'span', 'div', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
+]);
+
+function cleanNode(node, doc) {
+ const fragment = doc.createDocumentFragment();
+ node.childNodes.forEach((child) => {
+ if (child.nodeType === Node.TEXT_NODE) {
+ fragment.appendChild(doc.createTextNode(child.textContent));
+ } else if (child.nodeType === Node.ELEMENT_NODE) {
+ if (ALLOWED_TAGS.has(child.tagName.toLowerCase())) {
+ const el = doc.createElement(child.tagName.toLowerCase());
+ el.appendChild(cleanNode(child, doc));
+ fragment.appendChild(el);
+ } else {
+ fragment.appendChild(cleanNode(child, doc));
+ }
+ }
+ });
+ return fragment;
+}
+
+export function sanitizeHtml(html) {
+ if (!html) return '';
+ const doc = new DOMParser().parseFromString(html, 'text/html');
+ const cleaned = cleanNode(doc.body, document);
+ const wrapper = document.createElement('div');
+ wrapper.appendChild(cleaned);
+ return wrapper.innerHTML;
+}
+
+export function formatStringSnakeCase(string) {
+ const normalizedString = string.replace(/[^a-zA-Z0-9\s]/g, '_');
+ const formattedString = normalizedString.trim().toLowerCase().replace(/ /g, '_');
+ return formattedString;
+}
+
+export async function addPrefetchLinks() {
+ const { getConfig } = await import(`${getLibs()}/utils/utils.js`);
+ const { ietf } = getConfig().locale;
+ const topLevelDomain = exchangeRegionForTopLevelDomain(ietf);
+ const prefetchLink1 = createTag('link', {
+ rel: 'dns-prefetch',
+ href: `https://www.zazzle.${topLevelDomain}`,
+ });
+ const prefetchLink2 = createTag('link', {
+ rel: 'dns-prefetch',
+ href: `https://rlv.zcache.${topLevelDomain}`,
+ });
+
+ const preconnectLink1 = createTag('link', {
+ rel: 'preconnect',
+ href: `https://www.zazzle.${topLevelDomain}`,
+ });
+ const preconnectLink2 = createTag('link', {
+ rel: 'preconnect',
+ href: `https://rlv.zcache.${topLevelDomain}`,
+ });
+ document.head.appendChild(prefetchLink1);
+ document.head.appendChild(prefetchLink2);
+ document.head.appendChild(preconnectLink1);
+ document.head.appendChild(preconnectLink2);
+}
+
+function normalizeLocale(ietf) {
+ const SUPPORTED_REGIONS = new Set(['at', 'br', 'us', 'au', 'ca', 'gb', 'nz', 'de', 'ch', 'es', 'fr', 'be', 'jp', 'kr', 'nl', 'pt', 'se']);
+ const SUPPORTED_LANGUAGES = new Set(['en', 'de', 'es', 'fr', 'ja', 'ko', 'nl', 'pt', 'sv']);
+ if (!ietf) {
+ return { language: 'en', region: 'us' };
+ }
+
+ const [languageRaw = 'en', regionRaw = 'us'] = ietf.split('-');
+ const language = languageRaw.toLowerCase();
+ const region = regionRaw.toLowerCase();
+
+ return {
+ language: SUPPORTED_LANGUAGES.has(language) ? language : 'en',
+ region: SUPPORTED_REGIONS.has(region) ? region : 'us',
+ };
+}
+
+let storePromise = null;
+export async function createZazzleStore() {
+ if (storePromise) return storePromise;
+ storePromise = (async () => {
+ const [{ createZazzlePDPStore }, { getConfig }] = await Promise.all([
+ import('../sdk/index.min.js'),
+ import(`${getLibs()}/utils/utils.js`),
+ ]);
+
+ const { locale } = getConfig();
+ const { language, region } = normalizeLocale(locale?.ietf);
+
+ const store = createZazzlePDPStore({ language, region });
+
+ return {
+ env: store.env,
+ sdk: store,
+ };
+ })();
+ return storePromise;
+}
diff --git a/express/code/scripts/vendors/htm-preact.min.js b/express/code/scripts/vendors/htm-preact.min.js
new file mode 100644
index 000000000..3b8422e76
--- /dev/null
+++ b/express/code/scripts/vendors/htm-preact.min.js
@@ -0,0 +1 @@
+var _,n,e,t,o,r,u,l,i,c,f,s,a={},p=[],h=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,d=Array.isArray;function v(_,n){for(var e in n)_[e]=n[e];return _}function m(_){_&&_.parentNode&&_.parentNode.removeChild(_)}function y(n,e,t){var o,r,u,l={};for(u in e)"key"==u?o=e[u]:"ref"==u?r=e[u]:l[u]=e[u];if(arguments.length>2&&(l.children=arguments.length>3?_.call(arguments,2):t),"function"==typeof n&&null!=n.defaultProps)for(u in n.defaultProps)void 0===l[u]&&(l[u]=n.defaultProps[u]);return g(n,l,o,r,null)}function g(_,t,o,r,u){var l={type:_,props:t,key:o,ref:r,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:null==u?++e:u,__i:-1,__u:0};return null==u&&null!=n.vnode&&n.vnode(l),l}function b(){return{current:null}}function k(_){return _.children}function w(_,n){this.props=_,this.context=n}function C(_,n){if(null==n)return _.__?C(_.__,_.__i+1):null;for(var e;n<_.__k.length;n++)if(null!=(e=_.__k[n])&&null!=e.__e)return e.__e;return"function"==typeof _.type?C(_):null}function x(_){var n,e;if(null!=(_=_.__)&&null!=_.__c){for(_.__e=_.__c.base=null,n=0;n<_.__k.length;n++)if(null!=(e=_.__k[n])&&null!=e.__e){_.__e=_.__c.base=e.__e;break}return x(_)}}function H(_){(!_.__d&&(_.__d=!0)&&t.push(_)&&!E.__r++||o!=n.debounceRendering)&&((o=n.debounceRendering)||r)(E)}function E(){for(var _,e,o,r,l,i,c,f=1;t.length;)t.length>f&&t.sort(u),_=t.shift(),f=t.length,_.__d&&(o=void 0,r=void 0,l=(r=(e=_).__v).__e,i=[],c=[],e.__P&&((o=v({},r)).__v=r.__v+1,n.vnode&&n.vnode(o),M(e.__P,o,r,e.__n,e.__P.namespaceURI,32&r.__u?[l]:null,i,null==l?C(r):l,!!(32&r.__u),c),o.__v=r.__v,o.__.__k[o.__i]=o,W(i,o,c),r.__e=r.__=null,o.__e!=l&&x(o)));E.__r=0}function S(_,n,e,t,o,r,u,l,i,c,f){var s,h,v,m,y,b,w,x=t&&t.__k||p,H=n.length;for(i=function(_,n,e,t,o){var r,u,l,i,c,f=e.length,s=f,a=0;for(_.__k=new Array(o),r=0;r0?u=_.__k[r]=g(u.type,u.props,u.key,u.ref?u.ref:null,u.__v):_.__k[r]=u,i=r+a,u.__=_,u.__b=_.__b+1,l=null,-1!=(c=u.__i=U(u,e,i,s))&&(s--,(l=e[c])&&(l.__u|=2)),null==l||null==l.__v?(-1==c&&(o>f?a--:oi?a--:a++,u.__u|=4))):_.__k[r]=null;if(s)for(r=0;r(f?1:0))for(o=e-1,r=e+1;o>=0||r=0?o--:r++])&&!(2&c.__u)&&l==c.key&&i==c.type)return u;return-1}function N(_,n,e){"-"==n[0]?_.setProperty(n,null==e?"":e):_[n]=null==e?"":"number"!=typeof e||h.test(n)?e:e+"px"}function D(_,n,e,t,o){var r,u;_:if("style"==n)if("string"==typeof e)_.style.cssText=e;else{if("string"==typeof t&&(_.style.cssText=t=""),t)for(n in t)e&&n in e||N(_.style,n,"");if(e)for(n in e)t&&e[n]==t[n]||N(_.style,n,e[n])}else if("o"==n[0]&&"n"==n[1])r=n!=(n=n.replace(l,"$1")),u=n.toLowerCase(),n=u in _||"onFocusOut"==n||"onFocusIn"==n?u.slice(2):n.slice(2),_.l||(_.l={}),_.l[n+r]=e,e?t?e.u=t.u:(e.u=i,_.addEventListener(n,r?f:c,r)):_.removeEventListener(n,r?f:c,r);else{if("http://www.w3.org/2000/svg"==o)n=n.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if("width"!=n&&"height"!=n&&"href"!=n&&"list"!=n&&"form"!=n&&"tabIndex"!=n&&"download"!=n&&"rowSpan"!=n&&"colSpan"!=n&&"role"!=n&&"popover"!=n&&n in _)try{_[n]=null==e?"":e;break _}catch(_){}"function"==typeof e||(null==e||!1===e&&"-"!=n[4]?_.removeAttribute(n):_.setAttribute(n,"popover"==n&&1==e?"":e))}}function T(_){return function(e){if(this.l){var t=this.l[e.type+_];if(null==e.t)e.t=i++;else if(e.t0?_:d(_)?_.map(A):v({},_)}function L(e,t,o,r,u,l,i,c,f){var s,p,h,v,y,g,b,k=o.props||a,w=t.props,x=t.type;if("svg"==x?u="http://www.w3.org/2000/svg":"math"==x?u="http://www.w3.org/1998/Math/MathML":u||(u="http://www.w3.org/1999/xhtml"),null!=l)for(s=0;s=e.__.length&&e.__.push({}),e.__[_]}function t_(_){return G=1,o_(b_,_)}function o_(_,n,e){var t=e_(q++,2);if(t.t=_,!t.__c&&(t.__=[e?e(n):b_(void 0,n),function(_){var n=t.__N?t.__N[0]:t.__[0],e=t.t(n,_);n!==e&&(t.__N=[e,t.__[1]],t.__c.setState({}))}],t.__c=B,!B.__f)){var o=function(_,n,e){if(!t.__c.__H)return!0;var o=t.__c.__H.__.filter(function(_){return!!_.__c});if(o.every(function(_){return!_.__N}))return!r||r.call(this,_,n,e);var u=t.__c.props!==_;return o.forEach(function(_){if(_.__N){var n=_.__[0];_.__=_.__N,_.__N=void 0,n!==_.__[0]&&(u=!0)}}),r&&r.call(this,_,n,e)||u};B.__f=!0;var r=B.shouldComponentUpdate,u=B.componentWillUpdate;B.componentWillUpdate=function(_,n,e){if(this.__e){var t=r;r=void 0,o(_,n,e),r=t}u&&u.call(this,_,n,e)},B.shouldComponentUpdate=o}return t.__N||t.__}function r_(_,n){var e=e_(q++,3);!K.__s&&g_(e.__H,n)&&(e.__=_,e.u=n,B.__H.__h.push(e))}function u_(_,n){var e=e_(q++,4);!K.__s&&g_(e.__H,n)&&(e.__=_,e.u=n,B.__h.push(e))}function l_(_){return G=5,i_(function(){return{current:_}},[])}function i_(_,n){var e=e_(q++,7);return g_(e.__H,n)&&(e.__=_(),e.__H=n,e.__h=_),e.__}function c_(_,n){return G=8,i_(function(){return _},n)}function f_(_){var n=B.context[_.__c],e=e_(q++,9);return e.c=_,n?(null==e.__&&(e.__=!0,n.sub(B)),n.props.value):_.__}function s_(_,n){K.useDebugValue&&K.useDebugValue(n?n(_):_)}function a_(_){var n=e_(q++,10),e=t_();return n.__=_,B.componentDidCatch||(B.componentDidCatch=function(_,t){n.__&&n.__(_,t),e[1](_)}),[e[0],function(){e[1](void 0)}]}function p_(){var _=e_(q++,11);if(!_.__){for(var n=B.__v;null!==n&&!n.__m&&null!==n.__;)n=n.__;var e=n.__m||(n.__m=[0,0]);_.__="P"+e[0]+"-"+e[1]++}return _.__}function h_(){for(var _;_=J.shift();)if(_.__P&&_.__H)try{_.__H.__h.forEach(m_),_.__H.__h.forEach(y_),_.__H.__h=[]}catch(n){_.__H.__h=[],K.__e(n,_.__v)}}K.__b=function(_){B=null,Q&&Q(_)},K.__=function(_,n){_&&n.__k&&n.__k.__m&&(_.__m=n.__k.__m),n_&&n_(_,n)},K.__r=function(_){X&&X(_),q=0;var n=(B=_.__c).__H;n&&(V===B?(n.__h=[],B.__h=[],n.__.forEach(function(_){_.__N&&(_.__=_.__N),_.u=_.__N=void 0})):(n.__h.forEach(m_),n.__h.forEach(y_),n.__h=[],q=0)),V=B},K.diffed=function(_){Y&&Y(_);var n=_.__c;n&&n.__H&&(n.__H.__h.length&&(1!==J.push(n)&&z===K.requestAnimationFrame||((z=K.requestAnimationFrame)||v_)(h_)),n.__H.__.forEach(function(_){_.u&&(_.__H=_.u),_.u=void 0})),V=B=null},K.__c=function(_,n){n.some(function(_){try{_.__h.forEach(m_),_.__h=_.__h.filter(function(_){return!_.__||y_(_)})}catch(e){n.some(function(_){_.__h&&(_.__h=[])}),n=[],K.__e(e,_.__v)}}),Z&&Z(_,n)},K.unmount=function(_){__&&__(_);var n,e=_.__c;e&&e.__H&&(e.__H.__.forEach(function(_){try{m_(_)}catch(_){n=_}}),e.__H=void 0,n&&K.__e(n,e.__v))};var d_="function"==typeof requestAnimationFrame;function v_(_){var n,e=function(){clearTimeout(t),d_&&cancelAnimationFrame(n),setTimeout(_)},t=setTimeout(e,35);d_&&(n=requestAnimationFrame(e))}function m_(_){var n=B,e=_.__c;"function"==typeof e&&(_.__c=void 0,e()),B=n}function y_(_){var n=B;_.__c=_.__(),B=n}function g_(_,n){return!_||_.length!==n.length||n.some(function(n,e){return n!==_[e]})}function b_(_,n){return"function"==typeof n?n(_):n}var k_=function(_,n,e,t){var o;n[0]=0;for(var r=1;rn());return u_(()=>{function e(){const _=n();t(n=>Object.is(n,_)?n:_)}return e(),_(e)},[_,n]),s_(e),e}const x_=function(_){var n=w_.get(this);return n||(n=new Map,w_.set(this,n)),(n=k_(this,n.get(_)||(n.set(_,n=function(_){for(var n,e,t=1,o="",r="",u=[0],l=function(_){1===t&&(_||(o=o.replace(/^\s*\n\s*|\s*\n\s*$/g,"")))?u.push(0,_,o):3===t&&(_||o)?(u.push(3,_,o),t=2):2===t&&"..."===o&&_?u.push(4,_,0):2===t&&o&&!_?u.push(5,0,!0,o):t>=5&&((o||!_&&5===t)&&(u.push(t,0,o,e),t=6),_&&(u.push(t,_,0,e),t=6)),o=""},i=0;i<_.length;i++){i&&(1===t&&l(),l(i));for(var c=0;c<_[i].length;c++)n=_[i][c],1===t?"<"===n?(l(),u=[u],t=3):o+=n:4===t?"--"===o&&">"===n?(t=1,o=""):o=n+o[0]:r?n===r?r="":o+=n:'"'===n||"'"===n?r=n:">"===n?(l(),t=1):t&&("="===n?(t=5,e=o,o=""):"/"===n&&(t<5||">"===_[i][c+1])?(l(),3===t&&(u=u[0]),t=u,(u=u[0]).push(2,0,t),t=0):" "===n||"\t"===n||"\n"===n||"\r"===n?(l(),t=2):o+=n),3===t&&"!--"===o&&(t=4,u=u[0])}return l(),u}(_)),n),arguments,[])).length>1?n:n[0]}.bind(y);export{w as Component,k as Fragment,j as createContext,b as createRef,y as h,x_ as html,O as render,c_ as useCallback,f_ as useContext,s_ as useDebugValue,r_ as useEffect,a_ as useErrorBoundary,p_ as useId,u_ as useLayoutEffect,i_ as useMemo,o_ as useReducer,l_ as useRef,t_ as useState,C_ as useSyncExternalStore};
diff --git a/package.json b/package.json
index 5017e3e2c..ba30389f0 100644
--- a/package.json
+++ b/package.json
@@ -88,4 +88,4 @@
"@spectrum-web-components/tags": "^1.11.0",
"@spectrum-web-components/toast": "^1.11.0"
}
-}
+}
\ No newline at end of file