@lime-bundles/widget 2.3.0 → 2.4.1

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 CHANGED
@@ -20,12 +20,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
- LimeBundleElement: () => LimeBundleElement
23
+ LimeBundleElement: () => LimeBundleElement,
24
+ trackInputMode: () => trackInputMode
24
25
  });
25
26
  module.exports = __toCommonJS(index_exports);
26
27
 
27
28
  // src/lime-bundle.ts
28
- var import_core5 = require("@lime-bundles/core");
29
+ var import_core6 = require("@lime-bundles/core");
29
30
 
30
31
  // src/renderers/fixed.ts
31
32
  var import_core4 = require("@lime-bundles/core");
@@ -211,12 +212,11 @@ function renderFixedBundle(container, bundle, onAddToCart, onCleanup) {
211
212
  }
212
213
  function buildRowState(bundle, product, productIndex) {
213
214
  const selectedVariantIds = bundle.selectedVariantIds?.[productIndex] ?? null;
214
- const available = product.variants.nodes.filter(
215
- (v) => v.availableForSale
216
- );
217
- const eligibleVariants = selectedVariantIds && selectedVariantIds.length > 0 ? available.filter((v) => selectedVariantIds.includes(v.id)) : available;
218
- const isOos = eligibleVariants.length === 0;
219
- const selected = eligibleVariants[0] ?? null;
215
+ const merchantScoped = selectedVariantIds && selectedVariantIds.length > 0 ? product.variants.nodes.filter((v) => selectedVariantIds.includes(v.id)) : product.variants.nodes;
216
+ const firstInStock = merchantScoped.find((v) => v.availableForSale) ?? null;
217
+ const eligibleVariants = merchantScoped;
218
+ const isOos = !firstInStock;
219
+ const selected = firstInStock ?? merchantScoped[0] ?? null;
220
220
  const qty = selected ? (0, import_core4.resolveBundleQty)(bundle, product.id, selected.id) : 1;
221
221
  return { product, eligibleVariants, selected, qty, isOos };
222
222
  }
@@ -365,32 +365,85 @@ function renderProductRow(state, currency, qtyFor, onVariantChange) {
365
365
  };
366
366
  applyVariantToRow(state.selected);
367
367
  if (state.eligibleVariants.length > 1) {
368
- const select = document.createElement("select");
369
- select.className = "lb-bundle-variant-select";
370
- select.setAttribute("data-variant-select", "");
371
- select.setAttribute(
372
- "aria-label",
373
- `Select variant for ${state.product.title}`
368
+ const optionNames = state.eligibleVariants[0].selectedOptions.map(
369
+ (o) => o.name
374
370
  );
375
- state.eligibleVariants.forEach((variant) => {
376
- const opt = document.createElement("option");
377
- opt.value = variant.id;
378
- opt.textContent = variant.title;
379
- if (variant.id === state.selected?.id) opt.selected = true;
380
- select.appendChild(opt);
381
- });
382
- select.addEventListener("change", () => {
383
- const variant = state.eligibleVariants.find(
384
- (v) => v.id === select.value
371
+ const productIdTail = state.product.id.replace(/^.*\//, "");
372
+ const optionSelects = [];
373
+ const resolveVariant = (values) => state.eligibleVariants.find(
374
+ (v) => v.selectedOptions.every((o, i) => o.value === values[i]) && v.selectedOptions.length === values.length
375
+ ) ?? null;
376
+ const syncSelectsToVariant = (variant) => {
377
+ variant.selectedOptions.forEach((o, i) => {
378
+ const sel = optionSelects[i];
379
+ if (sel && sel.value !== o.value) sel.value = o.value;
380
+ });
381
+ };
382
+ const isValueAvailable = (optionIndex, value, selected) => state.eligibleVariants.some((v) => {
383
+ if (!v.availableForSale) return false;
384
+ if (v.selectedOptions[optionIndex]?.value !== value) return false;
385
+ return v.selectedOptions.every(
386
+ (o, i) => i === optionIndex || o.value === selected[i]
385
387
  );
386
- if (!variant) return;
388
+ });
389
+ const recomputeDisabled = (selected) => {
390
+ optionSelects.forEach((sel, i) => {
391
+ Array.from(sel.options).forEach((opt) => {
392
+ opt.disabled = !isValueAvailable(i, opt.value, selected);
393
+ });
394
+ });
395
+ };
396
+ const handleChange = () => {
397
+ const values = optionSelects.map((s) => s.value);
398
+ const variant = resolveVariant(values);
399
+ if (!variant) {
400
+ if (state.selected) {
401
+ syncSelectsToVariant(state.selected);
402
+ recomputeDisabled(state.selected.selectedOptions.map((o) => o.value));
403
+ }
404
+ return;
405
+ }
387
406
  state.selected = variant;
388
407
  state.qty = qtyFor(state.product.id, variant.id);
389
408
  if (qtyBadgeRef) qtyBadgeRef.textContent = String(state.qty);
390
409
  applyVariantToRow(variant);
410
+ recomputeDisabled(variant.selectedOptions.map((o) => o.value));
391
411
  onVariantChange();
412
+ };
413
+ const groupsContainer = el("div", "lb-bundle-variant-option-groups");
414
+ optionNames.forEach((name2, position) => {
415
+ const group = el("div", "lb-bundle-variant-option-group");
416
+ const label = el("span", "lb-bundle-variant-option-label");
417
+ label.textContent = name2;
418
+ group.appendChild(label);
419
+ const select = document.createElement("select");
420
+ select.className = "lb-bundle-variant-select";
421
+ select.setAttribute("data-variant-option", "");
422
+ select.setAttribute("data-option-position", String(position + 1));
423
+ select.name = `lb-variant-${productIdTail}-${position + 1}`;
424
+ select.setAttribute("aria-label", name2);
425
+ const seen = /* @__PURE__ */ new Set();
426
+ state.eligibleVariants.forEach((v) => {
427
+ const value = v.selectedOptions[position]?.value;
428
+ if (!value || seen.has(value)) return;
429
+ seen.add(value);
430
+ const opt = document.createElement("option");
431
+ opt.value = value;
432
+ opt.textContent = value;
433
+ if (state.selected?.selectedOptions[position]?.value === value) {
434
+ opt.selected = true;
435
+ }
436
+ select.appendChild(opt);
437
+ });
438
+ select.addEventListener("change", handleChange);
439
+ optionSelects.push(select);
440
+ group.appendChild(select);
441
+ groupsContainer.appendChild(group);
392
442
  });
393
- info.appendChild(select);
443
+ info.appendChild(groupsContainer);
444
+ if (state.selected) {
445
+ recomputeDisabled(state.selected.selectedOptions.map((o) => o.value));
446
+ }
394
447
  } else if (state.eligibleVariants.length === 1 && state.product.variants.nodes.length > 1) {
395
448
  const badge = el("span", "lb-bundle-variant-badge");
396
449
  badge.textContent = state.eligibleVariants[0].title;
@@ -479,6 +532,7 @@ function computeSale(totalCents, discount, rows) {
479
532
  }
480
533
 
481
534
  // src/renderers/mix-match.ts
535
+ var import_core5 = require("@lime-bundles/core");
482
536
  var PLACEHOLDER_THUMB_SVG2 = `
483
537
  <svg class="lb-bundle-placeholder-icon" viewBox="0 0 28 28" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false">
484
538
  <rect x="4" y="4" width="20" height="20" rx="3"></rect>
@@ -546,9 +600,6 @@ function renderMixMatchBundle(container, bundle, onAddToCart, onCleanup) {
546
600
  showSearch: wc.showSearch,
547
601
  onAdd: (product, variant) => addSelection(product, variant),
548
602
  onRemove: (productId, variantId) => removeSelection(productId, variantId),
549
- countFor: (productId, variantId) => selections.filter(
550
- (s) => s.productId === productId && s.variantId === variantId
551
- ).length,
552
603
  isOverMax: () => selections.length >= maxQty
553
604
  });
554
605
  root.appendChild(modal.el);
@@ -558,7 +609,7 @@ function renderMixMatchBundle(container, bundle, onAddToCart, onCleanup) {
558
609
  if (cta.disabled) return;
559
610
  const lines = selections.map((s) => ({
560
611
  merchandiseId: s.variantId,
561
- quantity: 1,
612
+ quantity: s.quantity,
562
613
  attributes: [
563
614
  { key: "_lime_bundle_gid", value: bundle.id },
564
615
  { key: "_lime_bundle_type", value: bundle.bundleType }
@@ -587,7 +638,13 @@ function renderMixMatchBundle(container, bundle, onAddToCart, onCleanup) {
587
638
  variantTitle: firstVariant.title,
588
639
  imageUrl: firstEligible.product.featuredImage?.url ?? null,
589
640
  priceCents: (0, import_core.parseCents)(firstVariant.price.amount),
590
- compareCents: firstVariant.compareAtPrice ? (0, import_core.parseCents)(firstVariant.compareAtPrice.amount) : null
641
+ compareCents: firstVariant.compareAtPrice ? (0, import_core.parseCents)(firstVariant.compareAtPrice.amount) : null,
642
+ unitPriceLabel: (0, import_core.formatUnitPrice)(
643
+ firstVariant.unitPrice,
644
+ firstVariant.unitPriceMeasurement,
645
+ currency
646
+ ),
647
+ quantity: (0, import_core5.resolveBundleQty)(bundle, firstEligible.product.id, firstVariant.id)
591
648
  });
592
649
  }
593
650
  afterMutation();
@@ -600,7 +657,13 @@ function renderMixMatchBundle(container, bundle, onAddToCart, onCleanup) {
600
657
  variantTitle: variant.title,
601
658
  imageUrl: product.featuredImage?.url ?? null,
602
659
  priceCents: (0, import_core.parseCents)(variant.price.amount),
603
- compareCents: variant.compareAtPrice ? (0, import_core.parseCents)(variant.compareAtPrice.amount) : null
660
+ compareCents: variant.compareAtPrice ? (0, import_core.parseCents)(variant.compareAtPrice.amount) : null,
661
+ unitPriceLabel: (0, import_core.formatUnitPrice)(
662
+ variant.unitPrice,
663
+ variant.unitPriceMeasurement,
664
+ currency
665
+ ),
666
+ quantity: (0, import_core5.resolveBundleQty)(bundle, product.id, variant.id)
604
667
  });
605
668
  afterMutation();
606
669
  }
@@ -767,6 +830,9 @@ function renderFilledSlot(selection, index, currency, onRemove) {
767
830
  } else {
768
831
  thumb.insertAdjacentHTML("beforeend", PLACEHOLDER_THUMB_SVG2);
769
832
  }
833
+ const qtyBadge = el("span", "lb-bundle-qty-badge");
834
+ qtyBadge.textContent = String(selection.quantity);
835
+ thumb.appendChild(qtyBadge);
770
836
  slot.appendChild(thumb);
771
837
  const info = el("div", "lb-mix-match__filled-info");
772
838
  const title = el("span", "lb-mix-match__filled-title");
@@ -777,16 +843,23 @@ function renderFilledSlot(selection, index, currency, onRemove) {
777
843
  variant.textContent = selection.variantTitle;
778
844
  info.appendChild(variant);
779
845
  }
846
+ const linePrice = selection.priceCents * selection.quantity;
847
+ const lineCompare = selection.compareCents !== null ? selection.compareCents * selection.quantity : null;
780
848
  const priceWrap = el("span", "lb-mix-match__filled-price");
781
- if (selection.compareCents && selection.compareCents > selection.priceCents) {
849
+ if (lineCompare !== null && lineCompare > linePrice) {
782
850
  const compare = el("span", "lb-mix-match__filled-compare");
783
- compare.textContent = (0, import_core.formatCents)(selection.compareCents, currency);
851
+ compare.textContent = (0, import_core.formatCents)(lineCompare, currency);
784
852
  priceWrap.appendChild(compare);
785
853
  }
786
854
  const priceEl = document.createElement("span");
787
- priceEl.textContent = (0, import_core.formatCents)(selection.priceCents, currency);
855
+ priceEl.textContent = (0, import_core.formatCents)(linePrice, currency);
788
856
  priceWrap.appendChild(priceEl);
789
857
  info.appendChild(priceWrap);
858
+ if (selection.unitPriceLabel) {
859
+ const unitPrice = el("span", "lb-bundle-product-unit-price");
860
+ unitPrice.textContent = selection.unitPriceLabel;
861
+ info.appendChild(unitPrice);
862
+ }
790
863
  slot.appendChild(info);
791
864
  const remove = document.createElement("button");
792
865
  remove.type = "button";
@@ -820,7 +893,10 @@ function renderPricingSection(showCompareAtPrice) {
820
893
  return;
821
894
  }
822
895
  wrap.style.display = "";
823
- const totalCents = selections.reduce((s, sel) => s + sel.priceCents, 0);
896
+ const totalCents = selections.reduce(
897
+ (s, sel) => s + sel.priceCents * sel.quantity,
898
+ 0
899
+ );
824
900
  const saleCents = (0, import_core.computeBundleSaleCents)(totalCents, bundle.discountConfig);
825
901
  if (showCompareAtPrice && totalCents > saleCents) {
826
902
  compare.textContent = (0, import_core.formatCents)(totalCents, currency);
@@ -847,7 +923,10 @@ function renderSavingsBar2() {
847
923
  wrap.style.display = "none";
848
924
  return;
849
925
  }
850
- const totalCents = selections.reduce((s, sel) => s + sel.priceCents, 0);
926
+ const totalCents = selections.reduce(
927
+ (s, sel) => s + sel.priceCents * sel.quantity,
928
+ 0
929
+ );
851
930
  const saleCents = (0, import_core.computeBundleSaleCents)(totalCents, bundle.discountConfig);
852
931
  const savings = Math.max(0, totalCents - saleCents);
853
932
  if (savings <= 0) {
@@ -941,8 +1020,10 @@ function renderModal(bundle, eligible, currency, handlers) {
941
1020
  rowsBuilt = true;
942
1021
  list.innerHTML = "";
943
1022
  eligible.forEach((ep) => {
944
- const variant = ep.firstAvailableVariant ?? ep.variants[0];
945
- if (!variant) return;
1023
+ const availableVariants = ep.variants;
1024
+ const firstAvailVariant = ep.variants.find((v) => v.availableForSale) ?? ep.firstAvailableVariant ?? ep.variants[0];
1025
+ if (!firstAvailVariant) return;
1026
+ let currentVariant = firstAvailVariant;
946
1027
  const productEl = el(
947
1028
  "div",
948
1029
  ep.isOos ? "lb-mix-match__modal-product lb-mix-match__modal-product--sold-out" : "lb-mix-match__modal-product",
@@ -964,26 +1045,147 @@ function renderModal(bundle, eligible, currency, handlers) {
964
1045
  } else {
965
1046
  thumb.insertAdjacentHTML("beforeend", PLACEHOLDER_THUMB_SVG2);
966
1047
  }
1048
+ const countBadge = el("span", "lb-bundle-qty-badge");
1049
+ countBadge.textContent = String(
1050
+ (0, import_core5.resolveBundleQty)(bundle, ep.product.id, currentVariant.id)
1051
+ );
1052
+ thumb.appendChild(countBadge);
967
1053
  productEl.appendChild(thumb);
968
1054
  const info = el("div", "lb-mix-match__modal-product-info");
969
- const title = el("span", "lb-mix-match__modal-product-title");
1055
+ const title = el("p", "lb-mix-match__modal-product-title");
970
1056
  title.textContent = ep.product.title;
971
1057
  info.appendChild(title);
972
- const price = el("span", "lb-mix-match__modal-product-price");
973
- price.textContent = (0, import_core.formatCents)((0, import_core.parseCents)(variant.price.amount), currency);
1058
+ const price = el("p", "lb-mix-match__modal-product-price");
1059
+ price.textContent = (0, import_core.formatCents)(
1060
+ (0, import_core.parseCents)(currentVariant.price.amount) * (0, import_core5.resolveBundleQty)(bundle, ep.product.id, currentVariant.id),
1061
+ currency
1062
+ );
974
1063
  info.appendChild(price);
975
- const unitPriceText = (0, import_core.formatUnitPrice)(
976
- variant.unitPrice,
977
- variant.unitPriceMeasurement,
1064
+ const unitPrice = el(
1065
+ "p",
1066
+ "lb-mix-match__modal-product-unit-price lb-bundle-product-unit-price"
1067
+ );
1068
+ const initialUnitText = (0, import_core.formatUnitPrice)(
1069
+ currentVariant.unitPrice,
1070
+ currentVariant.unitPriceMeasurement,
978
1071
  currency
979
1072
  );
980
- if (unitPriceText) {
981
- const unitPrice = el(
982
- "span",
983
- "lb-mix-match__modal-product-unit-price lb-bundle-product-unit-price"
1073
+ if (initialUnitText) {
1074
+ unitPrice.textContent = initialUnitText;
1075
+ } else {
1076
+ unitPrice.hidden = true;
1077
+ }
1078
+ info.appendChild(unitPrice);
1079
+ const row = {
1080
+ el: productEl,
1081
+ product: ep.product,
1082
+ variant: firstAvailVariant,
1083
+ updateCount: () => {
1084
+ }
1085
+ };
1086
+ if (availableVariants.length > 1) {
1087
+ const optionNames = availableVariants[0].selectedOptions.map(
1088
+ (o) => o.name
984
1089
  );
985
- unitPrice.textContent = unitPriceText;
986
- info.appendChild(unitPrice);
1090
+ const productIdTail = ep.product.id.replace(/^.*\//, "");
1091
+ const optionSelects = [];
1092
+ const resolveVariant = (values) => availableVariants.find(
1093
+ (v) => v.selectedOptions.length === values.length && v.selectedOptions.every((o, i) => o.value === values[i])
1094
+ ) ?? null;
1095
+ const syncSelectsToVariant = (v) => {
1096
+ v.selectedOptions.forEach((o, i) => {
1097
+ const sel = optionSelects[i];
1098
+ if (sel && sel.value !== o.value) sel.value = o.value;
1099
+ });
1100
+ };
1101
+ const isValueAvailable = (optionIndex, value, selected) => availableVariants.some((v) => {
1102
+ if (!v.availableForSale) return false;
1103
+ if (v.selectedOptions[optionIndex]?.value !== value) return false;
1104
+ return v.selectedOptions.every(
1105
+ (o, i) => i === optionIndex || o.value === selected[i]
1106
+ );
1107
+ });
1108
+ const recomputeDisabled = (selected) => {
1109
+ optionSelects.forEach((sel, i) => {
1110
+ Array.from(sel.options).forEach((opt) => {
1111
+ opt.disabled = !isValueAvailable(i, opt.value, selected);
1112
+ });
1113
+ });
1114
+ };
1115
+ const handleChange = () => {
1116
+ const values = optionSelects.map((s) => s.value);
1117
+ const next = resolveVariant(values);
1118
+ if (!next) {
1119
+ syncSelectsToVariant(currentVariant);
1120
+ recomputeDisabled(
1121
+ currentVariant.selectedOptions.map((o) => o.value)
1122
+ );
1123
+ return;
1124
+ }
1125
+ currentVariant = next;
1126
+ row.variant = next;
1127
+ const nextQty = (0, import_core5.resolveBundleQty)(
1128
+ bundle,
1129
+ ep.product.id,
1130
+ currentVariant.id
1131
+ );
1132
+ price.textContent = (0, import_core.formatCents)(
1133
+ (0, import_core.parseCents)(currentVariant.price.amount) * nextQty,
1134
+ currency
1135
+ );
1136
+ const nextUnitText = (0, import_core.formatUnitPrice)(
1137
+ currentVariant.unitPrice,
1138
+ currentVariant.unitPriceMeasurement,
1139
+ currency
1140
+ );
1141
+ if (nextUnitText) {
1142
+ unitPrice.textContent = nextUnitText;
1143
+ unitPrice.hidden = false;
1144
+ } else {
1145
+ unitPrice.textContent = "";
1146
+ unitPrice.hidden = true;
1147
+ }
1148
+ recomputeDisabled(next.selectedOptions.map((o) => o.value));
1149
+ rowUpdateCount();
1150
+ };
1151
+ const groupsContainer = el("div", "lb-bundle-variant-option-groups");
1152
+ optionNames.forEach((name, position) => {
1153
+ const group = el("div", "lb-bundle-variant-option-group");
1154
+ const label = el("span", "lb-bundle-variant-option-label");
1155
+ label.textContent = name;
1156
+ group.appendChild(label);
1157
+ const select = document.createElement("select");
1158
+ select.className = "lb-mix-match__variant-select";
1159
+ select.setAttribute("data-variant-option", "");
1160
+ select.setAttribute("data-option-position", String(position + 1));
1161
+ select.name = `lb-variant-${productIdTail}-${position + 1}`;
1162
+ select.setAttribute("aria-label", name);
1163
+ const seen = /* @__PURE__ */ new Set();
1164
+ availableVariants.forEach((v) => {
1165
+ const value = v.selectedOptions[position]?.value;
1166
+ if (!value || seen.has(value)) return;
1167
+ seen.add(value);
1168
+ const opt = document.createElement("option");
1169
+ opt.value = value;
1170
+ opt.textContent = value;
1171
+ if (firstAvailVariant.selectedOptions[position]?.value === value) {
1172
+ opt.selected = true;
1173
+ }
1174
+ select.appendChild(opt);
1175
+ });
1176
+ select.addEventListener("change", handleChange);
1177
+ optionSelects.push(select);
1178
+ group.appendChild(select);
1179
+ groupsContainer.appendChild(group);
1180
+ });
1181
+ info.appendChild(groupsContainer);
1182
+ recomputeDisabled(
1183
+ firstAvailVariant.selectedOptions.map((o) => o.value)
1184
+ );
1185
+ } else if (availableVariants.length === 1 && firstAvailVariant.title !== "Default Title") {
1186
+ const variantLabel = el("span", "lb-mix-match__filled-variant");
1187
+ variantLabel.textContent = firstAvailVariant.title;
1188
+ info.appendChild(variantLabel);
987
1189
  }
988
1190
  if (ep.isOos) {
989
1191
  const soldOut = el("span", "lb-mix-match__modal-sold-out-label");
@@ -991,56 +1193,26 @@ function renderModal(bundle, eligible, currency, handlers) {
991
1193
  info.appendChild(soldOut);
992
1194
  }
993
1195
  productEl.appendChild(info);
1196
+ const rowUpdateCount = () => {
1197
+ countBadge.textContent = String(
1198
+ (0, import_core5.resolveBundleQty)(bundle, ep.product.id, currentVariant.id)
1199
+ );
1200
+ };
994
1201
  if (!ep.isOos) {
995
1202
  const addBtn = document.createElement("button");
996
1203
  addBtn.type = "button";
997
1204
  addBtn.className = "lb-mix-match__modal-add";
998
- addBtn.setAttribute("aria-label", `Add ${ep.product.title}`);
999
- addBtn.innerHTML = PLUS_ICON_SVG;
1000
- const countBadge = el("span", "lb-bundle-qty-badge");
1001
- countBadge.style.display = "none";
1002
- addBtn.appendChild(countBadge);
1205
+ addBtn.textContent = "Add";
1003
1206
  addBtn.addEventListener("click", () => {
1004
1207
  if (handlers.isOverMax()) return;
1005
- handlers.onAdd(ep.product, variant);
1208
+ handlers.onAdd(ep.product, currentVariant);
1209
+ close();
1006
1210
  });
1007
1211
  productEl.appendChild(addBtn);
1008
- const removeBtn = document.createElement("button");
1009
- removeBtn.type = "button";
1010
- removeBtn.className = "lb-mix-match__slot-remove";
1011
- removeBtn.setAttribute("aria-label", `Remove one ${ep.product.title}`);
1012
- removeBtn.style.display = "none";
1013
- removeBtn.innerHTML = CLOSE_ICON_SVG;
1014
- removeBtn.addEventListener("click", (e) => {
1015
- e.stopPropagation();
1016
- handlers.onRemove(ep.product.id, variant.id);
1017
- });
1018
- productEl.appendChild(removeBtn);
1019
- productRows.push({
1020
- el: productEl,
1021
- product: ep.product,
1022
- variant,
1023
- updateCount: () => {
1024
- const count = handlers.countFor(ep.product.id, variant.id);
1025
- if (count > 0) {
1026
- countBadge.textContent = String(count);
1027
- countBadge.style.display = "";
1028
- removeBtn.style.display = "";
1029
- } else {
1030
- countBadge.style.display = "none";
1031
- removeBtn.style.display = "none";
1032
- }
1033
- }
1034
- });
1035
- } else {
1036
- productRows.push({
1037
- el: productEl,
1038
- product: ep.product,
1039
- variant,
1040
- updateCount: () => {
1041
- }
1042
- });
1043
1212
  }
1213
+ row.updateCount = ep.isOos ? () => {
1214
+ } : rowUpdateCount;
1215
+ productRows.push(row);
1044
1216
  list.appendChild(productEl);
1045
1217
  });
1046
1218
  refreshCounts();
@@ -1438,7 +1610,62 @@ function clamp(n, min, max) {
1438
1610
  }
1439
1611
 
1440
1612
  // src/lime-bundle.ts
1441
- var import_core6 = require("@lime-bundles/core");
1613
+ var import_core7 = require("@lime-bundles/core");
1614
+
1615
+ // src/utils/input-mode.ts
1616
+ var NAV_KEYS = /* @__PURE__ */ new Set([
1617
+ "Tab",
1618
+ "ArrowUp",
1619
+ "ArrowDown",
1620
+ "ArrowLeft",
1621
+ "ArrowRight",
1622
+ "Home",
1623
+ "End",
1624
+ "PageUp",
1625
+ "PageDown",
1626
+ "Enter",
1627
+ " ",
1628
+ "Escape"
1629
+ ]);
1630
+ var targets = /* @__PURE__ */ new Set();
1631
+ var listenersAttached = false;
1632
+ function setAll(on) {
1633
+ const off = on === "using-mouse" ? "using-keyboard" : "using-mouse";
1634
+ for (const el2 of targets) {
1635
+ el2.classList.add(on);
1636
+ el2.classList.remove(off);
1637
+ }
1638
+ }
1639
+ function onKeyDown(e) {
1640
+ if (NAV_KEYS.has(e.key)) setAll("using-keyboard");
1641
+ }
1642
+ function onPointerDown() {
1643
+ setAll("using-mouse");
1644
+ }
1645
+ function attachListeners() {
1646
+ if (listenersAttached) return;
1647
+ listenersAttached = true;
1648
+ document.addEventListener("keydown", onKeyDown, true);
1649
+ document.addEventListener("pointerdown", onPointerDown, true);
1650
+ }
1651
+ function detachListeners() {
1652
+ if (!listenersAttached) return;
1653
+ listenersAttached = false;
1654
+ document.removeEventListener("keydown", onKeyDown, true);
1655
+ document.removeEventListener("pointerdown", onPointerDown, true);
1656
+ }
1657
+ function trackInputMode(target) {
1658
+ target.classList.add("using-mouse");
1659
+ target.classList.remove("using-keyboard");
1660
+ targets.add(target);
1661
+ attachListeners();
1662
+ return () => {
1663
+ targets.delete(target);
1664
+ target.classList.remove("using-mouse");
1665
+ target.classList.remove("using-keyboard");
1666
+ if (targets.size === 0) detachListeners();
1667
+ };
1668
+ }
1442
1669
 
1443
1670
  // src/styles/bundle-css.ts
1444
1671
  var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle widget types */
@@ -1611,15 +1838,18 @@ var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle
1611
1838
  /* Product rows */
1612
1839
  .lb-bundle-product-row {
1613
1840
  display: flex;
1614
- gap: 12px;
1841
+ gap: 20px;
1615
1842
  padding: 12px 0;
1616
1843
  }
1617
1844
 
1618
1845
  .lb-bundle-thumbnail {
1619
1846
  position: relative;
1620
1847
  width: 48px;
1621
- height: 48px;
1622
1848
  min-width: 48px;
1849
+ /* Aspect-ratio comes from the merchant \`thumbnailRatio\` enum via Liquid;
1850
+ "original" sets it to \`auto\` so the box sizes to the image's intrinsic
1851
+ ratio. Default keeps the historical 1:1 behaviour. */
1852
+ aspect-ratio: var(--lb-thumbnail-aspect-ratio, 1 / 1);
1623
1853
  background: var(--lb-thumbnail-bg);
1624
1854
  border-radius: 8px;
1625
1855
  overflow: hidden;
@@ -1630,8 +1860,10 @@ var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle
1630
1860
 
1631
1861
  .lb-bundle-thumbnail img {
1632
1862
  width: 100%;
1633
- height: 100%;
1634
- object-fit: cover;
1863
+ /* Height + fit come from the same merchant enum; "original" sets them to
1864
+ \`auto\` / \`contain\` so the image renders uncropped at intrinsic ratio. */
1865
+ height: var(--lb-thumbnail-img-height, 100%);
1866
+ object-fit: var(--lb-thumbnail-img-fit, cover);
1635
1867
  }
1636
1868
 
1637
1869
  .lb-bundle-thumbnail svg {
@@ -1662,7 +1894,7 @@ var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle
1662
1894
  .lb-bundle-product-price {
1663
1895
  /* --lb-product-price-display fallback is the "on" branch; Liquid sets 'none' when merchant disables. */
1664
1896
  display: var(--lb-product-price-display, block);
1665
- font-size: 12px;
1897
+ font-size: 14px;
1666
1898
  font-weight: 400;
1667
1899
  line-height: 20px;
1668
1900
  color: var(--lb-text);
@@ -1679,7 +1911,7 @@ var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle
1679
1911
  .lb-bundle-product-compare-price {
1680
1912
  /* --lb-product-compare-display fallback is the "on" branch; Liquid sets 'none' when merchant disables. */
1681
1913
  display: var(--lb-product-compare-display, inline);
1682
- font-size: 12px;
1914
+ font-size: 14px;
1683
1915
  font-weight: 400;
1684
1916
  line-height: 20px;
1685
1917
  color: color-mix(in srgb, var(--lb-text) 60%, transparent);
@@ -1698,7 +1930,7 @@ var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle
1698
1930
  secondary text beneath the price row so it doesn't compete visually. */
1699
1931
  .lb-bundle-product-unit-price {
1700
1932
  display: block;
1701
- font-size: 11px;
1933
+ font-size: 12px;
1702
1934
  line-height: 16px;
1703
1935
  color: color-mix(in srgb, var(--lb-text) 60%, transparent);
1704
1936
  margin-top: 2px;
@@ -1719,6 +1951,56 @@ var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle
1719
1951
  margin-top: 8px;
1720
1952
  }
1721
1953
 
1954
+ /* Per-option variant pickers. Each option's label + select sit inside a
1955
+ .lb-bundle-variant-option-group (flex column, 2px gap between label and
1956
+ select); the groups stack inside a .lb-bundle-variant-option-groups
1957
+ parent (flex column, 12px gap between groups). The parent owns the top
1958
+ offset from the preceding unit-price line, so individual labels and
1959
+ selects don't carry their own vertical margins. */
1960
+ .lb-bundle-variant-option-groups {
1961
+ display: flex;
1962
+ flex-direction: column;
1963
+ gap: 12px;
1964
+ margin-top: 8px;
1965
+ }
1966
+
1967
+ .lb-bundle-variant-option-group {
1968
+ display: flex;
1969
+ flex-direction: column;
1970
+ gap: 2px;
1971
+ }
1972
+
1973
+ .lb-bundle-variant-option-label {
1974
+ display: block;
1975
+ margin: 0;
1976
+ font-size: 12px;
1977
+ line-height: 16px;
1978
+ font-weight: 600;
1979
+ letter-spacing: 0.05em;
1980
+ text-transform: uppercase;
1981
+ color: color-mix(in srgb, var(--lb-text) 60%, transparent);
1982
+ }
1983
+
1984
+ .lb-mix-match__modal-product-info .lb-bundle-variant-option-groups {
1985
+ margin-top: 4px;
1986
+ }
1987
+
1988
+ /* Focus-ring suppression for mouse users. A small JS helper \u2014 see
1989
+ packages/widget/src/utils/input-mode.ts and bundle-widget.js \u2014 toggles
1990
+ .using-mouse / .using-keyboard on the widget root (or html in the Liquid
1991
+ path) based on the customer's current input device. Default is mouse, so
1992
+ click-to-focus doesn't leave a keyboard-style ring. The modal overlay
1993
+ gets its own selector because the Liquid path reparents it to body,
1994
+ outside the widget root. */
1995
+ .using-mouse .lb-bundle-widget :focus,
1996
+ .using-mouse .lb-bundle-widget :focus-visible,
1997
+ .using-mouse .lb-mix-match__modal-overlay :focus,
1998
+ .using-mouse .lb-mix-match__modal-overlay :focus-visible {
1999
+ outline: none;
2000
+ outline-offset: 0;
2001
+ box-shadow: none;
2002
+ }
2003
+
1722
2004
  .lb-bundle-quantity {
1723
2005
  font-size: 12px;
1724
2006
  line-height: 16px;
@@ -1821,7 +2103,7 @@ var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle
1821
2103
  grid-template-rows: 1fr;
1822
2104
  grid-template-columns: 1fr;
1823
2105
  width: 100%;
1824
- padding: 16px;
2106
+ padding: 12px 16px;
1825
2107
  border: var(--lb-cta-border-width) solid var(--lb-cta-border-color);
1826
2108
  border-radius: var(--lb-cta-radius);
1827
2109
  font-size: 16px;
@@ -1956,14 +2238,14 @@ var BUNDLE_FIXED_CSS = `/* Lime Bundles \u2014 Fixed bundle styles */
1956
2238
 
1957
2239
  /* Fixed bundles: product rows */
1958
2240
  .lb-fixed .lb-bundle-product-row {
1959
- gap: 16px;
2241
+ gap: 20px;
1960
2242
  align-items: center;
1961
2243
  }
1962
2244
 
1963
- /* Fixed bundles: larger thumbnails */
2245
+ /* Fixed bundles: larger thumbnails. Height comes from --lb-thumbnail-aspect-ratio
2246
+ (set on .lb-bundle-widget via Liquid / applyWidgetConfigVars). */
1964
2247
  .lb-fixed .lb-bundle-thumbnail {
1965
2248
  width: 60px;
1966
- height: 60px;
1967
2249
  min-width: 60px;
1968
2250
  border-radius: var(--lb-image-border-radius);
1969
2251
  border: var(--lb-image-border-width) solid var(--lb-image-border-color);
@@ -1976,9 +2258,10 @@ var BUNDLE_FIXED_CSS = `/* Lime Bundles \u2014 Fixed bundle styles */
1976
2258
  border: none;
1977
2259
  }
1978
2260
 
1979
- /* Variant picker select \u2014 styled to match the variant badge aesthetic */
2261
+ /* Variant picker select \u2014 styled to match the variant badge aesthetic.
2262
+ Sits inside .lb-bundle-variant-option-group so vertical spacing is owned
2263
+ by the group/groups flex gap, not the select itself. */
1980
2264
  .lb-bundle-variant-select {
1981
- margin-top: 8px;
1982
2265
  display: inline-block;
1983
2266
  border: var(--lb-variant-border-width) solid var(--lb-variant-border-color);
1984
2267
  border-radius: var(--lb-variant-radius);
@@ -1995,7 +2278,8 @@ var BUNDLE_FIXED_CSS = `/* Lime Bundles \u2014 Fixed bundle styles */
1995
2278
  background-repeat: no-repeat;
1996
2279
  background-position: right 8px center;
1997
2280
  background-size: 12px;
1998
- max-width: 100%;
2281
+ width: 50%;
2282
+ max-width: 50%;
1999
2283
  }
2000
2284
 
2001
2285
  .lb-bundle-variant-select:focus-visible {
@@ -2064,7 +2348,10 @@ var BUNDLE_MIX_MATCH_CSS = `/* Lime Bundles \u2014 Mix & Match styles */
2064
2348
  width: 60px;
2065
2349
  height: 60px;
2066
2350
  min-width: 60px;
2067
- border: var(--lb-image-border-width) dashed color-mix(in srgb, var(--lb-text) 20%, transparent);
2351
+ /* 2px border is intentionally independent of --lb-image-border-width \u2014
2352
+ empty slots always need a visible dashed outline as an affordance,
2353
+ regardless of how the merchant has styled populated thumbnails. */
2354
+ border: 2px dashed color-mix(in srgb, var(--lb-text) 35%, transparent);
2068
2355
  border-radius: var(--lb-image-border-radius);
2069
2356
  box-sizing: border-box;
2070
2357
  display: flex;
@@ -2084,9 +2371,10 @@ var BUNDLE_MIX_MATCH_CSS = `/* Lime Bundles \u2014 Mix & Match styles */
2084
2371
  cursor: default;
2085
2372
  }
2086
2373
 
2374
+ /* Mix-match thumbnails. Height comes from --lb-thumbnail-aspect-ratio
2375
+ (set on .lb-bundle-widget via Liquid / applyWidgetConfigVars). */
2087
2376
  .lb-mix-match .lb-bundle-thumbnail {
2088
2377
  width: 60px;
2089
- height: 60px;
2090
2378
  min-width: 60px;
2091
2379
  border-radius: var(--lb-image-border-radius);
2092
2380
  border: var(--lb-image-border-width) solid var(--lb-image-border-color);
@@ -2321,7 +2609,7 @@ var BUNDLE_MIX_MATCH_CSS = `/* Lime Bundles \u2014 Mix & Match styles */
2321
2609
  .lb-mix-match__modal-product {
2322
2610
  display: flex;
2323
2611
  align-items: center;
2324
- gap: 12px;
2612
+ gap: 20px;
2325
2613
  padding: 12px 0;
2326
2614
  border-bottom: 1px solid color-mix(in srgb, var(--lb-picker-text) 7%, transparent);
2327
2615
  }
@@ -2333,8 +2621,11 @@ var BUNDLE_MIX_MATCH_CSS = `/* Lime Bundles \u2014 Mix & Match styles */
2333
2621
  .lb-mix-match__modal-product-thumb {
2334
2622
  position: relative;
2335
2623
  width: 48px;
2336
- height: 48px;
2337
2624
  min-width: 48px;
2625
+ /* Modal picker thumbs follow the merchant's pickerThumbnailRatio \u2014
2626
+ independent from the main widget's thumbnailRatio so a merchant can
2627
+ e.g. show tall picker thumbs with square main thumbs. */
2628
+ aspect-ratio: var(--lb-picker-thumbnail-aspect-ratio, 1 / 1);
2338
2629
  border-radius: var(--lb-picker-product-radius);
2339
2630
  border: var(--lb-picker-product-border-width) solid var(--lb-picker-product-border-color);
2340
2631
  box-sizing: border-box;
@@ -2355,8 +2646,10 @@ var BUNDLE_MIX_MATCH_CSS = `/* Lime Bundles \u2014 Mix & Match styles */
2355
2646
 
2356
2647
  .lb-mix-match__modal-product-thumb img {
2357
2648
  width: 100%;
2358
- height: 100%;
2359
- object-fit: cover;
2649
+ /* Height + fit come from pickerThumbnailRatio \u2014 "original" sets both
2650
+ to auto/contain so the image renders uncropped at intrinsic ratio. */
2651
+ height: var(--lb-picker-thumbnail-img-height, 100%);
2652
+ object-fit: var(--lb-picker-thumbnail-img-fit, cover);
2360
2653
  border-radius: max(0px, calc(var(--lb-picker-product-radius) - var(--lb-picker-product-border-width)));
2361
2654
  }
2362
2655
 
@@ -2393,7 +2686,6 @@ var BUNDLE_MIX_MATCH_CSS = `/* Lime Bundles \u2014 Mix & Match styles */
2393
2686
 
2394
2687
  .lb-mix-match__variant-select {
2395
2688
  font-size: 12px;
2396
- margin: 4px 0 0;
2397
2689
  padding: 4px 24px 4px 8px;
2398
2690
  border: var(--lb-picker-variant-border-width) solid var(--lb-picker-variant-border-color);
2399
2691
  border-radius: var(--lb-picker-variant-radius);
@@ -2406,7 +2698,8 @@ var BUNDLE_MIX_MATCH_CSS = `/* Lime Bundles \u2014 Mix & Match styles */
2406
2698
  font-family: inherit;
2407
2699
  min-height: 32px;
2408
2700
  cursor: pointer;
2409
- max-width: 120px;
2701
+ width: 50%;
2702
+ max-width: 50%;
2410
2703
  appearance: none;
2411
2704
  -webkit-appearance: none;
2412
2705
  }
@@ -2490,6 +2783,11 @@ var BUNDLE_MIX_MATCH_CSS = `/* Lime Bundles \u2014 Mix & Match styles */
2490
2783
  .lb-mix-match__modal-overlay--open .lb-mix-match__modal {
2491
2784
  transform: translateY(0);
2492
2785
  }
2786
+
2787
+ .lb-mix-match__variant-select {
2788
+ width: 80%;
2789
+ max-width: 80%;
2790
+ }
2493
2791
  }
2494
2792
 
2495
2793
  /* === Reduced Motion === */
@@ -2591,7 +2889,7 @@ var BUNDLE_VOLUME_CSS = `/* Lime Bundles \u2014 Volume / Quantity Breaks styles
2591
2889
 
2592
2890
  .lb-volume__tier-price {
2593
2891
  grid-column: 1 / -1;
2594
- font-size: 12px;
2892
+ font-size: 14px;
2595
2893
  font-weight: 500;
2596
2894
  color: var(--lb-text);
2597
2895
  }
@@ -2603,7 +2901,7 @@ var BUNDLE_VOLUME_CSS = `/* Lime Bundles \u2014 Volume / Quantity Breaks styles
2603
2901
 
2604
2902
  /* Compare-at (strikethrough) price */
2605
2903
  .lb-volume__tier-compare {
2606
- font-size: 12px;
2904
+ font-size: 14px;
2607
2905
  line-height: 16px;
2608
2906
  color: color-mix(in srgb, var(--lb-text) 60%, transparent);
2609
2907
  text-decoration: line-through;
@@ -2809,7 +3107,7 @@ var LimeBundleElement = class extends HTMLElement {
2809
3107
  const controller = new AbortController();
2810
3108
  this.abortController = controller;
2811
3109
  this.renderLoading();
2812
- const client = (0, import_core5.createStorefrontClient)({
3110
+ const client = (0, import_core6.createStorefrontClient)({
2813
3111
  shopDomain: this.shopDomain,
2814
3112
  accessToken: this.storefrontToken
2815
3113
  });
@@ -2834,7 +3132,7 @@ var LimeBundleElement = class extends HTMLElement {
2834
3132
  handle
2835
3133
  );
2836
3134
  }
2837
- const cssPromise = client.query(import_core5.SHOP_CUSTOM_CSS_QUERY, void 0, {
3135
+ const cssPromise = client.query(import_core6.SHOP_CUSTOM_CSS_QUERY, void 0, {
2838
3136
  signal: controller.signal
2839
3137
  }).catch(() => null);
2840
3138
  await bundlePromise;
@@ -2846,8 +3144,8 @@ var LimeBundleElement = class extends HTMLElement {
2846
3144
  }
2847
3145
  const css = await cssPromise;
2848
3146
  if (css?.shop?.metafield?.value) {
2849
- (0, import_core5.injectCustomCss)(this.shopDomain, css.shop.metafield.value);
2850
- const sanitized = (0, import_core5.sanitizeCustomCss)(css.shop.metafield.value);
3147
+ (0, import_core6.injectCustomCss)(this.shopDomain, css.shop.metafield.value);
3148
+ const sanitized = (0, import_core6.sanitizeCustomCss)(css.shop.metafield.value);
2851
3149
  if (sanitized.ok) this.shopCustomCss = sanitized.css;
2852
3150
  }
2853
3151
  await this.applyABVariants();
@@ -2875,14 +3173,14 @@ var LimeBundleElement = class extends HTMLElement {
2875
3173
  this.bundles.map(async (bundle) => {
2876
3174
  if (!bundle.abTestId || !bundle.abVariantB) return bundle;
2877
3175
  try {
2878
- const assignment = await (0, import_core5.getABTestAssignment)(
3176
+ const assignment = await (0, import_core6.getABTestAssignment)(
2879
3177
  this.appUrl,
2880
3178
  this.shopDomain,
2881
3179
  bundle.abTestId,
2882
3180
  bundle.id
2883
3181
  );
2884
3182
  if (assignment?.variant === "B") {
2885
- return (0, import_core5.applyABVariantB)(bundle);
3183
+ return (0, import_core6.applyABVariantB)(bundle);
2886
3184
  }
2887
3185
  } catch (err) {
2888
3186
  console.warn(
@@ -2897,7 +3195,7 @@ var LimeBundleElement = class extends HTMLElement {
2897
3195
  }
2898
3196
  async fetchSingleBundle(client, signal) {
2899
3197
  const data = await client.query(
2900
- import_core5.BUNDLE_METAOBJECT_QUERY,
3198
+ import_core6.BUNDLE_METAOBJECT_QUERY,
2901
3199
  { id: this.bundleGid },
2902
3200
  { signal }
2903
3201
  );
@@ -2905,7 +3203,7 @@ var LimeBundleElement = class extends HTMLElement {
2905
3203
  this.bundles = [];
2906
3204
  return;
2907
3205
  }
2908
- const parsed = (0, import_core5.parseMetaobjectBundle)(
3206
+ const parsed = (0, import_core6.parseMetaobjectBundle)(
2909
3207
  data.metaobject.id,
2910
3208
  data.metaobject.fields
2911
3209
  );
@@ -2913,7 +3211,7 @@ var LimeBundleElement = class extends HTMLElement {
2913
3211
  }
2914
3212
  async fetchProductBundles(client, signal, productHandle) {
2915
3213
  const data = await client.query(
2916
- import_core5.BUNDLES_FOR_PRODUCT_QUERY,
3214
+ import_core6.BUNDLES_FOR_PRODUCT_QUERY,
2917
3215
  { handle: productHandle },
2918
3216
  { signal }
2919
3217
  );
@@ -2924,7 +3222,7 @@ var LimeBundleElement = class extends HTMLElement {
2924
3222
  const refs = data.product.metafield?.references?.nodes ?? [];
2925
3223
  const bundles = [];
2926
3224
  for (const ref of refs) {
2927
- const parsed = (0, import_core5.parseMetaobjectBundle)(ref.id, ref.fields);
3225
+ const parsed = (0, import_core6.parseMetaobjectBundle)(ref.id, ref.fields);
2928
3226
  if (parsed) bundles.push(parsed);
2929
3227
  }
2930
3228
  this.bundles = bundles;
@@ -2957,7 +3255,7 @@ var LimeBundleElement = class extends HTMLElement {
2957
3255
  */
2958
3256
  async defaultAddToCart(lines) {
2959
3257
  if (typeof window === "undefined") return;
2960
- const client = (0, import_core5.createStorefrontClient)({
3258
+ const client = (0, import_core6.createStorefrontClient)({
2961
3259
  shopDomain: this.shopDomain,
2962
3260
  accessToken: this.storefrontToken
2963
3261
  });
@@ -2968,7 +3266,7 @@ var LimeBundleElement = class extends HTMLElement {
2968
3266
  let checkoutUrl = null;
2969
3267
  if (existingCartId) {
2970
3268
  const res = await client.query(
2971
- import_core5.CART_LINES_ADD_MUTATION,
3269
+ import_core6.CART_LINES_ADD_MUTATION,
2972
3270
  { cartId: existingCartId, lines }
2973
3271
  );
2974
3272
  const payload = res.cartLinesAdd;
@@ -2980,7 +3278,7 @@ var LimeBundleElement = class extends HTMLElement {
2980
3278
  }
2981
3279
  if (!checkoutUrl) {
2982
3280
  const res = await client.query(
2983
- import_core5.CART_CREATE_MUTATION,
3281
+ import_core6.CART_CREATE_MUTATION,
2984
3282
  { input: { lines } }
2985
3283
  );
2986
3284
  const payload = res.cartCreate;
@@ -3026,7 +3324,7 @@ var LimeBundleElement = class extends HTMLElement {
3026
3324
  const price = variant ? parseFloat(variant.price.amount) : 0;
3027
3325
  return sum + price * line.quantity;
3028
3326
  }, 0);
3029
- (0, import_core5.reportAddToCart)(
3327
+ (0, import_core6.reportAddToCart)(
3030
3328
  { shopDomain: this.shopDomain, appUrl: this.appUrl },
3031
3329
  {
3032
3330
  bundleGid: bundle.id,
@@ -3062,7 +3360,8 @@ var LimeBundleElement = class extends HTMLElement {
3062
3360
  container.setAttribute("aria-label", bundle.title);
3063
3361
  container.setAttribute("data-bundle-type", bundle.bundleType);
3064
3362
  container.setAttribute("data-bundle-gid", bundle.id);
3065
- (0, import_core6.applyWidgetConfigVars)(container, bundle.widgetConfig);
3363
+ (0, import_core7.applyWidgetConfigVars)(container, bundle.widgetConfig);
3364
+ this.renderCleanups.push(trackInputMode(container));
3066
3365
  const dispatch = (lines) => this.handleAddToCart(bundle, lines);
3067
3366
  const registerCleanup = (fn) => this.renderCleanups.push(fn);
3068
3367
  switch (bundle.bundleType) {
@@ -3097,8 +3396,8 @@ var LimeBundleElement = class extends HTMLElement {
3097
3396
  }
3098
3397
  setupImpressionFor(bundle, element) {
3099
3398
  if (!this.analyticsEnabled || !this.appUrl) return;
3100
- const cleanup = (0, import_core5.observeImpression)(element, () => {
3101
- (0, import_core5.reportImpression)(
3399
+ const cleanup = (0, import_core6.observeImpression)(element, () => {
3400
+ (0, import_core6.reportImpression)(
3102
3401
  { shopDomain: this.shopDomain, appUrl: this.appUrl },
3103
3402
  {
3104
3403
  bundleGid: bundle.id,
@@ -3165,6 +3464,7 @@ if (typeof customElements !== "undefined" && !customElements.get("lime-bundle"))
3165
3464
  }
3166
3465
  // Annotate the CommonJS export names for ESM import in node:
3167
3466
  0 && (module.exports = {
3168
- LimeBundleElement
3467
+ LimeBundleElement,
3468
+ trackInputMode
3169
3469
  });
3170
3470
  //# sourceMappingURL=index.cjs.map