@liquidcommerce/elements-sdk 2.7.23 → 2.7.25
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.checkout.esm.js +7113 -7076
- package/dist/index.esm.js +11548 -11464
- package/dist/types/core/google-tag-manager.service.d.ts +1 -0
- package/dist/types/interfaces/configs/global.interface.d.ts +2 -0
- package/dist/types/modules/product/components/product-image-carousel.component.d.ts +1 -0
- package/dist/types/modules/product-list/components/product-list-product-pre-cart.component.d.ts +1 -0
- package/dist/types/utils/image-bg-removal.d.ts +3 -0
- package/docs/v1/api/actions/cart-actions.md +9 -2
- package/docs/v1/api/actions/checkout-actions.md +2 -0
- package/docs/v1/api/client.md +84 -6
- package/docs/v1/api/configuration.md +10 -0
- package/docs/v1/api/typescript-types.md +5 -1
- package/docs/v1/getting-started/concepts.md +5 -3
- package/docs/v1/getting-started/installation.md +22 -1
- package/docs/v1/guides/cart-component.md +32 -0
- package/docs/v1/guides/product-component.md +6 -2
- package/docs/v1/guides/product-list-component.md +4 -5
- package/docs/v1/guides/theming.md +10 -0
- package/docs/v1/reference/analytics.md +108 -0
- package/docs/v1/reference/browser-support.md +3 -1
- package/docs/v1/reference/error-handling.md +8 -0
- package/docs/v1/reference/telemetry.md +85 -0
- package/docs/v1/reference/troubleshooting.md +1 -2
- package/package.json +8 -8
|
@@ -63,6 +63,7 @@ export declare class GoogleTagManagerService {
|
|
|
63
63
|
private readonly clientConfigService;
|
|
64
64
|
constructor();
|
|
65
65
|
static getInstance(): GoogleTagManagerService;
|
|
66
|
+
private isGTMEnabledEnvironment;
|
|
66
67
|
private waitForDOMReady;
|
|
67
68
|
private isGTMAlreadyLoaded;
|
|
68
69
|
private isContainerLoaded;
|
|
@@ -40,6 +40,8 @@ export interface IGlobalLayout {
|
|
|
40
40
|
personalizationCardStyle: 'outlined' | 'filled';
|
|
41
41
|
allowPromoCodes: boolean;
|
|
42
42
|
inputFieldStyle: 'outlined' | 'filled';
|
|
43
|
+
enableOrderedProductSizes: boolean;
|
|
44
|
+
orderedProductSizes: string[];
|
|
43
45
|
showPoweredBy: boolean;
|
|
44
46
|
poweredByMode: 'light' | 'dark';
|
|
45
47
|
}
|
|
@@ -8,6 +8,7 @@ export interface IImageCarouselParams {
|
|
|
8
8
|
export declare class ProductImageCarouselComponent extends BaseComponent<IImageCarouselParams, IProductComponent> {
|
|
9
9
|
get hostClasses(): string[];
|
|
10
10
|
private mainImageElement;
|
|
11
|
+
private mainImageMediaElement;
|
|
11
12
|
private galleryViewport;
|
|
12
13
|
private galleryContainer;
|
|
13
14
|
private thumbnails;
|
package/dist/types/modules/product-list/components/product-list-product-pre-cart.component.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export interface IProductListProductPreCartComponentParams {
|
|
|
5
5
|
productId: string;
|
|
6
6
|
}
|
|
7
7
|
export declare class ProductListProductPreCartComponent extends BaseComponent<IProductListProductPreCartComponentParams, IProductListComponent> {
|
|
8
|
+
get hostClasses(): string[];
|
|
8
9
|
private showRetailersContent;
|
|
9
10
|
private showEngravingForm;
|
|
10
11
|
private isInitialRender;
|
|
@@ -169,11 +169,16 @@ applyPromoCode(promoCode: string): Promise<void>
|
|
|
169
169
|
### Example
|
|
170
170
|
|
|
171
171
|
```javascript
|
|
172
|
+
// Listen for the outcome — an invalid code surfaces here, not as a rejection
|
|
173
|
+
window.addEventListener('lce:actions.cart_promo_code_failed', (event) => {
|
|
174
|
+
console.error('Invalid promo code:', event.detail.data);
|
|
175
|
+
});
|
|
176
|
+
|
|
172
177
|
try {
|
|
173
178
|
await window.LiquidCommerce.elements.actions.cart.applyPromoCode('SUMMER20');
|
|
174
|
-
console.log('Promo code applied successfully');
|
|
175
179
|
} catch (error) {
|
|
176
|
-
|
|
180
|
+
// Only reached on unexpected errors, not for an invalid code
|
|
181
|
+
console.error('Failed to apply promo code:', error);
|
|
177
182
|
}
|
|
178
183
|
```
|
|
179
184
|
|
|
@@ -183,6 +188,8 @@ try {
|
|
|
183
188
|
- Promo codes must be enabled in configuration
|
|
184
189
|
- Only one promo code can be active at a time
|
|
185
190
|
- Applying a new code replaces the existing one
|
|
191
|
+
- An invalid/rejected code does **not** reject the promise — the failure is surfaced via the `lce:actions.cart_promo_code_failed` event. Listen for that event to handle invalid codes.
|
|
192
|
+
- An empty or whitespace-only code is a silent no-op: it sets a `cart.error` on the store and returns without throwing.
|
|
186
193
|
|
|
187
194
|
---
|
|
188
195
|
|
|
@@ -4,6 +4,8 @@ Checkout actions allow you to programmatically control the checkout flow.
|
|
|
4
4
|
|
|
5
5
|
## Navigation Actions
|
|
6
6
|
|
|
7
|
+
> **Note:** `openCheckout()`, `closeCheckout()`, and `toggleCheckout()` are only available on the full `Elements()` client's `actions.checkout`. They are **not** present on the checkout-only client (`ElementsCheckout()`), whose `actions.checkout` is typed `IElementsCheckoutActions = Omit<ICheckoutActions, 'openCheckout' | 'closeCheckout' | 'toggleCheckout'>`. The remaining checkout actions are available on both clients.
|
|
8
|
+
|
|
7
9
|
### actions.checkout.openCheckout()
|
|
8
10
|
|
|
9
11
|
```typescript
|
package/docs/v1/api/client.md
CHANGED
|
@@ -11,7 +11,7 @@ Initialize the full SDK client.
|
|
|
11
11
|
```typescript
|
|
12
12
|
function Elements(
|
|
13
13
|
apiKey: string,
|
|
14
|
-
config
|
|
14
|
+
config?: ILiquidCommerceElementsConfig
|
|
15
15
|
): Promise<ILiquidCommerceElementsClient | null>
|
|
16
16
|
```
|
|
17
17
|
|
|
@@ -20,7 +20,7 @@ function Elements(
|
|
|
20
20
|
| Parameter | Type | Required | Description |
|
|
21
21
|
|-----------|-------------------------------|----------|-----------------------------|
|
|
22
22
|
| `apiKey` | string | Yes | Your LiquidCommerce API key |
|
|
23
|
-
| `config` | ILiquidCommerceElementsConfig |
|
|
23
|
+
| `config` | ILiquidCommerceElementsConfig | No | Configuration object |
|
|
24
24
|
|
|
25
25
|
**Returns:** Promise that resolves to the client instance, or `null` if initialization fails.
|
|
26
26
|
|
|
@@ -43,7 +43,7 @@ Initialize the checkout-only client (tree-shaken build).
|
|
|
43
43
|
```typescript
|
|
44
44
|
function ElementsCheckout(
|
|
45
45
|
apiKey: string,
|
|
46
|
-
config
|
|
46
|
+
config?: ILiquidCommerceElementsCheckoutClientConfig
|
|
47
47
|
): Promise<IElementsCheckoutClient | null>
|
|
48
48
|
```
|
|
49
49
|
|
|
@@ -52,7 +52,7 @@ function ElementsCheckout(
|
|
|
52
52
|
| Parameter | Type | Required | Description |
|
|
53
53
|
|-----------|---------------------------------------------|----------|-----------------------------|
|
|
54
54
|
| `apiKey` | string | Yes | Your LiquidCommerce API key |
|
|
55
|
-
| `config` | ILiquidCommerceElementsCheckoutClientConfig |
|
|
55
|
+
| `config` | ILiquidCommerceElementsCheckoutClientConfig | No | Checkout configuration |
|
|
56
56
|
|
|
57
57
|
**Example:**
|
|
58
58
|
|
|
@@ -71,7 +71,7 @@ Initialize the builder client, which exposes manual `inject*` / `update*` method
|
|
|
71
71
|
```typescript
|
|
72
72
|
function ElementsBuilder(
|
|
73
73
|
apiKey: string,
|
|
74
|
-
config
|
|
74
|
+
config?: ILiquidCommerceElementsBuilderConfig
|
|
75
75
|
): Promise<ILiquidCommerceElementsBuilderClient | null>
|
|
76
76
|
```
|
|
77
77
|
|
|
@@ -80,7 +80,7 @@ function ElementsBuilder(
|
|
|
80
80
|
| Parameter | Type | Required | Description |
|
|
81
81
|
|-----------|--------------------------------------|----------|-----------------------------|
|
|
82
82
|
| `apiKey` | string | Yes | Your LiquidCommerce API key |
|
|
83
|
-
| `config` | ILiquidCommerceElementsBuilderConfig |
|
|
83
|
+
| `config` | ILiquidCommerceElementsBuilderConfig | No | Builder configuration object (same shape as `ILiquidCommerceElementsConfig`) |
|
|
84
84
|
|
|
85
85
|
**Returns:** Promise that resolves to the builder client instance (`ILiquidCommerceElementsBuilderClient`), or `null` if initialization fails or it is called outside the browser.
|
|
86
86
|
|
|
@@ -296,6 +296,84 @@ interface ILiquidCommerceElementsClient {
|
|
|
296
296
|
}
|
|
297
297
|
```
|
|
298
298
|
|
|
299
|
+
### ILiquidCommerceElementsBuilderClient
|
|
300
|
+
|
|
301
|
+
The builder client (returned by `ElementsBuilder()`) exposes the same `inject*` methods plus a set of `update*Component` methods for applying theme/layout changes at runtime:
|
|
302
|
+
|
|
303
|
+
```typescript
|
|
304
|
+
interface ILiquidCommerceElementsBuilderClient {
|
|
305
|
+
// Runtime theme/layout updates (builder-only)
|
|
306
|
+
updateComponentGlobalConfigs(configs: UpdateComponentGlobalConfigs): Promise<void>;
|
|
307
|
+
updateProductComponent(configs: UpdateProductComponent): Promise<void>;
|
|
308
|
+
updateAddressComponent(configs: UpdateAddressComponent): void;
|
|
309
|
+
updateCartComponent(configs: UpdateCartComponent): void;
|
|
310
|
+
updateCheckoutComponent(configs: UpdateCheckoutComponent): void;
|
|
311
|
+
updateProductListComponent(configs: UpdateProductListComponent): void;
|
|
312
|
+
|
|
313
|
+
// Injection methods
|
|
314
|
+
injectElement(params: IBuilderInjectElementParams): Promise<IInjectedComponent | null>;
|
|
315
|
+
injectProductElement(params: IInjectProductElement[]): Promise<IInjectedComponent[]>;
|
|
316
|
+
injectAddressElement(containerId: string, options?: IAddressOptions): Promise<IInjectedComponent | null>;
|
|
317
|
+
injectCartElement(containerId: string): Promise<IInjectedComponent | null>;
|
|
318
|
+
injectCheckoutElement(params: IInjectCheckoutBuilderParams): Promise<IInjectedComponent | null>;
|
|
319
|
+
injectProductList(params: IInjectProductListParams): Promise<void>;
|
|
320
|
+
|
|
321
|
+
// Actions
|
|
322
|
+
actions: ILiquidCommerceElementsActions;
|
|
323
|
+
|
|
324
|
+
// Cleanup
|
|
325
|
+
destroy(): void;
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
#### Runtime theme updates (`update*Component`)
|
|
330
|
+
|
|
331
|
+
These methods are **builder-only** — they exist on the client returned by `ElementsBuilder()` and are **not** available on the full `Elements()` client. Each method applies theme changes to its scope and, when the passed `configs` include a non-empty `layout`, triggers targeted rerenders of only the components affected by those layout fields.
|
|
332
|
+
|
|
333
|
+
Return types are not uniform:
|
|
334
|
+
|
|
335
|
+
- `updateComponentGlobalConfigs()` and `updateProductComponent()` return `Promise<void>` (they may await product rerenders) — `await` them.
|
|
336
|
+
- `updateCartComponent()`, `updateCheckoutComponent()`, `updateAddressComponent()`, and `updateProductListComponent()` return `void` (synchronous).
|
|
337
|
+
|
|
338
|
+
```javascript
|
|
339
|
+
const builder = await ElementsBuilder('YOUR_API_KEY', { env: 'production' });
|
|
340
|
+
|
|
341
|
+
// Asynchronous — await these
|
|
342
|
+
await builder.updateComponentGlobalConfigs({
|
|
343
|
+
theme: { primaryColor: '#0a7d33', buttonCornerRadius: '8px' },
|
|
344
|
+
layout: { allowPromoCodes: true }
|
|
345
|
+
});
|
|
346
|
+
await builder.updateProductComponent({
|
|
347
|
+
theme: { backgroundColor: '#ffffff' },
|
|
348
|
+
layout: { addToCartButtonText: 'Add to bag' }
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
// Synchronous — no await needed
|
|
352
|
+
builder.updateCartComponent({ layout: { drawerHeaderText: 'Your bag' } });
|
|
353
|
+
builder.updateCheckoutComponent({ layout: { placeOrderButtonText: 'Pay now' } });
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
#### injectCheckoutElement (builder)
|
|
357
|
+
|
|
358
|
+
The builder's `injectCheckoutElement()` accepts `IInjectCheckoutBuilderParams`, which extends `IInjectCheckoutParams` with two **preview-only** fields:
|
|
359
|
+
|
|
360
|
+
```typescript
|
|
361
|
+
interface IInjectCheckoutBuilderParams extends IInjectCheckoutParams {
|
|
362
|
+
simulatePresale?: boolean; // simulate a presale lock in builder mode
|
|
363
|
+
presaleExpiresInMinutes?: number; // minutes until the simulated lock expires (defaults to 15)
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
`simulatePresale` and `presaleExpiresInMinutes` only take effect in the builder preview and have no counterpart on the full `Elements()` client's `injectCheckoutElement()`.
|
|
368
|
+
|
|
369
|
+
```javascript
|
|
370
|
+
await builder.injectCheckoutElement({
|
|
371
|
+
containerId: 'checkout',
|
|
372
|
+
simulatePresale: true,
|
|
373
|
+
presaleExpiresInMinutes: 30
|
|
374
|
+
});
|
|
375
|
+
```
|
|
376
|
+
|
|
299
377
|
## Methods Overview
|
|
300
378
|
|
|
301
379
|
### Injection Methods
|
|
@@ -30,6 +30,8 @@ interface ILiquidCommerceElementsConfig {
|
|
|
30
30
|
| `proxy` | `IElementsProxyConfig` | No | Proxy configuration for API requests |
|
|
31
31
|
| `development` | `ILiquidCommerceElementsDevelopmentConfig` | No | Development/testing options |
|
|
32
32
|
|
|
33
|
+
> **Note:** `debugMode` (`'console'` or `'panel'`) is **ignored in production** -- it is forced off when `env` is `'production'`. It only takes effect in non-production environments (`'development'` / `'staging'`).
|
|
34
|
+
|
|
33
35
|
---
|
|
34
36
|
|
|
35
37
|
## Theme Configuration
|
|
@@ -100,6 +102,8 @@ interface IFontFamily {
|
|
|
100
102
|
}
|
|
101
103
|
```
|
|
102
104
|
|
|
105
|
+
> **Note:** Only Google Fonts are supported -- `name` must be a valid Google Fonts family. `Poppins` is always injected as the default font family in addition to any fonts you specify. Font loading requires network access to `fonts.googleapis.com` and `fonts.gstatic.com`; if you run behind a CSP or proxy, allow these hosts.
|
|
106
|
+
|
|
103
107
|
#### IGlobalLayout
|
|
104
108
|
|
|
105
109
|
```typescript
|
|
@@ -109,6 +113,8 @@ interface IGlobalLayout {
|
|
|
109
113
|
personalizationCardStyle: 'outlined' | 'filled';
|
|
110
114
|
allowPromoCodes: boolean;
|
|
111
115
|
inputFieldStyle: 'outlined' | 'filled';
|
|
116
|
+
enableOrderedProductSizes: boolean;
|
|
117
|
+
orderedProductSizes: string[];
|
|
112
118
|
showPoweredBy: boolean;
|
|
113
119
|
poweredByMode: 'light' | 'dark';
|
|
114
120
|
}
|
|
@@ -121,9 +127,13 @@ interface IGlobalLayout {
|
|
|
121
127
|
| `personalizationCardStyle` | `'outlined' \| 'filled'` | Visual style for personalization cards |
|
|
122
128
|
| `allowPromoCodes` | `boolean` | Show promo code inputs in cart/checkout |
|
|
123
129
|
| `inputFieldStyle` | `'outlined' \| 'filled'` | Visual style for input fields |
|
|
130
|
+
| `enableOrderedProductSizes` | `boolean` | Enable a fixed display order for product/PLC size selectors (defined by `orderedProductSizes`) instead of the default ordering |
|
|
131
|
+
| `orderedProductSizes` | `string[]` | Ordered list of size values controlling the sequence in which size selectors are rendered; changes trigger targeted rerenders of the affected size selectors |
|
|
124
132
|
| `showPoweredBy` | `boolean` | Show "Powered by LiquidCommerce" badge |
|
|
125
133
|
| `poweredByMode` | `'light' \| 'dark'` | Color mode for the powered-by badge |
|
|
126
134
|
|
|
135
|
+
> **Note:** `showPoweredBy` is a server/plan-controlled setting and **cannot** be overridden by hosts. Any value supplied via `customTheme` (or a later config update) is stripped and the server value is restored. Only `poweredByMode` (`'light' \| 'dark'`) is host-overridable.
|
|
136
|
+
|
|
127
137
|
**Example:**
|
|
128
138
|
|
|
129
139
|
```javascript
|
|
@@ -178,6 +178,8 @@ interface IInjectCheckoutParams {
|
|
|
178
178
|
|
|
179
179
|
### IInjectCheckoutBuilderParams
|
|
180
180
|
|
|
181
|
+
`simulatePresale` and `presaleExpiresInMinutes` are builder-only preview controls (presale lock defaults to 15 minutes) and only take effect via `ElementsBuilder().injectCheckoutElement()`.
|
|
182
|
+
|
|
181
183
|
```typescript
|
|
182
184
|
interface IInjectCheckoutBuilderParams extends IInjectCheckoutParams {
|
|
183
185
|
simulatePresale?: boolean;
|
|
@@ -293,7 +295,7 @@ interface ILiquidCommerceElementsActions {
|
|
|
293
295
|
|
|
294
296
|
### IElementsCheckoutActions
|
|
295
297
|
|
|
296
|
-
Checkout actions available in the checkout-only client.
|
|
298
|
+
Checkout actions available in the checkout-only client. This is `ICheckoutActions` with `openCheckout`, `closeCheckout`, and `toggleCheckout` omitted -- the checkout-only client renders checkout independently and has no drawer navigation to open, close, or toggle.
|
|
297
299
|
|
|
298
300
|
```typescript
|
|
299
301
|
interface IElementsCheckoutActions extends Omit<ICheckoutActions, 'openCheckout' | 'closeCheckout' | 'toggleCheckout'> {}
|
|
@@ -378,6 +380,8 @@ interface UpdateProductListComponent {
|
|
|
378
380
|
}
|
|
379
381
|
```
|
|
380
382
|
|
|
383
|
+
These `Update*Component` types are the arguments to the `ElementsBuilder()` client's `update*Component` methods; see [Client API](./client.md) for their behavior and usage.
|
|
384
|
+
|
|
381
385
|
See [Configuration Reference](./configuration.md) for detailed theme property descriptions.
|
|
382
386
|
|
|
383
387
|
---
|
|
@@ -96,11 +96,11 @@ The SDK uses a two-phase initialization strategy for optimal performance:
|
|
|
96
96
|
- Store initialization
|
|
97
97
|
- Theme setup
|
|
98
98
|
- Core component registration
|
|
99
|
-
- Telemetry / logger wiring
|
|
99
|
+
- Telemetry / logger wiring (see [Telemetry & Privacy](../reference/telemetry.md))
|
|
100
100
|
- Debug panel (if enabled)
|
|
101
101
|
|
|
102
102
|
**Phase 2: Deferred Services (next macrotask, via `setTimeout(…, 0)`)**
|
|
103
|
-
- Analytics (Google Tag Manager)
|
|
103
|
+
- Analytics (Google Tag Manager — see [Analytics (GTM/GA4)](../reference/analytics.md))
|
|
104
104
|
- Cart pre-loading
|
|
105
105
|
- Heavy component registration
|
|
106
106
|
|
|
@@ -368,10 +368,12 @@ const client = await Elements('YOUR_API_KEY', {
|
|
|
368
368
|
```
|
|
369
369
|
|
|
370
370
|
**Debug Modes:**
|
|
371
|
-
- `'none'` - No debug output (
|
|
371
|
+
- `'none'` - No debug output (default)
|
|
372
372
|
- `'console'` - Log to browser console
|
|
373
373
|
- `'panel'` - Show debug panel on page
|
|
374
374
|
|
|
375
|
+
> **Production note:** `debugMode` has no effect when `env` is `'production'`. All debug output — console logging and the debug panel — is disabled in production regardless of the `debugMode` you pass. `'console'` and `'panel'` only take effect in non-production environments.
|
|
376
|
+
|
|
375
377
|
## Security & API Keys
|
|
376
378
|
|
|
377
379
|
### API Key Protection
|
|
@@ -30,6 +30,16 @@ Add the following script tag to your page's `<head>` section:
|
|
|
30
30
|
></script>
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
+
> **Note:** The host `elements.reservebar-worker.workers.dev` shown above is an example, partner-specific endpoint. Use the CDN URL provided by your LiquidCommerce representative in place of this host.
|
|
34
|
+
|
|
35
|
+
The path segment selects which bundle is served:
|
|
36
|
+
|
|
37
|
+
| Path | Bundle |
|
|
38
|
+
|------|--------|
|
|
39
|
+
| `/all/elements.js` | Full SDK bundle (product, cart, checkout, and all other elements) |
|
|
40
|
+
| `/checkout/elements.js` | Checkout-only bundle (tree-shaken, smaller) |
|
|
41
|
+
| `/all/beta/elements.js` | Beta channel of the full SDK bundle |
|
|
42
|
+
|
|
33
43
|
### Script Attributes
|
|
34
44
|
|
|
35
45
|
| Attribute | Required | Description |
|
|
@@ -140,7 +150,16 @@ const config: ILiquidCommerceElementsConfig = {
|
|
|
140
150
|
}
|
|
141
151
|
};
|
|
142
152
|
|
|
143
|
-
|
|
153
|
+
// Elements() returns `null` in SSR / non-browser environments, so the
|
|
154
|
+
// client is typed as `ILiquidCommerceElementsClient | null`.
|
|
155
|
+
const client: ILiquidCommerceElementsClient | null = await Elements('YOUR_API_KEY', config);
|
|
156
|
+
|
|
157
|
+
if (client) {
|
|
158
|
+
// Safe to use the client here
|
|
159
|
+
client.injectProductElement([
|
|
160
|
+
{ containerId: 'product-1', identifier: '00619947000020' }
|
|
161
|
+
]);
|
|
162
|
+
}
|
|
144
163
|
```
|
|
145
164
|
|
|
146
165
|
## Framework Integration
|
|
@@ -255,6 +274,8 @@ const client = await Elements('YOUR_API_KEY', {
|
|
|
255
274
|
});
|
|
256
275
|
```
|
|
257
276
|
|
|
277
|
+
> **Note:** `debugMode` is ignored when `env` is `'production'`. Debug logging and the debug panel are only activated in non-production environments (`development` or `staging`).
|
|
278
|
+
|
|
258
279
|
See [Configuration Reference](../api/configuration.md) for complete configuration options.
|
|
259
280
|
|
|
260
281
|
## Verification
|
|
@@ -6,6 +6,7 @@ The Cart component provides a slide-out drawer for managing shopping cart items,
|
|
|
6
6
|
|
|
7
7
|
The Cart component automatically:
|
|
8
8
|
- Displays cart items with images and details
|
|
9
|
+
- Removes white / near-white backgrounds from item images so products blend into the drawer (automatic, not host-configurable)
|
|
9
10
|
- Groups items by retailer
|
|
10
11
|
- Shows real-time pricing and totals
|
|
11
12
|
- Supports quantity updates
|
|
@@ -342,6 +343,17 @@ window.addEventListener('lce:actions.cart_item_quantity_decrease', (event) => {
|
|
|
342
343
|
});
|
|
343
344
|
```
|
|
344
345
|
|
|
346
|
+
### Engraving Updated
|
|
347
|
+
|
|
348
|
+
Fired when a cart line item's engraving is added or edited from the drawer (see [Engraving](#engraving)):
|
|
349
|
+
|
|
350
|
+
```javascript
|
|
351
|
+
window.addEventListener('lce:actions.cart_item_engraving_updated', (event) => {
|
|
352
|
+
const { cartId, itemId, engravingLines, previousEngravingLines } = event.detail.data;
|
|
353
|
+
console.log(`Engraving updated for ${itemId}:`, engravingLines);
|
|
354
|
+
});
|
|
355
|
+
```
|
|
356
|
+
|
|
345
357
|
### Promo Code Events
|
|
346
358
|
|
|
347
359
|
```javascript
|
|
@@ -546,6 +558,26 @@ Items are automatically grouped by retailer in the cart:
|
|
|
546
558
|
└─────────────────────────────────────┘
|
|
547
559
|
```
|
|
548
560
|
|
|
561
|
+
## Order Minimums
|
|
562
|
+
|
|
563
|
+
Retailers can require a minimum purchase amount before their items can be checked out. The cart enforces this per retailer:
|
|
564
|
+
|
|
565
|
+
- When a retailer's minimum is not met, the cart drawer shows a per-retailer alert reading `+$X needed for order minimum`, where `$X` is the remaining amount required for that retailer.
|
|
566
|
+
- The **Checkout** button is disabled until every retailer's minimum is met. (It is also disabled while the cart is loading/updating or when the cart is empty.)
|
|
567
|
+
|
|
568
|
+
No configuration is required — the minimums are defined by each retailer and enforced automatically.
|
|
569
|
+
|
|
570
|
+
## Engraving
|
|
571
|
+
|
|
572
|
+
For engravable items, shoppers can add or edit engraving directly from a cart line item, without leaving the drawer.
|
|
573
|
+
|
|
574
|
+
- If an engravable item has no engraving yet, the line item shows an **Add personalization** action (with the engraving fee) that opens the engraving form.
|
|
575
|
+
- If the item already has engraving, its engraving is shown on the line item with an **Edit** button that reopens the form.
|
|
576
|
+
|
|
577
|
+
The form respects the item's engraving constraints — `maxLines`, `maxCharsPerLine`, and the per-item `fee`. Saving emits [`lce:actions.cart_item_engraving_updated`](#engraving-updated) with the item's `engravingLines` and `previousEngravingLines`.
|
|
578
|
+
|
|
579
|
+
**Note:** This in-drawer editing is distinct from the `engravingLines` array passed to [`addProduct`](#add-product-to-cart), which pre-fills engraving at the time an item is added.
|
|
580
|
+
|
|
549
581
|
## Checkout Navigation
|
|
550
582
|
|
|
551
583
|
### Checkout Drawer (Default)
|
|
@@ -148,6 +148,8 @@ Products with multiple images display in an interactive carousel:
|
|
|
148
148
|
- Thumbnail preview
|
|
149
149
|
- Lazy loading for performance
|
|
150
150
|
|
|
151
|
+
**Background removal:** Product images (the main detail image and the gallery) automatically have their white/near-white background removed so photos blend into the surrounding page background instead of sitting on a white box. The SDK picks the technique per image based on the host background — blending the white away on light backgrounds, or keying it out to true transparency on dark or transparent backgrounds — and skips SVG artwork, which is already transparent. This is applied automatically and is not currently host-configurable.
|
|
152
|
+
|
|
151
153
|
### Size Selection
|
|
152
154
|
|
|
153
155
|
For products with multiple sizes:
|
|
@@ -206,8 +208,8 @@ For products with multiple retailers:
|
|
|
206
208
|
|
|
207
209
|
**Popup View**
|
|
208
210
|
- "See Delivery Options" button (shows the available fulfillment count, e.g. "See Delivery Options (3)")
|
|
209
|
-
-
|
|
210
|
-
-
|
|
211
|
+
- Opens a plain, scrollable list of the available delivery/retailer options
|
|
212
|
+
- No filtering or search — select a retailer from the list to choose it
|
|
211
213
|
|
|
212
214
|
### Personalization/Engraving
|
|
213
215
|
|
|
@@ -366,6 +368,7 @@ const client = await Elements('YOUR_API_KEY', {
|
|
|
366
368
|
showOnlyMainImage: false, // Show all images or just the main one
|
|
367
369
|
showTitle: true,
|
|
368
370
|
showDescription: true,
|
|
371
|
+
descriptionPosition: 'below', // Description placement: 'above' or 'below'
|
|
369
372
|
showQuantityCounter: true,
|
|
370
373
|
showOffHours: true, // Show when retailer is closed
|
|
371
374
|
quantityCounterStyle: 'outlined', // or 'ghost'
|
|
@@ -376,6 +379,7 @@ const client = await Elements('YOUR_API_KEY', {
|
|
|
376
379
|
addToCartButtonShowTotalPrice: true,
|
|
377
380
|
buyNowButtonText: 'Buy Now',
|
|
378
381
|
preSaleButtonText: 'Pre-Order',
|
|
382
|
+
prioritizeEngraving: false, // Show engraving option before add-to-cart
|
|
379
383
|
noAvailabilityText: 'Not available in your area'
|
|
380
384
|
}
|
|
381
385
|
}
|
|
@@ -260,18 +260,19 @@ Each product card shows:
|
|
|
260
260
|
- Product name
|
|
261
261
|
- Brand
|
|
262
262
|
- Price (or price range for multiple sizes)
|
|
263
|
-
- Rating (if available)
|
|
264
263
|
- Clickable image/card linking to the product detail page (when `productUrl` is configured)
|
|
265
264
|
- "Add to Cart" button (optional)
|
|
266
265
|
- Availability indicator
|
|
267
266
|
|
|
267
|
+
Product card images automatically have their white/near-white backgrounds removed so the product blends into the surrounding card and page background. This treatment is applied at render time and is not host-configurable.
|
|
268
|
+
|
|
268
269
|
### Card Interaction
|
|
269
270
|
|
|
270
271
|
**Click on card:** Navigate to product detail page (if `productUrl` configured — see [Product URL Map](#product-url-map) for partner-owned PDP URLs that aren't derivable from a token).
|
|
271
272
|
|
|
272
273
|
**Quick Add:** Add product to cart directly from list view (if enabled)
|
|
273
274
|
|
|
274
|
-
**Click on image:**
|
|
275
|
+
**Click on image:** Navigate to the configured `productUrl` (only when `productUrl` is set — otherwise the image is not a link)
|
|
275
276
|
|
|
276
277
|
## Customization
|
|
277
278
|
|
|
@@ -514,10 +515,8 @@ The product list component includes:
|
|
|
514
515
|
### Optimization Features
|
|
515
516
|
|
|
516
517
|
- **Image lazy loading**: Images load as they enter viewport
|
|
517
|
-
- **
|
|
518
|
+
- **Progressive loading**: Products load in batches via an `IntersectionObserver` sentinel as you scroll — each page is appended to the grid and loaded cards remain in the DOM
|
|
518
519
|
- **Debounced search**: Reduces API calls during typing
|
|
519
|
-
- **Filter caching**: Caches filter results
|
|
520
|
-
- **Progressive loading**: Loads in batches
|
|
521
520
|
|
|
522
521
|
### Large Catalogs
|
|
523
522
|
|
|
@@ -53,6 +53,12 @@ customTheme: {
|
|
|
53
53
|
}
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
+
**Constraints:**
|
|
57
|
+
|
|
58
|
+
- Only Google Fonts are supported. Each font's `name` must be a valid Google Font name (for example, `'Poppins'` or `'Inter'`).
|
|
59
|
+
- `Poppins` is always loaded as the default font regardless of your configuration, so it remains available even if you do not specify it.
|
|
60
|
+
- Font loading requires network access to `fonts.googleapis.com` and `fonts.gstatic.com`. If your environment enforces a Content Security Policy or routes traffic through a proxy, allow these hosts so fonts can load.
|
|
61
|
+
|
|
56
62
|
### Border Radius
|
|
57
63
|
|
|
58
64
|
```javascript
|
|
@@ -77,12 +83,16 @@ customTheme: {
|
|
|
77
83
|
personalizationCardStyle: 'outlined', // or 'filled'
|
|
78
84
|
allowPromoCodes: true,
|
|
79
85
|
inputFieldStyle: 'outlined', // or 'filled'
|
|
86
|
+
enableOrderedProductSizes: true, // enable custom ordering of the size selectors
|
|
87
|
+
orderedProductSizes: ['750ml', '1L', '1.75L'], // order applied to product and product-list size selectors
|
|
80
88
|
poweredByMode: 'light' // or 'dark' (note: showPoweredBy is controlled server-side and cannot be overridden via customTheme)
|
|
81
89
|
}
|
|
82
90
|
}
|
|
83
91
|
}
|
|
84
92
|
```
|
|
85
93
|
|
|
94
|
+
`enableOrderedProductSizes` and `orderedProductSizes` control the ordering of the size selectors rendered by the product and product-list components. When `enableOrderedProductSizes` is `true`, size options are sorted to match the sequence in the `orderedProductSizes` string array. Updating either key triggers a targeted rerender of the affected size selectors.
|
|
95
|
+
|
|
86
96
|
## Component Themes
|
|
87
97
|
|
|
88
98
|
### Product Component
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Analytics & Google Tag Manager
|
|
2
|
+
|
|
3
|
+
The SDK ships with a built-in Google Tag Manager (GTM) / Google Analytics 4 (GA4) integration. It automatically pushes GA4 ecommerce events for the interactions your shoppers perform in Elements components — product views, cart changes, checkout steps, purchases, and more.
|
|
4
|
+
|
|
5
|
+
This runs entirely inside the SDK. In most cases you do not need to configure or code anything.
|
|
6
|
+
|
|
7
|
+
## What You Need To Do
|
|
8
|
+
|
|
9
|
+
**Typically nothing.** The integration is automatic in production and staging. The SDK receives its GTM container configuration from the LiquidCommerce platform (per partner) and initializes itself after the DOM is ready.
|
|
10
|
+
|
|
11
|
+
It coexists with a host site's own GTM — see [Coexisting With Your Own GTM](#coexisting-with-your-own-gtm) below.
|
|
12
|
+
|
|
13
|
+
## Supported Environments
|
|
14
|
+
|
|
15
|
+
GTM initialization and every event push are enabled in production and staging. When the SDK is running in development or Builder mode, no container is loaded and no events are sent.
|
|
16
|
+
|
|
17
|
+
Events are suppressed when any of the following is true:
|
|
18
|
+
|
|
19
|
+
- `window` is undefined (server-side rendering).
|
|
20
|
+
- The SDK is running in Builder mode.
|
|
21
|
+
- The environment is `development`.
|
|
22
|
+
|
|
23
|
+
The environment defaults to `production` when none is provided, so a standard production embed is analytics-enabled out of the box; a staging embed is also analytics-enabled when server GTM config is enabled for the partner.
|
|
24
|
+
|
|
25
|
+
## How It Works
|
|
26
|
+
|
|
27
|
+
### Container injection
|
|
28
|
+
|
|
29
|
+
When enabled, the SDK injects the GTM container script:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
https://www.googletagmanager.com/gtm.js?id=<containerId>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The script is appended to `<head>` with `async` and `crossorigin="anonymous"`, and the SDK waits for GTM to initialize before flushing events.
|
|
36
|
+
|
|
37
|
+
### dataLayer and gtag
|
|
38
|
+
|
|
39
|
+
The SDK initializes the standard GTM globals **without clobbering an existing setup**:
|
|
40
|
+
|
|
41
|
+
- `window.dataLayer` is created only if it does not already exist.
|
|
42
|
+
- `window.gtag` is defined only if it is not already present.
|
|
43
|
+
|
|
44
|
+
Events are delivered using Google's recommended `window.dataLayer.push()` pattern.
|
|
45
|
+
|
|
46
|
+
### Event queueing
|
|
47
|
+
|
|
48
|
+
Events fired before GTM finishes initializing are queued (up to 100, oldest dropped first) and flushed once the container is ready. Queued events older than 30 seconds at flush time are discarded.
|
|
49
|
+
|
|
50
|
+
## Coexisting With Your Own GTM
|
|
51
|
+
|
|
52
|
+
The SDK detects an already-present partner/host GTM container rather than replacing it. When a host GTM install (an existing `gtag` function or an existing `googletagmanager.com/gtm.js` script tag) is detected, the SDK integrates with it.
|
|
53
|
+
|
|
54
|
+
When both the LiquidCommerce container and a partner container are initialized, events are sent to both using GA4's `send_to` targeting (a dual-container send). Only containers that are actually initialized are added to `send_to`, so events are never routed to a container that failed to load.
|
|
55
|
+
|
|
56
|
+
If the LiquidCommerce container can't be loaded, the SDK falls back — in order — to the partner container, any initialized GTM container on the page, or the basic `dataLayer` — so event tracking degrades gracefully instead of failing.
|
|
57
|
+
|
|
58
|
+
## Source Tracking (`tenant_*`)
|
|
59
|
+
|
|
60
|
+
Every event automatically carries source-tracking fields identifying the tenant and the SDK build:
|
|
61
|
+
|
|
62
|
+
| Field | Value |
|
|
63
|
+
| --- | --- |
|
|
64
|
+
| `tenant_name` | Partner name |
|
|
65
|
+
| `tenant_code` | Partner code |
|
|
66
|
+
| `tenant_env` | SDK environment |
|
|
67
|
+
| `tenant_source` | SDK package description and version |
|
|
68
|
+
|
|
69
|
+
## Events
|
|
70
|
+
|
|
71
|
+
All events are GA4-shaped and follow the standard ecommerce schema (`items[]`, `value`, `currency` — the SDK uses `USD`, `coupon`, etc.).
|
|
72
|
+
|
|
73
|
+
### Standard GA4 ecommerce events
|
|
74
|
+
|
|
75
|
+
| Event | Fired when |
|
|
76
|
+
| --- | --- |
|
|
77
|
+
| `view_item` | A shopper views a product |
|
|
78
|
+
| `view_item_list` | A shopper views a list of products |
|
|
79
|
+
| `select_item` | A shopper selects a product from a list |
|
|
80
|
+
| `add_to_cart` | A shopper adds an item to the cart |
|
|
81
|
+
| `view_cart` | A shopper views the cart |
|
|
82
|
+
| `remove_from_cart` | A shopper removes an item from the cart |
|
|
83
|
+
| `begin_checkout` | A shopper begins checkout |
|
|
84
|
+
| `add_shipping_info` | Shipping info is added during checkout |
|
|
85
|
+
| `add_payment_info` | Payment info is added during checkout |
|
|
86
|
+
| `purchase` | A purchase completes |
|
|
87
|
+
|
|
88
|
+
### Custom events
|
|
89
|
+
|
|
90
|
+
| Event | Fired when |
|
|
91
|
+
| --- | --- |
|
|
92
|
+
| `promo_code_attempt` | A promo code is submitted |
|
|
93
|
+
| `promo_code_applied` | A promo code is successfully applied |
|
|
94
|
+
| `promo_code_failed` | A promo code fails to apply |
|
|
95
|
+
| `gift_card_attempt` | A gift card is submitted |
|
|
96
|
+
| `gift_card_applied` | A gift card is successfully applied |
|
|
97
|
+
| `gift_card_failed` | A gift card fails to apply |
|
|
98
|
+
| `address_updated` | An address is successfully updated |
|
|
99
|
+
| `address_failed` | An address operation fails |
|
|
100
|
+
| `product_no_availability` | A product has no availability for any size/fulfillment |
|
|
101
|
+
| `product_size_no_availability` | A selected size has no availability |
|
|
102
|
+
| `product_fulfillment_no_availability` | A selected fulfillment type has no availability |
|
|
103
|
+
|
|
104
|
+
## Related Docs
|
|
105
|
+
|
|
106
|
+
- [Events Guide](../guides/events.md)
|
|
107
|
+
- [Client API](../api/client.md)
|
|
108
|
+
- [Troubleshooting](./troubleshooting.md)
|
|
@@ -25,7 +25,9 @@ In non-browser environments, initialization is skipped. If you call the SDK on t
|
|
|
25
25
|
it returns `null` and logs a warning instead of throwing.
|
|
26
26
|
|
|
27
27
|
Call `Elements`, `ElementsCheckout`, or `ElementsBuilder` from client-only code (e.g., after mount)
|
|
28
|
-
to render components.
|
|
28
|
+
to render components. `Elements` and `ElementsBuilder` resolve to no-op stubs from the main SSR
|
|
29
|
+
entry; `ElementsCheckout` ships in its own tree-shaken entry with a separate stub, so it is safe to
|
|
30
|
+
import even if you never use the other two.
|
|
29
31
|
|
|
30
32
|
## Polyfills (Legacy Browsers)
|
|
31
33
|
|
|
@@ -68,6 +68,14 @@ window.addEventListener('lce:actions.checkout_submit_failed', (event) => {
|
|
|
68
68
|
|
|
69
69
|
When a component fails to load, the SDK renders an error view inside the container and logs details to the console.
|
|
70
70
|
|
|
71
|
+
## Global Error Interception
|
|
72
|
+
|
|
73
|
+
On load, the SDK installs its own global handlers by reassigning `window.onerror` and `window.onunhandledrejection`. Each incoming error or rejection is classified by an `isSDKError` heuristic that inspects the error's message, stack, and source — matching a script `src` ending in `/elements.js`, known SDK class and directory patterns, and an `isSdk` flag on `SDKError` instances.
|
|
74
|
+
|
|
75
|
+
When an error is classified as SDK-originated, the handler logs it to the console and returns `true` (for `onerror`) or calls `event.preventDefault()` (for `onunhandledrejection`), so the error is swallowed and never reaches your app. Errors that are not classified as SDK-originated are chained to any handler that was already installed before the SDK loaded.
|
|
76
|
+
|
|
77
|
+
> **Implications:** SDK-originated errors are intentionally suppressed and will **not** surface in your host error monitoring (e.g. Sentry). Conversely, the heuristic is pattern-based and can occasionally match a non-SDK error, causing it to be swallowed too. If you rely on catching failures, use the `*_failed` events and `try/catch` described above rather than global error monitoring.
|
|
78
|
+
|
|
71
79
|
## Related Docs
|
|
72
80
|
|
|
73
81
|
- [Events Guide](../guides/events.md)
|