@liquidcommerce/elements-sdk 2.2.0-beta.4 → 2.2.0-beta.41
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 +1715 -569
- package/dist/index.esm.js +14589 -10538
- package/dist/types/constants/core.constant.d.ts +32 -0
- package/dist/types/constants/index.d.ts +0 -1
- package/dist/types/{modules/api-client → core}/api-client.service.d.ts +4 -2
- package/dist/types/core/auth.service.d.ts +31 -4
- package/dist/types/core/base-component.service.d.ts +7 -3
- package/dist/types/core/circuit-breaker.service.d.ts +54 -0
- package/dist/types/core/client/client-action.service.d.ts +19 -14
- package/dist/types/core/client/client-config.service.d.ts +5 -3
- package/dist/types/core/command/base-command.service.d.ts +5 -3
- package/dist/types/core/command/command.service.d.ts +2 -0
- package/dist/types/core/command/common-command.service.d.ts +2 -1
- package/dist/types/core/debug-panel/debug-panel.service.d.ts +43 -0
- package/dist/types/core/debug-panel/debug-panel.styles.d.ts +1 -0
- package/dist/types/core/fingerprint.service.d.ts +4 -9
- package/dist/types/core/google-tag-manager.service.d.ts +128 -2
- package/dist/types/core/logger/logger-factory.d.ts +3 -0
- package/dist/types/core/logger/logger.service.d.ts +8 -5
- package/dist/types/core/pubsub/interfaces/cart.interface.d.ts +1 -0
- package/dist/types/core/pubsub/interfaces/checkout.interface.d.ts +46 -6
- package/dist/types/core/pubsub/interfaces/core.interface.d.ts +5 -3
- package/dist/types/core/pubsub/interfaces/product.interface.d.ts +43 -6
- package/dist/types/core/pubsub/pubsub.service.d.ts +3 -2
- package/dist/types/core/sdk-error-handler.d.ts +1 -0
- package/dist/types/core/singleton-manager.service.d.ts +3 -3
- package/dist/types/core/store/interfaces/cart.interface.d.ts +1 -1
- package/dist/types/core/store/interfaces/checkout.interface.d.ts +0 -1
- package/dist/types/core/store/interfaces/core.interface.d.ts +5 -3
- package/dist/types/core/store/interfaces/product.interface.d.ts +18 -7
- package/dist/types/core/store/store.constant.d.ts +5 -1
- package/dist/types/core/store/store.service.d.ts +4 -2
- package/dist/types/core/telemetry/telemetry.interface.d.ts +80 -0
- package/dist/types/core/telemetry/telemetry.service.d.ts +27 -0
- package/dist/types/core/utils.d.ts +0 -4
- package/dist/types/elements-base-client.d.ts +49 -0
- package/dist/types/elements-builder-client.d.ts +2 -0
- package/dist/types/elements-client-helper.d.ts +3 -0
- package/dist/types/enums/core.enum.d.ts +9 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.umd.d.ts +2 -2
- package/dist/types/interfaces/cloud/catalog.interface.d.ts +43 -0
- package/dist/types/interfaces/cloud/index.d.ts +1 -0
- package/dist/types/interfaces/cloud/product.interface.d.ts +2 -0
- package/dist/types/interfaces/configs/checkout.interface.d.ts +1 -1
- package/dist/types/interfaces/configs/product.interface.d.ts +2 -0
- package/dist/types/interfaces/core.interface.d.ts +47 -19
- package/dist/types/modules/address/address.command.d.ts +1 -3
- package/dist/types/modules/cart/cart.commands.d.ts +2 -3
- package/dist/types/modules/cart/cart.commands.helper.d.ts +3 -2
- package/dist/types/modules/cart/cart.component.d.ts +1 -2
- package/dist/types/modules/cart/components/cart-footer.component.d.ts +1 -0
- package/dist/types/modules/cart/components/cart-item.component.d.ts +2 -6
- package/dist/types/modules/cart/components/index.d.ts +2 -0
- package/dist/types/modules/checkout/checkout.commands.d.ts +4 -4
- package/dist/types/modules/checkout/checkout.commands.helper.d.ts +1 -1
- package/dist/types/modules/checkout/checkout.component.d.ts +1 -2
- package/dist/types/modules/checkout/components/checkout-summary-section.component.d.ts +2 -0
- package/dist/types/modules/checkout/components/information/checkout-delivery-information-form.component.d.ts +1 -1
- package/dist/types/modules/checkout/components/summary/checkout-item-quantity.component.d.ts +0 -2
- package/dist/types/modules/checkout/components/summary/checkout-item.component.d.ts +2 -1
- package/dist/types/modules/checkout/components/summary/checkout-items.component.d.ts +1 -0
- package/dist/types/modules/checkout/components/summary/checkout-place-order-button.component.d.ts +0 -1
- package/dist/types/modules/checkout/constant.d.ts +0 -1
- package/dist/types/modules/product/components/components.d.ts +1 -1
- package/dist/types/modules/product/components/index.d.ts +1 -0
- package/dist/types/modules/product/components/product-add-to-cart-section.component.d.ts +1 -0
- package/dist/types/modules/product/components/product-interactions.component.d.ts +4 -1
- package/dist/types/modules/product/components/product-price.component.d.ts +1 -0
- package/dist/types/modules/product/components/product-retailers.component.d.ts +1 -0
- package/dist/types/modules/product/product.commands.d.ts +3 -4
- package/dist/types/modules/product/utils/helpers.d.ts +1 -1
- package/dist/types/modules/product/utils/retailer-hours.d.ts +1 -1
- package/dist/types/modules/product-list/components/index.d.ts +2 -0
- package/dist/types/modules/product-list/components/product-list-card.component.d.ts +36 -0
- package/dist/types/modules/product-list/components/product-list-filters.component.d.ts +21 -0
- package/dist/types/modules/product-list/product-list.commands.d.ts +12 -0
- package/dist/types/modules/product-list/product-list.component.d.ts +76 -0
- package/dist/types/modules/theme-provider/constants/component-groupings.d.ts +0 -2
- package/dist/types/modules/theme-provider/services/font-manager.service.d.ts +1 -0
- package/dist/types/modules/theme-provider/styles/product-list/index.d.ts +1 -0
- package/dist/types/modules/theme-provider/styles/product-list/product-list.style.d.ts +1 -0
- package/dist/types/modules/ui-components/alert/alert.component.d.ts +1 -1
- package/dist/types/modules/ui-components/engraving/engraving-form.component.d.ts +13 -11
- package/dist/types/modules/ui-components/engraving/engraving-view.component.d.ts +4 -9
- package/dist/types/modules/ui-components/lce-element/lce-element.component.d.ts +2 -0
- package/dist/types/modules/ui-components/purchase-min-alert/helpers.d.ts +1 -1
- package/dist/types/modules/ui-components/ui.commands.d.ts +1 -1
- package/dist/types/static/icon/index.d.ts +0 -1
- package/dist/types/utils/format.d.ts +2 -1
- package/docs/ACTIONS.md +1300 -0
- package/docs/BROWSER_SUPPORT.md +279 -0
- package/docs/CONFIGURATION.md +740 -0
- package/docs/DOCUMENTATION_INDEX.md +311 -0
- package/docs/EVENTS.md +765 -0
- package/docs/PROXY.md +228 -0
- package/docs/THEMING.md +592 -0
- package/docs/TROUBLESHOOTING.md +793 -0
- package/package.json +20 -17
- package/umd/elements.js +1 -1
- package/dist/types/constants/z-index.constant.d.ts +0 -24
- package/dist/types/core/pubsub/index.d.ts +0 -2
- package/dist/types/core/pubsub/interfaces/index.d.ts +0 -5
- package/dist/types/core/store/index.d.ts +0 -2
- package/dist/types/core/store/interfaces/index.d.ts +0 -5
- package/dist/types/modules/address/index.d.ts +0 -4
- package/dist/types/modules/api-client/api-client.interface.d.ts +0 -21
- package/dist/types/modules/api-client/index.d.ts +0 -2
- package/dist/types/modules/cart/index.d.ts +0 -1
- package/dist/types/modules/checkout/index.d.ts +0 -1
- package/dist/types/modules/product/constant.d.ts +0 -2
- package/dist/types/modules/product/index.d.ts +0 -1
- package/dist/types/modules/theme-provider/index.d.ts +0 -2
- package/dist/types/static/icon/completed.icon.d.ts +0 -2
package/README.md
CHANGED
|
@@ -28,48 +28,20 @@ Elements SDK
|
|
|
28
28
|
<summary>Click to expand</summary>
|
|
29
29
|
|
|
30
30
|
- [Overview](#-overview)
|
|
31
|
-
- [Latest Features](#-latest-features)
|
|
32
|
-
- [Key Features](#-key-features)
|
|
33
|
-
- [Architecture](#-architecture)
|
|
34
|
-
- [System Architecture](#system-architecture)
|
|
35
|
-
- [Component Architecture](#component-architecture)
|
|
36
|
-
- [Event Flow](#event-flow)
|
|
37
|
-
- [Features](#-features)
|
|
38
|
-
- [Installation](#-installation)
|
|
39
|
-
- [CDN Usage](#option-a--use-the-cdn)
|
|
40
|
-
- [NPM Installation](#option-b--install-from-npm)
|
|
41
|
-
- [Browser Support](#-browser-support)
|
|
42
31
|
- [Quick Start](#-quick-start)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
32
|
+
- [Advanced Usage](#-advanced-usage)
|
|
33
|
+
- [Browser Support](#-browser-support)
|
|
34
|
+
- [Configuration](#-configuration)
|
|
46
35
|
- [SDK Methods & API](#-sdk-methods--api)
|
|
47
|
-
- [Core Client Methods](#core-client-methods)
|
|
48
|
-
- [UI Methods](#ui-methods)
|
|
49
|
-
- [Builder Methods](#builder-methods-development-mode)
|
|
50
36
|
- [Actions](#-actions)
|
|
51
|
-
- [Product Actions](#product-actions)
|
|
52
|
-
- [Address Actions](#address-actions)
|
|
53
|
-
- [Cart Actions](#cart-actions)
|
|
54
|
-
- [Checkout Actions](#checkout-actions)
|
|
55
37
|
- [Events](#-events)
|
|
56
|
-
- [Event Listening](#event-listening)
|
|
57
|
-
- [Available Events](#available-events)
|
|
58
|
-
- [Configuration](#-configuration)
|
|
59
|
-
- [Module Options](#module-options)
|
|
60
|
-
- [Environment Options](#environment-options)
|
|
61
|
-
- [Auto-init Attributes](#auto-init-data-attributes)
|
|
62
38
|
- [Themes & Customization](#-themes--customization)
|
|
63
|
-
|
|
64
|
-
|
|
39
|
+
- [Features Deep Dive](#-features-deep-dive)
|
|
40
|
+
- [Core Capabilities](#-core-capabilities)
|
|
41
|
+
- [Integration Patterns](#-integration-patterns)
|
|
42
|
+
- [Error Handling](#-error-handling)
|
|
43
|
+
- [Performance & Best Practices](#-performance--best-practices)
|
|
65
44
|
- [Proxy Configuration](#-proxy-configuration)
|
|
66
|
-
- [Demo Pages](#-demo-pages)
|
|
67
|
-
- [Simple Demo](#simple-demo-demosimplehtml)
|
|
68
|
-
- [Advanced Demo](#advanced-demo-demoadvancedhtml)
|
|
69
|
-
- [Development Scripts](#-development-scripts)
|
|
70
|
-
- [Build Commands](#build-commands)
|
|
71
|
-
- [Code Quality](#code-quality-commands)
|
|
72
|
-
- [Maintenance](#maintenance-commands)
|
|
73
45
|
- [Documentation](#-documentation)
|
|
74
46
|
- [Versioning](#-versioning)
|
|
75
47
|
- [Support](#-support)
|
|
@@ -80,14 +52,6 @@ Elements SDK
|
|
|
80
52
|
|
|
81
53
|
The LiquidCommerce Elements SDK is a **production-ready JavaScript library** that enables partners to seamlessly integrate product displays, shopping carts, and checkout flows into any website. Built with performance and developer experience in mind.
|
|
82
54
|
|
|
83
|
-
### 🆕 Latest Features
|
|
84
|
-
|
|
85
|
-
- **Builder Mode**: Dynamic theme customization for development environments
|
|
86
|
-
- **Action Feedback Events**: All actions now emit success/failure events for better UX
|
|
87
|
-
- **Proxy Support**: Route API requests through your server to avoid ad blockers
|
|
88
|
-
- **Enhanced CLI**: Improved development scripts with parallel builds and better error handling
|
|
89
|
-
- **TypeScript Support**: Full TypeScript definitions for better IDE experience
|
|
90
|
-
|
|
91
55
|
### ✨ Key Features
|
|
92
56
|
|
|
93
57
|
<table>
|
|
@@ -133,399 +97,610 @@ The LiquidCommerce Elements SDK is a **production-ready JavaScript library** tha
|
|
|
133
97
|
</tr>
|
|
134
98
|
</table>
|
|
135
99
|
|
|
136
|
-
##
|
|
137
|
-
|
|
138
|
-
### System Architecture
|
|
139
|
-
|
|
140
|
-
```mermaid
|
|
141
|
-
graph TB
|
|
142
|
-
subgraph "Your Website"
|
|
143
|
-
HTML[HTML Page]
|
|
144
|
-
JS[JavaScript]
|
|
145
|
-
INIT[Elements SDK]
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
subgraph "Elements SDK Core"
|
|
149
|
-
CLIENT[Elements Client]
|
|
150
|
-
|
|
151
|
-
subgraph "Components"
|
|
152
|
-
PROD[Product Component]
|
|
153
|
-
CART[Cart Component]
|
|
154
|
-
CHECK[Checkout Component]
|
|
155
|
-
ADDR[Address Component]
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
subgraph "Services"
|
|
159
|
-
ACT[Actions Service]
|
|
160
|
-
EVT[Events Service]
|
|
161
|
-
API[API Client]
|
|
162
|
-
THEME[Theme Provider]
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
subgraph "UI Layer"
|
|
166
|
-
BTN[Cart Button]
|
|
167
|
-
FLOAT[Floating Cart]
|
|
168
|
-
DISP[Live Displays]
|
|
169
|
-
end
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
subgraph "LiquidCommerce API"
|
|
173
|
-
PAPI[Products API]
|
|
174
|
-
CAPI[Cart API]
|
|
175
|
-
OAPI[Orders API]
|
|
176
|
-
AAPI[Address API]
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
HTML --> INIT
|
|
180
|
-
JS --> CLIENT
|
|
181
|
-
|
|
182
|
-
CLIENT --> PROD
|
|
183
|
-
CLIENT --> CART
|
|
184
|
-
CLIENT --> CHECK
|
|
185
|
-
CLIENT --> ADDR
|
|
186
|
-
|
|
187
|
-
PROD --> API
|
|
188
|
-
CART --> API
|
|
189
|
-
CHECK --> API
|
|
190
|
-
ADDR --> API
|
|
191
|
-
|
|
192
|
-
API --> PAPI
|
|
193
|
-
API --> CAPI
|
|
194
|
-
API --> OAPI
|
|
195
|
-
API --> AAPI
|
|
196
|
-
|
|
197
|
-
ACT --> EVT
|
|
198
|
-
CLIENT --> ACT
|
|
199
|
-
CLIENT --> THEME
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
### Component Architecture
|
|
203
|
-
|
|
204
|
-
```mermaid
|
|
205
|
-
graph LR
|
|
206
|
-
subgraph "Product Component"
|
|
207
|
-
PD[Product Display]
|
|
208
|
-
PS[Size Selector]
|
|
209
|
-
PQ[Quantity Control]
|
|
210
|
-
PA[Add to Cart]
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
subgraph "Cart Component"
|
|
214
|
-
CI[Cart Items]
|
|
215
|
-
CQ[Quantity Update]
|
|
216
|
-
CP[Promo Code]
|
|
217
|
-
CT[Cart Total]
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
subgraph "Checkout Component"
|
|
221
|
-
CS[Shipping Info]
|
|
222
|
-
CB[Billing Info]
|
|
223
|
-
PM[Payment Method]
|
|
224
|
-
OS[Order Summary]
|
|
225
|
-
end
|
|
226
|
-
|
|
227
|
-
PD --> PS
|
|
228
|
-
PS --> PQ
|
|
229
|
-
PQ --> PA
|
|
230
|
-
|
|
231
|
-
CI --> CQ
|
|
232
|
-
CQ --> CT
|
|
233
|
-
CP --> CT
|
|
234
|
-
|
|
235
|
-
CS --> CB
|
|
236
|
-
CB --> PM
|
|
237
|
-
PM --> OS
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
### Event Flow
|
|
241
|
-
|
|
242
|
-
```mermaid
|
|
243
|
-
sequenceDiagram
|
|
244
|
-
participant User
|
|
245
|
-
participant SDK
|
|
246
|
-
participant Actions
|
|
247
|
-
participant Events
|
|
248
|
-
participant API
|
|
249
|
-
participant Website
|
|
250
|
-
|
|
251
|
-
User->>SDK: Add to Cart
|
|
252
|
-
SDK->>Actions: cart.addProduct()
|
|
253
|
-
Actions->>API: POST /cart/items
|
|
254
|
-
API-->>Actions: Response
|
|
255
|
-
Actions->>Events: Emit Success/Failure
|
|
256
|
-
Events->>Website: lce:actions.cart_product_add_success
|
|
257
|
-
Website->>User: Show Feedback
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
## 🚀 Features
|
|
261
|
-
|
|
262
|
-
- **🎯 Auto-initialization**: Single script tag with data attributes
|
|
263
|
-
- **📦 Zero Dependencies**: Everything bundled, no peer dependencies
|
|
264
|
-
- **🌐 CDN Ready**: No build step required for basic usage
|
|
265
|
-
- **⚡ Lightweight**: ~150KB minified bundle size
|
|
266
|
-
- **🔧 Framework Agnostic**: Works with React, Vue, Angular, or vanilla JS
|
|
267
|
-
- **📱 Responsive**: Mobile-first design approach
|
|
268
|
-
- **♿ Accessible**: WCAG 2.1 AA compliant components
|
|
269
|
-
- **🎨 Themeable**: Comprehensive customization system
|
|
270
|
-
- **🔐 Secure**: PCI compliant checkout flow
|
|
271
|
-
- **📊 Analytics Ready**: Built-in event system for tracking
|
|
272
|
-
- **🌍 Multi-environment**: Support for dev, staging, and production
|
|
273
|
-
- **🧪 Well Tested**: Comprehensive test coverage
|
|
274
|
-
|
|
275
|
-
## 📦 Installation
|
|
276
|
-
|
|
277
|
-
### Choose how to include the SDK
|
|
278
|
-
|
|
279
|
-
- **Use our CDN** (no build step required)
|
|
280
|
-
- **Install from NPM** (for bundlers like Vite, Webpack, etc.)
|
|
281
|
-
|
|
282
|
-
### Option A — Use the CDN
|
|
283
|
-
|
|
284
|
-
Include the script on your page. Use the production or beta URL:
|
|
100
|
+
## 🚀 Quick Start
|
|
285
101
|
|
|
286
|
-
|
|
287
|
-
<!-- Production (latest) -->
|
|
288
|
-
<script src="https://assets-elements.liquidcommerce.us/all/elements.js"></script>
|
|
102
|
+
The fastest way to add e-commerce to your site is with **auto-initialization** - a single script tag that does everything.
|
|
289
103
|
|
|
290
|
-
|
|
291
|
-
<script src="https://assets-elements.liquidcommerce.us/all/beta/elements.js"></script>
|
|
292
|
-
```
|
|
104
|
+
### The Simplest Setup (30 seconds)
|
|
293
105
|
|
|
294
|
-
|
|
106
|
+
Add this single script tag to your page:
|
|
295
107
|
|
|
296
108
|
```html
|
|
297
|
-
<script
|
|
109
|
+
<script
|
|
110
|
+
data-liquid-commerce-elements
|
|
111
|
+
data-token="YOUR_API_KEY"
|
|
112
|
+
data-env="production"
|
|
113
|
+
src="https://assets-elements.liquidcommerce.us/all/elements.js"
|
|
114
|
+
></script>
|
|
298
115
|
```
|
|
299
116
|
|
|
300
|
-
|
|
117
|
+
That's it! You now have:
|
|
118
|
+
- ✅ A floating cart button (bottom right)
|
|
119
|
+
- ✅ Full cart functionality
|
|
120
|
+
- ✅ Complete checkout flow
|
|
121
|
+
- ✅ Ready to add products
|
|
301
122
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
123
|
+
### Adding Products to Your Page
|
|
124
|
+
|
|
125
|
+
Now let's display products. Choose the method that fits your use case:
|
|
126
|
+
|
|
127
|
+
#### Method 1: Direct Attributes (Best for static pages)
|
|
128
|
+
|
|
129
|
+
Add products directly in the script tag:
|
|
130
|
+
|
|
131
|
+
```html
|
|
132
|
+
<div id="product-1"></div>
|
|
133
|
+
<div id="product-2"></div>
|
|
134
|
+
|
|
135
|
+
<script
|
|
136
|
+
data-liquid-commerce-elements
|
|
137
|
+
data-token="YOUR_API_KEY"
|
|
138
|
+
data-env="production"
|
|
139
|
+
data-container-1="product-1"
|
|
140
|
+
data-product-1="00619947000020"
|
|
141
|
+
data-container-2="product-2"
|
|
142
|
+
data-product-2="00832889005513"
|
|
143
|
+
src="https://assets-elements.liquidcommerce.us/all/elements.js"
|
|
144
|
+
></script>
|
|
306
145
|
```
|
|
307
146
|
|
|
308
|
-
|
|
147
|
+
**Use case:** Static HTML pages with known products
|
|
309
148
|
|
|
310
|
-
|
|
311
|
-
import { Elements } from '@liquidcommerceteam/elements-sdk';
|
|
149
|
+
#### Method 2: JSON Configuration (Best for CMS/dynamic content)
|
|
312
150
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
151
|
+
Configure products via a JSON script block:
|
|
152
|
+
|
|
153
|
+
```html
|
|
154
|
+
<div id="product-1"></div>
|
|
155
|
+
<div id="product-2"></div>
|
|
156
|
+
|
|
157
|
+
<script data-liquid-commerce-elements-products type="application/json">
|
|
158
|
+
[
|
|
159
|
+
{ "containerId": "product-1", "identifier": "00619947000020" },
|
|
160
|
+
{ "containerId": "product-2", "identifier": "00832889005513" }
|
|
161
|
+
]
|
|
162
|
+
</script>
|
|
163
|
+
|
|
164
|
+
<script
|
|
165
|
+
data-liquid-commerce-elements
|
|
166
|
+
data-token="YOUR_API_KEY"
|
|
167
|
+
data-env="production"
|
|
168
|
+
src="https://assets-elements.liquidcommerce.us/all/elements.js"
|
|
169
|
+
></script>
|
|
316
170
|
```
|
|
317
171
|
|
|
318
|
-
|
|
172
|
+
**Use case:** CMS platforms, templating engines, server-side rendering
|
|
319
173
|
|
|
320
|
-
|
|
174
|
+
#### Method 3: Annotated Elements (Best for grids/lists)
|
|
321
175
|
|
|
322
|
-
|
|
176
|
+
Mark any div with a data attribute:
|
|
323
177
|
|
|
324
|
-
|
|
178
|
+
```html
|
|
179
|
+
<div class="product-grid">
|
|
180
|
+
<div data-lce-product="00619947000020"></div>
|
|
181
|
+
<div data-lce-product="00832889005513"></div>
|
|
182
|
+
<div data-lce-product="00851468007252"></div>
|
|
183
|
+
</div>
|
|
325
184
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
185
|
+
<script
|
|
186
|
+
data-liquid-commerce-elements
|
|
187
|
+
data-token="YOUR_API_KEY"
|
|
188
|
+
data-env="production"
|
|
189
|
+
src="https://assets-elements.liquidcommerce.us/all/elements.js"
|
|
190
|
+
></script>
|
|
191
|
+
```
|
|
333
192
|
|
|
334
|
-
|
|
193
|
+
**Use case:** Product grids, category pages, search results
|
|
335
194
|
|
|
336
|
-
|
|
195
|
+
### Customizing the Cart Button
|
|
337
196
|
|
|
338
|
-
|
|
197
|
+
By default, you get a floating cart button. Here's how to customize it:
|
|
339
198
|
|
|
340
|
-
|
|
341
|
-
- At the end of the `<body>` (recommended), or
|
|
342
|
-
- In the `<head>` with `defer` so it doesn't block rendering.
|
|
199
|
+
#### Option 1: Cart Button in a Specific Container
|
|
343
200
|
|
|
344
201
|
```html
|
|
345
|
-
|
|
202
|
+
<nav>
|
|
203
|
+
<div id="header-cart"></div>
|
|
204
|
+
</nav>
|
|
205
|
+
|
|
346
206
|
<script
|
|
347
207
|
data-liquid-commerce-elements
|
|
348
208
|
data-token="YOUR_API_KEY"
|
|
349
209
|
data-env="production"
|
|
350
|
-
data-cart-
|
|
351
|
-
data-show-cart-items
|
|
210
|
+
data-cart-badge-button="header-cart"
|
|
352
211
|
src="https://assets-elements.liquidcommerce.us/all/elements.js"
|
|
353
212
|
></script>
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
#### Option 2: No Cart Button (Manual Control)
|
|
354
216
|
|
|
355
|
-
|
|
217
|
+
```html
|
|
356
218
|
<script
|
|
357
|
-
defer
|
|
358
219
|
data-liquid-commerce-elements
|
|
359
220
|
data-token="YOUR_API_KEY"
|
|
360
221
|
data-env="production"
|
|
361
|
-
data-cart-
|
|
362
|
-
data-show-cart-items
|
|
222
|
+
data-cart-button-hidden
|
|
363
223
|
src="https://assets-elements.liquidcommerce.us/all/elements.js"
|
|
364
224
|
></script>
|
|
365
225
|
```
|
|
366
226
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
- `data-cart-id="container-id"` - ID for cart button container (optional, creates floating button if omitted)
|
|
371
|
-
- `data-show-cart-items` - Show items count badge on cart button (optional)
|
|
372
|
-
- `data-enable-debugging` - Enable debug logging in development (optional)
|
|
227
|
+
### Advanced Auto-Init Features
|
|
228
|
+
|
|
229
|
+
#### Add Product via URL (Marketing Links)
|
|
373
230
|
|
|
374
|
-
|
|
231
|
+
Enable "add to cart" via URL parameters for email campaigns and ads:
|
|
375
232
|
|
|
376
233
|
```html
|
|
377
|
-
<
|
|
378
|
-
|
|
379
|
-
|
|
234
|
+
<script
|
|
235
|
+
data-liquid-commerce-elements
|
|
236
|
+
data-token="YOUR_API_KEY"
|
|
237
|
+
data-env="production"
|
|
238
|
+
data-product-param="lce_product"
|
|
239
|
+
data-product-fulfillment-type-param="lce_fulfillment"
|
|
240
|
+
src="https://assets-elements.liquidcommerce.us/all/elements.js"
|
|
241
|
+
></script>
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
Now this URL auto-adds a product to cart:
|
|
245
|
+
```
|
|
246
|
+
https://yoursite.com/shop?lce_product=00619947000020&lce_fulfillment=shipping
|
|
380
247
|
```
|
|
381
248
|
|
|
382
|
-
|
|
249
|
+
**Use case:** Email campaigns, social media ads, QR codes
|
|
383
250
|
|
|
384
|
-
|
|
251
|
+
#### Apply Promo Code via URL (Campaign Tracking)
|
|
385
252
|
|
|
386
|
-
|
|
253
|
+
Auto-apply promo codes from URL parameters:
|
|
387
254
|
|
|
388
255
|
```html
|
|
389
256
|
<script
|
|
390
257
|
data-liquid-commerce-elements
|
|
391
258
|
data-token="YOUR_API_KEY"
|
|
392
259
|
data-env="production"
|
|
393
|
-
data-
|
|
394
|
-
data-product-1="00619947000020"
|
|
395
|
-
data-container-2="pdp-2"
|
|
396
|
-
data-product-2="00832889005513"
|
|
260
|
+
data-promo-code-param="lce_promo"
|
|
397
261
|
src="https://assets-elements.liquidcommerce.us/all/elements.js"
|
|
398
262
|
></script>
|
|
399
263
|
```
|
|
400
264
|
|
|
401
|
-
|
|
265
|
+
Now this URL auto-applies a promo code:
|
|
266
|
+
```
|
|
267
|
+
https://yoursite.com/shop?lce_promo=SUMMER20
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
**Use case:** Promotional campaigns, influencer codes, affiliate links
|
|
271
|
+
|
|
272
|
+
#### Promo Ticker (Rotating Promotions)
|
|
273
|
+
|
|
274
|
+
Display rotating promotional messages:
|
|
402
275
|
|
|
403
276
|
```html
|
|
404
|
-
<script
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
277
|
+
<script
|
|
278
|
+
data-liquid-commerce-elements
|
|
279
|
+
data-token="YOUR_API_KEY"
|
|
280
|
+
data-env="production"
|
|
281
|
+
data-promo-code="FREESHIP"
|
|
282
|
+
data-promo-text="Free Shipping Today Only!|Use code FREESHIP at checkout"
|
|
283
|
+
data-promo-separator="•"
|
|
284
|
+
data-promo-active-from="2025-01-01T00:00:00Z"
|
|
285
|
+
data-promo-active-until="2025-01-31T23:59:59Z"
|
|
286
|
+
src="https://assets-elements.liquidcommerce.us/all/elements.js"
|
|
287
|
+
></script>
|
|
410
288
|
```
|
|
411
289
|
|
|
412
|
-
|
|
290
|
+
**Use case:** Time-sensitive promotions, holiday sales, flash deals
|
|
291
|
+
|
|
292
|
+
#### Debug Mode (Development)
|
|
293
|
+
|
|
294
|
+
Enable debug logging during development:
|
|
413
295
|
|
|
414
296
|
```html
|
|
415
|
-
<
|
|
416
|
-
|
|
297
|
+
<script
|
|
298
|
+
data-liquid-commerce-elements
|
|
299
|
+
data-token="YOUR_API_KEY"
|
|
300
|
+
data-env="development"
|
|
301
|
+
data-debug-mode="console"
|
|
302
|
+
src="https://assets-elements.liquidcommerce.us/all/elements.js"
|
|
303
|
+
></script>
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
**Debug modes:**
|
|
307
|
+
- `console` - Logs to browser console
|
|
308
|
+
- `panel` - Shows visual debug panel + console logs
|
|
309
|
+
- Not set - No debugging (production default)
|
|
310
|
+
|
|
311
|
+
### Complete Auto-Init Reference
|
|
312
|
+
|
|
313
|
+
Here's every available data attribute:
|
|
314
|
+
|
|
315
|
+
```html
|
|
316
|
+
<script
|
|
317
|
+
data-liquid-commerce-elements
|
|
318
|
+
|
|
319
|
+
<!-- Required -->
|
|
320
|
+
data-token="YOUR_API_KEY"
|
|
321
|
+
|
|
322
|
+
<!-- Environment -->
|
|
323
|
+
data-env="production|staging|development|local"
|
|
324
|
+
|
|
325
|
+
<!-- Cart Button -->
|
|
326
|
+
data-cart-button="container-id"
|
|
327
|
+
data-cart-badge-button="container-id"
|
|
328
|
+
data-cart-button-hidden
|
|
329
|
+
|
|
330
|
+
<!-- Cart Button with Position Prefixes -->
|
|
331
|
+
data-cart-button="above:.logo"
|
|
332
|
+
data-cart-badge-button="below:#header"
|
|
333
|
+
data-cart-button="inside:.nav"
|
|
334
|
+
data-cart-badge-button="replace:.old-cart"
|
|
335
|
+
|
|
336
|
+
<!-- Products (Method 1: Direct) -->
|
|
337
|
+
data-container-1="div-id"
|
|
338
|
+
data-product-1="identifier"
|
|
339
|
+
data-container-2="div-id"
|
|
340
|
+
data-product-2="identifier"
|
|
341
|
+
|
|
342
|
+
<!-- URL Parameters -->
|
|
343
|
+
data-product-param="lce_product"
|
|
344
|
+
data-product-fulfillment-type-param="lce_fulfillment"
|
|
345
|
+
data-promo-code-param="lce_promo"
|
|
346
|
+
|
|
347
|
+
<!-- Promo Ticker -->
|
|
348
|
+
data-promo-code="CODE"
|
|
349
|
+
data-promo-text="Message 1|Message 2"
|
|
350
|
+
data-promo-separator="•"
|
|
351
|
+
data-promo-active-from="2025-01-01T00:00:00Z"
|
|
352
|
+
data-promo-active-until="2025-12-31T23:59:59Z"
|
|
353
|
+
|
|
354
|
+
<!-- Debugging (dev only) -->
|
|
355
|
+
data-debug-mode="console|panel"
|
|
356
|
+
|
|
357
|
+
src="https://assets-elements.liquidcommerce.us/all/elements.js"
|
|
358
|
+
></script>
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
**📖 For complete auto-init options:** See [`docs/CONFIGURATION.md`](docs/CONFIGURATION.md) for all data attributes and configuration details.
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## 🔧 Advanced Usage
|
|
366
|
+
|
|
367
|
+
Need more control? Initialize programmatically for full access to the SDK API.
|
|
368
|
+
|
|
369
|
+
### Installation
|
|
370
|
+
|
|
371
|
+
**CDN:**
|
|
372
|
+
```html
|
|
373
|
+
<script src="https://assets-elements.liquidcommerce.us/all/elements.js"></script>
|
|
374
|
+
|
|
375
|
+
<!-- Pin to specific version: -->
|
|
376
|
+
<script src="https://assets-elements.liquidcommerce.us/all/1.2.3/elements.js"></script>
|
|
417
377
|
```
|
|
418
378
|
|
|
419
|
-
|
|
379
|
+
**NPM:**
|
|
380
|
+
```bash
|
|
381
|
+
npm install @liquidcommerce/elements-sdk
|
|
382
|
+
# or
|
|
383
|
+
pnpm add @liquidcommerce/elements-sdk
|
|
384
|
+
```
|
|
420
385
|
|
|
421
|
-
|
|
386
|
+
### Programmatic Initialization
|
|
422
387
|
|
|
423
388
|
```html
|
|
424
389
|
<script src="https://assets-elements.liquidcommerce.us/all/elements.js"></script>
|
|
425
390
|
<script>
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
}
|
|
391
|
+
(async () => {
|
|
392
|
+
const client = await window.Elements('YOUR_API_KEY', {
|
|
393
|
+
env: 'production',
|
|
394
|
+
debugMode: 'none',
|
|
395
|
+
customTheme: { /* theming overrides */ },
|
|
396
|
+
proxy: { /* proxy config */ }
|
|
397
|
+
});
|
|
432
398
|
|
|
433
|
-
|
|
434
|
-
|
|
399
|
+
// Inject components
|
|
400
|
+
const components = await client.injectProductElement([
|
|
401
|
+
{ containerId: 'pdp-1', identifier: '00619947000020' }
|
|
402
|
+
]);
|
|
403
|
+
|
|
404
|
+
// Create cart button
|
|
405
|
+
client.ui.cartButton('cart-container', true);
|
|
406
|
+
|
|
407
|
+
// Use actions API
|
|
408
|
+
await client.actions.cart.addProduct([{
|
|
409
|
+
identifier: '00619947000020',
|
|
410
|
+
fulfillmentType: 'shipping',
|
|
411
|
+
quantity: 1
|
|
412
|
+
}]);
|
|
413
|
+
})();
|
|
435
414
|
</script>
|
|
436
415
|
```
|
|
437
416
|
|
|
438
|
-
|
|
417
|
+
**NPM Import:**
|
|
418
|
+
```js
|
|
419
|
+
import { Elements } from '@liquidcommerce/elements-sdk';
|
|
420
|
+
|
|
421
|
+
const client = await Elements('YOUR_API_KEY', { env: 'production' });
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
## 🌐 Browser Support
|
|
427
|
+
|
|
428
|
+
⚠️ **Important**: This SDK is designed for browser environments only. It will not work in server-side rendering, Node.js, or other non-browser environments.
|
|
429
|
+
|
|
430
|
+
### Supported Browsers (2018+)
|
|
431
|
+
|
|
432
|
+
| Browser | Minimum Version | Released |
|
|
433
|
+
|---------|----------------|----------|
|
|
434
|
+
| Chrome | 66+ | April 2018 |
|
|
435
|
+
| Firefox | 60+ | May 2018 |
|
|
436
|
+
| Safari | 12+ | September 2018 |
|
|
437
|
+
| Edge | 79+ (Chromium) | January 2020 |
|
|
438
|
+
| Samsung Internet | 7.2+ | June 2018 |
|
|
439
|
+
|
|
440
|
+
📖 See [`docs/BROWSER_SUPPORT.md`](docs/BROWSER_SUPPORT.md) for detailed compatibility.
|
|
441
|
+
|
|
442
|
+
## ⚙️ Configuration
|
|
439
443
|
|
|
440
|
-
###
|
|
444
|
+
### Basic Configuration
|
|
441
445
|
|
|
442
|
-
|
|
446
|
+
```js
|
|
447
|
+
const client = await Elements('YOUR_API_KEY', {
|
|
448
|
+
env: 'production', // Environment
|
|
449
|
+
debugMode: 'none', // Debug mode
|
|
450
|
+
customTheme: { }, // Theme overrides
|
|
451
|
+
proxy: { }, // Proxy configuration
|
|
452
|
+
promoTicker: [ ] // Promotional messages
|
|
453
|
+
});
|
|
454
|
+
```
|
|
443
455
|
|
|
444
|
-
|
|
456
|
+
### Environment Options
|
|
445
457
|
|
|
446
|
-
|
|
458
|
+
```js
|
|
459
|
+
env: 'production' // Live environment (default)
|
|
460
|
+
env: 'staging' // Pre-production testing
|
|
461
|
+
env: 'development' // Development with extra logging
|
|
462
|
+
env: 'local' // Local development
|
|
463
|
+
```
|
|
447
464
|
|
|
448
|
-
|
|
465
|
+
### Debug Modes
|
|
449
466
|
|
|
450
467
|
```js
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
468
|
+
debugMode: 'none' // No debugging (production default)
|
|
469
|
+
debugMode: 'console' // Console logs only
|
|
470
|
+
debugMode: 'panel' // Visual debug panel + console logs
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
**Note:** Debug mode is automatically disabled in production environment for security.
|
|
474
|
+
|
|
475
|
+
### Custom Theme
|
|
476
|
+
|
|
477
|
+
Override default styles and layouts:
|
|
478
|
+
|
|
479
|
+
```js
|
|
480
|
+
customTheme: {
|
|
481
|
+
global: {
|
|
482
|
+
theme: {
|
|
483
|
+
primaryColor: '#007bff',
|
|
484
|
+
accentColor: '#6c757d',
|
|
485
|
+
successColor: '#28a745',
|
|
486
|
+
errorColor: '#dc3545',
|
|
487
|
+
buttonCornerRadius: '8px',
|
|
488
|
+
cardCornerRadius: '12px',
|
|
489
|
+
headingFont: {
|
|
490
|
+
name: 'Inter',
|
|
491
|
+
weights: [600, 700]
|
|
492
|
+
},
|
|
493
|
+
paragraphFont: {
|
|
494
|
+
name: 'Inter',
|
|
495
|
+
weights: [400, 500]
|
|
496
|
+
}
|
|
497
|
+
},
|
|
498
|
+
layout: {
|
|
499
|
+
allowPromoCodes: true,
|
|
500
|
+
inputFieldStyle: 'outlined'
|
|
501
|
+
}
|
|
502
|
+
},
|
|
503
|
+
product: {
|
|
504
|
+
layout: {
|
|
505
|
+
showDescription: true,
|
|
506
|
+
addToCartButtonText: 'Add to Cart',
|
|
507
|
+
fulfillmentDisplay: 'carousel'
|
|
508
|
+
}
|
|
509
|
+
},
|
|
510
|
+
cart: {
|
|
511
|
+
layout: {
|
|
512
|
+
showQuantityCounter: true,
|
|
513
|
+
drawerHeaderText: 'Your Cart'
|
|
514
|
+
}
|
|
515
|
+
},
|
|
516
|
+
checkout: {
|
|
517
|
+
layout: {
|
|
518
|
+
allowGiftCards: true,
|
|
519
|
+
emailOptIn: { show: true, checked: false, text: 'Email me with news' },
|
|
520
|
+
smsOptIn: { show: true, checked: false, text: 'Text me with updates' }
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
455
524
|
```
|
|
456
525
|
|
|
457
|
-
|
|
526
|
+
**📖 For complete theming options:** See [`docs/THEMING.md`](docs/THEMING.md)
|
|
458
527
|
|
|
459
|
-
|
|
528
|
+
### Proxy Configuration
|
|
460
529
|
|
|
461
|
-
|
|
530
|
+
Route API requests through your server to avoid ad blockers:
|
|
462
531
|
|
|
463
532
|
```js
|
|
464
|
-
|
|
533
|
+
proxy: {
|
|
534
|
+
baseUrl: 'https://yourdomain.com/api/proxy',
|
|
535
|
+
headers: {
|
|
536
|
+
'X-Custom-Auth': 'your-token'
|
|
537
|
+
}
|
|
538
|
+
}
|
|
465
539
|
```
|
|
466
540
|
|
|
467
|
-
|
|
541
|
+
See [`docs/PROXY.md`](docs/PROXY.md) for implementation guide.
|
|
468
542
|
|
|
469
|
-
|
|
543
|
+
### Promo Ticker
|
|
470
544
|
|
|
471
|
-
|
|
545
|
+
Display rotating promotional messages:
|
|
472
546
|
|
|
473
547
|
```js
|
|
474
|
-
|
|
548
|
+
promoTicker: [
|
|
549
|
+
{
|
|
550
|
+
promoCode: 'FREESHIP',
|
|
551
|
+
text: ['Free Shipping Today!', 'Use code FREESHIP'],
|
|
552
|
+
separator: '•',
|
|
553
|
+
activeFrom: '2025-01-01T00:00:00Z',
|
|
554
|
+
activeUntil: '2025-12-31T23:59:59Z'
|
|
555
|
+
}
|
|
556
|
+
]
|
|
475
557
|
```
|
|
476
558
|
|
|
477
|
-
|
|
559
|
+
**📖 For all configuration options:** See [`docs/CONFIGURATION.md`](docs/CONFIGURATION.md) for complete reference with TypeScript types.
|
|
560
|
+
|
|
561
|
+
---
|
|
562
|
+
|
|
563
|
+
## 📖 SDK Methods & API
|
|
564
|
+
|
|
565
|
+
### Component Injection
|
|
566
|
+
|
|
567
|
+
Inject SDK components into your page containers. All injection methods return wrapper objects that provide component control.
|
|
568
|
+
|
|
569
|
+
#### Products
|
|
570
|
+
|
|
571
|
+
```js
|
|
572
|
+
const components = await client.injectProductElement([
|
|
573
|
+
{ containerId: 'pdp-1', identifier: '00619947000020' },
|
|
574
|
+
{ containerId: 'pdp-2', identifier: '00832889005513' }
|
|
575
|
+
]);
|
|
576
|
+
|
|
577
|
+
// Returns: IInjectedComponent[] - Array of component wrappers
|
|
578
|
+
// components[0].rerender() - Rerender the first component
|
|
579
|
+
// components[0].getElement() - Get the container element
|
|
580
|
+
// components[0].getType() - Get component type
|
|
581
|
+
```
|
|
478
582
|
|
|
479
|
-
|
|
583
|
+
**Identifier types:** UPC, product ID, or Salsify grouping ID
|
|
480
584
|
|
|
481
|
-
|
|
585
|
+
#### Cart
|
|
482
586
|
|
|
483
587
|
```js
|
|
484
|
-
await client.
|
|
588
|
+
const component = await client.injectCartElement('cart-container');
|
|
589
|
+
|
|
590
|
+
// Returns: IInjectedComponent | null - Component wrapper or null if failed
|
|
591
|
+
// component.rerender() - Rerender the component
|
|
592
|
+
// component.getElement() - Get the container element
|
|
593
|
+
// component.getType() - Get component type
|
|
485
594
|
```
|
|
486
595
|
|
|
487
|
-
|
|
596
|
+
**Use case:** Dedicated cart page
|
|
488
597
|
|
|
489
|
-
####
|
|
598
|
+
#### Checkout
|
|
599
|
+
|
|
600
|
+
```js
|
|
601
|
+
const component = await client.injectCheckoutElement('checkout-container');
|
|
602
|
+
|
|
603
|
+
// Returns: IInjectedComponent | null - Component wrapper or null if failed
|
|
604
|
+
// component.rerender() - Rerender the component
|
|
605
|
+
// component.getElement() - Get the container element
|
|
606
|
+
// component.getType() - Get component type
|
|
607
|
+
```
|
|
490
608
|
|
|
491
|
-
|
|
609
|
+
**Use case:** Dedicated checkout page
|
|
492
610
|
|
|
493
|
-
|
|
611
|
+
#### Address
|
|
494
612
|
|
|
495
613
|
```js
|
|
496
|
-
client.
|
|
614
|
+
const component = await client.injectAddressElement('address-container');
|
|
497
615
|
|
|
498
|
-
//
|
|
499
|
-
|
|
616
|
+
// Returns: IInjectedComponent | null - Component wrapper or null if failed
|
|
617
|
+
// component.rerender() - Rerender the component
|
|
618
|
+
// component.getElement() - Get the container element
|
|
619
|
+
// component.getType() - Get component type
|
|
500
620
|
```
|
|
501
621
|
|
|
502
|
-
|
|
622
|
+
**Use case:** Shipping address collection page
|
|
503
623
|
|
|
504
|
-
|
|
624
|
+
#### Access All Injected Components
|
|
505
625
|
|
|
506
626
|
```js
|
|
507
|
-
|
|
627
|
+
// Get all injected components
|
|
628
|
+
const injectedComponents = client.getInjectedComponents();
|
|
508
629
|
|
|
509
|
-
//
|
|
510
|
-
|
|
630
|
+
// Access specific components by container ID
|
|
631
|
+
const productComponent = injectedComponents.get('product-container-1');
|
|
632
|
+
const cartComponent = injectedComponents.get('cart-container');
|
|
633
|
+
|
|
634
|
+
// Iterate through all components
|
|
635
|
+
injectedComponents.forEach((component, containerId) => {
|
|
636
|
+
console.log(`Container: ${containerId}, Type: ${component.getType()}`);
|
|
637
|
+
|
|
638
|
+
// Rerender specific components
|
|
639
|
+
if (component.getType() === 'product') {
|
|
640
|
+
component.rerender();
|
|
641
|
+
}
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
// Get all components of a specific type
|
|
645
|
+
const productComponents = Array.from(injectedComponents.values())
|
|
646
|
+
.filter(component => component.getType() === 'product');
|
|
647
|
+
|
|
648
|
+
// Rerender all components of a type
|
|
649
|
+
productComponents.forEach(component => component.rerender());
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
**Returns:** `Map<string, IInjectedComponent>` - Map of container IDs to component wrappers
|
|
653
|
+
|
|
654
|
+
**Use cases:**
|
|
655
|
+
- Debugging and inspecting injected components
|
|
656
|
+
- Bulk operations on multiple components
|
|
657
|
+
- Component management and cleanup
|
|
658
|
+
|
|
659
|
+
### UI Helpers
|
|
660
|
+
|
|
661
|
+
Create standalone UI elements that integrate with the SDK.
|
|
662
|
+
|
|
663
|
+
#### Cart Button (in container)
|
|
664
|
+
|
|
665
|
+
```js
|
|
666
|
+
client.ui.cartButton('header-cart', true);
|
|
511
667
|
```
|
|
512
668
|
|
|
513
|
-
|
|
669
|
+
**Parameters:**
|
|
670
|
+
- `containerId` - Where to place the button
|
|
671
|
+
- `showItemsCount` - Show item count badge (optional)
|
|
514
672
|
|
|
515
|
-
|
|
673
|
+
**Use case:** Header navigation, sidebar
|
|
516
674
|
|
|
517
|
-
|
|
675
|
+
#### Floating Cart Button
|
|
518
676
|
|
|
519
677
|
```js
|
|
520
|
-
client.ui.
|
|
678
|
+
client.ui.floatingCartButton(true);
|
|
521
679
|
```
|
|
522
680
|
|
|
523
|
-
|
|
681
|
+
**Parameters:**
|
|
682
|
+
- `showItemsCount` - Show item count badge (optional)
|
|
524
683
|
|
|
525
|
-
|
|
684
|
+
**Use case:** Always-visible cart access (bottom-right corner)
|
|
685
|
+
|
|
686
|
+
#### Live Cart Data Display
|
|
687
|
+
|
|
688
|
+
Bind elements to auto-update with cart data:
|
|
526
689
|
|
|
527
690
|
```js
|
|
528
|
-
|
|
691
|
+
// Show live subtotal
|
|
692
|
+
client.ui.cartSubtotal('cart-total-display');
|
|
693
|
+
|
|
694
|
+
// Show live item count
|
|
695
|
+
client.ui.cartItemsCount('cart-badge');
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
**Example:**
|
|
699
|
+
```html
|
|
700
|
+
<nav>
|
|
701
|
+
<span>Cart: $<span id="cart-total-display">0.00</span></span>
|
|
702
|
+
<span>(<span id="cart-badge">0</span> items)</span>
|
|
703
|
+
</nav>
|
|
529
704
|
```
|
|
530
705
|
|
|
531
706
|
### Builder Methods (Development Mode)
|
|
@@ -546,10 +721,12 @@ client.builder.updateCheckoutComponent(checkoutTheme);
|
|
|
546
721
|
client.builder.updateAddressComponent(addressTheme);
|
|
547
722
|
|
|
548
723
|
// Builder injection methods (same as regular methods)
|
|
549
|
-
await client.builder.injectProductElement(params);
|
|
550
|
-
await client.builder.injectCartElement(containerId);
|
|
551
|
-
await client.builder.injectCheckoutElement(containerId);
|
|
552
|
-
await client.builder.injectAddressElement(containerId);
|
|
724
|
+
const components = await client.builder.injectProductElement(params);
|
|
725
|
+
const component = await client.builder.injectCartElement(containerId);
|
|
726
|
+
const checkoutComponent = await client.builder.injectCheckoutElement(containerId);
|
|
727
|
+
const addressComponent = await client.builder.injectAddressElement(containerId);
|
|
728
|
+
|
|
729
|
+
// All return IInjectedComponent wrapper objects with rerender(), getElement(), getType() methods
|
|
553
730
|
```
|
|
554
731
|
|
|
555
732
|
## 🎬 Actions
|
|
@@ -568,7 +745,8 @@ const actions = window.elements.actions;
|
|
|
568
745
|
```js
|
|
569
746
|
// Get product details
|
|
570
747
|
const product = actions.product.getDetails('product-123');
|
|
571
|
-
console.log(product.
|
|
748
|
+
console.log(product.name, product.brand, product.region, product.variety);
|
|
749
|
+
console.log(product.priceInfo, product.description, product.tastingNotes);
|
|
572
750
|
```
|
|
573
751
|
|
|
574
752
|
### Address Actions
|
|
@@ -613,6 +791,34 @@ const address = actions.address.getDetails();
|
|
|
613
791
|
actions.address.clear();
|
|
614
792
|
```
|
|
615
793
|
|
|
794
|
+
#### Clear Address - Complete Reset
|
|
795
|
+
|
|
796
|
+
The `actions.address.clear()` action performs a comprehensive reset of the user's address and shopping session:
|
|
797
|
+
|
|
798
|
+
**What it clears:**
|
|
799
|
+
- ✅ **Address Data**: Removes all saved address information (street, city, state, zip, coordinates)
|
|
800
|
+
- ✅ **Cart Contents**: Completely resets the cart (removes all items, totals, promo codes)
|
|
801
|
+
- ✅ **Local Storage**: Completely removes the localStorage entry and its value
|
|
802
|
+
- ✅ **Database**: Deletes the persisted store from the server database
|
|
803
|
+
- ✅ **Checkout State**: Resets any pending checkout information
|
|
804
|
+
|
|
805
|
+
**Why it resets the cart:**
|
|
806
|
+
When an address is cleared, the cart must be reset because:
|
|
807
|
+
- Cart items have location-specific pricing and availability
|
|
808
|
+
- Fulfillment options are tied to specific addresses
|
|
809
|
+
- Delivery fees and shipping costs depend on location
|
|
810
|
+
- Without a valid address, cart operations would fail or show incorrect data
|
|
811
|
+
|
|
812
|
+
**Events fired:**
|
|
813
|
+
- `lce:actions.address_cleared` - Address successfully cleared
|
|
814
|
+
- `lce:actions.cart_reset` - Cart successfully reset
|
|
815
|
+
|
|
816
|
+
**Use cases:**
|
|
817
|
+
- Guest checkout option (clear previous user's data)
|
|
818
|
+
- Location change (start fresh with new address)
|
|
819
|
+
- Privacy compliance (complete data removal)
|
|
820
|
+
- Testing/development (reset to clean state)
|
|
821
|
+
|
|
616
822
|
**Notes**:
|
|
617
823
|
- To find Google Places IDs for the `setAddressByPlacesId` action, use the [Google Places ID Finder](https://developers.google.com/maps/documentation/places/web-service/place-id#find-id)
|
|
618
824
|
- The `setAddressManually` action automatically generates a Google Places API-formatted address string from the provided components
|
|
@@ -669,7 +875,7 @@ await actions.cart.removePromoCode();
|
|
|
669
875
|
|
|
670
876
|
// Get cart details
|
|
671
877
|
const cart = actions.cart.getDetails();
|
|
672
|
-
console.log(cart.total, cart.
|
|
878
|
+
console.log(cart.itemCount, cart.amounts.total, cart.amounts.giftCardTotal);
|
|
673
879
|
|
|
674
880
|
// Reset cart
|
|
675
881
|
await actions.cart.resetCart();
|
|
@@ -741,12 +947,10 @@ window.addEventListener('lce:actions.checkout_gift_card_failed', function(event)
|
|
|
741
947
|
|
|
742
948
|
// Get checkout details (safe, non-sensitive data only)
|
|
743
949
|
const checkout = actions.checkout.getDetails();
|
|
744
|
-
console.log(
|
|
745
|
-
console.log(
|
|
746
|
-
console.log(
|
|
747
|
-
console.log(
|
|
748
|
-
console.log('Has promo code:', checkout.hasPromoCode);
|
|
749
|
-
console.log('Has gift cards:', checkout.hasGiftCards);
|
|
950
|
+
console.log(checkout.itemCount, checkout.amounts.total, checkout.isGift);
|
|
951
|
+
console.log(checkout.hasAgeVerify, checkout.hasPromoCode, checkout.hasGiftCards);
|
|
952
|
+
console.log(checkout.acceptedAccountCreation, checkout.billingSameAsShipping);
|
|
953
|
+
console.log(checkout.marketingPreferences);
|
|
750
954
|
|
|
751
955
|
// Configure checkout options
|
|
752
956
|
await actions.checkout.toggleBillingSameAsShipping(true);
|
|
@@ -762,13 +966,14 @@ The SDK emits real-time events for all user interactions. Listen to these events
|
|
|
762
966
|
```js
|
|
763
967
|
// Listen for specific events
|
|
764
968
|
window.addEventListener('lce:actions.product_add_to_cart', function(event) {
|
|
765
|
-
const
|
|
766
|
-
console.log('Added to cart:',
|
|
969
|
+
const data = event.detail.data;
|
|
970
|
+
console.log('Added to cart:', data.identifier);
|
|
767
971
|
|
|
768
972
|
// Your custom logic here
|
|
769
973
|
analytics.track('Product Added', {
|
|
770
|
-
|
|
771
|
-
|
|
974
|
+
identifier: data.identifier,
|
|
975
|
+
quantity: data.quantity,
|
|
976
|
+
upc: data.upc
|
|
772
977
|
});
|
|
773
978
|
});
|
|
774
979
|
|
|
@@ -785,7 +990,7 @@ window.elements.onAllActions((data, metadata) => {
|
|
|
785
990
|
### Available Events
|
|
786
991
|
|
|
787
992
|
#### Product Events
|
|
788
|
-
- `lce:actions.product_loaded` - Product component loaded
|
|
993
|
+
- `lce:actions.product_loaded` - Product component loaded with comprehensive product details (region, country, abv, proof, age, variety, vintage, descriptions, tasting notes)
|
|
789
994
|
- `lce:actions.product_add_to_cart` - Item added to cart
|
|
790
995
|
- `lce:actions.product_quantity_increase` - Quantity increased
|
|
791
996
|
- `lce:actions.product_quantity_decrease` - Quantity decreased
|
|
@@ -793,6 +998,7 @@ window.elements.onAllActions((data, metadata) => {
|
|
|
793
998
|
- `lce:actions.product_fulfillment_type_changed` - Delivery method changed
|
|
794
999
|
|
|
795
1000
|
#### Cart Events
|
|
1001
|
+
- `lce:actions.cart_loaded` - Cart data loaded with complete cart information (itemCount, all amounts including giftCardTotal, detailed item data)
|
|
796
1002
|
- `lce:actions.cart_opened` - Cart displayed
|
|
797
1003
|
- `lce:actions.cart_closed` - Cart hidden
|
|
798
1004
|
- `lce:actions.cart_updated` - Cart contents changed
|
|
@@ -801,6 +1007,7 @@ window.elements.onAllActions((data, metadata) => {
|
|
|
801
1007
|
- `lce:actions.cart_reset` - Cart cleared
|
|
802
1008
|
|
|
803
1009
|
#### Checkout Events
|
|
1010
|
+
- `lce:actions.checkout_loaded` - Checkout data loaded with comprehensive details (acceptedAccountCreation, hasSubstitutionPolicy, billingSameAsShipping, marketing preferences, detailed items)
|
|
804
1011
|
- `lce:actions.checkout_opened` - Checkout started
|
|
805
1012
|
- `lce:actions.checkout_closed` - Checkout abandoned
|
|
806
1013
|
- `lce:actions.checkout_submit_started` - Order submission began
|
|
@@ -813,361 +1020,1300 @@ window.elements.onAllActions((data, metadata) => {
|
|
|
813
1020
|
- `lce:actions.address_updated` - Address information changed
|
|
814
1021
|
- `lce:actions.address_cleared` - Address removed
|
|
815
1022
|
|
|
816
|
-
See [`docs/EVENTS.md`](docs/EVENTS.md) for complete event reference with implementation examples.
|
|
1023
|
+
See [`docs/EVENTS.md`](docs/EVENTS.md) for complete event reference with all available fields and implementation examples.
|
|
817
1024
|
|
|
818
|
-
##
|
|
1025
|
+
## 🎨 Themes & Customization
|
|
1026
|
+
|
|
1027
|
+
The SDK provides a theming system that lets you match components to your brand.
|
|
819
1028
|
|
|
820
|
-
|
|
1029
|
+
### Global Theming
|
|
821
1030
|
|
|
822
1031
|
```js
|
|
823
1032
|
const client = await Elements('YOUR_API_KEY', {
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
1033
|
+
customTheme: {
|
|
1034
|
+
global: {
|
|
1035
|
+
theme: {
|
|
1036
|
+
primaryColor: '#007bff',
|
|
1037
|
+
accentColor: '#6c757d',
|
|
1038
|
+
successColor: '#28a745',
|
|
1039
|
+
errorColor: '#dc3545',
|
|
1040
|
+
warningColor: '#ffc107',
|
|
1041
|
+
defaultTextColor: '#212529',
|
|
1042
|
+
selectedTextColor: '#ffffff',
|
|
1043
|
+
drawerBackgroundColor: '#ffffff',
|
|
1044
|
+
buttonCornerRadius: '8px',
|
|
1045
|
+
cardCornerRadius: '12px',
|
|
1046
|
+
headingFont: {
|
|
1047
|
+
name: 'Inter',
|
|
1048
|
+
weights: [600, 700]
|
|
1049
|
+
},
|
|
1050
|
+
paragraphFont: {
|
|
1051
|
+
name: 'Inter',
|
|
1052
|
+
weights: [400, 500]
|
|
1053
|
+
}
|
|
1054
|
+
},
|
|
1055
|
+
layout: {
|
|
1056
|
+
enablePersonalization: true,
|
|
1057
|
+
personalizationText: 'Customize your product',
|
|
1058
|
+
personalizationCardStyle: 'outlined',
|
|
1059
|
+
allowPromoCodes: true,
|
|
1060
|
+
inputFieldStyle: 'outlined',
|
|
1061
|
+
poweredByMode: 'light'
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
829
1065
|
});
|
|
830
1066
|
```
|
|
831
1067
|
|
|
832
|
-
###
|
|
1068
|
+
### Component-Specific Theming
|
|
833
1069
|
|
|
834
|
-
|
|
835
|
-
- **`staging`**: Pre-production testing environment
|
|
836
|
-
- **`development`**: Development environment with additional debugging
|
|
837
|
-
- **`local`**: Local development environment
|
|
1070
|
+
#### Product Component
|
|
838
1071
|
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
1072
|
+
```js
|
|
1073
|
+
customTheme: {
|
|
1074
|
+
product: {
|
|
1075
|
+
theme: {
|
|
1076
|
+
backgroundColor: '#ffffff'
|
|
1077
|
+
},
|
|
1078
|
+
layout: {
|
|
1079
|
+
showImages: true,
|
|
1080
|
+
showTitle: true,
|
|
1081
|
+
showDescription: true,
|
|
1082
|
+
showQuantityCounter: true,
|
|
1083
|
+
quantityCounterStyle: 'outlined',
|
|
1084
|
+
fulfillmentDisplay: 'carousel',
|
|
1085
|
+
enableShippingFulfillment: true,
|
|
1086
|
+
enableOnDemandFulfillment: true,
|
|
1087
|
+
addToCartButtonText: 'Add to Cart',
|
|
1088
|
+
buyNowButtonText: 'Buy Now'
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
```
|
|
842
1093
|
|
|
843
|
-
|
|
844
|
-
- `data-token`: Your API key (required)
|
|
845
|
-
- `data-env`: Environment (defaults to production)
|
|
846
|
-
- `data-cart-id`: Container ID for cart button
|
|
847
|
-
- `data-enable-debugging`: Enable debugging mode
|
|
848
|
-
- `data-container-X` / `data-product-X`: Product mapping pairs
|
|
1094
|
+
#### Cart Component
|
|
849
1095
|
|
|
850
|
-
|
|
1096
|
+
```js
|
|
1097
|
+
customTheme: {
|
|
1098
|
+
cart: {
|
|
1099
|
+
theme: {
|
|
1100
|
+
backgroundColor: '#ffffff'
|
|
1101
|
+
},
|
|
1102
|
+
layout: {
|
|
1103
|
+
showQuantityCounter: true,
|
|
1104
|
+
quantityCounterStyle: 'outlined',
|
|
1105
|
+
drawerHeaderText: 'Your Cart',
|
|
1106
|
+
goToCheckoutButtonText: 'Checkout'
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
```
|
|
851
1111
|
|
|
852
|
-
|
|
1112
|
+
#### Checkout Component
|
|
853
1113
|
|
|
854
1114
|
```js
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
},
|
|
863
|
-
typography: {
|
|
864
|
-
fontFamily: 'Roboto, sans-serif',
|
|
865
|
-
fontSize: '16px'
|
|
1115
|
+
customTheme: {
|
|
1116
|
+
checkout: {
|
|
1117
|
+
theme: {
|
|
1118
|
+
backgroundColor: '#ffffff',
|
|
1119
|
+
checkoutCompleted: {
|
|
1120
|
+
customLogo: 'https://yourdomain.com/logo.png',
|
|
1121
|
+
customText: 'Thank you for your order!'
|
|
866
1122
|
}
|
|
867
1123
|
},
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
1124
|
+
layout: {
|
|
1125
|
+
emailOptIn: {
|
|
1126
|
+
show: true,
|
|
1127
|
+
checked: false,
|
|
1128
|
+
text: 'Email me with news'
|
|
872
1129
|
},
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
compactMode: false
|
|
882
|
-
}
|
|
883
|
-
},
|
|
884
|
-
checkout: {
|
|
885
|
-
layout: {
|
|
886
|
-
singlePage: true,
|
|
887
|
-
showOrderSummary: true
|
|
888
|
-
}
|
|
1130
|
+
smsOptIn: {
|
|
1131
|
+
show: true,
|
|
1132
|
+
checked: false,
|
|
1133
|
+
text: 'Text me updates'
|
|
1134
|
+
},
|
|
1135
|
+
allowGiftCards: true,
|
|
1136
|
+
drawerHeaderText: 'Checkout',
|
|
1137
|
+
placeOrderButtonText: 'Place Order'
|
|
889
1138
|
}
|
|
890
1139
|
}
|
|
891
|
-
}
|
|
1140
|
+
}
|
|
892
1141
|
```
|
|
893
1142
|
|
|
894
|
-
|
|
1143
|
+
#### Address Component
|
|
895
1144
|
|
|
896
1145
|
```js
|
|
897
|
-
|
|
1146
|
+
customTheme: {
|
|
1147
|
+
address: {
|
|
1148
|
+
theme: {
|
|
1149
|
+
backgroundColor: '#ffffff'
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
```
|
|
1154
|
+
|
|
1155
|
+
### Dynamic Theme Updates (Builder Mode)
|
|
1156
|
+
|
|
1157
|
+
In development with `isBuilder: true`, update themes in real-time:
|
|
1158
|
+
|
|
1159
|
+
```js
|
|
1160
|
+
const client = await Elements('YOUR_API_KEY', {
|
|
1161
|
+
env: 'development',
|
|
1162
|
+
isBuilder: true
|
|
1163
|
+
});
|
|
1164
|
+
|
|
1165
|
+
// Update global theme
|
|
898
1166
|
await client.builder.updateComponentGlobalConfigs({
|
|
899
|
-
|
|
1167
|
+
theme: { primaryColor: '#ff6b6b' }
|
|
900
1168
|
});
|
|
901
1169
|
|
|
1170
|
+
// Update component-specific themes
|
|
902
1171
|
await client.builder.updateProductComponent({
|
|
903
|
-
layout: {
|
|
1172
|
+
layout: { addToCartButtonText: 'Add to Bag' }
|
|
1173
|
+
});
|
|
1174
|
+
|
|
1175
|
+
client.builder.updateCartComponent({
|
|
1176
|
+
layout: { drawerHeaderText: 'Shopping Bag' }
|
|
1177
|
+
});
|
|
1178
|
+
|
|
1179
|
+
client.builder.updateCheckoutComponent({
|
|
1180
|
+
layout: { placeOrderButtonText: 'Complete Purchase' }
|
|
1181
|
+
});
|
|
1182
|
+
|
|
1183
|
+
client.builder.updateAddressComponent({
|
|
1184
|
+
theme: { backgroundColor: '#f8f9fa' }
|
|
904
1185
|
});
|
|
905
1186
|
```
|
|
906
1187
|
|
|
907
|
-
|
|
1188
|
+
**📖 For complete theming documentation:** See [`docs/THEMING.md`](docs/THEMING.md)
|
|
908
1189
|
|
|
909
|
-
|
|
1190
|
+
---
|
|
1191
|
+
|
|
1192
|
+
## 🎁 Features Deep Dive
|
|
1193
|
+
|
|
1194
|
+
### Product Personalization (Engraving)
|
|
1195
|
+
|
|
1196
|
+
The SDK provides a comprehensive personalization/engraving feature for products that support it. The personalization experience varies based on context:
|
|
1197
|
+
|
|
1198
|
+
#### Product View
|
|
1199
|
+
When browsing products, customers can add personalization through an enhanced form that includes:
|
|
1200
|
+
- Product information with pricing
|
|
1201
|
+
- Fulfillment/retailer selection (with pricing comparison)
|
|
1202
|
+
- Multi-line engraving inputs with character limits
|
|
1203
|
+
- Real-time price updates as customers select different retailers
|
|
1204
|
+
- Add-to-cart with personalization in one step
|
|
1205
|
+
|
|
1206
|
+
```js
|
|
1207
|
+
// Personalization appears automatically for engravable products
|
|
1208
|
+
// Customers can add engraving text and select which retailer to fulfill from
|
|
1209
|
+
|
|
1210
|
+
// Listen for when personalization is added via add-to-cart
|
|
1211
|
+
window.addEventListener('lce:actions.product_add_to_cart', (event) => {
|
|
1212
|
+
const { hasEngraving, engravingLines } = event.detail.data;
|
|
1213
|
+
if (hasEngraving) {
|
|
1214
|
+
console.log('Customer personalized:', engravingLines);
|
|
1215
|
+
}
|
|
1216
|
+
});
|
|
1217
|
+
```
|
|
1218
|
+
|
|
1219
|
+
#### Cart View
|
|
1220
|
+
In the cart, personalized items display:
|
|
1221
|
+
- Personalization text lines
|
|
1222
|
+
- Engraving fee (per item and total for quantity)
|
|
1223
|
+
- **Edit** button to modify the personalization
|
|
1224
|
+
- **Remove** button to remove personalization
|
|
1225
|
+
|
|
1226
|
+
```js
|
|
1227
|
+
// Customers can edit or remove engraving from cart items
|
|
1228
|
+
window.addEventListener('lce:actions.cart_item_engraving_updated', (event) => {
|
|
1229
|
+
const { identifier, engravingLines } = event.detail.data;
|
|
1230
|
+
console.log('Cart item engraving updated:', engravingLines);
|
|
1231
|
+
});
|
|
1232
|
+
```
|
|
1233
|
+
|
|
1234
|
+
#### Checkout View
|
|
1235
|
+
During checkout, personalized items show:
|
|
1236
|
+
- Personalization text lines (read-only)
|
|
1237
|
+
- Engraving fee included in pricing
|
|
1238
|
+
- **Remove** button only (editing not allowed in checkout)
|
|
1239
|
+
|
|
1240
|
+
**Design Decision:** Editing personalization during checkout is intentionally disabled to prevent order processing complications. Customers must return to the cart to make changes.
|
|
1241
|
+
|
|
1242
|
+
#### Theming & Configuration
|
|
1243
|
+
|
|
1244
|
+
Control personalization display through global configuration:
|
|
1245
|
+
|
|
1246
|
+
```js
|
|
1247
|
+
customTheme: {
|
|
1248
|
+
global: {
|
|
1249
|
+
layout: {
|
|
1250
|
+
enablePersonalization: true,
|
|
1251
|
+
personalizationText: 'Personalize your product',
|
|
1252
|
+
personalizationCardStyle: 'outlined' // or 'filled'
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
```
|
|
1257
|
+
|
|
1258
|
+
#### Key Features
|
|
1259
|
+
- **Smart pricing:** Automatically includes engraving fees in product price
|
|
1260
|
+
- **Retailer selection:** Compare prices from different retailers during personalization
|
|
1261
|
+
- **Character limits:** Enforces maximum characters per line
|
|
1262
|
+
- **Uppercase conversion:** Engraving text is automatically converted to uppercase
|
|
1263
|
+
- **Multi-line support:** Products can support 1 or more engraving lines
|
|
1264
|
+
- **Fee transparency:** Shows per-item and total fees (e.g., "$5.00 ($2.50 ea)")
|
|
1265
|
+
|
|
1266
|
+
**Note:** Personalization is automatically enabled for products that support it. The SDK handles all UI, validation, and state management.
|
|
1267
|
+
|
|
1268
|
+
### Gift Options
|
|
1269
|
+
|
|
1270
|
+
Allow orders to be marked as gifts with custom messages:
|
|
1271
|
+
|
|
1272
|
+
```js
|
|
1273
|
+
// Enable via theme
|
|
1274
|
+
customTheme: {
|
|
1275
|
+
checkout: {
|
|
1276
|
+
layout: {
|
|
1277
|
+
allowGiftOptions: true
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
// Toggle gift mode programmatically
|
|
1283
|
+
await client.actions.checkout.toggleIsGift(true);
|
|
1284
|
+
|
|
1285
|
+
// Set gift message
|
|
1286
|
+
await client.actions.checkout.updateGiftInfo({
|
|
1287
|
+
recipientName: 'John Doe',
|
|
1288
|
+
message: 'Happy Birthday!'
|
|
1289
|
+
});
|
|
1290
|
+
|
|
1291
|
+
// Listen for gift toggles
|
|
1292
|
+
window.addEventListener('lce:actions.checkout_is_gift_toggled', (event) => {
|
|
1293
|
+
const { isGift } = event.detail.data;
|
|
1294
|
+
console.log('Order is gift:', isGift);
|
|
1295
|
+
});
|
|
1296
|
+
```
|
|
1297
|
+
|
|
1298
|
+
### Tips (On-Demand Delivery)
|
|
1299
|
+
|
|
1300
|
+
Allow customers to tip delivery drivers:
|
|
1301
|
+
|
|
1302
|
+
```js
|
|
1303
|
+
// Tips are automatically enabled for onDemand fulfillment types
|
|
1304
|
+
|
|
1305
|
+
// Listen for tip updates
|
|
1306
|
+
window.addEventListener('lce:actions.checkout_tip_updated', (event) => {
|
|
1307
|
+
const { tipAmount, total } = event.detail.data;
|
|
1308
|
+
console.log(`Customer tipped $${tipAmount}`);
|
|
1309
|
+
});
|
|
1310
|
+
```
|
|
1311
|
+
|
|
1312
|
+
Tips are calculated as a percentage or fixed amount and added to the order total.
|
|
1313
|
+
|
|
1314
|
+
### Gift Cards
|
|
1315
|
+
|
|
1316
|
+
Accept gift card payments at checkout:
|
|
1317
|
+
|
|
1318
|
+
```js
|
|
1319
|
+
// Enable via theme
|
|
1320
|
+
customTheme: {
|
|
1321
|
+
checkout: {
|
|
1322
|
+
layout: {
|
|
1323
|
+
allowGiftCards: true
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
// Apply gift card programmatically
|
|
1329
|
+
await client.actions.checkout.applyGiftCard('GIFT-1234-5678-9012');
|
|
1330
|
+
|
|
1331
|
+
// Remove gift card
|
|
1332
|
+
await client.actions.checkout.removeGiftCard('GIFT-1234-5678-9012');
|
|
1333
|
+
|
|
1334
|
+
// Listen for gift card events
|
|
1335
|
+
window.addEventListener('lce:actions.checkout_gift_card_applied', (event) => {
|
|
1336
|
+
const { code, appliedAmount, remainingBalance } = event.detail.data;
|
|
1337
|
+
console.log(`Applied $${appliedAmount}, Remaining: $${remainingBalance}`);
|
|
1338
|
+
});
|
|
1339
|
+
|
|
1340
|
+
window.addEventListener('lce:actions.checkout_gift_card_failed', (event) => {
|
|
1341
|
+
const { code, error } = event.detail.data;
|
|
1342
|
+
console.log('Gift card failed:', error);
|
|
1343
|
+
});
|
|
1344
|
+
```
|
|
1345
|
+
|
|
1346
|
+
### Promo Codes
|
|
1347
|
+
|
|
1348
|
+
Apply promotional discount codes:
|
|
1349
|
+
|
|
1350
|
+
```js
|
|
1351
|
+
// Apply to cart
|
|
1352
|
+
await client.actions.cart.applyPromoCode('SUMMER20');
|
|
1353
|
+
|
|
1354
|
+
// Apply to checkout
|
|
1355
|
+
await client.actions.checkout.applyPromoCode('SAVE10');
|
|
1356
|
+
|
|
1357
|
+
// Remove promo code
|
|
1358
|
+
await client.actions.cart.removePromoCode();
|
|
1359
|
+
|
|
1360
|
+
// Listen for promo events
|
|
1361
|
+
window.addEventListener('lce:actions.cart_promo_code_applied', (event) => {
|
|
1362
|
+
const { code, discountAmount, newTotal } = event.detail.data;
|
|
1363
|
+
console.log(`${code} saved $${discountAmount}! New total: $${newTotal}`);
|
|
1364
|
+
});
|
|
1365
|
+
|
|
1366
|
+
window.addEventListener('lce:actions.cart_promo_code_failed', (event) => {
|
|
1367
|
+
const { code, error } = event.detail.data;
|
|
1368
|
+
console.log('Promo failed:', error.message);
|
|
1369
|
+
});
|
|
1370
|
+
```
|
|
1371
|
+
|
|
1372
|
+
### Promo Ticker
|
|
1373
|
+
|
|
1374
|
+
Display rotating promotional messages at the top of your site:
|
|
910
1375
|
|
|
911
1376
|
```js
|
|
1377
|
+
// Via initialization config
|
|
912
1378
|
const client = await Elements('YOUR_API_KEY', {
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
1379
|
+
promoTicker: [
|
|
1380
|
+
{
|
|
1381
|
+
promoCode: 'FREESHIP',
|
|
1382
|
+
text: ['Free Shipping Today!', 'Use code FREESHIP'],
|
|
1383
|
+
separator: '•',
|
|
1384
|
+
activeFrom: '2025-01-01T00:00:00Z',
|
|
1385
|
+
activeUntil: '2025-12-31T23:59:59Z'
|
|
1386
|
+
},
|
|
1387
|
+
{
|
|
1388
|
+
promoCode: 'SAVE20',
|
|
1389
|
+
text: ['20% Off Sitewide', 'Limited Time Only'],
|
|
1390
|
+
separator: '|',
|
|
1391
|
+
activeFrom: '2025-06-01T00:00:00Z',
|
|
1392
|
+
activeUntil: '2025-06-30T23:59:59Z'
|
|
1393
|
+
}
|
|
1394
|
+
]
|
|
1395
|
+
});
|
|
1396
|
+
|
|
1397
|
+
// Via auto-init
|
|
1398
|
+
<script
|
|
1399
|
+
data-liquid-commerce-elements
|
|
1400
|
+
data-token="YOUR_API_KEY"
|
|
1401
|
+
data-promo-code="FREESHIP"
|
|
1402
|
+
data-promo-text="Free Shipping Today!|Use code FREESHIP"
|
|
1403
|
+
data-promo-separator="•"
|
|
1404
|
+
data-promo-active-from="2025-01-01T00:00:00Z"
|
|
1405
|
+
data-promo-active-until="2025-12-31T23:59:59Z"
|
|
1406
|
+
src="https://assets-elements.liquidcommerce.us/all/elements.js"
|
|
1407
|
+
></script>
|
|
1408
|
+
```
|
|
1409
|
+
|
|
1410
|
+
The ticker automatically rotates messages and only shows active promotions.
|
|
1411
|
+
|
|
1412
|
+
### Marketing Preferences
|
|
1413
|
+
|
|
1414
|
+
Allow customers to opt-in to email and SMS marketing:
|
|
1415
|
+
|
|
1416
|
+
```js
|
|
1417
|
+
// Set defaults via theme
|
|
1418
|
+
customTheme: {
|
|
1419
|
+
checkout: {
|
|
1420
|
+
layout: {
|
|
1421
|
+
emailOptIn: { checked: false, visible: true },
|
|
1422
|
+
smsOptIn: { checked: false, visible: true }
|
|
918
1423
|
}
|
|
919
1424
|
}
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
// Update preferences programmatically
|
|
1428
|
+
await client.actions.checkout.toggleMarketingPreferences('canEmail', true);
|
|
1429
|
+
await client.actions.checkout.toggleMarketingPreferences('canSms', true);
|
|
1430
|
+
|
|
1431
|
+
// Listen for preference changes
|
|
1432
|
+
window.addEventListener('lce:actions.checkout_marketing_preferences_toggled', (event) => {
|
|
1433
|
+
const { field, value } = event.detail.data;
|
|
1434
|
+
console.log(`Customer ${value ? 'opted-in' : 'opted-out'} of ${field}`);
|
|
920
1435
|
});
|
|
921
1436
|
```
|
|
922
1437
|
|
|
923
|
-
|
|
1438
|
+
### Purchase Minimum Alerts
|
|
924
1439
|
|
|
925
|
-
|
|
1440
|
+
Automatically displays alerts when a retailer has minimum purchase requirements. No configuration needed - the SDK handles this automatically based on retailer rules.
|
|
926
1441
|
|
|
927
|
-
|
|
1442
|
+
### Age Verification
|
|
928
1443
|
|
|
929
|
-
-
|
|
930
|
-
- [`docs/EVENTS.md`](docs/EVENTS.md) - Events guide with implementation examples
|
|
931
|
-
- [`docs/BROWSER_SUPPORT.md`](docs/BROWSER_SUPPORT.md) - Detailed browser compatibility
|
|
932
|
-
- [`docs/PROXY.md`](docs/PROXY.md) - Proxy configuration for ad blocker avoidance
|
|
1444
|
+
For age-restricted products (alcohol, tobacco, etc.), the SDK automatically displays age verification prompts during checkout. This is handled based on product metadata and cannot be disabled for restricted items.
|
|
933
1445
|
|
|
934
|
-
|
|
1446
|
+
### Pre-Sale Countdown
|
|
1447
|
+
|
|
1448
|
+
For pre-sale or upcoming products, the SDK automatically displays a countdown timer until the product becomes available. Customers can add pre-sale items to cart, and the SDK handles the special fulfillment flow.
|
|
1449
|
+
|
|
1450
|
+
```js
|
|
1451
|
+
// Listen for when product is added to cart
|
|
1452
|
+
window.addEventListener('lce:actions.product_add_to_cart', (event) => {
|
|
1453
|
+
const { productId } = event.detail.data;
|
|
1454
|
+
console.log(`Product ${productId} added to cart`);
|
|
1455
|
+
});
|
|
1456
|
+
```
|
|
1457
|
+
|
|
1458
|
+
---
|
|
1459
|
+
|
|
1460
|
+
## 🔧 Core Capabilities
|
|
1461
|
+
|
|
1462
|
+
The SDK includes several built-in services that work behind the scenes to provide a robust, production-ready experience.
|
|
1463
|
+
|
|
1464
|
+
### State Management
|
|
1465
|
+
|
|
1466
|
+
The SDK uses a centralized store for all state management. Access state data via actions:
|
|
1467
|
+
|
|
1468
|
+
```js
|
|
1469
|
+
// Get current cart state
|
|
1470
|
+
const cart = await client.actions.cart.getDetails();
|
|
1471
|
+
console.log(cart.itemCount, cart.amounts.total, cart.amounts.giftCardTotal);
|
|
1472
|
+
|
|
1473
|
+
// Get current checkout state
|
|
1474
|
+
const checkout = await client.actions.checkout.getDetails();
|
|
1475
|
+
console.log(checkout.amounts.total, checkout.isGift, checkout.acceptedAccountCreation);
|
|
1476
|
+
console.log(checkout.billingSameAsShipping, checkout.marketingPreferences);
|
|
1477
|
+
|
|
1478
|
+
// Get current address
|
|
1479
|
+
const address = await client.actions.address.getDetails();
|
|
1480
|
+
console.log(address.formattedAddress, address.coordinates);
|
|
1481
|
+
|
|
1482
|
+
// Get product details
|
|
1483
|
+
const product = await client.actions.product.getDetails('00619947000020');
|
|
1484
|
+
console.log(product.name, product.region, product.variety, product.vintage);
|
|
1485
|
+
console.log(product.description, product.tastingNotes);
|
|
1486
|
+
```
|
|
1487
|
+
|
|
1488
|
+
**State is persistent:** Cart and address data persist across page reloads using localStorage.
|
|
1489
|
+
|
|
1490
|
+
### Event System (PubSub)
|
|
1491
|
+
|
|
1492
|
+
All SDK interactions emit events through a centralized event system:
|
|
1493
|
+
|
|
1494
|
+
```js
|
|
1495
|
+
// Subscribe to specific event
|
|
1496
|
+
window.addEventListener('lce:actions.cart_updated', (event) => {
|
|
1497
|
+
const { previous, current } = event.detail.data;
|
|
1498
|
+
console.log('Cart changed from', previous.amounts.total, 'to', current.amounts.total);
|
|
1499
|
+
});
|
|
1500
|
+
|
|
1501
|
+
// Subscribe to all action events
|
|
1502
|
+
if (window.elements) {
|
|
1503
|
+
window.elements.onAllActions((data, metadata) => {
|
|
1504
|
+
console.log('Action:', metadata.eventName, data);
|
|
1505
|
+
});
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
// Subscribe to all form events
|
|
1509
|
+
if (window.elements) {
|
|
1510
|
+
window.elements.onAllForms((data, metadata) => {
|
|
1511
|
+
console.log('Form:', metadata.eventName, data);
|
|
1512
|
+
});
|
|
1513
|
+
}
|
|
1514
|
+
```
|
|
1515
|
+
|
|
1516
|
+
**Event format:**
|
|
1517
|
+
```js
|
|
1518
|
+
{
|
|
1519
|
+
detail: {
|
|
1520
|
+
data: { /* event-specific payload */ },
|
|
1521
|
+
metadata: {
|
|
1522
|
+
eventName: 'lce:actions.cart_updated',
|
|
1523
|
+
timestamp: 1699564800000,
|
|
1524
|
+
source: 'sdk'
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
```
|
|
1529
|
+
|
|
1530
|
+
### Telemetry & Analytics
|
|
1531
|
+
|
|
1532
|
+
The SDK automatically tracks user interactions and performance metrics:
|
|
1533
|
+
|
|
1534
|
+
- **User interactions:** Add to cart, checkout started, checkout completed
|
|
1535
|
+
- **Performance metrics:** Component load times, API response times
|
|
1536
|
+
- **Error tracking:** Failed API calls, validation errors
|
|
1537
|
+
|
|
1538
|
+
**Note:** The SDK includes automatic Google Tag Manager (GTM) integration that tracks e-commerce events. GTM configuration is managed through your LiquidCommerce dashboard, not the client initialization.
|
|
1539
|
+
|
|
1540
|
+
**Custom Analytics:**
|
|
1541
|
+
|
|
1542
|
+
```js
|
|
1543
|
+
// Listen to events for custom analytics tracking
|
|
1544
|
+
window.addEventListener('lce:actions.product_add_to_cart', (event) => {
|
|
1545
|
+
const { productId, price, quantity } = event.detail.data;
|
|
1546
|
+
|
|
1547
|
+
// Track with your analytics provider
|
|
1548
|
+
gtag('event', 'add_to_cart', {
|
|
1549
|
+
currency: 'USD',
|
|
1550
|
+
value: price * quantity,
|
|
1551
|
+
items: [{ item_id: productId, quantity }]
|
|
1552
|
+
});
|
|
1553
|
+
|
|
1554
|
+
// Or Segment
|
|
1555
|
+
analytics.track('Product Added', {
|
|
1556
|
+
product_id: productId,
|
|
1557
|
+
price,
|
|
1558
|
+
quantity
|
|
1559
|
+
});
|
|
1560
|
+
});
|
|
1561
|
+
```
|
|
1562
|
+
|
|
1563
|
+
### Circuit Breaker
|
|
1564
|
+
|
|
1565
|
+
The SDK includes a circuit breaker pattern to prevent cascading failures:
|
|
1566
|
+
|
|
1567
|
+
```js
|
|
1568
|
+
// Automatically handles API failures
|
|
1569
|
+
// - After 5 consecutive failures, circuit opens
|
|
1570
|
+
// - Requests fail fast without hitting the API
|
|
1571
|
+
// - After 30 seconds, circuit half-opens
|
|
1572
|
+
// - Next successful request closes the circuit
|
|
1573
|
+
```
|
|
1574
|
+
|
|
1575
|
+
**Circuit states:**
|
|
1576
|
+
- **Closed:** Normal operation, all requests go through
|
|
1577
|
+
- **Open:** API is failing, requests fail fast
|
|
1578
|
+
- **Half-Open:** Testing if API recovered, limited requests allowed
|
|
1579
|
+
|
|
1580
|
+
This protects your site from slowdowns when the API is experiencing issues.
|
|
1581
|
+
|
|
1582
|
+
### Fingerprinting
|
|
1583
|
+
|
|
1584
|
+
The SDK generates a unique device fingerprint for fraud prevention and analytics:
|
|
1585
|
+
|
|
1586
|
+
```js
|
|
1587
|
+
// Automatically tracked:
|
|
1588
|
+
// - Browser fingerprint
|
|
1589
|
+
// - Device characteristics
|
|
1590
|
+
// - Session information
|
|
1591
|
+
|
|
1592
|
+
// Used for:
|
|
1593
|
+
// - Fraud detection
|
|
1594
|
+
// - Cart persistence across devices
|
|
1595
|
+
// - Personalization
|
|
1596
|
+
```
|
|
1597
|
+
|
|
1598
|
+
Fingerprinting is handled automatically and requires no configuration.
|
|
1599
|
+
|
|
1600
|
+
### Authentication
|
|
1601
|
+
|
|
1602
|
+
The SDK handles authentication automatically using your API key:
|
|
1603
|
+
|
|
1604
|
+
```js
|
|
1605
|
+
const client = await Elements('YOUR_API_KEY', {
|
|
1606
|
+
env: 'production'
|
|
1607
|
+
});
|
|
935
1608
|
|
|
936
|
-
|
|
1609
|
+
// All API requests include:
|
|
1610
|
+
// - API key authentication
|
|
1611
|
+
// - CORS headers
|
|
1612
|
+
// - Request signing (when required)
|
|
1613
|
+
```
|
|
937
1614
|
|
|
938
|
-
|
|
939
|
-
- Branch: `beta`
|
|
940
|
-
- Base URL: `https://assets-elements.liquidcommerce.us/all/beta/`
|
|
941
|
-
- Purpose: Testing and pre-release features
|
|
1615
|
+
**Token refresh:** The SDK automatically handles token expiration and refresh.
|
|
942
1616
|
|
|
943
|
-
###
|
|
944
|
-
|
|
945
|
-
-
|
|
946
|
-
|
|
1617
|
+
### Logger
|
|
1618
|
+
|
|
1619
|
+
Built-in logging system with configurable levels:
|
|
1620
|
+
|
|
1621
|
+
```js
|
|
1622
|
+
const client = await Elements('YOUR_API_KEY', {
|
|
1623
|
+
debugMode: 'console' // 'none' | 'console' | 'panel'
|
|
1624
|
+
});
|
|
947
1625
|
|
|
948
|
-
|
|
1626
|
+
// Debug mode options:
|
|
1627
|
+
// - 'none': No logging (production default)
|
|
1628
|
+
// - 'console': Logs to browser console
|
|
1629
|
+
// - 'panel': Shows visual debug panel + console logs
|
|
1630
|
+
```
|
|
949
1631
|
|
|
1632
|
+
**Console debug output:**
|
|
950
1633
|
```
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
│ ├── 1.2.4/elements.js
|
|
956
|
-
│ └── elements.js (beta latest)
|
|
957
|
-
├── 1.2.2/elements.js (production)
|
|
958
|
-
├── 1.2.3/elements.js (production)
|
|
959
|
-
└── elements.js (production latest)
|
|
1634
|
+
[LCE SDK] Product loaded: product-123
|
|
1635
|
+
[LCE SDK] Cart updated: 3 items, $45.99
|
|
1636
|
+
[LCE SDK] Checkout started
|
|
1637
|
+
[LCE SDK] API call: POST /cart/add (152ms)
|
|
960
1638
|
```
|
|
961
1639
|
|
|
962
|
-
|
|
1640
|
+
**Debug panel:**
|
|
1641
|
+
- Real-time event stream
|
|
1642
|
+
- API call inspector
|
|
1643
|
+
- State viewer
|
|
1644
|
+
- Performance metrics
|
|
1645
|
+
|
|
1646
|
+
### Command Pattern
|
|
963
1647
|
|
|
964
|
-
The SDK
|
|
1648
|
+
The SDK uses a command pattern for all operations:
|
|
1649
|
+
|
|
1650
|
+
```js
|
|
1651
|
+
// Commands are:
|
|
1652
|
+
// - Queued for execution
|
|
1653
|
+
// - Retried on failure
|
|
1654
|
+
// - Logged for debugging
|
|
1655
|
+
// - Cancelable
|
|
1656
|
+
|
|
1657
|
+
// Example: Adding to cart
|
|
1658
|
+
// 1. Command created: AddToCartCommand
|
|
1659
|
+
// 2. Command queued
|
|
1660
|
+
// 3. Command executed
|
|
1661
|
+
// 4. Success event emitted
|
|
1662
|
+
// 5. UI updated
|
|
1663
|
+
|
|
1664
|
+
// This ensures:
|
|
1665
|
+
// - Consistent error handling
|
|
1666
|
+
// - Automatic retries
|
|
1667
|
+
// - Full audit trail
|
|
1668
|
+
```
|
|
1669
|
+
|
|
1670
|
+
### Component Factory
|
|
1671
|
+
|
|
1672
|
+
Components are created on-demand using a factory pattern:
|
|
1673
|
+
|
|
1674
|
+
```js
|
|
1675
|
+
// When you call:
|
|
1676
|
+
const components = await client.injectProductElement([
|
|
1677
|
+
{ containerId: 'pdp-1', identifier: 'product-123' }
|
|
1678
|
+
]);
|
|
1679
|
+
// Returns: IInjectedComponent[] - Array of component wrappers
|
|
1680
|
+
|
|
1681
|
+
// The SDK:
|
|
1682
|
+
// 1. Creates a ProductComponent instance
|
|
1683
|
+
// 2. Registers it with the factory
|
|
1684
|
+
// 3. Injects it into the DOM
|
|
1685
|
+
// 4. Attaches event listeners
|
|
1686
|
+
// 5. Loads product data
|
|
1687
|
+
// 6. Renders the component
|
|
1688
|
+
|
|
1689
|
+
// Components are:
|
|
1690
|
+
// - Lazily loaded
|
|
1691
|
+
// - Automatically cleaned up
|
|
1692
|
+
// - Reusable across pages
|
|
1693
|
+
```
|
|
1694
|
+
|
|
1695
|
+
### Singleton Manager
|
|
1696
|
+
|
|
1697
|
+
Core services are managed as singletons:
|
|
1698
|
+
|
|
1699
|
+
```js
|
|
1700
|
+
// These services are initialized once and reused:
|
|
1701
|
+
// - ApiClient
|
|
1702
|
+
// - Store
|
|
1703
|
+
// - PubSub
|
|
1704
|
+
// - Logger
|
|
1705
|
+
// - Telemetry
|
|
1706
|
+
// - CircuitBreaker
|
|
1707
|
+
// - Fingerprint
|
|
1708
|
+
// - Auth
|
|
1709
|
+
|
|
1710
|
+
// This ensures:
|
|
1711
|
+
// - Consistent state
|
|
1712
|
+
// - Efficient memory usage
|
|
1713
|
+
// - No duplicate API calls
|
|
1714
|
+
```
|
|
1715
|
+
|
|
1716
|
+
---
|
|
965
1717
|
|
|
966
|
-
|
|
1718
|
+
## 🏗️ Integration Patterns
|
|
967
1719
|
|
|
968
|
-
|
|
1720
|
+
### React Integration
|
|
1721
|
+
|
|
1722
|
+
```jsx
|
|
1723
|
+
import { useEffect, useState } from 'react';
|
|
1724
|
+
import { Elements } from '@liquidcommerce/elements-sdk';
|
|
1725
|
+
|
|
1726
|
+
function ProductPage({ productId }) {
|
|
1727
|
+
const [client, setClient] = useState(null);
|
|
1728
|
+
|
|
1729
|
+
useEffect(() => {
|
|
1730
|
+
async function initSDK() {
|
|
1731
|
+
const elementsClient = await Elements(process.env.REACT_APP_LCE_API_KEY, {
|
|
1732
|
+
env: 'production'
|
|
1733
|
+
});
|
|
1734
|
+
setClient(elementsClient);
|
|
1735
|
+
|
|
1736
|
+
// Inject product
|
|
1737
|
+
await elementsClient.injectProductElement([
|
|
1738
|
+
{ containerId: 'product-container', identifier: productId }
|
|
1739
|
+
]);
|
|
1740
|
+
|
|
1741
|
+
// Create cart button
|
|
1742
|
+
elementsClient.ui.cartButton('cart-button', true);
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
initSDK();
|
|
1746
|
+
|
|
1747
|
+
// Cleanup
|
|
1748
|
+
return () => {
|
|
1749
|
+
// SDK handles cleanup automatically
|
|
1750
|
+
};
|
|
1751
|
+
}, [productId]);
|
|
1752
|
+
|
|
1753
|
+
return (
|
|
1754
|
+
<div>
|
|
1755
|
+
<div id="cart-button"></div>
|
|
1756
|
+
<div id="product-container"></div>
|
|
1757
|
+
</div>
|
|
1758
|
+
);
|
|
1759
|
+
}
|
|
1760
|
+
```
|
|
1761
|
+
|
|
1762
|
+
### Vue Integration
|
|
1763
|
+
|
|
1764
|
+
```vue
|
|
1765
|
+
<template>
|
|
1766
|
+
<div>
|
|
1767
|
+
<div ref="cartButton"></div>
|
|
1768
|
+
<div ref="productContainer"></div>
|
|
1769
|
+
</div>
|
|
1770
|
+
</template>
|
|
1771
|
+
|
|
1772
|
+
<script>
|
|
1773
|
+
import { Elements } from '@liquidcommerce/elements-sdk';
|
|
1774
|
+
|
|
1775
|
+
export default {
|
|
1776
|
+
name: 'ProductPage',
|
|
1777
|
+
props: ['productId'],
|
|
1778
|
+
async mounted() {
|
|
1779
|
+
this.client = await Elements(process.env.VUE_APP_LCE_API_KEY, {
|
|
1780
|
+
env: 'production'
|
|
1781
|
+
});
|
|
1782
|
+
|
|
1783
|
+
await this.client.injectProductElement([
|
|
1784
|
+
{ containerId: this.$refs.productContainer.id, identifier: this.productId }
|
|
1785
|
+
]);
|
|
1786
|
+
|
|
1787
|
+
this.client.ui.cartButton(this.$refs.cartButton.id, true);
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
</script>
|
|
1791
|
+
```
|
|
1792
|
+
|
|
1793
|
+
### Next.js Integration
|
|
1794
|
+
|
|
1795
|
+
```tsx
|
|
1796
|
+
'use client';
|
|
1797
|
+
|
|
1798
|
+
import { useEffect } from 'react';
|
|
1799
|
+
|
|
1800
|
+
export default function ProductPage({ productId }: { productId: string }) {
|
|
1801
|
+
useEffect(() => {
|
|
1802
|
+
// Load SDK script
|
|
1803
|
+
const script = document.createElement('script');
|
|
1804
|
+
script.src = 'https://assets-elements.liquidcommerce.us/all/elements.js';
|
|
1805
|
+
script.async = true;
|
|
1806
|
+
script.onload = async () => {
|
|
1807
|
+
const client = await (window as any).Elements(process.env.NEXT_PUBLIC_LCE_API_KEY, {
|
|
1808
|
+
env: 'production'
|
|
1809
|
+
});
|
|
1810
|
+
|
|
1811
|
+
const components = await client.injectProductElement([
|
|
1812
|
+
{ containerId: 'product-container', identifier: productId }
|
|
1813
|
+
]);
|
|
1814
|
+
|
|
1815
|
+
client.ui.floatingCartButton(true);
|
|
1816
|
+
};
|
|
1817
|
+
document.body.appendChild(script);
|
|
1818
|
+
|
|
1819
|
+
return () => {
|
|
1820
|
+
document.body.removeChild(script);
|
|
1821
|
+
};
|
|
1822
|
+
}, [productId]);
|
|
1823
|
+
|
|
1824
|
+
return <div id="product-container"></div>;
|
|
1825
|
+
}
|
|
1826
|
+
```
|
|
1827
|
+
|
|
1828
|
+
### WordPress Integration
|
|
969
1829
|
|
|
970
1830
|
```html
|
|
971
|
-
<!--
|
|
1831
|
+
<!-- In your theme's header.php or functions.php -->
|
|
972
1832
|
<script
|
|
973
1833
|
data-liquid-commerce-elements
|
|
974
|
-
data-token="
|
|
975
|
-
data-env="
|
|
976
|
-
|
|
977
|
-
src="../umd/elements.js"
|
|
1834
|
+
data-token="<?php echo get_option('lce_api_key'); ?>"
|
|
1835
|
+
data-env="production"
|
|
1836
|
+
src="https://assets-elements.liquidcommerce.us/all/elements.js"
|
|
978
1837
|
></script>
|
|
1838
|
+
|
|
1839
|
+
<!-- In your product template -->
|
|
1840
|
+
<div data-lce-product="<?php echo get_post_meta(get_the_ID(), 'product_upc', true); ?>"></div>
|
|
979
1841
|
```
|
|
980
1842
|
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
1843
|
+
### Shopify Integration
|
|
1844
|
+
|
|
1845
|
+
```html
|
|
1846
|
+
<!-- In theme.liquid -->
|
|
1847
|
+
<script
|
|
1848
|
+
data-liquid-commerce-elements
|
|
1849
|
+
data-token="{{ settings.lce_api_key }}"
|
|
1850
|
+
data-env="production"
|
|
1851
|
+
src="https://assets-elements.liquidcommerce.us/all/elements.js"
|
|
1852
|
+
></script>
|
|
986
1853
|
|
|
987
|
-
|
|
1854
|
+
<!-- In product template -->
|
|
1855
|
+
<div data-lce-product="{{ product.barcode }}"></div>
|
|
1856
|
+
```
|
|
988
1857
|
|
|
989
|
-
###
|
|
1858
|
+
### Multi-Page Applications
|
|
990
1859
|
|
|
991
|
-
|
|
1860
|
+
For SPAs and multi-page apps, initialize once and reuse:
|
|
992
1861
|
|
|
993
|
-
```
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
enableDebugging: true,
|
|
997
|
-
customTheme: { /* theme config */ }
|
|
998
|
-
});
|
|
1862
|
+
```js
|
|
1863
|
+
// app.js (initialize once)
|
|
1864
|
+
let elementsClient = null;
|
|
999
1865
|
|
|
1000
|
-
|
|
1001
|
-
|
|
1866
|
+
async function getElementsClient() {
|
|
1867
|
+
if (!elementsClient) {
|
|
1868
|
+
elementsClient = await Elements('YOUR_API_KEY', {
|
|
1869
|
+
env: 'production'
|
|
1870
|
+
});
|
|
1871
|
+
}
|
|
1872
|
+
return elementsClient;
|
|
1873
|
+
}
|
|
1874
|
+
|
|
1875
|
+
// product-page.js
|
|
1876
|
+
const client = await getElementsClient();
|
|
1002
1877
|
await client.injectProductElement([
|
|
1003
|
-
{ containerId:
|
|
1878
|
+
{ containerId: 'pdp-1', identifier: productId }
|
|
1004
1879
|
]);
|
|
1005
|
-
|
|
1880
|
+
|
|
1881
|
+
// cart-page.js
|
|
1882
|
+
const client = await getElementsClient();
|
|
1883
|
+
const cartComponent = await client.injectCartElement('cart-container');
|
|
1006
1884
|
```
|
|
1007
1885
|
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
- Dynamic theme updates
|
|
1886
|
+
---
|
|
1887
|
+
|
|
1888
|
+
## 🚨 Error Handling
|
|
1889
|
+
|
|
1890
|
+
### Initialization Errors
|
|
1014
1891
|
|
|
1015
|
-
|
|
1892
|
+
```js
|
|
1893
|
+
try {
|
|
1894
|
+
const client = await Elements('YOUR_API_KEY', {
|
|
1895
|
+
env: 'production'
|
|
1896
|
+
});
|
|
1897
|
+
} catch (error) {
|
|
1898
|
+
if (error.message.includes('Invalid API key')) {
|
|
1899
|
+
console.error('Authentication failed');
|
|
1900
|
+
} else if (error.message.includes('Network')) {
|
|
1901
|
+
console.error('Network error - check connectivity');
|
|
1902
|
+
} else {
|
|
1903
|
+
console.error('SDK initialization failed:', error);
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
```
|
|
1016
1907
|
|
|
1017
|
-
###
|
|
1908
|
+
### Action Errors
|
|
1018
1909
|
|
|
1019
|
-
|
|
1020
|
-
2. **Open demo files** in your browser
|
|
1021
|
-
3. **Update API keys** with your own credentials
|
|
1022
|
-
4. **Modify environment** settings as needed (`development`, `staging`, `production`)
|
|
1910
|
+
All actions emit failure events with detailed error information:
|
|
1023
1911
|
|
|
1024
|
-
|
|
1912
|
+
```js
|
|
1913
|
+
// Product loaded successfully
|
|
1914
|
+
window.addEventListener('lce:actions.product_loaded', (event) => {
|
|
1915
|
+
const { identifier, productData } = event.detail.data;
|
|
1916
|
+
console.log(`Product ${identifier} loaded successfully`);
|
|
1917
|
+
});
|
|
1025
1918
|
|
|
1026
|
-
|
|
1919
|
+
// Cart action failure
|
|
1920
|
+
window.addEventListener('lce:actions.cart_product_add_failed', (event) => {
|
|
1921
|
+
const { identifiers, error } = event.detail.data;
|
|
1922
|
+
console.error('Failed to add products:', error);
|
|
1923
|
+
|
|
1924
|
+
// Show user-friendly message
|
|
1925
|
+
showNotification('Could not add to cart. Please try again.', 'error');
|
|
1926
|
+
});
|
|
1027
1927
|
|
|
1028
|
-
|
|
1928
|
+
// Checkout failure
|
|
1929
|
+
window.addEventListener('lce:actions.checkout_submit_failed', (event) => {
|
|
1930
|
+
const { error, reason } = event.detail.data;
|
|
1931
|
+
console.error('Checkout failed:', reason);
|
|
1932
|
+
|
|
1933
|
+
// Handle specific errors
|
|
1934
|
+
if (reason.includes('payment')) {
|
|
1935
|
+
showNotification('Payment declined. Please check your card details.', 'error');
|
|
1936
|
+
} else if (reason.includes('inventory')) {
|
|
1937
|
+
showNotification('Some items are no longer available.', 'warning');
|
|
1938
|
+
} else {
|
|
1939
|
+
showNotification('Checkout failed. Please try again.', 'error');
|
|
1940
|
+
}
|
|
1941
|
+
});
|
|
1029
1942
|
|
|
1030
|
-
|
|
1943
|
+
// Address validation failure
|
|
1944
|
+
window.addEventListener('lce:actions.address_failed', (event) => {
|
|
1945
|
+
const { error } = event.detail.data;
|
|
1946
|
+
console.error('Address validation failed:', error);
|
|
1947
|
+
showNotification('Please enter a valid address.', 'error');
|
|
1948
|
+
});
|
|
1031
1949
|
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1950
|
+
// Promo code failure
|
|
1951
|
+
window.addEventListener('lce:actions.cart_promo_code_failed', (event) => {
|
|
1952
|
+
const { code, error } = event.detail.data;
|
|
1953
|
+
console.error(`Promo code ${code} failed:`, error);
|
|
1954
|
+
|
|
1955
|
+
if (error.includes('expired')) {
|
|
1956
|
+
showNotification('This promo code has expired.', 'warning');
|
|
1957
|
+
} else if (error.includes('invalid')) {
|
|
1958
|
+
showNotification('Invalid promo code.', 'error');
|
|
1959
|
+
} else if (error.includes('minimum')) {
|
|
1960
|
+
showNotification('Cart minimum not met for this promo.', 'warning');
|
|
1961
|
+
}
|
|
1962
|
+
});
|
|
1035
1963
|
```
|
|
1036
|
-
- Creates optimized ESM and UMD bundles for production
|
|
1037
|
-
- Generates TypeScript declarations
|
|
1038
|
-
- Enables minification and compression
|
|
1039
|
-
- Removes console logs and debugging code
|
|
1040
|
-
- **Output:** `dist/index.esm.js` (ESM) + `umd/elements.js` (UMD)
|
|
1041
1964
|
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1965
|
+
### Network Error Recovery
|
|
1966
|
+
|
|
1967
|
+
```js
|
|
1968
|
+
let retryCount = 0;
|
|
1969
|
+
const maxRetries = 3;
|
|
1970
|
+
|
|
1971
|
+
async function addProductWithRetry(productParams) {
|
|
1972
|
+
try {
|
|
1973
|
+
await client.actions.cart.addProduct(productParams);
|
|
1974
|
+
} catch (error) {
|
|
1975
|
+
if (retryCount < maxRetries && error.message.includes('Network')) {
|
|
1976
|
+
retryCount++;
|
|
1977
|
+
console.log(`Retrying... Attempt ${retryCount}/${maxRetries}`);
|
|
1978
|
+
setTimeout(() => addProductWithRetry(productParams), 1000 * retryCount);
|
|
1979
|
+
} else {
|
|
1980
|
+
console.error('Failed after retries:', error);
|
|
1981
|
+
showNotification('Network error. Please check your connection.', 'error');
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1045
1985
|
```
|
|
1046
|
-
- Creates unminified bundles with source maps
|
|
1047
|
-
- Preserves console logs and debugging code
|
|
1048
|
-
- Faster build times for development
|
|
1049
|
-
- **Output:** Same as build but with debugging enabled
|
|
1050
1986
|
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1987
|
+
### Global Error Handler
|
|
1988
|
+
|
|
1989
|
+
```js
|
|
1990
|
+
// Listen to all failed events
|
|
1991
|
+
window.addEventListener('lce:actions.cart_failed', handleError);
|
|
1992
|
+
window.addEventListener('lce:actions.checkout_failed', handleError);
|
|
1993
|
+
window.addEventListener('lce:actions.address_failed', handleError);
|
|
1994
|
+
window.addEventListener('lce:actions.cart_product_add_failed', handleError);
|
|
1995
|
+
|
|
1996
|
+
function handleError(event) {
|
|
1997
|
+
const { error, context } = event.detail.data;
|
|
1998
|
+
|
|
1999
|
+
// Log to error tracking service
|
|
2000
|
+
if (window.Sentry) {
|
|
2001
|
+
Sentry.captureException(error, {
|
|
2002
|
+
tags: { sdk: 'liquid-commerce' },
|
|
2003
|
+
extra: context
|
|
2004
|
+
});
|
|
2005
|
+
}
|
|
2006
|
+
|
|
2007
|
+
// Show user notification
|
|
2008
|
+
showNotification('Something went wrong. Please try again.', 'error');
|
|
2009
|
+
}
|
|
1054
2010
|
```
|
|
1055
|
-
- Same as `build:dev` but watches for file changes
|
|
1056
|
-
- Automatically rebuilds on source code changes
|
|
1057
|
-
- **Best for:** Active development
|
|
1058
2011
|
|
|
1059
|
-
|
|
2012
|
+
---
|
|
1060
2013
|
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
2014
|
+
## ⚡ Performance & Best Practices
|
|
2015
|
+
|
|
2016
|
+
### Lazy Loading Components
|
|
2017
|
+
|
|
2018
|
+
Only inject components when needed:
|
|
2019
|
+
|
|
2020
|
+
```js
|
|
2021
|
+
// ❌ Don't inject all components upfront
|
|
2022
|
+
await client.injectProductElement([/* 50 products */]);
|
|
2023
|
+
await client.injectCartElement('cart');
|
|
2024
|
+
await client.injectCheckoutElement('checkout');
|
|
2025
|
+
|
|
2026
|
+
// ✅ Inject components as user navigates
|
|
2027
|
+
// On product page:
|
|
2028
|
+
await client.injectProductElement([{ containerId: 'pdp', identifier: productId }]);
|
|
2029
|
+
|
|
2030
|
+
// On cart page (when user clicks cart):
|
|
2031
|
+
await client.injectCartElement('cart');
|
|
2032
|
+
|
|
2033
|
+
// On checkout (when user proceeds):
|
|
2034
|
+
await client.injectCheckoutElement('checkout');
|
|
1064
2035
|
```
|
|
1065
|
-
- Uses Biome to lint TypeScript/JavaScript files
|
|
1066
|
-
- Automatically fixes fixable issues
|
|
1067
|
-
- Enforces code style and catches common errors
|
|
1068
2036
|
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
2037
|
+
### Reuse Client Instance
|
|
2038
|
+
|
|
2039
|
+
Initialize once, use everywhere:
|
|
2040
|
+
|
|
2041
|
+
```js
|
|
2042
|
+
// ❌ Don't create multiple clients
|
|
2043
|
+
// page1.js
|
|
2044
|
+
const client1 = await Elements('KEY', { env: 'production' });
|
|
2045
|
+
// page2.js
|
|
2046
|
+
const client2 = await Elements('KEY', { env: 'production' });
|
|
2047
|
+
|
|
2048
|
+
// ✅ Create once, reuse
|
|
2049
|
+
// app.js
|
|
2050
|
+
window.lceClient = await Elements('KEY', { env: 'production' });
|
|
2051
|
+
|
|
2052
|
+
// page1.js
|
|
2053
|
+
const client = window.lceClient;
|
|
2054
|
+
await client.injectProductElement([...]);
|
|
2055
|
+
|
|
2056
|
+
// page2.js
|
|
2057
|
+
const client = window.lceClient;
|
|
2058
|
+
await client.injectCartElement('cart');
|
|
1072
2059
|
```
|
|
1073
|
-
- Uses Biome to format all source files
|
|
1074
|
-
- Ensures consistent code formatting
|
|
1075
|
-
- Applies formatting rules defined in `biome.json`
|
|
1076
2060
|
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
2061
|
+
### Batch Product Injections
|
|
2062
|
+
|
|
2063
|
+
Group product injections together:
|
|
2064
|
+
|
|
2065
|
+
```js
|
|
2066
|
+
// ❌ Don't inject products one by one
|
|
2067
|
+
await client.injectProductElement([{ containerId: 'p1', identifier: 'id1' }]);
|
|
2068
|
+
await client.injectProductElement([{ containerId: 'p2', identifier: 'id2' }]);
|
|
2069
|
+
await client.injectProductElement([{ containerId: 'p3', identifier: 'id3' }]);
|
|
2070
|
+
|
|
2071
|
+
// ✅ Inject all products at once
|
|
2072
|
+
await client.injectProductElement([
|
|
2073
|
+
{ containerId: 'p1', identifier: 'id1' },
|
|
2074
|
+
{ containerId: 'p2', identifier: 'id2' },
|
|
2075
|
+
{ containerId: 'p3', identifier: 'id3' }
|
|
2076
|
+
]);
|
|
1080
2077
|
```
|
|
1081
|
-
- Runs both linting and formatting in one command
|
|
1082
|
-
- Auto-fixes issues and formats code
|
|
1083
|
-
- **Recommended before commits**
|
|
1084
2078
|
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
2079
|
+
### Optimize Event Listeners
|
|
2080
|
+
|
|
2081
|
+
Use event delegation instead of multiple listeners:
|
|
2082
|
+
|
|
2083
|
+
```js
|
|
2084
|
+
// ❌ Don't listen to every event
|
|
2085
|
+
window.addEventListener('lce:actions.product_loaded', handler);
|
|
2086
|
+
window.addEventListener('lce:actions.product_add_to_cart', handler);
|
|
2087
|
+
window.addEventListener('lce:actions.cart_updated', handler);
|
|
2088
|
+
// ... 20 more listeners
|
|
2089
|
+
|
|
2090
|
+
// ✅ Use consolidated listeners
|
|
2091
|
+
window.elements.onAllActions((data, metadata) => {
|
|
2092
|
+
switch (metadata.eventName) {
|
|
2093
|
+
case 'lce:actions.product_loaded':
|
|
2094
|
+
handleProductLoad(data);
|
|
2095
|
+
break;
|
|
2096
|
+
case 'lce:actions.product_add_to_cart':
|
|
2097
|
+
handleAddToCart(data);
|
|
2098
|
+
break;
|
|
2099
|
+
case 'lce:actions.cart_updated':
|
|
2100
|
+
handleCartUpdate(data);
|
|
2101
|
+
break;
|
|
2102
|
+
}
|
|
2103
|
+
});
|
|
1088
2104
|
```
|
|
1089
|
-
- Combines `check` + `build:dev`
|
|
1090
|
-
- Complete code quality check + development build
|
|
1091
|
-
- **Perfect for:** Pre-commit workflow
|
|
1092
2105
|
|
|
1093
|
-
###
|
|
2106
|
+
### Defer Non-Critical Operations
|
|
1094
2107
|
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
2108
|
+
Load SDK after critical page content:
|
|
2109
|
+
|
|
2110
|
+
```html
|
|
2111
|
+
<!-- ❌ Don't load SDK in <head> -->
|
|
2112
|
+
<head>
|
|
2113
|
+
<script src="https://assets-elements.liquidcommerce.us/all/elements.js"></script>
|
|
2114
|
+
</head>
|
|
2115
|
+
|
|
2116
|
+
<!-- ✅ Load SDK with defer or at end of body -->
|
|
2117
|
+
<head>
|
|
2118
|
+
<script defer src="https://assets-elements.liquidcommerce.us/all/elements.js"></script>
|
|
2119
|
+
</head>
|
|
2120
|
+
|
|
2121
|
+
<!-- Or -->
|
|
2122
|
+
<body>
|
|
2123
|
+
<!-- Your page content -->
|
|
2124
|
+
<script src="https://assets-elements.liquidcommerce.us/all/elements.js"></script>
|
|
2125
|
+
</body>
|
|
1098
2126
|
```
|
|
1099
|
-
- Removes `dist/` and `umd/` directories
|
|
1100
|
-
- **Use when:** Build artifacts are corrupted
|
|
1101
2127
|
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
2128
|
+
### Use Auto-Init for Simple Cases
|
|
2129
|
+
|
|
2130
|
+
Auto-init is optimized for performance:
|
|
2131
|
+
|
|
2132
|
+
```html
|
|
2133
|
+
<!-- ✅ Auto-init is the fastest way for simple setups -->
|
|
2134
|
+
<div data-lce-product="00619947000020"></div>
|
|
2135
|
+
<div data-lce-product="00832889005513"></div>
|
|
2136
|
+
|
|
2137
|
+
<script
|
|
2138
|
+
data-liquid-commerce-elements
|
|
2139
|
+
data-token="YOUR_API_KEY"
|
|
2140
|
+
data-env="production"
|
|
2141
|
+
src="https://assets-elements.liquidcommerce.us/all/elements.js"
|
|
2142
|
+
></script>
|
|
1105
2143
|
```
|
|
1106
|
-
- Removes build outputs AND `node_modules/`
|
|
1107
|
-
- Reinstalls all dependencies with `pnpm install`
|
|
1108
|
-
- Runs a fresh production build
|
|
1109
|
-
- **Use when:** Dependency issues or major updates
|
|
1110
2144
|
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
2145
|
+
### Avoid Unnecessary Re-renders
|
|
2146
|
+
|
|
2147
|
+
Don't repeatedly inject the same component:
|
|
2148
|
+
|
|
2149
|
+
```js
|
|
2150
|
+
// ❌ Don't re-inject on every state change
|
|
2151
|
+
function updateProduct() {
|
|
2152
|
+
setProductId(newId);
|
|
2153
|
+
await client.injectProductElement([{ containerId: 'pdp', identifier: newId }]);
|
|
2154
|
+
}
|
|
2155
|
+
|
|
2156
|
+
// ✅ Components update automatically on state changes
|
|
2157
|
+
// Just inject once
|
|
2158
|
+
useEffect(() => {
|
|
2159
|
+
client.injectProductElement([{ containerId: 'pdp', identifier: productId }]);
|
|
2160
|
+
}, []); // Empty deps - inject once
|
|
2161
|
+
|
|
2162
|
+
// Product will auto-update when you call actions
|
|
2163
|
+
await client.actions.cart.addProduct([...]);
|
|
1114
2164
|
```
|
|
1115
|
-
- Generates `CHANGELOG.md` from conventional commits
|
|
1116
|
-
- Uses Angular commit convention
|
|
1117
|
-
- **Use when:** Preparing releases
|
|
1118
2165
|
|
|
1119
|
-
###
|
|
2166
|
+
### Cache Frequently Accessed Data
|
|
1120
2167
|
|
|
1121
|
-
|
|
2168
|
+
```js
|
|
2169
|
+
// ❌ Don't repeatedly fetch the same data
|
|
2170
|
+
async function showCartTotal() {
|
|
2171
|
+
const cart = await client.actions.cart.getDetails();
|
|
2172
|
+
return cart.amounts.total;
|
|
2173
|
+
}
|
|
2174
|
+
|
|
2175
|
+
// ✅ Use UI helpers that auto-update
|
|
2176
|
+
client.ui.cartSubtotal('cart-total-display');
|
|
2177
|
+
client.ui.cartItemsCount('cart-count-display');
|
|
2178
|
+
|
|
2179
|
+
// Or cache and listen to updates
|
|
2180
|
+
let cachedCart = await client.actions.cart.getDetails();
|
|
2181
|
+
window.addEventListener('lce:actions.cart_updated', (event) => {
|
|
2182
|
+
cachedCart = event.detail.data.current;
|
|
2183
|
+
});
|
|
2184
|
+
```
|
|
1122
2185
|
|
|
1123
|
-
|
|
1124
|
-
- **Target:** Modern bundlers (Vite, Webpack, etc.)
|
|
1125
|
-
- **Format:** ES Modules
|
|
1126
|
-
- **Optimizations:** Tree shaking, modern syntax
|
|
1127
|
-
- **Use case:** NPM package imports
|
|
2186
|
+
### Use CDN for Production
|
|
1128
2187
|
|
|
1129
|
-
|
|
1130
|
-
- **Target:** Direct browser usage
|
|
1131
|
-
- **Format:** Universal Module Definition
|
|
1132
|
-
- **Global:** `window.LiquidCommerceElements`
|
|
1133
|
-
- **Optimizations:** Maximum browser compatibility
|
|
1134
|
-
- **Use case:** CDN distribution, `<script>` tags
|
|
2188
|
+
Always use CDN in production for optimal caching:
|
|
1135
2189
|
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
-
|
|
2190
|
+
```js
|
|
2191
|
+
// ✅ CDN (recommended)
|
|
2192
|
+
<script src="https://assets-elements.liquidcommerce.us/all/elements.js"></script>
|
|
1139
2193
|
|
|
1140
|
-
|
|
2194
|
+
// ❌ Don't self-host unless necessary
|
|
2195
|
+
<script src="/static/elements.js"></script>
|
|
2196
|
+
```
|
|
1141
2197
|
|
|
1142
|
-
|
|
1143
|
-
```bash
|
|
1144
|
-
# Start development
|
|
1145
|
-
pnpm run dev
|
|
2198
|
+
### Minimize Theme Complexity
|
|
1146
2199
|
|
|
1147
|
-
|
|
1148
|
-
|
|
2200
|
+
Simpler themes = faster rendering:
|
|
2201
|
+
|
|
2202
|
+
```js
|
|
2203
|
+
// ❌ Don't override every style property
|
|
2204
|
+
customTheme: {
|
|
2205
|
+
global: {
|
|
2206
|
+
colors: { /* 20 color overrides */ },
|
|
2207
|
+
typography: { /* 15 typography overrides */ },
|
|
2208
|
+
shadows: { /* 10 shadow overrides */ },
|
|
2209
|
+
// ... 100 more overrides
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
|
|
2213
|
+
// ✅ Override only what's necessary
|
|
2214
|
+
customTheme: {
|
|
2215
|
+
global: {
|
|
2216
|
+
colors: {
|
|
2217
|
+
primary: '#007bff',
|
|
2218
|
+
secondary: '#6c757d'
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
1149
2222
|
```
|
|
1150
2223
|
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
2224
|
+
### Monitor Performance
|
|
2225
|
+
|
|
2226
|
+
Track SDK performance in production:
|
|
2227
|
+
|
|
2228
|
+
```js
|
|
2229
|
+
// Measure initialization time
|
|
2230
|
+
const start = performance.now();
|
|
2231
|
+
const client = await Elements('YOUR_API_KEY', { env: 'production' });
|
|
2232
|
+
console.log(`SDK initialized in ${performance.now() - start}ms`);
|
|
2233
|
+
|
|
2234
|
+
// Track component load times
|
|
2235
|
+
window.addEventListener('lce:actions.product_loaded', (event) => {
|
|
2236
|
+
const { loadTime } = event.detail.metadata;
|
|
2237
|
+
console.log(`Product loaded in ${loadTime}ms`);
|
|
2238
|
+
|
|
2239
|
+
// Send to analytics
|
|
2240
|
+
analytics.track('SDK Component Load', {
|
|
2241
|
+
component: 'product',
|
|
2242
|
+
duration: loadTime
|
|
2243
|
+
});
|
|
2244
|
+
});
|
|
2245
|
+
```
|
|
2246
|
+
|
|
2247
|
+
### Production Checklist
|
|
2248
|
+
|
|
2249
|
+
Before going live:
|
|
2250
|
+
|
|
2251
|
+
- ✅ Set `env: 'production'`
|
|
2252
|
+
- ✅ Set `debugMode: 'none'` (or omit)
|
|
2253
|
+
- ✅ Use CDN script URL
|
|
2254
|
+
- ✅ Pin to specific version (optional but recommended)
|
|
2255
|
+
- ✅ Configure proxy if using ad blockers
|
|
2256
|
+
- ✅ Test error handling
|
|
2257
|
+
- ✅ Verify event tracking
|
|
2258
|
+
- ✅ Check cart persistence
|
|
2259
|
+
- ✅ Test on target browsers
|
|
2260
|
+
- ✅ Measure performance metrics
|
|
1155
2261
|
|
|
1156
|
-
|
|
1157
|
-
pnpm run changelog
|
|
2262
|
+
**Production-ready init:**
|
|
1158
2263
|
|
|
1159
|
-
|
|
2264
|
+
```js
|
|
2265
|
+
const client = await Elements('YOUR_PRODUCTION_API_KEY', {
|
|
2266
|
+
env: 'production',
|
|
2267
|
+
debugMode: 'none',
|
|
2268
|
+
customTheme: { /* minimal overrides */ },
|
|
2269
|
+
proxy: { baseUrl: 'https://yourdomain.com/api/proxy' }
|
|
2270
|
+
});
|
|
1160
2271
|
```
|
|
1161
2272
|
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
pnpm run clean:hard
|
|
2273
|
+
**📖 For debugging and troubleshooting:** See [`docs/TROUBLESHOOTING.md`](docs/TROUBLESHOOTING.md) for comprehensive problem-solving guide.
|
|
2274
|
+
|
|
2275
|
+
---
|
|
1166
2276
|
|
|
1167
|
-
|
|
1168
|
-
|
|
2277
|
+
## 🔒 Proxy Configuration
|
|
2278
|
+
|
|
2279
|
+
Route API requests through your server to avoid ad blockers:
|
|
2280
|
+
|
|
2281
|
+
```js
|
|
2282
|
+
const client = await Elements('YOUR_API_KEY', {
|
|
2283
|
+
env: 'production',
|
|
2284
|
+
proxy: {
|
|
2285
|
+
baseUrl: 'https://yourdomain.com/api/liquidcommerce',
|
|
2286
|
+
headers: {
|
|
2287
|
+
'X-Custom-Header': 'value'
|
|
2288
|
+
}
|
|
2289
|
+
}
|
|
2290
|
+
});
|
|
1169
2291
|
```
|
|
1170
2292
|
|
|
2293
|
+
The SDK automatically handles routing and required headers. See [`docs/PROXY.md`](docs/PROXY.md) for complete proxy setup guide with Next.js examples.
|
|
2294
|
+
|
|
2295
|
+
## 📚 Documentation
|
|
2296
|
+
|
|
2297
|
+
**📖 Complete Documentation:**
|
|
2298
|
+
|
|
2299
|
+
- **[Documentation Index](docs/DOCUMENTATION_INDEX.md)** - Complete guide to all documentation
|
|
2300
|
+
- **[Configuration Reference](docs/CONFIGURATION.md)** - All configuration options with TypeScript types
|
|
2301
|
+
- **[Theming Guide](docs/THEMING.md)** - Complete customization reference
|
|
2302
|
+
- **[Actions Reference](docs/ACTIONS.md)** - Programmatic control with business use cases
|
|
2303
|
+
- **[Events Reference](docs/EVENTS.md)** - Event system and tracking guide
|
|
2304
|
+
- **[Troubleshooting Guide](docs/TROUBLESHOOTING.md)** - Common issues and solutions
|
|
2305
|
+
- **[Browser Support](docs/BROWSER_SUPPORT.md)** - Detailed browser compatibility
|
|
2306
|
+
- **[Proxy Setup](docs/PROXY.md)** - Ad blocker avoidance configuration
|
|
2307
|
+
|
|
2308
|
+
---
|
|
2309
|
+
|
|
2310
|
+
## 🏷️ Versioning
|
|
2311
|
+
|
|
2312
|
+
This project uses Semantic Versioning. Two CDN environments are available:
|
|
2313
|
+
|
|
2314
|
+
- **Production:** `https://assets-elements.liquidcommerce.us/all/elements.js` (stable)
|
|
2315
|
+
- **Beta:** `https://assets-elements.liquidcommerce.us/all/beta/elements.js` (pre-release)
|
|
2316
|
+
|
|
1171
2317
|
## 💬 Support
|
|
1172
2318
|
|
|
1173
2319
|
If you need help with your API key, environment selection, or implementation, contact your LiquidCommerce representative.
|