@lime-bundles/widget 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +82 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +82 -21
- package/dist/index.js.map +1 -1
- package/dist/lime-bundle.global.js +69 -23
- package/dist/lime-bundle.global.js.map +1 -1
- package/docs/web-component.md +19 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -70,6 +70,32 @@ function parseIso(iso) {
|
|
|
70
70
|
return Number.isFinite(t) ? t : null;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
// src/renderers/cta-button.ts
|
|
74
|
+
function buildCtaButton(label) {
|
|
75
|
+
const button = document.createElement("button");
|
|
76
|
+
button.type = "button";
|
|
77
|
+
button.className = "lb-bundle-cta";
|
|
78
|
+
button.setAttribute("data-add-bundle", "");
|
|
79
|
+
const labelSpan = document.createElement("span");
|
|
80
|
+
labelSpan.className = "lb-cta-label";
|
|
81
|
+
labelSpan.setAttribute("data-cta-label", "");
|
|
82
|
+
labelSpan.textContent = label;
|
|
83
|
+
button.appendChild(labelSpan);
|
|
84
|
+
const spinnerSpan = document.createElement("span");
|
|
85
|
+
spinnerSpan.className = "lb-cta-spinner";
|
|
86
|
+
spinnerSpan.setAttribute("data-cta-spinner", "");
|
|
87
|
+
spinnerSpan.setAttribute("aria-hidden", "true");
|
|
88
|
+
spinnerSpan.innerHTML = '<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><path d="M12 2a10 10 0 0 1 10 10" /></svg>';
|
|
89
|
+
button.appendChild(spinnerSpan);
|
|
90
|
+
return button;
|
|
91
|
+
}
|
|
92
|
+
function setCtaLabel(button, text) {
|
|
93
|
+
const label = button.querySelector("[data-cta-label]");
|
|
94
|
+
if (label) {
|
|
95
|
+
label.textContent = text;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
73
99
|
// src/renderers/dom.ts
|
|
74
100
|
function el(tag, className, attrs = {}) {
|
|
75
101
|
const node = document.createElement(tag);
|
|
@@ -410,15 +436,11 @@ function renderSavingsBar() {
|
|
|
410
436
|
};
|
|
411
437
|
}
|
|
412
438
|
function renderCta(bundle, oosCount, onClick) {
|
|
413
|
-
const
|
|
414
|
-
button
|
|
415
|
-
button.className = "lb-bundle-cta";
|
|
416
|
-
button.setAttribute("data-add-bundle", "");
|
|
439
|
+
const label = oosCount > 0 ? `${oosCount} item${oosCount === 1 ? "" : "s"} out of stock` : bundle.widgetConfig.cta.ctaText || "Add to cart";
|
|
440
|
+
const button = buildCtaButton(label);
|
|
417
441
|
if (oosCount > 0) {
|
|
418
442
|
button.disabled = true;
|
|
419
|
-
button.textContent = `${oosCount} item${oosCount === 1 ? "" : "s"} out of stock`;
|
|
420
443
|
} else {
|
|
421
|
-
button.textContent = bundle.widgetConfig.cta.ctaText || "Add to cart";
|
|
422
444
|
button.addEventListener("click", () => {
|
|
423
445
|
if (button.disabled) return;
|
|
424
446
|
onClick();
|
|
@@ -515,12 +537,8 @@ function renderMixMatchBundle(container, bundle, onAddToCart, onCleanup) {
|
|
|
515
537
|
isOverMax: () => selections.length >= maxQty
|
|
516
538
|
});
|
|
517
539
|
root.appendChild(modal.el);
|
|
518
|
-
const cta =
|
|
519
|
-
cta.type = "button";
|
|
520
|
-
cta.className = "lb-bundle-cta";
|
|
521
|
-
cta.setAttribute("data-add-bundle", "");
|
|
540
|
+
const cta = buildCtaButton(`Select ${requiredQty} items to unlock`);
|
|
522
541
|
cta.disabled = true;
|
|
523
|
-
cta.textContent = `Select ${requiredQty} items to unlock`;
|
|
524
542
|
cta.addEventListener("click", () => {
|
|
525
543
|
if (cta.disabled) return;
|
|
526
544
|
const lines = selections.map((s) => ({
|
|
@@ -613,10 +631,10 @@ function renderMixMatchBundle(container, bundle, onAddToCart, onCleanup) {
|
|
|
613
631
|
const count = selections.length;
|
|
614
632
|
if (count < requiredQty) {
|
|
615
633
|
cta.disabled = true;
|
|
616
|
-
cta
|
|
634
|
+
setCtaLabel(cta, `Select ${requiredQty - count} more to unlock`);
|
|
617
635
|
} else {
|
|
618
636
|
cta.disabled = false;
|
|
619
|
-
cta
|
|
637
|
+
setCtaLabel(cta, wc.cta.ctaText || "Add to cart");
|
|
620
638
|
}
|
|
621
639
|
}
|
|
622
640
|
}
|
|
@@ -1351,12 +1369,9 @@ function renderSavingsBar3(resolved, selectedIndex, currency) {
|
|
|
1351
1369
|
function renderCta2(bundle, onClick) {
|
|
1352
1370
|
const product = bundle.products[0];
|
|
1353
1371
|
const isAvailable = product?.variants.nodes.some((v) => v.availableForSale);
|
|
1354
|
-
const
|
|
1355
|
-
button
|
|
1356
|
-
button.className = "lb-bundle-cta";
|
|
1357
|
-
button.setAttribute("data-add-bundle", "");
|
|
1372
|
+
const label = isAvailable ? bundle.widgetConfig.cta.ctaText || "Add to cart" : "Sold out";
|
|
1373
|
+
const button = buildCtaButton(label);
|
|
1358
1374
|
if (!isAvailable) button.disabled = true;
|
|
1359
|
-
button.textContent = isAvailable ? bundle.widgetConfig.cta.ctaText || "Add to cart" : "Sold out";
|
|
1360
1375
|
button.addEventListener("click", () => {
|
|
1361
1376
|
if (button.disabled) return;
|
|
1362
1377
|
onClick();
|
|
@@ -1743,9 +1758,16 @@ var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle
|
|
|
1743
1758
|
display: none;
|
|
1744
1759
|
}
|
|
1745
1760
|
|
|
1746
|
-
/* CTA button
|
|
1761
|
+
/* CTA button.
|
|
1762
|
+
* Label and spinner share a single 1\xD71 grid cell so the button's intrinsic
|
|
1763
|
+
* width/height stays fixed when swapping between them \u2014 no layout shift when
|
|
1764
|
+
* entering the loading state. Visibility (not display) is used so the hidden
|
|
1765
|
+
* child still contributes to the cell's min-content sizing. See the
|
|
1766
|
+
* [data-loading="true"] rules below. */
|
|
1747
1767
|
.lb-bundle-cta {
|
|
1748
|
-
display:
|
|
1768
|
+
display: grid;
|
|
1769
|
+
grid-template-rows: 1fr;
|
|
1770
|
+
grid-template-columns: 1fr;
|
|
1749
1771
|
width: 100%;
|
|
1750
1772
|
padding: 16px;
|
|
1751
1773
|
border: var(--lb-cta-border-width) solid var(--lb-cta-border-color);
|
|
@@ -1774,12 +1796,51 @@ var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle
|
|
|
1774
1796
|
cursor: not-allowed;
|
|
1775
1797
|
}
|
|
1776
1798
|
|
|
1799
|
+
/* Both the label and the spinner occupy grid cell (1, 1). Only one is
|
|
1800
|
+
* visible at a time; the other keeps its box for sizing but is invisible. */
|
|
1801
|
+
.lb-cta-label,
|
|
1802
|
+
.lb-cta-spinner {
|
|
1803
|
+
grid-row: 1;
|
|
1804
|
+
grid-column: 1;
|
|
1805
|
+
display: flex;
|
|
1806
|
+
align-items: center;
|
|
1807
|
+
justify-content: center;
|
|
1808
|
+
min-width: 0;
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1811
|
+
.lb-cta-spinner {
|
|
1812
|
+
visibility: hidden;
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
.lb-cta-spinner svg {
|
|
1816
|
+
width: 20px;
|
|
1817
|
+
height: 20px;
|
|
1818
|
+
animation: lb-cta-spin 0.8s linear infinite;
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
@keyframes lb-cta-spin {
|
|
1822
|
+
to { transform: rotate(360deg); }
|
|
1823
|
+
}
|
|
1824
|
+
|
|
1777
1825
|
.lb-bundle-cta[data-loading="true"] {
|
|
1778
|
-
opacity: 0.7;
|
|
1779
1826
|
cursor: wait;
|
|
1780
1827
|
pointer-events: none;
|
|
1781
1828
|
}
|
|
1782
1829
|
|
|
1830
|
+
.lb-bundle-cta[data-loading="true"] .lb-cta-label {
|
|
1831
|
+
visibility: hidden;
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
.lb-bundle-cta[data-loading="true"] .lb-cta-spinner {
|
|
1835
|
+
visibility: visible;
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1839
|
+
.lb-cta-spinner svg {
|
|
1840
|
+
animation-duration: 2.5s;
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1783
1844
|
/* Error message */
|
|
1784
1845
|
.lb-bundle-error {
|
|
1785
1846
|
font-size: 16px;
|