@lime-bundles/widget 3.2.2 → 3.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.d.cts CHANGED
@@ -1,5 +1,64 @@
1
+ import { BuyerResolver } from '@lime-bundles/core';
2
+
3
+ /**
4
+ * <lime-bundle> Web Component — renders Lime Bundles on any storefront.
5
+ *
6
+ * ## The two modes
7
+ *
8
+ * Single-bundle (pinned):
9
+ * <lime-bundle
10
+ * shop-domain="my-shop.myshopify.com"
11
+ * storefront-token="shpat_..."
12
+ * bundle-gid="gid://shopify/Metaobject/42"
13
+ * ></lime-bundle>
14
+ *
15
+ * Product-aware (matches classic Liquid theme block behaviour — one snippet
16
+ * on the product page renders every active bundle configured against that
17
+ * product):
18
+ * <lime-bundle
19
+ * shop-domain="my-shop.myshopify.com"
20
+ * storefront-token="shpat_..."
21
+ * ></lime-bundle>
22
+ *
23
+ * Product resolution cascade (when no `bundle-gid` is set):
24
+ * 1. explicit `product-handle` attribute
25
+ * 2. <meta name="shopify:product-handle" content="..."> on the page
26
+ * 3. /products/<handle> segment of window.location.pathname
27
+ * 4. fallthrough: renders nothing, fires `lime-bundle:error`
28
+ *
29
+ * ## Add-to-cart behaviour
30
+ *
31
+ * Merchants who do nothing get a default: the widget calls Shopify's
32
+ * Storefront Cart API (tokenless — no extra scopes required) and redirects
33
+ * the browser to the returned checkoutUrl. One-click-to-checkout is the
34
+ * right UX for most merchants pasting the widget into Webflow / Wix /
35
+ * Squarespace / static HTML.
36
+ *
37
+ * Merchants with their own cart state (Hydrogen's useCart, a custom cart
38
+ * drawer, etc.) opt out by attaching a listener that calls
39
+ * `event.preventDefault()`:
40
+ *
41
+ * document.querySelector("lime-bundle").addEventListener(
42
+ * "lime-bundle:add-to-cart",
43
+ * (ev) => {
44
+ * ev.preventDefault(); // suppress the default redirect
45
+ * myCart.linesAdd(ev.detail.lines);
46
+ * },
47
+ * );
48
+ *
49
+ * The event is always dispatched; only the default action is conditional.
50
+ */
51
+
1
52
  declare class LimeBundleElement extends HTMLElement {
2
53
  static observedAttributes: string[];
54
+ /**
55
+ * B2B buyer identity. Set programmatically — `element.buyer = {...}` or
56
+ * `element.buyer = () => fetchToken()`. NEVER expose as an HTML attribute
57
+ * because the customer access token would land in DOM snapshots (Sentry,
58
+ * analytics, browser extensions) and Referer headers. See the package
59
+ * README ("Markets & B2B").
60
+ */
61
+ buyer: BuyerResolver | undefined;
3
62
  private shadow;
4
63
  private bundles;
5
64
  private abortController;
@@ -28,6 +87,22 @@ declare class LimeBundleElement extends HTMLElement {
28
87
  private get productHandleAttr();
29
88
  private get appUrl();
30
89
  private get analyticsEnabled();
90
+ private get country();
91
+ private get language();
92
+ private get marketId();
93
+ /**
94
+ * Returns the @inContext-wrapped query when any context field is set;
95
+ * otherwise the plain query. Keeps responses publicly cacheable when
96
+ * no buyer/country/language is set.
97
+ */
98
+ private wrapQueryForContext;
99
+ /**
100
+ * Returns true if this bundle should be hidden for the current market.
101
+ * For "all" bundles, always returns false (visible). For "specific"
102
+ * bundles, returns true when no marketId was set or when the bundle's
103
+ * marketIds doesn't include the configured market.
104
+ */
105
+ private isMarketHidden;
31
106
  private fetchBundle;
32
107
  /**
33
108
  * Resolve the visitor's A/B bucket for every bundle with an active test
package/dist/index.d.ts CHANGED
@@ -1,5 +1,64 @@
1
+ import { BuyerResolver } from '@lime-bundles/core';
2
+
3
+ /**
4
+ * <lime-bundle> Web Component — renders Lime Bundles on any storefront.
5
+ *
6
+ * ## The two modes
7
+ *
8
+ * Single-bundle (pinned):
9
+ * <lime-bundle
10
+ * shop-domain="my-shop.myshopify.com"
11
+ * storefront-token="shpat_..."
12
+ * bundle-gid="gid://shopify/Metaobject/42"
13
+ * ></lime-bundle>
14
+ *
15
+ * Product-aware (matches classic Liquid theme block behaviour — one snippet
16
+ * on the product page renders every active bundle configured against that
17
+ * product):
18
+ * <lime-bundle
19
+ * shop-domain="my-shop.myshopify.com"
20
+ * storefront-token="shpat_..."
21
+ * ></lime-bundle>
22
+ *
23
+ * Product resolution cascade (when no `bundle-gid` is set):
24
+ * 1. explicit `product-handle` attribute
25
+ * 2. <meta name="shopify:product-handle" content="..."> on the page
26
+ * 3. /products/<handle> segment of window.location.pathname
27
+ * 4. fallthrough: renders nothing, fires `lime-bundle:error`
28
+ *
29
+ * ## Add-to-cart behaviour
30
+ *
31
+ * Merchants who do nothing get a default: the widget calls Shopify's
32
+ * Storefront Cart API (tokenless — no extra scopes required) and redirects
33
+ * the browser to the returned checkoutUrl. One-click-to-checkout is the
34
+ * right UX for most merchants pasting the widget into Webflow / Wix /
35
+ * Squarespace / static HTML.
36
+ *
37
+ * Merchants with their own cart state (Hydrogen's useCart, a custom cart
38
+ * drawer, etc.) opt out by attaching a listener that calls
39
+ * `event.preventDefault()`:
40
+ *
41
+ * document.querySelector("lime-bundle").addEventListener(
42
+ * "lime-bundle:add-to-cart",
43
+ * (ev) => {
44
+ * ev.preventDefault(); // suppress the default redirect
45
+ * myCart.linesAdd(ev.detail.lines);
46
+ * },
47
+ * );
48
+ *
49
+ * The event is always dispatched; only the default action is conditional.
50
+ */
51
+
1
52
  declare class LimeBundleElement extends HTMLElement {
2
53
  static observedAttributes: string[];
54
+ /**
55
+ * B2B buyer identity. Set programmatically — `element.buyer = {...}` or
56
+ * `element.buyer = () => fetchToken()`. NEVER expose as an HTML attribute
57
+ * because the customer access token would land in DOM snapshots (Sentry,
58
+ * analytics, browser extensions) and Referer headers. See the package
59
+ * README ("Markets & B2B").
60
+ */
61
+ buyer: BuyerResolver | undefined;
3
62
  private shadow;
4
63
  private bundles;
5
64
  private abortController;
@@ -28,6 +87,22 @@ declare class LimeBundleElement extends HTMLElement {
28
87
  private get productHandleAttr();
29
88
  private get appUrl();
30
89
  private get analyticsEnabled();
90
+ private get country();
91
+ private get language();
92
+ private get marketId();
93
+ /**
94
+ * Returns the @inContext-wrapped query when any context field is set;
95
+ * otherwise the plain query. Keeps responses publicly cacheable when
96
+ * no buyer/country/language is set.
97
+ */
98
+ private wrapQueryForContext;
99
+ /**
100
+ * Returns true if this bundle should be hidden for the current market.
101
+ * For "all" bundles, always returns false (visible). For "specific"
102
+ * bundles, returns true when no marketId was set or when the bundle's
103
+ * marketIds doesn't include the configured market.
104
+ */
105
+ private isMarketHidden;
31
106
  private fetchBundle;
32
107
  /**
33
108
  * Resolve the visitor's A/B bucket for every bundle with an active test
package/dist/index.js CHANGED
@@ -13,7 +13,9 @@ import {
13
13
  injectCustomCss,
14
14
  sanitizeCustomCss,
15
15
  getABTestAssignment,
16
- applyABVariantB
16
+ applyABVariantB,
17
+ hasInContext,
18
+ withInContext
17
19
  } from "@lime-bundles/core";
18
20
 
19
21
  // src/renderers/fixed.ts
@@ -4137,8 +4139,19 @@ var LimeBundleElement = class extends HTMLElement {
4137
4139
  "product-handle",
4138
4140
  "app-url",
4139
4141
  "analytics",
4140
- "locale"
4142
+ "locale",
4143
+ "country",
4144
+ "language",
4145
+ "market-id"
4141
4146
  ];
4147
+ /**
4148
+ * B2B buyer identity. Set programmatically — `element.buyer = {...}` or
4149
+ * `element.buyer = () => fetchToken()`. NEVER expose as an HTML attribute
4150
+ * because the customer access token would land in DOM snapshots (Sentry,
4151
+ * analytics, browser extensions) and Referer headers. See the package
4152
+ * README ("Markets & B2B").
4153
+ */
4154
+ buyer = void 0;
4142
4155
  shadow;
4143
4156
  bundles = [];
4144
4157
  abortController = null;
@@ -4201,6 +4214,40 @@ var LimeBundleElement = class extends HTMLElement {
4201
4214
  get analyticsEnabled() {
4202
4215
  return this.getAttribute("analytics") !== "false";
4203
4216
  }
4217
+ get country() {
4218
+ return this.getAttribute("country") ?? void 0;
4219
+ }
4220
+ get language() {
4221
+ return this.getAttribute("language") ?? void 0;
4222
+ }
4223
+ get marketId() {
4224
+ return this.getAttribute("market-id") ?? void 0;
4225
+ }
4226
+ /**
4227
+ * Returns the @inContext-wrapped query when any context field is set;
4228
+ * otherwise the plain query. Keeps responses publicly cacheable when
4229
+ * no buyer/country/language is set.
4230
+ */
4231
+ wrapQueryForContext(query) {
4232
+ return hasInContext({
4233
+ shopDomain: this.shopDomain,
4234
+ accessToken: this.storefrontToken,
4235
+ country: this.country,
4236
+ language: this.language,
4237
+ buyer: this.buyer
4238
+ }) ? withInContext(query) : query;
4239
+ }
4240
+ /**
4241
+ * Returns true if this bundle should be hidden for the current market.
4242
+ * For "all" bundles, always returns false (visible). For "specific"
4243
+ * bundles, returns true when no marketId was set or when the bundle's
4244
+ * marketIds doesn't include the configured market.
4245
+ */
4246
+ isMarketHidden(bundle) {
4247
+ if (bundle.marketVisibility !== "specific") return false;
4248
+ if (!this.marketId) return true;
4249
+ return !bundle.marketIds.includes(this.marketId);
4250
+ }
4204
4251
  async fetchBundle() {
4205
4252
  if (!this.shopDomain || !this.storefrontToken) {
4206
4253
  this.renderError(
@@ -4214,7 +4261,10 @@ var LimeBundleElement = class extends HTMLElement {
4214
4261
  this.renderLoading();
4215
4262
  const client = createStorefrontClient({
4216
4263
  shopDomain: this.shopDomain,
4217
- accessToken: this.storefrontToken
4264
+ accessToken: this.storefrontToken,
4265
+ country: this.country,
4266
+ language: this.language,
4267
+ buyer: this.buyer
4218
4268
  });
4219
4269
  try {
4220
4270
  let bundlePromise;
@@ -4298,7 +4348,7 @@ var LimeBundleElement = class extends HTMLElement {
4298
4348
  }
4299
4349
  async fetchSingleBundle(client, signal) {
4300
4350
  const data = await client.query(
4301
- BUNDLE_METAOBJECT_QUERY,
4351
+ this.wrapQueryForContext(BUNDLE_METAOBJECT_QUERY),
4302
4352
  { id: this.bundleGid },
4303
4353
  { signal }
4304
4354
  );
@@ -4310,11 +4360,11 @@ var LimeBundleElement = class extends HTMLElement {
4310
4360
  data.metaobject.id,
4311
4361
  data.metaobject.fields
4312
4362
  );
4313
- this.bundles = parsed ? [parsed] : [];
4363
+ this.bundles = parsed && !this.isMarketHidden(parsed) ? [parsed] : [];
4314
4364
  }
4315
4365
  async fetchProductBundles(client, signal, productHandle) {
4316
4366
  const data = await client.query(
4317
- BUNDLES_FOR_PRODUCT_QUERY,
4367
+ this.wrapQueryForContext(BUNDLES_FOR_PRODUCT_QUERY),
4318
4368
  { handle: productHandle },
4319
4369
  { signal }
4320
4370
  );
@@ -4326,7 +4376,7 @@ var LimeBundleElement = class extends HTMLElement {
4326
4376
  const bundles = [];
4327
4377
  for (const ref of refs) {
4328
4378
  const parsed = parseMetaobjectBundle(ref.id, ref.fields);
4329
- if (parsed) bundles.push(parsed);
4379
+ if (parsed && !this.isMarketHidden(parsed)) bundles.push(parsed);
4330
4380
  }
4331
4381
  this.bundles = bundles;
4332
4382
  }