@liquidcommerce/elements-sdk 2.7.43 → 2.7.45
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 +5 -3
- package/dist/index.checkout.esm.js +10921 -8952
- package/dist/index.esm.js +15834 -13867
- package/dist/ssr-stub.esm.js +3 -0
- package/dist/types/core/a11y/focus-manager.service.d.ts +1 -1
- package/dist/types/core/api/api-result.d.ts +3 -0
- package/dist/types/core/client/actions/client-analytics-action.service.d.ts +35 -0
- package/dist/types/core/client/actions/client-checkout-action.service.d.ts +6 -0
- package/dist/types/core/client/client-action.service.d.ts +1 -0
- package/dist/types/core/client/client-config.service.d.ts +2 -0
- package/dist/types/core/google-tag-manager.service.d.ts +3 -2
- package/dist/types/core/pubsub/interfaces/checkout.interface.d.ts +6 -0
- package/dist/types/core/pubsub/interfaces/core.interface.d.ts +3 -1
- package/dist/types/core/store/interfaces/checkout.interface.d.ts +4 -0
- package/dist/types/enums/core.enum.d.ts +3 -0
- package/dist/types/index.checkout.d.ts +4 -2
- package/dist/types/index.d.ts +1 -0
- package/dist/types/interfaces/analytics.interface.d.ts +41 -0
- package/dist/types/interfaces/api/cart.interface.d.ts +2 -0
- package/dist/types/interfaces/api/checkout.interface.d.ts +7 -1
- package/dist/types/interfaces/api/delivery.interface.d.ts +24 -0
- package/dist/types/interfaces/api/index.d.ts +1 -0
- package/dist/types/interfaces/api/product.interface.d.ts +2 -0
- package/dist/types/interfaces/client.interface.d.ts +5 -0
- package/dist/types/interfaces/config.interface.d.ts +1 -0
- package/dist/types/modules/cart/cart.commands.d.ts +3 -1
- package/dist/types/modules/cart/components/cart-item.component.d.ts +2 -0
- package/dist/types/modules/checkout/checkout.commands.d.ts +41 -0
- package/dist/types/modules/checkout/components/checkout-completed.component.d.ts +4 -0
- package/dist/types/modules/checkout/components/checkout-delivery-method.component.d.ts +2 -0
- package/dist/types/modules/checkout/components/checkout-delivery-scheduling.component.d.ts +53 -0
- package/dist/types/modules/checkout/components/checkout-express-checkout.component.d.ts +3 -0
- package/dist/types/modules/checkout/components/checkout-item.component.d.ts +2 -0
- package/dist/types/modules/checkout/components/checkout-payment.component.d.ts +3 -0
- package/dist/types/modules/checkout/components/index.d.ts +1 -0
- package/dist/types/modules/product-list/product-list.commands.d.ts +5 -0
- package/dist/types/ssr/stub.checkout.d.ts +3 -1
- package/dist/types/ssr/stub.d.ts +3 -1
- package/dist/types/utils/delivery-scheduling.d.ts +75 -0
- package/dist/types/utils/fulfillment-unavailable.d.ts +8 -0
- package/docs/v1/README.md +1 -0
- package/docs/v1/api/actions/analytics-actions.md +326 -0
- package/docs/v1/api/actions/checkout-actions.md +47 -2
- package/docs/v1/api/actions/product-actions.md +1 -0
- package/docs/v1/api/client.md +9 -2
- package/docs/v1/api/configuration.md +4 -0
- package/docs/v1/api/typescript-types.md +110 -1
- package/docs/v1/guides/accessibility.md +8 -1
- package/docs/v1/guides/cart-component.md +2 -0
- package/docs/v1/guides/checkout-component.md +64 -2
- package/docs/v1/guides/events.md +36 -2
- package/docs/v1/guides/product-component.md +6 -0
- package/docs/v1/reference/analytics.md +52 -9
- package/package.json +4 -4
|
@@ -155,6 +155,7 @@ interface IFulfillment {
|
|
|
155
155
|
fee: number;
|
|
156
156
|
timezone: string;
|
|
157
157
|
hourStatus: { isOpen: boolean; openTime: string; isClosed: boolean; closeTime: string };
|
|
158
|
+
deliveryAvailability?: DeliveryAvailability; // same-day only, where the retailer schedules delivery
|
|
158
159
|
}
|
|
159
160
|
|
|
160
161
|
interface IProduct {
|
package/docs/v1/api/client.md
CHANGED
|
@@ -64,8 +64,10 @@ const client = await ElementsCheckout('YOUR_API_KEY', {
|
|
|
64
64
|
});
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
-
The checkout-only client exposes `injectCheckout()`, `injectExpressCheckout()`, `actions.checkout
|
|
68
|
-
and `destroy()`.
|
|
67
|
+
The checkout-only client exposes `injectCheckout()`, `injectExpressCheckout()`, `actions.checkout`,
|
|
68
|
+
`actions.analytics` and `destroy()`. `actions.analytics` reports the steps your own UI renders —
|
|
69
|
+
product views, address, availability, starting checkout — to the same GTM stream the checkout
|
|
70
|
+
reports to; see [Analytics Actions](./actions/analytics-actions.md).
|
|
69
71
|
|
|
70
72
|
#### injectExpressCheckout()
|
|
71
73
|
|
|
@@ -73,6 +75,9 @@ Injects only the Apple Pay and Google Pay wallet buttons, anywhere on the page,
|
|
|
73
75
|
the checkout UI. Confirming the wallet sheet places the order outright — the wallet's contact and
|
|
74
76
|
billing details are sent to the checkout, so the shopper never fills a checkout form.
|
|
75
77
|
|
|
78
|
+
Express checkout is off by default: pass `development.enableExpressCheckout: true` in the client config to show it. Without it this
|
|
79
|
+
method renders nothing and resolves to `null`.
|
|
80
|
+
|
|
76
81
|
```typescript
|
|
77
82
|
injectExpressCheckout(params: IInjectExpressCheckoutParams): Promise<IInjectedComponent | null>
|
|
78
83
|
```
|
|
@@ -591,6 +596,8 @@ import type {
|
|
|
591
596
|
} from '@liquidcommerce/elements-sdk';
|
|
592
597
|
```
|
|
593
598
|
|
|
599
|
+
Both package entries, including their Node/SSR stubs, export `DeliverySlot`, `DeliveryAvailability`, `CheckoutDeliveryScheduling` and `CheckoutDeliverySelection`. Both clients expose `actions.checkout.loadDeliverySlots(fulfillmentId)` and `actions.checkout.chooseDeliverySlot(fulfillmentId, slotId)`.
|
|
600
|
+
|
|
594
601
|
See [TypeScript Types](./typescript-types.md) for complete type reference.
|
|
595
602
|
|
|
596
603
|
## Best Practices
|
|
@@ -563,6 +563,7 @@ interface ILiquidCommerceElementsDevelopmentConfig {
|
|
|
563
563
|
customApiUrl?: string;
|
|
564
564
|
openShadowDom?: boolean;
|
|
565
565
|
mockMode?: boolean;
|
|
566
|
+
enableExpressCheckout?: boolean;
|
|
566
567
|
}
|
|
567
568
|
```
|
|
568
569
|
|
|
@@ -571,6 +572,9 @@ interface ILiquidCommerceElementsDevelopmentConfig {
|
|
|
571
572
|
| `customApiUrl` | `string` | Custom API URL for local or custom backend testing |
|
|
572
573
|
| `openShadowDom` | `boolean` | Use an OPEN (inspectable) Shadow DOM instead of the default closed mode, for debugging. Shadow DOM is always attached; forced off in production (default: `false`) |
|
|
573
574
|
| `mockMode` | `boolean` | Enable mock mode to receive mock data from the API; sends an `X-Liquid-Api-Mock-Mode` header with all requests (default: `false`) |
|
|
575
|
+
| `enableExpressCheckout` | `boolean` | Show the Apple Pay / Google Pay express checkout and the checkout's delivery-method switch (same-day vs shipping) — the express block and delivery-method section in the checkout element, and `injectExpressCheckoutElement()` / `injectExpressCheckout()`, which otherwise render nothing and resolve to `null`. Honoured in every environment, production included (default: `false`) |
|
|
576
|
+
|
|
577
|
+
> **Temporary:** this flag exists only while express checkout and the delivery-method switch are being verified. Once they are confirmed, the flag will be removed and both will always be on.
|
|
574
578
|
|
|
575
579
|
> To pre-select a payment method and skip the card form (in any environment), use [`actions.checkout.setSavedPaymentMethod`](./actions/checkout-actions.md#actionscheckoutsetsavedpaymentmethod) instead.
|
|
576
580
|
|
|
@@ -21,6 +21,8 @@ import { ElementsCheckout } from '@liquidcommerce/elements-sdk/checkout';
|
|
|
21
21
|
import type {
|
|
22
22
|
IElementsCheckoutClient,
|
|
23
23
|
IElementsCheckoutActions,
|
|
24
|
+
IAnalyticsActions,
|
|
25
|
+
IAnalyticsItem,
|
|
24
26
|
ILiquidCommerceElementsCheckoutClientConfig,
|
|
25
27
|
IInjectedComponent
|
|
26
28
|
} from '@liquidcommerce/elements-sdk/checkout';
|
|
@@ -81,7 +83,7 @@ Checkout-only client interface returned by `ElementsCheckout()`.
|
|
|
81
83
|
interface IElementsCheckoutClient {
|
|
82
84
|
injectCheckout(params: IInjectCheckoutParams): Promise<IInjectedComponent | null>;
|
|
83
85
|
injectExpressCheckout(params: IInjectExpressCheckoutParams): Promise<IInjectedComponent | null>;
|
|
84
|
-
actions: { checkout: IElementsCheckoutActions };
|
|
86
|
+
actions: { checkout: IElementsCheckoutActions; analytics: IAnalyticsActions };
|
|
85
87
|
destroy(): void;
|
|
86
88
|
}
|
|
87
89
|
|
|
@@ -158,6 +160,7 @@ interface ILiquidCommerceElementsDevelopmentConfig {
|
|
|
158
160
|
customApiUrl?: string;
|
|
159
161
|
openShadowDom?: boolean;
|
|
160
162
|
mockMode?: boolean; // when true, sends an 'X-Liquid-Api-Mock-Mode' header to receive mock data
|
|
163
|
+
enableExpressCheckout?: boolean; // show express checkout and the delivery-method switch; off by default, honoured in production
|
|
161
164
|
}
|
|
162
165
|
```
|
|
163
166
|
|
|
@@ -309,6 +312,7 @@ interface ILiquidCommerceElementsActions {
|
|
|
309
312
|
address: IAddressActions;
|
|
310
313
|
cart: ICartActions;
|
|
311
314
|
checkout: ICheckoutActions;
|
|
315
|
+
analytics: IAnalyticsActions;
|
|
312
316
|
}
|
|
313
317
|
```
|
|
314
318
|
|
|
@@ -320,6 +324,74 @@ Checkout actions available in the checkout-only client. This is `ICheckoutAction
|
|
|
320
324
|
interface IElementsCheckoutActions extends Omit<ICheckoutActions, 'openCheckout' | 'closeCheckout' | 'toggleCheckout'> {}
|
|
321
325
|
```
|
|
322
326
|
|
|
327
|
+
### IAnalyticsActions
|
|
328
|
+
|
|
329
|
+
Reports steps a host renders with its own UI to the SDK's GTM / GA4 stream. On both the full client
|
|
330
|
+
and the checkout-only client. See [Analytics Actions](./actions/analytics-actions.md).
|
|
331
|
+
|
|
332
|
+
```typescript
|
|
333
|
+
interface IAnalyticsActions {
|
|
334
|
+
search(searchTerm: string): void;
|
|
335
|
+
viewItem(item: IAnalyticsItem): void;
|
|
336
|
+
viewItemList(items: IAnalyticsItem[], list?: IAnalyticsItemList): void;
|
|
337
|
+
selectItem(item: IAnalyticsItem, list?: IAnalyticsItemList): void;
|
|
338
|
+
addToCart(item: IAnalyticsItem): void;
|
|
339
|
+
removeFromCart(item: IAnalyticsItem): void;
|
|
340
|
+
viewCart(items: IAnalyticsItem[]): void;
|
|
341
|
+
beginCheckout(items: IAnalyticsItem[], options?: { coupon?: string }): void;
|
|
342
|
+
addressUpdated(address: IAnalyticsAddress): void;
|
|
343
|
+
addressFailed(failure: IAnalyticsAddressFailure): void;
|
|
344
|
+
productNoAvailability(details: IAnalyticsAvailability): void;
|
|
345
|
+
productSizeNoAvailability(details: IAnalyticsAvailability): void;
|
|
346
|
+
productFulfillmentNoAvailability(details: IAnalyticsFulfillmentAvailability): void;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
interface IAnalyticsItem {
|
|
350
|
+
id: string; // the selected size's id
|
|
351
|
+
name: string;
|
|
352
|
+
brand?: string;
|
|
353
|
+
size?: string;
|
|
354
|
+
categoryPath?: string; // product catPath
|
|
355
|
+
price?: number; // cents
|
|
356
|
+
quantity?: number;
|
|
357
|
+
type?: string;
|
|
358
|
+
subType?: string;
|
|
359
|
+
image?: string;
|
|
360
|
+
upc?: string;
|
|
361
|
+
groupingId?: string;
|
|
362
|
+
index?: number;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
interface IAnalyticsItemList {
|
|
366
|
+
id?: string;
|
|
367
|
+
name?: string;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
interface IAnalyticsAddress {
|
|
371
|
+
placesId?: string;
|
|
372
|
+
formattedAddress?: string;
|
|
373
|
+
address: Partial<IAddressAddress>;
|
|
374
|
+
coordinates?: IAddressCoordinates;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
interface IAnalyticsAddressFailure {
|
|
378
|
+
placesId?: string;
|
|
379
|
+
formattedAddress?: string;
|
|
380
|
+
address?: Partial<IAddressAddress>;
|
|
381
|
+
error: string;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
interface IAnalyticsAvailability {
|
|
385
|
+
item: IAnalyticsItem;
|
|
386
|
+
reason: string;
|
|
387
|
+
address?: Partial<IAddressAddress>;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
interface IAnalyticsFulfillmentAvailability extends IAnalyticsAvailability {
|
|
391
|
+
fulfillmentType: FulfillmentType;
|
|
392
|
+
}
|
|
393
|
+
```
|
|
394
|
+
|
|
323
395
|
See [Actions API](./actions/) for detailed method signatures.
|
|
324
396
|
|
|
325
397
|
---
|
|
@@ -353,6 +425,7 @@ type ComponentType =
|
|
|
353
425
|
| 'drawer' | 'input' | 'engraving-form' | 'engraving-view'
|
|
354
426
|
| 'buttons-cart-open' | 'powered-by' | 'lce-element'
|
|
355
427
|
| 'purchase-min-alert' | 'alert' | 'promo-code-ticker'
|
|
428
|
+
| 'checkout-delivery-scheduling' // Internal child of checkout
|
|
356
429
|
// ...and additional internal component types
|
|
357
430
|
```
|
|
358
431
|
|
|
@@ -499,3 +572,39 @@ ownership and for reloading checkout when identity changes.
|
|
|
499
572
|
Order completion waits for queued preference work. It cannot race a late saved
|
|
500
573
|
opt-out or proceed with an unconfirmed saved choice. If applying a known choice
|
|
501
574
|
fails, the shopper can retry or explicitly choose the visible channel preference.
|
|
575
|
+
|
|
576
|
+
## Delivery scheduling types
|
|
577
|
+
|
|
578
|
+
The main and checkout-only entries, and their Node/SSR stubs, export these types.
|
|
579
|
+
|
|
580
|
+
```typescript
|
|
581
|
+
export interface DeliverySlot {
|
|
582
|
+
id: string; // server-issued, `<fulfillmentOptionId>:<window start, Unix seconds>`
|
|
583
|
+
start: string; // ISO-8601 UTC
|
|
584
|
+
end: string; // ISO-8601 UTC
|
|
585
|
+
cutoff: string; // ISO-8601 UTC, latest time to order for this window ("Order by")
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
export interface DeliveryAvailability {
|
|
589
|
+
status: 'available' | 'unavailable'; // available when the store can deliver now or offers windows
|
|
590
|
+
canDeliverNow: boolean;
|
|
591
|
+
canSchedule: boolean;
|
|
592
|
+
timezone: string | null; // store IANA time zone; null when the server has none. The SDK shows times in the viewer's browser time zone, not this one
|
|
593
|
+
nextSlot: DeliverySlot | null; // null on a product fulfillment of a closed store: checkout gives the windows
|
|
594
|
+
checkedAt: string;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
export interface CheckoutDeliveryScheduling {
|
|
598
|
+
availability: DeliveryAvailability;
|
|
599
|
+
slots: DeliverySlot[]; // only in answer to deliverySlotsFulfillmentId; empty otherwise
|
|
600
|
+
selectedSlotId: string | null; // null = as soon as possible / no window
|
|
601
|
+
selectedSlot?: DeliverySlot | null; // the accepted window with its real end and cutoff; null when none
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
export interface CheckoutDeliverySelection {
|
|
605
|
+
fulfillmentId: string;
|
|
606
|
+
slotId: string | null;
|
|
607
|
+
}
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
`ICheckoutFulfillment.deliveryScheduling` is optional. `ICheckoutPrepareParams` takes `deliverySelections?: CheckoutDeliverySelection[]` and `deliverySlotsFulfillmentId?: string`. `actions.checkout` adds `loadDeliverySlots(fulfillmentId: string): Promise<DeliverySlot[]>` and `chooseDeliverySlot(fulfillmentId: string, slotId: string | null): Promise<void>` on both clients, and `ICheckoutDetailsEventData` adds `deliveryScheduling: Record<string, CheckoutDeliveryScheduling>`.
|
|
@@ -152,7 +152,10 @@ on render, and a live region recreated with its text already in place is not ann
|
|
|
152
152
|
- An option in a single-select group carries its **whole** visible content in its accessible name.
|
|
153
153
|
`option` and `radio` have presentational children, so the name is the only channel: a delivery
|
|
154
154
|
option names the retailer, the price, the timing, the delivery fee and — for same-day — the
|
|
155
|
-
store address and whether it is currently closed.
|
|
155
|
+
store address and whether it is currently closed. A closed store that schedules delivery leads
|
|
156
|
+
with that instead ("Columbus Avenue Wines, closed now, schedule delivery"), followed by
|
|
157
|
+
"next arrival Thu, 1 PM – 2 PM" only when the server sends a next window; its card
|
|
158
|
+
stays enabled.
|
|
156
159
|
- The California Proposition 65 warning on the product is a native `<details>` / `<summary>`
|
|
157
160
|
disclosure: the summary is a button that exposes its expanded state, and `Enter` / `Space` toggle
|
|
158
161
|
it with no scripting involved. Its `+` / `−` indicator is decorative and hidden. In checkout it is
|
|
@@ -289,3 +292,7 @@ from the accessibility tree; unknown choices retain their named, keyboard-operab
|
|
|
289
292
|
checkboxes. Clearing account preferences reveals the controls and synchronizes
|
|
290
293
|
`aria-checked` with the current guest defaults. A shopper's explicit checkbox edit
|
|
291
294
|
keeps that channel visible when account data arrives later.
|
|
295
|
+
|
|
296
|
+
### Delivery date and arrival windows
|
|
297
|
+
|
|
298
|
+
The delivery picker is a named native modal dialog opened from each delivery's Schedule delivery or Edit control. Dates and arrival windows are radio groups with one tab stop each and arrow-key selection; the date strip scrolls inside the dialog and unavailable dates are disabled. While windows load, the dialog is marked busy and shows a loading line; Cancel and Close stay available. Changes are drafts until Save; Cancel, Close and Escape discard them, and closing returns focus to the opening control. The dialog stays the same modal while it is open: a date or window change updates its contents in place, so it is not announced again. Save errors keep the dialog open and move focus to the error. Success is announced politely; errors and an expired or unavailable window are announced assertively, each with its own message. No time zone is shown above the windows; the ASAP window's accessible name is "As soon as possible", and the first window's accessible name also carries its "Order by" time. The window list scrolls inside the dialog, and the chosen or focused window is kept in view as the picker opens, the date changes and arrow keys move.
|
|
@@ -14,6 +14,8 @@ The Cart component automatically:
|
|
|
14
14
|
- Persists cart across sessions and tabs
|
|
15
15
|
- Provides checkout navigation
|
|
16
16
|
|
|
17
|
+
A same-day line from a store that is closed now but takes orders for later (its fulfillment's `deliveryAvailability` says it cannot deliver now and can schedule) shows "Schedule delivery" in place of the delivery estimate. The shopper chooses the delivery window in checkout.
|
|
18
|
+
|
|
17
19
|
## Basic Usage
|
|
18
20
|
|
|
19
21
|
The cart is automatically available when using the SDK - no explicit injection needed for the drawer. However, you need a way for users to open it.
|
|
@@ -286,6 +286,31 @@ console.log(checkoutData);
|
|
|
286
286
|
// }
|
|
287
287
|
```
|
|
288
288
|
|
|
289
|
+
### Load Delivery Slots
|
|
290
|
+
|
|
291
|
+
Load the delivery windows for one fulfillment that has scheduled delivery. `getDetails().deliveryScheduling` is keyed by fulfillment ID:
|
|
292
|
+
|
|
293
|
+
```javascript
|
|
294
|
+
const actions = window.LiquidCommerce.elements.actions.checkout;
|
|
295
|
+
const [fulfillmentId] = Object.keys(actions.getDetails().deliveryScheduling);
|
|
296
|
+
|
|
297
|
+
const slots = await actions.loadDeliverySlots(fulfillmentId);
|
|
298
|
+
// [{ id: 'option_1:1791475200', start: '2026-10-08T16:00:00.000Z', end: '2026-10-08T17:00:00.000Z', cutoff: '2026-10-08T15:00:00.000Z' }, ...]
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Choose Delivery Slot
|
|
302
|
+
|
|
303
|
+
Save a window from the last loaded list, or `null` for as soon as possible:
|
|
304
|
+
|
|
305
|
+
```javascript
|
|
306
|
+
await window.LiquidCommerce.elements.actions.checkout.chooseDeliverySlot(fulfillmentId, slots[0].id);
|
|
307
|
+
|
|
308
|
+
// As soon as possible (only when availability.canDeliverNow is true)
|
|
309
|
+
await window.LiquidCommerce.elements.actions.checkout.chooseDeliverySlot(fulfillmentId, null);
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
The promise rejects when the window was not offered, the fulfillment is unknown or another checkout update is in flight. See the [checkout actions reference](../api/actions/checkout-actions.md#delivery-scheduling-actions).
|
|
313
|
+
|
|
289
314
|
## Events
|
|
290
315
|
|
|
291
316
|
### Checkout Lifecycle
|
|
@@ -373,7 +398,9 @@ window.addEventListener('lce:actions.checkout_item_quantity_decrease', (event) =
|
|
|
373
398
|
|
|
374
399
|
### Delivery Method
|
|
375
400
|
|
|
376
|
-
Fires when the shopper switches a single-item checkout between same-day delivery and shipping.
|
|
401
|
+
Fires when the shopper switches a single-item checkout between same-day delivery and shipping. The
|
|
402
|
+
switch is shown only with `development.enableExpressCheckout: true`, the same opt-in as express
|
|
403
|
+
checkout.
|
|
377
404
|
|
|
378
405
|
```javascript
|
|
379
406
|
window.addEventListener('lce:actions.checkout_delivery_method_updated', (event) => {
|
|
@@ -382,6 +409,17 @@ window.addEventListener('lce:actions.checkout_delivery_method_updated', (event)
|
|
|
382
409
|
});
|
|
383
410
|
```
|
|
384
411
|
|
|
412
|
+
### Delivery Time
|
|
413
|
+
|
|
414
|
+
Fires once after checkout accepts a delivery window or as soon as possible, from the built-in picker or from `chooseDeliverySlot`.
|
|
415
|
+
|
|
416
|
+
```javascript
|
|
417
|
+
window.addEventListener('lce:actions.checkout_delivery_selection_updated', (event) => {
|
|
418
|
+
const { deliveryScheduling } = event.detail.data;
|
|
419
|
+
console.log('Delivery windows by fulfillment:', deliveryScheduling);
|
|
420
|
+
});
|
|
421
|
+
```
|
|
422
|
+
|
|
385
423
|
### Tips
|
|
386
424
|
|
|
387
425
|
```javascript
|
|
@@ -427,6 +465,11 @@ window.addEventListener('lce:actions.checkout_express_checkout_availability', (e
|
|
|
427
465
|
const { data } = event.detail;
|
|
428
466
|
console.log(data.available ? `Wallets: ${data.wallets.join(', ')}` : 'No wallets available');
|
|
429
467
|
});
|
|
468
|
+
|
|
469
|
+
// The shopper tapped a wallet button and its sheet opened
|
|
470
|
+
window.addEventListener('lce:actions.checkout_express_checkout_started', (event) => {
|
|
471
|
+
console.log(`Wallet sheet opened: ${event.detail.data.wallet}`);
|
|
472
|
+
});
|
|
430
473
|
```
|
|
431
474
|
|
|
432
475
|
### Promo Codes
|
|
@@ -563,7 +606,12 @@ Apple Pay and Google Pay are offered as express checkout buttons at the top of t
|
|
|
563
606
|
the gift toggle. Tapping one collects the shopper's contact and billing details from the wallet and
|
|
564
607
|
places the order without them completing the checkout forms.
|
|
565
608
|
|
|
566
|
-
Express checkout is
|
|
609
|
+
Express checkout is off by default: pass `development.enableExpressCheckout: true` in the client config to show it. Without it the checkout element renders
|
|
610
|
+
no express block, and the injection methods below render nothing and resolve to `null`.
|
|
611
|
+
|
|
612
|
+
> **Temporary:** this flag exists only while express checkout and the delivery-method switch are being verified. Once they are confirmed, the flag will be removed and both will always be on.
|
|
613
|
+
|
|
614
|
+
Once enabled, express checkout is offered to every shopper whose platform can show a wallet. Each wallet is
|
|
567
615
|
requested with Stripe's `always` policy, so the button renders wherever the device supports it rather
|
|
568
616
|
than only where Stripe judges it good for conversion. The block hides itself entirely — heading,
|
|
569
617
|
buttons and divider — in four cases: the device or browser offers no wallet, the order is a
|
|
@@ -856,3 +904,17 @@ ownership and for reloading checkout when identity changes.
|
|
|
856
904
|
Order completion waits for queued preference work. It cannot race a late saved
|
|
857
905
|
opt-out or proceed with an unconfirmed saved choice. If applying a known choice
|
|
858
906
|
fails, the shopper can retry or explicitly choose the visible channel preference.
|
|
907
|
+
|
|
908
|
+
## Scheduled delivery
|
|
909
|
+
|
|
910
|
+
When an AccelPay retailer has scheduled delivery turned on, checkout shows a **Delivery time** row for that delivery, between the delivery details and payment. It reads "ASAP" while the store can deliver now, or asks for a window when it cannot. The row's button reads **Schedule** while the row is on as soon as possible, **Edit** after a window is saved, and **Schedule delivery** when the shopper must choose a window. It opens a dialog that loads the windows for that delivery: date cards for today and the next 7 days, then arrival windows. Days and times are in the shopper's own time zone (the browser's), so "Today" is the shopper's today; no time zone is shown. The window list scrolls inside the dialog and keeps the chosen window in view. The first window shows "Order by" with its cutoff, and **ASAP** sits next to it when the store can deliver now (screen readers hear "As soon as possible"). Choices are drafts until **Save**; Cancel, Close and Escape discard them.
|
|
911
|
+
|
|
912
|
+
The accepted window shows in the row and on the items in the order summary ("Scheduled for Thu, 1 PM – 2 PM"), and on the thank-you page as "Delivery time" with "Thu, 1 PM – 2 PM". An ASAP order adds no line there. If the window's cutoff passes before the order is placed, the SDK clears it, shows "Your delivery window has passed. Choose a new delivery time.", reopens the picker and keeps Place Order disabled until a new choice is saved. If the store no longer offers the window, the same happens with "Your delivery window is no longer available. Choose a new delivery time." Everything else the shopper entered stays.
|
|
913
|
+
|
|
914
|
+
A store that was added to the cart while closed cannot deliver now, so checkout asks for a window and offers no ASAP. If a store closes after the shopper chose ASAP, Place Order answers `delivery_window_required`: the SDK shows "The store cannot deliver now. Choose a delivery time.", opens the picker and keeps Place Order disabled until a window is saved.
|
|
915
|
+
|
|
916
|
+
In a checkout with more than one fulfillment group (another store, or shipping), each same-day group with scheduled delivery gets its own **Delivery time** row and its own picker, which loads that group's windows. Its button reads **Schedule this store's delivery** (**Edit** after a window is saved), and the picker is named after the store ("Schedule delivery from Columbus Avenue Wines"). Every prepare sends each group's current choice, so saving one group keeps the other's window. A group whose store can deliver now stays on as soon as possible; a group whose store cannot needs its own window before payment and Place Order. When a window lapses, only that group's window is cleared and only its picker reopens: the SDK clears the window whose cutoff passed on the page, and for `delivery_window_required` marks the groups that have no window. When an error names its group (`fulfillmentId` on the error entry), only that group is cleared. A name that is not a scheduling group of this checkout counts as no name; when the error names no group and the SDK cannot place it, every saved window is cleared (a refused window save clears nothing and asks for another time). When the save of one store's window is refused because the window of another store lapsed, the SDK clears that other window and names its store: "Choose a delivery window for Columbus Avenue Wines before continuing." Until each store that cannot deliver now has a window, payment says which: "Choose a delivery window for Amsterdam Liquors before continuing." In an order with more than one fulfillment group, the thank-you page has one line per group, named after its store: the accepted window for a scheduled group ("Columbus Avenue Wines" with "Thu, 1 PM – 2 PM"), and the group's own expectation for the others ("Harbor Spirits" with "Ships in 3-5 days"). A scheduled group never shows the as-soon-as-possible expectation. While a store that cannot deliver now has no accepted window, the express wallet buttons stay off, like the card form. When checkout refuses a store that has scheduled delivery and also another delivery method (`multiple_fulfillment_options_per_store`, code 5516), the SDK shows the refusal as the checkout error and keeps the saved windows: "Scheduled delivery cannot be combined with another delivery method from the same store. Choose ASAP delivery, or use one delivery method for all items from this store." When that store is closed now, the text leaves out ASAP: "This store is closed now. Use one delivery method for all items from this store." When the refusal says whether the store is closed now (`closedNow` on the error entry), the SDK uses that. Otherwise, when Place Order is refused, the SDK reads the cart again and decides "closed now" from its `deliveryAvailability`, because a store can close after the last prepare. Place Order and the express wallet stay off until a prepare succeeds after a change to the cart or to a delivery choice.
|
|
917
|
+
|
|
918
|
+
In the delivery-method switch, a same-day method whose `deliveryAvailability` says the store cannot deliver now but can schedule shows "Schedule delivery" in place of its delivery estimate. Without `deliveryAvailability` the card shows the estimate as before.
|
|
919
|
+
|
|
920
|
+
Checkouts without scheduled delivery are unchanged. For a custom UI, see `actions.checkout.loadDeliverySlots` and `actions.checkout.chooseDeliverySlot` in the checkout actions reference, and the `checkout_delivery_selection_updated` event.
|
package/docs/v1/guides/events.md
CHANGED
|
@@ -502,7 +502,7 @@ window.addEventListener('lce:actions.cart_product_add_failed', (event) => {
|
|
|
502
502
|
|
|
503
503
|
Fires when checkout data loads.
|
|
504
504
|
|
|
505
|
-
**Data includes:** `cartId`, `amounts`, `itemCount`, `isGift`, `billingSameAsShipping
|
|
505
|
+
**Data includes:** `cartId`, `amounts`, `itemCount`, `isGift`, `billingSameAsShipping`, `deliveryScheduling` (keyed by fulfillment ID).
|
|
506
506
|
|
|
507
507
|
**Example**
|
|
508
508
|
|
|
@@ -709,7 +709,8 @@ window.addEventListener('lce:actions.checkout_item_engraving_updated', (event) =
|
|
|
709
709
|
### `lce:actions.checkout_delivery_method_updated`
|
|
710
710
|
|
|
711
711
|
Fires when the shopper moves a single-item checkout between same-day delivery and shipping. The order
|
|
712
|
-
is re-priced, so the totals change with it.
|
|
712
|
+
is re-priced, so the totals change with it. The switch is shown only with
|
|
713
|
+
`development.enableExpressCheckout: true`.
|
|
713
714
|
|
|
714
715
|
**Data includes:** `cartId`, `fulfillmentType`, `previousFulfillmentType`, `fulfillmentId`.
|
|
715
716
|
|
|
@@ -893,6 +894,26 @@ window.addEventListener('lce:actions.checkout_express_checkout_availability', (e
|
|
|
893
894
|
});
|
|
894
895
|
```
|
|
895
896
|
|
|
897
|
+
### `lce:actions.checkout_express_checkout_started`
|
|
898
|
+
|
|
899
|
+
Fires when the shopper taps a wallet button and the SDK opens the wallet sheet, inside the checkout
|
|
900
|
+
or on a block placed with `injectExpressCheckout` / `injectExpressCheckoutElement`. It fires for every
|
|
901
|
+
tap, and not for a tap the block refuses (a total that moved, an unmet order minimum, a second tap
|
|
902
|
+
while an order is being placed). The tap happens inside Stripe's frame, so this is the only way a host
|
|
903
|
+
page learns of it — for instance, to report `add_to_cart` for a product-page wallet with
|
|
904
|
+
[`actions.analytics`](../api/actions/analytics-actions.md).
|
|
905
|
+
|
|
906
|
+
**Data includes:** `cartId`, `wallet` (Stripe's name for it: `'apple_pay'`, `'google_pay'`, …).
|
|
907
|
+
|
|
908
|
+
**Example**
|
|
909
|
+
|
|
910
|
+
```javascript
|
|
911
|
+
window.addEventListener('lce:actions.checkout_express_checkout_started', (event) => {
|
|
912
|
+
const { wallet } = event.detail.data;
|
|
913
|
+
console.log(`Wallet sheet opened: ${wallet}`);
|
|
914
|
+
});
|
|
915
|
+
```
|
|
916
|
+
|
|
896
917
|
### `lce:actions.checkout_payment_form_failed`
|
|
897
918
|
|
|
898
919
|
Fires when the card form cannot load Stripe.js, so the card fields cannot appear. The shopper sees a
|
|
@@ -946,6 +967,19 @@ window.addEventListener('lce:actions.checkout_product_add_failed', (event) => {
|
|
|
946
967
|
});
|
|
947
968
|
```
|
|
948
969
|
|
|
970
|
+
### `lce:actions.checkout_delivery_selection_updated`
|
|
971
|
+
|
|
972
|
+
Emitted once after checkout prepare accepts a delivery window or ASAP choice, from the built-in picker or from `actions.checkout.chooseDeliverySlot`. Draft choices in the picker and failed saves do not emit it.
|
|
973
|
+
|
|
974
|
+
**Data:** `ICheckoutDetailsEventData`, including `deliveryScheduling: Record<string, CheckoutDeliveryScheduling>` keyed by fulfillment ID, with each accepted `selectedSlotId` and `selectedSlot`.
|
|
975
|
+
|
|
976
|
+
```javascript
|
|
977
|
+
window.addEventListener('lce:actions.checkout_delivery_selection_updated', (event) => {
|
|
978
|
+
const scheduling = event.detail.data.deliveryScheduling;
|
|
979
|
+
console.log('Delivery windows:', scheduling);
|
|
980
|
+
});
|
|
981
|
+
```
|
|
982
|
+
|
|
949
983
|
## Form Events
|
|
950
984
|
|
|
951
985
|
### `lce:forms.customer`
|
|
@@ -480,6 +480,12 @@ await window.LiquidCommerce.elements.actions.address.setAddressManually(
|
|
|
480
480
|
);
|
|
481
481
|
```
|
|
482
482
|
|
|
483
|
+
## Buying when a retailer is closed
|
|
484
|
+
|
|
485
|
+
A same-day retailer whose store schedules delivery can take orders while it is closed. Its fulfillment then carries `deliveryAvailability`. When that says the store cannot deliver now but can schedule (`status: 'available'`, `canSchedule: true`), the retailer card stays on and shows "Schedule delivery". The product page shows no time: the server sends `nextSlot: null` for a closed store, and checkout asks the shopper to choose a delivery window. Add to Cart stays on. Screen readers hear "Columbus Avenue Wines, closed now, schedule delivery" in place of "Currently closed". When the server does send a `nextSlot`, the card adds it on a second line, in the shopper's own time zone ("Schedule delivery", then "Thu, 1 PM – 2 PM") and screen readers hear "…, next arrival Thu, 1 PM – 2 PM". The SDK selects a retailer that can deliver now first, then one that schedules delivery, and goes to shipping only when neither is available.
|
|
486
|
+
|
|
487
|
+
A closed store without scheduled delivery is blocked as before. An unknown or unavailable `deliveryAvailability`, or a `nextSlot` whose order cutoff has passed, never turns purchase on.
|
|
488
|
+
|
|
483
489
|
## Presale Products
|
|
484
490
|
|
|
485
491
|
Products in presale mode:
|
|
@@ -10,6 +10,11 @@ This runs entirely inside the SDK. In most cases you do not need to configure or
|
|
|
10
10
|
|
|
11
11
|
It coexists with a host site's own GTM — see [Coexisting With Your Own GTM](#coexisting-with-your-own-gtm) below.
|
|
12
12
|
|
|
13
|
+
The one case that needs code: if **your own UI** renders a step Elements would otherwise render — a
|
|
14
|
+
product page, an address picker, a cart, or a "Proceed to checkout" in front of the checkout-only
|
|
15
|
+
client — Elements never sees it. Report it with `actions.analytics` — see
|
|
16
|
+
[Reporting Steps Your Own UI Renders](#reporting-steps-your-own-ui-renders).
|
|
17
|
+
|
|
13
18
|
## Supported Environments
|
|
14
19
|
|
|
15
20
|
GTM initialization and every event push are enabled in production and staging. When the SDK is running in Builder mode, no container is loaded and no events are sent.
|
|
@@ -93,22 +98,23 @@ Every event automatically carries source-tracking fields identifying the tenant
|
|
|
93
98
|
|
|
94
99
|
## Events
|
|
95
100
|
|
|
96
|
-
All events are GA4-shaped and follow the standard ecommerce schema (`items[]`, `value`, `currency` — the SDK uses `USD`, `coupon`, etc.).
|
|
101
|
+
All events are GA4-shaped and follow the standard ecommerce schema (`items[]`, `value`, `currency` — the SDK uses `USD`, `coupon`, etc.). `search` is the exception: it carries only `search_term`.
|
|
97
102
|
|
|
98
103
|
### Standard GA4 ecommerce events
|
|
99
104
|
|
|
100
105
|
| Event | Fired when |
|
|
101
106
|
| --- | --- |
|
|
102
|
-
| `view_item` | A shopper views a product |
|
|
103
|
-
| `view_item_list` | A
|
|
104
|
-
| `select_item` | A shopper
|
|
105
|
-
| `add_to_cart` | A shopper adds an item
|
|
106
|
-
| `view_cart` |
|
|
107
|
-
| `remove_from_cart` | A shopper
|
|
108
|
-
| `begin_checkout` | A shopper begins checkout |
|
|
109
|
-
| `add_shipping_info` | Shipping info is added during checkout |
|
|
107
|
+
| `view_item` | A shopper views a product, and again on each size they switch to |
|
|
108
|
+
| `view_item_list` | A product list loads products: its first load, a filtered or searched list, each "load more" |
|
|
109
|
+
| `select_item` | A shopper opens a product from a product list card |
|
|
110
|
+
| `add_to_cart` | A shopper adds an item: from the product component or a list card, `actions.cart.addProduct()` / `actions.checkout.addProduct()`, a cart or checkout quantity increase, or a presale added straight to checkout |
|
|
111
|
+
| `view_cart` | The cart drawer opens with items in it — the cart button, `openCart()` / `toggleCart()`, the checkout's back button — or an add that opens it lands |
|
|
112
|
+
| `remove_from_cart` | A shopper lowers an item's quantity or removes it, in the cart or in the checkout |
|
|
113
|
+
| `begin_checkout` | A shopper begins checkout: the cart's Checkout button (also before its redirect to `checkout.pageUrl`), `actions.checkout.addProduct()`, `openCheckout()` / `toggleCheckout()` opening the drawer, a presale added straight to checkout, or the first wallet tap on express buttons placed on their own |
|
|
114
|
+
| `add_shipping_info` | Shipping info is added during checkout: the customer or gift recipient form is saved, or a wallet (Apple Pay / Google Pay) order hands over the wallet's contact details |
|
|
110
115
|
| `add_payment_info` | Payment info is added during checkout |
|
|
111
116
|
| `purchase` | A purchase completes |
|
|
117
|
+
| `search` | A search typed into the product list's search box runs |
|
|
112
118
|
|
|
113
119
|
### Custom events
|
|
114
120
|
|
|
@@ -126,8 +132,45 @@ All events are GA4-shaped and follow the standard ecommerce schema (`items[]`, `
|
|
|
126
132
|
| `product_size_no_availability` | A selected size has no availability |
|
|
127
133
|
| `product_fulfillment_no_availability` | A selected fulfillment type has no availability |
|
|
128
134
|
|
|
135
|
+
## Reporting Steps Your Own UI Renders
|
|
136
|
+
|
|
137
|
+
Elements reports the steps its components render. A host that renders some steps itself reports
|
|
138
|
+
them through `actions.analytics`, on the full client and on the checkout-only client:
|
|
139
|
+
|
|
140
|
+
| Action | Event |
|
|
141
|
+
| --- | --- |
|
|
142
|
+
| `search(searchTerm)` | `search` |
|
|
143
|
+
| `viewItem(item)` | `view_item` |
|
|
144
|
+
| `viewItemList(items, list?)` | `view_item_list` |
|
|
145
|
+
| `selectItem(item, list?)` | `select_item` |
|
|
146
|
+
| `addToCart(item)` | `add_to_cart` |
|
|
147
|
+
| `removeFromCart(item)` | `remove_from_cart` |
|
|
148
|
+
| `viewCart(items)` | `view_cart` |
|
|
149
|
+
| `beginCheckout(items, { coupon? })` | `begin_checkout` |
|
|
150
|
+
| `addressUpdated(address)` | `address_updated` |
|
|
151
|
+
| `addressFailed(failure)` | `address_failed` |
|
|
152
|
+
| `productNoAvailability(details)` | `product_no_availability` |
|
|
153
|
+
| `productSizeNoAvailability(details)` | `product_size_no_availability` |
|
|
154
|
+
| `productFulfillmentNoAvailability(details)` | `product_fulfillment_no_availability` |
|
|
155
|
+
|
|
156
|
+
They go through the same pipeline as the SDK's own events — same shape, `tenant_*` fields,
|
|
157
|
+
`send_to` targets, environment gating and queueing — so a report built on Elements events covers
|
|
158
|
+
both. There are no actions for `add_shipping_info`, `add_payment_info`, `purchase` or the promo code
|
|
159
|
+
and gift card events: the Elements checkout reports those itself, and a host reporting them too
|
|
160
|
+
would count every order twice. For the same reason, don't report a step an Elements component
|
|
161
|
+
renders — including `begin_checkout`, which Elements reports from the cart's Checkout button,
|
|
162
|
+
`actions.checkout.addProduct()`, `openCheckout()` / `toggleCheckout()`, a presale, and the first
|
|
163
|
+
wallet tap on express buttons placed on their own.
|
|
164
|
+
|
|
165
|
+
Malformed input never throws: the event is skipped and a warning logged, so reporting can't break
|
|
166
|
+
the host's page.
|
|
167
|
+
|
|
168
|
+
Items take prices in cents, as product responses carry them, and send them in dollars. Full
|
|
169
|
+
signatures and examples: [Analytics Actions](../api/actions/analytics-actions.md).
|
|
170
|
+
|
|
129
171
|
## Related Docs
|
|
130
172
|
|
|
131
173
|
- [Events Guide](../guides/events.md)
|
|
174
|
+
- [Analytics Actions](../api/actions/analytics-actions.md)
|
|
132
175
|
- [Client API](../api/client.md)
|
|
133
176
|
- [Troubleshooting](./troubleshooting.md)
|
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.7.
|
|
6
|
+
"version": "2.7.45",
|
|
7
7
|
"homepage": "https://docs.liquidcommerce.co/elements-sdk",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
"@biomejs/biome": "^2.5.15",
|
|
113
113
|
"@commitlint/cli": "^21.2.3",
|
|
114
114
|
"@commitlint/config-conventional": "^21.2.3",
|
|
115
|
-
"@playwright/test": "1.
|
|
115
|
+
"@playwright/test": "1.64.0",
|
|
116
116
|
"@rollup/plugin-alias": "^6.0.0",
|
|
117
117
|
"@rollup/plugin-commonjs": "^29.0.3",
|
|
118
118
|
"@rollup/plugin-json": "^6.1.0",
|
|
@@ -126,12 +126,12 @@
|
|
|
126
126
|
"@semantic-release/npm": "^13.2.0",
|
|
127
127
|
"@semantic-release/release-notes-generator": "^14.1.1",
|
|
128
128
|
"@types/core-js": "^2.5.8",
|
|
129
|
-
"@types/node": "^26.6.
|
|
129
|
+
"@types/node": "^26.6.5",
|
|
130
130
|
"conventional-changelog": "8.1.3",
|
|
131
131
|
"husky": "^9.1.7",
|
|
132
132
|
"jsdom": "30.1.2",
|
|
133
133
|
"process": "^0.11.10",
|
|
134
|
-
"rollup": "^4.64.
|
|
134
|
+
"rollup": "^4.64.5",
|
|
135
135
|
"rollup-obfuscator": "^4.1.1",
|
|
136
136
|
"rollup-plugin-typescript2": "^0.37.0",
|
|
137
137
|
"semantic-release": "^25.0.9",
|