@lime-bundles/widget 2.2.0 → 2.3.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.js CHANGED
@@ -16,13 +16,19 @@ import {
16
16
  applyABVariantB
17
17
  } from "@lime-bundles/core";
18
18
 
19
+ // src/renderers/fixed.ts
20
+ import {
21
+ resolveBundleQty
22
+ } from "@lime-bundles/core";
23
+
19
24
  // src/renderers/pricing.ts
20
25
  import {
21
26
  parseCents,
22
27
  formatCents,
23
28
  percentageDiscountUnit,
24
29
  computeFixedPricing,
25
- computeBundleSaleCents
30
+ computeBundleSaleCents,
31
+ formatUnitPrice
26
32
  } from "@lime-bundles/core";
27
33
 
28
34
  // src/renderers/countdown.ts
@@ -121,11 +127,7 @@ var PLACEHOLDER_THUMB_SVG = `
121
127
  </svg>`;
122
128
  function renderFixedBundle(container, bundle, onAddToCart, onCleanup) {
123
129
  const wc = bundle.widgetConfig;
124
- const qtyFor = (productId, variantId) => {
125
- const vq = bundle.variantQuantities[variantId];
126
- if (vq !== void 0) return vq;
127
- return bundle.productQuantities[productId] ?? 1;
128
- };
130
+ const qtyFor = (productId, variantId) => resolveBundleQty(bundle, productId, variantId);
129
131
  const rows = [];
130
132
  let oosCount = 0;
131
133
  bundle.products.forEach((product, idx) => {
@@ -216,9 +218,7 @@ function buildRowState(bundle, product, productIndex) {
216
218
  const eligibleVariants = selectedVariantIds && selectedVariantIds.length > 0 ? available.filter((v) => selectedVariantIds.includes(v.id)) : available;
217
219
  const isOos = eligibleVariants.length === 0;
218
220
  const selected = eligibleVariants[0] ?? null;
219
- const productQty = bundle.productQuantities[product.id] ?? 1;
220
- const variantQty = selected ? bundle.variantQuantities[selected.id] : void 0;
221
- const qty = variantQty ?? productQty;
221
+ const qty = selected ? resolveBundleQty(bundle, product.id, selected.id) : 1;
222
222
  return { product, eligibleVariants, selected, qty, isOos };
223
223
  }
224
224
  function renderHeader(bundle, currency) {
@@ -333,6 +333,11 @@ function renderProductRow(state, currency, qtyFor, onVariantChange) {
333
333
  prices.appendChild(compare);
334
334
  prices.appendChild(priceEl);
335
335
  info.appendChild(prices);
336
+ const unitPriceEl = el("span", "lb-bundle-product-unit-price", {
337
+ "data-product-unit-price": ""
338
+ });
339
+ unitPriceEl.setAttribute("hidden", "");
340
+ info.appendChild(unitPriceEl);
336
341
  const applyVariantToRow = (variant) => {
337
342
  const unit = parseCents(variant.price.amount);
338
343
  priceEl.textContent = formatCents(unit, currency);
@@ -347,6 +352,17 @@ function renderProductRow(state, currency, qtyFor, onVariantChange) {
347
352
  } else {
348
353
  compare.setAttribute("hidden", "");
349
354
  }
355
+ const unitText = formatUnitPrice(
356
+ variant.unitPrice,
357
+ variant.unitPriceMeasurement,
358
+ currency
359
+ );
360
+ if (unitText) {
361
+ unitPriceEl.textContent = unitText;
362
+ unitPriceEl.removeAttribute("hidden");
363
+ } else {
364
+ unitPriceEl.setAttribute("hidden", "");
365
+ }
350
366
  };
351
367
  applyVariantToRow(state.selected);
352
368
  if (state.eligibleVariants.length > 1) {
@@ -957,6 +973,19 @@ function renderModal(bundle, eligible, currency, handlers) {
957
973
  const price = el("span", "lb-mix-match__modal-product-price");
958
974
  price.textContent = formatCents(parseCents(variant.price.amount), currency);
959
975
  info.appendChild(price);
976
+ const unitPriceText = formatUnitPrice(
977
+ variant.unitPrice,
978
+ variant.unitPriceMeasurement,
979
+ currency
980
+ );
981
+ if (unitPriceText) {
982
+ const unitPrice = el(
983
+ "span",
984
+ "lb-mix-match__modal-product-unit-price lb-bundle-product-unit-price"
985
+ );
986
+ unitPrice.textContent = unitPriceText;
987
+ info.appendChild(unitPrice);
988
+ }
960
989
  if (ep.isOos) {
961
990
  const soldOut = el("span", "lb-mix-match__modal-sold-out-label");
962
991
  soldOut.textContent = "Sold out";
@@ -1422,7 +1451,6 @@ var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle
1422
1451
 
1423
1452
  .lb-bundle-widget {
1424
1453
  /* Internal CSS-only vars (not merchant-configurable). */
1425
- --lb-text-muted: #666666;
1426
1454
  --lb-thumbnail-bg: #F0F0F0;
1427
1455
  --lb-widget-pad: 20px;
1428
1456
  --lb-progress-color: var(--lb-primary-color);
@@ -1445,7 +1473,7 @@ var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle
1445
1473
  margin: 0 calc(-1 * var(--lb-widget-pad)) 20px;
1446
1474
  padding: 12px 20px;
1447
1475
  background: var(--lb-countdown-bg);
1448
- border-top: 1px solid rgba(0, 0, 0, 0.06);
1476
+ border-top: 1px solid color-mix(in srgb, var(--lb-text) 6%, transparent);
1449
1477
  display: flex;
1450
1478
  align-items: center;
1451
1479
  justify-content: space-between;
@@ -1485,11 +1513,20 @@ var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle
1485
1513
  display: none;
1486
1514
  }
1487
1515
 
1488
- /* Adjacent widget spacing \u2014 separates multiple bundles on the same product page */
1489
- .lb-bundle-widget + .lb-bundle-widget {
1516
+ /* Sibling widget spacing \u2014 separates multiple bundles on the same product page.
1517
+ Uses \`~\` (general sibling) rather than \`+\` (adjacent) because each Liquid
1518
+ loop iteration emits a {% style %} block before its widget div, so the
1519
+ rendered DOM alternates <style><widget><style><widget>. The \`+\` combinator
1520
+ requires immediate adjacency and would match nothing; \`~\` matches every
1521
+ widget after the first regardless of elements between. Single-widget pages
1522
+ stay unaffected (no prior \`.lb-bundle-widget\` sibling to match against).
1523
+ Only \`margin-top\` \u2014 do NOT override \`padding-top\` here. The gradient header
1524
+ uses \`margin-top: calc(-1 * var(--lb-widget-pad))\` to reach the widget's
1525
+ inner border edge, assuming padding-top == --lb-widget-pad. Changing
1526
+ padding-top on the subsequent widget breaks that math and leaves a visible
1527
+ gap above the header. */
1528
+ .lb-bundle-widget ~ .lb-bundle-widget {
1490
1529
  margin-top: 24px;
1491
- padding-top: 24px;
1492
- border-top: 1px solid var(--lb-border);
1493
1530
  }
1494
1531
 
1495
1532
  /* Header \u2014 gradient banner with title + savings badge */
@@ -1532,7 +1569,7 @@ var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle
1532
1569
  font-size: 16px;
1533
1570
  font-weight: 400;
1534
1571
  line-height: 20px;
1535
- color: var(--lb-text-muted);
1572
+ color: color-mix(in srgb, var(--lb-text) 60%, transparent);
1536
1573
  margin: 4px 0 0;
1537
1574
  }
1538
1575
 
@@ -1601,7 +1638,7 @@ var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle
1601
1638
  .lb-bundle-thumbnail svg {
1602
1639
  width: 28px;
1603
1640
  height: 28px;
1604
- color: #BBBBBB;
1641
+ color: color-mix(in srgb, var(--lb-text) 35%, transparent);
1605
1642
  }
1606
1643
 
1607
1644
  .lb-bundle-product-info {
@@ -1656,6 +1693,22 @@ var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle
1656
1693
  display: none;
1657
1694
  }
1658
1695
 
1696
+ /* Unit price (e.g. "$0.50/100ml") \u2014 only rendered when the merchant has
1697
+ configured unit pricing on the variant in the Shopify admin. No merchant
1698
+ toggle: present in admin \u2192 shown; absent \u2192 hidden. Styled as muted
1699
+ secondary text beneath the price row so it doesn't compete visually. */
1700
+ .lb-bundle-product-unit-price {
1701
+ display: block;
1702
+ font-size: 11px;
1703
+ line-height: 16px;
1704
+ color: color-mix(in srgb, var(--lb-text) 60%, transparent);
1705
+ margin-top: 2px;
1706
+ }
1707
+
1708
+ .lb-bundle-product-unit-price[hidden] {
1709
+ display: none;
1710
+ }
1711
+
1659
1712
  .lb-bundle-variant-badge {
1660
1713
  display: inline-block;
1661
1714
  border: var(--lb-variant-border-width) solid var(--lb-variant-border-color);
@@ -1663,14 +1716,14 @@ var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle
1663
1716
  padding: 8px 12px;
1664
1717
  font-size: 12px;
1665
1718
  line-height: 16px;
1666
- color: var(--lb-text-muted);
1719
+ color: color-mix(in srgb, var(--lb-text) 60%, transparent);
1667
1720
  margin-top: 8px;
1668
1721
  }
1669
1722
 
1670
1723
  .lb-bundle-quantity {
1671
1724
  font-size: 12px;
1672
1725
  line-height: 16px;
1673
- color: var(--lb-text-muted);
1726
+ color: color-mix(in srgb, var(--lb-text) 60%, transparent);
1674
1727
  margin-left: 8px;
1675
1728
  white-space: nowrap;
1676
1729
  }
@@ -1725,7 +1778,7 @@ var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle
1725
1778
  font-size: 16px;
1726
1779
  font-weight: 600;
1727
1780
  line-height: 20px;
1728
- padding: 12px 16px;
1781
+ padding: 8px 12px;
1729
1782
  border-radius: var(--lb-savings-bar-radius);
1730
1783
  margin-bottom: 12px;
1731
1784
  }
@@ -1870,7 +1923,7 @@ var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle
1870
1923
  .lb-bundle-placeholder-icon {
1871
1924
  width: 28px;
1872
1925
  height: 28px;
1873
- stroke: #BBBBBB;
1926
+ stroke: color-mix(in srgb, var(--lb-text) 35%, transparent);
1874
1927
  stroke-width: 1.5;
1875
1928
  fill: none;
1876
1929
  }
@@ -2287,7 +2340,7 @@ var BUNDLE_MIX_MATCH_CSS = `/* Lime Bundles \u2014 Mix & Match styles */
2287
2340
  border: var(--lb-picker-product-border-width) solid var(--lb-picker-product-border-color);
2288
2341
  box-sizing: border-box;
2289
2342
  overflow: visible;
2290
- background: #F0F0F0;
2343
+ background: var(--lb-thumbnail-bg);
2291
2344
  }
2292
2345
 
2293
2346
  /* Qty badge inside the picker modal inherits picker-product border (width + color) plus
@@ -2328,6 +2381,17 @@ var BUNDLE_MIX_MATCH_CSS = `/* Lime Bundles \u2014 Mix & Match styles */
2328
2381
  margin: 4px 0 0;
2329
2382
  }
2330
2383
 
2384
+ .lb-mix-match__modal-product-unit-price {
2385
+ font-size: 11px;
2386
+ line-height: 16px;
2387
+ color: color-mix(in srgb, var(--lb-text) 60%, transparent);
2388
+ margin: 2px 0 0;
2389
+ }
2390
+
2391
+ .lb-mix-match__modal-product-unit-price[hidden] {
2392
+ display: none;
2393
+ }
2394
+
2331
2395
  .lb-mix-match__variant-select {
2332
2396
  font-size: 12px;
2333
2397
  margin: 4px 0 0;