@liquidcommerce/elements-sdk 2.4.0 → 2.4.2

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/docs/EVENTS.md CHANGED
@@ -21,15 +21,16 @@ When customers interact with your LiquidCommerce elements, events automatically
21
21
  // Example: When someone adds to cart, send them a discount code
22
22
  window.addEventListener('lce:actions.product_add_to_cart', function(event) {
23
23
  // Customer just added a product to cart!
24
- const product = event.detail.data;
24
+ const data = event.detail.data;
25
25
 
26
26
  // Maybe send them a discount popup
27
- showDiscountPopup(product.productName);
27
+ showDiscountPopup(data.identifier);
28
28
 
29
29
  // Or track in your analytics
30
30
  analytics.track('Product Added', {
31
- product: product.productName,
32
- price: product.price
31
+ identifier: data.identifier,
32
+ quantity: data.quantity,
33
+ upc: data.upc
33
34
  });
34
35
  });
35
36
  ```
@@ -45,13 +46,13 @@ What do you want to achieve? Pick one:
45
46
  window.addEventListener('lce:actions.product_loaded', function(event) {
46
47
  // Product was viewed - track in your analytics
47
48
  const product = event.detail.data;
48
- console.log('Customer viewed:', product.productName);
49
+ console.log('Customer viewed:', product.name);
49
50
  });
50
51
 
51
52
  window.addEventListener('lce:actions.product_add_to_cart', function(event) {
52
53
  // Product was added to cart - this is a conversion!
53
- const product = event.detail.data;
54
- console.log('SALE OPPORTUNITY:', product.productName, '$' + product.price);
54
+ const data = event.detail.data;
55
+ console.log('SALE OPPORTUNITY:', data.identifier, 'qty:', data.quantity);
55
56
  });
56
57
  ```
57
58
 
@@ -75,12 +76,10 @@ window.addEventListener('lce:actions.checkout_submit_completed', function(event)
75
76
  ```javascript
76
77
  // Offer upsells when they add expensive items
77
78
  window.addEventListener('lce:actions.product_add_to_cart', function(event) {
78
- const product = event.detail.data;
79
+ const data = event.detail.data;
79
80
 
80
- if (product.price > 100) {
81
- // Show them complementary products
82
- showUpsellPopup(product.productId);
83
- }
81
+ // Trigger upsell based on product identifier
82
+ showUpsellPopup(data.identifier);
84
83
  });
85
84
  ```
86
85
 
@@ -121,6 +120,63 @@ window.addEventListener('lce:actions.client_ready', function(event) {
121
120
 
122
121
  **Note on Personalization:** Product personalization (engraving) is added during the add-to-cart action. The personalization is included in the `product_add_to_cart` event data. Once in cart, use `cart_item_engraving_updated` to track changes.
123
122
 
123
+ #### Product Details Event Data
124
+ When `lce:actions.product_loaded` fires, you get comprehensive product information:
125
+
126
+ ```javascript
127
+ window.addEventListener('lce:actions.product_loaded', function(event) {
128
+ const product = event.detail.data;
129
+
130
+ // Basic Information
131
+ console.log(product.id); // Product ID
132
+ console.log(product.name); // Product name
133
+ console.log(product.brand); // Brand name
134
+ console.log(product.category); // Category
135
+ console.log(product.catPath); // Category path
136
+ console.log(product.classification); // Product classification
137
+ console.log(product.type); // Product type
138
+ console.log(product.subType); // Product sub-type
139
+ console.log(product.salsifyGrouping); // Salsify grouping ID
140
+
141
+ // Visual Assets
142
+ console.log(product.mainImage); // Main product image URL
143
+ console.log(product.images); // Array of all product images
144
+
145
+ // Product Attributes
146
+ console.log(product.region); // Region (e.g., "Napa Valley")
147
+ console.log(product.country); // Country of origin
148
+ console.log(product.material); // Material type
149
+ console.log(product.abv); // Alcohol by volume
150
+ console.log(product.proof); // Proof
151
+ console.log(product.age); // Age statement
152
+ console.log(product.color); // Color description
153
+ console.log(product.flavor); // Flavor profile
154
+ console.log(product.variety); // Variety (e.g., "Cabernet Sauvignon")
155
+ console.log(product.appellation); // Appellation
156
+ console.log(product.vintage); // Vintage year
157
+
158
+ // Descriptions
159
+ console.log(product.description); // Plain text description
160
+ console.log(product.htmlDescription); // HTML formatted description
161
+ console.log(product.tastingNotes); // Tasting notes
162
+
163
+ // Pricing
164
+ console.log(product.priceInfo); // { min, max, avg } pricing across fulfillments
165
+
166
+ // Available Sizes & Fulfillments
167
+ console.log(product.sizes); // All available sizes with fulfillment options
168
+ console.log(product.selectedSizeId); // Currently selected size
169
+ console.log(product.selectedFulfillmentId); // Currently selected fulfillment
170
+ console.log(product.selectedFulfillmentType); // 'shipping' or 'onDemand'
171
+ });
172
+ ```
173
+
174
+ **Use Cases:**
175
+ - **Rich Analytics**: Track which product attributes drive conversions
176
+ - **Personalized Recommendations**: Suggest similar products based on variety, region, or flavor
177
+ - **Content Display**: Show detailed product information on your custom UI
178
+ - **Search & Filtering**: Build custom search based on product attributes
179
+
124
180
  ### 🛒 Cart Events (Track Purchase Intent)
125
181
  ```javascript
126
182
  // Cart lifecycle
@@ -155,6 +211,75 @@ window.addEventListener('lce:actions.cart_item_engraving_updated', function(even
155
211
  });
156
212
  ```
157
213
 
214
+ #### Cart Details Event Data
215
+ When `lce:actions.cart_loaded` or `lce:actions.cart_updated` fires, you get complete cart information:
216
+
217
+ ```javascript
218
+ window.addEventListener('lce:actions.cart_loaded', function(event) {
219
+ const cart = event.detail.data;
220
+
221
+ // Cart Identification
222
+ console.log(cart.id); // Cart ID
223
+ console.log(cart.promoCode); // Applied promo code (if any)
224
+
225
+ // Cart Items
226
+ console.log(cart.items); // Object with all cart items
227
+ console.log(cart.itemCount); // Total number of items in cart
228
+
229
+ // Each item contains:
230
+ Object.values(cart.items).forEach(item => {
231
+ console.log(item.id); // Cart item ID
232
+ console.log(item.name); // Product name
233
+ console.log(item.brand); // Brand
234
+ console.log(item.salsifyGrouping); // Salsify grouping ID
235
+ console.log(item.catPath); // Category path
236
+ console.log(item.size); // Size description
237
+ console.log(item.volume); // Volume
238
+ console.log(item.uom); // Unit of measure
239
+ console.log(item.pack); // Is pack (boolean)
240
+ console.log(item.packDesc); // Pack description
241
+ console.log(item.container); // Container type
242
+ console.log(item.containerType); // Container type classification
243
+ console.log(item.price); // Total price (unitPrice × quantity)
244
+ console.log(item.unitPrice); // Price per unit
245
+ console.log(item.quantity); // Quantity
246
+ console.log(item.maxQuantity); // Maximum allowed quantity
247
+ console.log(item.mainImage); // Product image URL
248
+ console.log(item.upc); // UPC code
249
+ console.log(item.sku); // SKU
250
+ console.log(item.partNumber); // Part number
251
+ console.log(item.retailerId); // Retailer ID
252
+ console.log(item.fulfillmentId); // Fulfillment ID
253
+ console.log(item.attributes); // Item attributes (engraving, etc.)
254
+ });
255
+
256
+ // Location Information
257
+ console.log(cart.location.placesId); // Google Places ID
258
+ console.log(cart.location.address); // Address object
259
+ console.log(cart.location.coordinates); // Lat/long coordinates
260
+
261
+ // Financial Breakdown
262
+ console.log(cart.amounts.subtotal); // Subtotal
263
+ console.log(cart.amounts.deliveryFee); // Delivery fee
264
+ console.log(cart.amounts.shippingFee); // Shipping fee
265
+ console.log(cart.amounts.platformFee); // Platform fee
266
+ console.log(cart.amounts.engravingFee); // Engraving/personalization fee
267
+ console.log(cart.amounts.discounts); // Total discounts
268
+ console.log(cart.amounts.giftCardTotal); // Gift card total applied
269
+ console.log(cart.amounts.total); // Final total
270
+
271
+ // Timestamps
272
+ console.log(cart.createdAt); // When cart was created
273
+ console.log(cart.updatedAt); // Last update timestamp
274
+ });
275
+ ```
276
+
277
+ **Use Cases:**
278
+ - **Abandoned Cart Recovery**: Track cart value and items for targeted recovery campaigns
279
+ - **Revenue Analytics**: Monitor average cart value, most popular items, cart composition
280
+ - **Inventory Management**: Track which products are frequently added/removed
281
+ - **Pricing Analysis**: Analyze impact of fees, discounts, and gift cards on cart totals
282
+
158
283
  ### 💳 Checkout Events (Track Purchase Process)
159
284
  ```javascript
160
285
  // Checkout lifecycle
@@ -191,6 +316,105 @@ window.addEventListener('lce:actions.cart_item_engraving_updated', function(even
191
316
  **Important Note on Checkout Personalization:**
192
317
  Personalization cannot be edited during checkout - only removed. This is by design to prevent order processing complications. If a customer wants to modify personalization, they must return to the cart. The checkout only displays personalization details and provides a remove option.
193
318
 
319
+ #### Checkout Details Event Data
320
+ When you call `actions.checkout.getDetails()`, you get comprehensive checkout information:
321
+
322
+ **Note:** The `lce:actions.checkout_loaded` event only contains `{ cartId: string }`. To get full checkout details, use `actions.checkout.getDetails()`.
323
+
324
+ ```javascript
325
+ // Get full checkout details via action
326
+ const checkout = actions.checkout.getDetails();
327
+
328
+ // Checkout Identification
329
+ console.log(checkout.cartId); // Associated cart ID
330
+
331
+ // Checkout Status Flags
332
+ console.log(checkout.acceptedAccountCreation); // Customer accepted account creation
333
+ console.log(checkout.hasAgeVerify); // Age verification required
334
+ console.log(checkout.hasSubstitutionPolicy); // Substitution policy accepted
335
+ console.log(checkout.isGift); // Order is a gift
336
+ console.log(checkout.billingSameAsShipping); // Billing address same as shipping
337
+ console.log(checkout.hasPromoCode); // Promo code applied
338
+ console.log(checkout.hasGiftCards); // Gift cards applied
339
+
340
+ // Marketing Preferences
341
+ console.log(checkout.marketingPreferences.canEmail); // Email opt-in status
342
+ console.log(checkout.marketingPreferences.canSms); // SMS opt-in status
343
+
344
+ // Order Summary
345
+ console.log(checkout.itemCount); // Total items in checkout
346
+
347
+ // Financial Breakdown
348
+ console.log(checkout.amounts.subtotal); // Subtotal
349
+ console.log(checkout.amounts.deliveryFee); // Delivery fee
350
+ console.log(checkout.amounts.shippingFee); // Shipping fee
351
+ console.log(checkout.amounts.platformFee); // Platform fee
352
+ console.log(checkout.amounts.engravingFee); // Engraving/personalization fee
353
+ console.log(checkout.amounts.discounts); // Total discounts
354
+ console.log(checkout.amounts.giftCardTotal); // Gift card total applied
355
+ console.log(checkout.amounts.tax); // Tax amount
356
+ console.log(checkout.amounts.bottleDeposits); // Bottle deposit fees
357
+ console.log(checkout.amounts.total); // Final total
358
+
359
+ // Checkout Items (detailed product information)
360
+ console.log(checkout.items); // Object with all checkout items
361
+
362
+ // Each checkout item contains comprehensive details:
363
+ Object.values(checkout.items).forEach(item => {
364
+ console.log(item.cartItemId); // Cart item ID
365
+ console.log(item.liquidId); // Liquid ID
366
+ console.log(item.variantId); // Variant ID
367
+ console.log(item.name); // Product name
368
+ console.log(item.brand); // Brand
369
+ console.log(item.salsifyGrouping); // Salsify grouping ID
370
+ console.log(item.catPath); // Category path
371
+
372
+ // Size & Container Information
373
+ console.log(item.size); // Size description
374
+ console.log(item.volume); // Volume
375
+ console.log(item.uom); // Unit of measure
376
+ console.log(item.pack); // Is pack (boolean)
377
+ console.log(item.packDesc); // Pack description
378
+ console.log(item.container); // Container type
379
+ console.log(item.containerType); // Container type classification
380
+
381
+ // Product Attributes
382
+ console.log(item.proof); // Proof
383
+ console.log(item.abv); // Alcohol by volume
384
+
385
+ // Pricing
386
+ console.log(item.price); // Total price (unitPrice × quantity)
387
+ console.log(item.unitPrice); // Price per unit
388
+ console.log(item.unitTax); // Tax per unit
389
+ console.log(item.bottleDeposits); // Bottle deposit fees
390
+ console.log(item.quantity); // Quantity
391
+
392
+ // Identifiers
393
+ console.log(item.upc); // UPC code
394
+ console.log(item.sku); // SKU
395
+ console.log(item.partNumber); // Part number
396
+
397
+ // Fulfillment Information
398
+ console.log(item.retailerId); // Retailer ID
399
+ console.log(item.retailerName); // Retailer name
400
+ console.log(item.fulfillmentId); // Fulfillment ID
401
+ console.log(item.expectationDetail); // Delivery expectation details
402
+
403
+ // Visual Assets
404
+ console.log(item.mainImage); // Product image URL
405
+
406
+ // Item Attributes (engraving, etc.)
407
+ console.log(item.attributes); // Item attributes object
408
+ });
409
+ ```
410
+
411
+ **Use Cases:**
412
+ - **Order Analytics**: Track checkout completion rates, average order values, popular items
413
+ - **Marketing Optimization**: Analyze opt-in rates, gift order patterns, promo code effectiveness
414
+ - **Revenue Tracking**: Monitor tax collection, fees, discounts, and gift card usage
415
+ - **Customer Insights**: Understand purchasing patterns, preferred retailers, delivery preferences
416
+ - **Compliance**: Track age verification requirements, substitution policy acceptance
417
+
194
418
  ### 📍 Address Events (Track Shipping Preferences)
195
419
  ```javascript
196
420
  'lce:actions.address_updated' // → "Customer entered shipping address"
@@ -333,9 +557,9 @@ applyPromoCodeWithFeedback('SAVE20');
333
557
  ```javascript
334
558
  // Automatically offer discounts for high-value carts
335
559
  window.addEventListener('lce:actions.cart_updated', function(event) {
336
- const cart = event.detail.data;
560
+ const cart = event.detail.data.current;
337
561
 
338
- if (cart.total > 200 && !cart.hasPromoCode) {
562
+ if (cart.amounts.total > 200 && !cart.promoCode) {
339
563
  // Show them a 10% off popup
340
564
  showPopup("Get 10% off orders over $200! Use code: SAVE10");
341
565
  }
@@ -392,35 +616,38 @@ window.addEventListener('lce:actions.product_loaded', function(event) {
392
616
  const product = event.detail.data;
393
617
 
394
618
  // Initialize stats if first time seeing this product
395
- if (!productStats[product.productId]) {
396
- productStats[product.productId] = {
397
- name: product.productName,
619
+ if (!productStats[product.id]) {
620
+ productStats[product.id] = {
621
+ name: product.name,
398
622
  views: 0,
399
623
  addedToCarts: 0,
400
624
  conversions: 0
401
625
  };
402
626
  }
403
627
 
404
- productStats[product.productId].views++;
628
+ productStats[product.id].views++;
405
629
  });
406
630
 
407
631
  window.addEventListener('lce:actions.product_add_to_cart', function(event) {
408
- const product = event.detail.data;
409
- productStats[product.productId].addedToCarts++;
632
+ const data = event.detail.data;
633
+ // Note: product_add_to_cart only has identifier, not full product details
634
+ if (productStats[data.identifier]) {
635
+ productStats[data.identifier].addedToCarts++;
636
+ }
410
637
  });
411
638
 
412
639
  window.addEventListener('lce:actions.checkout_submit_completed', function(event) {
413
640
  const order = event.detail.data;
414
-
415
- // Mark all purchased products as conversions
416
- order.items.forEach(function(item) {
417
- if (productStats[item.productId]) {
418
- productStats[item.productId].conversions++;
419
- }
420
- });
641
+ console.log('Order completed:', order.orderNumber, 'Total:', order.orderTotal);
421
642
 
422
643
  // Send stats to your analytics dashboard
423
644
  console.log('Product Performance:', productStats);
645
+
646
+ // Track conversion in analytics
647
+ analytics.track('Purchase', {
648
+ orderNumber: order.orderNumber,
649
+ total: order.orderTotal
650
+ });
424
651
  });
425
652
  ```
426
653
 
@@ -428,13 +655,13 @@ window.addEventListener('lce:actions.checkout_submit_completed', function(event)
428
655
  ```javascript
429
656
  // Show live activity to create FOMO (Fear of Missing Out)
430
657
  window.addEventListener('lce:actions.product_add_to_cart', function(event) {
431
- const product = event.detail.data;
658
+ const data = event.detail.data;
432
659
 
433
660
  // Show notification to other visitors
434
- showNotification(`Someone just bought ${product.productName}! Only 3 left!`);
661
+ showNotification(`Someone just bought product ${data.identifier}! Only 3 left!`);
435
662
 
436
663
  // Update inventory count on the page
437
- updateInventoryDisplay(product.productId, -1);
664
+ updateInventoryDisplay(data.identifier, -1);
438
665
  });
439
666
 
440
667
  window.addEventListener('lce:actions.cart_opened', function(event) {
@@ -480,16 +707,22 @@ function triggerCartRecovery() {
480
707
 
481
708
  ```javascript
482
709
  window.addEventListener('lce:actions.product_add_to_cart', function(event) {
483
- const product = event.detail.data;
710
+ const data = event.detail.data;
711
+
712
+ // Offer upsells based on product identifier
713
+ const upsellMap = {
714
+ 'phone-001': 'phone-cases',
715
+ 'laptop-001': 'laptop-accessories'
716
+ };
484
717
 
485
- // If they added a phone, suggest a case
486
- if (product.category === 'phones') {
487
- showUpsell('phone-cases');
718
+ if (upsellMap[data.identifier]) {
719
+ showUpsell(upsellMap[data.identifier]);
488
720
  }
489
721
 
490
- // If cart total is close to free shipping, tell them
491
- if (cart.total > 45 && cart.total < 50) {
492
- showMessage("Add $" + (50 - cart.total) + " more for FREE shipping!");
722
+ // Check if cart is close to free shipping threshold
723
+ const cart = actions.cart.getDetails();
724
+ if (cart.amounts.total > 45 && cart.amounts.total < 50) {
725
+ showMessage("Add $" + (50 - cart.amounts.total) + " more for FREE shipping!");
493
726
  }
494
727
  });
495
728
  ```
@@ -102,9 +102,26 @@ console.log('Container:', container); // Should not be null
102
102
  // 2. Wait for DOM
103
103
  window.addEventListener('DOMContentLoaded', async () => {
104
104
  const client = await Elements('YOUR_API_KEY', { env: 'production' });
105
- await client.injectProductElement([
105
+ const components = await client.injectProductElement([
106
106
  { containerId: 'product-container', identifier: 'product-123' }
107
107
  ]);
108
+
109
+ // Check if injection was successful
110
+ if (components.length > 0) {
111
+ console.log('Product component injected successfully');
112
+ // components[0].rerender() - Rerender if needed
113
+ // components[0].getElement() - Get container element
114
+ // components[0].getType() - Get component type
115
+ } else {
116
+ console.log('Product injection failed');
117
+ }
118
+
119
+ // Debug: Check all injected components
120
+ const allComponents = client.getInjectedComponents();
121
+ console.log('All injected components:', allComponents);
122
+ allComponents.forEach((component, containerId) => {
123
+ console.log(`Container: ${containerId}, Type: ${component.getType()}`);
124
+ });
108
125
  });
109
126
 
110
127
  // 3. Monitor product loading
@@ -636,7 +653,7 @@ onMounted(async () => {
636
653
  });
637
654
 
638
655
  window.addEventListener('lce:actions.cart_updated', (event) => {
639
- cartData.value = event.detail.data; // Vue reactivity
656
+ cartData.value = event.detail.data.current; // Vue reactivity
640
657
  });
641
658
  });
642
659
  </script>
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "LiquidCommerce Elements SDK",
4
4
  "license": "UNLICENSED",
5
5
  "author": "LiquidCommerce Team",
6
- "version": "2.4.0",
6
+ "version": "2.4.2",
7
7
  "homepage": "https://docs.liquidcommerce.co/elements-sdk",
8
8
  "repository": {
9
9
  "type": "git",
@@ -71,7 +71,7 @@
71
71
  "embeddable commerce"
72
72
  ],
73
73
  "devDependencies": {
74
- "@biomejs/biome": "2.2.6",
74
+ "@biomejs/biome": "2.2.7",
75
75
  "@commitlint/cli": "^20.1.0",
76
76
  "@commitlint/config-conventional": "^20.0.0",
77
77
  "@rollup/plugin-alias": "^5.1.1",
@@ -84,17 +84,17 @@
84
84
  "@semantic-release/commit-analyzer": "^13.0.1",
85
85
  "@semantic-release/git": "^10.0.1",
86
86
  "@semantic-release/github": "^12.0.0",
87
- "@semantic-release/npm": "^13.0.0",
87
+ "@semantic-release/npm": "^13.1.1",
88
88
  "@semantic-release/release-notes-generator": "^14.1.0",
89
89
  "@types/core-js": "^2.5.8",
90
- "@types/node": "^24.8.0",
90
+ "@types/node": "^24.9.1",
91
91
  "conventional-changelog-cli": "^5.0.0",
92
92
  "husky": "^9.1.7",
93
93
  "process": "^0.11.10",
94
- "rollup": "^4.52.4",
94
+ "rollup": "^4.52.5",
95
95
  "rollup-obfuscator": "^4.1.1",
96
96
  "rollup-plugin-typescript2": "^0.36.0",
97
- "semantic-release": "^24.2.9",
97
+ "semantic-release": "^25.0.1",
98
98
  "ts-node": "^10.9.2",
99
99
  "typescript": "^5.9.3"
100
100
  },