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

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
@@ -39,7 +39,7 @@ The render token configures the iframe's allowed origin(s), allowed payment meth
39
39
  The following flow is for credit card and bank account payment method types only.
40
40
 
41
41
  1. **Set up prerequisites**: create a `renderToken` (safe for client), and keep `apiKey` and `accountId` server-side only.
42
- 2. **Render your checkout UI** with one of the payment method components (e.g. `AmosCreditCardPaymentMethodForm`) along with the required `onResult` prop. Card and bank forms show a field-shaped skeleton immediately (sized from `appearance`, `additionalFields`, and `billingAddressRequirement`); iframe height is auto-managed.
42
+ 2. **Render your checkout UI** with one of the payment method components (e.g. `AmosCreditCardPaymentMethodForm`) along with the required `onResult` prop. Card and bank forms show a field-shaped skeleton immediately (sized from `appearance`, `additionalFields`, and `billingAddressRequirement`); Google Pay and Apple Pay paint a button-shaped skeleton in the parent document on first render so the 48px slot is reserved before the iframe loads.
43
43
  3. **User clicks "Pay now" button**: call `validateForm({ iframeRef })`, which returns `Promise<true>` if the embedded form is valid and `Promise<false>` otherwise.
44
44
  4. **Create payment intent on your server**: use your server-side Amos client to call `POST /payment_intents`. You may also associate this payment intent with a new or existing customer via `POST /customers`. This must be server-side because it uses your private API key.
45
45
  5. **Return the payment intent token to the browser**: your backend responds with the embed token (`components["schemas"]["EmbedToken"]`) needed for confirmation.
@@ -500,7 +500,7 @@ Renders the secure bank account iframe form. A field-shaped skeleton is shown im
500
500
 
501
501
  ### `AmosGooglePayButton`
502
502
 
503
- Renders the secure Google Pay iframe button (express checkout flow).
503
+ Renders the secure Google Pay iframe button (express checkout flow). A button-shaped skeleton is shown immediately and replaced by the iframe once appearance is applied.
504
504
 
505
505
  **Required props:**
506
506
 
@@ -527,7 +527,7 @@ Renders the secure Google Pay iframe button (express checkout flow).
527
527
 
528
528
  ### `AmosApplePayButton`
529
529
 
530
- Renders the secure Apple Pay iframe button (express checkout flow). Same required props and callbacks as `AmosGooglePayButton`.
530
+ Renders the secure Apple Pay iframe button (express checkout flow). Same required props and callbacks as `AmosGooglePayButton`. A button-shaped skeleton is shown immediately and replaced by the iframe once appearance is applied.
531
531
 
532
532
  **Optional visual props:**
533
533
 
package/dist/index.d.ts CHANGED
@@ -101,6 +101,11 @@ type AmosGooglePayButtonProps = {
101
101
  }) => Promise<components["schemas"]["EmbedToken"]["token"]>;
102
102
  onResult: (result: ConfirmationResult) => void;
103
103
  };
104
+ /**
105
+ * Renders the secure Google Pay iframe button. A button-shaped
106
+ * skeleton is painted in the parent document on first render (including
107
+ * SSR) so the slot height is reserved before the iframe loads.
108
+ */
104
109
  export declare function AmosGooglePayButton({ ref, renderToken, amount, merchantName, height, buttonProps, iframeProps, onInitiatePaymentIntentRequest, onResult, }: AmosGooglePayButtonProps): import("react").JSX.Element;
105
110
  type AmosApplePayButtonProps = {
106
111
  ref?: ForwardedIframeRef;
@@ -132,4 +137,9 @@ type AmosApplePayButtonProps = {
132
137
  }) => Promise<components["schemas"]["EmbedToken"]["token"]>;
133
138
  onResult: (result: ConfirmationResult) => void;
134
139
  };
140
+ /**
141
+ * Renders the secure Apple Pay iframe button. A button-shaped
142
+ * skeleton is painted in the parent document on first render (including
143
+ * SSR) so the slot height is reserved before the iframe loads.
144
+ */
135
145
  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(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]}})});
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.useLayoutEffect)(()=>{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)})}var d=`oklch(0.97 0 0)`;function f({height:r,borderRadius:i,containerRef:a}){return(0,t.useLayoutEffect)(()=>{(0,e.ensureSkeletonStyles)()},[]),(0,n.jsxs)(`div`,{style:{boxSizing:`border-box`,position:`relative`,width:`100%`,height:r,minHeight:r,overflow:`hidden`},children:[(0,n.jsx)(`div`,{className:`amos-js-form-skeleton-input amos-js-wallet-skeleton`,style:{position:`absolute`,inset:0,height:r,borderRadius:i,background:d,pointerEvents:`none`,zIndex:0},"aria-hidden":!0}),(0,n.jsx)(`div`,{ref:a,style:{position:`absolute`,inset:0,zIndex:1,width:`100%`,height:`100%`}})]})}function p({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 m({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 h({ref:r,renderToken:i,amount:a,merchantName:o,height:s=`48px`,buttonProps:c,iframeProps:l,onInitiatePaymentIntentRequest:d,onResult:p}){let m=(0,t.useRef)(null),h=(0,e.resolveWalletButtonSkeletonBorderRadius)({iframeStyle:l?.style,buttonProps:c});return u({containerRef:m,iframeRef:r,mount:e.mountAmosGooglePayButton,options:{renderToken:i,amount:a,merchantName:o,height:s,buttonProps:c,onInitiatePaymentIntentRequest:d,onResult:p},remountDeps:[i],iframePassthrough:l??{},updateDeps:[a,o,s,c,d,p]}),(0,n.jsx)(f,{height:s,borderRadius:h,containerRef:m})}function g({ref:r,renderToken:i,amount:a,merchantName:o,height:s=`48px`,buttonProps:c,iframeProps:l,onInitiatePaymentIntentRequest:d,onResult:p}){let m=(0,t.useRef)(null),h=(0,e.resolveWalletButtonSkeletonBorderRadius)({iframeStyle:l?.style,buttonProps:c});return u({containerRef:m,iframeRef:r,mount:e.mountAmosApplePayButton,options:{renderToken:i,amount:a,merchantName:o,height:s,buttonProps:c,onInitiatePaymentIntentRequest:d,onResult:p},remountDeps:[i],iframePassthrough:l??{},updateDeps:[a,o,s,c,d,p]}),(0,n.jsx)(f,{height:s,borderRadius:h,containerRef:m})}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]}})});
package/dist/index.mjs CHANGED
@@ -1,65 +1,102 @@
1
- import { confirmPaymentIntent as e, confirmSetupIntent as t, mountAmosApplePayButton as n, mountAmosBankAccountPaymentMethodForm as r, mountAmosCreditCardPaymentMethodForm as i, mountAmosGooglePayButton as a, resetForm as o, validateForm as s } from "@amos.com/amos-js";
2
- import { useEffect as c, useRef as l } from "react";
3
- import { jsx as u } from "react/jsx-runtime";
1
+ import { confirmPaymentIntent as e, confirmSetupIntent as t, ensureSkeletonStyles as n, mountAmosApplePayButton as r, mountAmosBankAccountPaymentMethodForm as i, mountAmosCreditCardPaymentMethodForm as a, mountAmosGooglePayButton as o, resetForm as s, resolveWalletButtonSkeletonBorderRadius as c, validateForm as l } from "@amos.com/amos-js";
2
+ import { useEffect as u, useLayoutEffect as d, useRef as f } from "react";
3
+ import { jsx as p, jsxs as m } from "react/jsx-runtime";
4
4
  export * from "@amos.com/amos-js";
5
5
  //#region src/index.tsx
6
- function d(e) {
6
+ function h(e) {
7
7
  return e ? e.current ?? null : null;
8
8
  }
9
- function f({ iframeRef: e }) {
10
- return s({ iframe: d(e) });
9
+ function g({ iframeRef: e }) {
10
+ return l({ iframe: h(e) });
11
11
  }
12
- function p({ iframeRef: t, token: n }) {
12
+ function _({ iframeRef: t, token: n }) {
13
13
  e({
14
- iframe: d(t),
14
+ iframe: h(t),
15
15
  token: n
16
16
  });
17
17
  }
18
- function m({ iframeRef: e, token: n }) {
18
+ function v({ iframeRef: e, token: n }) {
19
19
  t({
20
- iframe: d(e),
20
+ iframe: h(e),
21
21
  token: n
22
22
  });
23
23
  }
24
- function h({ iframeRef: e }) {
25
- o({ iframe: d(e) });
24
+ function y({ iframeRef: e }) {
25
+ s({ iframe: h(e) });
26
26
  }
27
- function g(e, t) {
27
+ function b(e, t) {
28
28
  typeof e == "function" ? e(t) : e && (e.current = t);
29
29
  }
30
- function _(e, { style: t, className: n, id: r, ...i }) {
30
+ function x(e, { style: t, className: n, id: r, ...i }) {
31
31
  n != null && (e.className = n), r != null && (e.id = r), Object.assign(e.style, t);
32
32
  for (let [t, n] of Object.entries(i)) n != null && (t in e ? Reflect.set(e, t, n) : e.setAttribute(t, String(n)));
33
33
  }
34
- function v({ containerRef: e, iframeRef: t, mount: n, options: r, remountDeps: i, iframePassthrough: a, updateDeps: o }) {
35
- let s = l(null);
36
- c(() => {
34
+ function S({ containerRef: e, iframeRef: t, mount: n, options: r, remountDeps: i, iframePassthrough: a, updateDeps: o }) {
35
+ let s = f(null);
36
+ d(() => {
37
37
  let i = e.current;
38
38
  if (!i) return;
39
39
  let o = n(i, r);
40
- return s.current = o, g(t, o.iframe), _(o.iframe, a), () => {
41
- o.destroy(), s.current = null, g(t, null);
40
+ return s.current = o, b(t, o.iframe), x(o.iframe, a), () => {
41
+ o.destroy(), s.current = null, b(t, null);
42
42
  };
43
- }, [...i]), c(() => {
43
+ }, [...i]), u(() => {
44
44
  s.current?.update(r);
45
- }, [...o]), c(() => {
45
+ }, [...o]), u(() => {
46
46
  let e = s.current?.iframe;
47
- e && _(e, a);
47
+ e && x(e, a);
48
48
  });
49
49
  }
50
- function y({ ref: e, renderToken: t, appearance: n, onResult: r, onValidityChange: a, additionalFields: o = { cardholderName: !1 }, billingAddressRequirement: s = "country", style: c, ...d }) {
51
- let f = l(null);
52
- return v({
53
- containerRef: f,
50
+ var C = "oklch(0.97 0 0)";
51
+ function w({ height: e, borderRadius: t, containerRef: r }) {
52
+ return d(() => {
53
+ n();
54
+ }, []), /* @__PURE__ */ m("div", {
55
+ style: {
56
+ boxSizing: "border-box",
57
+ position: "relative",
58
+ width: "100%",
59
+ height: e,
60
+ minHeight: e,
61
+ overflow: "hidden"
62
+ },
63
+ children: [/* @__PURE__ */ p("div", {
64
+ className: "amos-js-form-skeleton-input amos-js-wallet-skeleton",
65
+ style: {
66
+ position: "absolute",
67
+ inset: 0,
68
+ height: e,
69
+ borderRadius: t,
70
+ background: C,
71
+ pointerEvents: "none",
72
+ zIndex: 0
73
+ },
74
+ "aria-hidden": !0
75
+ }), /* @__PURE__ */ p("div", {
76
+ ref: r,
77
+ style: {
78
+ position: "absolute",
79
+ inset: 0,
80
+ zIndex: 1,
81
+ width: "100%",
82
+ height: "100%"
83
+ }
84
+ })]
85
+ });
86
+ }
87
+ function T({ ref: e, renderToken: t, appearance: n, onResult: r, onValidityChange: i, additionalFields: o = { cardholderName: !1 }, billingAddressRequirement: s = "country", style: c, ...l }) {
88
+ let u = f(null);
89
+ return S({
90
+ containerRef: u,
54
91
  iframeRef: e,
55
- mount: i,
92
+ mount: a,
56
93
  options: {
57
94
  renderToken: t,
58
95
  appearance: n,
59
96
  additionalFields: o,
60
97
  billingAddressRequirement: s,
61
98
  onResult: r,
62
- onValidityChange: a
99
+ onValidityChange: i
63
100
  },
64
101
  remountDeps: [
65
102
  t,
@@ -68,28 +105,28 @@ function y({ ref: e, renderToken: t, appearance: n, onResult: r, onValidityChang
68
105
  ],
69
106
  iframePassthrough: {
70
107
  style: c,
71
- ...d
108
+ ...l
72
109
  },
73
110
  updateDeps: [
74
111
  n,
75
112
  o,
76
113
  s,
77
114
  r,
78
- a
115
+ i
79
116
  ]
80
- }), /* @__PURE__ */ u("div", { ref: f });
117
+ }), /* @__PURE__ */ p("div", { ref: u });
81
118
  }
82
- function b({ ref: e, renderToken: t, appearance: n, onResult: i, onValidityChange: a, billingAddressRequirement: o = "country", style: s, ...c }) {
83
- let d = l(null);
84
- return v({
85
- containerRef: d,
119
+ function E({ ref: e, renderToken: t, appearance: n, onResult: r, onValidityChange: a, billingAddressRequirement: o = "country", style: s, ...c }) {
120
+ let l = f(null);
121
+ return S({
122
+ containerRef: l,
86
123
  iframeRef: e,
87
- mount: r,
124
+ mount: i,
88
125
  options: {
89
126
  renderToken: t,
90
127
  appearance: n,
91
128
  billingAddressRequirement: o,
92
- onResult: i,
129
+ onResult: r,
93
130
  onValidityChange: a
94
131
  },
95
132
  remountDeps: [t, o],
@@ -100,25 +137,28 @@ function b({ ref: e, renderToken: t, appearance: n, onResult: i, onValidityChang
100
137
  updateDeps: [
101
138
  n,
102
139
  o,
103
- i,
140
+ r,
104
141
  a
105
142
  ]
106
- }), /* @__PURE__ */ u("div", { ref: d });
143
+ }), /* @__PURE__ */ p("div", { ref: l });
107
144
  }
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,
145
+ function D({ ref: e, renderToken: t, amount: n, merchantName: r, height: i = "48px", buttonProps: a, iframeProps: s, onInitiatePaymentIntentRequest: l, onResult: u }) {
146
+ let d = f(null), m = c({
147
+ iframeStyle: s?.style,
148
+ buttonProps: a
149
+ });
150
+ return S({
151
+ containerRef: d,
112
152
  iframeRef: e,
113
- mount: a,
153
+ mount: o,
114
154
  options: {
115
155
  renderToken: t,
116
156
  amount: n,
117
157
  merchantName: r,
118
158
  height: i,
119
- buttonProps: o,
120
- onInitiatePaymentIntentRequest: c,
121
- onResult: d
159
+ buttonProps: a,
160
+ onInitiatePaymentIntentRequest: l,
161
+ onResult: u
122
162
  },
123
163
  remountDeps: [t],
124
164
  iframePassthrough: s ?? {},
@@ -126,38 +166,49 @@ function x({ ref: e, renderToken: t, amount: n, merchantName: r, height: i = "48
126
166
  n,
127
167
  r,
128
168
  i,
129
- o,
130
- c,
131
- d
169
+ a,
170
+ l,
171
+ u
132
172
  ]
133
- }), /* @__PURE__ */ u("div", { ref: f });
173
+ }), /* @__PURE__ */ p(w, {
174
+ height: i,
175
+ borderRadius: m,
176
+ containerRef: d
177
+ });
134
178
  }
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,
179
+ function O({ ref: e, renderToken: t, amount: n, merchantName: i, height: a = "48px", buttonProps: o, iframeProps: s, onInitiatePaymentIntentRequest: l, onResult: u }) {
180
+ let d = f(null), m = c({
181
+ iframeStyle: s?.style,
182
+ buttonProps: o
183
+ });
184
+ return S({
185
+ containerRef: d,
139
186
  iframeRef: e,
140
- mount: n,
187
+ mount: r,
141
188
  options: {
142
189
  renderToken: t,
143
- amount: r,
190
+ amount: n,
144
191
  merchantName: i,
145
192
  height: a,
146
193
  buttonProps: o,
147
- onInitiatePaymentIntentRequest: c,
148
- onResult: d
194
+ onInitiatePaymentIntentRequest: l,
195
+ onResult: u
149
196
  },
150
197
  remountDeps: [t],
151
198
  iframePassthrough: s ?? {},
152
199
  updateDeps: [
153
- r,
200
+ n,
154
201
  i,
155
202
  a,
156
203
  o,
157
- c,
158
- d
204
+ l,
205
+ u
159
206
  ]
160
- }), /* @__PURE__ */ u("div", { ref: f });
207
+ }), /* @__PURE__ */ p(w, {
208
+ height: a,
209
+ borderRadius: m,
210
+ containerRef: d
211
+ });
161
212
  }
162
213
  //#endregion
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 };
214
+ export { O as AmosApplePayButton, E as AmosBankAccountPaymentMethodForm, T as AmosCreditCardPaymentMethodForm, D as AmosGooglePayButton, _ as confirmPaymentIntent, v as confirmSetupIntent, y as resetForm, g as validateForm };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amos.com/react-amos-js",
3
- "version": "0.9.15",
3
+ "version": "0.9.16",
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.16",
51
+ "@amos.com/amos-js": "0.9.17",
52
52
  "@types/googlepay": "0.7.11"
53
53
  },
54
54
  "peerDependencies": {
package/src/index.tsx CHANGED
@@ -10,11 +10,13 @@ import {
10
10
  type BillingAddressRequirement,
11
11
  type ConfirmationResult,
12
12
  type CreditCardAdditionalFields,
13
+ ensureSkeletonStyles,
13
14
  type GooglePayButtonElementProps,
14
15
  mountAmosApplePayButton,
15
16
  mountAmosBankAccountPaymentMethodForm,
16
17
  mountAmosCreditCardPaymentMethodForm,
17
18
  mountAmosGooglePayButton,
19
+ resolveWalletButtonSkeletonBorderRadius,
18
20
  } from "@amos.com/amos-js";
19
21
  import type { components } from "@amos.com/node";
20
22
  import {
@@ -22,6 +24,7 @@ import {
22
24
  type Ref,
23
25
  type RefObject,
24
26
  useEffect,
27
+ useLayoutEffect,
25
28
  useRef,
26
29
  } from "react";
27
30
 
@@ -157,7 +160,7 @@ function useAmosEmbed<TOptions extends Record<string, unknown>>({
157
160
  const controllerRef = useRef<AmosEmbedController | null>(null);
158
161
 
159
162
  // biome-ignore lint/correctness/useExhaustiveDependencies: remount only when remountDeps change
160
- useEffect(() => {
163
+ useLayoutEffect(() => {
161
164
  const container = containerRef.current;
162
165
  if (!container) {
163
166
  return;
@@ -188,6 +191,59 @@ function useAmosEmbed<TOptions extends Record<string, unknown>>({
188
191
  });
189
192
  }
190
193
 
194
+ const SKELETON_ACCENT = "oklch(0.97 0 0)";
195
+
196
+ function WalletButtonSlot({
197
+ height,
198
+ borderRadius,
199
+ containerRef,
200
+ }: {
201
+ height: string;
202
+ borderRadius: string;
203
+ containerRef: RefObject<HTMLDivElement | null>;
204
+ }) {
205
+ useLayoutEffect(() => {
206
+ ensureSkeletonStyles();
207
+ }, []);
208
+
209
+ return (
210
+ <div
211
+ style={{
212
+ boxSizing: "border-box",
213
+ position: "relative",
214
+ width: "100%",
215
+ height,
216
+ minHeight: height,
217
+ overflow: "hidden",
218
+ }}
219
+ >
220
+ <div
221
+ className="amos-js-form-skeleton-input amos-js-wallet-skeleton"
222
+ style={{
223
+ position: "absolute",
224
+ inset: 0,
225
+ height,
226
+ borderRadius,
227
+ background: SKELETON_ACCENT,
228
+ pointerEvents: "none",
229
+ zIndex: 0,
230
+ }}
231
+ aria-hidden
232
+ />
233
+ <div
234
+ ref={containerRef}
235
+ style={{
236
+ position: "absolute",
237
+ inset: 0,
238
+ zIndex: 1,
239
+ width: "100%",
240
+ height: "100%",
241
+ }}
242
+ />
243
+ </div>
244
+ );
245
+ }
246
+
191
247
  type AmosCreditCardPaymentMethodFormProps = IframePassthroughProps & {
192
248
  renderToken: string;
193
249
  appearance?: Appearance;
@@ -326,6 +382,11 @@ type AmosGooglePayButtonProps = {
326
382
  onResult: (result: ConfirmationResult) => void;
327
383
  };
328
384
 
385
+ /**
386
+ * Renders the secure Google Pay iframe button. A button-shaped
387
+ * skeleton is painted in the parent document on first render (including
388
+ * SSR) so the slot height is reserved before the iframe loads.
389
+ */
329
390
  export function AmosGooglePayButton({
330
391
  ref,
331
392
  renderToken,
@@ -338,6 +399,10 @@ export function AmosGooglePayButton({
338
399
  onResult,
339
400
  }: AmosGooglePayButtonProps) {
340
401
  const containerRef = useRef<HTMLDivElement | null>(null);
402
+ const borderRadius = resolveWalletButtonSkeletonBorderRadius({
403
+ iframeStyle: iframeProps?.style as { borderRadius?: string | number },
404
+ buttonProps,
405
+ });
341
406
 
342
407
  useAmosEmbed({
343
408
  containerRef,
@@ -364,7 +429,13 @@ export function AmosGooglePayButton({
364
429
  ],
365
430
  });
366
431
 
367
- return <div ref={containerRef} />;
432
+ return (
433
+ <WalletButtonSlot
434
+ height={height}
435
+ borderRadius={borderRadius}
436
+ containerRef={containerRef}
437
+ />
438
+ );
368
439
  }
369
440
 
370
441
  type AmosApplePayButtonProps = {
@@ -401,6 +472,11 @@ type AmosApplePayButtonProps = {
401
472
  onResult: (result: ConfirmationResult) => void;
402
473
  };
403
474
 
475
+ /**
476
+ * Renders the secure Apple Pay iframe button. A button-shaped
477
+ * skeleton is painted in the parent document on first render (including
478
+ * SSR) so the slot height is reserved before the iframe loads.
479
+ */
404
480
  export function AmosApplePayButton({
405
481
  ref,
406
482
  renderToken,
@@ -413,6 +489,10 @@ export function AmosApplePayButton({
413
489
  onResult,
414
490
  }: AmosApplePayButtonProps) {
415
491
  const containerRef = useRef<HTMLDivElement | null>(null);
492
+ const borderRadius = resolveWalletButtonSkeletonBorderRadius({
493
+ iframeStyle: iframeProps?.style as { borderRadius?: string | number },
494
+ buttonProps,
495
+ });
416
496
 
417
497
  useAmosEmbed({
418
498
  containerRef,
@@ -439,5 +519,11 @@ export function AmosApplePayButton({
439
519
  ],
440
520
  });
441
521
 
442
- return <div ref={containerRef} />;
522
+ return (
523
+ <WalletButtonSlot
524
+ height={height}
525
+ borderRadius={borderRadius}
526
+ containerRef={containerRef}
527
+ />
528
+ );
443
529
  }