@lime-bundles/widget 4.6.4 → 4.6.6
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 +206 -74
- package/dist/index.js +206 -74
- package/dist/lime-bundle.global.js +127 -63
- package/dist/lime-bundle.global.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -257,6 +257,7 @@ function recalcPricing(container, products, formatMoney) {
|
|
|
257
257
|
savingsPercentEl.textContent = "(" + pct + "%)";
|
|
258
258
|
}
|
|
259
259
|
savingsBar.style.display = "";
|
|
260
|
+
savingsBar.classList.remove("lb-savings-pending");
|
|
260
261
|
} else {
|
|
261
262
|
savingsBar.style.display = "none";
|
|
262
263
|
}
|
|
@@ -380,6 +381,55 @@ function buildOptionGroups(container, product, selected) {
|
|
|
380
381
|
}
|
|
381
382
|
}
|
|
382
383
|
|
|
384
|
+
// ../render/src/product/placeholder.ts
|
|
385
|
+
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
386
|
+
var PLACEHOLDER_ATTR = "data-lb-placeholder";
|
|
387
|
+
var PLACEHOLDER_CLASS = "lb-thumb--placeholder";
|
|
388
|
+
function builtInMark() {
|
|
389
|
+
const svg = document.createElementNS(SVG_NS, "svg");
|
|
390
|
+
svg.setAttribute("class", "lb-bundle-placeholder-icon");
|
|
391
|
+
svg.setAttribute("viewBox", "0 0 48 48");
|
|
392
|
+
const rect = document.createElementNS(SVG_NS, "rect");
|
|
393
|
+
rect.setAttribute("x", "15");
|
|
394
|
+
rect.setAttribute("y", "15");
|
|
395
|
+
rect.setAttribute("width", "18");
|
|
396
|
+
rect.setAttribute("height", "18");
|
|
397
|
+
rect.setAttribute("rx", "2");
|
|
398
|
+
svg.appendChild(rect);
|
|
399
|
+
const dot = document.createElementNS(SVG_NS, "circle");
|
|
400
|
+
dot.setAttribute("cx", "20.5");
|
|
401
|
+
dot.setAttribute("cy", "20.5");
|
|
402
|
+
dot.setAttribute("r", "1.5");
|
|
403
|
+
svg.appendChild(dot);
|
|
404
|
+
const ridge = document.createElementNS(SVG_NS, "path");
|
|
405
|
+
ridge.setAttribute("d", "M33 27l-5-5L17 33");
|
|
406
|
+
svg.appendChild(ridge);
|
|
407
|
+
return svg;
|
|
408
|
+
}
|
|
409
|
+
var make = builtInMark;
|
|
410
|
+
function mark() {
|
|
411
|
+
const node = make();
|
|
412
|
+
const el2 = node.nodeType === 1 ? node : null;
|
|
413
|
+
if (el2) {
|
|
414
|
+
el2.setAttribute(PLACEHOLDER_ATTR, "");
|
|
415
|
+
el2.setAttribute("aria-hidden", "true");
|
|
416
|
+
el2.setAttribute("focusable", "false");
|
|
417
|
+
}
|
|
418
|
+
return node;
|
|
419
|
+
}
|
|
420
|
+
function showThumbnailPlaceholder(box2) {
|
|
421
|
+
const img = box2.querySelector("img");
|
|
422
|
+
if (img) img.remove();
|
|
423
|
+
box2.classList.add(PLACEHOLDER_CLASS);
|
|
424
|
+
if (box2.querySelector("[" + PLACEHOLDER_ATTR + "]")) return;
|
|
425
|
+
box2.appendChild(mark());
|
|
426
|
+
}
|
|
427
|
+
function hideThumbnailPlaceholder(box2) {
|
|
428
|
+
const existing = box2.querySelector("[" + PLACEHOLDER_ATTR + "]");
|
|
429
|
+
if (existing) existing.remove();
|
|
430
|
+
box2.classList.remove(PLACEHOLDER_CLASS);
|
|
431
|
+
}
|
|
432
|
+
|
|
383
433
|
// ../render/src/product/row.ts
|
|
384
434
|
var productImgSrc = /* @__PURE__ */ new WeakMap();
|
|
385
435
|
function updateThumbnail(row, variant, productImage) {
|
|
@@ -390,8 +440,12 @@ function updateThumbnail(row, variant, productImage) {
|
|
|
390
440
|
const seed = productImage || (img ? img.src : null);
|
|
391
441
|
if (seed) productImgSrc.set(row, seed);
|
|
392
442
|
}
|
|
393
|
-
const nextSrc = variant.image || productImgSrc.get(row) || null;
|
|
394
|
-
if (!nextSrc)
|
|
443
|
+
const nextSrc = variant && variant.image || productImgSrc.get(row) || null;
|
|
444
|
+
if (!nextSrc) {
|
|
445
|
+
showThumbnailPlaceholder(thumb);
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
hideThumbnailPlaceholder(thumb);
|
|
395
449
|
if (img) {
|
|
396
450
|
img.src = nextSrc;
|
|
397
451
|
img.srcset = "";
|
|
@@ -410,7 +464,10 @@ function updateInlineQuantity(row, qty) {
|
|
|
410
464
|
el2.textContent = "\xD7" + qty;
|
|
411
465
|
}
|
|
412
466
|
function applyVariant(row, variant, product, formatMoney) {
|
|
413
|
-
if (!variant)
|
|
467
|
+
if (!variant) {
|
|
468
|
+
updateThumbnail(row, null, product.featuredImage);
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
414
471
|
updateThumbnail(row, variant, product.featuredImage);
|
|
415
472
|
updateInlineQuantity(row, variant.quantity || product.quantity || 1);
|
|
416
473
|
const priceEl = row.querySelector("[data-product-price]");
|
|
@@ -460,8 +517,11 @@ function buildRowSkeleton(product, t, opts) {
|
|
|
460
517
|
if (opts.bogoRole) row.setAttribute("data-bogo-role", opts.bogoRole);
|
|
461
518
|
const thumb = box("div", "lb-bundle-thumbnail", { "data-thumbnail": "" });
|
|
462
519
|
const ratio = product.featuredImageRatio;
|
|
463
|
-
if (opts.thumbnailRatio === "original"
|
|
464
|
-
thumb.style.setProperty(
|
|
520
|
+
if (opts.thumbnailRatio === "original") {
|
|
521
|
+
thumb.style.setProperty(
|
|
522
|
+
"--lb-row-thumb-ratio",
|
|
523
|
+
String(ratio != null && ratio > 0 ? ratio : 1)
|
|
524
|
+
);
|
|
465
525
|
}
|
|
466
526
|
row.appendChild(thumb);
|
|
467
527
|
const info = box("div", "lb-bundle-product-info");
|
|
@@ -1426,17 +1486,25 @@ function buildPickerRow(p, rowIndex, ctx) {
|
|
|
1426
1486
|
addedBadge.textContent = t.addedItem || "Added";
|
|
1427
1487
|
addedBadge.hidden = true;
|
|
1428
1488
|
thumbDiv.appendChild(addedBadge);
|
|
1489
|
+
const paintThumb = (src) => {
|
|
1490
|
+
if (!src) {
|
|
1491
|
+
showThumbnailPlaceholder(thumbDiv);
|
|
1492
|
+
return;
|
|
1493
|
+
}
|
|
1494
|
+
hideThumbnailPlaceholder(thumbDiv);
|
|
1495
|
+
let img = thumbDiv.querySelector("img");
|
|
1496
|
+
if (!img) {
|
|
1497
|
+
img = document.createElement("img");
|
|
1498
|
+
img.sizes = PICKER_SIZES;
|
|
1499
|
+
img.alt = p.title;
|
|
1500
|
+
img.loading = "lazy";
|
|
1501
|
+
thumbDiv.appendChild(img);
|
|
1502
|
+
}
|
|
1503
|
+
img.src = imgWidth(src, PICKER_BASE_WIDTH);
|
|
1504
|
+
img.srcset = srcset(src, PICKER_WIDTHS);
|
|
1505
|
+
};
|
|
1429
1506
|
const firstAvailable = p.variants.find((v) => v.available) ?? null;
|
|
1430
|
-
|
|
1431
|
-
if (initialThumbSrc) {
|
|
1432
|
-
const img = document.createElement("img");
|
|
1433
|
-
img.src = imgWidth(initialThumbSrc, PICKER_BASE_WIDTH);
|
|
1434
|
-
img.srcset = srcset(initialThumbSrc, PICKER_WIDTHS);
|
|
1435
|
-
img.sizes = PICKER_SIZES;
|
|
1436
|
-
img.alt = p.title;
|
|
1437
|
-
img.loading = "lazy";
|
|
1438
|
-
thumbDiv.appendChild(img);
|
|
1439
|
-
}
|
|
1507
|
+
paintThumb(firstAvailable && firstAvailable.image || p.featuredImage);
|
|
1440
1508
|
row.appendChild(thumbDiv);
|
|
1441
1509
|
const infoDiv = document.createElement("div");
|
|
1442
1510
|
infoDiv.className = "lb-mix-match__modal-product-info";
|
|
@@ -1647,12 +1715,7 @@ function buildPickerRow(p, rowIndex, ctx) {
|
|
|
1647
1715
|
unitPriceEl.textContent = "";
|
|
1648
1716
|
unitPriceEl.hidden = true;
|
|
1649
1717
|
}
|
|
1650
|
-
|
|
1651
|
-
const imgSrc = v.image || p.featuredImage;
|
|
1652
|
-
if (rowImg && imgSrc) {
|
|
1653
|
-
rowImg.src = imgWidth(imgSrc, PICKER_BASE_WIDTH);
|
|
1654
|
-
rowImg.srcset = srcset(imgSrc, PICKER_WIDTHS);
|
|
1655
|
-
}
|
|
1718
|
+
paintThumb(v.image || p.featuredImage);
|
|
1656
1719
|
setBoundsForVariant?.(v, capacity.variantUnitsElsewhere(v.id));
|
|
1657
1720
|
if (v.options) recomputeDisabled(v.options);
|
|
1658
1721
|
refresh();
|
|
@@ -2230,6 +2293,8 @@ function buildSlotCard(item, trans, formatMoney, removable, onRemove, onEdit) {
|
|
|
2230
2293
|
img.alt = item.title;
|
|
2231
2294
|
img.loading = "lazy";
|
|
2232
2295
|
thumb.appendChild(img);
|
|
2296
|
+
} else {
|
|
2297
|
+
showThumbnailPlaceholder(thumb);
|
|
2233
2298
|
}
|
|
2234
2299
|
card.appendChild(thumb);
|
|
2235
2300
|
const info = document.createElement("div");
|
|
@@ -2458,7 +2523,7 @@ function seedSelection(eligibleProducts, rulesMap, requiredQty, courtesy) {
|
|
|
2458
2523
|
required.push(pick(p, v2, Math.max(1, rule.min)));
|
|
2459
2524
|
}
|
|
2460
2525
|
if (required.length || !courtesy?.enabled) return required;
|
|
2461
|
-
const qualifies = (p) => p.available && ruleFor(p.id, rulesMap).min <= requiredQty;
|
|
2526
|
+
const qualifies = (p) => p.available && ruleFor(p.id, rulesMap).min <= requiredQty && firstAvailable(p) !== null;
|
|
2462
2527
|
const seed = (courtesy.currentProductId != null ? eligibleProducts.find(
|
|
2463
2528
|
(p) => p.id === courtesy.currentProductId && qualifies(p)
|
|
2464
2529
|
) : null) ?? eligibleProducts.find(qualifies);
|
|
@@ -2496,6 +2561,7 @@ function el(tag, className, attrs = {}) {
|
|
|
2496
2561
|
}
|
|
2497
2562
|
function buildPickerModal(opts) {
|
|
2498
2563
|
const titleId = "lb-modal-title-" + opts.domId;
|
|
2564
|
+
const s = opts.strings || {};
|
|
2499
2565
|
const overlay = el("div", "lb-mix-match__modal-overlay", {
|
|
2500
2566
|
"data-modal-overlay": "",
|
|
2501
2567
|
"data-bundle-gid": opts.bundleGid,
|
|
@@ -2516,7 +2582,7 @@ function buildPickerModal(opts) {
|
|
|
2516
2582
|
const heading = el("div", "lb-mix-match__modal-heading");
|
|
2517
2583
|
const title = el("h4", "lb-mix-match__modal-title", { id: titleId });
|
|
2518
2584
|
if (opts.wizard) title.setAttribute("tabindex", "-1");
|
|
2519
|
-
title.textContent = "Add to your bundle";
|
|
2585
|
+
title.textContent = s.addToBundle || "Add to your bundle";
|
|
2520
2586
|
heading.appendChild(title);
|
|
2521
2587
|
heading.appendChild(
|
|
2522
2588
|
el("p", "lb-mix-match__modal-subtitle", { "data-modal-subtitle": "" })
|
|
@@ -2525,7 +2591,7 @@ function buildPickerModal(opts) {
|
|
|
2525
2591
|
const close = el("button", "lb-mix-match__modal-close", {
|
|
2526
2592
|
type: "button",
|
|
2527
2593
|
"data-modal-close": "",
|
|
2528
|
-
"aria-label": "Close"
|
|
2594
|
+
"aria-label": s.closeModal || "Close"
|
|
2529
2595
|
});
|
|
2530
2596
|
close.appendChild(
|
|
2531
2597
|
icon([
|
|
@@ -2566,15 +2632,15 @@ function buildPickerModal(opts) {
|
|
|
2566
2632
|
type: "text",
|
|
2567
2633
|
"data-modal-search": "",
|
|
2568
2634
|
role: "searchbox",
|
|
2569
|
-
"aria-label": "Search products",
|
|
2570
|
-
placeholder: "Search products",
|
|
2635
|
+
"aria-label": s.searchProducts || "Search products",
|
|
2636
|
+
placeholder: s.searchProducts || "Search products",
|
|
2571
2637
|
autocomplete: "off"
|
|
2572
2638
|
});
|
|
2573
2639
|
search.appendChild(input);
|
|
2574
2640
|
const clear = el("button", "lb-mix-match__modal-search-clear", {
|
|
2575
2641
|
type: "button",
|
|
2576
2642
|
"data-modal-search-clear": "",
|
|
2577
|
-
"aria-label": "Clear search",
|
|
2643
|
+
"aria-label": s.clearSearch || "Clear search",
|
|
2578
2644
|
style: "display: none;"
|
|
2579
2645
|
});
|
|
2580
2646
|
clear.appendChild(
|
|
@@ -2603,7 +2669,7 @@ function buildPickerModal(opts) {
|
|
|
2603
2669
|
style: "display: none;"
|
|
2604
2670
|
});
|
|
2605
2671
|
const emptyText = document.createElement("p");
|
|
2606
|
-
emptyText.textContent = "No products match your search";
|
|
2672
|
+
emptyText.textContent = s.noSearchResults || "No products match your search";
|
|
2607
2673
|
empty.appendChild(emptyText);
|
|
2608
2674
|
dialog.appendChild(empty);
|
|
2609
2675
|
dialog.appendChild(
|
|
@@ -2622,7 +2688,7 @@ function buildPickerModal(opts) {
|
|
|
2622
2688
|
"data-modal-back": "",
|
|
2623
2689
|
style: "display: none;"
|
|
2624
2690
|
});
|
|
2625
|
-
back.textContent = "Back";
|
|
2691
|
+
back.textContent = s.back || "Back";
|
|
2626
2692
|
footer.appendChild(back);
|
|
2627
2693
|
}
|
|
2628
2694
|
footer.appendChild(
|
|
@@ -2637,7 +2703,7 @@ function buildPickerModal(opts) {
|
|
|
2637
2703
|
"data-modal-next": "",
|
|
2638
2704
|
style: "display: none;"
|
|
2639
2705
|
});
|
|
2640
|
-
next.textContent = "Next";
|
|
2706
|
+
next.textContent = s.next || "Next";
|
|
2641
2707
|
footer.appendChild(next);
|
|
2642
2708
|
}
|
|
2643
2709
|
const done = el("button", "lb-mix-match__modal-done", {
|
|
@@ -2645,7 +2711,7 @@ function buildPickerModal(opts) {
|
|
|
2645
2711
|
"data-modal-done": "",
|
|
2646
2712
|
...opts.wizard ? { style: "display: none;" } : {}
|
|
2647
2713
|
});
|
|
2648
|
-
done.textContent = "Done";
|
|
2714
|
+
done.textContent = s.done || "Done";
|
|
2649
2715
|
footer.appendChild(done);
|
|
2650
2716
|
dialog.appendChild(footer);
|
|
2651
2717
|
overlay.appendChild(dialog);
|
|
@@ -2963,6 +3029,7 @@ function selectTier(container, allTiers, basePrice, discountType, index, transla
|
|
|
2963
3029
|
savingsPercentEl.textContent = "(" + savingsPct + "%)";
|
|
2964
3030
|
}
|
|
2965
3031
|
savingsBar.style.display = "";
|
|
3032
|
+
savingsBar.classList.remove("lb-savings-pending");
|
|
2966
3033
|
} else {
|
|
2967
3034
|
savingsBar.style.display = "none";
|
|
2968
3035
|
}
|
|
@@ -3146,6 +3213,7 @@ function recalcPricing2(container, sides, percent, buyQty, getQty, formatMoney)
|
|
|
3146
3213
|
savingsPercentEl.textContent = "(" + pct + "%)";
|
|
3147
3214
|
}
|
|
3148
3215
|
savingsBar.style.display = "";
|
|
3216
|
+
savingsBar.classList.remove("lb-savings-pending");
|
|
3149
3217
|
} else {
|
|
3150
3218
|
savingsBar.style.display = "none";
|
|
3151
3219
|
}
|
|
@@ -4532,6 +4600,15 @@ var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle
|
|
|
4532
4600
|
display: block;
|
|
4533
4601
|
}
|
|
4534
4602
|
|
|
4603
|
+
/* Same reset, one more victim. A thumbnail is emitted empty and filled at
|
|
4604
|
+
hydration, so between the two it matched \`div:empty\` and vanished \u2014 taking
|
|
4605
|
+
the row's gap with it and starting that title 72px left of every other
|
|
4606
|
+
row's (issue #552). The box holds its place either way now: the product's
|
|
4607
|
+
image lands in it, or the placeholder mark does. */
|
|
4608
|
+
.lb-bundle-thumbnail:empty {
|
|
4609
|
+
display: flex;
|
|
4610
|
+
}
|
|
4611
|
+
|
|
4535
4612
|
/* Divider */
|
|
4536
4613
|
.lb-bundle-divider {
|
|
4537
4614
|
height: var(--lb-border-width);
|
|
@@ -4570,11 +4647,6 @@ var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle
|
|
|
4570
4647
|
object-fit: var(--lb-thumbnail-img-fit, cover);
|
|
4571
4648
|
}
|
|
4572
4649
|
|
|
4573
|
-
.lb-bundle-thumbnail svg {
|
|
4574
|
-
width: 28px;
|
|
4575
|
-
height: 28px;
|
|
4576
|
-
color: color-mix(in srgb, var(--lb-text) 35%, transparent);
|
|
4577
|
-
}
|
|
4578
4650
|
|
|
4579
4651
|
.lb-bundle-product-info {
|
|
4580
4652
|
flex: 1;
|
|
@@ -4698,6 +4770,43 @@ a.lb-bundle-product-name:focus-visible {
|
|
|
4698
4770
|
gap: 4px;
|
|
4699
4771
|
}
|
|
4700
4772
|
|
|
4773
|
+
/* Variant picker select \u2014 styled to match the variant badge aesthetic.
|
|
4774
|
+
Sits inside .lb-bundle-variant-option-group so vertical spacing is owned
|
|
4775
|
+
by the group/groups flex gap, not the select itself.
|
|
4776
|
+
|
|
4777
|
+
Lives here, not in bundle-fixed.css, because every widget that renders an
|
|
4778
|
+
option group needs it and only the fixed widget loads that stylesheet: a
|
|
4779
|
+
page carrying just a Buy X Get Y bundle rendered raw browser selects, and
|
|
4780
|
+
the option-group height reservation (sized for the styled control) was
|
|
4781
|
+
wrong by 14px a group, which shifted the row on hydration.
|
|
4782
|
+
The same split applies to the headless package, which injects per type. */
|
|
4783
|
+
.lb-bundle-variant-select {
|
|
4784
|
+
display: inline-block;
|
|
4785
|
+
border: var(--lb-border-width) solid var(--lb-border);
|
|
4786
|
+
border-radius: var(--lb-radius);
|
|
4787
|
+
padding: 8px 32px 8px 12px;
|
|
4788
|
+
font-size: 12px;
|
|
4789
|
+
line-height: 16px;
|
|
4790
|
+
color: var(--lb-text);
|
|
4791
|
+
background: var(--lb-bg);
|
|
4792
|
+
font-family: inherit;
|
|
4793
|
+
cursor: pointer;
|
|
4794
|
+
appearance: none;
|
|
4795
|
+
-webkit-appearance: none;
|
|
4796
|
+
background-image: var(--lb-variant-chevron);
|
|
4797
|
+
background-repeat: no-repeat;
|
|
4798
|
+
background-position: right 8px center;
|
|
4799
|
+
background-size: 12px;
|
|
4800
|
+
width: 50%;
|
|
4801
|
+
max-width: 50%;
|
|
4802
|
+
}
|
|
4803
|
+
|
|
4804
|
+
.lb-bundle-variant-select:focus-visible {
|
|
4805
|
+
outline: 2px solid var(--lb-primary-color);
|
|
4806
|
+
outline-offset: 2px;
|
|
4807
|
+
box-shadow: none;
|
|
4808
|
+
}
|
|
4809
|
+
|
|
4701
4810
|
.lb-bundle-variant-option-label {
|
|
4702
4811
|
display: block;
|
|
4703
4812
|
margin: 0;
|
|
@@ -4979,15 +5088,33 @@ a.lb-bundle-product-name:focus-visible {
|
|
|
4979
5088
|
border: 0 !important;
|
|
4980
5089
|
}
|
|
4981
5090
|
|
|
4982
|
-
/*
|
|
5091
|
+
/* Missing-image placeholder.
|
|
5092
|
+
Two marks share these rules: Shopify's own \`placeholder_svg_tag\`
|
|
5093
|
+
illustration, which the theme scripts clone out of the <template> in
|
|
5094
|
+
bundle-widget.liquid, and the line glyph the headless renderer falls back to
|
|
5095
|
+
when there is no Liquid to supply one. */
|
|
5096
|
+
.lb-thumb--placeholder > [data-lb-placeholder] {
|
|
5097
|
+
display: block;
|
|
5098
|
+
width: 100%;
|
|
5099
|
+
/* The mark carries the box's height, not the other way round: the
|
|
5100
|
+
"original" thumbnail ratio sizes a box to its image's proportions and an
|
|
5101
|
+
imageless row has no image, so without this the box would be 60px by
|
|
5102
|
+
nothing. A box that already has a ratio caps the mark instead. */
|
|
5103
|
+
height: auto;
|
|
5104
|
+
max-height: 100%;
|
|
5105
|
+
aspect-ratio: 1 / 1;
|
|
5106
|
+
}
|
|
5107
|
+
|
|
4983
5108
|
.lb-bundle-placeholder-icon {
|
|
4984
|
-
width: 28px;
|
|
4985
|
-
height: 28px;
|
|
4986
5109
|
stroke: color-mix(in srgb, var(--lb-text) 35%, transparent);
|
|
4987
5110
|
stroke-width: 1.5;
|
|
4988
5111
|
fill: none;
|
|
4989
5112
|
}
|
|
4990
5113
|
|
|
5114
|
+
.lb-bundle-placeholder-svg {
|
|
5115
|
+
fill: color-mix(in srgb, var(--lb-text) 22%, transparent);
|
|
5116
|
+
}
|
|
5117
|
+
|
|
4991
5118
|
/* Out-of-stock product row */
|
|
4992
5119
|
.lb-bundle-product-row--oos {
|
|
4993
5120
|
opacity: 0.5;
|
|
@@ -5019,6 +5146,16 @@ a.lb-bundle-product-name:focus-visible {
|
|
|
5019
5146
|
white-space: nowrap;
|
|
5020
5147
|
}
|
|
5021
5148
|
|
|
5149
|
+
/* The savings line is laid out from first paint and revealed on hydration,
|
|
5150
|
+
rather than being display:none until then.
|
|
5151
|
+
Its amounts are money strings the server cannot know, so filling them in
|
|
5152
|
+
place moves whatever shares the line; revealing an already-laid-out box
|
|
5153
|
+
moves nothing. The band around it is vertically centred, so reserving the
|
|
5154
|
+
line costs no height of its own. JS drops the class in updatePricing. */
|
|
5155
|
+
.lb-bundle-savings-line.lb-savings-pending {
|
|
5156
|
+
visibility: hidden;
|
|
5157
|
+
}
|
|
5158
|
+
|
|
5022
5159
|
/* A/B test: hide save badge until JS swaps the label (prevents flash of default) */
|
|
5023
5160
|
.lb-ab-pending {
|
|
5024
5161
|
visibility: hidden;
|
|
@@ -5036,27 +5173,43 @@ a.lb-bundle-product-name:focus-visible {
|
|
|
5036
5173
|
The title is the one box NOT reserved this way: text wrapping depends on the
|
|
5037
5174
|
merchant's font, so it is server-rendered and its height is simply real. */
|
|
5038
5175
|
|
|
5176
|
+
/* A zero-width space, not a pixel height.
|
|
5177
|
+
These boxes are one line of text once JS fills them, and their height is
|
|
5178
|
+
whatever the merchant's font makes of \`line-height: normal\` \u2014 which the
|
|
5179
|
+
reset at the top of this file forces on every descendant, overriding the
|
|
5180
|
+
per-element line-heights above it. A hardcoded min-height therefore has to
|
|
5181
|
+
guess, and guessed 3px too tall: the row shrank on hydration in every theme.
|
|
5182
|
+
An empty line box measures exactly what the filled one will. */
|
|
5039
5183
|
.lb-bundle-product-price:empty {
|
|
5040
5184
|
display: inline-block;
|
|
5041
|
-
min-height: 20px;
|
|
5042
5185
|
}
|
|
5043
5186
|
|
|
5044
5187
|
.lb-bundle-variant-badge:empty {
|
|
5045
5188
|
display: block;
|
|
5046
|
-
min-height: 20px;
|
|
5047
5189
|
}
|
|
5048
5190
|
|
|
5049
5191
|
.lb-bundle-product-unit-price:empty {
|
|
5050
5192
|
display: block;
|
|
5051
|
-
|
|
5193
|
+
}
|
|
5194
|
+
|
|
5195
|
+
.lb-bundle-product-price:empty::before,
|
|
5196
|
+
.lb-bundle-variant-badge:empty::before,
|
|
5197
|
+
.lb-bundle-product-unit-price:empty::before,
|
|
5198
|
+
.lb-bundle-qty-inline:empty::before,
|
|
5199
|
+
.lb-bundle-sale-price:empty::before,
|
|
5200
|
+
.lb-bundle-compare-price:empty::before {
|
|
5201
|
+
content: "\\200B";
|
|
5052
5202
|
}
|
|
5053
5203
|
|
|
5054
5204
|
/* Label (16) + gap (4) + trigger (8 + 16 + 8 padding/line-height) per group,
|
|
5055
5205
|
plus the 8px gap between groups. --lb-row-option-count is set per row by
|
|
5056
|
-
Liquid, which knows how many options the product has.
|
|
5206
|
+
Liquid, which knows how many options the product has.
|
|
5207
|
+
|
|
5208
|
+
The trigger is border-box, so its border is already inside that 52px; the
|
|
5209
|
+
calc used to add it again and reserved 2px per group too much. */
|
|
5057
5210
|
.lb-bundle-variant-option-groups:empty {
|
|
5058
5211
|
min-height: calc(
|
|
5059
|
-
var(--lb-row-option-count, 1) *
|
|
5212
|
+
var(--lb-row-option-count, 1) * 52px +
|
|
5060
5213
|
(var(--lb-row-option-count, 1) - 1) * 8px
|
|
5061
5214
|
);
|
|
5062
5215
|
}
|
|
@@ -5136,36 +5289,6 @@ var BUNDLE_FIXED_CSS = `/* Lime Bundles \u2014 Fixed bundle styles */
|
|
|
5136
5289
|
font-variant-numeric: tabular-nums;
|
|
5137
5290
|
white-space: nowrap;
|
|
5138
5291
|
}
|
|
5139
|
-
|
|
5140
|
-
/* Variant picker select \u2014 styled to match the variant badge aesthetic.
|
|
5141
|
-
Sits inside .lb-bundle-variant-option-group so vertical spacing is owned
|
|
5142
|
-
by the group/groups flex gap, not the select itself. */
|
|
5143
|
-
.lb-bundle-variant-select {
|
|
5144
|
-
display: inline-block;
|
|
5145
|
-
border: var(--lb-border-width) solid var(--lb-border);
|
|
5146
|
-
border-radius: var(--lb-radius);
|
|
5147
|
-
padding: 8px 32px 8px 12px;
|
|
5148
|
-
font-size: 12px;
|
|
5149
|
-
line-height: 16px;
|
|
5150
|
-
color: var(--lb-text);
|
|
5151
|
-
background: var(--lb-bg);
|
|
5152
|
-
font-family: inherit;
|
|
5153
|
-
cursor: pointer;
|
|
5154
|
-
appearance: none;
|
|
5155
|
-
-webkit-appearance: none;
|
|
5156
|
-
background-image: var(--lb-variant-chevron);
|
|
5157
|
-
background-repeat: no-repeat;
|
|
5158
|
-
background-position: right 8px center;
|
|
5159
|
-
background-size: 12px;
|
|
5160
|
-
width: 50%;
|
|
5161
|
-
max-width: 50%;
|
|
5162
|
-
}
|
|
5163
|
-
|
|
5164
|
-
.lb-bundle-variant-select:focus-visible {
|
|
5165
|
-
outline: 2px solid var(--lb-primary-color);
|
|
5166
|
-
outline-offset: 2px;
|
|
5167
|
-
box-shadow: none;
|
|
5168
|
-
}
|
|
5169
5292
|
`;
|
|
5170
5293
|
var BUNDLE_MIX_MATCH_CSS = `/* Lime Bundles \u2014 Mix & Match styles */
|
|
5171
5294
|
|
|
@@ -6488,6 +6611,15 @@ var BUNDLE_BOGO_CSS = `/* Lime Bundles \u2014 BOGO (Buy X Get Y) bundle styles *
|
|
|
6488
6611
|
text-decoration: line-through;
|
|
6489
6612
|
opacity: 0.6;
|
|
6490
6613
|
}
|
|
6614
|
+
|
|
6615
|
+
/* The reward row's struck original is emitted empty and filled on hydration,
|
|
6616
|
+
so anything sharing its line moves when it appears. The count is the only
|
|
6617
|
+
such thing, and it is a count, not part of the price phrase: pinning it to
|
|
6618
|
+
the row's right edge makes its position independent of the price text \u2014 the
|
|
6619
|
+
same right-slot treatment the fixed widget gives its quantity chip. */
|
|
6620
|
+
.lb-bogo .lb-bundle-qty-inline {
|
|
6621
|
+
margin-left: auto;
|
|
6622
|
+
}
|
|
6491
6623
|
`;
|
|
6492
6624
|
var BUNDLE_MULTI_STEP_CSS = `/**
|
|
6493
6625
|
* Lime Bundles \u2014 Multi-step bundle widget styles (wizard chrome ONLY).
|