@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/README.md +7 -1
- package/dist/index.cjs +688 -518
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -3
- package/dist/index.d.ts +22 -3
- package/dist/index.js +633 -461
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1901 -0
- package/docs/css-variables.md +7 -1
- package/docs/hydrogen.md +29 -4
- package/docs/react-nextjs.md +24 -4
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -23,6 +23,7 @@ __export(index_exports, {
|
|
|
23
23
|
BUNDLES_FOR_PRODUCT_QUERY: () => import_core18.BUNDLES_FOR_PRODUCT_QUERY,
|
|
24
24
|
BUNDLE_METAOBJECT_QUERY: () => import_core18.BUNDLE_METAOBJECT_QUERY,
|
|
25
25
|
BogoBundle: () => BogoBundle,
|
|
26
|
+
BundleCountdown: () => BundleCountdown,
|
|
26
27
|
BundleParseError: () => import_core17.BundleParseError,
|
|
27
28
|
DEFAULT_OUT_OF_STOCK_BEHAVIOR: () => import_core18.DEFAULT_OUT_OF_STOCK_BEHAVIOR,
|
|
28
29
|
FixedBundle: () => FixedBundle,
|
|
@@ -75,7 +76,7 @@ __export(index_exports, {
|
|
|
75
76
|
module.exports = __toCommonJS(index_exports);
|
|
76
77
|
|
|
77
78
|
// src/components/FixedBundle.tsx
|
|
78
|
-
var
|
|
79
|
+
var import_react8 = require("react");
|
|
79
80
|
var import_core8 = require("@lime-bundles/core");
|
|
80
81
|
|
|
81
82
|
// src/hooks/useBundleData.ts
|
|
@@ -702,8 +703,48 @@ function VariantDropdown({
|
|
|
702
703
|
);
|
|
703
704
|
}
|
|
704
705
|
|
|
705
|
-
// src/components/
|
|
706
|
+
// src/components/BundleCountdown.tsx
|
|
707
|
+
var import_react7 = require("react");
|
|
706
708
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
709
|
+
function pad(n) {
|
|
710
|
+
return n < 10 ? "0" + n : String(n);
|
|
711
|
+
}
|
|
712
|
+
function formatRemaining(remaining) {
|
|
713
|
+
const days = Math.floor(remaining / 864e5);
|
|
714
|
+
const hours = Math.floor(remaining % 864e5 / 36e5);
|
|
715
|
+
const mins = Math.floor(remaining % 36e5 / 6e4);
|
|
716
|
+
const secs = Math.floor(remaining % 6e4 / 1e3);
|
|
717
|
+
return days > 0 ? days + "d " + pad(hours) + "h " + pad(mins) + "m " + pad(secs) + "s" : pad(hours) + "h " + pad(mins) + "m " + pad(secs) + "s";
|
|
718
|
+
}
|
|
719
|
+
function BundleCountdown({
|
|
720
|
+
endsAt,
|
|
721
|
+
widgetConfig,
|
|
722
|
+
label = "Limited time offer"
|
|
723
|
+
}) {
|
|
724
|
+
const enabled = !!endsAt && widgetConfig?.countdown?.showCountdown !== false;
|
|
725
|
+
const endTime = enabled ? new Date(endsAt).getTime() : NaN;
|
|
726
|
+
const [remaining, setRemaining] = (0, import_react7.useState)(null);
|
|
727
|
+
(0, import_react7.useEffect)(() => {
|
|
728
|
+
if (!enabled || isNaN(endTime)) {
|
|
729
|
+
setRemaining(null);
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
const update = () => setRemaining(endTime - Date.now());
|
|
733
|
+
update();
|
|
734
|
+
const interval = setInterval(update, 1e3);
|
|
735
|
+
return () => clearInterval(interval);
|
|
736
|
+
}, [enabled, endTime]);
|
|
737
|
+
if (!enabled || isNaN(endTime) || remaining === null || remaining <= 0) {
|
|
738
|
+
return null;
|
|
739
|
+
}
|
|
740
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "lb-bundle-countdown", "data-countdown": true, children: [
|
|
741
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "lb-bundle-countdown__label", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: label }) }),
|
|
742
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "lb-bundle-countdown__timer", "data-countdown-timer": true, children: formatRemaining(remaining) })
|
|
743
|
+
] });
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
// src/components/FixedBundle.tsx
|
|
747
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
707
748
|
function FixedBundle(props) {
|
|
708
749
|
const {
|
|
709
750
|
shopDomain,
|
|
@@ -727,10 +768,10 @@ function FixedBundle(props) {
|
|
|
727
768
|
bundleType: "fixed",
|
|
728
769
|
enabled: analyticsEnabled !== false
|
|
729
770
|
});
|
|
730
|
-
const [addingToCart, setAddingToCart] = (0,
|
|
731
|
-
const [cartError, setCartError] = (0,
|
|
732
|
-
const [selectedVariants, setSelectedVariants] = (0,
|
|
733
|
-
const handleVariantChange = (0,
|
|
771
|
+
const [addingToCart, setAddingToCart] = (0, import_react8.useState)(false);
|
|
772
|
+
const [cartError, setCartError] = (0, import_react8.useState)(null);
|
|
773
|
+
const [selectedVariants, setSelectedVariants] = (0, import_react8.useState)({});
|
|
774
|
+
const handleVariantChange = (0, import_react8.useCallback)(
|
|
734
775
|
(productId, variant) => {
|
|
735
776
|
setSelectedVariants((prev) => {
|
|
736
777
|
if (prev[productId] === variant) return prev;
|
|
@@ -742,7 +783,7 @@ function FixedBundle(props) {
|
|
|
742
783
|
const bundle = result.status === "success" && result.bundle.bundleType === "fixed" ? result.bundle : null;
|
|
743
784
|
const setConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);
|
|
744
785
|
const productsEdgeFadeRef = useEdgeFade();
|
|
745
|
-
(0,
|
|
786
|
+
(0, import_react8.useEffect)(() => {
|
|
746
787
|
if (result.status === "error") {
|
|
747
788
|
onError?.(result.error);
|
|
748
789
|
return;
|
|
@@ -755,7 +796,7 @@ function FixedBundle(props) {
|
|
|
755
796
|
);
|
|
756
797
|
}
|
|
757
798
|
}, [result, onError]);
|
|
758
|
-
const oosProductIds = (0,
|
|
799
|
+
const oosProductIds = (0, import_react8.useMemo)(() => {
|
|
759
800
|
if (!bundle) return /* @__PURE__ */ new Set();
|
|
760
801
|
return new Set(
|
|
761
802
|
bundle.products.filter(
|
|
@@ -765,7 +806,7 @@ function FixedBundle(props) {
|
|
|
765
806
|
).map((p) => p.id)
|
|
766
807
|
);
|
|
767
808
|
}, [bundle]);
|
|
768
|
-
const handleAddToCart = (0,
|
|
809
|
+
const handleAddToCart = (0, import_react8.useCallback)(async () => {
|
|
769
810
|
if (!bundle) return;
|
|
770
811
|
const bundleLines = bundle.products.filter(
|
|
771
812
|
(p) => p.variants.nodes.some(
|
|
@@ -820,9 +861,9 @@ function FixedBundle(props) {
|
|
|
820
861
|
}
|
|
821
862
|
}, [bundle, onAddToCart, onError, trackAddToCart, selectedVariants]);
|
|
822
863
|
if (result.status === "loading") {
|
|
823
|
-
return /* @__PURE__ */ (0,
|
|
824
|
-
/* @__PURE__ */ (0,
|
|
825
|
-
/* @__PURE__ */ (0,
|
|
864
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: `lb-bundle lb-bundle--loading ${className ?? ""}`, children: [
|
|
865
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "lb-skeleton lb-skeleton--title" }),
|
|
866
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "lb-skeleton lb-skeleton--products" })
|
|
826
867
|
] });
|
|
827
868
|
}
|
|
828
869
|
if (result.status === "error") return null;
|
|
@@ -849,7 +890,7 @@ function FixedBundle(props) {
|
|
|
849
890
|
const savingsPercent = comparePrice > 0 && savings > 0 ? Math.round(savings / comparePrice * 100) : 0;
|
|
850
891
|
const showCompare = bundle.widgetConfig.pricing.showComparePrice && savings > 0;
|
|
851
892
|
const showSavings = bundle.widgetConfig.savingsBar.visible && savings > 0;
|
|
852
|
-
return /* @__PURE__ */ (0,
|
|
893
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
853
894
|
"div",
|
|
854
895
|
{
|
|
855
896
|
ref: (el) => {
|
|
@@ -860,11 +901,18 @@ function FixedBundle(props) {
|
|
|
860
901
|
role: "region",
|
|
861
902
|
"aria-label": bundle.title,
|
|
862
903
|
children: [
|
|
863
|
-
/* @__PURE__ */ (0,
|
|
864
|
-
/* @__PURE__ */ (0,
|
|
865
|
-
bundle.description && /* @__PURE__ */ (0,
|
|
904
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "lb-bundle-header", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "lb-bundle-header__content", children: [
|
|
905
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { className: "lb-bundle-title", children: bundle.title }),
|
|
906
|
+
bundle.description && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "lb-bundle-subtitle", children: bundle.description })
|
|
866
907
|
] }) }),
|
|
867
|
-
/* @__PURE__ */ (0,
|
|
908
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
909
|
+
BundleCountdown,
|
|
910
|
+
{
|
|
911
|
+
endsAt: bundle.endsAt,
|
|
912
|
+
widgetConfig: bundle.widgetConfig
|
|
913
|
+
}
|
|
914
|
+
),
|
|
915
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "lb-bundle__products lb-edge-fade", ref: productsEdgeFadeRef, children: bundle.products.map((product) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
868
916
|
FixedProductRow,
|
|
869
917
|
{
|
|
870
918
|
bundle,
|
|
@@ -875,29 +923,29 @@ function FixedBundle(props) {
|
|
|
875
923
|
},
|
|
876
924
|
product.id
|
|
877
925
|
)) }),
|
|
878
|
-
/* @__PURE__ */ (0,
|
|
879
|
-
/* @__PURE__ */ (0,
|
|
880
|
-
/* @__PURE__ */ (0,
|
|
881
|
-
/* @__PURE__ */ (0,
|
|
882
|
-
showSavings && /* @__PURE__ */ (0,
|
|
926
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "lb-bundle-divider" }),
|
|
927
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "lb-bundle-summary", children: [
|
|
928
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "lb-bundle-summary__text", children: [
|
|
929
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "lb-bundle-summary__label", children: "Bundle total" }),
|
|
930
|
+
showSavings && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { className: "lb-bundle-savings-line", "data-savings-bar": true, children: [
|
|
883
931
|
"You save",
|
|
884
932
|
" ",
|
|
885
|
-
/* @__PURE__ */ (0,
|
|
933
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { "data-savings-amount": true, children: (0, import_core8.formatMoney)(savings, currency) }),
|
|
886
934
|
" ",
|
|
887
|
-
/* @__PURE__ */ (0,
|
|
935
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { "data-savings-percent": true, children: [
|
|
888
936
|
"(",
|
|
889
937
|
savingsPercent,
|
|
890
938
|
"%)"
|
|
891
939
|
] })
|
|
892
940
|
] })
|
|
893
941
|
] }),
|
|
894
|
-
/* @__PURE__ */ (0,
|
|
895
|
-
showCompare && /* @__PURE__ */ (0,
|
|
896
|
-
/* @__PURE__ */ (0,
|
|
942
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "lb-bundle-summary__prices", children: [
|
|
943
|
+
showCompare && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "lb-bundle-compare-price", "data-compare-price": true, children: (0, import_core8.formatMoney)(comparePrice, currency) }),
|
|
944
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "lb-bundle-sale-price", "data-sale-price": true, children: (0, import_core8.formatMoney)(salePrice, currency) })
|
|
897
945
|
] })
|
|
898
946
|
] }),
|
|
899
|
-
cartError && /* @__PURE__ */ (0,
|
|
900
|
-
/* @__PURE__ */ (0,
|
|
947
|
+
cartError && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "lb-bundle__error", role: "alert", children: cartError }),
|
|
948
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
901
949
|
"button",
|
|
902
950
|
{
|
|
903
951
|
className: "lb-bundle__cta",
|
|
@@ -913,7 +961,7 @@ function FixedBundle(props) {
|
|
|
913
961
|
}
|
|
914
962
|
function FixedProductRow({ bundle, product, currency, isOos, onVariantChange }) {
|
|
915
963
|
const variants = product.variants.nodes;
|
|
916
|
-
const optionNames = (0,
|
|
964
|
+
const optionNames = (0, import_react8.useMemo)(() => {
|
|
917
965
|
const first = variants[0];
|
|
918
966
|
return first ? first.selectedOptions.map((o) => o.name) : [];
|
|
919
967
|
}, [variants]);
|
|
@@ -922,7 +970,7 @@ function FixedProductRow({ bundle, product, currency, isOos, onVariantChange })
|
|
|
922
970
|
variants,
|
|
923
971
|
optionNames
|
|
924
972
|
});
|
|
925
|
-
(0,
|
|
973
|
+
(0, import_react8.useEffect)(() => {
|
|
926
974
|
onVariantChange(product.id, selectedVariant ?? null);
|
|
927
975
|
}, [selectedVariant, product.id, onVariantChange]);
|
|
928
976
|
const displayVariant = selectedVariant ?? variants.find(
|
|
@@ -943,15 +991,15 @@ function FixedProductRow({ bundle, product, currency, isOos, onVariantChange })
|
|
|
943
991
|
bundle.widgetConfig.lowStockThreshold,
|
|
944
992
|
bundle.widgetConfig.showLowStockBadge
|
|
945
993
|
);
|
|
946
|
-
return /* @__PURE__ */ (0,
|
|
994
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
947
995
|
"div",
|
|
948
996
|
{
|
|
949
997
|
className: isOos ? "lb-bundle-product-row lb-bundle-product-row--oos" : "lb-bundle-product-row",
|
|
950
998
|
"aria-disabled": isOos || void 0,
|
|
951
999
|
part: "product",
|
|
952
1000
|
children: [
|
|
953
|
-
isOos && /* @__PURE__ */ (0,
|
|
954
|
-
thumbImage && /* @__PURE__ */ (0,
|
|
1001
|
+
isOos && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "lb-bundle-product-row__oos", children: "Out of stock" }),
|
|
1002
|
+
thumbImage && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
955
1003
|
"img",
|
|
956
1004
|
{
|
|
957
1005
|
src: thumbImage.url,
|
|
@@ -960,11 +1008,11 @@ function FixedProductRow({ bundle, product, currency, isOos, onVariantChange })
|
|
|
960
1008
|
loading: "lazy"
|
|
961
1009
|
}
|
|
962
1010
|
),
|
|
963
|
-
/* @__PURE__ */ (0,
|
|
964
|
-
/* @__PURE__ */ (0,
|
|
965
|
-
!showPicker && displayVariant && variants.length > 1 && /* @__PURE__ */ (0,
|
|
966
|
-
/* @__PURE__ */ (0,
|
|
967
|
-
compareAt && /* @__PURE__ */ (0,
|
|
1011
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "lb-bundle__product-info", children: [
|
|
1012
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "lb-bundle__product-title", children: product.title }),
|
|
1013
|
+
!showPicker && displayVariant && variants.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "lb-bundle-variant-badge", children: displayVariant.title }),
|
|
1014
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "lb-bundle-product-prices", children: [
|
|
1015
|
+
compareAt && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
968
1016
|
"span",
|
|
969
1017
|
{
|
|
970
1018
|
className: "lb-bundle-product-compare-price",
|
|
@@ -972,9 +1020,9 @@ function FixedProductRow({ bundle, product, currency, isOos, onVariantChange })
|
|
|
972
1020
|
children: compareAt
|
|
973
1021
|
}
|
|
974
1022
|
),
|
|
975
|
-
/* @__PURE__ */ (0,
|
|
1023
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "lb-bundle__product-price", "data-product-price": true, children: priceText })
|
|
976
1024
|
] }),
|
|
977
|
-
unitPriceText && /* @__PURE__ */ (0,
|
|
1025
|
+
unitPriceText && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
978
1026
|
"span",
|
|
979
1027
|
{
|
|
980
1028
|
className: "lb-bundle__product-unit-price",
|
|
@@ -982,18 +1030,18 @@ function FixedProductRow({ bundle, product, currency, isOos, onVariantChange })
|
|
|
982
1030
|
children: unitPriceText
|
|
983
1031
|
}
|
|
984
1032
|
),
|
|
985
|
-
showLowStock && /* @__PURE__ */ (0,
|
|
1033
|
+
showLowStock && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "lb-bundle-low-stock-badge", children: [
|
|
986
1034
|
"Only ",
|
|
987
1035
|
displayVariant.quantityAvailable,
|
|
988
1036
|
" left"
|
|
989
1037
|
] }),
|
|
990
|
-
showPicker && /* @__PURE__ */ (0,
|
|
1038
|
+
showPicker && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "lb-bundle__product-variant-pickers", children: optionNames.map((optionName, optionIndex) => {
|
|
991
1039
|
const dropdownOptions = optionsFor(optionIndex).map((o) => ({
|
|
992
1040
|
value: o.value,
|
|
993
1041
|
label: o.value,
|
|
994
1042
|
disabled: o.disabled
|
|
995
1043
|
}));
|
|
996
|
-
return /* @__PURE__ */ (0,
|
|
1044
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
997
1045
|
VariantDropdown,
|
|
998
1046
|
{
|
|
999
1047
|
options: dropdownOptions,
|
|
@@ -1005,7 +1053,7 @@ function FixedProductRow({ bundle, product, currency, isOos, onVariantChange })
|
|
|
1005
1053
|
);
|
|
1006
1054
|
}) })
|
|
1007
1055
|
] }),
|
|
1008
|
-
displayVariant && /* @__PURE__ */ (0,
|
|
1056
|
+
displayVariant && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "lb-bundle-qty-chip", "data-qty-inline": true, children: [
|
|
1009
1057
|
"\xD7",
|
|
1010
1058
|
displayQty
|
|
1011
1059
|
] })
|
|
@@ -1015,16 +1063,16 @@ function FixedProductRow({ bundle, product, currency, isOos, onVariantChange })
|
|
|
1015
1063
|
}
|
|
1016
1064
|
|
|
1017
1065
|
// src/components/MixMatchBundle.tsx
|
|
1018
|
-
var
|
|
1066
|
+
var import_react13 = require("react");
|
|
1019
1067
|
var import_core11 = require("@lime-bundles/core");
|
|
1020
1068
|
|
|
1021
1069
|
// src/hooks/useShopSettings.ts
|
|
1022
|
-
var
|
|
1070
|
+
var import_react9 = require("react");
|
|
1023
1071
|
var import_core9 = require("@lime-bundles/core");
|
|
1024
1072
|
function useShopSettings(options) {
|
|
1025
|
-
const [outOfStockBehavior, setOutOfStockBehavior] = (0,
|
|
1073
|
+
const [outOfStockBehavior, setOutOfStockBehavior] = (0, import_react9.useState)(import_core9.DEFAULT_OUT_OF_STOCK_BEHAVIOR);
|
|
1026
1074
|
const { shopDomain, storefrontAccessToken } = options;
|
|
1027
|
-
(0,
|
|
1075
|
+
(0, import_react9.useEffect)(() => {
|
|
1028
1076
|
const controller = new AbortController();
|
|
1029
1077
|
let active = true;
|
|
1030
1078
|
fetchShopSettingsOrDefault({
|
|
@@ -1044,12 +1092,12 @@ function useShopSettings(options) {
|
|
|
1044
1092
|
}
|
|
1045
1093
|
|
|
1046
1094
|
// src/components/MixMatchPicker.tsx
|
|
1047
|
-
var
|
|
1095
|
+
var import_react12 = require("react");
|
|
1048
1096
|
var import_react_dom = require("react-dom");
|
|
1049
1097
|
var import_core10 = require("@lime-bundles/core");
|
|
1050
1098
|
|
|
1051
1099
|
// src/hooks/useScrollLock.ts
|
|
1052
|
-
var
|
|
1100
|
+
var import_react10 = require("react");
|
|
1053
1101
|
var lockCount = 0;
|
|
1054
1102
|
var savedY = 0;
|
|
1055
1103
|
function lock() {
|
|
@@ -1078,7 +1126,7 @@ function unlock() {
|
|
|
1078
1126
|
window.scrollTo(0, savedY);
|
|
1079
1127
|
}
|
|
1080
1128
|
function useScrollLock(active) {
|
|
1081
|
-
(0,
|
|
1129
|
+
(0, import_react10.useEffect)(() => {
|
|
1082
1130
|
if (!active) return;
|
|
1083
1131
|
lock();
|
|
1084
1132
|
return unlock;
|
|
@@ -1086,7 +1134,7 @@ function useScrollLock(active) {
|
|
|
1086
1134
|
}
|
|
1087
1135
|
|
|
1088
1136
|
// src/hooks/useFocusTrap.ts
|
|
1089
|
-
var
|
|
1137
|
+
var import_react11 = require("react");
|
|
1090
1138
|
var FOCUSABLE_SELECTOR = [
|
|
1091
1139
|
"a[href]",
|
|
1092
1140
|
"button:not([disabled])",
|
|
@@ -1111,8 +1159,8 @@ function useFocusTrap({
|
|
|
1111
1159
|
onEscape,
|
|
1112
1160
|
returnFocusRef
|
|
1113
1161
|
}) {
|
|
1114
|
-
const previouslyFocused = (0,
|
|
1115
|
-
(0,
|
|
1162
|
+
const previouslyFocused = (0, import_react11.useRef)(null);
|
|
1163
|
+
(0, import_react11.useEffect)(() => {
|
|
1116
1164
|
if (!active) return;
|
|
1117
1165
|
const container = containerRef.current;
|
|
1118
1166
|
previouslyFocused.current = document.activeElement ?? null;
|
|
@@ -1154,10 +1202,17 @@ function useFocusTrap({
|
|
|
1154
1202
|
}
|
|
1155
1203
|
|
|
1156
1204
|
// src/components/MixMatchPicker.tsx
|
|
1157
|
-
var
|
|
1158
|
-
function ruleFor(bundle, productId) {
|
|
1205
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1206
|
+
function ruleFor(bundle, productId, variantId) {
|
|
1207
|
+
if (variantId) {
|
|
1208
|
+
const vRule = bundle.variantRules[variantId];
|
|
1209
|
+
if (vRule) return vRule;
|
|
1210
|
+
}
|
|
1159
1211
|
return bundle.productRules[productId] ?? import_core10.DEFAULT_PRODUCT_RULE;
|
|
1160
1212
|
}
|
|
1213
|
+
function variantRuleFor(bundle, variantId) {
|
|
1214
|
+
return variantId ? bundle.variantRules[variantId] : void 0;
|
|
1215
|
+
}
|
|
1161
1216
|
function sanitizeId(gid) {
|
|
1162
1217
|
return gid.replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
1163
1218
|
}
|
|
@@ -1203,17 +1258,17 @@ function MixMatchPicker({
|
|
|
1203
1258
|
styleVarsRef
|
|
1204
1259
|
}) {
|
|
1205
1260
|
const wc = bundle.widgetConfig;
|
|
1206
|
-
const overlayRef = (0,
|
|
1207
|
-
const dialogRef = (0,
|
|
1208
|
-
const mouseDownTarget = (0,
|
|
1209
|
-
const [open, setOpen] = (0,
|
|
1210
|
-
const [query, setQuery] = (0,
|
|
1211
|
-
const [activeType, setActiveType] = (0,
|
|
1212
|
-
const eligible = (0,
|
|
1261
|
+
const overlayRef = (0, import_react12.useRef)(null);
|
|
1262
|
+
const dialogRef = (0, import_react12.useRef)(null);
|
|
1263
|
+
const mouseDownTarget = (0, import_react12.useRef)(null);
|
|
1264
|
+
const [open, setOpen] = (0, import_react12.useState)(false);
|
|
1265
|
+
const [query, setQuery] = (0, import_react12.useState)("");
|
|
1266
|
+
const [activeType, setActiveType] = (0, import_react12.useState)(FILTERS_ALL);
|
|
1267
|
+
const eligible = (0, import_react12.useMemo)(
|
|
1213
1268
|
() => buildEligibleProducts(bundle, outOfStockBehavior),
|
|
1214
1269
|
[bundle, outOfStockBehavior]
|
|
1215
1270
|
);
|
|
1216
|
-
const productTypes = (0,
|
|
1271
|
+
const productTypes = (0, import_react12.useMemo)(() => {
|
|
1217
1272
|
const types = [];
|
|
1218
1273
|
const seen = /* @__PURE__ */ new Set();
|
|
1219
1274
|
for (const ep of eligible) {
|
|
@@ -1229,7 +1284,7 @@ function MixMatchPicker({
|
|
|
1229
1284
|
const totalUnits = selections.reduce((sum, s) => sum + s.quantity, 0);
|
|
1230
1285
|
const atCapacity = totalUnits >= requiredQty;
|
|
1231
1286
|
const shownUnits = Math.min(totalUnits, requiredQty);
|
|
1232
|
-
(0,
|
|
1287
|
+
(0, import_react12.useEffect)(() => {
|
|
1233
1288
|
const id = requestAnimationFrame(() => setOpen(true));
|
|
1234
1289
|
return () => cancelAnimationFrame(id);
|
|
1235
1290
|
}, []);
|
|
@@ -1245,7 +1300,7 @@ function MixMatchPicker({
|
|
|
1245
1300
|
const pct = bundle.discountConfig.discountType === "percentage" && bundle.discountConfig.discountValue ? Math.round(bundle.discountConfig.discountValue) : 0;
|
|
1246
1301
|
return pct > 0 ? `Choose ${remaining} more to unlock ${pct}% off` : `Choose ${remaining} more to complete your bundle`;
|
|
1247
1302
|
})();
|
|
1248
|
-
const filtered = (0,
|
|
1303
|
+
const filtered = (0, import_react12.useMemo)(() => {
|
|
1249
1304
|
const nq = normalizeText(query.trim());
|
|
1250
1305
|
return eligible.filter((ep) => {
|
|
1251
1306
|
const matchesQuery = !nq || normalizeText(ep.product.title).includes(nq);
|
|
@@ -1270,7 +1325,7 @@ function MixMatchPicker({
|
|
|
1270
1325
|
// inside carries the interactive role + focus trap. So the static-element
|
|
1271
1326
|
// interaction lint does not apply to this backdrop.
|
|
1272
1327
|
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
|
|
1273
|
-
/* @__PURE__ */ (0,
|
|
1328
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1274
1329
|
"div",
|
|
1275
1330
|
{
|
|
1276
1331
|
ref: (el) => {
|
|
@@ -1282,7 +1337,7 @@ function MixMatchPicker({
|
|
|
1282
1337
|
"data-bundle-gid": bundle.id,
|
|
1283
1338
|
onMouseDown: onOverlayMouseDown,
|
|
1284
1339
|
onMouseUp: onOverlayMouseUp,
|
|
1285
|
-
children: /* @__PURE__ */ (0,
|
|
1340
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1286
1341
|
"div",
|
|
1287
1342
|
{
|
|
1288
1343
|
ref: dialogRef,
|
|
@@ -1292,13 +1347,13 @@ function MixMatchPicker({
|
|
|
1292
1347
|
"aria-labelledby": titleId,
|
|
1293
1348
|
tabIndex: -1,
|
|
1294
1349
|
children: [
|
|
1295
|
-
/* @__PURE__ */ (0,
|
|
1296
|
-
/* @__PURE__ */ (0,
|
|
1297
|
-
/* @__PURE__ */ (0,
|
|
1298
|
-
/* @__PURE__ */ (0,
|
|
1299
|
-
/* @__PURE__ */ (0,
|
|
1350
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "lb-mix-match__modal-header", children: [
|
|
1351
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "lb-mix-match__modal-header-top", children: [
|
|
1352
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "lb-mix-match__modal-heading", children: [
|
|
1353
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h4", { className: "lb-mix-match__modal-title", id: titleId, children: "Add to your bundle" }),
|
|
1354
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "lb-mix-match__modal-subtitle", "data-modal-subtitle": true, children: subtitle })
|
|
1300
1355
|
] }),
|
|
1301
|
-
/* @__PURE__ */ (0,
|
|
1356
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1302
1357
|
"button",
|
|
1303
1358
|
{
|
|
1304
1359
|
type: "button",
|
|
@@ -1306,16 +1361,16 @@ function MixMatchPicker({
|
|
|
1306
1361
|
"data-modal-close": true,
|
|
1307
1362
|
"aria-label": "Close",
|
|
1308
1363
|
onClick: onClose,
|
|
1309
|
-
children: /* @__PURE__ */ (0,
|
|
1364
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CloseIcon, {})
|
|
1310
1365
|
}
|
|
1311
1366
|
)
|
|
1312
1367
|
] }),
|
|
1313
|
-
/* @__PURE__ */ (0,
|
|
1368
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1314
1369
|
"div",
|
|
1315
1370
|
{
|
|
1316
1371
|
className: "lb-mix-match__progress lb-mix-match__modal-progress",
|
|
1317
1372
|
"data-progress": true,
|
|
1318
|
-
children: /* @__PURE__ */ (0,
|
|
1373
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1319
1374
|
"div",
|
|
1320
1375
|
{
|
|
1321
1376
|
className: "lb-mix-match__progress-segments",
|
|
@@ -1323,7 +1378,7 @@ function MixMatchPicker({
|
|
|
1323
1378
|
"aria-valuenow": shownUnits,
|
|
1324
1379
|
"aria-valuemin": 0,
|
|
1325
1380
|
"aria-valuemax": requiredQty,
|
|
1326
|
-
children: Array.from({ length: requiredQty }).map((_, i) => /* @__PURE__ */ (0,
|
|
1381
|
+
children: Array.from({ length: requiredQty }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1327
1382
|
"span",
|
|
1328
1383
|
{
|
|
1329
1384
|
className: `lb-mix-match__progress-segment${i < shownUnits ? " lb-mix-match__progress-segment--filled" : ""}`,
|
|
@@ -1336,8 +1391,8 @@ function MixMatchPicker({
|
|
|
1336
1391
|
}
|
|
1337
1392
|
)
|
|
1338
1393
|
] }),
|
|
1339
|
-
wc.showSearch && /* @__PURE__ */ (0,
|
|
1340
|
-
/* @__PURE__ */ (0,
|
|
1394
|
+
wc.showSearch && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "lb-mix-match__modal-search", children: [
|
|
1395
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1341
1396
|
"input",
|
|
1342
1397
|
{
|
|
1343
1398
|
type: "text",
|
|
@@ -1351,7 +1406,7 @@ function MixMatchPicker({
|
|
|
1351
1406
|
onChange: (e) => setQuery(e.target.value)
|
|
1352
1407
|
}
|
|
1353
1408
|
),
|
|
1354
|
-
query.length > 0 && /* @__PURE__ */ (0,
|
|
1409
|
+
query.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1355
1410
|
"button",
|
|
1356
1411
|
{
|
|
1357
1412
|
type: "button",
|
|
@@ -1359,11 +1414,11 @@ function MixMatchPicker({
|
|
|
1359
1414
|
"data-modal-search-clear": true,
|
|
1360
1415
|
"aria-label": "Clear search",
|
|
1361
1416
|
onClick: () => setQuery(""),
|
|
1362
|
-
children: /* @__PURE__ */ (0,
|
|
1417
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(SearchClearIcon, {})
|
|
1363
1418
|
}
|
|
1364
1419
|
)
|
|
1365
1420
|
] }),
|
|
1366
|
-
showFilters && /* @__PURE__ */ (0,
|
|
1421
|
+
showFilters && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1367
1422
|
"div",
|
|
1368
1423
|
{
|
|
1369
1424
|
className: "lb-mix-match__filters",
|
|
@@ -1372,7 +1427,7 @@ function MixMatchPicker({
|
|
|
1372
1427
|
"aria-label": "Filter by product type",
|
|
1373
1428
|
children: [FILTERS_ALL, ...productTypes].map((value) => {
|
|
1374
1429
|
const isActive = value === activeType;
|
|
1375
|
-
return /* @__PURE__ */ (0,
|
|
1430
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1376
1431
|
"button",
|
|
1377
1432
|
{
|
|
1378
1433
|
type: "button",
|
|
@@ -1387,7 +1442,7 @@ function MixMatchPicker({
|
|
|
1387
1442
|
})
|
|
1388
1443
|
}
|
|
1389
1444
|
),
|
|
1390
|
-
/* @__PURE__ */ (0,
|
|
1445
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "lb-mix-match__modal-list", "data-modal-list": true, children: filtered.map((ep) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1391
1446
|
MixMatchPickerRow,
|
|
1392
1447
|
{
|
|
1393
1448
|
bundle,
|
|
@@ -1406,10 +1461,10 @@ function MixMatchPicker({
|
|
|
1406
1461
|
},
|
|
1407
1462
|
ep.product.id
|
|
1408
1463
|
)) }),
|
|
1409
|
-
showEmpty && /* @__PURE__ */ (0,
|
|
1410
|
-
/* @__PURE__ */ (0,
|
|
1411
|
-
/* @__PURE__ */ (0,
|
|
1412
|
-
/* @__PURE__ */ (0,
|
|
1464
|
+
showEmpty && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "lb-mix-match__modal-empty", "data-modal-empty": true, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: "No products match your search" }) }),
|
|
1465
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { "data-modal-live": true, "aria-live": "polite", className: "lb-visually-hidden", children: `${filtered.length} products shown` }),
|
|
1466
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "lb-mix-match__modal-footer", children: [
|
|
1467
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1413
1468
|
"span",
|
|
1414
1469
|
{
|
|
1415
1470
|
className: "lb-mix-match__modal-footer-count",
|
|
@@ -1418,7 +1473,7 @@ function MixMatchPicker({
|
|
|
1418
1473
|
children: `${shownUnits} of ${requiredQty} added`
|
|
1419
1474
|
}
|
|
1420
1475
|
),
|
|
1421
|
-
/* @__PURE__ */ (0,
|
|
1476
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1422
1477
|
"button",
|
|
1423
1478
|
{
|
|
1424
1479
|
type: "button",
|
|
@@ -1455,14 +1510,16 @@ function MixMatchPickerRow({
|
|
|
1455
1510
|
}) {
|
|
1456
1511
|
const { product, variants, isOos } = eligible;
|
|
1457
1512
|
const rule = ruleFor(bundle, product.id);
|
|
1458
|
-
const optionNames = (0,
|
|
1513
|
+
const optionNames = (0, import_react12.useMemo)(() => {
|
|
1459
1514
|
const first = variants[0];
|
|
1460
1515
|
return first ? first.selectedOptions.map((o) => o.name) : [];
|
|
1461
1516
|
}, [variants]);
|
|
1462
1517
|
const showPicker = variants.length > 1 && optionNames.length > 0;
|
|
1463
1518
|
const { selectedValues, selectedVariant, setOptionValue, optionsFor } = useVariantSelection({ variants, optionNames });
|
|
1464
1519
|
const currentVariant = selectedVariant ?? variants.find((v) => (0, import_core10.isVariantFulfillable)(v, rule.min)) ?? eligible.firstAvailableVariant ?? variants[0] ?? null;
|
|
1465
|
-
const
|
|
1520
|
+
const vRule = ruleFor(bundle, product.id, currentVariant?.id);
|
|
1521
|
+
const variantMax = variantRuleFor(bundle, currentVariant?.id)?.max;
|
|
1522
|
+
const alreadyInBundle = (0, import_react12.useMemo)(() => {
|
|
1466
1523
|
if (!currentVariant) return 0;
|
|
1467
1524
|
let sum = 0;
|
|
1468
1525
|
for (const s of selections) {
|
|
@@ -1472,13 +1529,13 @@ function MixMatchPickerRow({
|
|
|
1472
1529
|
}
|
|
1473
1530
|
return sum;
|
|
1474
1531
|
}, [selections, product.id, currentVariant]);
|
|
1475
|
-
const committedSelection = (0,
|
|
1532
|
+
const committedSelection = (0, import_react12.useMemo)(
|
|
1476
1533
|
() => currentVariant ? selections.find((s) => s.variantId === currentVariant.id) ?? null : null,
|
|
1477
1534
|
[selections, currentVariant]
|
|
1478
1535
|
);
|
|
1479
1536
|
const variantInBundle = committedSelection !== null;
|
|
1480
1537
|
const committedQty = committedSelection?.quantity ?? 0;
|
|
1481
|
-
const productOtherUnits = (0,
|
|
1538
|
+
const productOtherUnits = (0, import_react12.useMemo)(() => {
|
|
1482
1539
|
if (!currentVariant) return 0;
|
|
1483
1540
|
let sum = 0;
|
|
1484
1541
|
for (const s of selections) {
|
|
@@ -1489,22 +1546,26 @@ function MixMatchPickerRow({
|
|
|
1489
1546
|
return sum;
|
|
1490
1547
|
}, [selections, product.id, currentVariant]);
|
|
1491
1548
|
const swapUnits = currentVariant ? swapUnitsFor?.(product.id, currentVariant.id) ?? 0 : 0;
|
|
1492
|
-
const inSwapState = swapUnits >=
|
|
1493
|
-
const spotCeiling = inSwapState ? swapUnits : Math.min(
|
|
1549
|
+
const inSwapState = swapUnits >= vRule.min;
|
|
1550
|
+
const spotCeiling = inSwapState ? swapUnits : Math.min(
|
|
1551
|
+
rule.max - productOtherUnits,
|
|
1552
|
+
committedQty + remainingUnits,
|
|
1553
|
+
variantMax ?? Infinity
|
|
1554
|
+
);
|
|
1494
1555
|
const cap = currentVariant ? (0, import_core10.maxAddableQuantity)(
|
|
1495
1556
|
currentVariant,
|
|
1496
1557
|
spotCeiling,
|
|
1497
1558
|
Math.max(0, alreadyInBundle - committedQty)
|
|
1498
1559
|
) : 0;
|
|
1499
|
-
const stepperMax = Math.max(
|
|
1500
|
-
const [qty, setQty] = (0,
|
|
1501
|
-
(0,
|
|
1502
|
-
setQty((prev) => Math.max(
|
|
1503
|
-
}, [stepperMax,
|
|
1560
|
+
const stepperMax = Math.max(vRule.min, cap);
|
|
1561
|
+
const [qty, setQty] = (0, import_react12.useState)(vRule.min);
|
|
1562
|
+
(0, import_react12.useEffect)(() => {
|
|
1563
|
+
setQty((prev) => Math.max(vRule.min, Math.min(prev, stepperMax)));
|
|
1564
|
+
}, [stepperMax, vRule.min]);
|
|
1504
1565
|
const currentVariantId = currentVariant?.id ?? null;
|
|
1505
|
-
(0,
|
|
1506
|
-
if (!variantInBundle) setQty(
|
|
1507
|
-
}, [variantInBundle, currentVariantId,
|
|
1566
|
+
(0, import_react12.useEffect)(() => {
|
|
1567
|
+
if (!variantInBundle) setQty(vRule.min);
|
|
1568
|
+
}, [variantInBundle, currentVariantId, vRule.min]);
|
|
1508
1569
|
if (!currentVariant) return null;
|
|
1509
1570
|
const thumbImage = currentVariant.image ?? product.featuredImage ?? null;
|
|
1510
1571
|
const unitPriceText = (0, import_core10.formatUnitPrice)(
|
|
@@ -1512,8 +1573,8 @@ function MixMatchPickerRow({
|
|
|
1512
1573
|
currentVariant.unitPriceMeasurement,
|
|
1513
1574
|
currency
|
|
1514
1575
|
);
|
|
1515
|
-
const noStock = cap <
|
|
1516
|
-
const needsMoreSpots = !variantInBundle && !inSwapState &&
|
|
1576
|
+
const noStock = cap < vRule.min;
|
|
1577
|
+
const needsMoreSpots = !variantInBundle && !inSwapState && vRule.min > remainingUnits;
|
|
1517
1578
|
const addDisabled = !variantInBundle && (inSwapState ? noStock : atCapacity || noStock || needsMoreSpots);
|
|
1518
1579
|
const lockedRequired = variantInBundle && currentVariant != null && !(canRemoveVariant?.(currentVariant.id) ?? true);
|
|
1519
1580
|
const stepperDisabled = isOos || !variantInBundle && addDisabled;
|
|
@@ -1524,7 +1585,7 @@ function MixMatchPickerRow({
|
|
|
1524
1585
|
return;
|
|
1525
1586
|
}
|
|
1526
1587
|
if (!currentVariant || noStock) return;
|
|
1527
|
-
const pickedQty = showStepper ? qty :
|
|
1588
|
+
const pickedQty = showStepper ? qty : vRule.min;
|
|
1528
1589
|
const item = {
|
|
1529
1590
|
productId: product.id,
|
|
1530
1591
|
variantId: currentVariant.id,
|
|
@@ -1546,7 +1607,7 @@ function MixMatchPickerRow({
|
|
|
1546
1607
|
}
|
|
1547
1608
|
const priceCents = parseFloat(currentVariant.price.amount);
|
|
1548
1609
|
const compareCents = currentVariant.compareAtPrice ? parseFloat(currentVariant.compareAtPrice.amount) : null;
|
|
1549
|
-
return /* @__PURE__ */ (0,
|
|
1610
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1550
1611
|
"div",
|
|
1551
1612
|
{
|
|
1552
1613
|
className: `lb-mix-match__modal-product${isOos ? " lb-mix-match__modal-product--sold-out" : ""}${variantInBundle ? " lb-mix-match__modal-product--in-bundle" : ""}`,
|
|
@@ -1555,8 +1616,8 @@ function MixMatchPickerRow({
|
|
|
1555
1616
|
"data-type": product.productType ?? "",
|
|
1556
1617
|
"aria-disabled": isOos || void 0,
|
|
1557
1618
|
children: [
|
|
1558
|
-
/* @__PURE__ */ (0,
|
|
1559
|
-
thumbImage && /* @__PURE__ */ (0,
|
|
1619
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "lb-mix-match__modal-product-thumb", children: [
|
|
1620
|
+
thumbImage && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1560
1621
|
"img",
|
|
1561
1622
|
{
|
|
1562
1623
|
src: thumbImage.url,
|
|
@@ -1564,10 +1625,10 @@ function MixMatchPickerRow({
|
|
|
1564
1625
|
loading: "lazy"
|
|
1565
1626
|
}
|
|
1566
1627
|
),
|
|
1567
|
-
variantInBundle && /* @__PURE__ */ (0,
|
|
1628
|
+
variantInBundle && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "lb-mix-match__modal-added-badge", children: "Added" })
|
|
1568
1629
|
] }),
|
|
1569
|
-
/* @__PURE__ */ (0,
|
|
1570
|
-
/* @__PURE__ */ (0,
|
|
1630
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "lb-mix-match__modal-product-info", children: [
|
|
1631
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "lb-mix-match__modal-product-title", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1571
1632
|
"a",
|
|
1572
1633
|
{
|
|
1573
1634
|
href: `/products/${product.handle}`,
|
|
@@ -1576,24 +1637,24 @@ function MixMatchPickerRow({
|
|
|
1576
1637
|
children: product.title
|
|
1577
1638
|
}
|
|
1578
1639
|
) }),
|
|
1579
|
-
/* @__PURE__ */ (0,
|
|
1580
|
-
/* @__PURE__ */ (0,
|
|
1581
|
-
compareCents !== null && compareCents > priceCents && /* @__PURE__ */ (0,
|
|
1640
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { className: "lb-mix-match__modal-product-price", children: [
|
|
1641
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { "data-row-price-sale": true, children: (0, import_core10.formatMoney)(priceCents, currency) }),
|
|
1642
|
+
compareCents !== null && compareCents > priceCents && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("s", { className: "lb-mix-match__modal-product-compare", "data-row-compare": true, children: (0, import_core10.formatMoney)(compareCents, currency) })
|
|
1582
1643
|
] }),
|
|
1583
|
-
unitPriceText && /* @__PURE__ */ (0,
|
|
1584
|
-
showPicker && /* @__PURE__ */ (0,
|
|
1644
|
+
unitPriceText && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "lb-mix-match__modal-product-unit-price lb-bundle-product-unit-price", children: unitPriceText }),
|
|
1645
|
+
showPicker && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "lb-bundle-variant-option-groups", children: optionNames.map((optionName, optionIndex) => {
|
|
1585
1646
|
const dropdownOptions = optionsFor(optionIndex).map((o) => ({
|
|
1586
1647
|
value: o.value,
|
|
1587
1648
|
label: o.value,
|
|
1588
1649
|
disabled: o.disabled
|
|
1589
1650
|
}));
|
|
1590
|
-
return /* @__PURE__ */ (0,
|
|
1651
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1591
1652
|
"div",
|
|
1592
1653
|
{
|
|
1593
1654
|
className: "lb-bundle-variant-option-group",
|
|
1594
1655
|
children: [
|
|
1595
|
-
/* @__PURE__ */ (0,
|
|
1596
|
-
/* @__PURE__ */ (0,
|
|
1656
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "lb-bundle-variant-option-label", children: optionName }),
|
|
1657
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1597
1658
|
VariantDropdown,
|
|
1598
1659
|
{
|
|
1599
1660
|
className: "lb-mix-match__variant-select-dropdown",
|
|
@@ -1608,17 +1669,17 @@ function MixMatchPickerRow({
|
|
|
1608
1669
|
optionName
|
|
1609
1670
|
);
|
|
1610
1671
|
}) }),
|
|
1611
|
-
!showPicker && variants.length === 1 && currentVariant.title !== "Default Title" && /* @__PURE__ */ (0,
|
|
1612
|
-
!isOos && needsMoreSpots && remainingUnits > 0 && /* @__PURE__ */ (0,
|
|
1613
|
-
isOos ? /* @__PURE__ */ (0,
|
|
1614
|
-
showStepper && /* @__PURE__ */ (0,
|
|
1672
|
+
!showPicker && variants.length === 1 && currentVariant.title !== "Default Title" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "lb-mix-match__filled-variant", children: currentVariant.title }),
|
|
1673
|
+
!isOos && needsMoreSpots && remainingUnits > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "lb-mix-match__modal-needs-spots", children: rule.min === 1 ? "Needs 1 spot" : `Needs ${rule.min} spots` }),
|
|
1674
|
+
isOos ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "lb-mix-match__modal-sold-out-label", children: "Sold out" }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "lb-mix-match__modal-product-actions", children: [
|
|
1675
|
+
showStepper && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "lb-bundle-variant-option-group lb-mix-match__qty-stepper-group", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1615
1676
|
"div",
|
|
1616
1677
|
{
|
|
1617
1678
|
className: "lb-mix-match__qty-stepper",
|
|
1618
1679
|
role: "group",
|
|
1619
1680
|
"aria-label": "Quantity",
|
|
1620
1681
|
children: [
|
|
1621
|
-
/* @__PURE__ */ (0,
|
|
1682
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1622
1683
|
"button",
|
|
1623
1684
|
{
|
|
1624
1685
|
type: "button",
|
|
@@ -1639,7 +1700,7 @@ function MixMatchPickerRow({
|
|
|
1639
1700
|
children: "\u2212"
|
|
1640
1701
|
}
|
|
1641
1702
|
),
|
|
1642
|
-
/* @__PURE__ */ (0,
|
|
1703
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1643
1704
|
"span",
|
|
1644
1705
|
{
|
|
1645
1706
|
className: "lb-mix-match__qty-stepper-value",
|
|
@@ -1648,7 +1709,7 @@ function MixMatchPickerRow({
|
|
|
1648
1709
|
children: shownQty
|
|
1649
1710
|
}
|
|
1650
1711
|
),
|
|
1651
|
-
/* @__PURE__ */ (0,
|
|
1712
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1652
1713
|
"button",
|
|
1653
1714
|
{
|
|
1654
1715
|
type: "button",
|
|
@@ -1672,7 +1733,7 @@ function MixMatchPickerRow({
|
|
|
1672
1733
|
]
|
|
1673
1734
|
}
|
|
1674
1735
|
) }),
|
|
1675
|
-
/* @__PURE__ */ (0,
|
|
1736
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1676
1737
|
"button",
|
|
1677
1738
|
{
|
|
1678
1739
|
type: "button",
|
|
@@ -1691,7 +1752,7 @@ function MixMatchPickerRow({
|
|
|
1691
1752
|
);
|
|
1692
1753
|
}
|
|
1693
1754
|
function CloseIcon() {
|
|
1694
|
-
return /* @__PURE__ */ (0,
|
|
1755
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1695
1756
|
"svg",
|
|
1696
1757
|
{
|
|
1697
1758
|
width: "20",
|
|
@@ -1701,14 +1762,14 @@ function CloseIcon() {
|
|
|
1701
1762
|
xmlns: "http://www.w3.org/2000/svg",
|
|
1702
1763
|
"aria-hidden": "true",
|
|
1703
1764
|
children: [
|
|
1704
|
-
/* @__PURE__ */ (0,
|
|
1705
|
-
/* @__PURE__ */ (0,
|
|
1765
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "5", y1: "5", x2: "15", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
|
|
1766
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "15", y1: "5", x2: "5", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
|
|
1706
1767
|
]
|
|
1707
1768
|
}
|
|
1708
1769
|
);
|
|
1709
1770
|
}
|
|
1710
1771
|
function SearchClearIcon() {
|
|
1711
|
-
return /* @__PURE__ */ (0,
|
|
1772
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1712
1773
|
"svg",
|
|
1713
1774
|
{
|
|
1714
1775
|
width: "16",
|
|
@@ -1717,17 +1778,25 @@ function SearchClearIcon() {
|
|
|
1717
1778
|
fill: "currentColor",
|
|
1718
1779
|
xmlns: "http://www.w3.org/2000/svg",
|
|
1719
1780
|
"aria-hidden": "true",
|
|
1720
|
-
children: /* @__PURE__ */ (0,
|
|
1781
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("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" })
|
|
1721
1782
|
}
|
|
1722
1783
|
);
|
|
1723
1784
|
}
|
|
1724
1785
|
|
|
1725
1786
|
// src/components/MixMatchBundle.tsx
|
|
1726
|
-
var
|
|
1727
|
-
function ruleFor2(bundle, productId) {
|
|
1787
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1788
|
+
function ruleFor2(bundle, productId, variantId) {
|
|
1789
|
+
if (variantId) {
|
|
1790
|
+
const vRule = bundle.variantRules[variantId];
|
|
1791
|
+
if (vRule) return vRule;
|
|
1792
|
+
}
|
|
1728
1793
|
return bundle.productRules[productId] ?? import_core11.DEFAULT_PRODUCT_RULE;
|
|
1729
1794
|
}
|
|
1795
|
+
function variantRuleFor2(bundle, variantId) {
|
|
1796
|
+
return variantId ? bundle.variantRules[variantId] : void 0;
|
|
1797
|
+
}
|
|
1730
1798
|
function canRemoveItem(bundle, selections, item) {
|
|
1799
|
+
if (variantRuleFor2(bundle, item.variantId)?.required) return false;
|
|
1731
1800
|
const rule = ruleFor2(bundle, item.productId);
|
|
1732
1801
|
if (!rule.required) return true;
|
|
1733
1802
|
const unitsElsewhere = selections.filter((s) => s.productId === item.productId && s !== item).reduce((sum, s) => sum + s.quantity, 0);
|
|
@@ -1748,7 +1817,8 @@ function MixMatchBundle(props) {
|
|
|
1748
1817
|
analyticsEnabled,
|
|
1749
1818
|
onAddToCart,
|
|
1750
1819
|
onError,
|
|
1751
|
-
className
|
|
1820
|
+
className,
|
|
1821
|
+
productHandle
|
|
1752
1822
|
} = props;
|
|
1753
1823
|
const result = useBundleData({
|
|
1754
1824
|
shopDomain,
|
|
@@ -1766,16 +1836,16 @@ function MixMatchBundle(props) {
|
|
|
1766
1836
|
bundleType: "mix_match",
|
|
1767
1837
|
enabled: analyticsEnabled !== false
|
|
1768
1838
|
});
|
|
1769
|
-
const [selections, setSelections] = (0,
|
|
1770
|
-
const [seededFor, setSeededFor] = (0,
|
|
1771
|
-
const [pickerOpen, setPickerOpen] = (0,
|
|
1772
|
-
const [addingToCart, setAddingToCart] = (0,
|
|
1773
|
-
const [cartError, setCartError] = (0,
|
|
1839
|
+
const [selections, setSelections] = (0, import_react13.useState)([]);
|
|
1840
|
+
const [seededFor, setSeededFor] = (0, import_react13.useState)(null);
|
|
1841
|
+
const [pickerOpen, setPickerOpen] = (0, import_react13.useState)(false);
|
|
1842
|
+
const [addingToCart, setAddingToCart] = (0, import_react13.useState)(false);
|
|
1843
|
+
const [cartError, setCartError] = (0, import_react13.useState)(null);
|
|
1774
1844
|
const bundle = result.status === "success" && result.bundle.bundleType === "mix_match" ? result.bundle : null;
|
|
1775
1845
|
const setConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);
|
|
1776
1846
|
const setModalConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);
|
|
1777
1847
|
const slotsEdgeFadeRef = useEdgeFade();
|
|
1778
|
-
(0,
|
|
1848
|
+
(0, import_react13.useEffect)(() => {
|
|
1779
1849
|
if (result.status === "error") {
|
|
1780
1850
|
onError?.(result.error);
|
|
1781
1851
|
return;
|
|
@@ -1788,40 +1858,67 @@ function MixMatchBundle(props) {
|
|
|
1788
1858
|
);
|
|
1789
1859
|
}
|
|
1790
1860
|
}, [result, onError]);
|
|
1791
|
-
(0,
|
|
1861
|
+
(0, import_react13.useEffect)(() => {
|
|
1792
1862
|
if (!bundle || seededFor === bundle.id) return;
|
|
1793
1863
|
setSeededFor(bundle.id);
|
|
1794
1864
|
const seedCurrency = bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? "USD";
|
|
1865
|
+
const pick = (product, variant, quantity) => ({
|
|
1866
|
+
productId: product.id,
|
|
1867
|
+
variantId: variant.id,
|
|
1868
|
+
title: product.title,
|
|
1869
|
+
url: `/products/${product.handle}`,
|
|
1870
|
+
variantTitle: variant.title,
|
|
1871
|
+
featuredImage: variant.image?.url ?? product.featuredImage?.url ?? null,
|
|
1872
|
+
price: parseFloat(variant.price.amount),
|
|
1873
|
+
compareAtPrice: variant.compareAtPrice ? parseFloat(variant.compareAtPrice.amount) : null,
|
|
1874
|
+
unitPrice: (0, import_core11.formatUnitPrice)(
|
|
1875
|
+
variant.unitPrice,
|
|
1876
|
+
variant.unitPriceMeasurement,
|
|
1877
|
+
seedCurrency
|
|
1878
|
+
),
|
|
1879
|
+
quantity
|
|
1880
|
+
});
|
|
1795
1881
|
const seeds = [];
|
|
1796
|
-
for (const
|
|
1797
|
-
|
|
1798
|
-
const
|
|
1799
|
-
|
|
1882
|
+
for (const product of bundle.products) {
|
|
1883
|
+
let seededVariant = false;
|
|
1884
|
+
for (const variant2 of product.variants.nodes) {
|
|
1885
|
+
const vRule = bundle.variantRules[variant2.id];
|
|
1886
|
+
if (!vRule?.required) continue;
|
|
1887
|
+
if (!(0, import_core11.isVariantFulfillable)(variant2, Math.max(1, vRule.min))) continue;
|
|
1888
|
+
seeds.push(pick(product, variant2, Math.max(1, vRule.min)));
|
|
1889
|
+
seededVariant = true;
|
|
1890
|
+
}
|
|
1891
|
+
if (seededVariant) continue;
|
|
1892
|
+
const rule = bundle.productRules[product.id];
|
|
1893
|
+
if (!rule?.required) continue;
|
|
1894
|
+
const variant = product.variants.nodes.find(
|
|
1800
1895
|
(v) => (0, import_core11.isVariantFulfillable)(v, rule.min)
|
|
1801
1896
|
);
|
|
1802
|
-
if (!
|
|
1803
|
-
seeds.push(
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1897
|
+
if (!variant) continue;
|
|
1898
|
+
seeds.push(pick(product, variant, rule.min));
|
|
1899
|
+
}
|
|
1900
|
+
if (seeds.length === 0 && productHandle) {
|
|
1901
|
+
const requiredUnits2 = bundle.minQuantity ?? 0;
|
|
1902
|
+
const qualifies = (p) => {
|
|
1903
|
+
const min = bundle.productRules[p.id]?.min ?? 1;
|
|
1904
|
+
return min <= requiredUnits2 && p.variants.nodes.some((v) => (0, import_core11.isVariantFulfillable)(v, min));
|
|
1905
|
+
};
|
|
1906
|
+
const seed = bundle.products.find(
|
|
1907
|
+
(p) => p.handle === productHandle && qualifies(p)
|
|
1908
|
+
) ?? bundle.products.find(qualifies);
|
|
1909
|
+
if (seed) {
|
|
1910
|
+
const min = bundle.productRules[seed.id]?.min ?? 1;
|
|
1911
|
+
const variant = seed.variants.nodes.find(
|
|
1912
|
+
(v) => (0, import_core11.isVariantFulfillable)(v, min)
|
|
1913
|
+
);
|
|
1914
|
+
if (variant) seeds.push(pick(seed, variant, min));
|
|
1915
|
+
}
|
|
1819
1916
|
}
|
|
1820
1917
|
if (seeds.length > 0) setSelections(seeds);
|
|
1821
|
-
}, [bundle, seededFor]);
|
|
1918
|
+
}, [bundle, seededFor, productHandle]);
|
|
1822
1919
|
const showStepper = bundle?.widgetConfig.mixMatchShowQuantitySelector !== false;
|
|
1823
1920
|
const requiredUnits = bundle?.minQuantity ?? 0;
|
|
1824
|
-
const totalQuantity = (0,
|
|
1921
|
+
const totalQuantity = (0, import_react13.useMemo)(
|
|
1825
1922
|
() => selections.reduce((sum, s) => sum + s.quantity, 0),
|
|
1826
1923
|
[selections]
|
|
1827
1924
|
);
|
|
@@ -1829,7 +1926,7 @@ function MixMatchBundle(props) {
|
|
|
1829
1926
|
const valid = !!bundle && meetsMinUnits;
|
|
1830
1927
|
const shownUnits = Math.min(totalQuantity, requiredUnits);
|
|
1831
1928
|
const remaining = Math.max(0, requiredUnits - shownUnits);
|
|
1832
|
-
const summary = (0,
|
|
1929
|
+
const summary = (0, import_react13.useMemo)(() => {
|
|
1833
1930
|
let comparePrice = 0;
|
|
1834
1931
|
let salePrice = 0;
|
|
1835
1932
|
for (const sel of selections) {
|
|
@@ -1847,7 +1944,7 @@ function MixMatchBundle(props) {
|
|
|
1847
1944
|
const savingsPercent = comparePrice > 0 && savings > 0 ? Math.round(savings / comparePrice * 100) : 0;
|
|
1848
1945
|
return { comparePrice, salePrice, savings, savingsPercent };
|
|
1849
1946
|
}, [selections, bundle]);
|
|
1850
|
-
const addSelection = (0,
|
|
1947
|
+
const addSelection = (0, import_react13.useCallback)(
|
|
1851
1948
|
(item) => {
|
|
1852
1949
|
setSelections((prev) => {
|
|
1853
1950
|
const units = prev.reduce((sum, s) => sum + s.quantity, 0);
|
|
@@ -1858,7 +1955,7 @@ function MixMatchBundle(props) {
|
|
|
1858
1955
|
},
|
|
1859
1956
|
[requiredUnits]
|
|
1860
1957
|
);
|
|
1861
|
-
const updateQuantity = (0,
|
|
1958
|
+
const updateQuantity = (0, import_react13.useCallback)(
|
|
1862
1959
|
(productId, variantId, quantity) => {
|
|
1863
1960
|
setSelections((prev) => {
|
|
1864
1961
|
const idx = prev.findIndex(
|
|
@@ -1881,7 +1978,7 @@ function MixMatchBundle(props) {
|
|
|
1881
1978
|
},
|
|
1882
1979
|
[requiredUnits]
|
|
1883
1980
|
);
|
|
1884
|
-
const swapSelection = (0,
|
|
1981
|
+
const swapSelection = (0, import_react13.useCallback)(
|
|
1885
1982
|
(item) => {
|
|
1886
1983
|
setSelections((prev) => {
|
|
1887
1984
|
if (!bundle) return prev;
|
|
@@ -1913,7 +2010,7 @@ function MixMatchBundle(props) {
|
|
|
1913
2010
|
},
|
|
1914
2011
|
[bundle]
|
|
1915
2012
|
);
|
|
1916
|
-
const removeVariant = (0,
|
|
2013
|
+
const removeVariant = (0, import_react13.useCallback)(
|
|
1917
2014
|
(variantId) => {
|
|
1918
2015
|
setSelections((prev) => {
|
|
1919
2016
|
const idx = prev.findIndex((s) => s.variantId === variantId);
|
|
@@ -1926,7 +2023,7 @@ function MixMatchBundle(props) {
|
|
|
1926
2023
|
},
|
|
1927
2024
|
[bundle]
|
|
1928
2025
|
);
|
|
1929
|
-
const removeSlot = (0,
|
|
2026
|
+
const removeSlot = (0, import_react13.useCallback)(
|
|
1930
2027
|
(index) => {
|
|
1931
2028
|
setSelections((prev) => {
|
|
1932
2029
|
if (index < 0 || index >= prev.length) return prev;
|
|
@@ -1938,7 +2035,7 @@ function MixMatchBundle(props) {
|
|
|
1938
2035
|
},
|
|
1939
2036
|
[bundle]
|
|
1940
2037
|
);
|
|
1941
|
-
const handleAddToCart = (0,
|
|
2038
|
+
const handleAddToCart = (0, import_react13.useCallback)(async () => {
|
|
1942
2039
|
if (!bundle || !valid) return;
|
|
1943
2040
|
const grouped = /* @__PURE__ */ new Map();
|
|
1944
2041
|
for (const sel of selections) {
|
|
@@ -1978,9 +2075,9 @@ function MixMatchBundle(props) {
|
|
|
1978
2075
|
}
|
|
1979
2076
|
}, [bundle, selections, valid, onAddToCart, onError, trackAddToCart, totalQuantity]);
|
|
1980
2077
|
if (result.status === "loading") {
|
|
1981
|
-
return /* @__PURE__ */ (0,
|
|
1982
|
-
/* @__PURE__ */ (0,
|
|
1983
|
-
/* @__PURE__ */ (0,
|
|
2078
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: `lb-bundle lb-bundle--loading ${className ?? ""}`, children: [
|
|
2079
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "lb-skeleton lb-skeleton--title" }),
|
|
2080
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "lb-skeleton lb-skeleton--products" })
|
|
1984
2081
|
] });
|
|
1985
2082
|
}
|
|
1986
2083
|
if (result.status === "error") return null;
|
|
@@ -1999,7 +2096,7 @@ function MixMatchBundle(props) {
|
|
|
1999
2096
|
if (requiredBlocked) return null;
|
|
2000
2097
|
const currency = bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? "USD";
|
|
2001
2098
|
const ctaLabel = addingToCart ? "Adding..." : bundle.widgetConfig.cta.ctaText || "Add to cart";
|
|
2002
|
-
return /* @__PURE__ */ (0,
|
|
2099
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
2003
2100
|
"div",
|
|
2004
2101
|
{
|
|
2005
2102
|
ref: (el) => {
|
|
@@ -2011,12 +2108,19 @@ function MixMatchBundle(props) {
|
|
|
2011
2108
|
"aria-label": bundle.title,
|
|
2012
2109
|
"data-required-quantity": requiredUnits,
|
|
2013
2110
|
children: [
|
|
2014
|
-
/* @__PURE__ */ (0,
|
|
2015
|
-
/* @__PURE__ */ (0,
|
|
2016
|
-
bundle.description && /* @__PURE__ */ (0,
|
|
2111
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "lb-bundle-header", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "lb-bundle-header__content", children: [
|
|
2112
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { className: "lb-bundle-title", children: bundle.title }),
|
|
2113
|
+
bundle.description && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "lb-bundle-subtitle", children: bundle.description })
|
|
2017
2114
|
] }) }),
|
|
2018
|
-
/* @__PURE__ */ (0,
|
|
2019
|
-
|
|
2115
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2116
|
+
BundleCountdown,
|
|
2117
|
+
{
|
|
2118
|
+
endsAt: bundle.endsAt,
|
|
2119
|
+
widgetConfig: bundle.widgetConfig
|
|
2120
|
+
}
|
|
2121
|
+
),
|
|
2122
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "lb-mix-match__progress", "data-progress": true, children: [
|
|
2123
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2020
2124
|
"div",
|
|
2021
2125
|
{
|
|
2022
2126
|
className: "lb-mix-match__progress-segments",
|
|
@@ -2024,7 +2128,7 @@ function MixMatchBundle(props) {
|
|
|
2024
2128
|
"aria-valuenow": shownUnits,
|
|
2025
2129
|
"aria-valuemin": 0,
|
|
2026
2130
|
"aria-valuemax": requiredUnits,
|
|
2027
|
-
children: Array.from({ length: requiredUnits }).map((_, i) => /* @__PURE__ */ (0,
|
|
2131
|
+
children: Array.from({ length: requiredUnits }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2028
2132
|
"span",
|
|
2029
2133
|
{
|
|
2030
2134
|
className: `lb-mix-match__progress-segment${i < shownUnits ? " lb-mix-match__progress-segment--filled" : ""}`,
|
|
@@ -2034,8 +2138,8 @@ function MixMatchBundle(props) {
|
|
|
2034
2138
|
))
|
|
2035
2139
|
}
|
|
2036
2140
|
),
|
|
2037
|
-
/* @__PURE__ */ (0,
|
|
2038
|
-
/* @__PURE__ */ (0,
|
|
2141
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "lb-mix-match__progress-labels", children: [
|
|
2142
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2039
2143
|
"span",
|
|
2040
2144
|
{
|
|
2041
2145
|
className: "lb-mix-match__progress-count",
|
|
@@ -2044,7 +2148,7 @@ function MixMatchBundle(props) {
|
|
|
2044
2148
|
children: `${shownUnits} of ${requiredUnits} added`
|
|
2045
2149
|
}
|
|
2046
2150
|
),
|
|
2047
|
-
/* @__PURE__ */ (0,
|
|
2151
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2048
2152
|
"span",
|
|
2049
2153
|
{
|
|
2050
2154
|
className: "lb-mix-match__progress-remaining",
|
|
@@ -2055,7 +2159,7 @@ function MixMatchBundle(props) {
|
|
|
2055
2159
|
)
|
|
2056
2160
|
] })
|
|
2057
2161
|
] }),
|
|
2058
|
-
/* @__PURE__ */ (0,
|
|
2162
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2059
2163
|
"div",
|
|
2060
2164
|
{
|
|
2061
2165
|
className: "lb-mix-match__slots lb-edge-fade",
|
|
@@ -2066,15 +2170,15 @@ function MixMatchBundle(props) {
|
|
|
2066
2170
|
button provides the keyboard/AT path (its activation bubbles
|
|
2067
2171
|
here); × stops propagation. */
|
|
2068
2172
|
// 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
|
|
2069
|
-
/* @__PURE__ */ (0,
|
|
2173
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
2070
2174
|
"div",
|
|
2071
2175
|
{
|
|
2072
2176
|
className: "lb-mix-match__slot lb-mix-match__slot--filled",
|
|
2073
2177
|
onClick: () => setPickerOpen(true),
|
|
2074
2178
|
children: [
|
|
2075
|
-
item.featuredImage && /* @__PURE__ */ (0,
|
|
2076
|
-
/* @__PURE__ */ (0,
|
|
2077
|
-
/* @__PURE__ */ (0,
|
|
2179
|
+
item.featuredImage && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "lb-bundle-thumbnail", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("img", { src: item.featuredImage, alt: item.title, loading: "lazy" }) }),
|
|
2180
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "lb-mix-match__filled-info", children: [
|
|
2181
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2078
2182
|
"button",
|
|
2079
2183
|
{
|
|
2080
2184
|
type: "button",
|
|
@@ -2083,15 +2187,15 @@ function MixMatchBundle(props) {
|
|
|
2083
2187
|
children: item.title
|
|
2084
2188
|
}
|
|
2085
2189
|
),
|
|
2086
|
-
item.variantTitle && item.variantTitle !== "Default Title" && /* @__PURE__ */ (0,
|
|
2087
|
-
/* @__PURE__ */ (0,
|
|
2088
|
-
item.compareAtPrice !== null && item.compareAtPrice > item.price && /* @__PURE__ */ (0,
|
|
2089
|
-
/* @__PURE__ */ (0,
|
|
2090
|
-
/* @__PURE__ */ (0,
|
|
2190
|
+
item.variantTitle && item.variantTitle !== "Default Title" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "lb-mix-match__filled-variant", children: item.variantTitle }),
|
|
2191
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "lb-mix-match__filled-price", children: [
|
|
2192
|
+
item.compareAtPrice !== null && item.compareAtPrice > item.price && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("s", { className: "lb-mix-match__filled-compare", children: (0, import_core11.formatMoney)(item.compareAtPrice, currency) }),
|
|
2193
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "lb-bundle-product-price", children: (0, import_core11.formatMoney)(item.price, currency) }),
|
|
2194
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "lb-bundle-qty-inline", children: `\xD7${item.quantity}` })
|
|
2091
2195
|
] }),
|
|
2092
|
-
item.unitPrice && /* @__PURE__ */ (0,
|
|
2196
|
+
item.unitPrice && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "lb-bundle-product-unit-price", children: item.unitPrice })
|
|
2093
2197
|
] }),
|
|
2094
|
-
canRemoveItem(bundle, selections, item) ? /* @__PURE__ */ (0,
|
|
2198
|
+
canRemoveItem(bundle, selections, item) ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2095
2199
|
"button",
|
|
2096
2200
|
{
|
|
2097
2201
|
type: "button",
|
|
@@ -2101,13 +2205,13 @@ function MixMatchBundle(props) {
|
|
|
2101
2205
|
e.stopPropagation();
|
|
2102
2206
|
removeSlot(index);
|
|
2103
2207
|
},
|
|
2104
|
-
children: /* @__PURE__ */ (0,
|
|
2208
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CloseIcon2, {})
|
|
2105
2209
|
}
|
|
2106
2210
|
) : (
|
|
2107
2211
|
/* Required pick at its floor — quiet state chip instead of
|
|
2108
2212
|
the ×; removal returns once another slot covers the
|
|
2109
2213
|
product's minimum (variant swap flow). */
|
|
2110
|
-
/* @__PURE__ */ (0,
|
|
2214
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "lb-mix-match__slot-required", children: "Required" })
|
|
2111
2215
|
)
|
|
2112
2216
|
]
|
|
2113
2217
|
},
|
|
@@ -2116,7 +2220,7 @@ function MixMatchBundle(props) {
|
|
|
2116
2220
|
))
|
|
2117
2221
|
}
|
|
2118
2222
|
),
|
|
2119
|
-
totalQuantity < requiredUnits && /* @__PURE__ */ (0,
|
|
2223
|
+
totalQuantity < requiredUnits && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
2120
2224
|
"button",
|
|
2121
2225
|
{
|
|
2122
2226
|
type: "button",
|
|
@@ -2124,34 +2228,34 @@ function MixMatchBundle(props) {
|
|
|
2124
2228
|
"data-add-product-trigger": true,
|
|
2125
2229
|
onClick: () => setPickerOpen(true),
|
|
2126
2230
|
children: [
|
|
2127
|
-
/* @__PURE__ */ (0,
|
|
2128
|
-
/* @__PURE__ */ (0,
|
|
2231
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "lb-mix-match__add-product-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PlusIcon, {}) }),
|
|
2232
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "lb-mix-match__add-product-label", children: "Add a product" })
|
|
2129
2233
|
]
|
|
2130
2234
|
}
|
|
2131
2235
|
),
|
|
2132
|
-
/* @__PURE__ */ (0,
|
|
2133
|
-
selections.length > 0 && /* @__PURE__ */ (0,
|
|
2134
|
-
/* @__PURE__ */ (0,
|
|
2135
|
-
/* @__PURE__ */ (0,
|
|
2136
|
-
bundle.widgetConfig.savingsBar.visible && summary.savings > 0 && /* @__PURE__ */ (0,
|
|
2236
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "lb-bundle-divider" }),
|
|
2237
|
+
selections.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "lb-bundle-summary", "data-pricing-section": true, children: [
|
|
2238
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "lb-bundle-summary__text", children: [
|
|
2239
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "lb-bundle-summary__label", children: "Bundle total" }),
|
|
2240
|
+
bundle.widgetConfig.savingsBar.visible && summary.savings > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { className: "lb-bundle-savings-line", "data-savings-bar": true, children: [
|
|
2137
2241
|
"You save",
|
|
2138
2242
|
" ",
|
|
2139
|
-
/* @__PURE__ */ (0,
|
|
2243
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { "data-savings-amount": true, children: (0, import_core11.formatMoney)(summary.savings, currency) }),
|
|
2140
2244
|
" ",
|
|
2141
|
-
/* @__PURE__ */ (0,
|
|
2245
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { "data-savings-percent": true, children: [
|
|
2142
2246
|
"(",
|
|
2143
2247
|
summary.savingsPercent,
|
|
2144
2248
|
"%)"
|
|
2145
2249
|
] })
|
|
2146
2250
|
] })
|
|
2147
2251
|
] }),
|
|
2148
|
-
/* @__PURE__ */ (0,
|
|
2149
|
-
bundle.widgetConfig.pricing.showComparePrice && summary.savings > 0 && /* @__PURE__ */ (0,
|
|
2150
|
-
/* @__PURE__ */ (0,
|
|
2252
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "lb-bundle-summary__prices", children: [
|
|
2253
|
+
bundle.widgetConfig.pricing.showComparePrice && summary.savings > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "lb-bundle-compare-price", "data-compare-price": true, children: (0, import_core11.formatMoney)(summary.comparePrice, currency) }),
|
|
2254
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "lb-bundle-sale-price", "data-sale-price": true, children: (0, import_core11.formatMoney)(summary.salePrice, currency) })
|
|
2151
2255
|
] })
|
|
2152
2256
|
] }),
|
|
2153
|
-
cartError && /* @__PURE__ */ (0,
|
|
2154
|
-
/* @__PURE__ */ (0,
|
|
2257
|
+
cartError && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "lb-bundle__error", role: "alert", children: cartError }),
|
|
2258
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2155
2259
|
"button",
|
|
2156
2260
|
{
|
|
2157
2261
|
className: "lb-bundle__cta",
|
|
@@ -2161,7 +2265,7 @@ function MixMatchBundle(props) {
|
|
|
2161
2265
|
children: ctaLabel
|
|
2162
2266
|
}
|
|
2163
2267
|
),
|
|
2164
|
-
pickerOpen && /* @__PURE__ */ (0,
|
|
2268
|
+
pickerOpen && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2165
2269
|
MixMatchPicker,
|
|
2166
2270
|
{
|
|
2167
2271
|
outOfStockBehavior,
|
|
@@ -2202,7 +2306,7 @@ function countInStockProducts(bundle) {
|
|
|
2202
2306
|
return count;
|
|
2203
2307
|
}
|
|
2204
2308
|
function PlusIcon() {
|
|
2205
|
-
return /* @__PURE__ */ (0,
|
|
2309
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
2206
2310
|
"svg",
|
|
2207
2311
|
{
|
|
2208
2312
|
width: "18",
|
|
@@ -2212,14 +2316,14 @@ function PlusIcon() {
|
|
|
2212
2316
|
xmlns: "http://www.w3.org/2000/svg",
|
|
2213
2317
|
"aria-hidden": "true",
|
|
2214
2318
|
children: [
|
|
2215
|
-
/* @__PURE__ */ (0,
|
|
2216
|
-
/* @__PURE__ */ (0,
|
|
2319
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "9", y1: "3", x2: "9", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
|
|
2320
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "3", y1: "9", x2: "15", y2: "9", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
|
|
2217
2321
|
]
|
|
2218
2322
|
}
|
|
2219
2323
|
);
|
|
2220
2324
|
}
|
|
2221
2325
|
function CloseIcon2() {
|
|
2222
|
-
return /* @__PURE__ */ (0,
|
|
2326
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
2223
2327
|
"svg",
|
|
2224
2328
|
{
|
|
2225
2329
|
width: "16",
|
|
@@ -2229,17 +2333,17 @@ function CloseIcon2() {
|
|
|
2229
2333
|
xmlns: "http://www.w3.org/2000/svg",
|
|
2230
2334
|
"aria-hidden": "true",
|
|
2231
2335
|
children: [
|
|
2232
|
-
/* @__PURE__ */ (0,
|
|
2233
|
-
/* @__PURE__ */ (0,
|
|
2336
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "5", y1: "5", x2: "15", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
|
|
2337
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "15", y1: "5", x2: "5", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
|
|
2234
2338
|
]
|
|
2235
2339
|
}
|
|
2236
2340
|
);
|
|
2237
2341
|
}
|
|
2238
2342
|
|
|
2239
2343
|
// src/components/VolumeBundle.tsx
|
|
2240
|
-
var
|
|
2344
|
+
var import_react14 = require("react");
|
|
2241
2345
|
var import_core12 = require("@lime-bundles/core");
|
|
2242
|
-
var
|
|
2346
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
2243
2347
|
function VolumeBundle(props) {
|
|
2244
2348
|
const {
|
|
2245
2349
|
shopDomain,
|
|
@@ -2263,13 +2367,30 @@ function VolumeBundle(props) {
|
|
|
2263
2367
|
bundleType: "volume",
|
|
2264
2368
|
enabled: analyticsEnabled !== false
|
|
2265
2369
|
});
|
|
2266
|
-
const [quantity, setQuantity] = (0,
|
|
2267
|
-
const [addingToCart, setAddingToCart] = (0,
|
|
2268
|
-
const [cartError, setCartError] = (0,
|
|
2370
|
+
const [quantity, setQuantity] = (0, import_react14.useState)(1);
|
|
2371
|
+
const [addingToCart, setAddingToCart] = (0, import_react14.useState)(false);
|
|
2372
|
+
const [cartError, setCartError] = (0, import_react14.useState)(null);
|
|
2373
|
+
const [seededFor, setSeededFor] = (0, import_react14.useState)(null);
|
|
2269
2374
|
const bundle = result.status === "success" && result.bundle.bundleType === "volume" ? result.bundle : null;
|
|
2375
|
+
(0, import_react14.useEffect)(() => {
|
|
2376
|
+
if (!bundle || seededFor === bundle.id) return;
|
|
2377
|
+
setSeededFor(bundle.id);
|
|
2378
|
+
const tiers = bundle.volumeTiers;
|
|
2379
|
+
if (tiers.length === 0) return;
|
|
2380
|
+
const best = (0, import_core12.bestValueTierIndex)(
|
|
2381
|
+
tiers,
|
|
2382
|
+
bundle.discountConfig.discountType
|
|
2383
|
+
);
|
|
2384
|
+
const idx = (0, import_core12.resolveDefaultTierIndex)(
|
|
2385
|
+
bundle.widgetConfig.defaultTier,
|
|
2386
|
+
tiers.length,
|
|
2387
|
+
best
|
|
2388
|
+
);
|
|
2389
|
+
setQuantity(tiers[idx].minQuantity);
|
|
2390
|
+
}, [bundle, seededFor]);
|
|
2270
2391
|
const setConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);
|
|
2271
2392
|
const tiersEdgeFadeRef = useEdgeFade();
|
|
2272
|
-
(0,
|
|
2393
|
+
(0, import_react14.useEffect)(() => {
|
|
2273
2394
|
if (result.status === "error") {
|
|
2274
2395
|
onError?.(result.error);
|
|
2275
2396
|
return;
|
|
@@ -2283,8 +2404,8 @@ function VolumeBundle(props) {
|
|
|
2283
2404
|
}
|
|
2284
2405
|
}, [result, onError]);
|
|
2285
2406
|
const product = bundle?.products[0];
|
|
2286
|
-
const variants = (0,
|
|
2287
|
-
const optionNames = (0,
|
|
2407
|
+
const variants = (0, import_react14.useMemo)(() => product?.variants.nodes ?? [], [product]);
|
|
2408
|
+
const optionNames = (0, import_react14.useMemo)(() => {
|
|
2288
2409
|
const first = variants[0];
|
|
2289
2410
|
return first ? first.selectedOptions.map((o) => o.name) : [];
|
|
2290
2411
|
}, [variants]);
|
|
@@ -2301,7 +2422,7 @@ function VolumeBundle(props) {
|
|
|
2301
2422
|
displayVariant.unitPriceMeasurement,
|
|
2302
2423
|
currency
|
|
2303
2424
|
) : null;
|
|
2304
|
-
const tierSavings = (0,
|
|
2425
|
+
const tierSavings = (0, import_react14.useMemo)(
|
|
2305
2426
|
() => bundle ? (0, import_core12.calculateTierSavings)(
|
|
2306
2427
|
bundle.volumeTiers,
|
|
2307
2428
|
basePrice,
|
|
@@ -2311,26 +2432,23 @@ function VolumeBundle(props) {
|
|
|
2311
2432
|
[bundle, basePrice, quantity]
|
|
2312
2433
|
);
|
|
2313
2434
|
const activeTier = bundle ? (0, import_core12.getActiveTier)(bundle.volumeTiers, quantity) : null;
|
|
2314
|
-
const popularTierIndex = (0,
|
|
2315
|
-
if (!bundle
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
}
|
|
2326
|
-
return best;
|
|
2327
|
-
}, [bundle, tierSavings]);
|
|
2435
|
+
const popularTierIndex = (0, import_react14.useMemo)(() => {
|
|
2436
|
+
if (!bundle || bundle.volumeTiers.length === 0) return -1;
|
|
2437
|
+
return (0, import_core12.resolvePopularTierIndex)(
|
|
2438
|
+
bundle.widgetConfig.popularBadge.tierIndex,
|
|
2439
|
+
bundle.widgetConfig.popularBadge.visible !== false,
|
|
2440
|
+
(0, import_core12.bestValueTierIndex)(
|
|
2441
|
+
bundle.volumeTiers,
|
|
2442
|
+
bundle.discountConfig.discountType
|
|
2443
|
+
)
|
|
2444
|
+
);
|
|
2445
|
+
}, [bundle]);
|
|
2328
2446
|
const activeUnitPrice = tierSavings.find((ts) => ts.tier === activeTier)?.unitPrice ?? basePrice;
|
|
2329
2447
|
const undiscountedTotal = basePrice * quantity;
|
|
2330
2448
|
const volumeTotal = activeUnitPrice * quantity;
|
|
2331
2449
|
const volumeSavings = Math.max(0, undiscountedTotal - volumeTotal);
|
|
2332
2450
|
const volumeSavingsPercent = undiscountedTotal > 0 && volumeSavings > 0 ? Math.round(volumeSavings / undiscountedTotal * 100) : 0;
|
|
2333
|
-
const handleAddToCart = (0,
|
|
2451
|
+
const handleAddToCart = (0, import_react14.useCallback)(async () => {
|
|
2334
2452
|
if (!bundle || !product) return;
|
|
2335
2453
|
const variant = selectedVariant ?? product.variants.nodes.find(
|
|
2336
2454
|
(v) => (0, import_core12.isVariantFulfillable)(v, quantity)
|
|
@@ -2376,15 +2494,15 @@ function VolumeBundle(props) {
|
|
|
2376
2494
|
tierSavings
|
|
2377
2495
|
]);
|
|
2378
2496
|
if (result.status === "loading") {
|
|
2379
|
-
return /* @__PURE__ */ (0,
|
|
2380
|
-
/* @__PURE__ */ (0,
|
|
2381
|
-
/* @__PURE__ */ (0,
|
|
2497
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: `lb-bundle lb-bundle--loading ${className ?? ""}`, children: [
|
|
2498
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "lb-skeleton lb-skeleton--title" }),
|
|
2499
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "lb-skeleton lb-skeleton--tiers" })
|
|
2382
2500
|
] });
|
|
2383
2501
|
}
|
|
2384
2502
|
if (result.status === "error") return null;
|
|
2385
2503
|
if (!bundle) return null;
|
|
2386
2504
|
if (!product) return null;
|
|
2387
|
-
return /* @__PURE__ */ (0,
|
|
2505
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2388
2506
|
"div",
|
|
2389
2507
|
{
|
|
2390
2508
|
ref: (el) => {
|
|
@@ -2395,12 +2513,19 @@ function VolumeBundle(props) {
|
|
|
2395
2513
|
role: "region",
|
|
2396
2514
|
"aria-label": bundle.title,
|
|
2397
2515
|
children: [
|
|
2398
|
-
/* @__PURE__ */ (0,
|
|
2399
|
-
/* @__PURE__ */ (0,
|
|
2400
|
-
bundle.description && /* @__PURE__ */ (0,
|
|
2516
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "lb-bundle-header", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "lb-bundle-header__content", children: [
|
|
2517
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { className: "lb-bundle-title", children: bundle.title }),
|
|
2518
|
+
bundle.description && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "lb-bundle-subtitle", children: bundle.description })
|
|
2401
2519
|
] }) }),
|
|
2402
|
-
/* @__PURE__ */ (0,
|
|
2403
|
-
|
|
2520
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2521
|
+
BundleCountdown,
|
|
2522
|
+
{
|
|
2523
|
+
endsAt: bundle.endsAt,
|
|
2524
|
+
widgetConfig: bundle.widgetConfig
|
|
2525
|
+
}
|
|
2526
|
+
),
|
|
2527
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "lb-bundle-product-row lb-bundle-product-row--volume", children: [
|
|
2528
|
+
thumbImage && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2404
2529
|
"img",
|
|
2405
2530
|
{
|
|
2406
2531
|
src: thumbImage.url,
|
|
@@ -2409,20 +2534,20 @@ function VolumeBundle(props) {
|
|
|
2409
2534
|
loading: "lazy"
|
|
2410
2535
|
}
|
|
2411
2536
|
),
|
|
2412
|
-
/* @__PURE__ */ (0,
|
|
2413
|
-
/* @__PURE__ */ (0,
|
|
2414
|
-
/* @__PURE__ */ (0,
|
|
2537
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "lb-bundle__product-info", children: [
|
|
2538
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "lb-bundle__product-title", children: product.title }),
|
|
2539
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "lb-bundle__product-price", children: [
|
|
2415
2540
|
(0, import_core12.formatMoney)(basePrice, currency),
|
|
2416
2541
|
" each"
|
|
2417
2542
|
] }),
|
|
2418
|
-
unitPriceText && /* @__PURE__ */ (0,
|
|
2419
|
-
showPicker && /* @__PURE__ */ (0,
|
|
2543
|
+
unitPriceText && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "lb-bundle__product-unit-price", children: unitPriceText }),
|
|
2544
|
+
showPicker && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "lb-bundle__product-variant-pickers", children: optionNames.map((optionName, optionIndex) => {
|
|
2420
2545
|
const dropdownOptions = optionsFor(optionIndex).map((o) => ({
|
|
2421
2546
|
value: o.value,
|
|
2422
2547
|
label: o.value,
|
|
2423
2548
|
disabled: o.disabled
|
|
2424
2549
|
}));
|
|
2425
|
-
return /* @__PURE__ */ (0,
|
|
2550
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2426
2551
|
VariantDropdown,
|
|
2427
2552
|
{
|
|
2428
2553
|
options: dropdownOptions,
|
|
@@ -2435,37 +2560,47 @@ function VolumeBundle(props) {
|
|
|
2435
2560
|
}) })
|
|
2436
2561
|
] })
|
|
2437
2562
|
] }),
|
|
2438
|
-
/* @__PURE__ */ (0,
|
|
2563
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2439
2564
|
"div",
|
|
2440
2565
|
{
|
|
2441
2566
|
className: "lb-bundle__tiers lb-edge-fade",
|
|
2442
|
-
role: "
|
|
2443
|
-
"aria-label": "
|
|
2567
|
+
role: "radiogroup",
|
|
2568
|
+
"aria-label": "Select quantity",
|
|
2444
2569
|
ref: tiersEdgeFadeRef,
|
|
2445
2570
|
children: tierSavings.map((ts, tierIndex) => {
|
|
2446
2571
|
const savingsPercent = Math.round(ts.savingsPercent);
|
|
2447
2572
|
const showCompare = bundle.widgetConfig.pricing.showComparePrice && ts.savings > 0;
|
|
2448
|
-
|
|
2573
|
+
const isChecked = activeTier === ts.tier;
|
|
2574
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2449
2575
|
"div",
|
|
2450
2576
|
{
|
|
2451
2577
|
className: `lb-bundle__tier ${ts.isActive ? "lb-bundle__tier--active" : ""}`,
|
|
2452
|
-
role: "
|
|
2578
|
+
role: "radio",
|
|
2579
|
+
"aria-checked": isChecked,
|
|
2580
|
+
tabIndex: isChecked ? 0 : -1,
|
|
2581
|
+
onClick: () => setQuantity(ts.tier.minQuantity),
|
|
2582
|
+
onKeyDown: (e) => {
|
|
2583
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
2584
|
+
e.preventDefault();
|
|
2585
|
+
setQuantity(ts.tier.minQuantity);
|
|
2586
|
+
}
|
|
2587
|
+
},
|
|
2453
2588
|
children: [
|
|
2454
|
-
/* @__PURE__ */ (0,
|
|
2455
|
-
/* @__PURE__ */ (0,
|
|
2456
|
-
/* @__PURE__ */ (0,
|
|
2589
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "lb-bundle__tier-radio", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "lb-bundle__tier-radio-dot" }) }),
|
|
2590
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "lb-bundle__tier-info", children: [
|
|
2591
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "lb-bundle__tier-label", children: [
|
|
2457
2592
|
"Buy ",
|
|
2458
2593
|
ts.tier.minQuantity
|
|
2459
2594
|
] }),
|
|
2460
|
-
/* @__PURE__ */ (0,
|
|
2461
|
-
showCompare && /* @__PURE__ */ (0,
|
|
2462
|
-
/* @__PURE__ */ (0,
|
|
2463
|
-
/* @__PURE__ */ (0,
|
|
2595
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "lb-bundle__tier-price", children: [
|
|
2596
|
+
showCompare && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "lb-bundle__tier-compare", children: (0, import_core12.formatMoney)(basePrice, currency) }),
|
|
2597
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: (0, import_core12.formatMoney)(ts.unitPrice, currency) }),
|
|
2598
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "lb-bundle__tier-unit", children: "each" })
|
|
2464
2599
|
] })
|
|
2465
2600
|
] }),
|
|
2466
|
-
(tierIndex === popularTierIndex || savingsPercent > 0) && /* @__PURE__ */ (0,
|
|
2467
|
-
tierIndex === popularTierIndex && /* @__PURE__ */ (0,
|
|
2468
|
-
savingsPercent > 0 && /* @__PURE__ */ (0,
|
|
2601
|
+
(tierIndex === popularTierIndex || savingsPercent > 0) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "lb-bundle__tier-right", children: [
|
|
2602
|
+
tierIndex === popularTierIndex && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "lb-bundle__tier-badge", children: bundle.widgetConfig.popularBadge.text }),
|
|
2603
|
+
savingsPercent > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "lb-bundle__tier-savings", children: [
|
|
2469
2604
|
"Save ",
|
|
2470
2605
|
savingsPercent,
|
|
2471
2606
|
"%"
|
|
@@ -2478,10 +2613,10 @@ function VolumeBundle(props) {
|
|
|
2478
2613
|
})
|
|
2479
2614
|
}
|
|
2480
2615
|
),
|
|
2481
|
-
/* @__PURE__ */ (0,
|
|
2482
|
-
/* @__PURE__ */ (0,
|
|
2483
|
-
/* @__PURE__ */ (0,
|
|
2484
|
-
/* @__PURE__ */ (0,
|
|
2616
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "lb-bundle__quantity-selector", children: [
|
|
2617
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("label", { htmlFor: `lb-qty-${bundle.id}`, children: "Quantity" }),
|
|
2618
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "lb-bundle__quantity-control", children: [
|
|
2619
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2485
2620
|
"button",
|
|
2486
2621
|
{
|
|
2487
2622
|
"aria-label": "Decrease quantity",
|
|
@@ -2489,7 +2624,7 @@ function VolumeBundle(props) {
|
|
|
2489
2624
|
children: "\u2212"
|
|
2490
2625
|
}
|
|
2491
2626
|
),
|
|
2492
|
-
/* @__PURE__ */ (0,
|
|
2627
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2493
2628
|
"input",
|
|
2494
2629
|
{
|
|
2495
2630
|
id: `lb-qty-${bundle.id}`,
|
|
@@ -2503,7 +2638,7 @@ function VolumeBundle(props) {
|
|
|
2503
2638
|
className: "lb-bundle__quantity-input"
|
|
2504
2639
|
}
|
|
2505
2640
|
),
|
|
2506
|
-
/* @__PURE__ */ (0,
|
|
2641
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2507
2642
|
"button",
|
|
2508
2643
|
{
|
|
2509
2644
|
"aria-label": "Increase quantity",
|
|
@@ -2513,23 +2648,23 @@ function VolumeBundle(props) {
|
|
|
2513
2648
|
)
|
|
2514
2649
|
] })
|
|
2515
2650
|
] }),
|
|
2516
|
-
cartError && /* @__PURE__ */ (0,
|
|
2651
|
+
cartError && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "lb-bundle__error", role: "alert", children: cartError }),
|
|
2517
2652
|
bundle && displayVariant && (0, import_core12.shouldShowLowStockBadge)(
|
|
2518
2653
|
displayVariant,
|
|
2519
2654
|
minTierQty,
|
|
2520
2655
|
bundle.widgetConfig.lowStockThreshold,
|
|
2521
2656
|
bundle.widgetConfig.showLowStockBadge
|
|
2522
|
-
) && /* @__PURE__ */ (0,
|
|
2657
|
+
) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "lb-bundle-low-stock-badge", children: [
|
|
2523
2658
|
"Only ",
|
|
2524
2659
|
displayVariant.quantityAvailable,
|
|
2525
2660
|
" left"
|
|
2526
2661
|
] }),
|
|
2527
|
-
/* @__PURE__ */ (0,
|
|
2528
|
-
/* @__PURE__ */ (0,
|
|
2529
|
-
/* @__PURE__ */ (0,
|
|
2530
|
-
/* @__PURE__ */ (0,
|
|
2662
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "lb-bundle-divider" }),
|
|
2663
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "lb-bundle-summary", children: [
|
|
2664
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "lb-bundle-summary__text", children: [
|
|
2665
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "lb-bundle-summary__label", "data-total-label": true, children: [
|
|
2531
2666
|
"Total",
|
|
2532
|
-
bundle.widgetConfig.pricing.showItemCount && /* @__PURE__ */ (0,
|
|
2667
|
+
bundle.widgetConfig.pricing.showItemCount && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { "data-item-count": true, children: [
|
|
2533
2668
|
" ",
|
|
2534
2669
|
"(",
|
|
2535
2670
|
quantity,
|
|
@@ -2538,24 +2673,24 @@ function VolumeBundle(props) {
|
|
|
2538
2673
|
")"
|
|
2539
2674
|
] })
|
|
2540
2675
|
] }),
|
|
2541
|
-
bundle.widgetConfig.savingsBar.visible && volumeSavings > 0 && /* @__PURE__ */ (0,
|
|
2676
|
+
bundle.widgetConfig.savingsBar.visible && volumeSavings > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "lb-bundle-savings-line", "data-savings-bar": true, children: [
|
|
2542
2677
|
"You save",
|
|
2543
2678
|
" ",
|
|
2544
|
-
/* @__PURE__ */ (0,
|
|
2679
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { "data-savings-amount": true, children: (0, import_core12.formatMoney)(volumeSavings, currency) }),
|
|
2545
2680
|
" ",
|
|
2546
|
-
/* @__PURE__ */ (0,
|
|
2681
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { "data-savings-percent": true, children: [
|
|
2547
2682
|
"(",
|
|
2548
2683
|
volumeSavingsPercent,
|
|
2549
2684
|
"%)"
|
|
2550
2685
|
] })
|
|
2551
2686
|
] })
|
|
2552
2687
|
] }),
|
|
2553
|
-
/* @__PURE__ */ (0,
|
|
2554
|
-
bundle.widgetConfig.pricing.showComparePrice && volumeSavings > 0 && /* @__PURE__ */ (0,
|
|
2555
|
-
/* @__PURE__ */ (0,
|
|
2688
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "lb-bundle-summary__prices", children: [
|
|
2689
|
+
bundle.widgetConfig.pricing.showComparePrice && volumeSavings > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "lb-bundle-compare-price", "data-compare-price": true, children: (0, import_core12.formatMoney)(undiscountedTotal, currency) }),
|
|
2690
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "lb-bundle-sale-price", "data-total-price": true, children: (0, import_core12.formatMoney)(volumeTotal, currency) })
|
|
2556
2691
|
] })
|
|
2557
2692
|
] }),
|
|
2558
|
-
/* @__PURE__ */ (0,
|
|
2693
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2559
2694
|
"button",
|
|
2560
2695
|
{
|
|
2561
2696
|
className: "lb-bundle__cta",
|
|
@@ -2571,9 +2706,9 @@ function VolumeBundle(props) {
|
|
|
2571
2706
|
}
|
|
2572
2707
|
|
|
2573
2708
|
// src/components/BogoBundle.tsx
|
|
2574
|
-
var
|
|
2709
|
+
var import_react15 = require("react");
|
|
2575
2710
|
var import_core13 = require("@lime-bundles/core");
|
|
2576
|
-
var
|
|
2711
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
2577
2712
|
function discountedUnit(price, percent) {
|
|
2578
2713
|
const cents = Math.round(price * 100);
|
|
2579
2714
|
const discounted = cents - Math.floor(cents * percent / 100);
|
|
@@ -2602,10 +2737,10 @@ function BogoBundle(props) {
|
|
|
2602
2737
|
bundleType: "bogo",
|
|
2603
2738
|
enabled: analyticsEnabled !== false
|
|
2604
2739
|
});
|
|
2605
|
-
const [addingToCart, setAddingToCart] = (0,
|
|
2606
|
-
const [cartError, setCartError] = (0,
|
|
2607
|
-
const [selectedVariants, setSelectedVariants] = (0,
|
|
2608
|
-
const handleVariantChange = (0,
|
|
2740
|
+
const [addingToCart, setAddingToCart] = (0, import_react15.useState)(false);
|
|
2741
|
+
const [cartError, setCartError] = (0, import_react15.useState)(null);
|
|
2742
|
+
const [selectedVariants, setSelectedVariants] = (0, import_react15.useState)({ buy: null, get: null });
|
|
2743
|
+
const handleVariantChange = (0, import_react15.useCallback)(
|
|
2609
2744
|
(role, variant) => {
|
|
2610
2745
|
setSelectedVariants((prev) => {
|
|
2611
2746
|
if (prev[role] === variant) return prev;
|
|
@@ -2616,7 +2751,7 @@ function BogoBundle(props) {
|
|
|
2616
2751
|
);
|
|
2617
2752
|
const bundle = result.status === "success" && result.bundle.bundleType === "bogo" ? result.bundle : null;
|
|
2618
2753
|
const setConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);
|
|
2619
|
-
(0,
|
|
2754
|
+
(0, import_react15.useEffect)(() => {
|
|
2620
2755
|
if (result.status === "error") {
|
|
2621
2756
|
onError?.(result.error);
|
|
2622
2757
|
return;
|
|
@@ -2629,28 +2764,28 @@ function BogoBundle(props) {
|
|
|
2629
2764
|
);
|
|
2630
2765
|
}
|
|
2631
2766
|
}, [result, onError]);
|
|
2632
|
-
const buyProduct = (0,
|
|
2767
|
+
const buyProduct = (0, import_react15.useMemo)(
|
|
2633
2768
|
() => bundle?.products.find((p) => p.id === bundle.buyProductId) ?? null,
|
|
2634
2769
|
[bundle]
|
|
2635
2770
|
);
|
|
2636
|
-
const getProduct = (0,
|
|
2771
|
+
const getProduct = (0, import_react15.useMemo)(
|
|
2637
2772
|
() => bundle?.products.find((p) => p.id === bundle.getProductId) ?? null,
|
|
2638
2773
|
[bundle]
|
|
2639
2774
|
);
|
|
2640
2775
|
const percent = bundle ? Math.min(100, Math.max(0, bundle.discountConfig.discountValue)) : 0;
|
|
2641
|
-
const resolveVariant = (0,
|
|
2776
|
+
const resolveVariant = (0, import_react15.useCallback)(
|
|
2642
2777
|
(product, selected, qty) => {
|
|
2643
2778
|
if (!product) return null;
|
|
2644
2779
|
return selected ?? product.variants.nodes.find((v) => (0, import_core13.isVariantFulfillable)(v, qty)) ?? product.variants.nodes[0] ?? null;
|
|
2645
2780
|
},
|
|
2646
2781
|
[]
|
|
2647
2782
|
);
|
|
2648
|
-
const oosSides = (0,
|
|
2783
|
+
const oosSides = (0, import_react15.useMemo)(() => {
|
|
2649
2784
|
if (!bundle) return 0;
|
|
2650
2785
|
const short = (product, qty) => !!product && !product.variants.nodes.some((v) => (0, import_core13.isVariantFulfillable)(v, qty));
|
|
2651
2786
|
return (short(buyProduct, bundle.buyQuantity) ? 1 : 0) + (short(getProduct, bundle.getQuantity) ? 1 : 0);
|
|
2652
2787
|
}, [bundle, buyProduct, getProduct]);
|
|
2653
|
-
const handleAddToCart = (0,
|
|
2788
|
+
const handleAddToCart = (0, import_react15.useCallback)(async () => {
|
|
2654
2789
|
if (!bundle || !buyProduct || !getProduct) return;
|
|
2655
2790
|
const buyVariant2 = resolveVariant(buyProduct, selectedVariants.buy, bundle.buyQuantity);
|
|
2656
2791
|
const getVariant2 = resolveVariant(getProduct, selectedVariants.get, bundle.getQuantity);
|
|
@@ -2697,9 +2832,9 @@ function BogoBundle(props) {
|
|
|
2697
2832
|
}
|
|
2698
2833
|
}, [bundle, buyProduct, getProduct, selectedVariants, resolveVariant, onAddToCart, onError, trackAddToCart, percent]);
|
|
2699
2834
|
if (result.status === "loading") {
|
|
2700
|
-
return /* @__PURE__ */ (0,
|
|
2701
|
-
/* @__PURE__ */ (0,
|
|
2702
|
-
/* @__PURE__ */ (0,
|
|
2835
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: `lb-bundle lb-bundle--loading ${className ?? ""}`, children: [
|
|
2836
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "lb-skeleton lb-skeleton--title" }),
|
|
2837
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "lb-skeleton lb-skeleton--products" })
|
|
2703
2838
|
] });
|
|
2704
2839
|
}
|
|
2705
2840
|
if (result.status === "error") return null;
|
|
@@ -2716,7 +2851,7 @@ function BogoBundle(props) {
|
|
|
2716
2851
|
const showCompare = bundle.widgetConfig.pricing.showComparePrice && savings > 0;
|
|
2717
2852
|
const showSavings = bundle.widgetConfig.savingsBar.visible && savings > 0;
|
|
2718
2853
|
const badge = percent === 100 ? "Free" : `${percent}% off`;
|
|
2719
|
-
return /* @__PURE__ */ (0,
|
|
2854
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
2720
2855
|
"div",
|
|
2721
2856
|
{
|
|
2722
2857
|
ref: (el) => {
|
|
@@ -2727,12 +2862,19 @@ function BogoBundle(props) {
|
|
|
2727
2862
|
role: "region",
|
|
2728
2863
|
"aria-label": bundle.title,
|
|
2729
2864
|
children: [
|
|
2730
|
-
/* @__PURE__ */ (0,
|
|
2731
|
-
/* @__PURE__ */ (0,
|
|
2732
|
-
bundle.description && /* @__PURE__ */ (0,
|
|
2865
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "lb-bundle-header", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "lb-bundle-header__content", children: [
|
|
2866
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h3", { className: "lb-bundle-title", children: bundle.title }),
|
|
2867
|
+
bundle.description && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "lb-bundle-subtitle", children: bundle.description })
|
|
2733
2868
|
] }) }),
|
|
2734
|
-
/* @__PURE__ */ (0,
|
|
2735
|
-
|
|
2869
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2870
|
+
BundleCountdown,
|
|
2871
|
+
{
|
|
2872
|
+
endsAt: bundle.endsAt,
|
|
2873
|
+
widgetConfig: bundle.widgetConfig
|
|
2874
|
+
}
|
|
2875
|
+
),
|
|
2876
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "lb-bundle__products", children: [
|
|
2877
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2736
2878
|
BogoProductRow,
|
|
2737
2879
|
{
|
|
2738
2880
|
side: "buy",
|
|
@@ -2744,11 +2886,11 @@ function BogoBundle(props) {
|
|
|
2744
2886
|
onVariantChange: handleVariantChange
|
|
2745
2887
|
}
|
|
2746
2888
|
),
|
|
2747
|
-
/* @__PURE__ */ (0,
|
|
2748
|
-
/* @__PURE__ */ (0,
|
|
2749
|
-
/* @__PURE__ */ (0,
|
|
2889
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "lb-bogo__plus", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { width: "12", height: "12", viewBox: "0 0 18 18", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
|
|
2890
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "9", y1: "3", x2: "9", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
|
|
2891
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "3", y1: "9", x2: "15", y2: "9", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
|
|
2750
2892
|
] }) }),
|
|
2751
|
-
/* @__PURE__ */ (0,
|
|
2893
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2752
2894
|
BogoProductRow,
|
|
2753
2895
|
{
|
|
2754
2896
|
side: "get",
|
|
@@ -2761,29 +2903,29 @@ function BogoBundle(props) {
|
|
|
2761
2903
|
}
|
|
2762
2904
|
)
|
|
2763
2905
|
] }),
|
|
2764
|
-
/* @__PURE__ */ (0,
|
|
2765
|
-
/* @__PURE__ */ (0,
|
|
2766
|
-
/* @__PURE__ */ (0,
|
|
2767
|
-
/* @__PURE__ */ (0,
|
|
2768
|
-
showSavings && /* @__PURE__ */ (0,
|
|
2906
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "lb-bundle-divider" }),
|
|
2907
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "lb-bundle-summary", children: [
|
|
2908
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "lb-bundle-summary__text", children: [
|
|
2909
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "lb-bundle-summary__label", children: "Bundle total" }),
|
|
2910
|
+
showSavings && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { className: "lb-bundle-savings-line", "data-savings-bar": true, children: [
|
|
2769
2911
|
"You save",
|
|
2770
2912
|
" ",
|
|
2771
|
-
/* @__PURE__ */ (0,
|
|
2913
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { "data-savings-amount": true, children: (0, import_core13.formatMoney)(savings, currency) }),
|
|
2772
2914
|
" ",
|
|
2773
|
-
/* @__PURE__ */ (0,
|
|
2915
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { "data-savings-percent": true, children: [
|
|
2774
2916
|
"(",
|
|
2775
2917
|
savingsPercent,
|
|
2776
2918
|
"%)"
|
|
2777
2919
|
] })
|
|
2778
2920
|
] })
|
|
2779
2921
|
] }),
|
|
2780
|
-
/* @__PURE__ */ (0,
|
|
2781
|
-
showCompare && /* @__PURE__ */ (0,
|
|
2782
|
-
/* @__PURE__ */ (0,
|
|
2922
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "lb-bundle-summary__prices", children: [
|
|
2923
|
+
showCompare && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "lb-bundle-compare-price", "data-compare-price": true, children: (0, import_core13.formatMoney)(comparePrice, currency) }),
|
|
2924
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "lb-bundle-sale-price", "data-sale-price": true, children: (0, import_core13.formatMoney)(salePrice, currency) })
|
|
2783
2925
|
] })
|
|
2784
2926
|
] }),
|
|
2785
|
-
cartError && /* @__PURE__ */ (0,
|
|
2786
|
-
/* @__PURE__ */ (0,
|
|
2927
|
+
cartError && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "lb-bundle__error", role: "alert", children: cartError }),
|
|
2928
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2787
2929
|
"button",
|
|
2788
2930
|
{
|
|
2789
2931
|
className: "lb-bundle__cta",
|
|
@@ -2799,7 +2941,7 @@ function BogoBundle(props) {
|
|
|
2799
2941
|
}
|
|
2800
2942
|
function BogoProductRow({ side, product, quantity, percent, badge, currency, onVariantChange }) {
|
|
2801
2943
|
const variants = product.variants.nodes;
|
|
2802
|
-
const optionNames = (0,
|
|
2944
|
+
const optionNames = (0, import_react15.useMemo)(() => {
|
|
2803
2945
|
const first = variants[0];
|
|
2804
2946
|
return first ? first.selectedOptions.map((o) => o.name) : [];
|
|
2805
2947
|
}, [variants]);
|
|
@@ -2808,7 +2950,7 @@ function BogoProductRow({ side, product, quantity, percent, badge, currency, onV
|
|
|
2808
2950
|
variants,
|
|
2809
2951
|
optionNames
|
|
2810
2952
|
});
|
|
2811
|
-
(0,
|
|
2953
|
+
(0, import_react15.useEffect)(() => {
|
|
2812
2954
|
onVariantChange(side, selectedVariant ?? null);
|
|
2813
2955
|
}, [selectedVariant, side, onVariantChange]);
|
|
2814
2956
|
const displayVariant = selectedVariant ?? variants.find((v) => (0, import_core13.isVariantFulfillable)(v, quantity)) ?? variants[0];
|
|
@@ -2822,8 +2964,8 @@ function BogoProductRow({ side, product, quantity, percent, badge, currency, onV
|
|
|
2822
2964
|
currency
|
|
2823
2965
|
) : null;
|
|
2824
2966
|
const thumbImage = displayVariant?.image ?? product.featuredImage;
|
|
2825
|
-
return /* @__PURE__ */ (0,
|
|
2826
|
-
thumbImage && /* @__PURE__ */ (0,
|
|
2967
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "lb-bundle-product-row", part: "product", "data-bogo-role": side, children: [
|
|
2968
|
+
thumbImage && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2827
2969
|
"img",
|
|
2828
2970
|
{
|
|
2829
2971
|
src: thumbImage.url,
|
|
@@ -2832,11 +2974,11 @@ function BogoProductRow({ side, product, quantity, percent, badge, currency, onV
|
|
|
2832
2974
|
loading: "lazy"
|
|
2833
2975
|
}
|
|
2834
2976
|
),
|
|
2835
|
-
/* @__PURE__ */ (0,
|
|
2836
|
-
/* @__PURE__ */ (0,
|
|
2837
|
-
!showPicker && displayVariant && variants.length > 1 && /* @__PURE__ */ (0,
|
|
2838
|
-
/* @__PURE__ */ (0,
|
|
2839
|
-
compareAt && /* @__PURE__ */ (0,
|
|
2977
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "lb-bundle__product-info", children: [
|
|
2978
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "lb-bundle__product-title", children: product.title }),
|
|
2979
|
+
!showPicker && displayVariant && variants.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "lb-bundle-variant-badge", children: displayVariant.title }),
|
|
2980
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "lb-bundle-product-prices", children: [
|
|
2981
|
+
compareAt && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2840
2982
|
"span",
|
|
2841
2983
|
{
|
|
2842
2984
|
className: "lb-bundle-product-compare-price",
|
|
@@ -2844,13 +2986,13 @@ function BogoProductRow({ side, product, quantity, percent, badge, currency, onV
|
|
|
2844
2986
|
children: compareAt
|
|
2845
2987
|
}
|
|
2846
2988
|
),
|
|
2847
|
-
/* @__PURE__ */ (0,
|
|
2848
|
-
/* @__PURE__ */ (0,
|
|
2989
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "lb-bundle__product-price", "data-product-price": true, children: priceText }),
|
|
2990
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "lb-bundle-qty-inline", "data-qty-inline": true, children: [
|
|
2849
2991
|
"\xD7",
|
|
2850
2992
|
quantity
|
|
2851
2993
|
] })
|
|
2852
2994
|
] }),
|
|
2853
|
-
unitPriceText && /* @__PURE__ */ (0,
|
|
2995
|
+
unitPriceText && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2854
2996
|
"span",
|
|
2855
2997
|
{
|
|
2856
2998
|
className: "lb-bundle__product-unit-price",
|
|
@@ -2858,13 +3000,13 @@ function BogoProductRow({ side, product, quantity, percent, badge, currency, onV
|
|
|
2858
3000
|
children: unitPriceText
|
|
2859
3001
|
}
|
|
2860
3002
|
),
|
|
2861
|
-
showPicker && /* @__PURE__ */ (0,
|
|
3003
|
+
showPicker && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "lb-bundle__product-variant-pickers", children: optionNames.map((optionName, optionIndex) => {
|
|
2862
3004
|
const dropdownOptions = optionsFor(optionIndex).map((o) => ({
|
|
2863
3005
|
value: o.value,
|
|
2864
3006
|
label: o.value,
|
|
2865
3007
|
disabled: o.disabled
|
|
2866
3008
|
}));
|
|
2867
|
-
return /* @__PURE__ */ (0,
|
|
3009
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2868
3010
|
VariantDropdown,
|
|
2869
3011
|
{
|
|
2870
3012
|
options: dropdownOptions,
|
|
@@ -2876,22 +3018,29 @@ function BogoProductRow({ side, product, quantity, percent, badge, currency, onV
|
|
|
2876
3018
|
);
|
|
2877
3019
|
}) })
|
|
2878
3020
|
] }),
|
|
2879
|
-
badge && /* @__PURE__ */ (0,
|
|
3021
|
+
badge && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "lb-bogo__badge", children: badge })
|
|
2880
3022
|
] });
|
|
2881
3023
|
}
|
|
2882
3024
|
|
|
2883
3025
|
// src/components/MultiStepBundle.tsx
|
|
2884
|
-
var
|
|
3026
|
+
var import_react17 = require("react");
|
|
2885
3027
|
var import_core15 = require("@lime-bundles/core");
|
|
2886
3028
|
|
|
2887
3029
|
// src/components/MultiStepPicker.tsx
|
|
2888
|
-
var
|
|
3030
|
+
var import_react16 = require("react");
|
|
2889
3031
|
var import_react_dom2 = require("react-dom");
|
|
2890
3032
|
var import_core14 = require("@lime-bundles/core");
|
|
2891
|
-
var
|
|
2892
|
-
function ruleFor3(bundle, productId) {
|
|
3033
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
3034
|
+
function ruleFor3(bundle, productId, variantId) {
|
|
3035
|
+
if (variantId) {
|
|
3036
|
+
const vRule = bundle.variantRules[variantId];
|
|
3037
|
+
if (vRule) return vRule;
|
|
3038
|
+
}
|
|
2893
3039
|
return bundle.productRules[productId] ?? import_core14.DEFAULT_PRODUCT_RULE;
|
|
2894
3040
|
}
|
|
3041
|
+
function variantRuleFor3(bundle, variantId) {
|
|
3042
|
+
return variantId ? bundle.variantRules[variantId] : void 0;
|
|
3043
|
+
}
|
|
2895
3044
|
function sanitizeId2(gid) {
|
|
2896
3045
|
return gid.replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
2897
3046
|
}
|
|
@@ -2935,17 +3084,17 @@ function MultiStepPicker({
|
|
|
2935
3084
|
}) {
|
|
2936
3085
|
const wc = bundle.widgetConfig;
|
|
2937
3086
|
const steps = bundle.steps;
|
|
2938
|
-
const overlayRef = (0,
|
|
2939
|
-
const dialogRef = (0,
|
|
2940
|
-
const titleRef = (0,
|
|
2941
|
-
const mouseDownTarget = (0,
|
|
2942
|
-
const [open, setOpen] = (0,
|
|
2943
|
-
const [stepIndex, setStepIndex] = (0,
|
|
3087
|
+
const overlayRef = (0, import_react16.useRef)(null);
|
|
3088
|
+
const dialogRef = (0, import_react16.useRef)(null);
|
|
3089
|
+
const titleRef = (0, import_react16.useRef)(null);
|
|
3090
|
+
const mouseDownTarget = (0, import_react16.useRef)(null);
|
|
3091
|
+
const [open, setOpen] = (0, import_react16.useState)(false);
|
|
3092
|
+
const [stepIndex, setStepIndex] = (0, import_react16.useState)(
|
|
2944
3093
|
() => Math.max(0, Math.min(steps.length - 1, initialStep))
|
|
2945
3094
|
);
|
|
2946
|
-
const [query, setQuery] = (0,
|
|
2947
|
-
const [activeType, setActiveType] = (0,
|
|
2948
|
-
const [announcement, setAnnouncement] = (0,
|
|
3095
|
+
const [query, setQuery] = (0, import_react16.useState)("");
|
|
3096
|
+
const [activeType, setActiveType] = (0, import_react16.useState)(FILTERS_ALL2);
|
|
3097
|
+
const [announcement, setAnnouncement] = (0, import_react16.useState)("");
|
|
2949
3098
|
const step = steps[stepIndex];
|
|
2950
3099
|
const stepMin = step?.minQuantity ?? 1;
|
|
2951
3100
|
const stepPicks = selections[stepIndex] ?? [];
|
|
@@ -2953,11 +3102,11 @@ function MultiStepPicker({
|
|
|
2953
3102
|
const stepIsSatisfied = unitsInStep >= stepMin;
|
|
2954
3103
|
const isLastStep = stepIndex === steps.length - 1;
|
|
2955
3104
|
const shownUnits = Math.min(unitsInStep, stepMin);
|
|
2956
|
-
const eligible = (0,
|
|
3105
|
+
const eligible = (0, import_react16.useMemo)(
|
|
2957
3106
|
() => buildEligibleProducts2(bundle, stepIndex, outOfStockBehavior),
|
|
2958
3107
|
[bundle, stepIndex, outOfStockBehavior]
|
|
2959
3108
|
);
|
|
2960
|
-
const productTypes = (0,
|
|
3109
|
+
const productTypes = (0, import_react16.useMemo)(() => {
|
|
2961
3110
|
const types = [];
|
|
2962
3111
|
const seen = /* @__PURE__ */ new Set();
|
|
2963
3112
|
for (const ep of eligible) {
|
|
@@ -2970,7 +3119,7 @@ function MultiStepPicker({
|
|
|
2970
3119
|
return types;
|
|
2971
3120
|
}, [eligible]);
|
|
2972
3121
|
const showFilters = wc.mixMatchShowTypeFilters && productTypes.length >= 2;
|
|
2973
|
-
(0,
|
|
3122
|
+
(0, import_react16.useEffect)(() => {
|
|
2974
3123
|
const id = requestAnimationFrame(() => setOpen(true));
|
|
2975
3124
|
return () => cancelAnimationFrame(id);
|
|
2976
3125
|
}, []);
|
|
@@ -2994,7 +3143,7 @@ function MultiStepPicker({
|
|
|
2994
3143
|
titleRef.current?.focus();
|
|
2995
3144
|
}
|
|
2996
3145
|
const subtitle = `Step ${stepIndex + 1} of ${steps.length} \xB7 ${step?.name ?? ""}`;
|
|
2997
|
-
const filtered = (0,
|
|
3146
|
+
const filtered = (0, import_react16.useMemo)(() => {
|
|
2998
3147
|
const nq = normalizeText2(query.trim());
|
|
2999
3148
|
return eligible.filter((ep) => {
|
|
3000
3149
|
const matchesQuery = !nq || normalizeText2(ep.product.title).includes(nq);
|
|
@@ -3019,7 +3168,7 @@ function MultiStepPicker({
|
|
|
3019
3168
|
// inside carries the interactive role + focus trap. So the static-element
|
|
3020
3169
|
// interaction lint does not apply to this backdrop.
|
|
3021
3170
|
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
|
|
3022
|
-
/* @__PURE__ */ (0,
|
|
3171
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3023
3172
|
"div",
|
|
3024
3173
|
{
|
|
3025
3174
|
ref: (el) => {
|
|
@@ -3031,7 +3180,7 @@ function MultiStepPicker({
|
|
|
3031
3180
|
"data-bundle-gid": bundle.id,
|
|
3032
3181
|
onMouseDown: onOverlayMouseDown,
|
|
3033
3182
|
onMouseUp: onOverlayMouseUp,
|
|
3034
|
-
children: /* @__PURE__ */ (0,
|
|
3183
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
3035
3184
|
"div",
|
|
3036
3185
|
{
|
|
3037
3186
|
ref: dialogRef,
|
|
@@ -3041,10 +3190,10 @@ function MultiStepPicker({
|
|
|
3041
3190
|
"aria-labelledby": titleId,
|
|
3042
3191
|
tabIndex: -1,
|
|
3043
3192
|
children: [
|
|
3044
|
-
/* @__PURE__ */ (0,
|
|
3045
|
-
/* @__PURE__ */ (0,
|
|
3046
|
-
/* @__PURE__ */ (0,
|
|
3047
|
-
/* @__PURE__ */ (0,
|
|
3193
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "lb-mix-match__modal-header", children: [
|
|
3194
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "lb-mix-match__modal-header-top", children: [
|
|
3195
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "lb-mix-match__modal-heading", children: [
|
|
3196
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3048
3197
|
"h4",
|
|
3049
3198
|
{
|
|
3050
3199
|
className: "lb-mix-match__modal-title",
|
|
@@ -3054,9 +3203,9 @@ function MultiStepPicker({
|
|
|
3054
3203
|
children: "Add to your bundle"
|
|
3055
3204
|
}
|
|
3056
3205
|
),
|
|
3057
|
-
/* @__PURE__ */ (0,
|
|
3206
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "lb-mix-match__modal-subtitle", "data-modal-subtitle": true, children: subtitle })
|
|
3058
3207
|
] }),
|
|
3059
|
-
/* @__PURE__ */ (0,
|
|
3208
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3060
3209
|
"button",
|
|
3061
3210
|
{
|
|
3062
3211
|
type: "button",
|
|
@@ -3064,16 +3213,16 @@ function MultiStepPicker({
|
|
|
3064
3213
|
"data-modal-close": true,
|
|
3065
3214
|
"aria-label": "Close",
|
|
3066
3215
|
onClick: onClose,
|
|
3067
|
-
children: /* @__PURE__ */ (0,
|
|
3216
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CloseIcon3, {})
|
|
3068
3217
|
}
|
|
3069
3218
|
)
|
|
3070
3219
|
] }),
|
|
3071
|
-
/* @__PURE__ */ (0,
|
|
3220
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3072
3221
|
"div",
|
|
3073
3222
|
{
|
|
3074
3223
|
className: "lb-mix-match__progress lb-mix-match__modal-progress",
|
|
3075
3224
|
"data-progress": true,
|
|
3076
|
-
children: /* @__PURE__ */ (0,
|
|
3225
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3077
3226
|
"div",
|
|
3078
3227
|
{
|
|
3079
3228
|
className: "lb-mix-match__progress-segments",
|
|
@@ -3082,7 +3231,7 @@ function MultiStepPicker({
|
|
|
3082
3231
|
"aria-valuenow": shownUnits,
|
|
3083
3232
|
"aria-valuemin": 0,
|
|
3084
3233
|
"aria-valuemax": stepMin,
|
|
3085
|
-
children: Array.from({ length: stepMin }).map((_, i) => /* @__PURE__ */ (0,
|
|
3234
|
+
children: Array.from({ length: stepMin }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3086
3235
|
"span",
|
|
3087
3236
|
{
|
|
3088
3237
|
className: `lb-mix-match__progress-segment${i < shownUnits ? " lb-mix-match__progress-segment--filled" : ""}`,
|
|
@@ -3095,8 +3244,8 @@ function MultiStepPicker({
|
|
|
3095
3244
|
}
|
|
3096
3245
|
)
|
|
3097
3246
|
] }),
|
|
3098
|
-
wc.showSearch && /* @__PURE__ */ (0,
|
|
3099
|
-
/* @__PURE__ */ (0,
|
|
3247
|
+
wc.showSearch && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "lb-mix-match__modal-search", children: [
|
|
3248
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3100
3249
|
"input",
|
|
3101
3250
|
{
|
|
3102
3251
|
type: "text",
|
|
@@ -3110,7 +3259,7 @@ function MultiStepPicker({
|
|
|
3110
3259
|
onChange: (e) => setQuery(e.target.value)
|
|
3111
3260
|
}
|
|
3112
3261
|
),
|
|
3113
|
-
query.length > 0 && /* @__PURE__ */ (0,
|
|
3262
|
+
query.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3114
3263
|
"button",
|
|
3115
3264
|
{
|
|
3116
3265
|
type: "button",
|
|
@@ -3118,11 +3267,11 @@ function MultiStepPicker({
|
|
|
3118
3267
|
"data-modal-search-clear": true,
|
|
3119
3268
|
"aria-label": "Clear search",
|
|
3120
3269
|
onClick: () => setQuery(""),
|
|
3121
|
-
children: /* @__PURE__ */ (0,
|
|
3270
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SearchClearIcon2, {})
|
|
3122
3271
|
}
|
|
3123
3272
|
)
|
|
3124
3273
|
] }),
|
|
3125
|
-
showFilters && /* @__PURE__ */ (0,
|
|
3274
|
+
showFilters && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3126
3275
|
"div",
|
|
3127
3276
|
{
|
|
3128
3277
|
className: "lb-mix-match__filters",
|
|
@@ -3131,7 +3280,7 @@ function MultiStepPicker({
|
|
|
3131
3280
|
"aria-label": "Filter by product type",
|
|
3132
3281
|
children: [FILTERS_ALL2, ...productTypes].map((value) => {
|
|
3133
3282
|
const isActive = value === activeType;
|
|
3134
|
-
return /* @__PURE__ */ (0,
|
|
3283
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3135
3284
|
"button",
|
|
3136
3285
|
{
|
|
3137
3286
|
type: "button",
|
|
@@ -3146,7 +3295,7 @@ function MultiStepPicker({
|
|
|
3146
3295
|
})
|
|
3147
3296
|
}
|
|
3148
3297
|
),
|
|
3149
|
-
/* @__PURE__ */ (0,
|
|
3298
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "lb-mix-match__modal-list", "data-modal-list": true, children: filtered.map((ep) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3150
3299
|
MultiStepPickerRow,
|
|
3151
3300
|
{
|
|
3152
3301
|
bundle,
|
|
@@ -3164,10 +3313,10 @@ function MultiStepPicker({
|
|
|
3164
3313
|
},
|
|
3165
3314
|
`${stepIndex}:${ep.product.id}`
|
|
3166
3315
|
)) }),
|
|
3167
|
-
showEmpty && /* @__PURE__ */ (0,
|
|
3168
|
-
/* @__PURE__ */ (0,
|
|
3169
|
-
/* @__PURE__ */ (0,
|
|
3170
|
-
stepIndex > 0 && /* @__PURE__ */ (0,
|
|
3316
|
+
showEmpty && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "lb-mix-match__modal-empty", "data-modal-empty": true, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { children: "No products match your search" }) }),
|
|
3317
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { "data-modal-live": true, "aria-live": "polite", className: "lb-visually-hidden", children: announcement || (query.trim() ? `${filtered.length} products shown` : "") }),
|
|
3318
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "lb-mix-match__modal-footer lb-multi-step__modal-footer", children: [
|
|
3319
|
+
stepIndex > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3171
3320
|
"button",
|
|
3172
3321
|
{
|
|
3173
3322
|
type: "button",
|
|
@@ -3177,7 +3326,7 @@ function MultiStepPicker({
|
|
|
3177
3326
|
children: "Back"
|
|
3178
3327
|
}
|
|
3179
3328
|
),
|
|
3180
|
-
/* @__PURE__ */ (0,
|
|
3329
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3181
3330
|
"span",
|
|
3182
3331
|
{
|
|
3183
3332
|
className: "lb-mix-match__modal-footer-count",
|
|
@@ -3186,7 +3335,7 @@ function MultiStepPicker({
|
|
|
3186
3335
|
children: `${shownUnits} of ${stepMin} added`
|
|
3187
3336
|
}
|
|
3188
3337
|
),
|
|
3189
|
-
!isLastStep && /* @__PURE__ */ (0,
|
|
3338
|
+
!isLastStep && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3190
3339
|
"button",
|
|
3191
3340
|
{
|
|
3192
3341
|
type: "button",
|
|
@@ -3199,7 +3348,7 @@ function MultiStepPicker({
|
|
|
3199
3348
|
children: "Next"
|
|
3200
3349
|
}
|
|
3201
3350
|
),
|
|
3202
|
-
isLastStep && /* @__PURE__ */ (0,
|
|
3351
|
+
isLastStep && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3203
3352
|
"button",
|
|
3204
3353
|
{
|
|
3205
3354
|
type: "button",
|
|
@@ -3237,25 +3386,27 @@ function MultiStepPickerRow({
|
|
|
3237
3386
|
const { product, variants, isOos } = eligible;
|
|
3238
3387
|
const rule = ruleFor3(bundle, product.id);
|
|
3239
3388
|
const step = bundle.steps[stepIndex];
|
|
3240
|
-
const optionNames = (0,
|
|
3389
|
+
const optionNames = (0, import_react16.useMemo)(() => {
|
|
3241
3390
|
const first = variants[0];
|
|
3242
3391
|
return first ? first.selectedOptions.map((o) => o.name) : [];
|
|
3243
3392
|
}, [variants]);
|
|
3244
3393
|
const showPicker = variants.length > 1 && optionNames.length > 0;
|
|
3245
3394
|
const { selectedValues, selectedVariant, setOptionValue, optionsFor } = useVariantSelection({ variants, optionNames });
|
|
3246
3395
|
const currentVariant = selectedVariant ?? variants.find((v) => (0, import_core14.isVariantFulfillable)(v, rule.min)) ?? eligible.firstAvailableVariant ?? variants[0] ?? null;
|
|
3247
|
-
const
|
|
3396
|
+
const vRule = ruleFor3(bundle, product.id, currentVariant?.id);
|
|
3397
|
+
const variantMax = variantRuleFor3(bundle, currentVariant?.id)?.max;
|
|
3398
|
+
const stepPicks = (0, import_react16.useMemo)(
|
|
3248
3399
|
() => selections[stepIndex] ?? [],
|
|
3249
3400
|
[selections, stepIndex]
|
|
3250
3401
|
);
|
|
3251
3402
|
const unitsInStep = stepPicks.reduce((sum, s) => sum + s.quantity, 0);
|
|
3252
|
-
const committedSelection = (0,
|
|
3403
|
+
const committedSelection = (0, import_react16.useMemo)(
|
|
3253
3404
|
() => currentVariant ? stepPicks.find((s) => s.variantId === currentVariant.id) ?? null : null,
|
|
3254
3405
|
[stepPicks, currentVariant]
|
|
3255
3406
|
);
|
|
3256
3407
|
const variantInStep = committedSelection !== null;
|
|
3257
3408
|
const committedQty = committedSelection?.quantity ?? 0;
|
|
3258
|
-
const productOtherUnits = (0,
|
|
3409
|
+
const productOtherUnits = (0, import_react16.useMemo)(() => {
|
|
3259
3410
|
if (!currentVariant) return 0;
|
|
3260
3411
|
let sum = 0;
|
|
3261
3412
|
for (let i = 0; i < selections.length; i++) {
|
|
@@ -3267,7 +3418,7 @@ function MultiStepPickerRow({
|
|
|
3267
3418
|
}
|
|
3268
3419
|
return sum;
|
|
3269
3420
|
}, [selections, product.id, currentVariant, stepIndex]);
|
|
3270
|
-
const variantOtherUnits = (0,
|
|
3421
|
+
const variantOtherUnits = (0, import_react16.useMemo)(() => {
|
|
3271
3422
|
if (!currentVariant) return 0;
|
|
3272
3423
|
let sum = 0;
|
|
3273
3424
|
for (const picks of selections) {
|
|
@@ -3278,24 +3429,27 @@ function MultiStepPickerRow({
|
|
|
3278
3429
|
return Math.max(0, sum - committedQty);
|
|
3279
3430
|
}, [selections, currentVariant, committedQty]);
|
|
3280
3431
|
const swapUnits = currentVariant ? swapUnitsFor?.(stepIndex, product.id, currentVariant.id) ?? 0 : 0;
|
|
3281
|
-
const inSwapState = swapUnits >=
|
|
3432
|
+
const inSwapState = swapUnits >= vRule.min;
|
|
3282
3433
|
const room = (0, import_core14.stepHeadroom)(step?.maxQuantity ?? null, unitsInStep);
|
|
3283
|
-
const productHeadroom =
|
|
3434
|
+
const productHeadroom = Math.min(
|
|
3435
|
+
rule.max - productOtherUnits,
|
|
3436
|
+
variantMax ?? Infinity
|
|
3437
|
+
);
|
|
3284
3438
|
const spotCeiling = inSwapState ? swapUnits : Math.min(
|
|
3285
3439
|
productHeadroom,
|
|
3286
3440
|
room === Number.POSITIVE_INFINITY ? productHeadroom : committedQty + room
|
|
3287
3441
|
);
|
|
3288
3442
|
const stockRemaining = currentVariant ? (0, import_core14.maxAddableQuantity)(currentVariant, Number.MAX_SAFE_INTEGER, variantOtherUnits) : 0;
|
|
3289
3443
|
const cap = Math.max(0, Math.min(spotCeiling, stockRemaining));
|
|
3290
|
-
const stepperMax = Math.max(
|
|
3291
|
-
const [qty, setQty] = (0,
|
|
3292
|
-
(0,
|
|
3293
|
-
setQty((prev) => Math.max(
|
|
3294
|
-
}, [stepperMax,
|
|
3444
|
+
const stepperMax = Math.max(vRule.min, cap);
|
|
3445
|
+
const [qty, setQty] = (0, import_react16.useState)(vRule.min);
|
|
3446
|
+
(0, import_react16.useEffect)(() => {
|
|
3447
|
+
setQty((prev) => Math.max(vRule.min, Math.min(prev, stepperMax)));
|
|
3448
|
+
}, [stepperMax, vRule.min]);
|
|
3295
3449
|
const currentVariantId = currentVariant?.id ?? null;
|
|
3296
|
-
(0,
|
|
3297
|
-
if (!variantInStep) setQty(
|
|
3298
|
-
}, [variantInStep, currentVariantId,
|
|
3450
|
+
(0, import_react16.useEffect)(() => {
|
|
3451
|
+
if (!variantInStep) setQty(vRule.min);
|
|
3452
|
+
}, [variantInStep, currentVariantId, vRule.min]);
|
|
3299
3453
|
if (!currentVariant || !step) return null;
|
|
3300
3454
|
const thumbImage = currentVariant.image ?? product.featuredImage ?? null;
|
|
3301
3455
|
const unitPriceText = (0, import_core14.formatUnitPrice)(
|
|
@@ -3303,8 +3457,8 @@ function MultiStepPickerRow({
|
|
|
3303
3457
|
currentVariant.unitPriceMeasurement,
|
|
3304
3458
|
currency
|
|
3305
3459
|
);
|
|
3306
|
-
const noStock = cap <
|
|
3307
|
-
const needsMoreSpots = !variantInStep && !inSwapState && room !== Number.POSITIVE_INFINITY &&
|
|
3460
|
+
const noStock = cap < vRule.min;
|
|
3461
|
+
const needsMoreSpots = !variantInStep && !inSwapState && room !== Number.POSITIVE_INFINITY && vRule.min > room;
|
|
3308
3462
|
const addDisabled = !variantInStep && (inSwapState ? noStock : noStock || needsMoreSpots);
|
|
3309
3463
|
const lockedRequired = variantInStep && currentVariant != null && !(canRemoveVariant?.(currentVariant.id) ?? true);
|
|
3310
3464
|
const stepperDisabled = isOos || !variantInStep && addDisabled;
|
|
@@ -3315,7 +3469,7 @@ function MultiStepPickerRow({
|
|
|
3315
3469
|
return;
|
|
3316
3470
|
}
|
|
3317
3471
|
if (!currentVariant || noStock) return;
|
|
3318
|
-
const pickedQty = showStepper ? qty :
|
|
3472
|
+
const pickedQty = showStepper ? qty : vRule.min;
|
|
3319
3473
|
const item = {
|
|
3320
3474
|
productId: product.id,
|
|
3321
3475
|
variantId: currentVariant.id,
|
|
@@ -3337,7 +3491,7 @@ function MultiStepPickerRow({
|
|
|
3337
3491
|
}
|
|
3338
3492
|
const priceCents = parseFloat(currentVariant.price.amount);
|
|
3339
3493
|
const compareCents = currentVariant.compareAtPrice ? parseFloat(currentVariant.compareAtPrice.amount) : null;
|
|
3340
|
-
return /* @__PURE__ */ (0,
|
|
3494
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
3341
3495
|
"div",
|
|
3342
3496
|
{
|
|
3343
3497
|
className: `lb-mix-match__modal-product${isOos ? " lb-mix-match__modal-product--sold-out" : ""}${variantInStep ? " lb-mix-match__modal-product--in-bundle" : ""}`,
|
|
@@ -3346,8 +3500,8 @@ function MultiStepPickerRow({
|
|
|
3346
3500
|
"data-type": product.productType ?? "",
|
|
3347
3501
|
"aria-disabled": isOos || void 0,
|
|
3348
3502
|
children: [
|
|
3349
|
-
/* @__PURE__ */ (0,
|
|
3350
|
-
thumbImage && /* @__PURE__ */ (0,
|
|
3503
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "lb-mix-match__modal-product-thumb", children: [
|
|
3504
|
+
thumbImage && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3351
3505
|
"img",
|
|
3352
3506
|
{
|
|
3353
3507
|
src: thumbImage.url,
|
|
@@ -3355,10 +3509,10 @@ function MultiStepPickerRow({
|
|
|
3355
3509
|
loading: "lazy"
|
|
3356
3510
|
}
|
|
3357
3511
|
),
|
|
3358
|
-
variantInStep && /* @__PURE__ */ (0,
|
|
3512
|
+
variantInStep && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "lb-mix-match__modal-added-badge", children: "Added" })
|
|
3359
3513
|
] }),
|
|
3360
|
-
/* @__PURE__ */ (0,
|
|
3361
|
-
/* @__PURE__ */ (0,
|
|
3514
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "lb-mix-match__modal-product-info", children: [
|
|
3515
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "lb-mix-match__modal-product-title", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3362
3516
|
"a",
|
|
3363
3517
|
{
|
|
3364
3518
|
href: `/products/${product.handle}`,
|
|
@@ -3367,24 +3521,24 @@ function MultiStepPickerRow({
|
|
|
3367
3521
|
children: product.title
|
|
3368
3522
|
}
|
|
3369
3523
|
) }),
|
|
3370
|
-
/* @__PURE__ */ (0,
|
|
3371
|
-
/* @__PURE__ */ (0,
|
|
3372
|
-
compareCents !== null && compareCents > priceCents && /* @__PURE__ */ (0,
|
|
3524
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("p", { className: "lb-mix-match__modal-product-price", children: [
|
|
3525
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { "data-row-price-sale": true, children: (0, import_core14.formatMoney)(priceCents, currency) }),
|
|
3526
|
+
compareCents !== null && compareCents > priceCents && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("s", { className: "lb-mix-match__modal-product-compare", "data-row-compare": true, children: (0, import_core14.formatMoney)(compareCents, currency) })
|
|
3373
3527
|
] }),
|
|
3374
|
-
unitPriceText && /* @__PURE__ */ (0,
|
|
3375
|
-
showPicker && /* @__PURE__ */ (0,
|
|
3528
|
+
unitPriceText && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "lb-mix-match__modal-product-unit-price lb-bundle-product-unit-price", children: unitPriceText }),
|
|
3529
|
+
showPicker && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "lb-bundle-variant-option-groups", children: optionNames.map((optionName, optionIndex) => {
|
|
3376
3530
|
const dropdownOptions = optionsFor(optionIndex).map((o) => ({
|
|
3377
3531
|
value: o.value,
|
|
3378
3532
|
label: o.value,
|
|
3379
3533
|
disabled: o.disabled
|
|
3380
3534
|
}));
|
|
3381
|
-
return /* @__PURE__ */ (0,
|
|
3535
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
3382
3536
|
"div",
|
|
3383
3537
|
{
|
|
3384
3538
|
className: "lb-bundle-variant-option-group",
|
|
3385
3539
|
children: [
|
|
3386
|
-
/* @__PURE__ */ (0,
|
|
3387
|
-
/* @__PURE__ */ (0,
|
|
3540
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "lb-bundle-variant-option-label", children: optionName }),
|
|
3541
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3388
3542
|
VariantDropdown,
|
|
3389
3543
|
{
|
|
3390
3544
|
className: "lb-mix-match__variant-select-dropdown",
|
|
@@ -3399,39 +3553,39 @@ function MultiStepPickerRow({
|
|
|
3399
3553
|
optionName
|
|
3400
3554
|
);
|
|
3401
3555
|
}) }),
|
|
3402
|
-
!showPicker && variants.length === 1 && currentVariant.title !== "Default Title" && /* @__PURE__ */ (0,
|
|
3403
|
-
!isOos && needsMoreSpots && room > 0 && /* @__PURE__ */ (0,
|
|
3404
|
-
isOos ? /* @__PURE__ */ (0,
|
|
3405
|
-
showStepper && /* @__PURE__ */ (0,
|
|
3556
|
+
!showPicker && variants.length === 1 && currentVariant.title !== "Default Title" && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "lb-mix-match__filled-variant", children: currentVariant.title }),
|
|
3557
|
+
!isOos && needsMoreSpots && room > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "lb-mix-match__modal-needs-spots", children: vRule.min === 1 ? "Needs 1 spot" : `Needs ${vRule.min} spots` }),
|
|
3558
|
+
isOos ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "lb-mix-match__modal-sold-out-label", children: "Sold out" }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "lb-mix-match__modal-product-actions", children: [
|
|
3559
|
+
showStepper && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "lb-bundle-variant-option-group lb-mix-match__qty-stepper-group", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
3406
3560
|
"div",
|
|
3407
3561
|
{
|
|
3408
3562
|
className: "lb-mix-match__qty-stepper",
|
|
3409
3563
|
role: "group",
|
|
3410
3564
|
"aria-label": "Quantity",
|
|
3411
3565
|
children: [
|
|
3412
|
-
/* @__PURE__ */ (0,
|
|
3566
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3413
3567
|
"button",
|
|
3414
3568
|
{
|
|
3415
3569
|
type: "button",
|
|
3416
3570
|
className: "lb-mix-match__qty-stepper-button lb-mix-match__qty-stepper-button--minus",
|
|
3417
3571
|
"aria-label": "Decrease quantity",
|
|
3418
|
-
disabled: stepperDisabled || shownQty <=
|
|
3572
|
+
disabled: stepperDisabled || shownQty <= vRule.min,
|
|
3419
3573
|
onClick: () => {
|
|
3420
3574
|
if (variantInStep && currentVariant) {
|
|
3421
3575
|
onUpdateQuantity(
|
|
3422
3576
|
stepIndex,
|
|
3423
3577
|
product.id,
|
|
3424
3578
|
currentVariant.id,
|
|
3425
|
-
Math.max(
|
|
3579
|
+
Math.max(vRule.min, committedQty - 1)
|
|
3426
3580
|
);
|
|
3427
3581
|
} else {
|
|
3428
|
-
setQty((q) => Math.max(
|
|
3582
|
+
setQty((q) => Math.max(vRule.min, q - 1));
|
|
3429
3583
|
}
|
|
3430
3584
|
},
|
|
3431
3585
|
children: "\u2212"
|
|
3432
3586
|
}
|
|
3433
3587
|
),
|
|
3434
|
-
/* @__PURE__ */ (0,
|
|
3588
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3435
3589
|
"span",
|
|
3436
3590
|
{
|
|
3437
3591
|
className: "lb-mix-match__qty-stepper-value",
|
|
@@ -3440,7 +3594,7 @@ function MultiStepPickerRow({
|
|
|
3440
3594
|
children: shownQty
|
|
3441
3595
|
}
|
|
3442
3596
|
),
|
|
3443
|
-
/* @__PURE__ */ (0,
|
|
3597
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3444
3598
|
"button",
|
|
3445
3599
|
{
|
|
3446
3600
|
type: "button",
|
|
@@ -3465,7 +3619,7 @@ function MultiStepPickerRow({
|
|
|
3465
3619
|
]
|
|
3466
3620
|
}
|
|
3467
3621
|
) }),
|
|
3468
|
-
/* @__PURE__ */ (0,
|
|
3622
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3469
3623
|
"button",
|
|
3470
3624
|
{
|
|
3471
3625
|
type: "button",
|
|
@@ -3484,7 +3638,7 @@ function MultiStepPickerRow({
|
|
|
3484
3638
|
);
|
|
3485
3639
|
}
|
|
3486
3640
|
function CloseIcon3() {
|
|
3487
|
-
return /* @__PURE__ */ (0,
|
|
3641
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
3488
3642
|
"svg",
|
|
3489
3643
|
{
|
|
3490
3644
|
width: "20",
|
|
@@ -3494,14 +3648,14 @@ function CloseIcon3() {
|
|
|
3494
3648
|
xmlns: "http://www.w3.org/2000/svg",
|
|
3495
3649
|
"aria-hidden": "true",
|
|
3496
3650
|
children: [
|
|
3497
|
-
/* @__PURE__ */ (0,
|
|
3498
|
-
/* @__PURE__ */ (0,
|
|
3651
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "5", y1: "5", x2: "15", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
|
|
3652
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "15", y1: "5", x2: "5", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
|
|
3499
3653
|
]
|
|
3500
3654
|
}
|
|
3501
3655
|
);
|
|
3502
3656
|
}
|
|
3503
3657
|
function SearchClearIcon2() {
|
|
3504
|
-
return /* @__PURE__ */ (0,
|
|
3658
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3505
3659
|
"svg",
|
|
3506
3660
|
{
|
|
3507
3661
|
width: "16",
|
|
@@ -3510,17 +3664,25 @@ function SearchClearIcon2() {
|
|
|
3510
3664
|
fill: "currentColor",
|
|
3511
3665
|
xmlns: "http://www.w3.org/2000/svg",
|
|
3512
3666
|
"aria-hidden": "true",
|
|
3513
|
-
children: /* @__PURE__ */ (0,
|
|
3667
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("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" })
|
|
3514
3668
|
}
|
|
3515
3669
|
);
|
|
3516
3670
|
}
|
|
3517
3671
|
|
|
3518
3672
|
// src/components/MultiStepBundle.tsx
|
|
3519
|
-
var
|
|
3520
|
-
function ruleFor4(bundle, productId) {
|
|
3673
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
3674
|
+
function ruleFor4(bundle, productId, variantId) {
|
|
3675
|
+
if (variantId) {
|
|
3676
|
+
const vRule = bundle.variantRules[variantId];
|
|
3677
|
+
if (vRule) return vRule;
|
|
3678
|
+
}
|
|
3521
3679
|
return bundle.productRules[productId] ?? import_core15.DEFAULT_PRODUCT_RULE;
|
|
3522
3680
|
}
|
|
3681
|
+
function variantRuleFor4(bundle, variantId) {
|
|
3682
|
+
return variantId ? bundle.variantRules[variantId] : void 0;
|
|
3683
|
+
}
|
|
3523
3684
|
function canRemoveItem2(bundle, selections, item) {
|
|
3685
|
+
if (variantRuleFor4(bundle, item.variantId)?.required) return false;
|
|
3524
3686
|
const rule = ruleFor4(bundle, item.productId);
|
|
3525
3687
|
if (!rule.required) return true;
|
|
3526
3688
|
let unitsElsewhere = 0;
|
|
@@ -3567,14 +3729,14 @@ function MultiStepBundle(props) {
|
|
|
3567
3729
|
bundleType: "multi_step",
|
|
3568
3730
|
enabled: analyticsEnabled !== false
|
|
3569
3731
|
});
|
|
3570
|
-
const [selections, setSelections] = (0,
|
|
3571
|
-
const [pickerOpenAt, setPickerOpenAt] = (0,
|
|
3572
|
-
const [addingToCart, setAddingToCart] = (0,
|
|
3573
|
-
const [cartError, setCartError] = (0,
|
|
3732
|
+
const [selections, setSelections] = (0, import_react17.useState)([]);
|
|
3733
|
+
const [pickerOpenAt, setPickerOpenAt] = (0, import_react17.useState)(null);
|
|
3734
|
+
const [addingToCart, setAddingToCart] = (0, import_react17.useState)(false);
|
|
3735
|
+
const [cartError, setCartError] = (0, import_react17.useState)(null);
|
|
3574
3736
|
const bundle = result.status === "success" && result.bundle.bundleType === "multi_step" ? result.bundle : null;
|
|
3575
3737
|
const setConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);
|
|
3576
3738
|
const setModalConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);
|
|
3577
|
-
(0,
|
|
3739
|
+
(0, import_react17.useEffect)(() => {
|
|
3578
3740
|
if (result.status === "error") {
|
|
3579
3741
|
onError?.(result.error);
|
|
3580
3742
|
return;
|
|
@@ -3587,8 +3749,8 @@ function MultiStepBundle(props) {
|
|
|
3587
3749
|
);
|
|
3588
3750
|
}
|
|
3589
3751
|
}, [result, onError]);
|
|
3590
|
-
const steps = (0,
|
|
3591
|
-
(0,
|
|
3752
|
+
const steps = (0, import_react17.useMemo)(() => bundle?.steps ?? [], [bundle]);
|
|
3753
|
+
(0, import_react17.useEffect)(() => {
|
|
3592
3754
|
const seeded = steps.map(() => []);
|
|
3593
3755
|
if (bundle) {
|
|
3594
3756
|
const seedCurrency = bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? "USD";
|
|
@@ -3623,26 +3785,26 @@ function MultiStepBundle(props) {
|
|
|
3623
3785
|
setSelections(seeded);
|
|
3624
3786
|
}, [bundle, steps]);
|
|
3625
3787
|
const showStepper = bundle?.widgetConfig.mixMatchShowQuantitySelector !== false;
|
|
3626
|
-
const totalMin = (0,
|
|
3788
|
+
const totalMin = (0, import_react17.useMemo)(
|
|
3627
3789
|
() => steps.reduce((sum, s) => sum + s.minQuantity, 0),
|
|
3628
3790
|
[steps]
|
|
3629
3791
|
);
|
|
3630
|
-
const unitsByStep = (0,
|
|
3792
|
+
const unitsByStep = (0, import_react17.useMemo)(
|
|
3631
3793
|
() => selections.map((picks) => picks.reduce((sum, s) => sum + s.quantity, 0)),
|
|
3632
3794
|
[selections]
|
|
3633
3795
|
);
|
|
3634
|
-
const totalQuantity = (0,
|
|
3796
|
+
const totalQuantity = (0, import_react17.useMemo)(
|
|
3635
3797
|
() => unitsByStep.reduce((sum, u) => sum + u, 0),
|
|
3636
3798
|
[unitsByStep]
|
|
3637
3799
|
);
|
|
3638
|
-
const stepSatisfied = (0,
|
|
3800
|
+
const stepSatisfied = (0, import_react17.useCallback)(
|
|
3639
3801
|
(i) => (unitsByStep[i] ?? 0) >= (steps[i]?.minQuantity ?? 1),
|
|
3640
3802
|
[unitsByStep, steps]
|
|
3641
3803
|
);
|
|
3642
3804
|
const allSatisfied = steps.length > 0 && steps.every((_, i) => stepSatisfied(i));
|
|
3643
3805
|
const valid = !!bundle && allSatisfied;
|
|
3644
3806
|
const completedSteps = steps.filter((_, i) => stepSatisfied(i)).length;
|
|
3645
|
-
const summary = (0,
|
|
3807
|
+
const summary = (0, import_react17.useMemo)(() => {
|
|
3646
3808
|
let comparePrice = 0;
|
|
3647
3809
|
let salePrice = 0;
|
|
3648
3810
|
for (const stepPicks of selections) {
|
|
@@ -3662,7 +3824,7 @@ function MultiStepBundle(props) {
|
|
|
3662
3824
|
const savingsPercent = comparePrice > 0 && savings > 0 ? Math.round(savings / comparePrice * 100) : 0;
|
|
3663
3825
|
return { comparePrice, salePrice, savings, savingsPercent };
|
|
3664
3826
|
}, [selections, bundle]);
|
|
3665
|
-
const addSelection = (0,
|
|
3827
|
+
const addSelection = (0, import_react17.useCallback)((step, item) => {
|
|
3666
3828
|
setSelections((prev) => {
|
|
3667
3829
|
if (step < 0 || step >= prev.length) return prev;
|
|
3668
3830
|
if (prev[step].some((s) => s.variantId === item.variantId)) return prev;
|
|
@@ -3671,7 +3833,7 @@ function MultiStepBundle(props) {
|
|
|
3671
3833
|
return next;
|
|
3672
3834
|
});
|
|
3673
3835
|
}, []);
|
|
3674
|
-
const swapSelection = (0,
|
|
3836
|
+
const swapSelection = (0, import_react17.useCallback)(
|
|
3675
3837
|
(step, item) => {
|
|
3676
3838
|
setSelections((prev) => {
|
|
3677
3839
|
if (!bundle || step < 0 || step >= prev.length) return prev;
|
|
@@ -3706,7 +3868,7 @@ function MultiStepBundle(props) {
|
|
|
3706
3868
|
},
|
|
3707
3869
|
[bundle]
|
|
3708
3870
|
);
|
|
3709
|
-
const updateQuantity = (0,
|
|
3871
|
+
const updateQuantity = (0, import_react17.useCallback)(
|
|
3710
3872
|
(step, productId, variantId, quantity) => {
|
|
3711
3873
|
setSelections((prev) => {
|
|
3712
3874
|
if (step < 0 || step >= prev.length) return prev;
|
|
@@ -3725,7 +3887,7 @@ function MultiStepBundle(props) {
|
|
|
3725
3887
|
},
|
|
3726
3888
|
[]
|
|
3727
3889
|
);
|
|
3728
|
-
const removeVariant = (0,
|
|
3890
|
+
const removeVariant = (0, import_react17.useCallback)(
|
|
3729
3891
|
(step, variantId) => {
|
|
3730
3892
|
setSelections((prev) => {
|
|
3731
3893
|
if (step < 0 || step >= prev.length) return prev;
|
|
@@ -3741,7 +3903,7 @@ function MultiStepBundle(props) {
|
|
|
3741
3903
|
},
|
|
3742
3904
|
[bundle]
|
|
3743
3905
|
);
|
|
3744
|
-
const removeSlot = (0,
|
|
3906
|
+
const removeSlot = (0, import_react17.useCallback)(
|
|
3745
3907
|
(step, index) => {
|
|
3746
3908
|
setSelections((prev) => {
|
|
3747
3909
|
if (step < 0 || step >= prev.length) return prev;
|
|
@@ -3757,7 +3919,7 @@ function MultiStepBundle(props) {
|
|
|
3757
3919
|
},
|
|
3758
3920
|
[bundle]
|
|
3759
3921
|
);
|
|
3760
|
-
const handleAddToCart = (0,
|
|
3922
|
+
const handleAddToCart = (0, import_react17.useCallback)(async () => {
|
|
3761
3923
|
if (!bundle || !valid) return;
|
|
3762
3924
|
const grouped = /* @__PURE__ */ new Map();
|
|
3763
3925
|
for (const stepPicks of selections) {
|
|
@@ -3798,9 +3960,9 @@ function MultiStepBundle(props) {
|
|
|
3798
3960
|
}
|
|
3799
3961
|
}, [bundle, selections, valid, onAddToCart, onError, trackAddToCart, totalQuantity, steps]);
|
|
3800
3962
|
if (result.status === "loading") {
|
|
3801
|
-
return /* @__PURE__ */ (0,
|
|
3802
|
-
/* @__PURE__ */ (0,
|
|
3803
|
-
/* @__PURE__ */ (0,
|
|
3963
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: `lb-bundle lb-bundle--loading ${className ?? ""}`, children: [
|
|
3964
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "lb-skeleton lb-skeleton--title" }),
|
|
3965
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "lb-skeleton lb-skeleton--products" })
|
|
3804
3966
|
] });
|
|
3805
3967
|
}
|
|
3806
3968
|
if (result.status === "error") return null;
|
|
@@ -3821,7 +3983,7 @@ function MultiStepBundle(props) {
|
|
|
3821
3983
|
if (requiredBlocked) return null;
|
|
3822
3984
|
const currency = bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? "USD";
|
|
3823
3985
|
const ctaLabel = addingToCart ? "Adding..." : bundle.widgetConfig.cta.ctaText || "Add to cart";
|
|
3824
|
-
return /* @__PURE__ */ (0,
|
|
3986
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
3825
3987
|
"div",
|
|
3826
3988
|
{
|
|
3827
3989
|
ref: (el) => {
|
|
@@ -3833,12 +3995,19 @@ function MultiStepBundle(props) {
|
|
|
3833
3995
|
"aria-label": bundle.title,
|
|
3834
3996
|
"data-required-quantity": totalMin,
|
|
3835
3997
|
children: [
|
|
3836
|
-
/* @__PURE__ */ (0,
|
|
3837
|
-
/* @__PURE__ */ (0,
|
|
3838
|
-
bundle.description && /* @__PURE__ */ (0,
|
|
3998
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "lb-bundle-header", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "lb-bundle-header__content", children: [
|
|
3999
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h3", { className: "lb-bundle-title", children: bundle.title }),
|
|
4000
|
+
bundle.description && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "lb-bundle-subtitle", children: bundle.description })
|
|
3839
4001
|
] }) }),
|
|
3840
|
-
/* @__PURE__ */ (0,
|
|
3841
|
-
|
|
4002
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4003
|
+
BundleCountdown,
|
|
4004
|
+
{
|
|
4005
|
+
endsAt: bundle.endsAt,
|
|
4006
|
+
widgetConfig: bundle.widgetConfig
|
|
4007
|
+
}
|
|
4008
|
+
),
|
|
4009
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "lb-mix-match__progress", "data-progress": true, children: [
|
|
4010
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
3842
4011
|
"div",
|
|
3843
4012
|
{
|
|
3844
4013
|
className: "lb-mix-match__progress-segments",
|
|
@@ -3846,7 +4015,7 @@ function MultiStepBundle(props) {
|
|
|
3846
4015
|
"aria-valuenow": completedSteps,
|
|
3847
4016
|
"aria-valuemin": 0,
|
|
3848
4017
|
"aria-valuemax": steps.length,
|
|
3849
|
-
children: Array.from({ length: steps.length }).map((_, i) => /* @__PURE__ */ (0,
|
|
4018
|
+
children: Array.from({ length: steps.length }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
3850
4019
|
"span",
|
|
3851
4020
|
{
|
|
3852
4021
|
className: `lb-mix-match__progress-segment${i < completedSteps ? " lb-mix-match__progress-segment--filled" : ""}`,
|
|
@@ -3856,8 +4025,8 @@ function MultiStepBundle(props) {
|
|
|
3856
4025
|
))
|
|
3857
4026
|
}
|
|
3858
4027
|
),
|
|
3859
|
-
/* @__PURE__ */ (0,
|
|
3860
|
-
/* @__PURE__ */ (0,
|
|
4028
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "lb-mix-match__progress-labels", children: [
|
|
4029
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
3861
4030
|
"span",
|
|
3862
4031
|
{
|
|
3863
4032
|
className: "lb-mix-match__progress-count",
|
|
@@ -3866,7 +4035,7 @@ function MultiStepBundle(props) {
|
|
|
3866
4035
|
children: `${completedSteps} of ${steps.length} steps completed`
|
|
3867
4036
|
}
|
|
3868
4037
|
),
|
|
3869
|
-
/* @__PURE__ */ (0,
|
|
4038
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
3870
4039
|
"span",
|
|
3871
4040
|
{
|
|
3872
4041
|
className: "lb-mix-match__progress-remaining",
|
|
@@ -3877,15 +4046,15 @@ function MultiStepBundle(props) {
|
|
|
3877
4046
|
)
|
|
3878
4047
|
] })
|
|
3879
4048
|
] }),
|
|
3880
|
-
/* @__PURE__ */ (0,
|
|
4049
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "lb-multi-step__groups", "data-step-groups": true, children: steps.map((step, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
3881
4050
|
"section",
|
|
3882
4051
|
{
|
|
3883
4052
|
className: "lb-multi-step__group",
|
|
3884
4053
|
"data-step-group": i,
|
|
3885
4054
|
children: [
|
|
3886
|
-
/* @__PURE__ */ (0,
|
|
3887
|
-
/* @__PURE__ */ (0,
|
|
3888
|
-
/* @__PURE__ */ (0,
|
|
4055
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "lb-multi-step__group-heading", children: [
|
|
4056
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "lb-multi-step__group-name", children: step.name }),
|
|
4057
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
3889
4058
|
"span",
|
|
3890
4059
|
{
|
|
3891
4060
|
className: `lb-multi-step__group-count${stepSatisfied(i) ? " lb-multi-step__group-count--met" : ""}`,
|
|
@@ -3894,7 +4063,7 @@ function MultiStepBundle(props) {
|
|
|
3894
4063
|
}
|
|
3895
4064
|
)
|
|
3896
4065
|
] }),
|
|
3897
|
-
/* @__PURE__ */ (0,
|
|
4066
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
3898
4067
|
"div",
|
|
3899
4068
|
{
|
|
3900
4069
|
className: "lb-mix-match__slots lb-edge-fade lb-multi-step__group-slots",
|
|
@@ -3904,13 +4073,13 @@ function MultiStepBundle(props) {
|
|
|
3904
4073
|
title button provides the keyboard/AT path (its
|
|
3905
4074
|
activation bubbles here); × stops propagation. */
|
|
3906
4075
|
// 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
|
|
3907
|
-
/* @__PURE__ */ (0,
|
|
4076
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
3908
4077
|
"div",
|
|
3909
4078
|
{
|
|
3910
4079
|
className: "lb-mix-match__slot lb-mix-match__slot--filled",
|
|
3911
4080
|
onClick: () => setPickerOpenAt(i),
|
|
3912
4081
|
children: [
|
|
3913
|
-
item.featuredImage && /* @__PURE__ */ (0,
|
|
4082
|
+
item.featuredImage && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "lb-bundle-thumbnail", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
3914
4083
|
"img",
|
|
3915
4084
|
{
|
|
3916
4085
|
src: item.featuredImage,
|
|
@@ -3918,8 +4087,8 @@ function MultiStepBundle(props) {
|
|
|
3918
4087
|
loading: "lazy"
|
|
3919
4088
|
}
|
|
3920
4089
|
) }),
|
|
3921
|
-
/* @__PURE__ */ (0,
|
|
3922
|
-
/* @__PURE__ */ (0,
|
|
4090
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "lb-mix-match__filled-info", children: [
|
|
4091
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
3923
4092
|
"button",
|
|
3924
4093
|
{
|
|
3925
4094
|
type: "button",
|
|
@@ -3928,15 +4097,15 @@ function MultiStepBundle(props) {
|
|
|
3928
4097
|
children: item.title
|
|
3929
4098
|
}
|
|
3930
4099
|
),
|
|
3931
|
-
item.variantTitle && item.variantTitle !== "Default Title" && /* @__PURE__ */ (0,
|
|
3932
|
-
/* @__PURE__ */ (0,
|
|
3933
|
-
item.compareAtPrice !== null && item.compareAtPrice > item.price && /* @__PURE__ */ (0,
|
|
3934
|
-
/* @__PURE__ */ (0,
|
|
3935
|
-
/* @__PURE__ */ (0,
|
|
4100
|
+
item.variantTitle && item.variantTitle !== "Default Title" && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "lb-mix-match__filled-variant", children: item.variantTitle }),
|
|
4101
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "lb-mix-match__filled-price", children: [
|
|
4102
|
+
item.compareAtPrice !== null && item.compareAtPrice > item.price && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("s", { className: "lb-mix-match__filled-compare", children: (0, import_core15.formatMoney)(item.compareAtPrice, currency) }),
|
|
4103
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "lb-bundle-product-price", children: (0, import_core15.formatMoney)(item.price, currency) }),
|
|
4104
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "lb-bundle-qty-inline", children: `\xD7${item.quantity}` })
|
|
3936
4105
|
] }),
|
|
3937
|
-
item.unitPrice && /* @__PURE__ */ (0,
|
|
4106
|
+
item.unitPrice && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "lb-bundle-product-unit-price", children: item.unitPrice })
|
|
3938
4107
|
] }),
|
|
3939
|
-
canRemoveItem2(bundle, selections, item) ? /* @__PURE__ */ (0,
|
|
4108
|
+
canRemoveItem2(bundle, selections, item) ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
3940
4109
|
"button",
|
|
3941
4110
|
{
|
|
3942
4111
|
type: "button",
|
|
@@ -3946,13 +4115,13 @@ function MultiStepBundle(props) {
|
|
|
3946
4115
|
e.stopPropagation();
|
|
3947
4116
|
removeSlot(i, index);
|
|
3948
4117
|
},
|
|
3949
|
-
children: /* @__PURE__ */ (0,
|
|
4118
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CloseIcon4, {})
|
|
3950
4119
|
}
|
|
3951
4120
|
) : (
|
|
3952
4121
|
/* Required pick at its floor — quiet state chip instead
|
|
3953
4122
|
of the ×; removal returns once another slot covers
|
|
3954
4123
|
the product's minimum (variant swap flow). */
|
|
3955
|
-
/* @__PURE__ */ (0,
|
|
4124
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "lb-mix-match__slot-required", children: "Required" })
|
|
3956
4125
|
)
|
|
3957
4126
|
]
|
|
3958
4127
|
},
|
|
@@ -3961,7 +4130,7 @@ function MultiStepBundle(props) {
|
|
|
3961
4130
|
))
|
|
3962
4131
|
}
|
|
3963
4132
|
),
|
|
3964
|
-
(0, import_core15.stepHeadroom)(step.maxQuantity, unitsByStep[i] ?? 0) !== 0 && /* @__PURE__ */ (0,
|
|
4133
|
+
(0, import_core15.stepHeadroom)(step.maxQuantity, unitsByStep[i] ?? 0) !== 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
3965
4134
|
"button",
|
|
3966
4135
|
{
|
|
3967
4136
|
type: "button",
|
|
@@ -3970,15 +4139,15 @@ function MultiStepBundle(props) {
|
|
|
3970
4139
|
"aria-label": `${step.minQuantity === 1 && step.maxQuantity === 1 ? "Choose a product" : "Choose products"}: ${step.name}`,
|
|
3971
4140
|
onClick: () => setPickerOpenAt(i),
|
|
3972
4141
|
children: [
|
|
3973
|
-
/* @__PURE__ */ (0,
|
|
4142
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
3974
4143
|
"span",
|
|
3975
4144
|
{
|
|
3976
4145
|
className: "lb-mix-match__add-product-icon",
|
|
3977
4146
|
"aria-hidden": "true",
|
|
3978
|
-
children: /* @__PURE__ */ (0,
|
|
4147
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PlusIcon2, {})
|
|
3979
4148
|
}
|
|
3980
4149
|
),
|
|
3981
|
-
/* @__PURE__ */ (0,
|
|
4150
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "lb-mix-match__add-product-label", children: step.minQuantity === 1 && step.maxQuantity === 1 ? "Choose a product" : "Choose products" })
|
|
3982
4151
|
]
|
|
3983
4152
|
}
|
|
3984
4153
|
)
|
|
@@ -3986,29 +4155,29 @@ function MultiStepBundle(props) {
|
|
|
3986
4155
|
},
|
|
3987
4156
|
i
|
|
3988
4157
|
)) }),
|
|
3989
|
-
/* @__PURE__ */ (0,
|
|
3990
|
-
allSatisfied && /* @__PURE__ */ (0,
|
|
3991
|
-
/* @__PURE__ */ (0,
|
|
3992
|
-
/* @__PURE__ */ (0,
|
|
3993
|
-
bundle.widgetConfig.savingsBar.visible && summary.savings > 0 && /* @__PURE__ */ (0,
|
|
4158
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "lb-bundle-divider" }),
|
|
4159
|
+
allSatisfied && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "lb-bundle-summary", "data-pricing-section": true, children: [
|
|
4160
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "lb-bundle-summary__text", children: [
|
|
4161
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "lb-bundle-summary__label", children: "Bundle total" }),
|
|
4162
|
+
bundle.widgetConfig.savingsBar.visible && summary.savings > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("p", { className: "lb-bundle-savings-line", "data-savings-bar": true, children: [
|
|
3994
4163
|
"You save",
|
|
3995
4164
|
" ",
|
|
3996
|
-
/* @__PURE__ */ (0,
|
|
4165
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { "data-savings-amount": true, children: (0, import_core15.formatMoney)(summary.savings, currency) }),
|
|
3997
4166
|
" ",
|
|
3998
|
-
/* @__PURE__ */ (0,
|
|
4167
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { "data-savings-percent": true, children: [
|
|
3999
4168
|
"(",
|
|
4000
4169
|
summary.savingsPercent,
|
|
4001
4170
|
"%)"
|
|
4002
4171
|
] })
|
|
4003
4172
|
] })
|
|
4004
4173
|
] }),
|
|
4005
|
-
/* @__PURE__ */ (0,
|
|
4006
|
-
bundle.widgetConfig.pricing.showComparePrice && summary.savings > 0 && /* @__PURE__ */ (0,
|
|
4007
|
-
/* @__PURE__ */ (0,
|
|
4174
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "lb-bundle-summary__prices", children: [
|
|
4175
|
+
bundle.widgetConfig.pricing.showComparePrice && summary.savings > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "lb-bundle-compare-price", "data-compare-price": true, children: (0, import_core15.formatMoney)(summary.comparePrice, currency) }),
|
|
4176
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "lb-bundle-sale-price", "data-sale-price": true, children: (0, import_core15.formatMoney)(summary.salePrice, currency) })
|
|
4008
4177
|
] })
|
|
4009
4178
|
] }),
|
|
4010
|
-
cartError && /* @__PURE__ */ (0,
|
|
4011
|
-
/* @__PURE__ */ (0,
|
|
4179
|
+
cartError && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "lb-bundle__error", role: "alert", children: cartError }),
|
|
4180
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4012
4181
|
"button",
|
|
4013
4182
|
{
|
|
4014
4183
|
className: "lb-bundle__cta",
|
|
@@ -4018,7 +4187,7 @@ function MultiStepBundle(props) {
|
|
|
4018
4187
|
children: ctaLabel
|
|
4019
4188
|
}
|
|
4020
4189
|
),
|
|
4021
|
-
pickerOpenAt !== null && /* @__PURE__ */ (0,
|
|
4190
|
+
pickerOpenAt !== null && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4022
4191
|
MultiStepPicker,
|
|
4023
4192
|
{
|
|
4024
4193
|
outOfStockBehavior,
|
|
@@ -4054,7 +4223,7 @@ function stepHasInStockProduct(bundle, stepIndex) {
|
|
|
4054
4223
|
});
|
|
4055
4224
|
}
|
|
4056
4225
|
function PlusIcon2() {
|
|
4057
|
-
return /* @__PURE__ */ (0,
|
|
4226
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
4058
4227
|
"svg",
|
|
4059
4228
|
{
|
|
4060
4229
|
width: "18",
|
|
@@ -4064,14 +4233,14 @@ function PlusIcon2() {
|
|
|
4064
4233
|
xmlns: "http://www.w3.org/2000/svg",
|
|
4065
4234
|
"aria-hidden": "true",
|
|
4066
4235
|
children: [
|
|
4067
|
-
/* @__PURE__ */ (0,
|
|
4068
|
-
/* @__PURE__ */ (0,
|
|
4236
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "9", y1: "3", x2: "9", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
|
|
4237
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "3", y1: "9", x2: "15", y2: "9", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
|
|
4069
4238
|
]
|
|
4070
4239
|
}
|
|
4071
4240
|
);
|
|
4072
4241
|
}
|
|
4073
4242
|
function CloseIcon4() {
|
|
4074
|
-
return /* @__PURE__ */ (0,
|
|
4243
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
4075
4244
|
"svg",
|
|
4076
4245
|
{
|
|
4077
4246
|
width: "16",
|
|
@@ -4081,8 +4250,8 @@ function CloseIcon4() {
|
|
|
4081
4250
|
xmlns: "http://www.w3.org/2000/svg",
|
|
4082
4251
|
"aria-hidden": "true",
|
|
4083
4252
|
children: [
|
|
4084
|
-
/* @__PURE__ */ (0,
|
|
4085
|
-
/* @__PURE__ */ (0,
|
|
4253
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "5", y1: "5", x2: "15", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
|
|
4254
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "15", y1: "5", x2: "5", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
|
|
4086
4255
|
]
|
|
4087
4256
|
}
|
|
4088
4257
|
);
|
|
@@ -4095,7 +4264,7 @@ async function fetchShopCustomCss(options) {
|
|
|
4095
4264
|
}
|
|
4096
4265
|
|
|
4097
4266
|
// src/hooks/useBundlesForProduct.ts
|
|
4098
|
-
var
|
|
4267
|
+
var import_react18 = require("react");
|
|
4099
4268
|
var import_core16 = require("@lime-bundles/core");
|
|
4100
4269
|
var INITIAL_STATE2 = {
|
|
4101
4270
|
status: "loading",
|
|
@@ -4103,10 +4272,10 @@ var INITIAL_STATE2 = {
|
|
|
4103
4272
|
error: null
|
|
4104
4273
|
};
|
|
4105
4274
|
function useBundlesForProduct(options) {
|
|
4106
|
-
const [state, setState] = (0,
|
|
4275
|
+
const [state, setState] = (0, import_react18.useState)(
|
|
4107
4276
|
INITIAL_STATE2
|
|
4108
4277
|
);
|
|
4109
|
-
(0,
|
|
4278
|
+
(0, import_react18.useEffect)(() => {
|
|
4110
4279
|
const controller = new AbortController();
|
|
4111
4280
|
setState(INITIAL_STATE2);
|
|
4112
4281
|
(0, import_core16.fetchBundlesForProduct)({
|
|
@@ -4155,6 +4324,7 @@ var import_core18 = require("@lime-bundles/core");
|
|
|
4155
4324
|
BUNDLES_FOR_PRODUCT_QUERY,
|
|
4156
4325
|
BUNDLE_METAOBJECT_QUERY,
|
|
4157
4326
|
BogoBundle,
|
|
4327
|
+
BundleCountdown,
|
|
4158
4328
|
BundleParseError,
|
|
4159
4329
|
DEFAULT_OUT_OF_STOCK_BEHAVIOR,
|
|
4160
4330
|
FixedBundle,
|