@lime-bundles/widget 4.6.4 → 4.6.5
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 +91 -45
- package/dist/index.js +91 -45
- package/dist/lime-bundle.global.js +79 -37
- 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
|
}
|
|
@@ -2458,7 +2459,7 @@ function seedSelection(eligibleProducts, rulesMap, requiredQty, courtesy) {
|
|
|
2458
2459
|
required.push(pick(p, v2, Math.max(1, rule.min)));
|
|
2459
2460
|
}
|
|
2460
2461
|
if (required.length || !courtesy?.enabled) return required;
|
|
2461
|
-
const qualifies = (p) => p.available && ruleFor(p.id, rulesMap).min <= requiredQty;
|
|
2462
|
+
const qualifies = (p) => p.available && ruleFor(p.id, rulesMap).min <= requiredQty && firstAvailable(p) !== null;
|
|
2462
2463
|
const seed = (courtesy.currentProductId != null ? eligibleProducts.find(
|
|
2463
2464
|
(p) => p.id === courtesy.currentProductId && qualifies(p)
|
|
2464
2465
|
) : null) ?? eligibleProducts.find(qualifies);
|
|
@@ -2496,6 +2497,7 @@ function el(tag, className, attrs = {}) {
|
|
|
2496
2497
|
}
|
|
2497
2498
|
function buildPickerModal(opts) {
|
|
2498
2499
|
const titleId = "lb-modal-title-" + opts.domId;
|
|
2500
|
+
const s = opts.strings || {};
|
|
2499
2501
|
const overlay = el("div", "lb-mix-match__modal-overlay", {
|
|
2500
2502
|
"data-modal-overlay": "",
|
|
2501
2503
|
"data-bundle-gid": opts.bundleGid,
|
|
@@ -2516,7 +2518,7 @@ function buildPickerModal(opts) {
|
|
|
2516
2518
|
const heading = el("div", "lb-mix-match__modal-heading");
|
|
2517
2519
|
const title = el("h4", "lb-mix-match__modal-title", { id: titleId });
|
|
2518
2520
|
if (opts.wizard) title.setAttribute("tabindex", "-1");
|
|
2519
|
-
title.textContent = "Add to your bundle";
|
|
2521
|
+
title.textContent = s.addToBundle || "Add to your bundle";
|
|
2520
2522
|
heading.appendChild(title);
|
|
2521
2523
|
heading.appendChild(
|
|
2522
2524
|
el("p", "lb-mix-match__modal-subtitle", { "data-modal-subtitle": "" })
|
|
@@ -2525,7 +2527,7 @@ function buildPickerModal(opts) {
|
|
|
2525
2527
|
const close = el("button", "lb-mix-match__modal-close", {
|
|
2526
2528
|
type: "button",
|
|
2527
2529
|
"data-modal-close": "",
|
|
2528
|
-
"aria-label": "Close"
|
|
2530
|
+
"aria-label": s.closeModal || "Close"
|
|
2529
2531
|
});
|
|
2530
2532
|
close.appendChild(
|
|
2531
2533
|
icon([
|
|
@@ -2566,15 +2568,15 @@ function buildPickerModal(opts) {
|
|
|
2566
2568
|
type: "text",
|
|
2567
2569
|
"data-modal-search": "",
|
|
2568
2570
|
role: "searchbox",
|
|
2569
|
-
"aria-label": "Search products",
|
|
2570
|
-
placeholder: "Search products",
|
|
2571
|
+
"aria-label": s.searchProducts || "Search products",
|
|
2572
|
+
placeholder: s.searchProducts || "Search products",
|
|
2571
2573
|
autocomplete: "off"
|
|
2572
2574
|
});
|
|
2573
2575
|
search.appendChild(input);
|
|
2574
2576
|
const clear = el("button", "lb-mix-match__modal-search-clear", {
|
|
2575
2577
|
type: "button",
|
|
2576
2578
|
"data-modal-search-clear": "",
|
|
2577
|
-
"aria-label": "Clear search",
|
|
2579
|
+
"aria-label": s.clearSearch || "Clear search",
|
|
2578
2580
|
style: "display: none;"
|
|
2579
2581
|
});
|
|
2580
2582
|
clear.appendChild(
|
|
@@ -2603,7 +2605,7 @@ function buildPickerModal(opts) {
|
|
|
2603
2605
|
style: "display: none;"
|
|
2604
2606
|
});
|
|
2605
2607
|
const emptyText = document.createElement("p");
|
|
2606
|
-
emptyText.textContent = "No products match your search";
|
|
2608
|
+
emptyText.textContent = s.noSearchResults || "No products match your search";
|
|
2607
2609
|
empty.appendChild(emptyText);
|
|
2608
2610
|
dialog.appendChild(empty);
|
|
2609
2611
|
dialog.appendChild(
|
|
@@ -2622,7 +2624,7 @@ function buildPickerModal(opts) {
|
|
|
2622
2624
|
"data-modal-back": "",
|
|
2623
2625
|
style: "display: none;"
|
|
2624
2626
|
});
|
|
2625
|
-
back.textContent = "Back";
|
|
2627
|
+
back.textContent = s.back || "Back";
|
|
2626
2628
|
footer.appendChild(back);
|
|
2627
2629
|
}
|
|
2628
2630
|
footer.appendChild(
|
|
@@ -2637,7 +2639,7 @@ function buildPickerModal(opts) {
|
|
|
2637
2639
|
"data-modal-next": "",
|
|
2638
2640
|
style: "display: none;"
|
|
2639
2641
|
});
|
|
2640
|
-
next.textContent = "Next";
|
|
2642
|
+
next.textContent = s.next || "Next";
|
|
2641
2643
|
footer.appendChild(next);
|
|
2642
2644
|
}
|
|
2643
2645
|
const done = el("button", "lb-mix-match__modal-done", {
|
|
@@ -2645,7 +2647,7 @@ function buildPickerModal(opts) {
|
|
|
2645
2647
|
"data-modal-done": "",
|
|
2646
2648
|
...opts.wizard ? { style: "display: none;" } : {}
|
|
2647
2649
|
});
|
|
2648
|
-
done.textContent = "Done";
|
|
2650
|
+
done.textContent = s.done || "Done";
|
|
2649
2651
|
footer.appendChild(done);
|
|
2650
2652
|
dialog.appendChild(footer);
|
|
2651
2653
|
overlay.appendChild(dialog);
|
|
@@ -2963,6 +2965,7 @@ function selectTier(container, allTiers, basePrice, discountType, index, transla
|
|
|
2963
2965
|
savingsPercentEl.textContent = "(" + savingsPct + "%)";
|
|
2964
2966
|
}
|
|
2965
2967
|
savingsBar.style.display = "";
|
|
2968
|
+
savingsBar.classList.remove("lb-savings-pending");
|
|
2966
2969
|
} else {
|
|
2967
2970
|
savingsBar.style.display = "none";
|
|
2968
2971
|
}
|
|
@@ -3146,6 +3149,7 @@ function recalcPricing2(container, sides, percent, buyQty, getQty, formatMoney)
|
|
|
3146
3149
|
savingsPercentEl.textContent = "(" + pct + "%)";
|
|
3147
3150
|
}
|
|
3148
3151
|
savingsBar.style.display = "";
|
|
3152
|
+
savingsBar.classList.remove("lb-savings-pending");
|
|
3149
3153
|
} else {
|
|
3150
3154
|
savingsBar.style.display = "none";
|
|
3151
3155
|
}
|
|
@@ -4698,6 +4702,43 @@ a.lb-bundle-product-name:focus-visible {
|
|
|
4698
4702
|
gap: 4px;
|
|
4699
4703
|
}
|
|
4700
4704
|
|
|
4705
|
+
/* Variant picker select \u2014 styled to match the variant badge aesthetic.
|
|
4706
|
+
Sits inside .lb-bundle-variant-option-group so vertical spacing is owned
|
|
4707
|
+
by the group/groups flex gap, not the select itself.
|
|
4708
|
+
|
|
4709
|
+
Lives here, not in bundle-fixed.css, because every widget that renders an
|
|
4710
|
+
option group needs it and only the fixed widget loads that stylesheet: a
|
|
4711
|
+
page carrying just a Buy X Get Y bundle rendered raw browser selects, and
|
|
4712
|
+
the option-group height reservation (sized for the styled control) was
|
|
4713
|
+
wrong by 14px a group, which shifted the row on hydration.
|
|
4714
|
+
The same split applies to the headless package, which injects per type. */
|
|
4715
|
+
.lb-bundle-variant-select {
|
|
4716
|
+
display: inline-block;
|
|
4717
|
+
border: var(--lb-border-width) solid var(--lb-border);
|
|
4718
|
+
border-radius: var(--lb-radius);
|
|
4719
|
+
padding: 8px 32px 8px 12px;
|
|
4720
|
+
font-size: 12px;
|
|
4721
|
+
line-height: 16px;
|
|
4722
|
+
color: var(--lb-text);
|
|
4723
|
+
background: var(--lb-bg);
|
|
4724
|
+
font-family: inherit;
|
|
4725
|
+
cursor: pointer;
|
|
4726
|
+
appearance: none;
|
|
4727
|
+
-webkit-appearance: none;
|
|
4728
|
+
background-image: var(--lb-variant-chevron);
|
|
4729
|
+
background-repeat: no-repeat;
|
|
4730
|
+
background-position: right 8px center;
|
|
4731
|
+
background-size: 12px;
|
|
4732
|
+
width: 50%;
|
|
4733
|
+
max-width: 50%;
|
|
4734
|
+
}
|
|
4735
|
+
|
|
4736
|
+
.lb-bundle-variant-select:focus-visible {
|
|
4737
|
+
outline: 2px solid var(--lb-primary-color);
|
|
4738
|
+
outline-offset: 2px;
|
|
4739
|
+
box-shadow: none;
|
|
4740
|
+
}
|
|
4741
|
+
|
|
4701
4742
|
.lb-bundle-variant-option-label {
|
|
4702
4743
|
display: block;
|
|
4703
4744
|
margin: 0;
|
|
@@ -5019,6 +5060,16 @@ a.lb-bundle-product-name:focus-visible {
|
|
|
5019
5060
|
white-space: nowrap;
|
|
5020
5061
|
}
|
|
5021
5062
|
|
|
5063
|
+
/* The savings line is laid out from first paint and revealed on hydration,
|
|
5064
|
+
rather than being display:none until then.
|
|
5065
|
+
Its amounts are money strings the server cannot know, so filling them in
|
|
5066
|
+
place moves whatever shares the line; revealing an already-laid-out box
|
|
5067
|
+
moves nothing. The band around it is vertically centred, so reserving the
|
|
5068
|
+
line costs no height of its own. JS drops the class in updatePricing. */
|
|
5069
|
+
.lb-bundle-savings-line.lb-savings-pending {
|
|
5070
|
+
visibility: hidden;
|
|
5071
|
+
}
|
|
5072
|
+
|
|
5022
5073
|
/* A/B test: hide save badge until JS swaps the label (prevents flash of default) */
|
|
5023
5074
|
.lb-ab-pending {
|
|
5024
5075
|
visibility: hidden;
|
|
@@ -5036,27 +5087,43 @@ a.lb-bundle-product-name:focus-visible {
|
|
|
5036
5087
|
The title is the one box NOT reserved this way: text wrapping depends on the
|
|
5037
5088
|
merchant's font, so it is server-rendered and its height is simply real. */
|
|
5038
5089
|
|
|
5090
|
+
/* A zero-width space, not a pixel height.
|
|
5091
|
+
These boxes are one line of text once JS fills them, and their height is
|
|
5092
|
+
whatever the merchant's font makes of \`line-height: normal\` \u2014 which the
|
|
5093
|
+
reset at the top of this file forces on every descendant, overriding the
|
|
5094
|
+
per-element line-heights above it. A hardcoded min-height therefore has to
|
|
5095
|
+
guess, and guessed 3px too tall: the row shrank on hydration in every theme.
|
|
5096
|
+
An empty line box measures exactly what the filled one will. */
|
|
5039
5097
|
.lb-bundle-product-price:empty {
|
|
5040
5098
|
display: inline-block;
|
|
5041
|
-
min-height: 20px;
|
|
5042
5099
|
}
|
|
5043
5100
|
|
|
5044
5101
|
.lb-bundle-variant-badge:empty {
|
|
5045
5102
|
display: block;
|
|
5046
|
-
min-height: 20px;
|
|
5047
5103
|
}
|
|
5048
5104
|
|
|
5049
5105
|
.lb-bundle-product-unit-price:empty {
|
|
5050
5106
|
display: block;
|
|
5051
|
-
|
|
5107
|
+
}
|
|
5108
|
+
|
|
5109
|
+
.lb-bundle-product-price:empty::before,
|
|
5110
|
+
.lb-bundle-variant-badge:empty::before,
|
|
5111
|
+
.lb-bundle-product-unit-price:empty::before,
|
|
5112
|
+
.lb-bundle-qty-inline:empty::before,
|
|
5113
|
+
.lb-bundle-sale-price:empty::before,
|
|
5114
|
+
.lb-bundle-compare-price:empty::before {
|
|
5115
|
+
content: "\\200B";
|
|
5052
5116
|
}
|
|
5053
5117
|
|
|
5054
5118
|
/* Label (16) + gap (4) + trigger (8 + 16 + 8 padding/line-height) per group,
|
|
5055
5119
|
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.
|
|
5120
|
+
Liquid, which knows how many options the product has.
|
|
5121
|
+
|
|
5122
|
+
The trigger is border-box, so its border is already inside that 52px; the
|
|
5123
|
+
calc used to add it again and reserved 2px per group too much. */
|
|
5057
5124
|
.lb-bundle-variant-option-groups:empty {
|
|
5058
5125
|
min-height: calc(
|
|
5059
|
-
var(--lb-row-option-count, 1) *
|
|
5126
|
+
var(--lb-row-option-count, 1) * 52px +
|
|
5060
5127
|
(var(--lb-row-option-count, 1) - 1) * 8px
|
|
5061
5128
|
);
|
|
5062
5129
|
}
|
|
@@ -5136,36 +5203,6 @@ var BUNDLE_FIXED_CSS = `/* Lime Bundles \u2014 Fixed bundle styles */
|
|
|
5136
5203
|
font-variant-numeric: tabular-nums;
|
|
5137
5204
|
white-space: nowrap;
|
|
5138
5205
|
}
|
|
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
5206
|
`;
|
|
5170
5207
|
var BUNDLE_MIX_MATCH_CSS = `/* Lime Bundles \u2014 Mix & Match styles */
|
|
5171
5208
|
|
|
@@ -6488,6 +6525,15 @@ var BUNDLE_BOGO_CSS = `/* Lime Bundles \u2014 BOGO (Buy X Get Y) bundle styles *
|
|
|
6488
6525
|
text-decoration: line-through;
|
|
6489
6526
|
opacity: 0.6;
|
|
6490
6527
|
}
|
|
6528
|
+
|
|
6529
|
+
/* The reward row's struck original is emitted empty and filled on hydration,
|
|
6530
|
+
so anything sharing its line moves when it appears. The count is the only
|
|
6531
|
+
such thing, and it is a count, not part of the price phrase: pinning it to
|
|
6532
|
+
the row's right edge makes its position independent of the price text \u2014 the
|
|
6533
|
+
same right-slot treatment the fixed widget gives its quantity chip. */
|
|
6534
|
+
.lb-bogo .lb-bundle-qty-inline {
|
|
6535
|
+
margin-left: auto;
|
|
6536
|
+
}
|
|
6491
6537
|
`;
|
|
6492
6538
|
var BUNDLE_MULTI_STEP_CSS = `/**
|
|
6493
6539
|
* Lime Bundles \u2014 Multi-step bundle widget styles (wizard chrome ONLY).
|
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
|
}
|
|
@@ -2457,7 +2458,7 @@ function seedSelection(eligibleProducts, rulesMap, requiredQty, courtesy) {
|
|
|
2457
2458
|
required.push(pick(p, v2, Math.max(1, rule.min)));
|
|
2458
2459
|
}
|
|
2459
2460
|
if (required.length || !courtesy?.enabled) return required;
|
|
2460
|
-
const qualifies = (p) => p.available && ruleFor(p.id, rulesMap).min <= requiredQty;
|
|
2461
|
+
const qualifies = (p) => p.available && ruleFor(p.id, rulesMap).min <= requiredQty && firstAvailable(p) !== null;
|
|
2461
2462
|
const seed = (courtesy.currentProductId != null ? eligibleProducts.find(
|
|
2462
2463
|
(p) => p.id === courtesy.currentProductId && qualifies(p)
|
|
2463
2464
|
) : null) ?? eligibleProducts.find(qualifies);
|
|
@@ -2495,6 +2496,7 @@ function el(tag, className, attrs = {}) {
|
|
|
2495
2496
|
}
|
|
2496
2497
|
function buildPickerModal(opts) {
|
|
2497
2498
|
const titleId = "lb-modal-title-" + opts.domId;
|
|
2499
|
+
const s = opts.strings || {};
|
|
2498
2500
|
const overlay = el("div", "lb-mix-match__modal-overlay", {
|
|
2499
2501
|
"data-modal-overlay": "",
|
|
2500
2502
|
"data-bundle-gid": opts.bundleGid,
|
|
@@ -2515,7 +2517,7 @@ function buildPickerModal(opts) {
|
|
|
2515
2517
|
const heading = el("div", "lb-mix-match__modal-heading");
|
|
2516
2518
|
const title = el("h4", "lb-mix-match__modal-title", { id: titleId });
|
|
2517
2519
|
if (opts.wizard) title.setAttribute("tabindex", "-1");
|
|
2518
|
-
title.textContent = "Add to your bundle";
|
|
2520
|
+
title.textContent = s.addToBundle || "Add to your bundle";
|
|
2519
2521
|
heading.appendChild(title);
|
|
2520
2522
|
heading.appendChild(
|
|
2521
2523
|
el("p", "lb-mix-match__modal-subtitle", { "data-modal-subtitle": "" })
|
|
@@ -2524,7 +2526,7 @@ function buildPickerModal(opts) {
|
|
|
2524
2526
|
const close = el("button", "lb-mix-match__modal-close", {
|
|
2525
2527
|
type: "button",
|
|
2526
2528
|
"data-modal-close": "",
|
|
2527
|
-
"aria-label": "Close"
|
|
2529
|
+
"aria-label": s.closeModal || "Close"
|
|
2528
2530
|
});
|
|
2529
2531
|
close.appendChild(
|
|
2530
2532
|
icon([
|
|
@@ -2565,15 +2567,15 @@ function buildPickerModal(opts) {
|
|
|
2565
2567
|
type: "text",
|
|
2566
2568
|
"data-modal-search": "",
|
|
2567
2569
|
role: "searchbox",
|
|
2568
|
-
"aria-label": "Search products",
|
|
2569
|
-
placeholder: "Search products",
|
|
2570
|
+
"aria-label": s.searchProducts || "Search products",
|
|
2571
|
+
placeholder: s.searchProducts || "Search products",
|
|
2570
2572
|
autocomplete: "off"
|
|
2571
2573
|
});
|
|
2572
2574
|
search.appendChild(input);
|
|
2573
2575
|
const clear = el("button", "lb-mix-match__modal-search-clear", {
|
|
2574
2576
|
type: "button",
|
|
2575
2577
|
"data-modal-search-clear": "",
|
|
2576
|
-
"aria-label": "Clear search",
|
|
2578
|
+
"aria-label": s.clearSearch || "Clear search",
|
|
2577
2579
|
style: "display: none;"
|
|
2578
2580
|
});
|
|
2579
2581
|
clear.appendChild(
|
|
@@ -2602,7 +2604,7 @@ function buildPickerModal(opts) {
|
|
|
2602
2604
|
style: "display: none;"
|
|
2603
2605
|
});
|
|
2604
2606
|
const emptyText = document.createElement("p");
|
|
2605
|
-
emptyText.textContent = "No products match your search";
|
|
2607
|
+
emptyText.textContent = s.noSearchResults || "No products match your search";
|
|
2606
2608
|
empty.appendChild(emptyText);
|
|
2607
2609
|
dialog.appendChild(empty);
|
|
2608
2610
|
dialog.appendChild(
|
|
@@ -2621,7 +2623,7 @@ function buildPickerModal(opts) {
|
|
|
2621
2623
|
"data-modal-back": "",
|
|
2622
2624
|
style: "display: none;"
|
|
2623
2625
|
});
|
|
2624
|
-
back.textContent = "Back";
|
|
2626
|
+
back.textContent = s.back || "Back";
|
|
2625
2627
|
footer.appendChild(back);
|
|
2626
2628
|
}
|
|
2627
2629
|
footer.appendChild(
|
|
@@ -2636,7 +2638,7 @@ function buildPickerModal(opts) {
|
|
|
2636
2638
|
"data-modal-next": "",
|
|
2637
2639
|
style: "display: none;"
|
|
2638
2640
|
});
|
|
2639
|
-
next.textContent = "Next";
|
|
2641
|
+
next.textContent = s.next || "Next";
|
|
2640
2642
|
footer.appendChild(next);
|
|
2641
2643
|
}
|
|
2642
2644
|
const done = el("button", "lb-mix-match__modal-done", {
|
|
@@ -2644,7 +2646,7 @@ function buildPickerModal(opts) {
|
|
|
2644
2646
|
"data-modal-done": "",
|
|
2645
2647
|
...opts.wizard ? { style: "display: none;" } : {}
|
|
2646
2648
|
});
|
|
2647
|
-
done.textContent = "Done";
|
|
2649
|
+
done.textContent = s.done || "Done";
|
|
2648
2650
|
footer.appendChild(done);
|
|
2649
2651
|
dialog.appendChild(footer);
|
|
2650
2652
|
overlay.appendChild(dialog);
|
|
@@ -2969,6 +2971,7 @@ function selectTier(container, allTiers, basePrice, discountType, index, transla
|
|
|
2969
2971
|
savingsPercentEl.textContent = "(" + savingsPct + "%)";
|
|
2970
2972
|
}
|
|
2971
2973
|
savingsBar.style.display = "";
|
|
2974
|
+
savingsBar.classList.remove("lb-savings-pending");
|
|
2972
2975
|
} else {
|
|
2973
2976
|
savingsBar.style.display = "none";
|
|
2974
2977
|
}
|
|
@@ -3152,6 +3155,7 @@ function recalcPricing2(container, sides, percent, buyQty, getQty, formatMoney)
|
|
|
3152
3155
|
savingsPercentEl.textContent = "(" + pct + "%)";
|
|
3153
3156
|
}
|
|
3154
3157
|
savingsBar.style.display = "";
|
|
3158
|
+
savingsBar.classList.remove("lb-savings-pending");
|
|
3155
3159
|
} else {
|
|
3156
3160
|
savingsBar.style.display = "none";
|
|
3157
3161
|
}
|
|
@@ -4708,6 +4712,43 @@ a.lb-bundle-product-name:focus-visible {
|
|
|
4708
4712
|
gap: 4px;
|
|
4709
4713
|
}
|
|
4710
4714
|
|
|
4715
|
+
/* Variant picker select \u2014 styled to match the variant badge aesthetic.
|
|
4716
|
+
Sits inside .lb-bundle-variant-option-group so vertical spacing is owned
|
|
4717
|
+
by the group/groups flex gap, not the select itself.
|
|
4718
|
+
|
|
4719
|
+
Lives here, not in bundle-fixed.css, because every widget that renders an
|
|
4720
|
+
option group needs it and only the fixed widget loads that stylesheet: a
|
|
4721
|
+
page carrying just a Buy X Get Y bundle rendered raw browser selects, and
|
|
4722
|
+
the option-group height reservation (sized for the styled control) was
|
|
4723
|
+
wrong by 14px a group, which shifted the row on hydration.
|
|
4724
|
+
The same split applies to the headless package, which injects per type. */
|
|
4725
|
+
.lb-bundle-variant-select {
|
|
4726
|
+
display: inline-block;
|
|
4727
|
+
border: var(--lb-border-width) solid var(--lb-border);
|
|
4728
|
+
border-radius: var(--lb-radius);
|
|
4729
|
+
padding: 8px 32px 8px 12px;
|
|
4730
|
+
font-size: 12px;
|
|
4731
|
+
line-height: 16px;
|
|
4732
|
+
color: var(--lb-text);
|
|
4733
|
+
background: var(--lb-bg);
|
|
4734
|
+
font-family: inherit;
|
|
4735
|
+
cursor: pointer;
|
|
4736
|
+
appearance: none;
|
|
4737
|
+
-webkit-appearance: none;
|
|
4738
|
+
background-image: var(--lb-variant-chevron);
|
|
4739
|
+
background-repeat: no-repeat;
|
|
4740
|
+
background-position: right 8px center;
|
|
4741
|
+
background-size: 12px;
|
|
4742
|
+
width: 50%;
|
|
4743
|
+
max-width: 50%;
|
|
4744
|
+
}
|
|
4745
|
+
|
|
4746
|
+
.lb-bundle-variant-select:focus-visible {
|
|
4747
|
+
outline: 2px solid var(--lb-primary-color);
|
|
4748
|
+
outline-offset: 2px;
|
|
4749
|
+
box-shadow: none;
|
|
4750
|
+
}
|
|
4751
|
+
|
|
4711
4752
|
.lb-bundle-variant-option-label {
|
|
4712
4753
|
display: block;
|
|
4713
4754
|
margin: 0;
|
|
@@ -5029,6 +5070,16 @@ a.lb-bundle-product-name:focus-visible {
|
|
|
5029
5070
|
white-space: nowrap;
|
|
5030
5071
|
}
|
|
5031
5072
|
|
|
5073
|
+
/* The savings line is laid out from first paint and revealed on hydration,
|
|
5074
|
+
rather than being display:none until then.
|
|
5075
|
+
Its amounts are money strings the server cannot know, so filling them in
|
|
5076
|
+
place moves whatever shares the line; revealing an already-laid-out box
|
|
5077
|
+
moves nothing. The band around it is vertically centred, so reserving the
|
|
5078
|
+
line costs no height of its own. JS drops the class in updatePricing. */
|
|
5079
|
+
.lb-bundle-savings-line.lb-savings-pending {
|
|
5080
|
+
visibility: hidden;
|
|
5081
|
+
}
|
|
5082
|
+
|
|
5032
5083
|
/* A/B test: hide save badge until JS swaps the label (prevents flash of default) */
|
|
5033
5084
|
.lb-ab-pending {
|
|
5034
5085
|
visibility: hidden;
|
|
@@ -5046,27 +5097,43 @@ a.lb-bundle-product-name:focus-visible {
|
|
|
5046
5097
|
The title is the one box NOT reserved this way: text wrapping depends on the
|
|
5047
5098
|
merchant's font, so it is server-rendered and its height is simply real. */
|
|
5048
5099
|
|
|
5100
|
+
/* A zero-width space, not a pixel height.
|
|
5101
|
+
These boxes are one line of text once JS fills them, and their height is
|
|
5102
|
+
whatever the merchant's font makes of \`line-height: normal\` \u2014 which the
|
|
5103
|
+
reset at the top of this file forces on every descendant, overriding the
|
|
5104
|
+
per-element line-heights above it. A hardcoded min-height therefore has to
|
|
5105
|
+
guess, and guessed 3px too tall: the row shrank on hydration in every theme.
|
|
5106
|
+
An empty line box measures exactly what the filled one will. */
|
|
5049
5107
|
.lb-bundle-product-price:empty {
|
|
5050
5108
|
display: inline-block;
|
|
5051
|
-
min-height: 20px;
|
|
5052
5109
|
}
|
|
5053
5110
|
|
|
5054
5111
|
.lb-bundle-variant-badge:empty {
|
|
5055
5112
|
display: block;
|
|
5056
|
-
min-height: 20px;
|
|
5057
5113
|
}
|
|
5058
5114
|
|
|
5059
5115
|
.lb-bundle-product-unit-price:empty {
|
|
5060
5116
|
display: block;
|
|
5061
|
-
|
|
5117
|
+
}
|
|
5118
|
+
|
|
5119
|
+
.lb-bundle-product-price:empty::before,
|
|
5120
|
+
.lb-bundle-variant-badge:empty::before,
|
|
5121
|
+
.lb-bundle-product-unit-price:empty::before,
|
|
5122
|
+
.lb-bundle-qty-inline:empty::before,
|
|
5123
|
+
.lb-bundle-sale-price:empty::before,
|
|
5124
|
+
.lb-bundle-compare-price:empty::before {
|
|
5125
|
+
content: "\\200B";
|
|
5062
5126
|
}
|
|
5063
5127
|
|
|
5064
5128
|
/* Label (16) + gap (4) + trigger (8 + 16 + 8 padding/line-height) per group,
|
|
5065
5129
|
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.
|
|
5130
|
+
Liquid, which knows how many options the product has.
|
|
5131
|
+
|
|
5132
|
+
The trigger is border-box, so its border is already inside that 52px; the
|
|
5133
|
+
calc used to add it again and reserved 2px per group too much. */
|
|
5067
5134
|
.lb-bundle-variant-option-groups:empty {
|
|
5068
5135
|
min-height: calc(
|
|
5069
|
-
var(--lb-row-option-count, 1) *
|
|
5136
|
+
var(--lb-row-option-count, 1) * 52px +
|
|
5070
5137
|
(var(--lb-row-option-count, 1) - 1) * 8px
|
|
5071
5138
|
);
|
|
5072
5139
|
}
|
|
@@ -5146,36 +5213,6 @@ var BUNDLE_FIXED_CSS = `/* Lime Bundles \u2014 Fixed bundle styles */
|
|
|
5146
5213
|
font-variant-numeric: tabular-nums;
|
|
5147
5214
|
white-space: nowrap;
|
|
5148
5215
|
}
|
|
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
5216
|
`;
|
|
5180
5217
|
var BUNDLE_MIX_MATCH_CSS = `/* Lime Bundles \u2014 Mix & Match styles */
|
|
5181
5218
|
|
|
@@ -6498,6 +6535,15 @@ var BUNDLE_BOGO_CSS = `/* Lime Bundles \u2014 BOGO (Buy X Get Y) bundle styles *
|
|
|
6498
6535
|
text-decoration: line-through;
|
|
6499
6536
|
opacity: 0.6;
|
|
6500
6537
|
}
|
|
6538
|
+
|
|
6539
|
+
/* The reward row's struck original is emitted empty and filled on hydration,
|
|
6540
|
+
so anything sharing its line moves when it appears. The count is the only
|
|
6541
|
+
such thing, and it is a count, not part of the price phrase: pinning it to
|
|
6542
|
+
the row's right edge makes its position independent of the price text \u2014 the
|
|
6543
|
+
same right-slot treatment the fixed widget gives its quantity chip. */
|
|
6544
|
+
.lb-bogo .lb-bundle-qty-inline {
|
|
6545
|
+
margin-left: auto;
|
|
6546
|
+
}
|
|
6501
6547
|
`;
|
|
6502
6548
|
var BUNDLE_MULTI_STEP_CSS = `/**
|
|
6503
6549
|
* Lime Bundles \u2014 Multi-step bundle widget styles (wizard chrome ONLY).
|