@liquidcommerce/elements-sdk 2.7.21 → 2.7.23
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 +1 -1
- package/dist/index.checkout.esm.js +7220 -7124
- package/dist/index.esm.js +11633 -11540
- package/dist/types/auto-initialize/shared-utils.d.ts +1 -0
- package/dist/types/clients/builder.d.ts +1 -1
- package/dist/types/clients/checkout.d.ts +1 -1
- package/dist/types/clients/main.d.ts +1 -1
- package/dist/types/core/pubsub/interfaces/address.interface.d.ts +3 -0
- package/dist/types/core/pubsub/interfaces/core.interface.d.ts +2 -2
- package/dist/types/utils/product.d.ts +5 -0
- package/docs/v1/api/actions/address-actions.md +20 -15
- package/docs/v1/api/actions/cart-actions.md +22 -23
- package/docs/v1/api/actions/checkout-actions.md +72 -25
- package/docs/v1/api/actions/product-actions.md +61 -15
- package/docs/v1/api/client.md +38 -14
- package/docs/v1/api/configuration.md +5 -1
- package/docs/v1/api/injection-methods.md +8 -4
- package/docs/v1/api/typescript-types.md +6 -0
- package/docs/v1/examples/advanced-patterns.md +7 -6
- package/docs/v1/examples/checkout-flow.md +1 -2
- package/docs/v1/getting-started/concepts.md +20 -25
- package/docs/v1/getting-started/installation.md +4 -4
- package/docs/v1/guides/address-component.md +12 -8
- package/docs/v1/guides/best-practices.md +5 -5
- package/docs/v1/guides/cart-component.md +27 -39
- package/docs/v1/guides/checkout-component.md +27 -29
- package/docs/v1/guides/events.md +4 -4
- package/docs/v1/guides/product-component.md +64 -19
- package/docs/v1/guides/product-list-component.md +8 -9
- package/docs/v1/guides/theming.md +6 -9
- package/docs/v1/integration/proxy-setup.md +22 -5
- package/docs/v1/reference/browser-support.md +2 -1
- package/docs/v1/reference/error-handling.md +12 -7
- package/docs/v1/reference/performance.md +1 -3
- package/docs/v1/reference/troubleshooting.md +3 -3
- package/package.json +9 -17
|
@@ -171,6 +171,7 @@ interface IProductLayout {
|
|
|
171
171
|
showOnlyMainImage: boolean;
|
|
172
172
|
showTitle: boolean;
|
|
173
173
|
showDescription: boolean;
|
|
174
|
+
descriptionPosition: 'above' | 'below';
|
|
174
175
|
showQuantityCounter: boolean;
|
|
175
176
|
showOffHours: boolean;
|
|
176
177
|
quantityCounterStyle: 'outlined' | 'ghost';
|
|
@@ -192,6 +193,7 @@ interface IProductLayout {
|
|
|
192
193
|
| `showOnlyMainImage` | `boolean` | Show only the main product image (no carousel) |
|
|
193
194
|
| `showTitle` | `boolean` | Show product title |
|
|
194
195
|
| `showDescription` | `boolean` | Show product description |
|
|
196
|
+
| `descriptionPosition` | `'above' \| 'below'` | Placement of the product description relative to other content |
|
|
195
197
|
| `showQuantityCounter` | `boolean` | Show quantity selector |
|
|
196
198
|
| `showOffHours` | `boolean` | Show off-hours messaging |
|
|
197
199
|
| `quantityCounterStyle` | `'outlined' \| 'ghost'` | Visual style for quantity counter |
|
|
@@ -509,13 +511,15 @@ See [Proxy Setup Guide](../integration/proxy-setup.md) for implementation detail
|
|
|
509
511
|
interface ILiquidCommerceElementsDevelopmentConfig {
|
|
510
512
|
customApiUrl?: string;
|
|
511
513
|
openShadowDom?: boolean;
|
|
514
|
+
mockMode?: boolean;
|
|
512
515
|
}
|
|
513
516
|
```
|
|
514
517
|
|
|
515
518
|
| Property | Type | Description |
|
|
516
519
|
|----------|------|-------------|
|
|
517
520
|
| `customApiUrl` | `string` | Custom API URL for local or custom backend testing |
|
|
518
|
-
| `openShadowDom` | `boolean` |
|
|
521
|
+
| `openShadowDom` | `boolean` | Use an OPEN (inspectable) Shadow DOM instead of the default closed mode, for debugging. Shadow DOM is always attached; forced off in production (default: `false`) |
|
|
522
|
+
| `mockMode` | `boolean` | Enable mock mode to receive mock data from the API; sends an `X-Liquid-Api-Mock-Mode` header with all requests (default: `false`) |
|
|
519
523
|
|
|
520
524
|
> To pre-select a payment method and skip the card form (in any environment), use [`actions.checkout.setSavedPaymentMethod`](./actions/checkout-actions.md#actionscheckoutsetsavedpaymentmethod) instead.
|
|
521
525
|
|
|
@@ -53,9 +53,12 @@ injectAddressElement(
|
|
|
53
53
|
|
|
54
54
|
```javascript
|
|
55
55
|
await client.injectAddressElement('address-container', {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
showLabel: true
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Listen for address changes via the published event (dispatched on window)
|
|
60
|
+
window.addEventListener('lce:actions.address_updated', (event) => {
|
|
61
|
+
console.log('Address set:', event.detail.data);
|
|
59
62
|
});
|
|
60
63
|
```
|
|
61
64
|
|
|
@@ -127,7 +130,7 @@ injectProductList(params: IInjectProductListParams): Promise<void>
|
|
|
127
130
|
interface IInjectProductListParams {
|
|
128
131
|
containerId: string;
|
|
129
132
|
slug: string; // Product list slug identifier
|
|
130
|
-
rows?: number; // Default:
|
|
133
|
+
rows?: number; // Default: 4
|
|
131
134
|
columns?: number; // Default: 4
|
|
132
135
|
filters?: ProductListFilterType[];
|
|
133
136
|
productUrl?: PLCProductUrl; // string template OR Record<identifier, url> map
|
|
@@ -192,6 +195,7 @@ injectProductListSearch(params: IInjectProductListSearchParams): Promise<void>
|
|
|
192
195
|
interface IInjectProductListSearchParams {
|
|
193
196
|
containerId: string;
|
|
194
197
|
slug: string; // Product list slug identifier
|
|
198
|
+
filters?: ProductListFilterType[];
|
|
195
199
|
}
|
|
196
200
|
```
|
|
197
201
|
|
|
@@ -103,6 +103,10 @@ interface ILiquidCommerceElementsConfig {
|
|
|
103
103
|
}
|
|
104
104
|
```
|
|
105
105
|
|
|
106
|
+
### ILiquidCommerceElementsBuilderConfig
|
|
107
|
+
|
|
108
|
+
Same shape as `ILiquidCommerceElementsConfig`, used by `ElementsBuilder()`.
|
|
109
|
+
|
|
106
110
|
### ILiquidCommerceElementsCheckoutClientConfig
|
|
107
111
|
|
|
108
112
|
Same shape as `ILiquidCommerceElementsConfig`, used for the checkout-only client.
|
|
@@ -135,6 +139,7 @@ interface IElementsProxyConfig {
|
|
|
135
139
|
interface ILiquidCommerceElementsDevelopmentConfig {
|
|
136
140
|
customApiUrl?: string;
|
|
137
141
|
openShadowDom?: boolean;
|
|
142
|
+
mockMode?: boolean; // when true, sends an 'X-Liquid-Api-Mock-Mode' header to receive mock data
|
|
138
143
|
}
|
|
139
144
|
```
|
|
140
145
|
|
|
@@ -215,6 +220,7 @@ type PLCProductUrl = string | Record<string, string>;
|
|
|
215
220
|
interface IInjectProductListSearchParams {
|
|
216
221
|
containerId: string;
|
|
217
222
|
slug: string;
|
|
223
|
+
filters?: ProductListFilterType[];
|
|
218
224
|
}
|
|
219
225
|
```
|
|
220
226
|
|
|
@@ -28,7 +28,8 @@ await window.LiquidCommerce.elements.actions.address.setAddressManually(
|
|
|
28
28
|
two: 'Apt 4',
|
|
29
29
|
city: 'New York',
|
|
30
30
|
state: 'NY',
|
|
31
|
-
zip: '10001'
|
|
31
|
+
zip: '10001',
|
|
32
|
+
country: 'US'
|
|
32
33
|
},
|
|
33
34
|
{
|
|
34
35
|
latitude: 40.7128,
|
|
@@ -49,17 +50,17 @@ await window.LiquidCommerce.elements.actions.address.setAddressManually(
|
|
|
49
50
|
|
|
50
51
|
```javascript
|
|
51
52
|
window.addEventListener('lce:actions.product_loaded', (event) => {
|
|
52
|
-
const { identifier, name,
|
|
53
|
+
const { identifier, name, priceInfo } = event.detail.data;
|
|
53
54
|
gtag('event', 'view_item', {
|
|
54
|
-
items: [{ item_id: identifier, item_name: name, price:
|
|
55
|
+
items: [{ item_id: identifier, item_name: name, price: (priceInfo?.minimum ?? 0) / 100 }]
|
|
55
56
|
});
|
|
56
57
|
});
|
|
57
58
|
|
|
58
59
|
window.addEventListener('lce:actions.checkout_submit_completed', (event) => {
|
|
59
|
-
const {
|
|
60
|
+
const { orderNumber, orderTotal } = event.detail.data;
|
|
60
61
|
gtag('event', 'purchase', {
|
|
61
|
-
transaction_id:
|
|
62
|
-
value:
|
|
62
|
+
transaction_id: orderNumber,
|
|
63
|
+
value: orderTotal / 100,
|
|
63
64
|
currency: 'USD'
|
|
64
65
|
});
|
|
65
66
|
});
|
|
@@ -60,14 +60,13 @@ When users click checkout, the cart redirects to your hosted checkout page with
|
|
|
60
60
|
data-liquid-commerce-elements
|
|
61
61
|
data-token="YOUR_API_KEY"
|
|
62
62
|
data-env="production"
|
|
63
|
-
data-checkout-container="checkout"
|
|
64
63
|
data-checkout-param="lce_checkout"
|
|
65
64
|
type="text/javascript"
|
|
66
65
|
src="https://elements.reservebar-worker.workers.dev/all/elements.js"
|
|
67
66
|
></script>
|
|
68
67
|
</head>
|
|
69
68
|
<body>
|
|
70
|
-
<div
|
|
69
|
+
<div data-lce-checkout></div>
|
|
71
70
|
</body>
|
|
72
71
|
</html>
|
|
73
72
|
```
|
|
@@ -96,12 +96,13 @@ 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
|
|
100
|
+
- Debug panel (if enabled)
|
|
99
101
|
|
|
100
|
-
**Phase 2: Deferred Services (
|
|
101
|
-
- Analytics
|
|
102
|
+
**Phase 2: Deferred Services (next macrotask, via `setTimeout(…, 0)`)**
|
|
103
|
+
- Analytics (Google Tag Manager)
|
|
102
104
|
- Cart pre-loading
|
|
103
105
|
- Heavy component registration
|
|
104
|
-
- Debug panel (if enabled)
|
|
105
106
|
|
|
106
107
|
This ensures fast initial page loads while still providing full functionality.
|
|
107
108
|
|
|
@@ -111,8 +112,8 @@ Listen for the client ready event to know when the SDK is initialized:
|
|
|
111
112
|
|
|
112
113
|
```javascript
|
|
113
114
|
window.addEventListener('lce:actions.client_ready', (event) => {
|
|
114
|
-
console.log('SDK version:', event.detail.version);
|
|
115
|
-
console.log('Ready at:', event.detail.timestamp);
|
|
115
|
+
console.log('SDK version:', event.detail.data.version);
|
|
116
|
+
console.log('Ready at:', event.detail.data.timestamp);
|
|
116
117
|
|
|
117
118
|
// Safe to use client
|
|
118
119
|
window.LiquidCommerce.elements.actions.cart.openCart();
|
|
@@ -207,18 +208,17 @@ The SDK maintains its own internal state for cart, checkout, and user data.
|
|
|
207
208
|
### Store Service
|
|
208
209
|
|
|
209
210
|
The SDK uses a centralized store service that:
|
|
210
|
-
- Maintains reactive state
|
|
211
|
+
- Maintains reactive state (in-memory, within a single tab)
|
|
211
212
|
- Persists data to localStorage
|
|
212
213
|
- Falls back to API storage
|
|
213
|
-
- Syncs across browser tabs
|
|
214
214
|
|
|
215
215
|
### State Persistence
|
|
216
216
|
|
|
217
217
|
**Cart State:**
|
|
218
218
|
- Saved to localStorage
|
|
219
219
|
- Persists across sessions
|
|
220
|
-
- Syncs across tabs automatically
|
|
221
220
|
- Survives page refreshes
|
|
221
|
+
- Other tabs pick up the persisted cart on their next load (no live cross-tab sync)
|
|
222
222
|
|
|
223
223
|
**Address State:**
|
|
224
224
|
- Saved when set by user
|
|
@@ -230,17 +230,9 @@ The SDK uses a centralized store service that:
|
|
|
230
230
|
- Exists during checkout flow
|
|
231
231
|
- Cleared after order completion
|
|
232
232
|
|
|
233
|
-
### Cross-Tab
|
|
233
|
+
### Cross-Tab Persistence
|
|
234
234
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
```javascript
|
|
238
|
-
// Tab 1
|
|
239
|
-
await window.LiquidCommerce.elements.actions.cart.addProduct([...]);
|
|
240
|
-
|
|
241
|
-
// Tab 2 automatically receives the update
|
|
242
|
-
// No additional code needed
|
|
243
|
-
```
|
|
235
|
+
State is persisted to `localStorage` keyed by device ID. The SDK does **not** register a `storage` listener, `BroadcastChannel`, or other inter-tab subscription, so there is **no live cross-tab synchronization** — a change made in one tab is only reflected in another already-open tab after that tab reloads (which re-runs the persisted-state load and re-fetches by the persisted cart ID).
|
|
244
236
|
|
|
245
237
|
## Component Lifecycle
|
|
246
238
|
|
|
@@ -269,10 +261,12 @@ Manual rerendering:
|
|
|
269
261
|
|
|
270
262
|
```javascript
|
|
271
263
|
const components = window.LiquidCommerce.elements.getInjectedComponents();
|
|
272
|
-
|
|
264
|
+
// The Map is keyed by the container ID passed to inject* (with any leading '#' stripped),
|
|
265
|
+
// not a '<type>-<index>' string. For a component injected into id="product":
|
|
266
|
+
const productComponent = components.get('product');
|
|
273
267
|
|
|
274
268
|
// Force rerender
|
|
275
|
-
productComponent
|
|
269
|
+
productComponent?.rerender();
|
|
276
270
|
```
|
|
277
271
|
|
|
278
272
|
### Component Removal
|
|
@@ -319,8 +313,9 @@ lce:forms.billing
|
|
|
319
313
|
|
|
320
314
|
```javascript
|
|
321
315
|
window.addEventListener('lce:actions.cart_item_added', (event) => {
|
|
322
|
-
console.log('Item added:', event.detail);
|
|
323
|
-
// {
|
|
316
|
+
console.log('Item added:', event.detail.data);
|
|
317
|
+
// event.detail is { data, metadata }; payload fields live under .data:
|
|
318
|
+
// { cartId, itemId, fulfillmentId, partNumber, quantity, engravingLines? }
|
|
324
319
|
});
|
|
325
320
|
```
|
|
326
321
|
|
|
@@ -332,14 +327,14 @@ The SDK is designed to fail gracefully and not crash your site.
|
|
|
332
327
|
|
|
333
328
|
### Error Isolation
|
|
334
329
|
|
|
335
|
-
SDK errors are
|
|
330
|
+
SDK errors are logged and also emitted as a `*_FAILED` event, then re-thrown so your code can catch them:
|
|
336
331
|
|
|
337
332
|
```javascript
|
|
338
|
-
//
|
|
333
|
+
// The SDK emits CART_PRODUCT_ADD_FAILED and re-throws, so this catch runs
|
|
339
334
|
try {
|
|
340
335
|
await window.LiquidCommerce.elements.actions.cart.addProduct([/* invalid data */]);
|
|
341
336
|
} catch (error) {
|
|
342
|
-
console.log('This error is
|
|
337
|
+
console.log('This error is re-thrown by the SDK and caught here');
|
|
343
338
|
}
|
|
344
339
|
|
|
345
340
|
// Your page keeps working
|
|
@@ -36,7 +36,7 @@ Add the following script tag to your page's `<head>` section:
|
|
|
36
36
|
|-----------|----------|-------------|
|
|
37
37
|
| `data-liquid-commerce-elements` | Yes | Identifies this as the Elements SDK script |
|
|
38
38
|
| `data-token` | Yes | Your LiquidCommerce API key |
|
|
39
|
-
| `data-env` |
|
|
39
|
+
| `data-env` | No | Environment: `development`, `staging`, or `production`. Defaults to `production` if omitted. |
|
|
40
40
|
| `defer` | Recommended | Allows non-blocking script loading |
|
|
41
41
|
|
|
42
42
|
### Where to Place the Script
|
|
@@ -73,7 +73,7 @@ If you only need checkout functionality (without product displays or cart), use
|
|
|
73
73
|
```html
|
|
74
74
|
<script
|
|
75
75
|
defer
|
|
76
|
-
data-liquid-commerce-elements
|
|
76
|
+
data-liquid-commerce-elements
|
|
77
77
|
data-token="YOUR_API_KEY"
|
|
78
78
|
data-env="production"
|
|
79
79
|
type="text/javascript"
|
|
@@ -245,7 +245,7 @@ The SDK accepts a configuration object during initialization:
|
|
|
245
245
|
|
|
246
246
|
```javascript
|
|
247
247
|
const client = await Elements('YOUR_API_KEY', {
|
|
248
|
-
env: 'production', //
|
|
248
|
+
env: 'production', // Optional (defaults to 'production'): 'development' | 'staging' | 'production'
|
|
249
249
|
debugMode: 'console', // Optional: 'none' | 'console' | 'panel'
|
|
250
250
|
customTheme: { /* ... */ }, // Optional: Theme customization
|
|
251
251
|
promoTicker: [ /* ... */ ], // Optional: Promo ticker configuration
|
|
@@ -293,7 +293,7 @@ If the SDK script fails to load:
|
|
|
293
293
|
If you see an error about Web Components:
|
|
294
294
|
|
|
295
295
|
```
|
|
296
|
-
[LiquidCommerce Elements] SDK requires support for Web Components
|
|
296
|
+
[LiquidCommerce Elements] SDK requires support for Web Components. Please include a Web Components polyfill for older browsers.
|
|
297
297
|
```
|
|
298
298
|
|
|
299
299
|
Include a Web Components polyfill before the SDK script:
|
|
@@ -34,10 +34,11 @@ Use the standalone address component when you need a dedicated address selection
|
|
|
34
34
|
```javascript
|
|
35
35
|
const client = await Elements('YOUR_API_KEY', { env: 'production' });
|
|
36
36
|
|
|
37
|
-
await client.injectAddressElement('address-container'
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
await client.injectAddressElement('address-container');
|
|
38
|
+
|
|
39
|
+
// React to address selection by listening for the address_updated event
|
|
40
|
+
window.addEventListener('lce:actions.address_updated', (event) => {
|
|
41
|
+
console.log('Address set:', event.detail.data);
|
|
41
42
|
});
|
|
42
43
|
```
|
|
43
44
|
|
|
@@ -67,10 +68,11 @@ For custom address flows without Google Places:
|
|
|
67
68
|
await window.LiquidCommerce.elements.actions.address.setAddressManually(
|
|
68
69
|
{
|
|
69
70
|
one: '123 Main Street',
|
|
70
|
-
two: 'Apt 4', // Optional
|
|
71
|
+
two: 'Apt 4', // Optional at runtime
|
|
71
72
|
city: 'New York',
|
|
72
73
|
state: 'NY',
|
|
73
|
-
zip: '10001'
|
|
74
|
+
zip: '10001',
|
|
75
|
+
country: 'US'
|
|
74
76
|
},
|
|
75
77
|
{
|
|
76
78
|
latitude: 40.7128,
|
|
@@ -85,6 +87,7 @@ await window.LiquidCommerce.elements.actions.address.setAddressManually(
|
|
|
85
87
|
- `city`: City name (required)
|
|
86
88
|
- `state`: Two-letter state code (required)
|
|
87
89
|
- `zip`: ZIP/postal code (required)
|
|
90
|
+
- `country`: Country code, e.g. `'US'` (required by the `IAddressAddress` type)
|
|
88
91
|
- `latitude`: Number between -90 and 90 (required)
|
|
89
92
|
- `longitude`: Number between -180 and 180 (required)
|
|
90
93
|
|
|
@@ -103,7 +106,8 @@ console.log(addressData);
|
|
|
103
106
|
// two: 'Apt 4',
|
|
104
107
|
// city: 'New York',
|
|
105
108
|
// state: 'NY',
|
|
106
|
-
// zip: '10001'
|
|
109
|
+
// zip: '10001',
|
|
110
|
+
// country: 'US'
|
|
107
111
|
// },
|
|
108
112
|
// coordinates: {
|
|
109
113
|
// latitude: 40.7128,
|
|
@@ -316,7 +320,7 @@ Addresses persist:
|
|
|
316
320
|
|
|
317
321
|
Addresses are:
|
|
318
322
|
- Stored locally in the browser
|
|
319
|
-
-
|
|
323
|
+
- Sent to LiquidCommerce servers for availability/product loading; the address id (with the cart id) may also be persisted server-side as a session fallback when localStorage is unavailable (and a delete request is sent when the address is cleared)
|
|
320
324
|
- Cleared when user logs out (if you implement logout handling)
|
|
321
325
|
|
|
322
326
|
## Best Practices
|
|
@@ -225,7 +225,7 @@ useEffect(() => {
|
|
|
225
225
|
// Update UI when cart changes
|
|
226
226
|
window.addEventListener('lce:actions.cart_updated', () => {
|
|
227
227
|
const cart = window.LiquidCommerce.elements.actions.cart.getDetails();
|
|
228
|
-
updateHeaderCartCount(cart.
|
|
228
|
+
updateHeaderCartCount(cart.itemCount);
|
|
229
229
|
});
|
|
230
230
|
```
|
|
231
231
|
|
|
@@ -233,18 +233,18 @@ window.addEventListener('lce:actions.cart_updated', () => {
|
|
|
233
233
|
|
|
234
234
|
```javascript
|
|
235
235
|
window.addEventListener('lce:actions.checkout_submit_completed', (event) => {
|
|
236
|
-
const {
|
|
236
|
+
const { orderNumber, orderTotal } = event.detail.data;
|
|
237
237
|
|
|
238
238
|
// Analytics
|
|
239
239
|
gtag('event', 'purchase', {
|
|
240
|
-
transaction_id:
|
|
241
|
-
value:
|
|
240
|
+
transaction_id: orderNumber,
|
|
241
|
+
value: orderTotal / 100
|
|
242
242
|
});
|
|
243
243
|
|
|
244
244
|
// Backend tracking
|
|
245
245
|
fetch('/api/track-order', {
|
|
246
246
|
method: 'POST',
|
|
247
|
-
body: JSON.stringify({
|
|
247
|
+
body: JSON.stringify({ orderNumber, orderTotal })
|
|
248
248
|
});
|
|
249
249
|
});
|
|
250
250
|
```
|
|
@@ -57,7 +57,7 @@ Show the number of items in the cart:
|
|
|
57
57
|
|
|
58
58
|
#### Floating Cart Button
|
|
59
59
|
|
|
60
|
-
Create a floating button (
|
|
60
|
+
Create a floating button (top-right corner):
|
|
61
61
|
|
|
62
62
|
```html
|
|
63
63
|
<script
|
|
@@ -174,9 +174,10 @@ await window.LiquidCommerce.elements.actions.cart.addProduct([
|
|
|
174
174
|
```
|
|
175
175
|
|
|
176
176
|
**Parameters:**
|
|
177
|
-
- `identifier` (string): Product UPC,
|
|
177
|
+
- `identifier` (string): Product UPC, size ID, or salsifyGrouping ID
|
|
178
178
|
- `fulfillmentType` (string): `'shipping'` or `'onDemand'`
|
|
179
179
|
- `quantity` (number): Number of items (default: 1)
|
|
180
|
+
- `engravingLines` (string[], optional): Engraving text lines for the product (applied when the product/variant supports engraving; ignored otherwise)
|
|
180
181
|
- Second parameter (boolean): Open cart after adding (default: false)
|
|
181
182
|
|
|
182
183
|
### Apply Promo Code
|
|
@@ -215,13 +216,12 @@ const cartData = window.LiquidCommerce.elements.actions.cart.getDetails();
|
|
|
215
216
|
console.log(cartData);
|
|
216
217
|
// {
|
|
217
218
|
// cartId: 'cart_abc123',
|
|
218
|
-
//
|
|
219
|
+
// promoCodeDiscount: 1000, // number | null
|
|
219
220
|
// subtotal: 9998, // in cents
|
|
220
|
-
//
|
|
221
|
-
//
|
|
222
|
-
//
|
|
223
|
-
//
|
|
224
|
-
// retailers: [...],
|
|
221
|
+
// itemCount: 5,
|
|
222
|
+
// items: {...}, // Record<itemId, ICartItem>
|
|
223
|
+
// retailers: {...}, // Record<retailerId, ICartRetailer>
|
|
224
|
+
// location: {...}, // or null
|
|
225
225
|
// ...
|
|
226
226
|
// }
|
|
227
227
|
```
|
|
@@ -282,8 +282,8 @@ Fired when cart data is loaded:
|
|
|
282
282
|
|
|
283
283
|
```javascript
|
|
284
284
|
window.addEventListener('lce:actions.cart_loaded', (event) => {
|
|
285
|
-
const { cartId,
|
|
286
|
-
console.log(`Cart loaded: ${
|
|
285
|
+
const { cartId, itemCount, subtotal } = event.detail.data;
|
|
286
|
+
console.log(`Cart loaded: ${itemCount} items, total: $${subtotal / 100}`);
|
|
287
287
|
});
|
|
288
288
|
```
|
|
289
289
|
|
|
@@ -305,8 +305,8 @@ Fired whenever cart contents change:
|
|
|
305
305
|
|
|
306
306
|
```javascript
|
|
307
307
|
window.addEventListener('lce:actions.cart_updated', (event) => {
|
|
308
|
-
const { cartId,
|
|
309
|
-
console.log('Cart updated:',
|
|
308
|
+
const { cartId, itemCount, subtotal } = event.detail.data.current;
|
|
309
|
+
console.log('Cart updated:', itemCount, 'items');
|
|
310
310
|
});
|
|
311
311
|
```
|
|
312
312
|
|
|
@@ -332,13 +332,13 @@ window.addEventListener('lce:actions.cart_item_removed', (event) => {
|
|
|
332
332
|
|
|
333
333
|
```javascript
|
|
334
334
|
window.addEventListener('lce:actions.cart_item_quantity_increase', (event) => {
|
|
335
|
-
const { cartId, itemId,
|
|
336
|
-
console.log(`Item ${itemId} quantity increased to ${
|
|
335
|
+
const { cartId, itemId, quantity } = event.detail.data;
|
|
336
|
+
console.log(`Item ${itemId} quantity increased to ${quantity}`);
|
|
337
337
|
});
|
|
338
338
|
|
|
339
339
|
window.addEventListener('lce:actions.cart_item_quantity_decrease', (event) => {
|
|
340
|
-
const { cartId, itemId,
|
|
341
|
-
console.log(`Item ${itemId} quantity decreased to ${
|
|
340
|
+
const { cartId, itemId, quantity } = event.detail.data;
|
|
341
|
+
console.log(`Item ${itemId} quantity decreased to ${quantity}`);
|
|
342
342
|
});
|
|
343
343
|
```
|
|
344
344
|
|
|
@@ -399,7 +399,7 @@ const client = await Elements('YOUR_API_KEY', {
|
|
|
399
399
|
},
|
|
400
400
|
layout: {
|
|
401
401
|
showQuantityCounter: true,
|
|
402
|
-
quantityCounterStyle: 'outlined', // or '
|
|
402
|
+
quantityCounterStyle: 'outlined', // or 'ghost'
|
|
403
403
|
drawerHeaderText: 'My Bag',
|
|
404
404
|
goToCheckoutButtonText: 'Checkout'
|
|
405
405
|
}
|
|
@@ -419,26 +419,13 @@ This allows the cart to survive:
|
|
|
419
419
|
- Browser restarts
|
|
420
420
|
- Navigation between pages
|
|
421
421
|
|
|
422
|
-
### Cross-Tab
|
|
423
|
-
|
|
424
|
-
When you update the cart in one tab, all other open tabs automatically sync:
|
|
425
|
-
|
|
426
|
-
```javascript
|
|
427
|
-
// Tab 1: Add item
|
|
428
|
-
await window.LiquidCommerce.elements.actions.cart.addProduct([...]);
|
|
429
|
-
|
|
430
|
-
// Tab 2: Cart automatically updates
|
|
431
|
-
// No additional code needed
|
|
432
|
-
```
|
|
422
|
+
### Cross-Tab Persistence
|
|
433
423
|
|
|
434
|
-
The SDK
|
|
435
|
-
- localStorage events
|
|
436
|
-
- Periodic polling
|
|
437
|
-
- API-based fallback
|
|
424
|
+
The cart is persisted to `localStorage` and reloaded on a fresh page load. The SDK does **not** provide live cross-tab synchronization — changes made in one tab will not automatically appear in other already-open tabs (there is no `storage` listener, `BroadcastChannel`, or polling). Another tab reflects the change only after it reloads.
|
|
438
425
|
|
|
439
426
|
### Session Duration
|
|
440
427
|
|
|
441
|
-
|
|
428
|
+
Cart and address session IDs are persisted in `localStorage` (with an API fallback) and are not automatically cleared by the SDK; cart lifetime/expiry is governed by server-side policy.
|
|
442
429
|
|
|
443
430
|
## Address Requirement
|
|
444
431
|
|
|
@@ -606,8 +593,9 @@ The `{token}` placeholder is replaced with the session checkout token.
|
|
|
606
593
|
```javascript
|
|
607
594
|
// Track cart events for analytics
|
|
608
595
|
window.addEventListener('lce:actions.cart_item_added', (event) => {
|
|
596
|
+
const { itemId, quantity } = event.detail.data;
|
|
609
597
|
gtag('event', 'add_to_cart', {
|
|
610
|
-
|
|
598
|
+
items: [{ item_id: itemId, quantity }],
|
|
611
599
|
currency: 'USD'
|
|
612
600
|
});
|
|
613
601
|
});
|
|
@@ -615,7 +603,7 @@ window.addEventListener('lce:actions.cart_item_added', (event) => {
|
|
|
615
603
|
window.addEventListener('lce:actions.cart_updated', (event) => {
|
|
616
604
|
// Update header cart count
|
|
617
605
|
document.getElementById('cart-badge').textContent =
|
|
618
|
-
event.detail.data.
|
|
606
|
+
event.detail.data.current.itemCount;
|
|
619
607
|
});
|
|
620
608
|
```
|
|
621
609
|
|
|
@@ -637,9 +625,9 @@ if (campaign === 'summer-sale') {
|
|
|
637
625
|
```javascript
|
|
638
626
|
// Store cart ID in your system
|
|
639
627
|
window.addEventListener('lce:actions.cart_updated', (event) => {
|
|
640
|
-
const { cartId,
|
|
628
|
+
const { cartId, itemCount } = event.detail.data.current;
|
|
641
629
|
|
|
642
|
-
if (
|
|
630
|
+
if (itemCount > 0) {
|
|
643
631
|
// Send cart ID to your backend for abandoned cart emails
|
|
644
632
|
fetch('/api/track-cart', {
|
|
645
633
|
method: 'POST',
|
|
@@ -695,9 +683,9 @@ Show appropriate messaging for empty carts:
|
|
|
695
683
|
|
|
696
684
|
```javascript
|
|
697
685
|
window.addEventListener('lce:actions.cart_updated', (event) => {
|
|
698
|
-
const {
|
|
686
|
+
const { itemCount } = event.detail.data.current;
|
|
699
687
|
|
|
700
|
-
if (
|
|
688
|
+
if (itemCount === 0) {
|
|
701
689
|
// Show empty state in your UI
|
|
702
690
|
document.getElementById('cart-status').textContent =
|
|
703
691
|
'Your cart is empty';
|