@amos.com/react-amos-js 0.9.13 → 0.9.15

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 CHANGED
@@ -10,7 +10,7 @@ It is a thin wrapper around [`@amos.com/amos-js`](../amos-js) that adapts the fr
10
10
  npm install @amos.com/react-amos-js @amos.com/node
11
11
  ```
12
12
 
13
- `@amos.com/node` is a **peer dependency** (requires `>=0.1.37`). Install it in your app for OpenAPI schema types (for example `components["schemas"]["CreatePaymentIntentInput"]`) used in the examples below, and for your server-side Amos API client. React (`^17`, `^18`, or `^19`) is also a peer dependency.
13
+ `@amos.com/node` is a **peer dependency** (requires `>=0.1.39`). Install it in your app for OpenAPI schema types (for example `components["schemas"]["CreatePaymentIntentInput"]`) used in the examples below, and for your server-side Amos API client. React (`^17`, `^18`, or `^19`) is also a peer dependency.
14
14
 
15
15
  ## What it gives you
16
16
 
@@ -28,7 +28,7 @@ npm install @amos.com/react-amos-js @amos.com/node
28
28
  3. Amos account ID (provided once your application has been approved)
29
29
  ```
30
30
 
31
- The render token configures the iframe's allowed origin(s), allowed payment methods, and the range of valid payment amounts. If the render token does not allow an origin, the iframe will not render. Similarly, components corresponding to different payment method types will not render if not allowed by the render token.
31
+ The render token configures the iframe's allowed origin(s), allowed payment methods, accepted billing countries or US states, and the range of valid payment amounts. These settings come from the render template and are embedded in the token JWT (`RenderTokenJwt`); billing geography is controlled by `billing_address_options` (`allowed_countries` for international templates, `allowed_states` for US-only). If the render token does not allow an origin, the iframe will not render. Similarly, components corresponding to different payment method types will not render if not allowed by the render token, and billing addresses outside the configured countries or states will be rejected.
32
32
 
33
33
  > **Note**: The render token also determines the environment (`production` or `sandbox`). Render tokens created on `dashboard.amos.com` have a `production` environment. Render tokens created on `dashboard-sandbox.amos.com` have a `sandbox` environment. Similarly, API keys can only access the environment that they were created in.
34
34
 
@@ -62,7 +62,7 @@ Setup intents are used to save payment methods for future use (e.g. recurring pa
62
62
 
63
63
  - On the server, call `POST /setup_intents` instead of `POST /payment_intents`.
64
64
  - On the client, call `confirmSetupIntent({ iframeRef, token })` instead of `confirmPaymentIntent({ iframeRef, token })`.
65
- - The same `onResult` callback is used for setup intents (`intent: "setup"`).
65
+ - The same `onResult` callback is used; succeeded setup intents arrive as `{ status: "succeeded", intent: "setup", setupIntent }`.
66
66
 
67
67
  The same `AmosCreditCardPaymentMethodForm` / `AmosBankAccountPaymentMethodForm` components support both payment intents and setup intents — they are differentiated by which confirmation function you call.
68
68
 
@@ -82,7 +82,7 @@ In short, your app orchestrates the payment flow, while sensitive payment data s
82
82
 
83
83
  ## Appearance
84
84
 
85
- Every component accepts an optional `appearance` prop that controls the look of the iframe UI. It contains a `themeVariables` object whose keys are CSS custom-property names and whose values are strings, and an optional `labels` setting for field label placement. You can update this prop after page load to update the iframe appearance.
85
+ Card and bank components accept an optional `appearance` prop that controls the look of the iframe UI. It contains a `themeVariables` object whose keys are CSS custom-property names and whose values are strings, and an optional `labels` setting for field label placement. You can update this prop after page load to update the iframe appearance. Wallet buttons do not take `appearance`.
86
86
 
87
87
  ```tsx
88
88
  <AmosCreditCardPaymentMethodForm
@@ -107,57 +107,57 @@ Every component accepts an optional `appearance` prop that controls the look of
107
107
 
108
108
  Set `labels` to control how field labels are rendered in card and bank account forms:
109
109
 
110
- | Value | Behavior |
111
- | ----- | -------- |
112
- | `above` (default) | Label text above each input |
113
- | `floating` | Label inside the control; moves up when focused or filled |
114
- | `placeholder` | No visible label; placeholder and `aria-label` only |
110
+ | Value | Behavior |
111
+ | ----------------- | --------------------------------------------------------- |
112
+ | `above` (default) | Label text above each input |
113
+ | `floating` | Label inside the control; moves up when focused or filled |
114
+ | `placeholder` | No visible label; placeholder and `aria-label` only |
115
115
 
116
116
  Radio groups (e.g. account type) always use an above-style group label regardless of this setting.
117
117
 
118
118
  ### Available theme variables
119
119
 
120
- | Variable | Purpose | Default |
121
- | ------------------------ | ---------------------------------------------- | --------------------------- |
122
- | `--background` | Page body and base surface color | `oklch(1 0 0)` |
123
- | `--foreground` | Default text color | `oklch(0.145 0 0)` |
124
- | `--primary` | Button fill and input text-selection highlight | `oklch(0.205 0 0)` |
125
- | `--primary-foreground` | Text on primary-colored surfaces | `oklch(0.985 0 0)` |
126
- | `--secondary` | Secondary button fill | `oklch(0.97 0 0)` |
127
- | `--secondary-foreground` | Text on secondary-colored surfaces | `oklch(0.205 0 0)` |
128
- | `--muted` | Muted surface color | `oklch(0.97 0 0)` |
129
- | `--muted-foreground` | Placeholder text, helper labels, muted icons | `oklch(0.556 0 0)` |
130
- | `--accent` | Hover/focus highlight for interactive items | `oklch(0.97 0 0)` |
131
- | `--accent-foreground` | Text on accent-highlighted items | `oklch(0.205 0 0)` |
132
- | `--destructive` | Error/invalid state borders, icons, and field error text | `oklch(0.577 0.245 27.325)` |
133
- | `--destructive-foreground` | Text on destructive-colored surfaces | `oklch(0.45 0.24 27.325)` |
134
- | `--border` | General border color | `oklch(0.922 0 0)` |
135
- | `--popover` | Dropdown / popover panel background | `oklch(1 0 0)` |
136
- | `--popover-foreground` | Dropdown / popover panel text color | `oklch(0.145 0 0)` |
137
- | `--input` | Input field border color | `oklch(0.922 0 0)` |
138
- | `--input-background` | Input field background fill | `var(--background)` |
139
- | `--input-height` | Height of text inputs and form controls | `2.25rem` |
140
- | `--input-font-size` | Font size of text inputs and dropdown fields | `0.875rem` |
141
- | `--input-font-weight` | Font weight of typed input values | `400` |
142
- | `--input-padding` | Horizontal padding inside inputs | `0.75rem` |
143
- | `--input-border-width` | Input field border width | `1px` |
144
- | `--input-shadow` | Input field box shadow | `0 1px 2px 0 rgb(0 0 0 / 0.05)` |
145
- | `--floating-input-height` | Height of inputs when labels are floating | `3.25rem` |
146
- | `--floating-label-font-size` | Font size of floating labels when focused or filled | `0.75rem` |
147
- | `--floating-label-empty-font-size` | Font size of floating labels when empty (unfocused) | `var(--input-font-size)` |
148
- | `--floating-label-font-weight` | Font weight of floating labels | `500` |
149
- | `--floating-label-color` | Color of floating labels when empty (unfocused) | `var(--muted-foreground)` |
150
- | `--floating-label-floated-color` | Color of floating labels when focused or filled | `var(--floating-label-color)` |
151
- | `--floating-label-offset` | Top offset of the shrunk floating label | `0.625rem` |
152
- | `--label-font-size` | Font size of above-style field labels | `0.875rem` |
153
- | `--label-font-weight` | Font weight of above-style field labels | `500` |
154
- | `--field-gap` | Vertical gap between stacked form fields | `1rem` |
155
- | `--control-gap` | Horizontal gap between side-by-side controls | `0.5rem` |
156
- | `--error-font-size` | Font size of field-level error messages | `0.875rem` |
157
- | `--radio-size` | Size of radio buttons on the bank account form | `1rem` |
158
- | `--ring` | Focus ring and outline color | `oklch(0.708 0 0)` |
159
- | `--ring-width` | Focus ring width | `3px` |
160
- | `--radius` | Base border-radius (derived into sm/md/lg/xl) | `0.625rem` |
120
+ | Variable | Purpose | Default |
121
+ | ---------------------------------- | -------------------------------------------------------- | ------------------------------- |
122
+ | `--background` | Page body and base surface color | `oklch(1 0 0)` |
123
+ | `--foreground` | Default text color | `oklch(0.145 0 0)` |
124
+ | `--primary` | Button fill and input text-selection highlight | `oklch(0.205 0 0)` |
125
+ | `--primary-foreground` | Text on primary-colored surfaces | `oklch(0.985 0 0)` |
126
+ | `--secondary` | Secondary button fill | `oklch(0.97 0 0)` |
127
+ | `--secondary-foreground` | Text on secondary-colored surfaces | `oklch(0.205 0 0)` |
128
+ | `--muted` | Muted surface color | `oklch(0.97 0 0)` |
129
+ | `--muted-foreground` | Placeholder text, helper labels, muted icons | `oklch(0.556 0 0)` |
130
+ | `--accent` | Hover/focus highlight for interactive items | `oklch(0.97 0 0)` |
131
+ | `--accent-foreground` | Text on accent-highlighted items | `oklch(0.205 0 0)` |
132
+ | `--destructive` | Error/invalid state borders, icons, and field error text | `oklch(0.577 0.245 27.325)` |
133
+ | `--destructive-foreground` | Text on destructive-colored surfaces | `oklch(0.45 0.24 27.325)` |
134
+ | `--border` | General border color | `oklch(0.922 0 0)` |
135
+ | `--popover` | Dropdown / popover panel background | `oklch(1 0 0)` |
136
+ | `--popover-foreground` | Dropdown / popover panel text color | `oklch(0.145 0 0)` |
137
+ | `--input` | Input field border color | `oklch(0.922 0 0)` |
138
+ | `--input-background` | Input field background fill | `var(--background)` |
139
+ | `--input-height` | Height of text inputs and form controls | `2.25rem` |
140
+ | `--input-font-size` | Font size of text inputs and dropdown fields | `0.875rem` |
141
+ | `--input-font-weight` | Font weight of typed input values | `400` |
142
+ | `--input-padding` | Horizontal padding inside inputs | `0.75rem` |
143
+ | `--input-border-width` | Input field border width | `1px` |
144
+ | `--input-shadow` | Input field box shadow | `0 1px 2px 0 rgb(0 0 0 / 0.05)` |
145
+ | `--floating-input-height` | Height of inputs when labels are floating | `3.25rem` |
146
+ | `--floating-label-font-size` | Font size of floating labels when focused or filled | `0.75rem` |
147
+ | `--floating-label-empty-font-size` | Font size of floating labels when empty (unfocused) | `var(--input-font-size)` |
148
+ | `--floating-label-font-weight` | Font weight of floating labels | `500` |
149
+ | `--floating-label-color` | Color of floating labels when empty (unfocused) | `var(--muted-foreground)` |
150
+ | `--floating-label-floated-color` | Color of floating labels when focused or filled | `var(--floating-label-color)` |
151
+ | `--floating-label-offset` | Top offset of the shrunk floating label | `0.625rem` |
152
+ | `--label-font-size` | Font size of above-style field labels | `0.875rem` |
153
+ | `--label-font-weight` | Font weight of above-style field labels | `500` |
154
+ | `--field-gap` | Vertical gap between stacked form fields | `1rem` |
155
+ | `--control-gap` | Horizontal gap between side-by-side controls | `0.5rem` |
156
+ | `--error-font-size` | Font size of field-level error messages | `0.875rem` |
157
+ | `--radio-size` | Size of radio buttons on the bank account form | `1rem` |
158
+ | `--ring` | Focus ring and outline color | `oklch(0.708 0 0)` |
159
+ | `--ring-width` | Focus ring width | `3px` |
160
+ | `--radius` | Base border-radius (derived into sm/md/lg/xl) | `0.625rem` |
161
161
 
162
162
  ## Examples
163
163
 
@@ -192,10 +192,11 @@ function CheckoutForm() {
192
192
  return;
193
193
  }
194
194
 
195
- const paymentIntentCreateAttributes: components["schemas"]["CreatePaymentIntentInput"] = {
196
- amount: 5000, // $50.00 in cents
197
- capture_method: "automatic",
198
- };
195
+ const paymentIntentCreateAttributes: components["schemas"]["CreatePaymentIntentInput"] =
196
+ {
197
+ amount: 5000, // $50.00 in cents
198
+ capture_method: "automatic",
199
+ };
199
200
 
200
201
  const response = await fetch("/api/payment-intents", {
201
202
  method: "POST",
@@ -246,58 +247,109 @@ function CheckoutForm() {
246
247
  }
247
248
  ```
248
249
 
249
- ### Rendering Google Pay within your checkout flow
250
+ ### Rendering Google Pay and Apple Pay within your checkout flow
250
251
 
251
252
  ```tsx
252
253
  import { useState } from "react";
253
- import { AmosGooglePayButton } from "@amos.com/react-amos-js";
254
+ import {
255
+ AmosApplePayButton,
256
+ AmosGooglePayButton,
257
+ type ConfirmationResult,
258
+ } from "@amos.com/react-amos-js";
259
+ import type { components } from "@amos.com/node";
260
+
261
+ async function createPaymentIntentToken({
262
+ paymentIntentCreateAttributes,
263
+ customerCreateAttributes,
264
+ }: {
265
+ paymentIntentCreateAttributes: components["schemas"]["CreatePaymentIntentInput"];
266
+ customerCreateAttributes: components["schemas"]["CreateCustomerInput"];
267
+ }): Promise<string> {
268
+ const response = await fetch("/api/payment-intents", {
269
+ method: "POST",
270
+ headers: { "Content-Type": "application/json" },
271
+ body: JSON.stringify({
272
+ customer: customerCreateAttributes,
273
+ paymentIntent: paymentIntentCreateAttributes,
274
+ }),
275
+ });
276
+ if (!response.ok) {
277
+ throw new Error("Failed to create payment intent.");
278
+ }
279
+ const { token } = (await response.json()) as { token: string };
280
+ return token;
281
+ }
254
282
 
255
- function CheckoutGooglePay() {
283
+ function CheckoutWallets({ renderToken }: { renderToken: string }) {
256
284
  const [error, setError] = useState<string | null>(null);
257
285
 
286
+ function handleResult(result: ConfirmationResult) {
287
+ if (result.status === "succeeded") {
288
+ console.log("Confirm returned:", result);
289
+ } else if (result.status === "failed") {
290
+ setError(result.errorMessage);
291
+ } else if (result.status === "incomplete") {
292
+ console.log("Recoverable:", result.reason);
293
+ }
294
+ }
295
+
258
296
  return (
259
297
  <>
260
- <AmosGooglePayButton
261
- renderToken="the-render-token-that-you-created-on-dashboard.amos.com"
262
- amount="5000" // $50.00 in cents, as a string
263
- merchantName="your-user-facing-merchant-name"
264
- onInitiatePaymentIntentRequest={async ({
265
- paymentIntentCreateAttributes,
266
- customerCreateAttributes,
267
- }) => {
268
- const response = await fetch("/api/payment-intents", {
269
- method: "POST",
270
- headers: { "Content-Type": "application/json" },
271
- body: JSON.stringify({
272
- customer: customerCreateAttributes,
273
- paymentIntent: paymentIntentCreateAttributes,
274
- }),
275
- });
276
-
277
- if (!response.ok) {
278
- throw new Error("Failed to create payment intent.");
279
- }
280
-
281
- const { token } = await response.json();
282
- return token;
283
- }}
284
- onResult={(result) => {
285
- if (result.status === "succeeded") {
286
- console.log("Confirm returned:", result);
287
- } else if (result.status === "failed") {
288
- console.error("Confirm failed:", result.errorMessage);
289
- } else if (result.status === "incomplete") {
290
- console.log("Recoverable:", result.reason);
291
- }
292
- }}
293
- />
294
- {error ? <p>{error}</p> : null}
298
+ <div style={{ display: "flex", gap: "12px" }}>
299
+ <div style={{ flex: "1 1 0", minWidth: 0 }}>
300
+ <AmosGooglePayButton
301
+ renderToken={renderToken}
302
+ amount="50.00"
303
+ merchantName="Example Store"
304
+ onInitiatePaymentIntentRequest={createPaymentIntentToken}
305
+ onResult={handleResult}
306
+ />
307
+ </div>
308
+ <div style={{ flex: "1 1 0", minWidth: 0 }}>
309
+ <AmosApplePayButton
310
+ renderToken={renderToken}
311
+ amount="50.00"
312
+ merchantName="Example Store"
313
+ onInitiatePaymentIntentRequest={createPaymentIntentToken}
314
+ onResult={handleResult}
315
+ />
316
+ </div>
317
+ </div>
318
+ {error ? <p role="alert">{error}</p> : null}
295
319
  </>
296
320
  );
297
321
  }
298
322
  ```
299
323
 
300
- `AmosApplePayButton` uses the same props and express-checkout callbacks. Drop it in the same place (or alongside Google Pay) with the same `amount`, `merchantName`, and `onInitiatePaymentIntentRequest` wiring. On Safari, the native payment sheet is used; on other browsers, Apple's QR handoff opens in a popup (`pay.apple.com`). While that popup is open, the SDK shows a waiting overlay on your page with a **Cancel payment** button.
324
+ Do not call `validateForm` or `confirmPaymentIntent` return the embed token from `onInitiatePaymentIntentRequest` and the SDK confirms. Size the mount slot; omitted `buttonProps` keep paint defaults and fill the iframe.
325
+
326
+ On Safari, Apple Pay uses the native payment sheet. On other browsers, Apple's QR handoff opens in a popup (`pay.apple.com`); while that popup is open, the SDK shows a waiting overlay with **Cancel payment**.
327
+
328
+ Optional visuals:
329
+
330
+ ```tsx
331
+ <AmosGooglePayButton
332
+ renderToken={renderToken}
333
+ amount="50.00"
334
+ merchantName="Example Store"
335
+ height="48px"
336
+ buttonProps={{ buttonType: "donate", buttonBorderType: "no_border" }}
337
+ iframeProps={{ style: { borderRadius: "8px" } }}
338
+ onInitiatePaymentIntentRequest={createPaymentIntentToken}
339
+ onResult={handleResult}
340
+ />
341
+
342
+ <AmosApplePayButton
343
+ renderToken={renderToken}
344
+ amount="50.00"
345
+ merchantName="Example Store"
346
+ height="48px"
347
+ buttonProps={{ type: "donate" }}
348
+ iframeProps={{ style: { borderRadius: "8px" } }}
349
+ onInitiatePaymentIntentRequest={createPaymentIntentToken}
350
+ onResult={handleResult}
351
+ />
352
+ ```
301
353
 
302
354
  ### Saving a payment method with setup intent (credit card)
303
355
 
@@ -453,7 +505,7 @@ Renders the secure Google Pay iframe button (express checkout flow).
453
505
  **Required props:**
454
506
 
455
507
  - `renderToken` (`string`)
456
- - `amount` (`string`)
508
+ - `amount` (`string`) — major-currency decimal string shown in the wallet sheet (e.g. `"50.00"` for $50.00). The iframe converts this to cents in `paymentIntentCreateAttributes.amount`.
457
509
  - `merchantName` (`string`)
458
510
  - `onInitiatePaymentIntentRequest` (callback receiving `{ paymentIntentCreateAttributes: components["schemas"]["CreatePaymentIntentInput"]; customerCreateAttributes: components["schemas"]["CreateCustomerInput"] }`, returns `Promise<components["schemas"]["EmbedToken"]["token"]>` — the embed JWT string for confirmation)
459
511
 
@@ -461,51 +513,36 @@ Renders the secure Google Pay iframe button (express checkout flow).
461
513
 
462
514
  **Optional props:**
463
515
 
464
- - `appearance` (`{ themeVariables?: Partial<Record<ThemeVariable, string>>; labels?: "above" | "floating" | "placeholder" }`)
465
- - `fullWidth` (`boolean`, defaults to `false`) fills the component's mount container
466
- - `buttonType` (`"book" | "buy" | "checkout" | "donate" | "order" | "pay" | "plain" | "subscribe" | "short" | "long"`, defaults to `"short"`)
467
- - `buttonColor` (`"default" | "black" | "white"`)
468
- - `buttonRadius` (`number`, 0–20)
469
- - `buttonSizeMode` (`"static" | "fill"`)
470
- - `buttonLocale` (`string`)
471
- - `buttonBorderType` (`"no_border" | "default_border"`)
472
- - `buttonStyle` — styles the Google Pay button **inside** the iframe, for example `buttonStyle={{ height: "48px" }}`
473
- - `iframeStyle` — styles the host-page `<iframe>` element
474
- - `style` — backward-compatible alias for `buttonStyle`; prefer the explicit name in new integrations
516
+ - `height` (`string`, defaults to `"48px"`) painted button height. CSS length (e.g. `"48px"`).
517
+ - `buttonProps` native Google Pay button options. Omitted fields keep `"plain"` / `"fill"`. The button fills the iframe; size the mount slot, not the button. Compact: `buttonProps={{ buttonSizeMode: "static", style: { width: "240px" } }}`.
518
+ - `iframeProps` — applied to the host-page `<iframe>` (e.g. `className`, `style`, `id`). Use CSS lengths with units in `style` (`{ borderRadius: "8px" }`). Amos does not ship Tailwind `className` only works if the host page defines those classes.
475
519
 
476
520
  ```tsx
477
521
  <AmosGooglePayButton
478
- fullWidth
479
- buttonStyle={{ height: "48px" }}
480
- iframeStyle={{ borderRadius: "6px" }}
522
+ buttonProps={{ buttonType: "donate", buttonBorderType: "no_border" }}
523
+ iframeProps={{ style: { borderRadius: "8px" } }}
481
524
  // ...required props
482
525
  />
483
526
  ```
484
527
 
485
- **Also accepts:** standard iframe props, minus `src`, `title`, `name`, `role`, `allow`, and `style`.
486
-
487
528
  ### `AmosApplePayButton`
488
529
 
489
530
  Renders the secure Apple Pay iframe button (express checkout flow). Same required props and callbacks as `AmosGooglePayButton`.
490
531
 
491
- **Optional visual props** use Apple's `<apple-pay-button>` attribute names:
532
+ **Optional visual props:**
492
533
 
493
- - `fullWidth` (`boolean`, defaults to `false`) — fills the component's mount container
494
- - `buttonstyle` (`"black" | "white" | "white-outline"`, defaults to `"black"`)
495
- - `type` (`"plain" | "buy" | "set-up" | "donate" | "check-out" | "book" | "subscribe" | "reload" | "add-money" | "top-up" | "order" | "rent" | "support" | "contribute" | "tip"`, defaults to `"plain"`)
496
- - `locale` (`string`, BCP 47, defaults to `"en-US"`)
497
- - `buttonStyle` — forwarded to the `<apple-pay-button>` inside the iframe. Apple maps a CSS `height` onto its required custom property.
498
- - `iframeStyle` — styles the host-page `<iframe>` element
499
- - `style` — backward-compatible alias for `buttonStyle`
534
+ - `height` (`string`, defaults to `"48px"`) — painted button height. CSS length (e.g. `"48px"`). Apple ignores CSS `height`; Amos maps this for you.
535
+ - `buttonProps` — native `<apple-pay-button>` attributes. Omitted fields keep Apple's `black` / `plain` / `en-US`. The button fills the iframe; size the mount slot, not the button. `style.width` also updates `--apple-pay-button-width` unless you set that custom property yourself.
536
+ - `iframeProps` host-page `<iframe>` chrome (same as Google Pay).
500
537
 
501
538
  ```tsx
502
539
  <AmosApplePayButton
503
- fullWidth
504
- buttonstyle="white-outline"
505
- type="buy"
506
- locale="en-GB"
507
- buttonStyle={{ height: "48px" }}
508
- iframeStyle={{ borderRadius: "6px" }}
540
+ buttonProps={{
541
+ buttonstyle: "white-outline",
542
+ type: "buy",
543
+ locale: "en-GB",
544
+ }}
545
+ iframeProps={{ style: { borderRadius: "8px" } }}
509
546
  // ...required props
510
547
  />
511
548
  ```
@@ -535,7 +572,7 @@ Re-exports of the same advanced helpers exposed by `@amos.com/amos-js`. Most int
535
572
  - **`ref` / `iframeRef`**: for card and bank forms, pass `ref={iframeRef}` to the form component. The same `iframeRef` must be used when calling `validateForm`, `confirmPaymentIntent`, `confirmSetupIntent`, or `resetForm`. The component forwards the ref to the inner iframe.
536
573
  - **`onResult` is not settlement proof**: `onResult` tells you when to stop waiting (e.g. dismiss a spinner). Verify payment or setup success on your backend via webhooks. On `status: "incomplete"`, unlock your UI — the customer can fix fields in the iframe and retry. Use `result.reason` (`"field_errors"` or `"validation_failed"`) to distinguish recoverable states.
537
574
  - **Same components for payment vs setup intents**: `AmosCreditCardPaymentMethodForm` and `AmosBankAccountPaymentMethodForm` support both payment intents and setup intents. The flow differs only by which server call you make and which confirmation function you use (`confirmPaymentIntent` vs `confirmSetupIntent`). Handle both payment and setup outcomes via `onResult`.
538
- - **Amount format**: for `AmosGooglePayButton` and `AmosApplePayButton`, `amount` is a string (e.g. `"5000"` for $50.00). For `components["schemas"]["CreatePaymentIntentInput"]` on the server, `amount` is a number in cents (e.g. `5000`).
575
+ - **Amount format**: for `AmosGooglePayButton` and `AmosApplePayButton`, `amount` is a major-currency decimal string (e.g. `"50.00"` for $50.00). For `components["schemas"]["CreatePaymentIntentInput"]` on the server (card/bank create, and the object the wallet iframe sends to `onInitiatePaymentIntentRequest`), `amount` is a number in cents (e.g. `5000`).
539
576
  - **Apple Pay waiting overlay**: on browsers where Apple's QR handoff opens in a popup (non-Safari), `AmosApplePayButton` shows a fixed full-viewport overlay on the host page until payment completes, the popup closes, or the user clicks **Cancel payment**. Avoid stacking other fixed UI above it.
540
577
  - **Going framework-free**: if you need to use Amos outside of React (vanilla JS, another framework, etc.), use [`@amos.com/amos-js`](../amos-js) directly.
541
578
 
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /// <reference types="googlepay" />
2
- import { Appearance, ApplePayButtonElementProps, BillingAddressRequirement, ConfirmationResult, CreditCardAdditionalFields, GooglePayButtonElementProps, WalletButtonStyle } from '@amos.com/amos-js';
2
+ import { Appearance, ApplePayButtonElementProps, BillingAddressRequirement, ConfirmationResult, CreditCardAdditionalFields, GooglePayButtonElementProps } from '@amos.com/amos-js';
3
3
  import { components } from '@amos.com/node';
4
- import { ComponentProps, RefObject } from 'react';
4
+ import { ComponentProps, Ref, RefObject } from 'react';
5
5
  export * from '@amos.com/amos-js';
6
6
  type IframeRef = RefObject<HTMLIFrameElement | null> | undefined;
7
7
  /**
@@ -40,25 +40,8 @@ export declare function confirmSetupIntent({ iframeRef, token, }: {
40
40
  export declare function resetForm({ iframeRef }: {
41
41
  iframeRef: IframeRef;
42
42
  }): void;
43
+ type ForwardedIframeRef = Ref<HTMLIFrameElement> | undefined;
43
44
  type IframePassthroughProps = Omit<ComponentProps<"iframe">, "src" | "title" | "name" | "role" | "allow">;
44
- type WalletStyleProps = {
45
- /**
46
- * Stretch the wallet button to fill the iframe width.
47
- *
48
- * @default false
49
- */
50
- fullWidth?: boolean;
51
- /** Styles applied to the wallet button inside the Amos iframe. */
52
- buttonStyle?: WalletButtonStyle;
53
- /** Styles applied to the host-page `<iframe>` element. */
54
- iframeStyle?: ComponentProps<"iframe">["style"];
55
- /**
56
- * Styles applied to the wallet button inside the Amos iframe.
57
- *
58
- * @deprecated Use `buttonStyle` to distinguish it from `iframeStyle`.
59
- */
60
- style?: WalletButtonStyle;
61
- };
62
45
  type AmosCreditCardPaymentMethodFormProps = IframePassthroughProps & {
63
46
  renderToken: string;
64
47
  appearance?: Appearance;
@@ -88,27 +71,65 @@ type AmosBankAccountPaymentMethodFormProps = IframePassthroughProps & {
88
71
  billingAddressRequirement?: BillingAddressRequirement;
89
72
  };
90
73
  export declare function AmosBankAccountPaymentMethodForm({ ref, renderToken, appearance, onResult, onValidityChange, billingAddressRequirement, style, ...rest }: AmosBankAccountPaymentMethodFormProps): import("react").JSX.Element;
91
- type AmosGooglePayButtonProps = Omit<IframePassthroughProps, "style"> & Omit<GooglePayButtonElementProps, "style"> & WalletStyleProps & {
74
+ type AmosGooglePayButtonProps = {
75
+ ref?: ForwardedIframeRef;
92
76
  renderToken: string;
77
+ /**
78
+ * Major-currency decimal string shown in the Google Pay sheet
79
+ * (e.g. `"50.00"` for $50.00). Converted to cents in
80
+ * `paymentIntentCreateAttributes.amount`.
81
+ */
93
82
  amount: string;
94
83
  merchantName: string;
95
- appearance?: Appearance;
84
+ /**
85
+ * Painted button height. CSS length (e.g. `"48px"`).
86
+ * @default "48px"
87
+ */
88
+ height?: string;
89
+ /**
90
+ * Native Google Pay button attributes and inner style. Omitted
91
+ * fields keep Amos paint defaults (`buttonType: "plain"`,
92
+ * `buttonSizeMode: "fill"`). The button fills the iframe — size the
93
+ * mount slot, not the button.
94
+ */
95
+ buttonProps?: GooglePayButtonElementProps;
96
+ /** Props applied to the host-page `<iframe>` element. */
97
+ iframeProps?: IframePassthroughProps;
96
98
  onInitiatePaymentIntentRequest: ({ paymentIntentCreateAttributes, customerCreateAttributes, }: {
97
99
  paymentIntentCreateAttributes: components["schemas"]["CreatePaymentIntentInput"];
98
100
  customerCreateAttributes: components["schemas"]["CreateCustomerInput"];
99
101
  }) => Promise<components["schemas"]["EmbedToken"]["token"]>;
100
102
  onResult: (result: ConfirmationResult) => void;
101
103
  };
102
- export declare function AmosGooglePayButton({ ref, renderToken, amount, merchantName, appearance, onInitiatePaymentIntentRequest, onResult, buttonType, buttonColor, buttonRadius, buttonSizeMode, buttonLocale, buttonBorderType, fullWidth, buttonStyle, iframeStyle, style, ...rest }: AmosGooglePayButtonProps): import("react").JSX.Element;
103
- type AmosApplePayButtonProps = Omit<IframePassthroughProps, "style" | "type"> & Omit<ApplePayButtonElementProps, "style"> & WalletStyleProps & {
104
+ export declare function AmosGooglePayButton({ ref, renderToken, amount, merchantName, height, buttonProps, iframeProps, onInitiatePaymentIntentRequest, onResult, }: AmosGooglePayButtonProps): import("react").JSX.Element;
105
+ type AmosApplePayButtonProps = {
106
+ ref?: ForwardedIframeRef;
104
107
  renderToken: string;
108
+ /**
109
+ * Major-currency decimal string shown in the Apple Pay sheet
110
+ * (e.g. `"50.00"` for $50.00). Converted to cents in
111
+ * `paymentIntentCreateAttributes.amount`.
112
+ */
105
113
  amount: string;
106
114
  merchantName: string;
107
- appearance?: Appearance;
115
+ /**
116
+ * Painted button height. CSS length (e.g. `"48px"`). Apple ignores
117
+ * CSS `height`; Amos maps this for you.
118
+ * @default "48px"
119
+ */
120
+ height?: string;
121
+ /**
122
+ * Native `<apple-pay-button>` attributes and inner style. Omitted
123
+ * fields keep Apple's defaults (`black` / `plain` / `en-US`). The
124
+ * button fills the iframe — size the mount slot, not the button.
125
+ */
126
+ buttonProps?: ApplePayButtonElementProps;
127
+ /** Props applied to the host-page `<iframe>` element. */
128
+ iframeProps?: IframePassthroughProps;
108
129
  onInitiatePaymentIntentRequest: ({ paymentIntentCreateAttributes, customerCreateAttributes, }: {
109
130
  paymentIntentCreateAttributes: components["schemas"]["CreatePaymentIntentInput"];
110
131
  customerCreateAttributes: components["schemas"]["CreateCustomerInput"];
111
132
  }) => Promise<components["schemas"]["EmbedToken"]["token"]>;
112
133
  onResult: (result: ConfirmationResult) => void;
113
134
  };
114
- export declare function AmosApplePayButton({ ref, renderToken, amount, merchantName, appearance, onInitiatePaymentIntentRequest, onResult, buttonstyle, type, locale, fullWidth, buttonStyle, iframeStyle, style, ...rest }: AmosApplePayButtonProps): import("react").JSX.Element;
135
+ export declare function AmosApplePayButton({ ref, renderToken, amount, merchantName, height, buttonProps, iframeProps, onInitiatePaymentIntentRequest, onResult, }: AmosApplePayButtonProps): import("react").JSX.Element;
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@amos.com/amos-js"),t=require("react"),n=require("react/jsx-runtime");function r(e){return e?e.current??null:null}function i({iframeRef:t}){return(0,e.validateForm)({iframe:r(t)})}function a({iframeRef:t,token:n}){(0,e.confirmPaymentIntent)({iframe:r(t),token:n})}function o({iframeRef:t,token:n}){(0,e.confirmSetupIntent)({iframe:r(t),token:n})}function s({iframeRef:t}){(0,e.resetForm)({iframe:r(t)})}function c(e,t){typeof e==`function`?e(t):e&&(e.current=t)}function l({buttonSizeMode:e,style:t,fullWidth:n}){return{buttonSizeMode:e??(n?`fill`:void 0),style:n?{width:`100%`,...t}:t}}function u({style:e,fullWidth:t}){return t?{style:{"--apple-pay-button-width":`100%`,width:`100%`,...e}}:{style:e}}function d(e,{style:t,className:n,id:r,...i}){n!=null&&(e.className=n),r!=null&&(e.id=r),t!=null&&Object.assign(e.style,t);for(let[t,n]of Object.entries(i))n!=null&&(t in e?Reflect.set(e,t,n):e.setAttribute(t,String(n)))}function f({containerRef:e,iframeRef:n,mount:r,options:i,remountDeps:a,iframePassthrough:o,updateDeps:s}){let l=(0,t.useRef)(null);(0,t.useEffect)(()=>{let t=e.current;if(!t)return;let a=r(t,i);return l.current=a,c(n,a.iframe),d(a.iframe,o),()=>{a.destroy(),l.current=null,c(n,null)}},[...a]),(0,t.useEffect)(()=>{l.current?.update(i)},[...s]),(0,t.useEffect)(()=>{let e=l.current?.iframe;e&&d(e,o)})}function p({ref:r,renderToken:i,appearance:a,onResult:o,onValidityChange:s,additionalFields:c={cardholderName:!1},billingAddressRequirement:l=`country`,style:u,...d}){let p=(0,t.useRef)(null);return f({containerRef:p,iframeRef:r,mount:e.mountAmosCreditCardPaymentMethodForm,options:{renderToken:i,appearance:a,additionalFields:c,billingAddressRequirement:l,onResult:o,onValidityChange:s},remountDeps:[i,c.cardholderName,l],iframePassthrough:{style:u,...d},updateDeps:[a,c,l,o,s]}),(0,n.jsx)(`div`,{ref:p})}function m({ref:r,renderToken:i,appearance:a,onResult:o,onValidityChange:s,billingAddressRequirement:c=`country`,style:l,...u}){let d=(0,t.useRef)(null);return f({containerRef:d,iframeRef:r,mount:e.mountAmosBankAccountPaymentMethodForm,options:{renderToken:i,appearance:a,billingAddressRequirement:c,onResult:o,onValidityChange:s},remountDeps:[i,c],iframePassthrough:{style:l,...u},updateDeps:[a,c,o,s]}),(0,n.jsx)(`div`,{ref:d})}function h({ref:r,renderToken:i,amount:a,merchantName:o,appearance:s,onInitiatePaymentIntentRequest:c,onResult:u,buttonType:d,buttonColor:p,buttonRadius:m,buttonSizeMode:h,buttonLocale:g,buttonBorderType:_,fullWidth:v=!1,buttonStyle:y,iframeStyle:b,style:x,...S}){let C=(0,t.useRef)(null),w=l({buttonSizeMode:h,style:y??x,fullWidth:v});return f({containerRef:C,iframeRef:r,mount:e.mountAmosGooglePayButton,options:{renderToken:i,amount:a,merchantName:o,appearance:s,onInitiatePaymentIntentRequest:c,onResult:u,buttonType:d,buttonColor:p,buttonRadius:m,buttonSizeMode:w.buttonSizeMode,buttonLocale:g,buttonBorderType:_,style:w.style},remountDeps:[i],iframePassthrough:{style:b,...S},updateDeps:[a,o,s,c,u,d,p,m,w.buttonSizeMode,g,_,w.style]}),(0,n.jsx)(`div`,{ref:C})}function g({ref:r,renderToken:i,amount:a,merchantName:o,appearance:s,onInitiatePaymentIntentRequest:c,onResult:l,buttonstyle:d,type:p,locale:m,fullWidth:h=!1,buttonStyle:g,iframeStyle:_,style:v,...y}){let b=(0,t.useRef)(null),x=u({style:g??v,fullWidth:h});return f({containerRef:b,iframeRef:r,mount:e.mountAmosApplePayButton,options:{renderToken:i,amount:a,merchantName:o,appearance:s,onInitiatePaymentIntentRequest:c,onResult:l,buttonstyle:d,type:p,locale:m,style:x.style},remountDeps:[i],iframePassthrough:{style:_,...y},updateDeps:[a,o,s,c,l,d,p,m,x.style]}),(0,n.jsx)(`div`,{ref:b})}exports.AmosApplePayButton=g,exports.AmosBankAccountPaymentMethodForm=m,exports.AmosCreditCardPaymentMethodForm=p,exports.AmosGooglePayButton=h,exports.confirmPaymentIntent=a,exports.confirmSetupIntent=o,exports.resetForm=s,exports.validateForm=i,Object.keys(e).forEach(function(t){t!=="default"&&!Object.prototype.hasOwnProperty.call(exports,t)&&Object.defineProperty(exports,t,{enumerable:!0,get:function(){return e[t]}})});
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@amos.com/amos-js"),t=require("react"),n=require("react/jsx-runtime");function r(e){return e?e.current??null:null}function i({iframeRef:t}){return(0,e.validateForm)({iframe:r(t)})}function a({iframeRef:t,token:n}){(0,e.confirmPaymentIntent)({iframe:r(t),token:n})}function o({iframeRef:t,token:n}){(0,e.confirmSetupIntent)({iframe:r(t),token:n})}function s({iframeRef:t}){(0,e.resetForm)({iframe:r(t)})}function c(e,t){typeof e==`function`?e(t):e&&(e.current=t)}function l(e,{style:t,className:n,id:r,...i}){n!=null&&(e.className=n),r!=null&&(e.id=r),Object.assign(e.style,t);for(let[t,n]of Object.entries(i))n!=null&&(t in e?Reflect.set(e,t,n):e.setAttribute(t,String(n)))}function u({containerRef:e,iframeRef:n,mount:r,options:i,remountDeps:a,iframePassthrough:o,updateDeps:s}){let u=(0,t.useRef)(null);(0,t.useEffect)(()=>{let t=e.current;if(!t)return;let a=r(t,i);return u.current=a,c(n,a.iframe),l(a.iframe,o),()=>{a.destroy(),u.current=null,c(n,null)}},[...a]),(0,t.useEffect)(()=>{u.current?.update(i)},[...s]),(0,t.useEffect)(()=>{let e=u.current?.iframe;e&&l(e,o)})}function d({ref:r,renderToken:i,appearance:a,onResult:o,onValidityChange:s,additionalFields:c={cardholderName:!1},billingAddressRequirement:l=`country`,style:d,...f}){let p=(0,t.useRef)(null);return u({containerRef:p,iframeRef:r,mount:e.mountAmosCreditCardPaymentMethodForm,options:{renderToken:i,appearance:a,additionalFields:c,billingAddressRequirement:l,onResult:o,onValidityChange:s},remountDeps:[i,c.cardholderName,l],iframePassthrough:{style:d,...f},updateDeps:[a,c,l,o,s]}),(0,n.jsx)(`div`,{ref:p})}function f({ref:r,renderToken:i,appearance:a,onResult:o,onValidityChange:s,billingAddressRequirement:c=`country`,style:l,...d}){let f=(0,t.useRef)(null);return u({containerRef:f,iframeRef:r,mount:e.mountAmosBankAccountPaymentMethodForm,options:{renderToken:i,appearance:a,billingAddressRequirement:c,onResult:o,onValidityChange:s},remountDeps:[i,c],iframePassthrough:{style:l,...d},updateDeps:[a,c,o,s]}),(0,n.jsx)(`div`,{ref:f})}function p({ref:r,renderToken:i,amount:a,merchantName:o,height:s=`48px`,buttonProps:c,iframeProps:l,onInitiatePaymentIntentRequest:d,onResult:f}){let p=(0,t.useRef)(null);return u({containerRef:p,iframeRef:r,mount:e.mountAmosGooglePayButton,options:{renderToken:i,amount:a,merchantName:o,height:s,buttonProps:c,onInitiatePaymentIntentRequest:d,onResult:f},remountDeps:[i],iframePassthrough:l??{},updateDeps:[a,o,s,c,d,f]}),(0,n.jsx)(`div`,{ref:p})}function m({ref:r,renderToken:i,amount:a,merchantName:o,height:s=`48px`,buttonProps:c,iframeProps:l,onInitiatePaymentIntentRequest:d,onResult:f}){let p=(0,t.useRef)(null);return u({containerRef:p,iframeRef:r,mount:e.mountAmosApplePayButton,options:{renderToken:i,amount:a,merchantName:o,height:s,buttonProps:c,onInitiatePaymentIntentRequest:d,onResult:f},remountDeps:[i],iframePassthrough:l??{},updateDeps:[a,o,s,c,d,f]}),(0,n.jsx)(`div`,{ref:p})}exports.AmosApplePayButton=m,exports.AmosBankAccountPaymentMethodForm=f,exports.AmosCreditCardPaymentMethodForm=d,exports.AmosGooglePayButton=p,exports.confirmPaymentIntent=a,exports.confirmSetupIntent=o,exports.resetForm=s,exports.validateForm=i,Object.keys(e).forEach(function(t){t!=="default"&&!Object.prototype.hasOwnProperty.call(exports,t)&&Object.defineProperty(exports,t,{enumerable:!0,get:function(){return e[t]}})});
package/dist/index.mjs CHANGED
@@ -27,45 +27,29 @@ function h({ iframeRef: e }) {
27
27
  function g(e, t) {
28
28
  typeof e == "function" ? e(t) : e && (e.current = t);
29
29
  }
30
- function _({ buttonSizeMode: e, style: t, fullWidth: n }) {
31
- return {
32
- buttonSizeMode: e ?? (n ? "fill" : void 0),
33
- style: n ? {
34
- width: "100%",
35
- ...t
36
- } : t
37
- };
38
- }
39
- function v({ style: e, fullWidth: t }) {
40
- return t ? { style: {
41
- "--apple-pay-button-width": "100%",
42
- width: "100%",
43
- ...e
44
- } } : { style: e };
45
- }
46
- function y(e, { style: t, className: n, id: r, ...i }) {
47
- n != null && (e.className = n), r != null && (e.id = r), t != null && Object.assign(e.style, t);
30
+ function _(e, { style: t, className: n, id: r, ...i }) {
31
+ n != null && (e.className = n), r != null && (e.id = r), Object.assign(e.style, t);
48
32
  for (let [t, n] of Object.entries(i)) n != null && (t in e ? Reflect.set(e, t, n) : e.setAttribute(t, String(n)));
49
33
  }
50
- function b({ containerRef: e, iframeRef: t, mount: n, options: r, remountDeps: i, iframePassthrough: a, updateDeps: o }) {
34
+ function v({ containerRef: e, iframeRef: t, mount: n, options: r, remountDeps: i, iframePassthrough: a, updateDeps: o }) {
51
35
  let s = l(null);
52
36
  c(() => {
53
37
  let i = e.current;
54
38
  if (!i) return;
55
39
  let o = n(i, r);
56
- return s.current = o, g(t, o.iframe), y(o.iframe, a), () => {
40
+ return s.current = o, g(t, o.iframe), _(o.iframe, a), () => {
57
41
  o.destroy(), s.current = null, g(t, null);
58
42
  };
59
43
  }, [...i]), c(() => {
60
44
  s.current?.update(r);
61
45
  }, [...o]), c(() => {
62
46
  let e = s.current?.iframe;
63
- e && y(e, a);
47
+ e && _(e, a);
64
48
  });
65
49
  }
66
- function x({ ref: e, renderToken: t, appearance: n, onResult: r, onValidityChange: a, additionalFields: o = { cardholderName: !1 }, billingAddressRequirement: s = "country", style: c, ...d }) {
50
+ function y({ ref: e, renderToken: t, appearance: n, onResult: r, onValidityChange: a, additionalFields: o = { cardholderName: !1 }, billingAddressRequirement: s = "country", style: c, ...d }) {
67
51
  let f = l(null);
68
- return b({
52
+ return v({
69
53
  containerRef: f,
70
54
  iframeRef: e,
71
55
  mount: i,
@@ -95,9 +79,9 @@ function x({ ref: e, renderToken: t, appearance: n, onResult: r, onValidityChang
95
79
  ]
96
80
  }), /* @__PURE__ */ u("div", { ref: f });
97
81
  }
98
- function S({ ref: e, renderToken: t, appearance: n, onResult: i, onValidityChange: a, billingAddressRequirement: o = "country", style: s, ...c }) {
82
+ function b({ ref: e, renderToken: t, appearance: n, onResult: i, onValidityChange: a, billingAddressRequirement: o = "country", style: s, ...c }) {
99
83
  let d = l(null);
100
- return b({
84
+ return v({
101
85
  containerRef: d,
102
86
  iframeRef: e,
103
87
  mount: r,
@@ -121,90 +105,59 @@ function S({ ref: e, renderToken: t, appearance: n, onResult: i, onValidityChang
121
105
  ]
122
106
  }), /* @__PURE__ */ u("div", { ref: d });
123
107
  }
124
- function C({ ref: e, renderToken: t, amount: n, merchantName: r, appearance: i, onInitiatePaymentIntentRequest: o, onResult: s, buttonType: c, buttonColor: d, buttonRadius: f, buttonSizeMode: p, buttonLocale: m, buttonBorderType: h, fullWidth: g = !1, buttonStyle: v, iframeStyle: y, style: x, ...S }) {
125
- let C = l(null), w = _({
126
- buttonSizeMode: p,
127
- style: v ?? x,
128
- fullWidth: g
129
- });
130
- return b({
131
- containerRef: C,
108
+ function x({ ref: e, renderToken: t, amount: n, merchantName: r, height: i = "48px", buttonProps: o, iframeProps: s, onInitiatePaymentIntentRequest: c, onResult: d }) {
109
+ let f = l(null);
110
+ return v({
111
+ containerRef: f,
132
112
  iframeRef: e,
133
113
  mount: a,
134
114
  options: {
135
115
  renderToken: t,
136
116
  amount: n,
137
117
  merchantName: r,
138
- appearance: i,
139
- onInitiatePaymentIntentRequest: o,
140
- onResult: s,
141
- buttonType: c,
142
- buttonColor: d,
143
- buttonRadius: f,
144
- buttonSizeMode: w.buttonSizeMode,
145
- buttonLocale: m,
146
- buttonBorderType: h,
147
- style: w.style
118
+ height: i,
119
+ buttonProps: o,
120
+ onInitiatePaymentIntentRequest: c,
121
+ onResult: d
148
122
  },
149
123
  remountDeps: [t],
150
- iframePassthrough: {
151
- style: y,
152
- ...S
153
- },
124
+ iframePassthrough: s ?? {},
154
125
  updateDeps: [
155
126
  n,
156
127
  r,
157
128
  i,
158
129
  o,
159
- s,
160
130
  c,
161
- d,
162
- f,
163
- w.buttonSizeMode,
164
- m,
165
- h,
166
- w.style
131
+ d
167
132
  ]
168
- }), /* @__PURE__ */ u("div", { ref: C });
133
+ }), /* @__PURE__ */ u("div", { ref: f });
169
134
  }
170
- function w({ ref: e, renderToken: t, amount: r, merchantName: i, appearance: a, onInitiatePaymentIntentRequest: o, onResult: s, buttonstyle: c, type: d, locale: f, fullWidth: p = !1, buttonStyle: m, iframeStyle: h, style: g, ..._ }) {
171
- let y = l(null), x = v({
172
- style: m ?? g,
173
- fullWidth: p
174
- });
175
- return b({
176
- containerRef: y,
135
+ function S({ ref: e, renderToken: t, amount: r, merchantName: i, height: a = "48px", buttonProps: o, iframeProps: s, onInitiatePaymentIntentRequest: c, onResult: d }) {
136
+ let f = l(null);
137
+ return v({
138
+ containerRef: f,
177
139
  iframeRef: e,
178
140
  mount: n,
179
141
  options: {
180
142
  renderToken: t,
181
143
  amount: r,
182
144
  merchantName: i,
183
- appearance: a,
184
- onInitiatePaymentIntentRequest: o,
185
- onResult: s,
186
- buttonstyle: c,
187
- type: d,
188
- locale: f,
189
- style: x.style
145
+ height: a,
146
+ buttonProps: o,
147
+ onInitiatePaymentIntentRequest: c,
148
+ onResult: d
190
149
  },
191
150
  remountDeps: [t],
192
- iframePassthrough: {
193
- style: h,
194
- ..._
195
- },
151
+ iframePassthrough: s ?? {},
196
152
  updateDeps: [
197
153
  r,
198
154
  i,
199
155
  a,
200
156
  o,
201
- s,
202
157
  c,
203
- d,
204
- f,
205
- x.style
158
+ d
206
159
  ]
207
- }), /* @__PURE__ */ u("div", { ref: y });
160
+ }), /* @__PURE__ */ u("div", { ref: f });
208
161
  }
209
162
  //#endregion
210
- export { w as AmosApplePayButton, S as AmosBankAccountPaymentMethodForm, x as AmosCreditCardPaymentMethodForm, C as AmosGooglePayButton, p as confirmPaymentIntent, m as confirmSetupIntent, h as resetForm, f as validateForm };
163
+ export { S as AmosApplePayButton, b as AmosBankAccountPaymentMethodForm, y as AmosCreditCardPaymentMethodForm, x as AmosGooglePayButton, p as confirmPaymentIntent, m as confirmSetupIntent, h as resetForm, f as validateForm };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amos.com/react-amos-js",
3
- "version": "0.9.13",
3
+ "version": "0.9.15",
4
4
  "main": "dist/index.js",
5
5
  "repository": {
6
6
  "type": "git",
@@ -48,7 +48,7 @@
48
48
  "vite-plugin-dts": "5.0.3"
49
49
  },
50
50
  "dependencies": {
51
- "@amos.com/amos-js": "0.9.14",
51
+ "@amos.com/amos-js": "0.9.16",
52
52
  "@types/googlepay": "0.7.11"
53
53
  },
54
54
  "peerDependencies": {
package/src/index.tsx CHANGED
@@ -15,7 +15,6 @@ import {
15
15
  mountAmosBankAccountPaymentMethodForm,
16
16
  mountAmosCreditCardPaymentMethodForm,
17
17
  mountAmosGooglePayButton,
18
- type WalletButtonStyle,
19
18
  } from "@amos.com/amos-js";
20
19
  import type { components } from "@amos.com/node";
21
20
  import {
@@ -109,59 +108,6 @@ type IframePassthroughProps = Omit<
109
108
  "src" | "title" | "name" | "role" | "allow"
110
109
  >;
111
110
 
112
- type WalletStyleProps = {
113
- /**
114
- * Stretch the wallet button to fill the iframe width.
115
- *
116
- * @default false
117
- */
118
- fullWidth?: boolean;
119
- /** Styles applied to the wallet button inside the Amos iframe. */
120
- buttonStyle?: WalletButtonStyle;
121
- /** Styles applied to the host-page `<iframe>` element. */
122
- iframeStyle?: ComponentProps<"iframe">["style"];
123
- /**
124
- * Styles applied to the wallet button inside the Amos iframe.
125
- *
126
- * @deprecated Use `buttonStyle` to distinguish it from `iframeStyle`.
127
- */
128
- style?: WalletButtonStyle;
129
- };
130
-
131
- function resolveGooglePayButtonLayout({
132
- buttonSizeMode,
133
- style,
134
- fullWidth,
135
- }: {
136
- buttonSizeMode?: GooglePayButtonElementProps["buttonSizeMode"];
137
- style?: WalletButtonStyle;
138
- fullWidth: boolean;
139
- }): Pick<GooglePayButtonElementProps, "buttonSizeMode" | "style"> {
140
- return {
141
- buttonSizeMode: buttonSizeMode ?? (fullWidth ? "fill" : undefined),
142
- style: fullWidth ? { width: "100%", ...style } : style,
143
- };
144
- }
145
-
146
- function resolveApplePayButtonLayout({
147
- style,
148
- fullWidth,
149
- }: {
150
- style?: WalletButtonStyle;
151
- fullWidth: boolean;
152
- }): Pick<ApplePayButtonElementProps, "style"> {
153
- if (!fullWidth) {
154
- return { style };
155
- }
156
- return {
157
- style: {
158
- "--apple-pay-button-width": "100%",
159
- width: "100%",
160
- ...style,
161
- },
162
- };
163
- }
164
-
165
111
  function applyIframePassthrough(
166
112
  iframe: HTMLIFrameElement,
167
113
  { style, className, id, ...rest }: IframePassthroughProps,
@@ -172,9 +118,7 @@ function applyIframePassthrough(
172
118
  if (id != null) {
173
119
  iframe.id = id;
174
120
  }
175
- if (style != null) {
176
- Object.assign(iframe.style, style);
177
- }
121
+ Object.assign(iframe.style, style);
178
122
  for (const [key, value] of Object.entries(rest)) {
179
123
  if (value == null) {
180
124
  continue;
@@ -348,50 +292,52 @@ export function AmosBankAccountPaymentMethodForm({
348
292
  return <div ref={containerRef} />;
349
293
  }
350
294
 
351
- type AmosGooglePayButtonProps = Omit<IframePassthroughProps, "style"> &
352
- Omit<GooglePayButtonElementProps, "style"> &
353
- WalletStyleProps & {
354
- renderToken: string;
355
- amount: string;
356
- merchantName: string;
357
- appearance?: Appearance;
358
- onInitiatePaymentIntentRequest: ({
359
- paymentIntentCreateAttributes,
360
- customerCreateAttributes,
361
- }: {
362
- paymentIntentCreateAttributes: components["schemas"]["CreatePaymentIntentInput"];
363
- customerCreateAttributes: components["schemas"]["CreateCustomerInput"];
364
- }) => Promise<components["schemas"]["EmbedToken"]["token"]>;
365
- onResult: (result: ConfirmationResult) => void;
366
- };
295
+ type AmosGooglePayButtonProps = {
296
+ ref?: ForwardedIframeRef;
297
+ renderToken: string;
298
+ /**
299
+ * Major-currency decimal string shown in the Google Pay sheet
300
+ * (e.g. `"50.00"` for $50.00). Converted to cents in
301
+ * `paymentIntentCreateAttributes.amount`.
302
+ */
303
+ amount: string;
304
+ merchantName: string;
305
+ /**
306
+ * Painted button height. CSS length (e.g. `"48px"`).
307
+ * @default "48px"
308
+ */
309
+ height?: string;
310
+ /**
311
+ * Native Google Pay button attributes and inner style. Omitted
312
+ * fields keep Amos paint defaults (`buttonType: "plain"`,
313
+ * `buttonSizeMode: "fill"`). The button fills the iframe — size the
314
+ * mount slot, not the button.
315
+ */
316
+ buttonProps?: GooglePayButtonElementProps;
317
+ /** Props applied to the host-page `<iframe>` element. */
318
+ iframeProps?: IframePassthroughProps;
319
+ onInitiatePaymentIntentRequest: ({
320
+ paymentIntentCreateAttributes,
321
+ customerCreateAttributes,
322
+ }: {
323
+ paymentIntentCreateAttributes: components["schemas"]["CreatePaymentIntentInput"];
324
+ customerCreateAttributes: components["schemas"]["CreateCustomerInput"];
325
+ }) => Promise<components["schemas"]["EmbedToken"]["token"]>;
326
+ onResult: (result: ConfirmationResult) => void;
327
+ };
367
328
 
368
329
  export function AmosGooglePayButton({
369
330
  ref,
370
331
  renderToken,
371
332
  amount,
372
333
  merchantName,
373
- appearance,
334
+ height = "48px",
335
+ buttonProps,
336
+ iframeProps,
374
337
  onInitiatePaymentIntentRequest,
375
338
  onResult,
376
- buttonType,
377
- buttonColor,
378
- buttonRadius,
379
- buttonSizeMode,
380
- buttonLocale,
381
- buttonBorderType,
382
- fullWidth = false,
383
- buttonStyle,
384
- iframeStyle,
385
- style,
386
- ...rest
387
339
  }: AmosGooglePayButtonProps) {
388
340
  const containerRef = useRef<HTMLDivElement | null>(null);
389
- const resolvedStyle = buttonStyle ?? style;
390
- const layout = resolveGooglePayButtonLayout({
391
- buttonSizeMode,
392
- style: resolvedStyle,
393
- fullWidth,
394
- });
395
341
 
396
342
  useAmosEmbed({
397
343
  containerRef,
@@ -401,78 +347,72 @@ export function AmosGooglePayButton({
401
347
  renderToken,
402
348
  amount,
403
349
  merchantName,
404
- appearance,
350
+ height,
351
+ buttonProps,
405
352
  onInitiatePaymentIntentRequest,
406
353
  onResult,
407
- buttonType,
408
- buttonColor,
409
- buttonRadius,
410
- buttonSizeMode: layout.buttonSizeMode,
411
- buttonLocale,
412
- buttonBorderType,
413
- style: layout.style,
414
354
  },
415
355
  remountDeps: [renderToken],
416
- iframePassthrough: { style: iframeStyle, ...rest },
356
+ iframePassthrough: iframeProps ?? {},
417
357
  updateDeps: [
418
358
  amount,
419
359
  merchantName,
420
- appearance,
360
+ height,
361
+ buttonProps,
421
362
  onInitiatePaymentIntentRequest,
422
363
  onResult,
423
- buttonType,
424
- buttonColor,
425
- buttonRadius,
426
- layout.buttonSizeMode,
427
- buttonLocale,
428
- buttonBorderType,
429
- layout.style,
430
364
  ],
431
365
  });
432
366
 
433
367
  return <div ref={containerRef} />;
434
368
  }
435
369
 
436
- type AmosApplePayButtonProps = Omit<IframePassthroughProps, "style" | "type"> &
437
- Omit<ApplePayButtonElementProps, "style"> &
438
- WalletStyleProps & {
439
- renderToken: string;
440
- amount: string;
441
- merchantName: string;
442
- appearance?: Appearance;
443
- onInitiatePaymentIntentRequest: ({
444
- paymentIntentCreateAttributes,
445
- customerCreateAttributes,
446
- }: {
447
- paymentIntentCreateAttributes: components["schemas"]["CreatePaymentIntentInput"];
448
- customerCreateAttributes: components["schemas"]["CreateCustomerInput"];
449
- }) => Promise<components["schemas"]["EmbedToken"]["token"]>;
450
- onResult: (result: ConfirmationResult) => void;
451
- };
370
+ type AmosApplePayButtonProps = {
371
+ ref?: ForwardedIframeRef;
372
+ renderToken: string;
373
+ /**
374
+ * Major-currency decimal string shown in the Apple Pay sheet
375
+ * (e.g. `"50.00"` for $50.00). Converted to cents in
376
+ * `paymentIntentCreateAttributes.amount`.
377
+ */
378
+ amount: string;
379
+ merchantName: string;
380
+ /**
381
+ * Painted button height. CSS length (e.g. `"48px"`). Apple ignores
382
+ * CSS `height`; Amos maps this for you.
383
+ * @default "48px"
384
+ */
385
+ height?: string;
386
+ /**
387
+ * Native `<apple-pay-button>` attributes and inner style. Omitted
388
+ * fields keep Apple's defaults (`black` / `plain` / `en-US`). The
389
+ * button fills the iframe — size the mount slot, not the button.
390
+ */
391
+ buttonProps?: ApplePayButtonElementProps;
392
+ /** Props applied to the host-page `<iframe>` element. */
393
+ iframeProps?: IframePassthroughProps;
394
+ onInitiatePaymentIntentRequest: ({
395
+ paymentIntentCreateAttributes,
396
+ customerCreateAttributes,
397
+ }: {
398
+ paymentIntentCreateAttributes: components["schemas"]["CreatePaymentIntentInput"];
399
+ customerCreateAttributes: components["schemas"]["CreateCustomerInput"];
400
+ }) => Promise<components["schemas"]["EmbedToken"]["token"]>;
401
+ onResult: (result: ConfirmationResult) => void;
402
+ };
452
403
 
453
404
  export function AmosApplePayButton({
454
405
  ref,
455
406
  renderToken,
456
407
  amount,
457
408
  merchantName,
458
- appearance,
409
+ height = "48px",
410
+ buttonProps,
411
+ iframeProps,
459
412
  onInitiatePaymentIntentRequest,
460
413
  onResult,
461
- buttonstyle,
462
- type,
463
- locale,
464
- fullWidth = false,
465
- buttonStyle,
466
- iframeStyle,
467
- style,
468
- ...rest
469
414
  }: AmosApplePayButtonProps) {
470
415
  const containerRef = useRef<HTMLDivElement | null>(null);
471
- const resolvedStyle = buttonStyle ?? style;
472
- const layout = resolveApplePayButtonLayout({
473
- style: resolvedStyle,
474
- fullWidth,
475
- });
476
416
 
477
417
  useAmosEmbed({
478
418
  containerRef,
@@ -482,26 +422,20 @@ export function AmosApplePayButton({
482
422
  renderToken,
483
423
  amount,
484
424
  merchantName,
485
- appearance,
425
+ height,
426
+ buttonProps,
486
427
  onInitiatePaymentIntentRequest,
487
428
  onResult,
488
- buttonstyle,
489
- type,
490
- locale,
491
- style: layout.style,
492
429
  },
493
430
  remountDeps: [renderToken],
494
- iframePassthrough: { style: iframeStyle, ...rest },
431
+ iframePassthrough: iframeProps ?? {},
495
432
  updateDeps: [
496
433
  amount,
497
434
  merchantName,
498
- appearance,
435
+ height,
436
+ buttonProps,
499
437
  onInitiatePaymentIntentRequest,
500
438
  onResult,
501
- buttonstyle,
502
- type,
503
- locale,
504
- layout.style,
505
439
  ],
506
440
  });
507
441