@lime-bundles/react 7.2.0 → 7.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/components/FixedBundle.tsx","../src/hooks/useBundleData.ts","../src/fetchBundleData.ts","../src/fetchShopSettings.ts","../src/hooks/useAnalytics.ts","../src/hooks/useWidgetConfigVars.ts","../src/hooks/useVariantSelection.ts","../src/hooks/useEdgeFade.ts","../src/components/VariantDropdown.tsx","../src/components/BundleCountdown.tsx","../src/components/MixMatchBundle.tsx","../src/components/MixMatchPicker.tsx","../src/hooks/useScrollLock.ts","../src/hooks/useFocusTrap.ts","../src/components/VolumeBundle.tsx","../src/components/BogoBundle.tsx","../src/components/MultiStepBundle.tsx","../src/components/MultiStepPicker.tsx","../src/fetchShopCustomCss.ts","../src/hooks/useBundlesForProduct.ts"],"sourcesContent":["// Bundle components — BYO-cart via `onAddToCart`.\nexport { FixedBundle } from \"./components/FixedBundle\";\nexport {\n MixMatchBundle,\n type MixMatchBundleProps,\n} from \"./components/MixMatchBundle\";\nexport {\n BundleCountdown,\n type BundleCountdownProps,\n} from \"./components/BundleCountdown\";\nexport { VolumeBundle } from \"./components/VolumeBundle\";\nexport { BogoBundle } from \"./components/BogoBundle\";\nexport { MultiStepBundle } from \"./components/MultiStepBundle\";\nexport type { BundleComponentProps } from \"./components/types\";\n\n// Variant picker primitives — composable for merchants who want to build\n// their own bundle UI on top of `useBundleData` while reusing the same\n// accessible custom dropdown.\nexport {\n VariantDropdown,\n type VariantDropdownProps,\n type VariantDropdownOption,\n} from \"./components/VariantDropdown\";\nexport {\n useVariantSelection,\n type UseVariantSelectionOptions,\n type UseVariantSelectionResult,\n} from \"./hooks/useVariantSelection\";\n\n// Data fetching\nexport {\n fetchBundleData,\n type FetchBundleDataOptions,\n} from \"./fetchBundleData\";\nexport {\n fetchShopSettings,\n fetchShopSettingsOrDefault,\n type FetchShopSettingsOptions,\n type ShopSettings,\n} from \"./fetchShopSettings\";\n/** @deprecated Superseded by `fetchShopSettings`; kept for compatibility. */\nexport {\n fetchShopCustomCss,\n type FetchShopCustomCssOptions,\n} from \"./fetchShopCustomCss\";\nexport {\n useBundleData,\n type UseBundleDataOptions,\n type UseBundleDataResult,\n} from \"./hooks/useBundleData\";\nexport {\n useBundlesForProduct,\n type UseBundlesForProductOptions,\n type UseBundlesForProductResult,\n} from \"./hooks/useBundlesForProduct\";\nexport { useAnalytics } from \"./hooks/useAnalytics\";\nexport { useWidgetConfigVars } from \"./hooks/useWidgetConfigVars\";\n\n// Re-export core types consumers commonly need.\nexport type {\n ParsedBundle,\n FixedBundleData,\n VolumeBundleData,\n MixMatchBundleData,\n BogoBundleData,\n MultiStepBundleData,\n ParsedMultiStep,\n BundleType,\n Product,\n ProductVariant,\n CartLineInput,\n WidgetConfig,\n HeaderConfig,\n LayoutConfig,\n ProductListConfig,\n ThumbnailRatio,\n PricingConfig,\n SavingsBarConfig,\n CtaConfig,\n CountdownConfig,\n PopularBadgeConfig,\n VolumeTier,\n DiscountConfig,\n PricingRow,\n FixedBundlePricing,\n ImageTransform,\n} from \"@lime-bundles/core\";\nexport { BundleParseError, StorefrontApiError } from \"@lime-bundles/core\";\n\n// DIY widget primitives — every helper a developer needs to build their\n// own bundle UI with the same data, math, and theming the first-party\n// widget uses. All live in `@lime-bundles/core`; importing from the\n// React package is shorthand for consumers who already pulled `react`.\nexport {\n // Bundle config + variant merging\n WIDGET_CONFIG_DEFAULTS,\n mergeWidgetConfig,\n applyWidgetConfigVars,\n thumbnailRatioVars,\n // Pricing (integer cents, matches Shopify Discount Function rounding)\n parseCents,\n formatCents,\n percentageDiscountUnit,\n computeFixedPricing,\n computeBundleSaleCents,\n // Volume-tier calculation\n calculateTierSavings,\n getActiveTier,\n // Multi-step wizard helpers\n productsForStep,\n stepHeadroom,\n // Mix-match quantity validation\n validateQuantity,\n // Image / countdown / money helpers\n transformImageUrl,\n formatCountdown,\n formatMoney,\n formatUnitPrice,\n calculateDiscount,\n // Analytics (optional — FixedBundle / VolumeBundle / MixMatchBundle\n // auto-fire these unless analyticsEnabled is set to false)\n reportImpression,\n reportAddToCart,\n observeImpression,\n // CSS injection + sanitizer\n injectCustomCss,\n sanitizeCustomCss,\n // Custom-storefront data fetching\n createStorefrontClient,\n fetchBundlesForProduct,\n parseMetaobjectBundle,\n parseMetaobjectBundleStrict,\n BUNDLE_METAOBJECT_QUERY,\n BUNDLES_FOR_PRODUCT_QUERY,\n SHOP_SETTINGS_QUERY,\n} from \"@lime-bundles/core\";\n","/**\n * Fixed bundle component — pre-selected products with a shared discount.\n */\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport {\n formatMoney,\n formatUnitPrice,\n calculateDiscount,\n resolveBundleQty,\n isVariantFulfillable,\n shouldShowLowStockBadge,\n type CartLineInput,\n type FixedBundleData,\n type Product,\n type ProductVariant,\n} from \"@lime-bundles/core\";\nimport { useBundleData } from \"../hooks/useBundleData\";\nimport { useAnalytics } from \"../hooks/useAnalytics\";\nimport { useWidgetConfigVars } from \"../hooks/useWidgetConfigVars\";\nimport { useVariantSelection } from \"../hooks/useVariantSelection\";\nimport { useEdgeFade } from \"../hooks/useEdgeFade\";\nimport { VariantDropdown } from \"./VariantDropdown\";\nimport type { BundleComponentProps } from \"./types\";\nimport { BundleCountdown } from \"./BundleCountdown\";\n\nexport function FixedBundle(props: BundleComponentProps) {\n const {\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n appUrl,\n analyticsEnabled,\n onAddToCart,\n onError,\n className,\n } = props;\n\n const result = useBundleData({\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n });\n\n const { elementRef, trackAddToCart } = useAnalytics({\n shopDomain,\n appUrl: appUrl ?? `https://${shopDomain}`,\n bundleGid,\n bundleType: \"fixed\",\n enabled: analyticsEnabled !== false,\n });\n\n const [addingToCart, setAddingToCart] = useState(false);\n const [cartError, setCartError] = useState<string | null>(null);\n // Tracks the customer's selected variant per product. Seeded with first\n // available variant on first render; updated by <ProductRow> via callback.\n const [selectedVariants, setSelectedVariants] = useState<\n Record<string, ProductVariant | null>\n >({});\n\n const handleVariantChange = useCallback(\n (productId: string, variant: ProductVariant | null) => {\n setSelectedVariants((prev) => {\n if (prev[productId] === variant) return prev;\n return { ...prev, [productId]: variant };\n });\n },\n [],\n );\n\n const bundle =\n result.status === \"success\" && result.bundle.bundleType === \"fixed\"\n ? (result.bundle as FixedBundleData)\n : null;\n\n // Apply merchant-config CSS vars (including --lb-thumbnail-aspect-ratio)\n // to the component root via a callback ref composed with elementRef.\n const setConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);\n\n // Scroll-aware edge fade on the inset product list.\n const productsEdgeFadeRef = useEdgeFade();\n\n // Surface load/narrowing errors via onError — in a useEffect so we don't\n // fire side effects during render.\n useEffect(() => {\n if (result.status === \"error\") {\n onError?.(result.error);\n return;\n }\n if (\n result.status === \"success\" &&\n result.bundle.bundleType !== \"fixed\"\n ) {\n onError?.(\n new Error(\n `FixedBundle: expected bundleType=\"fixed\", got \"${result.bundle.bundleType}\"`,\n ),\n );\n }\n }, [result, onError]);\n\n /**\n * Products the store can't sell at the quantity this bundle needs.\n *\n * A fixed bundle is all-or-nothing, so one unavailable product makes the\n * whole thing unbuyable. Previously nothing here modelled that: every row\n * rendered as normal and the CTA stayed live, then `handleAddToCart` filtered\n * the unfulfillable products out and bailed on an empty list — a button that\n * looked fine and silently did nothing.\n */\n const oosProductIds = useMemo(() => {\n if (!bundle) return new Set<string>();\n return new Set(\n bundle.products\n .filter(\n (p) =>\n !p.variants.nodes.some((v) =>\n isVariantFulfillable(v, resolveBundleQty(bundle, p.id, v.id)),\n ),\n )\n .map((p) => p.id),\n );\n }, [bundle]);\n\n const handleAddToCart = useCallback(async () => {\n if (!bundle) return;\n\n // Qty resolution (variantQuantities → productQuantities → 1) lives in\n // `@lime-bundles/core` so the five-runtime fallback chain has a single\n // source of truth. See resolveBundleQty + PR #147 history.\n const bundleLines = bundle.products\n .filter((p) =>\n p.variants.nodes.some((v) =>\n isVariantFulfillable(v, resolveBundleQty(bundle, p.id, v.id)),\n ),\n )\n .map((p) => {\n const variant =\n selectedVariants[p.id] ??\n p.variants.nodes.find((v) =>\n isVariantFulfillable(v, resolveBundleQty(bundle, p.id, v.id)),\n )!;\n return {\n productId: p.id,\n variant,\n quantity: resolveBundleQty(bundle, p.id, variant.id),\n };\n })\n .filter((line) => line.quantity > 0);\n\n if (bundleLines.length === 0) return;\n\n const lines: CartLineInput[] = bundleLines.map((line) => ({\n merchandiseId: line.variant.id,\n quantity: line.quantity,\n attributes: [\n { key: \"_lime_bundle_gid\", value: bundle.id },\n { key: \"_lime_bundle_type\", value: bundle.bundleType },\n ],\n }));\n\n setAddingToCart(true);\n setCartError(null);\n try {\n await onAddToCart(lines);\n const totalPrice = bundleLines.reduce((sum, line) => {\n const price = parseFloat(line.variant.price.amount);\n const discounted = calculateDiscount(\n price,\n bundle.discountConfig.discountType,\n bundle.discountConfig.discountValue,\n );\n return sum + discounted * line.quantity;\n }, 0);\n const totalQuantity = bundleLines.reduce(\n (sum, line) => sum + line.quantity,\n 0,\n );\n // productId is intentionally omitted — a fixed bundle spans multiple\n // products with no single \"page product\"; bundleGid on the event\n // already attributes to the bundle.\n trackAddToCart({\n quantity: totalQuantity,\n totalPrice: Math.round(totalPrice * 100) / 100,\n });\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setCartError(error.message);\n onError?.(error);\n } finally {\n setAddingToCart(false);\n }\n }, [bundle, onAddToCart, onError, trackAddToCart, selectedVariants]);\n\n if (result.status === \"loading\") {\n return (\n <div className={`lb-bundle lb-bundle--loading ${className ?? \"\"}`}>\n <div className=\"lb-skeleton lb-skeleton--title\" />\n <div className=\"lb-skeleton lb-skeleton--products\" />\n </div>\n );\n }\n\n if (result.status === \"error\") return null;\n // Bundle loaded but wasn't a \"fixed\" variant — render nothing; the\n // useEffect above has already invoked onError with a descriptive message.\n if (!bundle) return null;\n\n const currency =\n bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? \"USD\";\n\n // Receipt totals — sum each product's display-variant line at full price\n // and discounted price, then derive the savings amount + honest rounded\n // percent. Mirrors the storefront widget's summary band: compare-at before\n // sale price, sale price the heaviest element, one quiet \"You save\" line.\n let comparePrice = 0;\n let salePrice = 0;\n for (const product of bundle.products) {\n const variants = product.variants.nodes;\n const variant =\n selectedVariants[product.id] ??\n variants.find((v) =>\n isVariantFulfillable(v, resolveBundleQty(bundle, product.id, v.id)),\n ) ??\n variants[0];\n if (!variant) continue;\n const qty = resolveBundleQty(bundle, product.id, variant.id);\n const unit = parseFloat(variant.price.amount);\n comparePrice += unit * qty;\n salePrice +=\n calculateDiscount(\n unit,\n bundle.discountConfig.discountType,\n bundle.discountConfig.discountValue,\n ) * qty;\n }\n const savings = Math.max(0, comparePrice - salePrice);\n const savingsPercent =\n comparePrice > 0 && savings > 0\n ? Math.round((savings / comparePrice) * 100)\n : 0;\n const showCompare =\n bundle.widgetConfig.pricing.showComparePrice && savings > 0;\n const showSavings = bundle.widgetConfig.savingsBar.visible && savings > 0;\n\n return (\n <div\n ref={(el) => {\n elementRef(el);\n setConfigVarsRef(el);\n }}\n className={`lb-bundle lb-bundle--fixed ${className ?? \"\"}`}\n role=\"region\"\n aria-label={bundle.title}\n >\n <div className=\"lb-bundle-header\">\n <div className=\"lb-bundle-header__content\">\n <h3 className=\"lb-bundle-title\">{bundle.title}</h3>\n {bundle.description && (\n <p className=\"lb-bundle-subtitle\">{bundle.description}</p>\n )}\n </div>\n </div>\n\n <BundleCountdown\n endsAt={bundle.endsAt}\n widgetConfig={bundle.widgetConfig}\n />\n\n <div className=\"lb-bundle__products lb-edge-fade\" ref={productsEdgeFadeRef}>\n {bundle.products.map((product) => (\n <FixedProductRow\n key={product.id}\n bundle={bundle}\n product={product}\n currency={currency}\n isOos={oosProductIds.has(product.id)}\n onVariantChange={handleVariantChange}\n />\n ))}\n </div>\n\n <div className=\"lb-bundle-divider\" />\n\n <div className=\"lb-bundle-summary\">\n <div className=\"lb-bundle-summary__text\">\n <span className=\"lb-bundle-summary__label\">Bundle total</span>\n {showSavings && (\n <p className=\"lb-bundle-savings-line\" data-savings-bar>\n You save{\" \"}\n <span data-savings-amount>{formatMoney(savings, currency)}</span>{\" \"}\n <span data-savings-percent>({savingsPercent}%)</span>\n </p>\n )}\n </div>\n <span className=\"lb-bundle-summary__prices\">\n {showCompare && (\n <span className=\"lb-bundle-compare-price\" data-compare-price>\n {formatMoney(comparePrice, currency)}\n </span>\n )}\n <span className=\"lb-bundle-sale-price\" data-sale-price>\n {formatMoney(salePrice, currency)}\n </span>\n </span>\n </div>\n\n {cartError && (\n <p className=\"lb-bundle__error\" role=\"alert\">\n {cartError}\n </p>\n )}\n\n <button\n className=\"lb-bundle__cta\"\n onClick={handleAddToCart}\n disabled={addingToCart || oosProductIds.size > 0}\n aria-busy={addingToCart}\n >\n {addingToCart\n ? \"Adding...\"\n : oosProductIds.size > 0\n ? `${oosProductIds.size} item${oosProductIds.size === 1 ? \"\" : \"s\"} unavailable`\n : (bundle.widgetConfig.cta.ctaText ?? \"Add Bundle to Cart\")}\n </button>\n </div>\n );\n}\n\ninterface FixedProductRowProps {\n bundle: FixedBundleData;\n product: Product;\n currency: string;\n /** No variant can cover this bundle's required quantity. */\n isOos: boolean;\n onVariantChange: (productId: string, variant: ProductVariant | null) => void;\n}\n\nfunction FixedProductRow({ bundle, product, currency, isOos, onVariantChange }: FixedProductRowProps) {\n const variants = product.variants.nodes;\n const optionNames = useMemo<string[]>(() => {\n const first = variants[0];\n return first ? first.selectedOptions.map((o) => o.name) : [];\n }, [variants]);\n\n const showPicker = variants.length > 1 && optionNames.length > 0;\n\n const { selectedValues, selectedVariant, setOptionValue, optionsFor } =\n useVariantSelection({\n variants,\n optionNames,\n // Quantity-aware dropdown: a variant that can't cover this row's\n // bundle quantity greys out instead of walking the shopper into a\n // cart Shopify caps at add time.\n requiredQtyFor: (variantId) =>\n resolveBundleQty(bundle, product.id, variantId),\n });\n\n // Surface the selection to the parent so handleAddToCart picks the right\n // variant. Includes initial seed via effect so cart payload reflects the\n // first-available default before any picker interaction.\n useEffect(() => {\n onVariantChange(product.id, selectedVariant ?? null);\n }, [selectedVariant, product.id, onVariantChange]);\n\n // selectedVariant resolves null only during a transient invalid combo\n // (e.g. Size=Medium+Color=Red where that pairing is sold out). Fall back\n // to the first available so the row keeps showing a sensible price.\n const displayVariant =\n selectedVariant ??\n variants.find((v) =>\n isVariantFulfillable(v, resolveBundleQty(bundle, product.id, v.id)),\n ) ??\n variants[0];\n const priceText = displayVariant\n ? formatMoney(displayVariant.price.amount, currency)\n : formatMoney(product.priceRange.minVariantPrice.amount, currency);\n const compareAt =\n displayVariant?.compareAtPrice &&\n parseFloat(displayVariant.compareAtPrice.amount) >\n parseFloat(displayVariant.price.amount)\n ? formatMoney(displayVariant.compareAtPrice.amount, currency)\n : null;\n const unitPriceText = displayVariant\n ? formatUnitPrice(\n displayVariant.unitPrice,\n displayVariant.unitPriceMeasurement,\n currency,\n )\n : null;\n\n // \"×N\" quantity for the card's right-slot chip — always shown (even \"×1\")\n // so the quantity column reads cleanly down the card list.\n const displayQty = displayVariant\n ? resolveBundleQty(bundle, product.id, displayVariant.id)\n : 1;\n\n const thumbImage = displayVariant?.image ?? product.featuredImage;\n\n const showLowStock =\n !!displayVariant &&\n shouldShowLowStockBadge(\n displayVariant,\n resolveBundleQty(bundle, product.id, displayVariant.id),\n bundle.widgetConfig.lowStockThreshold,\n bundle.widgetConfig.showLowStockBadge,\n );\n\n return (\n <div\n // Same class the web component and Liquid use, so the shared stylesheet\n // greys the row identically on all three surfaces.\n className={\n isOos\n ? \"lb-bundle-product-row lb-bundle-product-row--oos\"\n : \"lb-bundle-product-row\"\n }\n aria-disabled={isOos || undefined}\n part=\"product\"\n >\n {isOos && <span className=\"lb-bundle-product-row__oos\">Out of stock</span>}\n {thumbImage && (\n <img\n src={thumbImage.url}\n alt={thumbImage.altText ?? product.title}\n className=\"lb-bundle__product-image\"\n loading=\"lazy\"\n // Intrinsic dimensions so the browser reserves the box before the\n // file arrives — without them the \"original\" thumbnail ratio has no\n // height until load and everything below the row jumps (issue #302).\n width={thumbImage.width ?? undefined}\n height={thumbImage.height ?? undefined}\n />\n )}\n {/* Info column flows name → variant badge → price (compare + sale) →\n unit price → pickers, mirroring the mix & match chosen-product card. */}\n <div className=\"lb-bundle__product-info\">\n <p className=\"lb-bundle__product-title\">{product.title}</p>\n {/* Read-only variant text sits directly under the title when a\n multi-variant product is scoped to a single variant. */}\n {!showPicker && displayVariant && variants.length > 1 && (\n <span className=\"lb-bundle-variant-badge\">\n {displayVariant.title}\n </span>\n )}\n <span className=\"lb-bundle-product-prices\">\n {compareAt && (\n <span\n className=\"lb-bundle-product-compare-price\"\n data-product-compare-price\n >\n {compareAt}\n </span>\n )}\n <span className=\"lb-bundle__product-price\" data-product-price>\n {priceText}\n </span>\n </span>\n {unitPriceText && (\n <span\n className=\"lb-bundle__product-unit-price\"\n data-product-unit-price\n >\n {unitPriceText}\n </span>\n )}\n {showLowStock && (\n <span className=\"lb-bundle-low-stock-badge\">\n Only {displayVariant.quantityAvailable} left\n </span>\n )}\n {showPicker && (\n <div className=\"lb-bundle__product-variant-pickers\">\n {optionNames.map((optionName, optionIndex) => {\n const dropdownOptions = optionsFor(optionIndex).map((o) => ({\n value: o.value,\n label: o.value,\n disabled: o.disabled,\n }));\n return (\n <VariantDropdown\n key={optionName}\n options={dropdownOptions}\n value={selectedValues[optionIndex] ?? null}\n onChange={(v) => setOptionValue(optionIndex, v)}\n ariaLabel={optionName}\n />\n );\n })}\n </div>\n )}\n </div>\n {/* Quantity chip — fixed-bundle products can't be removed, so the card's\n right slot (where mix & match shows the remove ×) shows how many of\n this product the bundle includes. Always shown, even ×1. */}\n {displayVariant && (\n <span className=\"lb-bundle-qty-chip\" data-qty-inline>\n &times;{displayQty}\n </span>\n )}\n </div>\n );\n}\n","/**\n * Client-side React hook wrapping `fetchBundleData` with loading / error\n * state + abort-on-unmount.\n *\n * For SSR / RSC contexts (Hydrogen loaders, Next.js server components),\n * prefer `fetchBundleData` directly and pass the result to a client\n * component as a prop — the hook's only value-add over the async\n * function is React state management.\n *\n * `UseBundleDataResult` is a discriminated union locked at v1.0.0:\n * narrowing via `status` is safe. Widening or adding states is a\n * breaking change.\n */\nimport { useState, useEffect } from \"react\";\nimport {\n injectCustomCss,\n type BuyerResolver,\n type ParsedBundle,\n} from \"@lime-bundles/core\";\nimport { fetchBundleData } from \"../fetchBundleData\";\nimport { fetchShopSettings } from \"../fetchShopSettings\";\n\nexport interface UseBundleDataOptions {\n shopDomain: string;\n storefrontAccessToken: string;\n bundleGid: string;\n /** ISO-3166 alpha-2 country, passed as Storefront `@inContext(country:)`. */\n country?: string;\n /** ISO-639-1 language, passed as `@inContext(language:)`. */\n language?: string;\n /** B2B buyer identity. Prefer the callback form to keep tokens off prop trees. */\n buyer?: BuyerResolver;\n /** Current visitor's Market GID — filters market-restricted bundles client-side. */\n marketId?: string;\n}\n\nexport type UseBundleDataResult =\n | { status: \"loading\"; bundle: null; error: null }\n | { status: \"success\"; bundle: ParsedBundle; error: null }\n | { status: \"error\"; bundle: null; error: Error };\n\nconst INITIAL_STATE: UseBundleDataResult = {\n status: \"loading\",\n bundle: null,\n error: null,\n};\n\nexport function useBundleData(\n options: UseBundleDataOptions,\n): UseBundleDataResult {\n const [state, setState] = useState<UseBundleDataResult>(INITIAL_STATE);\n\n useEffect(() => {\n const controller = new AbortController();\n setState(INITIAL_STATE);\n\n fetchBundleData({\n shopDomain: options.shopDomain,\n storefrontAccessToken: options.storefrontAccessToken,\n bundleGid: options.bundleGid,\n signal: controller.signal,\n country: options.country,\n language: options.language,\n buyer: options.buyer,\n marketId: options.marketId,\n })\n .then((bundle) => {\n if (controller.signal.aborted) return;\n setState({ status: \"success\", bundle, error: null });\n })\n .catch((err: unknown) => {\n if (controller.signal.aborted) return;\n setState({\n status: \"error\",\n bundle: null,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n });\n\n // Fire-and-forget custom CSS fetch — best-effort, failures never block\n // bundle rendering.\n fetchShopSettings({\n shopDomain: options.shopDomain,\n storefrontAccessToken: options.storefrontAccessToken,\n signal: controller.signal,\n })\n .then((settings) => {\n if (controller.signal.aborted) return;\n injectCustomCss(options.shopDomain, settings.customCss);\n })\n .catch(() => {\n // Silent — no merchant CSS is fine.\n });\n\n return () => {\n controller.abort();\n };\n }, [\n options.shopDomain,\n options.storefrontAccessToken,\n options.bundleGid,\n options.country,\n options.language,\n options.buyer,\n options.marketId,\n ]);\n\n return state;\n}\n","/**\n * Framework-agnostic async fetcher for bundle data.\n *\n * Primary path for Next.js App Router / RSC and Hydrogen loaders — call\n * this in a server-side context and pass the result as a prop to a\n * `\"use client\"` component. `useBundleData` is NOT needed in that\n * component because the data is already in hand.\n *\n * Always forward the end-buyer's IP via `buyerIp` when calling from SSR:\n * Shopify may return 430 Security Rejection for server-originated traffic\n * without it.\n *\n * Throws:\n * - `StorefrontApiError` on network / HTTP / GraphQL errors\n * - `BundleParseError` when the metaobject is missing, invalid type,\n * inactive, not yet started, or expired\n */\nimport {\n createStorefrontClient,\n hasInContext,\n BUNDLE_METAOBJECT_QUERY,\n withInContext,\n parseMetaobjectBundleStrict,\n isVisibleInMarket,\n BundleParseError,\n type BuyerResolver,\n type ParsedBundle,\n type BundleMetaobjectResponse,\n} from \"@lime-bundles/core\";\n\nexport interface FetchBundleDataOptions {\n shopDomain: string;\n storefrontAccessToken: string;\n bundleGid: string;\n /** Forwarded as `Shopify-Storefront-Buyer-IP` — required for SSR. */\n buyerIp?: string;\n /** Abort the in-flight request (used by `useBundleData` to cancel on unmount). */\n signal?: AbortSignal;\n /** Override the Storefront API version pinned in `createStorefrontClient`. */\n apiVersion?: string;\n /**\n * ISO-3166 alpha-2 country code passed as `@inContext(country: ...)`.\n * Drives Shopify Markets pricing, currency, and availability.\n */\n country?: string;\n /** ISO-639-1 language code passed as `@inContext(language: ...)`. */\n language?: string;\n /**\n * B2B buyer identity. Prefer the callback form for security — it lets\n * you fetch the customer access token just-in-time so it doesn't sit\n * in static prop trees. See packages/*\\/README.md → \"Markets & B2B\".\n */\n buyer?: BuyerResolver;\n /**\n * Shopify Market GID for the current visitor. When set and the bundle's\n * `marketVisibility === \"specific\"`, the bundle is filtered out if its\n * `marketIds` doesn't include this market. Returned to the caller via\n * `BundleVisibilityWarning[]` for surfacing.\n */\n marketId?: string;\n}\n\n/** Filtered bundle metadata. Returned alongside the bundle for SSR/RSC consumers. */\nexport interface BundleVisibilityWarning {\n bundleGid: string;\n reason: \"market_mismatch\";\n /** The marketId passed by the consumer that didn't match this bundle. */\n currentMarketId: string | null;\n /** The bundle's allowed Market GIDs. Empty for `marketVisibility === \"all\"`. */\n allowedMarketIds: string[];\n}\n\nexport interface FetchBundleDataResult {\n bundle: ParsedBundle | null;\n /** Populated when the bundle was hidden by the market gate. */\n warnings: BundleVisibilityWarning[];\n}\n\nexport async function fetchBundleData(\n options: FetchBundleDataOptions,\n): Promise<ParsedBundle> {\n const result = await fetchBundleDataWithWarnings(options);\n if (!result.bundle) {\n throw new BundleParseError(\n `Bundle hidden by market gate: ${options.bundleGid}`,\n \"not_found\",\n );\n }\n return result.bundle;\n}\n\n/**\n * Like `fetchBundleData` but surfaces market-gate misses as warnings instead\n * of throwing. Useful for consumers that render alternative content when a\n * bundle isn't available in the current market.\n */\nexport async function fetchBundleDataWithWarnings(\n options: FetchBundleDataOptions,\n): Promise<FetchBundleDataResult> {\n const config = {\n shopDomain: options.shopDomain,\n accessToken: options.storefrontAccessToken,\n buyerIp: options.buyerIp,\n apiVersion: options.apiVersion,\n country: options.country,\n language: options.language,\n buyer: options.buyer,\n };\n const client = createStorefrontClient(config);\n const query = hasInContext(config)\n ? withInContext(BUNDLE_METAOBJECT_QUERY)\n : BUNDLE_METAOBJECT_QUERY;\n\n const data = await client.query<BundleMetaobjectResponse>(\n query,\n { id: options.bundleGid },\n { signal: options.signal },\n );\n\n if (!data.metaobject) {\n throw new BundleParseError(\n `Bundle not found: ${options.bundleGid}`,\n \"not_found\",\n );\n }\n\n const bundle = parseMetaobjectBundleStrict(\n data.metaobject.id,\n data.metaobject.fields,\n );\n\n // Market visibility gate. The bundle is hidden when restricted to a\n // specific market list that doesn't include the caller's current\n // marketId. SDK is the primary gate for headless consumers (the\n // theme widget has its own Liquid gate; the discount function has its\n // own checkout-side gate).\n if (!isVisibleInMarket(bundle, options.marketId)) {\n return {\n bundle: null,\n warnings: [\n {\n bundleGid: options.bundleGid,\n reason: \"market_mismatch\",\n currentMarketId: options.marketId ?? null,\n allowedMarketIds: bundle.marketIds,\n },\n ],\n };\n }\n\n return { bundle, warnings: [] };\n}\n","/**\n * Best-effort fetch for the shop's `$app` settings metafields.\n *\n * Returns the raw custom CSS (still needs sanitization before injection — see\n * `injectCustomCss` from core).\n *\n * **Per-shop in-memory cache.** Multiple `<FixedBundle>` / `<VolumeBundle>` /\n * `<MixMatchBundle>` components on the same page share one network request —\n * the first caller fetches, concurrent callers await the same promise, and\n * resolved values are cached so subsequent mounts return instantly. Failures\n * are NOT cached so the next caller retries.\n *\n * The cache lives for the life of the JS module (typically one page load).\n * Merchants updating settings see changes on the next page load. The cache is\n * exposed as `__clearShopSettingsCache` for test use only.\n */\nimport {\n createStorefrontClient,\n SHOP_SETTINGS_QUERY,\n type ShopSettingsResponse,\n} from \"@lime-bundles/core\";\n\nexport interface FetchShopSettingsOptions {\n shopDomain: string;\n storefrontAccessToken: string;\n buyerIp?: string;\n signal?: AbortSignal;\n}\n\nexport interface ShopSettings {\n /** Raw, unsanitized merchant CSS. Null when unset. */\n customCss: string | null;\n}\n\n/** What callers get when the fetch fails: styling intact. */\nconst FALLBACK: ShopSettings = {\n customCss: null,\n};\n\n// Cache map: key = shopDomain, value = pending or resolved promise.\n// Failures delete their own entry so retries get a fresh fetch.\nconst cache = new Map<string, Promise<ShopSettings>>();\n\nexport async function fetchShopSettings(\n options: FetchShopSettingsOptions,\n): Promise<ShopSettings> {\n const cached = cache.get(options.shopDomain);\n if (cached) return cached;\n\n const promise = (async (): Promise<ShopSettings> => {\n const client = createStorefrontClient({\n shopDomain: options.shopDomain,\n accessToken: options.storefrontAccessToken,\n buyerIp: options.buyerIp,\n });\n\n const data = await client.query<ShopSettingsResponse>(\n SHOP_SETTINGS_QUERY,\n undefined,\n { signal: options.signal },\n );\n\n return {\n customCss: data.shop?.customCss?.value ?? null,\n };\n })();\n\n // Cache the promise synchronously so concurrent callers dedupe.\n cache.set(options.shopDomain, promise);\n\n // Evict on failure so the next caller can retry.\n promise.catch(() => {\n if (cache.get(options.shopDomain) === promise) {\n cache.delete(options.shopDomain);\n }\n });\n\n return promise;\n}\n\n/**\n * Same fetch, never rejects — a failed settings request must not stop a\n * bundle from appearing.\n */\nexport async function fetchShopSettingsOrDefault(\n options: FetchShopSettingsOptions,\n): Promise<ShopSettings> {\n try {\n return await fetchShopSettings(options);\n } catch {\n return FALLBACK;\n }\n}\n\n/**\n * Test-only helper. Clears the per-shop settings cache so each test starts\n * from a known state. Do not call from application code.\n */\nexport function __clearShopSettingsCache(): void {\n cache.clear();\n}\n","/**\n * Hook for analytics event reporting (impressions + add-to-cart).\n * Impressions fire once per mount using IntersectionObserver.\n */\nimport { useEffect, useMemo, useRef, useCallback, useState } from \"react\";\nimport {\n reportImpression,\n reportAddToCart,\n observeImpression,\n type AnalyticsConfig,\n} from \"@lime-bundles/core\";\n\nexport interface UseAnalyticsOptions {\n shopDomain: string;\n appUrl: string;\n bundleGid: string;\n bundleType: string;\n enabled?: boolean;\n}\n\nexport function useAnalytics(options: UseAnalyticsOptions) {\n const impressionFiredRef = useRef(false);\n // Callback ref + state so the observer effect re-runs when the host element\n // is attached (e.g. after a `loading` branch swaps in the real DOM node).\n const [element, setElement] = useState<HTMLElement | null>(null);\n const elementRef = useCallback((el: HTMLElement | null) => {\n setElement(el);\n }, []);\n\n const config: AnalyticsConfig = useMemo(\n () => ({ shopDomain: options.shopDomain, appUrl: options.appUrl }),\n [options.shopDomain, options.appUrl],\n );\n\n // Reset the fired flag when bundle identity changes so a reused component\n // (e.g. via navigation) can report a fresh impression.\n useEffect(() => {\n impressionFiredRef.current = false;\n }, [options.bundleGid]);\n\n // Set up impression observer once the element is attached\n useEffect(() => {\n if (options.enabled === false) return;\n if (impressionFiredRef.current) return;\n if (!element) return;\n\n const cleanup = observeImpression(element, () => {\n if (impressionFiredRef.current) return;\n impressionFiredRef.current = true;\n\n reportImpression(config, {\n bundleGid: options.bundleGid,\n bundleType: options.bundleType,\n });\n });\n\n return cleanup;\n }, [\n element,\n config,\n options.enabled,\n options.bundleGid,\n options.bundleType,\n ]);\n\n const trackAddToCart = useCallback(\n (event: {\n /** Optional — omit for multi-product bundles (fixed, mix-match). */\n productId?: string;\n quantity: number;\n totalPrice: number;\n }) => {\n if (options.enabled === false) return;\n\n reportAddToCart(config, {\n bundleGid: options.bundleGid,\n bundleType: options.bundleType,\n productId: event.productId,\n quantity: event.quantity,\n totalPrice: event.totalPrice,\n });\n },\n [\n config,\n options.enabled,\n options.bundleGid,\n options.bundleType,\n ],\n );\n\n return { elementRef, trackAddToCart };\n}\n","/**\n * Apply a bundle's `widgetConfig` to the component root as CSS custom\n * properties. Returns a callback ref so it composes with other callback\n * refs (e.g. `useAnalytics().elementRef`) without needing a ref-merge\n * library.\n *\n * Mirrors what the web component does in `applyWidgetConfigVars` — the\n * React surface uses a smaller subset of `--lb-*` vars in its own\n * stylesheet (`@lime-bundles/react/styles.css`), but having every var set\n * means merchant choices like `productList.thumbnailRatio` flow through to\n * the React image rules without further plumbing. Vars the React stylesheet\n * doesn't read are harmless extras.\n */\nimport { useCallback, useEffect, useRef } from \"react\";\nimport { applyWidgetConfigVars, type WidgetConfig } from \"@lime-bundles/core\";\n\nexport function useWidgetConfigVars(\n config: WidgetConfig | null | undefined,\n): (el: HTMLElement | null) => void {\n const elementRef = useRef<HTMLElement | null>(null);\n\n // Re-apply when config changes (e.g. async bundle load completes).\n useEffect(() => {\n if (elementRef.current && config) {\n applyWidgetConfigVars(elementRef.current, config);\n }\n }, [config]);\n\n // Apply on first attachment so the merchant's chosen ratio is in effect\n // before the browser does its first paint.\n return useCallback(\n (el: HTMLElement | null) => {\n elementRef.current = el;\n if (el && config) applyWidgetConfigVars(el, config);\n },\n [config],\n );\n}\n","/**\n * Per-product variant selection state for the React bundle components.\n *\n * Owns positional option-value selection for one product; derives the\n * resolved `ProductVariant` and an availability map (which option values\n * are currently disabled given the other selections). Mirrors the\n * `findVariantByOptions` / `isOptionValueAvailable` logic that powers the\n * Liquid widget and the `<lime-bundle>` web component, so the cascade\n * behaviour matches across all surfaces.\n */\nimport { useEffect, useMemo, useState, useCallback } from \"react\";\nimport { variants as variantsNs, type ProductVariant } from \"@lime-bundles/core\";\n\nconst { findVariantByOptions, isOptionValueAvailable, toPickerVariant } = variantsNs;\n\nexport interface UseVariantSelectionOptions {\n /** Storefront-API variants for the product (eligible set already filtered). */\n variants: ReadonlyArray<ProductVariant>;\n /** Positional option names for the product, e.g. `['Size', 'Color']`. */\n optionNames: ReadonlyArray<string>;\n /**\n * Optional initial variant. Defaults to the first variant that can cover\n * the slot (per `requiredQtyFor` when supplied), then the first available\n * variant, then the first variant.\n */\n initialVariant?: ProductVariant | null;\n /**\n * Canonical option-value order per option position (e.g. from\n * `Product.options[].values` on the Storefront API). When supplied, the\n * dropdown UI renders values in this merchant-defined order. When omitted,\n * order is variant-discovery order (which may not match Shopify admin).\n */\n optionValuesByPosition?: ReadonlyArray<ReadonlyArray<string>>;\n /**\n * Per-variant required quantity for the bundle slot this picker fills.\n * When provided, dropdown availability is quantity-aware (a variant short\n * of the bundle's needs greys out) instead of plain `availableForSale`.\n */\n requiredQtyFor?: (variantId: string) => number;\n}\n\nexport interface UseVariantSelectionResult {\n /** Positional option values matching `optionNames`. */\n selectedValues: ReadonlyArray<string>;\n /** The resolved variant for the current selection (null when no exact match). */\n selectedVariant: ProductVariant | null;\n /** Set the value at a single option position. */\n setOptionValue: (optionIndex: number, value: string) => void;\n /** All distinct values for an option position, paired with availability. */\n optionsFor: (\n optionIndex: number,\n ) => ReadonlyArray<{ value: string; disabled: boolean }>;\n}\n\nexport function useVariantSelection({\n variants,\n optionNames,\n initialVariant,\n optionValuesByPosition,\n requiredQtyFor,\n}: UseVariantSelectionOptions): UseVariantSelectionResult {\n const pickerVariants = useMemo(\n () => variants.map((v) => toPickerVariant(v, requiredQtyFor?.(v.id))),\n [variants, requiredQtyFor],\n );\n\n // Resolve the seed variant once per render; the memo covers both the\n // initial useState seed and the reset effect below. The default is\n // quantity-aware through the same pickerVariants that grey the dropdown,\n // so the initial selection never lands on a greyed option (#278) — with\n // plain availableForSale as the fallback when nothing can cover the slot\n // (the component's own OOS state locks the CTA in that case).\n const seed = useMemo(() => {\n if (initialVariant) return initialVariant;\n const covered = pickerVariants.find((p) => p.available);\n if (covered) {\n return variants.find((v) => v.id === covered.id) ?? null;\n }\n return variants.find((v) => v.availableForSale) ?? variants[0] ?? null;\n }, [initialVariant, variants, pickerVariants]);\n const [selectedValues, setSelectedValues] = useState<string[]>(() =>\n seed ? seed.selectedOptions.map((o) => o.value) : optionNames.map(() => \"\"),\n );\n\n // Reset selection when the caller swaps the product or supplies a new\n // initial variant. Keying on seed.id keeps variants/optionNames\n // recomputes from firing this spuriously.\n useEffect(() => {\n if (!seed) return;\n setSelectedValues(seed.selectedOptions.map((o) => o.value));\n // eslint-disable-next-line react-hooks/exhaustive-deps -- intentionally keyed on seed?.id, not seed itself\n }, [seed?.id]);\n\n const selectedVariant = useMemo<ProductVariant | null>(() => {\n if (selectedValues.length !== optionNames.length) return null;\n const match = findVariantByOptions(pickerVariants, selectedValues);\n if (!match) return null;\n return variants.find((v) => v.id === match.id) ?? null;\n }, [pickerVariants, selectedValues, variants, optionNames.length]);\n\n const setOptionValue = useCallback(\n (optionIndex: number, value: string) => {\n setSelectedValues((prev) => {\n const next = prev.slice();\n next[optionIndex] = value;\n return next;\n });\n },\n [],\n );\n\n const optionsByPosition = useMemo(() => {\n if (optionValuesByPosition) {\n return optionValuesByPosition.map((values) => values.slice());\n }\n const out: string[][] = optionNames.map(() => []);\n for (const v of variants) {\n v.selectedOptions.forEach((o, i) => {\n if (i < out.length && !out[i].includes(o.value)) out[i].push(o.value);\n });\n }\n return out;\n }, [variants, optionNames, optionValuesByPosition]);\n\n const optionsFor = useCallback(\n (optionIndex: number) => {\n const values = optionsByPosition[optionIndex] ?? [];\n return values.map((value) => ({\n value,\n disabled: !isOptionValueAvailable(\n pickerVariants,\n optionIndex,\n value,\n selectedValues,\n ),\n }));\n },\n [optionsByPosition, pickerVariants, selectedValues],\n );\n\n return {\n selectedValues,\n selectedVariant,\n setOptionValue,\n optionsFor,\n };\n}\n","/**\n * Scroll-aware edge fade for an inset scroll list (fixed products, mix & match\n * slots, volume tiers). Mirrors `LB.attachEdgeFade` in the Liquid theme's\n * bundle-widget.js (and `attachEdgeFade` in `@lime-bundles/widget`): the native\n * scrollbar is hidden by the `.lb-edge-fade` CSS class and a soft mask fades\n * whichever edge has scrolled-past content — never at rest.\n *\n * Toggles `data-edge-fade=\"top\" | \"bottom\" | \"both\"` on the element:\n * - bottom: at the very top, more below → fade the bottom edge\n * - top: at the very bottom, more above → fade the top edge\n * - both: scrolled in the middle → fade both edges\n * - (none): content fits, nothing to fade\n *\n * Returns a callback ref. Attach it to the scroll list (alongside the\n * `lb-edge-fade` className) — it wires a passive scroll listener plus a\n * ResizeObserver and a MutationObserver (childList + subtree, so dynamically\n * added/removed cards re-evaluate), updates once on attach, and tears\n * everything down when the node detaches or the component unmounts.\n *\n * Without JS (or before the ref attaches) the list simply scrolls with no bar\n * and no fade — a safe, quiet fallback.\n */\nimport { useCallback, useRef } from \"react\";\n\nfunction attachEdgeFade(el: HTMLElement): () => void {\n function update() {\n const scrollable = el.scrollHeight - el.clientHeight;\n if (scrollable <= 1) {\n el.removeAttribute(\"data-edge-fade\");\n return;\n }\n const atTop = el.scrollTop <= 1;\n const atBottom = el.scrollTop >= scrollable - 1;\n el.setAttribute(\n \"data-edge-fade\",\n atTop ? \"bottom\" : atBottom ? \"top\" : \"both\",\n );\n }\n\n el.addEventListener(\"scroll\", update, { passive: true });\n\n let resizeObserver: ResizeObserver | null = null;\n if (typeof ResizeObserver !== \"undefined\") {\n resizeObserver = new ResizeObserver(update);\n resizeObserver.observe(el);\n }\n\n let mutationObserver: MutationObserver | null = null;\n if (typeof MutationObserver !== \"undefined\") {\n mutationObserver = new MutationObserver(update);\n mutationObserver.observe(el, { childList: true, subtree: true });\n }\n\n update();\n\n return () => {\n el.removeEventListener(\"scroll\", update);\n resizeObserver?.disconnect();\n mutationObserver?.disconnect();\n };\n}\n\nexport function useEdgeFade(): (el: HTMLElement | null) => void {\n const cleanupRef = useRef<(() => void) | null>(null);\n\n return useCallback((el: HTMLElement | null) => {\n // Tear down a prior attachment first — covers both detach (el === null)\n // and re-attach to a new node across renders.\n cleanupRef.current?.();\n cleanupRef.current = null;\n\n if (el) {\n cleanupRef.current = attachEdgeFade(el);\n }\n }, []);\n}\n","/**\n * Accessible custom variant-picker dropdown for React bundle components.\n *\n * Controlled component — caller owns `value` and `onChange`. Mirrors the\n * WAI-ARIA combobox pattern shipped by the Liquid theme dropdown and the\n * `<lime-bundle>` web component dropdown. Keyboard / type-ahead /\n * positioning logic comes from `@lime-bundles/core` so all three surfaces\n * stay in lockstep.\n *\n * Asymmetry with the Liquid + web component surfaces: those expose a hidden\n * native `<select>` and the dropdown UI resyncs via MutationObserver if an\n * external script mutates `select.value`. The React component has no such\n * escape hatch — to change selection externally, re-render with a new\n * `value` prop. This is intentional: a synthetic-event-driven hidden\n * select would fight React reconciliation.\n */\nimport {\n useEffect,\n useId,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { dropdown } from \"@lime-bundles/core\";\n\nconst { computePosition, emptyTypeAheadState, handleKey, pushTypeAheadChar } =\n dropdown;\n\n// Layout-tuning constants for panel-height calculation. Inlined here\n// rather than imported from core so they stay tweakable without locking\n// numeric values into the public SDK contract.\nconst ITEM_HEIGHT_PX = 32;\nconst LIST_PAD_Y = 8;\nconst MAX_VISIBLE_ITEMS = 8;\ntype ComputePositionResult = dropdown.ComputePositionResult;\ntype TypeAheadState = dropdown.TypeAheadState;\n\n// Walk up to find the nearest ancestor that clips overflow on the Y axis.\n// Used so placement flips upward before the listbox would be hidden by a\n// scrollable container (`.lb-bundle__products`). Stops at body — past\n// that, the viewport bound is correct.\nfunction findScrollableAncestor(el: Element): HTMLElement | null {\n const win = el.ownerDocument?.defaultView;\n if (!win) return null;\n let cur: Element | null = el.parentElement;\n while (cur && cur !== el.ownerDocument.body) {\n const style = win.getComputedStyle(cur);\n const overflowY = style.overflowY;\n if (\n overflowY === \"auto\" ||\n overflowY === \"scroll\" ||\n overflowY === \"hidden\"\n ) {\n return cur as HTMLElement;\n }\n cur = cur.parentElement;\n }\n return null;\n}\n\nexport interface VariantDropdownOption {\n value: string;\n label: string;\n disabled?: boolean;\n}\n\nexport interface VariantDropdownProps {\n options: ReadonlyArray<VariantDropdownOption>;\n value: string | null;\n onChange: (value: string) => void;\n /** Accessible label, e.g. `\"Size\"`. */\n ariaLabel?: string;\n className?: string;\n}\n\nexport function VariantDropdown({\n options,\n value,\n onChange,\n ariaLabel,\n className,\n}: VariantDropdownProps) {\n const idBase = useId();\n const triggerRef = useRef<HTMLButtonElement>(null);\n const listboxRef = useRef<HTMLUListElement>(null);\n const typeAheadRef = useRef<TypeAheadState>(emptyTypeAheadState());\n const [isOpen, setIsOpen] = useState(false);\n const [activeIndex, setActiveIndex] = useState(-1);\n const [position, setPosition] = useState<ComputePositionResult | null>(null);\n\n const selectedIndex = useMemo(\n () => options.findIndex((o) => o.value === value),\n [options, value],\n );\n\n const optionsState = useMemo(\n () => options.map((o) => ({ disabled: !!o.disabled, label: o.label })),\n [options],\n );\n\n const selectedLabel =\n selectedIndex >= 0 ? options[selectedIndex].label : \"\";\n\n function open() {\n if (isOpen) return;\n setIsOpen(true);\n setActiveIndex(\n selectedIndex >= 0 && !optionsState[selectedIndex]?.disabled\n ? selectedIndex\n : optionsState.findIndex((o) => !o.disabled),\n );\n }\n\n function close(restoreFocus: boolean) {\n setIsOpen(false);\n setActiveIndex(-1);\n if (restoreFocus) triggerRef.current?.focus();\n }\n\n function commit(index: number) {\n const opt = options[index];\n if (!opt || opt.disabled) return;\n if (opt.value !== value) onChange(opt.value);\n close(true);\n }\n\n // position:fixed coords recomputed on open, then again on every scroll/resize\n // while open (those handlers close the panel — see effect below — so this\n // layout effect only runs once per open transition).\n useLayoutEffect(() => {\n if (!isOpen) return;\n const trigger = triggerRef.current;\n if (!trigger) return;\n const rect = trigger.getBoundingClientRect();\n if (rect.width === 0) return;\n const visibleCount = Math.min(options.length || 1, MAX_VISIBLE_ITEMS);\n const desiredHeight = visibleCount * ITEM_HEIGHT_PX + LIST_PAD_Y;\n // Trigger lives inside the bundle's product list which is overflow:auto\n // with a capped max-height. Without clip bounds the placement decision\n // uses viewport room and opens downward into the clipped zone, hiding\n // the panel behind the widget footer. Pass the scrollable ancestor's\n // rect so placement flips upward when the trigger nears its bottom.\n const scrollable = findScrollableAncestor(trigger);\n const clip = scrollable\n ? (() => {\n const r = scrollable.getBoundingClientRect();\n return { top: r.top, bottom: r.bottom };\n })()\n : undefined;\n setPosition(\n computePosition({\n trigger: {\n top: rect.top,\n bottom: rect.bottom,\n left: rect.left,\n width: rect.width,\n },\n viewportHeight: window.innerHeight,\n desiredHeight,\n clip,\n }),\n );\n }, [isOpen, options.length]);\n\n useEffect(() => {\n if (!isOpen) return;\n // composedPath() handles shadow-DOM retargeting (for merchants who\n // embed this component inside a custom element with shadow root).\n const isInsideDropdown = (event: Event): boolean => {\n const path = event.composedPath();\n const trigger = triggerRef.current;\n const listbox = listboxRef.current;\n return (\n (trigger != null && path.includes(trigger)) ||\n (listbox != null && path.includes(listbox))\n );\n };\n const onPointerdown = (event: PointerEvent) => {\n if (isInsideDropdown(event)) return;\n close(false);\n };\n const onScroll = (event: Event) => {\n // Scrolling within the listbox itself must not close the dropdown.\n if (isInsideDropdown(event)) return;\n close(false);\n };\n const onResize = () => close(false);\n document.addEventListener(\"pointerdown\", onPointerdown, true);\n window.addEventListener(\"scroll\", onScroll, true);\n window.addEventListener(\"resize\", onResize);\n return () => {\n document.removeEventListener(\"pointerdown\", onPointerdown, true);\n window.removeEventListener(\"scroll\", onScroll, true);\n window.removeEventListener(\"resize\", onResize);\n };\n }, [isOpen]);\n\n useEffect(() => {\n if (!isOpen || activeIndex < 0) return;\n const listbox = listboxRef.current;\n if (!listbox) return;\n const li = listbox.querySelector<HTMLElement>(\n `#${CSS.escape(`${idBase}-opt-${activeIndex}`)}`,\n );\n if (!li) return;\n // Scroll within the listbox only — Element.scrollIntoView falls through\n // to the document scroll when the listbox itself isn't overflowing,\n // which can yank the page.\n const liTop = li.offsetTop;\n const liBottom = liTop + li.offsetHeight;\n const visTop = listbox.scrollTop;\n const visBottom = visTop + listbox.clientHeight;\n if (liTop < visTop) {\n listbox.scrollTop = liTop;\n } else if (liBottom > visBottom) {\n listbox.scrollTop = liBottom - listbox.clientHeight;\n }\n }, [activeIndex, isOpen, idBase]);\n\n function onKeyDown(event: React.KeyboardEvent) {\n const action = handleKey(\n {\n key: event.key,\n ctrlKey: event.ctrlKey,\n metaKey: event.metaKey,\n altKey: event.altKey,\n shiftKey: event.shiftKey,\n },\n { isOpen, activeIndex, selectedIndex, options: optionsState },\n );\n if (action.preventDefault) event.preventDefault();\n switch (action.type) {\n case \"open\":\n open();\n if (action.activeIndex >= 0) setActiveIndex(action.activeIndex);\n return;\n case \"close\":\n close(action.restoreFocus);\n return;\n case \"move-active\":\n setActiveIndex(action.activeIndex);\n return;\n case \"commit\":\n commit(action.index);\n return;\n case \"type-ahead\": {\n const result = pushTypeAheadChar(\n typeAheadRef.current,\n action.char,\n Date.now(),\n optionsState,\n );\n typeAheadRef.current = result.newState;\n if (result.matchedIndex !== null) {\n if (!isOpen) open();\n setActiveIndex(result.matchedIndex);\n }\n return;\n }\n case \"passthrough\":\n return;\n }\n }\n\n function onShellBlur(event: React.FocusEvent) {\n const next = event.relatedTarget as Node | null;\n if (next && event.currentTarget.contains(next)) return;\n // Defer so focus has a chance to land elsewhere first.\n setTimeout(() => {\n if (!isOpen) return;\n const active = document.activeElement;\n if (\n !triggerRef.current?.contains(active) &&\n !listboxRef.current?.contains(active)\n ) {\n close(false);\n }\n }, 0);\n }\n\n const listboxId = `${idBase}-listbox`;\n const activeDescendantId =\n activeIndex >= 0 ? `${idBase}-opt-${activeIndex}` : undefined;\n\n // Only max-height comes from JS; CSS [data-placement] selectors\n // anchor the listbox against the position:relative .lb-dropdown shell\n // via top: 100% / bottom: 100%, so we never depend on inline coords\n // landing before paint.\n const panelStyle: React.CSSProperties | undefined = position\n ? { maxHeight: position.maxHeight }\n : undefined;\n\n return (\n <div\n className={`lb-dropdown${className ? ` ${className}` : \"\"}`}\n data-lb-dropdown=\"\"\n onBlur={onShellBlur}\n >\n <button\n ref={triggerRef}\n type=\"button\"\n className=\"lb-dropdown-trigger\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-expanded={isOpen}\n aria-controls={listboxId}\n aria-label={ariaLabel}\n aria-activedescendant={activeDescendantId}\n onClick={(e) => {\n e.preventDefault();\n if (isOpen) close(false);\n else open();\n }}\n onKeyDown={onKeyDown}\n >\n <span className=\"lb-dropdown-trigger-value\">{selectedLabel}</span>\n <span className=\"lb-dropdown-chevron\" aria-hidden=\"true\" />\n </button>\n <ul\n ref={listboxRef}\n id={listboxId}\n className=\"lb-dropdown-listbox\"\n role=\"listbox\"\n aria-label={ariaLabel}\n hidden={!isOpen}\n data-placement={position?.placement}\n style={panelStyle}\n // Prevent mousedown on a non-focusable <li> from blurring the\n // trigger button. Without this, focusout fires on the shell,\n // queues onShellBlur's setTimeout(0), and the close runs before\n // the synthesized click — so commit never runs and the trigger\n // label never updates. Mobile is unaffected because touchstart\n // doesn't shift focus.\n onMouseDown={(e) => e.preventDefault()}\n >\n {options.map((opt, i) => (\n // Keyboard activation lives on the trigger combobox via\n // aria-activedescendant — the WAI-ARIA combobox pattern keeps\n // focus on the button and tracks the active option by id, so\n // the option <li> elements deliberately have no key handlers.\n // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-noninteractive-element-interactions\n <li\n key={opt.value}\n id={`${idBase}-opt-${i}`}\n className={`lb-dropdown-option${i === activeIndex ? \" is-active\" : \"\"}`}\n role=\"option\"\n aria-selected={i === selectedIndex}\n aria-disabled={opt.disabled || undefined}\n data-value={opt.value}\n onClick={() => commit(i)}\n onMouseMove={() => {\n if (!opt.disabled && i !== activeIndex) setActiveIndex(i);\n }}\n >\n {opt.label}\n </li>\n ))}\n </ul>\n </div>\n );\n}\n","/**\n * Countdown strip — the React twin of the theme's `lb-widget-header.liquid`\n * countdown block and the render layer's `initCountdown`.\n *\n * Same markup, classes and timer format as the other two hosts, driven by the\n * merchant's `--lb-countdown-bg` / `--lb-countdown-text` vars that\n * `useWidgetConfigVars` already emits. Renders nothing without an end date,\n * and hides itself once the window closes — the discount stops applying at\n * that moment, so a still-ticking strip would advertise a price the checkout\n * no longer honours.\n */\nimport { useEffect, useState } from \"react\";\nimport type { WidgetConfig } from \"@lime-bundles/core\";\n\nfunction pad(n: number): string {\n return n < 10 ? \"0\" + n : String(n);\n}\n\nfunction formatRemaining(remaining: number): string {\n const days = Math.floor(remaining / 86400000);\n const hours = Math.floor((remaining % 86400000) / 3600000);\n const mins = Math.floor((remaining % 3600000) / 60000);\n const secs = Math.floor((remaining % 60000) / 1000);\n return days > 0\n ? days + \"d \" + pad(hours) + \"h \" + pad(mins) + \"m \" + pad(secs) + \"s\"\n : pad(hours) + \"h \" + pad(mins) + \"m \" + pad(secs) + \"s\";\n}\n\nexport interface BundleCountdownProps {\n /** The bundle's ISO end date; renders nothing when null. */\n endsAt: string | null | undefined;\n /** The bundle's widget config — gates on `countdown.showCountdown`. */\n widgetConfig: WidgetConfig | undefined;\n /** Label text; defaults to the theme's translation default. */\n label?: string;\n}\n\nexport function BundleCountdown({\n endsAt,\n widgetConfig,\n label = \"Limited time offer\",\n}: BundleCountdownProps) {\n const enabled =\n !!endsAt && widgetConfig?.countdown?.showCountdown !== false;\n const endTime = enabled ? new Date(endsAt!).getTime() : NaN;\n const [remaining, setRemaining] = useState<number | null>(null);\n\n useEffect(() => {\n if (!enabled || isNaN(endTime)) {\n setRemaining(null);\n return;\n }\n const update = () => setRemaining(endTime - Date.now());\n update();\n const interval = setInterval(update, 1000);\n return () => clearInterval(interval);\n }, [enabled, endTime]);\n\n if (!enabled || isNaN(endTime) || remaining === null || remaining <= 0) {\n return null;\n }\n\n return (\n <div className=\"lb-bundle-countdown\" data-countdown>\n <div className=\"lb-bundle-countdown__label\">\n <span>{label}</span>\n </div>\n <span className=\"lb-bundle-countdown__timer\" data-countdown-timer>\n {formatRemaining(remaining)}\n </span>\n </div>\n );\n}\n","/**\n * Mix-and-match bundle component.\n *\n * Customer picks products from a pool via a portaled picker modal; the\n * bundle qualifies when the TOTAL UNITS across picks (sum of per-pick\n * quantities) meets `bundle.minQuantity` — one product at qty 3 completes\n * a \"pick 3\" bundle, matching the discount function's unit-based gate.\n * Per-product `[min, max]` quantity bounds come from `bundle.productRules`\n * (products without an explicit rule use `DEFAULT_PRODUCT_RULE`).\n *\n * The UX mirrors the storefront theme widget one-for-one:\n * - a plain title + subtitle header,\n * - a SEGMENTED progress bar with count + remaining labels,\n * - a list of CHOSEN-PRODUCT CARDS (thumbnail, title, variant, price ×N,\n * remove ×),\n * - a single dashed \"Add a product\" slot that opens the picker modal,\n * - the picker modal itself (search, type filters, 2-col grid, per-pick\n * variant dropdowns + qty stepper + Add toggle, sticky Done footer),\n * - a receipt summary (compare/sale/savings) + CTA.\n *\n * See `extensions/bundle-theme/snippets/lb-mix-match.liquid` +\n * `extensions/bundle-theme/assets/bundle-mix-match.js` for the source of\n * truth, and `MixMatchPicker.tsx` for the modal.\n */\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport {\n formatMoney,\n formatUnitPrice,\n calculateDiscount,\n isVariantFulfillable,\n DEFAULT_PRODUCT_RULE,\n type CartLineInput,\n type MixMatchBundleData,\n type ProductRule,\n type ProductVariant,\n} from \"@lime-bundles/core\";\nimport { useBundleData } from \"../hooks/useBundleData\";\nimport { useAnalytics } from \"../hooks/useAnalytics\";\nimport { useWidgetConfigVars } from \"../hooks/useWidgetConfigVars\";\nimport { useEdgeFade } from \"../hooks/useEdgeFade\";\nimport { MixMatchPicker } from \"./MixMatchPicker\";\nimport type { SelectedItem } from \"./mix-match-types\";\nimport type { BundleComponentProps } from \"./types\";\nimport { BundleCountdown } from \"./BundleCountdown\";\n\n/**\n * The rule in force for a pick. Pass `variantId` and the variant's own rule\n * wins; without one this resolves the product rule, which is the envelope\n * covering every variant.\n */\nfunction ruleFor(\n bundle: MixMatchBundleData,\n productId: string,\n variantId?: string | null,\n): ProductRule {\n if (variantId) {\n const vRule = bundle.variantRules[variantId];\n if (vRule) return vRule;\n }\n return bundle.productRules[productId] ?? DEFAULT_PRODUCT_RULE;\n}\n\n/**\n * The variant's OWN rule, or undefined when it inherits the product's.\n * Distinct from `ruleFor`, which falls back — conflating the two would make\n * every variant of a required product unremovable.\n */\nfunction variantRuleFor(\n bundle: MixMatchBundleData,\n variantId: string | null | undefined,\n): ProductRule | undefined {\n return variantId ? bundle.variantRules[variantId] : undefined;\n}\n\n/**\n * PRODUCT-LEVEL lock for required products: removing a pick is allowed only\n * while the product's OTHER slots keep it at or above rule.min. This is what\n * lets shoppers swap variants (add Large, then remove Small) without ever\n * dropping the required product out of the bundle. *\n * A required VARIANT is stricter and needs no tally: slots are one per\n * (product, variant), so it has no other slot to fall back on and no sibling\n * may stand in for it. Naming the variant is what takes the swap off the\n * table.\n */\nfunction canRemoveItem(\n bundle: MixMatchBundleData,\n selections: SelectedItem[],\n item: SelectedItem,\n): boolean {\n if (variantRuleFor(bundle, item.variantId)?.required) return false;\n\n const rule = ruleFor(bundle, item.productId);\n if (!rule.required) return true;\n const unitsElsewhere = selections\n .filter((s) => s.productId === item.productId && s !== item)\n .reduce((sum, s) => sum + s.quantity, 0);\n return unitsElsewhere >= rule.min;\n}\n\n/**\n * ATOMIC VARIANT SWAP. A hard-capped required product (rule.min ===\n * rule.max) has no headroom for the add-then-remove variant swap the\n * product-level lock normally allows: adding a second variant would\n * overshoot the cap and removing the committed one would break the floor.\n * For those rows the picker button becomes \"Swap\" — the new variant's\n * units displace sibling-variant units instead of adding on top. Returns\n * the units available to take over, or 0 when the row isn't in the swap\n * state.\n */\nfunction swapUnitsForItem(\n bundle: MixMatchBundleData,\n selections: SelectedItem[],\n productId: string,\n variantId: string,\n): number {\n const rule = ruleFor(bundle, productId);\n if (!rule.required || rule.max !== rule.min) return 0;\n if (selections.some((s) => s.variantId === variantId)) return 0;\n return selections\n .filter((s) => s.productId === productId && s.variantId !== variantId)\n .reduce((sum, s) => sum + s.quantity, 0);\n}\n\nexport interface MixMatchBundleProps extends BundleComponentProps {\n /**\n * Handle of the product page this component is rendered on, when there is\n * one. Enables the theme widget's courtesy seed: with no required products,\n * the bundle starts with this product (or the first that qualifies)\n * pre-added at its rule minimum. Omit on non-product pages to start empty.\n */\n productHandle?: string | null;\n}\n\nexport function MixMatchBundle(props: MixMatchBundleProps) {\n const {\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n appUrl,\n analyticsEnabled,\n onAddToCart,\n onError,\n className,\n productHandle,\n } = props;\n\n const result = useBundleData({\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n });\n\n const { elementRef, trackAddToCart } = useAnalytics({\n shopDomain,\n appUrl: appUrl ?? `https://${shopDomain}`,\n bundleGid,\n bundleType: \"mix_match\",\n enabled: analyticsEnabled !== false,\n });\n\n // An ordered list of picks — one card per slot, in pick order. Matches the\n // theme's `selectedItems` array (one slot per (product, variant) pair — a\n // multi-variant product can fill several slots; the stepper owns each\n // pick's unit count, and completion counts total units vs minQuantity).\n const [selections, setSelections] = useState<SelectedItem[]>([]);\n const [seededFor, setSeededFor] = useState<string | null>(null);\n const [pickerOpen, setPickerOpen] = useState(false);\n const [addingToCart, setAddingToCart] = useState(false);\n const [cartError, setCartError] = useState<string | null>(null);\n\n const bundle =\n result.status === \"success\" && result.bundle.bundleType === \"mix_match\"\n ? (result.bundle as MixMatchBundleData)\n : null;\n\n // Apply merchant-config CSS vars to the widget root.\n const setConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);\n // The picker modal is portaled to document.body — outside the widget root —\n // so it needs its own carrier for the same `--lb-*` vars.\n const setModalConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);\n\n // Scroll-aware edge fade on the chosen-product slot list.\n const slotsEdgeFadeRef = useEdgeFade();\n\n useEffect(() => {\n if (result.status === \"error\") {\n onError?.(result.error);\n return;\n }\n if (\n result.status === \"success\" &&\n result.bundle.bundleType !== \"mix_match\"\n ) {\n onError?.(\n new Error(\n `MixMatchBundle: expected bundleType=\"mix_match\", got \"${result.bundle.bundleType}\"`,\n ),\n );\n }\n }, [result, onError]);\n\n // Seed the way the theme widget does when the bundle arrives: every\n // REQUIRED variant at its own minimum (a named variant beats the product\n // rule for that product), every REQUIRED product at rule.min, and — when\n // nothing is required and the host told us which product page we're on —\n // a courtesy pick of that product (or the first that qualifies) at its\n // rule minimum. Seeds count toward the requirement and required ones can\n // never drop below rule.min (see canRemoveItem).\n useEffect(() => {\n if (!bundle || seededFor === bundle.id) return;\n setSeededFor(bundle.id);\n const seedCurrency =\n bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? \"USD\";\n\n const pick = (\n product: (typeof bundle.products)[number],\n variant: (typeof bundle.products)[number][\"variants\"][\"nodes\"][number],\n quantity: number,\n ): SelectedItem => ({\n productId: product.id,\n variantId: variant.id,\n title: product.title,\n url: `/products/${product.handle}`,\n variantTitle: variant.title,\n featuredImage: variant.image?.url ?? product.featuredImage?.url ?? null,\n price: parseFloat(variant.price.amount),\n compareAtPrice: variant.compareAtPrice\n ? parseFloat(variant.compareAtPrice.amount)\n : null,\n unitPrice: formatUnitPrice(\n variant.unitPrice,\n variant.unitPriceMeasurement,\n seedCurrency,\n ),\n quantity,\n });\n\n const seeds: SelectedItem[] = [];\n for (const product of bundle.products) {\n // Variant-level first: seed every variant the merchant named, at its\n // own minimum. A product with named variants never also carries a\n // product-level `required` — the admin schema enforces it.\n let seededVariant = false;\n for (const variant of product.variants.nodes) {\n const vRule = bundle.variantRules[variant.id];\n if (!vRule?.required) continue;\n if (!isVariantFulfillable(variant, Math.max(1, vRule.min))) continue;\n seeds.push(pick(product, variant, Math.max(1, vRule.min)));\n seededVariant = true;\n }\n if (seededVariant) continue;\n\n const rule = bundle.productRules[product.id];\n if (!rule?.required) continue;\n const variant = product.variants.nodes.find((v) =>\n isVariantFulfillable(v, rule.min),\n );\n if (!variant) continue;\n seeds.push(pick(product, variant, rule.min));\n }\n\n if (seeds.length === 0 && productHandle) {\n const requiredUnits = bundle.minQuantity ?? 0;\n const qualifies = (p: (typeof bundle.products)[number]) => {\n const min = bundle.productRules[p.id]?.min ?? 1;\n return (\n min <= requiredUnits &&\n p.variants.nodes.some((v) => isVariantFulfillable(v, min))\n );\n };\n const seed =\n bundle.products.find(\n (p) => p.handle === productHandle && qualifies(p),\n ) ?? bundle.products.find(qualifies);\n if (seed) {\n const min = bundle.productRules[seed.id]?.min ?? 1;\n const variant = seed.variants.nodes.find((v) =>\n isVariantFulfillable(v, min),\n );\n if (variant) seeds.push(pick(seed, variant, min));\n }\n }\n\n if (seeds.length > 0) setSelections(seeds);\n }, [bundle, seededFor, productHandle]);\n\n const showStepper =\n bundle?.widgetConfig.mixMatchShowQuantitySelector !== false;\n\n // Completion counts TOTAL UNITS across picks (sum of per-pick quantities),\n // not distinct products — one product at qty 3 completes a \"pick 3\" bundle.\n const requiredUnits = bundle?.minQuantity ?? 0;\n\n const totalQuantity = useMemo(\n () => selections.reduce((sum, s) => sum + s.quantity, 0),\n [selections],\n );\n\n const meetsMinUnits = totalQuantity >= requiredUnits && requiredUnits > 0;\n const valid = !!bundle && meetsMinUnits;\n // Capped at requiredUnits for display — over-completion still reads full.\n const shownUnits = Math.min(totalQuantity, requiredUnits);\n const remaining = Math.max(0, requiredUnits - shownUnits);\n\n // Running receipt totals from the current selections — compare (full) and\n // discounted sale price, plus savings + honest rounded percent.\n const summary = useMemo(() => {\n let comparePrice = 0;\n let salePrice = 0;\n for (const sel of selections) {\n if (sel.quantity <= 0) continue;\n comparePrice += sel.price * sel.quantity;\n if (bundle) {\n salePrice +=\n calculateDiscount(\n sel.price,\n bundle.discountConfig.discountType,\n bundle.discountConfig.discountValue,\n ) * sel.quantity;\n }\n }\n const savings = Math.max(0, comparePrice - salePrice);\n const savingsPercent =\n comparePrice > 0 && savings > 0\n ? Math.round((savings / comparePrice) * 100)\n : 0;\n return { comparePrice, salePrice, savings, savingsPercent };\n }, [selections, bundle]);\n\n const addSelection = useCallback(\n (item: SelectedItem) => {\n setSelections((prev) => {\n const units = prev.reduce((sum, s) => sum + s.quantity, 0);\n // EXACT-SIZE: refuse a pick that would push the unit total past\n // requiredUnits — the picker caps the stepper at the remaining\n // open spots, but a stale click must not overshoot. Slots are\n // variant-scoped: refuse a duplicate of an already-committed\n // variant (the row shows the Added toggle for it instead).\n if (units + item.quantity > requiredUnits) return prev;\n if (prev.some((s) => s.variantId === item.variantId)) return prev;\n return [...prev, item];\n });\n },\n [requiredUnits],\n );\n\n // LIVE EDIT of a committed pick's quantity — driven by the picker stepper\n // on an in-bundle row. Setting state re-renders everything downstream\n // (progress, CTA gate, pricing, and every picker row's addability /\n // ceiling — freeing units re-enables rows disabled by the exact-size\n // rule). Removal stays with the Added toggle / slot ×.\n const updateQuantity = useCallback(\n (productId: string, variantId: string, quantity: number) => {\n setSelections((prev) => {\n const idx = prev.findIndex(\n (s) => s.productId === productId && s.variantId === variantId,\n );\n if (idx === -1) return prev;\n const otherUnits = prev.reduce(\n (sum, s, i) => (i === idx ? sum : sum + s.quantity),\n 0,\n );\n // EXACT-SIZE: the committed pick's headroom is its own units plus\n // the bundle's open spots — the unit total must never overshoot\n // requiredUnits, even on a stale click.\n const clamped = Math.max(\n 1,\n Math.min(quantity, requiredUnits - otherUnits),\n );\n if (clamped === prev[idx].quantity) return prev;\n const next = prev.slice();\n next[idx] = { ...next[idx], quantity: clamped };\n return next;\n });\n },\n [requiredUnits],\n );\n\n // ATOMIC VARIANT SWAP for hard-capped required products: replace units\n // of the product's other-variant picks with the new variant. The unit\n // total never moves, so the required floor and the hard cap both hold\n // throughout — which is why this bypasses the canRemoveItem guard (the\n // swap is exactly what that guard exists to enable).\n const swapSelection = useCallback(\n (item: SelectedItem) => {\n setSelections((prev) => {\n if (!bundle) return prev;\n const swapUnits = swapUnitsForItem(\n bundle,\n prev,\n item.productId,\n item.variantId,\n );\n if (swapUnits <= 0) return prev;\n const qty = Math.min(Math.max(1, item.quantity), swapUnits);\n let freed = 0;\n const next: SelectedItem[] = [];\n for (const s of prev) {\n if (\n freed < qty &&\n s.productId === item.productId &&\n s.variantId !== item.variantId\n ) {\n const take = Math.min(s.quantity, qty - freed);\n freed += take;\n if (s.quantity > take) {\n next.push({ ...s, quantity: s.quantity - take });\n }\n } else {\n next.push(s);\n }\n }\n if (freed === 0) return prev;\n next.push({ ...item, quantity: freed });\n return next;\n });\n },\n [bundle],\n );\n\n // Remove the slot holding a variant (the picker's \"Added\" toggle). Slots\n // are variant-scoped, so other variants of the product keep theirs.\n const removeVariant = useCallback(\n (variantId: string) => {\n setSelections((prev) => {\n const idx = prev.findIndex((s) => s.variantId === variantId);\n if (idx === -1) return prev;\n if (bundle && !canRemoveItem(bundle, prev, prev[idx])) return prev;\n const next = prev.slice();\n next.splice(idx, 1);\n return next;\n });\n },\n [bundle],\n );\n\n const removeSlot = useCallback(\n (index: number) => {\n setSelections((prev) => {\n if (index < 0 || index >= prev.length) return prev;\n if (bundle && !canRemoveItem(bundle, prev, prev[index])) return prev;\n const next = prev.slice();\n next.splice(index, 1);\n return next;\n });\n },\n [bundle],\n );\n\n const handleAddToCart = useCallback(async () => {\n if (!bundle || !valid) return;\n\n // Aggregate by (productId, variantId) — duplicate variants across slots\n // collapse into one cart line with summed quantity.\n const grouped = new Map<string, { variantId: string; quantity: number }>();\n for (const sel of selections) {\n if (sel.quantity <= 0) continue;\n const key = `${sel.productId}::${sel.variantId}`;\n const existing = grouped.get(key);\n if (existing) existing.quantity += sel.quantity;\n else grouped.set(key, { variantId: sel.variantId, quantity: sel.quantity });\n }\n\n const lines: CartLineInput[] = Array.from(grouped.values()).map((line) => ({\n merchandiseId: line.variantId,\n quantity: line.quantity,\n attributes: [\n { key: \"_lime_bundle_gid\", value: bundle.id },\n { key: \"_lime_bundle_type\", value: bundle.bundleType },\n ],\n }));\n\n setAddingToCart(true);\n setCartError(null);\n try {\n await onAddToCart(lines);\n\n const totalPrice = selections.reduce(\n (sum, sel) => sum + sel.price * sel.quantity,\n 0,\n );\n // productId omitted — mix-match spans multiple products; bundleGid\n // attributes the event to the bundle.\n trackAddToCart({\n quantity: totalQuantity,\n totalPrice: Math.round(totalPrice * 100) / 100,\n });\n\n setSelections([]);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setCartError(error.message);\n onError?.(error);\n } finally {\n setAddingToCart(false);\n }\n }, [bundle, selections, valid, onAddToCart, onError, trackAddToCart, totalQuantity]);\n\n if (result.status === \"loading\") {\n return (\n <div className={`lb-bundle lb-bundle--loading ${className ?? \"\"}`}>\n <div className=\"lb-skeleton lb-skeleton--title\" />\n <div className=\"lb-skeleton lb-skeleton--products\" />\n </div>\n );\n }\n\n if (result.status === \"error\") return null;\n if (!bundle) return null;\n\n // Bundle visibility guard: don't render unless at least minQuantity distinct\n // in-stock products exist. Deliberately conservative — completion counts\n // total units, so fewer products could technically satisfy the requirement\n // via the stepper, but this mirrors the Liquid `available_count` guard.\n const inStockCount = countInStockProducts(bundle);\n if (requiredUnits > 0 && inStockCount < requiredUnits) return null;\n\n // A required product with no purchasable variant means the bundle can\n // never qualify at checkout — don't render (guards the gap between a\n // live stock drop and the inventory webhook's status flip).\n const requiredBlocked = Object.entries(bundle.productRules).some(\n ([pid, rule]) => {\n if (!rule.required) return false;\n const product = bundle.products.find((p) => p.id === pid);\n return !product?.variants.nodes.some((v) =>\n isVariantFulfillable(v, rule.min),\n );\n },\n );\n if (requiredBlocked) return null;\n\n const currency =\n bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? \"USD\";\n\n // Label stays \"Add to cart\" (or the merchant's custom text) throughout;\n // only the disabled state tracks the unit requirement.\n const ctaLabel = addingToCart\n ? \"Adding...\"\n : bundle.widgetConfig.cta.ctaText || \"Add to cart\";\n\n return (\n <div\n ref={(el) => {\n elementRef(el);\n setConfigVarsRef(el);\n }}\n className={`lb-bundle lb-bundle--mix-match lb-mix-match ${className ?? \"\"}`}\n role=\"region\"\n aria-label={bundle.title}\n data-required-quantity={requiredUnits}\n >\n <div className=\"lb-bundle-header\">\n <div className=\"lb-bundle-header__content\">\n <h3 className=\"lb-bundle-title\">{bundle.title}</h3>\n {bundle.description && (\n <p className=\"lb-bundle-subtitle\">{bundle.description}</p>\n )}\n </div>\n </div>\n\n <BundleCountdown\n endsAt={bundle.endsAt}\n widgetConfig={bundle.widgetConfig}\n />\n\n {/* Segmented progress — one segment per required unit. */}\n <div className=\"lb-mix-match__progress\" data-progress>\n <div\n className=\"lb-mix-match__progress-segments\"\n role=\"progressbar\"\n aria-valuenow={shownUnits}\n aria-valuemin={0}\n aria-valuemax={requiredUnits}\n >\n {Array.from({ length: requiredUnits }).map((_, i) => (\n <span\n key={i}\n className={`lb-mix-match__progress-segment${i < shownUnits ? \" lb-mix-match__progress-segment--filled\" : \"\"}`}\n data-progress-segment\n />\n ))}\n </div>\n <div className=\"lb-mix-match__progress-labels\">\n <span\n className=\"lb-mix-match__progress-count\"\n data-progress-count\n aria-live=\"polite\"\n >\n {`${shownUnits} of ${requiredUnits} added`}\n </span>\n <span\n className=\"lb-mix-match__progress-remaining\"\n data-progress-remaining\n aria-live=\"polite\"\n >\n {remaining > 0 ? `${remaining} more to go` : \"Complete\"}\n </span>\n </div>\n </div>\n\n {/* Chosen-product cards. */}\n <div\n className=\"lb-mix-match__slots lb-edge-fade\"\n data-selection-slots\n ref={slotsEdgeFadeRef}\n >\n {selections.map((item, index) => (\n /* Whole card reopens the picker to edit this pick. The inner title\n button provides the keyboard/AT path (its activation bubbles\n here); × stops propagation. */\n // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions -- keyboard path is the inner \"Edit selection\" title button whose activation bubbles to this handler\n <div\n key={`${item.productId}:${item.variantId}:${index}`}\n className=\"lb-mix-match__slot lb-mix-match__slot--filled\"\n onClick={() => setPickerOpen(true)}\n >\n {item.featuredImage && (\n <div className=\"lb-bundle-thumbnail\">\n <img src={item.featuredImage} alt={item.title} loading=\"lazy\" />\n </div>\n )}\n <div className=\"lb-mix-match__filled-info\">\n <button\n type=\"button\"\n className=\"lb-mix-match__filled-title\"\n aria-label={`Edit selection: ${item.title}`}\n >\n {item.title}\n </button>\n {item.variantTitle && item.variantTitle !== \"Default Title\" && (\n <span className=\"lb-mix-match__filled-variant\">\n {item.variantTitle}\n </span>\n )}\n <span className=\"lb-mix-match__filled-price\">\n {item.compareAtPrice !== null &&\n item.compareAtPrice > item.price && (\n <s className=\"lb-mix-match__filled-compare\">\n {formatMoney(item.compareAtPrice, currency)}\n </s>\n )}\n <span className=\"lb-bundle-product-price\">\n {formatMoney(item.price, currency)}\n </span>\n <span className=\"lb-bundle-qty-inline\">{`×${item.quantity}`}</span>\n </span>\n {item.unitPrice && (\n <span className=\"lb-bundle-product-unit-price\">\n {item.unitPrice}\n </span>\n )}\n </div>\n {canRemoveItem(bundle, selections, item) ? (\n <button\n type=\"button\"\n className=\"lb-mix-match__slot-remove\"\n aria-label={`Remove ${item.title}`}\n onClick={(e) => {\n e.stopPropagation();\n removeSlot(index);\n }}\n >\n <CloseIcon />\n </button>\n ) : (\n /* Required pick at its floor — quiet state chip instead of\n the ×; removal returns once another slot covers the\n product's minimum (variant swap flow). */\n <span className=\"lb-mix-match__slot-required\">Required</span>\n )}\n </div>\n ))}\n </div>\n\n {/* Single dashed \"Add a product\" affordance — hidden once the required\n unit total is met. */}\n {totalQuantity < requiredUnits && (\n <button\n type=\"button\"\n className=\"lb-mix-match__add-product\"\n data-add-product-trigger\n onClick={() => setPickerOpen(true)}\n >\n <span className=\"lb-mix-match__add-product-icon\" aria-hidden=\"true\">\n <PlusIcon />\n </span>\n <span className=\"lb-mix-match__add-product-label\">Add a product</span>\n </button>\n )}\n\n <div className=\"lb-bundle-divider\" />\n\n {selections.length > 0 && (\n <div className=\"lb-bundle-summary\" data-pricing-section>\n <div className=\"lb-bundle-summary__text\">\n <span className=\"lb-bundle-summary__label\">Bundle total</span>\n {bundle.widgetConfig.savingsBar.visible && summary.savings > 0 && (\n <p className=\"lb-bundle-savings-line\" data-savings-bar>\n You save{\" \"}\n <span data-savings-amount>\n {formatMoney(summary.savings, currency)}\n </span>{\" \"}\n <span data-savings-percent>({summary.savingsPercent}%)</span>\n </p>\n )}\n </div>\n <span className=\"lb-bundle-summary__prices\">\n {bundle.widgetConfig.pricing.showComparePrice &&\n summary.savings > 0 && (\n <span className=\"lb-bundle-compare-price\" data-compare-price>\n {formatMoney(summary.comparePrice, currency)}\n </span>\n )}\n <span className=\"lb-bundle-sale-price\" data-sale-price>\n {formatMoney(summary.salePrice, currency)}\n </span>\n </span>\n </div>\n )}\n\n {cartError && (\n <p className=\"lb-bundle__error\" role=\"alert\">\n {cartError}\n </p>\n )}\n\n <button\n className=\"lb-bundle__cta\"\n onClick={handleAddToCart}\n disabled={addingToCart || !valid}\n aria-busy={addingToCart}\n >\n {ctaLabel}\n </button>\n\n {pickerOpen && (\n <MixMatchPicker\n bundle={bundle}\n currency={currency}\n requiredQty={requiredUnits}\n showStepper={showStepper}\n selections={selections}\n onAdd={addSelection}\n onUpdateQuantity={updateQuantity}\n onRemoveVariant={removeVariant}\n canRemoveVariant={(variantId) => {\n const item = selections.find((s) => s.variantId === variantId);\n return item ? canRemoveItem(bundle, selections, item) : true;\n }}\n swapUnitsFor={(productId, variantId) =>\n swapUnitsForItem(bundle, selections, productId, variantId)\n }\n onSwap={swapSelection}\n onClose={() => setPickerOpen(false)}\n styleVarsRef={setModalConfigVarsRef}\n />\n )}\n </div>\n );\n}\n\nfunction countInStockProducts(bundle: MixMatchBundleData): number {\n const seen = new Set<string>();\n let count = 0;\n for (const product of bundle.products) {\n if (seen.has(product.id)) continue;\n seen.add(product.id);\n const rule = ruleFor(bundle, product.id);\n const fulfillable = product.variants.nodes.some(\n (v: ProductVariant) => isVariantFulfillable(v, rule.min),\n );\n if (fulfillable) count += 1;\n }\n return count;\n}\n\nfunction PlusIcon() {\n return (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 18 18\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <line x1=\"9\" y1=\"3\" x2=\"9\" y2=\"15\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n <line x1=\"3\" y1=\"9\" x2=\"15\" y2=\"9\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n\nfunction CloseIcon() {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <line x1=\"5\" y1=\"5\" x2=\"15\" y2=\"15\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n <line x1=\"15\" y1=\"5\" x2=\"5\" y2=\"15\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n","/**\n * Mix-and-match picker modal — portaled to `document.body` so its\n * `position: fixed` overlay isn't clipped by a parent's `transform` /\n * `contain` (common in Shopify themes). Multi-add: the modal stays open as\n * the shopper toggles picks; \"Done\" closes it.\n *\n * Markup, class names and behaviour mirror the storefront theme widget\n * (`extensions/bundle-theme/snippets/lb-mix-match.liquid` +\n * `extensions/bundle-theme/assets/bundle-mix-match.js`) one-for-one so the\n * ported CSS in `bundle.css` styles this tree without changes.\n */\nimport {\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport {\n formatMoney,\n formatUnitPrice,\n isVariantFulfillable,\n maxAddableQuantity,\n DEFAULT_PRODUCT_RULE,\n type MixMatchBundleData,\n type Product,\n type ProductRule,\n type ProductVariant,\n} from \"@lime-bundles/core\";\nimport { VariantDropdown } from \"./VariantDropdown\";\nimport { useVariantSelection } from \"../hooks/useVariantSelection\";\nimport { useScrollLock } from \"../hooks/useScrollLock\";\nimport { useFocusTrap } from \"../hooks/useFocusTrap\";\nimport type { SelectedItem } from \"./mix-match-types\";\n\n/**\n * The rule in force for a pick. Pass `variantId` and the variant's own rule\n * wins; without one this resolves the product rule, which is the envelope\n * covering every variant.\n */\nfunction ruleFor(\n bundle: MixMatchBundleData,\n productId: string,\n variantId?: string | null,\n): ProductRule {\n if (variantId) {\n const vRule = bundle.variantRules[variantId];\n if (vRule) return vRule;\n }\n return bundle.productRules[productId] ?? DEFAULT_PRODUCT_RULE;\n}\n\n/**\n * The variant's OWN rule, or undefined when it inherits the product's.\n * Distinct from `ruleFor`, which falls back — callers that must know which\n * level a rule came from need this one.\n */\nfunction variantRuleFor(\n bundle: MixMatchBundleData,\n variantId: string | null | undefined,\n): ProductRule | undefined {\n return variantId ? bundle.variantRules[variantId] : undefined;\n}\n\nfunction sanitizeId(gid: string): string {\n return gid.replace(/[^a-zA-Z0-9_-]/g, \"-\");\n}\n\ninterface EligibleProduct {\n product: Product;\n variants: ProductVariant[];\n firstAvailableVariant: ProductVariant | null;\n isOos: boolean;\n}\n\nfunction buildEligibleProducts(\n bundle: MixMatchBundleData,\n): EligibleProduct[] {\n const result: EligibleProduct[] = [];\n const seen = new Set<string>();\n for (const product of bundle.products) {\n if (seen.has(product.id)) continue;\n seen.add(product.id);\n const rule = ruleFor(bundle, product.id);\n const available = product.variants.nodes.filter((v) =>\n isVariantFulfillable(v, rule.min),\n );\n // Sold-out products stay in the list greyed out; the status flip hides\n // a bundle that can't be completed.\n const isOos = available.length === 0;\n result.push({\n product,\n variants: product.variants.nodes,\n firstAvailableVariant: available[0] ?? null,\n isOos,\n });\n }\n return result;\n}\n\nfunction normalizeText(str: string): string {\n return str\n .normalize(\"NFD\")\n .replace(/[̀-ͯ]/g, \"\")\n .toLowerCase();\n}\n\nexport interface MixMatchPickerProps {\n bundle: MixMatchBundleData;\n currency: string;\n requiredQty: number;\n showStepper: boolean;\n selections: SelectedItem[];\n /** Add a pick. */\n onAdd: (item: SelectedItem) => void;\n /** Live-edit the committed pick's quantity (in-bundle row stepper).\n * Picks are variant-scoped, so both ids identify the slot. */\n onUpdateQuantity: (\n productId: string,\n variantId: string,\n quantity: number,\n ) => void;\n /** Remove the slot holding this variant (the \"Added\" toggle). Other\n * variants of the same product keep their slots. */\n onRemoveVariant: (variantId: string) => void;\n /** Whether the slot holding this variant may be removed — false only for\n * a required product's last covering pick (product-level lock). */\n canRemoveVariant?: (variantId: string) => boolean;\n /** Units an uncommitted variant of a hard-capped required product could\n * take over in an atomic swap (0 = row isn't in the swap state). */\n swapUnitsFor?: (productId: string, variantId: string) => number;\n /** Perform the atomic swap: the item's units displace sibling-variant\n * units of the same product. */\n onSwap?: (item: SelectedItem) => void;\n onClose: () => void;\n /** CSS-var carrier ref so the portaled overlay inherits merchant theming. */\n styleVarsRef: (el: HTMLElement | null) => void;\n}\n\nconst FILTERS_ALL = \"__all__\";\n\nexport function MixMatchPicker({\n bundle,\n currency,\n requiredQty,\n showStepper,\n selections,\n onAdd,\n onUpdateQuantity,\n onRemoveVariant,\n canRemoveVariant,\n swapUnitsFor,\n onSwap,\n onClose,\n styleVarsRef,\n}: MixMatchPickerProps) {\n const wc = bundle.widgetConfig;\n const overlayRef = useRef<HTMLDivElement | null>(null);\n const dialogRef = useRef<HTMLDivElement | null>(null);\n const closeBtnRef = useRef<HTMLButtonElement | null>(null);\n const mouseDownTarget = useRef<EventTarget | null>(null);\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState(\"\");\n const [activeType, setActiveType] = useState<string>(FILTERS_ALL);\n\n const eligible = useMemo(\n () => buildEligibleProducts(bundle),\n [bundle],\n );\n\n // Product-type filter pills: only when enabled AND there are ≥2 distinct\n // non-empty product types.\n const productTypes = useMemo(() => {\n const types: string[] = [];\n const seen = new Set<string>();\n for (const ep of eligible) {\n const ty = (ep.product.productType ?? \"\").trim();\n if (ty && !seen.has(ty)) {\n seen.add(ty);\n types.push(ty);\n }\n }\n return types;\n }, [eligible]);\n\n const showFilters = wc.mixMatchShowTypeFilters && productTypes.length >= 2;\n\n // Completion counts TOTAL UNITS across picks (sum of per-pick quantities),\n // matching the discount function's unit-based minQuantity gate.\n const totalUnits = selections.reduce((sum, s) => sum + s.quantity, 0);\n const atCapacity = totalUnits >= requiredQty;\n // Capped at requiredQty for display — over-completion still reads full.\n const shownUnits = Math.min(totalUnits, requiredQty);\n\n // Trigger the open transition on mount (display already shown).\n useEffect(() => {\n const id = requestAnimationFrame(() => setOpen(true));\n return () => cancelAnimationFrame(id);\n }, []);\n\n useScrollLock(true);\n // Initial focus lands on the close icon, not the search input — focusing\n // search on a phone pops the keyboard over half the modal unasked.\n useFocusTrap({\n active: true,\n containerRef: dialogRef,\n initialFocusRef: closeBtnRef,\n onEscape: onClose,\n });\n\n const remaining = Math.max(0, requiredQty - shownUnits);\n const subtitle = (() => {\n if (remaining <= 0) return \"Your bundle is complete\";\n const pct =\n bundle.discountConfig.discountType === \"percentage\" &&\n bundle.discountConfig.discountValue\n ? Math.round(bundle.discountConfig.discountValue)\n : 0;\n return pct > 0\n ? `Choose ${remaining} more to unlock ${pct}% off`\n : `Choose ${remaining} more to complete your bundle`;\n })();\n\n // Products already in the bundle when the modal opened (required seeds\n // included) sink below the ones still to pick. The snapshot is captured\n // once at mount — re-sorting live on add/remove would make the list jump\n // under the shopper's finger; the next open recomputes it.\n const [selectedAtOpen] = useState(\n () => new Set(selections.map((s) => s.productId)),\n );\n const ordered = useMemo(() => {\n const front: EligibleProduct[] = [];\n const back: EligibleProduct[] = [];\n for (const ep of eligible) {\n (selectedAtOpen.has(ep.product.id) ? back : front).push(ep);\n }\n return front.concat(back);\n }, [eligible, selectedAtOpen]);\n\n const filtered = useMemo(() => {\n const nq = normalizeText(query.trim());\n return ordered.filter((ep) => {\n const matchesQuery =\n !nq || normalizeText(ep.product.title).includes(nq);\n const matchesType =\n activeType === FILTERS_ALL ||\n (ep.product.productType ?? \"\") === activeType;\n return matchesQuery && matchesType;\n });\n }, [ordered, query, activeType]);\n\n const showEmpty = filtered.length === 0 && query.trim().length > 0;\n\n function onOverlayMouseDown(e: React.MouseEvent) {\n mouseDownTarget.current = e.target;\n }\n function onOverlayMouseUp(e: React.MouseEvent) {\n if (e.target === overlayRef.current && mouseDownTarget.current === overlayRef.current) {\n onClose();\n }\n mouseDownTarget.current = null;\n }\n\n const titleId = `lb-modal-title-${sanitizeId(bundle.id)}`;\n\n const modal = (\n // The overlay is a backdrop: click-outside-to-close is a mouse convenience;\n // keyboard users close via Escape (handled by useFocusTrap), and the dialog\n // inside carries the interactive role + focus trap. So the static-element\n // interaction lint does not apply to this backdrop.\n // eslint-disable-next-line jsx-a11y/no-static-element-interactions\n <div\n ref={(el) => {\n overlayRef.current = el;\n styleVarsRef(el);\n }}\n className={`lb-mix-match__modal-overlay${open ? \" lb-mix-match__modal-overlay--open\" : \"\"}`}\n data-modal-overlay\n data-bundle-gid={bundle.id}\n onMouseDown={onOverlayMouseDown}\n onMouseUp={onOverlayMouseUp}\n >\n <div\n ref={dialogRef}\n className={`lb-mix-match__modal${showFilters ? \"\" : \" lb-mix-match__modal--filters-hidden\"}`}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n tabIndex={-1}\n >\n <div className=\"lb-mix-match__modal-header\">\n <div className=\"lb-mix-match__modal-header-top\">\n <div className=\"lb-mix-match__modal-heading\">\n <h4 className=\"lb-mix-match__modal-title\" id={titleId}>\n Add to your bundle\n </h4>\n <p className=\"lb-mix-match__modal-subtitle\" data-modal-subtitle>\n {subtitle}\n </p>\n </div>\n <button\n ref={closeBtnRef}\n type=\"button\"\n className=\"lb-mix-match__modal-close\"\n data-modal-close\n aria-label=\"Close\"\n onClick={onClose}\n >\n <CloseIcon />\n </button>\n </div>\n <div\n className=\"lb-mix-match__progress lb-mix-match__modal-progress\"\n data-progress\n >\n <div\n className=\"lb-mix-match__progress-segments\"\n role=\"progressbar\"\n aria-valuenow={shownUnits}\n aria-valuemin={0}\n aria-valuemax={requiredQty}\n >\n {Array.from({ length: requiredQty }).map((_, i) => (\n <span\n key={i}\n className={`lb-mix-match__progress-segment${i < shownUnits ? \" lb-mix-match__progress-segment--filled\" : \"\"}`}\n data-progress-segment\n />\n ))}\n </div>\n </div>\n </div>\n\n {wc.showSearch && (\n <div className=\"lb-mix-match__modal-search\">\n <input\n type=\"text\"\n className=\"lb-mix-match__modal-search-input\"\n data-modal-search\n role=\"searchbox\"\n aria-label=\"Search products\"\n placeholder=\"Search products\"\n autoComplete=\"off\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n />\n {query.length > 0 && (\n <button\n type=\"button\"\n className=\"lb-mix-match__modal-search-clear\"\n data-modal-search-clear\n aria-label=\"Clear search\"\n onClick={() => setQuery(\"\")}\n >\n <SearchClearIcon />\n </button>\n )}\n </div>\n )}\n\n {showFilters && (\n <div\n className=\"lb-mix-match__filters\"\n data-modal-filters\n role=\"group\"\n aria-label=\"Filter by product type\"\n >\n {[FILTERS_ALL, ...productTypes].map((value) => {\n const isActive = value === activeType;\n return (\n <button\n key={value}\n type=\"button\"\n className={`lb-mix-match__filter${isActive ? \" lb-mix-match__filter--active\" : \"\"}`}\n data-filter={value}\n aria-pressed={isActive}\n onClick={() => setActiveType(value)}\n >\n {value === FILTERS_ALL ? \"All\" : value}\n </button>\n );\n })}\n </div>\n )}\n\n <div className=\"lb-mix-match__modal-list\" data-modal-list>\n {filtered.map((ep) => (\n <MixMatchPickerRow\n key={ep.product.id}\n bundle={bundle}\n eligible={ep}\n currency={currency}\n showStepper={showStepper}\n selections={selections}\n atCapacity={atCapacity}\n remainingUnits={remaining}\n onAdd={onAdd}\n onUpdateQuantity={onUpdateQuantity}\n onRemoveVariant={onRemoveVariant}\n canRemoveVariant={canRemoveVariant}\n swapUnitsFor={swapUnitsFor}\n onSwap={onSwap}\n />\n ))}\n </div>\n\n {showEmpty && (\n <div className=\"lb-mix-match__modal-empty\" data-modal-empty>\n <p>No products match your search</p>\n </div>\n )}\n\n <span data-modal-live aria-live=\"polite\" className=\"lb-visually-hidden\">\n {`${filtered.length} products shown`}\n </span>\n\n <div className=\"lb-mix-match__modal-footer\">\n <span\n className=\"lb-mix-match__modal-footer-count\"\n data-modal-footer-count\n aria-live=\"polite\"\n >\n {`${shownUnits} of ${requiredQty} added`}\n </span>\n <button\n type=\"button\"\n className=\"lb-mix-match__modal-done\"\n data-modal-done\n onClick={onClose}\n >\n Done\n </button>\n </div>\n </div>\n </div>\n );\n\n if (typeof document === \"undefined\") return null;\n return createPortal(modal, document.body);\n}\n\ninterface MixMatchPickerRowProps {\n bundle: MixMatchBundleData;\n eligible: EligibleProduct;\n currency: string;\n showStepper: boolean;\n selections: SelectedItem[];\n atCapacity: boolean;\n /** Open spots left in the bundle (requiredQty minus total units).\n * EXACT-SIZE: an unselected row whose rule.min exceeds this can't be\n * added, and the pre-add stepper caps at it. An in-bundle row's\n * headroom is its committed units plus this. */\n remainingUnits: number;\n onAdd: (item: SelectedItem) => void;\n onUpdateQuantity: (\n productId: string,\n variantId: string,\n quantity: number,\n ) => void;\n onRemoveVariant: (variantId: string) => void;\n canRemoveVariant?: (variantId: string) => boolean;\n swapUnitsFor?: (productId: string, variantId: string) => number;\n onSwap?: (item: SelectedItem) => void;\n}\n\nfunction MixMatchPickerRow({\n bundle,\n eligible,\n currency,\n showStepper,\n selections,\n atCapacity,\n remainingUnits,\n onAdd,\n onUpdateQuantity,\n onRemoveVariant,\n canRemoveVariant,\n swapUnitsFor,\n onSwap,\n}: MixMatchPickerRowProps) {\n const { product, variants, isOos } = eligible;\n const rule = ruleFor(bundle, product.id);\n\n const optionNames = useMemo<string[]>(() => {\n const first = variants[0];\n return first ? first.selectedOptions.map((o) => o.name) : [];\n }, [variants]);\n const showPicker = variants.length > 1 && optionNames.length > 0;\n\n const { selectedValues, selectedVariant, setOptionValue, optionsFor } =\n useVariantSelection({ variants, optionNames });\n\n const currentVariant =\n selectedVariant ??\n variants.find((v) => isVariantFulfillable(v, rule.min)) ??\n eligible.firstAvailableVariant ??\n variants[0] ??\n null;\n\n // The rule in force for this row. `rule` above stays the PRODUCT envelope\n // and is used wherever the question is about the product's total across\n // variants; `vRule` is what bounds this variant's own pick.\n const vRule = ruleFor(bundle, product.id, currentVariant?.id);\n const variantMax = variantRuleFor(bundle, currentVariant?.id)?.max;\n\n // Aggregate units of the current variant already pinned to the bundle — used\n // for the stock cap.\n const alreadyInBundle = useMemo(() => {\n if (!currentVariant) return 0;\n let sum = 0;\n for (const s of selections) {\n if (s.productId === product.id && s.variantId === currentVariant.id) {\n sum += s.quantity;\n }\n }\n return sum;\n }, [selections, product.id, currentVariant]);\n\n // Slots are VARIANT-scoped: the row's Added state, live stepper, and tint\n // all follow its currently-selected variant. Switching the dropdowns to an\n // uncommitted variant reverts the row to \"Add\" while the committed variant\n // keeps its slot — that's how a multi-variant product fills several slots.\n const committedSelection = useMemo(\n () =>\n currentVariant\n ? (selections.find((s) => s.variantId === currentVariant.id) ?? null)\n : null,\n [selections, currentVariant],\n );\n const variantInBundle = committedSelection !== null;\n const committedQty = committedSelection?.quantity ?? 0;\n\n // The merchant's rule.max caps the PRODUCT's total units across all its\n // variant slots, so sibling-variant slots reduce this row's share of it.\n const productOtherUnits = useMemo(() => {\n if (!currentVariant) return 0;\n let sum = 0;\n for (const s of selections) {\n if (s.productId === product.id && s.variantId !== currentVariant.id) {\n sum += s.quantity;\n }\n }\n return sum;\n }, [selections, product.id, currentVariant]);\n\n // ATOMIC SWAP state: a hard-capped required product's uncommitted\n // variants displace sibling units instead of adding, so the exact-size\n // and capacity gates don't apply and the ceiling is the units they can\n // take over.\n const swapUnits = currentVariant\n ? (swapUnitsFor?.(product.id, currentVariant.id) ?? 0)\n : 0;\n const inSwapState = swapUnits >= vRule.min;\n // EXACT-SIZE ceiling: an unselected row (committedQty 0) can add at most\n // the bundle's remaining open spots, so the pre-add stepper caps at\n // min(product headroom, remainingUnits). A committed (in-bundle) row edits\n // its pick LIVE — its own units already count toward the total, so its\n // headroom is its committed qty plus the open spots. Own committed units\n // draw from the same stock pool the stepper edits, so only units of this\n // variant held by OTHER slots reduce availability.\n // The variant's own cap binds independently of the envelope: sibling units\n // eat into the product's total, never into this variant's allowance.\n const spotCeiling = inSwapState\n ? swapUnits\n : Math.min(\n rule.max - productOtherUnits,\n committedQty + remainingUnits,\n variantMax ?? Infinity,\n );\n const cap = currentVariant\n ? maxAddableQuantity(\n currentVariant,\n spotCeiling,\n Math.max(0, alreadyInBundle - committedQty),\n )\n : 0;\n const stepperMax = Math.max(vRule.min, cap);\n\n const [qty, setQty] = useState(vRule.min);\n\n // Clamp the local qty whenever the bounds move (variant change / cross-slot\n // stock accounting), and reset to rule.min when the row's variant leaves\n // the bundle OR the shopper switches to an uncommitted variant — a fresh\n // pick shouldn't drag the previous variant's qty over.\n useEffect(() => {\n setQty((prev) => Math.max(vRule.min, Math.min(prev, stepperMax)));\n }, [stepperMax, vRule.min]);\n const currentVariantId = currentVariant?.id ?? null;\n useEffect(() => {\n if (!variantInBundle) setQty(vRule.min);\n }, [variantInBundle, currentVariantId, vRule.min]);\n\n if (!currentVariant) return null;\n\n const thumbImage = currentVariant.image ?? product.featuredImage ?? null;\n const unitPriceText = formatUnitPrice(\n currentVariant.unitPrice,\n currentVariant.unitPriceMeasurement,\n currency,\n );\n\n // Add disabled when: bundle full, stock (or the product's rule.max,\n // exhausted by sibling-variant slots) can't satisfy rule.min, or the\n // product's rule.min exceeds the remaining open spots (exact-size\n // enforcement — adding it would overshoot requiredQty).\n const noStock = cap < vRule.min;\n const needsMoreSpots =\n !variantInBundle && !inSwapState && vRule.min > remainingUnits;\n // A swap frees its own room, so only stock can block it.\n const addDisabled =\n !variantInBundle &&\n (inSwapState ? noStock : atCapacity || noStock || needsMoreSpots);\n // Required product's last covering pick — the Remove slot goes inert\n // (\"Required\"); removal returns once another slot covers the minimum.\n const lockedRequired =\n variantInBundle &&\n currentVariant != null &&\n !(canRemoveVariant?.(currentVariant.id) ?? true);\n // An in-bundle row keeps its stepper ENABLED — it edits the committed\n // pick's quantity live, bounded by [rule.min, stepperMax]. Unselected\n // rows lock the stepper together with Add.\n const stepperDisabled = isOos || (!variantInBundle && addDisabled);\n // The stepper shows (and edits) the committed qty while in the bundle,\n // and the local pre-add qty otherwise.\n const shownQty = variantInBundle ? committedQty : qty;\n\n function handleAddOrRemove() {\n if (variantInBundle && currentVariant) {\n onRemoveVariant(currentVariant.id);\n return;\n }\n if (!currentVariant || noStock) return;\n const pickedQty = showStepper ? qty : vRule.min;\n const item = {\n productId: product.id,\n variantId: currentVariant.id,\n title: product.title,\n url: `/products/${product.handle}`,\n variantTitle: currentVariant.title,\n featuredImage: thumbImage?.url ?? null,\n price: parseFloat(currentVariant.price.amount),\n compareAtPrice: currentVariant.compareAtPrice\n ? parseFloat(currentVariant.compareAtPrice.amount)\n : null,\n unitPrice: unitPriceText,\n quantity: pickedQty,\n };\n // ATOMIC SWAP: displaces sibling units, so it runs before (and\n // instead of) the capacity gates.\n if (inSwapState && onSwap) {\n onSwap({ ...item, quantity: Math.min(pickedQty, swapUnits) });\n return;\n }\n if (atCapacity || needsMoreSpots) return;\n onAdd(item);\n }\n\n const priceCents = parseFloat(currentVariant.price.amount);\n const compareCents = currentVariant.compareAtPrice\n ? parseFloat(currentVariant.compareAtPrice.amount)\n : null;\n\n return (\n <div\n className={`lb-mix-match__modal-product${isOos ? \" lb-mix-match__modal-product--sold-out\" : \"\"}${variantInBundle ? \" lb-mix-match__modal-product--in-bundle\" : \"\"}`}\n data-product-item\n data-title={normalizeText(product.title)}\n data-type={product.productType ?? \"\"}\n aria-disabled={isOos || undefined}\n >\n <div className=\"lb-mix-match__modal-product-thumb\">\n {thumbImage && (\n <img\n src={thumbImage.url}\n alt={thumbImage.altText ?? product.title}\n loading=\"lazy\"\n // Intrinsic dimensions reserve the \"original\"-ratio box pre-load\n // (issue #302); inert for the cropped ratios, where CSS sizes it.\n width={thumbImage.width ?? undefined}\n height={thumbImage.height ?? undefined}\n />\n )}\n {variantInBundle && (\n <span className=\"lb-mix-match__modal-added-badge\">Added</span>\n )}\n </div>\n\n <div className=\"lb-mix-match__modal-product-info\">\n {/* New tab keeps the in-progress bundle alive — same-tab navigation\n would wipe the shopper's picks. */}\n <p className=\"lb-mix-match__modal-product-title\">\n <a\n href={`/products/${product.handle}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {product.title}\n </a>\n </p>\n <p className=\"lb-mix-match__modal-product-price\">\n <span data-row-price-sale>{formatMoney(priceCents, currency)}</span>\n {compareCents !== null && compareCents > priceCents && (\n <s className=\"lb-mix-match__modal-product-compare\" data-row-compare>\n {formatMoney(compareCents, currency)}\n </s>\n )}\n </p>\n {unitPriceText && (\n <p className=\"lb-mix-match__modal-product-unit-price lb-bundle-product-unit-price\">\n {unitPriceText}\n </p>\n )}\n\n {showPicker && (\n <div className=\"lb-bundle-variant-option-groups\">\n {optionNames.map((optionName, optionIndex) => {\n const dropdownOptions = optionsFor(optionIndex).map((o) => ({\n value: o.value,\n label: o.value,\n disabled: o.disabled,\n }));\n return (\n <div\n key={optionName}\n className=\"lb-bundle-variant-option-group\"\n >\n <span className=\"lb-bundle-variant-option-label\">\n {optionName}\n </span>\n <VariantDropdown\n className=\"lb-mix-match__variant-select-dropdown\"\n options={dropdownOptions}\n value={selectedValues[optionIndex] ?? null}\n onChange={(v) => setOptionValue(optionIndex, v)}\n ariaLabel={optionName}\n />\n </div>\n );\n })}\n </div>\n )}\n {!showPicker &&\n variants.length === 1 &&\n currentVariant.title !== \"Default Title\" && (\n <span className=\"lb-mix-match__filled-variant\">\n {currentVariant.title}\n </span>\n )}\n\n {/* \"Needs N spots\" hint — exact-size enforcement: rule.min exceeds\n the remaining open spots, so Add and the stepper are disabled.\n Hidden at capacity (remaining 0), where the modal's complete\n state already tells the story for every row. */}\n {!isOos && needsMoreSpots && remainingUnits > 0 && (\n <span className=\"lb-mix-match__modal-needs-spots\">\n {rule.min === 1 ? \"Needs 1 spot\" : `Needs ${rule.min} spots`}\n </span>\n )}\n\n {isOos ? (\n <span className=\"lb-mix-match__modal-sold-out-label\">Sold out</span>\n ) : (\n <div className=\"lb-mix-match__modal-product-actions\">\n {showStepper && (\n <div className=\"lb-bundle-variant-option-group lb-mix-match__qty-stepper-group\">\n <div\n className=\"lb-mix-match__qty-stepper\"\n role=\"group\"\n aria-label=\"Quantity\"\n >\n <button\n type=\"button\"\n className=\"lb-mix-match__qty-stepper-button lb-mix-match__qty-stepper-button--minus\"\n aria-label=\"Decrease quantity\"\n disabled={stepperDisabled || shownQty <= rule.min}\n onClick={() => {\n if (variantInBundle && currentVariant) {\n // LIVE EDIT — propagate into selections state so\n // progress, CTA, pricing, and every other row's\n // addability re-evaluate immediately.\n onUpdateQuantity(\n product.id,\n currentVariant.id,\n Math.max(rule.min, committedQty - 1),\n );\n } else {\n setQty((q) => Math.max(rule.min, q - 1));\n }\n }}\n >\n {\"−\"}\n </button>\n <span\n className=\"lb-mix-match__qty-stepper-value\"\n data-row-qty\n aria-live=\"polite\"\n >\n {shownQty}\n </span>\n <button\n type=\"button\"\n className=\"lb-mix-match__qty-stepper-button lb-mix-match__qty-stepper-button--plus\"\n aria-label=\"Increase quantity\"\n disabled={stepperDisabled || shownQty >= stepperMax}\n onClick={() => {\n if (variantInBundle && currentVariant) {\n onUpdateQuantity(\n product.id,\n currentVariant.id,\n Math.min(stepperMax, committedQty + 1),\n );\n } else {\n setQty((q) => Math.min(stepperMax, q + 1));\n }\n }}\n >\n +\n </button>\n </div>\n </div>\n )}\n <button\n type=\"button\"\n className={`lb-mix-match__modal-add${variantInBundle ? \" lb-mix-match__modal-add--added\" : \"\"}${lockedRequired ? \" lb-mix-match__modal-add--required\" : \"\"}`}\n data-add-product\n aria-label={\n variantInBundle\n ? lockedRequired\n ? `${product.title} is required and cannot be removed`\n : `Remove ${product.title}`\n : `${inSwapState ? \"Swap\" : \"Add\"} ${product.title}`\n }\n disabled={addDisabled || lockedRequired}\n onClick={handleAddOrRemove}\n >\n {/* Explicit inverted \"Remove\" — state feedback lives on the\n thumbnail's \"Added\" badge, not the button. */}\n {variantInBundle\n ? lockedRequired\n ? \"Required\"\n : \"Remove\"\n : inSwapState\n ? \"Swap\"\n : \"Add\"}\n </button>\n </div>\n )}\n </div>\n </div>\n );\n}\n\nfunction CloseIcon() {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <line x1=\"5\" y1=\"5\" x2=\"15\" y2=\"15\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n <line x1=\"15\" y1=\"5\" x2=\"5\" y2=\"15\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n\nfunction SearchClearIcon() {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path d=\"M14.348 5.652a.5.5 0 0 0-.707 0L10 9.293 6.36 5.652a.5.5 0 1 0-.708.707L9.293 10l-3.641 3.641a.5.5 0 0 0 .708.707L10 10.707l3.641 3.641a.5.5 0 0 0 .707-.707L10.707 10l3.641-3.641a.5.5 0 0 0 0-.707z\" />\n </svg>\n );\n}\n","/**\n * Lock background scroll while a modal is open. iOS-safe: pins `<body>` to a\n * fixed position offset by the current scroll, then restores it on unlock.\n *\n * Mirrors the `scrollLock` helper in\n * `extensions/bundle-theme/assets/bundle-mix-match.js`. A module-level lock\n * count keeps nested/overlapping locks (e.g. two bundle widgets on one page)\n * from clobbering each other's body styles.\n */\nimport { useEffect } from \"react\";\n\nlet lockCount = 0;\nlet savedY = 0;\n\nfunction lock() {\n if (typeof document === \"undefined\") return;\n lockCount += 1;\n if (lockCount > 1) return;\n savedY = window.pageYOffset || document.documentElement.scrollTop;\n const body = document.body;\n body.style.position = \"fixed\";\n body.style.top = `-${savedY}px`;\n body.style.left = \"0\";\n body.style.right = \"0\";\n body.style.overflow = \"hidden\";\n}\n\nfunction unlock() {\n if (typeof document === \"undefined\") return;\n if (lockCount <= 0) return;\n lockCount -= 1;\n if (lockCount > 0) return;\n const body = document.body;\n body.style.position = \"\";\n body.style.top = \"\";\n body.style.left = \"\";\n body.style.right = \"\";\n body.style.overflow = \"\";\n window.scrollTo(0, savedY);\n}\n\n/** Lock background scroll while `active` is true. Unlocks on false/unmount. */\nexport function useScrollLock(active: boolean): void {\n useEffect(() => {\n if (!active) return;\n lock();\n return unlock;\n }, [active]);\n}\n","/**\n * Trap keyboard focus inside a container while a modal is open, handle the\n * Escape key, and restore focus to whatever was focused before the modal\n * opened (or to a caller-supplied element).\n *\n * Mirrors the focus-trap + Escape handling in\n * `extensions/bundle-theme/assets/bundle-mix-match.js`. The container ref is\n * the dialog element; Tab/Shift+Tab cycle within its focusable descendants.\n */\nimport { useEffect, useRef, type RefObject } from \"react\";\n\nconst FOCUSABLE_SELECTOR = [\n \"a[href]\",\n \"button:not([disabled])\",\n \"input:not([disabled])\",\n \"select:not([disabled])\",\n \"textarea:not([disabled])\",\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(\",\");\n\nfunction getFocusable(container: HTMLElement): HTMLElement[] {\n const nodes = container.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR);\n const result: HTMLElement[] = [];\n nodes.forEach((node) => {\n // offsetParent === null filters out display:none nodes (jsdom returns\n // null for everything, so the trap is a no-op there — acceptable, the\n // browser is the surface that matters).\n if (node.offsetParent !== null || typeof node.offsetParent === \"undefined\") {\n result.push(node);\n }\n });\n return result;\n}\n\nexport interface UseFocusTrapOptions {\n active: boolean;\n containerRef: RefObject<HTMLElement | null>;\n /** Called when Escape is pressed. */\n onEscape: () => void;\n /**\n * Element to focus when the trap activates (e.g. the modal's close\n * button — focusing an input here would pop the mobile keyboard over the\n * modal). Falls back to the container itself.\n */\n initialFocusRef?: RefObject<HTMLElement | null>;\n /**\n * Where to send focus when the trap deactivates. When omitted, focus is\n * restored to the element that was focused when the trap activated.\n */\n returnFocusRef?: RefObject<HTMLElement | null>;\n}\n\nexport function useFocusTrap({\n active,\n containerRef,\n onEscape,\n initialFocusRef,\n returnFocusRef,\n}: UseFocusTrapOptions): void {\n const previouslyFocused = useRef<HTMLElement | null>(null);\n\n useEffect(() => {\n if (!active) return;\n const container = containerRef.current;\n previouslyFocused.current =\n (document.activeElement as HTMLElement | null) ?? null;\n\n // Focus the caller's initial target (falling back to the dialog itself)\n // on open so Escape works immediately.\n const initial = initialFocusRef?.current ?? container;\n initial?.focus();\n\n function onKeyDown(e: KeyboardEvent) {\n if (e.key === \"Escape\") {\n e.preventDefault();\n onEscape();\n return;\n }\n if (e.key !== \"Tab\") return;\n const node = containerRef.current;\n if (!node) return;\n const focusable = getFocusable(node);\n if (focusable.length === 0) {\n e.preventDefault();\n return;\n }\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n const activeEl = document.activeElement;\n if (e.shiftKey && activeEl === first) {\n e.preventDefault();\n last.focus();\n } else if (!e.shiftKey && activeEl === last) {\n e.preventDefault();\n first.focus();\n }\n }\n\n document.addEventListener(\"keydown\", onKeyDown);\n return () => {\n document.removeEventListener(\"keydown\", onKeyDown);\n // Reading the ref at cleanup time is deliberate: focus must return to\n // wherever the caller's ref points when the trap closes (the node may\n // have mounted after activation), not to a snapshot from open time.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const target = returnFocusRef?.current ?? previouslyFocused.current;\n // Defer so focus restore lands after React has flushed the close.\n if (target && typeof target.focus === \"function\") {\n target.focus();\n }\n };\n // onEscape / initialFocusRef / returnFocusRef are stable enough for our\n // callers; re-running on `active` toggle is what matters.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [active]);\n}\n","/**\n * Volume bundle component — quantity selector with tier calculator.\n */\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport {\n formatMoney,\n formatUnitPrice,\n calculateTierSavings,\n getActiveTier,\n getMinTierQuantity,\n bestValueTierIndex,\n resolveDefaultTierIndex,\n resolvePopularTierIndex,\n isVariantFulfillable,\n resolveContextProduct,\n shouldShowLowStockBadge,\n type CartLineInput,\n type VolumeBundleData,\n} from \"@lime-bundles/core\";\nimport { useBundleData } from \"../hooks/useBundleData\";\nimport { useAnalytics } from \"../hooks/useAnalytics\";\nimport { useWidgetConfigVars } from \"../hooks/useWidgetConfigVars\";\nimport { useVariantSelection } from \"../hooks/useVariantSelection\";\nimport { useEdgeFade } from \"../hooks/useEdgeFade\";\nimport { VariantDropdown } from \"./VariantDropdown\";\nimport type { BundleComponentProps } from \"./types\";\nimport { BundleCountdown } from \"./BundleCountdown\";\n\nexport function VolumeBundle(props: BundleComponentProps) {\n const {\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n appUrl,\n analyticsEnabled,\n onAddToCart,\n onError,\n className,\n productId,\n } = props;\n\n const result = useBundleData({\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n });\n\n const { elementRef, trackAddToCart } = useAnalytics({\n shopDomain,\n appUrl: appUrl ?? `https://${shopDomain}`,\n bundleGid,\n bundleType: \"volume\",\n enabled: analyticsEnabled !== false,\n });\n\n const [quantity, setQuantity] = useState(1);\n const [addingToCart, setAddingToCart] = useState(false);\n const [cartError, setCartError] = useState<string | null>(null);\n const [seededFor, setSeededFor] = useState<string | null>(null);\n\n const bundle =\n result.status === \"success\" && result.bundle.bundleType === \"volume\"\n ? (result.bundle as VolumeBundleData)\n : null;\n\n // Start on the merchant's configured default tier, the way the Liquid\n // widget pre-selects it — once per bundle, so shopper interaction wins\n // from then on.\n useEffect(() => {\n if (!bundle || seededFor === bundle.id) return;\n setSeededFor(bundle.id);\n const tiers = bundle.volumeTiers;\n if (tiers.length === 0) return;\n const best = bestValueTierIndex(\n tiers,\n bundle.discountConfig.discountType,\n );\n const idx = resolveDefaultTierIndex(\n bundle.widgetConfig.defaultTier,\n tiers.length,\n best,\n );\n setQuantity(tiers[idx].minQuantity);\n }, [bundle, seededFor]);\n\n // Apply merchant-config CSS vars to the component root via a callback\n // ref composed with elementRef.\n const setConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);\n\n // Scroll-aware edge fade on the inset tier list.\n const tiersEdgeFadeRef = useEdgeFade();\n\n useEffect(() => {\n if (result.status === \"error\") {\n onError?.(result.error);\n return;\n }\n if (result.status === \"success\" && result.bundle.bundleType !== \"volume\") {\n onError?.(\n new Error(\n `VolumeBundle: expected bundleType=\"volume\", got \"${result.bundle.bundleType}\"`,\n ),\n );\n }\n }, [result, onError]);\n\n // The product this page is standing on (via the host's `productId` prop),\n // the way the theme widget binds to Liquid's `product`; the bundle's\n // first product only when the host supplied no context.\n const product = bundle\n ? resolveContextProduct(bundle.products, { productId })\n : undefined;\n const variants = useMemo(() => product?.variants.nodes ?? [], [product]);\n const optionNames = useMemo<string[]>(() => {\n const first = variants[0];\n return first ? first.selectedOptions.map((o) => o.name) : [];\n }, [variants]);\n const showPicker = variants.length > 1 && optionNames.length > 0;\n const { selectedValues, selectedVariant, setOptionValue, optionsFor } =\n useVariantSelection({ variants, optionNames });\n\n // Volume bundle: floor of fulfillability is the smallest tier's\n // minQuantity (anything below that can't even buy the cheapest tier).\n const minTierQty = bundle ? getMinTierQuantity(bundle.volumeTiers) : 1;\n /**\n * True when no variant can cover even the cheapest tier. The fallback to\n * `variants[0]` below keeps prices on screen, but without this flag the CTA\n * stayed live and add-to-cart silently bailed on `!variant`.\n */\n const isSoldOut =\n variants.length > 0 &&\n !variants.some((v) => isVariantFulfillable(v, minTierQty));\n const displayVariant =\n selectedVariant ??\n variants.find((v) => isVariantFulfillable(v, minTierQty)) ??\n variants[0];\n /**\n * Whether the display variant can cover a given tier's quantity. A \"buy 6\"\n * tier with 3 units left used to render live on every surface; the shopper\n * clicked through to a cart Shopify capped at add time.\n */\n const tierAvailable = useCallback(\n (tierQty: number): boolean =>\n Boolean(displayVariant && isVariantFulfillable(displayVariant, tierQty)),\n [displayVariant],\n );\n // The selected tier can become unavailable when the shopper switches to a\n // shallower-stocked variant; the CTA locks rather than silently bailing.\n const selectedTierUnavailable = !isSoldOut && !tierAvailable(quantity);\n const basePrice = displayVariant\n ? parseFloat(displayVariant.price.amount)\n : product\n ? parseFloat(product.priceRange.minVariantPrice.amount)\n : 0;\n const currency = product?.priceRange.minVariantPrice.currencyCode ?? \"USD\";\n const thumbImage = displayVariant?.image ?? product?.featuredImage ?? null;\n const unitPriceText = displayVariant\n ? formatUnitPrice(\n displayVariant.unitPrice,\n displayVariant.unitPriceMeasurement,\n currency,\n )\n : null;\n\n const tierSavings = useMemo(\n () =>\n bundle\n ? calculateTierSavings(\n bundle.volumeTiers,\n basePrice,\n quantity,\n bundle.discountConfig.discountType,\n )\n : [],\n [bundle, basePrice, quantity],\n );\n const activeTier = bundle\n ? getActiveTier(bundle.volumeTiers, quantity)\n : null;\n\n // Which tier wears the \"Most popular\" badge — the same resolution the\n // Liquid and web-component hosts run: the merchant's pinned tierIndex\n // (deliberately unclamped, so an out-of-range pin badges nothing), else\n // the best-savings tier ranked the way the theme ranks it.\n const popularTierIndex = useMemo(() => {\n if (!bundle || bundle.volumeTiers.length === 0) return -1;\n return resolvePopularTierIndex(\n bundle.widgetConfig.popularBadge.tierIndex,\n bundle.widgetConfig.popularBadge.visible !== false,\n bestValueTierIndex(\n bundle.volumeTiers,\n bundle.discountConfig.discountType,\n ),\n );\n }, [bundle]);\n\n // Receipt summary — total = active tier's discounted unit price × qty\n // (full base price when no tier is active yet). Compare-at = base × qty.\n // Mirrors the storefront volume widget's summary band + savings line.\n const activeUnitPrice =\n tierSavings.find((ts) => ts.tier === activeTier)?.unitPrice ?? basePrice;\n const undiscountedTotal = basePrice * quantity;\n const volumeTotal = activeUnitPrice * quantity;\n const volumeSavings = Math.max(0, undiscountedTotal - volumeTotal);\n const volumeSavingsPercent =\n undiscountedTotal > 0 && volumeSavings > 0\n ? Math.round((volumeSavings / undiscountedTotal) * 100)\n : 0;\n\n const handleAddToCart = useCallback(async () => {\n if (!bundle || !product) return;\n\n const variant =\n selectedVariant ??\n product.variants.nodes.find((v) =>\n isVariantFulfillable(v, quantity),\n );\n if (!variant) return;\n\n const lines: CartLineInput[] = [\n {\n merchandiseId: variant.id,\n quantity,\n attributes: [\n { key: \"_lime_bundle_gid\", value: bundle.id },\n { key: \"_lime_bundle_type\", value: bundle.bundleType },\n ],\n },\n ];\n\n setAddingToCart(true);\n setCartError(null);\n try {\n await onAddToCart(lines);\n // Reuse the canonical computation from calculateTierSavings so the\n // analytics unit price matches what the component rendered.\n const unitPrice =\n tierSavings.find((ts) => ts.tier === activeTier)?.unitPrice ??\n basePrice;\n trackAddToCart({\n productId: product.id,\n quantity,\n totalPrice: Math.round(unitPrice * quantity * 100) / 100,\n });\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setCartError(error.message);\n onError?.(error);\n } finally {\n setAddingToCart(false);\n }\n }, [\n bundle,\n product,\n quantity,\n activeTier,\n basePrice,\n onAddToCart,\n onError,\n trackAddToCart,\n selectedVariant,\n tierSavings,\n ]);\n\n if (result.status === \"loading\") {\n return (\n <div className={`lb-bundle lb-bundle--loading ${className ?? \"\"}`}>\n <div className=\"lb-skeleton lb-skeleton--title\" />\n <div className=\"lb-skeleton lb-skeleton--tiers\" />\n </div>\n );\n }\n\n if (result.status === \"error\") return null;\n if (!bundle) return null;\n if (!product) return null;\n\n return (\n <div\n ref={(el) => {\n elementRef(el);\n setConfigVarsRef(el);\n }}\n className={`lb-bundle lb-bundle--volume ${className ?? \"\"}`}\n role=\"region\"\n aria-label={bundle.title}\n >\n <div className=\"lb-bundle-header\">\n <div className=\"lb-bundle-header__content\">\n <h3 className=\"lb-bundle-title\">{bundle.title}</h3>\n {bundle.description && (\n <p className=\"lb-bundle-subtitle\">{bundle.description}</p>\n )}\n </div>\n </div>\n\n <BundleCountdown\n endsAt={bundle.endsAt}\n widgetConfig={bundle.widgetConfig}\n />\n\n <div className=\"lb-bundle-product-row lb-bundle-product-row--volume\">\n {thumbImage && (\n <img\n src={thumbImage.url}\n alt={thumbImage.altText ?? product.title}\n className=\"lb-bundle__product-image\"\n loading=\"lazy\"\n // Intrinsic dimensions reserve the \"original\"-ratio box pre-load\n // (issue #302); inert for the cropped ratios, where CSS sizes it.\n width={thumbImage.width ?? undefined}\n height={thumbImage.height ?? undefined}\n />\n )}\n <div className=\"lb-bundle__product-info\">\n <p className=\"lb-bundle__product-title\">{product.title}</p>\n <p className=\"lb-bundle__product-price\">\n {formatMoney(basePrice, currency)} each\n </p>\n {unitPriceText && (\n <p className=\"lb-bundle__product-unit-price\">{unitPriceText}</p>\n )}\n {showPicker && (\n <div className=\"lb-bundle__product-variant-pickers\">\n {optionNames.map((optionName, optionIndex) => {\n const dropdownOptions = optionsFor(optionIndex).map((o) => ({\n value: o.value,\n label: o.value,\n disabled: o.disabled,\n }));\n return (\n <VariantDropdown\n key={optionName}\n options={dropdownOptions}\n value={selectedValues[optionIndex] ?? null}\n onChange={(v) => setOptionValue(optionIndex, v)}\n ariaLabel={optionName}\n />\n );\n })}\n </div>\n )}\n </div>\n </div>\n\n <div\n className=\"lb-bundle__tiers lb-edge-fade\"\n role=\"radiogroup\"\n aria-label=\"Select quantity\"\n ref={tiersEdgeFadeRef}\n >\n {tierSavings.map((ts, tierIndex) => {\n const savingsPercent = Math.round(ts.savingsPercent);\n const showCompare =\n bundle.widgetConfig.pricing.showComparePrice && ts.savings > 0;\n // Checked = this tier is the one the current quantity lands on,\n // matching the single-selection radio the other hosts render.\n const isChecked = activeTier === ts.tier;\n const available = tierAvailable(ts.tier.minQuantity);\n return (\n <div\n key={ts.tier.minQuantity}\n className={`lb-bundle__tier ${ts.isActive ? \"lb-bundle__tier--active\" : \"\"} ${available ? \"\" : \"lb-bundle__tier--oos\"}`}\n role=\"radio\"\n aria-checked={isChecked}\n aria-disabled={available ? undefined : true}\n tabIndex={isChecked ? 0 : -1}\n onClick={() => {\n if (available) setQuantity(ts.tier.minQuantity);\n }}\n onKeyDown={(e) => {\n if ((e.key === \"Enter\" || e.key === \" \") && available) {\n e.preventDefault();\n setQuantity(ts.tier.minQuantity);\n }\n }}\n >\n <span className=\"lb-bundle__tier-radio\" aria-hidden=\"true\">\n <span className=\"lb-bundle__tier-radio-dot\" />\n </span>\n <span className=\"lb-bundle__tier-info\">\n <span className=\"lb-bundle__tier-label\">\n Buy {ts.tier.minQuantity}\n </span>\n <span className=\"lb-bundle__tier-price\">\n {showCompare && (\n <span className=\"lb-bundle__tier-compare\">\n {formatMoney(basePrice, currency)}\n </span>\n )}\n <span>{formatMoney(ts.unitPrice, currency)}</span>\n <span className=\"lb-bundle__tier-unit\">each</span>\n </span>\n </span>\n {(tierIndex === popularTierIndex || savingsPercent > 0) && (\n <span className=\"lb-bundle__tier-right\">\n {tierIndex === popularTierIndex && (\n <span className=\"lb-bundle__tier-badge\">\n {bundle.widgetConfig.popularBadge.text}\n </span>\n )}\n {savingsPercent > 0 && (\n <span className=\"lb-bundle__tier-savings\">\n Save {savingsPercent}%\n </span>\n )}\n </span>\n )}\n </div>\n );\n })}\n </div>\n\n <div className=\"lb-bundle__quantity-selector\">\n <label htmlFor={`lb-qty-${bundle.id}`}>Quantity</label>\n <div className=\"lb-bundle__quantity-control\">\n <button\n aria-label=\"Decrease quantity\"\n onClick={() => setQuantity((q) => Math.max(1, q - 1))}\n >\n −\n </button>\n <input\n id={`lb-qty-${bundle.id}`}\n type=\"number\"\n min={1}\n value={quantity}\n onChange={(e) => {\n const val = parseInt(e.target.value, 10);\n if (!isNaN(val) && val > 0) setQuantity(val);\n }}\n className=\"lb-bundle__quantity-input\"\n />\n <button\n aria-label=\"Increase quantity\"\n onClick={() => setQuantity((q) => q + 1)}\n >\n +\n </button>\n </div>\n </div>\n\n {cartError && (\n <p className=\"lb-bundle__error\" role=\"alert\">\n {cartError}\n </p>\n )}\n\n {bundle &&\n displayVariant &&\n shouldShowLowStockBadge(\n displayVariant,\n minTierQty,\n bundle.widgetConfig.lowStockThreshold,\n bundle.widgetConfig.showLowStockBadge,\n ) && (\n <span className=\"lb-bundle-low-stock-badge\">\n Only {displayVariant.quantityAvailable} left\n </span>\n )}\n\n <div className=\"lb-bundle-divider\" />\n\n <div className=\"lb-bundle-summary\">\n <div className=\"lb-bundle-summary__text\">\n <span className=\"lb-bundle-summary__label\" data-total-label>\n Total\n {bundle.widgetConfig.pricing.showItemCount && (\n <span data-item-count>\n {\" \"}\n ({quantity} item{quantity === 1 ? \"\" : \"s\"})\n </span>\n )}\n </span>\n {bundle.widgetConfig.savingsBar.visible && volumeSavings > 0 && (\n <p className=\"lb-bundle-savings-line\" data-savings-bar>\n You save{\" \"}\n <span data-savings-amount>\n {formatMoney(volumeSavings, currency)}\n </span>{\" \"}\n <span data-savings-percent>({volumeSavingsPercent}%)</span>\n </p>\n )}\n </div>\n <span className=\"lb-bundle-summary__prices\">\n {bundle.widgetConfig.pricing.showComparePrice &&\n volumeSavings > 0 && (\n <span className=\"lb-bundle-compare-price\" data-compare-price>\n {formatMoney(undiscountedTotal, currency)}\n </span>\n )}\n <span className=\"lb-bundle-sale-price\" data-total-price>\n {formatMoney(volumeTotal, currency)}\n </span>\n </span>\n </div>\n\n <button\n className=\"lb-bundle__cta\"\n onClick={handleAddToCart}\n disabled={addingToCart || isSoldOut || selectedTierUnavailable}\n aria-busy={addingToCart}\n >\n {addingToCart\n ? \"Adding...\"\n : isSoldOut || selectedTierUnavailable\n ? \"Sold out\"\n : (bundle.widgetConfig.cta.ctaText ?? `Add ${quantity} to Cart`)}\n </button>\n </div>\n );\n}\n","/**\n * BOGO (Buy X Get Y) bundle component — the shopper buys N units of the buy\n * product and gets M units of the get product at a percent discount\n * (100 = free). Renders a buy card, a \"+\" divider, and a get card wearing\n * the reward badge, with combined one-set pricing and a single CTA that\n * emits both cart lines (merged into one line when both sides resolve to\n * the same variant).\n */\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport {\n formatMoney,\n formatUnitPrice,\n isVariantFulfillable,\n type BogoBundleData,\n type CartLineInput,\n type Product,\n type ProductVariant,\n} from \"@lime-bundles/core\";\nimport { useBundleData } from \"../hooks/useBundleData\";\nimport { useAnalytics } from \"../hooks/useAnalytics\";\nimport { useWidgetConfigVars } from \"../hooks/useWidgetConfigVars\";\nimport { useVariantSelection } from \"../hooks/useVariantSelection\";\nimport { VariantDropdown } from \"./VariantDropdown\";\nimport type { BundleComponentProps } from \"./types\";\nimport { BundleCountdown } from \"./BundleCountdown\";\n\n/** Per-unit discounted price with floor rounding, matching Shopify. */\nfunction discountedUnit(price: number, percent: number): number {\n const cents = Math.round(price * 100);\n const discounted = cents - Math.floor((cents * percent) / 100);\n return discounted / 100;\n}\n\nexport function BogoBundle(props: BundleComponentProps) {\n const {\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n appUrl,\n analyticsEnabled,\n onAddToCart,\n onError,\n className,\n } = props;\n\n const result = useBundleData({\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n });\n\n const { elementRef, trackAddToCart } = useAnalytics({\n shopDomain,\n appUrl: appUrl ?? `https://${shopDomain}`,\n bundleGid,\n bundleType: \"bogo\",\n enabled: analyticsEnabled !== false,\n });\n\n const [addingToCart, setAddingToCart] = useState(false);\n const [cartError, setCartError] = useState<string | null>(null);\n // Selection is keyed by ROLE, not product id — a same-product BOGO\n // renders the one product on both cards with independent dropdowns.\n const [selectedVariants, setSelectedVariants] = useState<{\n buy: ProductVariant | null;\n get: ProductVariant | null;\n }>({ buy: null, get: null });\n\n const handleVariantChange = useCallback(\n (role: \"buy\" | \"get\", variant: ProductVariant | null) => {\n setSelectedVariants((prev) => {\n if (prev[role] === variant) return prev;\n return { ...prev, [role]: variant };\n });\n },\n [],\n );\n\n const bundle =\n result.status === \"success\" && result.bundle.bundleType === \"bogo\"\n ? (result.bundle as BogoBundleData)\n : null;\n\n const setConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);\n\n useEffect(() => {\n if (result.status === \"error\") {\n onError?.(result.error);\n return;\n }\n if (result.status === \"success\" && result.bundle.bundleType !== \"bogo\") {\n onError?.(\n new Error(\n `BogoBundle: expected bundleType=\"bogo\", got \"${result.bundle.bundleType}\"`,\n ),\n );\n }\n }, [result, onError]);\n\n const buyProduct = useMemo(\n () => bundle?.products.find((p) => p.id === bundle.buyProductId) ?? null,\n [bundle],\n );\n const getProduct = useMemo(\n () => bundle?.products.find((p) => p.id === bundle.getProductId) ?? null,\n [bundle],\n );\n\n const percent = bundle\n ? Math.min(100, Math.max(0, bundle.discountConfig.discountValue))\n : 0;\n\n const resolveVariant = useCallback(\n (product: Product | null, selected: ProductVariant | null, qty: number) => {\n if (!product) return null;\n return (\n selected ??\n product.variants.nodes.find((v) => isVariantFulfillable(v, qty)) ??\n product.variants.nodes[0] ??\n null\n );\n },\n [],\n );\n\n /**\n * Sides the store can't supply at the offer's quantities.\n *\n * `resolveVariant` falls back to `variants.nodes[0]` so a price always\n * renders, which meant an out-of-stock side looked normal and add-to-cart\n * shipped an unpurchasable variant that only failed at Shopify. Both sides\n * are required for the offer, so either one short locks the CTA.\n */\n const oosSides = useMemo(() => {\n if (!bundle) return 0;\n const short = (product: Product | null, qty: number) =>\n !!product &&\n !product.variants.nodes.some((v) => isVariantFulfillable(v, qty));\n return (\n (short(buyProduct, bundle.buyQuantity) ? 1 : 0) +\n (short(getProduct, bundle.getQuantity) ? 1 : 0)\n );\n }, [bundle, buyProduct, getProduct]);\n\n const handleAddToCart = useCallback(async () => {\n if (!bundle || !buyProduct || !getProduct) return;\n\n const buyVariant = resolveVariant(buyProduct, selectedVariants.buy, bundle.buyQuantity);\n const getVariant = resolveVariant(getProduct, selectedVariants.get, bundle.getQuantity);\n if (!buyVariant || !getVariant) return;\n\n const attributes = [\n { key: \"_lime_bundle_gid\", value: bundle.id },\n { key: \"_lime_bundle_type\", value: bundle.bundleType },\n ];\n // Same variant on both sides → one merged line so the host cart\n // doesn't show duplicates; checkout math is line-agnostic.\n const lines: CartLineInput[] =\n buyVariant.id === getVariant.id\n ? [\n {\n merchandiseId: buyVariant.id,\n quantity: bundle.buyQuantity + bundle.getQuantity,\n attributes,\n },\n ]\n : [\n {\n merchandiseId: buyVariant.id,\n quantity: bundle.buyQuantity,\n attributes,\n },\n {\n merchandiseId: getVariant.id,\n quantity: bundle.getQuantity,\n attributes,\n },\n ];\n\n setAddingToCart(true);\n setCartError(null);\n try {\n await onAddToCart(lines);\n const buyUnit = parseFloat(buyVariant.price.amount);\n const getUnit = parseFloat(getVariant.price.amount);\n const totalPrice =\n buyUnit * bundle.buyQuantity +\n discountedUnit(getUnit, percent) * bundle.getQuantity;\n trackAddToCart({\n quantity: bundle.buyQuantity + bundle.getQuantity,\n totalPrice: Math.round(totalPrice * 100) / 100,\n });\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setCartError(error.message);\n onError?.(error);\n } finally {\n setAddingToCart(false);\n }\n }, [bundle, buyProduct, getProduct, selectedVariants, resolveVariant, onAddToCart, onError, trackAddToCart, percent]);\n\n if (result.status === \"loading\") {\n return (\n <div className={`lb-bundle lb-bundle--loading ${className ?? \"\"}`}>\n <div className=\"lb-skeleton lb-skeleton--title\" />\n <div className=\"lb-skeleton lb-skeleton--products\" />\n </div>\n );\n }\n\n if (result.status === \"error\") return null;\n if (!bundle || !buyProduct || !getProduct) return null;\n\n const currency =\n bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? \"USD\";\n\n const buyVariant = resolveVariant(buyProduct, selectedVariants.buy, bundle.buyQuantity);\n const getVariant = resolveVariant(getProduct, selectedVariants.get, bundle.getQuantity);\n const buyUnit = buyVariant ? parseFloat(buyVariant.price.amount) : 0;\n const getUnit = getVariant ? parseFloat(getVariant.price.amount) : 0;\n const comparePrice = buyUnit * bundle.buyQuantity + getUnit * bundle.getQuantity;\n const salePrice =\n buyUnit * bundle.buyQuantity +\n discountedUnit(getUnit, percent) * bundle.getQuantity;\n const savings = Math.max(0, comparePrice - salePrice);\n const savingsPercent =\n comparePrice > 0 && savings > 0\n ? Math.round((savings / comparePrice) * 100)\n : 0;\n const showCompare =\n bundle.widgetConfig.pricing.showComparePrice && savings > 0;\n const showSavings = bundle.widgetConfig.savingsBar.visible && savings > 0;\n const badge = percent === 100 ? \"Free\" : `${percent}% off`;\n\n return (\n <div\n ref={(el) => {\n elementRef(el);\n setConfigVarsRef(el);\n }}\n className={`lb-bundle lb-bundle--bogo ${className ?? \"\"}`}\n role=\"region\"\n aria-label={bundle.title}\n >\n <div className=\"lb-bundle-header\">\n <div className=\"lb-bundle-header__content\">\n <h3 className=\"lb-bundle-title\">{bundle.title}</h3>\n {bundle.description && (\n <p className=\"lb-bundle-subtitle\">{bundle.description}</p>\n )}\n </div>\n </div>\n\n <BundleCountdown\n endsAt={bundle.endsAt}\n widgetConfig={bundle.widgetConfig}\n />\n\n <div className=\"lb-bundle__products\">\n <BogoProductRow\n side=\"buy\"\n product={buyProduct}\n quantity={bundle.buyQuantity}\n percent={percent}\n badge={null}\n currency={currency}\n onVariantChange={handleVariantChange}\n />\n <div className=\"lb-bogo__plus\" aria-hidden=\"true\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 18 18\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <line x1=\"9\" y1=\"3\" x2=\"9\" y2=\"15\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n <line x1=\"3\" y1=\"9\" x2=\"15\" y2=\"9\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n </div>\n <BogoProductRow\n side=\"get\"\n product={getProduct}\n quantity={bundle.getQuantity}\n percent={percent}\n badge={badge}\n currency={currency}\n onVariantChange={handleVariantChange}\n />\n </div>\n\n <div className=\"lb-bundle-divider\" />\n\n <div className=\"lb-bundle-summary\">\n <div className=\"lb-bundle-summary__text\">\n <span className=\"lb-bundle-summary__label\">Bundle total</span>\n {showSavings && (\n <p className=\"lb-bundle-savings-line\" data-savings-bar>\n You save{\" \"}\n <span data-savings-amount>{formatMoney(savings, currency)}</span>{\" \"}\n <span data-savings-percent>({savingsPercent}%)</span>\n </p>\n )}\n </div>\n <span className=\"lb-bundle-summary__prices\">\n {showCompare && (\n <span className=\"lb-bundle-compare-price\" data-compare-price>\n {formatMoney(comparePrice, currency)}\n </span>\n )}\n <span className=\"lb-bundle-sale-price\" data-sale-price>\n {formatMoney(salePrice, currency)}\n </span>\n </span>\n </div>\n\n {cartError && (\n <p className=\"lb-bundle__error\" role=\"alert\">\n {cartError}\n </p>\n )}\n\n <button\n className=\"lb-bundle__cta\"\n onClick={handleAddToCart}\n disabled={addingToCart || oosSides > 0}\n aria-busy={addingToCart}\n >\n {addingToCart\n ? \"Adding...\"\n : oosSides > 0\n ? `${oosSides} item${oosSides === 1 ? \"\" : \"s\"} unavailable`\n : (bundle.widgetConfig.cta.ctaText ?? \"Add Bundle to Cart\")}\n </button>\n </div>\n );\n}\n\ninterface BogoProductRowProps {\n side: \"buy\" | \"get\";\n product: Product;\n quantity: number;\n percent: number;\n /** Reward badge text; null on the buy row. */\n badge: string | null;\n currency: string;\n onVariantChange: (role: \"buy\" | \"get\", variant: ProductVariant | null) => void;\n}\n\nfunction BogoProductRow({ side, product, quantity, percent, badge, currency, onVariantChange }: BogoProductRowProps) {\n const variants = product.variants.nodes;\n const optionNames = useMemo<string[]>(() => {\n const first = variants[0];\n return first ? first.selectedOptions.map((o) => o.name) : [];\n }, [variants]);\n\n const showPicker = variants.length > 1 && optionNames.length > 0;\n\n const { selectedValues, selectedVariant, setOptionValue, optionsFor } =\n useVariantSelection({\n variants,\n optionNames,\n });\n\n useEffect(() => {\n onVariantChange(side, selectedVariant ?? null);\n }, [selectedVariant, side, onVariantChange]);\n\n const displayVariant =\n selectedVariant ??\n variants.find((v) => isVariantFulfillable(v, quantity)) ??\n variants[0];\n const unit = displayVariant ? parseFloat(displayVariant.price.amount) : 0;\n const isGet = side === \"get\" && percent > 0;\n const priceText = isGet\n ? formatMoney(discountedUnit(unit, percent), currency)\n : formatMoney(unit, currency);\n // Get row strikes its own original price (the reward); buy row shows a\n // regular compare-at when the variant has one.\n const compareAt = isGet\n ? formatMoney(unit, currency)\n : displayVariant?.compareAtPrice &&\n parseFloat(displayVariant.compareAtPrice.amount) > unit\n ? formatMoney(displayVariant.compareAtPrice.amount, currency)\n : null;\n const unitPriceText = displayVariant\n ? formatUnitPrice(\n displayVariant.unitPrice,\n displayVariant.unitPriceMeasurement,\n currency,\n )\n : null;\n\n const thumbImage = displayVariant?.image ?? product.featuredImage;\n\n return (\n <div className=\"lb-bundle-product-row\" part=\"product\" data-bogo-role={side}>\n {thumbImage && (\n <img\n src={thumbImage.url}\n alt={thumbImage.altText ?? product.title}\n className=\"lb-bundle__product-image\"\n loading=\"lazy\"\n // Intrinsic dimensions reserve the \"original\"-ratio box pre-load\n // (issue #302); inert for the cropped ratios, where CSS sizes it.\n width={thumbImage.width ?? undefined}\n height={thumbImage.height ?? undefined}\n />\n )}\n <div className=\"lb-bundle__product-info\">\n <p className=\"lb-bundle__product-title\">{product.title}</p>\n {!showPicker && displayVariant && variants.length > 1 && (\n <span className=\"lb-bundle-variant-badge\">\n {displayVariant.title}\n </span>\n )}\n <span className=\"lb-bundle-product-prices\">\n {compareAt && (\n <span\n className=\"lb-bundle-product-compare-price\"\n data-product-compare-price\n >\n {compareAt}\n </span>\n )}\n <span className=\"lb-bundle__product-price\" data-product-price>\n {priceText}\n </span>\n {/* Right-slot rule (WIDGET-DESIGN.md): the get card's corner holds\n the reward badge, so BOGO counts render inline on both cards. */}\n <span className=\"lb-bundle-qty-inline\" data-qty-inline>\n &times;{quantity}\n </span>\n </span>\n {unitPriceText && (\n <span\n className=\"lb-bundle__product-unit-price\"\n data-product-unit-price\n >\n {unitPriceText}\n </span>\n )}\n {showPicker && (\n <div className=\"lb-bundle__product-variant-pickers\">\n {optionNames.map((optionName, optionIndex) => {\n const dropdownOptions = optionsFor(optionIndex).map((o) => ({\n value: o.value,\n label: o.value,\n disabled: o.disabled,\n }));\n return (\n <VariantDropdown\n key={optionName}\n options={dropdownOptions}\n value={selectedValues[optionIndex] ?? null}\n onChange={(v) => setOptionValue(optionIndex, v)}\n ariaLabel={optionName}\n />\n );\n })}\n </div>\n )}\n </div>\n {badge && <span className=\"lb-bogo__badge\">{badge}</span>}\n </div>\n );\n}\n","/**\n * Multi-step bundle component.\n *\n * The customer walks named steps (\"Pick a shampoo\" → \"Pick a conditioner\")\n * through the mix & match picker modal presented as a WIZARD (Back / Next /\n * Done). Each step scopes the picker to its own product pool\n * (`productsForStep`) and carries its own min/max unit bounds; the CTA\n * enables when every step's minimum is met and the whole-bundle discount\n * applies to the combined total.\n *\n * Shared rules with the theme widget (`bundle-multi-step.js`):\n * - Picks are VARIANT-scoped per step: each (step, product, variant)\n * triple holds at most one slot.\n * - rule.min is a per-pick floor; rule.max caps the product's TOTAL\n * units across every slot in every step.\n * - Stock accounting sums a variant's units across ALL steps.\n * - Step maxQuantity (null = unlimited) bounds the step's unit total.\n *\n * The UX mirrors `extensions/bundle-theme/snippets/lb-multi-step.liquid`\n * one-for-one: overall segmented progress, per-step groups (heading button\n * reopens the wizard at that step, live \"x of n\" chip, chosen cards), a\n * single dashed \"Build your bundle\" trigger, receipt summary + CTA. See\n * `MultiStepPicker.tsx` for the wizard modal.\n */\nimport { Fragment, useCallback, useEffect, useMemo, useState } from \"react\";\nimport {\n formatMoney,\n formatUnitPrice,\n calculateDiscount,\n isVariantFulfillable,\n productsForStep,\n DEFAULT_PRODUCT_RULE,\n type CartLineInput,\n type MultiStepBundleData,\n type ProductRule,\n} from \"@lime-bundles/core\";\nimport { useBundleData } from \"../hooks/useBundleData\";\nimport { useAnalytics } from \"../hooks/useAnalytics\";\nimport { useWidgetConfigVars } from \"../hooks/useWidgetConfigVars\";\nimport { MultiStepPicker } from \"./MultiStepPicker\";\nimport type { SelectedItem } from \"./mix-match-types\";\nimport type { BundleComponentProps } from \"./types\";\nimport { BundleCountdown } from \"./BundleCountdown\";\n\n/**\n * The rule in force for a pick. Pass `variantId` and the variant's own rule\n * wins; without one this resolves the product rule, which is the envelope\n * covering every variant.\n */\nfunction ruleFor(\n bundle: MultiStepBundleData,\n productId: string,\n variantId?: string | null,\n): ProductRule {\n if (variantId) {\n const vRule = bundle.variantRules[variantId];\n if (vRule) return vRule;\n }\n return bundle.productRules[productId] ?? DEFAULT_PRODUCT_RULE;\n}\n\n/**\n * The variant's OWN rule, or undefined when it inherits the product's.\n * Distinct from `ruleFor`, which falls back — conflating the two would make\n * every variant of a required product unremovable.\n */\nfunction variantRuleFor(\n bundle: MultiStepBundleData,\n variantId: string | null | undefined,\n): ProductRule | undefined {\n return variantId ? bundle.variantRules[variantId] : undefined;\n}\n\n/**\n * PRODUCT-LEVEL lock for required products, STEP-AGNOSTIC like the rules\n * themselves (and the discount function's check): removing a pick is\n * allowed only while the product's other slots — in any step — keep it at\n * or above rule.min. This is what lets shoppers swap variants without ever\n * dropping the required product out of the bundle. *\n * A required VARIANT is stricter and needs no tally: slots are one per\n * (product, variant), so it has no other slot to fall back on and no sibling\n * may stand in for it. Naming the variant is what takes the swap off the\n * table.\n */\nfunction canRemoveItem(\n bundle: MultiStepBundleData,\n selections: SelectedItem[][],\n item: SelectedItem,\n): boolean {\n if (variantRuleFor(bundle, item.variantId)?.required) return false;\n\n const rule = ruleFor(bundle, item.productId);\n if (!rule.required) return true;\n let unitsElsewhere = 0;\n for (const stepPicks of selections) {\n for (const s of stepPicks) {\n if (s.productId === item.productId && s !== item) {\n unitsElsewhere += s.quantity;\n }\n }\n }\n return unitsElsewhere >= rule.min;\n}\n\n/**\n * ATOMIC VARIANT SWAP, scoped to ONE step. A hard-capped required product\n * (rule.min === rule.max) has no headroom for the add-then-remove variant\n * swap the product-level lock normally allows, so the wizard button\n * becomes \"Swap\": the new variant's units displace sibling-variant units\n * of the same product IN THE SAME STEP. Cross-step displacement is\n * deliberately off the table — it would drain another step below its\n * minimum. Returns the in-step units available to take over, or 0 when\n * the row isn't in the swap state.\n */\nfunction swapUnitsForItem(\n bundle: MultiStepBundleData,\n selections: SelectedItem[][],\n step: number,\n productId: string,\n variantId: string,\n): number {\n const rule = ruleFor(bundle, productId);\n if (!rule.required || rule.max !== rule.min) return 0;\n const stepPicks = selections[step] ?? [];\n if (stepPicks.some((s) => s.variantId === variantId)) return 0;\n return stepPicks\n .filter((s) => s.productId === productId && s.variantId !== variantId)\n .reduce((sum, s) => sum + s.quantity, 0);\n}\n\nexport function MultiStepBundle(props: BundleComponentProps) {\n const {\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n appUrl,\n analyticsEnabled,\n onAddToCart,\n onError,\n className,\n } = props;\n\n const result = useBundleData({\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n });\n\n const { elementRef, trackAddToCart } = useAnalytics({\n shopDomain,\n appUrl: appUrl ?? `https://${shopDomain}`,\n bundleGid,\n bundleType: \"multi_step\",\n enabled: analyticsEnabled !== false,\n });\n\n // Per-step selections: selections[i] = ordered variant-scoped picks of\n // step i. Mirrors the theme's `selections` array-of-arrays.\n const [selections, setSelections] = useState<SelectedItem[][]>([]);\n /** Step index the wizard is open at, or null when closed. */\n const [pickerOpenAt, setPickerOpenAt] = useState<number | null>(null);\n const [addingToCart, setAddingToCart] = useState(false);\n const [cartError, setCartError] = useState<string | null>(null);\n\n const bundle =\n result.status === \"success\" && result.bundle.bundleType === \"multi_step\"\n ? (result.bundle as MultiStepBundleData)\n : null;\n\n // Apply merchant-config CSS vars to the widget root + the portaled modal.\n const setConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);\n const setModalConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);\n\n useEffect(() => {\n if (result.status === \"error\") {\n onError?.(result.error);\n return;\n }\n if (\n result.status === \"success\" &&\n result.bundle.bundleType !== \"multi_step\"\n ) {\n onError?.(\n new Error(\n `MultiStepBundle: expected bundleType=\"multi_step\", got \"${result.bundle.bundleType}\"`,\n ),\n );\n }\n }, [result, onError]);\n\n const steps = useMemo(() => bundle?.steps ?? [], [bundle]);\n\n // Size the per-step selection arrays once the bundle arrives, pre-seeding\n // one pick per REQUIRED product into the FIRST step whose pool holds it\n // (first fulfillable variant at rule.min). Seeds count toward that step's\n // minimum and can never drop the product below rule.min (canRemoveItem).\n useEffect(() => {\n const seeded: SelectedItem[][] = steps.map(() => []);\n if (bundle) {\n const seedCurrency =\n bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? \"USD\";\n for (const [pid, rule] of Object.entries(bundle.productRules)) {\n if (!rule.required) continue;\n for (let i = 0; i < steps.length; i++) {\n const product = productsForStep(bundle, i).find((p) => p.id === pid);\n const variant = product?.variants.nodes.find((v) =>\n isVariantFulfillable(v, rule.min),\n );\n if (!product || !variant) continue;\n seeded[i].push({\n productId: product.id,\n variantId: variant.id,\n title: product.title,\n url: `/products/${product.handle}`,\n variantTitle: variant.title,\n featuredImage:\n variant.image?.url ?? product.featuredImage?.url ?? null,\n price: parseFloat(variant.price.amount),\n compareAtPrice: variant.compareAtPrice\n ? parseFloat(variant.compareAtPrice.amount)\n : null,\n unitPrice: formatUnitPrice(\n variant.unitPrice,\n variant.unitPriceMeasurement,\n seedCurrency,\n ),\n quantity: rule.min,\n });\n break;\n }\n }\n }\n setSelections(seeded);\n }, [bundle, steps]);\n\n const showStepper =\n bundle?.widgetConfig.mixMatchShowQuantitySelector !== false;\n\n /** Overall requirement — sum of step minimums. */\n const totalMin = useMemo(\n () => steps.reduce((sum, s) => sum + s.minQuantity, 0),\n [steps],\n );\n\n const unitsByStep = useMemo(\n () => selections.map((picks) => picks.reduce((sum, s) => sum + s.quantity, 0)),\n [selections],\n );\n const totalQuantity = useMemo(\n () => unitsByStep.reduce((sum, u) => sum + u, 0),\n [unitsByStep],\n );\n const stepSatisfied = useCallback(\n (i: number) => (unitsByStep[i] ?? 0) >= (steps[i]?.minQuantity ?? 1),\n [unitsByStep, steps],\n );\n const allSatisfied =\n steps.length > 0 && steps.every((_, i) => stepSatisfied(i));\n\n const valid = !!bundle && allSatisfied;\n // Overall progress counts completed STEPS (unit detail lives on the\n // per-step chips).\n const completedSteps = steps.filter((_, i) => stepSatisfied(i)).length;\n // The door sits directly above the first unsatisfied step (-1 = none:\n // the door disappears and the CTA is the remaining action).\n const firstUnsatisfied = steps.findIndex((_, i) => !stepSatisfied(i));\n const remainingSteps = steps.length - completedSteps;\n const anyPicks = selections.some((s) => s.length > 0);\n\n // Running receipt totals from all steps' selections.\n const summary = useMemo(() => {\n let comparePrice = 0;\n let salePrice = 0;\n for (const stepPicks of selections) {\n for (const sel of stepPicks) {\n if (sel.quantity <= 0) continue;\n comparePrice += sel.price * sel.quantity;\n if (bundle) {\n salePrice +=\n calculateDiscount(\n sel.price,\n bundle.discountConfig.discountType,\n bundle.discountConfig.discountValue,\n ) * sel.quantity;\n }\n }\n }\n const savings = Math.max(0, comparePrice - salePrice);\n const savingsPercent =\n comparePrice > 0 && savings > 0\n ? Math.round((savings / comparePrice) * 100)\n : 0;\n return { comparePrice, salePrice, savings, savingsPercent };\n }, [selections, bundle]);\n\n const addSelection = useCallback((step: number, item: SelectedItem) => {\n setSelections((prev) => {\n if (step < 0 || step >= prev.length) return prev;\n // Slots are variant-scoped WITHIN a step: refuse a duplicate of an\n // already-committed variant in this step (the row shows the Added\n // toggle for it instead). The same variant may hold slots in other\n // steps.\n if (prev[step].some((s) => s.variantId === item.variantId)) return prev;\n const next = prev.slice();\n next[step] = [...next[step], item];\n return next;\n });\n }, []);\n\n // ATOMIC VARIANT SWAP for hard-capped required products: replace units\n // of the product's other-variant picks IN THE SAME STEP with the new\n // variant. The step total never moves, so the required floor, the hard\n // cap, and the step's own min/max all hold throughout — which is why\n // this bypasses the canRemoveItem guard (the swap is exactly what that\n // guard exists to enable).\n const swapSelection = useCallback(\n (step: number, item: SelectedItem) => {\n setSelections((prev) => {\n if (!bundle || step < 0 || step >= prev.length) return prev;\n const swapUnits = swapUnitsForItem(\n bundle,\n prev,\n step,\n item.productId,\n item.variantId,\n );\n if (swapUnits <= 0) return prev;\n const qty = Math.min(Math.max(1, item.quantity), swapUnits);\n let freed = 0;\n const stepPicks: SelectedItem[] = [];\n for (const s of prev[step]) {\n if (\n freed < qty &&\n s.productId === item.productId &&\n s.variantId !== item.variantId\n ) {\n const take = Math.min(s.quantity, qty - freed);\n freed += take;\n if (s.quantity > take) {\n stepPicks.push({ ...s, quantity: s.quantity - take });\n }\n } else {\n stepPicks.push(s);\n }\n }\n if (freed === 0) return prev;\n stepPicks.push({ ...item, quantity: freed });\n const next = prev.slice();\n next[step] = stepPicks;\n return next;\n });\n },\n [bundle],\n );\n\n // LIVE EDIT of a committed pick's quantity within a step.\n const updateQuantity = useCallback(\n (step: number, productId: string, variantId: string, quantity: number) => {\n setSelections((prev) => {\n if (step < 0 || step >= prev.length) return prev;\n const idx = prev[step].findIndex(\n (s) => s.productId === productId && s.variantId === variantId,\n );\n if (idx === -1) return prev;\n const clamped = Math.max(1, quantity);\n if (clamped === prev[step][idx].quantity) return prev;\n const next = prev.slice();\n const stepPicks = next[step].slice();\n stepPicks[idx] = { ...stepPicks[idx], quantity: clamped };\n next[step] = stepPicks;\n return next;\n });\n },\n [],\n );\n\n // Remove the slot holding a variant in a step (the picker's Added toggle).\n const removeVariant = useCallback(\n (step: number, variantId: string) => {\n setSelections((prev) => {\n if (step < 0 || step >= prev.length) return prev;\n const idx = prev[step].findIndex((s) => s.variantId === variantId);\n if (idx === -1) return prev;\n if (bundle && !canRemoveItem(bundle, prev, prev[step][idx])) return prev;\n const next = prev.slice();\n const stepPicks = next[step].slice();\n stepPicks.splice(idx, 1);\n next[step] = stepPicks;\n return next;\n });\n },\n [bundle],\n );\n\n const removeSlot = useCallback(\n (step: number, index: number) => {\n setSelections((prev) => {\n if (step < 0 || step >= prev.length) return prev;\n if (index < 0 || index >= prev[step].length) return prev;\n if (bundle && !canRemoveItem(bundle, prev, prev[step][index]))\n return prev;\n const next = prev.slice();\n const stepPicks = next[step].slice();\n stepPicks.splice(index, 1);\n next[step] = stepPicks;\n return next;\n });\n },\n [bundle],\n );\n\n const handleAddToCart = useCallback(async () => {\n if (!bundle || !valid) return;\n\n // Flatten selections across steps, merging same-variant picks into one\n // cart line (matches the discount function, which sees cart lines, not\n // steps).\n const grouped = new Map<string, { variantId: string; quantity: number }>();\n for (const stepPicks of selections) {\n for (const sel of stepPicks) {\n if (sel.quantity <= 0) continue;\n const existing = grouped.get(sel.variantId);\n if (existing) existing.quantity += sel.quantity;\n else grouped.set(sel.variantId, { variantId: sel.variantId, quantity: sel.quantity });\n }\n }\n\n const lines: CartLineInput[] = Array.from(grouped.values()).map((line) => ({\n merchandiseId: line.variantId,\n quantity: line.quantity,\n attributes: [\n { key: \"_lime_bundle_gid\", value: bundle.id },\n { key: \"_lime_bundle_type\", value: bundle.bundleType },\n ],\n }));\n\n setAddingToCart(true);\n setCartError(null);\n try {\n await onAddToCart(lines);\n\n const totalPrice = selections.reduce(\n (sum, stepPicks) =>\n sum +\n stepPicks.reduce((s, sel) => s + sel.price * sel.quantity, 0),\n 0,\n );\n trackAddToCart({\n quantity: totalQuantity,\n totalPrice: Math.round(totalPrice * 100) / 100,\n });\n\n setSelections(steps.map(() => []));\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setCartError(error.message);\n onError?.(error);\n } finally {\n setAddingToCart(false);\n }\n }, [bundle, selections, valid, onAddToCart, onError, trackAddToCart, totalQuantity, steps]);\n\n if (result.status === \"loading\") {\n return (\n <div className={`lb-bundle lb-bundle--loading ${className ?? \"\"}`}>\n <div className=\"lb-skeleton lb-skeleton--title\" />\n <div className=\"lb-skeleton lb-skeleton--products\" />\n </div>\n );\n }\n\n if (result.status === \"error\") return null;\n if (!bundle || steps.length === 0) return null;\n\n // Bundle visibility guard: every step needs at least one in-stock\n // product — mirrors the Liquid widget's `every_step_available` gate.\n for (let i = 0; i < steps.length; i++) {\n if (!stepHasInStockProduct(bundle, i)) return null;\n }\n\n // A required product with no purchasable variant in any of its steps\n // means the bundle can never qualify at checkout — don't render (guards\n // the gap between a live stock drop and the webhook's status flip).\n const requiredBlocked = Object.entries(bundle.productRules).some(\n ([pid, rule]) => {\n if (!rule.required) return false;\n return !steps.some((_, i) =>\n productsForStep(bundle, i).some(\n (p) =>\n p.id === pid &&\n p.variants.nodes.some((v) => isVariantFulfillable(v, rule.min)),\n ),\n );\n },\n );\n if (requiredBlocked) return null;\n\n const currency =\n bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? \"USD\";\n\n // Label stays \"Add to cart\" (or the merchant's custom text) throughout;\n // only the disabled state tracks step satisfaction.\n const ctaLabel = addingToCart\n ? \"Adding...\"\n : bundle.widgetConfig.cta.ctaText || \"Add to cart\";\n\n return (\n <div\n ref={(el) => {\n elementRef(el);\n setConfigVarsRef(el);\n }}\n className={`lb-bundle lb-bundle--multi-step lb-mix-match lb-multi-step ${className ?? \"\"}`}\n role=\"region\"\n aria-label={bundle.title}\n data-required-quantity={totalMin}\n >\n <div className=\"lb-bundle-header\">\n <div className=\"lb-bundle-header__content\">\n <h3 className=\"lb-bundle-title\">{bundle.title}</h3>\n {bundle.description && (\n <p className=\"lb-bundle-subtitle\">{bundle.description}</p>\n )}\n </div>\n </div>\n\n <BundleCountdown\n endsAt={bundle.endsAt}\n widgetConfig={bundle.widgetConfig}\n />\n\n {/* Overall progress is STEP-based: one segment per step, filled as\n its minimum is met (unit detail lives on the per-step chips). */}\n <div className=\"lb-mix-match__progress\" data-progress>\n <div\n className=\"lb-mix-match__progress-segments\"\n role=\"progressbar\"\n aria-valuenow={completedSteps}\n aria-valuemin={0}\n aria-valuemax={steps.length}\n >\n {Array.from({ length: steps.length }).map((_, i) => (\n <span\n key={i}\n className={`lb-mix-match__progress-segment${i < completedSteps ? \" lb-mix-match__progress-segment--filled\" : \"\"}`}\n data-progress-segment\n />\n ))}\n </div>\n <div className=\"lb-mix-match__progress-labels\">\n <span\n className=\"lb-mix-match__progress-count\"\n data-progress-count\n aria-live=\"polite\"\n >\n {`${completedSteps} of ${steps.length} steps completed`}\n </span>\n <span\n className=\"lb-mix-match__progress-remaining\"\n data-progress-remaining\n aria-live=\"polite\"\n >\n {completedSteps < steps.length\n ? `${steps.length - completedSteps} more to go`\n : \"Complete\"}\n </span>\n </div>\n </div>\n\n {/* One dashed door plus one section per step. A step without picks is\n a slim checklist row (tap deep-links the wizard to that step); a\n step with picks shows the heading + chosen cards. The door sits\n directly above the first unsatisfied step and disappears once all\n are met. data-step-mode drives the shared spacing rules. */}\n <div className=\"lb-multi-step__groups\" data-step-groups>\n {steps.map((step, i) => (\n <Fragment key={i}>\n {i === firstUnsatisfied && (\n <button\n type=\"button\"\n className=\"lb-mix-match__add-product lb-multi-step__door\"\n data-step-door={firstUnsatisfied}\n aria-label={`${anyPicks ? \"Continue building\" : \"Choose your products\"}: ${step.name}`}\n onClick={() => setPickerOpenAt(firstUnsatisfied)}\n >\n <span\n className=\"lb-mix-match__add-product-icon\"\n aria-hidden=\"true\"\n >\n <PlusIcon />\n </span>\n <span className=\"lb-multi-step__door-copy\">\n <span className=\"lb-mix-match__add-product-label\">\n {anyPicks ? \"Continue building\" : \"Choose your products\"}\n </span>\n <span className=\"lb-multi-step__door-sub\">\n {anyPicks\n ? `${remainingSteps} ${remainingSteps === 1 ? \"step\" : \"steps\"} to go`\n : `${steps.length} quick ${steps.length === 1 ? \"step\" : \"steps\"}`}\n </span>\n </span>\n </button>\n )}\n {(selections[i] ?? []).length === 0 ? (\n <section\n className=\"lb-multi-step__group\"\n data-step-group={i}\n data-step-mode=\"row\"\n >\n <button\n type=\"button\"\n className=\"lb-multi-step__step-row\"\n data-step-row={i}\n aria-label={`${step.minQuantity === 1 && step.maxQuantity === 1 ? \"Choose a product\" : \"Choose products\"}: ${step.name}`}\n onClick={() => setPickerOpenAt(i)}\n >\n <span\n className=\"lb-multi-step__step-ix\"\n aria-hidden=\"true\"\n >\n {i + 1}\n </span>\n <span className=\"lb-multi-step__group-name\">\n {step.name}\n </span>\n <span\n className={`lb-multi-step__group-count${stepSatisfied(i) ? \" lb-multi-step__group-count--met\" : \"\"}`}\n data-step-count={i}\n >\n {`${Math.min(unitsByStep[i] ?? 0, step.minQuantity)} of ${step.minQuantity} added`}\n </span>\n </button>\n </section>\n ) : (\n <section\n className=\"lb-multi-step__group\"\n data-step-group={i}\n data-step-mode=\"open\"\n >\n <div className=\"lb-multi-step__group-heading\">\n <span className=\"lb-multi-step__group-name\">{step.name}</span>\n <span\n className={`lb-multi-step__group-count${stepSatisfied(i) ? \" lb-multi-step__group-count--met\" : \"\"}`}\n data-step-count={i}\n >\n {`${Math.min(unitsByStep[i] ?? 0, step.minQuantity)} of ${step.minQuantity} added`}\n </span>\n </div>\n <div\n className=\"lb-mix-match__slots lb-edge-fade lb-multi-step__group-slots\"\n data-step-slots={i}\n >\n {(selections[i] ?? []).map((item, index) => (\n /* Whole card reopens the wizard AT this step. The inner\n title button provides the keyboard/AT path (its\n activation bubbles here); × stops propagation. */\n // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions -- keyboard path is the inner \"Edit selection\" title button whose activation bubbles to this handler\n <div\n key={`${item.productId}:${item.variantId}:${index}`}\n className=\"lb-mix-match__slot lb-mix-match__slot--filled\"\n onClick={() => setPickerOpenAt(i)}\n >\n {item.featuredImage && (\n <div className=\"lb-bundle-thumbnail\">\n <img\n src={item.featuredImage}\n alt={item.title}\n loading=\"lazy\"\n />\n </div>\n )}\n <div className=\"lb-mix-match__filled-info\">\n <button\n type=\"button\"\n className=\"lb-mix-match__filled-title\"\n aria-label={`Edit selection: ${item.title}`}\n >\n {item.title}\n </button>\n {item.variantTitle &&\n item.variantTitle !== \"Default Title\" && (\n <span className=\"lb-mix-match__filled-variant\">\n {item.variantTitle}\n </span>\n )}\n <span className=\"lb-mix-match__filled-price\">\n {item.compareAtPrice !== null &&\n item.compareAtPrice > item.price && (\n <s className=\"lb-mix-match__filled-compare\">\n {formatMoney(item.compareAtPrice, currency)}\n </s>\n )}\n <span className=\"lb-bundle-product-price\">\n {formatMoney(item.price, currency)}\n </span>\n <span className=\"lb-bundle-qty-inline\">{`×${item.quantity}`}</span>\n </span>\n {item.unitPrice && (\n <span className=\"lb-bundle-product-unit-price\">\n {item.unitPrice}\n </span>\n )}\n </div>\n {canRemoveItem(bundle, selections, item) ? (\n <button\n type=\"button\"\n className=\"lb-mix-match__slot-remove\"\n aria-label={`Remove ${item.title}`}\n onClick={(e) => {\n e.stopPropagation();\n removeSlot(i, index);\n }}\n >\n <CloseIcon />\n </button>\n ) : (\n /* Required pick at its floor — quiet state chip instead\n of the ×; removal returns once another slot covers\n the product's minimum (variant swap flow). */\n <span className=\"lb-mix-match__slot-required\">\n Required\n </span>\n )}\n </div>\n ))}\n </div>\n </section>\n )}\n </Fragment>\n ))}\n </div>\n\n <div className=\"lb-bundle-divider\" />\n\n {/* Whole-bundle pricing — shown once every step's minimum is met. */}\n {allSatisfied && (\n <div className=\"lb-bundle-summary\" data-pricing-section>\n <div className=\"lb-bundle-summary__text\">\n <span className=\"lb-bundle-summary__label\">Bundle total</span>\n {bundle.widgetConfig.savingsBar.visible && summary.savings > 0 && (\n <p className=\"lb-bundle-savings-line\" data-savings-bar>\n You save{\" \"}\n <span data-savings-amount>\n {formatMoney(summary.savings, currency)}\n </span>{\" \"}\n <span data-savings-percent>({summary.savingsPercent}%)</span>\n </p>\n )}\n </div>\n <span className=\"lb-bundle-summary__prices\">\n {bundle.widgetConfig.pricing.showComparePrice &&\n summary.savings > 0 && (\n <span className=\"lb-bundle-compare-price\" data-compare-price>\n {formatMoney(summary.comparePrice, currency)}\n </span>\n )}\n <span className=\"lb-bundle-sale-price\" data-sale-price>\n {formatMoney(summary.salePrice, currency)}\n </span>\n </span>\n </div>\n )}\n\n {cartError && (\n <p className=\"lb-bundle__error\" role=\"alert\">\n {cartError}\n </p>\n )}\n\n <button\n className=\"lb-bundle__cta\"\n onClick={handleAddToCart}\n disabled={addingToCart || !valid}\n aria-busy={addingToCart}\n >\n {ctaLabel}\n </button>\n\n {pickerOpenAt !== null && (\n <MultiStepPicker\n bundle={bundle}\n currency={currency}\n initialStep={pickerOpenAt}\n showStepper={showStepper}\n selections={selections}\n onAdd={addSelection}\n onUpdateQuantity={updateQuantity}\n onRemoveVariant={removeVariant}\n canRemoveVariant={(variantId) => {\n for (const stepPicks of selections) {\n const item = stepPicks.find((p) => p.variantId === variantId);\n if (item) return canRemoveItem(bundle, selections, item);\n }\n return true;\n }}\n swapUnitsFor={(step, productId, variantId) =>\n swapUnitsForItem(bundle, selections, step, productId, variantId)\n }\n onSwap={swapSelection}\n onClose={() => setPickerOpenAt(null)}\n styleVarsRef={setModalConfigVarsRef}\n />\n )}\n </div>\n );\n}\n\n/** True when the step's pool has at least one product with a variant that\n * can fulfil that product's rule.min. */\nfunction stepHasInStockProduct(\n bundle: MultiStepBundleData,\n stepIndex: number,\n): boolean {\n return productsForStep(bundle, stepIndex).some((product) => {\n const rule = ruleFor(bundle, product.id);\n return product.variants.nodes.some((v) => isVariantFulfillable(v, rule.min));\n });\n}\n\nfunction PlusIcon() {\n return (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 18 18\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <line x1=\"9\" y1=\"3\" x2=\"9\" y2=\"15\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n <line x1=\"3\" y1=\"9\" x2=\"15\" y2=\"9\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n\nfunction CloseIcon() {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <line x1=\"5\" y1=\"5\" x2=\"15\" y2=\"15\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n <line x1=\"15\" y1=\"5\" x2=\"5\" y2=\"15\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n","/**\n * Multi-step wizard picker modal — the mix & match picker presented one\n * step at a time (\"Step 2 of 3 · Pick a conditioner\") with Back / Next in\n * the footer and Done on the last step. Portaled to `document.body` so its\n * `position: fixed` overlay isn't clipped by a parent's `transform` /\n * `contain` (common in Shopify themes).\n *\n * Markup, class names and behaviour mirror the storefront theme widget\n * (`extensions/bundle-theme/snippets/lb-multi-step.liquid` +\n * `extensions/bundle-theme/assets/bundle-multi-step.js`) one-for-one so\n * the ported CSS styles this tree without changes. Wizard rules:\n * - the product list, filter pills, and modal progress segments rebuild\n * per step (that step's pool and minimum);\n * - Next is disabled until the current step's minimum is met; Back is\n * hidden on step 1; Done (last step) closes the wizard;\n * - picks are variant-scoped per step; rule.max and stock account\n * across every step's slots.\n */\nimport {\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport {\n formatMoney,\n formatUnitPrice,\n isVariantFulfillable,\n maxAddableQuantity,\n productsForStep,\n stepHeadroom,\n DEFAULT_PRODUCT_RULE,\n type MultiStepBundleData,\n type Product,\n type ProductRule,\n type ProductVariant,\n} from \"@lime-bundles/core\";\nimport { VariantDropdown } from \"./VariantDropdown\";\nimport { useVariantSelection } from \"../hooks/useVariantSelection\";\nimport { useScrollLock } from \"../hooks/useScrollLock\";\nimport { useFocusTrap } from \"../hooks/useFocusTrap\";\nimport type { SelectedItem } from \"./mix-match-types\";\n\n/**\n * The rule in force for a pick. Pass `variantId` and the variant's own rule\n * wins; without one this resolves the product rule, which is the envelope\n * covering every variant.\n */\nfunction ruleFor(\n bundle: MultiStepBundleData,\n productId: string,\n variantId?: string | null,\n): ProductRule {\n if (variantId) {\n const vRule = bundle.variantRules[variantId];\n if (vRule) return vRule;\n }\n return bundle.productRules[productId] ?? DEFAULT_PRODUCT_RULE;\n}\n\n/**\n * The variant's OWN rule, or undefined when it inherits the product's.\n * Distinct from `ruleFor`, which falls back — conflating the two would make\n * every variant of a required product unremovable.\n */\nfunction variantRuleFor(\n bundle: MultiStepBundleData,\n variantId: string | null | undefined,\n): ProductRule | undefined {\n return variantId ? bundle.variantRules[variantId] : undefined;\n}\n\nfunction sanitizeId(gid: string): string {\n return gid.replace(/[^a-zA-Z0-9_-]/g, \"-\");\n}\n\ninterface EligibleProduct {\n product: Product;\n variants: ProductVariant[];\n firstAvailableVariant: ProductVariant | null;\n isOos: boolean;\n}\n\nfunction buildEligibleProducts(\n bundle: MultiStepBundleData,\n stepIndex: number,\n): EligibleProduct[] {\n const result: EligibleProduct[] = [];\n for (const product of productsForStep(bundle, stepIndex)) {\n const rule = ruleFor(bundle, product.id);\n const available = product.variants.nodes.filter((v) =>\n isVariantFulfillable(v, rule.min),\n );\n // Sold-out products stay in the list greyed out; the status flip hides\n // a bundle that can't be completed.\n const isOos = available.length === 0;\n result.push({\n product,\n variants: product.variants.nodes,\n firstAvailableVariant: available[0] ?? null,\n isOos,\n });\n }\n return result;\n}\n\nfunction normalizeText(str: string): string {\n return str\n .normalize(\"NFD\")\n .replace(/[̀-ͯ]/g, \"\")\n .toLowerCase();\n}\n\nexport interface MultiStepPickerProps {\n bundle: MultiStepBundleData;\n currency: string;\n /** Step the wizard opens at (heading click / first unsatisfied step). */\n initialStep: number;\n showStepper: boolean;\n /** Per-step selections — selections[i] = picks of step i. */\n selections: SelectedItem[][];\n /** Add a pick to a step. */\n onAdd: (step: number, item: SelectedItem) => void;\n /** Live-edit a committed pick's quantity within a step. */\n onUpdateQuantity: (\n step: number,\n productId: string,\n variantId: string,\n quantity: number,\n ) => void;\n /** Remove the slot holding this variant from a step (the Added toggle). */\n onRemoveVariant: (step: number, variantId: string) => void;\n /** Whether the slot holding this variant may be removed — false only for\n * a required product's last covering pick (product-level lock, computed\n * across every step). */\n canRemoveVariant?: (variantId: string) => boolean;\n /** In-step units an uncommitted variant of a hard-capped required\n * product could take over in an atomic swap (0 = not in swap state). */\n swapUnitsFor?: (step: number, productId: string, variantId: string) => number;\n /** Perform the atomic in-step swap: the item's units displace\n * sibling-variant units of the same product. */\n onSwap?: (step: number, item: SelectedItem) => void;\n onClose: () => void;\n /** CSS-var carrier ref so the portaled overlay inherits merchant theming. */\n styleVarsRef: (el: HTMLElement | null) => void;\n}\n\nconst FILTERS_ALL = \"__all__\";\n\nexport function MultiStepPicker({\n bundle,\n currency,\n initialStep,\n showStepper,\n selections,\n onAdd,\n onUpdateQuantity,\n onRemoveVariant,\n canRemoveVariant,\n swapUnitsFor,\n onSwap,\n onClose,\n styleVarsRef,\n}: MultiStepPickerProps) {\n const wc = bundle.widgetConfig;\n const steps = bundle.steps;\n const overlayRef = useRef<HTMLDivElement | null>(null);\n const dialogRef = useRef<HTMLDivElement | null>(null);\n const titleRef = useRef<HTMLHeadingElement | null>(null);\n const closeBtnRef = useRef<HTMLButtonElement | null>(null);\n const listRef = useRef<HTMLDivElement | null>(null);\n const mouseDownTarget = useRef<EventTarget | null>(null);\n const [open, setOpen] = useState(false);\n const [stepIndex, setStepIndex] = useState(() =>\n Math.max(0, Math.min(steps.length - 1, initialStep)),\n );\n const [query, setQuery] = useState(\"\");\n const [activeType, setActiveType] = useState<string>(FILTERS_ALL);\n /** Screen-reader step-change announcement ([data-modal-live]). */\n const [announcement, setAnnouncement] = useState(\"\");\n\n const step = steps[stepIndex];\n const stepMin = step?.minQuantity ?? 1;\n const stepPicks = selections[stepIndex] ?? [];\n const unitsInStep = stepPicks.reduce((sum, s) => sum + s.quantity, 0);\n const stepIsSatisfied = unitsInStep >= stepMin;\n const isLastStep = stepIndex === steps.length - 1;\n const shownUnits = Math.min(unitsInStep, stepMin);\n\n const eligible = useMemo(\n () => buildEligibleProducts(bundle, stepIndex),\n [bundle, stepIndex],\n );\n\n // Product-type filter pills for the CURRENT step's pool: only when\n // enabled AND there are ≥2 distinct non-empty product types.\n const productTypes = useMemo(() => {\n const types: string[] = [];\n const seen = new Set<string>();\n for (const ep of eligible) {\n const ty = (ep.product.productType ?? \"\").trim();\n if (ty && !seen.has(ty)) {\n seen.add(ty);\n types.push(ty);\n }\n }\n return types;\n }, [eligible]);\n\n const showFilters = wc.mixMatchShowTypeFilters && productTypes.length >= 2;\n\n // Trigger the open transition on mount (display already shown).\n useEffect(() => {\n const id = requestAnimationFrame(() => setOpen(true));\n return () => cancelAnimationFrame(id);\n }, []);\n\n useScrollLock(true);\n // Initial focus lands on the close icon, not the search input — focusing\n // search on a phone pops the keyboard over half the modal unasked.\n useFocusTrap({\n active: true,\n containerRef: dialogRef,\n initialFocusRef: closeBtnRef,\n onEscape: onClose,\n });\n\n // A step always presents from the top of its list — arriving mid-scroll\n // from the previous step hides the new step's first products.\n useEffect(() => {\n if (listRef.current) listRef.current.scrollTop = 0;\n }, [stepIndex]);\n\n // Products already picked in the shown step (required seeds included) sink\n // below the ones still to pick. The snapshot is captured per step load —\n // re-sorting live on add/remove would make the list jump under the\n // shopper's finger; the next step change (or open) recomputes it.\n const [selectedAtLoad, setSelectedAtLoad] = useState(\n () =>\n new Set((selections[stepIndex] ?? []).map((s) => s.productId)),\n );\n const ordered = useMemo(() => {\n const front: EligibleProduct[] = [];\n const back: EligibleProduct[] = [];\n for (const ep of eligible) {\n (selectedAtLoad.has(ep.product.id) ? back : front).push(ep);\n }\n return front.concat(back);\n }, [eligible, selectedAtLoad]);\n\n /** Wizard navigation: reset filters/search, announce, focus the title. */\n function goToStep(i: number) {\n const clamped = Math.max(0, Math.min(steps.length - 1, i));\n setStepIndex(clamped);\n setQuery(\"\");\n setActiveType(FILTERS_ALL);\n const target = steps[clamped];\n const targetPicks = selections[clamped] ?? [];\n setSelectedAtLoad(new Set(targetPicks.map((s) => s.productId)));\n const targetUnits = targetPicks.reduce((sum, s) => sum + s.quantity, 0);\n setAnnouncement(\n `Step ${clamped + 1} of ${steps.length}. ${target.name}. ` +\n `${Math.min(targetUnits, target.minQuantity)} of ${target.minQuantity} added`,\n );\n titleRef.current?.focus();\n }\n\n const subtitle = `Step ${stepIndex + 1} of ${steps.length} · ${step?.name ?? \"\"}`;\n\n const filtered = useMemo(() => {\n const nq = normalizeText(query.trim());\n return ordered.filter((ep) => {\n const matchesQuery = !nq || normalizeText(ep.product.title).includes(nq);\n const matchesType =\n activeType === FILTERS_ALL ||\n (ep.product.productType ?? \"\") === activeType;\n return matchesQuery && matchesType;\n });\n }, [ordered, query, activeType]);\n\n const showEmpty = filtered.length === 0 && query.trim().length > 0;\n\n function onOverlayMouseDown(e: React.MouseEvent) {\n mouseDownTarget.current = e.target;\n }\n function onOverlayMouseUp(e: React.MouseEvent) {\n if (\n e.target === overlayRef.current &&\n mouseDownTarget.current === overlayRef.current\n ) {\n onClose();\n }\n mouseDownTarget.current = null;\n }\n\n const titleId = `lb-modal-title-${sanitizeId(bundle.id)}`;\n\n const modal = (\n // The overlay is a backdrop: click-outside-to-close is a mouse convenience;\n // keyboard users close via Escape (handled by useFocusTrap), and the dialog\n // inside carries the interactive role + focus trap. So the static-element\n // interaction lint does not apply to this backdrop.\n // eslint-disable-next-line jsx-a11y/no-static-element-interactions\n <div\n ref={(el) => {\n overlayRef.current = el;\n styleVarsRef(el);\n }}\n className={`lb-mix-match__modal-overlay${open ? \" lb-mix-match__modal-overlay--open\" : \"\"}`}\n data-modal-overlay\n data-bundle-gid={bundle.id}\n onMouseDown={onOverlayMouseDown}\n onMouseUp={onOverlayMouseUp}\n >\n <div\n ref={dialogRef}\n className={`lb-mix-match__modal${showFilters ? \"\" : \" lb-mix-match__modal--filters-hidden\"}`}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n tabIndex={-1}\n >\n <div className=\"lb-mix-match__modal-header\">\n <div className=\"lb-mix-match__modal-header-top\">\n <div className=\"lb-mix-match__modal-heading\">\n <h4\n className=\"lb-mix-match__modal-title\"\n id={titleId}\n tabIndex={-1}\n ref={titleRef}\n >\n Add to your bundle\n </h4>\n <p className=\"lb-mix-match__modal-subtitle\" data-modal-subtitle>\n {subtitle}\n </p>\n </div>\n <button\n ref={closeBtnRef}\n type=\"button\"\n className=\"lb-mix-match__modal-close\"\n data-modal-close\n aria-label=\"Close\"\n onClick={onClose}\n >\n <CloseIcon />\n </button>\n </div>\n {/* Per-step progress — one segment per required unit of THIS step. */}\n <div\n className=\"lb-mix-match__progress lb-mix-match__modal-progress\"\n data-progress\n >\n <div\n className=\"lb-mix-match__progress-segments\"\n data-modal-step-segments\n role=\"progressbar\"\n aria-valuenow={shownUnits}\n aria-valuemin={0}\n aria-valuemax={stepMin}\n >\n {Array.from({ length: stepMin }).map((_, i) => (\n <span\n key={i}\n className={`lb-mix-match__progress-segment${i < shownUnits ? \" lb-mix-match__progress-segment--filled\" : \"\"}`}\n data-progress-segment\n />\n ))}\n </div>\n </div>\n </div>\n\n {wc.showSearch && (\n <div className=\"lb-mix-match__modal-search\">\n <input\n type=\"text\"\n className=\"lb-mix-match__modal-search-input\"\n data-modal-search\n role=\"searchbox\"\n aria-label=\"Search products\"\n placeholder=\"Search products\"\n autoComplete=\"off\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n />\n {query.length > 0 && (\n <button\n type=\"button\"\n className=\"lb-mix-match__modal-search-clear\"\n data-modal-search-clear\n aria-label=\"Clear search\"\n onClick={() => setQuery(\"\")}\n >\n <SearchClearIcon />\n </button>\n )}\n </div>\n )}\n\n {showFilters && (\n <div\n className=\"lb-mix-match__filters\"\n data-modal-filters\n role=\"group\"\n aria-label=\"Filter by product type\"\n >\n {[FILTERS_ALL, ...productTypes].map((value) => {\n const isActive = value === activeType;\n return (\n <button\n key={value}\n type=\"button\"\n className={`lb-mix-match__filter${isActive ? \" lb-mix-match__filter--active\" : \"\"}`}\n data-filter={value}\n aria-pressed={isActive}\n onClick={() => setActiveType(value)}\n >\n {value === FILTERS_ALL ? \"All\" : value}\n </button>\n );\n })}\n </div>\n )}\n\n <div className=\"lb-mix-match__modal-list\" data-modal-list ref={listRef}>\n {filtered.map((ep) => (\n <MultiStepPickerRow\n key={`${stepIndex}:${ep.product.id}`}\n bundle={bundle}\n eligible={ep}\n currency={currency}\n showStepper={showStepper}\n stepIndex={stepIndex}\n selections={selections}\n onAdd={onAdd}\n swapUnitsFor={swapUnitsFor}\n onSwap={onSwap}\n onUpdateQuantity={onUpdateQuantity}\n onRemoveVariant={onRemoveVariant}\n canRemoveVariant={canRemoveVariant}\n />\n ))}\n </div>\n\n {showEmpty && (\n <div className=\"lb-mix-match__modal-empty\" data-modal-empty>\n <p>No products match your search</p>\n </div>\n )}\n\n <span data-modal-live aria-live=\"polite\" className=\"lb-visually-hidden\">\n {announcement ||\n (query.trim() ? `${filtered.length} products shown` : \"\")}\n </span>\n\n <div className=\"lb-mix-match__modal-footer lb-multi-step__modal-footer\">\n {stepIndex > 0 && (\n <button\n type=\"button\"\n className=\"lb-multi-step__modal-back\"\n data-modal-back\n onClick={() => goToStep(stepIndex - 1)}\n >\n Back\n </button>\n )}\n <span\n className=\"lb-mix-match__modal-footer-count\"\n data-modal-footer-count\n aria-live=\"polite\"\n >\n {`${shownUnits} of ${stepMin} added`}\n </span>\n {!isLastStep && (\n <button\n type=\"button\"\n className=\"lb-mix-match__modal-done\"\n data-modal-next\n disabled={!stepIsSatisfied}\n onClick={() => {\n if (stepIsSatisfied) goToStep(stepIndex + 1);\n }}\n >\n Next\n </button>\n )}\n {isLastStep && (\n <button\n type=\"button\"\n className=\"lb-mix-match__modal-done\"\n data-modal-done\n disabled={!stepIsSatisfied}\n onClick={onClose}\n >\n Done\n </button>\n )}\n </div>\n </div>\n </div>\n );\n\n if (typeof document === \"undefined\") return null;\n return createPortal(modal, document.body);\n}\n\ninterface MultiStepPickerRowProps {\n bundle: MultiStepBundleData;\n eligible: EligibleProduct;\n currency: string;\n showStepper: boolean;\n /** Wizard step this row belongs to. */\n stepIndex: number;\n /** ALL steps' selections — cross-step stock + rule.max accounting. */\n selections: SelectedItem[][];\n onAdd: (step: number, item: SelectedItem) => void;\n onUpdateQuantity: (\n step: number,\n productId: string,\n variantId: string,\n quantity: number,\n ) => void;\n onRemoveVariant: (step: number, variantId: string) => void;\n canRemoveVariant?: (variantId: string) => boolean;\n swapUnitsFor?: (step: number, productId: string, variantId: string) => number;\n onSwap?: (step: number, item: SelectedItem) => void;\n}\n\nfunction MultiStepPickerRow({\n bundle,\n eligible,\n currency,\n showStepper,\n stepIndex,\n selections,\n onAdd,\n onUpdateQuantity,\n onRemoveVariant,\n canRemoveVariant,\n swapUnitsFor,\n onSwap,\n}: MultiStepPickerRowProps) {\n const { product, variants, isOos } = eligible;\n const rule = ruleFor(bundle, product.id);\n const step = bundle.steps[stepIndex];\n\n const optionNames = useMemo<string[]>(() => {\n const first = variants[0];\n return first ? first.selectedOptions.map((o) => o.name) : [];\n }, [variants]);\n const showPicker = variants.length > 1 && optionNames.length > 0;\n\n const { selectedValues, selectedVariant, setOptionValue, optionsFor } =\n useVariantSelection({ variants, optionNames });\n\n const currentVariant =\n selectedVariant ??\n variants.find((v) => isVariantFulfillable(v, rule.min)) ??\n eligible.firstAvailableVariant ??\n variants[0] ??\n null;\n\n // The rule in force for this row. `rule` above stays the PRODUCT envelope\n // and is used wherever the question is about the product's bundle-wide\n // total; `vRule` is what bounds this variant's own pick.\n const vRule = ruleFor(bundle, product.id, currentVariant?.id);\n const variantMax = variantRuleFor(bundle, currentVariant?.id)?.max;\n\n const stepPicks = useMemo(\n () => selections[stepIndex] ?? [],\n [selections, stepIndex],\n );\n const unitsInStep = stepPicks.reduce((sum, s) => sum + s.quantity, 0);\n\n // Slots are VARIANT-scoped within THIS step: the row's Added state, live\n // stepper, and tint follow its currently-selected variant's slot in the\n // current step. The same variant may hold slots in other steps.\n const committedSelection = useMemo(\n () =>\n currentVariant\n ? (stepPicks.find((s) => s.variantId === currentVariant.id) ?? null)\n : null,\n [stepPicks, currentVariant],\n );\n const variantInStep = committedSelection !== null;\n const committedQty = committedSelection?.quantity ?? 0;\n\n // rule.max caps the PRODUCT's total units across every slot in every\n // step, so slots other than this row's own reduce its share of it.\n const productOtherUnits = useMemo(() => {\n if (!currentVariant) return 0;\n let sum = 0;\n for (let i = 0; i < selections.length; i++) {\n for (const s of selections[i]) {\n if (s.productId !== product.id) continue;\n if (i === stepIndex && s.variantId === currentVariant.id) continue;\n sum += s.quantity;\n }\n }\n return sum;\n }, [selections, product.id, currentVariant, stepIndex]);\n\n // Stock accounting sums the variant's units across ALL steps — the same\n // physical inventory backs it no matter which step holds it.\n const variantOtherUnits = useMemo(() => {\n if (!currentVariant) return 0;\n let sum = 0;\n for (const picks of selections) {\n for (const s of picks) {\n if (s.variantId === currentVariant.id) sum += s.quantity;\n }\n }\n return Math.max(0, sum - committedQty);\n }, [selections, currentVariant, committedQty]);\n\n // ATOMIC SWAP state: a hard-capped required product's uncommitted\n // variants displace in-step sibling units instead of adding, so the\n // step-headroom gates don't apply and the ceiling is the units they\n // can take over.\n const swapUnits = currentVariant\n ? (swapUnitsFor?.(stepIndex, product.id, currentVariant.id) ?? 0)\n : 0;\n const inSwapState = swapUnits >= vRule.min;\n // Ceiling = min(rule.max − product units in other slots,\n // ownQty + step headroom, stock − variant units in other\n // slots). Mirrors setBoundsForVariant in the theme JS.\n const room = stepHeadroom(step?.maxQuantity ?? null, unitsInStep);\n // The variant's own cap binds independently of the envelope: sibling\n // units eat into the product's total, never into this variant's allowance.\n const productHeadroom = Math.min(\n rule.max - productOtherUnits,\n variantMax ?? Infinity,\n );\n const spotCeiling = inSwapState\n ? swapUnits\n : Math.min(\n productHeadroom,\n room === Number.POSITIVE_INFINITY\n ? productHeadroom\n : committedQty + room,\n );\n const stockRemaining = currentVariant\n ? maxAddableQuantity(currentVariant, Number.MAX_SAFE_INTEGER, variantOtherUnits)\n : 0;\n const cap = Math.max(0, Math.min(spotCeiling, stockRemaining));\n const stepperMax = Math.max(vRule.min, cap);\n\n const [qty, setQty] = useState(vRule.min);\n\n // Clamp the local qty whenever the bounds move, and reset to rule.min\n // when the row's variant leaves the step OR the shopper switches to an\n // uncommitted variant.\n useEffect(() => {\n setQty((prev) => Math.max(vRule.min, Math.min(prev, stepperMax)));\n }, [stepperMax, vRule.min]);\n const currentVariantId = currentVariant?.id ?? null;\n useEffect(() => {\n if (!variantInStep) setQty(vRule.min);\n }, [variantInStep, currentVariantId, vRule.min]);\n\n if (!currentVariant || !step) return null;\n\n const thumbImage = currentVariant.image ?? product.featuredImage ?? null;\n const unitPriceText = formatUnitPrice(\n currentVariant.unitPrice,\n currentVariant.unitPriceMeasurement,\n currency,\n );\n\n // Add disabled when: stock (or the product's bundle-wide rule.max) can't\n // satisfy rule.min, or the step's remaining headroom can't fit another\n // rule.min pick (step maximum enforcement).\n const noStock = cap < vRule.min;\n const needsMoreSpots =\n !variantInStep &&\n !inSwapState &&\n room !== Number.POSITIVE_INFINITY &&\n vRule.min > room;\n // A swap frees its own room, so only stock can block it.\n const addDisabled =\n !variantInStep && (inSwapState ? noStock : noStock || needsMoreSpots);\n // Required product's last covering pick — the Remove slot goes inert\n // (\"Required\"); removal returns once another slot covers the minimum.\n const lockedRequired =\n variantInStep &&\n currentVariant != null &&\n !(canRemoveVariant?.(currentVariant.id) ?? true);\n const stepperDisabled = isOos || (!variantInStep && addDisabled);\n const shownQty = variantInStep ? committedQty : qty;\n\n function handleAddOrRemove() {\n if (variantInStep && currentVariant) {\n onRemoveVariant(stepIndex, currentVariant.id);\n return;\n }\n if (!currentVariant || noStock) return;\n const pickedQty = showStepper ? qty : vRule.min;\n const item = {\n productId: product.id,\n variantId: currentVariant.id,\n title: product.title,\n url: `/products/${product.handle}`,\n variantTitle: currentVariant.title,\n featuredImage: thumbImage?.url ?? null,\n price: parseFloat(currentVariant.price.amount),\n compareAtPrice: currentVariant.compareAtPrice\n ? parseFloat(currentVariant.compareAtPrice.amount)\n : null,\n unitPrice: unitPriceText,\n quantity: pickedQty,\n };\n // ATOMIC SWAP: displaces in-step sibling units, so it runs before\n // (and instead of) the step-headroom gate.\n if (inSwapState && onSwap) {\n onSwap(stepIndex, { ...item, quantity: Math.min(pickedQty, swapUnits) });\n return;\n }\n if (needsMoreSpots) return;\n onAdd(stepIndex, item);\n }\n\n const priceCents = parseFloat(currentVariant.price.amount);\n const compareCents = currentVariant.compareAtPrice\n ? parseFloat(currentVariant.compareAtPrice.amount)\n : null;\n\n return (\n <div\n className={`lb-mix-match__modal-product${isOos ? \" lb-mix-match__modal-product--sold-out\" : \"\"}${variantInStep ? \" lb-mix-match__modal-product--in-bundle\" : \"\"}`}\n data-product-item\n data-title={normalizeText(product.title)}\n data-type={product.productType ?? \"\"}\n aria-disabled={isOos || undefined}\n >\n <div className=\"lb-mix-match__modal-product-thumb\">\n {thumbImage && (\n <img\n src={thumbImage.url}\n alt={thumbImage.altText ?? product.title}\n loading=\"lazy\"\n // Intrinsic dimensions reserve the \"original\"-ratio box pre-load\n // (issue #302); inert for the cropped ratios, where CSS sizes it.\n width={thumbImage.width ?? undefined}\n height={thumbImage.height ?? undefined}\n />\n )}\n {variantInStep && (\n <span className=\"lb-mix-match__modal-added-badge\">Added</span>\n )}\n </div>\n\n <div className=\"lb-mix-match__modal-product-info\">\n {/* New tab keeps the in-progress bundle alive — same-tab navigation\n would wipe the shopper's picks. */}\n <p className=\"lb-mix-match__modal-product-title\">\n <a\n href={`/products/${product.handle}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {product.title}\n </a>\n </p>\n <p className=\"lb-mix-match__modal-product-price\">\n <span data-row-price-sale>{formatMoney(priceCents, currency)}</span>\n {compareCents !== null && compareCents > priceCents && (\n <s className=\"lb-mix-match__modal-product-compare\" data-row-compare>\n {formatMoney(compareCents, currency)}\n </s>\n )}\n </p>\n {unitPriceText && (\n <p className=\"lb-mix-match__modal-product-unit-price lb-bundle-product-unit-price\">\n {unitPriceText}\n </p>\n )}\n\n {showPicker && (\n <div className=\"lb-bundle-variant-option-groups\">\n {optionNames.map((optionName, optionIndex) => {\n const dropdownOptions = optionsFor(optionIndex).map((o) => ({\n value: o.value,\n label: o.value,\n disabled: o.disabled,\n }));\n return (\n <div\n key={optionName}\n className=\"lb-bundle-variant-option-group\"\n >\n <span className=\"lb-bundle-variant-option-label\">\n {optionName}\n </span>\n <VariantDropdown\n className=\"lb-mix-match__variant-select-dropdown\"\n options={dropdownOptions}\n value={selectedValues[optionIndex] ?? null}\n onChange={(v) => setOptionValue(optionIndex, v)}\n ariaLabel={optionName}\n />\n </div>\n );\n })}\n </div>\n )}\n {!showPicker &&\n variants.length === 1 &&\n currentVariant.title !== \"Default Title\" && (\n <span className=\"lb-mix-match__filled-variant\">\n {currentVariant.title}\n </span>\n )}\n\n {/* \"Needs N spots\" hint — the step's remaining headroom can't fit\n another rule.min pick. Hidden at zero headroom, where the step's\n complete state already tells the story for every row. */}\n {!isOos && needsMoreSpots && room > 0 && (\n <span className=\"lb-mix-match__modal-needs-spots\">\n {vRule.min === 1 ? \"Needs 1 spot\" : `Needs ${vRule.min} spots`}\n </span>\n )}\n\n {isOos ? (\n <span className=\"lb-mix-match__modal-sold-out-label\">Sold out</span>\n ) : (\n <div className=\"lb-mix-match__modal-product-actions\">\n {showStepper && (\n <div className=\"lb-bundle-variant-option-group lb-mix-match__qty-stepper-group\">\n <div\n className=\"lb-mix-match__qty-stepper\"\n role=\"group\"\n aria-label=\"Quantity\"\n >\n <button\n type=\"button\"\n className=\"lb-mix-match__qty-stepper-button lb-mix-match__qty-stepper-button--minus\"\n aria-label=\"Decrease quantity\"\n disabled={stepperDisabled || shownQty <= vRule.min}\n onClick={() => {\n if (variantInStep && currentVariant) {\n // LIVE EDIT — propagate into selections state.\n onUpdateQuantity(\n stepIndex,\n product.id,\n currentVariant.id,\n Math.max(vRule.min, committedQty - 1),\n );\n } else {\n setQty((q) => Math.max(vRule.min, q - 1));\n }\n }}\n >\n {\"−\"}\n </button>\n <span\n className=\"lb-mix-match__qty-stepper-value\"\n data-row-qty\n aria-live=\"polite\"\n >\n {shownQty}\n </span>\n <button\n type=\"button\"\n className=\"lb-mix-match__qty-stepper-button lb-mix-match__qty-stepper-button--plus\"\n aria-label=\"Increase quantity\"\n disabled={stepperDisabled || shownQty >= stepperMax}\n onClick={() => {\n if (variantInStep && currentVariant) {\n onUpdateQuantity(\n stepIndex,\n product.id,\n currentVariant.id,\n Math.min(stepperMax, committedQty + 1),\n );\n } else {\n setQty((q) => Math.min(stepperMax, q + 1));\n }\n }}\n >\n +\n </button>\n </div>\n </div>\n )}\n <button\n type=\"button\"\n className={`lb-mix-match__modal-add${variantInStep ? \" lb-mix-match__modal-add--added\" : \"\"}${lockedRequired ? \" lb-mix-match__modal-add--required\" : \"\"}`}\n data-add-product\n aria-label={\n variantInStep\n ? lockedRequired\n ? `${product.title} is required and cannot be removed`\n : `Remove ${product.title}`\n : `${inSwapState ? \"Swap\" : \"Add\"} ${product.title}`\n }\n disabled={addDisabled || lockedRequired}\n onClick={handleAddOrRemove}\n >\n {/* Explicit inverted \"Remove\" — state feedback lives on the\n thumbnail's \"Added\" badge, not the button. */}\n {variantInStep\n ? lockedRequired\n ? \"Required\"\n : \"Remove\"\n : inSwapState\n ? \"Swap\"\n : \"Add\"}\n </button>\n </div>\n )}\n </div>\n </div>\n );\n}\n\nfunction CloseIcon() {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <line x1=\"5\" y1=\"5\" x2=\"15\" y2=\"15\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n <line x1=\"15\" y1=\"5\" x2=\"5\" y2=\"15\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n\nfunction SearchClearIcon() {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path d=\"M14.348 5.652a.5.5 0 0 0-.707 0L10 9.293 6.36 5.652a.5.5 0 1 0-.708.707L9.293 10l-3.641 3.641a.5.5 0 0 0 .708.707L10 10.707l3.641 3.641a.5.5 0 0 0 .707-.707L10.707 10l3.641-3.641a.5.5 0 0 0 0-.707z\" />\n </svg>\n );\n}\n","/**\n * @deprecated Use `fetchShopSettings`, which returns the custom CSS alongside\n * the shop's out-of-stock behaviour in the same round trip. This wrapper is\n * kept so existing integrations keep compiling; it shares the same per-shop\n * cache, so calling both costs one request.\n */\nimport { fetchShopSettings, __clearShopSettingsCache } from \"./fetchShopSettings\";\nimport type { FetchShopSettingsOptions } from \"./fetchShopSettings\";\n\nexport type FetchShopCustomCssOptions = FetchShopSettingsOptions;\n\n/** @deprecated Use `fetchShopSettings().customCss`. */\nexport async function fetchShopCustomCss(\n options: FetchShopCustomCssOptions,\n): Promise<string | null> {\n const settings = await fetchShopSettings(options);\n return settings.customCss;\n}\n\n/** @deprecated Use `__clearShopSettingsCache`. Test-only. */\nexport function __clearShopCssCache(): void {\n __clearShopSettingsCache();\n}\n","/**\n * Client-side React hook wrapping `fetchBundlesForProduct` — the\n * React-SDK analogue of the web component's auto-detect-by-current-product\n * mode. The web component reads the handle from `location.pathname`; a\n * React app already has it on the router, so the hook takes it as an\n * explicit `productHandle` option.\n *\n * Returns every active bundle configured against the product. Inactive,\n * draft, scheduled-for-later, and expired bundles are filtered out by\n * the core helper — consumers don't have to guard.\n *\n * For SSR / RSC contexts (Hydrogen loaders, Next.js server components),\n * prefer `fetchBundlesForProduct` directly and pass the list to a client\n * component as a prop. This hook's only value-add over the async\n * function is React state management + abort-on-unmount.\n *\n * `UseBundlesForProductResult` is a discriminated union locked at v2.0.0:\n * narrowing via `status` is safe. Widening or adding states is a\n * breaking change.\n */\nimport { useState, useEffect } from \"react\";\nimport {\n fetchBundlesForProduct,\n injectCustomCss,\n type ParsedBundle,\n} from \"@lime-bundles/core\";\nimport { fetchShopSettings } from \"../fetchShopSettings\";\n\nexport interface UseBundlesForProductOptions {\n shopDomain: string;\n storefrontAccessToken: string;\n productHandle: string;\n /** Forwarded as `Shopify-Storefront-Buyer-IP` — required for SSR paths. */\n buyerIp?: string;\n}\n\nexport type UseBundlesForProductResult =\n | { status: \"loading\"; bundles: null; error: null }\n | { status: \"success\"; bundles: ParsedBundle[]; error: null }\n | { status: \"error\"; bundles: null; error: Error };\n\nconst INITIAL_STATE: UseBundlesForProductResult = {\n status: \"loading\",\n bundles: null,\n error: null,\n};\n\nexport function useBundlesForProduct(\n options: UseBundlesForProductOptions,\n): UseBundlesForProductResult {\n const [state, setState] = useState<UseBundlesForProductResult>(\n INITIAL_STATE,\n );\n\n useEffect(() => {\n const controller = new AbortController();\n setState(INITIAL_STATE);\n\n fetchBundlesForProduct({\n shopDomain: options.shopDomain,\n storefrontAccessToken: options.storefrontAccessToken,\n productHandle: options.productHandle,\n buyerIp: options.buyerIp,\n signal: controller.signal,\n })\n .then((bundles) => {\n if (controller.signal.aborted) return;\n setState({ status: \"success\", bundles, error: null });\n })\n .catch((err: unknown) => {\n if (controller.signal.aborted) return;\n setState({\n status: \"error\",\n bundles: null,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n });\n\n // Fire-and-forget custom CSS fetch so storefronts using this hook get\n // merchant styling automatically — same behaviour as `useBundleData`.\n fetchShopSettings({\n shopDomain: options.shopDomain,\n storefrontAccessToken: options.storefrontAccessToken,\n signal: controller.signal,\n })\n .then((settings) => {\n if (controller.signal.aborted) return;\n injectCustomCss(options.shopDomain, settings.customCss);\n })\n .catch(() => {\n // Silent — no merchant CSS is fine.\n });\n\n return () => {\n controller.abort();\n };\n }, [\n options.shopDomain,\n options.storefrontAccessToken,\n options.productHandle,\n options.buyerIp,\n ]);\n\n return state;\n}\n"],"mappings":"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","names":["import_react","import_core","import_core","import_core","import_react","import_core","import_react","import_core","import_react","import_core","variantsNs","import_react","import_react","import_core","import_react","import_jsx_runtime","import_jsx_runtime","import_react","import_core","import_react","import_core","import_react","import_react","import_jsx_runtime","import_jsx_runtime","ruleFor","variantRuleFor","variant","requiredUnits","CloseIcon","import_react","import_core","import_jsx_runtime","import_react","import_core","import_jsx_runtime","buyVariant","getVariant","buyUnit","getUnit","import_react","import_core","import_react","import_react_dom","import_core","import_jsx_runtime","ruleFor","variantRuleFor","sanitizeId","buildEligibleProducts","normalizeText","FILTERS_ALL","CloseIcon","SearchClearIcon","import_jsx_runtime","ruleFor","variantRuleFor","canRemoveItem","swapUnitsForItem","PlusIcon","CloseIcon","import_react","import_core","INITIAL_STATE","import_core"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/components/FixedBundle.tsx","../src/hooks/useBundleData.ts","../src/fetchBundleData.ts","../src/fetchShopSettings.ts","../src/hooks/useAnalytics.ts","../src/hooks/useWidgetConfigVars.ts","../src/hooks/useVariantSelection.ts","../src/hooks/useEdgeFade.ts","../src/components/VariantDropdown.tsx","../src/components/BundleCountdown.tsx","../src/components/MixMatchBundle.tsx","../src/components/MixMatchPicker.tsx","../src/hooks/useScrollLock.ts","../src/hooks/useFocusTrap.ts","../src/components/VolumeBundle.tsx","../src/components/BogoBundle.tsx","../src/components/MultiStepBundle.tsx","../src/components/MultiStepPicker.tsx","../src/fetchShopCustomCss.ts","../src/hooks/useBundlesForProduct.ts"],"sourcesContent":["// Bundle components — BYO-cart via `onAddToCart`.\nexport { FixedBundle } from \"./components/FixedBundle\";\nexport {\n MixMatchBundle,\n type MixMatchBundleProps,\n} from \"./components/MixMatchBundle\";\nexport {\n BundleCountdown,\n type BundleCountdownProps,\n} from \"./components/BundleCountdown\";\nexport { VolumeBundle } from \"./components/VolumeBundle\";\nexport { BogoBundle } from \"./components/BogoBundle\";\nexport { MultiStepBundle } from \"./components/MultiStepBundle\";\nexport type { BundleComponentProps } from \"./components/types\";\n\n// Variant picker primitives — composable for merchants who want to build\n// their own bundle UI on top of `useBundleData` while reusing the same\n// accessible custom dropdown.\nexport {\n VariantDropdown,\n type VariantDropdownProps,\n type VariantDropdownOption,\n} from \"./components/VariantDropdown\";\nexport {\n useVariantSelection,\n type UseVariantSelectionOptions,\n type UseVariantSelectionResult,\n} from \"./hooks/useVariantSelection\";\n\n// Data fetching\nexport {\n fetchBundleData,\n type FetchBundleDataOptions,\n} from \"./fetchBundleData\";\nexport {\n fetchShopSettings,\n fetchShopSettingsOrDefault,\n type FetchShopSettingsOptions,\n type ShopSettings,\n} from \"./fetchShopSettings\";\n/** @deprecated Superseded by `fetchShopSettings`; kept for compatibility. */\nexport {\n fetchShopCustomCss,\n type FetchShopCustomCssOptions,\n} from \"./fetchShopCustomCss\";\nexport {\n useBundleData,\n type UseBundleDataOptions,\n type UseBundleDataResult,\n} from \"./hooks/useBundleData\";\nexport {\n useBundlesForProduct,\n type UseBundlesForProductOptions,\n type UseBundlesForProductResult,\n} from \"./hooks/useBundlesForProduct\";\nexport { useAnalytics } from \"./hooks/useAnalytics\";\nexport { useWidgetConfigVars } from \"./hooks/useWidgetConfigVars\";\n\n// Re-export core types consumers commonly need.\nexport type {\n ParsedBundle,\n FixedBundleData,\n VolumeBundleData,\n MixMatchBundleData,\n BogoBundleData,\n MultiStepBundleData,\n ParsedMultiStep,\n BundleType,\n Product,\n ProductVariant,\n CartLineInput,\n WidgetConfig,\n HeaderConfig,\n LayoutConfig,\n ProductListConfig,\n ThumbnailRatio,\n PricingConfig,\n SavingsBarConfig,\n CtaConfig,\n CountdownConfig,\n PopularBadgeConfig,\n VolumeTier,\n DiscountConfig,\n PricingRow,\n FixedBundlePricing,\n ImageTransform,\n} from \"@lime-bundles/core\";\nexport { BundleParseError, StorefrontApiError } from \"@lime-bundles/core\";\n\n// DIY widget primitives — every helper a developer needs to build their\n// own bundle UI with the same data, math, and theming the first-party\n// widget uses. All live in `@lime-bundles/core`; importing from the\n// React package is shorthand for consumers who already pulled `react`.\nexport {\n // Bundle config + variant merging\n WIDGET_CONFIG_DEFAULTS,\n mergeWidgetConfig,\n applyWidgetConfigVars,\n thumbnailRatioVars,\n // Pricing (integer cents, matches Shopify Discount Function rounding)\n parseCents,\n formatCents,\n percentageDiscountUnit,\n computeFixedPricing,\n computeBundleSaleCents,\n // Volume-tier calculation\n calculateTierSavings,\n getActiveTier,\n // Multi-step wizard helpers\n productsForStep,\n stepHeadroom,\n // Mix-match quantity validation\n validateQuantity,\n // Image / countdown / money helpers\n transformImageUrl,\n formatCountdown,\n formatMoney,\n formatUnitPrice,\n calculateDiscount,\n // Analytics (optional — FixedBundle / VolumeBundle / MixMatchBundle\n // auto-fire these unless analyticsEnabled is set to false)\n reportImpression,\n reportAddToCart,\n observeImpression,\n // CSS injection + sanitizer\n injectCustomCss,\n sanitizeCustomCss,\n // Custom-storefront data fetching\n createStorefrontClient,\n fetchBundlesForProduct,\n parseMetaobjectBundle,\n parseMetaobjectBundleStrict,\n BUNDLE_METAOBJECT_QUERY,\n BUNDLES_FOR_PRODUCT_QUERY,\n SHOP_SETTINGS_QUERY,\n} from \"@lime-bundles/core\";\n","/**\n * Fixed bundle component — pre-selected products with a shared discount.\n */\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport {\n formatMoney,\n formatUnitPrice,\n calculateDiscount,\n resolveBundleQty,\n isVariantFulfillable,\n shouldShowLowStockBadge,\n type CartLineInput,\n type FixedBundleData,\n type Product,\n type ProductVariant,\n} from \"@lime-bundles/core\";\nimport { useBundleData } from \"../hooks/useBundleData\";\nimport { useAnalytics } from \"../hooks/useAnalytics\";\nimport { useWidgetConfigVars } from \"../hooks/useWidgetConfigVars\";\nimport { useVariantSelection } from \"../hooks/useVariantSelection\";\nimport { useEdgeFade } from \"../hooks/useEdgeFade\";\nimport { VariantDropdown } from \"./VariantDropdown\";\nimport type { BundleComponentProps } from \"./types\";\nimport { BundleCountdown } from \"./BundleCountdown\";\n\nexport function FixedBundle(props: BundleComponentProps) {\n const {\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n appUrl,\n analyticsEnabled,\n onAddToCart,\n onError,\n className,\n } = props;\n\n const result = useBundleData({\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n });\n\n const { elementRef, trackAddToCart } = useAnalytics({\n shopDomain,\n appUrl: appUrl ?? `https://${shopDomain}`,\n bundleGid,\n bundleType: \"fixed\",\n enabled: analyticsEnabled !== false,\n });\n\n const [addingToCart, setAddingToCart] = useState(false);\n const [cartError, setCartError] = useState<string | null>(null);\n // Tracks the customer's selected variant per product. Seeded with first\n // available variant on first render; updated by <ProductRow> via callback.\n const [selectedVariants, setSelectedVariants] = useState<\n Record<string, ProductVariant | null>\n >({});\n\n const handleVariantChange = useCallback(\n (productId: string, variant: ProductVariant | null) => {\n setSelectedVariants((prev) => {\n if (prev[productId] === variant) return prev;\n return { ...prev, [productId]: variant };\n });\n },\n [],\n );\n\n const bundle =\n result.status === \"success\" && result.bundle.bundleType === \"fixed\"\n ? (result.bundle as FixedBundleData)\n : null;\n\n // Apply merchant-config CSS vars (including --lb-thumbnail-aspect-ratio)\n // to the component root via a callback ref composed with elementRef.\n const setConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);\n\n // Scroll-aware edge fade on the inset product list.\n const productsEdgeFadeRef = useEdgeFade();\n\n // Surface load/narrowing errors via onError — in a useEffect so we don't\n // fire side effects during render.\n useEffect(() => {\n if (result.status === \"error\") {\n onError?.(result.error);\n return;\n }\n if (\n result.status === \"success\" &&\n result.bundle.bundleType !== \"fixed\"\n ) {\n onError?.(\n new Error(\n `FixedBundle: expected bundleType=\"fixed\", got \"${result.bundle.bundleType}\"`,\n ),\n );\n }\n }, [result, onError]);\n\n /**\n * Products the store can't sell at the quantity this bundle needs.\n *\n * A fixed bundle is all-or-nothing, so one unavailable product makes the\n * whole thing unbuyable. Previously nothing here modelled that: every row\n * rendered as normal and the CTA stayed live, then `handleAddToCart` filtered\n * the unfulfillable products out and bailed on an empty list — a button that\n * looked fine and silently did nothing.\n */\n const oosProductIds = useMemo(() => {\n if (!bundle) return new Set<string>();\n return new Set(\n bundle.products\n .filter(\n (p) =>\n !p.variants.nodes.some((v) =>\n isVariantFulfillable(v, resolveBundleQty(bundle, p.id, v.id)),\n ),\n )\n .map((p) => p.id),\n );\n }, [bundle]);\n\n const handleAddToCart = useCallback(async () => {\n if (!bundle) return;\n\n // Qty resolution (variantQuantities → productQuantities → 1) lives in\n // `@lime-bundles/core` so the five-runtime fallback chain has a single\n // source of truth. See resolveBundleQty + PR #147 history.\n const bundleLines = bundle.products\n .filter((p) =>\n p.variants.nodes.some((v) =>\n isVariantFulfillable(v, resolveBundleQty(bundle, p.id, v.id)),\n ),\n )\n .map((p) => {\n const variant =\n selectedVariants[p.id] ??\n p.variants.nodes.find((v) =>\n isVariantFulfillable(v, resolveBundleQty(bundle, p.id, v.id)),\n )!;\n return {\n productId: p.id,\n variant,\n quantity: resolveBundleQty(bundle, p.id, variant.id),\n };\n })\n .filter((line) => line.quantity > 0);\n\n if (bundleLines.length === 0) return;\n\n const lines: CartLineInput[] = bundleLines.map((line) => ({\n merchandiseId: line.variant.id,\n quantity: line.quantity,\n attributes: [\n { key: \"_lime_bundle_gid\", value: bundle.id },\n { key: \"_lime_bundle_type\", value: bundle.bundleType },\n ],\n }));\n\n setAddingToCart(true);\n setCartError(null);\n try {\n await onAddToCart(lines);\n const totalPrice = bundleLines.reduce((sum, line) => {\n const price = parseFloat(line.variant.price.amount);\n const discounted = calculateDiscount(\n price,\n bundle.discountConfig.discountType,\n bundle.discountConfig.discountValue,\n );\n return sum + discounted * line.quantity;\n }, 0);\n const totalQuantity = bundleLines.reduce(\n (sum, line) => sum + line.quantity,\n 0,\n );\n // productId is intentionally omitted — a fixed bundle spans multiple\n // products with no single \"page product\"; bundleGid on the event\n // already attributes to the bundle.\n trackAddToCart({\n quantity: totalQuantity,\n totalPrice: Math.round(totalPrice * 100) / 100,\n });\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setCartError(error.message);\n onError?.(error);\n } finally {\n setAddingToCart(false);\n }\n }, [bundle, onAddToCart, onError, trackAddToCart, selectedVariants]);\n\n if (result.status === \"loading\") {\n return (\n <div className={`lb-bundle lb-bundle--loading ${className ?? \"\"}`}>\n <div className=\"lb-skeleton lb-skeleton--title\" />\n <div className=\"lb-skeleton lb-skeleton--products\" />\n </div>\n );\n }\n\n if (result.status === \"error\") return null;\n // Bundle loaded but wasn't a \"fixed\" variant — render nothing; the\n // useEffect above has already invoked onError with a descriptive message.\n if (!bundle) return null;\n\n const currency =\n bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? \"USD\";\n\n // Receipt totals — sum each product's display-variant line at full price\n // and discounted price, then derive the savings amount + honest rounded\n // percent. Mirrors the storefront widget's summary band: compare-at before\n // sale price, sale price the heaviest element, one quiet \"You save\" line.\n let comparePrice = 0;\n let salePrice = 0;\n for (const product of bundle.products) {\n const variants = product.variants.nodes;\n const variant =\n selectedVariants[product.id] ??\n variants.find((v) =>\n isVariantFulfillable(v, resolveBundleQty(bundle, product.id, v.id)),\n ) ??\n variants[0];\n if (!variant) continue;\n const qty = resolveBundleQty(bundle, product.id, variant.id);\n const unit = parseFloat(variant.price.amount);\n comparePrice += unit * qty;\n salePrice +=\n calculateDiscount(\n unit,\n bundle.discountConfig.discountType,\n bundle.discountConfig.discountValue,\n ) * qty;\n }\n const savings = Math.max(0, comparePrice - salePrice);\n const savingsPercent =\n comparePrice > 0 && savings > 0\n ? Math.round((savings / comparePrice) * 100)\n : 0;\n const showCompare =\n bundle.widgetConfig.pricing.showComparePrice && savings > 0;\n const showSavings = bundle.widgetConfig.savingsBar.visible && savings > 0;\n\n return (\n <div\n ref={(el) => {\n elementRef(el);\n setConfigVarsRef(el);\n }}\n className={`lb-bundle lb-bundle--fixed ${className ?? \"\"}`}\n role=\"region\"\n aria-label={bundle.title}\n >\n <div className=\"lb-bundle-header\">\n <div className=\"lb-bundle-header__content\">\n <h3 className=\"lb-bundle-title\">{bundle.title}</h3>\n {bundle.description && (\n <p className=\"lb-bundle-subtitle\">{bundle.description}</p>\n )}\n </div>\n </div>\n\n <BundleCountdown\n endsAt={bundle.endsAt}\n widgetConfig={bundle.widgetConfig}\n />\n\n <div className=\"lb-bundle__products lb-edge-fade\" ref={productsEdgeFadeRef}>\n {bundle.products.map((product) => (\n <FixedProductRow\n key={product.id}\n bundle={bundle}\n product={product}\n currency={currency}\n isOos={oosProductIds.has(product.id)}\n onVariantChange={handleVariantChange}\n />\n ))}\n </div>\n\n <div className=\"lb-bundle-divider\" />\n\n <div className=\"lb-bundle-summary\">\n <div className=\"lb-bundle-summary__text\">\n <span className=\"lb-bundle-summary__label\">Bundle total</span>\n {showSavings && (\n <p className=\"lb-bundle-savings-line\" data-savings-bar>\n You save{\" \"}\n <span data-savings-amount>{formatMoney(savings, currency)}</span>{\" \"}\n <span data-savings-percent>({savingsPercent}%)</span>\n </p>\n )}\n </div>\n <span className=\"lb-bundle-summary__prices\">\n {showCompare && (\n <span className=\"lb-bundle-compare-price\" data-compare-price>\n {formatMoney(comparePrice, currency)}\n </span>\n )}\n <span className=\"lb-bundle-sale-price\" data-sale-price>\n {formatMoney(salePrice, currency)}\n </span>\n </span>\n </div>\n\n {cartError && (\n <p className=\"lb-bundle__error\" role=\"alert\">\n {cartError}\n </p>\n )}\n\n <button\n className=\"lb-bundle__cta\"\n onClick={handleAddToCart}\n disabled={addingToCart || oosProductIds.size > 0}\n aria-busy={addingToCart}\n >\n {addingToCart\n ? \"Adding...\"\n : oosProductIds.size > 0\n ? `${oosProductIds.size} item${oosProductIds.size === 1 ? \"\" : \"s\"} unavailable`\n : (bundle.widgetConfig.cta.ctaText ?? \"Add Bundle to Cart\")}\n </button>\n </div>\n );\n}\n\ninterface FixedProductRowProps {\n bundle: FixedBundleData;\n product: Product;\n currency: string;\n /** No variant can cover this bundle's required quantity. */\n isOos: boolean;\n onVariantChange: (productId: string, variant: ProductVariant | null) => void;\n}\n\nfunction FixedProductRow({ bundle, product, currency, isOos, onVariantChange }: FixedProductRowProps) {\n const variants = product.variants.nodes;\n const optionNames = useMemo<string[]>(() => {\n const first = variants[0];\n return first ? first.selectedOptions.map((o) => o.name) : [];\n }, [variants]);\n\n const showPicker = variants.length > 1 && optionNames.length > 0;\n\n const { selectedValues, selectedVariant, setOptionValue, optionsFor } =\n useVariantSelection({\n variants,\n optionNames,\n // Quantity-aware dropdown: a variant that can't cover this row's\n // bundle quantity greys out instead of walking the shopper into a\n // cart Shopify caps at add time.\n requiredQtyFor: (variantId) =>\n resolveBundleQty(bundle, product.id, variantId),\n });\n\n // Surface the selection to the parent so handleAddToCart picks the right\n // variant. Includes initial seed via effect so cart payload reflects the\n // first-available default before any picker interaction.\n useEffect(() => {\n onVariantChange(product.id, selectedVariant ?? null);\n }, [selectedVariant, product.id, onVariantChange]);\n\n // selectedVariant resolves null only during a transient invalid combo\n // (e.g. Size=Medium+Color=Red where that pairing is sold out). Fall back\n // to the first available so the row keeps showing a sensible price.\n const displayVariant =\n selectedVariant ??\n variants.find((v) =>\n isVariantFulfillable(v, resolveBundleQty(bundle, product.id, v.id)),\n ) ??\n variants[0];\n const priceText = displayVariant\n ? formatMoney(displayVariant.price.amount, currency)\n : formatMoney(product.priceRange.minVariantPrice.amount, currency);\n const compareAt =\n displayVariant?.compareAtPrice &&\n parseFloat(displayVariant.compareAtPrice.amount) >\n parseFloat(displayVariant.price.amount)\n ? formatMoney(displayVariant.compareAtPrice.amount, currency)\n : null;\n const unitPriceText = displayVariant\n ? formatUnitPrice(\n displayVariant.unitPrice,\n displayVariant.unitPriceMeasurement,\n currency,\n )\n : null;\n\n // \"×N\" quantity for the card's right-slot chip — always shown (even \"×1\")\n // so the quantity column reads cleanly down the card list.\n const displayQty = displayVariant\n ? resolveBundleQty(bundle, product.id, displayVariant.id)\n : 1;\n\n const thumbImage = displayVariant?.image ?? product.featuredImage;\n\n const showLowStock =\n !!displayVariant &&\n shouldShowLowStockBadge(\n displayVariant,\n resolveBundleQty(bundle, product.id, displayVariant.id),\n bundle.widgetConfig.lowStockThreshold,\n bundle.widgetConfig.showLowStockBadge,\n );\n\n return (\n <div\n // Same class the web component and Liquid use, so the shared stylesheet\n // greys the row identically on all three surfaces.\n className={\n isOos\n ? \"lb-bundle-product-row lb-bundle-product-row--oos\"\n : \"lb-bundle-product-row\"\n }\n aria-disabled={isOos || undefined}\n part=\"product\"\n >\n {isOos && <span className=\"lb-bundle-product-row__oos\">Out of stock</span>}\n {thumbImage && (\n <img\n src={thumbImage.url}\n alt={thumbImage.altText ?? product.title}\n className=\"lb-bundle__product-image\"\n loading=\"lazy\"\n // Intrinsic dimensions so the browser reserves the box before the\n // file arrives — without them the \"original\" thumbnail ratio has no\n // height until load and everything below the row jumps (issue #302).\n width={thumbImage.width ?? undefined}\n height={thumbImage.height ?? undefined}\n />\n )}\n {/* Info column flows name → variant badge → price (compare + sale) →\n unit price → pickers, mirroring the mix & match chosen-product card. */}\n <div className=\"lb-bundle__product-info\">\n <p className=\"lb-bundle__product-title\">{product.title}</p>\n {/* Read-only variant text sits directly under the title when a\n multi-variant product is scoped to a single variant. */}\n {!showPicker && displayVariant && variants.length > 1 && (\n <span className=\"lb-bundle-variant-badge\">\n {displayVariant.title}\n </span>\n )}\n <span className=\"lb-bundle-product-prices\">\n {compareAt && (\n <span\n className=\"lb-bundle-product-compare-price\"\n data-product-compare-price\n >\n {compareAt}\n </span>\n )}\n <span className=\"lb-bundle__product-price\" data-product-price>\n {priceText}\n </span>\n </span>\n {unitPriceText && (\n <span\n className=\"lb-bundle__product-unit-price\"\n data-product-unit-price\n >\n {unitPriceText}\n </span>\n )}\n {showLowStock && (\n <span className=\"lb-bundle-low-stock-badge\">\n Only {displayVariant.quantityAvailable} left\n </span>\n )}\n {showPicker && (\n <div className=\"lb-bundle__product-variant-pickers\">\n {optionNames.map((optionName, optionIndex) => {\n const dropdownOptions = optionsFor(optionIndex).map((o) => ({\n value: o.value,\n label: o.value,\n disabled: o.disabled,\n }));\n return (\n <VariantDropdown\n key={optionName}\n options={dropdownOptions}\n value={selectedValues[optionIndex] ?? null}\n onChange={(v) => setOptionValue(optionIndex, v)}\n ariaLabel={optionName}\n />\n );\n })}\n </div>\n )}\n </div>\n {/* Quantity chip — fixed-bundle products can't be removed, so the card's\n right slot (where mix & match shows the remove ×) shows how many of\n this product the bundle includes. Always shown, even ×1. */}\n {displayVariant && (\n <span className=\"lb-bundle-qty-chip\" data-qty-inline>\n &times;{displayQty}\n </span>\n )}\n </div>\n );\n}\n","/**\n * Client-side React hook wrapping `fetchBundleData` with loading / error\n * state + abort-on-unmount.\n *\n * For SSR / RSC contexts (Hydrogen loaders, Next.js server components),\n * prefer `fetchBundleData` directly and pass the result to a client\n * component as a prop — the hook's only value-add over the async\n * function is React state management.\n *\n * `UseBundleDataResult` is a discriminated union locked at v1.0.0:\n * narrowing via `status` is safe. Widening or adding states is a\n * breaking change.\n */\nimport { useState, useEffect } from \"react\";\nimport {\n injectCustomCss,\n type BuyerResolver,\n type ParsedBundle,\n} from \"@lime-bundles/core\";\nimport { fetchBundleData } from \"../fetchBundleData\";\nimport { fetchShopSettings } from \"../fetchShopSettings\";\n\nexport interface UseBundleDataOptions {\n shopDomain: string;\n storefrontAccessToken: string;\n bundleGid: string;\n /** ISO-3166 alpha-2 country, passed as Storefront `@inContext(country:)`. */\n country?: string;\n /** ISO-639-1 language, passed as `@inContext(language:)`. */\n language?: string;\n /** B2B buyer identity. Prefer the callback form to keep tokens off prop trees. */\n buyer?: BuyerResolver;\n /** Current visitor's Market GID — filters market-restricted bundles client-side. */\n marketId?: string;\n}\n\nexport type UseBundleDataResult =\n | { status: \"loading\"; bundle: null; error: null }\n | { status: \"success\"; bundle: ParsedBundle; error: null }\n | { status: \"error\"; bundle: null; error: Error };\n\nconst INITIAL_STATE: UseBundleDataResult = {\n status: \"loading\",\n bundle: null,\n error: null,\n};\n\nexport function useBundleData(\n options: UseBundleDataOptions,\n): UseBundleDataResult {\n const [state, setState] = useState<UseBundleDataResult>(INITIAL_STATE);\n\n useEffect(() => {\n const controller = new AbortController();\n setState(INITIAL_STATE);\n\n fetchBundleData({\n shopDomain: options.shopDomain,\n storefrontAccessToken: options.storefrontAccessToken,\n bundleGid: options.bundleGid,\n signal: controller.signal,\n country: options.country,\n language: options.language,\n buyer: options.buyer,\n marketId: options.marketId,\n })\n .then((bundle) => {\n if (controller.signal.aborted) return;\n setState({ status: \"success\", bundle, error: null });\n })\n .catch((err: unknown) => {\n if (controller.signal.aborted) return;\n setState({\n status: \"error\",\n bundle: null,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n });\n\n // Fire-and-forget custom CSS fetch — best-effort, failures never block\n // bundle rendering.\n fetchShopSettings({\n shopDomain: options.shopDomain,\n storefrontAccessToken: options.storefrontAccessToken,\n signal: controller.signal,\n })\n .then((settings) => {\n if (controller.signal.aborted) return;\n injectCustomCss(options.shopDomain, settings.customCss);\n })\n .catch(() => {\n // Silent — no merchant CSS is fine.\n });\n\n return () => {\n controller.abort();\n };\n }, [\n options.shopDomain,\n options.storefrontAccessToken,\n options.bundleGid,\n options.country,\n options.language,\n options.buyer,\n options.marketId,\n ]);\n\n return state;\n}\n","/**\n * Framework-agnostic async fetcher for bundle data.\n *\n * Primary path for Next.js App Router / RSC and Hydrogen loaders — call\n * this in a server-side context and pass the result as a prop to a\n * `\"use client\"` component. `useBundleData` is NOT needed in that\n * component because the data is already in hand.\n *\n * Always forward the end-buyer's IP via `buyerIp` when calling from SSR:\n * Shopify may return 430 Security Rejection for server-originated traffic\n * without it.\n *\n * Throws:\n * - `StorefrontApiError` on network / HTTP / GraphQL errors\n * - `BundleParseError` when the metaobject is missing, invalid type,\n * inactive, not yet started, or expired\n */\nimport {\n createStorefrontClient,\n hasInContext,\n BUNDLE_METAOBJECT_QUERY,\n withInContext,\n parseMetaobjectBundleStrict,\n isVisibleInMarket,\n BundleParseError,\n type BuyerResolver,\n type ParsedBundle,\n type BundleMetaobjectResponse,\n} from \"@lime-bundles/core\";\n\nexport interface FetchBundleDataOptions {\n shopDomain: string;\n storefrontAccessToken: string;\n bundleGid: string;\n /** Forwarded as `Shopify-Storefront-Buyer-IP` — required for SSR. */\n buyerIp?: string;\n /** Abort the in-flight request (used by `useBundleData` to cancel on unmount). */\n signal?: AbortSignal;\n /** Override the Storefront API version pinned in `createStorefrontClient`. */\n apiVersion?: string;\n /**\n * ISO-3166 alpha-2 country code passed as `@inContext(country: ...)`.\n * Drives Shopify Markets pricing, currency, and availability.\n */\n country?: string;\n /** ISO-639-1 language code passed as `@inContext(language: ...)`. */\n language?: string;\n /**\n * B2B buyer identity. Prefer the callback form for security — it lets\n * you fetch the customer access token just-in-time so it doesn't sit\n * in static prop trees. See packages/*\\/README.md → \"Markets & B2B\".\n */\n buyer?: BuyerResolver;\n /**\n * Shopify Market GID for the current visitor. When set and the bundle's\n * `marketVisibility === \"specific\"`, the bundle is filtered out if its\n * `marketIds` doesn't include this market. Returned to the caller via\n * `BundleVisibilityWarning[]` for surfacing.\n */\n marketId?: string;\n}\n\n/** Filtered bundle metadata. Returned alongside the bundle for SSR/RSC consumers. */\nexport interface BundleVisibilityWarning {\n bundleGid: string;\n reason: \"market_mismatch\";\n /** The marketId passed by the consumer that didn't match this bundle. */\n currentMarketId: string | null;\n /** The bundle's allowed Market GIDs. Empty for `marketVisibility === \"all\"`. */\n allowedMarketIds: string[];\n}\n\nexport interface FetchBundleDataResult {\n bundle: ParsedBundle | null;\n /** Populated when the bundle was hidden by the market gate. */\n warnings: BundleVisibilityWarning[];\n}\n\nexport async function fetchBundleData(\n options: FetchBundleDataOptions,\n): Promise<ParsedBundle> {\n const result = await fetchBundleDataWithWarnings(options);\n if (!result.bundle) {\n throw new BundleParseError(\n `Bundle hidden by market gate: ${options.bundleGid}`,\n \"not_found\",\n );\n }\n return result.bundle;\n}\n\n/**\n * Like `fetchBundleData` but surfaces market-gate misses as warnings instead\n * of throwing. Useful for consumers that render alternative content when a\n * bundle isn't available in the current market.\n */\nexport async function fetchBundleDataWithWarnings(\n options: FetchBundleDataOptions,\n): Promise<FetchBundleDataResult> {\n const config = {\n shopDomain: options.shopDomain,\n accessToken: options.storefrontAccessToken,\n buyerIp: options.buyerIp,\n apiVersion: options.apiVersion,\n country: options.country,\n language: options.language,\n buyer: options.buyer,\n };\n const client = createStorefrontClient(config);\n const query = hasInContext(config)\n ? withInContext(BUNDLE_METAOBJECT_QUERY)\n : BUNDLE_METAOBJECT_QUERY;\n\n const data = await client.query<BundleMetaobjectResponse>(\n query,\n { id: options.bundleGid },\n { signal: options.signal },\n );\n\n if (!data.metaobject) {\n throw new BundleParseError(\n `Bundle not found: ${options.bundleGid}`,\n \"not_found\",\n );\n }\n\n const bundle = parseMetaobjectBundleStrict(\n data.metaobject.id,\n data.metaobject.fields,\n );\n\n // Market visibility gate. The bundle is hidden when restricted to a\n // specific market list that doesn't include the caller's current\n // marketId. SDK is the primary gate for headless consumers (the\n // theme widget has its own Liquid gate; the discount function has its\n // own checkout-side gate).\n if (!isVisibleInMarket(bundle, options.marketId)) {\n return {\n bundle: null,\n warnings: [\n {\n bundleGid: options.bundleGid,\n reason: \"market_mismatch\",\n currentMarketId: options.marketId ?? null,\n allowedMarketIds: bundle.marketIds,\n },\n ],\n };\n }\n\n return { bundle, warnings: [] };\n}\n","/**\n * Best-effort fetch for the shop's `$app` settings metafields.\n *\n * Returns the raw custom CSS (still needs sanitization before injection — see\n * `injectCustomCss` from core).\n *\n * **Per-shop in-memory cache.** Multiple `<FixedBundle>` / `<VolumeBundle>` /\n * `<MixMatchBundle>` components on the same page share one network request —\n * the first caller fetches, concurrent callers await the same promise, and\n * resolved values are cached so subsequent mounts return instantly. Failures\n * are NOT cached so the next caller retries.\n *\n * The cache lives for the life of the JS module (typically one page load).\n * Merchants updating settings see changes on the next page load. The cache is\n * exposed as `__clearShopSettingsCache` for test use only.\n */\nimport {\n createStorefrontClient,\n SHOP_SETTINGS_QUERY,\n type ShopSettingsResponse,\n} from \"@lime-bundles/core\";\n\nexport interface FetchShopSettingsOptions {\n shopDomain: string;\n storefrontAccessToken: string;\n buyerIp?: string;\n signal?: AbortSignal;\n}\n\nexport interface ShopSettings {\n /** Raw, unsanitized merchant CSS. Null when unset. */\n customCss: string | null;\n}\n\n/** What callers get when the fetch fails: styling intact. */\nconst FALLBACK: ShopSettings = {\n customCss: null,\n};\n\n// Cache map: key = shopDomain, value = pending or resolved promise.\n// Failures delete their own entry so retries get a fresh fetch.\nconst cache = new Map<string, Promise<ShopSettings>>();\n\nexport async function fetchShopSettings(\n options: FetchShopSettingsOptions,\n): Promise<ShopSettings> {\n const cached = cache.get(options.shopDomain);\n if (cached) return cached;\n\n const promise = (async (): Promise<ShopSettings> => {\n const client = createStorefrontClient({\n shopDomain: options.shopDomain,\n accessToken: options.storefrontAccessToken,\n buyerIp: options.buyerIp,\n });\n\n const data = await client.query<ShopSettingsResponse>(\n SHOP_SETTINGS_QUERY,\n undefined,\n { signal: options.signal },\n );\n\n return {\n customCss: data.shop?.customCss?.value ?? null,\n };\n })();\n\n // Cache the promise synchronously so concurrent callers dedupe.\n cache.set(options.shopDomain, promise);\n\n // Evict on failure so the next caller can retry.\n promise.catch(() => {\n if (cache.get(options.shopDomain) === promise) {\n cache.delete(options.shopDomain);\n }\n });\n\n return promise;\n}\n\n/**\n * Same fetch, never rejects — a failed settings request must not stop a\n * bundle from appearing.\n */\nexport async function fetchShopSettingsOrDefault(\n options: FetchShopSettingsOptions,\n): Promise<ShopSettings> {\n try {\n return await fetchShopSettings(options);\n } catch {\n return FALLBACK;\n }\n}\n\n/**\n * Test-only helper. Clears the per-shop settings cache so each test starts\n * from a known state. Do not call from application code.\n */\nexport function __clearShopSettingsCache(): void {\n cache.clear();\n}\n","/**\n * Hook for analytics event reporting (impressions + add-to-cart).\n * Impressions fire once per mount using IntersectionObserver.\n */\nimport { useEffect, useMemo, useRef, useCallback, useState } from \"react\";\nimport {\n reportImpression,\n reportAddToCart,\n observeImpression,\n type AnalyticsConfig,\n} from \"@lime-bundles/core\";\n\nexport interface UseAnalyticsOptions {\n shopDomain: string;\n appUrl: string;\n bundleGid: string;\n bundleType: string;\n enabled?: boolean;\n}\n\nexport function useAnalytics(options: UseAnalyticsOptions) {\n const impressionFiredRef = useRef(false);\n // Callback ref + state so the observer effect re-runs when the host element\n // is attached (e.g. after a `loading` branch swaps in the real DOM node).\n const [element, setElement] = useState<HTMLElement | null>(null);\n const elementRef = useCallback((el: HTMLElement | null) => {\n setElement(el);\n }, []);\n\n const config: AnalyticsConfig = useMemo(\n () => ({ shopDomain: options.shopDomain, appUrl: options.appUrl }),\n [options.shopDomain, options.appUrl],\n );\n\n // Reset the fired flag when bundle identity changes so a reused component\n // (e.g. via navigation) can report a fresh impression.\n useEffect(() => {\n impressionFiredRef.current = false;\n }, [options.bundleGid]);\n\n // Set up impression observer once the element is attached\n useEffect(() => {\n if (options.enabled === false) return;\n if (impressionFiredRef.current) return;\n if (!element) return;\n\n const cleanup = observeImpression(element, () => {\n if (impressionFiredRef.current) return;\n impressionFiredRef.current = true;\n\n reportImpression(config, {\n bundleGid: options.bundleGid,\n bundleType: options.bundleType,\n });\n });\n\n return cleanup;\n }, [\n element,\n config,\n options.enabled,\n options.bundleGid,\n options.bundleType,\n ]);\n\n const trackAddToCart = useCallback(\n (event: {\n /** Optional — omit for multi-product bundles (fixed, mix-match). */\n productId?: string;\n quantity: number;\n totalPrice: number;\n }) => {\n if (options.enabled === false) return;\n\n reportAddToCart(config, {\n bundleGid: options.bundleGid,\n bundleType: options.bundleType,\n productId: event.productId,\n quantity: event.quantity,\n totalPrice: event.totalPrice,\n });\n },\n [\n config,\n options.enabled,\n options.bundleGid,\n options.bundleType,\n ],\n );\n\n return { elementRef, trackAddToCart };\n}\n","/**\n * Apply a bundle's `widgetConfig` to the component root as CSS custom\n * properties. Returns a callback ref so it composes with other callback\n * refs (e.g. `useAnalytics().elementRef`) without needing a ref-merge\n * library.\n *\n * Mirrors what the web component does in `applyWidgetConfigVars` — the\n * React surface uses a smaller subset of `--lb-*` vars in its own\n * stylesheet (`@lime-bundles/react/styles.css`), but having every var set\n * means merchant choices like `productList.thumbnailRatio` flow through to\n * the React image rules without further plumbing. Vars the React stylesheet\n * doesn't read are harmless extras.\n */\nimport { useCallback, useEffect, useRef } from \"react\";\nimport { applyWidgetConfigVars, type WidgetConfig } from \"@lime-bundles/core\";\n\nexport function useWidgetConfigVars(\n config: WidgetConfig | null | undefined,\n): (el: HTMLElement | null) => void {\n const elementRef = useRef<HTMLElement | null>(null);\n\n // Re-apply when config changes (e.g. async bundle load completes).\n useEffect(() => {\n if (elementRef.current && config) {\n applyWidgetConfigVars(elementRef.current, config);\n }\n }, [config]);\n\n // Apply on first attachment so the merchant's chosen ratio is in effect\n // before the browser does its first paint.\n return useCallback(\n (el: HTMLElement | null) => {\n elementRef.current = el;\n if (el && config) applyWidgetConfigVars(el, config);\n },\n [config],\n );\n}\n","/**\n * Per-product variant selection state for the React bundle components.\n *\n * Owns positional option-value selection for one product; derives the\n * resolved `ProductVariant` and an availability map (which option values\n * are currently disabled given the other selections). Mirrors the\n * `findVariantByOptions` / `isOptionValueAvailable` logic that powers the\n * Liquid widget and the `<lime-bundle>` web component, so the cascade\n * behaviour matches across all surfaces.\n */\nimport { useEffect, useMemo, useState, useCallback } from \"react\";\nimport { variants as variantsNs, type ProductVariant } from \"@lime-bundles/core\";\n\nconst { findVariantByOptions, isOptionValueAvailable, toPickerVariant } = variantsNs;\n\nexport interface UseVariantSelectionOptions {\n /** Storefront-API variants for the product (eligible set already filtered). */\n variants: ReadonlyArray<ProductVariant>;\n /** Positional option names for the product, e.g. `['Size', 'Color']`. */\n optionNames: ReadonlyArray<string>;\n /**\n * Optional initial variant. Defaults to the first variant that can cover\n * the slot (per `requiredQtyFor` when supplied), then the first available\n * variant, then the first variant.\n */\n initialVariant?: ProductVariant | null;\n /**\n * Canonical option-value order per option position (e.g. from\n * `Product.options[].values` on the Storefront API). When supplied, the\n * dropdown UI renders values in this merchant-defined order. When omitted,\n * order is variant-discovery order (which may not match Shopify admin).\n */\n optionValuesByPosition?: ReadonlyArray<ReadonlyArray<string>>;\n /**\n * Per-variant required quantity for the bundle slot this picker fills.\n * When provided, dropdown availability is quantity-aware (a variant short\n * of the bundle's needs greys out) instead of plain `availableForSale`.\n */\n requiredQtyFor?: (variantId: string) => number;\n}\n\nexport interface UseVariantSelectionResult {\n /** Positional option values matching `optionNames`. */\n selectedValues: ReadonlyArray<string>;\n /** The resolved variant for the current selection (null when no exact match). */\n selectedVariant: ProductVariant | null;\n /** Set the value at a single option position. */\n setOptionValue: (optionIndex: number, value: string) => void;\n /** All distinct values for an option position, paired with availability. */\n optionsFor: (\n optionIndex: number,\n ) => ReadonlyArray<{ value: string; disabled: boolean }>;\n}\n\nexport function useVariantSelection({\n variants,\n optionNames,\n initialVariant,\n optionValuesByPosition,\n requiredQtyFor,\n}: UseVariantSelectionOptions): UseVariantSelectionResult {\n const pickerVariants = useMemo(\n () => variants.map((v) => toPickerVariant(v, requiredQtyFor?.(v.id))),\n [variants, requiredQtyFor],\n );\n\n // Resolve the seed variant once per render; the memo covers both the\n // initial useState seed and the reset effect below. The default is\n // quantity-aware through the same pickerVariants that grey the dropdown,\n // so the initial selection never lands on a greyed option (#278) — with\n // plain availableForSale as the fallback when nothing can cover the slot\n // (the component's own OOS state locks the CTA in that case).\n const seed = useMemo(() => {\n if (initialVariant) return initialVariant;\n const covered = pickerVariants.find((p) => p.available);\n if (covered) {\n return variants.find((v) => v.id === covered.id) ?? null;\n }\n return variants.find((v) => v.availableForSale) ?? variants[0] ?? null;\n }, [initialVariant, variants, pickerVariants]);\n const [selectedValues, setSelectedValues] = useState<string[]>(() =>\n seed ? seed.selectedOptions.map((o) => o.value) : optionNames.map(() => \"\"),\n );\n\n // Reset selection when the caller swaps the product or supplies a new\n // initial variant. Keying on seed.id keeps variants/optionNames\n // recomputes from firing this spuriously.\n useEffect(() => {\n if (!seed) return;\n setSelectedValues(seed.selectedOptions.map((o) => o.value));\n // eslint-disable-next-line react-hooks/exhaustive-deps -- intentionally keyed on seed?.id, not seed itself\n }, [seed?.id]);\n\n const selectedVariant = useMemo<ProductVariant | null>(() => {\n if (selectedValues.length !== optionNames.length) return null;\n const match = findVariantByOptions(pickerVariants, selectedValues);\n if (!match) return null;\n return variants.find((v) => v.id === match.id) ?? null;\n }, [pickerVariants, selectedValues, variants, optionNames.length]);\n\n const setOptionValue = useCallback(\n (optionIndex: number, value: string) => {\n setSelectedValues((prev) => {\n const next = prev.slice();\n next[optionIndex] = value;\n return next;\n });\n },\n [],\n );\n\n const optionsByPosition = useMemo(() => {\n if (optionValuesByPosition) {\n return optionValuesByPosition.map((values) => values.slice());\n }\n const out: string[][] = optionNames.map(() => []);\n for (const v of variants) {\n v.selectedOptions.forEach((o, i) => {\n if (i < out.length && !out[i].includes(o.value)) out[i].push(o.value);\n });\n }\n return out;\n }, [variants, optionNames, optionValuesByPosition]);\n\n const optionsFor = useCallback(\n (optionIndex: number) => {\n const values = optionsByPosition[optionIndex] ?? [];\n return values.map((value) => ({\n value,\n disabled: !isOptionValueAvailable(\n pickerVariants,\n optionIndex,\n value,\n selectedValues,\n ),\n }));\n },\n [optionsByPosition, pickerVariants, selectedValues],\n );\n\n return {\n selectedValues,\n selectedVariant,\n setOptionValue,\n optionsFor,\n };\n}\n","/**\n * Scroll-aware edge fade for an inset scroll list (fixed products, mix & match\n * slots, volume tiers). Mirrors `LB.attachEdgeFade` in the Liquid theme's\n * bundle-widget.js (and `attachEdgeFade` in `@lime-bundles/widget`): the native\n * scrollbar is hidden by the `.lb-edge-fade` CSS class and a soft mask fades\n * whichever edge has scrolled-past content — never at rest.\n *\n * Toggles `data-edge-fade=\"top\" | \"bottom\" | \"both\"` on the element:\n * - bottom: at the very top, more below → fade the bottom edge\n * - top: at the very bottom, more above → fade the top edge\n * - both: scrolled in the middle → fade both edges\n * - (none): content fits, nothing to fade\n *\n * Returns a callback ref. Attach it to the scroll list (alongside the\n * `lb-edge-fade` className) — it wires a passive scroll listener plus a\n * ResizeObserver and a MutationObserver (childList + subtree, so dynamically\n * added/removed cards re-evaluate), updates once on attach, and tears\n * everything down when the node detaches or the component unmounts.\n *\n * Without JS (or before the ref attaches) the list simply scrolls with no bar\n * and no fade — a safe, quiet fallback.\n */\nimport { useCallback, useRef } from \"react\";\n\nfunction attachEdgeFade(el: HTMLElement): () => void {\n function update() {\n const scrollable = el.scrollHeight - el.clientHeight;\n if (scrollable <= 1) {\n el.removeAttribute(\"data-edge-fade\");\n return;\n }\n const atTop = el.scrollTop <= 1;\n const atBottom = el.scrollTop >= scrollable - 1;\n el.setAttribute(\n \"data-edge-fade\",\n atTop ? \"bottom\" : atBottom ? \"top\" : \"both\",\n );\n }\n\n el.addEventListener(\"scroll\", update, { passive: true });\n\n let resizeObserver: ResizeObserver | null = null;\n if (typeof ResizeObserver !== \"undefined\") {\n resizeObserver = new ResizeObserver(update);\n resizeObserver.observe(el);\n }\n\n let mutationObserver: MutationObserver | null = null;\n if (typeof MutationObserver !== \"undefined\") {\n mutationObserver = new MutationObserver(update);\n mutationObserver.observe(el, { childList: true, subtree: true });\n }\n\n update();\n\n return () => {\n el.removeEventListener(\"scroll\", update);\n resizeObserver?.disconnect();\n mutationObserver?.disconnect();\n };\n}\n\nexport function useEdgeFade(): (el: HTMLElement | null) => void {\n const cleanupRef = useRef<(() => void) | null>(null);\n\n return useCallback((el: HTMLElement | null) => {\n // Tear down a prior attachment first — covers both detach (el === null)\n // and re-attach to a new node across renders.\n cleanupRef.current?.();\n cleanupRef.current = null;\n\n if (el) {\n cleanupRef.current = attachEdgeFade(el);\n }\n }, []);\n}\n","/**\n * Accessible custom variant-picker dropdown for React bundle components.\n *\n * Controlled component — caller owns `value` and `onChange`. Mirrors the\n * WAI-ARIA combobox pattern shipped by the Liquid theme dropdown and the\n * `<lime-bundle>` web component dropdown. Keyboard / type-ahead /\n * positioning logic comes from `@lime-bundles/core` so all three surfaces\n * stay in lockstep.\n *\n * Asymmetry with the Liquid + web component surfaces: those expose a hidden\n * native `<select>` and the dropdown UI resyncs via MutationObserver if an\n * external script mutates `select.value`. The React component has no such\n * escape hatch — to change selection externally, re-render with a new\n * `value` prop. This is intentional: a synthetic-event-driven hidden\n * select would fight React reconciliation.\n */\nimport {\n useEffect,\n useId,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { dropdown } from \"@lime-bundles/core\";\n\nconst { computePosition, emptyTypeAheadState, handleKey, pushTypeAheadChar } =\n dropdown;\n\n// Layout-tuning constants for panel-height calculation. Inlined here\n// rather than imported from core so they stay tweakable without locking\n// numeric values into the public SDK contract.\nconst ITEM_HEIGHT_PX = 32;\nconst LIST_PAD_Y = 8;\nconst MAX_VISIBLE_ITEMS = 8;\ntype ComputePositionResult = dropdown.ComputePositionResult;\ntype TypeAheadState = dropdown.TypeAheadState;\n\n// Walk up to find the nearest ancestor that clips overflow on the Y axis.\n// Used so placement flips upward before the listbox would be hidden by a\n// scrollable container (`.lb-bundle__products`). Stops at body — past\n// that, the viewport bound is correct.\nfunction findScrollableAncestor(el: Element): HTMLElement | null {\n const win = el.ownerDocument?.defaultView;\n if (!win) return null;\n let cur: Element | null = el.parentElement;\n while (cur && cur !== el.ownerDocument.body) {\n const style = win.getComputedStyle(cur);\n const overflowY = style.overflowY;\n if (\n overflowY === \"auto\" ||\n overflowY === \"scroll\" ||\n overflowY === \"hidden\"\n ) {\n return cur as HTMLElement;\n }\n cur = cur.parentElement;\n }\n return null;\n}\n\nexport interface VariantDropdownOption {\n value: string;\n label: string;\n disabled?: boolean;\n}\n\nexport interface VariantDropdownProps {\n options: ReadonlyArray<VariantDropdownOption>;\n value: string | null;\n onChange: (value: string) => void;\n /** Accessible label, e.g. `\"Size\"`. */\n ariaLabel?: string;\n className?: string;\n}\n\nexport function VariantDropdown({\n options,\n value,\n onChange,\n ariaLabel,\n className,\n}: VariantDropdownProps) {\n const idBase = useId();\n const triggerRef = useRef<HTMLButtonElement>(null);\n const listboxRef = useRef<HTMLUListElement>(null);\n const typeAheadRef = useRef<TypeAheadState>(emptyTypeAheadState());\n const [isOpen, setIsOpen] = useState(false);\n const [activeIndex, setActiveIndex] = useState(-1);\n const [position, setPosition] = useState<ComputePositionResult | null>(null);\n\n const selectedIndex = useMemo(\n () => options.findIndex((o) => o.value === value),\n [options, value],\n );\n\n const optionsState = useMemo(\n () => options.map((o) => ({ disabled: !!o.disabled, label: o.label })),\n [options],\n );\n\n const selectedLabel =\n selectedIndex >= 0 ? options[selectedIndex].label : \"\";\n\n function open() {\n if (isOpen) return;\n setIsOpen(true);\n setActiveIndex(\n selectedIndex >= 0 && !optionsState[selectedIndex]?.disabled\n ? selectedIndex\n : optionsState.findIndex((o) => !o.disabled),\n );\n }\n\n function close(restoreFocus: boolean) {\n setIsOpen(false);\n setActiveIndex(-1);\n if (restoreFocus) triggerRef.current?.focus();\n }\n\n function commit(index: number) {\n const opt = options[index];\n if (!opt || opt.disabled) return;\n if (opt.value !== value) onChange(opt.value);\n close(true);\n }\n\n // position:fixed coords recomputed on open, then again on every scroll/resize\n // while open (those handlers close the panel — see effect below — so this\n // layout effect only runs once per open transition).\n useLayoutEffect(() => {\n if (!isOpen) return;\n const trigger = triggerRef.current;\n if (!trigger) return;\n const rect = trigger.getBoundingClientRect();\n if (rect.width === 0) return;\n const visibleCount = Math.min(options.length || 1, MAX_VISIBLE_ITEMS);\n const desiredHeight = visibleCount * ITEM_HEIGHT_PX + LIST_PAD_Y;\n // Trigger lives inside the bundle's product list which is overflow:auto\n // with a capped max-height. Without clip bounds the placement decision\n // uses viewport room and opens downward into the clipped zone, hiding\n // the panel behind the widget footer. Pass the scrollable ancestor's\n // rect so placement flips upward when the trigger nears its bottom.\n const scrollable = findScrollableAncestor(trigger);\n const clip = scrollable\n ? (() => {\n const r = scrollable.getBoundingClientRect();\n return { top: r.top, bottom: r.bottom };\n })()\n : undefined;\n setPosition(\n computePosition({\n trigger: {\n top: rect.top,\n bottom: rect.bottom,\n left: rect.left,\n width: rect.width,\n },\n viewportHeight: window.innerHeight,\n desiredHeight,\n clip,\n }),\n );\n }, [isOpen, options.length]);\n\n useEffect(() => {\n if (!isOpen) return;\n // composedPath() handles shadow-DOM retargeting (for merchants who\n // embed this component inside a custom element with shadow root).\n const isInsideDropdown = (event: Event): boolean => {\n const path = event.composedPath();\n const trigger = triggerRef.current;\n const listbox = listboxRef.current;\n return (\n (trigger != null && path.includes(trigger)) ||\n (listbox != null && path.includes(listbox))\n );\n };\n const onPointerdown = (event: PointerEvent) => {\n if (isInsideDropdown(event)) return;\n close(false);\n };\n const onScroll = (event: Event) => {\n // Scrolling within the listbox itself must not close the dropdown.\n if (isInsideDropdown(event)) return;\n close(false);\n };\n const onResize = () => close(false);\n document.addEventListener(\"pointerdown\", onPointerdown, true);\n window.addEventListener(\"scroll\", onScroll, true);\n window.addEventListener(\"resize\", onResize);\n return () => {\n document.removeEventListener(\"pointerdown\", onPointerdown, true);\n window.removeEventListener(\"scroll\", onScroll, true);\n window.removeEventListener(\"resize\", onResize);\n };\n }, [isOpen]);\n\n useEffect(() => {\n if (!isOpen || activeIndex < 0) return;\n const listbox = listboxRef.current;\n if (!listbox) return;\n const li = listbox.querySelector<HTMLElement>(\n `#${CSS.escape(`${idBase}-opt-${activeIndex}`)}`,\n );\n if (!li) return;\n // Scroll within the listbox only — Element.scrollIntoView falls through\n // to the document scroll when the listbox itself isn't overflowing,\n // which can yank the page.\n const liTop = li.offsetTop;\n const liBottom = liTop + li.offsetHeight;\n const visTop = listbox.scrollTop;\n const visBottom = visTop + listbox.clientHeight;\n if (liTop < visTop) {\n listbox.scrollTop = liTop;\n } else if (liBottom > visBottom) {\n listbox.scrollTop = liBottom - listbox.clientHeight;\n }\n }, [activeIndex, isOpen, idBase]);\n\n function onKeyDown(event: React.KeyboardEvent) {\n const action = handleKey(\n {\n key: event.key,\n ctrlKey: event.ctrlKey,\n metaKey: event.metaKey,\n altKey: event.altKey,\n shiftKey: event.shiftKey,\n },\n { isOpen, activeIndex, selectedIndex, options: optionsState },\n );\n if (action.preventDefault) event.preventDefault();\n switch (action.type) {\n case \"open\":\n open();\n if (action.activeIndex >= 0) setActiveIndex(action.activeIndex);\n return;\n case \"close\":\n close(action.restoreFocus);\n return;\n case \"move-active\":\n setActiveIndex(action.activeIndex);\n return;\n case \"commit\":\n commit(action.index);\n return;\n case \"type-ahead\": {\n const result = pushTypeAheadChar(\n typeAheadRef.current,\n action.char,\n Date.now(),\n optionsState,\n );\n typeAheadRef.current = result.newState;\n if (result.matchedIndex !== null) {\n if (!isOpen) open();\n setActiveIndex(result.matchedIndex);\n }\n return;\n }\n case \"passthrough\":\n return;\n }\n }\n\n function onShellBlur(event: React.FocusEvent) {\n const next = event.relatedTarget as Node | null;\n if (next && event.currentTarget.contains(next)) return;\n // Defer so focus has a chance to land elsewhere first.\n setTimeout(() => {\n if (!isOpen) return;\n const active = document.activeElement;\n if (\n !triggerRef.current?.contains(active) &&\n !listboxRef.current?.contains(active)\n ) {\n close(false);\n }\n }, 0);\n }\n\n const listboxId = `${idBase}-listbox`;\n const activeDescendantId =\n activeIndex >= 0 ? `${idBase}-opt-${activeIndex}` : undefined;\n\n // Only max-height comes from JS; CSS [data-placement] selectors\n // anchor the listbox against the position:relative .lb-dropdown shell\n // via top: 100% / bottom: 100%, so we never depend on inline coords\n // landing before paint.\n const panelStyle: React.CSSProperties | undefined = position\n ? { maxHeight: position.maxHeight }\n : undefined;\n\n return (\n <div\n className={`lb-dropdown${className ? ` ${className}` : \"\"}`}\n data-lb-dropdown=\"\"\n onBlur={onShellBlur}\n >\n <button\n ref={triggerRef}\n type=\"button\"\n className=\"lb-dropdown-trigger\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-expanded={isOpen}\n aria-controls={listboxId}\n aria-label={ariaLabel}\n aria-activedescendant={activeDescendantId}\n onClick={(e) => {\n e.preventDefault();\n if (isOpen) close(false);\n else open();\n }}\n onKeyDown={onKeyDown}\n >\n <span className=\"lb-dropdown-trigger-value\">{selectedLabel}</span>\n <span className=\"lb-dropdown-chevron\" aria-hidden=\"true\" />\n </button>\n <ul\n ref={listboxRef}\n id={listboxId}\n className=\"lb-dropdown-listbox\"\n role=\"listbox\"\n aria-label={ariaLabel}\n hidden={!isOpen}\n data-placement={position?.placement}\n style={panelStyle}\n // Prevent mousedown on a non-focusable <li> from blurring the\n // trigger button. Without this, focusout fires on the shell,\n // queues onShellBlur's setTimeout(0), and the close runs before\n // the synthesized click — so commit never runs and the trigger\n // label never updates. Mobile is unaffected because touchstart\n // doesn't shift focus.\n onMouseDown={(e) => e.preventDefault()}\n >\n {options.map((opt, i) => (\n // Keyboard activation lives on the trigger combobox via\n // aria-activedescendant — the WAI-ARIA combobox pattern keeps\n // focus on the button and tracks the active option by id, so\n // the option <li> elements deliberately have no key handlers.\n // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-noninteractive-element-interactions\n <li\n key={opt.value}\n id={`${idBase}-opt-${i}`}\n className={`lb-dropdown-option${i === activeIndex ? \" is-active\" : \"\"}`}\n role=\"option\"\n aria-selected={i === selectedIndex}\n aria-disabled={opt.disabled || undefined}\n data-value={opt.value}\n onClick={() => commit(i)}\n onMouseMove={() => {\n if (!opt.disabled && i !== activeIndex) setActiveIndex(i);\n }}\n >\n {opt.label}\n </li>\n ))}\n </ul>\n </div>\n );\n}\n","/**\n * Countdown strip — the React twin of the theme's `lb-widget-header.liquid`\n * countdown block and the render layer's `initCountdown`.\n *\n * Same markup, classes and timer format as the other two hosts, driven by the\n * merchant's `--lb-countdown-bg` / `--lb-countdown-text` vars that\n * `useWidgetConfigVars` already emits. Renders nothing without an end date,\n * and hides itself once the window closes — the discount stops applying at\n * that moment, so a still-ticking strip would advertise a price the checkout\n * no longer honours.\n */\nimport { useEffect, useState } from \"react\";\nimport type { WidgetConfig } from \"@lime-bundles/core\";\n\nfunction pad(n: number): string {\n return n < 10 ? \"0\" + n : String(n);\n}\n\nfunction formatRemaining(remaining: number): string {\n const days = Math.floor(remaining / 86400000);\n const hours = Math.floor((remaining % 86400000) / 3600000);\n const mins = Math.floor((remaining % 3600000) / 60000);\n const secs = Math.floor((remaining % 60000) / 1000);\n return days > 0\n ? days + \"d \" + pad(hours) + \"h \" + pad(mins) + \"m \" + pad(secs) + \"s\"\n : pad(hours) + \"h \" + pad(mins) + \"m \" + pad(secs) + \"s\";\n}\n\nexport interface BundleCountdownProps {\n /** The bundle's ISO end date; renders nothing when null. */\n endsAt: string | null | undefined;\n /** The bundle's widget config — gates on `countdown.showCountdown`. */\n widgetConfig: WidgetConfig | undefined;\n /** Label text; defaults to the theme's translation default. */\n label?: string;\n}\n\nexport function BundleCountdown({\n endsAt,\n widgetConfig,\n label = \"Limited time offer\",\n}: BundleCountdownProps) {\n const enabled =\n !!endsAt && widgetConfig?.countdown?.showCountdown !== false;\n const endTime = enabled ? new Date(endsAt!).getTime() : NaN;\n const [remaining, setRemaining] = useState<number | null>(null);\n\n useEffect(() => {\n if (!enabled || isNaN(endTime)) {\n setRemaining(null);\n return;\n }\n const update = () => setRemaining(endTime - Date.now());\n update();\n const interval = setInterval(update, 1000);\n return () => clearInterval(interval);\n }, [enabled, endTime]);\n\n if (!enabled || isNaN(endTime) || remaining === null || remaining <= 0) {\n return null;\n }\n\n return (\n <div className=\"lb-bundle-countdown\" data-countdown>\n <div className=\"lb-bundle-countdown__label\">\n <span>{label}</span>\n </div>\n <span className=\"lb-bundle-countdown__timer\" data-countdown-timer>\n {formatRemaining(remaining)}\n </span>\n </div>\n );\n}\n","/**\n * Mix-and-match bundle component.\n *\n * Customer picks products from a pool via a portaled picker modal; the\n * bundle qualifies when the TOTAL UNITS across picks (sum of per-pick\n * quantities) meets `bundle.minQuantity` — one product at qty 3 completes\n * a \"pick 3\" bundle, matching the discount function's unit-based gate.\n * Per-product `[min, max]` quantity bounds come from `bundle.productRules`\n * (products without an explicit rule use `DEFAULT_PRODUCT_RULE`).\n *\n * The UX mirrors the storefront theme widget one-for-one:\n * - a plain title + subtitle header,\n * - a SEGMENTED progress bar with count + remaining labels,\n * - a list of CHOSEN-PRODUCT CARDS (thumbnail, title, variant, price ×N,\n * remove ×),\n * - a single dashed \"Add a product\" slot that opens the picker modal,\n * - the picker modal itself (search, type filters, 2-col grid, per-pick\n * variant dropdowns + qty stepper + Add toggle, sticky Done footer),\n * - a receipt summary (compare/sale/savings) + CTA.\n *\n * See `extensions/bundle-theme/snippets/lb-mix-match.liquid` +\n * `extensions/bundle-theme/assets/bundle-mix-match.js` for the source of\n * truth, and `MixMatchPicker.tsx` for the modal.\n */\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport {\n formatMoney,\n formatUnitPrice,\n calculateDiscount,\n isVariantFulfillable,\n DEFAULT_PRODUCT_RULE,\n type CartLineInput,\n type MixMatchBundleData,\n type ProductRule,\n type ProductVariant,\n} from \"@lime-bundles/core\";\nimport { useBundleData } from \"../hooks/useBundleData\";\nimport { useAnalytics } from \"../hooks/useAnalytics\";\nimport { useWidgetConfigVars } from \"../hooks/useWidgetConfigVars\";\nimport { useEdgeFade } from \"../hooks/useEdgeFade\";\nimport { MixMatchPicker } from \"./MixMatchPicker\";\nimport type { SelectedItem } from \"./mix-match-types\";\nimport type { BundleComponentProps } from \"./types\";\nimport { BundleCountdown } from \"./BundleCountdown\";\n\n/**\n * The rule in force for a pick. Pass `variantId` and the variant's own rule\n * wins; without one this resolves the product rule, which is the envelope\n * covering every variant.\n */\nfunction ruleFor(\n bundle: MixMatchBundleData,\n productId: string,\n variantId?: string | null,\n): ProductRule {\n if (variantId) {\n const vRule = bundle.variantRules[variantId];\n if (vRule) return vRule;\n }\n return bundle.productRules[productId] ?? DEFAULT_PRODUCT_RULE;\n}\n\n/**\n * The variant's OWN rule, or undefined when it inherits the product's.\n * Distinct from `ruleFor`, which falls back — conflating the two would make\n * every variant of a required product unremovable.\n */\nfunction variantRuleFor(\n bundle: MixMatchBundleData,\n variantId: string | null | undefined,\n): ProductRule | undefined {\n return variantId ? bundle.variantRules[variantId] : undefined;\n}\n\n/**\n * PRODUCT-LEVEL lock for required products: removing a pick is allowed only\n * while the product's OTHER slots keep it at or above rule.min. This is what\n * lets shoppers swap variants (add Large, then remove Small) without ever\n * dropping the required product out of the bundle. *\n * A required VARIANT is stricter and needs no tally: slots are one per\n * (product, variant), so it has no other slot to fall back on and no sibling\n * may stand in for it. Naming the variant is what takes the swap off the\n * table.\n */\nfunction canRemoveItem(\n bundle: MixMatchBundleData,\n selections: SelectedItem[],\n item: SelectedItem,\n): boolean {\n if (variantRuleFor(bundle, item.variantId)?.required) return false;\n\n const rule = ruleFor(bundle, item.productId);\n if (!rule.required) return true;\n const unitsElsewhere = selections\n .filter((s) => s.productId === item.productId && s !== item)\n .reduce((sum, s) => sum + s.quantity, 0);\n return unitsElsewhere >= rule.min;\n}\n\n/**\n * ATOMIC VARIANT SWAP. A hard-capped required product (rule.min ===\n * rule.max) has no headroom for the add-then-remove variant swap the\n * product-level lock normally allows: adding a second variant would\n * overshoot the cap and removing the committed one would break the floor.\n * For those rows the picker button becomes \"Swap\" — the new variant's\n * units displace sibling-variant units instead of adding on top. Returns\n * the units available to take over, or 0 when the row isn't in the swap\n * state.\n */\nfunction swapUnitsForItem(\n bundle: MixMatchBundleData,\n selections: SelectedItem[],\n productId: string,\n variantId: string,\n): number {\n const rule = ruleFor(bundle, productId);\n if (!rule.required || rule.max !== rule.min) return 0;\n if (selections.some((s) => s.variantId === variantId)) return 0;\n return selections\n .filter((s) => s.productId === productId && s.variantId !== variantId)\n .reduce((sum, s) => sum + s.quantity, 0);\n}\n\nexport interface MixMatchBundleProps extends BundleComponentProps {\n /**\n * Handle of the product page this component is rendered on, when there is\n * one. Enables the theme widget's courtesy seed: with no required products,\n * the bundle starts with this product (or the first that qualifies)\n * pre-added at its rule minimum. Omit on non-product pages to start empty.\n */\n productHandle?: string | null;\n}\n\nexport function MixMatchBundle(props: MixMatchBundleProps) {\n const {\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n appUrl,\n analyticsEnabled,\n onAddToCart,\n onError,\n className,\n productHandle,\n } = props;\n\n const result = useBundleData({\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n });\n\n const { elementRef, trackAddToCart } = useAnalytics({\n shopDomain,\n appUrl: appUrl ?? `https://${shopDomain}`,\n bundleGid,\n bundleType: \"mix_match\",\n enabled: analyticsEnabled !== false,\n });\n\n // An ordered list of picks — one card per slot, in pick order. Matches the\n // theme's `selectedItems` array (one slot per (product, variant) pair — a\n // multi-variant product can fill several slots; the stepper owns each\n // pick's unit count, and completion counts total units vs minQuantity).\n const [selections, setSelections] = useState<SelectedItem[]>([]);\n const [seededFor, setSeededFor] = useState<string | null>(null);\n const [pickerOpen, setPickerOpen] = useState(false);\n const [addingToCart, setAddingToCart] = useState(false);\n const [cartError, setCartError] = useState<string | null>(null);\n\n const bundle =\n result.status === \"success\" && result.bundle.bundleType === \"mix_match\"\n ? (result.bundle as MixMatchBundleData)\n : null;\n\n // Apply merchant-config CSS vars to the widget root.\n const setConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);\n // The picker modal is portaled to document.body — outside the widget root —\n // so it needs its own carrier for the same `--lb-*` vars.\n const setModalConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);\n\n // Scroll-aware edge fade on the chosen-product slot list.\n const slotsEdgeFadeRef = useEdgeFade();\n\n useEffect(() => {\n if (result.status === \"error\") {\n onError?.(result.error);\n return;\n }\n if (\n result.status === \"success\" &&\n result.bundle.bundleType !== \"mix_match\"\n ) {\n onError?.(\n new Error(\n `MixMatchBundle: expected bundleType=\"mix_match\", got \"${result.bundle.bundleType}\"`,\n ),\n );\n }\n }, [result, onError]);\n\n // Seed the way the theme widget does when the bundle arrives: every\n // REQUIRED variant at its own minimum (a named variant beats the product\n // rule for that product), every REQUIRED product at rule.min, and — when\n // nothing is required and the host told us which product page we're on —\n // a courtesy pick of that product (or the first that qualifies) at its\n // rule minimum. Seeds count toward the requirement and required ones can\n // never drop below rule.min (see canRemoveItem).\n useEffect(() => {\n if (!bundle || seededFor === bundle.id) return;\n setSeededFor(bundle.id);\n const seedCurrency =\n bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? \"USD\";\n\n const pick = (\n product: (typeof bundle.products)[number],\n variant: (typeof bundle.products)[number][\"variants\"][\"nodes\"][number],\n quantity: number,\n ): SelectedItem => ({\n productId: product.id,\n variantId: variant.id,\n title: product.title,\n url: `/products/${product.handle}`,\n variantTitle: variant.title,\n featuredImage: variant.image?.url ?? product.featuredImage?.url ?? null,\n price: parseFloat(variant.price.amount),\n compareAtPrice: variant.compareAtPrice\n ? parseFloat(variant.compareAtPrice.amount)\n : null,\n unitPrice: formatUnitPrice(\n variant.unitPrice,\n variant.unitPriceMeasurement,\n seedCurrency,\n ),\n quantity,\n });\n\n const seeds: SelectedItem[] = [];\n for (const product of bundle.products) {\n // Variant-level first: seed every variant the merchant named, at its\n // own minimum. A product with named variants never also carries a\n // product-level `required` — the admin schema enforces it.\n let seededVariant = false;\n for (const variant of product.variants.nodes) {\n const vRule = bundle.variantRules[variant.id];\n if (!vRule?.required) continue;\n if (!isVariantFulfillable(variant, Math.max(1, vRule.min))) continue;\n seeds.push(pick(product, variant, Math.max(1, vRule.min)));\n seededVariant = true;\n }\n if (seededVariant) continue;\n\n const rule = bundle.productRules[product.id];\n if (!rule?.required) continue;\n const variant = product.variants.nodes.find((v) =>\n isVariantFulfillable(v, rule.min),\n );\n if (!variant) continue;\n seeds.push(pick(product, variant, rule.min));\n }\n\n if (seeds.length === 0 && productHandle) {\n const requiredUnits = bundle.minQuantity ?? 0;\n const qualifies = (p: (typeof bundle.products)[number]) => {\n const min = bundle.productRules[p.id]?.min ?? 1;\n return (\n min <= requiredUnits &&\n p.variants.nodes.some((v) => isVariantFulfillable(v, min))\n );\n };\n const seed =\n bundle.products.find(\n (p) => p.handle === productHandle && qualifies(p),\n ) ?? bundle.products.find(qualifies);\n if (seed) {\n const min = bundle.productRules[seed.id]?.min ?? 1;\n const variant = seed.variants.nodes.find((v) =>\n isVariantFulfillable(v, min),\n );\n if (variant) seeds.push(pick(seed, variant, min));\n }\n }\n\n if (seeds.length > 0) setSelections(seeds);\n }, [bundle, seededFor, productHandle]);\n\n const showStepper =\n bundle?.widgetConfig.mixMatchShowQuantitySelector !== false;\n\n // Completion counts TOTAL UNITS across picks (sum of per-pick quantities),\n // not distinct products — one product at qty 3 completes a \"pick 3\" bundle.\n const requiredUnits = bundle?.minQuantity ?? 0;\n\n const totalQuantity = useMemo(\n () => selections.reduce((sum, s) => sum + s.quantity, 0),\n [selections],\n );\n\n const meetsMinUnits = totalQuantity >= requiredUnits && requiredUnits > 0;\n const valid = !!bundle && meetsMinUnits;\n // Capped at requiredUnits for display — over-completion still reads full.\n const shownUnits = Math.min(totalQuantity, requiredUnits);\n const remaining = Math.max(0, requiredUnits - shownUnits);\n\n // Running receipt totals from the current selections — compare (full) and\n // discounted sale price, plus savings + honest rounded percent.\n const summary = useMemo(() => {\n let comparePrice = 0;\n let salePrice = 0;\n for (const sel of selections) {\n if (sel.quantity <= 0) continue;\n comparePrice += sel.price * sel.quantity;\n if (bundle) {\n salePrice +=\n calculateDiscount(\n sel.price,\n bundle.discountConfig.discountType,\n bundle.discountConfig.discountValue,\n ) * sel.quantity;\n }\n }\n const savings = Math.max(0, comparePrice - salePrice);\n const savingsPercent =\n comparePrice > 0 && savings > 0\n ? Math.round((savings / comparePrice) * 100)\n : 0;\n return { comparePrice, salePrice, savings, savingsPercent };\n }, [selections, bundle]);\n\n const addSelection = useCallback(\n (item: SelectedItem) => {\n setSelections((prev) => {\n const units = prev.reduce((sum, s) => sum + s.quantity, 0);\n // EXACT-SIZE: refuse a pick that would push the unit total past\n // requiredUnits — the picker caps the stepper at the remaining\n // open spots, but a stale click must not overshoot. Slots are\n // variant-scoped: refuse a duplicate of an already-committed\n // variant (the row shows the Added toggle for it instead).\n if (units + item.quantity > requiredUnits) return prev;\n if (prev.some((s) => s.variantId === item.variantId)) return prev;\n return [...prev, item];\n });\n },\n [requiredUnits],\n );\n\n // LIVE EDIT of a committed pick's quantity — driven by the picker stepper\n // on an in-bundle row. Setting state re-renders everything downstream\n // (progress, CTA gate, pricing, and every picker row's addability /\n // ceiling — freeing units re-enables rows disabled by the exact-size\n // rule). Removal stays with the Added toggle / slot ×.\n const updateQuantity = useCallback(\n (productId: string, variantId: string, quantity: number) => {\n setSelections((prev) => {\n const idx = prev.findIndex(\n (s) => s.productId === productId && s.variantId === variantId,\n );\n if (idx === -1) return prev;\n const otherUnits = prev.reduce(\n (sum, s, i) => (i === idx ? sum : sum + s.quantity),\n 0,\n );\n // EXACT-SIZE: the committed pick's headroom is its own units plus\n // the bundle's open spots — the unit total must never overshoot\n // requiredUnits, even on a stale click.\n const clamped = Math.max(\n 1,\n Math.min(quantity, requiredUnits - otherUnits),\n );\n if (clamped === prev[idx].quantity) return prev;\n const next = prev.slice();\n next[idx] = { ...next[idx], quantity: clamped };\n return next;\n });\n },\n [requiredUnits],\n );\n\n // ATOMIC VARIANT SWAP for hard-capped required products: replace units\n // of the product's other-variant picks with the new variant. The unit\n // total never moves, so the required floor and the hard cap both hold\n // throughout — which is why this bypasses the canRemoveItem guard (the\n // swap is exactly what that guard exists to enable).\n const swapSelection = useCallback(\n (item: SelectedItem) => {\n setSelections((prev) => {\n if (!bundle) return prev;\n const swapUnits = swapUnitsForItem(\n bundle,\n prev,\n item.productId,\n item.variantId,\n );\n if (swapUnits <= 0) return prev;\n const qty = Math.min(Math.max(1, item.quantity), swapUnits);\n let freed = 0;\n const next: SelectedItem[] = [];\n for (const s of prev) {\n if (\n freed < qty &&\n s.productId === item.productId &&\n s.variantId !== item.variantId\n ) {\n const take = Math.min(s.quantity, qty - freed);\n freed += take;\n if (s.quantity > take) {\n next.push({ ...s, quantity: s.quantity - take });\n }\n } else {\n next.push(s);\n }\n }\n if (freed === 0) return prev;\n next.push({ ...item, quantity: freed });\n return next;\n });\n },\n [bundle],\n );\n\n // Remove the slot holding a variant (the picker's \"Added\" toggle). Slots\n // are variant-scoped, so other variants of the product keep theirs.\n const removeVariant = useCallback(\n (variantId: string) => {\n setSelections((prev) => {\n const idx = prev.findIndex((s) => s.variantId === variantId);\n if (idx === -1) return prev;\n if (bundle && !canRemoveItem(bundle, prev, prev[idx])) return prev;\n const next = prev.slice();\n next.splice(idx, 1);\n return next;\n });\n },\n [bundle],\n );\n\n const removeSlot = useCallback(\n (index: number) => {\n setSelections((prev) => {\n if (index < 0 || index >= prev.length) return prev;\n if (bundle && !canRemoveItem(bundle, prev, prev[index])) return prev;\n const next = prev.slice();\n next.splice(index, 1);\n return next;\n });\n },\n [bundle],\n );\n\n const handleAddToCart = useCallback(async () => {\n if (!bundle || !valid) return;\n\n // Aggregate by (productId, variantId) — duplicate variants across slots\n // collapse into one cart line with summed quantity.\n const grouped = new Map<string, { variantId: string; quantity: number }>();\n for (const sel of selections) {\n if (sel.quantity <= 0) continue;\n const key = `${sel.productId}::${sel.variantId}`;\n const existing = grouped.get(key);\n if (existing) existing.quantity += sel.quantity;\n else grouped.set(key, { variantId: sel.variantId, quantity: sel.quantity });\n }\n\n const lines: CartLineInput[] = Array.from(grouped.values()).map((line) => ({\n merchandiseId: line.variantId,\n quantity: line.quantity,\n attributes: [\n { key: \"_lime_bundle_gid\", value: bundle.id },\n { key: \"_lime_bundle_type\", value: bundle.bundleType },\n ],\n }));\n\n setAddingToCart(true);\n setCartError(null);\n try {\n await onAddToCart(lines);\n\n const totalPrice = selections.reduce(\n (sum, sel) => sum + sel.price * sel.quantity,\n 0,\n );\n // productId omitted — mix-match spans multiple products; bundleGid\n // attributes the event to the bundle.\n trackAddToCart({\n quantity: totalQuantity,\n totalPrice: Math.round(totalPrice * 100) / 100,\n });\n\n setSelections([]);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setCartError(error.message);\n onError?.(error);\n } finally {\n setAddingToCart(false);\n }\n }, [bundle, selections, valid, onAddToCart, onError, trackAddToCart, totalQuantity]);\n\n if (result.status === \"loading\") {\n return (\n <div className={`lb-bundle lb-bundle--loading ${className ?? \"\"}`}>\n <div className=\"lb-skeleton lb-skeleton--title\" />\n <div className=\"lb-skeleton lb-skeleton--products\" />\n </div>\n );\n }\n\n if (result.status === \"error\") return null;\n if (!bundle) return null;\n\n // Bundle visibility guard: don't render unless at least minQuantity distinct\n // in-stock products exist. Deliberately conservative — completion counts\n // total units, so fewer products could technically satisfy the requirement\n // via the stepper, but this mirrors the Liquid `available_count` guard.\n const inStockCount = countInStockProducts(bundle);\n if (requiredUnits > 0 && inStockCount < requiredUnits) return null;\n\n // A required product with no purchasable variant means the bundle can\n // never qualify at checkout — don't render (guards the gap between a\n // live stock drop and the inventory webhook's status flip).\n const requiredBlocked = Object.entries(bundle.productRules).some(\n ([pid, rule]) => {\n if (!rule.required) return false;\n const product = bundle.products.find((p) => p.id === pid);\n return !product?.variants.nodes.some((v) =>\n isVariantFulfillable(v, rule.min),\n );\n },\n );\n if (requiredBlocked) return null;\n\n const currency =\n bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? \"USD\";\n\n // Label stays \"Add to cart\" (or the merchant's custom text) throughout;\n // only the disabled state tracks the unit requirement.\n const ctaLabel = addingToCart\n ? \"Adding...\"\n : bundle.widgetConfig.cta.ctaText || \"Add to cart\";\n\n return (\n <div\n ref={(el) => {\n elementRef(el);\n setConfigVarsRef(el);\n }}\n className={`lb-bundle lb-bundle--mix-match lb-mix-match ${className ?? \"\"}`}\n role=\"region\"\n aria-label={bundle.title}\n data-required-quantity={requiredUnits}\n >\n <div className=\"lb-bundle-header\">\n <div className=\"lb-bundle-header__content\">\n <h3 className=\"lb-bundle-title\">{bundle.title}</h3>\n {bundle.description && (\n <p className=\"lb-bundle-subtitle\">{bundle.description}</p>\n )}\n </div>\n </div>\n\n <BundleCountdown\n endsAt={bundle.endsAt}\n widgetConfig={bundle.widgetConfig}\n />\n\n {/* Segmented progress — one segment per required unit. */}\n <div className=\"lb-mix-match__progress\" data-progress>\n <div\n className=\"lb-mix-match__progress-segments\"\n role=\"progressbar\"\n aria-valuenow={shownUnits}\n aria-valuemin={0}\n aria-valuemax={requiredUnits}\n >\n {Array.from({ length: requiredUnits }).map((_, i) => (\n <span\n key={i}\n className={`lb-mix-match__progress-segment${i < shownUnits ? \" lb-mix-match__progress-segment--filled\" : \"\"}`}\n data-progress-segment\n />\n ))}\n </div>\n <div className=\"lb-mix-match__progress-labels\">\n <span\n className=\"lb-mix-match__progress-count\"\n data-progress-count\n aria-live=\"polite\"\n >\n {`${shownUnits} of ${requiredUnits} added`}\n </span>\n <span\n className=\"lb-mix-match__progress-remaining\"\n data-progress-remaining\n aria-live=\"polite\"\n >\n {remaining > 0 ? `${remaining} more to go` : \"Complete\"}\n </span>\n </div>\n </div>\n\n {/* Chosen-product cards. */}\n <div\n className=\"lb-mix-match__slots lb-edge-fade\"\n data-selection-slots\n ref={slotsEdgeFadeRef}\n >\n {selections.map((item, index) => (\n /* Whole card reopens the picker to edit this pick. The inner title\n button provides the keyboard/AT path (its activation bubbles\n here); × stops propagation. */\n // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions -- keyboard path is the inner \"Edit selection\" title button whose activation bubbles to this handler\n <div\n key={`${item.productId}:${item.variantId}:${index}`}\n className=\"lb-mix-match__slot lb-mix-match__slot--filled\"\n onClick={() => setPickerOpen(true)}\n >\n {item.featuredImage && (\n <div className=\"lb-bundle-thumbnail\">\n <img src={item.featuredImage} alt={item.title} loading=\"lazy\" />\n </div>\n )}\n <div className=\"lb-mix-match__filled-info\">\n <button\n type=\"button\"\n className=\"lb-mix-match__filled-title\"\n aria-label={`Edit selection: ${item.title}`}\n >\n {item.title}\n </button>\n {item.variantTitle && item.variantTitle !== \"Default Title\" && (\n <span className=\"lb-mix-match__filled-variant\">\n {item.variantTitle}\n </span>\n )}\n <span className=\"lb-mix-match__filled-price\">\n {item.compareAtPrice !== null &&\n item.compareAtPrice > item.price && (\n <s className=\"lb-mix-match__filled-compare\">\n {formatMoney(item.compareAtPrice, currency)}\n </s>\n )}\n <span className=\"lb-bundle-product-price\">\n {formatMoney(item.price, currency)}\n </span>\n <span className=\"lb-bundle-qty-inline\">{`×${item.quantity}`}</span>\n </span>\n {item.unitPrice && (\n <span className=\"lb-bundle-product-unit-price\">\n {item.unitPrice}\n </span>\n )}\n </div>\n {canRemoveItem(bundle, selections, item) ? (\n <button\n type=\"button\"\n className=\"lb-mix-match__slot-remove\"\n aria-label={`Remove ${item.title}`}\n onClick={(e) => {\n e.stopPropagation();\n removeSlot(index);\n }}\n >\n <CloseIcon />\n </button>\n ) : (\n /* Required pick at its floor — quiet state chip instead of\n the ×; removal returns once another slot covers the\n product's minimum (variant swap flow). */\n <span className=\"lb-mix-match__slot-required\">Required</span>\n )}\n </div>\n ))}\n </div>\n\n {/* Single dashed \"Add a product\" affordance — hidden once the required\n unit total is met. */}\n {totalQuantity < requiredUnits && (\n <button\n type=\"button\"\n className=\"lb-mix-match__add-product\"\n data-add-product-trigger\n onClick={() => setPickerOpen(true)}\n >\n <span className=\"lb-mix-match__add-product-icon\" aria-hidden=\"true\">\n <PlusIcon />\n </span>\n <span className=\"lb-mix-match__add-product-label\">Add a product</span>\n </button>\n )}\n\n <div className=\"lb-bundle-divider\" />\n\n {selections.length > 0 && (\n <div className=\"lb-bundle-summary\" data-pricing-section>\n <div className=\"lb-bundle-summary__text\">\n <span className=\"lb-bundle-summary__label\">Bundle total</span>\n {bundle.widgetConfig.savingsBar.visible && summary.savings > 0 && (\n <p className=\"lb-bundle-savings-line\" data-savings-bar>\n You save{\" \"}\n <span data-savings-amount>\n {formatMoney(summary.savings, currency)}\n </span>{\" \"}\n <span data-savings-percent>({summary.savingsPercent}%)</span>\n </p>\n )}\n </div>\n <span className=\"lb-bundle-summary__prices\">\n {bundle.widgetConfig.pricing.showComparePrice &&\n summary.savings > 0 && (\n <span className=\"lb-bundle-compare-price\" data-compare-price>\n {formatMoney(summary.comparePrice, currency)}\n </span>\n )}\n <span className=\"lb-bundle-sale-price\" data-sale-price>\n {formatMoney(summary.salePrice, currency)}\n </span>\n </span>\n </div>\n )}\n\n {cartError && (\n <p className=\"lb-bundle__error\" role=\"alert\">\n {cartError}\n </p>\n )}\n\n <button\n className=\"lb-bundle__cta\"\n onClick={handleAddToCart}\n disabled={addingToCart || !valid}\n aria-busy={addingToCart}\n >\n {ctaLabel}\n </button>\n\n {pickerOpen && (\n <MixMatchPicker\n bundle={bundle}\n currency={currency}\n requiredQty={requiredUnits}\n showStepper={showStepper}\n selections={selections}\n onAdd={addSelection}\n onUpdateQuantity={updateQuantity}\n onRemoveVariant={removeVariant}\n canRemoveVariant={(variantId) => {\n const item = selections.find((s) => s.variantId === variantId);\n return item ? canRemoveItem(bundle, selections, item) : true;\n }}\n swapUnitsFor={(productId, variantId) =>\n swapUnitsForItem(bundle, selections, productId, variantId)\n }\n onSwap={swapSelection}\n onClose={() => setPickerOpen(false)}\n styleVarsRef={setModalConfigVarsRef}\n />\n )}\n </div>\n );\n}\n\nfunction countInStockProducts(bundle: MixMatchBundleData): number {\n const seen = new Set<string>();\n let count = 0;\n for (const product of bundle.products) {\n if (seen.has(product.id)) continue;\n seen.add(product.id);\n const rule = ruleFor(bundle, product.id);\n const fulfillable = product.variants.nodes.some(\n (v: ProductVariant) => isVariantFulfillable(v, rule.min),\n );\n if (fulfillable) count += 1;\n }\n return count;\n}\n\nfunction PlusIcon() {\n return (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 18 18\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <line x1=\"9\" y1=\"3\" x2=\"9\" y2=\"15\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n <line x1=\"3\" y1=\"9\" x2=\"15\" y2=\"9\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n\nfunction CloseIcon() {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <line x1=\"5\" y1=\"5\" x2=\"15\" y2=\"15\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n <line x1=\"15\" y1=\"5\" x2=\"5\" y2=\"15\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n","/**\n * Mix-and-match picker modal — portaled to `document.body` so its\n * `position: fixed` overlay isn't clipped by a parent's `transform` /\n * `contain` (common in Shopify themes). Multi-add: the modal stays open as\n * the shopper toggles picks; \"Done\" closes it.\n *\n * Markup, class names and behaviour mirror the storefront theme widget\n * (`extensions/bundle-theme/snippets/lb-mix-match.liquid` +\n * `extensions/bundle-theme/assets/bundle-mix-match.js`) one-for-one so the\n * ported CSS in `bundle.css` styles this tree without changes.\n */\nimport {\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport {\n formatMoney,\n formatUnitPrice,\n isVariantFulfillable,\n maxAddableQuantity,\n DEFAULT_PRODUCT_RULE,\n type MixMatchBundleData,\n type Product,\n type ProductRule,\n type ProductVariant,\n} from \"@lime-bundles/core\";\nimport { VariantDropdown } from \"./VariantDropdown\";\nimport { useVariantSelection } from \"../hooks/useVariantSelection\";\nimport { useScrollLock } from \"../hooks/useScrollLock\";\nimport { useFocusTrap } from \"../hooks/useFocusTrap\";\nimport type { SelectedItem } from \"./mix-match-types\";\n\n/**\n * The rule in force for a pick. Pass `variantId` and the variant's own rule\n * wins; without one this resolves the product rule, which is the envelope\n * covering every variant.\n */\nfunction ruleFor(\n bundle: MixMatchBundleData,\n productId: string,\n variantId?: string | null,\n): ProductRule {\n if (variantId) {\n const vRule = bundle.variantRules[variantId];\n if (vRule) return vRule;\n }\n return bundle.productRules[productId] ?? DEFAULT_PRODUCT_RULE;\n}\n\n/**\n * The variant's OWN rule, or undefined when it inherits the product's.\n * Distinct from `ruleFor`, which falls back — callers that must know which\n * level a rule came from need this one.\n */\nfunction variantRuleFor(\n bundle: MixMatchBundleData,\n variantId: string | null | undefined,\n): ProductRule | undefined {\n return variantId ? bundle.variantRules[variantId] : undefined;\n}\n\nfunction sanitizeId(gid: string): string {\n return gid.replace(/[^a-zA-Z0-9_-]/g, \"-\");\n}\n\ninterface EligibleProduct {\n product: Product;\n variants: ProductVariant[];\n firstAvailableVariant: ProductVariant | null;\n isOos: boolean;\n}\n\nfunction buildEligibleProducts(\n bundle: MixMatchBundleData,\n): EligibleProduct[] {\n const result: EligibleProduct[] = [];\n const seen = new Set<string>();\n for (const product of bundle.products) {\n if (seen.has(product.id)) continue;\n seen.add(product.id);\n const rule = ruleFor(bundle, product.id);\n const available = product.variants.nodes.filter((v) =>\n isVariantFulfillable(v, rule.min),\n );\n // Sold-out products stay in the list greyed out; the status flip hides\n // a bundle that can't be completed.\n const isOos = available.length === 0;\n result.push({\n product,\n variants: product.variants.nodes,\n firstAvailableVariant: available[0] ?? null,\n isOos,\n });\n }\n return result;\n}\n\nfunction normalizeText(str: string): string {\n return str\n .normalize(\"NFD\")\n .replace(/[̀-ͯ]/g, \"\")\n .toLowerCase();\n}\n\nexport interface MixMatchPickerProps {\n bundle: MixMatchBundleData;\n currency: string;\n requiredQty: number;\n showStepper: boolean;\n selections: SelectedItem[];\n /** Add a pick. */\n onAdd: (item: SelectedItem) => void;\n /** Live-edit the committed pick's quantity (in-bundle row stepper).\n * Picks are variant-scoped, so both ids identify the slot. */\n onUpdateQuantity: (\n productId: string,\n variantId: string,\n quantity: number,\n ) => void;\n /** Remove the slot holding this variant (the \"Added\" toggle). Other\n * variants of the same product keep their slots. */\n onRemoveVariant: (variantId: string) => void;\n /** Whether the slot holding this variant may be removed — false only for\n * a required product's last covering pick (product-level lock). */\n canRemoveVariant?: (variantId: string) => boolean;\n /** Units an uncommitted variant of a hard-capped required product could\n * take over in an atomic swap (0 = row isn't in the swap state). */\n swapUnitsFor?: (productId: string, variantId: string) => number;\n /** Perform the atomic swap: the item's units displace sibling-variant\n * units of the same product. */\n onSwap?: (item: SelectedItem) => void;\n onClose: () => void;\n /** CSS-var carrier ref so the portaled overlay inherits merchant theming. */\n styleVarsRef: (el: HTMLElement | null) => void;\n}\n\nconst FILTERS_ALL = \"__all__\";\n\nexport function MixMatchPicker({\n bundle,\n currency,\n requiredQty,\n showStepper,\n selections,\n onAdd,\n onUpdateQuantity,\n onRemoveVariant,\n canRemoveVariant,\n swapUnitsFor,\n onSwap,\n onClose,\n styleVarsRef,\n}: MixMatchPickerProps) {\n const wc = bundle.widgetConfig;\n const overlayRef = useRef<HTMLDivElement | null>(null);\n const dialogRef = useRef<HTMLDivElement | null>(null);\n const closeBtnRef = useRef<HTMLButtonElement | null>(null);\n const mouseDownTarget = useRef<EventTarget | null>(null);\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState(\"\");\n const [activeType, setActiveType] = useState<string>(FILTERS_ALL);\n\n const eligible = useMemo(\n () => buildEligibleProducts(bundle),\n [bundle],\n );\n\n // Product-type filter pills: only when enabled AND there are ≥2 distinct\n // non-empty product types.\n const productTypes = useMemo(() => {\n const types: string[] = [];\n const seen = new Set<string>();\n for (const ep of eligible) {\n const ty = (ep.product.productType ?? \"\").trim();\n if (ty && !seen.has(ty)) {\n seen.add(ty);\n types.push(ty);\n }\n }\n return types;\n }, [eligible]);\n\n const showFilters = wc.mixMatchShowTypeFilters && productTypes.length >= 2;\n\n // Completion counts TOTAL UNITS across picks (sum of per-pick quantities),\n // matching the discount function's unit-based minQuantity gate.\n const totalUnits = selections.reduce((sum, s) => sum + s.quantity, 0);\n const atCapacity = totalUnits >= requiredQty;\n // Capped at requiredQty for display — over-completion still reads full.\n const shownUnits = Math.min(totalUnits, requiredQty);\n\n // Trigger the open transition on mount (display already shown).\n useEffect(() => {\n const id = requestAnimationFrame(() => setOpen(true));\n return () => cancelAnimationFrame(id);\n }, []);\n\n useScrollLock(true);\n // Initial focus lands on the close icon, not the search input — focusing\n // search on a phone pops the keyboard over half the modal unasked.\n useFocusTrap({\n active: true,\n containerRef: dialogRef,\n initialFocusRef: closeBtnRef,\n onEscape: onClose,\n });\n\n const remaining = Math.max(0, requiredQty - shownUnits);\n const subtitle = (() => {\n if (remaining <= 0) return \"Your bundle is complete\";\n const pct =\n bundle.discountConfig.discountType === \"percentage\" &&\n bundle.discountConfig.discountValue\n ? Math.round(bundle.discountConfig.discountValue)\n : 0;\n return pct > 0\n ? `Choose ${remaining} more to unlock ${pct}% off`\n : `Choose ${remaining} more to complete your bundle`;\n })();\n\n // Products already in the bundle when the modal opened (required seeds\n // included) sink below the ones still to pick. The snapshot is captured\n // once at mount — re-sorting live on add/remove would make the list jump\n // under the shopper's finger; the next open recomputes it.\n const [selectedAtOpen] = useState(\n () => new Set(selections.map((s) => s.productId)),\n );\n const ordered = useMemo(() => {\n const front: EligibleProduct[] = [];\n const back: EligibleProduct[] = [];\n for (const ep of eligible) {\n (selectedAtOpen.has(ep.product.id) ? back : front).push(ep);\n }\n return front.concat(back);\n }, [eligible, selectedAtOpen]);\n\n const filtered = useMemo(() => {\n const nq = normalizeText(query.trim());\n return ordered.filter((ep) => {\n const matchesQuery =\n !nq || normalizeText(ep.product.title).includes(nq);\n const matchesType =\n activeType === FILTERS_ALL ||\n (ep.product.productType ?? \"\") === activeType;\n return matchesQuery && matchesType;\n });\n }, [ordered, query, activeType]);\n\n const showEmpty = filtered.length === 0 && query.trim().length > 0;\n\n function onOverlayMouseDown(e: React.MouseEvent) {\n mouseDownTarget.current = e.target;\n }\n function onOverlayMouseUp(e: React.MouseEvent) {\n if (e.target === overlayRef.current && mouseDownTarget.current === overlayRef.current) {\n onClose();\n }\n mouseDownTarget.current = null;\n }\n\n const titleId = `lb-modal-title-${sanitizeId(bundle.id)}`;\n\n const modal = (\n // The overlay is a backdrop: click-outside-to-close is a mouse convenience;\n // keyboard users close via Escape (handled by useFocusTrap), and the dialog\n // inside carries the interactive role + focus trap. So the static-element\n // interaction lint does not apply to this backdrop.\n // eslint-disable-next-line jsx-a11y/no-static-element-interactions\n <div\n ref={(el) => {\n overlayRef.current = el;\n styleVarsRef(el);\n }}\n className={`lb-mix-match__modal-overlay${open ? \" lb-mix-match__modal-overlay--open\" : \"\"}`}\n data-modal-overlay\n data-bundle-gid={bundle.id}\n onMouseDown={onOverlayMouseDown}\n onMouseUp={onOverlayMouseUp}\n >\n <div\n ref={dialogRef}\n className={`lb-mix-match__modal${showFilters ? \"\" : \" lb-mix-match__modal--filters-hidden\"}`}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n tabIndex={-1}\n >\n <div className=\"lb-mix-match__modal-header\">\n <div className=\"lb-mix-match__modal-header-top\">\n <div className=\"lb-mix-match__modal-heading\">\n <h4 className=\"lb-mix-match__modal-title\" id={titleId}>\n Add to your bundle\n </h4>\n <p className=\"lb-mix-match__modal-subtitle\" data-modal-subtitle>\n {subtitle}\n </p>\n </div>\n <button\n ref={closeBtnRef}\n type=\"button\"\n className=\"lb-mix-match__modal-close\"\n data-modal-close\n aria-label=\"Close\"\n onClick={onClose}\n >\n <CloseIcon />\n </button>\n </div>\n <div\n className=\"lb-mix-match__progress lb-mix-match__modal-progress\"\n data-progress\n >\n <div\n className=\"lb-mix-match__progress-segments\"\n role=\"progressbar\"\n aria-valuenow={shownUnits}\n aria-valuemin={0}\n aria-valuemax={requiredQty}\n >\n {Array.from({ length: requiredQty }).map((_, i) => (\n <span\n key={i}\n className={`lb-mix-match__progress-segment${i < shownUnits ? \" lb-mix-match__progress-segment--filled\" : \"\"}`}\n data-progress-segment\n />\n ))}\n </div>\n </div>\n </div>\n\n {wc.showSearch && (\n <div className=\"lb-mix-match__modal-search\">\n <input\n type=\"text\"\n className=\"lb-mix-match__modal-search-input\"\n data-modal-search\n role=\"searchbox\"\n aria-label=\"Search products\"\n placeholder=\"Search products\"\n autoComplete=\"off\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n />\n {query.length > 0 && (\n <button\n type=\"button\"\n className=\"lb-mix-match__modal-search-clear\"\n data-modal-search-clear\n aria-label=\"Clear search\"\n onClick={() => setQuery(\"\")}\n >\n <SearchClearIcon />\n </button>\n )}\n </div>\n )}\n\n {showFilters && (\n <div\n className=\"lb-mix-match__filters\"\n data-modal-filters\n role=\"group\"\n aria-label=\"Filter by product type\"\n >\n {[FILTERS_ALL, ...productTypes].map((value) => {\n const isActive = value === activeType;\n return (\n <button\n key={value}\n type=\"button\"\n className={`lb-mix-match__filter${isActive ? \" lb-mix-match__filter--active\" : \"\"}`}\n data-filter={value}\n aria-pressed={isActive}\n onClick={() => setActiveType(value)}\n >\n {value === FILTERS_ALL ? \"All\" : value}\n </button>\n );\n })}\n </div>\n )}\n\n <div className=\"lb-mix-match__modal-list\" data-modal-list>\n {filtered.map((ep) => (\n <MixMatchPickerRow\n key={ep.product.id}\n bundle={bundle}\n eligible={ep}\n currency={currency}\n showStepper={showStepper}\n selections={selections}\n atCapacity={atCapacity}\n remainingUnits={remaining}\n onAdd={onAdd}\n onUpdateQuantity={onUpdateQuantity}\n onRemoveVariant={onRemoveVariant}\n canRemoveVariant={canRemoveVariant}\n swapUnitsFor={swapUnitsFor}\n onSwap={onSwap}\n />\n ))}\n </div>\n\n {showEmpty && (\n <div className=\"lb-mix-match__modal-empty\" data-modal-empty>\n <p>No products match your search</p>\n </div>\n )}\n\n <span data-modal-live aria-live=\"polite\" className=\"lb-visually-hidden\">\n {`${filtered.length} products shown`}\n </span>\n\n <div className=\"lb-mix-match__modal-footer\">\n <span\n className=\"lb-mix-match__modal-footer-count\"\n data-modal-footer-count\n aria-live=\"polite\"\n >\n {`${shownUnits} of ${requiredQty} added`}\n </span>\n <button\n type=\"button\"\n className=\"lb-mix-match__modal-done\"\n data-modal-done\n onClick={onClose}\n >\n Done\n </button>\n </div>\n </div>\n </div>\n );\n\n if (typeof document === \"undefined\") return null;\n return createPortal(modal, document.body);\n}\n\ninterface MixMatchPickerRowProps {\n bundle: MixMatchBundleData;\n eligible: EligibleProduct;\n currency: string;\n showStepper: boolean;\n selections: SelectedItem[];\n atCapacity: boolean;\n /** Open spots left in the bundle (requiredQty minus total units).\n * EXACT-SIZE: an unselected row whose rule.min exceeds this can't be\n * added, and the pre-add stepper caps at it. An in-bundle row's\n * headroom is its committed units plus this. */\n remainingUnits: number;\n onAdd: (item: SelectedItem) => void;\n onUpdateQuantity: (\n productId: string,\n variantId: string,\n quantity: number,\n ) => void;\n onRemoveVariant: (variantId: string) => void;\n canRemoveVariant?: (variantId: string) => boolean;\n swapUnitsFor?: (productId: string, variantId: string) => number;\n onSwap?: (item: SelectedItem) => void;\n}\n\nfunction MixMatchPickerRow({\n bundle,\n eligible,\n currency,\n showStepper,\n selections,\n atCapacity,\n remainingUnits,\n onAdd,\n onUpdateQuantity,\n onRemoveVariant,\n canRemoveVariant,\n swapUnitsFor,\n onSwap,\n}: MixMatchPickerRowProps) {\n const { product, variants, isOos } = eligible;\n const rule = ruleFor(bundle, product.id);\n\n const optionNames = useMemo<string[]>(() => {\n const first = variants[0];\n return first ? first.selectedOptions.map((o) => o.name) : [];\n }, [variants]);\n const showPicker = variants.length > 1 && optionNames.length > 0;\n\n const { selectedValues, selectedVariant, setOptionValue, optionsFor } =\n useVariantSelection({ variants, optionNames });\n\n const currentVariant =\n selectedVariant ??\n variants.find((v) => isVariantFulfillable(v, rule.min)) ??\n eligible.firstAvailableVariant ??\n variants[0] ??\n null;\n\n // The rule in force for this row. `rule` above stays the PRODUCT envelope\n // and is used wherever the question is about the product's total across\n // variants; `vRule` is what bounds this variant's own pick.\n const vRule = ruleFor(bundle, product.id, currentVariant?.id);\n const variantMax = variantRuleFor(bundle, currentVariant?.id)?.max;\n\n // Aggregate units of the current variant already pinned to the bundle — used\n // for the stock cap.\n const alreadyInBundle = useMemo(() => {\n if (!currentVariant) return 0;\n let sum = 0;\n for (const s of selections) {\n if (s.productId === product.id && s.variantId === currentVariant.id) {\n sum += s.quantity;\n }\n }\n return sum;\n }, [selections, product.id, currentVariant]);\n\n // Slots are VARIANT-scoped: the row's Added state, live stepper, and tint\n // all follow its currently-selected variant. Switching the dropdowns to an\n // uncommitted variant reverts the row to \"Add\" while the committed variant\n // keeps its slot — that's how a multi-variant product fills several slots.\n const committedSelection = useMemo(\n () =>\n currentVariant\n ? (selections.find((s) => s.variantId === currentVariant.id) ?? null)\n : null,\n [selections, currentVariant],\n );\n const variantInBundle = committedSelection !== null;\n const committedQty = committedSelection?.quantity ?? 0;\n\n // The merchant's rule.max caps the PRODUCT's total units across all its\n // variant slots, so sibling-variant slots reduce this row's share of it.\n const productOtherUnits = useMemo(() => {\n if (!currentVariant) return 0;\n let sum = 0;\n for (const s of selections) {\n if (s.productId === product.id && s.variantId !== currentVariant.id) {\n sum += s.quantity;\n }\n }\n return sum;\n }, [selections, product.id, currentVariant]);\n\n // ATOMIC SWAP state: a hard-capped required product's uncommitted\n // variants displace sibling units instead of adding, so the exact-size\n // and capacity gates don't apply and the ceiling is the units they can\n // take over.\n const swapUnits = currentVariant\n ? (swapUnitsFor?.(product.id, currentVariant.id) ?? 0)\n : 0;\n const inSwapState = swapUnits >= vRule.min;\n // EXACT-SIZE ceiling: an unselected row (committedQty 0) can add at most\n // the bundle's remaining open spots, so the pre-add stepper caps at\n // min(product headroom, remainingUnits). A committed (in-bundle) row edits\n // its pick LIVE — its own units already count toward the total, so its\n // headroom is its committed qty plus the open spots. Own committed units\n // draw from the same stock pool the stepper edits, so only units of this\n // variant held by OTHER slots reduce availability.\n // The variant's own cap binds independently of the envelope: sibling units\n // eat into the product's total, never into this variant's allowance.\n const spotCeiling = inSwapState\n ? swapUnits\n : Math.min(\n rule.max - productOtherUnits,\n committedQty + remainingUnits,\n variantMax ?? Infinity,\n );\n const cap = currentVariant\n ? maxAddableQuantity(\n currentVariant,\n spotCeiling,\n Math.max(0, alreadyInBundle - committedQty),\n )\n : 0;\n const stepperMax = Math.max(vRule.min, cap);\n\n const [qty, setQty] = useState(vRule.min);\n\n // Clamp the local qty whenever the bounds move (variant change / cross-slot\n // stock accounting), and reset to rule.min when the row's variant leaves\n // the bundle OR the shopper switches to an uncommitted variant — a fresh\n // pick shouldn't drag the previous variant's qty over.\n useEffect(() => {\n setQty((prev) => Math.max(vRule.min, Math.min(prev, stepperMax)));\n }, [stepperMax, vRule.min]);\n const currentVariantId = currentVariant?.id ?? null;\n useEffect(() => {\n if (!variantInBundle) setQty(vRule.min);\n }, [variantInBundle, currentVariantId, vRule.min]);\n\n if (!currentVariant) return null;\n\n const thumbImage = currentVariant.image ?? product.featuredImage ?? null;\n const unitPriceText = formatUnitPrice(\n currentVariant.unitPrice,\n currentVariant.unitPriceMeasurement,\n currency,\n );\n\n // Add disabled when: bundle full, stock (or the product's rule.max,\n // exhausted by sibling-variant slots) can't satisfy rule.min, or the\n // product's rule.min exceeds the remaining open spots (exact-size\n // enforcement — adding it would overshoot requiredQty).\n const noStock = cap < vRule.min;\n const needsMoreSpots =\n !variantInBundle && !inSwapState && vRule.min > remainingUnits;\n // A swap frees its own room, so only stock can block it.\n const addDisabled =\n !variantInBundle &&\n (inSwapState ? noStock : atCapacity || noStock || needsMoreSpots);\n // Required product's last covering pick — the Remove slot goes inert\n // (\"Required\"); removal returns once another slot covers the minimum.\n const lockedRequired =\n variantInBundle &&\n currentVariant != null &&\n !(canRemoveVariant?.(currentVariant.id) ?? true);\n // An in-bundle row keeps its stepper ENABLED — it edits the committed\n // pick's quantity live, bounded by [rule.min, stepperMax]. Unselected\n // rows lock the stepper together with Add.\n const stepperDisabled = isOos || (!variantInBundle && addDisabled);\n // The stepper shows (and edits) the committed qty while in the bundle,\n // and the local pre-add qty otherwise.\n const shownQty = variantInBundle ? committedQty : qty;\n\n function handleAddOrRemove() {\n if (variantInBundle && currentVariant) {\n onRemoveVariant(currentVariant.id);\n return;\n }\n if (!currentVariant || noStock) return;\n const pickedQty = showStepper ? qty : vRule.min;\n const item = {\n productId: product.id,\n variantId: currentVariant.id,\n title: product.title,\n url: `/products/${product.handle}`,\n variantTitle: currentVariant.title,\n featuredImage: thumbImage?.url ?? null,\n price: parseFloat(currentVariant.price.amount),\n compareAtPrice: currentVariant.compareAtPrice\n ? parseFloat(currentVariant.compareAtPrice.amount)\n : null,\n unitPrice: unitPriceText,\n quantity: pickedQty,\n };\n // ATOMIC SWAP: displaces sibling units, so it runs before (and\n // instead of) the capacity gates.\n if (inSwapState && onSwap) {\n onSwap({ ...item, quantity: Math.min(pickedQty, swapUnits) });\n return;\n }\n if (atCapacity || needsMoreSpots) return;\n onAdd(item);\n }\n\n const priceCents = parseFloat(currentVariant.price.amount);\n const compareCents = currentVariant.compareAtPrice\n ? parseFloat(currentVariant.compareAtPrice.amount)\n : null;\n\n return (\n <div\n className={`lb-mix-match__modal-product${isOos ? \" lb-mix-match__modal-product--sold-out\" : \"\"}${variantInBundle ? \" lb-mix-match__modal-product--in-bundle\" : \"\"}`}\n data-product-item\n data-title={normalizeText(product.title)}\n data-type={product.productType ?? \"\"}\n aria-disabled={isOos || undefined}\n >\n <div className=\"lb-mix-match__modal-product-thumb\">\n {thumbImage && (\n <img\n src={thumbImage.url}\n alt={thumbImage.altText ?? product.title}\n loading=\"lazy\"\n // Intrinsic dimensions reserve the \"original\"-ratio box pre-load\n // (issue #302); inert for the cropped ratios, where CSS sizes it.\n width={thumbImage.width ?? undefined}\n height={thumbImage.height ?? undefined}\n />\n )}\n {variantInBundle && (\n <span className=\"lb-mix-match__modal-added-badge\">Added</span>\n )}\n </div>\n\n <div className=\"lb-mix-match__modal-product-info\">\n {/* New tab keeps the in-progress bundle alive — same-tab navigation\n would wipe the shopper's picks. */}\n <p className=\"lb-mix-match__modal-product-title\">\n <a\n href={`/products/${product.handle}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {product.title}\n </a>\n </p>\n <p className=\"lb-mix-match__modal-product-price\">\n <span data-row-price-sale>{formatMoney(priceCents, currency)}</span>\n {compareCents !== null && compareCents > priceCents && (\n <s className=\"lb-mix-match__modal-product-compare\" data-row-compare>\n {formatMoney(compareCents, currency)}\n </s>\n )}\n </p>\n {unitPriceText && (\n <p className=\"lb-mix-match__modal-product-unit-price lb-bundle-product-unit-price\">\n {unitPriceText}\n </p>\n )}\n\n {showPicker && (\n <div className=\"lb-bundle-variant-option-groups\">\n {optionNames.map((optionName, optionIndex) => {\n const dropdownOptions = optionsFor(optionIndex).map((o) => ({\n value: o.value,\n label: o.value,\n disabled: o.disabled,\n }));\n return (\n <div\n key={optionName}\n className=\"lb-bundle-variant-option-group\"\n >\n <span className=\"lb-bundle-variant-option-label\">\n {optionName}\n </span>\n <VariantDropdown\n className=\"lb-mix-match__variant-select-dropdown\"\n options={dropdownOptions}\n value={selectedValues[optionIndex] ?? null}\n onChange={(v) => setOptionValue(optionIndex, v)}\n ariaLabel={optionName}\n />\n </div>\n );\n })}\n </div>\n )}\n {!showPicker &&\n variants.length === 1 &&\n currentVariant.title !== \"Default Title\" && (\n <span className=\"lb-mix-match__filled-variant\">\n {currentVariant.title}\n </span>\n )}\n\n {/* \"Needs N spots\" hint — exact-size enforcement: rule.min exceeds\n the remaining open spots, so Add and the stepper are disabled.\n Hidden at capacity (remaining 0), where the modal's complete\n state already tells the story for every row. */}\n {!isOos && needsMoreSpots && remainingUnits > 0 && (\n <span className=\"lb-mix-match__modal-needs-spots\">\n {rule.min === 1 ? \"Needs 1 spot\" : `Needs ${rule.min} spots`}\n </span>\n )}\n\n {isOos ? (\n <span className=\"lb-mix-match__modal-sold-out-label\">Sold out</span>\n ) : (\n <div className=\"lb-mix-match__modal-product-actions\">\n {showStepper && (\n <div className=\"lb-bundle-variant-option-group lb-mix-match__qty-stepper-group\">\n <div\n className=\"lb-mix-match__qty-stepper\"\n role=\"group\"\n aria-label=\"Quantity\"\n >\n <button\n type=\"button\"\n className=\"lb-mix-match__qty-stepper-button lb-mix-match__qty-stepper-button--minus\"\n aria-label=\"Decrease quantity\"\n disabled={stepperDisabled || shownQty <= rule.min}\n onClick={() => {\n if (variantInBundle && currentVariant) {\n // LIVE EDIT — propagate into selections state so\n // progress, CTA, pricing, and every other row's\n // addability re-evaluate immediately.\n onUpdateQuantity(\n product.id,\n currentVariant.id,\n Math.max(rule.min, committedQty - 1),\n );\n } else {\n setQty((q) => Math.max(rule.min, q - 1));\n }\n }}\n >\n {\"−\"}\n </button>\n <span\n className=\"lb-mix-match__qty-stepper-value\"\n data-row-qty\n aria-live=\"polite\"\n >\n {shownQty}\n </span>\n <button\n type=\"button\"\n className=\"lb-mix-match__qty-stepper-button lb-mix-match__qty-stepper-button--plus\"\n aria-label=\"Increase quantity\"\n disabled={stepperDisabled || shownQty >= stepperMax}\n onClick={() => {\n if (variantInBundle && currentVariant) {\n onUpdateQuantity(\n product.id,\n currentVariant.id,\n Math.min(stepperMax, committedQty + 1),\n );\n } else {\n setQty((q) => Math.min(stepperMax, q + 1));\n }\n }}\n >\n +\n </button>\n </div>\n </div>\n )}\n <button\n type=\"button\"\n className={`lb-mix-match__modal-add${variantInBundle ? \" lb-mix-match__modal-add--added\" : \"\"}${lockedRequired ? \" lb-mix-match__modal-add--required\" : \"\"}`}\n data-add-product\n aria-label={\n variantInBundle\n ? lockedRequired\n ? `${product.title} is required and cannot be removed`\n : `Remove ${product.title}`\n : `${inSwapState ? \"Swap\" : \"Add\"} ${product.title}`\n }\n disabled={addDisabled || lockedRequired}\n onClick={handleAddOrRemove}\n >\n {/* Explicit inverted \"Remove\" — state feedback lives on the\n thumbnail's \"Added\" badge, not the button. */}\n {variantInBundle\n ? lockedRequired\n ? \"Required\"\n : \"Remove\"\n : inSwapState\n ? \"Swap\"\n : \"Add\"}\n </button>\n </div>\n )}\n </div>\n </div>\n );\n}\n\nfunction CloseIcon() {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <line x1=\"5\" y1=\"5\" x2=\"15\" y2=\"15\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n <line x1=\"15\" y1=\"5\" x2=\"5\" y2=\"15\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n\nfunction SearchClearIcon() {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path d=\"M14.348 5.652a.5.5 0 0 0-.707 0L10 9.293 6.36 5.652a.5.5 0 1 0-.708.707L9.293 10l-3.641 3.641a.5.5 0 0 0 .708.707L10 10.707l3.641 3.641a.5.5 0 0 0 .707-.707L10.707 10l3.641-3.641a.5.5 0 0 0 0-.707z\" />\n </svg>\n );\n}\n","/**\n * Lock background scroll while a modal is open. iOS-safe: pins `<body>` to a\n * fixed position offset by the current scroll, then restores it on unlock.\n *\n * Mirrors the `scrollLock` helper in\n * `extensions/bundle-theme/assets/bundle-mix-match.js`. A module-level lock\n * count keeps nested/overlapping locks (e.g. two bundle widgets on one page)\n * from clobbering each other's body styles.\n */\nimport { useEffect } from \"react\";\n\nlet lockCount = 0;\nlet savedY = 0;\n\nfunction lock() {\n if (typeof document === \"undefined\") return;\n lockCount += 1;\n if (lockCount > 1) return;\n savedY = window.pageYOffset || document.documentElement.scrollTop;\n const body = document.body;\n body.style.position = \"fixed\";\n body.style.top = `-${savedY}px`;\n body.style.left = \"0\";\n body.style.right = \"0\";\n body.style.overflow = \"hidden\";\n}\n\nfunction unlock() {\n if (typeof document === \"undefined\") return;\n if (lockCount <= 0) return;\n lockCount -= 1;\n if (lockCount > 0) return;\n const body = document.body;\n body.style.position = \"\";\n body.style.top = \"\";\n body.style.left = \"\";\n body.style.right = \"\";\n body.style.overflow = \"\";\n window.scrollTo(0, savedY);\n}\n\n/** Lock background scroll while `active` is true. Unlocks on false/unmount. */\nexport function useScrollLock(active: boolean): void {\n useEffect(() => {\n if (!active) return;\n lock();\n return unlock;\n }, [active]);\n}\n","/**\n * Trap keyboard focus inside a container while a modal is open, handle the\n * Escape key, and restore focus to whatever was focused before the modal\n * opened (or to a caller-supplied element).\n *\n * Mirrors the focus-trap + Escape handling in\n * `extensions/bundle-theme/assets/bundle-mix-match.js`. The container ref is\n * the dialog element; Tab/Shift+Tab cycle within its focusable descendants.\n */\nimport { useEffect, useRef, type RefObject } from \"react\";\n\nconst FOCUSABLE_SELECTOR = [\n \"a[href]\",\n \"button:not([disabled])\",\n \"input:not([disabled])\",\n \"select:not([disabled])\",\n \"textarea:not([disabled])\",\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(\",\");\n\nfunction getFocusable(container: HTMLElement): HTMLElement[] {\n const nodes = container.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR);\n const result: HTMLElement[] = [];\n nodes.forEach((node) => {\n // offsetParent === null filters out display:none nodes (jsdom returns\n // null for everything, so the trap is a no-op there — acceptable, the\n // browser is the surface that matters).\n if (node.offsetParent !== null || typeof node.offsetParent === \"undefined\") {\n result.push(node);\n }\n });\n return result;\n}\n\nexport interface UseFocusTrapOptions {\n active: boolean;\n containerRef: RefObject<HTMLElement | null>;\n /** Called when Escape is pressed. */\n onEscape: () => void;\n /**\n * Element to focus when the trap activates (e.g. the modal's close\n * button — focusing an input here would pop the mobile keyboard over the\n * modal). Falls back to the container itself.\n */\n initialFocusRef?: RefObject<HTMLElement | null>;\n /**\n * Where to send focus when the trap deactivates. When omitted, focus is\n * restored to the element that was focused when the trap activated.\n */\n returnFocusRef?: RefObject<HTMLElement | null>;\n}\n\nexport function useFocusTrap({\n active,\n containerRef,\n onEscape,\n initialFocusRef,\n returnFocusRef,\n}: UseFocusTrapOptions): void {\n const previouslyFocused = useRef<HTMLElement | null>(null);\n\n useEffect(() => {\n if (!active) return;\n const container = containerRef.current;\n previouslyFocused.current =\n (document.activeElement as HTMLElement | null) ?? null;\n\n // Focus the caller's initial target (falling back to the dialog itself)\n // on open so Escape works immediately.\n const initial = initialFocusRef?.current ?? container;\n initial?.focus();\n\n function onKeyDown(e: KeyboardEvent) {\n if (e.key === \"Escape\") {\n e.preventDefault();\n onEscape();\n return;\n }\n if (e.key !== \"Tab\") return;\n const node = containerRef.current;\n if (!node) return;\n const focusable = getFocusable(node);\n if (focusable.length === 0) {\n e.preventDefault();\n return;\n }\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n const activeEl = document.activeElement;\n if (e.shiftKey && activeEl === first) {\n e.preventDefault();\n last.focus();\n } else if (!e.shiftKey && activeEl === last) {\n e.preventDefault();\n first.focus();\n }\n }\n\n document.addEventListener(\"keydown\", onKeyDown);\n return () => {\n document.removeEventListener(\"keydown\", onKeyDown);\n // Reading the ref at cleanup time is deliberate: focus must return to\n // wherever the caller's ref points when the trap closes (the node may\n // have mounted after activation), not to a snapshot from open time.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const target = returnFocusRef?.current ?? previouslyFocused.current;\n // Defer so focus restore lands after React has flushed the close.\n if (target && typeof target.focus === \"function\") {\n target.focus();\n }\n };\n // onEscape / initialFocusRef / returnFocusRef are stable enough for our\n // callers; re-running on `active` toggle is what matters.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [active]);\n}\n","/**\n * Volume bundle component — quantity selector with tier calculator.\n */\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport {\n formatMoney,\n formatUnitPrice,\n calculateTierSavings,\n getActiveTier,\n getMinTierQuantity,\n bestValueTierIndex,\n resolveDefaultTierIndex,\n resolvePopularTierIndex,\n isVariantFulfillable,\n resolveContextProduct,\n shouldShowLowStockBadge,\n type CartLineInput,\n type VolumeBundleData,\n} from \"@lime-bundles/core\";\nimport { useBundleData } from \"../hooks/useBundleData\";\nimport { useAnalytics } from \"../hooks/useAnalytics\";\nimport { useWidgetConfigVars } from \"../hooks/useWidgetConfigVars\";\nimport { useVariantSelection } from \"../hooks/useVariantSelection\";\nimport { useEdgeFade } from \"../hooks/useEdgeFade\";\nimport { VariantDropdown } from \"./VariantDropdown\";\nimport type { BundleComponentProps } from \"./types\";\nimport { BundleCountdown } from \"./BundleCountdown\";\n\nexport function VolumeBundle(props: BundleComponentProps) {\n const {\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n appUrl,\n analyticsEnabled,\n onAddToCart,\n onError,\n className,\n productId,\n } = props;\n\n const result = useBundleData({\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n });\n\n const { elementRef, trackAddToCart } = useAnalytics({\n shopDomain,\n appUrl: appUrl ?? `https://${shopDomain}`,\n bundleGid,\n bundleType: \"volume\",\n enabled: analyticsEnabled !== false,\n });\n\n const [quantity, setQuantity] = useState(1);\n const [addingToCart, setAddingToCart] = useState(false);\n const [cartError, setCartError] = useState<string | null>(null);\n const [seededFor, setSeededFor] = useState<string | null>(null);\n\n const bundle =\n result.status === \"success\" && result.bundle.bundleType === \"volume\"\n ? (result.bundle as VolumeBundleData)\n : null;\n\n // Start on the merchant's configured default tier, the way the Liquid\n // widget pre-selects it — once per bundle, so shopper interaction wins\n // from then on.\n useEffect(() => {\n if (!bundle || seededFor === bundle.id) return;\n setSeededFor(bundle.id);\n const tiers = bundle.volumeTiers;\n if (tiers.length === 0) return;\n const best = bestValueTierIndex(\n tiers,\n bundle.discountConfig.discountType,\n );\n const idx = resolveDefaultTierIndex(\n bundle.widgetConfig.defaultTier,\n tiers.length,\n best,\n );\n setQuantity(tiers[idx].minQuantity);\n }, [bundle, seededFor]);\n\n // Apply merchant-config CSS vars to the component root via a callback\n // ref composed with elementRef.\n const setConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);\n\n // Scroll-aware edge fade on the inset tier list.\n const tiersEdgeFadeRef = useEdgeFade();\n\n useEffect(() => {\n if (result.status === \"error\") {\n onError?.(result.error);\n return;\n }\n if (result.status === \"success\" && result.bundle.bundleType !== \"volume\") {\n onError?.(\n new Error(\n `VolumeBundle: expected bundleType=\"volume\", got \"${result.bundle.bundleType}\"`,\n ),\n );\n }\n }, [result, onError]);\n\n // The product this page is standing on (via the host's `productId` prop),\n // the way the theme widget binds to Liquid's `product`; the bundle's\n // first product only when the host supplied no context.\n const product = bundle\n ? resolveContextProduct(bundle.products, { productId })\n : undefined;\n const variants = useMemo(() => product?.variants.nodes ?? [], [product]);\n const optionNames = useMemo<string[]>(() => {\n const first = variants[0];\n return first ? first.selectedOptions.map((o) => o.name) : [];\n }, [variants]);\n const showPicker = variants.length > 1 && optionNames.length > 0;\n const { selectedValues, selectedVariant, setOptionValue, optionsFor } =\n useVariantSelection({ variants, optionNames });\n\n // Volume bundle: floor of fulfillability is the smallest tier's\n // minQuantity (anything below that can't even buy the cheapest tier).\n const minTierQty = bundle ? getMinTierQuantity(bundle.volumeTiers) : 1;\n /**\n * True when no variant can cover even the cheapest tier. The fallback to\n * `variants[0]` below keeps prices on screen, but without this flag the CTA\n * stayed live and add-to-cart silently bailed on `!variant`.\n */\n const isSoldOut =\n variants.length > 0 &&\n !variants.some((v) => isVariantFulfillable(v, minTierQty));\n const displayVariant =\n selectedVariant ??\n variants.find((v) => isVariantFulfillable(v, minTierQty)) ??\n variants[0];\n /**\n * Whether the display variant can cover a given tier's quantity. A \"buy 6\"\n * tier with 3 units left used to render live on every surface; the shopper\n * clicked through to a cart Shopify capped at add time.\n */\n const tierAvailable = useCallback(\n (tierQty: number): boolean =>\n Boolean(displayVariant && isVariantFulfillable(displayVariant, tierQty)),\n [displayVariant],\n );\n // The selected tier can become unavailable when the shopper switches to a\n // shallower-stocked variant; the CTA locks rather than silently bailing.\n const selectedTierUnavailable = !isSoldOut && !tierAvailable(quantity);\n const basePrice = displayVariant\n ? parseFloat(displayVariant.price.amount)\n : product\n ? parseFloat(product.priceRange.minVariantPrice.amount)\n : 0;\n const currency = product?.priceRange.minVariantPrice.currencyCode ?? \"USD\";\n const thumbImage = displayVariant?.image ?? product?.featuredImage ?? null;\n const unitPriceText = displayVariant\n ? formatUnitPrice(\n displayVariant.unitPrice,\n displayVariant.unitPriceMeasurement,\n currency,\n )\n : null;\n\n const tierSavings = useMemo(\n () =>\n bundle\n ? calculateTierSavings(\n bundle.volumeTiers,\n basePrice,\n quantity,\n bundle.discountConfig.discountType,\n )\n : [],\n [bundle, basePrice, quantity],\n );\n const activeTier = bundle\n ? getActiveTier(bundle.volumeTiers, quantity)\n : null;\n\n // Which tier wears the \"Most popular\" badge — the same resolution the\n // Liquid and web-component hosts run: the merchant's pinned tierIndex\n // (deliberately unclamped, so an out-of-range pin badges nothing), else\n // the best-savings tier ranked the way the theme ranks it.\n const popularTierIndex = useMemo(() => {\n if (!bundle || bundle.volumeTiers.length === 0) return -1;\n return resolvePopularTierIndex(\n bundle.widgetConfig.popularBadge.tierIndex,\n bundle.widgetConfig.popularBadge.visible !== false,\n bestValueTierIndex(\n bundle.volumeTiers,\n bundle.discountConfig.discountType,\n ),\n );\n }, [bundle]);\n\n // Receipt summary — total = active tier's discounted unit price × qty\n // (full base price when no tier is active yet). Compare-at = base × qty.\n // Mirrors the storefront volume widget's summary band + savings line.\n const activeUnitPrice =\n tierSavings.find((ts) => ts.tier === activeTier)?.unitPrice ?? basePrice;\n const undiscountedTotal = basePrice * quantity;\n const volumeTotal = activeUnitPrice * quantity;\n const volumeSavings = Math.max(0, undiscountedTotal - volumeTotal);\n const volumeSavingsPercent =\n undiscountedTotal > 0 && volumeSavings > 0\n ? Math.round((volumeSavings / undiscountedTotal) * 100)\n : 0;\n\n const handleAddToCart = useCallback(async () => {\n if (!bundle || !product) return;\n\n const variant =\n selectedVariant ??\n product.variants.nodes.find((v) =>\n isVariantFulfillable(v, quantity),\n );\n if (!variant) return;\n\n const lines: CartLineInput[] = [\n {\n merchandiseId: variant.id,\n quantity,\n attributes: [\n { key: \"_lime_bundle_gid\", value: bundle.id },\n { key: \"_lime_bundle_type\", value: bundle.bundleType },\n ],\n },\n ];\n\n setAddingToCart(true);\n setCartError(null);\n try {\n await onAddToCart(lines);\n // Reuse the canonical computation from calculateTierSavings so the\n // analytics unit price matches what the component rendered.\n const unitPrice =\n tierSavings.find((ts) => ts.tier === activeTier)?.unitPrice ??\n basePrice;\n trackAddToCart({\n productId: product.id,\n quantity,\n totalPrice: Math.round(unitPrice * quantity * 100) / 100,\n });\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setCartError(error.message);\n onError?.(error);\n } finally {\n setAddingToCart(false);\n }\n }, [\n bundle,\n product,\n quantity,\n activeTier,\n basePrice,\n onAddToCart,\n onError,\n trackAddToCart,\n selectedVariant,\n tierSavings,\n ]);\n\n if (result.status === \"loading\") {\n return (\n <div className={`lb-bundle lb-bundle--loading ${className ?? \"\"}`}>\n <div className=\"lb-skeleton lb-skeleton--title\" />\n <div className=\"lb-skeleton lb-skeleton--tiers\" />\n </div>\n );\n }\n\n if (result.status === \"error\") return null;\n if (!bundle) return null;\n if (!product) return null;\n\n return (\n <div\n ref={(el) => {\n elementRef(el);\n setConfigVarsRef(el);\n }}\n className={`lb-bundle lb-bundle--volume ${className ?? \"\"}`}\n role=\"region\"\n aria-label={bundle.title}\n >\n <div className=\"lb-bundle-header\">\n <div className=\"lb-bundle-header__content\">\n <h3 className=\"lb-bundle-title\">{bundle.title}</h3>\n {bundle.description && (\n <p className=\"lb-bundle-subtitle\">{bundle.description}</p>\n )}\n </div>\n </div>\n\n <BundleCountdown\n endsAt={bundle.endsAt}\n widgetConfig={bundle.widgetConfig}\n />\n\n <div className=\"lb-bundle-product-row lb-bundle-product-row--volume\">\n {thumbImage && (\n <img\n src={thumbImage.url}\n alt={thumbImage.altText ?? product.title}\n className=\"lb-bundle__product-image\"\n loading=\"lazy\"\n // Intrinsic dimensions reserve the \"original\"-ratio box pre-load\n // (issue #302); inert for the cropped ratios, where CSS sizes it.\n width={thumbImage.width ?? undefined}\n height={thumbImage.height ?? undefined}\n />\n )}\n <div className=\"lb-bundle__product-info\">\n <p className=\"lb-bundle__product-title\">{product.title}</p>\n <p className=\"lb-bundle__product-price\">\n {formatMoney(basePrice, currency)} each\n </p>\n {unitPriceText && (\n <p className=\"lb-bundle__product-unit-price\">{unitPriceText}</p>\n )}\n {showPicker && (\n <div className=\"lb-bundle__product-variant-pickers\">\n {optionNames.map((optionName, optionIndex) => {\n const dropdownOptions = optionsFor(optionIndex).map((o) => ({\n value: o.value,\n label: o.value,\n disabled: o.disabled,\n }));\n return (\n <VariantDropdown\n key={optionName}\n options={dropdownOptions}\n value={selectedValues[optionIndex] ?? null}\n onChange={(v) => setOptionValue(optionIndex, v)}\n ariaLabel={optionName}\n />\n );\n })}\n </div>\n )}\n </div>\n </div>\n\n <div\n className=\"lb-bundle__tiers lb-edge-fade\"\n role=\"radiogroup\"\n aria-label=\"Select quantity\"\n ref={tiersEdgeFadeRef}\n >\n {tierSavings.map((ts, tierIndex) => {\n const savingsPercent = Math.round(ts.savingsPercent);\n const showCompare =\n bundle.widgetConfig.pricing.showComparePrice && ts.savings > 0;\n // Checked = this tier is the one the current quantity lands on,\n // matching the single-selection radio the other hosts render.\n const isChecked = activeTier === ts.tier;\n const available = tierAvailable(ts.tier.minQuantity);\n return (\n <div\n key={ts.tier.minQuantity}\n className={`lb-bundle__tier ${ts.isActive ? \"lb-bundle__tier--active\" : \"\"} ${available ? \"\" : \"lb-bundle__tier--oos\"}`}\n role=\"radio\"\n aria-checked={isChecked}\n aria-disabled={available ? undefined : true}\n tabIndex={isChecked ? 0 : -1}\n onClick={() => {\n if (available) setQuantity(ts.tier.minQuantity);\n }}\n onKeyDown={(e) => {\n if ((e.key === \"Enter\" || e.key === \" \") && available) {\n e.preventDefault();\n setQuantity(ts.tier.minQuantity);\n }\n }}\n >\n <span className=\"lb-bundle__tier-radio\" aria-hidden=\"true\">\n <span className=\"lb-bundle__tier-radio-dot\" />\n </span>\n <span className=\"lb-bundle__tier-info\">\n <span className=\"lb-bundle__tier-label\">\n Buy {ts.tier.minQuantity}\n </span>\n <span className=\"lb-bundle__tier-price\">\n {showCompare && (\n <span className=\"lb-bundle__tier-compare\">\n {formatMoney(basePrice, currency)}\n </span>\n )}\n <span>{formatMoney(ts.unitPrice, currency)}</span>\n <span className=\"lb-bundle__tier-unit\">each</span>\n </span>\n </span>\n {(tierIndex === popularTierIndex || savingsPercent > 0) && (\n <span className=\"lb-bundle__tier-right\">\n {tierIndex === popularTierIndex && (\n <span className=\"lb-bundle__tier-badge\">\n {bundle.widgetConfig.popularBadge.text}\n </span>\n )}\n {savingsPercent > 0 && (\n <span className=\"lb-bundle__tier-savings\">\n Save {savingsPercent}%\n </span>\n )}\n </span>\n )}\n </div>\n );\n })}\n </div>\n\n <div className=\"lb-bundle__quantity-selector\">\n <label htmlFor={`lb-qty-${bundle.id}`}>Quantity</label>\n <div className=\"lb-bundle__quantity-control\">\n <button\n aria-label=\"Decrease quantity\"\n onClick={() => setQuantity((q) => Math.max(1, q - 1))}\n >\n −\n </button>\n <input\n id={`lb-qty-${bundle.id}`}\n type=\"number\"\n min={1}\n value={quantity}\n onChange={(e) => {\n const val = parseInt(e.target.value, 10);\n if (!isNaN(val) && val > 0) setQuantity(val);\n }}\n className=\"lb-bundle__quantity-input\"\n />\n <button\n aria-label=\"Increase quantity\"\n onClick={() => setQuantity((q) => q + 1)}\n >\n +\n </button>\n </div>\n </div>\n\n {cartError && (\n <p className=\"lb-bundle__error\" role=\"alert\">\n {cartError}\n </p>\n )}\n\n {bundle &&\n displayVariant &&\n shouldShowLowStockBadge(\n displayVariant,\n minTierQty,\n bundle.widgetConfig.lowStockThreshold,\n bundle.widgetConfig.showLowStockBadge,\n ) && (\n <span className=\"lb-bundle-low-stock-badge\">\n Only {displayVariant.quantityAvailable} left\n </span>\n )}\n\n <div className=\"lb-bundle-divider\" />\n\n <div className=\"lb-bundle-summary\">\n <div className=\"lb-bundle-summary__text\">\n <span className=\"lb-bundle-summary__label\" data-total-label>\n Total\n {bundle.widgetConfig.pricing.showItemCount && (\n <span data-item-count>\n {\" \"}\n ({quantity} item{quantity === 1 ? \"\" : \"s\"})\n </span>\n )}\n </span>\n {bundle.widgetConfig.savingsBar.visible && volumeSavings > 0 && (\n <p className=\"lb-bundle-savings-line\" data-savings-bar>\n You save{\" \"}\n <span data-savings-amount>\n {formatMoney(volumeSavings, currency)}\n </span>{\" \"}\n <span data-savings-percent>({volumeSavingsPercent}%)</span>\n </p>\n )}\n </div>\n <span className=\"lb-bundle-summary__prices\">\n {bundle.widgetConfig.pricing.showComparePrice &&\n volumeSavings > 0 && (\n <span className=\"lb-bundle-compare-price\" data-compare-price>\n {formatMoney(undiscountedTotal, currency)}\n </span>\n )}\n <span className=\"lb-bundle-sale-price\" data-total-price>\n {formatMoney(volumeTotal, currency)}\n </span>\n </span>\n </div>\n\n <button\n className=\"lb-bundle__cta\"\n onClick={handleAddToCart}\n disabled={addingToCart || isSoldOut || selectedTierUnavailable}\n aria-busy={addingToCart}\n >\n {addingToCart\n ? \"Adding...\"\n : isSoldOut || selectedTierUnavailable\n ? \"Sold out\"\n : (bundle.widgetConfig.cta.ctaText ?? `Add ${quantity} to Cart`)}\n </button>\n </div>\n );\n}\n","/**\n * BOGO (Buy X Get Y) bundle component — the shopper buys N units of the buy\n * product and gets M units of the get product at a percent discount\n * (100 = free). Renders a buy card, a \"+\" divider, and a get card wearing\n * the reward badge, with combined one-set pricing and a single CTA that\n * emits both cart lines (merged into one line when both sides resolve to\n * the same variant).\n */\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport {\n formatMoney,\n formatUnitPrice,\n isVariantFulfillable,\n type BogoBundleData,\n type CartLineInput,\n type Product,\n type ProductVariant,\n} from \"@lime-bundles/core\";\nimport { useBundleData } from \"../hooks/useBundleData\";\nimport { useAnalytics } from \"../hooks/useAnalytics\";\nimport { useWidgetConfigVars } from \"../hooks/useWidgetConfigVars\";\nimport { useVariantSelection } from \"../hooks/useVariantSelection\";\nimport { VariantDropdown } from \"./VariantDropdown\";\nimport type { BundleComponentProps } from \"./types\";\nimport { BundleCountdown } from \"./BundleCountdown\";\n\n/** Per-unit discounted price with floor rounding, matching Shopify. */\nfunction discountedUnit(price: number, percent: number): number {\n const cents = Math.round(price * 100);\n const discounted = cents - Math.floor((cents * percent) / 100);\n return discounted / 100;\n}\n\nexport function BogoBundle(props: BundleComponentProps) {\n const {\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n appUrl,\n analyticsEnabled,\n onAddToCart,\n onError,\n className,\n } = props;\n\n const result = useBundleData({\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n });\n\n const { elementRef, trackAddToCart } = useAnalytics({\n shopDomain,\n appUrl: appUrl ?? `https://${shopDomain}`,\n bundleGid,\n bundleType: \"bogo\",\n enabled: analyticsEnabled !== false,\n });\n\n const [addingToCart, setAddingToCart] = useState(false);\n const [cartError, setCartError] = useState<string | null>(null);\n // Selection is keyed by ROLE, not product id — a same-product BOGO\n // renders the one product on both cards with independent dropdowns.\n const [selectedVariants, setSelectedVariants] = useState<{\n buy: ProductVariant | null;\n get: ProductVariant | null;\n }>({ buy: null, get: null });\n\n const handleVariantChange = useCallback(\n (role: \"buy\" | \"get\", variant: ProductVariant | null) => {\n setSelectedVariants((prev) => {\n if (prev[role] === variant) return prev;\n return { ...prev, [role]: variant };\n });\n },\n [],\n );\n\n const bundle =\n result.status === \"success\" && result.bundle.bundleType === \"bogo\"\n ? (result.bundle as BogoBundleData)\n : null;\n\n const setConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);\n\n useEffect(() => {\n if (result.status === \"error\") {\n onError?.(result.error);\n return;\n }\n if (result.status === \"success\" && result.bundle.bundleType !== \"bogo\") {\n onError?.(\n new Error(\n `BogoBundle: expected bundleType=\"bogo\", got \"${result.bundle.bundleType}\"`,\n ),\n );\n }\n }, [result, onError]);\n\n const buyProduct = useMemo(\n () => bundle?.products.find((p) => p.id === bundle.buyProductId) ?? null,\n [bundle],\n );\n const getProduct = useMemo(\n () => bundle?.products.find((p) => p.id === bundle.getProductId) ?? null,\n [bundle],\n );\n\n const percent = bundle\n ? Math.min(100, Math.max(0, bundle.discountConfig.discountValue))\n : 0;\n\n const resolveVariant = useCallback(\n (product: Product | null, selected: ProductVariant | null, qty: number) => {\n if (!product) return null;\n return (\n selected ??\n product.variants.nodes.find((v) => isVariantFulfillable(v, qty)) ??\n product.variants.nodes[0] ??\n null\n );\n },\n [],\n );\n\n /**\n * Sides the store can't supply at the offer's quantities.\n *\n * `resolveVariant` falls back to `variants.nodes[0]` so a price always\n * renders, which meant an out-of-stock side looked normal and add-to-cart\n * shipped an unpurchasable variant that only failed at Shopify. Both sides\n * are required for the offer, so either one short locks the CTA.\n */\n const oosSides = useMemo(() => {\n if (!bundle) return 0;\n const short = (product: Product | null, qty: number) =>\n !!product &&\n !product.variants.nodes.some((v) => isVariantFulfillable(v, qty));\n return (\n (short(buyProduct, bundle.buyQuantity) ? 1 : 0) +\n (short(getProduct, bundle.getQuantity) ? 1 : 0)\n );\n }, [bundle, buyProduct, getProduct]);\n\n const handleAddToCart = useCallback(async () => {\n if (!bundle || !buyProduct || !getProduct) return;\n\n const buyVariant = resolveVariant(buyProduct, selectedVariants.buy, bundle.buyQuantity);\n const getVariant = resolveVariant(getProduct, selectedVariants.get, bundle.getQuantity);\n if (!buyVariant || !getVariant) return;\n\n const attributes = [\n { key: \"_lime_bundle_gid\", value: bundle.id },\n { key: \"_lime_bundle_type\", value: bundle.bundleType },\n ];\n // Same variant on both sides → one merged line so the host cart\n // doesn't show duplicates; checkout math is line-agnostic.\n const lines: CartLineInput[] =\n buyVariant.id === getVariant.id\n ? [\n {\n merchandiseId: buyVariant.id,\n quantity: bundle.buyQuantity + bundle.getQuantity,\n attributes,\n },\n ]\n : [\n {\n merchandiseId: buyVariant.id,\n quantity: bundle.buyQuantity,\n attributes,\n },\n {\n merchandiseId: getVariant.id,\n quantity: bundle.getQuantity,\n attributes,\n },\n ];\n\n setAddingToCart(true);\n setCartError(null);\n try {\n await onAddToCart(lines);\n const buyUnit = parseFloat(buyVariant.price.amount);\n const getUnit = parseFloat(getVariant.price.amount);\n const totalPrice =\n buyUnit * bundle.buyQuantity +\n discountedUnit(getUnit, percent) * bundle.getQuantity;\n trackAddToCart({\n quantity: bundle.buyQuantity + bundle.getQuantity,\n totalPrice: Math.round(totalPrice * 100) / 100,\n });\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setCartError(error.message);\n onError?.(error);\n } finally {\n setAddingToCart(false);\n }\n }, [bundle, buyProduct, getProduct, selectedVariants, resolveVariant, onAddToCart, onError, trackAddToCart, percent]);\n\n if (result.status === \"loading\") {\n return (\n <div className={`lb-bundle lb-bundle--loading ${className ?? \"\"}`}>\n <div className=\"lb-skeleton lb-skeleton--title\" />\n <div className=\"lb-skeleton lb-skeleton--products\" />\n </div>\n );\n }\n\n if (result.status === \"error\") return null;\n if (!bundle || !buyProduct || !getProduct) return null;\n\n const currency =\n bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? \"USD\";\n\n const buyVariant = resolveVariant(buyProduct, selectedVariants.buy, bundle.buyQuantity);\n const getVariant = resolveVariant(getProduct, selectedVariants.get, bundle.getQuantity);\n const buyUnit = buyVariant ? parseFloat(buyVariant.price.amount) : 0;\n const getUnit = getVariant ? parseFloat(getVariant.price.amount) : 0;\n const comparePrice = buyUnit * bundle.buyQuantity + getUnit * bundle.getQuantity;\n const salePrice =\n buyUnit * bundle.buyQuantity +\n discountedUnit(getUnit, percent) * bundle.getQuantity;\n const savings = Math.max(0, comparePrice - salePrice);\n const savingsPercent =\n comparePrice > 0 && savings > 0\n ? Math.round((savings / comparePrice) * 100)\n : 0;\n const showCompare =\n bundle.widgetConfig.pricing.showComparePrice && savings > 0;\n const showSavings = bundle.widgetConfig.savingsBar.visible && savings > 0;\n const badge = percent === 100 ? \"Free\" : `${percent}% off`;\n\n return (\n <div\n ref={(el) => {\n elementRef(el);\n setConfigVarsRef(el);\n }}\n className={`lb-bundle lb-bundle--bogo ${className ?? \"\"}`}\n role=\"region\"\n aria-label={bundle.title}\n >\n <div className=\"lb-bundle-header\">\n <div className=\"lb-bundle-header__content\">\n <h3 className=\"lb-bundle-title\">{bundle.title}</h3>\n {bundle.description && (\n <p className=\"lb-bundle-subtitle\">{bundle.description}</p>\n )}\n </div>\n </div>\n\n <BundleCountdown\n endsAt={bundle.endsAt}\n widgetConfig={bundle.widgetConfig}\n />\n\n <div className=\"lb-bundle__products\">\n <BogoProductRow\n side=\"buy\"\n product={buyProduct}\n quantity={bundle.buyQuantity}\n percent={percent}\n badge={null}\n currency={currency}\n onVariantChange={handleVariantChange}\n />\n <div className=\"lb-bogo__plus\" aria-hidden=\"true\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 18 18\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <line x1=\"9\" y1=\"3\" x2=\"9\" y2=\"15\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n <line x1=\"3\" y1=\"9\" x2=\"15\" y2=\"9\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n </div>\n <BogoProductRow\n side=\"get\"\n product={getProduct}\n quantity={bundle.getQuantity}\n percent={percent}\n badge={badge}\n currency={currency}\n onVariantChange={handleVariantChange}\n />\n </div>\n\n <div className=\"lb-bundle-divider\" />\n\n <div className=\"lb-bundle-summary\">\n <div className=\"lb-bundle-summary__text\">\n <span className=\"lb-bundle-summary__label\">Bundle total</span>\n {showSavings && (\n <p className=\"lb-bundle-savings-line\" data-savings-bar>\n You save{\" \"}\n <span data-savings-amount>{formatMoney(savings, currency)}</span>{\" \"}\n <span data-savings-percent>({savingsPercent}%)</span>\n </p>\n )}\n </div>\n <span className=\"lb-bundle-summary__prices\">\n {showCompare && (\n <span className=\"lb-bundle-compare-price\" data-compare-price>\n {formatMoney(comparePrice, currency)}\n </span>\n )}\n <span className=\"lb-bundle-sale-price\" data-sale-price>\n {formatMoney(salePrice, currency)}\n </span>\n </span>\n </div>\n\n {cartError && (\n <p className=\"lb-bundle__error\" role=\"alert\">\n {cartError}\n </p>\n )}\n\n <button\n className=\"lb-bundle__cta\"\n onClick={handleAddToCart}\n disabled={addingToCart || oosSides > 0}\n aria-busy={addingToCart}\n >\n {addingToCart\n ? \"Adding...\"\n : oosSides > 0\n ? `${oosSides} item${oosSides === 1 ? \"\" : \"s\"} unavailable`\n : (bundle.widgetConfig.cta.ctaText ?? \"Add Bundle to Cart\")}\n </button>\n </div>\n );\n}\n\ninterface BogoProductRowProps {\n side: \"buy\" | \"get\";\n product: Product;\n quantity: number;\n percent: number;\n /** Reward badge text; null on the buy row. */\n badge: string | null;\n currency: string;\n onVariantChange: (role: \"buy\" | \"get\", variant: ProductVariant | null) => void;\n}\n\nfunction BogoProductRow({ side, product, quantity, percent, badge, currency, onVariantChange }: BogoProductRowProps) {\n const variants = product.variants.nodes;\n const optionNames = useMemo<string[]>(() => {\n const first = variants[0];\n return first ? first.selectedOptions.map((o) => o.name) : [];\n }, [variants]);\n\n const showPicker = variants.length > 1 && optionNames.length > 0;\n\n const { selectedValues, selectedVariant, setOptionValue, optionsFor } =\n useVariantSelection({\n variants,\n optionNames,\n });\n\n useEffect(() => {\n onVariantChange(side, selectedVariant ?? null);\n }, [selectedVariant, side, onVariantChange]);\n\n const displayVariant =\n selectedVariant ??\n variants.find((v) => isVariantFulfillable(v, quantity)) ??\n variants[0];\n const unit = displayVariant ? parseFloat(displayVariant.price.amount) : 0;\n const isGet = side === \"get\" && percent > 0;\n const priceText = isGet\n ? formatMoney(discountedUnit(unit, percent), currency)\n : formatMoney(unit, currency);\n // Get row strikes its own original price (the reward); buy row shows a\n // regular compare-at when the variant has one.\n const compareAt = isGet\n ? formatMoney(unit, currency)\n : displayVariant?.compareAtPrice &&\n parseFloat(displayVariant.compareAtPrice.amount) > unit\n ? formatMoney(displayVariant.compareAtPrice.amount, currency)\n : null;\n const unitPriceText = displayVariant\n ? formatUnitPrice(\n displayVariant.unitPrice,\n displayVariant.unitPriceMeasurement,\n currency,\n )\n : null;\n\n const thumbImage = displayVariant?.image ?? product.featuredImage;\n\n return (\n <div className=\"lb-bundle-product-row\" part=\"product\" data-bogo-role={side}>\n {thumbImage && (\n <img\n src={thumbImage.url}\n alt={thumbImage.altText ?? product.title}\n className=\"lb-bundle__product-image\"\n loading=\"lazy\"\n // Intrinsic dimensions reserve the \"original\"-ratio box pre-load\n // (issue #302); inert for the cropped ratios, where CSS sizes it.\n width={thumbImage.width ?? undefined}\n height={thumbImage.height ?? undefined}\n />\n )}\n <div className=\"lb-bundle__product-info\">\n <p className=\"lb-bundle__product-title\">{product.title}</p>\n {!showPicker && displayVariant && variants.length > 1 && (\n <span className=\"lb-bundle-variant-badge\">\n {displayVariant.title}\n </span>\n )}\n <span className=\"lb-bundle-product-prices\">\n {compareAt && (\n <span\n className=\"lb-bundle-product-compare-price\"\n data-product-compare-price\n >\n {compareAt}\n </span>\n )}\n <span className=\"lb-bundle__product-price\" data-product-price>\n {priceText}\n </span>\n {/* Right-slot rule (WIDGET-DESIGN.md): the get card's corner holds\n the reward badge, so BOGO counts render inline on both cards. */}\n <span className=\"lb-bundle-qty-inline\" data-qty-inline>\n &times;{quantity}\n </span>\n </span>\n {unitPriceText && (\n <span\n className=\"lb-bundle__product-unit-price\"\n data-product-unit-price\n >\n {unitPriceText}\n </span>\n )}\n {showPicker && (\n <div className=\"lb-bundle__product-variant-pickers\">\n {optionNames.map((optionName, optionIndex) => {\n const dropdownOptions = optionsFor(optionIndex).map((o) => ({\n value: o.value,\n label: o.value,\n disabled: o.disabled,\n }));\n return (\n <VariantDropdown\n key={optionName}\n options={dropdownOptions}\n value={selectedValues[optionIndex] ?? null}\n onChange={(v) => setOptionValue(optionIndex, v)}\n ariaLabel={optionName}\n />\n );\n })}\n </div>\n )}\n </div>\n {badge && <span className=\"lb-bogo__badge\">{badge}</span>}\n </div>\n );\n}\n","/**\n * Multi-step bundle component.\n *\n * The customer walks named steps (\"Pick a shampoo\" → \"Pick a conditioner\")\n * through the mix & match picker modal presented as a WIZARD (Back / Next /\n * Done). Each step scopes the picker to its own product pool\n * (`productsForStep`) and carries its own min/max unit bounds; the CTA\n * enables when every step's minimum is met and the whole-bundle discount\n * applies to the combined total.\n *\n * Shared rules with the theme widget (`bundle-multi-step.js`):\n * - Picks are VARIANT-scoped per step: each (step, product, variant)\n * triple holds at most one slot.\n * - rule.min is a per-pick floor; rule.max caps the product's TOTAL\n * units across every slot in every step.\n * - Stock accounting sums a variant's units across ALL steps.\n * - Step maxQuantity (null = unlimited) bounds the step's unit total.\n *\n * The UX mirrors `extensions/bundle-theme/snippets/lb-multi-step.liquid`\n * one-for-one: overall segmented progress, per-step groups (heading button\n * reopens the wizard at that step, live \"x of n\" chip, chosen cards), a\n * single dashed \"Build your bundle\" trigger, receipt summary + CTA. See\n * `MultiStepPicker.tsx` for the wizard modal.\n */\nimport { Fragment, useCallback, useEffect, useMemo, useState } from \"react\";\nimport {\n formatMoney,\n formatUnitPrice,\n calculateDiscount,\n isVariantFulfillable,\n productsForStep,\n DEFAULT_PRODUCT_RULE,\n type CartLineInput,\n type MultiStepBundleData,\n type ProductRule,\n} from \"@lime-bundles/core\";\nimport { useBundleData } from \"../hooks/useBundleData\";\nimport { useAnalytics } from \"../hooks/useAnalytics\";\nimport { useWidgetConfigVars } from \"../hooks/useWidgetConfigVars\";\nimport { MultiStepPicker } from \"./MultiStepPicker\";\nimport type { SelectedItem } from \"./mix-match-types\";\nimport type { BundleComponentProps } from \"./types\";\nimport { BundleCountdown } from \"./BundleCountdown\";\n\n/**\n * The rule in force for a pick. Pass `variantId` and the variant's own rule\n * wins; without one this resolves the product rule, which is the envelope\n * covering every variant.\n */\nfunction ruleFor(\n bundle: MultiStepBundleData,\n productId: string,\n variantId?: string | null,\n): ProductRule {\n if (variantId) {\n const vRule = bundle.variantRules[variantId];\n if (vRule) return vRule;\n }\n return bundle.productRules[productId] ?? DEFAULT_PRODUCT_RULE;\n}\n\n/**\n * The variant's OWN rule, or undefined when it inherits the product's.\n * Distinct from `ruleFor`, which falls back — conflating the two would make\n * every variant of a required product unremovable.\n */\nfunction variantRuleFor(\n bundle: MultiStepBundleData,\n variantId: string | null | undefined,\n): ProductRule | undefined {\n return variantId ? bundle.variantRules[variantId] : undefined;\n}\n\n/**\n * PRODUCT-LEVEL lock for required products, STEP-AGNOSTIC like the rules\n * themselves (and the discount function's check): removing a pick is\n * allowed only while the product's other slots — in any step — keep it at\n * or above rule.min. This is what lets shoppers swap variants without ever\n * dropping the required product out of the bundle. *\n * A required VARIANT is stricter and needs no tally: slots are one per\n * (product, variant), so it has no other slot to fall back on and no sibling\n * may stand in for it. Naming the variant is what takes the swap off the\n * table.\n */\nfunction canRemoveItem(\n bundle: MultiStepBundleData,\n selections: SelectedItem[][],\n item: SelectedItem,\n): boolean {\n if (variantRuleFor(bundle, item.variantId)?.required) return false;\n\n const rule = ruleFor(bundle, item.productId);\n if (!rule.required) return true;\n let unitsElsewhere = 0;\n for (const stepPicks of selections) {\n for (const s of stepPicks) {\n if (s.productId === item.productId && s !== item) {\n unitsElsewhere += s.quantity;\n }\n }\n }\n return unitsElsewhere >= rule.min;\n}\n\n/**\n * ATOMIC VARIANT SWAP, scoped to ONE step. A hard-capped required product\n * (rule.min === rule.max) has no headroom for the add-then-remove variant\n * swap the product-level lock normally allows, so the wizard button\n * becomes \"Swap\": the new variant's units displace sibling-variant units\n * of the same product IN THE SAME STEP. Cross-step displacement is\n * deliberately off the table — it would drain another step below its\n * minimum. Returns the in-step units available to take over, or 0 when\n * the row isn't in the swap state.\n */\nfunction swapUnitsForItem(\n bundle: MultiStepBundleData,\n selections: SelectedItem[][],\n step: number,\n productId: string,\n variantId: string,\n): number {\n const rule = ruleFor(bundle, productId);\n if (!rule.required || rule.max !== rule.min) return 0;\n const stepPicks = selections[step] ?? [];\n if (stepPicks.some((s) => s.variantId === variantId)) return 0;\n return stepPicks\n .filter((s) => s.productId === productId && s.variantId !== variantId)\n .reduce((sum, s) => sum + s.quantity, 0);\n}\n\nexport function MultiStepBundle(props: BundleComponentProps) {\n const {\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n appUrl,\n analyticsEnabled,\n onAddToCart,\n onError,\n className,\n } = props;\n\n const result = useBundleData({\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n });\n\n const { elementRef, trackAddToCart } = useAnalytics({\n shopDomain,\n appUrl: appUrl ?? `https://${shopDomain}`,\n bundleGid,\n bundleType: \"multi_step\",\n enabled: analyticsEnabled !== false,\n });\n\n // Per-step selections: selections[i] = ordered variant-scoped picks of\n // step i. Mirrors the theme's `selections` array-of-arrays.\n const [selections, setSelections] = useState<SelectedItem[][]>([]);\n /** Step index the wizard is open at, or null when closed. */\n const [pickerOpenAt, setPickerOpenAt] = useState<number | null>(null);\n const [addingToCart, setAddingToCart] = useState(false);\n const [cartError, setCartError] = useState<string | null>(null);\n\n const bundle =\n result.status === \"success\" && result.bundle.bundleType === \"multi_step\"\n ? (result.bundle as MultiStepBundleData)\n : null;\n\n // Apply merchant-config CSS vars to the widget root + the portaled modal.\n const setConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);\n const setModalConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);\n\n useEffect(() => {\n if (result.status === \"error\") {\n onError?.(result.error);\n return;\n }\n if (\n result.status === \"success\" &&\n result.bundle.bundleType !== \"multi_step\"\n ) {\n onError?.(\n new Error(\n `MultiStepBundle: expected bundleType=\"multi_step\", got \"${result.bundle.bundleType}\"`,\n ),\n );\n }\n }, [result, onError]);\n\n const steps = useMemo(() => bundle?.steps ?? [], [bundle]);\n\n // Size the per-step selection arrays once the bundle arrives, pre-seeding\n // one pick per REQUIRED product into the FIRST step whose pool holds it\n // (first fulfillable variant at rule.min). Seeds count toward that step's\n // minimum and can never drop the product below rule.min (canRemoveItem).\n useEffect(() => {\n const seeded: SelectedItem[][] = steps.map(() => []);\n if (bundle) {\n const seedCurrency =\n bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? \"USD\";\n for (const [pid, rule] of Object.entries(bundle.productRules)) {\n if (!rule.required) continue;\n for (let i = 0; i < steps.length; i++) {\n const product = productsForStep(bundle, i).find((p) => p.id === pid);\n const variant = product?.variants.nodes.find((v) =>\n isVariantFulfillable(v, rule.min),\n );\n if (!product || !variant) continue;\n seeded[i].push({\n productId: product.id,\n variantId: variant.id,\n title: product.title,\n url: `/products/${product.handle}`,\n variantTitle: variant.title,\n featuredImage:\n variant.image?.url ?? product.featuredImage?.url ?? null,\n price: parseFloat(variant.price.amount),\n compareAtPrice: variant.compareAtPrice\n ? parseFloat(variant.compareAtPrice.amount)\n : null,\n unitPrice: formatUnitPrice(\n variant.unitPrice,\n variant.unitPriceMeasurement,\n seedCurrency,\n ),\n quantity: rule.min,\n });\n break;\n }\n }\n }\n setSelections(seeded);\n }, [bundle, steps]);\n\n const showStepper =\n bundle?.widgetConfig.mixMatchShowQuantitySelector !== false;\n\n /** Overall requirement — sum of step minimums. */\n const totalMin = useMemo(\n () => steps.reduce((sum, s) => sum + s.minQuantity, 0),\n [steps],\n );\n\n const unitsByStep = useMemo(\n () => selections.map((picks) => picks.reduce((sum, s) => sum + s.quantity, 0)),\n [selections],\n );\n const totalQuantity = useMemo(\n () => unitsByStep.reduce((sum, u) => sum + u, 0),\n [unitsByStep],\n );\n const stepSatisfied = useCallback(\n (i: number) => (unitsByStep[i] ?? 0) >= (steps[i]?.minQuantity ?? 1),\n [unitsByStep, steps],\n );\n const allSatisfied =\n steps.length > 0 && steps.every((_, i) => stepSatisfied(i));\n\n const valid = !!bundle && allSatisfied;\n // Overall progress counts completed STEPS (unit detail lives on the\n // per-step chips).\n const completedSteps = steps.filter((_, i) => stepSatisfied(i)).length;\n // The door sits directly above the first unsatisfied step (-1 = none:\n // the door disappears and the CTA is the remaining action).\n const firstUnsatisfied = steps.findIndex((_, i) => !stepSatisfied(i));\n const remainingSteps = steps.length - completedSteps;\n const anyPicks = selections.some((s) => s.length > 0);\n\n // Running receipt totals from all steps' selections.\n const summary = useMemo(() => {\n let comparePrice = 0;\n let salePrice = 0;\n for (const stepPicks of selections) {\n for (const sel of stepPicks) {\n if (sel.quantity <= 0) continue;\n comparePrice += sel.price * sel.quantity;\n if (bundle) {\n salePrice +=\n calculateDiscount(\n sel.price,\n bundle.discountConfig.discountType,\n bundle.discountConfig.discountValue,\n ) * sel.quantity;\n }\n }\n }\n const savings = Math.max(0, comparePrice - salePrice);\n const savingsPercent =\n comparePrice > 0 && savings > 0\n ? Math.round((savings / comparePrice) * 100)\n : 0;\n return { comparePrice, salePrice, savings, savingsPercent };\n }, [selections, bundle]);\n\n const addSelection = useCallback((step: number, item: SelectedItem) => {\n setSelections((prev) => {\n if (step < 0 || step >= prev.length) return prev;\n // Slots are variant-scoped WITHIN a step: refuse a duplicate of an\n // already-committed variant in this step (the row shows the Added\n // toggle for it instead). The same variant may hold slots in other\n // steps.\n if (prev[step].some((s) => s.variantId === item.variantId)) return prev;\n const next = prev.slice();\n next[step] = [...next[step], item];\n return next;\n });\n }, []);\n\n // ATOMIC VARIANT SWAP for hard-capped required products: replace units\n // of the product's other-variant picks IN THE SAME STEP with the new\n // variant. The step total never moves, so the required floor, the hard\n // cap, and the step's own min/max all hold throughout — which is why\n // this bypasses the canRemoveItem guard (the swap is exactly what that\n // guard exists to enable).\n const swapSelection = useCallback(\n (step: number, item: SelectedItem) => {\n setSelections((prev) => {\n if (!bundle || step < 0 || step >= prev.length) return prev;\n const swapUnits = swapUnitsForItem(\n bundle,\n prev,\n step,\n item.productId,\n item.variantId,\n );\n if (swapUnits <= 0) return prev;\n const qty = Math.min(Math.max(1, item.quantity), swapUnits);\n let freed = 0;\n const stepPicks: SelectedItem[] = [];\n for (const s of prev[step]) {\n if (\n freed < qty &&\n s.productId === item.productId &&\n s.variantId !== item.variantId\n ) {\n const take = Math.min(s.quantity, qty - freed);\n freed += take;\n if (s.quantity > take) {\n stepPicks.push({ ...s, quantity: s.quantity - take });\n }\n } else {\n stepPicks.push(s);\n }\n }\n if (freed === 0) return prev;\n stepPicks.push({ ...item, quantity: freed });\n const next = prev.slice();\n next[step] = stepPicks;\n return next;\n });\n },\n [bundle],\n );\n\n // LIVE EDIT of a committed pick's quantity within a step.\n const updateQuantity = useCallback(\n (step: number, productId: string, variantId: string, quantity: number) => {\n setSelections((prev) => {\n if (step < 0 || step >= prev.length) return prev;\n const idx = prev[step].findIndex(\n (s) => s.productId === productId && s.variantId === variantId,\n );\n if (idx === -1) return prev;\n const clamped = Math.max(1, quantity);\n if (clamped === prev[step][idx].quantity) return prev;\n const next = prev.slice();\n const stepPicks = next[step].slice();\n stepPicks[idx] = { ...stepPicks[idx], quantity: clamped };\n next[step] = stepPicks;\n return next;\n });\n },\n [],\n );\n\n // Remove the slot holding a variant in a step (the picker's Added toggle).\n const removeVariant = useCallback(\n (step: number, variantId: string) => {\n setSelections((prev) => {\n if (step < 0 || step >= prev.length) return prev;\n const idx = prev[step].findIndex((s) => s.variantId === variantId);\n if (idx === -1) return prev;\n if (bundle && !canRemoveItem(bundle, prev, prev[step][idx])) return prev;\n const next = prev.slice();\n const stepPicks = next[step].slice();\n stepPicks.splice(idx, 1);\n next[step] = stepPicks;\n return next;\n });\n },\n [bundle],\n );\n\n const removeSlot = useCallback(\n (step: number, index: number) => {\n setSelections((prev) => {\n if (step < 0 || step >= prev.length) return prev;\n if (index < 0 || index >= prev[step].length) return prev;\n if (bundle && !canRemoveItem(bundle, prev, prev[step][index]))\n return prev;\n const next = prev.slice();\n const stepPicks = next[step].slice();\n stepPicks.splice(index, 1);\n next[step] = stepPicks;\n return next;\n });\n },\n [bundle],\n );\n\n const handleAddToCart = useCallback(async () => {\n if (!bundle || !valid) return;\n\n // Flatten selections across steps, merging same-variant picks into one\n // cart line (matches the discount function, which sees cart lines, not\n // steps).\n const grouped = new Map<string, { variantId: string; quantity: number }>();\n for (const stepPicks of selections) {\n for (const sel of stepPicks) {\n if (sel.quantity <= 0) continue;\n const existing = grouped.get(sel.variantId);\n if (existing) existing.quantity += sel.quantity;\n else grouped.set(sel.variantId, { variantId: sel.variantId, quantity: sel.quantity });\n }\n }\n\n const lines: CartLineInput[] = Array.from(grouped.values()).map((line) => ({\n merchandiseId: line.variantId,\n quantity: line.quantity,\n attributes: [\n { key: \"_lime_bundle_gid\", value: bundle.id },\n { key: \"_lime_bundle_type\", value: bundle.bundleType },\n ],\n }));\n\n setAddingToCart(true);\n setCartError(null);\n try {\n await onAddToCart(lines);\n\n const totalPrice = selections.reduce(\n (sum, stepPicks) =>\n sum +\n stepPicks.reduce((s, sel) => s + sel.price * sel.quantity, 0),\n 0,\n );\n trackAddToCart({\n quantity: totalQuantity,\n totalPrice: Math.round(totalPrice * 100) / 100,\n });\n\n setSelections(steps.map(() => []));\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setCartError(error.message);\n onError?.(error);\n } finally {\n setAddingToCart(false);\n }\n }, [bundle, selections, valid, onAddToCart, onError, trackAddToCart, totalQuantity, steps]);\n\n if (result.status === \"loading\") {\n return (\n <div className={`lb-bundle lb-bundle--loading ${className ?? \"\"}`}>\n <div className=\"lb-skeleton lb-skeleton--title\" />\n <div className=\"lb-skeleton lb-skeleton--products\" />\n </div>\n );\n }\n\n if (result.status === \"error\") return null;\n if (!bundle || steps.length === 0) return null;\n\n // Bundle visibility guard: every step needs at least one in-stock\n // product — mirrors the Liquid widget's `every_step_available` gate.\n for (let i = 0; i < steps.length; i++) {\n if (!stepHasInStockProduct(bundle, i)) return null;\n }\n\n // A required product with no purchasable variant in any of its steps\n // means the bundle can never qualify at checkout — don't render (guards\n // the gap between a live stock drop and the webhook's status flip).\n const requiredBlocked = Object.entries(bundle.productRules).some(\n ([pid, rule]) => {\n if (!rule.required) return false;\n return !steps.some((_, i) =>\n productsForStep(bundle, i).some(\n (p) =>\n p.id === pid &&\n p.variants.nodes.some((v) => isVariantFulfillable(v, rule.min)),\n ),\n );\n },\n );\n if (requiredBlocked) return null;\n\n const currency =\n bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? \"USD\";\n\n // Label stays \"Add to cart\" (or the merchant's custom text) throughout;\n // only the disabled state tracks step satisfaction.\n const ctaLabel = addingToCart\n ? \"Adding...\"\n : bundle.widgetConfig.cta.ctaText || \"Add to cart\";\n\n return (\n <div\n ref={(el) => {\n elementRef(el);\n setConfigVarsRef(el);\n }}\n className={`lb-bundle lb-bundle--multi-step lb-mix-match lb-multi-step ${className ?? \"\"}`}\n role=\"region\"\n aria-label={bundle.title}\n data-required-quantity={totalMin}\n >\n <div className=\"lb-bundle-header\">\n <div className=\"lb-bundle-header__content\">\n <h3 className=\"lb-bundle-title\">{bundle.title}</h3>\n {bundle.description && (\n <p className=\"lb-bundle-subtitle\">{bundle.description}</p>\n )}\n </div>\n </div>\n\n <BundleCountdown\n endsAt={bundle.endsAt}\n widgetConfig={bundle.widgetConfig}\n />\n\n {/* Overall progress is STEP-based: one segment per step, filled as\n its minimum is met (unit detail lives on the per-step chips). */}\n <div className=\"lb-mix-match__progress\" data-progress>\n <div\n className=\"lb-mix-match__progress-segments\"\n role=\"progressbar\"\n aria-valuenow={completedSteps}\n aria-valuemin={0}\n aria-valuemax={steps.length}\n >\n {Array.from({ length: steps.length }).map((_, i) => (\n <span\n key={i}\n className={`lb-mix-match__progress-segment${i < completedSteps ? \" lb-mix-match__progress-segment--filled\" : \"\"}`}\n data-progress-segment\n />\n ))}\n </div>\n <div className=\"lb-mix-match__progress-labels\">\n <span\n className=\"lb-mix-match__progress-count\"\n data-progress-count\n aria-live=\"polite\"\n >\n {`${completedSteps} of ${steps.length} steps completed`}\n </span>\n <span\n className=\"lb-mix-match__progress-remaining\"\n data-progress-remaining\n aria-live=\"polite\"\n >\n {completedSteps < steps.length\n ? `${steps.length - completedSteps} more to go`\n : \"Complete\"}\n </span>\n </div>\n </div>\n\n {/* One dashed door plus one section per step. A step without picks is\n a slim checklist row (tap deep-links the wizard to that step); a\n step with picks shows the heading + chosen cards. The door sits\n directly above the first unsatisfied step and disappears once all\n are met. data-step-mode drives the shared spacing rules. */}\n <div className=\"lb-multi-step__groups\" data-step-groups>\n {steps.map((step, i) => (\n <Fragment key={i}>\n {i === firstUnsatisfied && (\n <button\n type=\"button\"\n className=\"lb-mix-match__add-product lb-multi-step__door\"\n data-step-door={firstUnsatisfied}\n aria-label={`${anyPicks ? \"Continue building\" : \"Choose your products\"}: ${step.name}`}\n onClick={() => setPickerOpenAt(firstUnsatisfied)}\n >\n <span\n className=\"lb-mix-match__add-product-icon\"\n aria-hidden=\"true\"\n >\n <PlusIcon />\n </span>\n <span className=\"lb-multi-step__door-copy\">\n <span className=\"lb-mix-match__add-product-label\">\n {anyPicks ? \"Continue building\" : \"Choose your products\"}\n </span>\n <span className=\"lb-multi-step__door-sub\">\n {anyPicks\n ? `${remainingSteps} ${remainingSteps === 1 ? \"step\" : \"steps\"} to go`\n : `${steps.length} quick ${steps.length === 1 ? \"step\" : \"steps\"}`}\n </span>\n </span>\n </button>\n )}\n {(selections[i] ?? []).length === 0 ? (\n <section\n className=\"lb-multi-step__group\"\n data-step-group={i}\n data-step-mode=\"row\"\n >\n <button\n type=\"button\"\n className=\"lb-multi-step__step-row\"\n data-step-row={i}\n aria-label={`${step.minQuantity === 1 && step.maxQuantity === 1 ? \"Choose a product\" : \"Choose products\"}: ${step.name}`}\n onClick={() => setPickerOpenAt(i)}\n >\n <span\n className=\"lb-multi-step__step-ix\"\n aria-hidden=\"true\"\n >\n {i + 1}\n </span>\n <span className=\"lb-multi-step__group-name\">\n {step.name}\n </span>\n <span\n className={`lb-multi-step__group-count${stepSatisfied(i) ? \" lb-multi-step__group-count--met\" : \"\"}`}\n data-step-count={i}\n >\n {`${Math.min(unitsByStep[i] ?? 0, step.minQuantity)} of ${step.minQuantity} added`}\n </span>\n </button>\n </section>\n ) : (\n <section\n className=\"lb-multi-step__group\"\n data-step-group={i}\n data-step-mode=\"open\"\n >\n <div className=\"lb-multi-step__group-heading\">\n <span className=\"lb-multi-step__group-name\">{step.name}</span>\n <span\n className={`lb-multi-step__group-count${stepSatisfied(i) ? \" lb-multi-step__group-count--met\" : \"\"}`}\n data-step-count={i}\n >\n {`${Math.min(unitsByStep[i] ?? 0, step.minQuantity)} of ${step.minQuantity} added`}\n </span>\n </div>\n <div\n className=\"lb-mix-match__slots lb-edge-fade lb-multi-step__group-slots\"\n data-step-slots={i}\n >\n {(selections[i] ?? []).map((item, index) => (\n /* Whole card reopens the wizard AT this step. The inner\n title button provides the keyboard/AT path (its\n activation bubbles here); × stops propagation. */\n // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions -- keyboard path is the inner \"Edit selection\" title button whose activation bubbles to this handler\n <div\n key={`${item.productId}:${item.variantId}:${index}`}\n className=\"lb-mix-match__slot lb-mix-match__slot--filled\"\n onClick={() => setPickerOpenAt(i)}\n >\n {item.featuredImage && (\n <div className=\"lb-bundle-thumbnail\">\n <img\n src={item.featuredImage}\n alt={item.title}\n loading=\"lazy\"\n />\n </div>\n )}\n <div className=\"lb-mix-match__filled-info\">\n <button\n type=\"button\"\n className=\"lb-mix-match__filled-title\"\n aria-label={`Edit selection: ${item.title}`}\n >\n {item.title}\n </button>\n {item.variantTitle &&\n item.variantTitle !== \"Default Title\" && (\n <span className=\"lb-mix-match__filled-variant\">\n {item.variantTitle}\n </span>\n )}\n <span className=\"lb-mix-match__filled-price\">\n {item.compareAtPrice !== null &&\n item.compareAtPrice > item.price && (\n <s className=\"lb-mix-match__filled-compare\">\n {formatMoney(item.compareAtPrice, currency)}\n </s>\n )}\n <span className=\"lb-bundle-product-price\">\n {formatMoney(item.price, currency)}\n </span>\n <span className=\"lb-bundle-qty-inline\">{`×${item.quantity}`}</span>\n </span>\n {item.unitPrice && (\n <span className=\"lb-bundle-product-unit-price\">\n {item.unitPrice}\n </span>\n )}\n </div>\n {canRemoveItem(bundle, selections, item) ? (\n <button\n type=\"button\"\n className=\"lb-mix-match__slot-remove\"\n aria-label={`Remove ${item.title}`}\n onClick={(e) => {\n e.stopPropagation();\n removeSlot(i, index);\n }}\n >\n <CloseIcon />\n </button>\n ) : (\n /* Required pick at its floor — quiet state chip instead\n of the ×; removal returns once another slot covers\n the product's minimum (variant swap flow). */\n <span className=\"lb-mix-match__slot-required\">\n Required\n </span>\n )}\n </div>\n ))}\n </div>\n </section>\n )}\n </Fragment>\n ))}\n </div>\n\n <div className=\"lb-bundle-divider\" />\n\n {/* Whole-bundle pricing — shown once every step's minimum is met. */}\n {allSatisfied && (\n <div className=\"lb-bundle-summary\" data-pricing-section>\n <div className=\"lb-bundle-summary__text\">\n <span className=\"lb-bundle-summary__label\">Bundle total</span>\n {bundle.widgetConfig.savingsBar.visible && summary.savings > 0 && (\n <p className=\"lb-bundle-savings-line\" data-savings-bar>\n You save{\" \"}\n <span data-savings-amount>\n {formatMoney(summary.savings, currency)}\n </span>{\" \"}\n <span data-savings-percent>({summary.savingsPercent}%)</span>\n </p>\n )}\n </div>\n <span className=\"lb-bundle-summary__prices\">\n {bundle.widgetConfig.pricing.showComparePrice &&\n summary.savings > 0 && (\n <span className=\"lb-bundle-compare-price\" data-compare-price>\n {formatMoney(summary.comparePrice, currency)}\n </span>\n )}\n <span className=\"lb-bundle-sale-price\" data-sale-price>\n {formatMoney(summary.salePrice, currency)}\n </span>\n </span>\n </div>\n )}\n\n {cartError && (\n <p className=\"lb-bundle__error\" role=\"alert\">\n {cartError}\n </p>\n )}\n\n <button\n className=\"lb-bundle__cta\"\n onClick={handleAddToCart}\n disabled={addingToCart || !valid}\n aria-busy={addingToCart}\n >\n {ctaLabel}\n </button>\n\n {pickerOpenAt !== null && (\n <MultiStepPicker\n bundle={bundle}\n currency={currency}\n initialStep={pickerOpenAt}\n showStepper={showStepper}\n selections={selections}\n onAdd={addSelection}\n onUpdateQuantity={updateQuantity}\n onRemoveVariant={removeVariant}\n canRemoveVariant={(variantId) => {\n for (const stepPicks of selections) {\n const item = stepPicks.find((p) => p.variantId === variantId);\n if (item) return canRemoveItem(bundle, selections, item);\n }\n return true;\n }}\n swapUnitsFor={(step, productId, variantId) =>\n swapUnitsForItem(bundle, selections, step, productId, variantId)\n }\n onSwap={swapSelection}\n onClose={() => setPickerOpenAt(null)}\n styleVarsRef={setModalConfigVarsRef}\n />\n )}\n </div>\n );\n}\n\n/** True when the step's pool has at least one product with a variant that\n * can fulfil that product's rule.min. */\nfunction stepHasInStockProduct(\n bundle: MultiStepBundleData,\n stepIndex: number,\n): boolean {\n return productsForStep(bundle, stepIndex).some((product) => {\n const rule = ruleFor(bundle, product.id);\n return product.variants.nodes.some((v) => isVariantFulfillable(v, rule.min));\n });\n}\n\nfunction PlusIcon() {\n return (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 18 18\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <line x1=\"9\" y1=\"3\" x2=\"9\" y2=\"15\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n <line x1=\"3\" y1=\"9\" x2=\"15\" y2=\"9\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n\nfunction CloseIcon() {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <line x1=\"5\" y1=\"5\" x2=\"15\" y2=\"15\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n <line x1=\"15\" y1=\"5\" x2=\"5\" y2=\"15\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n","/**\n * Multi-step wizard picker modal — the mix & match picker presented one\n * step at a time (\"Step 2 of 3 · Pick a conditioner\") with Back / Next in\n * the footer and Done on the last step. Portaled to `document.body` so its\n * `position: fixed` overlay isn't clipped by a parent's `transform` /\n * `contain` (common in Shopify themes).\n *\n * Markup, class names and behaviour mirror the storefront theme widget\n * (`extensions/bundle-theme/snippets/lb-multi-step.liquid` +\n * `extensions/bundle-theme/assets/bundle-multi-step.js`) one-for-one so\n * the ported CSS styles this tree without changes. Wizard rules:\n * - the product list, filter pills, and modal progress segments rebuild\n * per step (that step's pool and minimum);\n * - Next is disabled until the current step's minimum is met; Back is\n * hidden on step 1; Done (last step) closes the wizard;\n * - picks are variant-scoped per step; rule.max and stock account\n * across every step's slots.\n */\nimport {\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport {\n formatMoney,\n formatUnitPrice,\n isVariantFulfillable,\n maxAddableQuantity,\n productsForStep,\n stepHeadroom,\n DEFAULT_PRODUCT_RULE,\n type MultiStepBundleData,\n type Product,\n type ProductRule,\n type ProductVariant,\n} from \"@lime-bundles/core\";\nimport { VariantDropdown } from \"./VariantDropdown\";\nimport { useVariantSelection } from \"../hooks/useVariantSelection\";\nimport { useScrollLock } from \"../hooks/useScrollLock\";\nimport { useFocusTrap } from \"../hooks/useFocusTrap\";\nimport type { SelectedItem } from \"./mix-match-types\";\n\n/**\n * The rule in force for a pick. Pass `variantId` and the variant's own rule\n * wins; without one this resolves the product rule, which is the envelope\n * covering every variant.\n */\nfunction ruleFor(\n bundle: MultiStepBundleData,\n productId: string,\n variantId?: string | null,\n): ProductRule {\n if (variantId) {\n const vRule = bundle.variantRules[variantId];\n if (vRule) return vRule;\n }\n return bundle.productRules[productId] ?? DEFAULT_PRODUCT_RULE;\n}\n\n/**\n * The variant's OWN rule, or undefined when it inherits the product's.\n * Distinct from `ruleFor`, which falls back — conflating the two would make\n * every variant of a required product unremovable.\n */\nfunction variantRuleFor(\n bundle: MultiStepBundleData,\n variantId: string | null | undefined,\n): ProductRule | undefined {\n return variantId ? bundle.variantRules[variantId] : undefined;\n}\n\nfunction sanitizeId(gid: string): string {\n return gid.replace(/[^a-zA-Z0-9_-]/g, \"-\");\n}\n\ninterface EligibleProduct {\n product: Product;\n variants: ProductVariant[];\n firstAvailableVariant: ProductVariant | null;\n isOos: boolean;\n}\n\nfunction buildEligibleProducts(\n bundle: MultiStepBundleData,\n stepIndex: number,\n): EligibleProduct[] {\n const result: EligibleProduct[] = [];\n for (const product of productsForStep(bundle, stepIndex)) {\n const rule = ruleFor(bundle, product.id);\n const available = product.variants.nodes.filter((v) =>\n isVariantFulfillable(v, rule.min),\n );\n // Sold-out products stay in the list greyed out; the status flip hides\n // a bundle that can't be completed.\n const isOos = available.length === 0;\n result.push({\n product,\n variants: product.variants.nodes,\n firstAvailableVariant: available[0] ?? null,\n isOos,\n });\n }\n return result;\n}\n\nfunction normalizeText(str: string): string {\n return str\n .normalize(\"NFD\")\n .replace(/[̀-ͯ]/g, \"\")\n .toLowerCase();\n}\n\nexport interface MultiStepPickerProps {\n bundle: MultiStepBundleData;\n currency: string;\n /** Step the wizard opens at (heading click / first unsatisfied step). */\n initialStep: number;\n showStepper: boolean;\n /** Per-step selections — selections[i] = picks of step i. */\n selections: SelectedItem[][];\n /** Add a pick to a step. */\n onAdd: (step: number, item: SelectedItem) => void;\n /** Live-edit a committed pick's quantity within a step. */\n onUpdateQuantity: (\n step: number,\n productId: string,\n variantId: string,\n quantity: number,\n ) => void;\n /** Remove the slot holding this variant from a step (the Added toggle). */\n onRemoveVariant: (step: number, variantId: string) => void;\n /** Whether the slot holding this variant may be removed — false only for\n * a required product's last covering pick (product-level lock, computed\n * across every step). */\n canRemoveVariant?: (variantId: string) => boolean;\n /** In-step units an uncommitted variant of a hard-capped required\n * product could take over in an atomic swap (0 = not in swap state). */\n swapUnitsFor?: (step: number, productId: string, variantId: string) => number;\n /** Perform the atomic in-step swap: the item's units displace\n * sibling-variant units of the same product. */\n onSwap?: (step: number, item: SelectedItem) => void;\n onClose: () => void;\n /** CSS-var carrier ref so the portaled overlay inherits merchant theming. */\n styleVarsRef: (el: HTMLElement | null) => void;\n}\n\nconst FILTERS_ALL = \"__all__\";\n\nexport function MultiStepPicker({\n bundle,\n currency,\n initialStep,\n showStepper,\n selections,\n onAdd,\n onUpdateQuantity,\n onRemoveVariant,\n canRemoveVariant,\n swapUnitsFor,\n onSwap,\n onClose,\n styleVarsRef,\n}: MultiStepPickerProps) {\n const wc = bundle.widgetConfig;\n const steps = bundle.steps;\n const overlayRef = useRef<HTMLDivElement | null>(null);\n const dialogRef = useRef<HTMLDivElement | null>(null);\n const titleRef = useRef<HTMLHeadingElement | null>(null);\n const closeBtnRef = useRef<HTMLButtonElement | null>(null);\n const listRef = useRef<HTMLDivElement | null>(null);\n const mouseDownTarget = useRef<EventTarget | null>(null);\n const [open, setOpen] = useState(false);\n const [stepIndex, setStepIndex] = useState(() =>\n Math.max(0, Math.min(steps.length - 1, initialStep)),\n );\n const [query, setQuery] = useState(\"\");\n const [activeType, setActiveType] = useState<string>(FILTERS_ALL);\n /** Screen-reader step-change announcement ([data-modal-live]). */\n const [announcement, setAnnouncement] = useState(\"\");\n\n const step = steps[stepIndex];\n const stepMin = step?.minQuantity ?? 1;\n const stepPicks = selections[stepIndex] ?? [];\n const unitsInStep = stepPicks.reduce((sum, s) => sum + s.quantity, 0);\n const stepIsSatisfied = unitsInStep >= stepMin;\n const isLastStep = stepIndex === steps.length - 1;\n const shownUnits = Math.min(unitsInStep, stepMin);\n\n const eligible = useMemo(\n () => buildEligibleProducts(bundle, stepIndex),\n [bundle, stepIndex],\n );\n\n // Product-type filter pills for the CURRENT step's pool: only when\n // enabled AND there are ≥2 distinct non-empty product types.\n const productTypes = useMemo(() => {\n const types: string[] = [];\n const seen = new Set<string>();\n for (const ep of eligible) {\n const ty = (ep.product.productType ?? \"\").trim();\n if (ty && !seen.has(ty)) {\n seen.add(ty);\n types.push(ty);\n }\n }\n return types;\n }, [eligible]);\n\n const showFilters = wc.mixMatchShowTypeFilters && productTypes.length >= 2;\n\n // Trigger the open transition on mount (display already shown).\n useEffect(() => {\n const id = requestAnimationFrame(() => setOpen(true));\n return () => cancelAnimationFrame(id);\n }, []);\n\n useScrollLock(true);\n // Initial focus lands on the close icon, not the search input — focusing\n // search on a phone pops the keyboard over half the modal unasked.\n useFocusTrap({\n active: true,\n containerRef: dialogRef,\n initialFocusRef: closeBtnRef,\n onEscape: onClose,\n });\n\n // A step always presents from the top of its list — arriving mid-scroll\n // from the previous step hides the new step's first products.\n useEffect(() => {\n if (listRef.current) listRef.current.scrollTop = 0;\n }, [stepIndex]);\n\n // Products already picked in the shown step (required seeds included) sink\n // below the ones still to pick. The snapshot is captured per step load —\n // re-sorting live on add/remove would make the list jump under the\n // shopper's finger; the next step change (or open) recomputes it.\n const [selectedAtLoad, setSelectedAtLoad] = useState(\n () =>\n new Set((selections[stepIndex] ?? []).map((s) => s.productId)),\n );\n const ordered = useMemo(() => {\n const front: EligibleProduct[] = [];\n const back: EligibleProduct[] = [];\n for (const ep of eligible) {\n (selectedAtLoad.has(ep.product.id) ? back : front).push(ep);\n }\n return front.concat(back);\n }, [eligible, selectedAtLoad]);\n\n // Auto-advance: with the merchant setting on, a step filled to its\n // maximum has nothing left to do, so the wizard moves on by itself.\n // Guarded to an actual unit increase within the current step, so opening\n // the wizard at an already-full step (chosen-card edit) stays put, a swap\n // (total fixed) never fires it, and the last step never advances.\n const autoAdvance = wc.multiStepAutoAdvance === true;\n const lastSeen = useRef({ step: stepIndex, units: unitsInStep });\n useEffect(() => {\n const prev = lastSeen.current;\n lastSeen.current = { step: stepIndex, units: unitsInStep };\n if (!autoAdvance || isLastStep || prev.step !== stepIndex) return;\n if (unitsInStep <= prev.units) return;\n // A step without a maximum has Infinity headroom and never hits 0.\n if (stepHeadroom(step?.maxQuantity ?? null, unitsInStep) === 0) {\n goToStep(stepIndex + 1);\n }\n });\n\n /** Wizard navigation: reset filters/search, announce, focus the title. */\n function goToStep(i: number) {\n const clamped = Math.max(0, Math.min(steps.length - 1, i));\n setStepIndex(clamped);\n setQuery(\"\");\n setActiveType(FILTERS_ALL);\n const target = steps[clamped];\n const targetPicks = selections[clamped] ?? [];\n setSelectedAtLoad(new Set(targetPicks.map((s) => s.productId)));\n const targetUnits = targetPicks.reduce((sum, s) => sum + s.quantity, 0);\n setAnnouncement(\n `Step ${clamped + 1} of ${steps.length}. ${target.name}. ` +\n `${Math.min(targetUnits, target.minQuantity)} of ${target.minQuantity} added`,\n );\n titleRef.current?.focus();\n }\n\n const subtitle = `Step ${stepIndex + 1} of ${steps.length} · ${step?.name ?? \"\"}`;\n\n const filtered = useMemo(() => {\n const nq = normalizeText(query.trim());\n return ordered.filter((ep) => {\n const matchesQuery = !nq || normalizeText(ep.product.title).includes(nq);\n const matchesType =\n activeType === FILTERS_ALL ||\n (ep.product.productType ?? \"\") === activeType;\n return matchesQuery && matchesType;\n });\n }, [ordered, query, activeType]);\n\n const showEmpty = filtered.length === 0 && query.trim().length > 0;\n\n function onOverlayMouseDown(e: React.MouseEvent) {\n mouseDownTarget.current = e.target;\n }\n function onOverlayMouseUp(e: React.MouseEvent) {\n if (\n e.target === overlayRef.current &&\n mouseDownTarget.current === overlayRef.current\n ) {\n onClose();\n }\n mouseDownTarget.current = null;\n }\n\n const titleId = `lb-modal-title-${sanitizeId(bundle.id)}`;\n\n const modal = (\n // The overlay is a backdrop: click-outside-to-close is a mouse convenience;\n // keyboard users close via Escape (handled by useFocusTrap), and the dialog\n // inside carries the interactive role + focus trap. So the static-element\n // interaction lint does not apply to this backdrop.\n // eslint-disable-next-line jsx-a11y/no-static-element-interactions\n <div\n ref={(el) => {\n overlayRef.current = el;\n styleVarsRef(el);\n }}\n className={`lb-mix-match__modal-overlay${open ? \" lb-mix-match__modal-overlay--open\" : \"\"}`}\n data-modal-overlay\n data-bundle-gid={bundle.id}\n onMouseDown={onOverlayMouseDown}\n onMouseUp={onOverlayMouseUp}\n >\n <div\n ref={dialogRef}\n className={`lb-mix-match__modal${showFilters ? \"\" : \" lb-mix-match__modal--filters-hidden\"}`}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n tabIndex={-1}\n >\n <div className=\"lb-mix-match__modal-header\">\n <div className=\"lb-mix-match__modal-header-top\">\n <div className=\"lb-mix-match__modal-heading\">\n <h4\n className=\"lb-mix-match__modal-title\"\n id={titleId}\n tabIndex={-1}\n ref={titleRef}\n >\n Add to your bundle\n </h4>\n <p className=\"lb-mix-match__modal-subtitle\" data-modal-subtitle>\n {subtitle}\n </p>\n </div>\n <button\n ref={closeBtnRef}\n type=\"button\"\n className=\"lb-mix-match__modal-close\"\n data-modal-close\n aria-label=\"Close\"\n onClick={onClose}\n >\n <CloseIcon />\n </button>\n </div>\n {/* Per-step progress — one segment per required unit of THIS step. */}\n <div\n className=\"lb-mix-match__progress lb-mix-match__modal-progress\"\n data-progress\n >\n <div\n className=\"lb-mix-match__progress-segments\"\n data-modal-step-segments\n role=\"progressbar\"\n aria-valuenow={shownUnits}\n aria-valuemin={0}\n aria-valuemax={stepMin}\n >\n {Array.from({ length: stepMin }).map((_, i) => (\n <span\n key={i}\n className={`lb-mix-match__progress-segment${i < shownUnits ? \" lb-mix-match__progress-segment--filled\" : \"\"}`}\n data-progress-segment\n />\n ))}\n </div>\n </div>\n </div>\n\n {wc.showSearch && (\n <div className=\"lb-mix-match__modal-search\">\n <input\n type=\"text\"\n className=\"lb-mix-match__modal-search-input\"\n data-modal-search\n role=\"searchbox\"\n aria-label=\"Search products\"\n placeholder=\"Search products\"\n autoComplete=\"off\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n />\n {query.length > 0 && (\n <button\n type=\"button\"\n className=\"lb-mix-match__modal-search-clear\"\n data-modal-search-clear\n aria-label=\"Clear search\"\n onClick={() => setQuery(\"\")}\n >\n <SearchClearIcon />\n </button>\n )}\n </div>\n )}\n\n {showFilters && (\n <div\n className=\"lb-mix-match__filters\"\n data-modal-filters\n role=\"group\"\n aria-label=\"Filter by product type\"\n >\n {[FILTERS_ALL, ...productTypes].map((value) => {\n const isActive = value === activeType;\n return (\n <button\n key={value}\n type=\"button\"\n className={`lb-mix-match__filter${isActive ? \" lb-mix-match__filter--active\" : \"\"}`}\n data-filter={value}\n aria-pressed={isActive}\n onClick={() => setActiveType(value)}\n >\n {value === FILTERS_ALL ? \"All\" : value}\n </button>\n );\n })}\n </div>\n )}\n\n <div className=\"lb-mix-match__modal-list\" data-modal-list ref={listRef}>\n {filtered.map((ep) => (\n <MultiStepPickerRow\n key={`${stepIndex}:${ep.product.id}`}\n bundle={bundle}\n eligible={ep}\n currency={currency}\n showStepper={showStepper}\n stepIndex={stepIndex}\n selections={selections}\n onAdd={onAdd}\n swapUnitsFor={swapUnitsFor}\n onSwap={onSwap}\n onUpdateQuantity={onUpdateQuantity}\n onRemoveVariant={onRemoveVariant}\n canRemoveVariant={canRemoveVariant}\n />\n ))}\n </div>\n\n {showEmpty && (\n <div className=\"lb-mix-match__modal-empty\" data-modal-empty>\n <p>No products match your search</p>\n </div>\n )}\n\n <span data-modal-live aria-live=\"polite\" className=\"lb-visually-hidden\">\n {announcement ||\n (query.trim() ? `${filtered.length} products shown` : \"\")}\n </span>\n\n <div className=\"lb-mix-match__modal-footer lb-multi-step__modal-footer\">\n {stepIndex > 0 && (\n <button\n type=\"button\"\n className=\"lb-multi-step__modal-back\"\n data-modal-back\n onClick={() => goToStep(stepIndex - 1)}\n >\n Back\n </button>\n )}\n <span\n className=\"lb-mix-match__modal-footer-count\"\n data-modal-footer-count\n aria-live=\"polite\"\n >\n {`${shownUnits} of ${stepMin} added`}\n </span>\n {!isLastStep && (\n <button\n type=\"button\"\n className=\"lb-mix-match__modal-done\"\n data-modal-next\n disabled={!stepIsSatisfied}\n onClick={() => {\n if (stepIsSatisfied) goToStep(stepIndex + 1);\n }}\n >\n Next\n </button>\n )}\n {isLastStep && (\n <button\n type=\"button\"\n className=\"lb-mix-match__modal-done\"\n data-modal-done\n disabled={!stepIsSatisfied}\n onClick={onClose}\n >\n Done\n </button>\n )}\n </div>\n </div>\n </div>\n );\n\n if (typeof document === \"undefined\") return null;\n return createPortal(modal, document.body);\n}\n\ninterface MultiStepPickerRowProps {\n bundle: MultiStepBundleData;\n eligible: EligibleProduct;\n currency: string;\n showStepper: boolean;\n /** Wizard step this row belongs to. */\n stepIndex: number;\n /** ALL steps' selections — cross-step stock + rule.max accounting. */\n selections: SelectedItem[][];\n onAdd: (step: number, item: SelectedItem) => void;\n onUpdateQuantity: (\n step: number,\n productId: string,\n variantId: string,\n quantity: number,\n ) => void;\n onRemoveVariant: (step: number, variantId: string) => void;\n canRemoveVariant?: (variantId: string) => boolean;\n swapUnitsFor?: (step: number, productId: string, variantId: string) => number;\n onSwap?: (step: number, item: SelectedItem) => void;\n}\n\nfunction MultiStepPickerRow({\n bundle,\n eligible,\n currency,\n showStepper,\n stepIndex,\n selections,\n onAdd,\n onUpdateQuantity,\n onRemoveVariant,\n canRemoveVariant,\n swapUnitsFor,\n onSwap,\n}: MultiStepPickerRowProps) {\n const { product, variants, isOos } = eligible;\n const rule = ruleFor(bundle, product.id);\n const step = bundle.steps[stepIndex];\n\n const optionNames = useMemo<string[]>(() => {\n const first = variants[0];\n return first ? first.selectedOptions.map((o) => o.name) : [];\n }, [variants]);\n const showPicker = variants.length > 1 && optionNames.length > 0;\n\n const { selectedValues, selectedVariant, setOptionValue, optionsFor } =\n useVariantSelection({ variants, optionNames });\n\n const currentVariant =\n selectedVariant ??\n variants.find((v) => isVariantFulfillable(v, rule.min)) ??\n eligible.firstAvailableVariant ??\n variants[0] ??\n null;\n\n // The rule in force for this row. `rule` above stays the PRODUCT envelope\n // and is used wherever the question is about the product's bundle-wide\n // total; `vRule` is what bounds this variant's own pick.\n const vRule = ruleFor(bundle, product.id, currentVariant?.id);\n const variantMax = variantRuleFor(bundle, currentVariant?.id)?.max;\n\n const stepPicks = useMemo(\n () => selections[stepIndex] ?? [],\n [selections, stepIndex],\n );\n const unitsInStep = stepPicks.reduce((sum, s) => sum + s.quantity, 0);\n\n // Slots are VARIANT-scoped within THIS step: the row's Added state, live\n // stepper, and tint follow its currently-selected variant's slot in the\n // current step. The same variant may hold slots in other steps.\n const committedSelection = useMemo(\n () =>\n currentVariant\n ? (stepPicks.find((s) => s.variantId === currentVariant.id) ?? null)\n : null,\n [stepPicks, currentVariant],\n );\n const variantInStep = committedSelection !== null;\n const committedQty = committedSelection?.quantity ?? 0;\n\n // rule.max caps the PRODUCT's total units across every slot in every\n // step, so slots other than this row's own reduce its share of it.\n const productOtherUnits = useMemo(() => {\n if (!currentVariant) return 0;\n let sum = 0;\n for (let i = 0; i < selections.length; i++) {\n for (const s of selections[i]) {\n if (s.productId !== product.id) continue;\n if (i === stepIndex && s.variantId === currentVariant.id) continue;\n sum += s.quantity;\n }\n }\n return sum;\n }, [selections, product.id, currentVariant, stepIndex]);\n\n // Stock accounting sums the variant's units across ALL steps — the same\n // physical inventory backs it no matter which step holds it.\n const variantOtherUnits = useMemo(() => {\n if (!currentVariant) return 0;\n let sum = 0;\n for (const picks of selections) {\n for (const s of picks) {\n if (s.variantId === currentVariant.id) sum += s.quantity;\n }\n }\n return Math.max(0, sum - committedQty);\n }, [selections, currentVariant, committedQty]);\n\n // ATOMIC SWAP state: a hard-capped required product's uncommitted\n // variants displace in-step sibling units instead of adding, so the\n // step-headroom gates don't apply and the ceiling is the units they\n // can take over.\n const swapUnits = currentVariant\n ? (swapUnitsFor?.(stepIndex, product.id, currentVariant.id) ?? 0)\n : 0;\n const inSwapState = swapUnits >= vRule.min;\n // Ceiling = min(rule.max − product units in other slots,\n // ownQty + step headroom, stock − variant units in other\n // slots). Mirrors setBoundsForVariant in the theme JS.\n const room = stepHeadroom(step?.maxQuantity ?? null, unitsInStep);\n // The variant's own cap binds independently of the envelope: sibling\n // units eat into the product's total, never into this variant's allowance.\n const productHeadroom = Math.min(\n rule.max - productOtherUnits,\n variantMax ?? Infinity,\n );\n const spotCeiling = inSwapState\n ? swapUnits\n : Math.min(\n productHeadroom,\n room === Number.POSITIVE_INFINITY\n ? productHeadroom\n : committedQty + room,\n );\n const stockRemaining = currentVariant\n ? maxAddableQuantity(currentVariant, Number.MAX_SAFE_INTEGER, variantOtherUnits)\n : 0;\n const cap = Math.max(0, Math.min(spotCeiling, stockRemaining));\n const stepperMax = Math.max(vRule.min, cap);\n\n const [qty, setQty] = useState(vRule.min);\n\n // Clamp the local qty whenever the bounds move, and reset to rule.min\n // when the row's variant leaves the step OR the shopper switches to an\n // uncommitted variant.\n useEffect(() => {\n setQty((prev) => Math.max(vRule.min, Math.min(prev, stepperMax)));\n }, [stepperMax, vRule.min]);\n const currentVariantId = currentVariant?.id ?? null;\n useEffect(() => {\n if (!variantInStep) setQty(vRule.min);\n }, [variantInStep, currentVariantId, vRule.min]);\n\n if (!currentVariant || !step) return null;\n\n const thumbImage = currentVariant.image ?? product.featuredImage ?? null;\n const unitPriceText = formatUnitPrice(\n currentVariant.unitPrice,\n currentVariant.unitPriceMeasurement,\n currency,\n );\n\n // Add disabled when: stock (or the product's bundle-wide rule.max) can't\n // satisfy rule.min, or the step's remaining headroom can't fit another\n // rule.min pick (step maximum enforcement).\n const noStock = cap < vRule.min;\n const needsMoreSpots =\n !variantInStep &&\n !inSwapState &&\n room !== Number.POSITIVE_INFINITY &&\n vRule.min > room;\n // A swap frees its own room, so only stock can block it.\n const addDisabled =\n !variantInStep && (inSwapState ? noStock : noStock || needsMoreSpots);\n // Required product's last covering pick — the Remove slot goes inert\n // (\"Required\"); removal returns once another slot covers the minimum.\n const lockedRequired =\n variantInStep &&\n currentVariant != null &&\n !(canRemoveVariant?.(currentVariant.id) ?? true);\n const stepperDisabled = isOos || (!variantInStep && addDisabled);\n const shownQty = variantInStep ? committedQty : qty;\n\n function handleAddOrRemove() {\n if (variantInStep && currentVariant) {\n onRemoveVariant(stepIndex, currentVariant.id);\n return;\n }\n if (!currentVariant || noStock) return;\n const pickedQty = showStepper ? qty : vRule.min;\n const item = {\n productId: product.id,\n variantId: currentVariant.id,\n title: product.title,\n url: `/products/${product.handle}`,\n variantTitle: currentVariant.title,\n featuredImage: thumbImage?.url ?? null,\n price: parseFloat(currentVariant.price.amount),\n compareAtPrice: currentVariant.compareAtPrice\n ? parseFloat(currentVariant.compareAtPrice.amount)\n : null,\n unitPrice: unitPriceText,\n quantity: pickedQty,\n };\n // ATOMIC SWAP: displaces in-step sibling units, so it runs before\n // (and instead of) the step-headroom gate.\n if (inSwapState && onSwap) {\n onSwap(stepIndex, { ...item, quantity: Math.min(pickedQty, swapUnits) });\n return;\n }\n if (needsMoreSpots) return;\n onAdd(stepIndex, item);\n }\n\n const priceCents = parseFloat(currentVariant.price.amount);\n const compareCents = currentVariant.compareAtPrice\n ? parseFloat(currentVariant.compareAtPrice.amount)\n : null;\n\n return (\n <div\n className={`lb-mix-match__modal-product${isOos ? \" lb-mix-match__modal-product--sold-out\" : \"\"}${variantInStep ? \" lb-mix-match__modal-product--in-bundle\" : \"\"}`}\n data-product-item\n data-title={normalizeText(product.title)}\n data-type={product.productType ?? \"\"}\n aria-disabled={isOos || undefined}\n >\n <div className=\"lb-mix-match__modal-product-thumb\">\n {thumbImage && (\n <img\n src={thumbImage.url}\n alt={thumbImage.altText ?? product.title}\n loading=\"lazy\"\n // Intrinsic dimensions reserve the \"original\"-ratio box pre-load\n // (issue #302); inert for the cropped ratios, where CSS sizes it.\n width={thumbImage.width ?? undefined}\n height={thumbImage.height ?? undefined}\n />\n )}\n {variantInStep && (\n <span className=\"lb-mix-match__modal-added-badge\">Added</span>\n )}\n </div>\n\n <div className=\"lb-mix-match__modal-product-info\">\n {/* New tab keeps the in-progress bundle alive — same-tab navigation\n would wipe the shopper's picks. */}\n <p className=\"lb-mix-match__modal-product-title\">\n <a\n href={`/products/${product.handle}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {product.title}\n </a>\n </p>\n <p className=\"lb-mix-match__modal-product-price\">\n <span data-row-price-sale>{formatMoney(priceCents, currency)}</span>\n {compareCents !== null && compareCents > priceCents && (\n <s className=\"lb-mix-match__modal-product-compare\" data-row-compare>\n {formatMoney(compareCents, currency)}\n </s>\n )}\n </p>\n {unitPriceText && (\n <p className=\"lb-mix-match__modal-product-unit-price lb-bundle-product-unit-price\">\n {unitPriceText}\n </p>\n )}\n\n {showPicker && (\n <div className=\"lb-bundle-variant-option-groups\">\n {optionNames.map((optionName, optionIndex) => {\n const dropdownOptions = optionsFor(optionIndex).map((o) => ({\n value: o.value,\n label: o.value,\n disabled: o.disabled,\n }));\n return (\n <div\n key={optionName}\n className=\"lb-bundle-variant-option-group\"\n >\n <span className=\"lb-bundle-variant-option-label\">\n {optionName}\n </span>\n <VariantDropdown\n className=\"lb-mix-match__variant-select-dropdown\"\n options={dropdownOptions}\n value={selectedValues[optionIndex] ?? null}\n onChange={(v) => setOptionValue(optionIndex, v)}\n ariaLabel={optionName}\n />\n </div>\n );\n })}\n </div>\n )}\n {!showPicker &&\n variants.length === 1 &&\n currentVariant.title !== \"Default Title\" && (\n <span className=\"lb-mix-match__filled-variant\">\n {currentVariant.title}\n </span>\n )}\n\n {/* \"Needs N spots\" hint — the step's remaining headroom can't fit\n another rule.min pick. Hidden at zero headroom, where the step's\n complete state already tells the story for every row. */}\n {!isOos && needsMoreSpots && room > 0 && (\n <span className=\"lb-mix-match__modal-needs-spots\">\n {vRule.min === 1 ? \"Needs 1 spot\" : `Needs ${vRule.min} spots`}\n </span>\n )}\n\n {isOos ? (\n <span className=\"lb-mix-match__modal-sold-out-label\">Sold out</span>\n ) : (\n <div className=\"lb-mix-match__modal-product-actions\">\n {showStepper && (\n <div className=\"lb-bundle-variant-option-group lb-mix-match__qty-stepper-group\">\n <div\n className=\"lb-mix-match__qty-stepper\"\n role=\"group\"\n aria-label=\"Quantity\"\n >\n <button\n type=\"button\"\n className=\"lb-mix-match__qty-stepper-button lb-mix-match__qty-stepper-button--minus\"\n aria-label=\"Decrease quantity\"\n disabled={stepperDisabled || shownQty <= vRule.min}\n onClick={() => {\n if (variantInStep && currentVariant) {\n // LIVE EDIT — propagate into selections state.\n onUpdateQuantity(\n stepIndex,\n product.id,\n currentVariant.id,\n Math.max(vRule.min, committedQty - 1),\n );\n } else {\n setQty((q) => Math.max(vRule.min, q - 1));\n }\n }}\n >\n {\"−\"}\n </button>\n <span\n className=\"lb-mix-match__qty-stepper-value\"\n data-row-qty\n aria-live=\"polite\"\n >\n {shownQty}\n </span>\n <button\n type=\"button\"\n className=\"lb-mix-match__qty-stepper-button lb-mix-match__qty-stepper-button--plus\"\n aria-label=\"Increase quantity\"\n disabled={stepperDisabled || shownQty >= stepperMax}\n onClick={() => {\n if (variantInStep && currentVariant) {\n onUpdateQuantity(\n stepIndex,\n product.id,\n currentVariant.id,\n Math.min(stepperMax, committedQty + 1),\n );\n } else {\n setQty((q) => Math.min(stepperMax, q + 1));\n }\n }}\n >\n +\n </button>\n </div>\n </div>\n )}\n <button\n type=\"button\"\n className={`lb-mix-match__modal-add${variantInStep ? \" lb-mix-match__modal-add--added\" : \"\"}${lockedRequired ? \" lb-mix-match__modal-add--required\" : \"\"}`}\n data-add-product\n aria-label={\n variantInStep\n ? lockedRequired\n ? `${product.title} is required and cannot be removed`\n : `Remove ${product.title}`\n : `${inSwapState ? \"Swap\" : \"Add\"} ${product.title}`\n }\n disabled={addDisabled || lockedRequired}\n onClick={handleAddOrRemove}\n >\n {/* Explicit inverted \"Remove\" — state feedback lives on the\n thumbnail's \"Added\" badge, not the button. */}\n {variantInStep\n ? lockedRequired\n ? \"Required\"\n : \"Remove\"\n : inSwapState\n ? \"Swap\"\n : \"Add\"}\n </button>\n </div>\n )}\n </div>\n </div>\n );\n}\n\nfunction CloseIcon() {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <line x1=\"5\" y1=\"5\" x2=\"15\" y2=\"15\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n <line x1=\"15\" y1=\"5\" x2=\"5\" y2=\"15\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n\nfunction SearchClearIcon() {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path d=\"M14.348 5.652a.5.5 0 0 0-.707 0L10 9.293 6.36 5.652a.5.5 0 1 0-.708.707L9.293 10l-3.641 3.641a.5.5 0 0 0 .708.707L10 10.707l3.641 3.641a.5.5 0 0 0 .707-.707L10.707 10l3.641-3.641a.5.5 0 0 0 0-.707z\" />\n </svg>\n );\n}\n","/**\n * @deprecated Use `fetchShopSettings`, which returns the custom CSS alongside\n * the shop's out-of-stock behaviour in the same round trip. This wrapper is\n * kept so existing integrations keep compiling; it shares the same per-shop\n * cache, so calling both costs one request.\n */\nimport { fetchShopSettings, __clearShopSettingsCache } from \"./fetchShopSettings\";\nimport type { FetchShopSettingsOptions } from \"./fetchShopSettings\";\n\nexport type FetchShopCustomCssOptions = FetchShopSettingsOptions;\n\n/** @deprecated Use `fetchShopSettings().customCss`. */\nexport async function fetchShopCustomCss(\n options: FetchShopCustomCssOptions,\n): Promise<string | null> {\n const settings = await fetchShopSettings(options);\n return settings.customCss;\n}\n\n/** @deprecated Use `__clearShopSettingsCache`. Test-only. */\nexport function __clearShopCssCache(): void {\n __clearShopSettingsCache();\n}\n","/**\n * Client-side React hook wrapping `fetchBundlesForProduct` — the\n * React-SDK analogue of the web component's auto-detect-by-current-product\n * mode. The web component reads the handle from `location.pathname`; a\n * React app already has it on the router, so the hook takes it as an\n * explicit `productHandle` option.\n *\n * Returns every active bundle configured against the product. Inactive,\n * draft, scheduled-for-later, and expired bundles are filtered out by\n * the core helper — consumers don't have to guard.\n *\n * For SSR / RSC contexts (Hydrogen loaders, Next.js server components),\n * prefer `fetchBundlesForProduct` directly and pass the list to a client\n * component as a prop. This hook's only value-add over the async\n * function is React state management + abort-on-unmount.\n *\n * `UseBundlesForProductResult` is a discriminated union locked at v2.0.0:\n * narrowing via `status` is safe. Widening or adding states is a\n * breaking change.\n */\nimport { useState, useEffect } from \"react\";\nimport {\n fetchBundlesForProduct,\n injectCustomCss,\n type ParsedBundle,\n} from \"@lime-bundles/core\";\nimport { fetchShopSettings } from \"../fetchShopSettings\";\n\nexport interface UseBundlesForProductOptions {\n shopDomain: string;\n storefrontAccessToken: string;\n productHandle: string;\n /** Forwarded as `Shopify-Storefront-Buyer-IP` — required for SSR paths. */\n buyerIp?: string;\n}\n\nexport type UseBundlesForProductResult =\n | { status: \"loading\"; bundles: null; error: null }\n | { status: \"success\"; bundles: ParsedBundle[]; error: null }\n | { status: \"error\"; bundles: null; error: Error };\n\nconst INITIAL_STATE: UseBundlesForProductResult = {\n status: \"loading\",\n bundles: null,\n error: null,\n};\n\nexport function useBundlesForProduct(\n options: UseBundlesForProductOptions,\n): UseBundlesForProductResult {\n const [state, setState] = useState<UseBundlesForProductResult>(\n INITIAL_STATE,\n );\n\n useEffect(() => {\n const controller = new AbortController();\n setState(INITIAL_STATE);\n\n fetchBundlesForProduct({\n shopDomain: options.shopDomain,\n storefrontAccessToken: options.storefrontAccessToken,\n productHandle: options.productHandle,\n buyerIp: options.buyerIp,\n signal: controller.signal,\n })\n .then((bundles) => {\n if (controller.signal.aborted) return;\n setState({ status: \"success\", bundles, error: null });\n })\n .catch((err: unknown) => {\n if (controller.signal.aborted) return;\n setState({\n status: \"error\",\n bundles: null,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n });\n\n // Fire-and-forget custom CSS fetch so storefronts using this hook get\n // merchant styling automatically — same behaviour as `useBundleData`.\n fetchShopSettings({\n shopDomain: options.shopDomain,\n storefrontAccessToken: options.storefrontAccessToken,\n signal: controller.signal,\n })\n .then((settings) => {\n if (controller.signal.aborted) return;\n injectCustomCss(options.shopDomain, settings.customCss);\n })\n .catch(() => {\n // Silent — no merchant CSS is fine.\n });\n\n return () => {\n controller.abort();\n };\n }, [\n options.shopDomain,\n options.storefrontAccessToken,\n options.productHandle,\n options.buyerIp,\n ]);\n\n return state;\n}\n"],"mappings":"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","names":["import_react","import_core","import_core","import_core","import_react","import_core","import_react","import_core","import_react","import_core","variantsNs","import_react","import_react","import_core","import_react","import_jsx_runtime","import_jsx_runtime","import_react","import_core","import_react","import_core","import_react","import_react","import_jsx_runtime","import_jsx_runtime","ruleFor","variantRuleFor","variant","requiredUnits","CloseIcon","import_react","import_core","import_jsx_runtime","import_react","import_core","import_jsx_runtime","buyVariant","getVariant","buyUnit","getUnit","import_react","import_core","import_react","import_react_dom","import_core","import_jsx_runtime","ruleFor","variantRuleFor","sanitizeId","buildEligibleProducts","normalizeText","FILTERS_ALL","CloseIcon","SearchClearIcon","import_jsx_runtime","ruleFor","variantRuleFor","canRemoveItem","swapUnitsForItem","PlusIcon","CloseIcon","import_react","import_core","INITIAL_STATE","import_core"]}