@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.js
CHANGED
|
@@ -256,6 +256,7 @@ function recalcPricing(container, products, formatMoney) {
|
|
|
256
256
|
savingsPercentEl.textContent = "(" + pct + "%)";
|
|
257
257
|
}
|
|
258
258
|
savingsBar.style.display = "";
|
|
259
|
+
savingsBar.classList.remove("lb-savings-pending");
|
|
259
260
|
} else {
|
|
260
261
|
savingsBar.style.display = "none";
|
|
261
262
|
}
|
|
@@ -379,6 +380,55 @@ function buildOptionGroups(container, product, selected) {
|
|
|
379
380
|
}
|
|
380
381
|
}
|
|
381
382
|
|
|
383
|
+
// ../render/src/product/placeholder.ts
|
|
384
|
+
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
385
|
+
var PLACEHOLDER_ATTR = "data-lb-placeholder";
|
|
386
|
+
var PLACEHOLDER_CLASS = "lb-thumb--placeholder";
|
|
387
|
+
function builtInMark() {
|
|
388
|
+
const svg = document.createElementNS(SVG_NS, "svg");
|
|
389
|
+
svg.setAttribute("class", "lb-bundle-placeholder-icon");
|
|
390
|
+
svg.setAttribute("viewBox", "0 0 48 48");
|
|
391
|
+
const rect = document.createElementNS(SVG_NS, "rect");
|
|
392
|
+
rect.setAttribute("x", "15");
|
|
393
|
+
rect.setAttribute("y", "15");
|
|
394
|
+
rect.setAttribute("width", "18");
|
|
395
|
+
rect.setAttribute("height", "18");
|
|
396
|
+
rect.setAttribute("rx", "2");
|
|
397
|
+
svg.appendChild(rect);
|
|
398
|
+
const dot = document.createElementNS(SVG_NS, "circle");
|
|
399
|
+
dot.setAttribute("cx", "20.5");
|
|
400
|
+
dot.setAttribute("cy", "20.5");
|
|
401
|
+
dot.setAttribute("r", "1.5");
|
|
402
|
+
svg.appendChild(dot);
|
|
403
|
+
const ridge = document.createElementNS(SVG_NS, "path");
|
|
404
|
+
ridge.setAttribute("d", "M33 27l-5-5L17 33");
|
|
405
|
+
svg.appendChild(ridge);
|
|
406
|
+
return svg;
|
|
407
|
+
}
|
|
408
|
+
var make = builtInMark;
|
|
409
|
+
function mark() {
|
|
410
|
+
const node = make();
|
|
411
|
+
const el2 = node.nodeType === 1 ? node : null;
|
|
412
|
+
if (el2) {
|
|
413
|
+
el2.setAttribute(PLACEHOLDER_ATTR, "");
|
|
414
|
+
el2.setAttribute("aria-hidden", "true");
|
|
415
|
+
el2.setAttribute("focusable", "false");
|
|
416
|
+
}
|
|
417
|
+
return node;
|
|
418
|
+
}
|
|
419
|
+
function showThumbnailPlaceholder(box2) {
|
|
420
|
+
const img = box2.querySelector("img");
|
|
421
|
+
if (img) img.remove();
|
|
422
|
+
box2.classList.add(PLACEHOLDER_CLASS);
|
|
423
|
+
if (box2.querySelector("[" + PLACEHOLDER_ATTR + "]")) return;
|
|
424
|
+
box2.appendChild(mark());
|
|
425
|
+
}
|
|
426
|
+
function hideThumbnailPlaceholder(box2) {
|
|
427
|
+
const existing = box2.querySelector("[" + PLACEHOLDER_ATTR + "]");
|
|
428
|
+
if (existing) existing.remove();
|
|
429
|
+
box2.classList.remove(PLACEHOLDER_CLASS);
|
|
430
|
+
}
|
|
431
|
+
|
|
382
432
|
// ../render/src/product/row.ts
|
|
383
433
|
var productImgSrc = /* @__PURE__ */ new WeakMap();
|
|
384
434
|
function updateThumbnail(row, variant, productImage) {
|
|
@@ -389,8 +439,12 @@ function updateThumbnail(row, variant, productImage) {
|
|
|
389
439
|
const seed = productImage || (img ? img.src : null);
|
|
390
440
|
if (seed) productImgSrc.set(row, seed);
|
|
391
441
|
}
|
|
392
|
-
const nextSrc = variant.image || productImgSrc.get(row) || null;
|
|
393
|
-
if (!nextSrc)
|
|
442
|
+
const nextSrc = variant && variant.image || productImgSrc.get(row) || null;
|
|
443
|
+
if (!nextSrc) {
|
|
444
|
+
showThumbnailPlaceholder(thumb);
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
hideThumbnailPlaceholder(thumb);
|
|
394
448
|
if (img) {
|
|
395
449
|
img.src = nextSrc;
|
|
396
450
|
img.srcset = "";
|
|
@@ -409,7 +463,10 @@ function updateInlineQuantity(row, qty) {
|
|
|
409
463
|
el2.textContent = "\xD7" + qty;
|
|
410
464
|
}
|
|
411
465
|
function applyVariant(row, variant, product, formatMoney) {
|
|
412
|
-
if (!variant)
|
|
466
|
+
if (!variant) {
|
|
467
|
+
updateThumbnail(row, null, product.featuredImage);
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
413
470
|
updateThumbnail(row, variant, product.featuredImage);
|
|
414
471
|
updateInlineQuantity(row, variant.quantity || product.quantity || 1);
|
|
415
472
|
const priceEl = row.querySelector("[data-product-price]");
|
|
@@ -459,8 +516,11 @@ function buildRowSkeleton(product, t, opts) {
|
|
|
459
516
|
if (opts.bogoRole) row.setAttribute("data-bogo-role", opts.bogoRole);
|
|
460
517
|
const thumb = box("div", "lb-bundle-thumbnail", { "data-thumbnail": "" });
|
|
461
518
|
const ratio = product.featuredImageRatio;
|
|
462
|
-
if (opts.thumbnailRatio === "original"
|
|
463
|
-
thumb.style.setProperty(
|
|
519
|
+
if (opts.thumbnailRatio === "original") {
|
|
520
|
+
thumb.style.setProperty(
|
|
521
|
+
"--lb-row-thumb-ratio",
|
|
522
|
+
String(ratio != null && ratio > 0 ? ratio : 1)
|
|
523
|
+
);
|
|
464
524
|
}
|
|
465
525
|
row.appendChild(thumb);
|
|
466
526
|
const info = box("div", "lb-bundle-product-info");
|
|
@@ -1425,17 +1485,25 @@ function buildPickerRow(p, rowIndex, ctx) {
|
|
|
1425
1485
|
addedBadge.textContent = t.addedItem || "Added";
|
|
1426
1486
|
addedBadge.hidden = true;
|
|
1427
1487
|
thumbDiv.appendChild(addedBadge);
|
|
1488
|
+
const paintThumb = (src) => {
|
|
1489
|
+
if (!src) {
|
|
1490
|
+
showThumbnailPlaceholder(thumbDiv);
|
|
1491
|
+
return;
|
|
1492
|
+
}
|
|
1493
|
+
hideThumbnailPlaceholder(thumbDiv);
|
|
1494
|
+
let img = thumbDiv.querySelector("img");
|
|
1495
|
+
if (!img) {
|
|
1496
|
+
img = document.createElement("img");
|
|
1497
|
+
img.sizes = PICKER_SIZES;
|
|
1498
|
+
img.alt = p.title;
|
|
1499
|
+
img.loading = "lazy";
|
|
1500
|
+
thumbDiv.appendChild(img);
|
|
1501
|
+
}
|
|
1502
|
+
img.src = imgWidth(src, PICKER_BASE_WIDTH);
|
|
1503
|
+
img.srcset = srcset(src, PICKER_WIDTHS);
|
|
1504
|
+
};
|
|
1428
1505
|
const firstAvailable = p.variants.find((v) => v.available) ?? null;
|
|
1429
|
-
|
|
1430
|
-
if (initialThumbSrc) {
|
|
1431
|
-
const img = document.createElement("img");
|
|
1432
|
-
img.src = imgWidth(initialThumbSrc, PICKER_BASE_WIDTH);
|
|
1433
|
-
img.srcset = srcset(initialThumbSrc, PICKER_WIDTHS);
|
|
1434
|
-
img.sizes = PICKER_SIZES;
|
|
1435
|
-
img.alt = p.title;
|
|
1436
|
-
img.loading = "lazy";
|
|
1437
|
-
thumbDiv.appendChild(img);
|
|
1438
|
-
}
|
|
1506
|
+
paintThumb(firstAvailable && firstAvailable.image || p.featuredImage);
|
|
1439
1507
|
row.appendChild(thumbDiv);
|
|
1440
1508
|
const infoDiv = document.createElement("div");
|
|
1441
1509
|
infoDiv.className = "lb-mix-match__modal-product-info";
|
|
@@ -1646,12 +1714,7 @@ function buildPickerRow(p, rowIndex, ctx) {
|
|
|
1646
1714
|
unitPriceEl.textContent = "";
|
|
1647
1715
|
unitPriceEl.hidden = true;
|
|
1648
1716
|
}
|
|
1649
|
-
|
|
1650
|
-
const imgSrc = v.image || p.featuredImage;
|
|
1651
|
-
if (rowImg && imgSrc) {
|
|
1652
|
-
rowImg.src = imgWidth(imgSrc, PICKER_BASE_WIDTH);
|
|
1653
|
-
rowImg.srcset = srcset(imgSrc, PICKER_WIDTHS);
|
|
1654
|
-
}
|
|
1717
|
+
paintThumb(v.image || p.featuredImage);
|
|
1655
1718
|
setBoundsForVariant?.(v, capacity.variantUnitsElsewhere(v.id));
|
|
1656
1719
|
if (v.options) recomputeDisabled(v.options);
|
|
1657
1720
|
refresh();
|
|
@@ -2229,6 +2292,8 @@ function buildSlotCard(item, trans, formatMoney, removable, onRemove, onEdit) {
|
|
|
2229
2292
|
img.alt = item.title;
|
|
2230
2293
|
img.loading = "lazy";
|
|
2231
2294
|
thumb.appendChild(img);
|
|
2295
|
+
} else {
|
|
2296
|
+
showThumbnailPlaceholder(thumb);
|
|
2232
2297
|
}
|
|
2233
2298
|
card.appendChild(thumb);
|
|
2234
2299
|
const info = document.createElement("div");
|
|
@@ -2457,7 +2522,7 @@ function seedSelection(eligibleProducts, rulesMap, requiredQty, courtesy) {
|
|
|
2457
2522
|
required.push(pick(p, v2, Math.max(1, rule.min)));
|
|
2458
2523
|
}
|
|
2459
2524
|
if (required.length || !courtesy?.enabled) return required;
|
|
2460
|
-
const qualifies = (p) => p.available && ruleFor(p.id, rulesMap).min <= requiredQty;
|
|
2525
|
+
const qualifies = (p) => p.available && ruleFor(p.id, rulesMap).min <= requiredQty && firstAvailable(p) !== null;
|
|
2461
2526
|
const seed = (courtesy.currentProductId != null ? eligibleProducts.find(
|
|
2462
2527
|
(p) => p.id === courtesy.currentProductId && qualifies(p)
|
|
2463
2528
|
) : null) ?? eligibleProducts.find(qualifies);
|
|
@@ -2495,6 +2560,7 @@ function el(tag, className, attrs = {}) {
|
|
|
2495
2560
|
}
|
|
2496
2561
|
function buildPickerModal(opts) {
|
|
2497
2562
|
const titleId = "lb-modal-title-" + opts.domId;
|
|
2563
|
+
const s = opts.strings || {};
|
|
2498
2564
|
const overlay = el("div", "lb-mix-match__modal-overlay", {
|
|
2499
2565
|
"data-modal-overlay": "",
|
|
2500
2566
|
"data-bundle-gid": opts.bundleGid,
|
|
@@ -2515,7 +2581,7 @@ function buildPickerModal(opts) {
|
|
|
2515
2581
|
const heading = el("div", "lb-mix-match__modal-heading");
|
|
2516
2582
|
const title = el("h4", "lb-mix-match__modal-title", { id: titleId });
|
|
2517
2583
|
if (opts.wizard) title.setAttribute("tabindex", "-1");
|
|
2518
|
-
title.textContent = "Add to your bundle";
|
|
2584
|
+
title.textContent = s.addToBundle || "Add to your bundle";
|
|
2519
2585
|
heading.appendChild(title);
|
|
2520
2586
|
heading.appendChild(
|
|
2521
2587
|
el("p", "lb-mix-match__modal-subtitle", { "data-modal-subtitle": "" })
|
|
@@ -2524,7 +2590,7 @@ function buildPickerModal(opts) {
|
|
|
2524
2590
|
const close = el("button", "lb-mix-match__modal-close", {
|
|
2525
2591
|
type: "button",
|
|
2526
2592
|
"data-modal-close": "",
|
|
2527
|
-
"aria-label": "Close"
|
|
2593
|
+
"aria-label": s.closeModal || "Close"
|
|
2528
2594
|
});
|
|
2529
2595
|
close.appendChild(
|
|
2530
2596
|
icon([
|
|
@@ -2565,15 +2631,15 @@ function buildPickerModal(opts) {
|
|
|
2565
2631
|
type: "text",
|
|
2566
2632
|
"data-modal-search": "",
|
|
2567
2633
|
role: "searchbox",
|
|
2568
|
-
"aria-label": "Search products",
|
|
2569
|
-
placeholder: "Search products",
|
|
2634
|
+
"aria-label": s.searchProducts || "Search products",
|
|
2635
|
+
placeholder: s.searchProducts || "Search products",
|
|
2570
2636
|
autocomplete: "off"
|
|
2571
2637
|
});
|
|
2572
2638
|
search.appendChild(input);
|
|
2573
2639
|
const clear = el("button", "lb-mix-match__modal-search-clear", {
|
|
2574
2640
|
type: "button",
|
|
2575
2641
|
"data-modal-search-clear": "",
|
|
2576
|
-
"aria-label": "Clear search",
|
|
2642
|
+
"aria-label": s.clearSearch || "Clear search",
|
|
2577
2643
|
style: "display: none;"
|
|
2578
2644
|
});
|
|
2579
2645
|
clear.appendChild(
|
|
@@ -2602,7 +2668,7 @@ function buildPickerModal(opts) {
|
|
|
2602
2668
|
style: "display: none;"
|
|
2603
2669
|
});
|
|
2604
2670
|
const emptyText = document.createElement("p");
|
|
2605
|
-
emptyText.textContent = "No products match your search";
|
|
2671
|
+
emptyText.textContent = s.noSearchResults || "No products match your search";
|
|
2606
2672
|
empty.appendChild(emptyText);
|
|
2607
2673
|
dialog.appendChild(empty);
|
|
2608
2674
|
dialog.appendChild(
|
|
@@ -2621,7 +2687,7 @@ function buildPickerModal(opts) {
|
|
|
2621
2687
|
"data-modal-back": "",
|
|
2622
2688
|
style: "display: none;"
|
|
2623
2689
|
});
|
|
2624
|
-
back.textContent = "Back";
|
|
2690
|
+
back.textContent = s.back || "Back";
|
|
2625
2691
|
footer.appendChild(back);
|
|
2626
2692
|
}
|
|
2627
2693
|
footer.appendChild(
|
|
@@ -2636,7 +2702,7 @@ function buildPickerModal(opts) {
|
|
|
2636
2702
|
"data-modal-next": "",
|
|
2637
2703
|
style: "display: none;"
|
|
2638
2704
|
});
|
|
2639
|
-
next.textContent = "Next";
|
|
2705
|
+
next.textContent = s.next || "Next";
|
|
2640
2706
|
footer.appendChild(next);
|
|
2641
2707
|
}
|
|
2642
2708
|
const done = el("button", "lb-mix-match__modal-done", {
|
|
@@ -2644,7 +2710,7 @@ function buildPickerModal(opts) {
|
|
|
2644
2710
|
"data-modal-done": "",
|
|
2645
2711
|
...opts.wizard ? { style: "display: none;" } : {}
|
|
2646
2712
|
});
|
|
2647
|
-
done.textContent = "Done";
|
|
2713
|
+
done.textContent = s.done || "Done";
|
|
2648
2714
|
footer.appendChild(done);
|
|
2649
2715
|
dialog.appendChild(footer);
|
|
2650
2716
|
overlay.appendChild(dialog);
|
|
@@ -2969,6 +3035,7 @@ function selectTier(container, allTiers, basePrice, discountType, index, transla
|
|
|
2969
3035
|
savingsPercentEl.textContent = "(" + savingsPct + "%)";
|
|
2970
3036
|
}
|
|
2971
3037
|
savingsBar.style.display = "";
|
|
3038
|
+
savingsBar.classList.remove("lb-savings-pending");
|
|
2972
3039
|
} else {
|
|
2973
3040
|
savingsBar.style.display = "none";
|
|
2974
3041
|
}
|
|
@@ -3152,6 +3219,7 @@ function recalcPricing2(container, sides, percent, buyQty, getQty, formatMoney)
|
|
|
3152
3219
|
savingsPercentEl.textContent = "(" + pct + "%)";
|
|
3153
3220
|
}
|
|
3154
3221
|
savingsBar.style.display = "";
|
|
3222
|
+
savingsBar.classList.remove("lb-savings-pending");
|
|
3155
3223
|
} else {
|
|
3156
3224
|
savingsBar.style.display = "none";
|
|
3157
3225
|
}
|
|
@@ -4542,6 +4610,15 @@ var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle
|
|
|
4542
4610
|
display: block;
|
|
4543
4611
|
}
|
|
4544
4612
|
|
|
4613
|
+
/* Same reset, one more victim. A thumbnail is emitted empty and filled at
|
|
4614
|
+
hydration, so between the two it matched \`div:empty\` and vanished \u2014 taking
|
|
4615
|
+
the row's gap with it and starting that title 72px left of every other
|
|
4616
|
+
row's (issue #552). The box holds its place either way now: the product's
|
|
4617
|
+
image lands in it, or the placeholder mark does. */
|
|
4618
|
+
.lb-bundle-thumbnail:empty {
|
|
4619
|
+
display: flex;
|
|
4620
|
+
}
|
|
4621
|
+
|
|
4545
4622
|
/* Divider */
|
|
4546
4623
|
.lb-bundle-divider {
|
|
4547
4624
|
height: var(--lb-border-width);
|
|
@@ -4580,11 +4657,6 @@ var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle
|
|
|
4580
4657
|
object-fit: var(--lb-thumbnail-img-fit, cover);
|
|
4581
4658
|
}
|
|
4582
4659
|
|
|
4583
|
-
.lb-bundle-thumbnail svg {
|
|
4584
|
-
width: 28px;
|
|
4585
|
-
height: 28px;
|
|
4586
|
-
color: color-mix(in srgb, var(--lb-text) 35%, transparent);
|
|
4587
|
-
}
|
|
4588
4660
|
|
|
4589
4661
|
.lb-bundle-product-info {
|
|
4590
4662
|
flex: 1;
|
|
@@ -4708,6 +4780,43 @@ a.lb-bundle-product-name:focus-visible {
|
|
|
4708
4780
|
gap: 4px;
|
|
4709
4781
|
}
|
|
4710
4782
|
|
|
4783
|
+
/* Variant picker select \u2014 styled to match the variant badge aesthetic.
|
|
4784
|
+
Sits inside .lb-bundle-variant-option-group so vertical spacing is owned
|
|
4785
|
+
by the group/groups flex gap, not the select itself.
|
|
4786
|
+
|
|
4787
|
+
Lives here, not in bundle-fixed.css, because every widget that renders an
|
|
4788
|
+
option group needs it and only the fixed widget loads that stylesheet: a
|
|
4789
|
+
page carrying just a Buy X Get Y bundle rendered raw browser selects, and
|
|
4790
|
+
the option-group height reservation (sized for the styled control) was
|
|
4791
|
+
wrong by 14px a group, which shifted the row on hydration.
|
|
4792
|
+
The same split applies to the headless package, which injects per type. */
|
|
4793
|
+
.lb-bundle-variant-select {
|
|
4794
|
+
display: inline-block;
|
|
4795
|
+
border: var(--lb-border-width) solid var(--lb-border);
|
|
4796
|
+
border-radius: var(--lb-radius);
|
|
4797
|
+
padding: 8px 32px 8px 12px;
|
|
4798
|
+
font-size: 12px;
|
|
4799
|
+
line-height: 16px;
|
|
4800
|
+
color: var(--lb-text);
|
|
4801
|
+
background: var(--lb-bg);
|
|
4802
|
+
font-family: inherit;
|
|
4803
|
+
cursor: pointer;
|
|
4804
|
+
appearance: none;
|
|
4805
|
+
-webkit-appearance: none;
|
|
4806
|
+
background-image: var(--lb-variant-chevron);
|
|
4807
|
+
background-repeat: no-repeat;
|
|
4808
|
+
background-position: right 8px center;
|
|
4809
|
+
background-size: 12px;
|
|
4810
|
+
width: 50%;
|
|
4811
|
+
max-width: 50%;
|
|
4812
|
+
}
|
|
4813
|
+
|
|
4814
|
+
.lb-bundle-variant-select:focus-visible {
|
|
4815
|
+
outline: 2px solid var(--lb-primary-color);
|
|
4816
|
+
outline-offset: 2px;
|
|
4817
|
+
box-shadow: none;
|
|
4818
|
+
}
|
|
4819
|
+
|
|
4711
4820
|
.lb-bundle-variant-option-label {
|
|
4712
4821
|
display: block;
|
|
4713
4822
|
margin: 0;
|
|
@@ -4989,15 +5098,33 @@ a.lb-bundle-product-name:focus-visible {
|
|
|
4989
5098
|
border: 0 !important;
|
|
4990
5099
|
}
|
|
4991
5100
|
|
|
4992
|
-
/*
|
|
5101
|
+
/* Missing-image placeholder.
|
|
5102
|
+
Two marks share these rules: Shopify's own \`placeholder_svg_tag\`
|
|
5103
|
+
illustration, which the theme scripts clone out of the <template> in
|
|
5104
|
+
bundle-widget.liquid, and the line glyph the headless renderer falls back to
|
|
5105
|
+
when there is no Liquid to supply one. */
|
|
5106
|
+
.lb-thumb--placeholder > [data-lb-placeholder] {
|
|
5107
|
+
display: block;
|
|
5108
|
+
width: 100%;
|
|
5109
|
+
/* The mark carries the box's height, not the other way round: the
|
|
5110
|
+
"original" thumbnail ratio sizes a box to its image's proportions and an
|
|
5111
|
+
imageless row has no image, so without this the box would be 60px by
|
|
5112
|
+
nothing. A box that already has a ratio caps the mark instead. */
|
|
5113
|
+
height: auto;
|
|
5114
|
+
max-height: 100%;
|
|
5115
|
+
aspect-ratio: 1 / 1;
|
|
5116
|
+
}
|
|
5117
|
+
|
|
4993
5118
|
.lb-bundle-placeholder-icon {
|
|
4994
|
-
width: 28px;
|
|
4995
|
-
height: 28px;
|
|
4996
5119
|
stroke: color-mix(in srgb, var(--lb-text) 35%, transparent);
|
|
4997
5120
|
stroke-width: 1.5;
|
|
4998
5121
|
fill: none;
|
|
4999
5122
|
}
|
|
5000
5123
|
|
|
5124
|
+
.lb-bundle-placeholder-svg {
|
|
5125
|
+
fill: color-mix(in srgb, var(--lb-text) 22%, transparent);
|
|
5126
|
+
}
|
|
5127
|
+
|
|
5001
5128
|
/* Out-of-stock product row */
|
|
5002
5129
|
.lb-bundle-product-row--oos {
|
|
5003
5130
|
opacity: 0.5;
|
|
@@ -5029,6 +5156,16 @@ a.lb-bundle-product-name:focus-visible {
|
|
|
5029
5156
|
white-space: nowrap;
|
|
5030
5157
|
}
|
|
5031
5158
|
|
|
5159
|
+
/* The savings line is laid out from first paint and revealed on hydration,
|
|
5160
|
+
rather than being display:none until then.
|
|
5161
|
+
Its amounts are money strings the server cannot know, so filling them in
|
|
5162
|
+
place moves whatever shares the line; revealing an already-laid-out box
|
|
5163
|
+
moves nothing. The band around it is vertically centred, so reserving the
|
|
5164
|
+
line costs no height of its own. JS drops the class in updatePricing. */
|
|
5165
|
+
.lb-bundle-savings-line.lb-savings-pending {
|
|
5166
|
+
visibility: hidden;
|
|
5167
|
+
}
|
|
5168
|
+
|
|
5032
5169
|
/* A/B test: hide save badge until JS swaps the label (prevents flash of default) */
|
|
5033
5170
|
.lb-ab-pending {
|
|
5034
5171
|
visibility: hidden;
|
|
@@ -5046,27 +5183,43 @@ a.lb-bundle-product-name:focus-visible {
|
|
|
5046
5183
|
The title is the one box NOT reserved this way: text wrapping depends on the
|
|
5047
5184
|
merchant's font, so it is server-rendered and its height is simply real. */
|
|
5048
5185
|
|
|
5186
|
+
/* A zero-width space, not a pixel height.
|
|
5187
|
+
These boxes are one line of text once JS fills them, and their height is
|
|
5188
|
+
whatever the merchant's font makes of \`line-height: normal\` \u2014 which the
|
|
5189
|
+
reset at the top of this file forces on every descendant, overriding the
|
|
5190
|
+
per-element line-heights above it. A hardcoded min-height therefore has to
|
|
5191
|
+
guess, and guessed 3px too tall: the row shrank on hydration in every theme.
|
|
5192
|
+
An empty line box measures exactly what the filled one will. */
|
|
5049
5193
|
.lb-bundle-product-price:empty {
|
|
5050
5194
|
display: inline-block;
|
|
5051
|
-
min-height: 20px;
|
|
5052
5195
|
}
|
|
5053
5196
|
|
|
5054
5197
|
.lb-bundle-variant-badge:empty {
|
|
5055
5198
|
display: block;
|
|
5056
|
-
min-height: 20px;
|
|
5057
5199
|
}
|
|
5058
5200
|
|
|
5059
5201
|
.lb-bundle-product-unit-price:empty {
|
|
5060
5202
|
display: block;
|
|
5061
|
-
|
|
5203
|
+
}
|
|
5204
|
+
|
|
5205
|
+
.lb-bundle-product-price:empty::before,
|
|
5206
|
+
.lb-bundle-variant-badge:empty::before,
|
|
5207
|
+
.lb-bundle-product-unit-price:empty::before,
|
|
5208
|
+
.lb-bundle-qty-inline:empty::before,
|
|
5209
|
+
.lb-bundle-sale-price:empty::before,
|
|
5210
|
+
.lb-bundle-compare-price:empty::before {
|
|
5211
|
+
content: "\\200B";
|
|
5062
5212
|
}
|
|
5063
5213
|
|
|
5064
5214
|
/* Label (16) + gap (4) + trigger (8 + 16 + 8 padding/line-height) per group,
|
|
5065
5215
|
plus the 8px gap between groups. --lb-row-option-count is set per row by
|
|
5066
|
-
Liquid, which knows how many options the product has.
|
|
5216
|
+
Liquid, which knows how many options the product has.
|
|
5217
|
+
|
|
5218
|
+
The trigger is border-box, so its border is already inside that 52px; the
|
|
5219
|
+
calc used to add it again and reserved 2px per group too much. */
|
|
5067
5220
|
.lb-bundle-variant-option-groups:empty {
|
|
5068
5221
|
min-height: calc(
|
|
5069
|
-
var(--lb-row-option-count, 1) *
|
|
5222
|
+
var(--lb-row-option-count, 1) * 52px +
|
|
5070
5223
|
(var(--lb-row-option-count, 1) - 1) * 8px
|
|
5071
5224
|
);
|
|
5072
5225
|
}
|
|
@@ -5146,36 +5299,6 @@ var BUNDLE_FIXED_CSS = `/* Lime Bundles \u2014 Fixed bundle styles */
|
|
|
5146
5299
|
font-variant-numeric: tabular-nums;
|
|
5147
5300
|
white-space: nowrap;
|
|
5148
5301
|
}
|
|
5149
|
-
|
|
5150
|
-
/* Variant picker select \u2014 styled to match the variant badge aesthetic.
|
|
5151
|
-
Sits inside .lb-bundle-variant-option-group so vertical spacing is owned
|
|
5152
|
-
by the group/groups flex gap, not the select itself. */
|
|
5153
|
-
.lb-bundle-variant-select {
|
|
5154
|
-
display: inline-block;
|
|
5155
|
-
border: var(--lb-border-width) solid var(--lb-border);
|
|
5156
|
-
border-radius: var(--lb-radius);
|
|
5157
|
-
padding: 8px 32px 8px 12px;
|
|
5158
|
-
font-size: 12px;
|
|
5159
|
-
line-height: 16px;
|
|
5160
|
-
color: var(--lb-text);
|
|
5161
|
-
background: var(--lb-bg);
|
|
5162
|
-
font-family: inherit;
|
|
5163
|
-
cursor: pointer;
|
|
5164
|
-
appearance: none;
|
|
5165
|
-
-webkit-appearance: none;
|
|
5166
|
-
background-image: var(--lb-variant-chevron);
|
|
5167
|
-
background-repeat: no-repeat;
|
|
5168
|
-
background-position: right 8px center;
|
|
5169
|
-
background-size: 12px;
|
|
5170
|
-
width: 50%;
|
|
5171
|
-
max-width: 50%;
|
|
5172
|
-
}
|
|
5173
|
-
|
|
5174
|
-
.lb-bundle-variant-select:focus-visible {
|
|
5175
|
-
outline: 2px solid var(--lb-primary-color);
|
|
5176
|
-
outline-offset: 2px;
|
|
5177
|
-
box-shadow: none;
|
|
5178
|
-
}
|
|
5179
5302
|
`;
|
|
5180
5303
|
var BUNDLE_MIX_MATCH_CSS = `/* Lime Bundles \u2014 Mix & Match styles */
|
|
5181
5304
|
|
|
@@ -6498,6 +6621,15 @@ var BUNDLE_BOGO_CSS = `/* Lime Bundles \u2014 BOGO (Buy X Get Y) bundle styles *
|
|
|
6498
6621
|
text-decoration: line-through;
|
|
6499
6622
|
opacity: 0.6;
|
|
6500
6623
|
}
|
|
6624
|
+
|
|
6625
|
+
/* The reward row's struck original is emitted empty and filled on hydration,
|
|
6626
|
+
so anything sharing its line moves when it appears. The count is the only
|
|
6627
|
+
such thing, and it is a count, not part of the price phrase: pinning it to
|
|
6628
|
+
the row's right edge makes its position independent of the price text \u2014 the
|
|
6629
|
+
same right-slot treatment the fixed widget gives its quantity chip. */
|
|
6630
|
+
.lb-bogo .lb-bundle-qty-inline {
|
|
6631
|
+
margin-left: auto;
|
|
6632
|
+
}
|
|
6501
6633
|
`;
|
|
6502
6634
|
var BUNDLE_MULTI_STEP_CSS = `/**
|
|
6503
6635
|
* Lime Bundles \u2014 Multi-step bundle widget styles (wizard chrome ONLY).
|