@lime-bundles/widget 4.2.0 → 4.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/README.md CHANGED
@@ -58,6 +58,7 @@ document.querySelector("lime-bundle").addEventListener(
58
58
  | `storefront-token` | ✓ | Storefront Access Token from `/app/settings/headless`. |
59
59
  | `bundle-gid` | | Render one specific bundle. Overrides auto-detect. |
60
60
  | `product-handle` | | Render bundles for this handle. Overrides URL detection. |
61
+ | `product-id` | | The product this embed is standing on — full GID or bare numeric id. Volume bundles price and sell this product; falls back to the handle cascade, then the bundle's first product. |
61
62
  | `app-url` | | Enables impression + add-to-cart analytics when set. |
62
63
  | `analytics` | | `"false"` suppresses analytics even when `app-url` is set. |
63
64
  | `locale` | | BCP-47 tag forwarded to the Storefront API. |
@@ -67,6 +68,8 @@ document.querySelector("lime-bundle").addEventListener(
67
68
 
68
69
  **Product resolution** (when `bundle-gid` is absent): explicit `product-handle` → `<meta name="shopify:product-handle">` → `/products/<handle>` URL segment.
69
70
 
71
+ **Multi-product binding**: a volume bundle can span several products, and the widget prices and sells the one the shopper is looking at: explicit `product-id` → the handle cascade above → the bundle's first product. On a pinned `bundle-gid` embed outside a `/products/<handle>` URL, set `product-id` (or `product-handle`) or the first product is what gets sold.
72
+
70
73
  Changing any attribute at runtime re-fetches and re-renders.
71
74
 
72
75
  ### B2B buyer identity (programmatic property only)
package/dist/index.cjs CHANGED
@@ -28,6 +28,28 @@ module.exports = __toCommonJS(index_exports);
28
28
  // src/lime-bundle.ts
29
29
  var import_core6 = require("@lime-bundles/core");
30
30
 
31
+ // ../render/src/host.ts
32
+ function intlFormatMoney(currencyCode) {
33
+ return (cents) => {
34
+ try {
35
+ return new Intl.NumberFormat(void 0, {
36
+ style: "currency",
37
+ currency: currencyCode
38
+ }).format(cents / 100);
39
+ } catch {
40
+ return currencyCode + " " + (cents / 100).toFixed(2);
41
+ }
42
+ };
43
+ }
44
+ var BUNDLE_GID_ATTRIBUTE = "_lime_bundle_gid";
45
+ var BUNDLE_TYPE_ATTRIBUTE = "_lime_bundle_type";
46
+ function bundleLineAttributes(bundleGid, bundleType) {
47
+ return [
48
+ { key: BUNDLE_GID_ATTRIBUTE, value: bundleGid },
49
+ { key: BUNDLE_TYPE_ATTRIBUTE, value: bundleType }
50
+ ];
51
+ }
52
+
31
53
  // ../render/src/adapt.ts
32
54
  var import_core = require("@lime-bundles/core");
33
55
  function numericId(gid) {
@@ -230,28 +252,6 @@ function recalcPricing(container, products, formatMoney) {
230
252
  }
231
253
  }
232
254
 
233
- // ../render/src/host.ts
234
- function intlFormatMoney(currencyCode) {
235
- return (cents) => {
236
- try {
237
- return new Intl.NumberFormat(void 0, {
238
- style: "currency",
239
- currency: currencyCode
240
- }).format(cents / 100);
241
- } catch {
242
- return currencyCode + " " + (cents / 100).toFixed(2);
243
- }
244
- };
245
- }
246
- var BUNDLE_GID_ATTRIBUTE = "_lime_bundle_gid";
247
- var BUNDLE_TYPE_ATTRIBUTE = "_lime_bundle_type";
248
- function bundleLineAttributes(bundleGid, bundleType) {
249
- return [
250
- { key: BUNDLE_GID_ATTRIBUTE, value: bundleGid },
251
- { key: BUNDLE_TYPE_ATTRIBUTE, value: bundleType }
252
- ];
253
- }
254
-
255
255
  // ../render/src/product/option-selects.ts
256
256
  function bindVariantSelects(row, getProduct, onSelected) {
257
257
  const optionSelects = row.querySelectorAll("[data-variant-option]");
@@ -2939,9 +2939,9 @@ function selectTier(container, allTiers, basePrice, discountType, index, transla
2939
2939
  }
2940
2940
 
2941
2941
  // src/renderers/volume.ts
2942
- function renderVolumeBundle(container, bundle, onAddToCart) {
2942
+ function renderVolumeBundle(container, bundle, onAddToCart, productContext) {
2943
2943
  const wc = bundle.widgetConfig;
2944
- const product = bundle.products[0];
2944
+ const product = (0, import_core4.resolveContextProduct)(bundle.products, productContext);
2945
2945
  if (!product) return;
2946
2946
  const variants = product.variants.nodes;
2947
2947
  const minTierQty = Math.min(
@@ -6737,6 +6737,7 @@ var LimeBundleElement = class extends HTMLElement {
6737
6737
  "storefront-token",
6738
6738
  "bundle-gid",
6739
6739
  "product-handle",
6740
+ "product-id",
6740
6741
  "app-url",
6741
6742
  "analytics",
6742
6743
  "locale",
@@ -6797,7 +6798,7 @@ var LimeBundleElement = class extends HTMLElement {
6797
6798
  }
6798
6799
  attributeChangedCallback(name, oldValue, newValue) {
6799
6800
  if (oldValue === newValue || !this.isConnected) return;
6800
- if (name === "bundle-gid" || name === "product-handle" || name === "shop-domain" || name === "storefront-token") {
6801
+ if (name === "bundle-gid" || name === "product-handle" || name === "product-id" || name === "shop-domain" || name === "storefront-token") {
6801
6802
  if (this.shopDomain && this.storefrontToken) {
6802
6803
  this.fetchBundle();
6803
6804
  }
@@ -6815,6 +6816,16 @@ var LimeBundleElement = class extends HTMLElement {
6815
6816
  get productHandleAttr() {
6816
6817
  return this.getAttribute("product-handle") ?? "";
6817
6818
  }
6819
+ /**
6820
+ * The current product's id — full GID (`gid://shopify/Product/123`) or
6821
+ * bare numeric id. Tells multi-product renderers (volume) which of the
6822
+ * bundle's products this embed is standing on; takes precedence over the
6823
+ * handle cascade. Without it (and with no resolvable handle) they bind to
6824
+ * the bundle's first product.
6825
+ */
6826
+ get productIdAttr() {
6827
+ return this.getAttribute("product-id") ?? "";
6828
+ }
6818
6829
  get appUrl() {
6819
6830
  return this.getAttribute("app-url") ?? "";
6820
6831
  }
@@ -6988,7 +6999,7 @@ var LimeBundleElement = class extends HTMLElement {
6988
6999
  });
6989
7000
  const storage = window.localStorage;
6990
7001
  const key = cartStorageKey(this.shopDomain);
6991
- const existingCartId = storage?.getItem(key) ?? null;
7002
+ let cartId = storage?.getItem(key) ?? null;
6992
7003
  const isStaleCartError = (errors) => errors.length > 0 && errors.every((e) => (e.field ?? []).includes("cartId"));
6993
7004
  const stockCapped = (warnings) => (warnings ?? []).some((w) => w.code === "MERCHANDISE_NOT_ENOUGH_STOCK");
6994
7005
  const fail = (message) => {
@@ -7002,10 +7013,17 @@ var LimeBundleElement = class extends HTMLElement {
7002
7013
  };
7003
7014
  try {
7004
7015
  let checkoutUrl = null;
7005
- if (existingCartId) {
7016
+ if (cartId) {
7017
+ cartId = await this.clearAbandonedBundleLines(
7018
+ client,
7019
+ cartId,
7020
+ () => storage?.removeItem(key)
7021
+ );
7022
+ }
7023
+ if (cartId) {
7006
7024
  const res = await client.query(
7007
7025
  import_core6.CART_LINES_ADD_MUTATION,
7008
- { cartId: existingCartId, lines }
7026
+ { cartId, lines }
7009
7027
  );
7010
7028
  const payload = res.cartLinesAdd;
7011
7029
  if (payload?.userErrors?.length) {
@@ -7058,6 +7076,42 @@ var LimeBundleElement = class extends HTMLElement {
7058
7076
  );
7059
7077
  }
7060
7078
  }
7079
+ /**
7080
+ * Remove this widget's own earlier lines — the ones tagged with the
7081
+ * `_lime_bundle_gid` attribute — from the saved cart, so a shopper who
7082
+ * clicked add three times while deciding checks out with only what they
7083
+ * just built. Lines without the tag were put in the cart by something
7084
+ * else (the host site, a previous non-widget purchase flow) and are
7085
+ * left alone.
7086
+ *
7087
+ * Returns the cart id when the cart is still usable. Returns null after
7088
+ * calling `dropSavedCart` when it isn't: either the id no longer
7089
+ * resolves (expired or merged on Shopify's side), or the removal itself
7090
+ * failed — in both cases a fresh cart is the only way to guarantee the
7091
+ * checkout matches the shopper's current build.
7092
+ */
7093
+ async clearAbandonedBundleLines(client, cartId, dropSavedCart) {
7094
+ const res = await client.query(import_core6.CART_LINES_QUERY, {
7095
+ cartId
7096
+ });
7097
+ if (!res.cart) {
7098
+ dropSavedCart();
7099
+ return null;
7100
+ }
7101
+ const abandonedLineIds = res.cart.lines.nodes.filter(
7102
+ (line) => line.attributes.some((attr) => attr.key === BUNDLE_GID_ATTRIBUTE)
7103
+ ).map((line) => line.id);
7104
+ if (abandonedLineIds.length === 0) return cartId;
7105
+ const removal = await client.query(
7106
+ import_core6.CART_LINES_REMOVE_MUTATION,
7107
+ { cartId, lineIds: abandonedLineIds }
7108
+ );
7109
+ if (removal.cartLinesRemove?.userErrors?.length) {
7110
+ dropSavedCart();
7111
+ return null;
7112
+ }
7113
+ return cartId;
7114
+ }
7061
7115
  reportAddToCartEvent(bundle, lines) {
7062
7116
  if (!this.analyticsEnabled || !this.appUrl) return;
7063
7117
  const quantity = lines.reduce((sum, l) => sum + l.quantity, 0);
@@ -7129,7 +7183,10 @@ var LimeBundleElement = class extends HTMLElement {
7129
7183
  );
7130
7184
  break;
7131
7185
  case "volume":
7132
- renderVolumeBundle(container, bundle, dispatch);
7186
+ renderVolumeBundle(container, bundle, dispatch, {
7187
+ productId: this.productIdAttr || null,
7188
+ productHandle: this.currentProductHandle
7189
+ });
7133
7190
  break;
7134
7191
  case "bogo":
7135
7192
  renderBogoBundle(container, bundle, dispatch, registerCleanup);
package/dist/index.d.cts CHANGED
@@ -26,6 +26,10 @@ import { BuyerResolver } from '@lime-bundles/core';
26
26
  * 3. /products/<handle> segment of window.location.pathname
27
27
  * 4. fallthrough: renders nothing, fires `lime-bundle:error`
28
28
  *
29
+ * Multi-product renderers (volume) bind to the product this embed is
30
+ * standing on: the explicit `product-id` attribute wins, then the handle
31
+ * cascade above, then the bundle's first product when neither names one.
32
+ *
29
33
  * ## Add-to-cart behaviour
30
34
  *
31
35
  * Merchants who do nothing get a default: the widget calls Shopify's
@@ -92,6 +96,14 @@ declare class LimeBundleElement extends HTMLElement {
92
96
  private get storefrontToken();
93
97
  private get bundleGid();
94
98
  private get productHandleAttr();
99
+ /**
100
+ * The current product's id — full GID (`gid://shopify/Product/123`) or
101
+ * bare numeric id. Tells multi-product renderers (volume) which of the
102
+ * bundle's products this embed is standing on; takes precedence over the
103
+ * handle cascade. Without it (and with no resolvable handle) they bind to
104
+ * the bundle's first product.
105
+ */
106
+ private get productIdAttr();
95
107
  private get appUrl();
96
108
  private get analyticsEnabled();
97
109
  private get country();
@@ -128,6 +140,21 @@ declare class LimeBundleElement extends HTMLElement {
128
140
  * instead of creating a new one every click.
129
141
  */
130
142
  private defaultAddToCart;
143
+ /**
144
+ * Remove this widget's own earlier lines — the ones tagged with the
145
+ * `_lime_bundle_gid` attribute — from the saved cart, so a shopper who
146
+ * clicked add three times while deciding checks out with only what they
147
+ * just built. Lines without the tag were put in the cart by something
148
+ * else (the host site, a previous non-widget purchase flow) and are
149
+ * left alone.
150
+ *
151
+ * Returns the cart id when the cart is still usable. Returns null after
152
+ * calling `dropSavedCart` when it isn't: either the id no longer
153
+ * resolves (expired or merged on Shopify's side), or the removal itself
154
+ * failed — in both cases a fresh cart is the only way to guarantee the
155
+ * checkout matches the shopper's current build.
156
+ */
157
+ private clearAbandonedBundleLines;
131
158
  private reportAddToCartEvent;
132
159
  private renderBundles;
133
160
  private setupImpressionFor;
package/dist/index.d.ts CHANGED
@@ -26,6 +26,10 @@ import { BuyerResolver } from '@lime-bundles/core';
26
26
  * 3. /products/<handle> segment of window.location.pathname
27
27
  * 4. fallthrough: renders nothing, fires `lime-bundle:error`
28
28
  *
29
+ * Multi-product renderers (volume) bind to the product this embed is
30
+ * standing on: the explicit `product-id` attribute wins, then the handle
31
+ * cascade above, then the bundle's first product when neither names one.
32
+ *
29
33
  * ## Add-to-cart behaviour
30
34
  *
31
35
  * Merchants who do nothing get a default: the widget calls Shopify's
@@ -92,6 +96,14 @@ declare class LimeBundleElement extends HTMLElement {
92
96
  private get storefrontToken();
93
97
  private get bundleGid();
94
98
  private get productHandleAttr();
99
+ /**
100
+ * The current product's id — full GID (`gid://shopify/Product/123`) or
101
+ * bare numeric id. Tells multi-product renderers (volume) which of the
102
+ * bundle's products this embed is standing on; takes precedence over the
103
+ * handle cascade. Without it (and with no resolvable handle) they bind to
104
+ * the bundle's first product.
105
+ */
106
+ private get productIdAttr();
95
107
  private get appUrl();
96
108
  private get analyticsEnabled();
97
109
  private get country();
@@ -128,6 +140,21 @@ declare class LimeBundleElement extends HTMLElement {
128
140
  * instead of creating a new one every click.
129
141
  */
130
142
  private defaultAddToCart;
143
+ /**
144
+ * Remove this widget's own earlier lines — the ones tagged with the
145
+ * `_lime_bundle_gid` attribute — from the saved cart, so a shopper who
146
+ * clicked add three times while deciding checks out with only what they
147
+ * just built. Lines without the tag were put in the cart by something
148
+ * else (the host site, a previous non-widget purchase flow) and are
149
+ * left alone.
150
+ *
151
+ * Returns the cart id when the cart is still usable. Returns null after
152
+ * calling `dropSavedCart` when it isn't: either the id no longer
153
+ * resolves (expired or merged on Shopify's side), or the removal itself
154
+ * failed — in both cases a fresh cart is the only way to guarantee the
155
+ * checkout matches the shopper's current build.
156
+ */
157
+ private clearAbandonedBundleLines;
131
158
  private reportAddToCartEvent;
132
159
  private renderBundles;
133
160
  private setupImpressionFor;
package/dist/index.js CHANGED
@@ -5,6 +5,8 @@ import {
5
5
  BUNDLES_FOR_PRODUCT_QUERY,
6
6
  CART_CREATE_MUTATION,
7
7
  CART_LINES_ADD_MUTATION,
8
+ CART_LINES_QUERY,
9
+ CART_LINES_REMOVE_MUTATION,
8
10
  SHOP_SETTINGS_QUERY,
9
11
  parseMetaobjectBundle,
10
12
  observeImpression,
@@ -19,6 +21,28 @@ import {
19
21
  resolveAbTests
20
22
  } from "@lime-bundles/core";
21
23
 
24
+ // ../render/src/host.ts
25
+ function intlFormatMoney(currencyCode) {
26
+ return (cents) => {
27
+ try {
28
+ return new Intl.NumberFormat(void 0, {
29
+ style: "currency",
30
+ currency: currencyCode
31
+ }).format(cents / 100);
32
+ } catch {
33
+ return currencyCode + " " + (cents / 100).toFixed(2);
34
+ }
35
+ };
36
+ }
37
+ var BUNDLE_GID_ATTRIBUTE = "_lime_bundle_gid";
38
+ var BUNDLE_TYPE_ATTRIBUTE = "_lime_bundle_type";
39
+ function bundleLineAttributes(bundleGid, bundleType) {
40
+ return [
41
+ { key: BUNDLE_GID_ATTRIBUTE, value: bundleGid },
42
+ { key: BUNDLE_TYPE_ATTRIBUTE, value: bundleType }
43
+ ];
44
+ }
45
+
22
46
  // ../render/src/adapt.ts
23
47
  import {
24
48
  formatUnitPrice,
@@ -226,28 +250,6 @@ function recalcPricing(container, products, formatMoney) {
226
250
  }
227
251
  }
228
252
 
229
- // ../render/src/host.ts
230
- function intlFormatMoney(currencyCode) {
231
- return (cents) => {
232
- try {
233
- return new Intl.NumberFormat(void 0, {
234
- style: "currency",
235
- currency: currencyCode
236
- }).format(cents / 100);
237
- } catch {
238
- return currencyCode + " " + (cents / 100).toFixed(2);
239
- }
240
- };
241
- }
242
- var BUNDLE_GID_ATTRIBUTE = "_lime_bundle_gid";
243
- var BUNDLE_TYPE_ATTRIBUTE = "_lime_bundle_type";
244
- function bundleLineAttributes(bundleGid, bundleType) {
245
- return [
246
- { key: BUNDLE_GID_ATTRIBUTE, value: bundleGid },
247
- { key: BUNDLE_TYPE_ATTRIBUTE, value: bundleType }
248
- ];
249
- }
250
-
251
253
  // ../render/src/product/option-selects.ts
252
254
  function bindVariantSelects(row, getProduct, onSelected) {
253
255
  const optionSelects = row.querySelectorAll("[data-variant-option]");
@@ -2809,6 +2811,7 @@ function renderMixMatchBundle(container, bundle, onAddToCart, onCleanup, current
2809
2811
  import {
2810
2812
  bestValueTierIndex,
2811
2813
  isVariantFulfillable as isVariantFulfillable2,
2814
+ resolveContextProduct,
2812
2815
  resolveDefaultTierIndex,
2813
2816
  resolvePopularTierIndex,
2814
2817
  stockCapForVariant as stockCapForVariant2
@@ -2941,9 +2944,9 @@ function selectTier(container, allTiers, basePrice, discountType, index, transla
2941
2944
  }
2942
2945
 
2943
2946
  // src/renderers/volume.ts
2944
- function renderVolumeBundle(container, bundle, onAddToCart) {
2947
+ function renderVolumeBundle(container, bundle, onAddToCart, productContext) {
2945
2948
  const wc = bundle.widgetConfig;
2946
- const product = bundle.products[0];
2949
+ const product = resolveContextProduct(bundle.products, productContext);
2947
2950
  if (!product) return;
2948
2951
  const variants = product.variants.nodes;
2949
2952
  const minTierQty = Math.min(
@@ -6742,6 +6745,7 @@ var LimeBundleElement = class extends HTMLElement {
6742
6745
  "storefront-token",
6743
6746
  "bundle-gid",
6744
6747
  "product-handle",
6748
+ "product-id",
6745
6749
  "app-url",
6746
6750
  "analytics",
6747
6751
  "locale",
@@ -6802,7 +6806,7 @@ var LimeBundleElement = class extends HTMLElement {
6802
6806
  }
6803
6807
  attributeChangedCallback(name, oldValue, newValue) {
6804
6808
  if (oldValue === newValue || !this.isConnected) return;
6805
- if (name === "bundle-gid" || name === "product-handle" || name === "shop-domain" || name === "storefront-token") {
6809
+ if (name === "bundle-gid" || name === "product-handle" || name === "product-id" || name === "shop-domain" || name === "storefront-token") {
6806
6810
  if (this.shopDomain && this.storefrontToken) {
6807
6811
  this.fetchBundle();
6808
6812
  }
@@ -6820,6 +6824,16 @@ var LimeBundleElement = class extends HTMLElement {
6820
6824
  get productHandleAttr() {
6821
6825
  return this.getAttribute("product-handle") ?? "";
6822
6826
  }
6827
+ /**
6828
+ * The current product's id — full GID (`gid://shopify/Product/123`) or
6829
+ * bare numeric id. Tells multi-product renderers (volume) which of the
6830
+ * bundle's products this embed is standing on; takes precedence over the
6831
+ * handle cascade. Without it (and with no resolvable handle) they bind to
6832
+ * the bundle's first product.
6833
+ */
6834
+ get productIdAttr() {
6835
+ return this.getAttribute("product-id") ?? "";
6836
+ }
6823
6837
  get appUrl() {
6824
6838
  return this.getAttribute("app-url") ?? "";
6825
6839
  }
@@ -6993,7 +7007,7 @@ var LimeBundleElement = class extends HTMLElement {
6993
7007
  });
6994
7008
  const storage = window.localStorage;
6995
7009
  const key = cartStorageKey(this.shopDomain);
6996
- const existingCartId = storage?.getItem(key) ?? null;
7010
+ let cartId = storage?.getItem(key) ?? null;
6997
7011
  const isStaleCartError = (errors) => errors.length > 0 && errors.every((e) => (e.field ?? []).includes("cartId"));
6998
7012
  const stockCapped = (warnings) => (warnings ?? []).some((w) => w.code === "MERCHANDISE_NOT_ENOUGH_STOCK");
6999
7013
  const fail = (message) => {
@@ -7007,10 +7021,17 @@ var LimeBundleElement = class extends HTMLElement {
7007
7021
  };
7008
7022
  try {
7009
7023
  let checkoutUrl = null;
7010
- if (existingCartId) {
7024
+ if (cartId) {
7025
+ cartId = await this.clearAbandonedBundleLines(
7026
+ client,
7027
+ cartId,
7028
+ () => storage?.removeItem(key)
7029
+ );
7030
+ }
7031
+ if (cartId) {
7011
7032
  const res = await client.query(
7012
7033
  CART_LINES_ADD_MUTATION,
7013
- { cartId: existingCartId, lines }
7034
+ { cartId, lines }
7014
7035
  );
7015
7036
  const payload = res.cartLinesAdd;
7016
7037
  if (payload?.userErrors?.length) {
@@ -7063,6 +7084,42 @@ var LimeBundleElement = class extends HTMLElement {
7063
7084
  );
7064
7085
  }
7065
7086
  }
7087
+ /**
7088
+ * Remove this widget's own earlier lines — the ones tagged with the
7089
+ * `_lime_bundle_gid` attribute — from the saved cart, so a shopper who
7090
+ * clicked add three times while deciding checks out with only what they
7091
+ * just built. Lines without the tag were put in the cart by something
7092
+ * else (the host site, a previous non-widget purchase flow) and are
7093
+ * left alone.
7094
+ *
7095
+ * Returns the cart id when the cart is still usable. Returns null after
7096
+ * calling `dropSavedCart` when it isn't: either the id no longer
7097
+ * resolves (expired or merged on Shopify's side), or the removal itself
7098
+ * failed — in both cases a fresh cart is the only way to guarantee the
7099
+ * checkout matches the shopper's current build.
7100
+ */
7101
+ async clearAbandonedBundleLines(client, cartId, dropSavedCart) {
7102
+ const res = await client.query(CART_LINES_QUERY, {
7103
+ cartId
7104
+ });
7105
+ if (!res.cart) {
7106
+ dropSavedCart();
7107
+ return null;
7108
+ }
7109
+ const abandonedLineIds = res.cart.lines.nodes.filter(
7110
+ (line) => line.attributes.some((attr) => attr.key === BUNDLE_GID_ATTRIBUTE)
7111
+ ).map((line) => line.id);
7112
+ if (abandonedLineIds.length === 0) return cartId;
7113
+ const removal = await client.query(
7114
+ CART_LINES_REMOVE_MUTATION,
7115
+ { cartId, lineIds: abandonedLineIds }
7116
+ );
7117
+ if (removal.cartLinesRemove?.userErrors?.length) {
7118
+ dropSavedCart();
7119
+ return null;
7120
+ }
7121
+ return cartId;
7122
+ }
7066
7123
  reportAddToCartEvent(bundle, lines) {
7067
7124
  if (!this.analyticsEnabled || !this.appUrl) return;
7068
7125
  const quantity = lines.reduce((sum, l) => sum + l.quantity, 0);
@@ -7134,7 +7191,10 @@ var LimeBundleElement = class extends HTMLElement {
7134
7191
  );
7135
7192
  break;
7136
7193
  case "volume":
7137
- renderVolumeBundle(container, bundle, dispatch);
7194
+ renderVolumeBundle(container, bundle, dispatch, {
7195
+ productId: this.productIdAttr || null,
7196
+ productHandle: this.currentProductHandle
7197
+ });
7138
7198
  break;
7139
7199
  case "bogo":
7140
7200
  renderBogoBundle(container, bundle, dispatch, registerCleanup);