@lime-bundles/widget 4.0.0 → 4.1.1
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 +235 -86
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +217 -62
- package/dist/lime-bundle.global.js +34 -20
- package/dist/lime-bundle.global.js.map +1 -1
- package/docs/css-variables.md +7 -1
- package/docs/hydrogen.md +29 -4
- package/docs/react-nextjs.md +24 -4
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -26,7 +26,7 @@ __export(index_exports, {
|
|
|
26
26
|
module.exports = __toCommonJS(index_exports);
|
|
27
27
|
|
|
28
28
|
// src/lime-bundle.ts
|
|
29
|
-
var
|
|
29
|
+
var import_core6 = require("@lime-bundles/core");
|
|
30
30
|
|
|
31
31
|
// ../render/src/adapt.ts
|
|
32
32
|
var import_core = require("@lime-bundles/core");
|
|
@@ -511,7 +511,7 @@ function buildWidgetShell(typeClass, opts) {
|
|
|
511
511
|
"data-countdown": ""
|
|
512
512
|
});
|
|
513
513
|
const label2 = box("span", "lb-bundle-countdown-label");
|
|
514
|
-
label2.textContent = opts.countdownLabel ?? "
|
|
514
|
+
label2.textContent = opts.countdownLabel ?? "Limited time offer";
|
|
515
515
|
countdown.appendChild(label2);
|
|
516
516
|
countdown.appendChild(
|
|
517
517
|
box("span", "lb-bundle-countdown-timer", {
|
|
@@ -523,10 +523,12 @@ function buildWidgetShell(typeClass, opts) {
|
|
|
523
523
|
const products = box("div", typeClass + "__products lb-edge-fade");
|
|
524
524
|
root.appendChild(products);
|
|
525
525
|
root.appendChild(box("div", "lb-bundle-divider"));
|
|
526
|
-
const summary = box("div", "lb-bundle-summary"
|
|
526
|
+
const summary = box("div", "lb-bundle-summary", {
|
|
527
|
+
"data-pricing-section": ""
|
|
528
|
+
});
|
|
527
529
|
const text = box("div", "lb-bundle-summary__text");
|
|
528
530
|
const label = box("span", "lb-bundle-summary__label");
|
|
529
|
-
label.textContent = opts.summaryLabel ?? "Bundle
|
|
531
|
+
label.textContent = opts.summaryLabel ?? "Bundle total";
|
|
530
532
|
text.appendChild(label);
|
|
531
533
|
if (opts.withItemCount) {
|
|
532
534
|
label.appendChild(box("span", "", { "data-item-count": "" }));
|
|
@@ -557,6 +559,7 @@ function buildWidgetShell(typeClass, opts) {
|
|
|
557
559
|
summary.appendChild(prices);
|
|
558
560
|
root.appendChild(summary);
|
|
559
561
|
const cta = box("button", "lb-bundle-cta", {
|
|
562
|
+
"data-cta-text": opts.ctaText,
|
|
560
563
|
type: "button",
|
|
561
564
|
"data-add-bundle": ""
|
|
562
565
|
});
|
|
@@ -575,7 +578,9 @@ function buildWidgetShell(typeClass, opts) {
|
|
|
575
578
|
);
|
|
576
579
|
return { root, products, cta };
|
|
577
580
|
}
|
|
578
|
-
function buildVolumeTiers(tiers, groupLabel) {
|
|
581
|
+
function buildVolumeTiers(tiers, groupLabel, opts = {}) {
|
|
582
|
+
const showCompare = opts.showCompare !== false;
|
|
583
|
+
const showPriceEach = opts.showPriceEach !== false;
|
|
579
584
|
const group = box("div", "lb-volume__tiers lb-edge-fade", {
|
|
580
585
|
role: "radiogroup",
|
|
581
586
|
"aria-label": groupLabel,
|
|
@@ -600,8 +605,17 @@ function buildVolumeTiers(tiers, groupLabel) {
|
|
|
600
605
|
label.textContent = tier.label;
|
|
601
606
|
info.appendChild(label);
|
|
602
607
|
const price = box("span", "lb-volume__tier-price");
|
|
603
|
-
|
|
604
|
-
|
|
608
|
+
if (showCompare && (tier.percent > 0 || tier.amountCents > 0)) {
|
|
609
|
+
price.appendChild(box("span", "lb-volume__tier-compare"));
|
|
610
|
+
}
|
|
611
|
+
if (showPriceEach) {
|
|
612
|
+
price.appendChild(box("span", "", { "data-tier-price-each": "" }));
|
|
613
|
+
if (opts.unitLabel) {
|
|
614
|
+
const unit = box("span", "lb-volume__tier-unit");
|
|
615
|
+
unit.textContent = opts.unitLabel;
|
|
616
|
+
price.appendChild(unit);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
605
619
|
info.appendChild(price);
|
|
606
620
|
el2.appendChild(info);
|
|
607
621
|
if (tier.badgeLabel || tier.savingsLabel) {
|
|
@@ -710,7 +724,10 @@ var DEFAULT_STRINGS = {
|
|
|
710
724
|
required: "Required",
|
|
711
725
|
soldOut: "Sold out",
|
|
712
726
|
outOfStock: "Out of stock",
|
|
713
|
-
itemsOutOfStock:
|
|
727
|
+
itemsOutOfStock: {
|
|
728
|
+
one: "__COUNT__ item out of stock",
|
|
729
|
+
other: "__COUNT__ items out of stock"
|
|
730
|
+
},
|
|
714
731
|
quantity: "Quantity",
|
|
715
732
|
increaseQuantity: "Increase quantity",
|
|
716
733
|
decreaseQuantity: "Decrease quantity",
|
|
@@ -730,11 +747,26 @@ var DEFAULT_STRINGS = {
|
|
|
730
747
|
stepsCompleted: "__COUNT__ of __TOTAL__ steps completed",
|
|
731
748
|
each: " each",
|
|
732
749
|
buyQty: "Buy __COUNT__",
|
|
750
|
+
itemCount: {
|
|
751
|
+
one: "__COUNT__ item",
|
|
752
|
+
other: "__COUNT__ items"
|
|
753
|
+
},
|
|
733
754
|
needsSpots: {
|
|
734
755
|
one: "Needs __COUNT__ spot",
|
|
735
756
|
other: "Needs __COUNT__ spots"
|
|
736
757
|
}
|
|
737
758
|
};
|
|
759
|
+
function formatItemsOutOfStock(t, count) {
|
|
760
|
+
const raw = t.itemsOutOfStock;
|
|
761
|
+
let tpl;
|
|
762
|
+
if (raw && typeof raw === "object") {
|
|
763
|
+
const form = new Intl.PluralRules(t.locale || "en").select(count);
|
|
764
|
+
tpl = raw[form] || raw.other;
|
|
765
|
+
} else {
|
|
766
|
+
tpl = raw;
|
|
767
|
+
}
|
|
768
|
+
return (tpl || "__COUNT__ items out of stock").split("__COUNT__").join(String(count));
|
|
769
|
+
}
|
|
738
770
|
|
|
739
771
|
// ../render/src/dropdown/bind.ts
|
|
740
772
|
var import_core2 = require("@lime-bundles/core");
|
|
@@ -1191,7 +1223,7 @@ function renderFixedBundle(container, bundle, outOfStockBehavior, onAddToCart, o
|
|
|
1191
1223
|
shell.cta.disabled = true;
|
|
1192
1224
|
const label = shell.cta.querySelector("[data-cta-label]");
|
|
1193
1225
|
if (label) {
|
|
1194
|
-
label.textContent = (t
|
|
1226
|
+
label.textContent = formatItemsOutOfStock(t, oosProducts.length);
|
|
1195
1227
|
}
|
|
1196
1228
|
} else {
|
|
1197
1229
|
shell.cta.addEventListener("click", () => {
|
|
@@ -1249,15 +1281,38 @@ function formatSubtitle(remaining, discountType, discountValue, t) {
|
|
|
1249
1281
|
|
|
1250
1282
|
// ../render/src/picker/rules.ts
|
|
1251
1283
|
var DEFAULT_RULE = { min: 1, max: 99 };
|
|
1252
|
-
function ruleFor(productId, rulesMap) {
|
|
1284
|
+
function ruleFor(productId, rulesMap, variantId) {
|
|
1285
|
+
if (variantId != null) {
|
|
1286
|
+
const vRule = rulesMap["gid://shopify/ProductVariant/" + variantId];
|
|
1287
|
+
if (vRule && typeof vRule.min === "number" && typeof vRule.max === "number") {
|
|
1288
|
+
return vRule;
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1253
1291
|
const rule = rulesMap["gid://shopify/Product/" + productId];
|
|
1254
1292
|
if (!rule || typeof rule.min !== "number" || typeof rule.max !== "number") {
|
|
1255
1293
|
return DEFAULT_RULE;
|
|
1256
1294
|
}
|
|
1257
1295
|
return rule;
|
|
1258
1296
|
}
|
|
1259
|
-
function
|
|
1260
|
-
|
|
1297
|
+
function variantRuleFor(variantId, rulesMap) {
|
|
1298
|
+
if (variantId == null) return void 0;
|
|
1299
|
+
const rule = rulesMap["gid://shopify/ProductVariant/" + variantId];
|
|
1300
|
+
if (!rule || typeof rule.min !== "number" || typeof rule.max !== "number") {
|
|
1301
|
+
return void 0;
|
|
1302
|
+
}
|
|
1303
|
+
return rule;
|
|
1304
|
+
}
|
|
1305
|
+
function mergeRuleMaps(productRules, variantRules) {
|
|
1306
|
+
const products = productRules ?? {};
|
|
1307
|
+
if (!variantRules) return products;
|
|
1308
|
+
const keys = Object.keys(variantRules);
|
|
1309
|
+
if (keys.length === 0) return products;
|
|
1310
|
+
const merged = { ...products };
|
|
1311
|
+
for (const key of keys) merged[key] = variantRules[key];
|
|
1312
|
+
return merged;
|
|
1313
|
+
}
|
|
1314
|
+
function defaultPickQuantity(productId, rulesMap, variantId) {
|
|
1315
|
+
return ruleFor(productId, rulesMap, variantId).min;
|
|
1261
1316
|
}
|
|
1262
1317
|
function totalUnits(items) {
|
|
1263
1318
|
let qty = 0;
|
|
@@ -1277,11 +1332,9 @@ function committedQtyForVariant(items, variantId) {
|
|
|
1277
1332
|
function isRowAddable(rule, remainingSpots) {
|
|
1278
1333
|
return rule.min <= remainingSpots;
|
|
1279
1334
|
}
|
|
1280
|
-
function stepperCeiling(rule, remainingSpots, stock, ownQty = 0, productOtherUnits = 0) {
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
ownQty + remainingSpots
|
|
1284
|
-
);
|
|
1335
|
+
function stepperCeiling(rule, remainingSpots, stock, ownQty = 0, productOtherUnits = 0, variantMax) {
|
|
1336
|
+
let ceiling = Math.min(rule.max - productOtherUnits, ownQty + remainingSpots);
|
|
1337
|
+
if (typeof variantMax === "number") ceiling = Math.min(ceiling, variantMax);
|
|
1285
1338
|
return typeof stock === "number" ? Math.min(ceiling, stock) : ceiling;
|
|
1286
1339
|
}
|
|
1287
1340
|
|
|
@@ -1360,7 +1413,8 @@ function buildPickerRow(p, rowIndex, ctx) {
|
|
|
1360
1413
|
}
|
|
1361
1414
|
infoDiv.appendChild(titleEl);
|
|
1362
1415
|
let currentVariant = firstAvailable ?? (p.variants.length > 0 ? p.variants[0] : null);
|
|
1363
|
-
const
|
|
1416
|
+
const ruleForVariant = (v) => ruleFor(p.id, rulesMap, v ? v.id : null);
|
|
1417
|
+
const modalQty = currentVariant ? ruleForVariant(currentVariant).min : 1;
|
|
1364
1418
|
const priceEl = document.createElement("p");
|
|
1365
1419
|
priceEl.className = "lb-mix-match__modal-product-price";
|
|
1366
1420
|
priceEl.setAttribute("data-row-price", "");
|
|
@@ -1396,8 +1450,8 @@ function buildPickerRow(p, rowIndex, ctx) {
|
|
|
1396
1450
|
infoDiv.appendChild(unitPriceEl);
|
|
1397
1451
|
let qtyGroup = null;
|
|
1398
1452
|
let qtyValueEl = null;
|
|
1399
|
-
let current =
|
|
1400
|
-
let effectiveMax =
|
|
1453
|
+
let current = ruleForVariant(currentVariant).min;
|
|
1454
|
+
let effectiveMax = ruleForVariant(currentVariant).max;
|
|
1401
1455
|
let paint = null;
|
|
1402
1456
|
let setBoundsForVariant = null;
|
|
1403
1457
|
if (p.available && ctx.showQtySelector) {
|
|
@@ -1419,7 +1473,7 @@ function buildPickerRow(p, rowIndex, ctx) {
|
|
|
1419
1473
|
qtyValueEl.className = "lb-mix-match__qty-stepper-value";
|
|
1420
1474
|
qtyValueEl.setAttribute("data-row-qty", "");
|
|
1421
1475
|
qtyValueEl.setAttribute("aria-live", "polite");
|
|
1422
|
-
qtyValueEl.textContent = String(
|
|
1476
|
+
qtyValueEl.textContent = String(ruleForVariant(currentVariant).min);
|
|
1423
1477
|
const qtyPlusBtn = document.createElement("button");
|
|
1424
1478
|
qtyPlusBtn.type = "button";
|
|
1425
1479
|
qtyPlusBtn.className = "lb-mix-match__qty-stepper-button lb-mix-match__qty-stepper-button--plus";
|
|
@@ -1436,7 +1490,7 @@ function buildPickerRow(p, rowIndex, ctx) {
|
|
|
1436
1490
|
paint = () => {
|
|
1437
1491
|
valueEl.textContent = String(current);
|
|
1438
1492
|
valueEl.setAttribute("data-qty", String(current));
|
|
1439
|
-
qtyMinusBtn.disabled = stepperDisabled || current <=
|
|
1493
|
+
qtyMinusBtn.disabled = stepperDisabled || current <= ruleForVariant(currentVariant).min;
|
|
1440
1494
|
qtyPlusBtn.disabled = stepperDisabled || current >= effectiveMax;
|
|
1441
1495
|
};
|
|
1442
1496
|
setBoundsForVariant = (variant, alreadyInBundle = 0) => {
|
|
@@ -1447,18 +1501,21 @@ function buildPickerRow(p, rowIndex, ctx) {
|
|
|
1447
1501
|
const stock = variant ? variant.inventoryQuantity : null;
|
|
1448
1502
|
const othersInBundle = Math.max(0, alreadyInBundle - ownQty);
|
|
1449
1503
|
const stockCap = typeof stock === "number" ? Math.max(0, stock - othersInBundle) : void 0;
|
|
1504
|
+
const vMax = variantRuleFor(variantId, rulesMap)?.max;
|
|
1505
|
+
const rMin = ruleForVariant(variant).min;
|
|
1450
1506
|
effectiveMax = swapUnits > 0 ? typeof stockCap === "number" ? Math.min(swapUnits, stockCap) : swapUnits : stepperCeiling(
|
|
1451
1507
|
pRule,
|
|
1452
1508
|
capacity.remainingSpots(),
|
|
1453
1509
|
stockCap,
|
|
1454
1510
|
ownQty,
|
|
1455
|
-
otherUnits
|
|
1511
|
+
otherUnits,
|
|
1512
|
+
vMax
|
|
1456
1513
|
);
|
|
1457
|
-
if (effectiveMax <
|
|
1458
|
-
current =
|
|
1514
|
+
if (effectiveMax < rMin) {
|
|
1515
|
+
current = rMin;
|
|
1459
1516
|
} else {
|
|
1460
1517
|
if (current > effectiveMax) current = effectiveMax;
|
|
1461
|
-
if (current <
|
|
1518
|
+
if (current < rMin) current = rMin;
|
|
1462
1519
|
}
|
|
1463
1520
|
paint();
|
|
1464
1521
|
};
|
|
@@ -1469,7 +1526,7 @@ function buildPickerRow(p, rowIndex, ctx) {
|
|
|
1469
1526
|
}
|
|
1470
1527
|
};
|
|
1471
1528
|
qtyMinusBtn.addEventListener("click", () => {
|
|
1472
|
-
if (current >
|
|
1529
|
+
if (current > ruleForVariant(currentVariant).min) current -= 1;
|
|
1473
1530
|
paint();
|
|
1474
1531
|
commitQtyToBundle();
|
|
1475
1532
|
});
|
|
@@ -1539,7 +1596,7 @@ function buildPickerRow(p, rowIndex, ctx) {
|
|
|
1539
1596
|
}
|
|
1540
1597
|
currentVariant = v;
|
|
1541
1598
|
row.setAttribute("data-selected-variant-id", String(v.id));
|
|
1542
|
-
const resolvedQty =
|
|
1599
|
+
const resolvedQty = ruleForVariant(v).min;
|
|
1543
1600
|
priceSaleEl.textContent = formatMoney(v.price * resolvedQty);
|
|
1544
1601
|
paintRowCompare(priceCompareEl, v, resolvedQty);
|
|
1545
1602
|
if (v.unitPrice) {
|
|
@@ -1641,17 +1698,19 @@ function buildPickerRow(p, rowIndex, ctx) {
|
|
|
1641
1698
|
if (setBoundsForVariant) {
|
|
1642
1699
|
const committed = capacity.ownQty(variant.id);
|
|
1643
1700
|
if (committed > 0) current = committed;
|
|
1644
|
-
else if (lastVariantId !== variant.id)
|
|
1701
|
+
else if (lastVariantId !== variant.id)
|
|
1702
|
+
current = ruleForVariant(variant).min;
|
|
1645
1703
|
lastVariantId = variant.id;
|
|
1646
1704
|
setBoundsForVariant(variant, already);
|
|
1647
1705
|
}
|
|
1648
1706
|
const rowSwapUnits = capacity.swapUnits(p.id, variant.id);
|
|
1649
|
-
const
|
|
1707
|
+
const vRule = ruleForVariant(variant);
|
|
1708
|
+
const inSwapState = rowSwapUnits >= vRule.min;
|
|
1650
1709
|
const remaining = capacity.remainingSpots();
|
|
1651
|
-
const needsMoreSpots = !inBundle && !inSwapState && !isRowAddable(
|
|
1710
|
+
const needsMoreSpots = !inBundle && !inSwapState && !isRowAddable(vRule, remaining);
|
|
1652
1711
|
if (needsSpotsEl) {
|
|
1653
1712
|
if (needsMoreSpots && remaining > 0) {
|
|
1654
|
-
needsSpotsEl.textContent = formatNeedsSpots(
|
|
1713
|
+
needsSpotsEl.textContent = formatNeedsSpots(vRule.min, t);
|
|
1655
1714
|
needsSpotsEl.hidden = false;
|
|
1656
1715
|
} else {
|
|
1657
1716
|
needsSpotsEl.hidden = true;
|
|
@@ -1688,11 +1747,11 @@ function buildPickerRow(p, rowIndex, ctx) {
|
|
|
1688
1747
|
addBtn.classList.remove("lb-mix-match__modal-add--required");
|
|
1689
1748
|
row.classList.remove("lb-mix-match__modal-product--in-bundle");
|
|
1690
1749
|
addedBadge.hidden = true;
|
|
1691
|
-
const noStock = typeof stock === "number" ? Math.max(0, stock - already) <
|
|
1750
|
+
const noStock = typeof stock === "number" ? Math.max(0, stock - already) < vRule.min : false;
|
|
1692
1751
|
if (inSwapState) {
|
|
1693
1752
|
addBtn.disabled = noStock;
|
|
1694
1753
|
} else {
|
|
1695
|
-
const productMaxed = pRule.max - capacity.productUnitsElsewhere(p.id, variant.id) <
|
|
1754
|
+
const productMaxed = pRule.max - capacity.productUnitsElsewhere(p.id, variant.id) < vRule.min;
|
|
1696
1755
|
addBtn.disabled = noStock || productMaxed || needsMoreSpots || capacity.isFull();
|
|
1697
1756
|
}
|
|
1698
1757
|
}
|
|
@@ -1844,7 +1903,7 @@ function createPickerModal(deps) {
|
|
|
1844
1903
|
rowQtyEl.getAttribute("data-qty") || rowQtyEl.textContent || "",
|
|
1845
1904
|
10
|
|
1846
1905
|
) || 1
|
|
1847
|
-
) : defaultPickQuantity(prod.id, deps.rulesMap);
|
|
1906
|
+
) : defaultPickQuantity(prod.id, deps.rulesMap, selectedVariant.id);
|
|
1848
1907
|
const newItem = {
|
|
1849
1908
|
productId: prod.id,
|
|
1850
1909
|
variantId: selectedVariant.id,
|
|
@@ -2053,6 +2112,7 @@ function productUnitsInOtherSlots(items, productId, excludeVariantId) {
|
|
|
2053
2112
|
return qty;
|
|
2054
2113
|
}
|
|
2055
2114
|
function canRemovePick(items, item, rulesMap) {
|
|
2115
|
+
if (variantRuleFor(item.variantId, rulesMap)?.required) return false;
|
|
2056
2116
|
const rule = ruleFor(item.productId, rulesMap);
|
|
2057
2117
|
if (!rule.required) return true;
|
|
2058
2118
|
let unitsElsewhere = 0;
|
|
@@ -2317,8 +2377,17 @@ function seedSelection(eligibleProducts, rulesMap, requiredQty, courtesy) {
|
|
|
2317
2377
|
});
|
|
2318
2378
|
const required = [];
|
|
2319
2379
|
for (const p of eligibleProducts) {
|
|
2380
|
+
if (!p.available || !p.variants) continue;
|
|
2381
|
+
let seededVariant = false;
|
|
2382
|
+
for (const v3 of p.variants) {
|
|
2383
|
+
const vRule = variantRuleFor(v3.id, rulesMap);
|
|
2384
|
+
if (!vRule?.required || !v3.available) continue;
|
|
2385
|
+
required.push(pick(p, v3, Math.max(1, vRule.min)));
|
|
2386
|
+
seededVariant = true;
|
|
2387
|
+
}
|
|
2388
|
+
if (seededVariant) continue;
|
|
2320
2389
|
const rule = ruleFor(p.id, rulesMap);
|
|
2321
|
-
if (!rule.required
|
|
2390
|
+
if (!rule.required) continue;
|
|
2322
2391
|
const v2 = firstAvailable(p);
|
|
2323
2392
|
if (!v2) continue;
|
|
2324
2393
|
required.push(pick(p, v2, Math.max(1, rule.min)));
|
|
@@ -2519,17 +2588,17 @@ function buildPickerModal(opts) {
|
|
|
2519
2588
|
}
|
|
2520
2589
|
|
|
2521
2590
|
// src/renderers/mix-match.ts
|
|
2522
|
-
function renderMixMatchBundle(container, bundle, outOfStockBehavior, onAddToCart, onCleanup) {
|
|
2591
|
+
function renderMixMatchBundle(container, bundle, outOfStockBehavior, onAddToCart, onCleanup, currentProductHandle) {
|
|
2523
2592
|
const wc = bundle.widgetConfig;
|
|
2524
2593
|
const t = DEFAULT_STRINGS;
|
|
2525
2594
|
const requiredQty = bundle.minQuantity || 1;
|
|
2526
|
-
const rulesMap = bundle.productRules
|
|
2595
|
+
const rulesMap = mergeRuleMaps(bundle.productRules, bundle.variantRules);
|
|
2527
2596
|
const adapted = adaptProducts(bundle);
|
|
2528
|
-
const eligibleProducts = adapted.map((p) => ({
|
|
2597
|
+
const eligibleProducts = adapted.map((p, i) => ({
|
|
2529
2598
|
id: Number(p.productId),
|
|
2530
2599
|
title: p.title ?? "",
|
|
2531
2600
|
url: p.url ?? null,
|
|
2532
|
-
type: "",
|
|
2601
|
+
type: bundle.products[i]?.productType ?? "",
|
|
2533
2602
|
featuredImage: p.featuredImage ?? null,
|
|
2534
2603
|
available: p.variants.some((v) => v.available),
|
|
2535
2604
|
optionNames: p.optionNames,
|
|
@@ -2574,16 +2643,21 @@ function renderMixMatchBundle(container, bundle, outOfStockBehavior, onAddToCart
|
|
|
2574
2643
|
const overlay = buildPickerModal({
|
|
2575
2644
|
bundleGid: bundle.id,
|
|
2576
2645
|
domId: bundle.id.replace(/\D/g, ""),
|
|
2577
|
-
showSearch:
|
|
2578
|
-
showTypeFilters: false,
|
|
2646
|
+
showSearch: wc.showSearch !== false,
|
|
2647
|
+
showTypeFilters: wc.mixMatchShowTypeFilters !== false,
|
|
2579
2648
|
segmentCount: requiredQty,
|
|
2580
2649
|
wizard: false
|
|
2581
2650
|
});
|
|
2582
2651
|
shell.root.appendChild(overlay);
|
|
2652
|
+
const currentIdx = currentProductHandle ? bundle.products.findIndex((p) => p.handle === currentProductHandle) : -1;
|
|
2583
2653
|
const selectedItems = seedSelection(
|
|
2584
2654
|
eligibleProducts,
|
|
2585
2655
|
rulesMap,
|
|
2586
|
-
requiredQty
|
|
2656
|
+
requiredQty,
|
|
2657
|
+
{
|
|
2658
|
+
enabled: !!currentProductHandle,
|
|
2659
|
+
currentProductId: currentIdx !== -1 ? eligibleProducts[currentIdx]?.id ?? null : null
|
|
2660
|
+
}
|
|
2587
2661
|
);
|
|
2588
2662
|
const rowCapacity = {
|
|
2589
2663
|
remainingSpots: () => remainingUnits(selectedItems, requiredQty),
|
|
@@ -2620,7 +2694,13 @@ function renderMixMatchBundle(container, bundle, outOfStockBehavior, onAddToCart
|
|
|
2620
2694
|
shell.root,
|
|
2621
2695
|
selectedItems,
|
|
2622
2696
|
requiredQty,
|
|
2623
|
-
|
|
2697
|
+
// The shared updater reads the theme data-block shape: discount fields
|
|
2698
|
+
// flat, not nested under discountConfig. Passing the bundle itself left
|
|
2699
|
+
// `discountType` undefined, so the summary never painted.
|
|
2700
|
+
{
|
|
2701
|
+
discountType: bundle.discountConfig.discountType,
|
|
2702
|
+
discountValue: bundle.discountConfig.discountValue
|
|
2703
|
+
},
|
|
2624
2704
|
(total, type, value) => (0, import_core3.calculateDiscount)(total, type, value),
|
|
2625
2705
|
updatePricing2(formatMoney)
|
|
2626
2706
|
);
|
|
@@ -2633,7 +2713,7 @@ function renderMixMatchBundle(container, bundle, outOfStockBehavior, onAddToCart
|
|
|
2633
2713
|
rulesMap,
|
|
2634
2714
|
eligibleProducts,
|
|
2635
2715
|
requiredQty,
|
|
2636
|
-
showQtySelector:
|
|
2716
|
+
showQtySelector: wc.mixMatchShowQuantitySelector !== false,
|
|
2637
2717
|
items: selectedItems,
|
|
2638
2718
|
formatMoney,
|
|
2639
2719
|
rowCapacity,
|
|
@@ -2644,7 +2724,9 @@ function renderMixMatchBundle(container, bundle, outOfStockBehavior, onAddToCart
|
|
|
2644
2724
|
onSelectionChanged: updateAll,
|
|
2645
2725
|
addSelection: (item) => {
|
|
2646
2726
|
if (totalUnits(selectedItems) + (item.quantity || 1) > requiredQty) return;
|
|
2647
|
-
const
|
|
2727
|
+
const vMax = variantRuleFor(item.variantId, rulesMap)?.max;
|
|
2728
|
+
let headroom = ruleFor(item.productId, rulesMap).max - productUnitsInOtherSlots(selectedItems, item.productId, item.variantId);
|
|
2729
|
+
if (typeof vMax === "number") headroom = Math.min(headroom, vMax);
|
|
2648
2730
|
if ((item.quantity || 1) > headroom) return;
|
|
2649
2731
|
selectedItems.push(item);
|
|
2650
2732
|
updateAll();
|
|
@@ -2694,6 +2776,9 @@ function renderMixMatchBundle(container, bundle, outOfStockBehavior, onAddToCart
|
|
|
2694
2776
|
onCleanup?.(bindDropdowns(shell.root));
|
|
2695
2777
|
}
|
|
2696
2778
|
|
|
2779
|
+
// src/renderers/volume.ts
|
|
2780
|
+
var import_core4 = require("@lime-bundles/core");
|
|
2781
|
+
|
|
2697
2782
|
// ../render/src/volume/pricing.ts
|
|
2698
2783
|
function calcTierPrice(basePrice, discountType, tierEl) {
|
|
2699
2784
|
if (discountType === "fixed_amount") {
|
|
@@ -2722,6 +2807,23 @@ function formatItemCount(qty, translations) {
|
|
|
2722
2807
|
const tpl = translations.itemCount[form] || translations.itemCount.other || "__COUNT__";
|
|
2723
2808
|
return " (" + tpl.split("__COUNT__").join(String(qty)) + ")";
|
|
2724
2809
|
}
|
|
2810
|
+
function updateAllTierPrices(allTiers, basePrice, discountType, formatMoney) {
|
|
2811
|
+
for (let i = 0; i < allTiers.length; i++) {
|
|
2812
|
+
const tierEl = allTiers[i];
|
|
2813
|
+
const priceEachEl = tierEl.querySelector(
|
|
2814
|
+
"[data-tier-price-each]"
|
|
2815
|
+
);
|
|
2816
|
+
if (priceEachEl) {
|
|
2817
|
+
priceEachEl.textContent = formatMoney(
|
|
2818
|
+
calcTierPrice(basePrice, discountType, tierEl)
|
|
2819
|
+
);
|
|
2820
|
+
}
|
|
2821
|
+
const compareEl = tierEl.querySelector(
|
|
2822
|
+
".lb-volume__tier-compare"
|
|
2823
|
+
);
|
|
2824
|
+
if (compareEl) compareEl.textContent = formatMoney(basePrice);
|
|
2825
|
+
}
|
|
2826
|
+
}
|
|
2725
2827
|
function selectTier(container, allTiers, basePrice, discountType, index, translations, formatMoney) {
|
|
2726
2828
|
for (let i = 0; i < allTiers.length; i++) {
|
|
2727
2829
|
allTiers[i].setAttribute("aria-checked", i === index ? "true" : "false");
|
|
@@ -2779,8 +2881,17 @@ function renderVolumeBundle(container, bundle, outOfStockBehavior, onAddToCart)
|
|
|
2779
2881
|
const discountType = bundle.discountConfig.discountType;
|
|
2780
2882
|
const formatMoney = intlFormatMoney(product.priceRange.minVariantPrice.currencyCode);
|
|
2781
2883
|
const t = DEFAULT_STRINGS;
|
|
2782
|
-
const
|
|
2783
|
-
const defaultIdx = 0
|
|
2884
|
+
const bestIdx = (0, import_core4.bestValueTierIndex)(bundle.volumeTiers, discountType);
|
|
2885
|
+
const defaultIdx = (0, import_core4.resolveDefaultTierIndex)(
|
|
2886
|
+
wc.defaultTier,
|
|
2887
|
+
bundle.volumeTiers.length,
|
|
2888
|
+
bestIdx
|
|
2889
|
+
);
|
|
2890
|
+
const popularIdx = (0, import_core4.resolvePopularTierIndex)(
|
|
2891
|
+
wc.popularBadge?.tierIndex,
|
|
2892
|
+
wc.popularBadge?.visible !== false,
|
|
2893
|
+
bestIdx
|
|
2894
|
+
);
|
|
2784
2895
|
const tiers = bundle.volumeTiers.map((tier, i) => {
|
|
2785
2896
|
const percent = discountType === "fixed_amount" ? 0 : Math.round(tier.percentage ?? 0);
|
|
2786
2897
|
const amountCents = discountType === "fixed_amount" ? Math.round((tier.amount ?? 0) * 100) : 0;
|
|
@@ -2801,16 +2912,21 @@ function renderVolumeBundle(container, bundle, outOfStockBehavior, onAddToCart)
|
|
|
2801
2912
|
title: bundle.title,
|
|
2802
2913
|
subtitle: bundle.description,
|
|
2803
2914
|
summaryLabel: "Total",
|
|
2804
|
-
withItemCount:
|
|
2915
|
+
withItemCount: wc.pricing?.showItemCount !== false,
|
|
2805
2916
|
totalPriceSlot: true,
|
|
2806
2917
|
showSavingsBar: wc.savingsBar?.visible !== false,
|
|
2807
2918
|
showComparePrice: wc.pricing?.showCompareAtPrice !== false,
|
|
2808
2919
|
ctaText: wc.cta?.ctaText || t.addToCart || "Add to cart",
|
|
2809
2920
|
endsAt: wc.countdown?.showCountdown === false ? null : bundle.endsAt
|
|
2810
2921
|
});
|
|
2811
|
-
const group = buildVolumeTiers(tiers, "Select quantity"
|
|
2922
|
+
const group = buildVolumeTiers(tiers, "Select quantity", {
|
|
2923
|
+
showCompare: wc.pricing?.showComparePrice !== false,
|
|
2924
|
+
showPriceEach: wc.pricing?.showPerUnitPrice !== false,
|
|
2925
|
+
unitLabel: (t.each || "each").trim()
|
|
2926
|
+
});
|
|
2812
2927
|
shell.products.replaceWith(group);
|
|
2813
2928
|
const tierEls = group.querySelectorAll("[data-tier-index]");
|
|
2929
|
+
updateAllTierPrices(tierEls, basePrice, discountType, formatMoney);
|
|
2814
2930
|
let selectedIndex = defaultIdx;
|
|
2815
2931
|
const apply = () => selectTier(shell.root, tierEls, basePrice, discountType, selectedIndex, t, formatMoney);
|
|
2816
2932
|
group.addEventListener("click", (e) => {
|
|
@@ -2960,6 +3076,13 @@ function buildBogoCartItems(sides, percent, buyQty, getQty) {
|
|
|
2960
3076
|
}
|
|
2961
3077
|
|
|
2962
3078
|
// src/renderers/bogo.ts
|
|
3079
|
+
function buildBogoPlus() {
|
|
3080
|
+
const plus = document.createElement("div");
|
|
3081
|
+
plus.className = "lb-bogo__plus";
|
|
3082
|
+
plus.setAttribute("aria-hidden", "true");
|
|
3083
|
+
plus.innerHTML = '<svg width="12" height="12" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><line x1="9" y1="3" x2="9" y2="15" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><line x1="3" y1="9" x2="15" y2="9" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>';
|
|
3084
|
+
return plus;
|
|
3085
|
+
}
|
|
2963
3086
|
function renderBogoBundle(container, bundle, outOfStockBehavior, onAddToCart, onCleanup) {
|
|
2964
3087
|
const wc = bundle.widgetConfig;
|
|
2965
3088
|
const buyProduct = bundle.products.find((p) => p.id === bundle.buyProductId);
|
|
@@ -3008,6 +3131,7 @@ function renderBogoBundle(container, bundle, outOfStockBehavior, onAddToCart, on
|
|
|
3008
3131
|
const badgeText = percent >= 100 ? "Free" : percent + "% off";
|
|
3009
3132
|
sides.forEach((side, i) => {
|
|
3010
3133
|
const isGet = i === 1;
|
|
3134
|
+
if (isGet) shell.products.appendChild(buildBogoPlus());
|
|
3011
3135
|
const isOos = !side.variants.some((v) => v.available);
|
|
3012
3136
|
const row = buildRowSkeleton(side, t, {
|
|
3013
3137
|
isOos,
|
|
@@ -3036,7 +3160,7 @@ function renderBogoBundle(container, bundle, outOfStockBehavior, onAddToCart, on
|
|
|
3036
3160
|
shell.cta.disabled = true;
|
|
3037
3161
|
const label = shell.cta.querySelector("[data-cta-label]");
|
|
3038
3162
|
if (label) {
|
|
3039
|
-
label.textContent = (t
|
|
3163
|
+
label.textContent = formatItemsOutOfStock(t, oosCount);
|
|
3040
3164
|
}
|
|
3041
3165
|
} else {
|
|
3042
3166
|
shell.cta.addEventListener("click", () => {
|
|
@@ -3056,7 +3180,7 @@ function renderBogoBundle(container, bundle, outOfStockBehavior, onAddToCart, on
|
|
|
3056
3180
|
}
|
|
3057
3181
|
|
|
3058
3182
|
// src/renderers/multi-step.ts
|
|
3059
|
-
var
|
|
3183
|
+
var import_core5 = require("@lime-bundles/core");
|
|
3060
3184
|
|
|
3061
3185
|
// ../render/src/multi-step/i18n.ts
|
|
3062
3186
|
function stepOfLabel(i, total, t) {
|
|
@@ -3104,6 +3228,7 @@ function allSatisfied(selections, steps) {
|
|
|
3104
3228
|
return true;
|
|
3105
3229
|
}
|
|
3106
3230
|
function canRemovePick2(selections, item, rulesMap) {
|
|
3231
|
+
if (variantRuleFor(item.variantId, rulesMap)?.required) return false;
|
|
3107
3232
|
const rule = ruleFor(item.productId, rulesMap);
|
|
3108
3233
|
if (!rule.required) return true;
|
|
3109
3234
|
let unitsElsewhere = 0;
|
|
@@ -3456,7 +3581,7 @@ function createWizard(deps) {
|
|
|
3456
3581
|
rowQtyEl.getAttribute("data-qty") || rowQtyEl.textContent || "",
|
|
3457
3582
|
10
|
|
3458
3583
|
) || 1
|
|
3459
|
-
) : defaultPickQuantity(prod.id, deps.rulesMap);
|
|
3584
|
+
) : defaultPickQuantity(prod.id, deps.rulesMap, selectedVariant.id);
|
|
3460
3585
|
const newItem = {
|
|
3461
3586
|
productId: prod.id,
|
|
3462
3587
|
variantId: selectedVariant.id,
|
|
@@ -3676,7 +3801,7 @@ function createWizard(deps) {
|
|
|
3676
3801
|
function renderMultiStepBundle(container, bundle, outOfStockBehavior, onAddToCart, onCleanup) {
|
|
3677
3802
|
const wc = bundle.widgetConfig;
|
|
3678
3803
|
const t = DEFAULT_STRINGS;
|
|
3679
|
-
const rulesMap = bundle.productRules
|
|
3804
|
+
const rulesMap = mergeRuleMaps(bundle.productRules, bundle.variantRules);
|
|
3680
3805
|
const steps = bundle.steps ?? [];
|
|
3681
3806
|
if (!steps.length) return;
|
|
3682
3807
|
const quantities = {
|
|
@@ -3684,7 +3809,7 @@ function renderMultiStepBundle(container, bundle, outOfStockBehavior, onAddToCar
|
|
|
3684
3809
|
variantQuantities: bundle.variantQuantities
|
|
3685
3810
|
};
|
|
3686
3811
|
const pools = steps.map(
|
|
3687
|
-
(_, i) => (0,
|
|
3812
|
+
(_, i) => (0, import_core5.productsForStep)(bundle, i).map((product) => {
|
|
3688
3813
|
const p = adaptProduct(product, bundle.id, {
|
|
3689
3814
|
quantities,
|
|
3690
3815
|
allowedVariantIds: null
|
|
@@ -3758,8 +3883,8 @@ function renderMultiStepBundle(container, bundle, outOfStockBehavior, onAddToCar
|
|
|
3758
3883
|
const overlay = buildPickerModal({
|
|
3759
3884
|
bundleGid: bundle.id,
|
|
3760
3885
|
domId: bundle.id.replace(/\D/g, ""),
|
|
3761
|
-
showSearch:
|
|
3762
|
-
showTypeFilters:
|
|
3886
|
+
showSearch: wc.showSearch !== false,
|
|
3887
|
+
showTypeFilters: wc.mixMatchShowTypeFilters !== false,
|
|
3763
3888
|
segmentCount: null,
|
|
3764
3889
|
wizard: true
|
|
3765
3890
|
});
|
|
@@ -3794,7 +3919,7 @@ function renderMultiStepBundle(container, bundle, outOfStockBehavior, onAddToCar
|
|
|
3794
3919
|
discountType: bundle.discountConfig.discountType,
|
|
3795
3920
|
discountValue: bundle.discountConfig.discountValue
|
|
3796
3921
|
},
|
|
3797
|
-
(total, type, value) => (0,
|
|
3922
|
+
(total, type, value) => (0, import_core5.calculateDiscount)(total, type, value),
|
|
3798
3923
|
updatePricing2(formatMoney)
|
|
3799
3924
|
);
|
|
3800
3925
|
updateProgress2(bodyDeps);
|
|
@@ -3806,8 +3931,8 @@ function renderMultiStepBundle(container, bundle, outOfStockBehavior, onAddToCar
|
|
|
3806
3931
|
selections,
|
|
3807
3932
|
t,
|
|
3808
3933
|
rulesMap,
|
|
3809
|
-
showQtySelector:
|
|
3810
|
-
showTypeFilters:
|
|
3934
|
+
showQtySelector: wc.mixMatchShowQuantitySelector !== false,
|
|
3935
|
+
showTypeFilters: wc.mixMatchShowTypeFilters !== false,
|
|
3811
3936
|
formatMoney,
|
|
3812
3937
|
dropdown: void 0,
|
|
3813
3938
|
portalTarget: null,
|
|
@@ -3857,7 +3982,7 @@ function renderMultiStepBundle(container, bundle, outOfStockBehavior, onAddToCar
|
|
|
3857
3982
|
}
|
|
3858
3983
|
|
|
3859
3984
|
// src/lime-bundle.ts
|
|
3860
|
-
var
|
|
3985
|
+
var import_core7 = require("@lime-bundles/core");
|
|
3861
3986
|
|
|
3862
3987
|
// src/utils/input-mode.ts
|
|
3863
3988
|
var NAV_KEYS = /* @__PURE__ */ new Set([
|
|
@@ -4196,7 +4321,10 @@ a.lb-bundle-product-name:focus-visible {
|
|
|
4196
4321
|
toggle: present in admin \u2192 shown; absent \u2192 hidden. Styled as muted
|
|
4197
4322
|
secondary text beneath the price row so it doesn't compete visually. */
|
|
4198
4323
|
.lb-bundle-product-unit-price {
|
|
4199
|
-
|
|
4324
|
+
/* Fallback is the "on" branch; Liquid sets 'none' when the merchant disables
|
|
4325
|
+
productList.showUnitPrice. The [hidden] rule below still wins for rows
|
|
4326
|
+
whose variant has no unit price at all. */
|
|
4327
|
+
display: var(--lb-product-unit-price-display, block);
|
|
4200
4328
|
font-size: 12px;
|
|
4201
4329
|
line-height: 16px;
|
|
4202
4330
|
color: color-mix(in srgb, var(--lb-text) 60%, transparent);
|
|
@@ -4375,6 +4503,10 @@ a.lb-bundle-product-name:focus-visible {
|
|
|
4375
4503
|
cards). Quiet, theme-inherited; the fixed widget uses .lb-bundle-qty-chip in
|
|
4376
4504
|
the card's right slot instead. */
|
|
4377
4505
|
.lb-bundle-qty-inline {
|
|
4506
|
+
/* Fallback is the "on" branch; Liquid sets 'none' when the merchant disables
|
|
4507
|
+
productList.showQuantity. The fixed widget's chip carries its own var
|
|
4508
|
+
because it is a flex box, not inline text. */
|
|
4509
|
+
display: var(--lb-product-qty-inline-display, inline);
|
|
4378
4510
|
font-size: 13px;
|
|
4379
4511
|
font-weight: 400;
|
|
4380
4512
|
color: color-mix(in srgb, var(--lb-text) 55%, transparent);
|
|
@@ -4607,6 +4739,10 @@ a.lb-bundle-product-name:focus-visible {
|
|
|
4607
4739
|
.lb-bundle-thumbnail[style*="--lb-row-thumb-ratio"] {
|
|
4608
4740
|
aspect-ratio: var(--lb-row-thumb-ratio);
|
|
4609
4741
|
}
|
|
4742
|
+
/* This selector outranks the \`.lb-bundle-thumbnail\` rule above, so Liquid must
|
|
4743
|
+
emit the inline var for the "original" ratio and nothing else. Emitting it
|
|
4744
|
+
unconditionally silently replaced every merchant ratio with the image's own,
|
|
4745
|
+
which looks like the setting being ignored. */
|
|
4610
4746
|
`;
|
|
4611
4747
|
var BUNDLE_FIXED_CSS = `/* Lime Bundles \u2014 Fixed bundle styles */
|
|
4612
4748
|
|
|
@@ -4656,7 +4792,10 @@ var BUNDLE_FIXED_CSS = `/* Lime Bundles \u2014 Fixed bundle styles */
|
|
|
4656
4792
|
min-width: 34px;
|
|
4657
4793
|
height: 28px;
|
|
4658
4794
|
padding: 0 8px;
|
|
4659
|
-
|
|
4795
|
+
/* Fallback is the "on" branch; Liquid sets 'none' when the merchant disables
|
|
4796
|
+
productList.showQuantity. Separate from --lb-product-qty-inline-display
|
|
4797
|
+
because this chip is a flex box and the other counts are inline text. */
|
|
4798
|
+
display: var(--lb-product-qty-chip-display, inline-flex);
|
|
4660
4799
|
align-items: center;
|
|
4661
4800
|
justify-content: center;
|
|
4662
4801
|
border-radius: var(--lb-radius-sm);
|
|
@@ -6499,6 +6638,13 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
6499
6638
|
buyer = void 0;
|
|
6500
6639
|
shadow;
|
|
6501
6640
|
bundles = [];
|
|
6641
|
+
/**
|
|
6642
|
+
* The product handle this embed is standing on, when one can be resolved
|
|
6643
|
+
* (attribute → meta tag → /products/<handle> path). The mix-and-match
|
|
6644
|
+
* courtesy seed uses it to pre-add the current product the way the theme
|
|
6645
|
+
* widget does; null on pages with no product context.
|
|
6646
|
+
*/
|
|
6647
|
+
currentProductHandle = null;
|
|
6502
6648
|
abortController = null;
|
|
6503
6649
|
impressionCleanups = [];
|
|
6504
6650
|
/**
|
|
@@ -6518,7 +6664,7 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
6518
6664
|
* before the first render. Defaults to `show_greyed_out` so a failed or
|
|
6519
6665
|
* missing fetch degrades to "bundles still render".
|
|
6520
6666
|
*/
|
|
6521
|
-
outOfStockBehavior =
|
|
6667
|
+
outOfStockBehavior = import_core6.DEFAULT_OUT_OF_STOCK_BEHAVIOR;
|
|
6522
6668
|
constructor() {
|
|
6523
6669
|
super();
|
|
6524
6670
|
this.shadow = this.attachShadow({ mode: "open" });
|
|
@@ -6580,13 +6726,13 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
6580
6726
|
* no buyer/country/language is set.
|
|
6581
6727
|
*/
|
|
6582
6728
|
wrapQueryForContext(query) {
|
|
6583
|
-
return (0,
|
|
6729
|
+
return (0, import_core6.hasInContext)({
|
|
6584
6730
|
shopDomain: this.shopDomain,
|
|
6585
6731
|
accessToken: this.storefrontToken,
|
|
6586
6732
|
country: this.country,
|
|
6587
6733
|
language: this.language,
|
|
6588
6734
|
buyer: this.buyer
|
|
6589
|
-
}) ? (0,
|
|
6735
|
+
}) ? (0, import_core6.withInContext)(query) : query;
|
|
6590
6736
|
}
|
|
6591
6737
|
/**
|
|
6592
6738
|
* Returns true if this bundle should be hidden for the current market.
|
|
@@ -6595,7 +6741,7 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
6595
6741
|
* marketIds doesn't include the configured market.
|
|
6596
6742
|
*/
|
|
6597
6743
|
isMarketHidden(bundle) {
|
|
6598
|
-
return !(0,
|
|
6744
|
+
return !(0, import_core6.isVisibleInMarket)(bundle, this.marketId);
|
|
6599
6745
|
}
|
|
6600
6746
|
async fetchBundle() {
|
|
6601
6747
|
if (!this.shopDomain || !this.storefrontToken) {
|
|
@@ -6608,7 +6754,7 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
6608
6754
|
const controller = new AbortController();
|
|
6609
6755
|
this.abortController = controller;
|
|
6610
6756
|
this.renderLoading();
|
|
6611
|
-
const client = (0,
|
|
6757
|
+
const client = (0, import_core6.createStorefrontClient)({
|
|
6612
6758
|
shopDomain: this.shopDomain,
|
|
6613
6759
|
accessToken: this.storefrontToken,
|
|
6614
6760
|
country: this.country,
|
|
@@ -6618,11 +6764,12 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
6618
6764
|
try {
|
|
6619
6765
|
let bundlePromise;
|
|
6620
6766
|
let singleBundleMode = false;
|
|
6767
|
+
this.currentProductHandle = resolveProductHandle(this.productHandleAttr);
|
|
6621
6768
|
if (this.bundleGid) {
|
|
6622
6769
|
singleBundleMode = true;
|
|
6623
6770
|
bundlePromise = this.fetchSingleBundle(client, controller.signal);
|
|
6624
6771
|
} else {
|
|
6625
|
-
const handle =
|
|
6772
|
+
const handle = this.currentProductHandle;
|
|
6626
6773
|
if (!handle) {
|
|
6627
6774
|
this.teardownImpressions();
|
|
6628
6775
|
this.renderError(
|
|
@@ -6636,7 +6783,7 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
6636
6783
|
handle
|
|
6637
6784
|
);
|
|
6638
6785
|
}
|
|
6639
|
-
const shopSettingsPromise = client.query(
|
|
6786
|
+
const shopSettingsPromise = client.query(import_core6.SHOP_SETTINGS_QUERY, void 0, {
|
|
6640
6787
|
signal: controller.signal
|
|
6641
6788
|
}).catch(() => null);
|
|
6642
6789
|
await bundlePromise;
|
|
@@ -6649,11 +6796,11 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
6649
6796
|
const shopSettings = await shopSettingsPromise;
|
|
6650
6797
|
const customCss = shopSettings?.shop?.customCss?.value;
|
|
6651
6798
|
if (customCss) {
|
|
6652
|
-
(0,
|
|
6653
|
-
const sanitized = (0,
|
|
6799
|
+
(0, import_core6.injectCustomCss)(this.shopDomain, customCss);
|
|
6800
|
+
const sanitized = (0, import_core6.sanitizeCustomCss)(customCss);
|
|
6654
6801
|
if (sanitized.ok) this.shopCustomCss = sanitized.css;
|
|
6655
6802
|
}
|
|
6656
|
-
this.outOfStockBehavior = (0,
|
|
6803
|
+
this.outOfStockBehavior = (0, import_core6.parseOutOfStockBehavior)(
|
|
6657
6804
|
shopSettings?.shop?.outOfStockBehavior?.value
|
|
6658
6805
|
);
|
|
6659
6806
|
this.renderBundles();
|
|
@@ -6668,7 +6815,7 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
6668
6815
|
}
|
|
6669
6816
|
async fetchSingleBundle(client, signal) {
|
|
6670
6817
|
const data = await client.query(
|
|
6671
|
-
this.wrapQueryForContext(
|
|
6818
|
+
this.wrapQueryForContext(import_core6.BUNDLE_METAOBJECT_QUERY),
|
|
6672
6819
|
{ id: this.bundleGid },
|
|
6673
6820
|
{ signal }
|
|
6674
6821
|
);
|
|
@@ -6676,7 +6823,7 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
6676
6823
|
this.bundles = [];
|
|
6677
6824
|
return;
|
|
6678
6825
|
}
|
|
6679
|
-
const parsed = (0,
|
|
6826
|
+
const parsed = (0, import_core6.parseMetaobjectBundle)(
|
|
6680
6827
|
data.metaobject.id,
|
|
6681
6828
|
data.metaobject.fields
|
|
6682
6829
|
);
|
|
@@ -6684,7 +6831,7 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
6684
6831
|
}
|
|
6685
6832
|
async fetchProductBundles(client, signal, productHandle) {
|
|
6686
6833
|
const data = await client.query(
|
|
6687
|
-
this.wrapQueryForContext(
|
|
6834
|
+
this.wrapQueryForContext(import_core6.BUNDLES_FOR_PRODUCT_QUERY),
|
|
6688
6835
|
{ handle: productHandle },
|
|
6689
6836
|
{ signal }
|
|
6690
6837
|
);
|
|
@@ -6695,10 +6842,10 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
6695
6842
|
const refs = data.product.metafield?.references?.nodes ?? [];
|
|
6696
6843
|
const bundles = [];
|
|
6697
6844
|
for (const ref of refs) {
|
|
6698
|
-
const parsed = (0,
|
|
6845
|
+
const parsed = (0, import_core6.parseMetaobjectBundle)(ref.id, ref.fields);
|
|
6699
6846
|
if (parsed && !this.isMarketHidden(parsed)) bundles.push(parsed);
|
|
6700
6847
|
}
|
|
6701
|
-
this.bundles = bundles;
|
|
6848
|
+
this.bundles = (0, import_core6.resolveAbTests)(bundles, (0, import_core6.getVisitorId)());
|
|
6702
6849
|
}
|
|
6703
6850
|
/**
|
|
6704
6851
|
* Dispatch add-to-cart with a cancelable event, then — unless a listener
|
|
@@ -6728,7 +6875,7 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
6728
6875
|
*/
|
|
6729
6876
|
async defaultAddToCart(lines) {
|
|
6730
6877
|
if (typeof window === "undefined") return;
|
|
6731
|
-
const client = (0,
|
|
6878
|
+
const client = (0, import_core6.createStorefrontClient)({
|
|
6732
6879
|
shopDomain: this.shopDomain,
|
|
6733
6880
|
accessToken: this.storefrontToken
|
|
6734
6881
|
});
|
|
@@ -6739,7 +6886,7 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
6739
6886
|
let checkoutUrl = null;
|
|
6740
6887
|
if (existingCartId) {
|
|
6741
6888
|
const res = await client.query(
|
|
6742
|
-
|
|
6889
|
+
import_core6.CART_LINES_ADD_MUTATION,
|
|
6743
6890
|
{ cartId: existingCartId, lines }
|
|
6744
6891
|
);
|
|
6745
6892
|
const payload = res.cartLinesAdd;
|
|
@@ -6751,7 +6898,7 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
6751
6898
|
}
|
|
6752
6899
|
if (!checkoutUrl) {
|
|
6753
6900
|
const res = await client.query(
|
|
6754
|
-
|
|
6901
|
+
import_core6.CART_CREATE_MUTATION,
|
|
6755
6902
|
{ input: { lines } }
|
|
6756
6903
|
);
|
|
6757
6904
|
const payload = res.cartCreate;
|
|
@@ -6797,7 +6944,7 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
6797
6944
|
const price = variant ? parseFloat(variant.price.amount) : 0;
|
|
6798
6945
|
return sum + price * line.quantity;
|
|
6799
6946
|
}, 0);
|
|
6800
|
-
(0,
|
|
6947
|
+
(0, import_core6.reportAddToCart)(
|
|
6801
6948
|
{ shopDomain: this.shopDomain, appUrl: this.appUrl },
|
|
6802
6949
|
{
|
|
6803
6950
|
bundleGid: bundle.id,
|
|
@@ -6836,7 +6983,8 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
6836
6983
|
container.setAttribute("aria-label", bundle.title);
|
|
6837
6984
|
container.setAttribute("data-bundle-type", bundle.bundleType);
|
|
6838
6985
|
container.setAttribute("data-bundle-gid", bundle.id);
|
|
6839
|
-
(
|
|
6986
|
+
if (bundle.endsAt) container.setAttribute("data-ends-at", bundle.endsAt);
|
|
6987
|
+
(0, import_core7.applyWidgetConfigVars)(container, bundle.widgetConfig);
|
|
6840
6988
|
this.renderCleanups.push(trackInputMode(container));
|
|
6841
6989
|
const dispatch = (lines) => this.handleAddToCart(bundle, lines);
|
|
6842
6990
|
const registerCleanup = (fn) => this.renderCleanups.push(fn);
|
|
@@ -6856,7 +7004,8 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
6856
7004
|
bundle,
|
|
6857
7005
|
this.outOfStockBehavior,
|
|
6858
7006
|
dispatch,
|
|
6859
|
-
registerCleanup
|
|
7007
|
+
registerCleanup,
|
|
7008
|
+
this.currentProductHandle
|
|
6860
7009
|
);
|
|
6861
7010
|
break;
|
|
6862
7011
|
case "volume":
|
|
@@ -6902,8 +7051,8 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
6902
7051
|
}
|
|
6903
7052
|
setupImpressionFor(bundle, element) {
|
|
6904
7053
|
if (!this.analyticsEnabled || !this.appUrl) return;
|
|
6905
|
-
const cleanup = (0,
|
|
6906
|
-
(0,
|
|
7054
|
+
const cleanup = (0, import_core6.observeImpression)(element, () => {
|
|
7055
|
+
(0, import_core6.reportImpression)(
|
|
6907
7056
|
{ shopDomain: this.shopDomain, appUrl: this.appUrl },
|
|
6908
7057
|
{
|
|
6909
7058
|
bundleGid: bundle.id,
|