@liquidcommerce/elements-sdk 2.7.24 → 2.7.26

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.
Files changed (91) hide show
  1. package/README.md +20 -4
  2. package/dist/index.checkout.esm.js +8435 -7152
  3. package/dist/index.esm.js +13789 -11658
  4. package/dist/types/core/a11y/announcer.service.d.ts +16 -0
  5. package/dist/types/core/a11y/focus-manager.service.d.ts +21 -0
  6. package/dist/types/core/a11y/focusable.d.ts +5 -0
  7. package/dist/types/core/a11y/glyph-button.d.ts +8 -0
  8. package/dist/types/core/a11y/index.d.ts +5 -0
  9. package/dist/types/core/a11y/single-select.d.ts +16 -0
  10. package/dist/types/core/base-component.service.d.ts +2 -0
  11. package/dist/types/core/google-tag-manager.service.d.ts +1 -0
  12. package/dist/types/interfaces/configs/global.interface.d.ts +2 -0
  13. package/dist/types/modules/address/address-display.component.d.ts +3 -1
  14. package/dist/types/modules/address/address-input.component.d.ts +10 -1
  15. package/dist/types/modules/cart/components/cart-body.component.d.ts +1 -0
  16. package/dist/types/modules/cart/components/cart-item-quantity-price.component.d.ts +5 -0
  17. package/dist/types/modules/cart/components/cart-item.component.d.ts +6 -0
  18. package/dist/types/modules/checkout/components/checkout-completed.component.d.ts +2 -0
  19. package/dist/types/modules/checkout/components/checkout-item-quantity.component.d.ts +1 -0
  20. package/dist/types/modules/checkout/components/checkout-payment.component.d.ts +1 -0
  21. package/dist/types/modules/checkout/components/checkout-place-order-button.component.d.ts +2 -0
  22. package/dist/types/modules/product/components/components.d.ts +6 -1
  23. package/dist/types/modules/product/components/product-add-to-cart-section.component.d.ts +6 -1
  24. package/dist/types/modules/product/components/product-drawer.component.d.ts +6 -0
  25. package/dist/types/modules/product/components/product-image-carousel.component.d.ts +1 -0
  26. package/dist/types/modules/product/components/product-retailers-carousel.component.d.ts +1 -0
  27. package/dist/types/modules/product/components/product-retailers-popup-list.component.d.ts +5 -0
  28. package/dist/types/modules/product/product.commands.d.ts +2 -2
  29. package/dist/types/modules/product-list/components/card-components/product-price-and-personalization.d.ts +2 -1
  30. package/dist/types/modules/product-list/components/card-components/product-quantity-selector.d.ts +2 -1
  31. package/dist/types/modules/product-list/components/card-components/product-sizes-list.d.ts +1 -0
  32. package/dist/types/modules/product-list/components/filter-components/product-list-fulfillment-filter.d.ts +1 -0
  33. package/dist/types/modules/product-list/components/product-list-filters.component.d.ts +1 -0
  34. package/dist/types/modules/product-list/components/product-list-product-pre-cart.component.d.ts +2 -0
  35. package/dist/types/modules/product-list/product-list.commands.d.ts +1 -1
  36. package/dist/types/modules/product-list/product-list.component.d.ts +3 -0
  37. package/dist/types/modules/theme-provider/services/contrast-guard.service.d.ts +19 -0
  38. package/dist/types/modules/ui-components/alert/alert.component.d.ts +1 -1
  39. package/dist/types/modules/ui-components/buttons/buttons-open-cart.component.d.ts +5 -0
  40. package/dist/types/modules/ui-components/drawer/drawer.component.d.ts +14 -0
  41. package/dist/types/modules/ui-components/engraving/engraving-form.component.d.ts +2 -0
  42. package/dist/types/modules/ui-components/engraving/engraving-view.component.d.ts +1 -0
  43. package/dist/types/modules/ui-components/input/input.component.d.ts +5 -0
  44. package/dist/types/modules/ui-components/lce-element/lce-element.component.d.ts +9 -1
  45. package/dist/types/modules/ui-components/ui.commands.d.ts +3 -1
  46. package/dist/types/static/icon/arrow-right.icon.d.ts +1 -1
  47. package/dist/types/static/icon/bag.icon.d.ts +1 -1
  48. package/dist/types/static/icon/check.icon.d.ts +1 -1
  49. package/dist/types/static/icon/checkbox.icon.d.ts +1 -1
  50. package/dist/types/static/icon/chevron-down.icon.d.ts +1 -1
  51. package/dist/types/static/icon/chevron-left.icon.d.ts +1 -1
  52. package/dist/types/static/icon/chevron-up.icon.d.ts +1 -1
  53. package/dist/types/static/icon/close.icon.d.ts +1 -1
  54. package/dist/types/static/icon/error-info.icon.d.ts +1 -1
  55. package/dist/types/static/icon/filter.icon.d.ts +1 -1
  56. package/dist/types/static/icon/icon.a11y.d.ts +1 -0
  57. package/dist/types/static/icon/icon.types.d.ts +1 -0
  58. package/dist/types/static/icon/index.d.ts +1 -0
  59. package/dist/types/static/icon/info.icon.d.ts +1 -1
  60. package/dist/types/static/icon/loading-spinner.icon.d.ts +1 -1
  61. package/dist/types/static/icon/search.icon.d.ts +1 -1
  62. package/dist/types/static/icon/success.icon.d.ts +1 -1
  63. package/dist/types/static/icon/trash.icon.d.ts +1 -1
  64. package/dist/types/static/icon/warning.icon.d.ts +1 -1
  65. package/dist/types/utils/color-contrast.d.ts +16 -0
  66. package/docs/v1/README.md +3 -0
  67. package/docs/v1/api/actions/address-actions.md +1 -1
  68. package/docs/v1/api/actions/cart-actions.md +9 -2
  69. package/docs/v1/api/actions/checkout-actions.md +2 -0
  70. package/docs/v1/api/client.md +88 -9
  71. package/docs/v1/api/configuration.md +23 -0
  72. package/docs/v1/api/typescript-types.md +5 -1
  73. package/docs/v1/api/ui-helpers.md +2 -2
  74. package/docs/v1/getting-started/concepts.md +29 -10
  75. package/docs/v1/getting-started/installation.md +23 -2
  76. package/docs/v1/getting-started/quick-start.md +8 -3
  77. package/docs/v1/guides/accessibility.md +190 -0
  78. package/docs/v1/guides/address-component.md +3 -3
  79. package/docs/v1/guides/best-practices.md +1 -1
  80. package/docs/v1/guides/cart-component.md +35 -3
  81. package/docs/v1/guides/events.md +18 -5
  82. package/docs/v1/guides/product-component.md +6 -2
  83. package/docs/v1/guides/product-list-component.md +4 -5
  84. package/docs/v1/guides/theming.md +16 -1
  85. package/docs/v1/integration/vanilla-js.md +1 -1
  86. package/docs/v1/reference/analytics.md +108 -0
  87. package/docs/v1/reference/browser-support.md +3 -1
  88. package/docs/v1/reference/error-handling.md +9 -1
  89. package/docs/v1/reference/telemetry.md +85 -0
  90. package/docs/v1/reference/troubleshooting.md +1 -2
  91. package/package.json +44 -15
@@ -1,2 +1,2 @@
1
1
  import type { IconProps } from './icon.types';
2
- export declare const CloseIcon: ({ width, height, className, color }: IconProps) => string;
2
+ export declare const CloseIcon: ({ width, height, className, color, label }: IconProps) => string;
@@ -1,2 +1,2 @@
1
1
  import type { IconProps } from './icon.types';
2
- export declare const ErrorInfoIcon: ({ width, height, className, color }: IconProps) => string;
2
+ export declare const ErrorInfoIcon: ({ width, height, className, color, label }: IconProps) => string;
@@ -1,2 +1,2 @@
1
1
  import type { IconProps } from './icon.types';
2
- export declare const FilterIcon: ({ width, height, className, color }: IconProps) => string;
2
+ export declare const FilterIcon: ({ width, height, className, color, label }: IconProps) => string;
@@ -0,0 +1 @@
1
+ export declare function iconA11yAttributes(label?: string): string;
@@ -3,4 +3,5 @@ export interface IconProps {
3
3
  height?: number;
4
4
  className?: string;
5
5
  color?: string | null;
6
+ label?: string;
6
7
  }
@@ -7,6 +7,7 @@ export * from './chevron-left.icon';
7
7
  export * from './chevron-up.icon';
8
8
  export * from './close.icon';
9
9
  export * from './error-info.icon';
10
+ export * from './icon.a11y';
10
11
  export * from './icon.types';
11
12
  export * from './info.icon';
12
13
  export * from './loading-spinner.icon';
@@ -1,2 +1,2 @@
1
1
  import type { IconProps } from './icon.types';
2
- export declare const InfoIcon: ({ width, height, className, color }: IconProps) => string;
2
+ export declare const InfoIcon: ({ width, height, className, color, label }: IconProps) => string;
@@ -1,2 +1,2 @@
1
1
  import type { IconProps } from './icon.types';
2
- export declare const LoadingSpinnerIcon: ({ width, height, className, color }: IconProps) => string;
2
+ export declare const LoadingSpinnerIcon: ({ width, height, className, color, label }: IconProps) => string;
@@ -1,2 +1,2 @@
1
1
  import type { IconProps } from './icon.types';
2
- export declare const SearchIcon: ({ width, height, className, color }: IconProps) => string;
2
+ export declare const SearchIcon: ({ width, height, className, color, label }: IconProps) => string;
@@ -1,2 +1,2 @@
1
1
  import type { IconProps } from './icon.types';
2
- export declare const SuccessIcon: ({ width, height, className, color }: IconProps) => string;
2
+ export declare const SuccessIcon: ({ width, height, className, color, label }: IconProps) => string;
@@ -1,2 +1,2 @@
1
1
  import type { IconProps } from './icon.types';
2
- export declare const TrashIcon: ({ width, height, className, color }: IconProps) => string;
2
+ export declare const TrashIcon: ({ width, height, className, color, label }: IconProps) => string;
@@ -1,2 +1,2 @@
1
1
  import type { IconProps } from './icon.types';
2
- export declare const WarningIcon: ({ width, height, className, color }: IconProps) => string;
2
+ export declare const WarningIcon: ({ width, height, className, color, label }: IconProps) => string;
@@ -0,0 +1,16 @@
1
+ export interface IRgbColor {
2
+ r: number;
3
+ g: number;
4
+ b: number;
5
+ a: number;
6
+ }
7
+ export declare const TEXT_CONTRAST_MIN = 4.5;
8
+ export declare const NON_TEXT_CONTRAST_MIN = 3;
9
+ export declare function parseColor(value: string | null | undefined): IRgbColor | null;
10
+ export declare function toHexColor({ r, g, b }: IRgbColor): string;
11
+ export declare function compositeOver(foreground: IRgbColor, background: IRgbColor): IRgbColor;
12
+ export declare function relativeLuminance({ r, g, b }: IRgbColor): number;
13
+ export declare function contrastRatio(foreground: IRgbColor, background: IRgbColor): number;
14
+ export declare function meetsContrast(foreground: IRgbColor, background: IRgbColor, minRatio: number): boolean;
15
+ export declare function ensureContrast(foreground: IRgbColor, background: IRgbColor, minRatio: number): IRgbColor;
16
+ export declare function ensureContrastAgainstAll(foreground: IRgbColor, backgrounds: IRgbColor[], minRatio: number): IRgbColor;
package/docs/v1/README.md CHANGED
@@ -32,6 +32,7 @@ In-depth guides for each major component:
32
32
  - **[Address Component](./guides/address-component.md)** - Delivery location management
33
33
  - **[Product List Component](./guides/product-list-component.md)** - Filterable product catalogs
34
34
  - **[Theming](./guides/theming.md)** - Customize appearance and branding
35
+ - **[Accessibility](./guides/accessibility.md)** - Keyboard, screen reader, contrast and focus behaviour
35
36
  - **[Events](./guides/events.md)** - Event system and subscriptions
36
37
  - **[Best Practices](./guides/best-practices.md)** - Patterns, tips, and recommendations
37
38
 
@@ -83,6 +84,8 @@ Technical reference and troubleshooting:
83
84
  - **[Troubleshooting](./reference/troubleshooting.md)** - Common issues and solutions
84
85
  - **[Error Handling](./reference/error-handling.md)** - Error types and debugging
85
86
  - **[Performance](./reference/performance.md)** - Optimization tips and best practices
87
+ - **[Analytics](./reference/analytics.md)** - Google Tag Manager / GA4 integration
88
+ - **[Telemetry](./reference/telemetry.md)** - What the SDK reports and how to control it
86
89
 
87
90
  ### Examples
88
91
 
@@ -275,7 +275,7 @@ window.addEventListener('lce:actions.client_ready', () => {
275
275
  // Prompt for address on first visit
276
276
  showAddressModal();
277
277
  }
278
- });
278
+ }, { once: true });
279
279
  ```
280
280
 
281
281
  ## See Also
@@ -169,11 +169,16 @@ applyPromoCode(promoCode: string): Promise<void>
169
169
  ### Example
170
170
 
171
171
  ```javascript
172
+ // Listen for the outcome — an invalid code surfaces here, not as a rejection
173
+ window.addEventListener('lce:actions.cart_promo_code_failed', (event) => {
174
+ console.error('Invalid promo code:', event.detail.data);
175
+ });
176
+
172
177
  try {
173
178
  await window.LiquidCommerce.elements.actions.cart.applyPromoCode('SUMMER20');
174
- console.log('Promo code applied successfully');
175
179
  } catch (error) {
176
- console.error('Invalid promo code:', error);
180
+ // Only reached on unexpected errors, not for an invalid code
181
+ console.error('Failed to apply promo code:', error);
177
182
  }
178
183
  ```
179
184
 
@@ -183,6 +188,8 @@ try {
183
188
  - Promo codes must be enabled in configuration
184
189
  - Only one promo code can be active at a time
185
190
  - Applying a new code replaces the existing one
191
+ - An invalid/rejected code does **not** reject the promise — the failure is surfaced via the `lce:actions.cart_promo_code_failed` event. Listen for that event to handle invalid codes.
192
+ - An empty or whitespace-only code is a silent no-op: it sets a `cart.error` on the store and returns without throwing.
186
193
 
187
194
  ---
188
195
 
@@ -4,6 +4,8 @@ Checkout actions allow you to programmatically control the checkout flow.
4
4
 
5
5
  ## Navigation Actions
6
6
 
7
+ > **Note:** `openCheckout()`, `closeCheckout()`, and `toggleCheckout()` are only available on the full `Elements()` client's `actions.checkout`. They are **not** present on the checkout-only client (`ElementsCheckout()`), whose `actions.checkout` is typed `IElementsCheckoutActions = Omit<ICheckoutActions, 'openCheckout' | 'closeCheckout' | 'toggleCheckout'>`. The remaining checkout actions are available on both clients.
8
+
7
9
  ### actions.checkout.openCheckout()
8
10
 
9
11
  ```typescript
@@ -11,7 +11,7 @@ Initialize the full SDK client.
11
11
  ```typescript
12
12
  function Elements(
13
13
  apiKey: string,
14
- config: ILiquidCommerceElementsConfig
14
+ config?: ILiquidCommerceElementsConfig
15
15
  ): Promise<ILiquidCommerceElementsClient | null>
16
16
  ```
17
17
 
@@ -20,7 +20,7 @@ function Elements(
20
20
  | Parameter | Type | Required | Description |
21
21
  |-----------|-------------------------------|----------|-----------------------------|
22
22
  | `apiKey` | string | Yes | Your LiquidCommerce API key |
23
- | `config` | ILiquidCommerceElementsConfig | Yes | Configuration object |
23
+ | `config` | ILiquidCommerceElementsConfig | No | Configuration object |
24
24
 
25
25
  **Returns:** Promise that resolves to the client instance, or `null` if initialization fails.
26
26
 
@@ -43,7 +43,7 @@ Initialize the checkout-only client (tree-shaken build).
43
43
  ```typescript
44
44
  function ElementsCheckout(
45
45
  apiKey: string,
46
- config: ILiquidCommerceElementsCheckoutClientConfig
46
+ config?: ILiquidCommerceElementsCheckoutClientConfig
47
47
  ): Promise<IElementsCheckoutClient | null>
48
48
  ```
49
49
 
@@ -52,7 +52,7 @@ function ElementsCheckout(
52
52
  | Parameter | Type | Required | Description |
53
53
  |-----------|---------------------------------------------|----------|-----------------------------|
54
54
  | `apiKey` | string | Yes | Your LiquidCommerce API key |
55
- | `config` | ILiquidCommerceElementsCheckoutClientConfig | Yes | Checkout configuration |
55
+ | `config` | ILiquidCommerceElementsCheckoutClientConfig | No | Checkout configuration |
56
56
 
57
57
  **Example:**
58
58
 
@@ -71,7 +71,7 @@ Initialize the builder client, which exposes manual `inject*` / `update*` method
71
71
  ```typescript
72
72
  function ElementsBuilder(
73
73
  apiKey: string,
74
- config: ILiquidCommerceElementsBuilderConfig
74
+ config?: ILiquidCommerceElementsBuilderConfig
75
75
  ): Promise<ILiquidCommerceElementsBuilderClient | null>
76
76
  ```
77
77
 
@@ -80,7 +80,7 @@ function ElementsBuilder(
80
80
  | Parameter | Type | Required | Description |
81
81
  |-----------|--------------------------------------|----------|-----------------------------|
82
82
  | `apiKey` | string | Yes | Your LiquidCommerce API key |
83
- | `config` | ILiquidCommerceElementsBuilderConfig | Yes | Builder configuration object (same shape as `ILiquidCommerceElementsConfig`) |
83
+ | `config` | ILiquidCommerceElementsBuilderConfig | No | Builder configuration object (same shape as `ILiquidCommerceElementsConfig`) |
84
84
 
85
85
  **Returns:** Promise that resolves to the builder client instance (`ILiquidCommerceElementsBuilderClient`), or `null` if initialization fails or it is called outside the browser.
86
86
 
@@ -256,7 +256,7 @@ window.addEventListener('lce:actions.client_ready', ( event ) => {
256
256
 
257
257
  // Safe to use client
258
258
  window.LiquidCommerce.elements.injectProductElement([...]);
259
- });
259
+ }, { once: true });
260
260
  ```
261
261
 
262
262
  ## Client Interface
@@ -296,6 +296,84 @@ interface ILiquidCommerceElementsClient {
296
296
  }
297
297
  ```
298
298
 
299
+ ### ILiquidCommerceElementsBuilderClient
300
+
301
+ The builder client (returned by `ElementsBuilder()`) exposes the same `inject*` methods plus a set of `update*Component` methods for applying theme/layout changes at runtime:
302
+
303
+ ```typescript
304
+ interface ILiquidCommerceElementsBuilderClient {
305
+ // Runtime theme/layout updates (builder-only)
306
+ updateComponentGlobalConfigs(configs: UpdateComponentGlobalConfigs): Promise<void>;
307
+ updateProductComponent(configs: UpdateProductComponent): Promise<void>;
308
+ updateAddressComponent(configs: UpdateAddressComponent): void;
309
+ updateCartComponent(configs: UpdateCartComponent): void;
310
+ updateCheckoutComponent(configs: UpdateCheckoutComponent): void;
311
+ updateProductListComponent(configs: UpdateProductListComponent): void;
312
+
313
+ // Injection methods
314
+ injectElement(params: IBuilderInjectElementParams): Promise<IInjectedComponent | null>;
315
+ injectProductElement(params: IInjectProductElement[]): Promise<IInjectedComponent[]>;
316
+ injectAddressElement(containerId: string, options?: IAddressOptions): Promise<IInjectedComponent | null>;
317
+ injectCartElement(containerId: string): Promise<IInjectedComponent | null>;
318
+ injectCheckoutElement(params: IInjectCheckoutBuilderParams): Promise<IInjectedComponent | null>;
319
+ injectProductList(params: IInjectProductListParams): Promise<void>;
320
+
321
+ // Actions
322
+ actions: ILiquidCommerceElementsActions;
323
+
324
+ // Cleanup
325
+ destroy(): void;
326
+ }
327
+ ```
328
+
329
+ #### Runtime theme updates (`update*Component`)
330
+
331
+ These methods are **builder-only** — they exist on the client returned by `ElementsBuilder()` and are **not** available on the full `Elements()` client. Each method applies theme changes to its scope and, when the passed `configs` include a non-empty `layout`, triggers targeted rerenders of only the components affected by those layout fields.
332
+
333
+ Return types are not uniform:
334
+
335
+ - `updateComponentGlobalConfigs()` and `updateProductComponent()` return `Promise<void>` (they may await product rerenders) — `await` them.
336
+ - `updateCartComponent()`, `updateCheckoutComponent()`, `updateAddressComponent()`, and `updateProductListComponent()` return `void` (synchronous).
337
+
338
+ ```javascript
339
+ const builder = await ElementsBuilder('YOUR_API_KEY', { env: 'production' });
340
+
341
+ // Asynchronous — await these
342
+ await builder.updateComponentGlobalConfigs({
343
+ theme: { primaryColor: '#0a7d33', buttonCornerRadius: '8px' },
344
+ layout: { allowPromoCodes: true }
345
+ });
346
+ await builder.updateProductComponent({
347
+ theme: { backgroundColor: '#ffffff' },
348
+ layout: { addToCartButtonText: 'Add to bag' }
349
+ });
350
+
351
+ // Synchronous — no await needed
352
+ builder.updateCartComponent({ layout: { drawerHeaderText: 'Your bag' } });
353
+ builder.updateCheckoutComponent({ layout: { placeOrderButtonText: 'Pay now' } });
354
+ ```
355
+
356
+ #### injectCheckoutElement (builder)
357
+
358
+ The builder's `injectCheckoutElement()` accepts `IInjectCheckoutBuilderParams`, which extends `IInjectCheckoutParams` with two **preview-only** fields:
359
+
360
+ ```typescript
361
+ interface IInjectCheckoutBuilderParams extends IInjectCheckoutParams {
362
+ simulatePresale?: boolean; // simulate a presale lock in builder mode
363
+ presaleExpiresInMinutes?: number; // minutes until the simulated lock expires (defaults to 15)
364
+ }
365
+ ```
366
+
367
+ `simulatePresale` and `presaleExpiresInMinutes` only take effect in the builder preview and have no counterpart on the full `Elements()` client's `injectCheckoutElement()`.
368
+
369
+ ```javascript
370
+ await builder.injectCheckoutElement({
371
+ containerId: 'checkout',
372
+ simulatePresale: true,
373
+ presaleExpiresInMinutes: 30
374
+ });
375
+ ```
376
+
299
377
  ## Methods Overview
300
378
 
301
379
  ### Injection Methods
@@ -410,7 +488,8 @@ const config: ILiquidCommerceElementsConfig = {
410
488
  env: 'production'
411
489
  };
412
490
 
413
- const client: ILiquidCommerceElementsClient = await Elements('KEY', config);
491
+ // Elements() resolves to `null` on failure, so the type is nullable.
492
+ const client: ILiquidCommerceElementsClient | null = await Elements('KEY', config);
414
493
  ```
415
494
 
416
495
  ### Type Exports
@@ -488,7 +567,7 @@ if (window.LiquidCommerce?.elements) {
488
567
  // Wait for client ready
489
568
  window.addEventListener('lce:actions.client_ready', () => {
490
569
  window.LiquidCommerce.elements.actions.cart.openCart();
491
- });
570
+ }, { once: true });
492
571
  }
493
572
  ```
494
573
 
@@ -30,6 +30,8 @@ interface ILiquidCommerceElementsConfig {
30
30
  | `proxy` | `IElementsProxyConfig` | No | Proxy configuration for API requests |
31
31
  | `development` | `ILiquidCommerceElementsDevelopmentConfig` | No | Development/testing options |
32
32
 
33
+ > **Note:** `debugMode` (`'console'` or `'panel'`) is **ignored in production** -- it is forced off when `env` is `'production'`. It only takes effect in non-production environments (`'development'` / `'staging'`).
34
+
33
35
  ---
34
36
 
35
37
  ## Theme Configuration
@@ -72,9 +74,22 @@ interface IGlobalTheme {
72
74
  warningColor: string;
73
75
  successColor: string;
74
76
  drawerBackgroundColor: string;
77
+
78
+ /**
79
+ * Boundary color for form fields. Optional; defaults to a neutral that clears the 3:1
80
+ * contrast required by WCAG 1.4.11.
81
+ */
82
+ inputBorderColor?: string;
83
+
84
+ /** Keyboard focus ring color. Must reach 3:1 against the surface behind the control. */
85
+ focusRingColor?: string;
75
86
  }
76
87
  ```
77
88
 
89
+ > `inputBorderColor` and `focusRingColor` are optional. If you omit them — or supply a value that
90
+ > fails contrast — the runtime contrast guard substitutes a compliant color. Set them explicitly to
91
+ > keep those two details on-brand. See [Accessibility](../guides/accessibility.md).
92
+
78
93
  | Property | Type | Description |
79
94
  |----------|------|-------------|
80
95
  | `buttonCornerRadius` | `string` | CSS border-radius for buttons (e.g., `'8px'`) |
@@ -100,6 +115,8 @@ interface IFontFamily {
100
115
  }
101
116
  ```
102
117
 
118
+ > **Note:** Only Google Fonts are supported -- `name` must be a valid Google Fonts family. `Poppins` is always injected as the default font family in addition to any fonts you specify. Font loading requires network access to `fonts.googleapis.com` and `fonts.gstatic.com`; if you run behind a CSP or proxy, allow these hosts.
119
+
103
120
  #### IGlobalLayout
104
121
 
105
122
  ```typescript
@@ -109,6 +126,8 @@ interface IGlobalLayout {
109
126
  personalizationCardStyle: 'outlined' | 'filled';
110
127
  allowPromoCodes: boolean;
111
128
  inputFieldStyle: 'outlined' | 'filled';
129
+ enableOrderedProductSizes: boolean;
130
+ orderedProductSizes: string[];
112
131
  showPoweredBy: boolean;
113
132
  poweredByMode: 'light' | 'dark';
114
133
  }
@@ -121,9 +140,13 @@ interface IGlobalLayout {
121
140
  | `personalizationCardStyle` | `'outlined' \| 'filled'` | Visual style for personalization cards |
122
141
  | `allowPromoCodes` | `boolean` | Show promo code inputs in cart/checkout |
123
142
  | `inputFieldStyle` | `'outlined' \| 'filled'` | Visual style for input fields |
143
+ | `enableOrderedProductSizes` | `boolean` | Enable a fixed display order for product/PLC size selectors (defined by `orderedProductSizes`) instead of the default ordering |
144
+ | `orderedProductSizes` | `string[]` | Ordered list of size values controlling the sequence in which size selectors are rendered; changes trigger targeted rerenders of the affected size selectors |
124
145
  | `showPoweredBy` | `boolean` | Show "Powered by LiquidCommerce" badge |
125
146
  | `poweredByMode` | `'light' \| 'dark'` | Color mode for the powered-by badge |
126
147
 
148
+ > **Note:** `showPoweredBy` is a server/plan-controlled setting and **cannot** be overridden by hosts. Any value supplied via `customTheme` (or a later config update) is stripped and the server value is restored. Only `poweredByMode` (`'light' \| 'dark'`) is host-overridable.
149
+
127
150
  **Example:**
128
151
 
129
152
  ```javascript
@@ -178,6 +178,8 @@ interface IInjectCheckoutParams {
178
178
 
179
179
  ### IInjectCheckoutBuilderParams
180
180
 
181
+ `simulatePresale` and `presaleExpiresInMinutes` are builder-only preview controls (presale lock defaults to 15 minutes) and only take effect via `ElementsBuilder().injectCheckoutElement()`.
182
+
181
183
  ```typescript
182
184
  interface IInjectCheckoutBuilderParams extends IInjectCheckoutParams {
183
185
  simulatePresale?: boolean;
@@ -293,7 +295,7 @@ interface ILiquidCommerceElementsActions {
293
295
 
294
296
  ### IElementsCheckoutActions
295
297
 
296
- Checkout actions available in the checkout-only client. Omits drawer-related methods.
298
+ Checkout actions available in the checkout-only client. This is `ICheckoutActions` with `openCheckout`, `closeCheckout`, and `toggleCheckout` omitted -- the checkout-only client renders checkout independently and has no drawer navigation to open, close, or toggle.
297
299
 
298
300
  ```typescript
299
301
  interface IElementsCheckoutActions extends Omit<ICheckoutActions, 'openCheckout' | 'closeCheckout' | 'toggleCheckout'> {}
@@ -378,6 +380,8 @@ interface UpdateProductListComponent {
378
380
  }
379
381
  ```
380
382
 
383
+ These `Update*Component` types are the arguments to the `ElementsBuilder()` client's `update*Component` methods; see [Client API](./client.md) for their behavior and usage.
384
+
381
385
  See [Configuration Reference](./configuration.md) for detailed theme property descriptions.
382
386
 
383
387
  ---
@@ -136,7 +136,7 @@ window.LiquidCommerce.elements.ui.cartItemsCount('items-count', { hideZero: fals
136
136
  <script>
137
137
  window.addEventListener('lce:actions.client_ready', () => {
138
138
  window.LiquidCommerce.elements.ui.cartButton('cart-btn', true);
139
- });
139
+ }, { once: true });
140
140
  </script>
141
141
  ```
142
142
 
@@ -153,7 +153,7 @@ window.addEventListener('lce:actions.client_ready', () => {
153
153
  window.addEventListener('lce:actions.client_ready', () => {
154
154
  window.LiquidCommerce.elements.ui.cartItemsCount('item-count');
155
155
  window.LiquidCommerce.elements.ui.cartSubtotal('cart-total');
156
- });
156
+ }, { once: true });
157
157
  </script>
158
158
  ```
159
159
 
@@ -96,11 +96,11 @@ The SDK uses a two-phase initialization strategy for optimal performance:
96
96
  - Store initialization
97
97
  - Theme setup
98
98
  - Core component registration
99
- - Telemetry / logger wiring
99
+ - Telemetry / logger wiring (see [Telemetry & Privacy](../reference/telemetry.md))
100
100
  - Debug panel (if enabled)
101
101
 
102
102
  **Phase 2: Deferred Services (next macrotask, via `setTimeout(…, 0)`)**
103
- - Analytics (Google Tag Manager)
103
+ - Analytics (Google Tag Manager — see [Analytics (GTM/GA4)](../reference/analytics.md))
104
104
  - Cart pre-loading
105
105
  - Heavy component registration
106
106
 
@@ -117,7 +117,7 @@ window.addEventListener('lce:actions.client_ready', (event) => {
117
117
 
118
118
  // Safe to use client
119
119
  window.LiquidCommerce.elements.actions.cart.openCart();
120
- });
120
+ }, { once: true });
121
121
  ```
122
122
 
123
123
  ## Declarative vs Programmatic
@@ -197,7 +197,7 @@ window.addEventListener('lce:actions.client_ready', async () => {
197
197
  await window.LiquidCommerce.elements.injectProductElement([
198
198
  { containerId: 'dynamic-product', identifier: selectedProductId }
199
199
  ]);
200
- });
200
+ }, { once: true });
201
201
  </script>
202
202
  ```
203
203
 
@@ -327,20 +327,37 @@ The SDK is designed to fail gracefully and not crash your site.
327
327
 
328
328
  ### Error Isolation
329
329
 
330
- SDK errors are logged and also emitted as a `*_FAILED` event, then re-thrown so your code can catch them:
330
+ Most action failures are **not** thrown. Action methods take one of three paths, so `try/catch`
331
+ alone is not enough to detect failure:
332
+
333
+ | Situation | Behaviour |
334
+ |---|---|
335
+ | Malformed argument (missing `identifier`, invalid `fulfillmentType`, `quantity < 1`) | Throws `SDKError` — `try/catch` catches it |
336
+ | Empty array or no arguments | Logs a warning and **resolves**. No event, no throw. |
337
+ | Valid input that fails at runtime (product not found, unavailable variant, API error) | Publishes `lce:actions.cart_product_add_failed` and **resolves** |
338
+
339
+ So listen for the `*_failed` event **and** wrap the call in `try/catch`:
331
340
 
332
341
  ```javascript
333
- // The SDK emits CART_PRODUCT_ADD_FAILED and re-throws, so this catch runs
342
+ window.addEventListener('lce:actions.cart_product_add_failed', (event) => {
343
+ console.log('Add to cart failed:', event.detail.data);
344
+ });
345
+
334
346
  try {
335
- await window.LiquidCommerce.elements.actions.cart.addProduct([/* invalid data */]);
347
+ // Throws only if the argument itself is malformed.
348
+ await window.LiquidCommerce.elements.actions.cart.addProduct([
349
+ { identifier: '00619947000020', fulfillmentType: 'shipping', quantity: 1 }
350
+ ]);
336
351
  } catch (error) {
337
- console.log('This error is re-thrown by the SDK and caught here');
352
+ console.log('Malformed input rejected by the SDK');
338
353
  }
339
354
 
340
- // Your page keeps working
355
+ // Either way, your page keeps working
341
356
  console.log('Page still functional');
342
357
  ```
343
358
 
359
+ See [Error Handling](../reference/error-handling.md) for the full matrix.
360
+
344
361
  ### Error Types
345
362
 
346
363
  The SDK uses a custom `SDKError` class for all errors:
@@ -368,10 +385,12 @@ const client = await Elements('YOUR_API_KEY', {
368
385
  ```
369
386
 
370
387
  **Debug Modes:**
371
- - `'none'` - No debug output (production default)
388
+ - `'none'` - No debug output (default)
372
389
  - `'console'` - Log to browser console
373
390
  - `'panel'` - Show debug panel on page
374
391
 
392
+ > **Production note:** `debugMode` has no effect when `env` is `'production'`. All debug output — console logging and the debug panel — is disabled in production regardless of the `debugMode` you pass. `'console'` and `'panel'` only take effect in non-production environments.
393
+
375
394
  ## Security & API Keys
376
395
 
377
396
  ### API Key Protection
@@ -30,6 +30,16 @@ Add the following script tag to your page's `<head>` section:
30
30
  ></script>
31
31
  ```
32
32
 
33
+ > **Note:** The host `elements.reservebar-worker.workers.dev` shown above is an example, partner-specific endpoint. Use the CDN URL provided by your LiquidCommerce representative in place of this host.
34
+
35
+ The path segment selects which bundle is served:
36
+
37
+ | Path | Bundle |
38
+ |------|--------|
39
+ | `/all/elements.js` | Full SDK bundle (product, cart, checkout, and all other elements) |
40
+ | `/checkout/checkout.js` | Checkout-only bundle (tree-shaken, smaller) |
41
+ | `/all/beta/elements.js` | Beta channel of the full SDK bundle |
42
+
33
43
  ### Script Attributes
34
44
 
35
45
  | Attribute | Required | Description |
@@ -77,7 +87,7 @@ If you only need checkout functionality (without product displays or cart), use
77
87
  data-token="YOUR_API_KEY"
78
88
  data-env="production"
79
89
  type="text/javascript"
80
- src="https://elements.reservebar-worker.workers.dev/checkout/elements.js"
90
+ src="https://elements.reservebar-worker.workers.dev/checkout/checkout.js"
81
91
  ></script>
82
92
  ```
83
93
 
@@ -140,7 +150,16 @@ const config: ILiquidCommerceElementsConfig = {
140
150
  }
141
151
  };
142
152
 
143
- const client: ILiquidCommerceElementsClient = await Elements('YOUR_API_KEY', config);
153
+ // Elements() returns `null` in SSR / non-browser environments, so the
154
+ // client is typed as `ILiquidCommerceElementsClient | null`.
155
+ const client: ILiquidCommerceElementsClient | null = await Elements('YOUR_API_KEY', config);
156
+
157
+ if (client) {
158
+ // Safe to use the client here
159
+ client.injectProductElement([
160
+ { containerId: 'product-1', identifier: '00619947000020' }
161
+ ]);
162
+ }
144
163
  ```
145
164
 
146
165
  ## Framework Integration
@@ -255,6 +274,8 @@ const client = await Elements('YOUR_API_KEY', {
255
274
  });
256
275
  ```
257
276
 
277
+ > **Note:** `debugMode` is ignored when `env` is `'production'`. Debug logging and the debug panel are only activated in non-production environments (`development` or `staging`).
278
+
258
279
  See [Configuration Reference](../api/configuration.md) for complete configuration options.
259
280
 
260
281
  ## Verification
@@ -165,7 +165,7 @@ If you prefer JavaScript over HTML attributes:
165
165
  identifier: '00619947000020'
166
166
  }
167
167
  ]);
168
- });
168
+ }, { once: true });
169
169
  </script>
170
170
  </head>
171
171
  <body>
@@ -181,10 +181,15 @@ Or with NPM:
181
181
  import { Elements } from '@liquidcommerce/elements-sdk';
182
182
 
183
183
  async function initProduct() {
184
+ // Elements() resolves to `null` if initialization fails — it never throws.
184
185
  const client = await Elements('YOUR_API_KEY', {
185
186
  env: 'production'
186
187
  });
187
-
188
+
189
+ if (!client) {
190
+ return;
191
+ }
192
+
188
193
  await client.injectProductElement([
189
194
  {
190
195
  containerId: 'product-display',
@@ -256,7 +261,7 @@ window.addEventListener('lce:actions.client_ready', async () => {
256
261
 
257
262
  // You can customize after initialization
258
263
  // See Theming Guide for more options
259
- });
264
+ }, { once: true });
260
265
  </script>
261
266
  ```
262
267