@lime-bundles/react 6.0.0 → 6.2.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.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/components/FixedBundle.tsx
2
- import { useCallback as useCallback5, useEffect as useEffect6, useMemo as useMemo4, useState as useState5 } from "react";
2
+ import { useCallback as useCallback5, useEffect as useEffect7, useMemo as useMemo4, useState as useState6 } from "react";
3
3
  import {
4
4
  formatMoney,
5
5
  formatUnitPrice,
@@ -659,8 +659,48 @@ function VariantDropdown({
659
659
  );
660
660
  }
661
661
 
662
- // src/components/FixedBundle.tsx
662
+ // src/components/BundleCountdown.tsx
663
+ import { useEffect as useEffect6, useState as useState5 } from "react";
663
664
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
665
+ function pad(n) {
666
+ return n < 10 ? "0" + n : String(n);
667
+ }
668
+ function formatRemaining(remaining) {
669
+ const days = Math.floor(remaining / 864e5);
670
+ const hours = Math.floor(remaining % 864e5 / 36e5);
671
+ const mins = Math.floor(remaining % 36e5 / 6e4);
672
+ const secs = Math.floor(remaining % 6e4 / 1e3);
673
+ return days > 0 ? days + "d " + pad(hours) + "h " + pad(mins) + "m " + pad(secs) + "s" : pad(hours) + "h " + pad(mins) + "m " + pad(secs) + "s";
674
+ }
675
+ function BundleCountdown({
676
+ endsAt,
677
+ widgetConfig,
678
+ label = "Limited time offer"
679
+ }) {
680
+ const enabled = !!endsAt && widgetConfig?.countdown?.showCountdown !== false;
681
+ const endTime = enabled ? new Date(endsAt).getTime() : NaN;
682
+ const [remaining, setRemaining] = useState5(null);
683
+ useEffect6(() => {
684
+ if (!enabled || isNaN(endTime)) {
685
+ setRemaining(null);
686
+ return;
687
+ }
688
+ const update = () => setRemaining(endTime - Date.now());
689
+ update();
690
+ const interval = setInterval(update, 1e3);
691
+ return () => clearInterval(interval);
692
+ }, [enabled, endTime]);
693
+ if (!enabled || isNaN(endTime) || remaining === null || remaining <= 0) {
694
+ return null;
695
+ }
696
+ return /* @__PURE__ */ jsxs2("div", { className: "lb-bundle-countdown", "data-countdown": true, children: [
697
+ /* @__PURE__ */ jsx2("div", { className: "lb-bundle-countdown__label", children: /* @__PURE__ */ jsx2("span", { children: label }) }),
698
+ /* @__PURE__ */ jsx2("span", { className: "lb-bundle-countdown__timer", "data-countdown-timer": true, children: formatRemaining(remaining) })
699
+ ] });
700
+ }
701
+
702
+ // src/components/FixedBundle.tsx
703
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
664
704
  function FixedBundle(props) {
665
705
  const {
666
706
  shopDomain,
@@ -684,9 +724,9 @@ function FixedBundle(props) {
684
724
  bundleType: "fixed",
685
725
  enabled: analyticsEnabled !== false
686
726
  });
687
- const [addingToCart, setAddingToCart] = useState5(false);
688
- const [cartError, setCartError] = useState5(null);
689
- const [selectedVariants, setSelectedVariants] = useState5({});
727
+ const [addingToCart, setAddingToCart] = useState6(false);
728
+ const [cartError, setCartError] = useState6(null);
729
+ const [selectedVariants, setSelectedVariants] = useState6({});
690
730
  const handleVariantChange = useCallback5(
691
731
  (productId, variant) => {
692
732
  setSelectedVariants((prev) => {
@@ -699,7 +739,7 @@ function FixedBundle(props) {
699
739
  const bundle = result.status === "success" && result.bundle.bundleType === "fixed" ? result.bundle : null;
700
740
  const setConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);
701
741
  const productsEdgeFadeRef = useEdgeFade();
702
- useEffect6(() => {
742
+ useEffect7(() => {
703
743
  if (result.status === "error") {
704
744
  onError?.(result.error);
705
745
  return;
@@ -777,9 +817,9 @@ function FixedBundle(props) {
777
817
  }
778
818
  }, [bundle, onAddToCart, onError, trackAddToCart, selectedVariants]);
779
819
  if (result.status === "loading") {
780
- return /* @__PURE__ */ jsxs2("div", { className: `lb-bundle lb-bundle--loading ${className ?? ""}`, children: [
781
- /* @__PURE__ */ jsx2("div", { className: "lb-skeleton lb-skeleton--title" }),
782
- /* @__PURE__ */ jsx2("div", { className: "lb-skeleton lb-skeleton--products" })
820
+ return /* @__PURE__ */ jsxs3("div", { className: `lb-bundle lb-bundle--loading ${className ?? ""}`, children: [
821
+ /* @__PURE__ */ jsx3("div", { className: "lb-skeleton lb-skeleton--title" }),
822
+ /* @__PURE__ */ jsx3("div", { className: "lb-skeleton lb-skeleton--products" })
783
823
  ] });
784
824
  }
785
825
  if (result.status === "error") return null;
@@ -806,7 +846,7 @@ function FixedBundle(props) {
806
846
  const savingsPercent = comparePrice > 0 && savings > 0 ? Math.round(savings / comparePrice * 100) : 0;
807
847
  const showCompare = bundle.widgetConfig.pricing.showComparePrice && savings > 0;
808
848
  const showSavings = bundle.widgetConfig.savingsBar.visible && savings > 0;
809
- return /* @__PURE__ */ jsxs2(
849
+ return /* @__PURE__ */ jsxs3(
810
850
  "div",
811
851
  {
812
852
  ref: (el) => {
@@ -817,11 +857,18 @@ function FixedBundle(props) {
817
857
  role: "region",
818
858
  "aria-label": bundle.title,
819
859
  children: [
820
- /* @__PURE__ */ jsx2("div", { className: "lb-bundle-header", children: /* @__PURE__ */ jsxs2("div", { className: "lb-bundle-header__content", children: [
821
- /* @__PURE__ */ jsx2("h3", { className: "lb-bundle-title", children: bundle.title }),
822
- bundle.description && /* @__PURE__ */ jsx2("p", { className: "lb-bundle-subtitle", children: bundle.description })
860
+ /* @__PURE__ */ jsx3("div", { className: "lb-bundle-header", children: /* @__PURE__ */ jsxs3("div", { className: "lb-bundle-header__content", children: [
861
+ /* @__PURE__ */ jsx3("h3", { className: "lb-bundle-title", children: bundle.title }),
862
+ bundle.description && /* @__PURE__ */ jsx3("p", { className: "lb-bundle-subtitle", children: bundle.description })
823
863
  ] }) }),
824
- /* @__PURE__ */ jsx2("div", { className: "lb-bundle__products lb-edge-fade", ref: productsEdgeFadeRef, children: bundle.products.map((product) => /* @__PURE__ */ jsx2(
864
+ /* @__PURE__ */ jsx3(
865
+ BundleCountdown,
866
+ {
867
+ endsAt: bundle.endsAt,
868
+ widgetConfig: bundle.widgetConfig
869
+ }
870
+ ),
871
+ /* @__PURE__ */ jsx3("div", { className: "lb-bundle__products lb-edge-fade", ref: productsEdgeFadeRef, children: bundle.products.map((product) => /* @__PURE__ */ jsx3(
825
872
  FixedProductRow,
826
873
  {
827
874
  bundle,
@@ -832,29 +879,29 @@ function FixedBundle(props) {
832
879
  },
833
880
  product.id
834
881
  )) }),
835
- /* @__PURE__ */ jsx2("div", { className: "lb-bundle-divider" }),
836
- /* @__PURE__ */ jsxs2("div", { className: "lb-bundle-summary", children: [
837
- /* @__PURE__ */ jsxs2("div", { className: "lb-bundle-summary__text", children: [
838
- /* @__PURE__ */ jsx2("span", { className: "lb-bundle-summary__label", children: "Bundle price" }),
839
- showSavings && /* @__PURE__ */ jsxs2("p", { className: "lb-bundle-savings-line", "data-savings-bar": true, children: [
882
+ /* @__PURE__ */ jsx3("div", { className: "lb-bundle-divider" }),
883
+ /* @__PURE__ */ jsxs3("div", { className: "lb-bundle-summary", children: [
884
+ /* @__PURE__ */ jsxs3("div", { className: "lb-bundle-summary__text", children: [
885
+ /* @__PURE__ */ jsx3("span", { className: "lb-bundle-summary__label", children: "Bundle total" }),
886
+ showSavings && /* @__PURE__ */ jsxs3("p", { className: "lb-bundle-savings-line", "data-savings-bar": true, children: [
840
887
  "You save",
841
888
  " ",
842
- /* @__PURE__ */ jsx2("span", { "data-savings-amount": true, children: formatMoney(savings, currency) }),
889
+ /* @__PURE__ */ jsx3("span", { "data-savings-amount": true, children: formatMoney(savings, currency) }),
843
890
  " ",
844
- /* @__PURE__ */ jsxs2("span", { "data-savings-percent": true, children: [
891
+ /* @__PURE__ */ jsxs3("span", { "data-savings-percent": true, children: [
845
892
  "(",
846
893
  savingsPercent,
847
894
  "%)"
848
895
  ] })
849
896
  ] })
850
897
  ] }),
851
- /* @__PURE__ */ jsxs2("span", { className: "lb-bundle-summary__prices", children: [
852
- showCompare && /* @__PURE__ */ jsx2("span", { className: "lb-bundle-compare-price", "data-compare-price": true, children: formatMoney(comparePrice, currency) }),
853
- /* @__PURE__ */ jsx2("span", { className: "lb-bundle-sale-price", "data-sale-price": true, children: formatMoney(salePrice, currency) })
898
+ /* @__PURE__ */ jsxs3("span", { className: "lb-bundle-summary__prices", children: [
899
+ showCompare && /* @__PURE__ */ jsx3("span", { className: "lb-bundle-compare-price", "data-compare-price": true, children: formatMoney(comparePrice, currency) }),
900
+ /* @__PURE__ */ jsx3("span", { className: "lb-bundle-sale-price", "data-sale-price": true, children: formatMoney(salePrice, currency) })
854
901
  ] })
855
902
  ] }),
856
- cartError && /* @__PURE__ */ jsx2("p", { className: "lb-bundle__error", role: "alert", children: cartError }),
857
- /* @__PURE__ */ jsx2(
903
+ cartError && /* @__PURE__ */ jsx3("p", { className: "lb-bundle__error", role: "alert", children: cartError }),
904
+ /* @__PURE__ */ jsx3(
858
905
  "button",
859
906
  {
860
907
  className: "lb-bundle__cta",
@@ -879,7 +926,7 @@ function FixedProductRow({ bundle, product, currency, isOos, onVariantChange })
879
926
  variants,
880
927
  optionNames
881
928
  });
882
- useEffect6(() => {
929
+ useEffect7(() => {
883
930
  onVariantChange(product.id, selectedVariant ?? null);
884
931
  }, [selectedVariant, product.id, onVariantChange]);
885
932
  const displayVariant = selectedVariant ?? variants.find(
@@ -900,15 +947,15 @@ function FixedProductRow({ bundle, product, currency, isOos, onVariantChange })
900
947
  bundle.widgetConfig.lowStockThreshold,
901
948
  bundle.widgetConfig.showLowStockBadge
902
949
  );
903
- return /* @__PURE__ */ jsxs2(
950
+ return /* @__PURE__ */ jsxs3(
904
951
  "div",
905
952
  {
906
953
  className: isOos ? "lb-bundle-product-row lb-bundle-product-row--oos" : "lb-bundle-product-row",
907
954
  "aria-disabled": isOos || void 0,
908
955
  part: "product",
909
956
  children: [
910
- isOos && /* @__PURE__ */ jsx2("span", { className: "lb-bundle-product-row__oos", children: "Out of stock" }),
911
- thumbImage && /* @__PURE__ */ jsx2(
957
+ isOos && /* @__PURE__ */ jsx3("span", { className: "lb-bundle-product-row__oos", children: "Out of stock" }),
958
+ thumbImage && /* @__PURE__ */ jsx3(
912
959
  "img",
913
960
  {
914
961
  src: thumbImage.url,
@@ -917,11 +964,11 @@ function FixedProductRow({ bundle, product, currency, isOos, onVariantChange })
917
964
  loading: "lazy"
918
965
  }
919
966
  ),
920
- /* @__PURE__ */ jsxs2("div", { className: "lb-bundle__product-info", children: [
921
- /* @__PURE__ */ jsx2("p", { className: "lb-bundle__product-title", children: product.title }),
922
- !showPicker && displayVariant && variants.length > 1 && /* @__PURE__ */ jsx2("span", { className: "lb-bundle-variant-badge", children: displayVariant.title }),
923
- /* @__PURE__ */ jsxs2("span", { className: "lb-bundle-product-prices", children: [
924
- compareAt && /* @__PURE__ */ jsx2(
967
+ /* @__PURE__ */ jsxs3("div", { className: "lb-bundle__product-info", children: [
968
+ /* @__PURE__ */ jsx3("p", { className: "lb-bundle__product-title", children: product.title }),
969
+ !showPicker && displayVariant && variants.length > 1 && /* @__PURE__ */ jsx3("span", { className: "lb-bundle-variant-badge", children: displayVariant.title }),
970
+ /* @__PURE__ */ jsxs3("span", { className: "lb-bundle-product-prices", children: [
971
+ compareAt && /* @__PURE__ */ jsx3(
925
972
  "span",
926
973
  {
927
974
  className: "lb-bundle-product-compare-price",
@@ -929,9 +976,9 @@ function FixedProductRow({ bundle, product, currency, isOos, onVariantChange })
929
976
  children: compareAt
930
977
  }
931
978
  ),
932
- /* @__PURE__ */ jsx2("span", { className: "lb-bundle__product-price", "data-product-price": true, children: priceText })
979
+ /* @__PURE__ */ jsx3("span", { className: "lb-bundle__product-price", "data-product-price": true, children: priceText })
933
980
  ] }),
934
- unitPriceText && /* @__PURE__ */ jsx2(
981
+ unitPriceText && /* @__PURE__ */ jsx3(
935
982
  "span",
936
983
  {
937
984
  className: "lb-bundle__product-unit-price",
@@ -939,18 +986,18 @@ function FixedProductRow({ bundle, product, currency, isOos, onVariantChange })
939
986
  children: unitPriceText
940
987
  }
941
988
  ),
942
- showLowStock && /* @__PURE__ */ jsxs2("span", { className: "lb-bundle-low-stock-badge", children: [
989
+ showLowStock && /* @__PURE__ */ jsxs3("span", { className: "lb-bundle-low-stock-badge", children: [
943
990
  "Only ",
944
991
  displayVariant.quantityAvailable,
945
992
  " left"
946
993
  ] }),
947
- showPicker && /* @__PURE__ */ jsx2("div", { className: "lb-bundle__product-variant-pickers", children: optionNames.map((optionName, optionIndex) => {
994
+ showPicker && /* @__PURE__ */ jsx3("div", { className: "lb-bundle__product-variant-pickers", children: optionNames.map((optionName, optionIndex) => {
948
995
  const dropdownOptions = optionsFor(optionIndex).map((o) => ({
949
996
  value: o.value,
950
997
  label: o.value,
951
998
  disabled: o.disabled
952
999
  }));
953
- return /* @__PURE__ */ jsx2(
1000
+ return /* @__PURE__ */ jsx3(
954
1001
  VariantDropdown,
955
1002
  {
956
1003
  options: dropdownOptions,
@@ -962,7 +1009,7 @@ function FixedProductRow({ bundle, product, currency, isOos, onVariantChange })
962
1009
  );
963
1010
  }) })
964
1011
  ] }),
965
- displayVariant && /* @__PURE__ */ jsxs2("span", { className: "lb-bundle-qty-chip", "data-qty-inline": true, children: [
1012
+ displayVariant && /* @__PURE__ */ jsxs3("span", { className: "lb-bundle-qty-chip", "data-qty-inline": true, children: [
966
1013
  "\xD7",
967
1014
  displayQty
968
1015
  ] })
@@ -972,7 +1019,7 @@ function FixedProductRow({ bundle, product, currency, isOos, onVariantChange })
972
1019
  }
973
1020
 
974
1021
  // src/components/MixMatchBundle.tsx
975
- import { useCallback as useCallback6, useEffect as useEffect11, useMemo as useMemo6, useState as useState8 } from "react";
1022
+ import { useCallback as useCallback6, useEffect as useEffect12, useMemo as useMemo6, useState as useState9 } from "react";
976
1023
  import {
977
1024
  formatMoney as formatMoney3,
978
1025
  formatUnitPrice as formatUnitPrice3,
@@ -982,14 +1029,14 @@ import {
982
1029
  } from "@lime-bundles/core";
983
1030
 
984
1031
  // src/hooks/useShopSettings.ts
985
- import { useEffect as useEffect7, useState as useState6 } from "react";
1032
+ import { useEffect as useEffect8, useState as useState7 } from "react";
986
1033
  import {
987
1034
  DEFAULT_OUT_OF_STOCK_BEHAVIOR as DEFAULT_OUT_OF_STOCK_BEHAVIOR2
988
1035
  } from "@lime-bundles/core";
989
1036
  function useShopSettings(options) {
990
- const [outOfStockBehavior, setOutOfStockBehavior] = useState6(DEFAULT_OUT_OF_STOCK_BEHAVIOR2);
1037
+ const [outOfStockBehavior, setOutOfStockBehavior] = useState7(DEFAULT_OUT_OF_STOCK_BEHAVIOR2);
991
1038
  const { shopDomain, storefrontAccessToken } = options;
992
- useEffect7(() => {
1039
+ useEffect8(() => {
993
1040
  const controller = new AbortController();
994
1041
  let active = true;
995
1042
  fetchShopSettingsOrDefault({
@@ -1010,10 +1057,10 @@ function useShopSettings(options) {
1010
1057
 
1011
1058
  // src/components/MixMatchPicker.tsx
1012
1059
  import {
1013
- useEffect as useEffect10,
1060
+ useEffect as useEffect11,
1014
1061
  useMemo as useMemo5,
1015
1062
  useRef as useRef6,
1016
- useState as useState7
1063
+ useState as useState8
1017
1064
  } from "react";
1018
1065
  import { createPortal } from "react-dom";
1019
1066
  import {
@@ -1025,7 +1072,7 @@ import {
1025
1072
  } from "@lime-bundles/core";
1026
1073
 
1027
1074
  // src/hooks/useScrollLock.ts
1028
- import { useEffect as useEffect8 } from "react";
1075
+ import { useEffect as useEffect9 } from "react";
1029
1076
  var lockCount = 0;
1030
1077
  var savedY = 0;
1031
1078
  function lock() {
@@ -1054,7 +1101,7 @@ function unlock() {
1054
1101
  window.scrollTo(0, savedY);
1055
1102
  }
1056
1103
  function useScrollLock(active) {
1057
- useEffect8(() => {
1104
+ useEffect9(() => {
1058
1105
  if (!active) return;
1059
1106
  lock();
1060
1107
  return unlock;
@@ -1062,7 +1109,7 @@ function useScrollLock(active) {
1062
1109
  }
1063
1110
 
1064
1111
  // src/hooks/useFocusTrap.ts
1065
- import { useEffect as useEffect9, useRef as useRef5 } from "react";
1112
+ import { useEffect as useEffect10, useRef as useRef5 } from "react";
1066
1113
  var FOCUSABLE_SELECTOR = [
1067
1114
  "a[href]",
1068
1115
  "button:not([disabled])",
@@ -1088,7 +1135,7 @@ function useFocusTrap({
1088
1135
  returnFocusRef
1089
1136
  }) {
1090
1137
  const previouslyFocused = useRef5(null);
1091
- useEffect9(() => {
1138
+ useEffect10(() => {
1092
1139
  if (!active) return;
1093
1140
  const container = containerRef.current;
1094
1141
  previouslyFocused.current = document.activeElement ?? null;
@@ -1130,10 +1177,17 @@ function useFocusTrap({
1130
1177
  }
1131
1178
 
1132
1179
  // src/components/MixMatchPicker.tsx
1133
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1134
- function ruleFor(bundle, productId) {
1180
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1181
+ function ruleFor(bundle, productId, variantId) {
1182
+ if (variantId) {
1183
+ const vRule = bundle.variantRules[variantId];
1184
+ if (vRule) return vRule;
1185
+ }
1135
1186
  return bundle.productRules[productId] ?? DEFAULT_PRODUCT_RULE;
1136
1187
  }
1188
+ function variantRuleFor(bundle, variantId) {
1189
+ return variantId ? bundle.variantRules[variantId] : void 0;
1190
+ }
1137
1191
  function sanitizeId(gid) {
1138
1192
  return gid.replace(/[^a-zA-Z0-9_-]/g, "-");
1139
1193
  }
@@ -1182,9 +1236,9 @@ function MixMatchPicker({
1182
1236
  const overlayRef = useRef6(null);
1183
1237
  const dialogRef = useRef6(null);
1184
1238
  const mouseDownTarget = useRef6(null);
1185
- const [open, setOpen] = useState7(false);
1186
- const [query, setQuery] = useState7("");
1187
- const [activeType, setActiveType] = useState7(FILTERS_ALL);
1239
+ const [open, setOpen] = useState8(false);
1240
+ const [query, setQuery] = useState8("");
1241
+ const [activeType, setActiveType] = useState8(FILTERS_ALL);
1188
1242
  const eligible = useMemo5(
1189
1243
  () => buildEligibleProducts(bundle, outOfStockBehavior),
1190
1244
  [bundle, outOfStockBehavior]
@@ -1205,7 +1259,7 @@ function MixMatchPicker({
1205
1259
  const totalUnits = selections.reduce((sum, s) => sum + s.quantity, 0);
1206
1260
  const atCapacity = totalUnits >= requiredQty;
1207
1261
  const shownUnits = Math.min(totalUnits, requiredQty);
1208
- useEffect10(() => {
1262
+ useEffect11(() => {
1209
1263
  const id = requestAnimationFrame(() => setOpen(true));
1210
1264
  return () => cancelAnimationFrame(id);
1211
1265
  }, []);
@@ -1246,7 +1300,7 @@ function MixMatchPicker({
1246
1300
  // inside carries the interactive role + focus trap. So the static-element
1247
1301
  // interaction lint does not apply to this backdrop.
1248
1302
  // eslint-disable-next-line jsx-a11y/no-static-element-interactions
1249
- /* @__PURE__ */ jsx3(
1303
+ /* @__PURE__ */ jsx4(
1250
1304
  "div",
1251
1305
  {
1252
1306
  ref: (el) => {
@@ -1258,7 +1312,7 @@ function MixMatchPicker({
1258
1312
  "data-bundle-gid": bundle.id,
1259
1313
  onMouseDown: onOverlayMouseDown,
1260
1314
  onMouseUp: onOverlayMouseUp,
1261
- children: /* @__PURE__ */ jsxs3(
1315
+ children: /* @__PURE__ */ jsxs4(
1262
1316
  "div",
1263
1317
  {
1264
1318
  ref: dialogRef,
@@ -1268,13 +1322,13 @@ function MixMatchPicker({
1268
1322
  "aria-labelledby": titleId,
1269
1323
  tabIndex: -1,
1270
1324
  children: [
1271
- /* @__PURE__ */ jsxs3("div", { className: "lb-mix-match__modal-header", children: [
1272
- /* @__PURE__ */ jsxs3("div", { className: "lb-mix-match__modal-header-top", children: [
1273
- /* @__PURE__ */ jsxs3("div", { className: "lb-mix-match__modal-heading", children: [
1274
- /* @__PURE__ */ jsx3("h4", { className: "lb-mix-match__modal-title", id: titleId, children: "Add to your bundle" }),
1275
- /* @__PURE__ */ jsx3("p", { className: "lb-mix-match__modal-subtitle", "data-modal-subtitle": true, children: subtitle })
1325
+ /* @__PURE__ */ jsxs4("div", { className: "lb-mix-match__modal-header", children: [
1326
+ /* @__PURE__ */ jsxs4("div", { className: "lb-mix-match__modal-header-top", children: [
1327
+ /* @__PURE__ */ jsxs4("div", { className: "lb-mix-match__modal-heading", children: [
1328
+ /* @__PURE__ */ jsx4("h4", { className: "lb-mix-match__modal-title", id: titleId, children: "Add to your bundle" }),
1329
+ /* @__PURE__ */ jsx4("p", { className: "lb-mix-match__modal-subtitle", "data-modal-subtitle": true, children: subtitle })
1276
1330
  ] }),
1277
- /* @__PURE__ */ jsx3(
1331
+ /* @__PURE__ */ jsx4(
1278
1332
  "button",
1279
1333
  {
1280
1334
  type: "button",
@@ -1282,16 +1336,16 @@ function MixMatchPicker({
1282
1336
  "data-modal-close": true,
1283
1337
  "aria-label": "Close",
1284
1338
  onClick: onClose,
1285
- children: /* @__PURE__ */ jsx3(CloseIcon, {})
1339
+ children: /* @__PURE__ */ jsx4(CloseIcon, {})
1286
1340
  }
1287
1341
  )
1288
1342
  ] }),
1289
- /* @__PURE__ */ jsx3(
1343
+ /* @__PURE__ */ jsx4(
1290
1344
  "div",
1291
1345
  {
1292
1346
  className: "lb-mix-match__progress lb-mix-match__modal-progress",
1293
1347
  "data-progress": true,
1294
- children: /* @__PURE__ */ jsx3(
1348
+ children: /* @__PURE__ */ jsx4(
1295
1349
  "div",
1296
1350
  {
1297
1351
  className: "lb-mix-match__progress-segments",
@@ -1299,7 +1353,7 @@ function MixMatchPicker({
1299
1353
  "aria-valuenow": shownUnits,
1300
1354
  "aria-valuemin": 0,
1301
1355
  "aria-valuemax": requiredQty,
1302
- children: Array.from({ length: requiredQty }).map((_, i) => /* @__PURE__ */ jsx3(
1356
+ children: Array.from({ length: requiredQty }).map((_, i) => /* @__PURE__ */ jsx4(
1303
1357
  "span",
1304
1358
  {
1305
1359
  className: `lb-mix-match__progress-segment${i < shownUnits ? " lb-mix-match__progress-segment--filled" : ""}`,
@@ -1312,8 +1366,8 @@ function MixMatchPicker({
1312
1366
  }
1313
1367
  )
1314
1368
  ] }),
1315
- wc.showSearch && /* @__PURE__ */ jsxs3("div", { className: "lb-mix-match__modal-search", children: [
1316
- /* @__PURE__ */ jsx3(
1369
+ wc.showSearch && /* @__PURE__ */ jsxs4("div", { className: "lb-mix-match__modal-search", children: [
1370
+ /* @__PURE__ */ jsx4(
1317
1371
  "input",
1318
1372
  {
1319
1373
  type: "text",
@@ -1327,7 +1381,7 @@ function MixMatchPicker({
1327
1381
  onChange: (e) => setQuery(e.target.value)
1328
1382
  }
1329
1383
  ),
1330
- query.length > 0 && /* @__PURE__ */ jsx3(
1384
+ query.length > 0 && /* @__PURE__ */ jsx4(
1331
1385
  "button",
1332
1386
  {
1333
1387
  type: "button",
@@ -1335,11 +1389,11 @@ function MixMatchPicker({
1335
1389
  "data-modal-search-clear": true,
1336
1390
  "aria-label": "Clear search",
1337
1391
  onClick: () => setQuery(""),
1338
- children: /* @__PURE__ */ jsx3(SearchClearIcon, {})
1392
+ children: /* @__PURE__ */ jsx4(SearchClearIcon, {})
1339
1393
  }
1340
1394
  )
1341
1395
  ] }),
1342
- showFilters && /* @__PURE__ */ jsx3(
1396
+ showFilters && /* @__PURE__ */ jsx4(
1343
1397
  "div",
1344
1398
  {
1345
1399
  className: "lb-mix-match__filters",
@@ -1348,7 +1402,7 @@ function MixMatchPicker({
1348
1402
  "aria-label": "Filter by product type",
1349
1403
  children: [FILTERS_ALL, ...productTypes].map((value) => {
1350
1404
  const isActive = value === activeType;
1351
- return /* @__PURE__ */ jsx3(
1405
+ return /* @__PURE__ */ jsx4(
1352
1406
  "button",
1353
1407
  {
1354
1408
  type: "button",
@@ -1363,7 +1417,7 @@ function MixMatchPicker({
1363
1417
  })
1364
1418
  }
1365
1419
  ),
1366
- /* @__PURE__ */ jsx3("div", { className: "lb-mix-match__modal-list", "data-modal-list": true, children: filtered.map((ep) => /* @__PURE__ */ jsx3(
1420
+ /* @__PURE__ */ jsx4("div", { className: "lb-mix-match__modal-list", "data-modal-list": true, children: filtered.map((ep) => /* @__PURE__ */ jsx4(
1367
1421
  MixMatchPickerRow,
1368
1422
  {
1369
1423
  bundle,
@@ -1382,10 +1436,10 @@ function MixMatchPicker({
1382
1436
  },
1383
1437
  ep.product.id
1384
1438
  )) }),
1385
- showEmpty && /* @__PURE__ */ jsx3("div", { className: "lb-mix-match__modal-empty", "data-modal-empty": true, children: /* @__PURE__ */ jsx3("p", { children: "No products match your search" }) }),
1386
- /* @__PURE__ */ jsx3("span", { "data-modal-live": true, "aria-live": "polite", className: "lb-visually-hidden", children: `${filtered.length} products shown` }),
1387
- /* @__PURE__ */ jsxs3("div", { className: "lb-mix-match__modal-footer", children: [
1388
- /* @__PURE__ */ jsx3(
1439
+ showEmpty && /* @__PURE__ */ jsx4("div", { className: "lb-mix-match__modal-empty", "data-modal-empty": true, children: /* @__PURE__ */ jsx4("p", { children: "No products match your search" }) }),
1440
+ /* @__PURE__ */ jsx4("span", { "data-modal-live": true, "aria-live": "polite", className: "lb-visually-hidden", children: `${filtered.length} products shown` }),
1441
+ /* @__PURE__ */ jsxs4("div", { className: "lb-mix-match__modal-footer", children: [
1442
+ /* @__PURE__ */ jsx4(
1389
1443
  "span",
1390
1444
  {
1391
1445
  className: "lb-mix-match__modal-footer-count",
@@ -1394,7 +1448,7 @@ function MixMatchPicker({
1394
1448
  children: `${shownUnits} of ${requiredQty} added`
1395
1449
  }
1396
1450
  ),
1397
- /* @__PURE__ */ jsx3(
1451
+ /* @__PURE__ */ jsx4(
1398
1452
  "button",
1399
1453
  {
1400
1454
  type: "button",
@@ -1438,6 +1492,8 @@ function MixMatchPickerRow({
1438
1492
  const showPicker = variants.length > 1 && optionNames.length > 0;
1439
1493
  const { selectedValues, selectedVariant, setOptionValue, optionsFor } = useVariantSelection({ variants, optionNames });
1440
1494
  const currentVariant = selectedVariant ?? variants.find((v) => isVariantFulfillable2(v, rule.min)) ?? eligible.firstAvailableVariant ?? variants[0] ?? null;
1495
+ const vRule = ruleFor(bundle, product.id, currentVariant?.id);
1496
+ const variantMax = variantRuleFor(bundle, currentVariant?.id)?.max;
1441
1497
  const alreadyInBundle = useMemo5(() => {
1442
1498
  if (!currentVariant) return 0;
1443
1499
  let sum = 0;
@@ -1465,22 +1521,26 @@ function MixMatchPickerRow({
1465
1521
  return sum;
1466
1522
  }, [selections, product.id, currentVariant]);
1467
1523
  const swapUnits = currentVariant ? swapUnitsFor?.(product.id, currentVariant.id) ?? 0 : 0;
1468
- const inSwapState = swapUnits >= rule.min;
1469
- const spotCeiling = inSwapState ? swapUnits : Math.min(rule.max - productOtherUnits, committedQty + remainingUnits);
1524
+ const inSwapState = swapUnits >= vRule.min;
1525
+ const spotCeiling = inSwapState ? swapUnits : Math.min(
1526
+ rule.max - productOtherUnits,
1527
+ committedQty + remainingUnits,
1528
+ variantMax ?? Infinity
1529
+ );
1470
1530
  const cap = currentVariant ? maxAddableQuantity(
1471
1531
  currentVariant,
1472
1532
  spotCeiling,
1473
1533
  Math.max(0, alreadyInBundle - committedQty)
1474
1534
  ) : 0;
1475
- const stepperMax = Math.max(rule.min, cap);
1476
- const [qty, setQty] = useState7(rule.min);
1477
- useEffect10(() => {
1478
- setQty((prev) => Math.max(rule.min, Math.min(prev, stepperMax)));
1479
- }, [stepperMax, rule.min]);
1535
+ const stepperMax = Math.max(vRule.min, cap);
1536
+ const [qty, setQty] = useState8(vRule.min);
1537
+ useEffect11(() => {
1538
+ setQty((prev) => Math.max(vRule.min, Math.min(prev, stepperMax)));
1539
+ }, [stepperMax, vRule.min]);
1480
1540
  const currentVariantId = currentVariant?.id ?? null;
1481
- useEffect10(() => {
1482
- if (!variantInBundle) setQty(rule.min);
1483
- }, [variantInBundle, currentVariantId, rule.min]);
1541
+ useEffect11(() => {
1542
+ if (!variantInBundle) setQty(vRule.min);
1543
+ }, [variantInBundle, currentVariantId, vRule.min]);
1484
1544
  if (!currentVariant) return null;
1485
1545
  const thumbImage = currentVariant.image ?? product.featuredImage ?? null;
1486
1546
  const unitPriceText = formatUnitPrice2(
@@ -1488,8 +1548,8 @@ function MixMatchPickerRow({
1488
1548
  currentVariant.unitPriceMeasurement,
1489
1549
  currency
1490
1550
  );
1491
- const noStock = cap < rule.min;
1492
- const needsMoreSpots = !variantInBundle && !inSwapState && rule.min > remainingUnits;
1551
+ const noStock = cap < vRule.min;
1552
+ const needsMoreSpots = !variantInBundle && !inSwapState && vRule.min > remainingUnits;
1493
1553
  const addDisabled = !variantInBundle && (inSwapState ? noStock : atCapacity || noStock || needsMoreSpots);
1494
1554
  const lockedRequired = variantInBundle && currentVariant != null && !(canRemoveVariant?.(currentVariant.id) ?? true);
1495
1555
  const stepperDisabled = isOos || !variantInBundle && addDisabled;
@@ -1500,7 +1560,7 @@ function MixMatchPickerRow({
1500
1560
  return;
1501
1561
  }
1502
1562
  if (!currentVariant || noStock) return;
1503
- const pickedQty = showStepper ? qty : rule.min;
1563
+ const pickedQty = showStepper ? qty : vRule.min;
1504
1564
  const item = {
1505
1565
  productId: product.id,
1506
1566
  variantId: currentVariant.id,
@@ -1522,7 +1582,7 @@ function MixMatchPickerRow({
1522
1582
  }
1523
1583
  const priceCents = parseFloat(currentVariant.price.amount);
1524
1584
  const compareCents = currentVariant.compareAtPrice ? parseFloat(currentVariant.compareAtPrice.amount) : null;
1525
- return /* @__PURE__ */ jsxs3(
1585
+ return /* @__PURE__ */ jsxs4(
1526
1586
  "div",
1527
1587
  {
1528
1588
  className: `lb-mix-match__modal-product${isOos ? " lb-mix-match__modal-product--sold-out" : ""}${variantInBundle ? " lb-mix-match__modal-product--in-bundle" : ""}`,
@@ -1531,8 +1591,8 @@ function MixMatchPickerRow({
1531
1591
  "data-type": product.productType ?? "",
1532
1592
  "aria-disabled": isOos || void 0,
1533
1593
  children: [
1534
- /* @__PURE__ */ jsxs3("div", { className: "lb-mix-match__modal-product-thumb", children: [
1535
- thumbImage && /* @__PURE__ */ jsx3(
1594
+ /* @__PURE__ */ jsxs4("div", { className: "lb-mix-match__modal-product-thumb", children: [
1595
+ thumbImage && /* @__PURE__ */ jsx4(
1536
1596
  "img",
1537
1597
  {
1538
1598
  src: thumbImage.url,
@@ -1540,10 +1600,10 @@ function MixMatchPickerRow({
1540
1600
  loading: "lazy"
1541
1601
  }
1542
1602
  ),
1543
- variantInBundle && /* @__PURE__ */ jsx3("span", { className: "lb-mix-match__modal-added-badge", children: "Added" })
1603
+ variantInBundle && /* @__PURE__ */ jsx4("span", { className: "lb-mix-match__modal-added-badge", children: "Added" })
1544
1604
  ] }),
1545
- /* @__PURE__ */ jsxs3("div", { className: "lb-mix-match__modal-product-info", children: [
1546
- /* @__PURE__ */ jsx3("p", { className: "lb-mix-match__modal-product-title", children: /* @__PURE__ */ jsx3(
1605
+ /* @__PURE__ */ jsxs4("div", { className: "lb-mix-match__modal-product-info", children: [
1606
+ /* @__PURE__ */ jsx4("p", { className: "lb-mix-match__modal-product-title", children: /* @__PURE__ */ jsx4(
1547
1607
  "a",
1548
1608
  {
1549
1609
  href: `/products/${product.handle}`,
@@ -1552,24 +1612,24 @@ function MixMatchPickerRow({
1552
1612
  children: product.title
1553
1613
  }
1554
1614
  ) }),
1555
- /* @__PURE__ */ jsxs3("p", { className: "lb-mix-match__modal-product-price", children: [
1556
- /* @__PURE__ */ jsx3("span", { "data-row-price-sale": true, children: formatMoney2(priceCents, currency) }),
1557
- compareCents !== null && compareCents > priceCents && /* @__PURE__ */ jsx3("s", { className: "lb-mix-match__modal-product-compare", "data-row-compare": true, children: formatMoney2(compareCents, currency) })
1615
+ /* @__PURE__ */ jsxs4("p", { className: "lb-mix-match__modal-product-price", children: [
1616
+ /* @__PURE__ */ jsx4("span", { "data-row-price-sale": true, children: formatMoney2(priceCents, currency) }),
1617
+ compareCents !== null && compareCents > priceCents && /* @__PURE__ */ jsx4("s", { className: "lb-mix-match__modal-product-compare", "data-row-compare": true, children: formatMoney2(compareCents, currency) })
1558
1618
  ] }),
1559
- unitPriceText && /* @__PURE__ */ jsx3("p", { className: "lb-mix-match__modal-product-unit-price lb-bundle-product-unit-price", children: unitPriceText }),
1560
- showPicker && /* @__PURE__ */ jsx3("div", { className: "lb-bundle-variant-option-groups", children: optionNames.map((optionName, optionIndex) => {
1619
+ unitPriceText && /* @__PURE__ */ jsx4("p", { className: "lb-mix-match__modal-product-unit-price lb-bundle-product-unit-price", children: unitPriceText }),
1620
+ showPicker && /* @__PURE__ */ jsx4("div", { className: "lb-bundle-variant-option-groups", children: optionNames.map((optionName, optionIndex) => {
1561
1621
  const dropdownOptions = optionsFor(optionIndex).map((o) => ({
1562
1622
  value: o.value,
1563
1623
  label: o.value,
1564
1624
  disabled: o.disabled
1565
1625
  }));
1566
- return /* @__PURE__ */ jsxs3(
1626
+ return /* @__PURE__ */ jsxs4(
1567
1627
  "div",
1568
1628
  {
1569
1629
  className: "lb-bundle-variant-option-group",
1570
1630
  children: [
1571
- /* @__PURE__ */ jsx3("span", { className: "lb-bundle-variant-option-label", children: optionName }),
1572
- /* @__PURE__ */ jsx3(
1631
+ /* @__PURE__ */ jsx4("span", { className: "lb-bundle-variant-option-label", children: optionName }),
1632
+ /* @__PURE__ */ jsx4(
1573
1633
  VariantDropdown,
1574
1634
  {
1575
1635
  className: "lb-mix-match__variant-select-dropdown",
@@ -1584,17 +1644,17 @@ function MixMatchPickerRow({
1584
1644
  optionName
1585
1645
  );
1586
1646
  }) }),
1587
- !showPicker && variants.length === 1 && currentVariant.title !== "Default Title" && /* @__PURE__ */ jsx3("span", { className: "lb-mix-match__filled-variant", children: currentVariant.title }),
1588
- !isOos && needsMoreSpots && remainingUnits > 0 && /* @__PURE__ */ jsx3("span", { className: "lb-mix-match__modal-needs-spots", children: rule.min === 1 ? "Needs 1 spot" : `Needs ${rule.min} spots` }),
1589
- isOos ? /* @__PURE__ */ jsx3("span", { className: "lb-mix-match__modal-sold-out-label", children: "Sold out" }) : /* @__PURE__ */ jsxs3("div", { className: "lb-mix-match__modal-product-actions", children: [
1590
- showStepper && /* @__PURE__ */ jsx3("div", { className: "lb-bundle-variant-option-group lb-mix-match__qty-stepper-group", children: /* @__PURE__ */ jsxs3(
1647
+ !showPicker && variants.length === 1 && currentVariant.title !== "Default Title" && /* @__PURE__ */ jsx4("span", { className: "lb-mix-match__filled-variant", children: currentVariant.title }),
1648
+ !isOos && needsMoreSpots && remainingUnits > 0 && /* @__PURE__ */ jsx4("span", { className: "lb-mix-match__modal-needs-spots", children: rule.min === 1 ? "Needs 1 spot" : `Needs ${rule.min} spots` }),
1649
+ isOos ? /* @__PURE__ */ jsx4("span", { className: "lb-mix-match__modal-sold-out-label", children: "Sold out" }) : /* @__PURE__ */ jsxs4("div", { className: "lb-mix-match__modal-product-actions", children: [
1650
+ showStepper && /* @__PURE__ */ jsx4("div", { className: "lb-bundle-variant-option-group lb-mix-match__qty-stepper-group", children: /* @__PURE__ */ jsxs4(
1591
1651
  "div",
1592
1652
  {
1593
1653
  className: "lb-mix-match__qty-stepper",
1594
1654
  role: "group",
1595
1655
  "aria-label": "Quantity",
1596
1656
  children: [
1597
- /* @__PURE__ */ jsx3(
1657
+ /* @__PURE__ */ jsx4(
1598
1658
  "button",
1599
1659
  {
1600
1660
  type: "button",
@@ -1615,7 +1675,7 @@ function MixMatchPickerRow({
1615
1675
  children: "\u2212"
1616
1676
  }
1617
1677
  ),
1618
- /* @__PURE__ */ jsx3(
1678
+ /* @__PURE__ */ jsx4(
1619
1679
  "span",
1620
1680
  {
1621
1681
  className: "lb-mix-match__qty-stepper-value",
@@ -1624,7 +1684,7 @@ function MixMatchPickerRow({
1624
1684
  children: shownQty
1625
1685
  }
1626
1686
  ),
1627
- /* @__PURE__ */ jsx3(
1687
+ /* @__PURE__ */ jsx4(
1628
1688
  "button",
1629
1689
  {
1630
1690
  type: "button",
@@ -1648,7 +1708,7 @@ function MixMatchPickerRow({
1648
1708
  ]
1649
1709
  }
1650
1710
  ) }),
1651
- /* @__PURE__ */ jsx3(
1711
+ /* @__PURE__ */ jsx4(
1652
1712
  "button",
1653
1713
  {
1654
1714
  type: "button",
@@ -1667,7 +1727,7 @@ function MixMatchPickerRow({
1667
1727
  );
1668
1728
  }
1669
1729
  function CloseIcon() {
1670
- return /* @__PURE__ */ jsxs3(
1730
+ return /* @__PURE__ */ jsxs4(
1671
1731
  "svg",
1672
1732
  {
1673
1733
  width: "20",
@@ -1677,14 +1737,14 @@ function CloseIcon() {
1677
1737
  xmlns: "http://www.w3.org/2000/svg",
1678
1738
  "aria-hidden": "true",
1679
1739
  children: [
1680
- /* @__PURE__ */ jsx3("line", { x1: "5", y1: "5", x2: "15", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
1681
- /* @__PURE__ */ jsx3("line", { x1: "15", y1: "5", x2: "5", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
1740
+ /* @__PURE__ */ jsx4("line", { x1: "5", y1: "5", x2: "15", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
1741
+ /* @__PURE__ */ jsx4("line", { x1: "15", y1: "5", x2: "5", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
1682
1742
  ]
1683
1743
  }
1684
1744
  );
1685
1745
  }
1686
1746
  function SearchClearIcon() {
1687
- return /* @__PURE__ */ jsx3(
1747
+ return /* @__PURE__ */ jsx4(
1688
1748
  "svg",
1689
1749
  {
1690
1750
  width: "16",
@@ -1693,17 +1753,25 @@ function SearchClearIcon() {
1693
1753
  fill: "currentColor",
1694
1754
  xmlns: "http://www.w3.org/2000/svg",
1695
1755
  "aria-hidden": "true",
1696
- children: /* @__PURE__ */ jsx3("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" })
1756
+ children: /* @__PURE__ */ jsx4("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" })
1697
1757
  }
1698
1758
  );
1699
1759
  }
1700
1760
 
1701
1761
  // src/components/MixMatchBundle.tsx
1702
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1703
- function ruleFor2(bundle, productId) {
1762
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1763
+ function ruleFor2(bundle, productId, variantId) {
1764
+ if (variantId) {
1765
+ const vRule = bundle.variantRules[variantId];
1766
+ if (vRule) return vRule;
1767
+ }
1704
1768
  return bundle.productRules[productId] ?? DEFAULT_PRODUCT_RULE2;
1705
1769
  }
1770
+ function variantRuleFor2(bundle, variantId) {
1771
+ return variantId ? bundle.variantRules[variantId] : void 0;
1772
+ }
1706
1773
  function canRemoveItem(bundle, selections, item) {
1774
+ if (variantRuleFor2(bundle, item.variantId)?.required) return false;
1707
1775
  const rule = ruleFor2(bundle, item.productId);
1708
1776
  if (!rule.required) return true;
1709
1777
  const unitsElsewhere = selections.filter((s) => s.productId === item.productId && s !== item).reduce((sum, s) => sum + s.quantity, 0);
@@ -1724,7 +1792,8 @@ function MixMatchBundle(props) {
1724
1792
  analyticsEnabled,
1725
1793
  onAddToCart,
1726
1794
  onError,
1727
- className
1795
+ className,
1796
+ productHandle
1728
1797
  } = props;
1729
1798
  const result = useBundleData({
1730
1799
  shopDomain,
@@ -1742,16 +1811,16 @@ function MixMatchBundle(props) {
1742
1811
  bundleType: "mix_match",
1743
1812
  enabled: analyticsEnabled !== false
1744
1813
  });
1745
- const [selections, setSelections] = useState8([]);
1746
- const [seededFor, setSeededFor] = useState8(null);
1747
- const [pickerOpen, setPickerOpen] = useState8(false);
1748
- const [addingToCart, setAddingToCart] = useState8(false);
1749
- const [cartError, setCartError] = useState8(null);
1814
+ const [selections, setSelections] = useState9([]);
1815
+ const [seededFor, setSeededFor] = useState9(null);
1816
+ const [pickerOpen, setPickerOpen] = useState9(false);
1817
+ const [addingToCart, setAddingToCart] = useState9(false);
1818
+ const [cartError, setCartError] = useState9(null);
1750
1819
  const bundle = result.status === "success" && result.bundle.bundleType === "mix_match" ? result.bundle : null;
1751
1820
  const setConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);
1752
1821
  const setModalConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);
1753
1822
  const slotsEdgeFadeRef = useEdgeFade();
1754
- useEffect11(() => {
1823
+ useEffect12(() => {
1755
1824
  if (result.status === "error") {
1756
1825
  onError?.(result.error);
1757
1826
  return;
@@ -1764,37 +1833,64 @@ function MixMatchBundle(props) {
1764
1833
  );
1765
1834
  }
1766
1835
  }, [result, onError]);
1767
- useEffect11(() => {
1836
+ useEffect12(() => {
1768
1837
  if (!bundle || seededFor === bundle.id) return;
1769
1838
  setSeededFor(bundle.id);
1770
1839
  const seedCurrency = bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? "USD";
1840
+ const pick = (product, variant, quantity) => ({
1841
+ productId: product.id,
1842
+ variantId: variant.id,
1843
+ title: product.title,
1844
+ url: `/products/${product.handle}`,
1845
+ variantTitle: variant.title,
1846
+ featuredImage: variant.image?.url ?? product.featuredImage?.url ?? null,
1847
+ price: parseFloat(variant.price.amount),
1848
+ compareAtPrice: variant.compareAtPrice ? parseFloat(variant.compareAtPrice.amount) : null,
1849
+ unitPrice: formatUnitPrice3(
1850
+ variant.unitPrice,
1851
+ variant.unitPriceMeasurement,
1852
+ seedCurrency
1853
+ ),
1854
+ quantity
1855
+ });
1771
1856
  const seeds = [];
1772
- for (const [pid, rule] of Object.entries(bundle.productRules)) {
1773
- if (!rule.required) continue;
1774
- const product = bundle.products.find((p) => p.id === pid);
1775
- const variant = product?.variants.nodes.find(
1857
+ for (const product of bundle.products) {
1858
+ let seededVariant = false;
1859
+ for (const variant2 of product.variants.nodes) {
1860
+ const vRule = bundle.variantRules[variant2.id];
1861
+ if (!vRule?.required) continue;
1862
+ if (!isVariantFulfillable3(variant2, Math.max(1, vRule.min))) continue;
1863
+ seeds.push(pick(product, variant2, Math.max(1, vRule.min)));
1864
+ seededVariant = true;
1865
+ }
1866
+ if (seededVariant) continue;
1867
+ const rule = bundle.productRules[product.id];
1868
+ if (!rule?.required) continue;
1869
+ const variant = product.variants.nodes.find(
1776
1870
  (v) => isVariantFulfillable3(v, rule.min)
1777
1871
  );
1778
- if (!product || !variant) continue;
1779
- seeds.push({
1780
- productId: product.id,
1781
- variantId: variant.id,
1782
- title: product.title,
1783
- url: `/products/${product.handle}`,
1784
- variantTitle: variant.title,
1785
- featuredImage: variant.image?.url ?? product.featuredImage?.url ?? null,
1786
- price: parseFloat(variant.price.amount),
1787
- compareAtPrice: variant.compareAtPrice ? parseFloat(variant.compareAtPrice.amount) : null,
1788
- unitPrice: formatUnitPrice3(
1789
- variant.unitPrice,
1790
- variant.unitPriceMeasurement,
1791
- seedCurrency
1792
- ),
1793
- quantity: rule.min
1794
- });
1872
+ if (!variant) continue;
1873
+ seeds.push(pick(product, variant, rule.min));
1874
+ }
1875
+ if (seeds.length === 0 && productHandle) {
1876
+ const requiredUnits2 = bundle.minQuantity ?? 0;
1877
+ const qualifies = (p) => {
1878
+ const min = bundle.productRules[p.id]?.min ?? 1;
1879
+ return min <= requiredUnits2 && p.variants.nodes.some((v) => isVariantFulfillable3(v, min));
1880
+ };
1881
+ const seed = bundle.products.find(
1882
+ (p) => p.handle === productHandle && qualifies(p)
1883
+ ) ?? bundle.products.find(qualifies);
1884
+ if (seed) {
1885
+ const min = bundle.productRules[seed.id]?.min ?? 1;
1886
+ const variant = seed.variants.nodes.find(
1887
+ (v) => isVariantFulfillable3(v, min)
1888
+ );
1889
+ if (variant) seeds.push(pick(seed, variant, min));
1890
+ }
1795
1891
  }
1796
1892
  if (seeds.length > 0) setSelections(seeds);
1797
- }, [bundle, seededFor]);
1893
+ }, [bundle, seededFor, productHandle]);
1798
1894
  const showStepper = bundle?.widgetConfig.mixMatchShowQuantitySelector !== false;
1799
1895
  const requiredUnits = bundle?.minQuantity ?? 0;
1800
1896
  const totalQuantity = useMemo6(
@@ -1954,9 +2050,9 @@ function MixMatchBundle(props) {
1954
2050
  }
1955
2051
  }, [bundle, selections, valid, onAddToCart, onError, trackAddToCart, totalQuantity]);
1956
2052
  if (result.status === "loading") {
1957
- return /* @__PURE__ */ jsxs4("div", { className: `lb-bundle lb-bundle--loading ${className ?? ""}`, children: [
1958
- /* @__PURE__ */ jsx4("div", { className: "lb-skeleton lb-skeleton--title" }),
1959
- /* @__PURE__ */ jsx4("div", { className: "lb-skeleton lb-skeleton--products" })
2053
+ return /* @__PURE__ */ jsxs5("div", { className: `lb-bundle lb-bundle--loading ${className ?? ""}`, children: [
2054
+ /* @__PURE__ */ jsx5("div", { className: "lb-skeleton lb-skeleton--title" }),
2055
+ /* @__PURE__ */ jsx5("div", { className: "lb-skeleton lb-skeleton--products" })
1960
2056
  ] });
1961
2057
  }
1962
2058
  if (result.status === "error") return null;
@@ -1975,7 +2071,7 @@ function MixMatchBundle(props) {
1975
2071
  if (requiredBlocked) return null;
1976
2072
  const currency = bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? "USD";
1977
2073
  const ctaLabel = addingToCart ? "Adding..." : bundle.widgetConfig.cta.ctaText || "Add to cart";
1978
- return /* @__PURE__ */ jsxs4(
2074
+ return /* @__PURE__ */ jsxs5(
1979
2075
  "div",
1980
2076
  {
1981
2077
  ref: (el) => {
@@ -1987,12 +2083,19 @@ function MixMatchBundle(props) {
1987
2083
  "aria-label": bundle.title,
1988
2084
  "data-required-quantity": requiredUnits,
1989
2085
  children: [
1990
- /* @__PURE__ */ jsx4("div", { className: "lb-bundle-header", children: /* @__PURE__ */ jsxs4("div", { className: "lb-bundle-header__content", children: [
1991
- /* @__PURE__ */ jsx4("h3", { className: "lb-bundle-title", children: bundle.title }),
1992
- bundle.description && /* @__PURE__ */ jsx4("p", { className: "lb-bundle-subtitle", children: bundle.description })
2086
+ /* @__PURE__ */ jsx5("div", { className: "lb-bundle-header", children: /* @__PURE__ */ jsxs5("div", { className: "lb-bundle-header__content", children: [
2087
+ /* @__PURE__ */ jsx5("h3", { className: "lb-bundle-title", children: bundle.title }),
2088
+ bundle.description && /* @__PURE__ */ jsx5("p", { className: "lb-bundle-subtitle", children: bundle.description })
1993
2089
  ] }) }),
1994
- /* @__PURE__ */ jsxs4("div", { className: "lb-mix-match__progress", "data-progress": true, children: [
1995
- /* @__PURE__ */ jsx4(
2090
+ /* @__PURE__ */ jsx5(
2091
+ BundleCountdown,
2092
+ {
2093
+ endsAt: bundle.endsAt,
2094
+ widgetConfig: bundle.widgetConfig
2095
+ }
2096
+ ),
2097
+ /* @__PURE__ */ jsxs5("div", { className: "lb-mix-match__progress", "data-progress": true, children: [
2098
+ /* @__PURE__ */ jsx5(
1996
2099
  "div",
1997
2100
  {
1998
2101
  className: "lb-mix-match__progress-segments",
@@ -2000,7 +2103,7 @@ function MixMatchBundle(props) {
2000
2103
  "aria-valuenow": shownUnits,
2001
2104
  "aria-valuemin": 0,
2002
2105
  "aria-valuemax": requiredUnits,
2003
- children: Array.from({ length: requiredUnits }).map((_, i) => /* @__PURE__ */ jsx4(
2106
+ children: Array.from({ length: requiredUnits }).map((_, i) => /* @__PURE__ */ jsx5(
2004
2107
  "span",
2005
2108
  {
2006
2109
  className: `lb-mix-match__progress-segment${i < shownUnits ? " lb-mix-match__progress-segment--filled" : ""}`,
@@ -2010,8 +2113,8 @@ function MixMatchBundle(props) {
2010
2113
  ))
2011
2114
  }
2012
2115
  ),
2013
- /* @__PURE__ */ jsxs4("div", { className: "lb-mix-match__progress-labels", children: [
2014
- /* @__PURE__ */ jsx4(
2116
+ /* @__PURE__ */ jsxs5("div", { className: "lb-mix-match__progress-labels", children: [
2117
+ /* @__PURE__ */ jsx5(
2015
2118
  "span",
2016
2119
  {
2017
2120
  className: "lb-mix-match__progress-count",
@@ -2020,7 +2123,7 @@ function MixMatchBundle(props) {
2020
2123
  children: `${shownUnits} of ${requiredUnits} added`
2021
2124
  }
2022
2125
  ),
2023
- /* @__PURE__ */ jsx4(
2126
+ /* @__PURE__ */ jsx5(
2024
2127
  "span",
2025
2128
  {
2026
2129
  className: "lb-mix-match__progress-remaining",
@@ -2031,7 +2134,7 @@ function MixMatchBundle(props) {
2031
2134
  )
2032
2135
  ] })
2033
2136
  ] }),
2034
- /* @__PURE__ */ jsx4(
2137
+ /* @__PURE__ */ jsx5(
2035
2138
  "div",
2036
2139
  {
2037
2140
  className: "lb-mix-match__slots lb-edge-fade",
@@ -2042,15 +2145,15 @@ function MixMatchBundle(props) {
2042
2145
  button provides the keyboard/AT path (its activation bubbles
2043
2146
  here); × stops propagation. */
2044
2147
  // 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
2045
- /* @__PURE__ */ jsxs4(
2148
+ /* @__PURE__ */ jsxs5(
2046
2149
  "div",
2047
2150
  {
2048
2151
  className: "lb-mix-match__slot lb-mix-match__slot--filled",
2049
2152
  onClick: () => setPickerOpen(true),
2050
2153
  children: [
2051
- item.featuredImage && /* @__PURE__ */ jsx4("div", { className: "lb-bundle-thumbnail", children: /* @__PURE__ */ jsx4("img", { src: item.featuredImage, alt: item.title, loading: "lazy" }) }),
2052
- /* @__PURE__ */ jsxs4("div", { className: "lb-mix-match__filled-info", children: [
2053
- /* @__PURE__ */ jsx4(
2154
+ item.featuredImage && /* @__PURE__ */ jsx5("div", { className: "lb-bundle-thumbnail", children: /* @__PURE__ */ jsx5("img", { src: item.featuredImage, alt: item.title, loading: "lazy" }) }),
2155
+ /* @__PURE__ */ jsxs5("div", { className: "lb-mix-match__filled-info", children: [
2156
+ /* @__PURE__ */ jsx5(
2054
2157
  "button",
2055
2158
  {
2056
2159
  type: "button",
@@ -2059,15 +2162,15 @@ function MixMatchBundle(props) {
2059
2162
  children: item.title
2060
2163
  }
2061
2164
  ),
2062
- item.variantTitle && item.variantTitle !== "Default Title" && /* @__PURE__ */ jsx4("span", { className: "lb-mix-match__filled-variant", children: item.variantTitle }),
2063
- /* @__PURE__ */ jsxs4("span", { className: "lb-mix-match__filled-price", children: [
2064
- item.compareAtPrice !== null && item.compareAtPrice > item.price && /* @__PURE__ */ jsx4("s", { className: "lb-mix-match__filled-compare", children: formatMoney3(item.compareAtPrice, currency) }),
2065
- /* @__PURE__ */ jsx4("span", { className: "lb-bundle-product-price", children: formatMoney3(item.price, currency) }),
2066
- /* @__PURE__ */ jsx4("span", { className: "lb-bundle-qty-inline", children: `\xD7${item.quantity}` })
2165
+ item.variantTitle && item.variantTitle !== "Default Title" && /* @__PURE__ */ jsx5("span", { className: "lb-mix-match__filled-variant", children: item.variantTitle }),
2166
+ /* @__PURE__ */ jsxs5("span", { className: "lb-mix-match__filled-price", children: [
2167
+ item.compareAtPrice !== null && item.compareAtPrice > item.price && /* @__PURE__ */ jsx5("s", { className: "lb-mix-match__filled-compare", children: formatMoney3(item.compareAtPrice, currency) }),
2168
+ /* @__PURE__ */ jsx5("span", { className: "lb-bundle-product-price", children: formatMoney3(item.price, currency) }),
2169
+ /* @__PURE__ */ jsx5("span", { className: "lb-bundle-qty-inline", children: `\xD7${item.quantity}` })
2067
2170
  ] }),
2068
- item.unitPrice && /* @__PURE__ */ jsx4("span", { className: "lb-bundle-product-unit-price", children: item.unitPrice })
2171
+ item.unitPrice && /* @__PURE__ */ jsx5("span", { className: "lb-bundle-product-unit-price", children: item.unitPrice })
2069
2172
  ] }),
2070
- canRemoveItem(bundle, selections, item) ? /* @__PURE__ */ jsx4(
2173
+ canRemoveItem(bundle, selections, item) ? /* @__PURE__ */ jsx5(
2071
2174
  "button",
2072
2175
  {
2073
2176
  type: "button",
@@ -2077,13 +2180,13 @@ function MixMatchBundle(props) {
2077
2180
  e.stopPropagation();
2078
2181
  removeSlot(index);
2079
2182
  },
2080
- children: /* @__PURE__ */ jsx4(CloseIcon2, {})
2183
+ children: /* @__PURE__ */ jsx5(CloseIcon2, {})
2081
2184
  }
2082
2185
  ) : (
2083
2186
  /* Required pick at its floor — quiet state chip instead of
2084
2187
  the ×; removal returns once another slot covers the
2085
2188
  product's minimum (variant swap flow). */
2086
- /* @__PURE__ */ jsx4("span", { className: "lb-mix-match__slot-required", children: "Required" })
2189
+ /* @__PURE__ */ jsx5("span", { className: "lb-mix-match__slot-required", children: "Required" })
2087
2190
  )
2088
2191
  ]
2089
2192
  },
@@ -2092,7 +2195,7 @@ function MixMatchBundle(props) {
2092
2195
  ))
2093
2196
  }
2094
2197
  ),
2095
- totalQuantity < requiredUnits && /* @__PURE__ */ jsxs4(
2198
+ totalQuantity < requiredUnits && /* @__PURE__ */ jsxs5(
2096
2199
  "button",
2097
2200
  {
2098
2201
  type: "button",
@@ -2100,34 +2203,34 @@ function MixMatchBundle(props) {
2100
2203
  "data-add-product-trigger": true,
2101
2204
  onClick: () => setPickerOpen(true),
2102
2205
  children: [
2103
- /* @__PURE__ */ jsx4("span", { className: "lb-mix-match__add-product-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx4(PlusIcon, {}) }),
2104
- /* @__PURE__ */ jsx4("span", { className: "lb-mix-match__add-product-label", children: "Add a product" })
2206
+ /* @__PURE__ */ jsx5("span", { className: "lb-mix-match__add-product-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx5(PlusIcon, {}) }),
2207
+ /* @__PURE__ */ jsx5("span", { className: "lb-mix-match__add-product-label", children: "Add a product" })
2105
2208
  ]
2106
2209
  }
2107
2210
  ),
2108
- /* @__PURE__ */ jsx4("div", { className: "lb-bundle-divider" }),
2109
- selections.length > 0 && /* @__PURE__ */ jsxs4("div", { className: "lb-bundle-summary", "data-pricing-section": true, children: [
2110
- /* @__PURE__ */ jsxs4("div", { className: "lb-bundle-summary__text", children: [
2111
- /* @__PURE__ */ jsx4("span", { className: "lb-bundle-summary__label", children: "Bundle total" }),
2112
- bundle.widgetConfig.savingsBar.visible && summary.savings > 0 && /* @__PURE__ */ jsxs4("p", { className: "lb-bundle-savings-line", "data-savings-bar": true, children: [
2211
+ /* @__PURE__ */ jsx5("div", { className: "lb-bundle-divider" }),
2212
+ selections.length > 0 && /* @__PURE__ */ jsxs5("div", { className: "lb-bundle-summary", "data-pricing-section": true, children: [
2213
+ /* @__PURE__ */ jsxs5("div", { className: "lb-bundle-summary__text", children: [
2214
+ /* @__PURE__ */ jsx5("span", { className: "lb-bundle-summary__label", children: "Bundle total" }),
2215
+ bundle.widgetConfig.savingsBar.visible && summary.savings > 0 && /* @__PURE__ */ jsxs5("p", { className: "lb-bundle-savings-line", "data-savings-bar": true, children: [
2113
2216
  "You save",
2114
2217
  " ",
2115
- /* @__PURE__ */ jsx4("span", { "data-savings-amount": true, children: formatMoney3(summary.savings, currency) }),
2218
+ /* @__PURE__ */ jsx5("span", { "data-savings-amount": true, children: formatMoney3(summary.savings, currency) }),
2116
2219
  " ",
2117
- /* @__PURE__ */ jsxs4("span", { "data-savings-percent": true, children: [
2220
+ /* @__PURE__ */ jsxs5("span", { "data-savings-percent": true, children: [
2118
2221
  "(",
2119
2222
  summary.savingsPercent,
2120
2223
  "%)"
2121
2224
  ] })
2122
2225
  ] })
2123
2226
  ] }),
2124
- /* @__PURE__ */ jsxs4("span", { className: "lb-bundle-summary__prices", children: [
2125
- bundle.widgetConfig.pricing.showComparePrice && summary.savings > 0 && /* @__PURE__ */ jsx4("span", { className: "lb-bundle-compare-price", "data-compare-price": true, children: formatMoney3(summary.comparePrice, currency) }),
2126
- /* @__PURE__ */ jsx4("span", { className: "lb-bundle-sale-price", "data-sale-price": true, children: formatMoney3(summary.salePrice, currency) })
2227
+ /* @__PURE__ */ jsxs5("span", { className: "lb-bundle-summary__prices", children: [
2228
+ bundle.widgetConfig.pricing.showComparePrice && summary.savings > 0 && /* @__PURE__ */ jsx5("span", { className: "lb-bundle-compare-price", "data-compare-price": true, children: formatMoney3(summary.comparePrice, currency) }),
2229
+ /* @__PURE__ */ jsx5("span", { className: "lb-bundle-sale-price", "data-sale-price": true, children: formatMoney3(summary.salePrice, currency) })
2127
2230
  ] })
2128
2231
  ] }),
2129
- cartError && /* @__PURE__ */ jsx4("p", { className: "lb-bundle__error", role: "alert", children: cartError }),
2130
- /* @__PURE__ */ jsx4(
2232
+ cartError && /* @__PURE__ */ jsx5("p", { className: "lb-bundle__error", role: "alert", children: cartError }),
2233
+ /* @__PURE__ */ jsx5(
2131
2234
  "button",
2132
2235
  {
2133
2236
  className: "lb-bundle__cta",
@@ -2137,7 +2240,7 @@ function MixMatchBundle(props) {
2137
2240
  children: ctaLabel
2138
2241
  }
2139
2242
  ),
2140
- pickerOpen && /* @__PURE__ */ jsx4(
2243
+ pickerOpen && /* @__PURE__ */ jsx5(
2141
2244
  MixMatchPicker,
2142
2245
  {
2143
2246
  outOfStockBehavior,
@@ -2178,7 +2281,7 @@ function countInStockProducts(bundle) {
2178
2281
  return count;
2179
2282
  }
2180
2283
  function PlusIcon() {
2181
- return /* @__PURE__ */ jsxs4(
2284
+ return /* @__PURE__ */ jsxs5(
2182
2285
  "svg",
2183
2286
  {
2184
2287
  width: "18",
@@ -2188,14 +2291,14 @@ function PlusIcon() {
2188
2291
  xmlns: "http://www.w3.org/2000/svg",
2189
2292
  "aria-hidden": "true",
2190
2293
  children: [
2191
- /* @__PURE__ */ jsx4("line", { x1: "9", y1: "3", x2: "9", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
2192
- /* @__PURE__ */ jsx4("line", { x1: "3", y1: "9", x2: "15", y2: "9", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
2294
+ /* @__PURE__ */ jsx5("line", { x1: "9", y1: "3", x2: "9", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
2295
+ /* @__PURE__ */ jsx5("line", { x1: "3", y1: "9", x2: "15", y2: "9", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
2193
2296
  ]
2194
2297
  }
2195
2298
  );
2196
2299
  }
2197
2300
  function CloseIcon2() {
2198
- return /* @__PURE__ */ jsxs4(
2301
+ return /* @__PURE__ */ jsxs5(
2199
2302
  "svg",
2200
2303
  {
2201
2304
  width: "16",
@@ -2205,25 +2308,28 @@ function CloseIcon2() {
2205
2308
  xmlns: "http://www.w3.org/2000/svg",
2206
2309
  "aria-hidden": "true",
2207
2310
  children: [
2208
- /* @__PURE__ */ jsx4("line", { x1: "5", y1: "5", x2: "15", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
2209
- /* @__PURE__ */ jsx4("line", { x1: "15", y1: "5", x2: "5", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
2311
+ /* @__PURE__ */ jsx5("line", { x1: "5", y1: "5", x2: "15", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
2312
+ /* @__PURE__ */ jsx5("line", { x1: "15", y1: "5", x2: "5", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
2210
2313
  ]
2211
2314
  }
2212
2315
  );
2213
2316
  }
2214
2317
 
2215
2318
  // src/components/VolumeBundle.tsx
2216
- import { useCallback as useCallback7, useEffect as useEffect12, useMemo as useMemo7, useState as useState9 } from "react";
2319
+ import { useCallback as useCallback7, useEffect as useEffect13, useMemo as useMemo7, useState as useState10 } from "react";
2217
2320
  import {
2218
2321
  formatMoney as formatMoney4,
2219
2322
  formatUnitPrice as formatUnitPrice4,
2220
2323
  calculateTierSavings,
2221
2324
  getActiveTier,
2222
2325
  getMinTierQuantity,
2326
+ bestValueTierIndex,
2327
+ resolveDefaultTierIndex,
2328
+ resolvePopularTierIndex,
2223
2329
  isVariantFulfillable as isVariantFulfillable4,
2224
2330
  shouldShowLowStockBadge as shouldShowLowStockBadge2
2225
2331
  } from "@lime-bundles/core";
2226
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
2332
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
2227
2333
  function VolumeBundle(props) {
2228
2334
  const {
2229
2335
  shopDomain,
@@ -2247,13 +2353,30 @@ function VolumeBundle(props) {
2247
2353
  bundleType: "volume",
2248
2354
  enabled: analyticsEnabled !== false
2249
2355
  });
2250
- const [quantity, setQuantity] = useState9(1);
2251
- const [addingToCart, setAddingToCart] = useState9(false);
2252
- const [cartError, setCartError] = useState9(null);
2356
+ const [quantity, setQuantity] = useState10(1);
2357
+ const [addingToCart, setAddingToCart] = useState10(false);
2358
+ const [cartError, setCartError] = useState10(null);
2359
+ const [seededFor, setSeededFor] = useState10(null);
2253
2360
  const bundle = result.status === "success" && result.bundle.bundleType === "volume" ? result.bundle : null;
2361
+ useEffect13(() => {
2362
+ if (!bundle || seededFor === bundle.id) return;
2363
+ setSeededFor(bundle.id);
2364
+ const tiers = bundle.volumeTiers;
2365
+ if (tiers.length === 0) return;
2366
+ const best = bestValueTierIndex(
2367
+ tiers,
2368
+ bundle.discountConfig.discountType
2369
+ );
2370
+ const idx = resolveDefaultTierIndex(
2371
+ bundle.widgetConfig.defaultTier,
2372
+ tiers.length,
2373
+ best
2374
+ );
2375
+ setQuantity(tiers[idx].minQuantity);
2376
+ }, [bundle, seededFor]);
2254
2377
  const setConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);
2255
2378
  const tiersEdgeFadeRef = useEdgeFade();
2256
- useEffect12(() => {
2379
+ useEffect13(() => {
2257
2380
  if (result.status === "error") {
2258
2381
  onError?.(result.error);
2259
2382
  return;
@@ -2296,19 +2419,16 @@ function VolumeBundle(props) {
2296
2419
  );
2297
2420
  const activeTier = bundle ? getActiveTier(bundle.volumeTiers, quantity) : null;
2298
2421
  const popularTierIndex = useMemo7(() => {
2299
- if (!bundle?.widgetConfig.popularBadge.visible || tierSavings.length === 0) {
2300
- return -1;
2301
- }
2302
- const pinned = bundle.widgetConfig.popularBadge.tierIndex;
2303
- if (pinned !== void 0) {
2304
- return Math.min(Math.max(pinned, 0), tierSavings.length - 1);
2305
- }
2306
- let best = 0;
2307
- for (let i = 1; i < tierSavings.length; i++) {
2308
- if (tierSavings[i].savings > tierSavings[best].savings) best = i;
2309
- }
2310
- return best;
2311
- }, [bundle, tierSavings]);
2422
+ if (!bundle || bundle.volumeTiers.length === 0) return -1;
2423
+ return resolvePopularTierIndex(
2424
+ bundle.widgetConfig.popularBadge.tierIndex,
2425
+ bundle.widgetConfig.popularBadge.visible !== false,
2426
+ bestValueTierIndex(
2427
+ bundle.volumeTiers,
2428
+ bundle.discountConfig.discountType
2429
+ )
2430
+ );
2431
+ }, [bundle]);
2312
2432
  const activeUnitPrice = tierSavings.find((ts) => ts.tier === activeTier)?.unitPrice ?? basePrice;
2313
2433
  const undiscountedTotal = basePrice * quantity;
2314
2434
  const volumeTotal = activeUnitPrice * quantity;
@@ -2360,15 +2480,15 @@ function VolumeBundle(props) {
2360
2480
  tierSavings
2361
2481
  ]);
2362
2482
  if (result.status === "loading") {
2363
- return /* @__PURE__ */ jsxs5("div", { className: `lb-bundle lb-bundle--loading ${className ?? ""}`, children: [
2364
- /* @__PURE__ */ jsx5("div", { className: "lb-skeleton lb-skeleton--title" }),
2365
- /* @__PURE__ */ jsx5("div", { className: "lb-skeleton lb-skeleton--tiers" })
2483
+ return /* @__PURE__ */ jsxs6("div", { className: `lb-bundle lb-bundle--loading ${className ?? ""}`, children: [
2484
+ /* @__PURE__ */ jsx6("div", { className: "lb-skeleton lb-skeleton--title" }),
2485
+ /* @__PURE__ */ jsx6("div", { className: "lb-skeleton lb-skeleton--tiers" })
2366
2486
  ] });
2367
2487
  }
2368
2488
  if (result.status === "error") return null;
2369
2489
  if (!bundle) return null;
2370
2490
  if (!product) return null;
2371
- return /* @__PURE__ */ jsxs5(
2491
+ return /* @__PURE__ */ jsxs6(
2372
2492
  "div",
2373
2493
  {
2374
2494
  ref: (el) => {
@@ -2379,12 +2499,19 @@ function VolumeBundle(props) {
2379
2499
  role: "region",
2380
2500
  "aria-label": bundle.title,
2381
2501
  children: [
2382
- /* @__PURE__ */ jsx5("div", { className: "lb-bundle-header", children: /* @__PURE__ */ jsxs5("div", { className: "lb-bundle-header__content", children: [
2383
- /* @__PURE__ */ jsx5("h3", { className: "lb-bundle-title", children: bundle.title }),
2384
- bundle.description && /* @__PURE__ */ jsx5("p", { className: "lb-bundle-subtitle", children: bundle.description })
2502
+ /* @__PURE__ */ jsx6("div", { className: "lb-bundle-header", children: /* @__PURE__ */ jsxs6("div", { className: "lb-bundle-header__content", children: [
2503
+ /* @__PURE__ */ jsx6("h3", { className: "lb-bundle-title", children: bundle.title }),
2504
+ bundle.description && /* @__PURE__ */ jsx6("p", { className: "lb-bundle-subtitle", children: bundle.description })
2385
2505
  ] }) }),
2386
- /* @__PURE__ */ jsxs5("div", { className: "lb-bundle-product-row lb-bundle-product-row--volume", children: [
2387
- thumbImage && /* @__PURE__ */ jsx5(
2506
+ /* @__PURE__ */ jsx6(
2507
+ BundleCountdown,
2508
+ {
2509
+ endsAt: bundle.endsAt,
2510
+ widgetConfig: bundle.widgetConfig
2511
+ }
2512
+ ),
2513
+ /* @__PURE__ */ jsxs6("div", { className: "lb-bundle-product-row lb-bundle-product-row--volume", children: [
2514
+ thumbImage && /* @__PURE__ */ jsx6(
2388
2515
  "img",
2389
2516
  {
2390
2517
  src: thumbImage.url,
@@ -2393,20 +2520,20 @@ function VolumeBundle(props) {
2393
2520
  loading: "lazy"
2394
2521
  }
2395
2522
  ),
2396
- /* @__PURE__ */ jsxs5("div", { className: "lb-bundle__product-info", children: [
2397
- /* @__PURE__ */ jsx5("p", { className: "lb-bundle__product-title", children: product.title }),
2398
- /* @__PURE__ */ jsxs5("p", { className: "lb-bundle__product-price", children: [
2523
+ /* @__PURE__ */ jsxs6("div", { className: "lb-bundle__product-info", children: [
2524
+ /* @__PURE__ */ jsx6("p", { className: "lb-bundle__product-title", children: product.title }),
2525
+ /* @__PURE__ */ jsxs6("p", { className: "lb-bundle__product-price", children: [
2399
2526
  formatMoney4(basePrice, currency),
2400
2527
  " each"
2401
2528
  ] }),
2402
- unitPriceText && /* @__PURE__ */ jsx5("p", { className: "lb-bundle__product-unit-price", children: unitPriceText }),
2403
- showPicker && /* @__PURE__ */ jsx5("div", { className: "lb-bundle__product-variant-pickers", children: optionNames.map((optionName, optionIndex) => {
2529
+ unitPriceText && /* @__PURE__ */ jsx6("p", { className: "lb-bundle__product-unit-price", children: unitPriceText }),
2530
+ showPicker && /* @__PURE__ */ jsx6("div", { className: "lb-bundle__product-variant-pickers", children: optionNames.map((optionName, optionIndex) => {
2404
2531
  const dropdownOptions = optionsFor(optionIndex).map((o) => ({
2405
2532
  value: o.value,
2406
2533
  label: o.value,
2407
2534
  disabled: o.disabled
2408
2535
  }));
2409
- return /* @__PURE__ */ jsx5(
2536
+ return /* @__PURE__ */ jsx6(
2410
2537
  VariantDropdown,
2411
2538
  {
2412
2539
  options: dropdownOptions,
@@ -2419,37 +2546,47 @@ function VolumeBundle(props) {
2419
2546
  }) })
2420
2547
  ] })
2421
2548
  ] }),
2422
- /* @__PURE__ */ jsx5(
2549
+ /* @__PURE__ */ jsx6(
2423
2550
  "div",
2424
2551
  {
2425
2552
  className: "lb-bundle__tiers lb-edge-fade",
2426
- role: "table",
2427
- "aria-label": "Volume discounts",
2553
+ role: "radiogroup",
2554
+ "aria-label": "Select quantity",
2428
2555
  ref: tiersEdgeFadeRef,
2429
2556
  children: tierSavings.map((ts, tierIndex) => {
2430
2557
  const savingsPercent = Math.round(ts.savingsPercent);
2431
2558
  const showCompare = bundle.widgetConfig.pricing.showComparePrice && ts.savings > 0;
2432
- return /* @__PURE__ */ jsxs5(
2559
+ const isChecked = activeTier === ts.tier;
2560
+ return /* @__PURE__ */ jsxs6(
2433
2561
  "div",
2434
2562
  {
2435
2563
  className: `lb-bundle__tier ${ts.isActive ? "lb-bundle__tier--active" : ""}`,
2436
- role: "row",
2564
+ role: "radio",
2565
+ "aria-checked": isChecked,
2566
+ tabIndex: isChecked ? 0 : -1,
2567
+ onClick: () => setQuantity(ts.tier.minQuantity),
2568
+ onKeyDown: (e) => {
2569
+ if (e.key === "Enter" || e.key === " ") {
2570
+ e.preventDefault();
2571
+ setQuantity(ts.tier.minQuantity);
2572
+ }
2573
+ },
2437
2574
  children: [
2438
- /* @__PURE__ */ jsx5("span", { className: "lb-bundle__tier-radio", "aria-hidden": "true", children: /* @__PURE__ */ jsx5("span", { className: "lb-bundle__tier-radio-dot" }) }),
2439
- /* @__PURE__ */ jsxs5("span", { className: "lb-bundle__tier-info", role: "cell", children: [
2440
- /* @__PURE__ */ jsxs5("span", { className: "lb-bundle__tier-label", children: [
2575
+ /* @__PURE__ */ jsx6("span", { className: "lb-bundle__tier-radio", "aria-hidden": "true", children: /* @__PURE__ */ jsx6("span", { className: "lb-bundle__tier-radio-dot" }) }),
2576
+ /* @__PURE__ */ jsxs6("span", { className: "lb-bundle__tier-info", children: [
2577
+ /* @__PURE__ */ jsxs6("span", { className: "lb-bundle__tier-label", children: [
2441
2578
  "Buy ",
2442
2579
  ts.tier.minQuantity
2443
2580
  ] }),
2444
- /* @__PURE__ */ jsxs5("span", { className: "lb-bundle__tier-price", children: [
2445
- showCompare && /* @__PURE__ */ jsx5("span", { className: "lb-bundle__tier-compare", children: formatMoney4(basePrice, currency) }),
2446
- /* @__PURE__ */ jsx5("span", { children: formatMoney4(ts.unitPrice, currency) }),
2447
- /* @__PURE__ */ jsx5("span", { className: "lb-bundle__tier-unit", children: "each" })
2581
+ /* @__PURE__ */ jsxs6("span", { className: "lb-bundle__tier-price", children: [
2582
+ showCompare && /* @__PURE__ */ jsx6("span", { className: "lb-bundle__tier-compare", children: formatMoney4(basePrice, currency) }),
2583
+ /* @__PURE__ */ jsx6("span", { children: formatMoney4(ts.unitPrice, currency) }),
2584
+ /* @__PURE__ */ jsx6("span", { className: "lb-bundle__tier-unit", children: "each" })
2448
2585
  ] })
2449
2586
  ] }),
2450
- (tierIndex === popularTierIndex || savingsPercent > 0) && /* @__PURE__ */ jsxs5("span", { className: "lb-bundle__tier-right", role: "cell", children: [
2451
- tierIndex === popularTierIndex && /* @__PURE__ */ jsx5("span", { className: "lb-bundle__tier-badge", children: bundle.widgetConfig.popularBadge.text }),
2452
- savingsPercent > 0 && /* @__PURE__ */ jsxs5("span", { className: "lb-bundle__tier-savings", children: [
2587
+ (tierIndex === popularTierIndex || savingsPercent > 0) && /* @__PURE__ */ jsxs6("span", { className: "lb-bundle__tier-right", children: [
2588
+ tierIndex === popularTierIndex && /* @__PURE__ */ jsx6("span", { className: "lb-bundle__tier-badge", children: bundle.widgetConfig.popularBadge.text }),
2589
+ savingsPercent > 0 && /* @__PURE__ */ jsxs6("span", { className: "lb-bundle__tier-savings", children: [
2453
2590
  "Save ",
2454
2591
  savingsPercent,
2455
2592
  "%"
@@ -2462,10 +2599,10 @@ function VolumeBundle(props) {
2462
2599
  })
2463
2600
  }
2464
2601
  ),
2465
- /* @__PURE__ */ jsxs5("div", { className: "lb-bundle__quantity-selector", children: [
2466
- /* @__PURE__ */ jsx5("label", { htmlFor: `lb-qty-${bundle.id}`, children: "Quantity" }),
2467
- /* @__PURE__ */ jsxs5("div", { className: "lb-bundle__quantity-control", children: [
2468
- /* @__PURE__ */ jsx5(
2602
+ /* @__PURE__ */ jsxs6("div", { className: "lb-bundle__quantity-selector", children: [
2603
+ /* @__PURE__ */ jsx6("label", { htmlFor: `lb-qty-${bundle.id}`, children: "Quantity" }),
2604
+ /* @__PURE__ */ jsxs6("div", { className: "lb-bundle__quantity-control", children: [
2605
+ /* @__PURE__ */ jsx6(
2469
2606
  "button",
2470
2607
  {
2471
2608
  "aria-label": "Decrease quantity",
@@ -2473,7 +2610,7 @@ function VolumeBundle(props) {
2473
2610
  children: "\u2212"
2474
2611
  }
2475
2612
  ),
2476
- /* @__PURE__ */ jsx5(
2613
+ /* @__PURE__ */ jsx6(
2477
2614
  "input",
2478
2615
  {
2479
2616
  id: `lb-qty-${bundle.id}`,
@@ -2487,7 +2624,7 @@ function VolumeBundle(props) {
2487
2624
  className: "lb-bundle__quantity-input"
2488
2625
  }
2489
2626
  ),
2490
- /* @__PURE__ */ jsx5(
2627
+ /* @__PURE__ */ jsx6(
2491
2628
  "button",
2492
2629
  {
2493
2630
  "aria-label": "Increase quantity",
@@ -2497,23 +2634,23 @@ function VolumeBundle(props) {
2497
2634
  )
2498
2635
  ] })
2499
2636
  ] }),
2500
- cartError && /* @__PURE__ */ jsx5("p", { className: "lb-bundle__error", role: "alert", children: cartError }),
2637
+ cartError && /* @__PURE__ */ jsx6("p", { className: "lb-bundle__error", role: "alert", children: cartError }),
2501
2638
  bundle && displayVariant && shouldShowLowStockBadge2(
2502
2639
  displayVariant,
2503
2640
  minTierQty,
2504
2641
  bundle.widgetConfig.lowStockThreshold,
2505
2642
  bundle.widgetConfig.showLowStockBadge
2506
- ) && /* @__PURE__ */ jsxs5("span", { className: "lb-bundle-low-stock-badge", children: [
2643
+ ) && /* @__PURE__ */ jsxs6("span", { className: "lb-bundle-low-stock-badge", children: [
2507
2644
  "Only ",
2508
2645
  displayVariant.quantityAvailable,
2509
2646
  " left"
2510
2647
  ] }),
2511
- /* @__PURE__ */ jsx5("div", { className: "lb-bundle-divider" }),
2512
- /* @__PURE__ */ jsxs5("div", { className: "lb-bundle-summary", children: [
2513
- /* @__PURE__ */ jsxs5("div", { className: "lb-bundle-summary__text", children: [
2514
- /* @__PURE__ */ jsxs5("span", { className: "lb-bundle-summary__label", "data-total-label": true, children: [
2648
+ /* @__PURE__ */ jsx6("div", { className: "lb-bundle-divider" }),
2649
+ /* @__PURE__ */ jsxs6("div", { className: "lb-bundle-summary", children: [
2650
+ /* @__PURE__ */ jsxs6("div", { className: "lb-bundle-summary__text", children: [
2651
+ /* @__PURE__ */ jsxs6("span", { className: "lb-bundle-summary__label", "data-total-label": true, children: [
2515
2652
  "Total",
2516
- bundle.widgetConfig.pricing.showItemCount && /* @__PURE__ */ jsxs5("span", { "data-item-count": true, children: [
2653
+ bundle.widgetConfig.pricing.showItemCount && /* @__PURE__ */ jsxs6("span", { "data-item-count": true, children: [
2517
2654
  " ",
2518
2655
  "(",
2519
2656
  quantity,
@@ -2522,24 +2659,24 @@ function VolumeBundle(props) {
2522
2659
  ")"
2523
2660
  ] })
2524
2661
  ] }),
2525
- bundle.widgetConfig.savingsBar.visible && volumeSavings > 0 && /* @__PURE__ */ jsxs5("p", { className: "lb-bundle-savings-line", "data-savings-bar": true, children: [
2662
+ bundle.widgetConfig.savingsBar.visible && volumeSavings > 0 && /* @__PURE__ */ jsxs6("p", { className: "lb-bundle-savings-line", "data-savings-bar": true, children: [
2526
2663
  "You save",
2527
2664
  " ",
2528
- /* @__PURE__ */ jsx5("span", { "data-savings-amount": true, children: formatMoney4(volumeSavings, currency) }),
2665
+ /* @__PURE__ */ jsx6("span", { "data-savings-amount": true, children: formatMoney4(volumeSavings, currency) }),
2529
2666
  " ",
2530
- /* @__PURE__ */ jsxs5("span", { "data-savings-percent": true, children: [
2667
+ /* @__PURE__ */ jsxs6("span", { "data-savings-percent": true, children: [
2531
2668
  "(",
2532
2669
  volumeSavingsPercent,
2533
2670
  "%)"
2534
2671
  ] })
2535
2672
  ] })
2536
2673
  ] }),
2537
- /* @__PURE__ */ jsxs5("span", { className: "lb-bundle-summary__prices", children: [
2538
- bundle.widgetConfig.pricing.showComparePrice && volumeSavings > 0 && /* @__PURE__ */ jsx5("span", { className: "lb-bundle-compare-price", "data-compare-price": true, children: formatMoney4(undiscountedTotal, currency) }),
2539
- /* @__PURE__ */ jsx5("span", { className: "lb-bundle-sale-price", "data-total-price": true, children: formatMoney4(volumeTotal, currency) })
2674
+ /* @__PURE__ */ jsxs6("span", { className: "lb-bundle-summary__prices", children: [
2675
+ bundle.widgetConfig.pricing.showComparePrice && volumeSavings > 0 && /* @__PURE__ */ jsx6("span", { className: "lb-bundle-compare-price", "data-compare-price": true, children: formatMoney4(undiscountedTotal, currency) }),
2676
+ /* @__PURE__ */ jsx6("span", { className: "lb-bundle-sale-price", "data-total-price": true, children: formatMoney4(volumeTotal, currency) })
2540
2677
  ] })
2541
2678
  ] }),
2542
- /* @__PURE__ */ jsx5(
2679
+ /* @__PURE__ */ jsx6(
2543
2680
  "button",
2544
2681
  {
2545
2682
  className: "lb-bundle__cta",
@@ -2555,13 +2692,13 @@ function VolumeBundle(props) {
2555
2692
  }
2556
2693
 
2557
2694
  // src/components/BogoBundle.tsx
2558
- import { useCallback as useCallback8, useEffect as useEffect13, useMemo as useMemo8, useState as useState10 } from "react";
2695
+ import { useCallback as useCallback8, useEffect as useEffect14, useMemo as useMemo8, useState as useState11 } from "react";
2559
2696
  import {
2560
2697
  formatMoney as formatMoney5,
2561
2698
  formatUnitPrice as formatUnitPrice5,
2562
2699
  isVariantFulfillable as isVariantFulfillable5
2563
2700
  } from "@lime-bundles/core";
2564
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
2701
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
2565
2702
  function discountedUnit(price, percent) {
2566
2703
  const cents = Math.round(price * 100);
2567
2704
  const discounted = cents - Math.floor(cents * percent / 100);
@@ -2590,9 +2727,9 @@ function BogoBundle(props) {
2590
2727
  bundleType: "bogo",
2591
2728
  enabled: analyticsEnabled !== false
2592
2729
  });
2593
- const [addingToCart, setAddingToCart] = useState10(false);
2594
- const [cartError, setCartError] = useState10(null);
2595
- const [selectedVariants, setSelectedVariants] = useState10({ buy: null, get: null });
2730
+ const [addingToCart, setAddingToCart] = useState11(false);
2731
+ const [cartError, setCartError] = useState11(null);
2732
+ const [selectedVariants, setSelectedVariants] = useState11({ buy: null, get: null });
2596
2733
  const handleVariantChange = useCallback8(
2597
2734
  (role, variant) => {
2598
2735
  setSelectedVariants((prev) => {
@@ -2604,7 +2741,7 @@ function BogoBundle(props) {
2604
2741
  );
2605
2742
  const bundle = result.status === "success" && result.bundle.bundleType === "bogo" ? result.bundle : null;
2606
2743
  const setConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);
2607
- useEffect13(() => {
2744
+ useEffect14(() => {
2608
2745
  if (result.status === "error") {
2609
2746
  onError?.(result.error);
2610
2747
  return;
@@ -2685,9 +2822,9 @@ function BogoBundle(props) {
2685
2822
  }
2686
2823
  }, [bundle, buyProduct, getProduct, selectedVariants, resolveVariant, onAddToCart, onError, trackAddToCart, percent]);
2687
2824
  if (result.status === "loading") {
2688
- return /* @__PURE__ */ jsxs6("div", { className: `lb-bundle lb-bundle--loading ${className ?? ""}`, children: [
2689
- /* @__PURE__ */ jsx6("div", { className: "lb-skeleton lb-skeleton--title" }),
2690
- /* @__PURE__ */ jsx6("div", { className: "lb-skeleton lb-skeleton--products" })
2825
+ return /* @__PURE__ */ jsxs7("div", { className: `lb-bundle lb-bundle--loading ${className ?? ""}`, children: [
2826
+ /* @__PURE__ */ jsx7("div", { className: "lb-skeleton lb-skeleton--title" }),
2827
+ /* @__PURE__ */ jsx7("div", { className: "lb-skeleton lb-skeleton--products" })
2691
2828
  ] });
2692
2829
  }
2693
2830
  if (result.status === "error") return null;
@@ -2704,7 +2841,7 @@ function BogoBundle(props) {
2704
2841
  const showCompare = bundle.widgetConfig.pricing.showComparePrice && savings > 0;
2705
2842
  const showSavings = bundle.widgetConfig.savingsBar.visible && savings > 0;
2706
2843
  const badge = percent === 100 ? "Free" : `${percent}% off`;
2707
- return /* @__PURE__ */ jsxs6(
2844
+ return /* @__PURE__ */ jsxs7(
2708
2845
  "div",
2709
2846
  {
2710
2847
  ref: (el) => {
@@ -2715,12 +2852,19 @@ function BogoBundle(props) {
2715
2852
  role: "region",
2716
2853
  "aria-label": bundle.title,
2717
2854
  children: [
2718
- /* @__PURE__ */ jsx6("div", { className: "lb-bundle-header", children: /* @__PURE__ */ jsxs6("div", { className: "lb-bundle-header__content", children: [
2719
- /* @__PURE__ */ jsx6("h3", { className: "lb-bundle-title", children: bundle.title }),
2720
- bundle.description && /* @__PURE__ */ jsx6("p", { className: "lb-bundle-subtitle", children: bundle.description })
2855
+ /* @__PURE__ */ jsx7("div", { className: "lb-bundle-header", children: /* @__PURE__ */ jsxs7("div", { className: "lb-bundle-header__content", children: [
2856
+ /* @__PURE__ */ jsx7("h3", { className: "lb-bundle-title", children: bundle.title }),
2857
+ bundle.description && /* @__PURE__ */ jsx7("p", { className: "lb-bundle-subtitle", children: bundle.description })
2721
2858
  ] }) }),
2722
- /* @__PURE__ */ jsxs6("div", { className: "lb-bundle__products", children: [
2723
- /* @__PURE__ */ jsx6(
2859
+ /* @__PURE__ */ jsx7(
2860
+ BundleCountdown,
2861
+ {
2862
+ endsAt: bundle.endsAt,
2863
+ widgetConfig: bundle.widgetConfig
2864
+ }
2865
+ ),
2866
+ /* @__PURE__ */ jsxs7("div", { className: "lb-bundle__products", children: [
2867
+ /* @__PURE__ */ jsx7(
2724
2868
  BogoProductRow,
2725
2869
  {
2726
2870
  side: "buy",
@@ -2732,11 +2876,11 @@ function BogoBundle(props) {
2732
2876
  onVariantChange: handleVariantChange
2733
2877
  }
2734
2878
  ),
2735
- /* @__PURE__ */ jsx6("div", { className: "lb-bogo__plus", "aria-hidden": "true", children: /* @__PURE__ */ jsxs6("svg", { width: "12", height: "12", viewBox: "0 0 18 18", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
2736
- /* @__PURE__ */ jsx6("line", { x1: "9", y1: "3", x2: "9", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
2737
- /* @__PURE__ */ jsx6("line", { x1: "3", y1: "9", x2: "15", y2: "9", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
2879
+ /* @__PURE__ */ jsx7("div", { className: "lb-bogo__plus", "aria-hidden": "true", children: /* @__PURE__ */ jsxs7("svg", { width: "12", height: "12", viewBox: "0 0 18 18", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
2880
+ /* @__PURE__ */ jsx7("line", { x1: "9", y1: "3", x2: "9", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
2881
+ /* @__PURE__ */ jsx7("line", { x1: "3", y1: "9", x2: "15", y2: "9", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
2738
2882
  ] }) }),
2739
- /* @__PURE__ */ jsx6(
2883
+ /* @__PURE__ */ jsx7(
2740
2884
  BogoProductRow,
2741
2885
  {
2742
2886
  side: "get",
@@ -2749,29 +2893,29 @@ function BogoBundle(props) {
2749
2893
  }
2750
2894
  )
2751
2895
  ] }),
2752
- /* @__PURE__ */ jsx6("div", { className: "lb-bundle-divider" }),
2753
- /* @__PURE__ */ jsxs6("div", { className: "lb-bundle-summary", children: [
2754
- /* @__PURE__ */ jsxs6("div", { className: "lb-bundle-summary__text", children: [
2755
- /* @__PURE__ */ jsx6("span", { className: "lb-bundle-summary__label", children: "Bundle price" }),
2756
- showSavings && /* @__PURE__ */ jsxs6("p", { className: "lb-bundle-savings-line", "data-savings-bar": true, children: [
2896
+ /* @__PURE__ */ jsx7("div", { className: "lb-bundle-divider" }),
2897
+ /* @__PURE__ */ jsxs7("div", { className: "lb-bundle-summary", children: [
2898
+ /* @__PURE__ */ jsxs7("div", { className: "lb-bundle-summary__text", children: [
2899
+ /* @__PURE__ */ jsx7("span", { className: "lb-bundle-summary__label", children: "Bundle total" }),
2900
+ showSavings && /* @__PURE__ */ jsxs7("p", { className: "lb-bundle-savings-line", "data-savings-bar": true, children: [
2757
2901
  "You save",
2758
2902
  " ",
2759
- /* @__PURE__ */ jsx6("span", { "data-savings-amount": true, children: formatMoney5(savings, currency) }),
2903
+ /* @__PURE__ */ jsx7("span", { "data-savings-amount": true, children: formatMoney5(savings, currency) }),
2760
2904
  " ",
2761
- /* @__PURE__ */ jsxs6("span", { "data-savings-percent": true, children: [
2905
+ /* @__PURE__ */ jsxs7("span", { "data-savings-percent": true, children: [
2762
2906
  "(",
2763
2907
  savingsPercent,
2764
2908
  "%)"
2765
2909
  ] })
2766
2910
  ] })
2767
2911
  ] }),
2768
- /* @__PURE__ */ jsxs6("span", { className: "lb-bundle-summary__prices", children: [
2769
- showCompare && /* @__PURE__ */ jsx6("span", { className: "lb-bundle-compare-price", "data-compare-price": true, children: formatMoney5(comparePrice, currency) }),
2770
- /* @__PURE__ */ jsx6("span", { className: "lb-bundle-sale-price", "data-sale-price": true, children: formatMoney5(salePrice, currency) })
2912
+ /* @__PURE__ */ jsxs7("span", { className: "lb-bundle-summary__prices", children: [
2913
+ showCompare && /* @__PURE__ */ jsx7("span", { className: "lb-bundle-compare-price", "data-compare-price": true, children: formatMoney5(comparePrice, currency) }),
2914
+ /* @__PURE__ */ jsx7("span", { className: "lb-bundle-sale-price", "data-sale-price": true, children: formatMoney5(salePrice, currency) })
2771
2915
  ] })
2772
2916
  ] }),
2773
- cartError && /* @__PURE__ */ jsx6("p", { className: "lb-bundle__error", role: "alert", children: cartError }),
2774
- /* @__PURE__ */ jsx6(
2917
+ cartError && /* @__PURE__ */ jsx7("p", { className: "lb-bundle__error", role: "alert", children: cartError }),
2918
+ /* @__PURE__ */ jsx7(
2775
2919
  "button",
2776
2920
  {
2777
2921
  className: "lb-bundle__cta",
@@ -2796,7 +2940,7 @@ function BogoProductRow({ side, product, quantity, percent, badge, currency, onV
2796
2940
  variants,
2797
2941
  optionNames
2798
2942
  });
2799
- useEffect13(() => {
2943
+ useEffect14(() => {
2800
2944
  onVariantChange(side, selectedVariant ?? null);
2801
2945
  }, [selectedVariant, side, onVariantChange]);
2802
2946
  const displayVariant = selectedVariant ?? variants.find((v) => isVariantFulfillable5(v, quantity)) ?? variants[0];
@@ -2810,8 +2954,8 @@ function BogoProductRow({ side, product, quantity, percent, badge, currency, onV
2810
2954
  currency
2811
2955
  ) : null;
2812
2956
  const thumbImage = displayVariant?.image ?? product.featuredImage;
2813
- return /* @__PURE__ */ jsxs6("div", { className: "lb-bundle-product-row", part: "product", "data-bogo-role": side, children: [
2814
- thumbImage && /* @__PURE__ */ jsx6(
2957
+ return /* @__PURE__ */ jsxs7("div", { className: "lb-bundle-product-row", part: "product", "data-bogo-role": side, children: [
2958
+ thumbImage && /* @__PURE__ */ jsx7(
2815
2959
  "img",
2816
2960
  {
2817
2961
  src: thumbImage.url,
@@ -2820,11 +2964,11 @@ function BogoProductRow({ side, product, quantity, percent, badge, currency, onV
2820
2964
  loading: "lazy"
2821
2965
  }
2822
2966
  ),
2823
- /* @__PURE__ */ jsxs6("div", { className: "lb-bundle__product-info", children: [
2824
- /* @__PURE__ */ jsx6("p", { className: "lb-bundle__product-title", children: product.title }),
2825
- !showPicker && displayVariant && variants.length > 1 && /* @__PURE__ */ jsx6("span", { className: "lb-bundle-variant-badge", children: displayVariant.title }),
2826
- /* @__PURE__ */ jsxs6("span", { className: "lb-bundle-product-prices", children: [
2827
- compareAt && /* @__PURE__ */ jsx6(
2967
+ /* @__PURE__ */ jsxs7("div", { className: "lb-bundle__product-info", children: [
2968
+ /* @__PURE__ */ jsx7("p", { className: "lb-bundle__product-title", children: product.title }),
2969
+ !showPicker && displayVariant && variants.length > 1 && /* @__PURE__ */ jsx7("span", { className: "lb-bundle-variant-badge", children: displayVariant.title }),
2970
+ /* @__PURE__ */ jsxs7("span", { className: "lb-bundle-product-prices", children: [
2971
+ compareAt && /* @__PURE__ */ jsx7(
2828
2972
  "span",
2829
2973
  {
2830
2974
  className: "lb-bundle-product-compare-price",
@@ -2832,13 +2976,13 @@ function BogoProductRow({ side, product, quantity, percent, badge, currency, onV
2832
2976
  children: compareAt
2833
2977
  }
2834
2978
  ),
2835
- /* @__PURE__ */ jsx6("span", { className: "lb-bundle__product-price", "data-product-price": true, children: priceText }),
2836
- /* @__PURE__ */ jsxs6("span", { className: "lb-bundle-qty-inline", "data-qty-inline": true, children: [
2979
+ /* @__PURE__ */ jsx7("span", { className: "lb-bundle__product-price", "data-product-price": true, children: priceText }),
2980
+ /* @__PURE__ */ jsxs7("span", { className: "lb-bundle-qty-inline", "data-qty-inline": true, children: [
2837
2981
  "\xD7",
2838
2982
  quantity
2839
2983
  ] })
2840
2984
  ] }),
2841
- unitPriceText && /* @__PURE__ */ jsx6(
2985
+ unitPriceText && /* @__PURE__ */ jsx7(
2842
2986
  "span",
2843
2987
  {
2844
2988
  className: "lb-bundle__product-unit-price",
@@ -2846,13 +2990,13 @@ function BogoProductRow({ side, product, quantity, percent, badge, currency, onV
2846
2990
  children: unitPriceText
2847
2991
  }
2848
2992
  ),
2849
- showPicker && /* @__PURE__ */ jsx6("div", { className: "lb-bundle__product-variant-pickers", children: optionNames.map((optionName, optionIndex) => {
2993
+ showPicker && /* @__PURE__ */ jsx7("div", { className: "lb-bundle__product-variant-pickers", children: optionNames.map((optionName, optionIndex) => {
2850
2994
  const dropdownOptions = optionsFor(optionIndex).map((o) => ({
2851
2995
  value: o.value,
2852
2996
  label: o.value,
2853
2997
  disabled: o.disabled
2854
2998
  }));
2855
- return /* @__PURE__ */ jsx6(
2999
+ return /* @__PURE__ */ jsx7(
2856
3000
  VariantDropdown,
2857
3001
  {
2858
3002
  options: dropdownOptions,
@@ -2864,12 +3008,12 @@ function BogoProductRow({ side, product, quantity, percent, badge, currency, onV
2864
3008
  );
2865
3009
  }) })
2866
3010
  ] }),
2867
- badge && /* @__PURE__ */ jsx6("span", { className: "lb-bogo__badge", children: badge })
3011
+ badge && /* @__PURE__ */ jsx7("span", { className: "lb-bogo__badge", children: badge })
2868
3012
  ] });
2869
3013
  }
2870
3014
 
2871
3015
  // src/components/MultiStepBundle.tsx
2872
- import { useCallback as useCallback9, useEffect as useEffect15, useMemo as useMemo10, useState as useState12 } from "react";
3016
+ import { useCallback as useCallback9, useEffect as useEffect16, useMemo as useMemo10, useState as useState13 } from "react";
2873
3017
  import {
2874
3018
  formatMoney as formatMoney7,
2875
3019
  formatUnitPrice as formatUnitPrice7,
@@ -2882,10 +3026,10 @@ import {
2882
3026
 
2883
3027
  // src/components/MultiStepPicker.tsx
2884
3028
  import {
2885
- useEffect as useEffect14,
3029
+ useEffect as useEffect15,
2886
3030
  useMemo as useMemo9,
2887
3031
  useRef as useRef7,
2888
- useState as useState11
3032
+ useState as useState12
2889
3033
  } from "react";
2890
3034
  import { createPortal as createPortal2 } from "react-dom";
2891
3035
  import {
@@ -2897,10 +3041,17 @@ import {
2897
3041
  stepHeadroom,
2898
3042
  DEFAULT_PRODUCT_RULE as DEFAULT_PRODUCT_RULE3
2899
3043
  } from "@lime-bundles/core";
2900
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
2901
- function ruleFor3(bundle, productId) {
3044
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
3045
+ function ruleFor3(bundle, productId, variantId) {
3046
+ if (variantId) {
3047
+ const vRule = bundle.variantRules[variantId];
3048
+ if (vRule) return vRule;
3049
+ }
2902
3050
  return bundle.productRules[productId] ?? DEFAULT_PRODUCT_RULE3;
2903
3051
  }
3052
+ function variantRuleFor3(bundle, variantId) {
3053
+ return variantId ? bundle.variantRules[variantId] : void 0;
3054
+ }
2904
3055
  function sanitizeId2(gid) {
2905
3056
  return gid.replace(/[^a-zA-Z0-9_-]/g, "-");
2906
3057
  }
@@ -2948,13 +3099,13 @@ function MultiStepPicker({
2948
3099
  const dialogRef = useRef7(null);
2949
3100
  const titleRef = useRef7(null);
2950
3101
  const mouseDownTarget = useRef7(null);
2951
- const [open, setOpen] = useState11(false);
2952
- const [stepIndex, setStepIndex] = useState11(
3102
+ const [open, setOpen] = useState12(false);
3103
+ const [stepIndex, setStepIndex] = useState12(
2953
3104
  () => Math.max(0, Math.min(steps.length - 1, initialStep))
2954
3105
  );
2955
- const [query, setQuery] = useState11("");
2956
- const [activeType, setActiveType] = useState11(FILTERS_ALL2);
2957
- const [announcement, setAnnouncement] = useState11("");
3106
+ const [query, setQuery] = useState12("");
3107
+ const [activeType, setActiveType] = useState12(FILTERS_ALL2);
3108
+ const [announcement, setAnnouncement] = useState12("");
2958
3109
  const step = steps[stepIndex];
2959
3110
  const stepMin = step?.minQuantity ?? 1;
2960
3111
  const stepPicks = selections[stepIndex] ?? [];
@@ -2979,7 +3130,7 @@ function MultiStepPicker({
2979
3130
  return types;
2980
3131
  }, [eligible]);
2981
3132
  const showFilters = wc.mixMatchShowTypeFilters && productTypes.length >= 2;
2982
- useEffect14(() => {
3133
+ useEffect15(() => {
2983
3134
  const id = requestAnimationFrame(() => setOpen(true));
2984
3135
  return () => cancelAnimationFrame(id);
2985
3136
  }, []);
@@ -3028,7 +3179,7 @@ function MultiStepPicker({
3028
3179
  // inside carries the interactive role + focus trap. So the static-element
3029
3180
  // interaction lint does not apply to this backdrop.
3030
3181
  // eslint-disable-next-line jsx-a11y/no-static-element-interactions
3031
- /* @__PURE__ */ jsx7(
3182
+ /* @__PURE__ */ jsx8(
3032
3183
  "div",
3033
3184
  {
3034
3185
  ref: (el) => {
@@ -3040,7 +3191,7 @@ function MultiStepPicker({
3040
3191
  "data-bundle-gid": bundle.id,
3041
3192
  onMouseDown: onOverlayMouseDown,
3042
3193
  onMouseUp: onOverlayMouseUp,
3043
- children: /* @__PURE__ */ jsxs7(
3194
+ children: /* @__PURE__ */ jsxs8(
3044
3195
  "div",
3045
3196
  {
3046
3197
  ref: dialogRef,
@@ -3050,10 +3201,10 @@ function MultiStepPicker({
3050
3201
  "aria-labelledby": titleId,
3051
3202
  tabIndex: -1,
3052
3203
  children: [
3053
- /* @__PURE__ */ jsxs7("div", { className: "lb-mix-match__modal-header", children: [
3054
- /* @__PURE__ */ jsxs7("div", { className: "lb-mix-match__modal-header-top", children: [
3055
- /* @__PURE__ */ jsxs7("div", { className: "lb-mix-match__modal-heading", children: [
3056
- /* @__PURE__ */ jsx7(
3204
+ /* @__PURE__ */ jsxs8("div", { className: "lb-mix-match__modal-header", children: [
3205
+ /* @__PURE__ */ jsxs8("div", { className: "lb-mix-match__modal-header-top", children: [
3206
+ /* @__PURE__ */ jsxs8("div", { className: "lb-mix-match__modal-heading", children: [
3207
+ /* @__PURE__ */ jsx8(
3057
3208
  "h4",
3058
3209
  {
3059
3210
  className: "lb-mix-match__modal-title",
@@ -3063,9 +3214,9 @@ function MultiStepPicker({
3063
3214
  children: "Add to your bundle"
3064
3215
  }
3065
3216
  ),
3066
- /* @__PURE__ */ jsx7("p", { className: "lb-mix-match__modal-subtitle", "data-modal-subtitle": true, children: subtitle })
3217
+ /* @__PURE__ */ jsx8("p", { className: "lb-mix-match__modal-subtitle", "data-modal-subtitle": true, children: subtitle })
3067
3218
  ] }),
3068
- /* @__PURE__ */ jsx7(
3219
+ /* @__PURE__ */ jsx8(
3069
3220
  "button",
3070
3221
  {
3071
3222
  type: "button",
@@ -3073,16 +3224,16 @@ function MultiStepPicker({
3073
3224
  "data-modal-close": true,
3074
3225
  "aria-label": "Close",
3075
3226
  onClick: onClose,
3076
- children: /* @__PURE__ */ jsx7(CloseIcon3, {})
3227
+ children: /* @__PURE__ */ jsx8(CloseIcon3, {})
3077
3228
  }
3078
3229
  )
3079
3230
  ] }),
3080
- /* @__PURE__ */ jsx7(
3231
+ /* @__PURE__ */ jsx8(
3081
3232
  "div",
3082
3233
  {
3083
3234
  className: "lb-mix-match__progress lb-mix-match__modal-progress",
3084
3235
  "data-progress": true,
3085
- children: /* @__PURE__ */ jsx7(
3236
+ children: /* @__PURE__ */ jsx8(
3086
3237
  "div",
3087
3238
  {
3088
3239
  className: "lb-mix-match__progress-segments",
@@ -3091,7 +3242,7 @@ function MultiStepPicker({
3091
3242
  "aria-valuenow": shownUnits,
3092
3243
  "aria-valuemin": 0,
3093
3244
  "aria-valuemax": stepMin,
3094
- children: Array.from({ length: stepMin }).map((_, i) => /* @__PURE__ */ jsx7(
3245
+ children: Array.from({ length: stepMin }).map((_, i) => /* @__PURE__ */ jsx8(
3095
3246
  "span",
3096
3247
  {
3097
3248
  className: `lb-mix-match__progress-segment${i < shownUnits ? " lb-mix-match__progress-segment--filled" : ""}`,
@@ -3104,8 +3255,8 @@ function MultiStepPicker({
3104
3255
  }
3105
3256
  )
3106
3257
  ] }),
3107
- wc.showSearch && /* @__PURE__ */ jsxs7("div", { className: "lb-mix-match__modal-search", children: [
3108
- /* @__PURE__ */ jsx7(
3258
+ wc.showSearch && /* @__PURE__ */ jsxs8("div", { className: "lb-mix-match__modal-search", children: [
3259
+ /* @__PURE__ */ jsx8(
3109
3260
  "input",
3110
3261
  {
3111
3262
  type: "text",
@@ -3119,7 +3270,7 @@ function MultiStepPicker({
3119
3270
  onChange: (e) => setQuery(e.target.value)
3120
3271
  }
3121
3272
  ),
3122
- query.length > 0 && /* @__PURE__ */ jsx7(
3273
+ query.length > 0 && /* @__PURE__ */ jsx8(
3123
3274
  "button",
3124
3275
  {
3125
3276
  type: "button",
@@ -3127,11 +3278,11 @@ function MultiStepPicker({
3127
3278
  "data-modal-search-clear": true,
3128
3279
  "aria-label": "Clear search",
3129
3280
  onClick: () => setQuery(""),
3130
- children: /* @__PURE__ */ jsx7(SearchClearIcon2, {})
3281
+ children: /* @__PURE__ */ jsx8(SearchClearIcon2, {})
3131
3282
  }
3132
3283
  )
3133
3284
  ] }),
3134
- showFilters && /* @__PURE__ */ jsx7(
3285
+ showFilters && /* @__PURE__ */ jsx8(
3135
3286
  "div",
3136
3287
  {
3137
3288
  className: "lb-mix-match__filters",
@@ -3140,7 +3291,7 @@ function MultiStepPicker({
3140
3291
  "aria-label": "Filter by product type",
3141
3292
  children: [FILTERS_ALL2, ...productTypes].map((value) => {
3142
3293
  const isActive = value === activeType;
3143
- return /* @__PURE__ */ jsx7(
3294
+ return /* @__PURE__ */ jsx8(
3144
3295
  "button",
3145
3296
  {
3146
3297
  type: "button",
@@ -3155,7 +3306,7 @@ function MultiStepPicker({
3155
3306
  })
3156
3307
  }
3157
3308
  ),
3158
- /* @__PURE__ */ jsx7("div", { className: "lb-mix-match__modal-list", "data-modal-list": true, children: filtered.map((ep) => /* @__PURE__ */ jsx7(
3309
+ /* @__PURE__ */ jsx8("div", { className: "lb-mix-match__modal-list", "data-modal-list": true, children: filtered.map((ep) => /* @__PURE__ */ jsx8(
3159
3310
  MultiStepPickerRow,
3160
3311
  {
3161
3312
  bundle,
@@ -3173,10 +3324,10 @@ function MultiStepPicker({
3173
3324
  },
3174
3325
  `${stepIndex}:${ep.product.id}`
3175
3326
  )) }),
3176
- showEmpty && /* @__PURE__ */ jsx7("div", { className: "lb-mix-match__modal-empty", "data-modal-empty": true, children: /* @__PURE__ */ jsx7("p", { children: "No products match your search" }) }),
3177
- /* @__PURE__ */ jsx7("span", { "data-modal-live": true, "aria-live": "polite", className: "lb-visually-hidden", children: announcement || (query.trim() ? `${filtered.length} products shown` : "") }),
3178
- /* @__PURE__ */ jsxs7("div", { className: "lb-mix-match__modal-footer lb-multi-step__modal-footer", children: [
3179
- stepIndex > 0 && /* @__PURE__ */ jsx7(
3327
+ showEmpty && /* @__PURE__ */ jsx8("div", { className: "lb-mix-match__modal-empty", "data-modal-empty": true, children: /* @__PURE__ */ jsx8("p", { children: "No products match your search" }) }),
3328
+ /* @__PURE__ */ jsx8("span", { "data-modal-live": true, "aria-live": "polite", className: "lb-visually-hidden", children: announcement || (query.trim() ? `${filtered.length} products shown` : "") }),
3329
+ /* @__PURE__ */ jsxs8("div", { className: "lb-mix-match__modal-footer lb-multi-step__modal-footer", children: [
3330
+ stepIndex > 0 && /* @__PURE__ */ jsx8(
3180
3331
  "button",
3181
3332
  {
3182
3333
  type: "button",
@@ -3186,7 +3337,7 @@ function MultiStepPicker({
3186
3337
  children: "Back"
3187
3338
  }
3188
3339
  ),
3189
- /* @__PURE__ */ jsx7(
3340
+ /* @__PURE__ */ jsx8(
3190
3341
  "span",
3191
3342
  {
3192
3343
  className: "lb-mix-match__modal-footer-count",
@@ -3195,7 +3346,7 @@ function MultiStepPicker({
3195
3346
  children: `${shownUnits} of ${stepMin} added`
3196
3347
  }
3197
3348
  ),
3198
- !isLastStep && /* @__PURE__ */ jsx7(
3349
+ !isLastStep && /* @__PURE__ */ jsx8(
3199
3350
  "button",
3200
3351
  {
3201
3352
  type: "button",
@@ -3208,7 +3359,7 @@ function MultiStepPicker({
3208
3359
  children: "Next"
3209
3360
  }
3210
3361
  ),
3211
- isLastStep && /* @__PURE__ */ jsx7(
3362
+ isLastStep && /* @__PURE__ */ jsx8(
3212
3363
  "button",
3213
3364
  {
3214
3365
  type: "button",
@@ -3253,6 +3404,8 @@ function MultiStepPickerRow({
3253
3404
  const showPicker = variants.length > 1 && optionNames.length > 0;
3254
3405
  const { selectedValues, selectedVariant, setOptionValue, optionsFor } = useVariantSelection({ variants, optionNames });
3255
3406
  const currentVariant = selectedVariant ?? variants.find((v) => isVariantFulfillable6(v, rule.min)) ?? eligible.firstAvailableVariant ?? variants[0] ?? null;
3407
+ const vRule = ruleFor3(bundle, product.id, currentVariant?.id);
3408
+ const variantMax = variantRuleFor3(bundle, currentVariant?.id)?.max;
3256
3409
  const stepPicks = useMemo9(
3257
3410
  () => selections[stepIndex] ?? [],
3258
3411
  [selections, stepIndex]
@@ -3287,24 +3440,27 @@ function MultiStepPickerRow({
3287
3440
  return Math.max(0, sum - committedQty);
3288
3441
  }, [selections, currentVariant, committedQty]);
3289
3442
  const swapUnits = currentVariant ? swapUnitsFor?.(stepIndex, product.id, currentVariant.id) ?? 0 : 0;
3290
- const inSwapState = swapUnits >= rule.min;
3443
+ const inSwapState = swapUnits >= vRule.min;
3291
3444
  const room = stepHeadroom(step?.maxQuantity ?? null, unitsInStep);
3292
- const productHeadroom = rule.max - productOtherUnits;
3445
+ const productHeadroom = Math.min(
3446
+ rule.max - productOtherUnits,
3447
+ variantMax ?? Infinity
3448
+ );
3293
3449
  const spotCeiling = inSwapState ? swapUnits : Math.min(
3294
3450
  productHeadroom,
3295
3451
  room === Number.POSITIVE_INFINITY ? productHeadroom : committedQty + room
3296
3452
  );
3297
3453
  const stockRemaining = currentVariant ? maxAddableQuantity2(currentVariant, Number.MAX_SAFE_INTEGER, variantOtherUnits) : 0;
3298
3454
  const cap = Math.max(0, Math.min(spotCeiling, stockRemaining));
3299
- const stepperMax = Math.max(rule.min, cap);
3300
- const [qty, setQty] = useState11(rule.min);
3301
- useEffect14(() => {
3302
- setQty((prev) => Math.max(rule.min, Math.min(prev, stepperMax)));
3303
- }, [stepperMax, rule.min]);
3455
+ const stepperMax = Math.max(vRule.min, cap);
3456
+ const [qty, setQty] = useState12(vRule.min);
3457
+ useEffect15(() => {
3458
+ setQty((prev) => Math.max(vRule.min, Math.min(prev, stepperMax)));
3459
+ }, [stepperMax, vRule.min]);
3304
3460
  const currentVariantId = currentVariant?.id ?? null;
3305
- useEffect14(() => {
3306
- if (!variantInStep) setQty(rule.min);
3307
- }, [variantInStep, currentVariantId, rule.min]);
3461
+ useEffect15(() => {
3462
+ if (!variantInStep) setQty(vRule.min);
3463
+ }, [variantInStep, currentVariantId, vRule.min]);
3308
3464
  if (!currentVariant || !step) return null;
3309
3465
  const thumbImage = currentVariant.image ?? product.featuredImage ?? null;
3310
3466
  const unitPriceText = formatUnitPrice6(
@@ -3312,8 +3468,8 @@ function MultiStepPickerRow({
3312
3468
  currentVariant.unitPriceMeasurement,
3313
3469
  currency
3314
3470
  );
3315
- const noStock = cap < rule.min;
3316
- const needsMoreSpots = !variantInStep && !inSwapState && room !== Number.POSITIVE_INFINITY && rule.min > room;
3471
+ const noStock = cap < vRule.min;
3472
+ const needsMoreSpots = !variantInStep && !inSwapState && room !== Number.POSITIVE_INFINITY && vRule.min > room;
3317
3473
  const addDisabled = !variantInStep && (inSwapState ? noStock : noStock || needsMoreSpots);
3318
3474
  const lockedRequired = variantInStep && currentVariant != null && !(canRemoveVariant?.(currentVariant.id) ?? true);
3319
3475
  const stepperDisabled = isOos || !variantInStep && addDisabled;
@@ -3324,7 +3480,7 @@ function MultiStepPickerRow({
3324
3480
  return;
3325
3481
  }
3326
3482
  if (!currentVariant || noStock) return;
3327
- const pickedQty = showStepper ? qty : rule.min;
3483
+ const pickedQty = showStepper ? qty : vRule.min;
3328
3484
  const item = {
3329
3485
  productId: product.id,
3330
3486
  variantId: currentVariant.id,
@@ -3346,7 +3502,7 @@ function MultiStepPickerRow({
3346
3502
  }
3347
3503
  const priceCents = parseFloat(currentVariant.price.amount);
3348
3504
  const compareCents = currentVariant.compareAtPrice ? parseFloat(currentVariant.compareAtPrice.amount) : null;
3349
- return /* @__PURE__ */ jsxs7(
3505
+ return /* @__PURE__ */ jsxs8(
3350
3506
  "div",
3351
3507
  {
3352
3508
  className: `lb-mix-match__modal-product${isOos ? " lb-mix-match__modal-product--sold-out" : ""}${variantInStep ? " lb-mix-match__modal-product--in-bundle" : ""}`,
@@ -3355,8 +3511,8 @@ function MultiStepPickerRow({
3355
3511
  "data-type": product.productType ?? "",
3356
3512
  "aria-disabled": isOos || void 0,
3357
3513
  children: [
3358
- /* @__PURE__ */ jsxs7("div", { className: "lb-mix-match__modal-product-thumb", children: [
3359
- thumbImage && /* @__PURE__ */ jsx7(
3514
+ /* @__PURE__ */ jsxs8("div", { className: "lb-mix-match__modal-product-thumb", children: [
3515
+ thumbImage && /* @__PURE__ */ jsx8(
3360
3516
  "img",
3361
3517
  {
3362
3518
  src: thumbImage.url,
@@ -3364,10 +3520,10 @@ function MultiStepPickerRow({
3364
3520
  loading: "lazy"
3365
3521
  }
3366
3522
  ),
3367
- variantInStep && /* @__PURE__ */ jsx7("span", { className: "lb-mix-match__modal-added-badge", children: "Added" })
3523
+ variantInStep && /* @__PURE__ */ jsx8("span", { className: "lb-mix-match__modal-added-badge", children: "Added" })
3368
3524
  ] }),
3369
- /* @__PURE__ */ jsxs7("div", { className: "lb-mix-match__modal-product-info", children: [
3370
- /* @__PURE__ */ jsx7("p", { className: "lb-mix-match__modal-product-title", children: /* @__PURE__ */ jsx7(
3525
+ /* @__PURE__ */ jsxs8("div", { className: "lb-mix-match__modal-product-info", children: [
3526
+ /* @__PURE__ */ jsx8("p", { className: "lb-mix-match__modal-product-title", children: /* @__PURE__ */ jsx8(
3371
3527
  "a",
3372
3528
  {
3373
3529
  href: `/products/${product.handle}`,
@@ -3376,24 +3532,24 @@ function MultiStepPickerRow({
3376
3532
  children: product.title
3377
3533
  }
3378
3534
  ) }),
3379
- /* @__PURE__ */ jsxs7("p", { className: "lb-mix-match__modal-product-price", children: [
3380
- /* @__PURE__ */ jsx7("span", { "data-row-price-sale": true, children: formatMoney6(priceCents, currency) }),
3381
- compareCents !== null && compareCents > priceCents && /* @__PURE__ */ jsx7("s", { className: "lb-mix-match__modal-product-compare", "data-row-compare": true, children: formatMoney6(compareCents, currency) })
3535
+ /* @__PURE__ */ jsxs8("p", { className: "lb-mix-match__modal-product-price", children: [
3536
+ /* @__PURE__ */ jsx8("span", { "data-row-price-sale": true, children: formatMoney6(priceCents, currency) }),
3537
+ compareCents !== null && compareCents > priceCents && /* @__PURE__ */ jsx8("s", { className: "lb-mix-match__modal-product-compare", "data-row-compare": true, children: formatMoney6(compareCents, currency) })
3382
3538
  ] }),
3383
- unitPriceText && /* @__PURE__ */ jsx7("p", { className: "lb-mix-match__modal-product-unit-price lb-bundle-product-unit-price", children: unitPriceText }),
3384
- showPicker && /* @__PURE__ */ jsx7("div", { className: "lb-bundle-variant-option-groups", children: optionNames.map((optionName, optionIndex) => {
3539
+ unitPriceText && /* @__PURE__ */ jsx8("p", { className: "lb-mix-match__modal-product-unit-price lb-bundle-product-unit-price", children: unitPriceText }),
3540
+ showPicker && /* @__PURE__ */ jsx8("div", { className: "lb-bundle-variant-option-groups", children: optionNames.map((optionName, optionIndex) => {
3385
3541
  const dropdownOptions = optionsFor(optionIndex).map((o) => ({
3386
3542
  value: o.value,
3387
3543
  label: o.value,
3388
3544
  disabled: o.disabled
3389
3545
  }));
3390
- return /* @__PURE__ */ jsxs7(
3546
+ return /* @__PURE__ */ jsxs8(
3391
3547
  "div",
3392
3548
  {
3393
3549
  className: "lb-bundle-variant-option-group",
3394
3550
  children: [
3395
- /* @__PURE__ */ jsx7("span", { className: "lb-bundle-variant-option-label", children: optionName }),
3396
- /* @__PURE__ */ jsx7(
3551
+ /* @__PURE__ */ jsx8("span", { className: "lb-bundle-variant-option-label", children: optionName }),
3552
+ /* @__PURE__ */ jsx8(
3397
3553
  VariantDropdown,
3398
3554
  {
3399
3555
  className: "lb-mix-match__variant-select-dropdown",
@@ -3408,39 +3564,39 @@ function MultiStepPickerRow({
3408
3564
  optionName
3409
3565
  );
3410
3566
  }) }),
3411
- !showPicker && variants.length === 1 && currentVariant.title !== "Default Title" && /* @__PURE__ */ jsx7("span", { className: "lb-mix-match__filled-variant", children: currentVariant.title }),
3412
- !isOos && needsMoreSpots && room > 0 && /* @__PURE__ */ jsx7("span", { className: "lb-mix-match__modal-needs-spots", children: rule.min === 1 ? "Needs 1 spot" : `Needs ${rule.min} spots` }),
3413
- isOos ? /* @__PURE__ */ jsx7("span", { className: "lb-mix-match__modal-sold-out-label", children: "Sold out" }) : /* @__PURE__ */ jsxs7("div", { className: "lb-mix-match__modal-product-actions", children: [
3414
- showStepper && /* @__PURE__ */ jsx7("div", { className: "lb-bundle-variant-option-group lb-mix-match__qty-stepper-group", children: /* @__PURE__ */ jsxs7(
3567
+ !showPicker && variants.length === 1 && currentVariant.title !== "Default Title" && /* @__PURE__ */ jsx8("span", { className: "lb-mix-match__filled-variant", children: currentVariant.title }),
3568
+ !isOos && needsMoreSpots && room > 0 && /* @__PURE__ */ jsx8("span", { className: "lb-mix-match__modal-needs-spots", children: vRule.min === 1 ? "Needs 1 spot" : `Needs ${vRule.min} spots` }),
3569
+ isOos ? /* @__PURE__ */ jsx8("span", { className: "lb-mix-match__modal-sold-out-label", children: "Sold out" }) : /* @__PURE__ */ jsxs8("div", { className: "lb-mix-match__modal-product-actions", children: [
3570
+ showStepper && /* @__PURE__ */ jsx8("div", { className: "lb-bundle-variant-option-group lb-mix-match__qty-stepper-group", children: /* @__PURE__ */ jsxs8(
3415
3571
  "div",
3416
3572
  {
3417
3573
  className: "lb-mix-match__qty-stepper",
3418
3574
  role: "group",
3419
3575
  "aria-label": "Quantity",
3420
3576
  children: [
3421
- /* @__PURE__ */ jsx7(
3577
+ /* @__PURE__ */ jsx8(
3422
3578
  "button",
3423
3579
  {
3424
3580
  type: "button",
3425
3581
  className: "lb-mix-match__qty-stepper-button lb-mix-match__qty-stepper-button--minus",
3426
3582
  "aria-label": "Decrease quantity",
3427
- disabled: stepperDisabled || shownQty <= rule.min,
3583
+ disabled: stepperDisabled || shownQty <= vRule.min,
3428
3584
  onClick: () => {
3429
3585
  if (variantInStep && currentVariant) {
3430
3586
  onUpdateQuantity(
3431
3587
  stepIndex,
3432
3588
  product.id,
3433
3589
  currentVariant.id,
3434
- Math.max(rule.min, committedQty - 1)
3590
+ Math.max(vRule.min, committedQty - 1)
3435
3591
  );
3436
3592
  } else {
3437
- setQty((q) => Math.max(rule.min, q - 1));
3593
+ setQty((q) => Math.max(vRule.min, q - 1));
3438
3594
  }
3439
3595
  },
3440
3596
  children: "\u2212"
3441
3597
  }
3442
3598
  ),
3443
- /* @__PURE__ */ jsx7(
3599
+ /* @__PURE__ */ jsx8(
3444
3600
  "span",
3445
3601
  {
3446
3602
  className: "lb-mix-match__qty-stepper-value",
@@ -3449,7 +3605,7 @@ function MultiStepPickerRow({
3449
3605
  children: shownQty
3450
3606
  }
3451
3607
  ),
3452
- /* @__PURE__ */ jsx7(
3608
+ /* @__PURE__ */ jsx8(
3453
3609
  "button",
3454
3610
  {
3455
3611
  type: "button",
@@ -3474,7 +3630,7 @@ function MultiStepPickerRow({
3474
3630
  ]
3475
3631
  }
3476
3632
  ) }),
3477
- /* @__PURE__ */ jsx7(
3633
+ /* @__PURE__ */ jsx8(
3478
3634
  "button",
3479
3635
  {
3480
3636
  type: "button",
@@ -3493,7 +3649,7 @@ function MultiStepPickerRow({
3493
3649
  );
3494
3650
  }
3495
3651
  function CloseIcon3() {
3496
- return /* @__PURE__ */ jsxs7(
3652
+ return /* @__PURE__ */ jsxs8(
3497
3653
  "svg",
3498
3654
  {
3499
3655
  width: "20",
@@ -3503,14 +3659,14 @@ function CloseIcon3() {
3503
3659
  xmlns: "http://www.w3.org/2000/svg",
3504
3660
  "aria-hidden": "true",
3505
3661
  children: [
3506
- /* @__PURE__ */ jsx7("line", { x1: "5", y1: "5", x2: "15", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
3507
- /* @__PURE__ */ jsx7("line", { x1: "15", y1: "5", x2: "5", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
3662
+ /* @__PURE__ */ jsx8("line", { x1: "5", y1: "5", x2: "15", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
3663
+ /* @__PURE__ */ jsx8("line", { x1: "15", y1: "5", x2: "5", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
3508
3664
  ]
3509
3665
  }
3510
3666
  );
3511
3667
  }
3512
3668
  function SearchClearIcon2() {
3513
- return /* @__PURE__ */ jsx7(
3669
+ return /* @__PURE__ */ jsx8(
3514
3670
  "svg",
3515
3671
  {
3516
3672
  width: "16",
@@ -3519,17 +3675,25 @@ function SearchClearIcon2() {
3519
3675
  fill: "currentColor",
3520
3676
  xmlns: "http://www.w3.org/2000/svg",
3521
3677
  "aria-hidden": "true",
3522
- children: /* @__PURE__ */ jsx7("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" })
3678
+ children: /* @__PURE__ */ jsx8("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" })
3523
3679
  }
3524
3680
  );
3525
3681
  }
3526
3682
 
3527
3683
  // src/components/MultiStepBundle.tsx
3528
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
3529
- function ruleFor4(bundle, productId) {
3684
+ import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
3685
+ function ruleFor4(bundle, productId, variantId) {
3686
+ if (variantId) {
3687
+ const vRule = bundle.variantRules[variantId];
3688
+ if (vRule) return vRule;
3689
+ }
3530
3690
  return bundle.productRules[productId] ?? DEFAULT_PRODUCT_RULE4;
3531
3691
  }
3692
+ function variantRuleFor4(bundle, variantId) {
3693
+ return variantId ? bundle.variantRules[variantId] : void 0;
3694
+ }
3532
3695
  function canRemoveItem2(bundle, selections, item) {
3696
+ if (variantRuleFor4(bundle, item.variantId)?.required) return false;
3533
3697
  const rule = ruleFor4(bundle, item.productId);
3534
3698
  if (!rule.required) return true;
3535
3699
  let unitsElsewhere = 0;
@@ -3576,14 +3740,14 @@ function MultiStepBundle(props) {
3576
3740
  bundleType: "multi_step",
3577
3741
  enabled: analyticsEnabled !== false
3578
3742
  });
3579
- const [selections, setSelections] = useState12([]);
3580
- const [pickerOpenAt, setPickerOpenAt] = useState12(null);
3581
- const [addingToCart, setAddingToCart] = useState12(false);
3582
- const [cartError, setCartError] = useState12(null);
3743
+ const [selections, setSelections] = useState13([]);
3744
+ const [pickerOpenAt, setPickerOpenAt] = useState13(null);
3745
+ const [addingToCart, setAddingToCart] = useState13(false);
3746
+ const [cartError, setCartError] = useState13(null);
3583
3747
  const bundle = result.status === "success" && result.bundle.bundleType === "multi_step" ? result.bundle : null;
3584
3748
  const setConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);
3585
3749
  const setModalConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);
3586
- useEffect15(() => {
3750
+ useEffect16(() => {
3587
3751
  if (result.status === "error") {
3588
3752
  onError?.(result.error);
3589
3753
  return;
@@ -3597,7 +3761,7 @@ function MultiStepBundle(props) {
3597
3761
  }
3598
3762
  }, [result, onError]);
3599
3763
  const steps = useMemo10(() => bundle?.steps ?? [], [bundle]);
3600
- useEffect15(() => {
3764
+ useEffect16(() => {
3601
3765
  const seeded = steps.map(() => []);
3602
3766
  if (bundle) {
3603
3767
  const seedCurrency = bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? "USD";
@@ -3807,9 +3971,9 @@ function MultiStepBundle(props) {
3807
3971
  }
3808
3972
  }, [bundle, selections, valid, onAddToCart, onError, trackAddToCart, totalQuantity, steps]);
3809
3973
  if (result.status === "loading") {
3810
- return /* @__PURE__ */ jsxs8("div", { className: `lb-bundle lb-bundle--loading ${className ?? ""}`, children: [
3811
- /* @__PURE__ */ jsx8("div", { className: "lb-skeleton lb-skeleton--title" }),
3812
- /* @__PURE__ */ jsx8("div", { className: "lb-skeleton lb-skeleton--products" })
3974
+ return /* @__PURE__ */ jsxs9("div", { className: `lb-bundle lb-bundle--loading ${className ?? ""}`, children: [
3975
+ /* @__PURE__ */ jsx9("div", { className: "lb-skeleton lb-skeleton--title" }),
3976
+ /* @__PURE__ */ jsx9("div", { className: "lb-skeleton lb-skeleton--products" })
3813
3977
  ] });
3814
3978
  }
3815
3979
  if (result.status === "error") return null;
@@ -3830,7 +3994,7 @@ function MultiStepBundle(props) {
3830
3994
  if (requiredBlocked) return null;
3831
3995
  const currency = bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? "USD";
3832
3996
  const ctaLabel = addingToCart ? "Adding..." : bundle.widgetConfig.cta.ctaText || "Add to cart";
3833
- return /* @__PURE__ */ jsxs8(
3997
+ return /* @__PURE__ */ jsxs9(
3834
3998
  "div",
3835
3999
  {
3836
4000
  ref: (el) => {
@@ -3842,12 +4006,19 @@ function MultiStepBundle(props) {
3842
4006
  "aria-label": bundle.title,
3843
4007
  "data-required-quantity": totalMin,
3844
4008
  children: [
3845
- /* @__PURE__ */ jsx8("div", { className: "lb-bundle-header", children: /* @__PURE__ */ jsxs8("div", { className: "lb-bundle-header__content", children: [
3846
- /* @__PURE__ */ jsx8("h3", { className: "lb-bundle-title", children: bundle.title }),
3847
- bundle.description && /* @__PURE__ */ jsx8("p", { className: "lb-bundle-subtitle", children: bundle.description })
4009
+ /* @__PURE__ */ jsx9("div", { className: "lb-bundle-header", children: /* @__PURE__ */ jsxs9("div", { className: "lb-bundle-header__content", children: [
4010
+ /* @__PURE__ */ jsx9("h3", { className: "lb-bundle-title", children: bundle.title }),
4011
+ bundle.description && /* @__PURE__ */ jsx9("p", { className: "lb-bundle-subtitle", children: bundle.description })
3848
4012
  ] }) }),
3849
- /* @__PURE__ */ jsxs8("div", { className: "lb-mix-match__progress", "data-progress": true, children: [
3850
- /* @__PURE__ */ jsx8(
4013
+ /* @__PURE__ */ jsx9(
4014
+ BundleCountdown,
4015
+ {
4016
+ endsAt: bundle.endsAt,
4017
+ widgetConfig: bundle.widgetConfig
4018
+ }
4019
+ ),
4020
+ /* @__PURE__ */ jsxs9("div", { className: "lb-mix-match__progress", "data-progress": true, children: [
4021
+ /* @__PURE__ */ jsx9(
3851
4022
  "div",
3852
4023
  {
3853
4024
  className: "lb-mix-match__progress-segments",
@@ -3855,7 +4026,7 @@ function MultiStepBundle(props) {
3855
4026
  "aria-valuenow": completedSteps,
3856
4027
  "aria-valuemin": 0,
3857
4028
  "aria-valuemax": steps.length,
3858
- children: Array.from({ length: steps.length }).map((_, i) => /* @__PURE__ */ jsx8(
4029
+ children: Array.from({ length: steps.length }).map((_, i) => /* @__PURE__ */ jsx9(
3859
4030
  "span",
3860
4031
  {
3861
4032
  className: `lb-mix-match__progress-segment${i < completedSteps ? " lb-mix-match__progress-segment--filled" : ""}`,
@@ -3865,8 +4036,8 @@ function MultiStepBundle(props) {
3865
4036
  ))
3866
4037
  }
3867
4038
  ),
3868
- /* @__PURE__ */ jsxs8("div", { className: "lb-mix-match__progress-labels", children: [
3869
- /* @__PURE__ */ jsx8(
4039
+ /* @__PURE__ */ jsxs9("div", { className: "lb-mix-match__progress-labels", children: [
4040
+ /* @__PURE__ */ jsx9(
3870
4041
  "span",
3871
4042
  {
3872
4043
  className: "lb-mix-match__progress-count",
@@ -3875,7 +4046,7 @@ function MultiStepBundle(props) {
3875
4046
  children: `${completedSteps} of ${steps.length} steps completed`
3876
4047
  }
3877
4048
  ),
3878
- /* @__PURE__ */ jsx8(
4049
+ /* @__PURE__ */ jsx9(
3879
4050
  "span",
3880
4051
  {
3881
4052
  className: "lb-mix-match__progress-remaining",
@@ -3886,15 +4057,15 @@ function MultiStepBundle(props) {
3886
4057
  )
3887
4058
  ] })
3888
4059
  ] }),
3889
- /* @__PURE__ */ jsx8("div", { className: "lb-multi-step__groups", "data-step-groups": true, children: steps.map((step, i) => /* @__PURE__ */ jsxs8(
4060
+ /* @__PURE__ */ jsx9("div", { className: "lb-multi-step__groups", "data-step-groups": true, children: steps.map((step, i) => /* @__PURE__ */ jsxs9(
3890
4061
  "section",
3891
4062
  {
3892
4063
  className: "lb-multi-step__group",
3893
4064
  "data-step-group": i,
3894
4065
  children: [
3895
- /* @__PURE__ */ jsxs8("div", { className: "lb-multi-step__group-heading", children: [
3896
- /* @__PURE__ */ jsx8("span", { className: "lb-multi-step__group-name", children: step.name }),
3897
- /* @__PURE__ */ jsx8(
4066
+ /* @__PURE__ */ jsxs9("div", { className: "lb-multi-step__group-heading", children: [
4067
+ /* @__PURE__ */ jsx9("span", { className: "lb-multi-step__group-name", children: step.name }),
4068
+ /* @__PURE__ */ jsx9(
3898
4069
  "span",
3899
4070
  {
3900
4071
  className: `lb-multi-step__group-count${stepSatisfied(i) ? " lb-multi-step__group-count--met" : ""}`,
@@ -3903,7 +4074,7 @@ function MultiStepBundle(props) {
3903
4074
  }
3904
4075
  )
3905
4076
  ] }),
3906
- /* @__PURE__ */ jsx8(
4077
+ /* @__PURE__ */ jsx9(
3907
4078
  "div",
3908
4079
  {
3909
4080
  className: "lb-mix-match__slots lb-edge-fade lb-multi-step__group-slots",
@@ -3913,13 +4084,13 @@ function MultiStepBundle(props) {
3913
4084
  title button provides the keyboard/AT path (its
3914
4085
  activation bubbles here); × stops propagation. */
3915
4086
  // 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
3916
- /* @__PURE__ */ jsxs8(
4087
+ /* @__PURE__ */ jsxs9(
3917
4088
  "div",
3918
4089
  {
3919
4090
  className: "lb-mix-match__slot lb-mix-match__slot--filled",
3920
4091
  onClick: () => setPickerOpenAt(i),
3921
4092
  children: [
3922
- item.featuredImage && /* @__PURE__ */ jsx8("div", { className: "lb-bundle-thumbnail", children: /* @__PURE__ */ jsx8(
4093
+ item.featuredImage && /* @__PURE__ */ jsx9("div", { className: "lb-bundle-thumbnail", children: /* @__PURE__ */ jsx9(
3923
4094
  "img",
3924
4095
  {
3925
4096
  src: item.featuredImage,
@@ -3927,8 +4098,8 @@ function MultiStepBundle(props) {
3927
4098
  loading: "lazy"
3928
4099
  }
3929
4100
  ) }),
3930
- /* @__PURE__ */ jsxs8("div", { className: "lb-mix-match__filled-info", children: [
3931
- /* @__PURE__ */ jsx8(
4101
+ /* @__PURE__ */ jsxs9("div", { className: "lb-mix-match__filled-info", children: [
4102
+ /* @__PURE__ */ jsx9(
3932
4103
  "button",
3933
4104
  {
3934
4105
  type: "button",
@@ -3937,15 +4108,15 @@ function MultiStepBundle(props) {
3937
4108
  children: item.title
3938
4109
  }
3939
4110
  ),
3940
- item.variantTitle && item.variantTitle !== "Default Title" && /* @__PURE__ */ jsx8("span", { className: "lb-mix-match__filled-variant", children: item.variantTitle }),
3941
- /* @__PURE__ */ jsxs8("span", { className: "lb-mix-match__filled-price", children: [
3942
- item.compareAtPrice !== null && item.compareAtPrice > item.price && /* @__PURE__ */ jsx8("s", { className: "lb-mix-match__filled-compare", children: formatMoney7(item.compareAtPrice, currency) }),
3943
- /* @__PURE__ */ jsx8("span", { className: "lb-bundle-product-price", children: formatMoney7(item.price, currency) }),
3944
- /* @__PURE__ */ jsx8("span", { className: "lb-bundle-qty-inline", children: `\xD7${item.quantity}` })
4111
+ item.variantTitle && item.variantTitle !== "Default Title" && /* @__PURE__ */ jsx9("span", { className: "lb-mix-match__filled-variant", children: item.variantTitle }),
4112
+ /* @__PURE__ */ jsxs9("span", { className: "lb-mix-match__filled-price", children: [
4113
+ item.compareAtPrice !== null && item.compareAtPrice > item.price && /* @__PURE__ */ jsx9("s", { className: "lb-mix-match__filled-compare", children: formatMoney7(item.compareAtPrice, currency) }),
4114
+ /* @__PURE__ */ jsx9("span", { className: "lb-bundle-product-price", children: formatMoney7(item.price, currency) }),
4115
+ /* @__PURE__ */ jsx9("span", { className: "lb-bundle-qty-inline", children: `\xD7${item.quantity}` })
3945
4116
  ] }),
3946
- item.unitPrice && /* @__PURE__ */ jsx8("span", { className: "lb-bundle-product-unit-price", children: item.unitPrice })
4117
+ item.unitPrice && /* @__PURE__ */ jsx9("span", { className: "lb-bundle-product-unit-price", children: item.unitPrice })
3947
4118
  ] }),
3948
- canRemoveItem2(bundle, selections, item) ? /* @__PURE__ */ jsx8(
4119
+ canRemoveItem2(bundle, selections, item) ? /* @__PURE__ */ jsx9(
3949
4120
  "button",
3950
4121
  {
3951
4122
  type: "button",
@@ -3955,13 +4126,13 @@ function MultiStepBundle(props) {
3955
4126
  e.stopPropagation();
3956
4127
  removeSlot(i, index);
3957
4128
  },
3958
- children: /* @__PURE__ */ jsx8(CloseIcon4, {})
4129
+ children: /* @__PURE__ */ jsx9(CloseIcon4, {})
3959
4130
  }
3960
4131
  ) : (
3961
4132
  /* Required pick at its floor — quiet state chip instead
3962
4133
  of the ×; removal returns once another slot covers
3963
4134
  the product's minimum (variant swap flow). */
3964
- /* @__PURE__ */ jsx8("span", { className: "lb-mix-match__slot-required", children: "Required" })
4135
+ /* @__PURE__ */ jsx9("span", { className: "lb-mix-match__slot-required", children: "Required" })
3965
4136
  )
3966
4137
  ]
3967
4138
  },
@@ -3970,7 +4141,7 @@ function MultiStepBundle(props) {
3970
4141
  ))
3971
4142
  }
3972
4143
  ),
3973
- stepHeadroom2(step.maxQuantity, unitsByStep[i] ?? 0) !== 0 && /* @__PURE__ */ jsxs8(
4144
+ stepHeadroom2(step.maxQuantity, unitsByStep[i] ?? 0) !== 0 && /* @__PURE__ */ jsxs9(
3974
4145
  "button",
3975
4146
  {
3976
4147
  type: "button",
@@ -3979,15 +4150,15 @@ function MultiStepBundle(props) {
3979
4150
  "aria-label": `${step.minQuantity === 1 && step.maxQuantity === 1 ? "Choose a product" : "Choose products"}: ${step.name}`,
3980
4151
  onClick: () => setPickerOpenAt(i),
3981
4152
  children: [
3982
- /* @__PURE__ */ jsx8(
4153
+ /* @__PURE__ */ jsx9(
3983
4154
  "span",
3984
4155
  {
3985
4156
  className: "lb-mix-match__add-product-icon",
3986
4157
  "aria-hidden": "true",
3987
- children: /* @__PURE__ */ jsx8(PlusIcon2, {})
4158
+ children: /* @__PURE__ */ jsx9(PlusIcon2, {})
3988
4159
  }
3989
4160
  ),
3990
- /* @__PURE__ */ jsx8("span", { className: "lb-mix-match__add-product-label", children: step.minQuantity === 1 && step.maxQuantity === 1 ? "Choose a product" : "Choose products" })
4161
+ /* @__PURE__ */ jsx9("span", { className: "lb-mix-match__add-product-label", children: step.minQuantity === 1 && step.maxQuantity === 1 ? "Choose a product" : "Choose products" })
3991
4162
  ]
3992
4163
  }
3993
4164
  )
@@ -3995,29 +4166,29 @@ function MultiStepBundle(props) {
3995
4166
  },
3996
4167
  i
3997
4168
  )) }),
3998
- /* @__PURE__ */ jsx8("div", { className: "lb-bundle-divider" }),
3999
- allSatisfied && /* @__PURE__ */ jsxs8("div", { className: "lb-bundle-summary", "data-pricing-section": true, children: [
4000
- /* @__PURE__ */ jsxs8("div", { className: "lb-bundle-summary__text", children: [
4001
- /* @__PURE__ */ jsx8("span", { className: "lb-bundle-summary__label", children: "Bundle total" }),
4002
- bundle.widgetConfig.savingsBar.visible && summary.savings > 0 && /* @__PURE__ */ jsxs8("p", { className: "lb-bundle-savings-line", "data-savings-bar": true, children: [
4169
+ /* @__PURE__ */ jsx9("div", { className: "lb-bundle-divider" }),
4170
+ allSatisfied && /* @__PURE__ */ jsxs9("div", { className: "lb-bundle-summary", "data-pricing-section": true, children: [
4171
+ /* @__PURE__ */ jsxs9("div", { className: "lb-bundle-summary__text", children: [
4172
+ /* @__PURE__ */ jsx9("span", { className: "lb-bundle-summary__label", children: "Bundle total" }),
4173
+ bundle.widgetConfig.savingsBar.visible && summary.savings > 0 && /* @__PURE__ */ jsxs9("p", { className: "lb-bundle-savings-line", "data-savings-bar": true, children: [
4003
4174
  "You save",
4004
4175
  " ",
4005
- /* @__PURE__ */ jsx8("span", { "data-savings-amount": true, children: formatMoney7(summary.savings, currency) }),
4176
+ /* @__PURE__ */ jsx9("span", { "data-savings-amount": true, children: formatMoney7(summary.savings, currency) }),
4006
4177
  " ",
4007
- /* @__PURE__ */ jsxs8("span", { "data-savings-percent": true, children: [
4178
+ /* @__PURE__ */ jsxs9("span", { "data-savings-percent": true, children: [
4008
4179
  "(",
4009
4180
  summary.savingsPercent,
4010
4181
  "%)"
4011
4182
  ] })
4012
4183
  ] })
4013
4184
  ] }),
4014
- /* @__PURE__ */ jsxs8("span", { className: "lb-bundle-summary__prices", children: [
4015
- bundle.widgetConfig.pricing.showComparePrice && summary.savings > 0 && /* @__PURE__ */ jsx8("span", { className: "lb-bundle-compare-price", "data-compare-price": true, children: formatMoney7(summary.comparePrice, currency) }),
4016
- /* @__PURE__ */ jsx8("span", { className: "lb-bundle-sale-price", "data-sale-price": true, children: formatMoney7(summary.salePrice, currency) })
4185
+ /* @__PURE__ */ jsxs9("span", { className: "lb-bundle-summary__prices", children: [
4186
+ bundle.widgetConfig.pricing.showComparePrice && summary.savings > 0 && /* @__PURE__ */ jsx9("span", { className: "lb-bundle-compare-price", "data-compare-price": true, children: formatMoney7(summary.comparePrice, currency) }),
4187
+ /* @__PURE__ */ jsx9("span", { className: "lb-bundle-sale-price", "data-sale-price": true, children: formatMoney7(summary.salePrice, currency) })
4017
4188
  ] })
4018
4189
  ] }),
4019
- cartError && /* @__PURE__ */ jsx8("p", { className: "lb-bundle__error", role: "alert", children: cartError }),
4020
- /* @__PURE__ */ jsx8(
4190
+ cartError && /* @__PURE__ */ jsx9("p", { className: "lb-bundle__error", role: "alert", children: cartError }),
4191
+ /* @__PURE__ */ jsx9(
4021
4192
  "button",
4022
4193
  {
4023
4194
  className: "lb-bundle__cta",
@@ -4027,7 +4198,7 @@ function MultiStepBundle(props) {
4027
4198
  children: ctaLabel
4028
4199
  }
4029
4200
  ),
4030
- pickerOpenAt !== null && /* @__PURE__ */ jsx8(
4201
+ pickerOpenAt !== null && /* @__PURE__ */ jsx9(
4031
4202
  MultiStepPicker,
4032
4203
  {
4033
4204
  outOfStockBehavior,
@@ -4063,7 +4234,7 @@ function stepHasInStockProduct(bundle, stepIndex) {
4063
4234
  });
4064
4235
  }
4065
4236
  function PlusIcon2() {
4066
- return /* @__PURE__ */ jsxs8(
4237
+ return /* @__PURE__ */ jsxs9(
4067
4238
  "svg",
4068
4239
  {
4069
4240
  width: "18",
@@ -4073,14 +4244,14 @@ function PlusIcon2() {
4073
4244
  xmlns: "http://www.w3.org/2000/svg",
4074
4245
  "aria-hidden": "true",
4075
4246
  children: [
4076
- /* @__PURE__ */ jsx8("line", { x1: "9", y1: "3", x2: "9", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
4077
- /* @__PURE__ */ jsx8("line", { x1: "3", y1: "9", x2: "15", y2: "9", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
4247
+ /* @__PURE__ */ jsx9("line", { x1: "9", y1: "3", x2: "9", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
4248
+ /* @__PURE__ */ jsx9("line", { x1: "3", y1: "9", x2: "15", y2: "9", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
4078
4249
  ]
4079
4250
  }
4080
4251
  );
4081
4252
  }
4082
4253
  function CloseIcon4() {
4083
- return /* @__PURE__ */ jsxs8(
4254
+ return /* @__PURE__ */ jsxs9(
4084
4255
  "svg",
4085
4256
  {
4086
4257
  width: "16",
@@ -4090,8 +4261,8 @@ function CloseIcon4() {
4090
4261
  xmlns: "http://www.w3.org/2000/svg",
4091
4262
  "aria-hidden": "true",
4092
4263
  children: [
4093
- /* @__PURE__ */ jsx8("line", { x1: "5", y1: "5", x2: "15", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
4094
- /* @__PURE__ */ jsx8("line", { x1: "15", y1: "5", x2: "5", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
4264
+ /* @__PURE__ */ jsx9("line", { x1: "5", y1: "5", x2: "15", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
4265
+ /* @__PURE__ */ jsx9("line", { x1: "15", y1: "5", x2: "5", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
4095
4266
  ]
4096
4267
  }
4097
4268
  );
@@ -4104,7 +4275,7 @@ async function fetchShopCustomCss(options) {
4104
4275
  }
4105
4276
 
4106
4277
  // src/hooks/useBundlesForProduct.ts
4107
- import { useState as useState13, useEffect as useEffect16 } from "react";
4278
+ import { useState as useState14, useEffect as useEffect17 } from "react";
4108
4279
  import {
4109
4280
  fetchBundlesForProduct,
4110
4281
  injectCustomCss as injectCustomCss2
@@ -4115,10 +4286,10 @@ var INITIAL_STATE2 = {
4115
4286
  error: null
4116
4287
  };
4117
4288
  function useBundlesForProduct(options) {
4118
- const [state, setState] = useState13(
4289
+ const [state, setState] = useState14(
4119
4290
  INITIAL_STATE2
4120
4291
  );
4121
- useEffect16(() => {
4292
+ useEffect17(() => {
4122
4293
  const controller = new AbortController();
4123
4294
  setState(INITIAL_STATE2);
4124
4295
  fetchBundlesForProduct({
@@ -4200,6 +4371,7 @@ export {
4200
4371
  BUNDLES_FOR_PRODUCT_QUERY,
4201
4372
  BUNDLE_METAOBJECT_QUERY2 as BUNDLE_METAOBJECT_QUERY,
4202
4373
  BogoBundle,
4374
+ BundleCountdown,
4203
4375
  BundleParseError2 as BundleParseError,
4204
4376
  DEFAULT_OUT_OF_STOCK_BEHAVIOR3 as DEFAULT_OUT_OF_STOCK_BEHAVIOR,
4205
4377
  FixedBundle,