@lime-bundles/widget 2.0.0 → 2.1.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.d.cts CHANGED
@@ -60,7 +60,6 @@ declare class LimeBundleElement extends HTMLElement {
60
60
  private setupImpressionFor;
61
61
  private renderLoading;
62
62
  private renderError;
63
- private render;
64
63
  }
65
64
 
66
65
  export { LimeBundleElement };
package/dist/index.d.ts CHANGED
@@ -60,7 +60,6 @@ declare class LimeBundleElement extends HTMLElement {
60
60
  private setupImpressionFor;
61
61
  private renderLoading;
62
62
  private renderError;
63
- private render;
64
63
  }
65
64
 
66
65
  export { LimeBundleElement };
package/dist/index.js CHANGED
@@ -544,7 +544,20 @@ function renderMixMatchBundle(container, bundle, onAddToCart, onCleanup) {
544
544
  })
545
545
  );
546
546
  container.appendChild(root);
547
- renderSlots();
547
+ const firstEligible = eligible.find((ep) => !ep.isOos);
548
+ const firstVariant = firstEligible?.firstAvailableVariant ?? firstEligible?.variants[0];
549
+ if (firstEligible && firstVariant) {
550
+ selections.push({
551
+ productId: firstEligible.product.id,
552
+ productTitle: firstEligible.product.title,
553
+ variantId: firstVariant.id,
554
+ variantTitle: firstVariant.title,
555
+ imageUrl: firstEligible.product.featuredImage?.url ?? null,
556
+ priceCents: parseCents(firstVariant.price.amount),
557
+ compareCents: firstVariant.compareAtPrice ? parseCents(firstVariant.compareAtPrice.amount) : null
558
+ });
559
+ }
560
+ afterMutation();
548
561
  function addSelection(product, variant) {
549
562
  if (selections.length >= maxQty) return;
550
563
  selections.push({
@@ -1089,15 +1102,15 @@ function renderVolumeBundle(container, bundle, onAddToCart, onCleanup) {
1089
1102
  if (!variant && wc.outOfStockBehavior === "hide") return;
1090
1103
  const basePriceCents = variant ? parseCents(variant.price.amount) : 0;
1091
1104
  const currency = variant?.price.currencyCode ?? "USD";
1105
+ const discountType = bundle.discountConfig.discountType;
1092
1106
  const resolved = bundle.volumeTiers.map((tier, index) => {
1093
1107
  let perUnit;
1094
- if (tier.discountType === "fixed_amount") {
1095
- const amt = Math.round(tier.discountValue * 100);
1108
+ if (discountType === "fixed_amount") {
1109
+ const amt = Math.round((tier.amount ?? 0) * 100);
1096
1110
  perUnit = Math.max(0, basePriceCents - amt);
1097
1111
  } else {
1098
- const discount = Math.floor(
1099
- basePriceCents * tier.discountValue / 100
1100
- );
1112
+ const pct = tier.percentage ?? 0;
1113
+ const discount = Math.floor(basePriceCents * pct / 100);
1101
1114
  perUnit = Math.max(0, basePriceCents - discount);
1102
1115
  }
1103
1116
  return {
@@ -1115,7 +1128,9 @@ function renderVolumeBundle(container, bundle, onAddToCart, onCleanup) {
1115
1128
  }
1116
1129
  const popularIndex = wc.popularBadge.tierIndex !== void 0 ? clamp(wc.popularBadge.tierIndex, 0, resolved.length - 1) : bestTierIndex;
1117
1130
  const root = el("div", "lb-volume");
1118
- root.appendChild(renderHeader3(bundle, resolved, selectedIndex, currency));
1131
+ root.appendChild(
1132
+ renderHeader3(bundle, resolved, selectedIndex, currency, discountType)
1133
+ );
1119
1134
  if (wc.countdown.showCountdown && bundle.endsAt) {
1120
1135
  const countdown = renderCountdown(bundle.endsAt);
1121
1136
  if (countdown) {
@@ -1216,7 +1231,7 @@ function renderVolumeBundle(container, bundle, onAddToCart, onCleanup) {
1216
1231
  }
1217
1232
  const badgeEl = root.querySelector("[data-header-badge]");
1218
1233
  if (badgeEl) {
1219
- const label = badgeFor(resolved[idx], currency);
1234
+ const label = badgeFor(resolved[idx], currency, discountType);
1220
1235
  if (label) {
1221
1236
  badgeEl.textContent = label;
1222
1237
  badgeEl.style.display = "";
@@ -1226,7 +1241,7 @@ function renderVolumeBundle(container, bundle, onAddToCart, onCleanup) {
1226
1241
  }
1227
1242
  }
1228
1243
  }
1229
- function renderHeader3(bundle, resolved, selectedIndex, currency) {
1244
+ function renderHeader3(bundle, resolved, selectedIndex, currency, discountType) {
1230
1245
  const wc = bundle.widgetConfig;
1231
1246
  const header = el("div", "lb-bundle-header");
1232
1247
  const content = el("div", "lb-bundle-header__content");
@@ -1235,7 +1250,7 @@ function renderHeader3(bundle, resolved, selectedIndex, currency) {
1235
1250
  content.appendChild(title);
1236
1251
  header.appendChild(content);
1237
1252
  if (wc.pricing.showSaveBadge) {
1238
- const badge = badgeFor(resolved[selectedIndex], currency);
1253
+ const badge = badgeFor(resolved[selectedIndex], currency, discountType);
1239
1254
  if (badge) {
1240
1255
  const badgeEl = el("span", "lb-bundle-header__badge", {
1241
1256
  "data-header-badge": ""
@@ -1348,14 +1363,18 @@ function renderCta2(bundle, onClick) {
1348
1363
  });
1349
1364
  return button;
1350
1365
  }
1351
- function badgeFor(resolved, currency) {
1366
+ function badgeFor(resolved, currency, discountType) {
1352
1367
  if (!resolved) return null;
1353
1368
  const { tier } = resolved;
1354
- if (tier.discountType === "fixed_amount" && tier.discountValue > 0) {
1355
- return `-${formatCents(Math.round(tier.discountValue * 100), currency)}`;
1369
+ if (discountType === "fixed_amount") {
1370
+ const amount = tier.amount ?? 0;
1371
+ if (amount > 0) return `-${formatCents(Math.round(amount * 100), currency)}`;
1372
+ return null;
1356
1373
  }
1357
- if (tier.discountType === "percentage" && tier.discountValue > 0) {
1358
- return `-${Math.round(tier.discountValue)}%`;
1374
+ if (discountType === "percentage") {
1375
+ const pct = tier.percentage ?? 0;
1376
+ if (pct > 0) return `-${Math.round(pct)}%`;
1377
+ return null;
1359
1378
  }
1360
1379
  return null;
1361
1380
  }
@@ -1400,6 +1419,10 @@ var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle
1400
1419
  border-radius: var(--lb-radius);
1401
1420
  padding: var(--lb-widget-pad) var(--lb-widget-pad) 20px;
1402
1421
  box-sizing: border-box;
1422
+ /* Cap the widget at a comfortable reading width on desktop. Below
1423
+ 440px viewports the container is already narrower than the cap,
1424
+ so the rule is inert on mobile. */
1425
+ max-width: 440px;
1403
1426
  }
1404
1427
 
1405
1428
  /* Countdown timer bar \u2014 sits below the gradient header */
@@ -2464,6 +2487,103 @@ var BUNDLE_VOLUME_CSS = `/* Lime Bundles \u2014 Volume / Quantity Breaks styles
2464
2487
  }
2465
2488
 
2466
2489
 
2490
+ `;
2491
+ var BUNDLE_SKELETON_CSS = `/* Lime Bundles \u2014 web-component loading skeleton (not mirrored to theme assets) */
2492
+
2493
+ .lb-bundle-widget--loading {
2494
+ display: block;
2495
+ padding: var(--lb-widget-pad, 20px);
2496
+ border: 1px solid var(--lb-border, #E5E5E5);
2497
+ border-radius: var(--lb-radius, 12px);
2498
+ background: var(--lb-bg, #FFFFFF);
2499
+ /* Contain layout/paint so the skeleton doesn't influence ancestor
2500
+ layout once the real content swaps in. */
2501
+ contain: layout paint;
2502
+ }
2503
+
2504
+ .lb-bundle-widget--loading .lb-skeleton {
2505
+ background: linear-gradient(
2506
+ 90deg,
2507
+ rgba(0, 0, 0, 0.06) 0%,
2508
+ rgba(0, 0, 0, 0.10) 50%,
2509
+ rgba(0, 0, 0, 0.06) 100%
2510
+ );
2511
+ background-size: 200% 100%;
2512
+ border-radius: 6px;
2513
+ animation: lb-skeleton-pulse 1.4s ease-in-out infinite;
2514
+ }
2515
+
2516
+ .lb-bundle-widget--loading .lb-skeleton--title {
2517
+ height: 28px;
2518
+ width: 60%;
2519
+ margin-bottom: 16px;
2520
+ }
2521
+
2522
+ .lb-bundle-widget--loading .lb-skeleton--products {
2523
+ display: grid;
2524
+ gap: 12px;
2525
+ margin-bottom: 16px;
2526
+ }
2527
+
2528
+ .lb-bundle-widget--loading .lb-skeleton--row {
2529
+ display: grid;
2530
+ grid-template-columns: 56px 1fr 60px;
2531
+ gap: 12px;
2532
+ align-items: center;
2533
+ }
2534
+
2535
+ .lb-bundle-widget--loading .lb-skeleton--thumb {
2536
+ height: 56px;
2537
+ width: 56px;
2538
+ border-radius: 8px;
2539
+ }
2540
+
2541
+ .lb-bundle-widget--loading .lb-skeleton--line {
2542
+ height: 14px;
2543
+ border-radius: 4px;
2544
+ }
2545
+
2546
+ .lb-bundle-widget--loading .lb-skeleton--line + .lb-skeleton--line {
2547
+ margin-top: 8px;
2548
+ width: 70%;
2549
+ }
2550
+
2551
+ .lb-bundle-widget--loading .lb-skeleton--price {
2552
+ height: 20px;
2553
+ width: 60px;
2554
+ }
2555
+
2556
+ .lb-bundle-widget--loading .lb-skeleton--footer {
2557
+ margin-top: 16px;
2558
+ padding-top: 16px;
2559
+ border-top: 1px solid var(--lb-border, #E5E5E5);
2560
+ display: grid;
2561
+ grid-template-columns: 1fr auto;
2562
+ gap: 12px;
2563
+ align-items: center;
2564
+ }
2565
+
2566
+ .lb-bundle-widget--loading .lb-skeleton--total {
2567
+ height: 24px;
2568
+ width: 40%;
2569
+ }
2570
+
2571
+ .lb-bundle-widget--loading .lb-skeleton--cta {
2572
+ height: 44px;
2573
+ width: 140px;
2574
+ border-radius: var(--lb-cta-radius, 8px);
2575
+ }
2576
+
2577
+ @keyframes lb-skeleton-pulse {
2578
+ 0% { background-position: 0% 50%; }
2579
+ 100% { background-position: -200% 50%; }
2580
+ }
2581
+
2582
+ @media (prefers-reduced-motion: reduce) {
2583
+ .lb-bundle-widget--loading .lb-skeleton {
2584
+ animation: none;
2585
+ }
2586
+ }
2467
2587
  `;
2468
2588
 
2469
2589
  // src/lime-bundle.ts
@@ -2513,7 +2633,6 @@ var LimeBundleElement = class extends HTMLElement {
2513
2633
  this.shadow = this.attachShadow({ mode: "open" });
2514
2634
  }
2515
2635
  connectedCallback() {
2516
- this.render();
2517
2636
  this.fetchBundle();
2518
2637
  }
2519
2638
  disconnectedCallback() {
@@ -2868,9 +2987,39 @@ var LimeBundleElement = class extends HTMLElement {
2868
2987
  renderLoading() {
2869
2988
  this.shadow.innerHTML = `
2870
2989
  <style>${BUNDLE_BASE_CSS}</style>
2871
- <div class="lb-bundle-widget lb-bundle-widget--loading" aria-busy="true">
2990
+ <style>${BUNDLE_SKELETON_CSS}</style>
2991
+ <div class="lb-bundle-widget lb-bundle-widget--loading" aria-busy="true" aria-label="Loading bundle">
2872
2992
  <div class="lb-skeleton lb-skeleton--title"></div>
2873
- <div class="lb-skeleton lb-skeleton--products"></div>
2993
+ <div class="lb-skeleton--products">
2994
+ <div class="lb-skeleton--row">
2995
+ <div class="lb-skeleton lb-skeleton--thumb"></div>
2996
+ <div>
2997
+ <div class="lb-skeleton lb-skeleton--line"></div>
2998
+ <div class="lb-skeleton lb-skeleton--line"></div>
2999
+ </div>
3000
+ <div class="lb-skeleton lb-skeleton--price"></div>
3001
+ </div>
3002
+ <div class="lb-skeleton--row">
3003
+ <div class="lb-skeleton lb-skeleton--thumb"></div>
3004
+ <div>
3005
+ <div class="lb-skeleton lb-skeleton--line"></div>
3006
+ <div class="lb-skeleton lb-skeleton--line"></div>
3007
+ </div>
3008
+ <div class="lb-skeleton lb-skeleton--price"></div>
3009
+ </div>
3010
+ <div class="lb-skeleton--row">
3011
+ <div class="lb-skeleton lb-skeleton--thumb"></div>
3012
+ <div>
3013
+ <div class="lb-skeleton lb-skeleton--line"></div>
3014
+ <div class="lb-skeleton lb-skeleton--line"></div>
3015
+ </div>
3016
+ <div class="lb-skeleton lb-skeleton--price"></div>
3017
+ </div>
3018
+ </div>
3019
+ <div class="lb-skeleton--footer">
3020
+ <div class="lb-skeleton lb-skeleton--total"></div>
3021
+ <div class="lb-skeleton lb-skeleton--cta"></div>
3022
+ </div>
2874
3023
  </div>
2875
3024
  `;
2876
3025
  }
@@ -2884,9 +3033,6 @@ var LimeBundleElement = class extends HTMLElement {
2884
3033
  })
2885
3034
  );
2886
3035
  }
2887
- render() {
2888
- this.shadow.innerHTML = `<style>${BUNDLE_BASE_CSS}</style>`;
2889
- }
2890
3036
  };
2891
3037
 
2892
3038
  // src/index.ts