@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.js
CHANGED
|
@@ -4,7 +4,9 @@ import {
|
|
|
4
4
|
formatMoney,
|
|
5
5
|
formatUnitPrice,
|
|
6
6
|
calculateDiscount,
|
|
7
|
-
resolveBundleQty
|
|
7
|
+
resolveBundleQty,
|
|
8
|
+
isVariantFulfillable,
|
|
9
|
+
shouldShowLowStockBadge
|
|
8
10
|
} from "@lime-bundles/core";
|
|
9
11
|
|
|
10
12
|
// src/hooks/useBundleData.ts
|
|
@@ -302,6 +304,20 @@ var { computePosition, emptyTypeAheadState, handleKey, pushTypeAheadChar } = dro
|
|
|
302
304
|
var ITEM_HEIGHT_PX = 32;
|
|
303
305
|
var LIST_PAD_Y = 8;
|
|
304
306
|
var MAX_VISIBLE_ITEMS = 8;
|
|
307
|
+
function findScrollableAncestor(el) {
|
|
308
|
+
const win = el.ownerDocument?.defaultView;
|
|
309
|
+
if (!win) return null;
|
|
310
|
+
let cur = el.parentElement;
|
|
311
|
+
while (cur && cur !== el.ownerDocument.body) {
|
|
312
|
+
const style = win.getComputedStyle(cur);
|
|
313
|
+
const overflowY = style.overflowY;
|
|
314
|
+
if (overflowY === "auto" || overflowY === "scroll" || overflowY === "hidden") {
|
|
315
|
+
return cur;
|
|
316
|
+
}
|
|
317
|
+
cur = cur.parentElement;
|
|
318
|
+
}
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
305
321
|
function VariantDropdown({
|
|
306
322
|
options,
|
|
307
323
|
value,
|
|
@@ -351,6 +367,11 @@ function VariantDropdown({
|
|
|
351
367
|
if (rect.width === 0) return;
|
|
352
368
|
const visibleCount = Math.min(options.length || 1, MAX_VISIBLE_ITEMS);
|
|
353
369
|
const desiredHeight = visibleCount * ITEM_HEIGHT_PX + LIST_PAD_Y;
|
|
370
|
+
const scrollable = findScrollableAncestor(trigger);
|
|
371
|
+
const clip = scrollable ? (() => {
|
|
372
|
+
const r = scrollable.getBoundingClientRect();
|
|
373
|
+
return { top: r.top, bottom: r.bottom };
|
|
374
|
+
})() : void 0;
|
|
354
375
|
setPosition(
|
|
355
376
|
computePosition({
|
|
356
377
|
trigger: {
|
|
@@ -360,7 +381,8 @@ function VariantDropdown({
|
|
|
360
381
|
width: rect.width
|
|
361
382
|
},
|
|
362
383
|
viewportHeight: window.innerHeight,
|
|
363
|
-
desiredHeight
|
|
384
|
+
desiredHeight,
|
|
385
|
+
clip
|
|
364
386
|
})
|
|
365
387
|
);
|
|
366
388
|
}, [isOpen, options.length]);
|
|
@@ -594,8 +616,14 @@ function FixedBundle(props) {
|
|
|
594
616
|
}, [result, onError]);
|
|
595
617
|
const handleAddToCart = useCallback4(async () => {
|
|
596
618
|
if (!bundle) return;
|
|
597
|
-
const bundleLines = bundle.products.filter(
|
|
598
|
-
|
|
619
|
+
const bundleLines = bundle.products.filter(
|
|
620
|
+
(p) => p.variants.nodes.some(
|
|
621
|
+
(v) => isVariantFulfillable(v, resolveBundleQty(bundle, p.id, v.id))
|
|
622
|
+
)
|
|
623
|
+
).map((p) => {
|
|
624
|
+
const variant = selectedVariants[p.id] ?? p.variants.nodes.find(
|
|
625
|
+
(v) => isVariantFulfillable(v, resolveBundleQty(bundle, p.id, v.id))
|
|
626
|
+
);
|
|
599
627
|
return {
|
|
600
628
|
productId: p.id,
|
|
601
629
|
variant,
|
|
@@ -665,6 +693,7 @@ function FixedBundle(props) {
|
|
|
665
693
|
/* @__PURE__ */ jsx2("div", { className: "lb-bundle__products", children: bundle.products.map((product) => /* @__PURE__ */ jsx2(
|
|
666
694
|
FixedProductRow,
|
|
667
695
|
{
|
|
696
|
+
bundle,
|
|
668
697
|
product,
|
|
669
698
|
currency,
|
|
670
699
|
onVariantChange: handleVariantChange
|
|
@@ -686,7 +715,7 @@ function FixedBundle(props) {
|
|
|
686
715
|
}
|
|
687
716
|
);
|
|
688
717
|
}
|
|
689
|
-
function FixedProductRow({ product, currency, onVariantChange }) {
|
|
718
|
+
function FixedProductRow({ bundle, product, currency, onVariantChange }) {
|
|
690
719
|
const variants = product.variants.nodes;
|
|
691
720
|
const optionNames = useMemo4(() => {
|
|
692
721
|
const first = variants[0];
|
|
@@ -700,7 +729,9 @@ function FixedProductRow({ product, currency, onVariantChange }) {
|
|
|
700
729
|
useEffect6(() => {
|
|
701
730
|
onVariantChange(product.id, selectedVariant ?? null);
|
|
702
731
|
}, [selectedVariant, product.id, onVariantChange]);
|
|
703
|
-
const displayVariant = selectedVariant ?? variants.find(
|
|
732
|
+
const displayVariant = selectedVariant ?? variants.find(
|
|
733
|
+
(v) => isVariantFulfillable(v, resolveBundleQty(bundle, product.id, v.id))
|
|
734
|
+
) ?? variants[0];
|
|
704
735
|
const priceText = displayVariant ? formatMoney(displayVariant.price.amount, currency) : formatMoney(product.priceRange.minVariantPrice.amount, currency);
|
|
705
736
|
const unitPriceText = displayVariant ? formatUnitPrice(
|
|
706
737
|
displayVariant.unitPrice,
|
|
@@ -708,6 +739,12 @@ function FixedProductRow({ product, currency, onVariantChange }) {
|
|
|
708
739
|
currency
|
|
709
740
|
) : null;
|
|
710
741
|
const thumbImage = displayVariant?.image ?? product.featuredImage;
|
|
742
|
+
const showLowStock = !!displayVariant && shouldShowLowStockBadge(
|
|
743
|
+
displayVariant,
|
|
744
|
+
resolveBundleQty(bundle, product.id, displayVariant.id),
|
|
745
|
+
bundle.widgetConfig.lowStockThreshold,
|
|
746
|
+
bundle.widgetConfig.showLowStockBadge
|
|
747
|
+
);
|
|
711
748
|
return /* @__PURE__ */ jsxs2("div", { className: "lb-bundle__product", part: "product", children: [
|
|
712
749
|
thumbImage && /* @__PURE__ */ jsx2(
|
|
713
750
|
"img",
|
|
@@ -722,6 +759,11 @@ function FixedProductRow({ product, currency, onVariantChange }) {
|
|
|
722
759
|
/* @__PURE__ */ jsx2("p", { className: "lb-bundle__product-title", children: product.title }),
|
|
723
760
|
/* @__PURE__ */ jsx2("p", { className: "lb-bundle__product-price", children: priceText }),
|
|
724
761
|
unitPriceText && /* @__PURE__ */ jsx2("p", { className: "lb-bundle__product-unit-price", children: unitPriceText }),
|
|
762
|
+
showLowStock && /* @__PURE__ */ jsxs2("span", { className: "lb-bundle-low-stock-badge", children: [
|
|
763
|
+
"Only ",
|
|
764
|
+
displayVariant.quantityAvailable,
|
|
765
|
+
" left"
|
|
766
|
+
] }),
|
|
725
767
|
showPicker && /* @__PURE__ */ jsx2("div", { className: "lb-bundle__product-variant-pickers", children: optionNames.map((optionName, optionIndex) => {
|
|
726
768
|
const dropdownOptions = optionsFor(optionIndex).map((o) => ({
|
|
727
769
|
value: o.value,
|
|
@@ -748,10 +790,15 @@ import { useCallback as useCallback5, useEffect as useEffect7, useMemo as useMem
|
|
|
748
790
|
import {
|
|
749
791
|
formatMoney as formatMoney2,
|
|
750
792
|
formatUnitPrice as formatUnitPrice2,
|
|
751
|
-
|
|
752
|
-
|
|
793
|
+
isVariantFulfillable as isVariantFulfillable2,
|
|
794
|
+
shouldShowLowStockBadge as shouldShowLowStockBadge2,
|
|
795
|
+
maxAddableQuantity,
|
|
796
|
+
DEFAULT_PRODUCT_RULE
|
|
753
797
|
} from "@lime-bundles/core";
|
|
754
798
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
799
|
+
function ruleFor(bundle, productId) {
|
|
800
|
+
return bundle.productRules[productId] ?? DEFAULT_PRODUCT_RULE;
|
|
801
|
+
}
|
|
755
802
|
function MixMatchBundle(props) {
|
|
756
803
|
const {
|
|
757
804
|
shopDomain,
|
|
@@ -795,56 +842,92 @@ function MixMatchBundle(props) {
|
|
|
795
842
|
);
|
|
796
843
|
}
|
|
797
844
|
}, [result, onError]);
|
|
798
|
-
const
|
|
799
|
-
|
|
800
|
-
|
|
845
|
+
const showStepper = bundle?.widgetConfig.mixMatchShowQuantitySelector !== false;
|
|
846
|
+
const distinctSelectedProducts = useMemo5(() => {
|
|
847
|
+
const ids = /* @__PURE__ */ new Set();
|
|
848
|
+
for (const sel of selections.values()) {
|
|
849
|
+
if (sel.quantity > 0) ids.add(sel.productId);
|
|
850
|
+
}
|
|
851
|
+
return ids;
|
|
852
|
+
}, [selections]);
|
|
853
|
+
const totalQuantity = useMemo5(
|
|
854
|
+
() => Array.from(selections.values()).reduce((sum, s) => sum + s.quantity, 0),
|
|
855
|
+
[selections]
|
|
801
856
|
);
|
|
802
|
-
const
|
|
803
|
-
const
|
|
857
|
+
const requiredPicks = bundle?.minQuantity ?? 0;
|
|
858
|
+
const meetsMinPicks = distinctSelectedProducts.size >= requiredPicks;
|
|
859
|
+
const valid = !!bundle && meetsMinPicks;
|
|
860
|
+
const remaining = Math.max(0, requiredPicks - distinctSelectedProducts.size);
|
|
861
|
+
const validationMessage = valid ? null : remaining > 0 ? `Pick ${remaining} more product${remaining === 1 ? "" : "s"}` : null;
|
|
862
|
+
const selectVariant = useCallback5(
|
|
804
863
|
(productId, variant) => {
|
|
864
|
+
if (!bundle) return;
|
|
865
|
+
const rule = ruleFor(bundle, productId);
|
|
866
|
+
const maxAddable = maxAddableQuantity(variant, rule.max, 0);
|
|
867
|
+
if (maxAddable < rule.min) return;
|
|
805
868
|
setSelections((prev) => {
|
|
806
869
|
const next = new Map(prev);
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
next.set(key, {
|
|
813
|
-
productId,
|
|
814
|
-
variantId: variant.id,
|
|
815
|
-
quantity: configuredQty
|
|
816
|
-
});
|
|
817
|
-
}
|
|
870
|
+
next.set(`${productId}:${variant.id}`, {
|
|
871
|
+
productId,
|
|
872
|
+
variantId: variant.id,
|
|
873
|
+
quantity: rule.min
|
|
874
|
+
});
|
|
818
875
|
return next;
|
|
819
876
|
});
|
|
820
877
|
},
|
|
821
878
|
[bundle]
|
|
822
879
|
);
|
|
823
|
-
const
|
|
824
|
-
(
|
|
880
|
+
const deselect = useCallback5((productId, variantId) => {
|
|
881
|
+
setSelections((prev) => {
|
|
882
|
+
if (!prev.has(`${productId}:${variantId}`)) return prev;
|
|
883
|
+
const next = new Map(prev);
|
|
884
|
+
next.delete(`${productId}:${variantId}`);
|
|
885
|
+
return next;
|
|
886
|
+
});
|
|
887
|
+
}, []);
|
|
888
|
+
const setQuantity = useCallback5(
|
|
889
|
+
(productId, variant, quantity) => {
|
|
890
|
+
if (!bundle) return;
|
|
891
|
+
const rule = ruleFor(bundle, productId);
|
|
892
|
+
const maxAddable = maxAddableQuantity(variant, rule.max, 0);
|
|
893
|
+
const key = `${productId}:${variant.id}`;
|
|
825
894
|
setSelections((prev) => {
|
|
826
895
|
const next = new Map(prev);
|
|
827
|
-
|
|
828
|
-
if (quantity <= 0) {
|
|
896
|
+
if (quantity < rule.min || maxAddable < rule.min) {
|
|
829
897
|
next.delete(key);
|
|
830
|
-
|
|
831
|
-
next.set(key, { productId, variantId, quantity });
|
|
898
|
+
return next;
|
|
832
899
|
}
|
|
900
|
+
const clamped = Math.min(quantity, maxAddable);
|
|
901
|
+
next.set(key, {
|
|
902
|
+
productId,
|
|
903
|
+
variantId: variant.id,
|
|
904
|
+
quantity: clamped
|
|
905
|
+
});
|
|
833
906
|
return next;
|
|
834
907
|
});
|
|
835
908
|
},
|
|
836
|
-
[]
|
|
909
|
+
[bundle]
|
|
837
910
|
);
|
|
838
911
|
const handleAddToCart = useCallback5(async () => {
|
|
839
|
-
if (!bundle || !
|
|
840
|
-
const
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
}
|
|
912
|
+
if (!bundle || !valid) return;
|
|
913
|
+
const byVariant = /* @__PURE__ */ new Map();
|
|
914
|
+
for (const sel of selections.values()) {
|
|
915
|
+
if (sel.quantity <= 0) continue;
|
|
916
|
+
byVariant.set(
|
|
917
|
+
sel.variantId,
|
|
918
|
+
(byVariant.get(sel.variantId) ?? 0) + sel.quantity
|
|
919
|
+
);
|
|
920
|
+
}
|
|
921
|
+
const lines = Array.from(byVariant.entries()).map(
|
|
922
|
+
([variantId, quantity]) => ({
|
|
923
|
+
merchandiseId: variantId,
|
|
924
|
+
quantity,
|
|
925
|
+
attributes: [
|
|
926
|
+
{ key: "_lime_bundle_gid", value: bundle.id },
|
|
927
|
+
{ key: "_lime_bundle_type", value: bundle.bundleType }
|
|
928
|
+
]
|
|
929
|
+
})
|
|
930
|
+
);
|
|
848
931
|
setAddingToCart(true);
|
|
849
932
|
setCartError(null);
|
|
850
933
|
try {
|
|
@@ -870,15 +953,7 @@ function MixMatchBundle(props) {
|
|
|
870
953
|
} finally {
|
|
871
954
|
setAddingToCart(false);
|
|
872
955
|
}
|
|
873
|
-
}, [
|
|
874
|
-
bundle,
|
|
875
|
-
selections,
|
|
876
|
-
validation.valid,
|
|
877
|
-
onAddToCart,
|
|
878
|
-
onError,
|
|
879
|
-
trackAddToCart,
|
|
880
|
-
totalQuantity
|
|
881
|
-
]);
|
|
956
|
+
}, [bundle, selections, valid, onAddToCart, onError, trackAddToCart, totalQuantity]);
|
|
882
957
|
if (result.status === "loading") {
|
|
883
958
|
return /* @__PURE__ */ jsxs3("div", { className: `lb-bundle lb-bundle--loading ${className ?? ""}`, children: [
|
|
884
959
|
/* @__PURE__ */ jsx3("div", { className: "lb-skeleton lb-skeleton--title" }),
|
|
@@ -901,26 +976,29 @@ function MixMatchBundle(props) {
|
|
|
901
976
|
children: [
|
|
902
977
|
/* @__PURE__ */ jsx3("h3", { className: "lb-bundle__title", children: bundle.title }),
|
|
903
978
|
bundle.discountLabel && /* @__PURE__ */ jsx3("span", { className: "lb-bundle__discount-badge", children: bundle.discountLabel }),
|
|
904
|
-
/* @__PURE__ */ jsx3("p", { className: "lb-bundle__instructions", children:
|
|
979
|
+
/* @__PURE__ */ jsx3("p", { className: "lb-bundle__instructions", children: requiredPicks > 0 ? `Pick ${requiredPicks} product${requiredPicks === 1 ? "" : "s"}` : "Pick your products" }),
|
|
905
980
|
/* @__PURE__ */ jsx3("div", { className: "lb-bundle__products lb-bundle__products--selectable", children: bundle.products.map((product) => /* @__PURE__ */ jsx3(
|
|
906
981
|
MixMatchProductRow,
|
|
907
982
|
{
|
|
983
|
+
bundle,
|
|
908
984
|
product,
|
|
909
985
|
currency,
|
|
986
|
+
showStepper,
|
|
910
987
|
selections,
|
|
911
|
-
|
|
912
|
-
|
|
988
|
+
onSelect: selectVariant,
|
|
989
|
+
onDeselect: deselect,
|
|
990
|
+
onSetQuantity: setQuantity
|
|
913
991
|
},
|
|
914
992
|
product.id
|
|
915
993
|
)) }),
|
|
916
|
-
|
|
994
|
+
validationMessage && /* @__PURE__ */ jsx3("p", { className: "lb-bundle__validation", role: "status", children: validationMessage }),
|
|
917
995
|
cartError && /* @__PURE__ */ jsx3("p", { className: "lb-bundle__error", role: "alert", children: cartError }),
|
|
918
996
|
/* @__PURE__ */ jsx3(
|
|
919
997
|
"button",
|
|
920
998
|
{
|
|
921
999
|
className: "lb-bundle__cta",
|
|
922
1000
|
onClick: handleAddToCart,
|
|
923
|
-
disabled: addingToCart || !
|
|
1001
|
+
disabled: addingToCart || !valid,
|
|
924
1002
|
"aria-busy": addingToCart,
|
|
925
1003
|
children: addingToCart ? "Adding..." : bundle.widgetConfig.cta.ctaText ?? `Add ${totalQuantity} Items to Cart`
|
|
926
1004
|
}
|
|
@@ -930,11 +1008,14 @@ function MixMatchBundle(props) {
|
|
|
930
1008
|
);
|
|
931
1009
|
}
|
|
932
1010
|
function MixMatchProductRow({
|
|
1011
|
+
bundle,
|
|
933
1012
|
product,
|
|
934
1013
|
currency,
|
|
1014
|
+
showStepper,
|
|
935
1015
|
selections,
|
|
936
|
-
|
|
937
|
-
|
|
1016
|
+
onSelect,
|
|
1017
|
+
onDeselect,
|
|
1018
|
+
onSetQuantity
|
|
938
1019
|
}) {
|
|
939
1020
|
const variants = product.variants.nodes;
|
|
940
1021
|
const optionNames = useMemo5(() => {
|
|
@@ -942,9 +1023,12 @@ function MixMatchProductRow({
|
|
|
942
1023
|
return first ? first.selectedOptions.map((o) => o.name) : [];
|
|
943
1024
|
}, [variants]);
|
|
944
1025
|
const showPicker = variants.length > 1 && optionNames.length > 0;
|
|
1026
|
+
const rule = ruleFor(bundle, product.id);
|
|
945
1027
|
const { selectedValues, selectedVariant, setOptionValue, optionsFor } = useVariantSelection({ variants, optionNames });
|
|
946
|
-
const displayVariant = selectedVariant ?? variants.find((v) => v.
|
|
1028
|
+
const displayVariant = selectedVariant ?? variants.find((v) => isVariantFulfillable2(v, rule.min)) ?? variants[0] ?? null;
|
|
947
1029
|
if (!displayVariant) return null;
|
|
1030
|
+
const fulfillable = isVariantFulfillable2(displayVariant, rule.min);
|
|
1031
|
+
const maxAddable = maxAddableQuantity(displayVariant, rule.max, 0);
|
|
948
1032
|
const key = `${product.id}:${displayVariant.id}`;
|
|
949
1033
|
const selected = selections.get(key);
|
|
950
1034
|
const thumbImage = displayVariant.image ?? product.featuredImage;
|
|
@@ -971,6 +1055,16 @@ function MixMatchProductRow({
|
|
|
971
1055
|
/* @__PURE__ */ jsx3("p", { className: "lb-bundle__product-title", children: product.title }),
|
|
972
1056
|
/* @__PURE__ */ jsx3("p", { className: "lb-bundle__product-price", children: formatMoney2(displayVariant.price.amount, currency) }),
|
|
973
1057
|
unitPriceText && /* @__PURE__ */ jsx3("p", { className: "lb-bundle__product-unit-price", children: unitPriceText }),
|
|
1058
|
+
shouldShowLowStockBadge2(
|
|
1059
|
+
displayVariant,
|
|
1060
|
+
rule.min,
|
|
1061
|
+
bundle.widgetConfig.lowStockThreshold,
|
|
1062
|
+
bundle.widgetConfig.showLowStockBadge
|
|
1063
|
+
) && /* @__PURE__ */ jsxs3("span", { className: "lb-bundle-low-stock-badge", children: [
|
|
1064
|
+
"Only ",
|
|
1065
|
+
displayVariant.quantityAvailable,
|
|
1066
|
+
" left"
|
|
1067
|
+
] }),
|
|
974
1068
|
showPicker && !selected && /* @__PURE__ */ jsx3("div", { className: "lb-bundle__product-variant-pickers", children: optionNames.map((optionName, optionIndex) => {
|
|
975
1069
|
const dropdownOptions = optionsFor(optionIndex).map((o) => ({
|
|
976
1070
|
value: o.value,
|
|
@@ -989,39 +1083,58 @@ function MixMatchProductRow({
|
|
|
989
1083
|
);
|
|
990
1084
|
}) })
|
|
991
1085
|
] }),
|
|
992
|
-
/* @__PURE__ */ jsx3("div", { className: "lb-bundle__product-actions", children: selected ? /* @__PURE__ */ jsxs3("div", { className: "lb-bundle__quantity-control", children: [
|
|
1086
|
+
/* @__PURE__ */ jsx3("div", { className: "lb-bundle__product-actions", children: selected ? showStepper ? /* @__PURE__ */ jsxs3("div", { className: "lb-bundle__quantity-control", children: [
|
|
993
1087
|
/* @__PURE__ */ jsx3(
|
|
994
1088
|
"button",
|
|
995
1089
|
{
|
|
996
1090
|
"aria-label": `Decrease ${product.title}`,
|
|
997
|
-
onClick: () =>
|
|
1091
|
+
onClick: () => onSetQuantity(
|
|
998
1092
|
product.id,
|
|
999
|
-
displayVariant
|
|
1093
|
+
displayVariant,
|
|
1000
1094
|
selected.quantity - 1
|
|
1001
1095
|
),
|
|
1096
|
+
disabled: selected.quantity <= rule.min,
|
|
1002
1097
|
children: "\u2212"
|
|
1003
1098
|
}
|
|
1004
1099
|
),
|
|
1005
|
-
/* @__PURE__ */ jsx3("span", { children: selected.quantity }),
|
|
1100
|
+
/* @__PURE__ */ jsx3("span", { "aria-live": "polite", children: selected.quantity }),
|
|
1006
1101
|
/* @__PURE__ */ jsx3(
|
|
1007
1102
|
"button",
|
|
1008
1103
|
{
|
|
1009
1104
|
"aria-label": `Increase ${product.title}`,
|
|
1010
|
-
onClick: () =>
|
|
1105
|
+
onClick: () => onSetQuantity(
|
|
1011
1106
|
product.id,
|
|
1012
|
-
displayVariant
|
|
1107
|
+
displayVariant,
|
|
1013
1108
|
selected.quantity + 1
|
|
1014
1109
|
),
|
|
1110
|
+
disabled: selected.quantity >= maxAddable,
|
|
1015
1111
|
children: "+"
|
|
1016
1112
|
}
|
|
1113
|
+
),
|
|
1114
|
+
/* @__PURE__ */ jsx3(
|
|
1115
|
+
"button",
|
|
1116
|
+
{
|
|
1117
|
+
className: "lb-bundle__remove-btn",
|
|
1118
|
+
"aria-label": `Remove ${product.title}`,
|
|
1119
|
+
onClick: () => onDeselect(product.id, displayVariant.id),
|
|
1120
|
+
children: "Remove"
|
|
1121
|
+
}
|
|
1017
1122
|
)
|
|
1018
1123
|
] }) : /* @__PURE__ */ jsx3(
|
|
1124
|
+
"button",
|
|
1125
|
+
{
|
|
1126
|
+
className: "lb-bundle__select-btn lb-bundle__select-btn--selected",
|
|
1127
|
+
"aria-label": `Remove ${product.title}`,
|
|
1128
|
+
onClick: () => onDeselect(product.id, displayVariant.id),
|
|
1129
|
+
children: "Selected"
|
|
1130
|
+
}
|
|
1131
|
+
) : /* @__PURE__ */ jsx3(
|
|
1019
1132
|
"button",
|
|
1020
1133
|
{
|
|
1021
1134
|
className: "lb-bundle__select-btn",
|
|
1022
|
-
onClick: () =>
|
|
1023
|
-
disabled: !
|
|
1024
|
-
children:
|
|
1135
|
+
onClick: () => onSelect(product.id, displayVariant),
|
|
1136
|
+
disabled: !fulfillable || maxAddable <= 0,
|
|
1137
|
+
children: fulfillable && maxAddable > 0 ? "Select" : "Sold out"
|
|
1025
1138
|
}
|
|
1026
1139
|
) })
|
|
1027
1140
|
]
|
|
@@ -1035,7 +1148,9 @@ import {
|
|
|
1035
1148
|
formatMoney as formatMoney3,
|
|
1036
1149
|
formatUnitPrice as formatUnitPrice3,
|
|
1037
1150
|
calculateTierSavings,
|
|
1038
|
-
getActiveTier
|
|
1151
|
+
getActiveTier,
|
|
1152
|
+
isVariantFulfillable as isVariantFulfillable3,
|
|
1153
|
+
shouldShowLowStockBadge as shouldShowLowStockBadge3
|
|
1039
1154
|
} from "@lime-bundles/core";
|
|
1040
1155
|
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1041
1156
|
function VolumeBundle(props) {
|
|
@@ -1087,7 +1202,8 @@ function VolumeBundle(props) {
|
|
|
1087
1202
|
}, [variants]);
|
|
1088
1203
|
const showPicker = variants.length > 1 && optionNames.length > 0;
|
|
1089
1204
|
const { selectedValues, selectedVariant, setOptionValue, optionsFor } = useVariantSelection({ variants, optionNames });
|
|
1090
|
-
const
|
|
1205
|
+
const minTierQty = bundle?.volumeTiers[0]?.minQuantity ?? 1;
|
|
1206
|
+
const displayVariant = selectedVariant ?? variants.find((v) => isVariantFulfillable3(v, minTierQty)) ?? variants[0];
|
|
1091
1207
|
const basePrice = displayVariant ? parseFloat(displayVariant.price.amount) : product ? parseFloat(product.priceRange.minVariantPrice.amount) : 0;
|
|
1092
1208
|
const currency = product?.priceRange.minVariantPrice.currencyCode ?? "USD";
|
|
1093
1209
|
const thumbImage = displayVariant?.image ?? product?.featuredImage ?? null;
|
|
@@ -1108,7 +1224,9 @@ function VolumeBundle(props) {
|
|
|
1108
1224
|
const activeTier = bundle ? getActiveTier(bundle.volumeTiers, quantity) : null;
|
|
1109
1225
|
const handleAddToCart = useCallback6(async () => {
|
|
1110
1226
|
if (!bundle || !product) return;
|
|
1111
|
-
const variant = selectedVariant ?? product.variants.nodes.find(
|
|
1227
|
+
const variant = selectedVariant ?? product.variants.nodes.find(
|
|
1228
|
+
(v) => isVariantFulfillable3(v, quantity)
|
|
1229
|
+
);
|
|
1112
1230
|
if (!variant) return;
|
|
1113
1231
|
const lines = [
|
|
1114
1232
|
{
|
|
@@ -1273,6 +1391,16 @@ function VolumeBundle(props) {
|
|
|
1273
1391
|
] })
|
|
1274
1392
|
] }),
|
|
1275
1393
|
cartError && /* @__PURE__ */ jsx4("p", { className: "lb-bundle__error", role: "alert", children: cartError }),
|
|
1394
|
+
bundle && displayVariant && shouldShowLowStockBadge3(
|
|
1395
|
+
displayVariant,
|
|
1396
|
+
minTierQty,
|
|
1397
|
+
bundle.widgetConfig.lowStockThreshold,
|
|
1398
|
+
bundle.widgetConfig.showLowStockBadge
|
|
1399
|
+
) && /* @__PURE__ */ jsxs4("span", { className: "lb-bundle-low-stock-badge", children: [
|
|
1400
|
+
"Only ",
|
|
1401
|
+
displayVariant.quantityAvailable,
|
|
1402
|
+
" left"
|
|
1403
|
+
] }),
|
|
1276
1404
|
/* @__PURE__ */ jsx4(
|
|
1277
1405
|
"button",
|
|
1278
1406
|
{
|
|
@@ -1359,7 +1487,7 @@ import {
|
|
|
1359
1487
|
computeBundleSaleCents,
|
|
1360
1488
|
calculateTierSavings as calculateTierSavings2,
|
|
1361
1489
|
getActiveTier as getActiveTier2,
|
|
1362
|
-
validateQuantity
|
|
1490
|
+
validateQuantity,
|
|
1363
1491
|
transformImageUrl,
|
|
1364
1492
|
formatCountdown,
|
|
1365
1493
|
formatMoney as formatMoney4,
|
|
@@ -1427,6 +1555,6 @@ export {
|
|
|
1427
1555
|
useBundlesForProduct,
|
|
1428
1556
|
useVariantSelection,
|
|
1429
1557
|
useWidgetConfigVars,
|
|
1430
|
-
|
|
1558
|
+
validateQuantity
|
|
1431
1559
|
};
|
|
1432
1560
|
//# sourceMappingURL=index.js.map
|