@liquidcommerce/elements-sdk 2.7.41 → 2.7.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/index.checkout.esm.js +9750 -8113
- package/dist/index.esm.js +14705 -13100
- package/dist/ssr-stub.esm.js +5 -0
- package/dist/types/clients/base.d.ts +1 -0
- package/dist/types/clients/helpers.d.ts +2 -1
- package/dist/types/core/api/api-client.service.d.ts +7 -3
- package/dist/types/core/pubsub/interfaces/checkout.interface.d.ts +11 -0
- package/dist/types/core/pubsub/interfaces/core.interface.d.ts +3 -1
- package/dist/types/core/store/interfaces/checkout.interface.d.ts +18 -1
- package/dist/types/core/store/interfaces/core.interface.d.ts +2 -2
- package/dist/types/enums/core.enum.d.ts +5 -0
- package/dist/types/index.checkout.d.ts +2 -1
- package/dist/types/interfaces/api/checkout.interface.d.ts +32 -0
- package/dist/types/interfaces/client.interface.d.ts +3 -1
- package/dist/types/interfaces/configs/checkout.interface.d.ts +1 -0
- package/dist/types/interfaces/injection.interface.d.ts +6 -0
- package/dist/types/modules/checkout/checkout.commands.d.ts +38 -3
- package/dist/types/modules/checkout/checkout.component.d.ts +1 -0
- package/dist/types/modules/checkout/components/checkout-buyer.component.d.ts +1 -0
- package/dist/types/modules/checkout/components/checkout-deliver-to.component.d.ts +1 -0
- package/dist/types/modules/checkout/components/checkout-delivery-method.component.d.ts +22 -0
- package/dist/types/modules/checkout/components/checkout-express-checkout.component.d.ts +61 -0
- package/dist/types/modules/checkout/components/checkout-express-completion.component.d.ts +21 -0
- package/dist/types/modules/checkout/components/checkout-place-order-button.component.d.ts +0 -6
- package/dist/types/modules/checkout/components/index.d.ts +3 -0
- package/dist/types/modules/checkout/constant.d.ts +12 -0
- package/dist/types/modules/checkout/customer-prefill.d.ts +4 -1
- package/dist/types/modules/checkout/express-wallet.d.ts +12 -0
- package/dist/types/modules/checkout/styles/delivery-method.style.d.ts +1 -0
- package/dist/types/modules/checkout/styles/express-checkout.style.d.ts +1 -0
- package/dist/types/modules/checkout/styles/express-completion.style.d.ts +1 -0
- package/dist/types/modules/ui-components/alert/alert.component.d.ts +10 -10
- package/dist/types/modules/ui-components/input/input.component.d.ts +1 -1
- package/dist/types/utils/format.d.ts +4 -0
- package/docs/v1/api/actions/checkout-actions.md +3 -1
- package/docs/v1/api/client.md +49 -0
- package/docs/v1/api/configuration.md +3 -1
- package/docs/v1/api/typescript-types.md +10 -1
- package/docs/v1/guides/accessibility.md +29 -0
- package/docs/v1/guides/checkout-component.md +77 -3
- package/docs/v1/guides/events.md +35 -0
- package/docs/v1/guides/theming.md +1 -0
- package/docs/v1/reference/analytics.md +14 -2
- package/package.json +7 -7
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getExpressCheckoutStyles: () => string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getExpressCompletionStyles: () => string;
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import { BaseComponent, type IOnStoreChanged } from '@/core/base-component.service';
|
|
2
2
|
import type { StorePaths } from '@/core/store/interfaces/core.interface';
|
|
3
|
+
export type AlertLevel = 'success' | 'warning' | 'error';
|
|
3
4
|
export interface IAlertComponentParams {
|
|
4
|
-
|
|
5
|
-
fromEvents?: boolean;
|
|
5
|
+
storePaths: StorePaths[];
|
|
6
6
|
showFirstEvent?: boolean;
|
|
7
7
|
autoHideDelay?: number;
|
|
8
8
|
}
|
|
9
9
|
export declare class AlertComponent extends BaseComponent<IAlertComponentParams, null> {
|
|
10
10
|
private hideTimeout;
|
|
11
|
-
private
|
|
12
|
-
private lastAnnouncedKey;
|
|
11
|
+
private lastAnnounced;
|
|
13
12
|
get hostClasses(): string[];
|
|
14
13
|
beforeSetupStoreWatchers(): void;
|
|
15
|
-
afterRender(): void;
|
|
16
14
|
onStoreWatch(changes: IOnStoreChanged[]): void;
|
|
17
|
-
|
|
18
|
-
private createErrorElement;
|
|
19
|
-
private scheduleHide;
|
|
20
|
-
private hideAllErrors;
|
|
21
|
-
private updateAlert;
|
|
15
|
+
afterRender(): void;
|
|
22
16
|
protected template(): HTMLElement[];
|
|
17
|
+
private getAlerts;
|
|
18
|
+
private discard;
|
|
19
|
+
private createAlert;
|
|
20
|
+
private createDismissButton;
|
|
21
|
+
private scheduleSuccessHide;
|
|
22
|
+
private announce;
|
|
23
23
|
disconnectedCallback(): void;
|
|
24
24
|
}
|
|
@@ -22,7 +22,7 @@ export interface IInputComponentParams {
|
|
|
22
22
|
label?: string;
|
|
23
23
|
ariaLabel?: string;
|
|
24
24
|
name: string;
|
|
25
|
-
autocomplete?: boolean;
|
|
25
|
+
autocomplete?: boolean | string;
|
|
26
26
|
disabled?: boolean;
|
|
27
27
|
}
|
|
28
28
|
export declare class InputComponent extends BaseComponent<IInputComponentParams, null> {
|
|
@@ -13,3 +13,7 @@ export declare function normalizeEngravingLines(lines: readonly (string | null |
|
|
|
13
13
|
export declare function normalizeText<T extends string | null | undefined>(value: T): T;
|
|
14
14
|
export declare function normalizeEmail<T extends string | null | undefined>(value: T): T;
|
|
15
15
|
export declare function normalizeCode<T extends string | null | undefined>(value: T): T;
|
|
16
|
+
export declare function formatPaymentMethodLabel(card: {
|
|
17
|
+
brand?: string | null;
|
|
18
|
+
last4?: string | null;
|
|
19
|
+
} | null | undefined): string;
|
|
@@ -532,7 +532,9 @@ After `lce:actions.checkout_loaded`, call
|
|
|
532
532
|
`await elements.actions.checkout.updateCustomerInfo(fields, { saveIfValid: true })`
|
|
533
533
|
to validate and prepare complete account details, then show their editable summary.
|
|
534
534
|
Supply names, email, a US phone number, and a real `birthDate` in `MM/DD/YYYY` format
|
|
535
|
-
(age 21+, year 1930 or later).
|
|
535
|
+
(age 21+, year 1930 or later). The `birthDate` may be blank when the partner does not require a
|
|
536
|
+
date of birth (`checkout.layout.requireBirthDate: false`); a supplied one is still validated.
|
|
537
|
+
A shipping street must already be selected.
|
|
536
538
|
Omitted apartment and delivery instructions retain their existing checkout values.
|
|
537
539
|
Partial or invalid details stay in the form; backend validation failures reject the
|
|
538
540
|
promise, show the checkout error, and keep details editable. The host should handle that rejection.
|
package/docs/v1/api/client.md
CHANGED
|
@@ -64,6 +64,55 @@ 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()`.
|
|
69
|
+
|
|
70
|
+
#### injectExpressCheckout()
|
|
71
|
+
|
|
72
|
+
Injects only the Apple Pay and Google Pay wallet buttons, anywhere on the page, without the rest of
|
|
73
|
+
the checkout UI. Confirming the wallet sheet places the order outright — the wallet's contact and
|
|
74
|
+
billing details are sent to the checkout, so the shopper never fills a checkout form.
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
injectExpressCheckout(params: IInjectExpressCheckoutParams): Promise<IInjectedComponent | null>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
| Parameter | Type | Required | Description |
|
|
81
|
+
|-----------|------|----------|-------------|
|
|
82
|
+
| `containerId` | string | Yes | ID of an element that already exists in the DOM |
|
|
83
|
+
| `checkoutId` | string | No | Checkout token to bind the buttons to. Omit to use the checkout already loaded |
|
|
84
|
+
| `variant` | `'buttons' \| 'section'` | No | `'buttons'` (default) is the wallet row alone; `'section'` adds the "Express Checkout" heading and OR divider |
|
|
85
|
+
|
|
86
|
+
A checkout is prepared at injection time rather than when a button is tapped: Stripe gives the
|
|
87
|
+
wallet's click handler one second to open its sheet, which is not enough time to create a checkout
|
|
88
|
+
and a payment session. Without a `checkoutId` the checkout already in the store is reused, so the
|
|
89
|
+
buttons can be injected beside a checkout the page has already loaded; the checkout-only client has
|
|
90
|
+
no cart to fall back on, so it throws when there is no loaded checkout to attach to. Inject again
|
|
91
|
+
with a new token whenever the address or fulfillment changes — the amounts the sheet shows come from
|
|
92
|
+
the checkout the buttons were prepared against.
|
|
93
|
+
|
|
94
|
+
The buttons only render where the shopper's platform offers a wallet, and the block hides itself
|
|
95
|
+
entirely otherwise. Subscribe to `lce:actions.checkout_express_checkout_availability` to know which
|
|
96
|
+
state you are in. Both wallets require an HTTPS origin on a domain registered with Stripe, each
|
|
97
|
+
subdomain separately — see the
|
|
98
|
+
[checkout component guide](../guides/checkout-component.md#express-checkout-apple-pay-and-google-pay).
|
|
99
|
+
|
|
100
|
+
```javascript
|
|
101
|
+
await client.injectExpressCheckout({
|
|
102
|
+
containerId: 'express-checkout-container'
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The full client exposes the same component as `injectExpressCheckoutElement()`, with the same
|
|
107
|
+
parameters. It differs in one way: with no `checkoutId` and no checkout loaded, it prepares one from
|
|
108
|
+
the current cart rather than throwing.
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
await client.injectExpressCheckoutElement({
|
|
112
|
+
containerId: 'pdp-express-checkout'
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
67
116
|
### ElementsBuilder()
|
|
68
117
|
|
|
69
118
|
Initialize the builder client, which exposes manual `inject*` / `update*` methods for fully programmatic composition.
|
|
@@ -335,6 +335,7 @@ interface ICheckoutLayout {
|
|
|
335
335
|
emailOptIn: ICheckoutMarketingOptIn;
|
|
336
336
|
smsOptIn: ICheckoutMarketingOptIn;
|
|
337
337
|
allowGiftCards: boolean;
|
|
338
|
+
requireBirthDate?: boolean;
|
|
338
339
|
legalMessage: ICheckoutLegalMessage;
|
|
339
340
|
continueShoppingUrl: string;
|
|
340
341
|
exitUrl: string;
|
|
@@ -350,6 +351,7 @@ interface ICheckoutLayout {
|
|
|
350
351
|
| `emailOptIn` | `ICheckoutMarketingOptIn` | Email marketing opt-in configuration |
|
|
351
352
|
| `smsOptIn` | `ICheckoutMarketingOptIn` | SMS marketing opt-in configuration |
|
|
352
353
|
| `allowGiftCards` | `boolean` | Enable gift card payment option |
|
|
354
|
+
| `requireBirthDate` | `boolean` | Whether the shopper must enter a date of birth to place an order. Defaults to `true`. When `false` the form's field is optional and express checkout does not ask for it |
|
|
353
355
|
| `legalMessage` | `ICheckoutLegalMessage` | Legal/terms message configuration |
|
|
354
356
|
| `continueShoppingUrl` | `string` | URL for "Continue Shopping" link |
|
|
355
357
|
| `exitUrl` | `string` | URL for exit/back navigation |
|
|
@@ -546,7 +548,7 @@ interface IElementsGTMConfig {
|
|
|
546
548
|
}
|
|
547
549
|
```
|
|
548
550
|
|
|
549
|
-
If your site loads its own GTM container through Google tag gateway for advertisers, set `gatewayUrl` to that first-party path (e.g. `'https://www.yoursite.com/metrics/'` or `'/metrics/'`) so the SDK recognizes the container
|
|
551
|
+
If your site loads its own GTM container through Google tag gateway for advertisers, set `gatewayUrl` to that first-party path (e.g. `'https://www.yoursite.com/metrics/'` or `'/metrics/'`) so the SDK recognizes the container before GTM has booted it. It affects detection only: your container receives SDK events through `dataLayer` with or without it. Declarative equivalent: `data-gtm-gateway-url`. An empty or non-string value drops the whole `gtm` config with a console warning.
|
|
550
552
|
|
|
551
553
|
See [Analytics → Google tag gateway](../reference/analytics.md#google-tag-gateway).
|
|
552
554
|
|
|
@@ -80,9 +80,16 @@ Checkout-only client interface returned by `ElementsCheckout()`.
|
|
|
80
80
|
```typescript
|
|
81
81
|
interface IElementsCheckoutClient {
|
|
82
82
|
injectCheckout(params: IInjectCheckoutParams): Promise<IInjectedComponent | null>;
|
|
83
|
+
injectExpressCheckout(params: IInjectExpressCheckoutParams): Promise<IInjectedComponent | null>;
|
|
83
84
|
actions: { checkout: IElementsCheckoutActions };
|
|
84
85
|
destroy(): void;
|
|
85
86
|
}
|
|
87
|
+
|
|
88
|
+
interface IInjectExpressCheckoutParams {
|
|
89
|
+
containerId: string;
|
|
90
|
+
checkoutId?: string; // omit to use the checkout already loaded
|
|
91
|
+
variant?: 'section' | 'buttons'; // 'buttons' is the default outside the checkout element
|
|
92
|
+
}
|
|
86
93
|
```
|
|
87
94
|
|
|
88
95
|
---
|
|
@@ -440,7 +447,9 @@ After `lce:actions.checkout_loaded`, call
|
|
|
440
447
|
`await elements.actions.checkout.updateCustomerInfo(fields, { saveIfValid: true })`
|
|
441
448
|
to validate and prepare complete account details, then show their editable summary.
|
|
442
449
|
Supply names, email, a US phone number, and a real `birthDate` in `MM/DD/YYYY` format
|
|
443
|
-
(age 21+, year 1930 or later).
|
|
450
|
+
(age 21+, year 1930 or later). The `birthDate` may be blank when the partner does not require a
|
|
451
|
+
date of birth (`checkout.layout.requireBirthDate: false`); a supplied one is still validated.
|
|
452
|
+
A shipping street must already be selected.
|
|
444
453
|
Omitted apartment and delivery instructions retain their existing checkout values.
|
|
445
454
|
Partial or invalid details stay in the form; backend validation failures reject the
|
|
446
455
|
promise, show the checkout error, and keep details editable. The host should handle that rejection.
|
|
@@ -105,6 +105,7 @@ Content that appears or changes without navigation is announced through a shared
|
|
|
105
105
|
| Cart or checkout opened / closed | "Shopping cart opened" / "Shopping cart closed" |
|
|
106
106
|
| Panel closed (product) | "Closed. Back to product options." |
|
|
107
107
|
| Item added / removed, promo applied, totals changed | The new state, e.g. "Promo code SPRING applied, $5.00 off" |
|
|
108
|
+
| Express checkout payment failed | "Express checkout failed. …" |
|
|
108
109
|
| Product list filtered or searched | "12 products found, showing 12" |
|
|
109
110
|
| Validation failed | The field name and the error, interrupting (assertive) |
|
|
110
111
|
| Carousel image changed | "Image 2 of 4" |
|
|
@@ -120,6 +121,14 @@ on render, and a live region recreated with its text already in place is not ann
|
|
|
120
121
|
`aria-selected` / `aria-checked` — not toggle buttons with `aria-pressed`, which would describe
|
|
121
122
|
each choice as an independent on/off switch. Product sizes are a `listbox`; the delivery options
|
|
122
123
|
under each method are a `radiogroup`.
|
|
124
|
+
- Checkout's **Delivery Method** section is an accordion whose header is a real `button` carrying
|
|
125
|
+
`aria-expanded`, and whose two methods are a `radiogroup` of `radio` cards. Choosing one re-prices
|
|
126
|
+
the order, so selection does not follow focus here either: arrow keys move between the methods and
|
|
127
|
+
`Enter` / `Space` commits, rather than committing a switch the shopper was only passing through.
|
|
128
|
+
A method that cannot fulfil is `aria-disabled` and not activatable, but the **Change Location**
|
|
129
|
+
button inside it stays reachable — it is the way out of that state, so it must not be sealed in
|
|
130
|
+
with the option it sits under. Each card names the method, its fee and its timing, or, when it
|
|
131
|
+
cannot fulfil, the reason why.
|
|
123
132
|
- The delivery-method controls are a `tablist` of `tab`s. Only one method's options are rendered at
|
|
124
133
|
a time, so the selected tab carries `aria-controls` and the region it swaps in is the matching
|
|
125
134
|
`tabpanel`, labelled by that tab; the inactive tab points at nothing, because there is nothing
|
|
@@ -163,6 +172,26 @@ element on a page labels its own sections.
|
|
|
163
172
|
The checkout element has its own outline and is not covered by the above. Where any element's
|
|
164
173
|
top-level heading sits in **your** page's outline is yours to place.
|
|
165
174
|
|
|
175
|
+
### Express checkout
|
|
176
|
+
|
|
177
|
+
The Apple Pay and Google Pay buttons are rendered by Stripe inside an iframe, so their own labels
|
|
178
|
+
and keyboard behaviour are Stripe's. What the SDK owns around them:
|
|
179
|
+
|
|
180
|
+
- The **"Express Checkout" heading** is an `h3`, matching the other checkout section headings. It is
|
|
181
|
+
rendered only by the `section` variant; injected on their own the buttons carry no heading, and the
|
|
182
|
+
host page's own outline supplies it.
|
|
183
|
+
- The **`OR` divider** is decorative and carries `aria-hidden="true"`, so "OR" is not announced as
|
|
184
|
+
content between the buttons and the section below.
|
|
185
|
+
- When the shopper's device offers **no wallet**, the heading and the divider are removed from the
|
|
186
|
+
accessibility tree along with the buttons, so no orphan rule or empty heading is left behind. The block is also removed on a gift order, which express cannot place, and where a
|
|
187
|
+
payment method is already bound to the checkout. It is offered to every shopper otherwise.
|
|
188
|
+
- The **wallet sheet is browser UI**, not an SDK overlay: the browser owns focus while it is open and
|
|
189
|
+
returns it to the button that opened it. Dismissing the sheet changes nothing in the page, so
|
|
190
|
+
nothing is announced.
|
|
191
|
+
- Failures are announced assertively, because the shopper has just authorised a payment and the sheet
|
|
192
|
+
that showed the error has already closed. Confirming the sheet places the order outright, so there
|
|
193
|
+
is nothing to announce on the success path beyond the order confirmation itself.
|
|
194
|
+
|
|
166
195
|
### Images and icons
|
|
167
196
|
|
|
168
197
|
- Product photos use the product name as their alt text; a photo painted as a CSS background is
|
|
@@ -371,6 +371,17 @@ window.addEventListener('lce:actions.checkout_item_quantity_decrease', (event) =
|
|
|
371
371
|
});
|
|
372
372
|
```
|
|
373
373
|
|
|
374
|
+
### Delivery Method
|
|
375
|
+
|
|
376
|
+
Fires when the shopper switches a single-item checkout between same-day delivery and shipping.
|
|
377
|
+
|
|
378
|
+
```javascript
|
|
379
|
+
window.addEventListener('lce:actions.checkout_delivery_method_updated', (event) => {
|
|
380
|
+
const { fulfillmentType, previousFulfillmentType } = event.detail.data;
|
|
381
|
+
console.log(`Delivery method: ${previousFulfillmentType} to ${fulfillmentType}`);
|
|
382
|
+
});
|
|
383
|
+
```
|
|
384
|
+
|
|
374
385
|
### Tips
|
|
375
386
|
|
|
376
387
|
```javascript
|
|
@@ -402,6 +413,16 @@ window.addEventListener('lce:actions.checkout_submit_failed', (event) => {
|
|
|
402
413
|
});
|
|
403
414
|
```
|
|
404
415
|
|
|
416
|
+
### Express Checkout
|
|
417
|
+
|
|
418
|
+
```javascript
|
|
419
|
+
// Wallet availability settled or changed (always fires at least once per block)
|
|
420
|
+
window.addEventListener('lce:actions.checkout_express_checkout_availability', (event) => {
|
|
421
|
+
const { data } = event.detail;
|
|
422
|
+
console.log(data.available ? `Wallets: ${data.wallets.join(', ')}` : 'No wallets available');
|
|
423
|
+
});
|
|
424
|
+
```
|
|
425
|
+
|
|
405
426
|
### Promo Codes
|
|
406
427
|
|
|
407
428
|
```javascript
|
|
@@ -496,13 +517,63 @@ const client = await Elements('YOUR_API_KEY', {
|
|
|
496
517
|
|
|
497
518
|
The SDK uses Stripe for payment processing. Payment form is embedded and handles:
|
|
498
519
|
- Credit/debit cards
|
|
499
|
-
- Apple Pay (when available)
|
|
500
|
-
- Google Pay (when available)
|
|
501
520
|
- PCI compliance
|
|
502
521
|
- 3D Secure authentication
|
|
503
522
|
|
|
504
523
|
No additional Stripe integration code needed - it's built-in.
|
|
505
524
|
|
|
525
|
+
### Express checkout (Apple Pay and Google Pay)
|
|
526
|
+
|
|
527
|
+
Apple Pay and Google Pay are offered as express checkout buttons at the top of the checkout, above
|
|
528
|
+
the gift toggle. Tapping one collects the shopper's contact and billing details from the wallet and
|
|
529
|
+
places the order without them completing the checkout forms.
|
|
530
|
+
|
|
531
|
+
Express checkout is offered to every shopper whose platform can show a wallet. Each wallet is
|
|
532
|
+
requested with Stripe's `always` policy, so the button renders wherever the device supports it rather
|
|
533
|
+
than only where Stripe judges it good for conversion. The block hides itself entirely — heading,
|
|
534
|
+
buttons and divider — in four cases: the device or browser offers no wallet, the order is a
|
|
535
|
+
gift, a payment method is already bound to the checkout, or Stripe.js fails to load. Subscribe to
|
|
536
|
+
[`lce:actions.checkout_express_checkout_availability`](./events.md) to know which state you are in.
|
|
537
|
+
|
|
538
|
+
Two things are required outside the SDK:
|
|
539
|
+
|
|
540
|
+
- **The page must be served over HTTPS.** Stripe requires this in development as well as production;
|
|
541
|
+
the wallet buttons do not render on a plain-HTTP page.
|
|
542
|
+
- **Every domain that serves the buttons must be registered with Stripe** for the account issuing the
|
|
543
|
+
publishable key, in both sandbox and live mode. Stripe requires this for Apple Pay and Google Pay
|
|
544
|
+
alike, and it covers subdomains: `shop.example.com` is registered separately from `example.com`.
|
|
545
|
+
Registering in live mode registers the sandbox too. This applies per partner domain.
|
|
546
|
+
|
|
547
|
+
Approving the wallet sheet hands the order to the **express completion view**, which replaces the
|
|
548
|
+
checkout form the moment the sheet closes. The view saves the shopper's name, email and phone from
|
|
549
|
+
the wallet as the checkout's customer and binds the approved payment method; the wallet's billing
|
|
550
|
+
address goes to Stripe with that payment method, and the order's own billing address stays the one
|
|
551
|
+
the checkout already holds. Then it asks for the one thing no wallet returns — the shopper's **date
|
|
552
|
+
of birth** — with the same 21+ validation as the form, and places the order from its **Complete
|
|
553
|
+
order** button. A date the shopper already typed into the form is used instead, and the view goes
|
|
554
|
+
straight to placing the order. When the partner has turned off **Require date of birth** in the
|
|
555
|
+
builder (`checkout.layout.requireBirthDate: false`), the view skips the step and places the order as
|
|
556
|
+
soon as the payment method is bound. A shopper can step **back to checkout** from the view; the
|
|
557
|
+
payment method stays bound, and the form asks for the date of birth itself when one is required.
|
|
558
|
+
|
|
559
|
+
If the wallet sheet itself fails — a declined authorisation, or a total that changed while it was
|
|
560
|
+
open — the sheet reports the reason and nothing is handed on. Anything that fails after the sheet
|
|
561
|
+
has closed is reported on the view, with a retry. The order is placed only for the checkout and the
|
|
562
|
+
total the sheet was opened for: the server verifies both against the wallet's intent at completion,
|
|
563
|
+
so a total that moved in between is refused there as well and the shopper approves again.
|
|
564
|
+
|
|
565
|
+
The wallet tap is also refused, with nothing charged, when a cart is below a retailer's minimum
|
|
566
|
+
purchase amount — the same condition that keeps the Place Order button disabled. Presale checkouts
|
|
567
|
+
are exempt from it, as they are there.
|
|
568
|
+
|
|
569
|
+
Express checkout is not offered on a gift order: a gift needs the recipient's name, email, phone and
|
|
570
|
+
message, and no wallet returns any of them. Turning on "Send as a gift" hides the block, and turning
|
|
571
|
+
it back off restores it.
|
|
572
|
+
|
|
573
|
+
The buttons are not confined to the checkout element. Inject them anywhere on the page with
|
|
574
|
+
`injectExpressCheckoutElement()` on the full client, or `injectExpressCheckout()` on the
|
|
575
|
+
checkout-only client.
|
|
576
|
+
|
|
506
577
|
## Checkout Flow
|
|
507
578
|
|
|
508
579
|
### Standard Flow
|
|
@@ -623,6 +694,7 @@ window.addEventListener('lce:actions.checkout_submit_failed', () => {
|
|
|
623
694
|
checkout: {
|
|
624
695
|
layout: {
|
|
625
696
|
allowGiftCards: true, // Show gift card input
|
|
697
|
+
requireBirthDate: true, // Require a date of birth to place an order
|
|
626
698
|
emailOptIn: {
|
|
627
699
|
show: true, // Show email opt-in checkbox
|
|
628
700
|
checked: false, // Default unchecked
|
|
@@ -691,7 +763,9 @@ After `lce:actions.checkout_loaded`, call
|
|
|
691
763
|
`await elements.actions.checkout.updateCustomerInfo(fields, { saveIfValid: true })`
|
|
692
764
|
to validate and prepare complete account details, then show their editable summary.
|
|
693
765
|
Supply names, email, a US phone number, and a real `birthDate` in `MM/DD/YYYY` format
|
|
694
|
-
(age 21+, year 1930 or later).
|
|
766
|
+
(age 21+, year 1930 or later). The `birthDate` may be blank when the partner does not require a
|
|
767
|
+
date of birth (`checkout.layout.requireBirthDate: false`); a supplied one is still validated.
|
|
768
|
+
A shipping street must already be selected.
|
|
695
769
|
Omitted apartment and delivery instructions retain their existing checkout values.
|
|
696
770
|
Partial or invalid details stay in the form; backend validation failures reject the
|
|
697
771
|
promise, show the checkout error, and keep details editable. The host should handle that rejection.
|
package/docs/v1/guides/events.md
CHANGED
|
@@ -706,6 +706,22 @@ window.addEventListener('lce:actions.checkout_item_engraving_updated', (event) =
|
|
|
706
706
|
});
|
|
707
707
|
```
|
|
708
708
|
|
|
709
|
+
### `lce:actions.checkout_delivery_method_updated`
|
|
710
|
+
|
|
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.
|
|
713
|
+
|
|
714
|
+
**Data includes:** `cartId`, `fulfillmentType`, `previousFulfillmentType`, `fulfillmentId`.
|
|
715
|
+
|
|
716
|
+
**Example**
|
|
717
|
+
|
|
718
|
+
```javascript
|
|
719
|
+
window.addEventListener('lce:actions.checkout_delivery_method_updated', (event) => {
|
|
720
|
+
const { data } = event.detail;
|
|
721
|
+
console.log('Delivery method now', data.fulfillmentType);
|
|
722
|
+
});
|
|
723
|
+
```
|
|
724
|
+
|
|
709
725
|
### `lce:actions.checkout_tip_updated`
|
|
710
726
|
|
|
711
727
|
Fires when delivery tips are updated.
|
|
@@ -858,6 +874,25 @@ window.addEventListener('lce:actions.checkout_gift_card_failed', (event) => {
|
|
|
858
874
|
});
|
|
859
875
|
```
|
|
860
876
|
|
|
877
|
+
### `lce:actions.checkout_express_checkout_availability`
|
|
878
|
+
|
|
879
|
+
Fires once the express checkout block has settled which wallet buttons the shopper can reach, and
|
|
880
|
+
again whenever that changes. It always fires at least once per block. `available` is `false` on a
|
|
881
|
+
device or browser that offers no wallet, on a gift order, when a payment method is already bound to
|
|
882
|
+
the checkout, and when Stripe.js cannot load; in every case the SDK hides the whole block including
|
|
883
|
+
its divider.
|
|
884
|
+
|
|
885
|
+
**Data includes:** `cartId`, `available`, `wallets`.
|
|
886
|
+
|
|
887
|
+
**Example**
|
|
888
|
+
|
|
889
|
+
```javascript
|
|
890
|
+
window.addEventListener('lce:actions.checkout_express_checkout_availability', (event) => {
|
|
891
|
+
const { data } = event.detail;
|
|
892
|
+
console.log(data.available ? `Wallets: ${data.wallets.join(', ')}` : 'No wallets available');
|
|
893
|
+
});
|
|
894
|
+
```
|
|
895
|
+
|
|
861
896
|
### `lce:actions.checkout_product_add_success`
|
|
862
897
|
|
|
863
898
|
Fires when products are added to checkout via the actions API.
|
|
@@ -168,6 +168,7 @@ customTheme: {
|
|
|
168
168
|
text: 'Receive SMS updates about your order and exclusive deals.'
|
|
169
169
|
},
|
|
170
170
|
allowGiftCards: true,
|
|
171
|
+
requireBirthDate: true,
|
|
171
172
|
legalMessage: { show: true, text: 'By placing your order, you agree to our Terms of Service and Privacy Policy.' },
|
|
172
173
|
continueShoppingUrl: 'https://yoursite.com/shop',
|
|
173
174
|
exitUrl: 'https://yoursite.com',
|
|
@@ -52,7 +52,17 @@ The SDK detects an already-present partner/host GTM container rather than replac
|
|
|
52
52
|
|
|
53
53
|
### Google tag gateway
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
[Google tag gateway for advertisers](https://developers.google.com/tag-platform/tag-manager/gateway/get-started) serves your Google tags from your own domain instead of Google's. Your GTM container loads from a first-party path such as `https://www.yoursite.com/metrics/` instead of `https://www.googletagmanager.com/gtm.js?id=GTM-XXXX`, and its measurement requests (e.g. GA4 `/g/collect` hits) go out through that same path. Your CDN or load balancer forwards them to Google, so they are less likely to be blocked than requests to Google's domains.
|
|
56
|
+
|
|
57
|
+
#### How the SDK works with it
|
|
58
|
+
|
|
59
|
+
- The SDK pushes every event to the page's `window.dataLayer`. Your container reads that same `dataLayer`, so it receives SDK events whether it loads from Google or from your gateway. Keep the default `dataLayer` name: a container renamed with `&l=` never sees them.
|
|
60
|
+
- The SDK never loads your container and proxies nothing. The LiquidCommerce container still loads from `googletagmanager.com`.
|
|
61
|
+
- To send SDK events to your own GA4 property, add a Custom Event trigger in your container on the [event names](#events) below and a GA4 Event tag that fires on it. The SDK puts `items`, `value` and `currency` at the top level of each event, not inside an `ecommerce` object, so map them with Data Layer Variables rather than the GA4 tag's "Send Ecommerce data" option.
|
|
62
|
+
|
|
63
|
+
#### `gatewayUrl`
|
|
64
|
+
|
|
65
|
+
Tell the SDK your gateway path so it can recognize your container:
|
|
56
66
|
|
|
57
67
|
```javascript
|
|
58
68
|
const client = await Elements('YOUR_API_KEY', {
|
|
@@ -62,7 +72,9 @@ const client = await Elements('YOUR_API_KEY', {
|
|
|
62
72
|
|
|
63
73
|
Or declaratively, on the script tag: `data-gtm-gateway-url="/metrics/"`.
|
|
64
74
|
|
|
65
|
-
A gateway script URL usually carries no container ID, so
|
|
75
|
+
A gateway script URL usually carries no container ID, so until GTM has booted your container this setting is the only way the SDK can match the script tag to it. Once matched, your container ID is added to each event's `send_to` targets. The setting is optional: events reach your container through `dataLayer` without it.
|
|
76
|
+
|
|
77
|
+
A script with the same origin whose path starts with that value is matched to your partner container by container ID: an `id=` query parameter must equal your partner container ID, and a script without one counts only once GTM's `window.google_tag_manager` registry lists your container ID (or while no container has booted yet). A gateway serving a different container or a GA4/Ads tag is therefore never taken for yours. Relative values resolve against the current page.
|
|
66
78
|
|
|
67
79
|
When both the LiquidCommerce container and a partner container are initialized, events are sent to both using GA4's `send_to` targeting (a dual-container send). Only containers that are actually initialized are added to `send_to`, so events are never routed to a container that failed to load.
|
|
68
80
|
|
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.42",
|
|
7
7
|
"homepage": "https://docs.liquidcommerce.co/elements-sdk",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
},
|
|
15
15
|
"module": "./dist/index.esm.js",
|
|
16
16
|
"types": "./dist/types/index.d.ts",
|
|
17
|
-
"packageManager": "pnpm@
|
|
17
|
+
"packageManager": "pnpm@12.9.1",
|
|
18
18
|
"exports": {
|
|
19
19
|
".": {
|
|
20
20
|
"types": "./dist/types/index.d.ts",
|
|
@@ -109,7 +109,7 @@
|
|
|
109
109
|
"theming"
|
|
110
110
|
],
|
|
111
111
|
"devDependencies": {
|
|
112
|
-
"@biomejs/biome": "^2.5.
|
|
112
|
+
"@biomejs/biome": "^2.5.15",
|
|
113
113
|
"@commitlint/cli": "^21.2.3",
|
|
114
114
|
"@commitlint/config-conventional": "^21.2.3",
|
|
115
115
|
"@playwright/test": "1.63.0",
|
|
@@ -126,18 +126,18 @@
|
|
|
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.4",
|
|
130
130
|
"conventional-changelog": "8.1.3",
|
|
131
131
|
"husky": "^9.1.7",
|
|
132
|
-
"jsdom": "30.1.
|
|
132
|
+
"jsdom": "30.1.2",
|
|
133
133
|
"process": "^0.11.10",
|
|
134
|
-
"rollup": "^4.
|
|
134
|
+
"rollup": "^4.64.0",
|
|
135
135
|
"rollup-obfuscator": "^4.1.1",
|
|
136
136
|
"rollup-plugin-typescript2": "^0.37.0",
|
|
137
137
|
"semantic-release": "^25.0.9",
|
|
138
138
|
"ts-node": "^10.9.2",
|
|
139
139
|
"typescript": "6.0.3",
|
|
140
|
-
"vitest": "5.0.
|
|
140
|
+
"vitest": "5.0.3"
|
|
141
141
|
},
|
|
142
142
|
"engines": {
|
|
143
143
|
"node": ">=22"
|