@lime-bundles/react 6.2.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/dist/index.cjs +304 -303
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -41
- package/dist/index.d.ts +15 -41
- package/dist/index.js +138 -140
- package/dist/index.js.map +1 -1
- package/dist/styles.css +35 -7
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -81,13 +81,10 @@ async function fetchBundleDataWithWarnings(options) {
|
|
|
81
81
|
// src/fetchShopSettings.ts
|
|
82
82
|
import {
|
|
83
83
|
createStorefrontClient as createStorefrontClient2,
|
|
84
|
-
SHOP_SETTINGS_QUERY
|
|
85
|
-
DEFAULT_OUT_OF_STOCK_BEHAVIOR,
|
|
86
|
-
parseOutOfStockBehavior
|
|
84
|
+
SHOP_SETTINGS_QUERY
|
|
87
85
|
} from "@lime-bundles/core";
|
|
88
86
|
var FALLBACK = {
|
|
89
|
-
customCss: null
|
|
90
|
-
outOfStockBehavior: DEFAULT_OUT_OF_STOCK_BEHAVIOR
|
|
87
|
+
customCss: null
|
|
91
88
|
};
|
|
92
89
|
var cache = /* @__PURE__ */ new Map();
|
|
93
90
|
async function fetchShopSettings(options) {
|
|
@@ -105,10 +102,7 @@ async function fetchShopSettings(options) {
|
|
|
105
102
|
{ signal: options.signal }
|
|
106
103
|
);
|
|
107
104
|
return {
|
|
108
|
-
customCss: data.shop?.customCss?.value ?? null
|
|
109
|
-
outOfStockBehavior: parseOutOfStockBehavior(
|
|
110
|
-
data.shop?.outOfStockBehavior?.value
|
|
111
|
-
)
|
|
105
|
+
customCss: data.shop?.customCss?.value ?? null
|
|
112
106
|
};
|
|
113
107
|
})();
|
|
114
108
|
cache.set(options.shopDomain, promise);
|
|
@@ -266,19 +260,25 @@ function useWidgetConfigVars(config) {
|
|
|
266
260
|
import { useEffect as useEffect4, useMemo as useMemo2, useState as useState3, useCallback as useCallback3 } from "react";
|
|
267
261
|
import { variants as variantsNs } from "@lime-bundles/core";
|
|
268
262
|
var { findVariantByOptions, isOptionValueAvailable, toPickerVariant } = variantsNs;
|
|
269
|
-
function defaultInitial(variants) {
|
|
270
|
-
return variants.find((v) => v.availableForSale) ?? variants[0] ?? null;
|
|
271
|
-
}
|
|
272
263
|
function useVariantSelection({
|
|
273
264
|
variants,
|
|
274
265
|
optionNames,
|
|
275
266
|
initialVariant,
|
|
276
|
-
optionValuesByPosition
|
|
267
|
+
optionValuesByPosition,
|
|
268
|
+
requiredQtyFor
|
|
277
269
|
}) {
|
|
278
|
-
const
|
|
279
|
-
() =>
|
|
280
|
-
[
|
|
270
|
+
const pickerVariants = useMemo2(
|
|
271
|
+
() => variants.map((v) => toPickerVariant(v, requiredQtyFor?.(v.id))),
|
|
272
|
+
[variants, requiredQtyFor]
|
|
281
273
|
);
|
|
274
|
+
const seed = useMemo2(() => {
|
|
275
|
+
if (initialVariant) return initialVariant;
|
|
276
|
+
const covered = pickerVariants.find((p) => p.available);
|
|
277
|
+
if (covered) {
|
|
278
|
+
return variants.find((v) => v.id === covered.id) ?? null;
|
|
279
|
+
}
|
|
280
|
+
return variants.find((v) => v.availableForSale) ?? variants[0] ?? null;
|
|
281
|
+
}, [initialVariant, variants, pickerVariants]);
|
|
282
282
|
const [selectedValues, setSelectedValues] = useState3(
|
|
283
283
|
() => seed ? seed.selectedOptions.map((o) => o.value) : optionNames.map(() => "")
|
|
284
284
|
);
|
|
@@ -286,10 +286,6 @@ function useVariantSelection({
|
|
|
286
286
|
if (!seed) return;
|
|
287
287
|
setSelectedValues(seed.selectedOptions.map((o) => o.value));
|
|
288
288
|
}, [seed?.id]);
|
|
289
|
-
const pickerVariants = useMemo2(
|
|
290
|
-
() => variants.map((v) => toPickerVariant(v)),
|
|
291
|
-
[variants]
|
|
292
|
-
);
|
|
293
289
|
const selectedVariant = useMemo2(() => {
|
|
294
290
|
if (selectedValues.length !== optionNames.length) return null;
|
|
295
291
|
const match = findVariantByOptions(pickerVariants, selectedValues);
|
|
@@ -924,7 +920,11 @@ function FixedProductRow({ bundle, product, currency, isOos, onVariantChange })
|
|
|
924
920
|
const showPicker = variants.length > 1 && optionNames.length > 0;
|
|
925
921
|
const { selectedValues, selectedVariant, setOptionValue, optionsFor } = useVariantSelection({
|
|
926
922
|
variants,
|
|
927
|
-
optionNames
|
|
923
|
+
optionNames,
|
|
924
|
+
// Quantity-aware dropdown: a variant that can't cover this row's
|
|
925
|
+
// bundle quantity greys out instead of walking the shopper into a
|
|
926
|
+
// cart Shopify caps at add time.
|
|
927
|
+
requiredQtyFor: (variantId) => resolveBundleQty(bundle, product.id, variantId)
|
|
928
928
|
});
|
|
929
929
|
useEffect7(() => {
|
|
930
930
|
onVariantChange(product.id, selectedVariant ?? null);
|
|
@@ -1019,7 +1019,7 @@ function FixedProductRow({ bundle, product, currency, isOos, onVariantChange })
|
|
|
1019
1019
|
}
|
|
1020
1020
|
|
|
1021
1021
|
// src/components/MixMatchBundle.tsx
|
|
1022
|
-
import { useCallback as useCallback6, useEffect as
|
|
1022
|
+
import { useCallback as useCallback6, useEffect as useEffect11, useMemo as useMemo6, useState as useState8 } from "react";
|
|
1023
1023
|
import {
|
|
1024
1024
|
formatMoney as formatMoney3,
|
|
1025
1025
|
formatUnitPrice as formatUnitPrice3,
|
|
@@ -1028,39 +1028,12 @@ import {
|
|
|
1028
1028
|
DEFAULT_PRODUCT_RULE as DEFAULT_PRODUCT_RULE2
|
|
1029
1029
|
} from "@lime-bundles/core";
|
|
1030
1030
|
|
|
1031
|
-
// src/hooks/useShopSettings.ts
|
|
1032
|
-
import { useEffect as useEffect8, useState as useState7 } from "react";
|
|
1033
|
-
import {
|
|
1034
|
-
DEFAULT_OUT_OF_STOCK_BEHAVIOR as DEFAULT_OUT_OF_STOCK_BEHAVIOR2
|
|
1035
|
-
} from "@lime-bundles/core";
|
|
1036
|
-
function useShopSettings(options) {
|
|
1037
|
-
const [outOfStockBehavior, setOutOfStockBehavior] = useState7(DEFAULT_OUT_OF_STOCK_BEHAVIOR2);
|
|
1038
|
-
const { shopDomain, storefrontAccessToken } = options;
|
|
1039
|
-
useEffect8(() => {
|
|
1040
|
-
const controller = new AbortController();
|
|
1041
|
-
let active = true;
|
|
1042
|
-
fetchShopSettingsOrDefault({
|
|
1043
|
-
shopDomain,
|
|
1044
|
-
storefrontAccessToken,
|
|
1045
|
-
signal: controller.signal
|
|
1046
|
-
}).then((settings) => {
|
|
1047
|
-
if (!active || controller.signal.aborted) return;
|
|
1048
|
-
setOutOfStockBehavior(settings.outOfStockBehavior);
|
|
1049
|
-
});
|
|
1050
|
-
return () => {
|
|
1051
|
-
active = false;
|
|
1052
|
-
controller.abort();
|
|
1053
|
-
};
|
|
1054
|
-
}, [shopDomain, storefrontAccessToken]);
|
|
1055
|
-
return { outOfStockBehavior };
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
1031
|
// src/components/MixMatchPicker.tsx
|
|
1059
1032
|
import {
|
|
1060
|
-
useEffect as
|
|
1033
|
+
useEffect as useEffect10,
|
|
1061
1034
|
useMemo as useMemo5,
|
|
1062
1035
|
useRef as useRef6,
|
|
1063
|
-
useState as
|
|
1036
|
+
useState as useState7
|
|
1064
1037
|
} from "react";
|
|
1065
1038
|
import { createPortal } from "react-dom";
|
|
1066
1039
|
import {
|
|
@@ -1072,7 +1045,7 @@ import {
|
|
|
1072
1045
|
} from "@lime-bundles/core";
|
|
1073
1046
|
|
|
1074
1047
|
// src/hooks/useScrollLock.ts
|
|
1075
|
-
import { useEffect as
|
|
1048
|
+
import { useEffect as useEffect8 } from "react";
|
|
1076
1049
|
var lockCount = 0;
|
|
1077
1050
|
var savedY = 0;
|
|
1078
1051
|
function lock() {
|
|
@@ -1101,7 +1074,7 @@ function unlock() {
|
|
|
1101
1074
|
window.scrollTo(0, savedY);
|
|
1102
1075
|
}
|
|
1103
1076
|
function useScrollLock(active) {
|
|
1104
|
-
|
|
1077
|
+
useEffect8(() => {
|
|
1105
1078
|
if (!active) return;
|
|
1106
1079
|
lock();
|
|
1107
1080
|
return unlock;
|
|
@@ -1109,7 +1082,7 @@ function useScrollLock(active) {
|
|
|
1109
1082
|
}
|
|
1110
1083
|
|
|
1111
1084
|
// src/hooks/useFocusTrap.ts
|
|
1112
|
-
import { useEffect as
|
|
1085
|
+
import { useEffect as useEffect9, useRef as useRef5 } from "react";
|
|
1113
1086
|
var FOCUSABLE_SELECTOR = [
|
|
1114
1087
|
"a[href]",
|
|
1115
1088
|
"button:not([disabled])",
|
|
@@ -1132,14 +1105,16 @@ function useFocusTrap({
|
|
|
1132
1105
|
active,
|
|
1133
1106
|
containerRef,
|
|
1134
1107
|
onEscape,
|
|
1108
|
+
initialFocusRef,
|
|
1135
1109
|
returnFocusRef
|
|
1136
1110
|
}) {
|
|
1137
1111
|
const previouslyFocused = useRef5(null);
|
|
1138
|
-
|
|
1112
|
+
useEffect9(() => {
|
|
1139
1113
|
if (!active) return;
|
|
1140
1114
|
const container = containerRef.current;
|
|
1141
1115
|
previouslyFocused.current = document.activeElement ?? null;
|
|
1142
|
-
container
|
|
1116
|
+
const initial = initialFocusRef?.current ?? container;
|
|
1117
|
+
initial?.focus();
|
|
1143
1118
|
function onKeyDown(e) {
|
|
1144
1119
|
if (e.key === "Escape") {
|
|
1145
1120
|
e.preventDefault();
|
|
@@ -1191,7 +1166,7 @@ function variantRuleFor(bundle, variantId) {
|
|
|
1191
1166
|
function sanitizeId(gid) {
|
|
1192
1167
|
return gid.replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
1193
1168
|
}
|
|
1194
|
-
function buildEligibleProducts(bundle
|
|
1169
|
+
function buildEligibleProducts(bundle) {
|
|
1195
1170
|
const result = [];
|
|
1196
1171
|
const seen = /* @__PURE__ */ new Set();
|
|
1197
1172
|
for (const product of bundle.products) {
|
|
@@ -1202,7 +1177,6 @@ function buildEligibleProducts(bundle, oosBehavior) {
|
|
|
1202
1177
|
(v) => isVariantFulfillable2(v, rule.min)
|
|
1203
1178
|
);
|
|
1204
1179
|
const isOos = available.length === 0;
|
|
1205
|
-
if (isOos && oosBehavior === "hide") continue;
|
|
1206
1180
|
result.push({
|
|
1207
1181
|
product,
|
|
1208
1182
|
variants: product.variants.nodes,
|
|
@@ -1217,7 +1191,6 @@ function normalizeText(str) {
|
|
|
1217
1191
|
}
|
|
1218
1192
|
var FILTERS_ALL = "__all__";
|
|
1219
1193
|
function MixMatchPicker({
|
|
1220
|
-
outOfStockBehavior,
|
|
1221
1194
|
bundle,
|
|
1222
1195
|
currency,
|
|
1223
1196
|
requiredQty,
|
|
@@ -1235,13 +1208,14 @@ function MixMatchPicker({
|
|
|
1235
1208
|
const wc = bundle.widgetConfig;
|
|
1236
1209
|
const overlayRef = useRef6(null);
|
|
1237
1210
|
const dialogRef = useRef6(null);
|
|
1211
|
+
const closeBtnRef = useRef6(null);
|
|
1238
1212
|
const mouseDownTarget = useRef6(null);
|
|
1239
|
-
const [open, setOpen] =
|
|
1240
|
-
const [query, setQuery] =
|
|
1241
|
-
const [activeType, setActiveType] =
|
|
1213
|
+
const [open, setOpen] = useState7(false);
|
|
1214
|
+
const [query, setQuery] = useState7("");
|
|
1215
|
+
const [activeType, setActiveType] = useState7(FILTERS_ALL);
|
|
1242
1216
|
const eligible = useMemo5(
|
|
1243
|
-
() => buildEligibleProducts(bundle
|
|
1244
|
-
[bundle
|
|
1217
|
+
() => buildEligibleProducts(bundle),
|
|
1218
|
+
[bundle]
|
|
1245
1219
|
);
|
|
1246
1220
|
const productTypes = useMemo5(() => {
|
|
1247
1221
|
const types = [];
|
|
@@ -1259,7 +1233,7 @@ function MixMatchPicker({
|
|
|
1259
1233
|
const totalUnits = selections.reduce((sum, s) => sum + s.quantity, 0);
|
|
1260
1234
|
const atCapacity = totalUnits >= requiredQty;
|
|
1261
1235
|
const shownUnits = Math.min(totalUnits, requiredQty);
|
|
1262
|
-
|
|
1236
|
+
useEffect10(() => {
|
|
1263
1237
|
const id = requestAnimationFrame(() => setOpen(true));
|
|
1264
1238
|
return () => cancelAnimationFrame(id);
|
|
1265
1239
|
}, []);
|
|
@@ -1267,6 +1241,7 @@ function MixMatchPicker({
|
|
|
1267
1241
|
useFocusTrap({
|
|
1268
1242
|
active: true,
|
|
1269
1243
|
containerRef: dialogRef,
|
|
1244
|
+
initialFocusRef: closeBtnRef,
|
|
1270
1245
|
onEscape: onClose
|
|
1271
1246
|
});
|
|
1272
1247
|
const remaining = Math.max(0, requiredQty - shownUnits);
|
|
@@ -1275,14 +1250,25 @@ function MixMatchPicker({
|
|
|
1275
1250
|
const pct = bundle.discountConfig.discountType === "percentage" && bundle.discountConfig.discountValue ? Math.round(bundle.discountConfig.discountValue) : 0;
|
|
1276
1251
|
return pct > 0 ? `Choose ${remaining} more to unlock ${pct}% off` : `Choose ${remaining} more to complete your bundle`;
|
|
1277
1252
|
})();
|
|
1253
|
+
const [selectedAtOpen] = useState7(
|
|
1254
|
+
() => new Set(selections.map((s) => s.productId))
|
|
1255
|
+
);
|
|
1256
|
+
const ordered = useMemo5(() => {
|
|
1257
|
+
const front = [];
|
|
1258
|
+
const back = [];
|
|
1259
|
+
for (const ep of eligible) {
|
|
1260
|
+
(selectedAtOpen.has(ep.product.id) ? back : front).push(ep);
|
|
1261
|
+
}
|
|
1262
|
+
return front.concat(back);
|
|
1263
|
+
}, [eligible, selectedAtOpen]);
|
|
1278
1264
|
const filtered = useMemo5(() => {
|
|
1279
1265
|
const nq = normalizeText(query.trim());
|
|
1280
|
-
return
|
|
1266
|
+
return ordered.filter((ep) => {
|
|
1281
1267
|
const matchesQuery = !nq || normalizeText(ep.product.title).includes(nq);
|
|
1282
1268
|
const matchesType = activeType === FILTERS_ALL || (ep.product.productType ?? "") === activeType;
|
|
1283
1269
|
return matchesQuery && matchesType;
|
|
1284
1270
|
});
|
|
1285
|
-
}, [
|
|
1271
|
+
}, [ordered, query, activeType]);
|
|
1286
1272
|
const showEmpty = filtered.length === 0 && query.trim().length > 0;
|
|
1287
1273
|
function onOverlayMouseDown(e) {
|
|
1288
1274
|
mouseDownTarget.current = e.target;
|
|
@@ -1331,6 +1317,7 @@ function MixMatchPicker({
|
|
|
1331
1317
|
/* @__PURE__ */ jsx4(
|
|
1332
1318
|
"button",
|
|
1333
1319
|
{
|
|
1320
|
+
ref: closeBtnRef,
|
|
1334
1321
|
type: "button",
|
|
1335
1322
|
className: "lb-mix-match__modal-close",
|
|
1336
1323
|
"data-modal-close": true,
|
|
@@ -1533,12 +1520,12 @@ function MixMatchPickerRow({
|
|
|
1533
1520
|
Math.max(0, alreadyInBundle - committedQty)
|
|
1534
1521
|
) : 0;
|
|
1535
1522
|
const stepperMax = Math.max(vRule.min, cap);
|
|
1536
|
-
const [qty, setQty] =
|
|
1537
|
-
|
|
1523
|
+
const [qty, setQty] = useState7(vRule.min);
|
|
1524
|
+
useEffect10(() => {
|
|
1538
1525
|
setQty((prev) => Math.max(vRule.min, Math.min(prev, stepperMax)));
|
|
1539
1526
|
}, [stepperMax, vRule.min]);
|
|
1540
1527
|
const currentVariantId = currentVariant?.id ?? null;
|
|
1541
|
-
|
|
1528
|
+
useEffect10(() => {
|
|
1542
1529
|
if (!variantInBundle) setQty(vRule.min);
|
|
1543
1530
|
}, [variantInBundle, currentVariantId, vRule.min]);
|
|
1544
1531
|
if (!currentVariant) return null;
|
|
@@ -1800,10 +1787,6 @@ function MixMatchBundle(props) {
|
|
|
1800
1787
|
storefrontAccessToken,
|
|
1801
1788
|
bundleGid
|
|
1802
1789
|
});
|
|
1803
|
-
const { outOfStockBehavior } = useShopSettings({
|
|
1804
|
-
shopDomain,
|
|
1805
|
-
storefrontAccessToken
|
|
1806
|
-
});
|
|
1807
1790
|
const { elementRef, trackAddToCart } = useAnalytics({
|
|
1808
1791
|
shopDomain,
|
|
1809
1792
|
appUrl: appUrl ?? `https://${shopDomain}`,
|
|
@@ -1811,16 +1794,16 @@ function MixMatchBundle(props) {
|
|
|
1811
1794
|
bundleType: "mix_match",
|
|
1812
1795
|
enabled: analyticsEnabled !== false
|
|
1813
1796
|
});
|
|
1814
|
-
const [selections, setSelections] =
|
|
1815
|
-
const [seededFor, setSeededFor] =
|
|
1816
|
-
const [pickerOpen, setPickerOpen] =
|
|
1817
|
-
const [addingToCart, setAddingToCart] =
|
|
1818
|
-
const [cartError, setCartError] =
|
|
1797
|
+
const [selections, setSelections] = useState8([]);
|
|
1798
|
+
const [seededFor, setSeededFor] = useState8(null);
|
|
1799
|
+
const [pickerOpen, setPickerOpen] = useState8(false);
|
|
1800
|
+
const [addingToCart, setAddingToCart] = useState8(false);
|
|
1801
|
+
const [cartError, setCartError] = useState8(null);
|
|
1819
1802
|
const bundle = result.status === "success" && result.bundle.bundleType === "mix_match" ? result.bundle : null;
|
|
1820
1803
|
const setConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);
|
|
1821
1804
|
const setModalConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);
|
|
1822
1805
|
const slotsEdgeFadeRef = useEdgeFade();
|
|
1823
|
-
|
|
1806
|
+
useEffect11(() => {
|
|
1824
1807
|
if (result.status === "error") {
|
|
1825
1808
|
onError?.(result.error);
|
|
1826
1809
|
return;
|
|
@@ -1833,7 +1816,7 @@ function MixMatchBundle(props) {
|
|
|
1833
1816
|
);
|
|
1834
1817
|
}
|
|
1835
1818
|
}, [result, onError]);
|
|
1836
|
-
|
|
1819
|
+
useEffect11(() => {
|
|
1837
1820
|
if (!bundle || seededFor === bundle.id) return;
|
|
1838
1821
|
setSeededFor(bundle.id);
|
|
1839
1822
|
const seedCurrency = bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? "USD";
|
|
@@ -2243,7 +2226,6 @@ function MixMatchBundle(props) {
|
|
|
2243
2226
|
pickerOpen && /* @__PURE__ */ jsx5(
|
|
2244
2227
|
MixMatchPicker,
|
|
2245
2228
|
{
|
|
2246
|
-
outOfStockBehavior,
|
|
2247
2229
|
bundle,
|
|
2248
2230
|
currency,
|
|
2249
2231
|
requiredQty: requiredUnits,
|
|
@@ -2316,7 +2298,7 @@ function CloseIcon2() {
|
|
|
2316
2298
|
}
|
|
2317
2299
|
|
|
2318
2300
|
// src/components/VolumeBundle.tsx
|
|
2319
|
-
import { useCallback as useCallback7, useEffect as
|
|
2301
|
+
import { useCallback as useCallback7, useEffect as useEffect12, useMemo as useMemo7, useState as useState9 } from "react";
|
|
2320
2302
|
import {
|
|
2321
2303
|
formatMoney as formatMoney4,
|
|
2322
2304
|
formatUnitPrice as formatUnitPrice4,
|
|
@@ -2353,12 +2335,12 @@ function VolumeBundle(props) {
|
|
|
2353
2335
|
bundleType: "volume",
|
|
2354
2336
|
enabled: analyticsEnabled !== false
|
|
2355
2337
|
});
|
|
2356
|
-
const [quantity, setQuantity] =
|
|
2357
|
-
const [addingToCart, setAddingToCart] =
|
|
2358
|
-
const [cartError, setCartError] =
|
|
2359
|
-
const [seededFor, setSeededFor] =
|
|
2338
|
+
const [quantity, setQuantity] = useState9(1);
|
|
2339
|
+
const [addingToCart, setAddingToCart] = useState9(false);
|
|
2340
|
+
const [cartError, setCartError] = useState9(null);
|
|
2341
|
+
const [seededFor, setSeededFor] = useState9(null);
|
|
2360
2342
|
const bundle = result.status === "success" && result.bundle.bundleType === "volume" ? result.bundle : null;
|
|
2361
|
-
|
|
2343
|
+
useEffect12(() => {
|
|
2362
2344
|
if (!bundle || seededFor === bundle.id) return;
|
|
2363
2345
|
setSeededFor(bundle.id);
|
|
2364
2346
|
const tiers = bundle.volumeTiers;
|
|
@@ -2376,7 +2358,7 @@ function VolumeBundle(props) {
|
|
|
2376
2358
|
}, [bundle, seededFor]);
|
|
2377
2359
|
const setConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);
|
|
2378
2360
|
const tiersEdgeFadeRef = useEdgeFade();
|
|
2379
|
-
|
|
2361
|
+
useEffect12(() => {
|
|
2380
2362
|
if (result.status === "error") {
|
|
2381
2363
|
onError?.(result.error);
|
|
2382
2364
|
return;
|
|
@@ -2400,6 +2382,11 @@ function VolumeBundle(props) {
|
|
|
2400
2382
|
const minTierQty = bundle ? getMinTierQuantity(bundle.volumeTiers) : 1;
|
|
2401
2383
|
const isSoldOut = variants.length > 0 && !variants.some((v) => isVariantFulfillable4(v, minTierQty));
|
|
2402
2384
|
const displayVariant = selectedVariant ?? variants.find((v) => isVariantFulfillable4(v, minTierQty)) ?? variants[0];
|
|
2385
|
+
const tierAvailable = useCallback7(
|
|
2386
|
+
(tierQty) => Boolean(displayVariant && isVariantFulfillable4(displayVariant, tierQty)),
|
|
2387
|
+
[displayVariant]
|
|
2388
|
+
);
|
|
2389
|
+
const selectedTierUnavailable = !isSoldOut && !tierAvailable(quantity);
|
|
2403
2390
|
const basePrice = displayVariant ? parseFloat(displayVariant.price.amount) : product ? parseFloat(product.priceRange.minVariantPrice.amount) : 0;
|
|
2404
2391
|
const currency = product?.priceRange.minVariantPrice.currencyCode ?? "USD";
|
|
2405
2392
|
const thumbImage = displayVariant?.image ?? product?.featuredImage ?? null;
|
|
@@ -2557,16 +2544,20 @@ function VolumeBundle(props) {
|
|
|
2557
2544
|
const savingsPercent = Math.round(ts.savingsPercent);
|
|
2558
2545
|
const showCompare = bundle.widgetConfig.pricing.showComparePrice && ts.savings > 0;
|
|
2559
2546
|
const isChecked = activeTier === ts.tier;
|
|
2547
|
+
const available = tierAvailable(ts.tier.minQuantity);
|
|
2560
2548
|
return /* @__PURE__ */ jsxs6(
|
|
2561
2549
|
"div",
|
|
2562
2550
|
{
|
|
2563
|
-
className: `lb-bundle__tier ${ts.isActive ? "lb-bundle__tier--active" : ""}`,
|
|
2551
|
+
className: `lb-bundle__tier ${ts.isActive ? "lb-bundle__tier--active" : ""} ${available ? "" : "lb-bundle__tier--oos"}`,
|
|
2564
2552
|
role: "radio",
|
|
2565
2553
|
"aria-checked": isChecked,
|
|
2554
|
+
"aria-disabled": available ? void 0 : true,
|
|
2566
2555
|
tabIndex: isChecked ? 0 : -1,
|
|
2567
|
-
onClick: () =>
|
|
2556
|
+
onClick: () => {
|
|
2557
|
+
if (available) setQuantity(ts.tier.minQuantity);
|
|
2558
|
+
},
|
|
2568
2559
|
onKeyDown: (e) => {
|
|
2569
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
2560
|
+
if ((e.key === "Enter" || e.key === " ") && available) {
|
|
2570
2561
|
e.preventDefault();
|
|
2571
2562
|
setQuantity(ts.tier.minQuantity);
|
|
2572
2563
|
}
|
|
@@ -2681,9 +2672,9 @@ function VolumeBundle(props) {
|
|
|
2681
2672
|
{
|
|
2682
2673
|
className: "lb-bundle__cta",
|
|
2683
2674
|
onClick: handleAddToCart,
|
|
2684
|
-
disabled: addingToCart || isSoldOut,
|
|
2675
|
+
disabled: addingToCart || isSoldOut || selectedTierUnavailable,
|
|
2685
2676
|
"aria-busy": addingToCart,
|
|
2686
|
-
children: addingToCart ? "Adding..." : isSoldOut ? "Sold out" : bundle.widgetConfig.cta.ctaText ?? `Add ${quantity} to Cart`
|
|
2677
|
+
children: addingToCart ? "Adding..." : isSoldOut || selectedTierUnavailable ? "Sold out" : bundle.widgetConfig.cta.ctaText ?? `Add ${quantity} to Cart`
|
|
2687
2678
|
}
|
|
2688
2679
|
)
|
|
2689
2680
|
]
|
|
@@ -2692,7 +2683,7 @@ function VolumeBundle(props) {
|
|
|
2692
2683
|
}
|
|
2693
2684
|
|
|
2694
2685
|
// src/components/BogoBundle.tsx
|
|
2695
|
-
import { useCallback as useCallback8, useEffect as
|
|
2686
|
+
import { useCallback as useCallback8, useEffect as useEffect13, useMemo as useMemo8, useState as useState10 } from "react";
|
|
2696
2687
|
import {
|
|
2697
2688
|
formatMoney as formatMoney5,
|
|
2698
2689
|
formatUnitPrice as formatUnitPrice5,
|
|
@@ -2727,9 +2718,9 @@ function BogoBundle(props) {
|
|
|
2727
2718
|
bundleType: "bogo",
|
|
2728
2719
|
enabled: analyticsEnabled !== false
|
|
2729
2720
|
});
|
|
2730
|
-
const [addingToCart, setAddingToCart] =
|
|
2731
|
-
const [cartError, setCartError] =
|
|
2732
|
-
const [selectedVariants, setSelectedVariants] =
|
|
2721
|
+
const [addingToCart, setAddingToCart] = useState10(false);
|
|
2722
|
+
const [cartError, setCartError] = useState10(null);
|
|
2723
|
+
const [selectedVariants, setSelectedVariants] = useState10({ buy: null, get: null });
|
|
2733
2724
|
const handleVariantChange = useCallback8(
|
|
2734
2725
|
(role, variant) => {
|
|
2735
2726
|
setSelectedVariants((prev) => {
|
|
@@ -2741,7 +2732,7 @@ function BogoBundle(props) {
|
|
|
2741
2732
|
);
|
|
2742
2733
|
const bundle = result.status === "success" && result.bundle.bundleType === "bogo" ? result.bundle : null;
|
|
2743
2734
|
const setConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);
|
|
2744
|
-
|
|
2735
|
+
useEffect13(() => {
|
|
2745
2736
|
if (result.status === "error") {
|
|
2746
2737
|
onError?.(result.error);
|
|
2747
2738
|
return;
|
|
@@ -2940,7 +2931,7 @@ function BogoProductRow({ side, product, quantity, percent, badge, currency, onV
|
|
|
2940
2931
|
variants,
|
|
2941
2932
|
optionNames
|
|
2942
2933
|
});
|
|
2943
|
-
|
|
2934
|
+
useEffect13(() => {
|
|
2944
2935
|
onVariantChange(side, selectedVariant ?? null);
|
|
2945
2936
|
}, [selectedVariant, side, onVariantChange]);
|
|
2946
2937
|
const displayVariant = selectedVariant ?? variants.find((v) => isVariantFulfillable5(v, quantity)) ?? variants[0];
|
|
@@ -3013,7 +3004,7 @@ function BogoProductRow({ side, product, quantity, percent, badge, currency, onV
|
|
|
3013
3004
|
}
|
|
3014
3005
|
|
|
3015
3006
|
// src/components/MultiStepBundle.tsx
|
|
3016
|
-
import { useCallback as useCallback9, useEffect as
|
|
3007
|
+
import { useCallback as useCallback9, useEffect as useEffect15, useMemo as useMemo10, useState as useState12 } from "react";
|
|
3017
3008
|
import {
|
|
3018
3009
|
formatMoney as formatMoney7,
|
|
3019
3010
|
formatUnitPrice as formatUnitPrice7,
|
|
@@ -3026,10 +3017,10 @@ import {
|
|
|
3026
3017
|
|
|
3027
3018
|
// src/components/MultiStepPicker.tsx
|
|
3028
3019
|
import {
|
|
3029
|
-
useEffect as
|
|
3020
|
+
useEffect as useEffect14,
|
|
3030
3021
|
useMemo as useMemo9,
|
|
3031
3022
|
useRef as useRef7,
|
|
3032
|
-
useState as
|
|
3023
|
+
useState as useState11
|
|
3033
3024
|
} from "react";
|
|
3034
3025
|
import { createPortal as createPortal2 } from "react-dom";
|
|
3035
3026
|
import {
|
|
@@ -3055,7 +3046,7 @@ function variantRuleFor3(bundle, variantId) {
|
|
|
3055
3046
|
function sanitizeId2(gid) {
|
|
3056
3047
|
return gid.replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
3057
3048
|
}
|
|
3058
|
-
function buildEligibleProducts2(bundle, stepIndex
|
|
3049
|
+
function buildEligibleProducts2(bundle, stepIndex) {
|
|
3059
3050
|
const result = [];
|
|
3060
3051
|
for (const product of productsForStep(bundle, stepIndex)) {
|
|
3061
3052
|
const rule = ruleFor3(bundle, product.id);
|
|
@@ -3063,7 +3054,6 @@ function buildEligibleProducts2(bundle, stepIndex, oosBehavior) {
|
|
|
3063
3054
|
(v) => isVariantFulfillable6(v, rule.min)
|
|
3064
3055
|
);
|
|
3065
3056
|
const isOos = available.length === 0;
|
|
3066
|
-
if (isOos && oosBehavior === "hide") continue;
|
|
3067
3057
|
result.push({
|
|
3068
3058
|
product,
|
|
3069
3059
|
variants: product.variants.nodes,
|
|
@@ -3078,7 +3068,6 @@ function normalizeText2(str) {
|
|
|
3078
3068
|
}
|
|
3079
3069
|
var FILTERS_ALL2 = "__all__";
|
|
3080
3070
|
function MultiStepPicker({
|
|
3081
|
-
outOfStockBehavior,
|
|
3082
3071
|
bundle,
|
|
3083
3072
|
currency,
|
|
3084
3073
|
initialStep,
|
|
@@ -3098,14 +3087,16 @@ function MultiStepPicker({
|
|
|
3098
3087
|
const overlayRef = useRef7(null);
|
|
3099
3088
|
const dialogRef = useRef7(null);
|
|
3100
3089
|
const titleRef = useRef7(null);
|
|
3090
|
+
const closeBtnRef = useRef7(null);
|
|
3091
|
+
const listRef = useRef7(null);
|
|
3101
3092
|
const mouseDownTarget = useRef7(null);
|
|
3102
|
-
const [open, setOpen] =
|
|
3103
|
-
const [stepIndex, setStepIndex] =
|
|
3093
|
+
const [open, setOpen] = useState11(false);
|
|
3094
|
+
const [stepIndex, setStepIndex] = useState11(
|
|
3104
3095
|
() => Math.max(0, Math.min(steps.length - 1, initialStep))
|
|
3105
3096
|
);
|
|
3106
|
-
const [query, setQuery] =
|
|
3107
|
-
const [activeType, setActiveType] =
|
|
3108
|
-
const [announcement, setAnnouncement] =
|
|
3097
|
+
const [query, setQuery] = useState11("");
|
|
3098
|
+
const [activeType, setActiveType] = useState11(FILTERS_ALL2);
|
|
3099
|
+
const [announcement, setAnnouncement] = useState11("");
|
|
3109
3100
|
const step = steps[stepIndex];
|
|
3110
3101
|
const stepMin = step?.minQuantity ?? 1;
|
|
3111
3102
|
const stepPicks = selections[stepIndex] ?? [];
|
|
@@ -3114,8 +3105,8 @@ function MultiStepPicker({
|
|
|
3114
3105
|
const isLastStep = stepIndex === steps.length - 1;
|
|
3115
3106
|
const shownUnits = Math.min(unitsInStep, stepMin);
|
|
3116
3107
|
const eligible = useMemo9(
|
|
3117
|
-
() => buildEligibleProducts2(bundle, stepIndex
|
|
3118
|
-
[bundle, stepIndex
|
|
3108
|
+
() => buildEligibleProducts2(bundle, stepIndex),
|
|
3109
|
+
[bundle, stepIndex]
|
|
3119
3110
|
);
|
|
3120
3111
|
const productTypes = useMemo9(() => {
|
|
3121
3112
|
const types = [];
|
|
@@ -3130,7 +3121,7 @@ function MultiStepPicker({
|
|
|
3130
3121
|
return types;
|
|
3131
3122
|
}, [eligible]);
|
|
3132
3123
|
const showFilters = wc.mixMatchShowTypeFilters && productTypes.length >= 2;
|
|
3133
|
-
|
|
3124
|
+
useEffect14(() => {
|
|
3134
3125
|
const id = requestAnimationFrame(() => setOpen(true));
|
|
3135
3126
|
return () => cancelAnimationFrame(id);
|
|
3136
3127
|
}, []);
|
|
@@ -3138,8 +3129,23 @@ function MultiStepPicker({
|
|
|
3138
3129
|
useFocusTrap({
|
|
3139
3130
|
active: true,
|
|
3140
3131
|
containerRef: dialogRef,
|
|
3132
|
+
initialFocusRef: closeBtnRef,
|
|
3141
3133
|
onEscape: onClose
|
|
3142
3134
|
});
|
|
3135
|
+
useEffect14(() => {
|
|
3136
|
+
if (listRef.current) listRef.current.scrollTop = 0;
|
|
3137
|
+
}, [stepIndex]);
|
|
3138
|
+
const [selectedAtLoad, setSelectedAtLoad] = useState11(
|
|
3139
|
+
() => new Set((selections[stepIndex] ?? []).map((s) => s.productId))
|
|
3140
|
+
);
|
|
3141
|
+
const ordered = useMemo9(() => {
|
|
3142
|
+
const front = [];
|
|
3143
|
+
const back = [];
|
|
3144
|
+
for (const ep of eligible) {
|
|
3145
|
+
(selectedAtLoad.has(ep.product.id) ? back : front).push(ep);
|
|
3146
|
+
}
|
|
3147
|
+
return front.concat(back);
|
|
3148
|
+
}, [eligible, selectedAtLoad]);
|
|
3143
3149
|
function goToStep(i) {
|
|
3144
3150
|
const clamped = Math.max(0, Math.min(steps.length - 1, i));
|
|
3145
3151
|
setStepIndex(clamped);
|
|
@@ -3147,6 +3153,7 @@ function MultiStepPicker({
|
|
|
3147
3153
|
setActiveType(FILTERS_ALL2);
|
|
3148
3154
|
const target = steps[clamped];
|
|
3149
3155
|
const targetPicks = selections[clamped] ?? [];
|
|
3156
|
+
setSelectedAtLoad(new Set(targetPicks.map((s) => s.productId)));
|
|
3150
3157
|
const targetUnits = targetPicks.reduce((sum, s) => sum + s.quantity, 0);
|
|
3151
3158
|
setAnnouncement(
|
|
3152
3159
|
`Step ${clamped + 1} of ${steps.length}. ${target.name}. ${Math.min(targetUnits, target.minQuantity)} of ${target.minQuantity} added`
|
|
@@ -3156,12 +3163,12 @@ function MultiStepPicker({
|
|
|
3156
3163
|
const subtitle = `Step ${stepIndex + 1} of ${steps.length} \xB7 ${step?.name ?? ""}`;
|
|
3157
3164
|
const filtered = useMemo9(() => {
|
|
3158
3165
|
const nq = normalizeText2(query.trim());
|
|
3159
|
-
return
|
|
3166
|
+
return ordered.filter((ep) => {
|
|
3160
3167
|
const matchesQuery = !nq || normalizeText2(ep.product.title).includes(nq);
|
|
3161
3168
|
const matchesType = activeType === FILTERS_ALL2 || (ep.product.productType ?? "") === activeType;
|
|
3162
3169
|
return matchesQuery && matchesType;
|
|
3163
3170
|
});
|
|
3164
|
-
}, [
|
|
3171
|
+
}, [ordered, query, activeType]);
|
|
3165
3172
|
const showEmpty = filtered.length === 0 && query.trim().length > 0;
|
|
3166
3173
|
function onOverlayMouseDown(e) {
|
|
3167
3174
|
mouseDownTarget.current = e.target;
|
|
@@ -3219,6 +3226,7 @@ function MultiStepPicker({
|
|
|
3219
3226
|
/* @__PURE__ */ jsx8(
|
|
3220
3227
|
"button",
|
|
3221
3228
|
{
|
|
3229
|
+
ref: closeBtnRef,
|
|
3222
3230
|
type: "button",
|
|
3223
3231
|
className: "lb-mix-match__modal-close",
|
|
3224
3232
|
"data-modal-close": true,
|
|
@@ -3306,7 +3314,7 @@ function MultiStepPicker({
|
|
|
3306
3314
|
})
|
|
3307
3315
|
}
|
|
3308
3316
|
),
|
|
3309
|
-
/* @__PURE__ */ jsx8("div", { className: "lb-mix-match__modal-list", "data-modal-list": true, children: filtered.map((ep) => /* @__PURE__ */ jsx8(
|
|
3317
|
+
/* @__PURE__ */ jsx8("div", { className: "lb-mix-match__modal-list", "data-modal-list": true, ref: listRef, children: filtered.map((ep) => /* @__PURE__ */ jsx8(
|
|
3310
3318
|
MultiStepPickerRow,
|
|
3311
3319
|
{
|
|
3312
3320
|
bundle,
|
|
@@ -3453,12 +3461,12 @@ function MultiStepPickerRow({
|
|
|
3453
3461
|
const stockRemaining = currentVariant ? maxAddableQuantity2(currentVariant, Number.MAX_SAFE_INTEGER, variantOtherUnits) : 0;
|
|
3454
3462
|
const cap = Math.max(0, Math.min(spotCeiling, stockRemaining));
|
|
3455
3463
|
const stepperMax = Math.max(vRule.min, cap);
|
|
3456
|
-
const [qty, setQty] =
|
|
3457
|
-
|
|
3464
|
+
const [qty, setQty] = useState11(vRule.min);
|
|
3465
|
+
useEffect14(() => {
|
|
3458
3466
|
setQty((prev) => Math.max(vRule.min, Math.min(prev, stepperMax)));
|
|
3459
3467
|
}, [stepperMax, vRule.min]);
|
|
3460
3468
|
const currentVariantId = currentVariant?.id ?? null;
|
|
3461
|
-
|
|
3469
|
+
useEffect14(() => {
|
|
3462
3470
|
if (!variantInStep) setQty(vRule.min);
|
|
3463
3471
|
}, [variantInStep, currentVariantId, vRule.min]);
|
|
3464
3472
|
if (!currentVariant || !step) return null;
|
|
@@ -3729,10 +3737,6 @@ function MultiStepBundle(props) {
|
|
|
3729
3737
|
storefrontAccessToken,
|
|
3730
3738
|
bundleGid
|
|
3731
3739
|
});
|
|
3732
|
-
const { outOfStockBehavior } = useShopSettings({
|
|
3733
|
-
shopDomain,
|
|
3734
|
-
storefrontAccessToken
|
|
3735
|
-
});
|
|
3736
3740
|
const { elementRef, trackAddToCart } = useAnalytics({
|
|
3737
3741
|
shopDomain,
|
|
3738
3742
|
appUrl: appUrl ?? `https://${shopDomain}`,
|
|
@@ -3740,14 +3744,14 @@ function MultiStepBundle(props) {
|
|
|
3740
3744
|
bundleType: "multi_step",
|
|
3741
3745
|
enabled: analyticsEnabled !== false
|
|
3742
3746
|
});
|
|
3743
|
-
const [selections, setSelections] =
|
|
3744
|
-
const [pickerOpenAt, setPickerOpenAt] =
|
|
3745
|
-
const [addingToCart, setAddingToCart] =
|
|
3746
|
-
const [cartError, setCartError] =
|
|
3747
|
+
const [selections, setSelections] = useState12([]);
|
|
3748
|
+
const [pickerOpenAt, setPickerOpenAt] = useState12(null);
|
|
3749
|
+
const [addingToCart, setAddingToCart] = useState12(false);
|
|
3750
|
+
const [cartError, setCartError] = useState12(null);
|
|
3747
3751
|
const bundle = result.status === "success" && result.bundle.bundleType === "multi_step" ? result.bundle : null;
|
|
3748
3752
|
const setConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);
|
|
3749
3753
|
const setModalConfigVarsRef = useWidgetConfigVars(bundle?.widgetConfig);
|
|
3750
|
-
|
|
3754
|
+
useEffect15(() => {
|
|
3751
3755
|
if (result.status === "error") {
|
|
3752
3756
|
onError?.(result.error);
|
|
3753
3757
|
return;
|
|
@@ -3761,7 +3765,7 @@ function MultiStepBundle(props) {
|
|
|
3761
3765
|
}
|
|
3762
3766
|
}, [result, onError]);
|
|
3763
3767
|
const steps = useMemo10(() => bundle?.steps ?? [], [bundle]);
|
|
3764
|
-
|
|
3768
|
+
useEffect15(() => {
|
|
3765
3769
|
const seeded = steps.map(() => []);
|
|
3766
3770
|
if (bundle) {
|
|
3767
3771
|
const seedCurrency = bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? "USD";
|
|
@@ -4201,7 +4205,6 @@ function MultiStepBundle(props) {
|
|
|
4201
4205
|
pickerOpenAt !== null && /* @__PURE__ */ jsx9(
|
|
4202
4206
|
MultiStepPicker,
|
|
4203
4207
|
{
|
|
4204
|
-
outOfStockBehavior,
|
|
4205
4208
|
bundle,
|
|
4206
4209
|
currency,
|
|
4207
4210
|
initialStep: pickerOpenAt,
|
|
@@ -4275,7 +4278,7 @@ async function fetchShopCustomCss(options) {
|
|
|
4275
4278
|
}
|
|
4276
4279
|
|
|
4277
4280
|
// src/hooks/useBundlesForProduct.ts
|
|
4278
|
-
import { useState as
|
|
4281
|
+
import { useState as useState13, useEffect as useEffect16 } from "react";
|
|
4279
4282
|
import {
|
|
4280
4283
|
fetchBundlesForProduct,
|
|
4281
4284
|
injectCustomCss as injectCustomCss2
|
|
@@ -4286,10 +4289,10 @@ var INITIAL_STATE2 = {
|
|
|
4286
4289
|
error: null
|
|
4287
4290
|
};
|
|
4288
4291
|
function useBundlesForProduct(options) {
|
|
4289
|
-
const [state, setState] =
|
|
4292
|
+
const [state, setState] = useState13(
|
|
4290
4293
|
INITIAL_STATE2
|
|
4291
4294
|
);
|
|
4292
|
-
|
|
4295
|
+
useEffect16(() => {
|
|
4293
4296
|
const controller = new AbortController();
|
|
4294
4297
|
setState(INITIAL_STATE2);
|
|
4295
4298
|
fetchBundlesForProduct({
|
|
@@ -4363,9 +4366,7 @@ import {
|
|
|
4363
4366
|
parseMetaobjectBundleStrict as parseMetaobjectBundleStrict2,
|
|
4364
4367
|
BUNDLE_METAOBJECT_QUERY as BUNDLE_METAOBJECT_QUERY2,
|
|
4365
4368
|
BUNDLES_FOR_PRODUCT_QUERY,
|
|
4366
|
-
SHOP_SETTINGS_QUERY as SHOP_SETTINGS_QUERY2
|
|
4367
|
-
DEFAULT_OUT_OF_STOCK_BEHAVIOR as DEFAULT_OUT_OF_STOCK_BEHAVIOR3,
|
|
4368
|
-
parseOutOfStockBehavior as parseOutOfStockBehavior2
|
|
4369
|
+
SHOP_SETTINGS_QUERY as SHOP_SETTINGS_QUERY2
|
|
4369
4370
|
} from "@lime-bundles/core";
|
|
4370
4371
|
export {
|
|
4371
4372
|
BUNDLES_FOR_PRODUCT_QUERY,
|
|
@@ -4373,7 +4374,6 @@ export {
|
|
|
4373
4374
|
BogoBundle,
|
|
4374
4375
|
BundleCountdown,
|
|
4375
4376
|
BundleParseError2 as BundleParseError,
|
|
4376
|
-
DEFAULT_OUT_OF_STOCK_BEHAVIOR3 as DEFAULT_OUT_OF_STOCK_BEHAVIOR,
|
|
4377
4377
|
FixedBundle,
|
|
4378
4378
|
MixMatchBundle,
|
|
4379
4379
|
MultiStepBundle,
|
|
@@ -4404,7 +4404,6 @@ export {
|
|
|
4404
4404
|
parseCents,
|
|
4405
4405
|
parseMetaobjectBundle,
|
|
4406
4406
|
parseMetaobjectBundleStrict2 as parseMetaobjectBundleStrict,
|
|
4407
|
-
parseOutOfStockBehavior2 as parseOutOfStockBehavior,
|
|
4408
4407
|
percentageDiscountUnit,
|
|
4409
4408
|
productsForStep3 as productsForStep,
|
|
4410
4409
|
reportAddToCart2 as reportAddToCart,
|
|
@@ -4416,7 +4415,6 @@ export {
|
|
|
4416
4415
|
useAnalytics,
|
|
4417
4416
|
useBundleData,
|
|
4418
4417
|
useBundlesForProduct,
|
|
4419
|
-
useShopSettings,
|
|
4420
4418
|
useVariantSelection,
|
|
4421
4419
|
useWidgetConfigVars,
|
|
4422
4420
|
validateQuantity
|