@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.cjs
CHANGED
|
@@ -75,6 +75,32 @@ function parseIso(iso) {
|
|
|
75
75
|
return Number.isFinite(t) ? t : null;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
// src/renderers/cta-button.ts
|
|
79
|
+
function buildCtaButton(label) {
|
|
80
|
+
const button = document.createElement("button");
|
|
81
|
+
button.type = "button";
|
|
82
|
+
button.className = "lb-bundle-cta";
|
|
83
|
+
button.setAttribute("data-add-bundle", "");
|
|
84
|
+
const labelSpan = document.createElement("span");
|
|
85
|
+
labelSpan.className = "lb-cta-label";
|
|
86
|
+
labelSpan.setAttribute("data-cta-label", "");
|
|
87
|
+
labelSpan.textContent = label;
|
|
88
|
+
button.appendChild(labelSpan);
|
|
89
|
+
const spinnerSpan = document.createElement("span");
|
|
90
|
+
spinnerSpan.className = "lb-cta-spinner";
|
|
91
|
+
spinnerSpan.setAttribute("data-cta-spinner", "");
|
|
92
|
+
spinnerSpan.setAttribute("aria-hidden", "true");
|
|
93
|
+
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>';
|
|
94
|
+
button.appendChild(spinnerSpan);
|
|
95
|
+
return button;
|
|
96
|
+
}
|
|
97
|
+
function setCtaLabel(button, text) {
|
|
98
|
+
const label = button.querySelector("[data-cta-label]");
|
|
99
|
+
if (label) {
|
|
100
|
+
label.textContent = text;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
78
104
|
// src/renderers/dom.ts
|
|
79
105
|
function el(tag, className, attrs = {}) {
|
|
80
106
|
const node = document.createElement(tag);
|
|
@@ -412,15 +438,11 @@ function renderSavingsBar() {
|
|
|
412
438
|
};
|
|
413
439
|
}
|
|
414
440
|
function renderCta(bundle, oosCount, onClick) {
|
|
415
|
-
const
|
|
416
|
-
button
|
|
417
|
-
button.className = "lb-bundle-cta";
|
|
418
|
-
button.setAttribute("data-add-bundle", "");
|
|
441
|
+
const label = oosCount > 0 ? `${oosCount} item${oosCount === 1 ? "" : "s"} out of stock` : bundle.widgetConfig.cta.ctaText || "Add to cart";
|
|
442
|
+
const button = buildCtaButton(label);
|
|
419
443
|
if (oosCount > 0) {
|
|
420
444
|
button.disabled = true;
|
|
421
|
-
button.textContent = `${oosCount} item${oosCount === 1 ? "" : "s"} out of stock`;
|
|
422
445
|
} else {
|
|
423
|
-
button.textContent = bundle.widgetConfig.cta.ctaText || "Add to cart";
|
|
424
446
|
button.addEventListener("click", () => {
|
|
425
447
|
if (button.disabled) return;
|
|
426
448
|
onClick();
|
|
@@ -517,12 +539,8 @@ function renderMixMatchBundle(container, bundle, onAddToCart, onCleanup) {
|
|
|
517
539
|
isOverMax: () => selections.length >= maxQty
|
|
518
540
|
});
|
|
519
541
|
root.appendChild(modal.el);
|
|
520
|
-
const cta =
|
|
521
|
-
cta.type = "button";
|
|
522
|
-
cta.className = "lb-bundle-cta";
|
|
523
|
-
cta.setAttribute("data-add-bundle", "");
|
|
542
|
+
const cta = buildCtaButton(`Select ${requiredQty} items to unlock`);
|
|
524
543
|
cta.disabled = true;
|
|
525
|
-
cta.textContent = `Select ${requiredQty} items to unlock`;
|
|
526
544
|
cta.addEventListener("click", () => {
|
|
527
545
|
if (cta.disabled) return;
|
|
528
546
|
const lines = selections.map((s) => ({
|
|
@@ -615,10 +633,10 @@ function renderMixMatchBundle(container, bundle, onAddToCart, onCleanup) {
|
|
|
615
633
|
const count = selections.length;
|
|
616
634
|
if (count < requiredQty) {
|
|
617
635
|
cta.disabled = true;
|
|
618
|
-
cta
|
|
636
|
+
setCtaLabel(cta, `Select ${requiredQty - count} more to unlock`);
|
|
619
637
|
} else {
|
|
620
638
|
cta.disabled = false;
|
|
621
|
-
cta
|
|
639
|
+
setCtaLabel(cta, wc.cta.ctaText || "Add to cart");
|
|
622
640
|
}
|
|
623
641
|
}
|
|
624
642
|
}
|
|
@@ -1353,12 +1371,9 @@ function renderSavingsBar3(resolved, selectedIndex, currency) {
|
|
|
1353
1371
|
function renderCta2(bundle, onClick) {
|
|
1354
1372
|
const product = bundle.products[0];
|
|
1355
1373
|
const isAvailable = product?.variants.nodes.some((v) => v.availableForSale);
|
|
1356
|
-
const
|
|
1357
|
-
button
|
|
1358
|
-
button.className = "lb-bundle-cta";
|
|
1359
|
-
button.setAttribute("data-add-bundle", "");
|
|
1374
|
+
const label = isAvailable ? bundle.widgetConfig.cta.ctaText || "Add to cart" : "Sold out";
|
|
1375
|
+
const button = buildCtaButton(label);
|
|
1360
1376
|
if (!isAvailable) button.disabled = true;
|
|
1361
|
-
button.textContent = isAvailable ? bundle.widgetConfig.cta.ctaText || "Add to cart" : "Sold out";
|
|
1362
1377
|
button.addEventListener("click", () => {
|
|
1363
1378
|
if (button.disabled) return;
|
|
1364
1379
|
onClick();
|
|
@@ -1745,9 +1760,16 @@ var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle
|
|
|
1745
1760
|
display: none;
|
|
1746
1761
|
}
|
|
1747
1762
|
|
|
1748
|
-
/* CTA button
|
|
1763
|
+
/* CTA button.
|
|
1764
|
+
* Label and spinner share a single 1\xD71 grid cell so the button's intrinsic
|
|
1765
|
+
* width/height stays fixed when swapping between them \u2014 no layout shift when
|
|
1766
|
+
* entering the loading state. Visibility (not display) is used so the hidden
|
|
1767
|
+
* child still contributes to the cell's min-content sizing. See the
|
|
1768
|
+
* [data-loading="true"] rules below. */
|
|
1749
1769
|
.lb-bundle-cta {
|
|
1750
|
-
display:
|
|
1770
|
+
display: grid;
|
|
1771
|
+
grid-template-rows: 1fr;
|
|
1772
|
+
grid-template-columns: 1fr;
|
|
1751
1773
|
width: 100%;
|
|
1752
1774
|
padding: 16px;
|
|
1753
1775
|
border: var(--lb-cta-border-width) solid var(--lb-cta-border-color);
|
|
@@ -1776,12 +1798,51 @@ var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle
|
|
|
1776
1798
|
cursor: not-allowed;
|
|
1777
1799
|
}
|
|
1778
1800
|
|
|
1801
|
+
/* Both the label and the spinner occupy grid cell (1, 1). Only one is
|
|
1802
|
+
* visible at a time; the other keeps its box for sizing but is invisible. */
|
|
1803
|
+
.lb-cta-label,
|
|
1804
|
+
.lb-cta-spinner {
|
|
1805
|
+
grid-row: 1;
|
|
1806
|
+
grid-column: 1;
|
|
1807
|
+
display: flex;
|
|
1808
|
+
align-items: center;
|
|
1809
|
+
justify-content: center;
|
|
1810
|
+
min-width: 0;
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1813
|
+
.lb-cta-spinner {
|
|
1814
|
+
visibility: hidden;
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
.lb-cta-spinner svg {
|
|
1818
|
+
width: 20px;
|
|
1819
|
+
height: 20px;
|
|
1820
|
+
animation: lb-cta-spin 0.8s linear infinite;
|
|
1821
|
+
}
|
|
1822
|
+
|
|
1823
|
+
@keyframes lb-cta-spin {
|
|
1824
|
+
to { transform: rotate(360deg); }
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1779
1827
|
.lb-bundle-cta[data-loading="true"] {
|
|
1780
|
-
opacity: 0.7;
|
|
1781
1828
|
cursor: wait;
|
|
1782
1829
|
pointer-events: none;
|
|
1783
1830
|
}
|
|
1784
1831
|
|
|
1832
|
+
.lb-bundle-cta[data-loading="true"] .lb-cta-label {
|
|
1833
|
+
visibility: hidden;
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1836
|
+
.lb-bundle-cta[data-loading="true"] .lb-cta-spinner {
|
|
1837
|
+
visibility: visible;
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1841
|
+
.lb-cta-spinner svg {
|
|
1842
|
+
animation-duration: 2.5s;
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1785
1846
|
/* Error message */
|
|
1786
1847
|
.lb-bundle-error {
|
|
1787
1848
|
font-size: 16px;
|