@lime-bundles/react 6.1.0 → 7.0.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 +673 -543
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -42
- package/dist/index.d.ts +35 -42
- package/dist/index.js +589 -460
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1929 -0
- package/docs/hydrogen.md +28 -3
- package/docs/react-nextjs.md +23 -3
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -20,62 +20,60 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
-
BUNDLES_FOR_PRODUCT_QUERY: () =>
|
|
24
|
-
BUNDLE_METAOBJECT_QUERY: () =>
|
|
23
|
+
BUNDLES_FOR_PRODUCT_QUERY: () => import_core17.BUNDLES_FOR_PRODUCT_QUERY,
|
|
24
|
+
BUNDLE_METAOBJECT_QUERY: () => import_core17.BUNDLE_METAOBJECT_QUERY,
|
|
25
25
|
BogoBundle: () => BogoBundle,
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
BundleCountdown: () => BundleCountdown,
|
|
27
|
+
BundleParseError: () => import_core16.BundleParseError,
|
|
28
28
|
FixedBundle: () => FixedBundle,
|
|
29
29
|
MixMatchBundle: () => MixMatchBundle,
|
|
30
30
|
MultiStepBundle: () => MultiStepBundle,
|
|
31
|
-
SHOP_SETTINGS_QUERY: () =>
|
|
32
|
-
StorefrontApiError: () =>
|
|
31
|
+
SHOP_SETTINGS_QUERY: () => import_core17.SHOP_SETTINGS_QUERY,
|
|
32
|
+
StorefrontApiError: () => import_core16.StorefrontApiError,
|
|
33
33
|
VariantDropdown: () => VariantDropdown,
|
|
34
34
|
VolumeBundle: () => VolumeBundle,
|
|
35
|
-
WIDGET_CONFIG_DEFAULTS: () =>
|
|
36
|
-
applyWidgetConfigVars: () =>
|
|
37
|
-
calculateDiscount: () =>
|
|
38
|
-
calculateTierSavings: () =>
|
|
39
|
-
computeBundleSaleCents: () =>
|
|
40
|
-
computeFixedPricing: () =>
|
|
41
|
-
createStorefrontClient: () =>
|
|
35
|
+
WIDGET_CONFIG_DEFAULTS: () => import_core17.WIDGET_CONFIG_DEFAULTS,
|
|
36
|
+
applyWidgetConfigVars: () => import_core17.applyWidgetConfigVars,
|
|
37
|
+
calculateDiscount: () => import_core17.calculateDiscount,
|
|
38
|
+
calculateTierSavings: () => import_core17.calculateTierSavings,
|
|
39
|
+
computeBundleSaleCents: () => import_core17.computeBundleSaleCents,
|
|
40
|
+
computeFixedPricing: () => import_core17.computeFixedPricing,
|
|
41
|
+
createStorefrontClient: () => import_core17.createStorefrontClient,
|
|
42
42
|
fetchBundleData: () => fetchBundleData,
|
|
43
|
-
fetchBundlesForProduct: () =>
|
|
43
|
+
fetchBundlesForProduct: () => import_core17.fetchBundlesForProduct,
|
|
44
44
|
fetchShopCustomCss: () => fetchShopCustomCss,
|
|
45
45
|
fetchShopSettings: () => fetchShopSettings,
|
|
46
46
|
fetchShopSettingsOrDefault: () => fetchShopSettingsOrDefault,
|
|
47
|
-
formatCents: () =>
|
|
48
|
-
formatCountdown: () =>
|
|
49
|
-
formatMoney: () =>
|
|
50
|
-
formatUnitPrice: () =>
|
|
51
|
-
getActiveTier: () =>
|
|
52
|
-
injectCustomCss: () =>
|
|
53
|
-
mergeWidgetConfig: () =>
|
|
54
|
-
observeImpression: () =>
|
|
55
|
-
parseCents: () =>
|
|
56
|
-
parseMetaobjectBundle: () =>
|
|
57
|
-
parseMetaobjectBundleStrict: () =>
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
transformImageUrl: () => import_core18.transformImageUrl,
|
|
47
|
+
formatCents: () => import_core17.formatCents,
|
|
48
|
+
formatCountdown: () => import_core17.formatCountdown,
|
|
49
|
+
formatMoney: () => import_core17.formatMoney,
|
|
50
|
+
formatUnitPrice: () => import_core17.formatUnitPrice,
|
|
51
|
+
getActiveTier: () => import_core17.getActiveTier,
|
|
52
|
+
injectCustomCss: () => import_core17.injectCustomCss,
|
|
53
|
+
mergeWidgetConfig: () => import_core17.mergeWidgetConfig,
|
|
54
|
+
observeImpression: () => import_core17.observeImpression,
|
|
55
|
+
parseCents: () => import_core17.parseCents,
|
|
56
|
+
parseMetaobjectBundle: () => import_core17.parseMetaobjectBundle,
|
|
57
|
+
parseMetaobjectBundleStrict: () => import_core17.parseMetaobjectBundleStrict,
|
|
58
|
+
percentageDiscountUnit: () => import_core17.percentageDiscountUnit,
|
|
59
|
+
productsForStep: () => import_core17.productsForStep,
|
|
60
|
+
reportAddToCart: () => import_core17.reportAddToCart,
|
|
61
|
+
reportImpression: () => import_core17.reportImpression,
|
|
62
|
+
sanitizeCustomCss: () => import_core17.sanitizeCustomCss,
|
|
63
|
+
stepHeadroom: () => import_core17.stepHeadroom,
|
|
64
|
+
thumbnailRatioVars: () => import_core17.thumbnailRatioVars,
|
|
65
|
+
transformImageUrl: () => import_core17.transformImageUrl,
|
|
67
66
|
useAnalytics: () => useAnalytics,
|
|
68
67
|
useBundleData: () => useBundleData,
|
|
69
68
|
useBundlesForProduct: () => useBundlesForProduct,
|
|
70
|
-
useShopSettings: () => useShopSettings,
|
|
71
69
|
useVariantSelection: () => useVariantSelection,
|
|
72
70
|
useWidgetConfigVars: () => useWidgetConfigVars,
|
|
73
|
-
validateQuantity: () =>
|
|
71
|
+
validateQuantity: () => import_core17.validateQuantity
|
|
74
72
|
});
|
|
75
73
|
module.exports = __toCommonJS(index_exports);
|
|
76
74
|
|
|
77
75
|
// src/components/FixedBundle.tsx
|
|
78
|
-
var
|
|
76
|
+
var import_react8 = require("react");
|
|
79
77
|
var import_core8 = require("@lime-bundles/core");
|
|
80
78
|
|
|
81
79
|
// src/hooks/useBundleData.ts
|
|
@@ -140,8 +138,7 @@ async function fetchBundleDataWithWarnings(options) {
|
|
|
140
138
|
// src/fetchShopSettings.ts
|
|
141
139
|
var import_core2 = require("@lime-bundles/core");
|
|
142
140
|
var FALLBACK = {
|
|
143
|
-
customCss: null
|
|
144
|
-
outOfStockBehavior: import_core2.DEFAULT_OUT_OF_STOCK_BEHAVIOR
|
|
141
|
+
customCss: null
|
|
145
142
|
};
|
|
146
143
|
var cache = /* @__PURE__ */ new Map();
|
|
147
144
|
async function fetchShopSettings(options) {
|
|
@@ -159,10 +156,7 @@ async function fetchShopSettings(options) {
|
|
|
159
156
|
{ signal: options.signal }
|
|
160
157
|
);
|
|
161
158
|
return {
|
|
162
|
-
customCss: data.shop?.customCss?.value ?? null
|
|
163
|
-
outOfStockBehavior: (0, import_core2.parseOutOfStockBehavior)(
|
|
164
|
-
data.shop?.outOfStockBehavior?.value
|
|
165
|
-
)
|
|
159
|
+
customCss: data.shop?.customCss?.value ?? null
|
|
166
160
|
};
|
|
167
161
|
})();
|
|
168
162
|
cache.set(options.shopDomain, promise);
|
|
@@ -316,19 +310,25 @@ function useWidgetConfigVars(config) {
|
|
|
316
310
|
var import_react4 = require("react");
|
|
317
311
|
var import_core6 = require("@lime-bundles/core");
|
|
318
312
|
var { findVariantByOptions, isOptionValueAvailable, toPickerVariant } = import_core6.variants;
|
|
319
|
-
function defaultInitial(variants) {
|
|
320
|
-
return variants.find((v) => v.availableForSale) ?? variants[0] ?? null;
|
|
321
|
-
}
|
|
322
313
|
function useVariantSelection({
|
|
323
314
|
variants,
|
|
324
315
|
optionNames,
|
|
325
316
|
initialVariant,
|
|
326
|
-
optionValuesByPosition
|
|
317
|
+
optionValuesByPosition,
|
|
318
|
+
requiredQtyFor
|
|
327
319
|
}) {
|
|
328
|
-
const
|
|
329
|
-
() =>
|
|
330
|
-
[
|
|
320
|
+
const pickerVariants = (0, import_react4.useMemo)(
|
|
321
|
+
() => variants.map((v) => toPickerVariant(v, requiredQtyFor?.(v.id))),
|
|
322
|
+
[variants, requiredQtyFor]
|
|
331
323
|
);
|
|
324
|
+
const seed = (0, import_react4.useMemo)(() => {
|
|
325
|
+
if (initialVariant) return initialVariant;
|
|
326
|
+
const covered = pickerVariants.find((p) => p.available);
|
|
327
|
+
if (covered) {
|
|
328
|
+
return variants.find((v) => v.id === covered.id) ?? null;
|
|
329
|
+
}
|
|
330
|
+
return variants.find((v) => v.availableForSale) ?? variants[0] ?? null;
|
|
331
|
+
}, [initialVariant, variants, pickerVariants]);
|
|
332
332
|
const [selectedValues, setSelectedValues] = (0, import_react4.useState)(
|
|
333
333
|
() => seed ? seed.selectedOptions.map((o) => o.value) : optionNames.map(() => "")
|
|
334
334
|
);
|
|
@@ -336,10 +336,6 @@ function useVariantSelection({
|
|
|
336
336
|
if (!seed) return;
|
|
337
337
|
setSelectedValues(seed.selectedOptions.map((o) => o.value));
|
|
338
338
|
}, [seed?.id]);
|
|
339
|
-
const pickerVariants = (0, import_react4.useMemo)(
|
|
340
|
-
() => variants.map((v) => toPickerVariant(v)),
|
|
341
|
-
[variants]
|
|
342
|
-
);
|
|
343
339
|
const selectedVariant = (0, import_react4.useMemo)(() => {
|
|
344
340
|
if (selectedValues.length !== optionNames.length) return null;
|
|
345
341
|
const match = findVariantByOptions(pickerVariants, selectedValues);
|
|
@@ -702,8 +698,48 @@ function VariantDropdown({
|
|
|
702
698
|
);
|
|
703
699
|
}
|
|
704
700
|
|
|
705
|
-
// src/components/
|
|
701
|
+
// src/components/BundleCountdown.tsx
|
|
702
|
+
var import_react7 = require("react");
|
|
706
703
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
704
|
+
function pad(n) {
|
|
705
|
+
return n < 10 ? "0" + n : String(n);
|
|
706
|
+
}
|
|
707
|
+
function formatRemaining(remaining) {
|
|
708
|
+
const days = Math.floor(remaining / 864e5);
|
|
709
|
+
const hours = Math.floor(remaining % 864e5 / 36e5);
|
|
710
|
+
const mins = Math.floor(remaining % 36e5 / 6e4);
|
|
711
|
+
const secs = Math.floor(remaining % 6e4 / 1e3);
|
|
712
|
+
return days > 0 ? days + "d " + pad(hours) + "h " + pad(mins) + "m " + pad(secs) + "s" : pad(hours) + "h " + pad(mins) + "m " + pad(secs) + "s";
|
|
713
|
+
}
|
|
714
|
+
function BundleCountdown({
|
|
715
|
+
endsAt,
|
|
716
|
+
widgetConfig,
|
|
717
|
+
label = "Limited time offer"
|
|
718
|
+
}) {
|
|
719
|
+
const enabled = !!endsAt && widgetConfig?.countdown?.showCountdown !== false;
|
|
720
|
+
const endTime = enabled ? new Date(endsAt).getTime() : NaN;
|
|
721
|
+
const [remaining, setRemaining] = (0, import_react7.useState)(null);
|
|
722
|
+
(0, import_react7.useEffect)(() => {
|
|
723
|
+
if (!enabled || isNaN(endTime)) {
|
|
724
|
+
setRemaining(null);
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
const update = () => setRemaining(endTime - Date.now());
|
|
728
|
+
update();
|
|
729
|
+
const interval = setInterval(update, 1e3);
|
|
730
|
+
return () => clearInterval(interval);
|
|
731
|
+
}, [enabled, endTime]);
|
|
732
|
+
if (!enabled || isNaN(endTime) || remaining === null || remaining <= 0) {
|
|
733
|
+
return null;
|
|
734
|
+
}
|
|
735
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "lb-bundle-countdown", "data-countdown": true, children: [
|
|
736
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "lb-bundle-countdown__label", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: label }) }),
|
|
737
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "lb-bundle-countdown__timer", "data-countdown-timer": true, children: formatRemaining(remaining) })
|
|
738
|
+
] });
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
// src/components/FixedBundle.tsx
|
|
742
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
707
743
|
function FixedBundle(props) {
|
|
708
744
|
const {
|
|
709
745
|
shopDomain,
|
|
@@ -727,10 +763,10 @@ function FixedBundle(props) {
|
|
|
727
763
|
bundleType: "fixed",
|
|
728
764
|
enabled: analyticsEnabled !== false
|
|
729
765
|
});
|
|
730
|
-
const [addingToCart, setAddingToCart] = (0,
|
|
731
|
-
const [cartError, setCartError] = (0,
|
|
732
|
-
const [selectedVariants, setSelectedVariants] = (0,
|
|
733
|
-
const handleVariantChange = (0,
|
|
766
|
+
const [addingToCart, setAddingToCart] = (0, import_react8.useState)(false);
|
|
767
|
+
const [cartError, setCartError] = (0, import_react8.useState)(null);
|
|
768
|
+
const [selectedVariants, setSelectedVariants] = (0, import_react8.useState)({});
|
|
769
|
+
const handleVariantChange = (0, import_react8.useCallback)(
|
|
734
770
|
(productId, variant) => {
|
|
735
771
|
setSelectedVariants((prev) => {
|
|
736
772
|
if (prev[productId] === variant) return prev;
|
|
@@ -742,7 +778,7 @@ function FixedBundle(props) {
|
|
|
742
778
|
const bundle = result.status === "success" && result.bundle.bundleType === "fixed" ? result.bundle : null;
|
|
743
779
|
const setConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);
|
|
744
780
|
const productsEdgeFadeRef = useEdgeFade();
|
|
745
|
-
(0,
|
|
781
|
+
(0, import_react8.useEffect)(() => {
|
|
746
782
|
if (result.status === "error") {
|
|
747
783
|
onError?.(result.error);
|
|
748
784
|
return;
|
|
@@ -755,7 +791,7 @@ function FixedBundle(props) {
|
|
|
755
791
|
);
|
|
756
792
|
}
|
|
757
793
|
}, [result, onError]);
|
|
758
|
-
const oosProductIds = (0,
|
|
794
|
+
const oosProductIds = (0, import_react8.useMemo)(() => {
|
|
759
795
|
if (!bundle) return /* @__PURE__ */ new Set();
|
|
760
796
|
return new Set(
|
|
761
797
|
bundle.products.filter(
|
|
@@ -765,7 +801,7 @@ function FixedBundle(props) {
|
|
|
765
801
|
).map((p) => p.id)
|
|
766
802
|
);
|
|
767
803
|
}, [bundle]);
|
|
768
|
-
const handleAddToCart = (0,
|
|
804
|
+
const handleAddToCart = (0, import_react8.useCallback)(async () => {
|
|
769
805
|
if (!bundle) return;
|
|
770
806
|
const bundleLines = bundle.products.filter(
|
|
771
807
|
(p) => p.variants.nodes.some(
|
|
@@ -820,9 +856,9 @@ function FixedBundle(props) {
|
|
|
820
856
|
}
|
|
821
857
|
}, [bundle, onAddToCart, onError, trackAddToCart, selectedVariants]);
|
|
822
858
|
if (result.status === "loading") {
|
|
823
|
-
return /* @__PURE__ */ (0,
|
|
824
|
-
/* @__PURE__ */ (0,
|
|
825
|
-
/* @__PURE__ */ (0,
|
|
859
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: `lb-bundle lb-bundle--loading ${className ?? ""}`, children: [
|
|
860
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "lb-skeleton lb-skeleton--title" }),
|
|
861
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "lb-skeleton lb-skeleton--products" })
|
|
826
862
|
] });
|
|
827
863
|
}
|
|
828
864
|
if (result.status === "error") return null;
|
|
@@ -849,7 +885,7 @@ function FixedBundle(props) {
|
|
|
849
885
|
const savingsPercent = comparePrice > 0 && savings > 0 ? Math.round(savings / comparePrice * 100) : 0;
|
|
850
886
|
const showCompare = bundle.widgetConfig.pricing.showComparePrice && savings > 0;
|
|
851
887
|
const showSavings = bundle.widgetConfig.savingsBar.visible && savings > 0;
|
|
852
|
-
return /* @__PURE__ */ (0,
|
|
888
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
853
889
|
"div",
|
|
854
890
|
{
|
|
855
891
|
ref: (el) => {
|
|
@@ -860,11 +896,18 @@ function FixedBundle(props) {
|
|
|
860
896
|
role: "region",
|
|
861
897
|
"aria-label": bundle.title,
|
|
862
898
|
children: [
|
|
863
|
-
/* @__PURE__ */ (0,
|
|
864
|
-
/* @__PURE__ */ (0,
|
|
865
|
-
bundle.description && /* @__PURE__ */ (0,
|
|
899
|
+
/* @__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: [
|
|
900
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { className: "lb-bundle-title", children: bundle.title }),
|
|
901
|
+
bundle.description && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "lb-bundle-subtitle", children: bundle.description })
|
|
866
902
|
] }) }),
|
|
867
|
-
/* @__PURE__ */ (0,
|
|
903
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
904
|
+
BundleCountdown,
|
|
905
|
+
{
|
|
906
|
+
endsAt: bundle.endsAt,
|
|
907
|
+
widgetConfig: bundle.widgetConfig
|
|
908
|
+
}
|
|
909
|
+
),
|
|
910
|
+
/* @__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
911
|
FixedProductRow,
|
|
869
912
|
{
|
|
870
913
|
bundle,
|
|
@@ -875,29 +918,29 @@ function FixedBundle(props) {
|
|
|
875
918
|
},
|
|
876
919
|
product.id
|
|
877
920
|
)) }),
|
|
878
|
-
/* @__PURE__ */ (0,
|
|
879
|
-
/* @__PURE__ */ (0,
|
|
880
|
-
/* @__PURE__ */ (0,
|
|
881
|
-
/* @__PURE__ */ (0,
|
|
882
|
-
showSavings && /* @__PURE__ */ (0,
|
|
921
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "lb-bundle-divider" }),
|
|
922
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "lb-bundle-summary", children: [
|
|
923
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "lb-bundle-summary__text", children: [
|
|
924
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "lb-bundle-summary__label", children: "Bundle total" }),
|
|
925
|
+
showSavings && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { className: "lb-bundle-savings-line", "data-savings-bar": true, children: [
|
|
883
926
|
"You save",
|
|
884
927
|
" ",
|
|
885
|
-
/* @__PURE__ */ (0,
|
|
928
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { "data-savings-amount": true, children: (0, import_core8.formatMoney)(savings, currency) }),
|
|
886
929
|
" ",
|
|
887
|
-
/* @__PURE__ */ (0,
|
|
930
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { "data-savings-percent": true, children: [
|
|
888
931
|
"(",
|
|
889
932
|
savingsPercent,
|
|
890
933
|
"%)"
|
|
891
934
|
] })
|
|
892
935
|
] })
|
|
893
936
|
] }),
|
|
894
|
-
/* @__PURE__ */ (0,
|
|
895
|
-
showCompare && /* @__PURE__ */ (0,
|
|
896
|
-
/* @__PURE__ */ (0,
|
|
937
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "lb-bundle-summary__prices", children: [
|
|
938
|
+
showCompare && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "lb-bundle-compare-price", "data-compare-price": true, children: (0, import_core8.formatMoney)(comparePrice, currency) }),
|
|
939
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "lb-bundle-sale-price", "data-sale-price": true, children: (0, import_core8.formatMoney)(salePrice, currency) })
|
|
897
940
|
] })
|
|
898
941
|
] }),
|
|
899
|
-
cartError && /* @__PURE__ */ (0,
|
|
900
|
-
/* @__PURE__ */ (0,
|
|
942
|
+
cartError && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "lb-bundle__error", role: "alert", children: cartError }),
|
|
943
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
901
944
|
"button",
|
|
902
945
|
{
|
|
903
946
|
className: "lb-bundle__cta",
|
|
@@ -913,16 +956,20 @@ function FixedBundle(props) {
|
|
|
913
956
|
}
|
|
914
957
|
function FixedProductRow({ bundle, product, currency, isOos, onVariantChange }) {
|
|
915
958
|
const variants = product.variants.nodes;
|
|
916
|
-
const optionNames = (0,
|
|
959
|
+
const optionNames = (0, import_react8.useMemo)(() => {
|
|
917
960
|
const first = variants[0];
|
|
918
961
|
return first ? first.selectedOptions.map((o) => o.name) : [];
|
|
919
962
|
}, [variants]);
|
|
920
963
|
const showPicker = variants.length > 1 && optionNames.length > 0;
|
|
921
964
|
const { selectedValues, selectedVariant, setOptionValue, optionsFor } = useVariantSelection({
|
|
922
965
|
variants,
|
|
923
|
-
optionNames
|
|
966
|
+
optionNames,
|
|
967
|
+
// Quantity-aware dropdown: a variant that can't cover this row's
|
|
968
|
+
// bundle quantity greys out instead of walking the shopper into a
|
|
969
|
+
// cart Shopify caps at add time.
|
|
970
|
+
requiredQtyFor: (variantId) => (0, import_core8.resolveBundleQty)(bundle, product.id, variantId)
|
|
924
971
|
});
|
|
925
|
-
(0,
|
|
972
|
+
(0, import_react8.useEffect)(() => {
|
|
926
973
|
onVariantChange(product.id, selectedVariant ?? null);
|
|
927
974
|
}, [selectedVariant, product.id, onVariantChange]);
|
|
928
975
|
const displayVariant = selectedVariant ?? variants.find(
|
|
@@ -943,15 +990,15 @@ function FixedProductRow({ bundle, product, currency, isOos, onVariantChange })
|
|
|
943
990
|
bundle.widgetConfig.lowStockThreshold,
|
|
944
991
|
bundle.widgetConfig.showLowStockBadge
|
|
945
992
|
);
|
|
946
|
-
return /* @__PURE__ */ (0,
|
|
993
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
947
994
|
"div",
|
|
948
995
|
{
|
|
949
996
|
className: isOos ? "lb-bundle-product-row lb-bundle-product-row--oos" : "lb-bundle-product-row",
|
|
950
997
|
"aria-disabled": isOos || void 0,
|
|
951
998
|
part: "product",
|
|
952
999
|
children: [
|
|
953
|
-
isOos && /* @__PURE__ */ (0,
|
|
954
|
-
thumbImage && /* @__PURE__ */ (0,
|
|
1000
|
+
isOos && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "lb-bundle-product-row__oos", children: "Out of stock" }),
|
|
1001
|
+
thumbImage && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
955
1002
|
"img",
|
|
956
1003
|
{
|
|
957
1004
|
src: thumbImage.url,
|
|
@@ -960,11 +1007,11 @@ function FixedProductRow({ bundle, product, currency, isOos, onVariantChange })
|
|
|
960
1007
|
loading: "lazy"
|
|
961
1008
|
}
|
|
962
1009
|
),
|
|
963
|
-
/* @__PURE__ */ (0,
|
|
964
|
-
/* @__PURE__ */ (0,
|
|
965
|
-
!showPicker && displayVariant && variants.length > 1 && /* @__PURE__ */ (0,
|
|
966
|
-
/* @__PURE__ */ (0,
|
|
967
|
-
compareAt && /* @__PURE__ */ (0,
|
|
1010
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "lb-bundle__product-info", children: [
|
|
1011
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "lb-bundle__product-title", children: product.title }),
|
|
1012
|
+
!showPicker && displayVariant && variants.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "lb-bundle-variant-badge", children: displayVariant.title }),
|
|
1013
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "lb-bundle-product-prices", children: [
|
|
1014
|
+
compareAt && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
968
1015
|
"span",
|
|
969
1016
|
{
|
|
970
1017
|
className: "lb-bundle-product-compare-price",
|
|
@@ -972,9 +1019,9 @@ function FixedProductRow({ bundle, product, currency, isOos, onVariantChange })
|
|
|
972
1019
|
children: compareAt
|
|
973
1020
|
}
|
|
974
1021
|
),
|
|
975
|
-
/* @__PURE__ */ (0,
|
|
1022
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "lb-bundle__product-price", "data-product-price": true, children: priceText })
|
|
976
1023
|
] }),
|
|
977
|
-
unitPriceText && /* @__PURE__ */ (0,
|
|
1024
|
+
unitPriceText && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
978
1025
|
"span",
|
|
979
1026
|
{
|
|
980
1027
|
className: "lb-bundle__product-unit-price",
|
|
@@ -982,18 +1029,18 @@ function FixedProductRow({ bundle, product, currency, isOos, onVariantChange })
|
|
|
982
1029
|
children: unitPriceText
|
|
983
1030
|
}
|
|
984
1031
|
),
|
|
985
|
-
showLowStock && /* @__PURE__ */ (0,
|
|
1032
|
+
showLowStock && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "lb-bundle-low-stock-badge", children: [
|
|
986
1033
|
"Only ",
|
|
987
1034
|
displayVariant.quantityAvailable,
|
|
988
1035
|
" left"
|
|
989
1036
|
] }),
|
|
990
|
-
showPicker && /* @__PURE__ */ (0,
|
|
1037
|
+
showPicker && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "lb-bundle__product-variant-pickers", children: optionNames.map((optionName, optionIndex) => {
|
|
991
1038
|
const dropdownOptions = optionsFor(optionIndex).map((o) => ({
|
|
992
1039
|
value: o.value,
|
|
993
1040
|
label: o.value,
|
|
994
1041
|
disabled: o.disabled
|
|
995
1042
|
}));
|
|
996
|
-
return /* @__PURE__ */ (0,
|
|
1043
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
997
1044
|
VariantDropdown,
|
|
998
1045
|
{
|
|
999
1046
|
options: dropdownOptions,
|
|
@@ -1005,7 +1052,7 @@ function FixedProductRow({ bundle, product, currency, isOos, onVariantChange })
|
|
|
1005
1052
|
);
|
|
1006
1053
|
}) })
|
|
1007
1054
|
] }),
|
|
1008
|
-
displayVariant && /* @__PURE__ */ (0,
|
|
1055
|
+
displayVariant && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "lb-bundle-qty-chip", "data-qty-inline": true, children: [
|
|
1009
1056
|
"\xD7",
|
|
1010
1057
|
displayQty
|
|
1011
1058
|
] })
|
|
@@ -1016,37 +1063,12 @@ function FixedProductRow({ bundle, product, currency, isOos, onVariantChange })
|
|
|
1016
1063
|
|
|
1017
1064
|
// src/components/MixMatchBundle.tsx
|
|
1018
1065
|
var import_react12 = require("react");
|
|
1019
|
-
var
|
|
1020
|
-
|
|
1021
|
-
// src/hooks/useShopSettings.ts
|
|
1022
|
-
var import_react8 = require("react");
|
|
1023
|
-
var import_core9 = require("@lime-bundles/core");
|
|
1024
|
-
function useShopSettings(options) {
|
|
1025
|
-
const [outOfStockBehavior, setOutOfStockBehavior] = (0, import_react8.useState)(import_core9.DEFAULT_OUT_OF_STOCK_BEHAVIOR);
|
|
1026
|
-
const { shopDomain, storefrontAccessToken } = options;
|
|
1027
|
-
(0, import_react8.useEffect)(() => {
|
|
1028
|
-
const controller = new AbortController();
|
|
1029
|
-
let active = true;
|
|
1030
|
-
fetchShopSettingsOrDefault({
|
|
1031
|
-
shopDomain,
|
|
1032
|
-
storefrontAccessToken,
|
|
1033
|
-
signal: controller.signal
|
|
1034
|
-
}).then((settings) => {
|
|
1035
|
-
if (!active || controller.signal.aborted) return;
|
|
1036
|
-
setOutOfStockBehavior(settings.outOfStockBehavior);
|
|
1037
|
-
});
|
|
1038
|
-
return () => {
|
|
1039
|
-
active = false;
|
|
1040
|
-
controller.abort();
|
|
1041
|
-
};
|
|
1042
|
-
}, [shopDomain, storefrontAccessToken]);
|
|
1043
|
-
return { outOfStockBehavior };
|
|
1044
|
-
}
|
|
1066
|
+
var import_core10 = require("@lime-bundles/core");
|
|
1045
1067
|
|
|
1046
1068
|
// src/components/MixMatchPicker.tsx
|
|
1047
1069
|
var import_react11 = require("react");
|
|
1048
1070
|
var import_react_dom = require("react-dom");
|
|
1049
|
-
var
|
|
1071
|
+
var import_core9 = require("@lime-bundles/core");
|
|
1050
1072
|
|
|
1051
1073
|
// src/hooks/useScrollLock.ts
|
|
1052
1074
|
var import_react9 = require("react");
|
|
@@ -1109,6 +1131,7 @@ function useFocusTrap({
|
|
|
1109
1131
|
active,
|
|
1110
1132
|
containerRef,
|
|
1111
1133
|
onEscape,
|
|
1134
|
+
initialFocusRef,
|
|
1112
1135
|
returnFocusRef
|
|
1113
1136
|
}) {
|
|
1114
1137
|
const previouslyFocused = (0, import_react10.useRef)(null);
|
|
@@ -1116,7 +1139,8 @@ function useFocusTrap({
|
|
|
1116
1139
|
if (!active) return;
|
|
1117
1140
|
const container = containerRef.current;
|
|
1118
1141
|
previouslyFocused.current = document.activeElement ?? null;
|
|
1119
|
-
container
|
|
1142
|
+
const initial = initialFocusRef?.current ?? container;
|
|
1143
|
+
initial?.focus();
|
|
1120
1144
|
function onKeyDown(e) {
|
|
1121
1145
|
if (e.key === "Escape") {
|
|
1122
1146
|
e.preventDefault();
|
|
@@ -1154,13 +1178,13 @@ function useFocusTrap({
|
|
|
1154
1178
|
}
|
|
1155
1179
|
|
|
1156
1180
|
// src/components/MixMatchPicker.tsx
|
|
1157
|
-
var
|
|
1181
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1158
1182
|
function ruleFor(bundle, productId, variantId) {
|
|
1159
1183
|
if (variantId) {
|
|
1160
1184
|
const vRule = bundle.variantRules[variantId];
|
|
1161
1185
|
if (vRule) return vRule;
|
|
1162
1186
|
}
|
|
1163
|
-
return bundle.productRules[productId] ??
|
|
1187
|
+
return bundle.productRules[productId] ?? import_core9.DEFAULT_PRODUCT_RULE;
|
|
1164
1188
|
}
|
|
1165
1189
|
function variantRuleFor(bundle, variantId) {
|
|
1166
1190
|
return variantId ? bundle.variantRules[variantId] : void 0;
|
|
@@ -1168,7 +1192,7 @@ function variantRuleFor(bundle, variantId) {
|
|
|
1168
1192
|
function sanitizeId(gid) {
|
|
1169
1193
|
return gid.replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
1170
1194
|
}
|
|
1171
|
-
function buildEligibleProducts(bundle
|
|
1195
|
+
function buildEligibleProducts(bundle) {
|
|
1172
1196
|
const result = [];
|
|
1173
1197
|
const seen = /* @__PURE__ */ new Set();
|
|
1174
1198
|
for (const product of bundle.products) {
|
|
@@ -1176,10 +1200,9 @@ function buildEligibleProducts(bundle, oosBehavior) {
|
|
|
1176
1200
|
seen.add(product.id);
|
|
1177
1201
|
const rule = ruleFor(bundle, product.id);
|
|
1178
1202
|
const available = product.variants.nodes.filter(
|
|
1179
|
-
(v) => (0,
|
|
1203
|
+
(v) => (0, import_core9.isVariantFulfillable)(v, rule.min)
|
|
1180
1204
|
);
|
|
1181
1205
|
const isOos = available.length === 0;
|
|
1182
|
-
if (isOos && oosBehavior === "hide") continue;
|
|
1183
1206
|
result.push({
|
|
1184
1207
|
product,
|
|
1185
1208
|
variants: product.variants.nodes,
|
|
@@ -1194,7 +1217,6 @@ function normalizeText(str) {
|
|
|
1194
1217
|
}
|
|
1195
1218
|
var FILTERS_ALL = "__all__";
|
|
1196
1219
|
function MixMatchPicker({
|
|
1197
|
-
outOfStockBehavior,
|
|
1198
1220
|
bundle,
|
|
1199
1221
|
currency,
|
|
1200
1222
|
requiredQty,
|
|
@@ -1212,13 +1234,14 @@ function MixMatchPicker({
|
|
|
1212
1234
|
const wc = bundle.widgetConfig;
|
|
1213
1235
|
const overlayRef = (0, import_react11.useRef)(null);
|
|
1214
1236
|
const dialogRef = (0, import_react11.useRef)(null);
|
|
1237
|
+
const closeBtnRef = (0, import_react11.useRef)(null);
|
|
1215
1238
|
const mouseDownTarget = (0, import_react11.useRef)(null);
|
|
1216
1239
|
const [open, setOpen] = (0, import_react11.useState)(false);
|
|
1217
1240
|
const [query, setQuery] = (0, import_react11.useState)("");
|
|
1218
1241
|
const [activeType, setActiveType] = (0, import_react11.useState)(FILTERS_ALL);
|
|
1219
1242
|
const eligible = (0, import_react11.useMemo)(
|
|
1220
|
-
() => buildEligibleProducts(bundle
|
|
1221
|
-
[bundle
|
|
1243
|
+
() => buildEligibleProducts(bundle),
|
|
1244
|
+
[bundle]
|
|
1222
1245
|
);
|
|
1223
1246
|
const productTypes = (0, import_react11.useMemo)(() => {
|
|
1224
1247
|
const types = [];
|
|
@@ -1244,6 +1267,7 @@ function MixMatchPicker({
|
|
|
1244
1267
|
useFocusTrap({
|
|
1245
1268
|
active: true,
|
|
1246
1269
|
containerRef: dialogRef,
|
|
1270
|
+
initialFocusRef: closeBtnRef,
|
|
1247
1271
|
onEscape: onClose
|
|
1248
1272
|
});
|
|
1249
1273
|
const remaining = Math.max(0, requiredQty - shownUnits);
|
|
@@ -1252,14 +1276,25 @@ function MixMatchPicker({
|
|
|
1252
1276
|
const pct = bundle.discountConfig.discountType === "percentage" && bundle.discountConfig.discountValue ? Math.round(bundle.discountConfig.discountValue) : 0;
|
|
1253
1277
|
return pct > 0 ? `Choose ${remaining} more to unlock ${pct}% off` : `Choose ${remaining} more to complete your bundle`;
|
|
1254
1278
|
})();
|
|
1279
|
+
const [selectedAtOpen] = (0, import_react11.useState)(
|
|
1280
|
+
() => new Set(selections.map((s) => s.productId))
|
|
1281
|
+
);
|
|
1282
|
+
const ordered = (0, import_react11.useMemo)(() => {
|
|
1283
|
+
const front = [];
|
|
1284
|
+
const back = [];
|
|
1285
|
+
for (const ep of eligible) {
|
|
1286
|
+
(selectedAtOpen.has(ep.product.id) ? back : front).push(ep);
|
|
1287
|
+
}
|
|
1288
|
+
return front.concat(back);
|
|
1289
|
+
}, [eligible, selectedAtOpen]);
|
|
1255
1290
|
const filtered = (0, import_react11.useMemo)(() => {
|
|
1256
1291
|
const nq = normalizeText(query.trim());
|
|
1257
|
-
return
|
|
1292
|
+
return ordered.filter((ep) => {
|
|
1258
1293
|
const matchesQuery = !nq || normalizeText(ep.product.title).includes(nq);
|
|
1259
1294
|
const matchesType = activeType === FILTERS_ALL || (ep.product.productType ?? "") === activeType;
|
|
1260
1295
|
return matchesQuery && matchesType;
|
|
1261
1296
|
});
|
|
1262
|
-
}, [
|
|
1297
|
+
}, [ordered, query, activeType]);
|
|
1263
1298
|
const showEmpty = filtered.length === 0 && query.trim().length > 0;
|
|
1264
1299
|
function onOverlayMouseDown(e) {
|
|
1265
1300
|
mouseDownTarget.current = e.target;
|
|
@@ -1277,7 +1312,7 @@ function MixMatchPicker({
|
|
|
1277
1312
|
// inside carries the interactive role + focus trap. So the static-element
|
|
1278
1313
|
// interaction lint does not apply to this backdrop.
|
|
1279
1314
|
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
|
|
1280
|
-
/* @__PURE__ */ (0,
|
|
1315
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1281
1316
|
"div",
|
|
1282
1317
|
{
|
|
1283
1318
|
ref: (el) => {
|
|
@@ -1289,7 +1324,7 @@ function MixMatchPicker({
|
|
|
1289
1324
|
"data-bundle-gid": bundle.id,
|
|
1290
1325
|
onMouseDown: onOverlayMouseDown,
|
|
1291
1326
|
onMouseUp: onOverlayMouseUp,
|
|
1292
|
-
children: /* @__PURE__ */ (0,
|
|
1327
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1293
1328
|
"div",
|
|
1294
1329
|
{
|
|
1295
1330
|
ref: dialogRef,
|
|
@@ -1299,30 +1334,31 @@ function MixMatchPicker({
|
|
|
1299
1334
|
"aria-labelledby": titleId,
|
|
1300
1335
|
tabIndex: -1,
|
|
1301
1336
|
children: [
|
|
1302
|
-
/* @__PURE__ */ (0,
|
|
1303
|
-
/* @__PURE__ */ (0,
|
|
1304
|
-
/* @__PURE__ */ (0,
|
|
1305
|
-
/* @__PURE__ */ (0,
|
|
1306
|
-
/* @__PURE__ */ (0,
|
|
1337
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "lb-mix-match__modal-header", children: [
|
|
1338
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "lb-mix-match__modal-header-top", children: [
|
|
1339
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "lb-mix-match__modal-heading", children: [
|
|
1340
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h4", { className: "lb-mix-match__modal-title", id: titleId, children: "Add to your bundle" }),
|
|
1341
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "lb-mix-match__modal-subtitle", "data-modal-subtitle": true, children: subtitle })
|
|
1307
1342
|
] }),
|
|
1308
|
-
/* @__PURE__ */ (0,
|
|
1343
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1309
1344
|
"button",
|
|
1310
1345
|
{
|
|
1346
|
+
ref: closeBtnRef,
|
|
1311
1347
|
type: "button",
|
|
1312
1348
|
className: "lb-mix-match__modal-close",
|
|
1313
1349
|
"data-modal-close": true,
|
|
1314
1350
|
"aria-label": "Close",
|
|
1315
1351
|
onClick: onClose,
|
|
1316
|
-
children: /* @__PURE__ */ (0,
|
|
1352
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CloseIcon, {})
|
|
1317
1353
|
}
|
|
1318
1354
|
)
|
|
1319
1355
|
] }),
|
|
1320
|
-
/* @__PURE__ */ (0,
|
|
1356
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1321
1357
|
"div",
|
|
1322
1358
|
{
|
|
1323
1359
|
className: "lb-mix-match__progress lb-mix-match__modal-progress",
|
|
1324
1360
|
"data-progress": true,
|
|
1325
|
-
children: /* @__PURE__ */ (0,
|
|
1361
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1326
1362
|
"div",
|
|
1327
1363
|
{
|
|
1328
1364
|
className: "lb-mix-match__progress-segments",
|
|
@@ -1330,7 +1366,7 @@ function MixMatchPicker({
|
|
|
1330
1366
|
"aria-valuenow": shownUnits,
|
|
1331
1367
|
"aria-valuemin": 0,
|
|
1332
1368
|
"aria-valuemax": requiredQty,
|
|
1333
|
-
children: Array.from({ length: requiredQty }).map((_, i) => /* @__PURE__ */ (0,
|
|
1369
|
+
children: Array.from({ length: requiredQty }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1334
1370
|
"span",
|
|
1335
1371
|
{
|
|
1336
1372
|
className: `lb-mix-match__progress-segment${i < shownUnits ? " lb-mix-match__progress-segment--filled" : ""}`,
|
|
@@ -1343,8 +1379,8 @@ function MixMatchPicker({
|
|
|
1343
1379
|
}
|
|
1344
1380
|
)
|
|
1345
1381
|
] }),
|
|
1346
|
-
wc.showSearch && /* @__PURE__ */ (0,
|
|
1347
|
-
/* @__PURE__ */ (0,
|
|
1382
|
+
wc.showSearch && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "lb-mix-match__modal-search", children: [
|
|
1383
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1348
1384
|
"input",
|
|
1349
1385
|
{
|
|
1350
1386
|
type: "text",
|
|
@@ -1358,7 +1394,7 @@ function MixMatchPicker({
|
|
|
1358
1394
|
onChange: (e) => setQuery(e.target.value)
|
|
1359
1395
|
}
|
|
1360
1396
|
),
|
|
1361
|
-
query.length > 0 && /* @__PURE__ */ (0,
|
|
1397
|
+
query.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1362
1398
|
"button",
|
|
1363
1399
|
{
|
|
1364
1400
|
type: "button",
|
|
@@ -1366,11 +1402,11 @@ function MixMatchPicker({
|
|
|
1366
1402
|
"data-modal-search-clear": true,
|
|
1367
1403
|
"aria-label": "Clear search",
|
|
1368
1404
|
onClick: () => setQuery(""),
|
|
1369
|
-
children: /* @__PURE__ */ (0,
|
|
1405
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(SearchClearIcon, {})
|
|
1370
1406
|
}
|
|
1371
1407
|
)
|
|
1372
1408
|
] }),
|
|
1373
|
-
showFilters && /* @__PURE__ */ (0,
|
|
1409
|
+
showFilters && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1374
1410
|
"div",
|
|
1375
1411
|
{
|
|
1376
1412
|
className: "lb-mix-match__filters",
|
|
@@ -1379,7 +1415,7 @@ function MixMatchPicker({
|
|
|
1379
1415
|
"aria-label": "Filter by product type",
|
|
1380
1416
|
children: [FILTERS_ALL, ...productTypes].map((value) => {
|
|
1381
1417
|
const isActive = value === activeType;
|
|
1382
|
-
return /* @__PURE__ */ (0,
|
|
1418
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1383
1419
|
"button",
|
|
1384
1420
|
{
|
|
1385
1421
|
type: "button",
|
|
@@ -1394,7 +1430,7 @@ function MixMatchPicker({
|
|
|
1394
1430
|
})
|
|
1395
1431
|
}
|
|
1396
1432
|
),
|
|
1397
|
-
/* @__PURE__ */ (0,
|
|
1433
|
+
/* @__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)(
|
|
1398
1434
|
MixMatchPickerRow,
|
|
1399
1435
|
{
|
|
1400
1436
|
bundle,
|
|
@@ -1413,10 +1449,10 @@ function MixMatchPicker({
|
|
|
1413
1449
|
},
|
|
1414
1450
|
ep.product.id
|
|
1415
1451
|
)) }),
|
|
1416
|
-
showEmpty && /* @__PURE__ */ (0,
|
|
1417
|
-
/* @__PURE__ */ (0,
|
|
1418
|
-
/* @__PURE__ */ (0,
|
|
1419
|
-
/* @__PURE__ */ (0,
|
|
1452
|
+
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" }) }),
|
|
1453
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { "data-modal-live": true, "aria-live": "polite", className: "lb-visually-hidden", children: `${filtered.length} products shown` }),
|
|
1454
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "lb-mix-match__modal-footer", children: [
|
|
1455
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1420
1456
|
"span",
|
|
1421
1457
|
{
|
|
1422
1458
|
className: "lb-mix-match__modal-footer-count",
|
|
@@ -1425,7 +1461,7 @@ function MixMatchPicker({
|
|
|
1425
1461
|
children: `${shownUnits} of ${requiredQty} added`
|
|
1426
1462
|
}
|
|
1427
1463
|
),
|
|
1428
|
-
/* @__PURE__ */ (0,
|
|
1464
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1429
1465
|
"button",
|
|
1430
1466
|
{
|
|
1431
1467
|
type: "button",
|
|
@@ -1468,7 +1504,7 @@ function MixMatchPickerRow({
|
|
|
1468
1504
|
}, [variants]);
|
|
1469
1505
|
const showPicker = variants.length > 1 && optionNames.length > 0;
|
|
1470
1506
|
const { selectedValues, selectedVariant, setOptionValue, optionsFor } = useVariantSelection({ variants, optionNames });
|
|
1471
|
-
const currentVariant = selectedVariant ?? variants.find((v) => (0,
|
|
1507
|
+
const currentVariant = selectedVariant ?? variants.find((v) => (0, import_core9.isVariantFulfillable)(v, rule.min)) ?? eligible.firstAvailableVariant ?? variants[0] ?? null;
|
|
1472
1508
|
const vRule = ruleFor(bundle, product.id, currentVariant?.id);
|
|
1473
1509
|
const variantMax = variantRuleFor(bundle, currentVariant?.id)?.max;
|
|
1474
1510
|
const alreadyInBundle = (0, import_react11.useMemo)(() => {
|
|
@@ -1504,7 +1540,7 @@ function MixMatchPickerRow({
|
|
|
1504
1540
|
committedQty + remainingUnits,
|
|
1505
1541
|
variantMax ?? Infinity
|
|
1506
1542
|
);
|
|
1507
|
-
const cap = currentVariant ? (0,
|
|
1543
|
+
const cap = currentVariant ? (0, import_core9.maxAddableQuantity)(
|
|
1508
1544
|
currentVariant,
|
|
1509
1545
|
spotCeiling,
|
|
1510
1546
|
Math.max(0, alreadyInBundle - committedQty)
|
|
@@ -1520,7 +1556,7 @@ function MixMatchPickerRow({
|
|
|
1520
1556
|
}, [variantInBundle, currentVariantId, vRule.min]);
|
|
1521
1557
|
if (!currentVariant) return null;
|
|
1522
1558
|
const thumbImage = currentVariant.image ?? product.featuredImage ?? null;
|
|
1523
|
-
const unitPriceText = (0,
|
|
1559
|
+
const unitPriceText = (0, import_core9.formatUnitPrice)(
|
|
1524
1560
|
currentVariant.unitPrice,
|
|
1525
1561
|
currentVariant.unitPriceMeasurement,
|
|
1526
1562
|
currency
|
|
@@ -1559,7 +1595,7 @@ function MixMatchPickerRow({
|
|
|
1559
1595
|
}
|
|
1560
1596
|
const priceCents = parseFloat(currentVariant.price.amount);
|
|
1561
1597
|
const compareCents = currentVariant.compareAtPrice ? parseFloat(currentVariant.compareAtPrice.amount) : null;
|
|
1562
|
-
return /* @__PURE__ */ (0,
|
|
1598
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1563
1599
|
"div",
|
|
1564
1600
|
{
|
|
1565
1601
|
className: `lb-mix-match__modal-product${isOos ? " lb-mix-match__modal-product--sold-out" : ""}${variantInBundle ? " lb-mix-match__modal-product--in-bundle" : ""}`,
|
|
@@ -1568,8 +1604,8 @@ function MixMatchPickerRow({
|
|
|
1568
1604
|
"data-type": product.productType ?? "",
|
|
1569
1605
|
"aria-disabled": isOos || void 0,
|
|
1570
1606
|
children: [
|
|
1571
|
-
/* @__PURE__ */ (0,
|
|
1572
|
-
thumbImage && /* @__PURE__ */ (0,
|
|
1607
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "lb-mix-match__modal-product-thumb", children: [
|
|
1608
|
+
thumbImage && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1573
1609
|
"img",
|
|
1574
1610
|
{
|
|
1575
1611
|
src: thumbImage.url,
|
|
@@ -1577,10 +1613,10 @@ function MixMatchPickerRow({
|
|
|
1577
1613
|
loading: "lazy"
|
|
1578
1614
|
}
|
|
1579
1615
|
),
|
|
1580
|
-
variantInBundle && /* @__PURE__ */ (0,
|
|
1616
|
+
variantInBundle && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "lb-mix-match__modal-added-badge", children: "Added" })
|
|
1581
1617
|
] }),
|
|
1582
|
-
/* @__PURE__ */ (0,
|
|
1583
|
-
/* @__PURE__ */ (0,
|
|
1618
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "lb-mix-match__modal-product-info", children: [
|
|
1619
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "lb-mix-match__modal-product-title", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1584
1620
|
"a",
|
|
1585
1621
|
{
|
|
1586
1622
|
href: `/products/${product.handle}`,
|
|
@@ -1589,24 +1625,24 @@ function MixMatchPickerRow({
|
|
|
1589
1625
|
children: product.title
|
|
1590
1626
|
}
|
|
1591
1627
|
) }),
|
|
1592
|
-
/* @__PURE__ */ (0,
|
|
1593
|
-
/* @__PURE__ */ (0,
|
|
1594
|
-
compareCents !== null && compareCents > priceCents && /* @__PURE__ */ (0,
|
|
1628
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { className: "lb-mix-match__modal-product-price", children: [
|
|
1629
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { "data-row-price-sale": true, children: (0, import_core9.formatMoney)(priceCents, currency) }),
|
|
1630
|
+
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_core9.formatMoney)(compareCents, currency) })
|
|
1595
1631
|
] }),
|
|
1596
|
-
unitPriceText && /* @__PURE__ */ (0,
|
|
1597
|
-
showPicker && /* @__PURE__ */ (0,
|
|
1632
|
+
unitPriceText && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "lb-mix-match__modal-product-unit-price lb-bundle-product-unit-price", children: unitPriceText }),
|
|
1633
|
+
showPicker && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "lb-bundle-variant-option-groups", children: optionNames.map((optionName, optionIndex) => {
|
|
1598
1634
|
const dropdownOptions = optionsFor(optionIndex).map((o) => ({
|
|
1599
1635
|
value: o.value,
|
|
1600
1636
|
label: o.value,
|
|
1601
1637
|
disabled: o.disabled
|
|
1602
1638
|
}));
|
|
1603
|
-
return /* @__PURE__ */ (0,
|
|
1639
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1604
1640
|
"div",
|
|
1605
1641
|
{
|
|
1606
1642
|
className: "lb-bundle-variant-option-group",
|
|
1607
1643
|
children: [
|
|
1608
|
-
/* @__PURE__ */ (0,
|
|
1609
|
-
/* @__PURE__ */ (0,
|
|
1644
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "lb-bundle-variant-option-label", children: optionName }),
|
|
1645
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1610
1646
|
VariantDropdown,
|
|
1611
1647
|
{
|
|
1612
1648
|
className: "lb-mix-match__variant-select-dropdown",
|
|
@@ -1621,17 +1657,17 @@ function MixMatchPickerRow({
|
|
|
1621
1657
|
optionName
|
|
1622
1658
|
);
|
|
1623
1659
|
}) }),
|
|
1624
|
-
!showPicker && variants.length === 1 && currentVariant.title !== "Default Title" && /* @__PURE__ */ (0,
|
|
1625
|
-
!isOos && needsMoreSpots && remainingUnits > 0 && /* @__PURE__ */ (0,
|
|
1626
|
-
isOos ? /* @__PURE__ */ (0,
|
|
1627
|
-
showStepper && /* @__PURE__ */ (0,
|
|
1660
|
+
!showPicker && variants.length === 1 && currentVariant.title !== "Default Title" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "lb-mix-match__filled-variant", children: currentVariant.title }),
|
|
1661
|
+
!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` }),
|
|
1662
|
+
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: [
|
|
1663
|
+
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)(
|
|
1628
1664
|
"div",
|
|
1629
1665
|
{
|
|
1630
1666
|
className: "lb-mix-match__qty-stepper",
|
|
1631
1667
|
role: "group",
|
|
1632
1668
|
"aria-label": "Quantity",
|
|
1633
1669
|
children: [
|
|
1634
|
-
/* @__PURE__ */ (0,
|
|
1670
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1635
1671
|
"button",
|
|
1636
1672
|
{
|
|
1637
1673
|
type: "button",
|
|
@@ -1652,7 +1688,7 @@ function MixMatchPickerRow({
|
|
|
1652
1688
|
children: "\u2212"
|
|
1653
1689
|
}
|
|
1654
1690
|
),
|
|
1655
|
-
/* @__PURE__ */ (0,
|
|
1691
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1656
1692
|
"span",
|
|
1657
1693
|
{
|
|
1658
1694
|
className: "lb-mix-match__qty-stepper-value",
|
|
@@ -1661,7 +1697,7 @@ function MixMatchPickerRow({
|
|
|
1661
1697
|
children: shownQty
|
|
1662
1698
|
}
|
|
1663
1699
|
),
|
|
1664
|
-
/* @__PURE__ */ (0,
|
|
1700
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1665
1701
|
"button",
|
|
1666
1702
|
{
|
|
1667
1703
|
type: "button",
|
|
@@ -1685,7 +1721,7 @@ function MixMatchPickerRow({
|
|
|
1685
1721
|
]
|
|
1686
1722
|
}
|
|
1687
1723
|
) }),
|
|
1688
|
-
/* @__PURE__ */ (0,
|
|
1724
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1689
1725
|
"button",
|
|
1690
1726
|
{
|
|
1691
1727
|
type: "button",
|
|
@@ -1704,7 +1740,7 @@ function MixMatchPickerRow({
|
|
|
1704
1740
|
);
|
|
1705
1741
|
}
|
|
1706
1742
|
function CloseIcon() {
|
|
1707
|
-
return /* @__PURE__ */ (0,
|
|
1743
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1708
1744
|
"svg",
|
|
1709
1745
|
{
|
|
1710
1746
|
width: "20",
|
|
@@ -1714,14 +1750,14 @@ function CloseIcon() {
|
|
|
1714
1750
|
xmlns: "http://www.w3.org/2000/svg",
|
|
1715
1751
|
"aria-hidden": "true",
|
|
1716
1752
|
children: [
|
|
1717
|
-
/* @__PURE__ */ (0,
|
|
1718
|
-
/* @__PURE__ */ (0,
|
|
1753
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "5", y1: "5", x2: "15", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
|
|
1754
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "15", y1: "5", x2: "5", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
|
|
1719
1755
|
]
|
|
1720
1756
|
}
|
|
1721
1757
|
);
|
|
1722
1758
|
}
|
|
1723
1759
|
function SearchClearIcon() {
|
|
1724
|
-
return /* @__PURE__ */ (0,
|
|
1760
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1725
1761
|
"svg",
|
|
1726
1762
|
{
|
|
1727
1763
|
width: "16",
|
|
@@ -1730,19 +1766,19 @@ function SearchClearIcon() {
|
|
|
1730
1766
|
fill: "currentColor",
|
|
1731
1767
|
xmlns: "http://www.w3.org/2000/svg",
|
|
1732
1768
|
"aria-hidden": "true",
|
|
1733
|
-
children: /* @__PURE__ */ (0,
|
|
1769
|
+
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" })
|
|
1734
1770
|
}
|
|
1735
1771
|
);
|
|
1736
1772
|
}
|
|
1737
1773
|
|
|
1738
1774
|
// src/components/MixMatchBundle.tsx
|
|
1739
|
-
var
|
|
1775
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1740
1776
|
function ruleFor2(bundle, productId, variantId) {
|
|
1741
1777
|
if (variantId) {
|
|
1742
1778
|
const vRule = bundle.variantRules[variantId];
|
|
1743
1779
|
if (vRule) return vRule;
|
|
1744
1780
|
}
|
|
1745
|
-
return bundle.productRules[productId] ??
|
|
1781
|
+
return bundle.productRules[productId] ?? import_core10.DEFAULT_PRODUCT_RULE;
|
|
1746
1782
|
}
|
|
1747
1783
|
function variantRuleFor2(bundle, variantId) {
|
|
1748
1784
|
return variantId ? bundle.variantRules[variantId] : void 0;
|
|
@@ -1769,17 +1805,14 @@ function MixMatchBundle(props) {
|
|
|
1769
1805
|
analyticsEnabled,
|
|
1770
1806
|
onAddToCart,
|
|
1771
1807
|
onError,
|
|
1772
|
-
className
|
|
1808
|
+
className,
|
|
1809
|
+
productHandle
|
|
1773
1810
|
} = props;
|
|
1774
1811
|
const result = useBundleData({
|
|
1775
1812
|
shopDomain,
|
|
1776
1813
|
storefrontAccessToken,
|
|
1777
1814
|
bundleGid
|
|
1778
1815
|
});
|
|
1779
|
-
const { outOfStockBehavior } = useShopSettings({
|
|
1780
|
-
shopDomain,
|
|
1781
|
-
storefrontAccessToken
|
|
1782
|
-
});
|
|
1783
1816
|
const { elementRef, trackAddToCart } = useAnalytics({
|
|
1784
1817
|
shopDomain,
|
|
1785
1818
|
appUrl: appUrl ?? `https://${shopDomain}`,
|
|
@@ -1813,33 +1846,60 @@ function MixMatchBundle(props) {
|
|
|
1813
1846
|
if (!bundle || seededFor === bundle.id) return;
|
|
1814
1847
|
setSeededFor(bundle.id);
|
|
1815
1848
|
const seedCurrency = bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? "USD";
|
|
1849
|
+
const pick = (product, variant, quantity) => ({
|
|
1850
|
+
productId: product.id,
|
|
1851
|
+
variantId: variant.id,
|
|
1852
|
+
title: product.title,
|
|
1853
|
+
url: `/products/${product.handle}`,
|
|
1854
|
+
variantTitle: variant.title,
|
|
1855
|
+
featuredImage: variant.image?.url ?? product.featuredImage?.url ?? null,
|
|
1856
|
+
price: parseFloat(variant.price.amount),
|
|
1857
|
+
compareAtPrice: variant.compareAtPrice ? parseFloat(variant.compareAtPrice.amount) : null,
|
|
1858
|
+
unitPrice: (0, import_core10.formatUnitPrice)(
|
|
1859
|
+
variant.unitPrice,
|
|
1860
|
+
variant.unitPriceMeasurement,
|
|
1861
|
+
seedCurrency
|
|
1862
|
+
),
|
|
1863
|
+
quantity
|
|
1864
|
+
});
|
|
1816
1865
|
const seeds = [];
|
|
1817
|
-
for (const
|
|
1818
|
-
|
|
1819
|
-
const
|
|
1820
|
-
|
|
1821
|
-
|
|
1866
|
+
for (const product of bundle.products) {
|
|
1867
|
+
let seededVariant = false;
|
|
1868
|
+
for (const variant2 of product.variants.nodes) {
|
|
1869
|
+
const vRule = bundle.variantRules[variant2.id];
|
|
1870
|
+
if (!vRule?.required) continue;
|
|
1871
|
+
if (!(0, import_core10.isVariantFulfillable)(variant2, Math.max(1, vRule.min))) continue;
|
|
1872
|
+
seeds.push(pick(product, variant2, Math.max(1, vRule.min)));
|
|
1873
|
+
seededVariant = true;
|
|
1874
|
+
}
|
|
1875
|
+
if (seededVariant) continue;
|
|
1876
|
+
const rule = bundle.productRules[product.id];
|
|
1877
|
+
if (!rule?.required) continue;
|
|
1878
|
+
const variant = product.variants.nodes.find(
|
|
1879
|
+
(v) => (0, import_core10.isVariantFulfillable)(v, rule.min)
|
|
1822
1880
|
);
|
|
1823
|
-
if (!
|
|
1824
|
-
seeds.push(
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1881
|
+
if (!variant) continue;
|
|
1882
|
+
seeds.push(pick(product, variant, rule.min));
|
|
1883
|
+
}
|
|
1884
|
+
if (seeds.length === 0 && productHandle) {
|
|
1885
|
+
const requiredUnits2 = bundle.minQuantity ?? 0;
|
|
1886
|
+
const qualifies = (p) => {
|
|
1887
|
+
const min = bundle.productRules[p.id]?.min ?? 1;
|
|
1888
|
+
return min <= requiredUnits2 && p.variants.nodes.some((v) => (0, import_core10.isVariantFulfillable)(v, min));
|
|
1889
|
+
};
|
|
1890
|
+
const seed = bundle.products.find(
|
|
1891
|
+
(p) => p.handle === productHandle && qualifies(p)
|
|
1892
|
+
) ?? bundle.products.find(qualifies);
|
|
1893
|
+
if (seed) {
|
|
1894
|
+
const min = bundle.productRules[seed.id]?.min ?? 1;
|
|
1895
|
+
const variant = seed.variants.nodes.find(
|
|
1896
|
+
(v) => (0, import_core10.isVariantFulfillable)(v, min)
|
|
1897
|
+
);
|
|
1898
|
+
if (variant) seeds.push(pick(seed, variant, min));
|
|
1899
|
+
}
|
|
1840
1900
|
}
|
|
1841
1901
|
if (seeds.length > 0) setSelections(seeds);
|
|
1842
|
-
}, [bundle, seededFor]);
|
|
1902
|
+
}, [bundle, seededFor, productHandle]);
|
|
1843
1903
|
const showStepper = bundle?.widgetConfig.mixMatchShowQuantitySelector !== false;
|
|
1844
1904
|
const requiredUnits = bundle?.minQuantity ?? 0;
|
|
1845
1905
|
const totalQuantity = (0, import_react12.useMemo)(
|
|
@@ -1857,7 +1917,7 @@ function MixMatchBundle(props) {
|
|
|
1857
1917
|
if (sel.quantity <= 0) continue;
|
|
1858
1918
|
comparePrice += sel.price * sel.quantity;
|
|
1859
1919
|
if (bundle) {
|
|
1860
|
-
salePrice += (0,
|
|
1920
|
+
salePrice += (0, import_core10.calculateDiscount)(
|
|
1861
1921
|
sel.price,
|
|
1862
1922
|
bundle.discountConfig.discountType,
|
|
1863
1923
|
bundle.discountConfig.discountValue
|
|
@@ -1999,9 +2059,9 @@ function MixMatchBundle(props) {
|
|
|
1999
2059
|
}
|
|
2000
2060
|
}, [bundle, selections, valid, onAddToCart, onError, trackAddToCart, totalQuantity]);
|
|
2001
2061
|
if (result.status === "loading") {
|
|
2002
|
-
return /* @__PURE__ */ (0,
|
|
2003
|
-
/* @__PURE__ */ (0,
|
|
2004
|
-
/* @__PURE__ */ (0,
|
|
2062
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: `lb-bundle lb-bundle--loading ${className ?? ""}`, children: [
|
|
2063
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "lb-skeleton lb-skeleton--title" }),
|
|
2064
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "lb-skeleton lb-skeleton--products" })
|
|
2005
2065
|
] });
|
|
2006
2066
|
}
|
|
2007
2067
|
if (result.status === "error") return null;
|
|
@@ -2013,14 +2073,14 @@ function MixMatchBundle(props) {
|
|
|
2013
2073
|
if (!rule.required) return false;
|
|
2014
2074
|
const product = bundle.products.find((p) => p.id === pid);
|
|
2015
2075
|
return !product?.variants.nodes.some(
|
|
2016
|
-
(v) => (0,
|
|
2076
|
+
(v) => (0, import_core10.isVariantFulfillable)(v, rule.min)
|
|
2017
2077
|
);
|
|
2018
2078
|
}
|
|
2019
2079
|
);
|
|
2020
2080
|
if (requiredBlocked) return null;
|
|
2021
2081
|
const currency = bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? "USD";
|
|
2022
2082
|
const ctaLabel = addingToCart ? "Adding..." : bundle.widgetConfig.cta.ctaText || "Add to cart";
|
|
2023
|
-
return /* @__PURE__ */ (0,
|
|
2083
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
2024
2084
|
"div",
|
|
2025
2085
|
{
|
|
2026
2086
|
ref: (el) => {
|
|
@@ -2032,12 +2092,19 @@ function MixMatchBundle(props) {
|
|
|
2032
2092
|
"aria-label": bundle.title,
|
|
2033
2093
|
"data-required-quantity": requiredUnits,
|
|
2034
2094
|
children: [
|
|
2035
|
-
/* @__PURE__ */ (0,
|
|
2036
|
-
/* @__PURE__ */ (0,
|
|
2037
|
-
bundle.description && /* @__PURE__ */ (0,
|
|
2095
|
+
/* @__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: [
|
|
2096
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { className: "lb-bundle-title", children: bundle.title }),
|
|
2097
|
+
bundle.description && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "lb-bundle-subtitle", children: bundle.description })
|
|
2038
2098
|
] }) }),
|
|
2039
|
-
/* @__PURE__ */ (0,
|
|
2040
|
-
|
|
2099
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2100
|
+
BundleCountdown,
|
|
2101
|
+
{
|
|
2102
|
+
endsAt: bundle.endsAt,
|
|
2103
|
+
widgetConfig: bundle.widgetConfig
|
|
2104
|
+
}
|
|
2105
|
+
),
|
|
2106
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "lb-mix-match__progress", "data-progress": true, children: [
|
|
2107
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2041
2108
|
"div",
|
|
2042
2109
|
{
|
|
2043
2110
|
className: "lb-mix-match__progress-segments",
|
|
@@ -2045,7 +2112,7 @@ function MixMatchBundle(props) {
|
|
|
2045
2112
|
"aria-valuenow": shownUnits,
|
|
2046
2113
|
"aria-valuemin": 0,
|
|
2047
2114
|
"aria-valuemax": requiredUnits,
|
|
2048
|
-
children: Array.from({ length: requiredUnits }).map((_, i) => /* @__PURE__ */ (0,
|
|
2115
|
+
children: Array.from({ length: requiredUnits }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2049
2116
|
"span",
|
|
2050
2117
|
{
|
|
2051
2118
|
className: `lb-mix-match__progress-segment${i < shownUnits ? " lb-mix-match__progress-segment--filled" : ""}`,
|
|
@@ -2055,8 +2122,8 @@ function MixMatchBundle(props) {
|
|
|
2055
2122
|
))
|
|
2056
2123
|
}
|
|
2057
2124
|
),
|
|
2058
|
-
/* @__PURE__ */ (0,
|
|
2059
|
-
/* @__PURE__ */ (0,
|
|
2125
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "lb-mix-match__progress-labels", children: [
|
|
2126
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2060
2127
|
"span",
|
|
2061
2128
|
{
|
|
2062
2129
|
className: "lb-mix-match__progress-count",
|
|
@@ -2065,7 +2132,7 @@ function MixMatchBundle(props) {
|
|
|
2065
2132
|
children: `${shownUnits} of ${requiredUnits} added`
|
|
2066
2133
|
}
|
|
2067
2134
|
),
|
|
2068
|
-
/* @__PURE__ */ (0,
|
|
2135
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2069
2136
|
"span",
|
|
2070
2137
|
{
|
|
2071
2138
|
className: "lb-mix-match__progress-remaining",
|
|
@@ -2076,7 +2143,7 @@ function MixMatchBundle(props) {
|
|
|
2076
2143
|
)
|
|
2077
2144
|
] })
|
|
2078
2145
|
] }),
|
|
2079
|
-
/* @__PURE__ */ (0,
|
|
2146
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2080
2147
|
"div",
|
|
2081
2148
|
{
|
|
2082
2149
|
className: "lb-mix-match__slots lb-edge-fade",
|
|
@@ -2087,15 +2154,15 @@ function MixMatchBundle(props) {
|
|
|
2087
2154
|
button provides the keyboard/AT path (its activation bubbles
|
|
2088
2155
|
here); × stops propagation. */
|
|
2089
2156
|
// 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
|
|
2090
|
-
/* @__PURE__ */ (0,
|
|
2157
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
2091
2158
|
"div",
|
|
2092
2159
|
{
|
|
2093
2160
|
className: "lb-mix-match__slot lb-mix-match__slot--filled",
|
|
2094
2161
|
onClick: () => setPickerOpen(true),
|
|
2095
2162
|
children: [
|
|
2096
|
-
item.featuredImage && /* @__PURE__ */ (0,
|
|
2097
|
-
/* @__PURE__ */ (0,
|
|
2098
|
-
/* @__PURE__ */ (0,
|
|
2163
|
+
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" }) }),
|
|
2164
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "lb-mix-match__filled-info", children: [
|
|
2165
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2099
2166
|
"button",
|
|
2100
2167
|
{
|
|
2101
2168
|
type: "button",
|
|
@@ -2104,15 +2171,15 @@ function MixMatchBundle(props) {
|
|
|
2104
2171
|
children: item.title
|
|
2105
2172
|
}
|
|
2106
2173
|
),
|
|
2107
|
-
item.variantTitle && item.variantTitle !== "Default Title" && /* @__PURE__ */ (0,
|
|
2108
|
-
/* @__PURE__ */ (0,
|
|
2109
|
-
item.compareAtPrice !== null && item.compareAtPrice > item.price && /* @__PURE__ */ (0,
|
|
2110
|
-
/* @__PURE__ */ (0,
|
|
2111
|
-
/* @__PURE__ */ (0,
|
|
2174
|
+
item.variantTitle && item.variantTitle !== "Default Title" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "lb-mix-match__filled-variant", children: item.variantTitle }),
|
|
2175
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "lb-mix-match__filled-price", children: [
|
|
2176
|
+
item.compareAtPrice !== null && item.compareAtPrice > item.price && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("s", { className: "lb-mix-match__filled-compare", children: (0, import_core10.formatMoney)(item.compareAtPrice, currency) }),
|
|
2177
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "lb-bundle-product-price", children: (0, import_core10.formatMoney)(item.price, currency) }),
|
|
2178
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "lb-bundle-qty-inline", children: `\xD7${item.quantity}` })
|
|
2112
2179
|
] }),
|
|
2113
|
-
item.unitPrice && /* @__PURE__ */ (0,
|
|
2180
|
+
item.unitPrice && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "lb-bundle-product-unit-price", children: item.unitPrice })
|
|
2114
2181
|
] }),
|
|
2115
|
-
canRemoveItem(bundle, selections, item) ? /* @__PURE__ */ (0,
|
|
2182
|
+
canRemoveItem(bundle, selections, item) ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2116
2183
|
"button",
|
|
2117
2184
|
{
|
|
2118
2185
|
type: "button",
|
|
@@ -2122,13 +2189,13 @@ function MixMatchBundle(props) {
|
|
|
2122
2189
|
e.stopPropagation();
|
|
2123
2190
|
removeSlot(index);
|
|
2124
2191
|
},
|
|
2125
|
-
children: /* @__PURE__ */ (0,
|
|
2192
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CloseIcon2, {})
|
|
2126
2193
|
}
|
|
2127
2194
|
) : (
|
|
2128
2195
|
/* Required pick at its floor — quiet state chip instead of
|
|
2129
2196
|
the ×; removal returns once another slot covers the
|
|
2130
2197
|
product's minimum (variant swap flow). */
|
|
2131
|
-
/* @__PURE__ */ (0,
|
|
2198
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "lb-mix-match__slot-required", children: "Required" })
|
|
2132
2199
|
)
|
|
2133
2200
|
]
|
|
2134
2201
|
},
|
|
@@ -2137,7 +2204,7 @@ function MixMatchBundle(props) {
|
|
|
2137
2204
|
))
|
|
2138
2205
|
}
|
|
2139
2206
|
),
|
|
2140
|
-
totalQuantity < requiredUnits && /* @__PURE__ */ (0,
|
|
2207
|
+
totalQuantity < requiredUnits && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
2141
2208
|
"button",
|
|
2142
2209
|
{
|
|
2143
2210
|
type: "button",
|
|
@@ -2145,34 +2212,34 @@ function MixMatchBundle(props) {
|
|
|
2145
2212
|
"data-add-product-trigger": true,
|
|
2146
2213
|
onClick: () => setPickerOpen(true),
|
|
2147
2214
|
children: [
|
|
2148
|
-
/* @__PURE__ */ (0,
|
|
2149
|
-
/* @__PURE__ */ (0,
|
|
2215
|
+
/* @__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, {}) }),
|
|
2216
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "lb-mix-match__add-product-label", children: "Add a product" })
|
|
2150
2217
|
]
|
|
2151
2218
|
}
|
|
2152
2219
|
),
|
|
2153
|
-
/* @__PURE__ */ (0,
|
|
2154
|
-
selections.length > 0 && /* @__PURE__ */ (0,
|
|
2155
|
-
/* @__PURE__ */ (0,
|
|
2156
|
-
/* @__PURE__ */ (0,
|
|
2157
|
-
bundle.widgetConfig.savingsBar.visible && summary.savings > 0 && /* @__PURE__ */ (0,
|
|
2220
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "lb-bundle-divider" }),
|
|
2221
|
+
selections.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "lb-bundle-summary", "data-pricing-section": true, children: [
|
|
2222
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "lb-bundle-summary__text", children: [
|
|
2223
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "lb-bundle-summary__label", children: "Bundle total" }),
|
|
2224
|
+
bundle.widgetConfig.savingsBar.visible && summary.savings > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { className: "lb-bundle-savings-line", "data-savings-bar": true, children: [
|
|
2158
2225
|
"You save",
|
|
2159
2226
|
" ",
|
|
2160
|
-
/* @__PURE__ */ (0,
|
|
2227
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { "data-savings-amount": true, children: (0, import_core10.formatMoney)(summary.savings, currency) }),
|
|
2161
2228
|
" ",
|
|
2162
|
-
/* @__PURE__ */ (0,
|
|
2229
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { "data-savings-percent": true, children: [
|
|
2163
2230
|
"(",
|
|
2164
2231
|
summary.savingsPercent,
|
|
2165
2232
|
"%)"
|
|
2166
2233
|
] })
|
|
2167
2234
|
] })
|
|
2168
2235
|
] }),
|
|
2169
|
-
/* @__PURE__ */ (0,
|
|
2170
|
-
bundle.widgetConfig.pricing.showComparePrice && summary.savings > 0 && /* @__PURE__ */ (0,
|
|
2171
|
-
/* @__PURE__ */ (0,
|
|
2236
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "lb-bundle-summary__prices", children: [
|
|
2237
|
+
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_core10.formatMoney)(summary.comparePrice, currency) }),
|
|
2238
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "lb-bundle-sale-price", "data-sale-price": true, children: (0, import_core10.formatMoney)(summary.salePrice, currency) })
|
|
2172
2239
|
] })
|
|
2173
2240
|
] }),
|
|
2174
|
-
cartError && /* @__PURE__ */ (0,
|
|
2175
|
-
/* @__PURE__ */ (0,
|
|
2241
|
+
cartError && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "lb-bundle__error", role: "alert", children: cartError }),
|
|
2242
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2176
2243
|
"button",
|
|
2177
2244
|
{
|
|
2178
2245
|
className: "lb-bundle__cta",
|
|
@@ -2182,10 +2249,9 @@ function MixMatchBundle(props) {
|
|
|
2182
2249
|
children: ctaLabel
|
|
2183
2250
|
}
|
|
2184
2251
|
),
|
|
2185
|
-
pickerOpen && /* @__PURE__ */ (0,
|
|
2252
|
+
pickerOpen && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2186
2253
|
MixMatchPicker,
|
|
2187
2254
|
{
|
|
2188
|
-
outOfStockBehavior,
|
|
2189
2255
|
bundle,
|
|
2190
2256
|
currency,
|
|
2191
2257
|
requiredQty: requiredUnits,
|
|
@@ -2216,14 +2282,14 @@ function countInStockProducts(bundle) {
|
|
|
2216
2282
|
seen.add(product.id);
|
|
2217
2283
|
const rule = ruleFor2(bundle, product.id);
|
|
2218
2284
|
const fulfillable = product.variants.nodes.some(
|
|
2219
|
-
(v) => (0,
|
|
2285
|
+
(v) => (0, import_core10.isVariantFulfillable)(v, rule.min)
|
|
2220
2286
|
);
|
|
2221
2287
|
if (fulfillable) count += 1;
|
|
2222
2288
|
}
|
|
2223
2289
|
return count;
|
|
2224
2290
|
}
|
|
2225
2291
|
function PlusIcon() {
|
|
2226
|
-
return /* @__PURE__ */ (0,
|
|
2292
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
2227
2293
|
"svg",
|
|
2228
2294
|
{
|
|
2229
2295
|
width: "18",
|
|
@@ -2233,14 +2299,14 @@ function PlusIcon() {
|
|
|
2233
2299
|
xmlns: "http://www.w3.org/2000/svg",
|
|
2234
2300
|
"aria-hidden": "true",
|
|
2235
2301
|
children: [
|
|
2236
|
-
/* @__PURE__ */ (0,
|
|
2237
|
-
/* @__PURE__ */ (0,
|
|
2302
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "9", y1: "3", x2: "9", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
|
|
2303
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "3", y1: "9", x2: "15", y2: "9", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
|
|
2238
2304
|
]
|
|
2239
2305
|
}
|
|
2240
2306
|
);
|
|
2241
2307
|
}
|
|
2242
2308
|
function CloseIcon2() {
|
|
2243
|
-
return /* @__PURE__ */ (0,
|
|
2309
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
2244
2310
|
"svg",
|
|
2245
2311
|
{
|
|
2246
2312
|
width: "16",
|
|
@@ -2250,8 +2316,8 @@ function CloseIcon2() {
|
|
|
2250
2316
|
xmlns: "http://www.w3.org/2000/svg",
|
|
2251
2317
|
"aria-hidden": "true",
|
|
2252
2318
|
children: [
|
|
2253
|
-
/* @__PURE__ */ (0,
|
|
2254
|
-
/* @__PURE__ */ (0,
|
|
2319
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "5", y1: "5", x2: "15", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
|
|
2320
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "15", y1: "5", x2: "5", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
|
|
2255
2321
|
]
|
|
2256
2322
|
}
|
|
2257
2323
|
);
|
|
@@ -2259,8 +2325,8 @@ function CloseIcon2() {
|
|
|
2259
2325
|
|
|
2260
2326
|
// src/components/VolumeBundle.tsx
|
|
2261
2327
|
var import_react13 = require("react");
|
|
2262
|
-
var
|
|
2263
|
-
var
|
|
2328
|
+
var import_core11 = require("@lime-bundles/core");
|
|
2329
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
2264
2330
|
function VolumeBundle(props) {
|
|
2265
2331
|
const {
|
|
2266
2332
|
shopDomain,
|
|
@@ -2287,7 +2353,24 @@ function VolumeBundle(props) {
|
|
|
2287
2353
|
const [quantity, setQuantity] = (0, import_react13.useState)(1);
|
|
2288
2354
|
const [addingToCart, setAddingToCart] = (0, import_react13.useState)(false);
|
|
2289
2355
|
const [cartError, setCartError] = (0, import_react13.useState)(null);
|
|
2356
|
+
const [seededFor, setSeededFor] = (0, import_react13.useState)(null);
|
|
2290
2357
|
const bundle = result.status === "success" && result.bundle.bundleType === "volume" ? result.bundle : null;
|
|
2358
|
+
(0, import_react13.useEffect)(() => {
|
|
2359
|
+
if (!bundle || seededFor === bundle.id) return;
|
|
2360
|
+
setSeededFor(bundle.id);
|
|
2361
|
+
const tiers = bundle.volumeTiers;
|
|
2362
|
+
if (tiers.length === 0) return;
|
|
2363
|
+
const best = (0, import_core11.bestValueTierIndex)(
|
|
2364
|
+
tiers,
|
|
2365
|
+
bundle.discountConfig.discountType
|
|
2366
|
+
);
|
|
2367
|
+
const idx = (0, import_core11.resolveDefaultTierIndex)(
|
|
2368
|
+
bundle.widgetConfig.defaultTier,
|
|
2369
|
+
tiers.length,
|
|
2370
|
+
best
|
|
2371
|
+
);
|
|
2372
|
+
setQuantity(tiers[idx].minQuantity);
|
|
2373
|
+
}, [bundle, seededFor]);
|
|
2291
2374
|
const setConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);
|
|
2292
2375
|
const tiersEdgeFadeRef = useEdgeFade();
|
|
2293
2376
|
(0, import_react13.useEffect)(() => {
|
|
@@ -2311,19 +2394,24 @@ function VolumeBundle(props) {
|
|
|
2311
2394
|
}, [variants]);
|
|
2312
2395
|
const showPicker = variants.length > 1 && optionNames.length > 0;
|
|
2313
2396
|
const { selectedValues, selectedVariant, setOptionValue, optionsFor } = useVariantSelection({ variants, optionNames });
|
|
2314
|
-
const minTierQty = bundle ? (0,
|
|
2315
|
-
const isSoldOut = variants.length > 0 && !variants.some((v) => (0,
|
|
2316
|
-
const displayVariant = selectedVariant ?? variants.find((v) => (0,
|
|
2397
|
+
const minTierQty = bundle ? (0, import_core11.getMinTierQuantity)(bundle.volumeTiers) : 1;
|
|
2398
|
+
const isSoldOut = variants.length > 0 && !variants.some((v) => (0, import_core11.isVariantFulfillable)(v, minTierQty));
|
|
2399
|
+
const displayVariant = selectedVariant ?? variants.find((v) => (0, import_core11.isVariantFulfillable)(v, minTierQty)) ?? variants[0];
|
|
2400
|
+
const tierAvailable = (0, import_react13.useCallback)(
|
|
2401
|
+
(tierQty) => Boolean(displayVariant && (0, import_core11.isVariantFulfillable)(displayVariant, tierQty)),
|
|
2402
|
+
[displayVariant]
|
|
2403
|
+
);
|
|
2404
|
+
const selectedTierUnavailable = !isSoldOut && !tierAvailable(quantity);
|
|
2317
2405
|
const basePrice = displayVariant ? parseFloat(displayVariant.price.amount) : product ? parseFloat(product.priceRange.minVariantPrice.amount) : 0;
|
|
2318
2406
|
const currency = product?.priceRange.minVariantPrice.currencyCode ?? "USD";
|
|
2319
2407
|
const thumbImage = displayVariant?.image ?? product?.featuredImage ?? null;
|
|
2320
|
-
const unitPriceText = displayVariant ? (0,
|
|
2408
|
+
const unitPriceText = displayVariant ? (0, import_core11.formatUnitPrice)(
|
|
2321
2409
|
displayVariant.unitPrice,
|
|
2322
2410
|
displayVariant.unitPriceMeasurement,
|
|
2323
2411
|
currency
|
|
2324
2412
|
) : null;
|
|
2325
2413
|
const tierSavings = (0, import_react13.useMemo)(
|
|
2326
|
-
() => bundle ? (0,
|
|
2414
|
+
() => bundle ? (0, import_core11.calculateTierSavings)(
|
|
2327
2415
|
bundle.volumeTiers,
|
|
2328
2416
|
basePrice,
|
|
2329
2417
|
quantity,
|
|
@@ -2331,21 +2419,18 @@ function VolumeBundle(props) {
|
|
|
2331
2419
|
) : [],
|
|
2332
2420
|
[bundle, basePrice, quantity]
|
|
2333
2421
|
);
|
|
2334
|
-
const activeTier = bundle ? (0,
|
|
2422
|
+
const activeTier = bundle ? (0, import_core11.getActiveTier)(bundle.volumeTiers, quantity) : null;
|
|
2335
2423
|
const popularTierIndex = (0, import_react13.useMemo)(() => {
|
|
2336
|
-
if (!bundle
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
}
|
|
2347
|
-
return best;
|
|
2348
|
-
}, [bundle, tierSavings]);
|
|
2424
|
+
if (!bundle || bundle.volumeTiers.length === 0) return -1;
|
|
2425
|
+
return (0, import_core11.resolvePopularTierIndex)(
|
|
2426
|
+
bundle.widgetConfig.popularBadge.tierIndex,
|
|
2427
|
+
bundle.widgetConfig.popularBadge.visible !== false,
|
|
2428
|
+
(0, import_core11.bestValueTierIndex)(
|
|
2429
|
+
bundle.volumeTiers,
|
|
2430
|
+
bundle.discountConfig.discountType
|
|
2431
|
+
)
|
|
2432
|
+
);
|
|
2433
|
+
}, [bundle]);
|
|
2349
2434
|
const activeUnitPrice = tierSavings.find((ts) => ts.tier === activeTier)?.unitPrice ?? basePrice;
|
|
2350
2435
|
const undiscountedTotal = basePrice * quantity;
|
|
2351
2436
|
const volumeTotal = activeUnitPrice * quantity;
|
|
@@ -2354,7 +2439,7 @@ function VolumeBundle(props) {
|
|
|
2354
2439
|
const handleAddToCart = (0, import_react13.useCallback)(async () => {
|
|
2355
2440
|
if (!bundle || !product) return;
|
|
2356
2441
|
const variant = selectedVariant ?? product.variants.nodes.find(
|
|
2357
|
-
(v) => (0,
|
|
2442
|
+
(v) => (0, import_core11.isVariantFulfillable)(v, quantity)
|
|
2358
2443
|
);
|
|
2359
2444
|
if (!variant) return;
|
|
2360
2445
|
const lines = [
|
|
@@ -2397,15 +2482,15 @@ function VolumeBundle(props) {
|
|
|
2397
2482
|
tierSavings
|
|
2398
2483
|
]);
|
|
2399
2484
|
if (result.status === "loading") {
|
|
2400
|
-
return /* @__PURE__ */ (0,
|
|
2401
|
-
/* @__PURE__ */ (0,
|
|
2402
|
-
/* @__PURE__ */ (0,
|
|
2485
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: `lb-bundle lb-bundle--loading ${className ?? ""}`, children: [
|
|
2486
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "lb-skeleton lb-skeleton--title" }),
|
|
2487
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "lb-skeleton lb-skeleton--tiers" })
|
|
2403
2488
|
] });
|
|
2404
2489
|
}
|
|
2405
2490
|
if (result.status === "error") return null;
|
|
2406
2491
|
if (!bundle) return null;
|
|
2407
2492
|
if (!product) return null;
|
|
2408
|
-
return /* @__PURE__ */ (0,
|
|
2493
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2409
2494
|
"div",
|
|
2410
2495
|
{
|
|
2411
2496
|
ref: (el) => {
|
|
@@ -2416,12 +2501,19 @@ function VolumeBundle(props) {
|
|
|
2416
2501
|
role: "region",
|
|
2417
2502
|
"aria-label": bundle.title,
|
|
2418
2503
|
children: [
|
|
2419
|
-
/* @__PURE__ */ (0,
|
|
2420
|
-
/* @__PURE__ */ (0,
|
|
2421
|
-
bundle.description && /* @__PURE__ */ (0,
|
|
2504
|
+
/* @__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: [
|
|
2505
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { className: "lb-bundle-title", children: bundle.title }),
|
|
2506
|
+
bundle.description && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "lb-bundle-subtitle", children: bundle.description })
|
|
2422
2507
|
] }) }),
|
|
2423
|
-
/* @__PURE__ */ (0,
|
|
2424
|
-
|
|
2508
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2509
|
+
BundleCountdown,
|
|
2510
|
+
{
|
|
2511
|
+
endsAt: bundle.endsAt,
|
|
2512
|
+
widgetConfig: bundle.widgetConfig
|
|
2513
|
+
}
|
|
2514
|
+
),
|
|
2515
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "lb-bundle-product-row lb-bundle-product-row--volume", children: [
|
|
2516
|
+
thumbImage && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2425
2517
|
"img",
|
|
2426
2518
|
{
|
|
2427
2519
|
src: thumbImage.url,
|
|
@@ -2430,20 +2522,20 @@ function VolumeBundle(props) {
|
|
|
2430
2522
|
loading: "lazy"
|
|
2431
2523
|
}
|
|
2432
2524
|
),
|
|
2433
|
-
/* @__PURE__ */ (0,
|
|
2434
|
-
/* @__PURE__ */ (0,
|
|
2435
|
-
/* @__PURE__ */ (0,
|
|
2436
|
-
(0,
|
|
2525
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "lb-bundle__product-info", children: [
|
|
2526
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "lb-bundle__product-title", children: product.title }),
|
|
2527
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "lb-bundle__product-price", children: [
|
|
2528
|
+
(0, import_core11.formatMoney)(basePrice, currency),
|
|
2437
2529
|
" each"
|
|
2438
2530
|
] }),
|
|
2439
|
-
unitPriceText && /* @__PURE__ */ (0,
|
|
2440
|
-
showPicker && /* @__PURE__ */ (0,
|
|
2531
|
+
unitPriceText && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "lb-bundle__product-unit-price", children: unitPriceText }),
|
|
2532
|
+
showPicker && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "lb-bundle__product-variant-pickers", children: optionNames.map((optionName, optionIndex) => {
|
|
2441
2533
|
const dropdownOptions = optionsFor(optionIndex).map((o) => ({
|
|
2442
2534
|
value: o.value,
|
|
2443
2535
|
label: o.value,
|
|
2444
2536
|
disabled: o.disabled
|
|
2445
2537
|
}));
|
|
2446
|
-
return /* @__PURE__ */ (0,
|
|
2538
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2447
2539
|
VariantDropdown,
|
|
2448
2540
|
{
|
|
2449
2541
|
options: dropdownOptions,
|
|
@@ -2456,37 +2548,51 @@ function VolumeBundle(props) {
|
|
|
2456
2548
|
}) })
|
|
2457
2549
|
] })
|
|
2458
2550
|
] }),
|
|
2459
|
-
/* @__PURE__ */ (0,
|
|
2551
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2460
2552
|
"div",
|
|
2461
2553
|
{
|
|
2462
2554
|
className: "lb-bundle__tiers lb-edge-fade",
|
|
2463
|
-
role: "
|
|
2464
|
-
"aria-label": "
|
|
2555
|
+
role: "radiogroup",
|
|
2556
|
+
"aria-label": "Select quantity",
|
|
2465
2557
|
ref: tiersEdgeFadeRef,
|
|
2466
2558
|
children: tierSavings.map((ts, tierIndex) => {
|
|
2467
2559
|
const savingsPercent = Math.round(ts.savingsPercent);
|
|
2468
2560
|
const showCompare = bundle.widgetConfig.pricing.showComparePrice && ts.savings > 0;
|
|
2469
|
-
|
|
2561
|
+
const isChecked = activeTier === ts.tier;
|
|
2562
|
+
const available = tierAvailable(ts.tier.minQuantity);
|
|
2563
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2470
2564
|
"div",
|
|
2471
2565
|
{
|
|
2472
|
-
className: `lb-bundle__tier ${ts.isActive ? "lb-bundle__tier--active" : ""}`,
|
|
2473
|
-
role: "
|
|
2566
|
+
className: `lb-bundle__tier ${ts.isActive ? "lb-bundle__tier--active" : ""} ${available ? "" : "lb-bundle__tier--oos"}`,
|
|
2567
|
+
role: "radio",
|
|
2568
|
+
"aria-checked": isChecked,
|
|
2569
|
+
"aria-disabled": available ? void 0 : true,
|
|
2570
|
+
tabIndex: isChecked ? 0 : -1,
|
|
2571
|
+
onClick: () => {
|
|
2572
|
+
if (available) setQuantity(ts.tier.minQuantity);
|
|
2573
|
+
},
|
|
2574
|
+
onKeyDown: (e) => {
|
|
2575
|
+
if ((e.key === "Enter" || e.key === " ") && available) {
|
|
2576
|
+
e.preventDefault();
|
|
2577
|
+
setQuantity(ts.tier.minQuantity);
|
|
2578
|
+
}
|
|
2579
|
+
},
|
|
2474
2580
|
children: [
|
|
2475
|
-
/* @__PURE__ */ (0,
|
|
2476
|
-
/* @__PURE__ */ (0,
|
|
2477
|
-
/* @__PURE__ */ (0,
|
|
2581
|
+
/* @__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" }) }),
|
|
2582
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "lb-bundle__tier-info", children: [
|
|
2583
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "lb-bundle__tier-label", children: [
|
|
2478
2584
|
"Buy ",
|
|
2479
2585
|
ts.tier.minQuantity
|
|
2480
2586
|
] }),
|
|
2481
|
-
/* @__PURE__ */ (0,
|
|
2482
|
-
showCompare && /* @__PURE__ */ (0,
|
|
2483
|
-
/* @__PURE__ */ (0,
|
|
2484
|
-
/* @__PURE__ */ (0,
|
|
2587
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "lb-bundle__tier-price", children: [
|
|
2588
|
+
showCompare && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "lb-bundle__tier-compare", children: (0, import_core11.formatMoney)(basePrice, currency) }),
|
|
2589
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: (0, import_core11.formatMoney)(ts.unitPrice, currency) }),
|
|
2590
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "lb-bundle__tier-unit", children: "each" })
|
|
2485
2591
|
] })
|
|
2486
2592
|
] }),
|
|
2487
|
-
(tierIndex === popularTierIndex || savingsPercent > 0) && /* @__PURE__ */ (0,
|
|
2488
|
-
tierIndex === popularTierIndex && /* @__PURE__ */ (0,
|
|
2489
|
-
savingsPercent > 0 && /* @__PURE__ */ (0,
|
|
2593
|
+
(tierIndex === popularTierIndex || savingsPercent > 0) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "lb-bundle__tier-right", children: [
|
|
2594
|
+
tierIndex === popularTierIndex && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "lb-bundle__tier-badge", children: bundle.widgetConfig.popularBadge.text }),
|
|
2595
|
+
savingsPercent > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "lb-bundle__tier-savings", children: [
|
|
2490
2596
|
"Save ",
|
|
2491
2597
|
savingsPercent,
|
|
2492
2598
|
"%"
|
|
@@ -2499,10 +2605,10 @@ function VolumeBundle(props) {
|
|
|
2499
2605
|
})
|
|
2500
2606
|
}
|
|
2501
2607
|
),
|
|
2502
|
-
/* @__PURE__ */ (0,
|
|
2503
|
-
/* @__PURE__ */ (0,
|
|
2504
|
-
/* @__PURE__ */ (0,
|
|
2505
|
-
/* @__PURE__ */ (0,
|
|
2608
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "lb-bundle__quantity-selector", children: [
|
|
2609
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("label", { htmlFor: `lb-qty-${bundle.id}`, children: "Quantity" }),
|
|
2610
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "lb-bundle__quantity-control", children: [
|
|
2611
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2506
2612
|
"button",
|
|
2507
2613
|
{
|
|
2508
2614
|
"aria-label": "Decrease quantity",
|
|
@@ -2510,7 +2616,7 @@ function VolumeBundle(props) {
|
|
|
2510
2616
|
children: "\u2212"
|
|
2511
2617
|
}
|
|
2512
2618
|
),
|
|
2513
|
-
/* @__PURE__ */ (0,
|
|
2619
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2514
2620
|
"input",
|
|
2515
2621
|
{
|
|
2516
2622
|
id: `lb-qty-${bundle.id}`,
|
|
@@ -2524,7 +2630,7 @@ function VolumeBundle(props) {
|
|
|
2524
2630
|
className: "lb-bundle__quantity-input"
|
|
2525
2631
|
}
|
|
2526
2632
|
),
|
|
2527
|
-
/* @__PURE__ */ (0,
|
|
2633
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2528
2634
|
"button",
|
|
2529
2635
|
{
|
|
2530
2636
|
"aria-label": "Increase quantity",
|
|
@@ -2534,23 +2640,23 @@ function VolumeBundle(props) {
|
|
|
2534
2640
|
)
|
|
2535
2641
|
] })
|
|
2536
2642
|
] }),
|
|
2537
|
-
cartError && /* @__PURE__ */ (0,
|
|
2538
|
-
bundle && displayVariant && (0,
|
|
2643
|
+
cartError && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "lb-bundle__error", role: "alert", children: cartError }),
|
|
2644
|
+
bundle && displayVariant && (0, import_core11.shouldShowLowStockBadge)(
|
|
2539
2645
|
displayVariant,
|
|
2540
2646
|
minTierQty,
|
|
2541
2647
|
bundle.widgetConfig.lowStockThreshold,
|
|
2542
2648
|
bundle.widgetConfig.showLowStockBadge
|
|
2543
|
-
) && /* @__PURE__ */ (0,
|
|
2649
|
+
) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "lb-bundle-low-stock-badge", children: [
|
|
2544
2650
|
"Only ",
|
|
2545
2651
|
displayVariant.quantityAvailable,
|
|
2546
2652
|
" left"
|
|
2547
2653
|
] }),
|
|
2548
|
-
/* @__PURE__ */ (0,
|
|
2549
|
-
/* @__PURE__ */ (0,
|
|
2550
|
-
/* @__PURE__ */ (0,
|
|
2551
|
-
/* @__PURE__ */ (0,
|
|
2654
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "lb-bundle-divider" }),
|
|
2655
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "lb-bundle-summary", children: [
|
|
2656
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "lb-bundle-summary__text", children: [
|
|
2657
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "lb-bundle-summary__label", "data-total-label": true, children: [
|
|
2552
2658
|
"Total",
|
|
2553
|
-
bundle.widgetConfig.pricing.showItemCount && /* @__PURE__ */ (0,
|
|
2659
|
+
bundle.widgetConfig.pricing.showItemCount && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { "data-item-count": true, children: [
|
|
2554
2660
|
" ",
|
|
2555
2661
|
"(",
|
|
2556
2662
|
quantity,
|
|
@@ -2559,31 +2665,31 @@ function VolumeBundle(props) {
|
|
|
2559
2665
|
")"
|
|
2560
2666
|
] })
|
|
2561
2667
|
] }),
|
|
2562
|
-
bundle.widgetConfig.savingsBar.visible && volumeSavings > 0 && /* @__PURE__ */ (0,
|
|
2668
|
+
bundle.widgetConfig.savingsBar.visible && volumeSavings > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "lb-bundle-savings-line", "data-savings-bar": true, children: [
|
|
2563
2669
|
"You save",
|
|
2564
2670
|
" ",
|
|
2565
|
-
/* @__PURE__ */ (0,
|
|
2671
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { "data-savings-amount": true, children: (0, import_core11.formatMoney)(volumeSavings, currency) }),
|
|
2566
2672
|
" ",
|
|
2567
|
-
/* @__PURE__ */ (0,
|
|
2673
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { "data-savings-percent": true, children: [
|
|
2568
2674
|
"(",
|
|
2569
2675
|
volumeSavingsPercent,
|
|
2570
2676
|
"%)"
|
|
2571
2677
|
] })
|
|
2572
2678
|
] })
|
|
2573
2679
|
] }),
|
|
2574
|
-
/* @__PURE__ */ (0,
|
|
2575
|
-
bundle.widgetConfig.pricing.showComparePrice && volumeSavings > 0 && /* @__PURE__ */ (0,
|
|
2576
|
-
/* @__PURE__ */ (0,
|
|
2680
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "lb-bundle-summary__prices", children: [
|
|
2681
|
+
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_core11.formatMoney)(undiscountedTotal, currency) }),
|
|
2682
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "lb-bundle-sale-price", "data-total-price": true, children: (0, import_core11.formatMoney)(volumeTotal, currency) })
|
|
2577
2683
|
] })
|
|
2578
2684
|
] }),
|
|
2579
|
-
/* @__PURE__ */ (0,
|
|
2685
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2580
2686
|
"button",
|
|
2581
2687
|
{
|
|
2582
2688
|
className: "lb-bundle__cta",
|
|
2583
2689
|
onClick: handleAddToCart,
|
|
2584
|
-
disabled: addingToCart || isSoldOut,
|
|
2690
|
+
disabled: addingToCart || isSoldOut || selectedTierUnavailable,
|
|
2585
2691
|
"aria-busy": addingToCart,
|
|
2586
|
-
children: addingToCart ? "Adding..." : isSoldOut ? "Sold out" : bundle.widgetConfig.cta.ctaText ?? `Add ${quantity} to Cart`
|
|
2692
|
+
children: addingToCart ? "Adding..." : isSoldOut || selectedTierUnavailable ? "Sold out" : bundle.widgetConfig.cta.ctaText ?? `Add ${quantity} to Cart`
|
|
2587
2693
|
}
|
|
2588
2694
|
)
|
|
2589
2695
|
]
|
|
@@ -2593,8 +2699,8 @@ function VolumeBundle(props) {
|
|
|
2593
2699
|
|
|
2594
2700
|
// src/components/BogoBundle.tsx
|
|
2595
2701
|
var import_react14 = require("react");
|
|
2596
|
-
var
|
|
2597
|
-
var
|
|
2702
|
+
var import_core12 = require("@lime-bundles/core");
|
|
2703
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
2598
2704
|
function discountedUnit(price, percent) {
|
|
2599
2705
|
const cents = Math.round(price * 100);
|
|
2600
2706
|
const discounted = cents - Math.floor(cents * percent / 100);
|
|
@@ -2662,13 +2768,13 @@ function BogoBundle(props) {
|
|
|
2662
2768
|
const resolveVariant = (0, import_react14.useCallback)(
|
|
2663
2769
|
(product, selected, qty) => {
|
|
2664
2770
|
if (!product) return null;
|
|
2665
|
-
return selected ?? product.variants.nodes.find((v) => (0,
|
|
2771
|
+
return selected ?? product.variants.nodes.find((v) => (0, import_core12.isVariantFulfillable)(v, qty)) ?? product.variants.nodes[0] ?? null;
|
|
2666
2772
|
},
|
|
2667
2773
|
[]
|
|
2668
2774
|
);
|
|
2669
2775
|
const oosSides = (0, import_react14.useMemo)(() => {
|
|
2670
2776
|
if (!bundle) return 0;
|
|
2671
|
-
const short = (product, qty) => !!product && !product.variants.nodes.some((v) => (0,
|
|
2777
|
+
const short = (product, qty) => !!product && !product.variants.nodes.some((v) => (0, import_core12.isVariantFulfillable)(v, qty));
|
|
2672
2778
|
return (short(buyProduct, bundle.buyQuantity) ? 1 : 0) + (short(getProduct, bundle.getQuantity) ? 1 : 0);
|
|
2673
2779
|
}, [bundle, buyProduct, getProduct]);
|
|
2674
2780
|
const handleAddToCart = (0, import_react14.useCallback)(async () => {
|
|
@@ -2718,9 +2824,9 @@ function BogoBundle(props) {
|
|
|
2718
2824
|
}
|
|
2719
2825
|
}, [bundle, buyProduct, getProduct, selectedVariants, resolveVariant, onAddToCart, onError, trackAddToCart, percent]);
|
|
2720
2826
|
if (result.status === "loading") {
|
|
2721
|
-
return /* @__PURE__ */ (0,
|
|
2722
|
-
/* @__PURE__ */ (0,
|
|
2723
|
-
/* @__PURE__ */ (0,
|
|
2827
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: `lb-bundle lb-bundle--loading ${className ?? ""}`, children: [
|
|
2828
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "lb-skeleton lb-skeleton--title" }),
|
|
2829
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "lb-skeleton lb-skeleton--products" })
|
|
2724
2830
|
] });
|
|
2725
2831
|
}
|
|
2726
2832
|
if (result.status === "error") return null;
|
|
@@ -2737,7 +2843,7 @@ function BogoBundle(props) {
|
|
|
2737
2843
|
const showCompare = bundle.widgetConfig.pricing.showComparePrice && savings > 0;
|
|
2738
2844
|
const showSavings = bundle.widgetConfig.savingsBar.visible && savings > 0;
|
|
2739
2845
|
const badge = percent === 100 ? "Free" : `${percent}% off`;
|
|
2740
|
-
return /* @__PURE__ */ (0,
|
|
2846
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
2741
2847
|
"div",
|
|
2742
2848
|
{
|
|
2743
2849
|
ref: (el) => {
|
|
@@ -2748,12 +2854,19 @@ function BogoBundle(props) {
|
|
|
2748
2854
|
role: "region",
|
|
2749
2855
|
"aria-label": bundle.title,
|
|
2750
2856
|
children: [
|
|
2751
|
-
/* @__PURE__ */ (0,
|
|
2752
|
-
/* @__PURE__ */ (0,
|
|
2753
|
-
bundle.description && /* @__PURE__ */ (0,
|
|
2857
|
+
/* @__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: [
|
|
2858
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h3", { className: "lb-bundle-title", children: bundle.title }),
|
|
2859
|
+
bundle.description && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "lb-bundle-subtitle", children: bundle.description })
|
|
2754
2860
|
] }) }),
|
|
2755
|
-
/* @__PURE__ */ (0,
|
|
2756
|
-
|
|
2861
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2862
|
+
BundleCountdown,
|
|
2863
|
+
{
|
|
2864
|
+
endsAt: bundle.endsAt,
|
|
2865
|
+
widgetConfig: bundle.widgetConfig
|
|
2866
|
+
}
|
|
2867
|
+
),
|
|
2868
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "lb-bundle__products", children: [
|
|
2869
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2757
2870
|
BogoProductRow,
|
|
2758
2871
|
{
|
|
2759
2872
|
side: "buy",
|
|
@@ -2765,11 +2878,11 @@ function BogoBundle(props) {
|
|
|
2765
2878
|
onVariantChange: handleVariantChange
|
|
2766
2879
|
}
|
|
2767
2880
|
),
|
|
2768
|
-
/* @__PURE__ */ (0,
|
|
2769
|
-
/* @__PURE__ */ (0,
|
|
2770
|
-
/* @__PURE__ */ (0,
|
|
2881
|
+
/* @__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: [
|
|
2882
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "9", y1: "3", x2: "9", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
|
|
2883
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "3", y1: "9", x2: "15", y2: "9", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
|
|
2771
2884
|
] }) }),
|
|
2772
|
-
/* @__PURE__ */ (0,
|
|
2885
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2773
2886
|
BogoProductRow,
|
|
2774
2887
|
{
|
|
2775
2888
|
side: "get",
|
|
@@ -2782,29 +2895,29 @@ function BogoBundle(props) {
|
|
|
2782
2895
|
}
|
|
2783
2896
|
)
|
|
2784
2897
|
] }),
|
|
2785
|
-
/* @__PURE__ */ (0,
|
|
2786
|
-
/* @__PURE__ */ (0,
|
|
2787
|
-
/* @__PURE__ */ (0,
|
|
2788
|
-
/* @__PURE__ */ (0,
|
|
2789
|
-
showSavings && /* @__PURE__ */ (0,
|
|
2898
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "lb-bundle-divider" }),
|
|
2899
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "lb-bundle-summary", children: [
|
|
2900
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "lb-bundle-summary__text", children: [
|
|
2901
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "lb-bundle-summary__label", children: "Bundle total" }),
|
|
2902
|
+
showSavings && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { className: "lb-bundle-savings-line", "data-savings-bar": true, children: [
|
|
2790
2903
|
"You save",
|
|
2791
2904
|
" ",
|
|
2792
|
-
/* @__PURE__ */ (0,
|
|
2905
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { "data-savings-amount": true, children: (0, import_core12.formatMoney)(savings, currency) }),
|
|
2793
2906
|
" ",
|
|
2794
|
-
/* @__PURE__ */ (0,
|
|
2907
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { "data-savings-percent": true, children: [
|
|
2795
2908
|
"(",
|
|
2796
2909
|
savingsPercent,
|
|
2797
2910
|
"%)"
|
|
2798
2911
|
] })
|
|
2799
2912
|
] })
|
|
2800
2913
|
] }),
|
|
2801
|
-
/* @__PURE__ */ (0,
|
|
2802
|
-
showCompare && /* @__PURE__ */ (0,
|
|
2803
|
-
/* @__PURE__ */ (0,
|
|
2914
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "lb-bundle-summary__prices", children: [
|
|
2915
|
+
showCompare && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "lb-bundle-compare-price", "data-compare-price": true, children: (0, import_core12.formatMoney)(comparePrice, currency) }),
|
|
2916
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "lb-bundle-sale-price", "data-sale-price": true, children: (0, import_core12.formatMoney)(salePrice, currency) })
|
|
2804
2917
|
] })
|
|
2805
2918
|
] }),
|
|
2806
|
-
cartError && /* @__PURE__ */ (0,
|
|
2807
|
-
/* @__PURE__ */ (0,
|
|
2919
|
+
cartError && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "lb-bundle__error", role: "alert", children: cartError }),
|
|
2920
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2808
2921
|
"button",
|
|
2809
2922
|
{
|
|
2810
2923
|
className: "lb-bundle__cta",
|
|
@@ -2832,19 +2945,19 @@ function BogoProductRow({ side, product, quantity, percent, badge, currency, onV
|
|
|
2832
2945
|
(0, import_react14.useEffect)(() => {
|
|
2833
2946
|
onVariantChange(side, selectedVariant ?? null);
|
|
2834
2947
|
}, [selectedVariant, side, onVariantChange]);
|
|
2835
|
-
const displayVariant = selectedVariant ?? variants.find((v) => (0,
|
|
2948
|
+
const displayVariant = selectedVariant ?? variants.find((v) => (0, import_core12.isVariantFulfillable)(v, quantity)) ?? variants[0];
|
|
2836
2949
|
const unit = displayVariant ? parseFloat(displayVariant.price.amount) : 0;
|
|
2837
2950
|
const isGet = side === "get" && percent > 0;
|
|
2838
|
-
const priceText = isGet ? (0,
|
|
2839
|
-
const compareAt = isGet ? (0,
|
|
2840
|
-
const unitPriceText = displayVariant ? (0,
|
|
2951
|
+
const priceText = isGet ? (0, import_core12.formatMoney)(discountedUnit(unit, percent), currency) : (0, import_core12.formatMoney)(unit, currency);
|
|
2952
|
+
const compareAt = isGet ? (0, import_core12.formatMoney)(unit, currency) : displayVariant?.compareAtPrice && parseFloat(displayVariant.compareAtPrice.amount) > unit ? (0, import_core12.formatMoney)(displayVariant.compareAtPrice.amount, currency) : null;
|
|
2953
|
+
const unitPriceText = displayVariant ? (0, import_core12.formatUnitPrice)(
|
|
2841
2954
|
displayVariant.unitPrice,
|
|
2842
2955
|
displayVariant.unitPriceMeasurement,
|
|
2843
2956
|
currency
|
|
2844
2957
|
) : null;
|
|
2845
2958
|
const thumbImage = displayVariant?.image ?? product.featuredImage;
|
|
2846
|
-
return /* @__PURE__ */ (0,
|
|
2847
|
-
thumbImage && /* @__PURE__ */ (0,
|
|
2959
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "lb-bundle-product-row", part: "product", "data-bogo-role": side, children: [
|
|
2960
|
+
thumbImage && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2848
2961
|
"img",
|
|
2849
2962
|
{
|
|
2850
2963
|
src: thumbImage.url,
|
|
@@ -2853,11 +2966,11 @@ function BogoProductRow({ side, product, quantity, percent, badge, currency, onV
|
|
|
2853
2966
|
loading: "lazy"
|
|
2854
2967
|
}
|
|
2855
2968
|
),
|
|
2856
|
-
/* @__PURE__ */ (0,
|
|
2857
|
-
/* @__PURE__ */ (0,
|
|
2858
|
-
!showPicker && displayVariant && variants.length > 1 && /* @__PURE__ */ (0,
|
|
2859
|
-
/* @__PURE__ */ (0,
|
|
2860
|
-
compareAt && /* @__PURE__ */ (0,
|
|
2969
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "lb-bundle__product-info", children: [
|
|
2970
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "lb-bundle__product-title", children: product.title }),
|
|
2971
|
+
!showPicker && displayVariant && variants.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "lb-bundle-variant-badge", children: displayVariant.title }),
|
|
2972
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "lb-bundle-product-prices", children: [
|
|
2973
|
+
compareAt && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2861
2974
|
"span",
|
|
2862
2975
|
{
|
|
2863
2976
|
className: "lb-bundle-product-compare-price",
|
|
@@ -2865,13 +2978,13 @@ function BogoProductRow({ side, product, quantity, percent, badge, currency, onV
|
|
|
2865
2978
|
children: compareAt
|
|
2866
2979
|
}
|
|
2867
2980
|
),
|
|
2868
|
-
/* @__PURE__ */ (0,
|
|
2869
|
-
/* @__PURE__ */ (0,
|
|
2981
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "lb-bundle__product-price", "data-product-price": true, children: priceText }),
|
|
2982
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "lb-bundle-qty-inline", "data-qty-inline": true, children: [
|
|
2870
2983
|
"\xD7",
|
|
2871
2984
|
quantity
|
|
2872
2985
|
] })
|
|
2873
2986
|
] }),
|
|
2874
|
-
unitPriceText && /* @__PURE__ */ (0,
|
|
2987
|
+
unitPriceText && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2875
2988
|
"span",
|
|
2876
2989
|
{
|
|
2877
2990
|
className: "lb-bundle__product-unit-price",
|
|
@@ -2879,13 +2992,13 @@ function BogoProductRow({ side, product, quantity, percent, badge, currency, onV
|
|
|
2879
2992
|
children: unitPriceText
|
|
2880
2993
|
}
|
|
2881
2994
|
),
|
|
2882
|
-
showPicker && /* @__PURE__ */ (0,
|
|
2995
|
+
showPicker && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "lb-bundle__product-variant-pickers", children: optionNames.map((optionName, optionIndex) => {
|
|
2883
2996
|
const dropdownOptions = optionsFor(optionIndex).map((o) => ({
|
|
2884
2997
|
value: o.value,
|
|
2885
2998
|
label: o.value,
|
|
2886
2999
|
disabled: o.disabled
|
|
2887
3000
|
}));
|
|
2888
|
-
return /* @__PURE__ */ (0,
|
|
3001
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2889
3002
|
VariantDropdown,
|
|
2890
3003
|
{
|
|
2891
3004
|
options: dropdownOptions,
|
|
@@ -2897,25 +3010,25 @@ function BogoProductRow({ side, product, quantity, percent, badge, currency, onV
|
|
|
2897
3010
|
);
|
|
2898
3011
|
}) })
|
|
2899
3012
|
] }),
|
|
2900
|
-
badge && /* @__PURE__ */ (0,
|
|
3013
|
+
badge && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "lb-bogo__badge", children: badge })
|
|
2901
3014
|
] });
|
|
2902
3015
|
}
|
|
2903
3016
|
|
|
2904
3017
|
// src/components/MultiStepBundle.tsx
|
|
2905
3018
|
var import_react16 = require("react");
|
|
2906
|
-
var
|
|
3019
|
+
var import_core14 = require("@lime-bundles/core");
|
|
2907
3020
|
|
|
2908
3021
|
// src/components/MultiStepPicker.tsx
|
|
2909
3022
|
var import_react15 = require("react");
|
|
2910
3023
|
var import_react_dom2 = require("react-dom");
|
|
2911
|
-
var
|
|
2912
|
-
var
|
|
3024
|
+
var import_core13 = require("@lime-bundles/core");
|
|
3025
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
2913
3026
|
function ruleFor3(bundle, productId, variantId) {
|
|
2914
3027
|
if (variantId) {
|
|
2915
3028
|
const vRule = bundle.variantRules[variantId];
|
|
2916
3029
|
if (vRule) return vRule;
|
|
2917
3030
|
}
|
|
2918
|
-
return bundle.productRules[productId] ??
|
|
3031
|
+
return bundle.productRules[productId] ?? import_core13.DEFAULT_PRODUCT_RULE;
|
|
2919
3032
|
}
|
|
2920
3033
|
function variantRuleFor3(bundle, variantId) {
|
|
2921
3034
|
return variantId ? bundle.variantRules[variantId] : void 0;
|
|
@@ -2923,15 +3036,14 @@ function variantRuleFor3(bundle, variantId) {
|
|
|
2923
3036
|
function sanitizeId2(gid) {
|
|
2924
3037
|
return gid.replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
2925
3038
|
}
|
|
2926
|
-
function buildEligibleProducts2(bundle, stepIndex
|
|
3039
|
+
function buildEligibleProducts2(bundle, stepIndex) {
|
|
2927
3040
|
const result = [];
|
|
2928
|
-
for (const product of (0,
|
|
3041
|
+
for (const product of (0, import_core13.productsForStep)(bundle, stepIndex)) {
|
|
2929
3042
|
const rule = ruleFor3(bundle, product.id);
|
|
2930
3043
|
const available = product.variants.nodes.filter(
|
|
2931
|
-
(v) => (0,
|
|
3044
|
+
(v) => (0, import_core13.isVariantFulfillable)(v, rule.min)
|
|
2932
3045
|
);
|
|
2933
3046
|
const isOos = available.length === 0;
|
|
2934
|
-
if (isOos && oosBehavior === "hide") continue;
|
|
2935
3047
|
result.push({
|
|
2936
3048
|
product,
|
|
2937
3049
|
variants: product.variants.nodes,
|
|
@@ -2946,7 +3058,6 @@ function normalizeText2(str) {
|
|
|
2946
3058
|
}
|
|
2947
3059
|
var FILTERS_ALL2 = "__all__";
|
|
2948
3060
|
function MultiStepPicker({
|
|
2949
|
-
outOfStockBehavior,
|
|
2950
3061
|
bundle,
|
|
2951
3062
|
currency,
|
|
2952
3063
|
initialStep,
|
|
@@ -2966,6 +3077,8 @@ function MultiStepPicker({
|
|
|
2966
3077
|
const overlayRef = (0, import_react15.useRef)(null);
|
|
2967
3078
|
const dialogRef = (0, import_react15.useRef)(null);
|
|
2968
3079
|
const titleRef = (0, import_react15.useRef)(null);
|
|
3080
|
+
const closeBtnRef = (0, import_react15.useRef)(null);
|
|
3081
|
+
const listRef = (0, import_react15.useRef)(null);
|
|
2969
3082
|
const mouseDownTarget = (0, import_react15.useRef)(null);
|
|
2970
3083
|
const [open, setOpen] = (0, import_react15.useState)(false);
|
|
2971
3084
|
const [stepIndex, setStepIndex] = (0, import_react15.useState)(
|
|
@@ -2982,8 +3095,8 @@ function MultiStepPicker({
|
|
|
2982
3095
|
const isLastStep = stepIndex === steps.length - 1;
|
|
2983
3096
|
const shownUnits = Math.min(unitsInStep, stepMin);
|
|
2984
3097
|
const eligible = (0, import_react15.useMemo)(
|
|
2985
|
-
() => buildEligibleProducts2(bundle, stepIndex
|
|
2986
|
-
[bundle, stepIndex
|
|
3098
|
+
() => buildEligibleProducts2(bundle, stepIndex),
|
|
3099
|
+
[bundle, stepIndex]
|
|
2987
3100
|
);
|
|
2988
3101
|
const productTypes = (0, import_react15.useMemo)(() => {
|
|
2989
3102
|
const types = [];
|
|
@@ -3006,8 +3119,23 @@ function MultiStepPicker({
|
|
|
3006
3119
|
useFocusTrap({
|
|
3007
3120
|
active: true,
|
|
3008
3121
|
containerRef: dialogRef,
|
|
3122
|
+
initialFocusRef: closeBtnRef,
|
|
3009
3123
|
onEscape: onClose
|
|
3010
3124
|
});
|
|
3125
|
+
(0, import_react15.useEffect)(() => {
|
|
3126
|
+
if (listRef.current) listRef.current.scrollTop = 0;
|
|
3127
|
+
}, [stepIndex]);
|
|
3128
|
+
const [selectedAtLoad, setSelectedAtLoad] = (0, import_react15.useState)(
|
|
3129
|
+
() => new Set((selections[stepIndex] ?? []).map((s) => s.productId))
|
|
3130
|
+
);
|
|
3131
|
+
const ordered = (0, import_react15.useMemo)(() => {
|
|
3132
|
+
const front = [];
|
|
3133
|
+
const back = [];
|
|
3134
|
+
for (const ep of eligible) {
|
|
3135
|
+
(selectedAtLoad.has(ep.product.id) ? back : front).push(ep);
|
|
3136
|
+
}
|
|
3137
|
+
return front.concat(back);
|
|
3138
|
+
}, [eligible, selectedAtLoad]);
|
|
3011
3139
|
function goToStep(i) {
|
|
3012
3140
|
const clamped = Math.max(0, Math.min(steps.length - 1, i));
|
|
3013
3141
|
setStepIndex(clamped);
|
|
@@ -3015,6 +3143,7 @@ function MultiStepPicker({
|
|
|
3015
3143
|
setActiveType(FILTERS_ALL2);
|
|
3016
3144
|
const target = steps[clamped];
|
|
3017
3145
|
const targetPicks = selections[clamped] ?? [];
|
|
3146
|
+
setSelectedAtLoad(new Set(targetPicks.map((s) => s.productId)));
|
|
3018
3147
|
const targetUnits = targetPicks.reduce((sum, s) => sum + s.quantity, 0);
|
|
3019
3148
|
setAnnouncement(
|
|
3020
3149
|
`Step ${clamped + 1} of ${steps.length}. ${target.name}. ${Math.min(targetUnits, target.minQuantity)} of ${target.minQuantity} added`
|
|
@@ -3024,12 +3153,12 @@ function MultiStepPicker({
|
|
|
3024
3153
|
const subtitle = `Step ${stepIndex + 1} of ${steps.length} \xB7 ${step?.name ?? ""}`;
|
|
3025
3154
|
const filtered = (0, import_react15.useMemo)(() => {
|
|
3026
3155
|
const nq = normalizeText2(query.trim());
|
|
3027
|
-
return
|
|
3156
|
+
return ordered.filter((ep) => {
|
|
3028
3157
|
const matchesQuery = !nq || normalizeText2(ep.product.title).includes(nq);
|
|
3029
3158
|
const matchesType = activeType === FILTERS_ALL2 || (ep.product.productType ?? "") === activeType;
|
|
3030
3159
|
return matchesQuery && matchesType;
|
|
3031
3160
|
});
|
|
3032
|
-
}, [
|
|
3161
|
+
}, [ordered, query, activeType]);
|
|
3033
3162
|
const showEmpty = filtered.length === 0 && query.trim().length > 0;
|
|
3034
3163
|
function onOverlayMouseDown(e) {
|
|
3035
3164
|
mouseDownTarget.current = e.target;
|
|
@@ -3047,7 +3176,7 @@ function MultiStepPicker({
|
|
|
3047
3176
|
// inside carries the interactive role + focus trap. So the static-element
|
|
3048
3177
|
// interaction lint does not apply to this backdrop.
|
|
3049
3178
|
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
|
|
3050
|
-
/* @__PURE__ */ (0,
|
|
3179
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3051
3180
|
"div",
|
|
3052
3181
|
{
|
|
3053
3182
|
ref: (el) => {
|
|
@@ -3059,7 +3188,7 @@ function MultiStepPicker({
|
|
|
3059
3188
|
"data-bundle-gid": bundle.id,
|
|
3060
3189
|
onMouseDown: onOverlayMouseDown,
|
|
3061
3190
|
onMouseUp: onOverlayMouseUp,
|
|
3062
|
-
children: /* @__PURE__ */ (0,
|
|
3191
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
3063
3192
|
"div",
|
|
3064
3193
|
{
|
|
3065
3194
|
ref: dialogRef,
|
|
@@ -3069,10 +3198,10 @@ function MultiStepPicker({
|
|
|
3069
3198
|
"aria-labelledby": titleId,
|
|
3070
3199
|
tabIndex: -1,
|
|
3071
3200
|
children: [
|
|
3072
|
-
/* @__PURE__ */ (0,
|
|
3073
|
-
/* @__PURE__ */ (0,
|
|
3074
|
-
/* @__PURE__ */ (0,
|
|
3075
|
-
/* @__PURE__ */ (0,
|
|
3201
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "lb-mix-match__modal-header", children: [
|
|
3202
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "lb-mix-match__modal-header-top", children: [
|
|
3203
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "lb-mix-match__modal-heading", children: [
|
|
3204
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3076
3205
|
"h4",
|
|
3077
3206
|
{
|
|
3078
3207
|
className: "lb-mix-match__modal-title",
|
|
@@ -3082,26 +3211,27 @@ function MultiStepPicker({
|
|
|
3082
3211
|
children: "Add to your bundle"
|
|
3083
3212
|
}
|
|
3084
3213
|
),
|
|
3085
|
-
/* @__PURE__ */ (0,
|
|
3214
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "lb-mix-match__modal-subtitle", "data-modal-subtitle": true, children: subtitle })
|
|
3086
3215
|
] }),
|
|
3087
|
-
/* @__PURE__ */ (0,
|
|
3216
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3088
3217
|
"button",
|
|
3089
3218
|
{
|
|
3219
|
+
ref: closeBtnRef,
|
|
3090
3220
|
type: "button",
|
|
3091
3221
|
className: "lb-mix-match__modal-close",
|
|
3092
3222
|
"data-modal-close": true,
|
|
3093
3223
|
"aria-label": "Close",
|
|
3094
3224
|
onClick: onClose,
|
|
3095
|
-
children: /* @__PURE__ */ (0,
|
|
3225
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CloseIcon3, {})
|
|
3096
3226
|
}
|
|
3097
3227
|
)
|
|
3098
3228
|
] }),
|
|
3099
|
-
/* @__PURE__ */ (0,
|
|
3229
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3100
3230
|
"div",
|
|
3101
3231
|
{
|
|
3102
3232
|
className: "lb-mix-match__progress lb-mix-match__modal-progress",
|
|
3103
3233
|
"data-progress": true,
|
|
3104
|
-
children: /* @__PURE__ */ (0,
|
|
3234
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3105
3235
|
"div",
|
|
3106
3236
|
{
|
|
3107
3237
|
className: "lb-mix-match__progress-segments",
|
|
@@ -3110,7 +3240,7 @@ function MultiStepPicker({
|
|
|
3110
3240
|
"aria-valuenow": shownUnits,
|
|
3111
3241
|
"aria-valuemin": 0,
|
|
3112
3242
|
"aria-valuemax": stepMin,
|
|
3113
|
-
children: Array.from({ length: stepMin }).map((_, i) => /* @__PURE__ */ (0,
|
|
3243
|
+
children: Array.from({ length: stepMin }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3114
3244
|
"span",
|
|
3115
3245
|
{
|
|
3116
3246
|
className: `lb-mix-match__progress-segment${i < shownUnits ? " lb-mix-match__progress-segment--filled" : ""}`,
|
|
@@ -3123,8 +3253,8 @@ function MultiStepPicker({
|
|
|
3123
3253
|
}
|
|
3124
3254
|
)
|
|
3125
3255
|
] }),
|
|
3126
|
-
wc.showSearch && /* @__PURE__ */ (0,
|
|
3127
|
-
/* @__PURE__ */ (0,
|
|
3256
|
+
wc.showSearch && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "lb-mix-match__modal-search", children: [
|
|
3257
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3128
3258
|
"input",
|
|
3129
3259
|
{
|
|
3130
3260
|
type: "text",
|
|
@@ -3138,7 +3268,7 @@ function MultiStepPicker({
|
|
|
3138
3268
|
onChange: (e) => setQuery(e.target.value)
|
|
3139
3269
|
}
|
|
3140
3270
|
),
|
|
3141
|
-
query.length > 0 && /* @__PURE__ */ (0,
|
|
3271
|
+
query.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3142
3272
|
"button",
|
|
3143
3273
|
{
|
|
3144
3274
|
type: "button",
|
|
@@ -3146,11 +3276,11 @@ function MultiStepPicker({
|
|
|
3146
3276
|
"data-modal-search-clear": true,
|
|
3147
3277
|
"aria-label": "Clear search",
|
|
3148
3278
|
onClick: () => setQuery(""),
|
|
3149
|
-
children: /* @__PURE__ */ (0,
|
|
3279
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SearchClearIcon2, {})
|
|
3150
3280
|
}
|
|
3151
3281
|
)
|
|
3152
3282
|
] }),
|
|
3153
|
-
showFilters && /* @__PURE__ */ (0,
|
|
3283
|
+
showFilters && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3154
3284
|
"div",
|
|
3155
3285
|
{
|
|
3156
3286
|
className: "lb-mix-match__filters",
|
|
@@ -3159,7 +3289,7 @@ function MultiStepPicker({
|
|
|
3159
3289
|
"aria-label": "Filter by product type",
|
|
3160
3290
|
children: [FILTERS_ALL2, ...productTypes].map((value) => {
|
|
3161
3291
|
const isActive = value === activeType;
|
|
3162
|
-
return /* @__PURE__ */ (0,
|
|
3292
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3163
3293
|
"button",
|
|
3164
3294
|
{
|
|
3165
3295
|
type: "button",
|
|
@@ -3174,7 +3304,7 @@ function MultiStepPicker({
|
|
|
3174
3304
|
})
|
|
3175
3305
|
}
|
|
3176
3306
|
),
|
|
3177
|
-
/* @__PURE__ */ (0,
|
|
3307
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "lb-mix-match__modal-list", "data-modal-list": true, ref: listRef, children: filtered.map((ep) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3178
3308
|
MultiStepPickerRow,
|
|
3179
3309
|
{
|
|
3180
3310
|
bundle,
|
|
@@ -3192,10 +3322,10 @@ function MultiStepPicker({
|
|
|
3192
3322
|
},
|
|
3193
3323
|
`${stepIndex}:${ep.product.id}`
|
|
3194
3324
|
)) }),
|
|
3195
|
-
showEmpty && /* @__PURE__ */ (0,
|
|
3196
|
-
/* @__PURE__ */ (0,
|
|
3197
|
-
/* @__PURE__ */ (0,
|
|
3198
|
-
stepIndex > 0 && /* @__PURE__ */ (0,
|
|
3325
|
+
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" }) }),
|
|
3326
|
+
/* @__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` : "") }),
|
|
3327
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "lb-mix-match__modal-footer lb-multi-step__modal-footer", children: [
|
|
3328
|
+
stepIndex > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3199
3329
|
"button",
|
|
3200
3330
|
{
|
|
3201
3331
|
type: "button",
|
|
@@ -3205,7 +3335,7 @@ function MultiStepPicker({
|
|
|
3205
3335
|
children: "Back"
|
|
3206
3336
|
}
|
|
3207
3337
|
),
|
|
3208
|
-
/* @__PURE__ */ (0,
|
|
3338
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3209
3339
|
"span",
|
|
3210
3340
|
{
|
|
3211
3341
|
className: "lb-mix-match__modal-footer-count",
|
|
@@ -3214,7 +3344,7 @@ function MultiStepPicker({
|
|
|
3214
3344
|
children: `${shownUnits} of ${stepMin} added`
|
|
3215
3345
|
}
|
|
3216
3346
|
),
|
|
3217
|
-
!isLastStep && /* @__PURE__ */ (0,
|
|
3347
|
+
!isLastStep && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3218
3348
|
"button",
|
|
3219
3349
|
{
|
|
3220
3350
|
type: "button",
|
|
@@ -3227,7 +3357,7 @@ function MultiStepPicker({
|
|
|
3227
3357
|
children: "Next"
|
|
3228
3358
|
}
|
|
3229
3359
|
),
|
|
3230
|
-
isLastStep && /* @__PURE__ */ (0,
|
|
3360
|
+
isLastStep && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3231
3361
|
"button",
|
|
3232
3362
|
{
|
|
3233
3363
|
type: "button",
|
|
@@ -3271,7 +3401,7 @@ function MultiStepPickerRow({
|
|
|
3271
3401
|
}, [variants]);
|
|
3272
3402
|
const showPicker = variants.length > 1 && optionNames.length > 0;
|
|
3273
3403
|
const { selectedValues, selectedVariant, setOptionValue, optionsFor } = useVariantSelection({ variants, optionNames });
|
|
3274
|
-
const currentVariant = selectedVariant ?? variants.find((v) => (0,
|
|
3404
|
+
const currentVariant = selectedVariant ?? variants.find((v) => (0, import_core13.isVariantFulfillable)(v, rule.min)) ?? eligible.firstAvailableVariant ?? variants[0] ?? null;
|
|
3275
3405
|
const vRule = ruleFor3(bundle, product.id, currentVariant?.id);
|
|
3276
3406
|
const variantMax = variantRuleFor3(bundle, currentVariant?.id)?.max;
|
|
3277
3407
|
const stepPicks = (0, import_react15.useMemo)(
|
|
@@ -3309,7 +3439,7 @@ function MultiStepPickerRow({
|
|
|
3309
3439
|
}, [selections, currentVariant, committedQty]);
|
|
3310
3440
|
const swapUnits = currentVariant ? swapUnitsFor?.(stepIndex, product.id, currentVariant.id) ?? 0 : 0;
|
|
3311
3441
|
const inSwapState = swapUnits >= vRule.min;
|
|
3312
|
-
const room = (0,
|
|
3442
|
+
const room = (0, import_core13.stepHeadroom)(step?.maxQuantity ?? null, unitsInStep);
|
|
3313
3443
|
const productHeadroom = Math.min(
|
|
3314
3444
|
rule.max - productOtherUnits,
|
|
3315
3445
|
variantMax ?? Infinity
|
|
@@ -3318,7 +3448,7 @@ function MultiStepPickerRow({
|
|
|
3318
3448
|
productHeadroom,
|
|
3319
3449
|
room === Number.POSITIVE_INFINITY ? productHeadroom : committedQty + room
|
|
3320
3450
|
);
|
|
3321
|
-
const stockRemaining = currentVariant ? (0,
|
|
3451
|
+
const stockRemaining = currentVariant ? (0, import_core13.maxAddableQuantity)(currentVariant, Number.MAX_SAFE_INTEGER, variantOtherUnits) : 0;
|
|
3322
3452
|
const cap = Math.max(0, Math.min(spotCeiling, stockRemaining));
|
|
3323
3453
|
const stepperMax = Math.max(vRule.min, cap);
|
|
3324
3454
|
const [qty, setQty] = (0, import_react15.useState)(vRule.min);
|
|
@@ -3331,7 +3461,7 @@ function MultiStepPickerRow({
|
|
|
3331
3461
|
}, [variantInStep, currentVariantId, vRule.min]);
|
|
3332
3462
|
if (!currentVariant || !step) return null;
|
|
3333
3463
|
const thumbImage = currentVariant.image ?? product.featuredImage ?? null;
|
|
3334
|
-
const unitPriceText = (0,
|
|
3464
|
+
const unitPriceText = (0, import_core13.formatUnitPrice)(
|
|
3335
3465
|
currentVariant.unitPrice,
|
|
3336
3466
|
currentVariant.unitPriceMeasurement,
|
|
3337
3467
|
currency
|
|
@@ -3370,7 +3500,7 @@ function MultiStepPickerRow({
|
|
|
3370
3500
|
}
|
|
3371
3501
|
const priceCents = parseFloat(currentVariant.price.amount);
|
|
3372
3502
|
const compareCents = currentVariant.compareAtPrice ? parseFloat(currentVariant.compareAtPrice.amount) : null;
|
|
3373
|
-
return /* @__PURE__ */ (0,
|
|
3503
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
3374
3504
|
"div",
|
|
3375
3505
|
{
|
|
3376
3506
|
className: `lb-mix-match__modal-product${isOos ? " lb-mix-match__modal-product--sold-out" : ""}${variantInStep ? " lb-mix-match__modal-product--in-bundle" : ""}`,
|
|
@@ -3379,8 +3509,8 @@ function MultiStepPickerRow({
|
|
|
3379
3509
|
"data-type": product.productType ?? "",
|
|
3380
3510
|
"aria-disabled": isOos || void 0,
|
|
3381
3511
|
children: [
|
|
3382
|
-
/* @__PURE__ */ (0,
|
|
3383
|
-
thumbImage && /* @__PURE__ */ (0,
|
|
3512
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "lb-mix-match__modal-product-thumb", children: [
|
|
3513
|
+
thumbImage && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3384
3514
|
"img",
|
|
3385
3515
|
{
|
|
3386
3516
|
src: thumbImage.url,
|
|
@@ -3388,10 +3518,10 @@ function MultiStepPickerRow({
|
|
|
3388
3518
|
loading: "lazy"
|
|
3389
3519
|
}
|
|
3390
3520
|
),
|
|
3391
|
-
variantInStep && /* @__PURE__ */ (0,
|
|
3521
|
+
variantInStep && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "lb-mix-match__modal-added-badge", children: "Added" })
|
|
3392
3522
|
] }),
|
|
3393
|
-
/* @__PURE__ */ (0,
|
|
3394
|
-
/* @__PURE__ */ (0,
|
|
3523
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "lb-mix-match__modal-product-info", children: [
|
|
3524
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "lb-mix-match__modal-product-title", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3395
3525
|
"a",
|
|
3396
3526
|
{
|
|
3397
3527
|
href: `/products/${product.handle}`,
|
|
@@ -3400,24 +3530,24 @@ function MultiStepPickerRow({
|
|
|
3400
3530
|
children: product.title
|
|
3401
3531
|
}
|
|
3402
3532
|
) }),
|
|
3403
|
-
/* @__PURE__ */ (0,
|
|
3404
|
-
/* @__PURE__ */ (0,
|
|
3405
|
-
compareCents !== null && compareCents > priceCents && /* @__PURE__ */ (0,
|
|
3533
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("p", { className: "lb-mix-match__modal-product-price", children: [
|
|
3534
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { "data-row-price-sale": true, children: (0, import_core13.formatMoney)(priceCents, currency) }),
|
|
3535
|
+
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_core13.formatMoney)(compareCents, currency) })
|
|
3406
3536
|
] }),
|
|
3407
|
-
unitPriceText && /* @__PURE__ */ (0,
|
|
3408
|
-
showPicker && /* @__PURE__ */ (0,
|
|
3537
|
+
unitPriceText && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "lb-mix-match__modal-product-unit-price lb-bundle-product-unit-price", children: unitPriceText }),
|
|
3538
|
+
showPicker && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "lb-bundle-variant-option-groups", children: optionNames.map((optionName, optionIndex) => {
|
|
3409
3539
|
const dropdownOptions = optionsFor(optionIndex).map((o) => ({
|
|
3410
3540
|
value: o.value,
|
|
3411
3541
|
label: o.value,
|
|
3412
3542
|
disabled: o.disabled
|
|
3413
3543
|
}));
|
|
3414
|
-
return /* @__PURE__ */ (0,
|
|
3544
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
3415
3545
|
"div",
|
|
3416
3546
|
{
|
|
3417
3547
|
className: "lb-bundle-variant-option-group",
|
|
3418
3548
|
children: [
|
|
3419
|
-
/* @__PURE__ */ (0,
|
|
3420
|
-
/* @__PURE__ */ (0,
|
|
3549
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "lb-bundle-variant-option-label", children: optionName }),
|
|
3550
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3421
3551
|
VariantDropdown,
|
|
3422
3552
|
{
|
|
3423
3553
|
className: "lb-mix-match__variant-select-dropdown",
|
|
@@ -3432,17 +3562,17 @@ function MultiStepPickerRow({
|
|
|
3432
3562
|
optionName
|
|
3433
3563
|
);
|
|
3434
3564
|
}) }),
|
|
3435
|
-
!showPicker && variants.length === 1 && currentVariant.title !== "Default Title" && /* @__PURE__ */ (0,
|
|
3436
|
-
!isOos && needsMoreSpots && room > 0 && /* @__PURE__ */ (0,
|
|
3437
|
-
isOos ? /* @__PURE__ */ (0,
|
|
3438
|
-
showStepper && /* @__PURE__ */ (0,
|
|
3565
|
+
!showPicker && variants.length === 1 && currentVariant.title !== "Default Title" && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "lb-mix-match__filled-variant", children: currentVariant.title }),
|
|
3566
|
+
!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` }),
|
|
3567
|
+
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: [
|
|
3568
|
+
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)(
|
|
3439
3569
|
"div",
|
|
3440
3570
|
{
|
|
3441
3571
|
className: "lb-mix-match__qty-stepper",
|
|
3442
3572
|
role: "group",
|
|
3443
3573
|
"aria-label": "Quantity",
|
|
3444
3574
|
children: [
|
|
3445
|
-
/* @__PURE__ */ (0,
|
|
3575
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3446
3576
|
"button",
|
|
3447
3577
|
{
|
|
3448
3578
|
type: "button",
|
|
@@ -3464,7 +3594,7 @@ function MultiStepPickerRow({
|
|
|
3464
3594
|
children: "\u2212"
|
|
3465
3595
|
}
|
|
3466
3596
|
),
|
|
3467
|
-
/* @__PURE__ */ (0,
|
|
3597
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3468
3598
|
"span",
|
|
3469
3599
|
{
|
|
3470
3600
|
className: "lb-mix-match__qty-stepper-value",
|
|
@@ -3473,7 +3603,7 @@ function MultiStepPickerRow({
|
|
|
3473
3603
|
children: shownQty
|
|
3474
3604
|
}
|
|
3475
3605
|
),
|
|
3476
|
-
/* @__PURE__ */ (0,
|
|
3606
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3477
3607
|
"button",
|
|
3478
3608
|
{
|
|
3479
3609
|
type: "button",
|
|
@@ -3498,7 +3628,7 @@ function MultiStepPickerRow({
|
|
|
3498
3628
|
]
|
|
3499
3629
|
}
|
|
3500
3630
|
) }),
|
|
3501
|
-
/* @__PURE__ */ (0,
|
|
3631
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3502
3632
|
"button",
|
|
3503
3633
|
{
|
|
3504
3634
|
type: "button",
|
|
@@ -3517,7 +3647,7 @@ function MultiStepPickerRow({
|
|
|
3517
3647
|
);
|
|
3518
3648
|
}
|
|
3519
3649
|
function CloseIcon3() {
|
|
3520
|
-
return /* @__PURE__ */ (0,
|
|
3650
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
3521
3651
|
"svg",
|
|
3522
3652
|
{
|
|
3523
3653
|
width: "20",
|
|
@@ -3527,14 +3657,14 @@ function CloseIcon3() {
|
|
|
3527
3657
|
xmlns: "http://www.w3.org/2000/svg",
|
|
3528
3658
|
"aria-hidden": "true",
|
|
3529
3659
|
children: [
|
|
3530
|
-
/* @__PURE__ */ (0,
|
|
3531
|
-
/* @__PURE__ */ (0,
|
|
3660
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "5", y1: "5", x2: "15", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
|
|
3661
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "15", y1: "5", x2: "5", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
|
|
3532
3662
|
]
|
|
3533
3663
|
}
|
|
3534
3664
|
);
|
|
3535
3665
|
}
|
|
3536
3666
|
function SearchClearIcon2() {
|
|
3537
|
-
return /* @__PURE__ */ (0,
|
|
3667
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3538
3668
|
"svg",
|
|
3539
3669
|
{
|
|
3540
3670
|
width: "16",
|
|
@@ -3543,19 +3673,19 @@ function SearchClearIcon2() {
|
|
|
3543
3673
|
fill: "currentColor",
|
|
3544
3674
|
xmlns: "http://www.w3.org/2000/svg",
|
|
3545
3675
|
"aria-hidden": "true",
|
|
3546
|
-
children: /* @__PURE__ */ (0,
|
|
3676
|
+
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" })
|
|
3547
3677
|
}
|
|
3548
3678
|
);
|
|
3549
3679
|
}
|
|
3550
3680
|
|
|
3551
3681
|
// src/components/MultiStepBundle.tsx
|
|
3552
|
-
var
|
|
3682
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
3553
3683
|
function ruleFor4(bundle, productId, variantId) {
|
|
3554
3684
|
if (variantId) {
|
|
3555
3685
|
const vRule = bundle.variantRules[variantId];
|
|
3556
3686
|
if (vRule) return vRule;
|
|
3557
3687
|
}
|
|
3558
|
-
return bundle.productRules[productId] ??
|
|
3688
|
+
return bundle.productRules[productId] ?? import_core14.DEFAULT_PRODUCT_RULE;
|
|
3559
3689
|
}
|
|
3560
3690
|
function variantRuleFor4(bundle, variantId) {
|
|
3561
3691
|
return variantId ? bundle.variantRules[variantId] : void 0;
|
|
@@ -3597,10 +3727,6 @@ function MultiStepBundle(props) {
|
|
|
3597
3727
|
storefrontAccessToken,
|
|
3598
3728
|
bundleGid
|
|
3599
3729
|
});
|
|
3600
|
-
const { outOfStockBehavior } = useShopSettings({
|
|
3601
|
-
shopDomain,
|
|
3602
|
-
storefrontAccessToken
|
|
3603
|
-
});
|
|
3604
3730
|
const { elementRef, trackAddToCart } = useAnalytics({
|
|
3605
3731
|
shopDomain,
|
|
3606
3732
|
appUrl: appUrl ?? `https://${shopDomain}`,
|
|
@@ -3636,9 +3762,9 @@ function MultiStepBundle(props) {
|
|
|
3636
3762
|
for (const [pid, rule] of Object.entries(bundle.productRules)) {
|
|
3637
3763
|
if (!rule.required) continue;
|
|
3638
3764
|
for (let i = 0; i < steps.length; i++) {
|
|
3639
|
-
const product = (0,
|
|
3765
|
+
const product = (0, import_core14.productsForStep)(bundle, i).find((p) => p.id === pid);
|
|
3640
3766
|
const variant = product?.variants.nodes.find(
|
|
3641
|
-
(v) => (0,
|
|
3767
|
+
(v) => (0, import_core14.isVariantFulfillable)(v, rule.min)
|
|
3642
3768
|
);
|
|
3643
3769
|
if (!product || !variant) continue;
|
|
3644
3770
|
seeded[i].push({
|
|
@@ -3650,7 +3776,7 @@ function MultiStepBundle(props) {
|
|
|
3650
3776
|
featuredImage: variant.image?.url ?? product.featuredImage?.url ?? null,
|
|
3651
3777
|
price: parseFloat(variant.price.amount),
|
|
3652
3778
|
compareAtPrice: variant.compareAtPrice ? parseFloat(variant.compareAtPrice.amount) : null,
|
|
3653
|
-
unitPrice: (0,
|
|
3779
|
+
unitPrice: (0, import_core14.formatUnitPrice)(
|
|
3654
3780
|
variant.unitPrice,
|
|
3655
3781
|
variant.unitPriceMeasurement,
|
|
3656
3782
|
seedCurrency
|
|
@@ -3691,7 +3817,7 @@ function MultiStepBundle(props) {
|
|
|
3691
3817
|
if (sel.quantity <= 0) continue;
|
|
3692
3818
|
comparePrice += sel.price * sel.quantity;
|
|
3693
3819
|
if (bundle) {
|
|
3694
|
-
salePrice += (0,
|
|
3820
|
+
salePrice += (0, import_core14.calculateDiscount)(
|
|
3695
3821
|
sel.price,
|
|
3696
3822
|
bundle.discountConfig.discountType,
|
|
3697
3823
|
bundle.discountConfig.discountValue
|
|
@@ -3839,9 +3965,9 @@ function MultiStepBundle(props) {
|
|
|
3839
3965
|
}
|
|
3840
3966
|
}, [bundle, selections, valid, onAddToCart, onError, trackAddToCart, totalQuantity, steps]);
|
|
3841
3967
|
if (result.status === "loading") {
|
|
3842
|
-
return /* @__PURE__ */ (0,
|
|
3843
|
-
/* @__PURE__ */ (0,
|
|
3844
|
-
/* @__PURE__ */ (0,
|
|
3968
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: `lb-bundle lb-bundle--loading ${className ?? ""}`, children: [
|
|
3969
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "lb-skeleton lb-skeleton--title" }),
|
|
3970
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "lb-skeleton lb-skeleton--products" })
|
|
3845
3971
|
] });
|
|
3846
3972
|
}
|
|
3847
3973
|
if (result.status === "error") return null;
|
|
@@ -3853,8 +3979,8 @@ function MultiStepBundle(props) {
|
|
|
3853
3979
|
([pid, rule]) => {
|
|
3854
3980
|
if (!rule.required) return false;
|
|
3855
3981
|
return !steps.some(
|
|
3856
|
-
(_, i) => (0,
|
|
3857
|
-
(p) => p.id === pid && p.variants.nodes.some((v) => (0,
|
|
3982
|
+
(_, i) => (0, import_core14.productsForStep)(bundle, i).some(
|
|
3983
|
+
(p) => p.id === pid && p.variants.nodes.some((v) => (0, import_core14.isVariantFulfillable)(v, rule.min))
|
|
3858
3984
|
)
|
|
3859
3985
|
);
|
|
3860
3986
|
}
|
|
@@ -3862,7 +3988,7 @@ function MultiStepBundle(props) {
|
|
|
3862
3988
|
if (requiredBlocked) return null;
|
|
3863
3989
|
const currency = bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? "USD";
|
|
3864
3990
|
const ctaLabel = addingToCart ? "Adding..." : bundle.widgetConfig.cta.ctaText || "Add to cart";
|
|
3865
|
-
return /* @__PURE__ */ (0,
|
|
3991
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
3866
3992
|
"div",
|
|
3867
3993
|
{
|
|
3868
3994
|
ref: (el) => {
|
|
@@ -3874,12 +4000,19 @@ function MultiStepBundle(props) {
|
|
|
3874
4000
|
"aria-label": bundle.title,
|
|
3875
4001
|
"data-required-quantity": totalMin,
|
|
3876
4002
|
children: [
|
|
3877
|
-
/* @__PURE__ */ (0,
|
|
3878
|
-
/* @__PURE__ */ (0,
|
|
3879
|
-
bundle.description && /* @__PURE__ */ (0,
|
|
4003
|
+
/* @__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: [
|
|
4004
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h3", { className: "lb-bundle-title", children: bundle.title }),
|
|
4005
|
+
bundle.description && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "lb-bundle-subtitle", children: bundle.description })
|
|
3880
4006
|
] }) }),
|
|
3881
|
-
/* @__PURE__ */ (0,
|
|
3882
|
-
|
|
4007
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4008
|
+
BundleCountdown,
|
|
4009
|
+
{
|
|
4010
|
+
endsAt: bundle.endsAt,
|
|
4011
|
+
widgetConfig: bundle.widgetConfig
|
|
4012
|
+
}
|
|
4013
|
+
),
|
|
4014
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "lb-mix-match__progress", "data-progress": true, children: [
|
|
4015
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
3883
4016
|
"div",
|
|
3884
4017
|
{
|
|
3885
4018
|
className: "lb-mix-match__progress-segments",
|
|
@@ -3887,7 +4020,7 @@ function MultiStepBundle(props) {
|
|
|
3887
4020
|
"aria-valuenow": completedSteps,
|
|
3888
4021
|
"aria-valuemin": 0,
|
|
3889
4022
|
"aria-valuemax": steps.length,
|
|
3890
|
-
children: Array.from({ length: steps.length }).map((_, i) => /* @__PURE__ */ (0,
|
|
4023
|
+
children: Array.from({ length: steps.length }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
3891
4024
|
"span",
|
|
3892
4025
|
{
|
|
3893
4026
|
className: `lb-mix-match__progress-segment${i < completedSteps ? " lb-mix-match__progress-segment--filled" : ""}`,
|
|
@@ -3897,8 +4030,8 @@ function MultiStepBundle(props) {
|
|
|
3897
4030
|
))
|
|
3898
4031
|
}
|
|
3899
4032
|
),
|
|
3900
|
-
/* @__PURE__ */ (0,
|
|
3901
|
-
/* @__PURE__ */ (0,
|
|
4033
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "lb-mix-match__progress-labels", children: [
|
|
4034
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
3902
4035
|
"span",
|
|
3903
4036
|
{
|
|
3904
4037
|
className: "lb-mix-match__progress-count",
|
|
@@ -3907,7 +4040,7 @@ function MultiStepBundle(props) {
|
|
|
3907
4040
|
children: `${completedSteps} of ${steps.length} steps completed`
|
|
3908
4041
|
}
|
|
3909
4042
|
),
|
|
3910
|
-
/* @__PURE__ */ (0,
|
|
4043
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
3911
4044
|
"span",
|
|
3912
4045
|
{
|
|
3913
4046
|
className: "lb-mix-match__progress-remaining",
|
|
@@ -3918,15 +4051,15 @@ function MultiStepBundle(props) {
|
|
|
3918
4051
|
)
|
|
3919
4052
|
] })
|
|
3920
4053
|
] }),
|
|
3921
|
-
/* @__PURE__ */ (0,
|
|
4054
|
+
/* @__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)(
|
|
3922
4055
|
"section",
|
|
3923
4056
|
{
|
|
3924
4057
|
className: "lb-multi-step__group",
|
|
3925
4058
|
"data-step-group": i,
|
|
3926
4059
|
children: [
|
|
3927
|
-
/* @__PURE__ */ (0,
|
|
3928
|
-
/* @__PURE__ */ (0,
|
|
3929
|
-
/* @__PURE__ */ (0,
|
|
4060
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "lb-multi-step__group-heading", children: [
|
|
4061
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "lb-multi-step__group-name", children: step.name }),
|
|
4062
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
3930
4063
|
"span",
|
|
3931
4064
|
{
|
|
3932
4065
|
className: `lb-multi-step__group-count${stepSatisfied(i) ? " lb-multi-step__group-count--met" : ""}`,
|
|
@@ -3935,7 +4068,7 @@ function MultiStepBundle(props) {
|
|
|
3935
4068
|
}
|
|
3936
4069
|
)
|
|
3937
4070
|
] }),
|
|
3938
|
-
/* @__PURE__ */ (0,
|
|
4071
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
3939
4072
|
"div",
|
|
3940
4073
|
{
|
|
3941
4074
|
className: "lb-mix-match__slots lb-edge-fade lb-multi-step__group-slots",
|
|
@@ -3945,13 +4078,13 @@ function MultiStepBundle(props) {
|
|
|
3945
4078
|
title button provides the keyboard/AT path (its
|
|
3946
4079
|
activation bubbles here); × stops propagation. */
|
|
3947
4080
|
// 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
|
|
3948
|
-
/* @__PURE__ */ (0,
|
|
4081
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
3949
4082
|
"div",
|
|
3950
4083
|
{
|
|
3951
4084
|
className: "lb-mix-match__slot lb-mix-match__slot--filled",
|
|
3952
4085
|
onClick: () => setPickerOpenAt(i),
|
|
3953
4086
|
children: [
|
|
3954
|
-
item.featuredImage && /* @__PURE__ */ (0,
|
|
4087
|
+
item.featuredImage && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "lb-bundle-thumbnail", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
3955
4088
|
"img",
|
|
3956
4089
|
{
|
|
3957
4090
|
src: item.featuredImage,
|
|
@@ -3959,8 +4092,8 @@ function MultiStepBundle(props) {
|
|
|
3959
4092
|
loading: "lazy"
|
|
3960
4093
|
}
|
|
3961
4094
|
) }),
|
|
3962
|
-
/* @__PURE__ */ (0,
|
|
3963
|
-
/* @__PURE__ */ (0,
|
|
4095
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "lb-mix-match__filled-info", children: [
|
|
4096
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
3964
4097
|
"button",
|
|
3965
4098
|
{
|
|
3966
4099
|
type: "button",
|
|
@@ -3969,15 +4102,15 @@ function MultiStepBundle(props) {
|
|
|
3969
4102
|
children: item.title
|
|
3970
4103
|
}
|
|
3971
4104
|
),
|
|
3972
|
-
item.variantTitle && item.variantTitle !== "Default Title" && /* @__PURE__ */ (0,
|
|
3973
|
-
/* @__PURE__ */ (0,
|
|
3974
|
-
item.compareAtPrice !== null && item.compareAtPrice > item.price && /* @__PURE__ */ (0,
|
|
3975
|
-
/* @__PURE__ */ (0,
|
|
3976
|
-
/* @__PURE__ */ (0,
|
|
4105
|
+
item.variantTitle && item.variantTitle !== "Default Title" && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "lb-mix-match__filled-variant", children: item.variantTitle }),
|
|
4106
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "lb-mix-match__filled-price", children: [
|
|
4107
|
+
item.compareAtPrice !== null && item.compareAtPrice > item.price && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("s", { className: "lb-mix-match__filled-compare", children: (0, import_core14.formatMoney)(item.compareAtPrice, currency) }),
|
|
4108
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "lb-bundle-product-price", children: (0, import_core14.formatMoney)(item.price, currency) }),
|
|
4109
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "lb-bundle-qty-inline", children: `\xD7${item.quantity}` })
|
|
3977
4110
|
] }),
|
|
3978
|
-
item.unitPrice && /* @__PURE__ */ (0,
|
|
4111
|
+
item.unitPrice && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "lb-bundle-product-unit-price", children: item.unitPrice })
|
|
3979
4112
|
] }),
|
|
3980
|
-
canRemoveItem2(bundle, selections, item) ? /* @__PURE__ */ (0,
|
|
4113
|
+
canRemoveItem2(bundle, selections, item) ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
3981
4114
|
"button",
|
|
3982
4115
|
{
|
|
3983
4116
|
type: "button",
|
|
@@ -3987,13 +4120,13 @@ function MultiStepBundle(props) {
|
|
|
3987
4120
|
e.stopPropagation();
|
|
3988
4121
|
removeSlot(i, index);
|
|
3989
4122
|
},
|
|
3990
|
-
children: /* @__PURE__ */ (0,
|
|
4123
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CloseIcon4, {})
|
|
3991
4124
|
}
|
|
3992
4125
|
) : (
|
|
3993
4126
|
/* Required pick at its floor — quiet state chip instead
|
|
3994
4127
|
of the ×; removal returns once another slot covers
|
|
3995
4128
|
the product's minimum (variant swap flow). */
|
|
3996
|
-
/* @__PURE__ */ (0,
|
|
4129
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "lb-mix-match__slot-required", children: "Required" })
|
|
3997
4130
|
)
|
|
3998
4131
|
]
|
|
3999
4132
|
},
|
|
@@ -4002,7 +4135,7 @@ function MultiStepBundle(props) {
|
|
|
4002
4135
|
))
|
|
4003
4136
|
}
|
|
4004
4137
|
),
|
|
4005
|
-
(0,
|
|
4138
|
+
(0, import_core14.stepHeadroom)(step.maxQuantity, unitsByStep[i] ?? 0) !== 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
4006
4139
|
"button",
|
|
4007
4140
|
{
|
|
4008
4141
|
type: "button",
|
|
@@ -4011,15 +4144,15 @@ function MultiStepBundle(props) {
|
|
|
4011
4144
|
"aria-label": `${step.minQuantity === 1 && step.maxQuantity === 1 ? "Choose a product" : "Choose products"}: ${step.name}`,
|
|
4012
4145
|
onClick: () => setPickerOpenAt(i),
|
|
4013
4146
|
children: [
|
|
4014
|
-
/* @__PURE__ */ (0,
|
|
4147
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4015
4148
|
"span",
|
|
4016
4149
|
{
|
|
4017
4150
|
className: "lb-mix-match__add-product-icon",
|
|
4018
4151
|
"aria-hidden": "true",
|
|
4019
|
-
children: /* @__PURE__ */ (0,
|
|
4152
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PlusIcon2, {})
|
|
4020
4153
|
}
|
|
4021
4154
|
),
|
|
4022
|
-
/* @__PURE__ */ (0,
|
|
4155
|
+
/* @__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" })
|
|
4023
4156
|
]
|
|
4024
4157
|
}
|
|
4025
4158
|
)
|
|
@@ -4027,29 +4160,29 @@ function MultiStepBundle(props) {
|
|
|
4027
4160
|
},
|
|
4028
4161
|
i
|
|
4029
4162
|
)) }),
|
|
4030
|
-
/* @__PURE__ */ (0,
|
|
4031
|
-
allSatisfied && /* @__PURE__ */ (0,
|
|
4032
|
-
/* @__PURE__ */ (0,
|
|
4033
|
-
/* @__PURE__ */ (0,
|
|
4034
|
-
bundle.widgetConfig.savingsBar.visible && summary.savings > 0 && /* @__PURE__ */ (0,
|
|
4163
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "lb-bundle-divider" }),
|
|
4164
|
+
allSatisfied && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "lb-bundle-summary", "data-pricing-section": true, children: [
|
|
4165
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "lb-bundle-summary__text", children: [
|
|
4166
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "lb-bundle-summary__label", children: "Bundle total" }),
|
|
4167
|
+
bundle.widgetConfig.savingsBar.visible && summary.savings > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("p", { className: "lb-bundle-savings-line", "data-savings-bar": true, children: [
|
|
4035
4168
|
"You save",
|
|
4036
4169
|
" ",
|
|
4037
|
-
/* @__PURE__ */ (0,
|
|
4170
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { "data-savings-amount": true, children: (0, import_core14.formatMoney)(summary.savings, currency) }),
|
|
4038
4171
|
" ",
|
|
4039
|
-
/* @__PURE__ */ (0,
|
|
4172
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { "data-savings-percent": true, children: [
|
|
4040
4173
|
"(",
|
|
4041
4174
|
summary.savingsPercent,
|
|
4042
4175
|
"%)"
|
|
4043
4176
|
] })
|
|
4044
4177
|
] })
|
|
4045
4178
|
] }),
|
|
4046
|
-
/* @__PURE__ */ (0,
|
|
4047
|
-
bundle.widgetConfig.pricing.showComparePrice && summary.savings > 0 && /* @__PURE__ */ (0,
|
|
4048
|
-
/* @__PURE__ */ (0,
|
|
4179
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "lb-bundle-summary__prices", children: [
|
|
4180
|
+
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_core14.formatMoney)(summary.comparePrice, currency) }),
|
|
4181
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "lb-bundle-sale-price", "data-sale-price": true, children: (0, import_core14.formatMoney)(summary.salePrice, currency) })
|
|
4049
4182
|
] })
|
|
4050
4183
|
] }),
|
|
4051
|
-
cartError && /* @__PURE__ */ (0,
|
|
4052
|
-
/* @__PURE__ */ (0,
|
|
4184
|
+
cartError && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "lb-bundle__error", role: "alert", children: cartError }),
|
|
4185
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4053
4186
|
"button",
|
|
4054
4187
|
{
|
|
4055
4188
|
className: "lb-bundle__cta",
|
|
@@ -4059,10 +4192,9 @@ function MultiStepBundle(props) {
|
|
|
4059
4192
|
children: ctaLabel
|
|
4060
4193
|
}
|
|
4061
4194
|
),
|
|
4062
|
-
pickerOpenAt !== null && /* @__PURE__ */ (0,
|
|
4195
|
+
pickerOpenAt !== null && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4063
4196
|
MultiStepPicker,
|
|
4064
4197
|
{
|
|
4065
|
-
outOfStockBehavior,
|
|
4066
4198
|
bundle,
|
|
4067
4199
|
currency,
|
|
4068
4200
|
initialStep: pickerOpenAt,
|
|
@@ -4089,13 +4221,13 @@ function MultiStepBundle(props) {
|
|
|
4089
4221
|
);
|
|
4090
4222
|
}
|
|
4091
4223
|
function stepHasInStockProduct(bundle, stepIndex) {
|
|
4092
|
-
return (0,
|
|
4224
|
+
return (0, import_core14.productsForStep)(bundle, stepIndex).some((product) => {
|
|
4093
4225
|
const rule = ruleFor4(bundle, product.id);
|
|
4094
|
-
return product.variants.nodes.some((v) => (0,
|
|
4226
|
+
return product.variants.nodes.some((v) => (0, import_core14.isVariantFulfillable)(v, rule.min));
|
|
4095
4227
|
});
|
|
4096
4228
|
}
|
|
4097
4229
|
function PlusIcon2() {
|
|
4098
|
-
return /* @__PURE__ */ (0,
|
|
4230
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
4099
4231
|
"svg",
|
|
4100
4232
|
{
|
|
4101
4233
|
width: "18",
|
|
@@ -4105,14 +4237,14 @@ function PlusIcon2() {
|
|
|
4105
4237
|
xmlns: "http://www.w3.org/2000/svg",
|
|
4106
4238
|
"aria-hidden": "true",
|
|
4107
4239
|
children: [
|
|
4108
|
-
/* @__PURE__ */ (0,
|
|
4109
|
-
/* @__PURE__ */ (0,
|
|
4240
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "9", y1: "3", x2: "9", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
|
|
4241
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "3", y1: "9", x2: "15", y2: "9", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
|
|
4110
4242
|
]
|
|
4111
4243
|
}
|
|
4112
4244
|
);
|
|
4113
4245
|
}
|
|
4114
4246
|
function CloseIcon4() {
|
|
4115
|
-
return /* @__PURE__ */ (0,
|
|
4247
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
4116
4248
|
"svg",
|
|
4117
4249
|
{
|
|
4118
4250
|
width: "16",
|
|
@@ -4122,8 +4254,8 @@ function CloseIcon4() {
|
|
|
4122
4254
|
xmlns: "http://www.w3.org/2000/svg",
|
|
4123
4255
|
"aria-hidden": "true",
|
|
4124
4256
|
children: [
|
|
4125
|
-
/* @__PURE__ */ (0,
|
|
4126
|
-
/* @__PURE__ */ (0,
|
|
4257
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "5", y1: "5", x2: "15", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
|
|
4258
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "15", y1: "5", x2: "5", y2: "15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
|
|
4127
4259
|
]
|
|
4128
4260
|
}
|
|
4129
4261
|
);
|
|
@@ -4137,7 +4269,7 @@ async function fetchShopCustomCss(options) {
|
|
|
4137
4269
|
|
|
4138
4270
|
// src/hooks/useBundlesForProduct.ts
|
|
4139
4271
|
var import_react17 = require("react");
|
|
4140
|
-
var
|
|
4272
|
+
var import_core15 = require("@lime-bundles/core");
|
|
4141
4273
|
var INITIAL_STATE2 = {
|
|
4142
4274
|
status: "loading",
|
|
4143
4275
|
bundles: null,
|
|
@@ -4150,7 +4282,7 @@ function useBundlesForProduct(options) {
|
|
|
4150
4282
|
(0, import_react17.useEffect)(() => {
|
|
4151
4283
|
const controller = new AbortController();
|
|
4152
4284
|
setState(INITIAL_STATE2);
|
|
4153
|
-
(0,
|
|
4285
|
+
(0, import_core15.fetchBundlesForProduct)({
|
|
4154
4286
|
shopDomain: options.shopDomain,
|
|
4155
4287
|
storefrontAccessToken: options.storefrontAccessToken,
|
|
4156
4288
|
productHandle: options.productHandle,
|
|
@@ -4173,7 +4305,7 @@ function useBundlesForProduct(options) {
|
|
|
4173
4305
|
signal: controller.signal
|
|
4174
4306
|
}).then((settings) => {
|
|
4175
4307
|
if (controller.signal.aborted) return;
|
|
4176
|
-
(0,
|
|
4308
|
+
(0, import_core15.injectCustomCss)(options.shopDomain, settings.customCss);
|
|
4177
4309
|
}).catch(() => {
|
|
4178
4310
|
});
|
|
4179
4311
|
return () => {
|
|
@@ -4189,15 +4321,15 @@ function useBundlesForProduct(options) {
|
|
|
4189
4321
|
}
|
|
4190
4322
|
|
|
4191
4323
|
// src/index.ts
|
|
4324
|
+
var import_core16 = require("@lime-bundles/core");
|
|
4192
4325
|
var import_core17 = require("@lime-bundles/core");
|
|
4193
|
-
var import_core18 = require("@lime-bundles/core");
|
|
4194
4326
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4195
4327
|
0 && (module.exports = {
|
|
4196
4328
|
BUNDLES_FOR_PRODUCT_QUERY,
|
|
4197
4329
|
BUNDLE_METAOBJECT_QUERY,
|
|
4198
4330
|
BogoBundle,
|
|
4331
|
+
BundleCountdown,
|
|
4199
4332
|
BundleParseError,
|
|
4200
|
-
DEFAULT_OUT_OF_STOCK_BEHAVIOR,
|
|
4201
4333
|
FixedBundle,
|
|
4202
4334
|
MixMatchBundle,
|
|
4203
4335
|
MultiStepBundle,
|
|
@@ -4228,7 +4360,6 @@ var import_core18 = require("@lime-bundles/core");
|
|
|
4228
4360
|
parseCents,
|
|
4229
4361
|
parseMetaobjectBundle,
|
|
4230
4362
|
parseMetaobjectBundleStrict,
|
|
4231
|
-
parseOutOfStockBehavior,
|
|
4232
4363
|
percentageDiscountUnit,
|
|
4233
4364
|
productsForStep,
|
|
4234
4365
|
reportAddToCart,
|
|
@@ -4240,7 +4371,6 @@ var import_core18 = require("@lime-bundles/core");
|
|
|
4240
4371
|
useAnalytics,
|
|
4241
4372
|
useBundleData,
|
|
4242
4373
|
useBundlesForProduct,
|
|
4243
|
-
useShopSettings,
|
|
4244
4374
|
useVariantSelection,
|
|
4245
4375
|
useWidgetConfigVars,
|
|
4246
4376
|
validateQuantity
|