@lime-bundles/react 2.4.0 → 3.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 +187 -65
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +199 -71
- package/dist/index.js.map +1 -1
- package/docs/css-variables.md +11 -0
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -349,6 +349,20 @@ var { computePosition, emptyTypeAheadState, handleKey, pushTypeAheadChar } = imp
|
|
|
349
349
|
var ITEM_HEIGHT_PX = 32;
|
|
350
350
|
var LIST_PAD_Y = 8;
|
|
351
351
|
var MAX_VISIBLE_ITEMS = 8;
|
|
352
|
+
function findScrollableAncestor(el) {
|
|
353
|
+
const win = el.ownerDocument?.defaultView;
|
|
354
|
+
if (!win) return null;
|
|
355
|
+
let cur = el.parentElement;
|
|
356
|
+
while (cur && cur !== el.ownerDocument.body) {
|
|
357
|
+
const style = win.getComputedStyle(cur);
|
|
358
|
+
const overflowY = style.overflowY;
|
|
359
|
+
if (overflowY === "auto" || overflowY === "scroll" || overflowY === "hidden") {
|
|
360
|
+
return cur;
|
|
361
|
+
}
|
|
362
|
+
cur = cur.parentElement;
|
|
363
|
+
}
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
352
366
|
function VariantDropdown({
|
|
353
367
|
options,
|
|
354
368
|
value,
|
|
@@ -398,6 +412,11 @@ function VariantDropdown({
|
|
|
398
412
|
if (rect.width === 0) return;
|
|
399
413
|
const visibleCount = Math.min(options.length || 1, MAX_VISIBLE_ITEMS);
|
|
400
414
|
const desiredHeight = visibleCount * ITEM_HEIGHT_PX + LIST_PAD_Y;
|
|
415
|
+
const scrollable = findScrollableAncestor(trigger);
|
|
416
|
+
const clip = scrollable ? (() => {
|
|
417
|
+
const r = scrollable.getBoundingClientRect();
|
|
418
|
+
return { top: r.top, bottom: r.bottom };
|
|
419
|
+
})() : void 0;
|
|
401
420
|
setPosition(
|
|
402
421
|
computePosition({
|
|
403
422
|
trigger: {
|
|
@@ -407,7 +426,8 @@ function VariantDropdown({
|
|
|
407
426
|
width: rect.width
|
|
408
427
|
},
|
|
409
428
|
viewportHeight: window.innerHeight,
|
|
410
|
-
desiredHeight
|
|
429
|
+
desiredHeight,
|
|
430
|
+
clip
|
|
411
431
|
})
|
|
412
432
|
);
|
|
413
433
|
}, [isOpen, options.length]);
|
|
@@ -641,8 +661,14 @@ function FixedBundle(props) {
|
|
|
641
661
|
}, [result, onError]);
|
|
642
662
|
const handleAddToCart = (0, import_react6.useCallback)(async () => {
|
|
643
663
|
if (!bundle) return;
|
|
644
|
-
const bundleLines = bundle.products.filter(
|
|
645
|
-
|
|
664
|
+
const bundleLines = bundle.products.filter(
|
|
665
|
+
(p) => p.variants.nodes.some(
|
|
666
|
+
(v) => (0, import_core8.isVariantFulfillable)(v, (0, import_core8.resolveBundleQty)(bundle, p.id, v.id))
|
|
667
|
+
)
|
|
668
|
+
).map((p) => {
|
|
669
|
+
const variant = selectedVariants[p.id] ?? p.variants.nodes.find(
|
|
670
|
+
(v) => (0, import_core8.isVariantFulfillable)(v, (0, import_core8.resolveBundleQty)(bundle, p.id, v.id))
|
|
671
|
+
);
|
|
646
672
|
return {
|
|
647
673
|
productId: p.id,
|
|
648
674
|
variant,
|
|
@@ -712,6 +738,7 @@ function FixedBundle(props) {
|
|
|
712
738
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "lb-bundle__products", children: bundle.products.map((product) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
713
739
|
FixedProductRow,
|
|
714
740
|
{
|
|
741
|
+
bundle,
|
|
715
742
|
product,
|
|
716
743
|
currency,
|
|
717
744
|
onVariantChange: handleVariantChange
|
|
@@ -733,7 +760,7 @@ function FixedBundle(props) {
|
|
|
733
760
|
}
|
|
734
761
|
);
|
|
735
762
|
}
|
|
736
|
-
function FixedProductRow({ product, currency, onVariantChange }) {
|
|
763
|
+
function FixedProductRow({ bundle, product, currency, onVariantChange }) {
|
|
737
764
|
const variants = product.variants.nodes;
|
|
738
765
|
const optionNames = (0, import_react6.useMemo)(() => {
|
|
739
766
|
const first = variants[0];
|
|
@@ -747,7 +774,9 @@ function FixedProductRow({ product, currency, onVariantChange }) {
|
|
|
747
774
|
(0, import_react6.useEffect)(() => {
|
|
748
775
|
onVariantChange(product.id, selectedVariant ?? null);
|
|
749
776
|
}, [selectedVariant, product.id, onVariantChange]);
|
|
750
|
-
const displayVariant = selectedVariant ?? variants.find(
|
|
777
|
+
const displayVariant = selectedVariant ?? variants.find(
|
|
778
|
+
(v) => (0, import_core8.isVariantFulfillable)(v, (0, import_core8.resolveBundleQty)(bundle, product.id, v.id))
|
|
779
|
+
) ?? variants[0];
|
|
751
780
|
const priceText = displayVariant ? (0, import_core8.formatMoney)(displayVariant.price.amount, currency) : (0, import_core8.formatMoney)(product.priceRange.minVariantPrice.amount, currency);
|
|
752
781
|
const unitPriceText = displayVariant ? (0, import_core8.formatUnitPrice)(
|
|
753
782
|
displayVariant.unitPrice,
|
|
@@ -755,6 +784,12 @@ function FixedProductRow({ product, currency, onVariantChange }) {
|
|
|
755
784
|
currency
|
|
756
785
|
) : null;
|
|
757
786
|
const thumbImage = displayVariant?.image ?? product.featuredImage;
|
|
787
|
+
const showLowStock = !!displayVariant && (0, import_core8.shouldShowLowStockBadge)(
|
|
788
|
+
displayVariant,
|
|
789
|
+
(0, import_core8.resolveBundleQty)(bundle, product.id, displayVariant.id),
|
|
790
|
+
bundle.widgetConfig.lowStockThreshold,
|
|
791
|
+
bundle.widgetConfig.showLowStockBadge
|
|
792
|
+
);
|
|
758
793
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "lb-bundle__product", part: "product", children: [
|
|
759
794
|
thumbImage && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
760
795
|
"img",
|
|
@@ -769,6 +804,11 @@ function FixedProductRow({ product, currency, onVariantChange }) {
|
|
|
769
804
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "lb-bundle__product-title", children: product.title }),
|
|
770
805
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "lb-bundle__product-price", children: priceText }),
|
|
771
806
|
unitPriceText && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "lb-bundle__product-unit-price", children: unitPriceText }),
|
|
807
|
+
showLowStock && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "lb-bundle-low-stock-badge", children: [
|
|
808
|
+
"Only ",
|
|
809
|
+
displayVariant.quantityAvailable,
|
|
810
|
+
" left"
|
|
811
|
+
] }),
|
|
772
812
|
showPicker && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "lb-bundle__product-variant-pickers", children: optionNames.map((optionName, optionIndex) => {
|
|
773
813
|
const dropdownOptions = optionsFor(optionIndex).map((o) => ({
|
|
774
814
|
value: o.value,
|
|
@@ -794,6 +834,9 @@ function FixedProductRow({ product, currency, onVariantChange }) {
|
|
|
794
834
|
var import_react7 = require("react");
|
|
795
835
|
var import_core9 = require("@lime-bundles/core");
|
|
796
836
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
837
|
+
function ruleFor(bundle, productId) {
|
|
838
|
+
return bundle.productRules[productId] ?? import_core9.DEFAULT_PRODUCT_RULE;
|
|
839
|
+
}
|
|
797
840
|
function MixMatchBundle(props) {
|
|
798
841
|
const {
|
|
799
842
|
shopDomain,
|
|
@@ -837,56 +880,92 @@ function MixMatchBundle(props) {
|
|
|
837
880
|
);
|
|
838
881
|
}
|
|
839
882
|
}, [result, onError]);
|
|
840
|
-
const
|
|
841
|
-
|
|
842
|
-
|
|
883
|
+
const showStepper = bundle?.widgetConfig.mixMatchShowQuantitySelector !== false;
|
|
884
|
+
const distinctSelectedProducts = (0, import_react7.useMemo)(() => {
|
|
885
|
+
const ids = /* @__PURE__ */ new Set();
|
|
886
|
+
for (const sel of selections.values()) {
|
|
887
|
+
if (sel.quantity > 0) ids.add(sel.productId);
|
|
888
|
+
}
|
|
889
|
+
return ids;
|
|
890
|
+
}, [selections]);
|
|
891
|
+
const totalQuantity = (0, import_react7.useMemo)(
|
|
892
|
+
() => Array.from(selections.values()).reduce((sum, s) => sum + s.quantity, 0),
|
|
893
|
+
[selections]
|
|
843
894
|
);
|
|
844
|
-
const
|
|
845
|
-
const
|
|
895
|
+
const requiredPicks = bundle?.minQuantity ?? 0;
|
|
896
|
+
const meetsMinPicks = distinctSelectedProducts.size >= requiredPicks;
|
|
897
|
+
const valid = !!bundle && meetsMinPicks;
|
|
898
|
+
const remaining = Math.max(0, requiredPicks - distinctSelectedProducts.size);
|
|
899
|
+
const validationMessage = valid ? null : remaining > 0 ? `Pick ${remaining} more product${remaining === 1 ? "" : "s"}` : null;
|
|
900
|
+
const selectVariant = (0, import_react7.useCallback)(
|
|
846
901
|
(productId, variant) => {
|
|
902
|
+
if (!bundle) return;
|
|
903
|
+
const rule = ruleFor(bundle, productId);
|
|
904
|
+
const maxAddable = (0, import_core9.maxAddableQuantity)(variant, rule.max, 0);
|
|
905
|
+
if (maxAddable < rule.min) return;
|
|
847
906
|
setSelections((prev) => {
|
|
848
907
|
const next = new Map(prev);
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
next.set(key, {
|
|
855
|
-
productId,
|
|
856
|
-
variantId: variant.id,
|
|
857
|
-
quantity: configuredQty
|
|
858
|
-
});
|
|
859
|
-
}
|
|
908
|
+
next.set(`${productId}:${variant.id}`, {
|
|
909
|
+
productId,
|
|
910
|
+
variantId: variant.id,
|
|
911
|
+
quantity: rule.min
|
|
912
|
+
});
|
|
860
913
|
return next;
|
|
861
914
|
});
|
|
862
915
|
},
|
|
863
916
|
[bundle]
|
|
864
917
|
);
|
|
865
|
-
const
|
|
866
|
-
(
|
|
918
|
+
const deselect = (0, import_react7.useCallback)((productId, variantId) => {
|
|
919
|
+
setSelections((prev) => {
|
|
920
|
+
if (!prev.has(`${productId}:${variantId}`)) return prev;
|
|
921
|
+
const next = new Map(prev);
|
|
922
|
+
next.delete(`${productId}:${variantId}`);
|
|
923
|
+
return next;
|
|
924
|
+
});
|
|
925
|
+
}, []);
|
|
926
|
+
const setQuantity = (0, import_react7.useCallback)(
|
|
927
|
+
(productId, variant, quantity) => {
|
|
928
|
+
if (!bundle) return;
|
|
929
|
+
const rule = ruleFor(bundle, productId);
|
|
930
|
+
const maxAddable = (0, import_core9.maxAddableQuantity)(variant, rule.max, 0);
|
|
931
|
+
const key = `${productId}:${variant.id}`;
|
|
867
932
|
setSelections((prev) => {
|
|
868
933
|
const next = new Map(prev);
|
|
869
|
-
|
|
870
|
-
if (quantity <= 0) {
|
|
934
|
+
if (quantity < rule.min || maxAddable < rule.min) {
|
|
871
935
|
next.delete(key);
|
|
872
|
-
|
|
873
|
-
next.set(key, { productId, variantId, quantity });
|
|
936
|
+
return next;
|
|
874
937
|
}
|
|
938
|
+
const clamped = Math.min(quantity, maxAddable);
|
|
939
|
+
next.set(key, {
|
|
940
|
+
productId,
|
|
941
|
+
variantId: variant.id,
|
|
942
|
+
quantity: clamped
|
|
943
|
+
});
|
|
875
944
|
return next;
|
|
876
945
|
});
|
|
877
946
|
},
|
|
878
|
-
[]
|
|
947
|
+
[bundle]
|
|
879
948
|
);
|
|
880
949
|
const handleAddToCart = (0, import_react7.useCallback)(async () => {
|
|
881
|
-
if (!bundle || !
|
|
882
|
-
const
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
}
|
|
950
|
+
if (!bundle || !valid) return;
|
|
951
|
+
const byVariant = /* @__PURE__ */ new Map();
|
|
952
|
+
for (const sel of selections.values()) {
|
|
953
|
+
if (sel.quantity <= 0) continue;
|
|
954
|
+
byVariant.set(
|
|
955
|
+
sel.variantId,
|
|
956
|
+
(byVariant.get(sel.variantId) ?? 0) + sel.quantity
|
|
957
|
+
);
|
|
958
|
+
}
|
|
959
|
+
const lines = Array.from(byVariant.entries()).map(
|
|
960
|
+
([variantId, quantity]) => ({
|
|
961
|
+
merchandiseId: variantId,
|
|
962
|
+
quantity,
|
|
963
|
+
attributes: [
|
|
964
|
+
{ key: "_lime_bundle_gid", value: bundle.id },
|
|
965
|
+
{ key: "_lime_bundle_type", value: bundle.bundleType }
|
|
966
|
+
]
|
|
967
|
+
})
|
|
968
|
+
);
|
|
890
969
|
setAddingToCart(true);
|
|
891
970
|
setCartError(null);
|
|
892
971
|
try {
|
|
@@ -912,15 +991,7 @@ function MixMatchBundle(props) {
|
|
|
912
991
|
} finally {
|
|
913
992
|
setAddingToCart(false);
|
|
914
993
|
}
|
|
915
|
-
}, [
|
|
916
|
-
bundle,
|
|
917
|
-
selections,
|
|
918
|
-
validation.valid,
|
|
919
|
-
onAddToCart,
|
|
920
|
-
onError,
|
|
921
|
-
trackAddToCart,
|
|
922
|
-
totalQuantity
|
|
923
|
-
]);
|
|
994
|
+
}, [bundle, selections, valid, onAddToCart, onError, trackAddToCart, totalQuantity]);
|
|
924
995
|
if (result.status === "loading") {
|
|
925
996
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: `lb-bundle lb-bundle--loading ${className ?? ""}`, children: [
|
|
926
997
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "lb-skeleton lb-skeleton--title" }),
|
|
@@ -943,26 +1014,29 @@ function MixMatchBundle(props) {
|
|
|
943
1014
|
children: [
|
|
944
1015
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { className: "lb-bundle__title", children: bundle.title }),
|
|
945
1016
|
bundle.discountLabel && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "lb-bundle__discount-badge", children: bundle.discountLabel }),
|
|
946
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "lb-bundle__instructions", children:
|
|
1017
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "lb-bundle__instructions", children: requiredPicks > 0 ? `Pick ${requiredPicks} product${requiredPicks === 1 ? "" : "s"}` : "Pick your products" }),
|
|
947
1018
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "lb-bundle__products lb-bundle__products--selectable", children: bundle.products.map((product) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
948
1019
|
MixMatchProductRow,
|
|
949
1020
|
{
|
|
1021
|
+
bundle,
|
|
950
1022
|
product,
|
|
951
1023
|
currency,
|
|
1024
|
+
showStepper,
|
|
952
1025
|
selections,
|
|
953
|
-
|
|
954
|
-
|
|
1026
|
+
onSelect: selectVariant,
|
|
1027
|
+
onDeselect: deselect,
|
|
1028
|
+
onSetQuantity: setQuantity
|
|
955
1029
|
},
|
|
956
1030
|
product.id
|
|
957
1031
|
)) }),
|
|
958
|
-
|
|
1032
|
+
validationMessage && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "lb-bundle__validation", role: "status", children: validationMessage }),
|
|
959
1033
|
cartError && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "lb-bundle__error", role: "alert", children: cartError }),
|
|
960
1034
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
961
1035
|
"button",
|
|
962
1036
|
{
|
|
963
1037
|
className: "lb-bundle__cta",
|
|
964
1038
|
onClick: handleAddToCart,
|
|
965
|
-
disabled: addingToCart || !
|
|
1039
|
+
disabled: addingToCart || !valid,
|
|
966
1040
|
"aria-busy": addingToCart,
|
|
967
1041
|
children: addingToCart ? "Adding..." : bundle.widgetConfig.cta.ctaText ?? `Add ${totalQuantity} Items to Cart`
|
|
968
1042
|
}
|
|
@@ -972,11 +1046,14 @@ function MixMatchBundle(props) {
|
|
|
972
1046
|
);
|
|
973
1047
|
}
|
|
974
1048
|
function MixMatchProductRow({
|
|
1049
|
+
bundle,
|
|
975
1050
|
product,
|
|
976
1051
|
currency,
|
|
1052
|
+
showStepper,
|
|
977
1053
|
selections,
|
|
978
|
-
|
|
979
|
-
|
|
1054
|
+
onSelect,
|
|
1055
|
+
onDeselect,
|
|
1056
|
+
onSetQuantity
|
|
980
1057
|
}) {
|
|
981
1058
|
const variants = product.variants.nodes;
|
|
982
1059
|
const optionNames = (0, import_react7.useMemo)(() => {
|
|
@@ -984,9 +1061,12 @@ function MixMatchProductRow({
|
|
|
984
1061
|
return first ? first.selectedOptions.map((o) => o.name) : [];
|
|
985
1062
|
}, [variants]);
|
|
986
1063
|
const showPicker = variants.length > 1 && optionNames.length > 0;
|
|
1064
|
+
const rule = ruleFor(bundle, product.id);
|
|
987
1065
|
const { selectedValues, selectedVariant, setOptionValue, optionsFor } = useVariantSelection({ variants, optionNames });
|
|
988
|
-
const displayVariant = selectedVariant ?? variants.find((v) => v.
|
|
1066
|
+
const displayVariant = selectedVariant ?? variants.find((v) => (0, import_core9.isVariantFulfillable)(v, rule.min)) ?? variants[0] ?? null;
|
|
989
1067
|
if (!displayVariant) return null;
|
|
1068
|
+
const fulfillable = (0, import_core9.isVariantFulfillable)(displayVariant, rule.min);
|
|
1069
|
+
const maxAddable = (0, import_core9.maxAddableQuantity)(displayVariant, rule.max, 0);
|
|
990
1070
|
const key = `${product.id}:${displayVariant.id}`;
|
|
991
1071
|
const selected = selections.get(key);
|
|
992
1072
|
const thumbImage = displayVariant.image ?? product.featuredImage;
|
|
@@ -1013,6 +1093,16 @@ function MixMatchProductRow({
|
|
|
1013
1093
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "lb-bundle__product-title", children: product.title }),
|
|
1014
1094
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "lb-bundle__product-price", children: (0, import_core9.formatMoney)(displayVariant.price.amount, currency) }),
|
|
1015
1095
|
unitPriceText && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "lb-bundle__product-unit-price", children: unitPriceText }),
|
|
1096
|
+
(0, import_core9.shouldShowLowStockBadge)(
|
|
1097
|
+
displayVariant,
|
|
1098
|
+
rule.min,
|
|
1099
|
+
bundle.widgetConfig.lowStockThreshold,
|
|
1100
|
+
bundle.widgetConfig.showLowStockBadge
|
|
1101
|
+
) && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "lb-bundle-low-stock-badge", children: [
|
|
1102
|
+
"Only ",
|
|
1103
|
+
displayVariant.quantityAvailable,
|
|
1104
|
+
" left"
|
|
1105
|
+
] }),
|
|
1016
1106
|
showPicker && !selected && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "lb-bundle__product-variant-pickers", children: optionNames.map((optionName, optionIndex) => {
|
|
1017
1107
|
const dropdownOptions = optionsFor(optionIndex).map((o) => ({
|
|
1018
1108
|
value: o.value,
|
|
@@ -1031,39 +1121,58 @@ function MixMatchProductRow({
|
|
|
1031
1121
|
);
|
|
1032
1122
|
}) })
|
|
1033
1123
|
] }),
|
|
1034
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "lb-bundle__product-actions", children: selected ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "lb-bundle__quantity-control", children: [
|
|
1124
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "lb-bundle__product-actions", children: selected ? showStepper ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "lb-bundle__quantity-control", children: [
|
|
1035
1125
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1036
1126
|
"button",
|
|
1037
1127
|
{
|
|
1038
1128
|
"aria-label": `Decrease ${product.title}`,
|
|
1039
|
-
onClick: () =>
|
|
1129
|
+
onClick: () => onSetQuantity(
|
|
1040
1130
|
product.id,
|
|
1041
|
-
displayVariant
|
|
1131
|
+
displayVariant,
|
|
1042
1132
|
selected.quantity - 1
|
|
1043
1133
|
),
|
|
1134
|
+
disabled: selected.quantity <= rule.min,
|
|
1044
1135
|
children: "\u2212"
|
|
1045
1136
|
}
|
|
1046
1137
|
),
|
|
1047
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: selected.quantity }),
|
|
1138
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { "aria-live": "polite", children: selected.quantity }),
|
|
1048
1139
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1049
1140
|
"button",
|
|
1050
1141
|
{
|
|
1051
1142
|
"aria-label": `Increase ${product.title}`,
|
|
1052
|
-
onClick: () =>
|
|
1143
|
+
onClick: () => onSetQuantity(
|
|
1053
1144
|
product.id,
|
|
1054
|
-
displayVariant
|
|
1145
|
+
displayVariant,
|
|
1055
1146
|
selected.quantity + 1
|
|
1056
1147
|
),
|
|
1148
|
+
disabled: selected.quantity >= maxAddable,
|
|
1057
1149
|
children: "+"
|
|
1058
1150
|
}
|
|
1151
|
+
),
|
|
1152
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1153
|
+
"button",
|
|
1154
|
+
{
|
|
1155
|
+
className: "lb-bundle__remove-btn",
|
|
1156
|
+
"aria-label": `Remove ${product.title}`,
|
|
1157
|
+
onClick: () => onDeselect(product.id, displayVariant.id),
|
|
1158
|
+
children: "Remove"
|
|
1159
|
+
}
|
|
1059
1160
|
)
|
|
1060
1161
|
] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1162
|
+
"button",
|
|
1163
|
+
{
|
|
1164
|
+
className: "lb-bundle__select-btn lb-bundle__select-btn--selected",
|
|
1165
|
+
"aria-label": `Remove ${product.title}`,
|
|
1166
|
+
onClick: () => onDeselect(product.id, displayVariant.id),
|
|
1167
|
+
children: "Selected"
|
|
1168
|
+
}
|
|
1169
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1061
1170
|
"button",
|
|
1062
1171
|
{
|
|
1063
1172
|
className: "lb-bundle__select-btn",
|
|
1064
|
-
onClick: () =>
|
|
1065
|
-
disabled: !
|
|
1066
|
-
children:
|
|
1173
|
+
onClick: () => onSelect(product.id, displayVariant),
|
|
1174
|
+
disabled: !fulfillable || maxAddable <= 0,
|
|
1175
|
+
children: fulfillable && maxAddable > 0 ? "Select" : "Sold out"
|
|
1067
1176
|
}
|
|
1068
1177
|
) })
|
|
1069
1178
|
]
|
|
@@ -1124,7 +1233,8 @@ function VolumeBundle(props) {
|
|
|
1124
1233
|
}, [variants]);
|
|
1125
1234
|
const showPicker = variants.length > 1 && optionNames.length > 0;
|
|
1126
1235
|
const { selectedValues, selectedVariant, setOptionValue, optionsFor } = useVariantSelection({ variants, optionNames });
|
|
1127
|
-
const
|
|
1236
|
+
const minTierQty = bundle?.volumeTiers[0]?.minQuantity ?? 1;
|
|
1237
|
+
const displayVariant = selectedVariant ?? variants.find((v) => (0, import_core10.isVariantFulfillable)(v, minTierQty)) ?? variants[0];
|
|
1128
1238
|
const basePrice = displayVariant ? parseFloat(displayVariant.price.amount) : product ? parseFloat(product.priceRange.minVariantPrice.amount) : 0;
|
|
1129
1239
|
const currency = product?.priceRange.minVariantPrice.currencyCode ?? "USD";
|
|
1130
1240
|
const thumbImage = displayVariant?.image ?? product?.featuredImage ?? null;
|
|
@@ -1145,7 +1255,9 @@ function VolumeBundle(props) {
|
|
|
1145
1255
|
const activeTier = bundle ? (0, import_core10.getActiveTier)(bundle.volumeTiers, quantity) : null;
|
|
1146
1256
|
const handleAddToCart = (0, import_react8.useCallback)(async () => {
|
|
1147
1257
|
if (!bundle || !product) return;
|
|
1148
|
-
const variant = selectedVariant ?? product.variants.nodes.find(
|
|
1258
|
+
const variant = selectedVariant ?? product.variants.nodes.find(
|
|
1259
|
+
(v) => (0, import_core10.isVariantFulfillable)(v, quantity)
|
|
1260
|
+
);
|
|
1149
1261
|
if (!variant) return;
|
|
1150
1262
|
const lines = [
|
|
1151
1263
|
{
|
|
@@ -1310,6 +1422,16 @@ function VolumeBundle(props) {
|
|
|
1310
1422
|
] })
|
|
1311
1423
|
] }),
|
|
1312
1424
|
cartError && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "lb-bundle__error", role: "alert", children: cartError }),
|
|
1425
|
+
bundle && displayVariant && (0, import_core10.shouldShowLowStockBadge)(
|
|
1426
|
+
displayVariant,
|
|
1427
|
+
minTierQty,
|
|
1428
|
+
bundle.widgetConfig.lowStockThreshold,
|
|
1429
|
+
bundle.widgetConfig.showLowStockBadge
|
|
1430
|
+
) && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "lb-bundle-low-stock-badge", children: [
|
|
1431
|
+
"Only ",
|
|
1432
|
+
displayVariant.quantityAvailable,
|
|
1433
|
+
" left"
|
|
1434
|
+
] }),
|
|
1313
1435
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1314
1436
|
"button",
|
|
1315
1437
|
{
|