@amos.com/react-amos-js 0.11.26 → 0.11.28

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
@@ -141,7 +141,7 @@ appearance={{
141
141
 
142
142
  Rules override `themeVariables` for the properties they set (Stripe). `--input-height` / `--floating-input-height` are a **minimum**; `.Input` `padding`, `fontSize`, and `lineHeight` can grow the field. Floated input text padding is `--floating-value-padding-top` and `--floating-value-padding-bottom`. Rule values may reference allowlisted tokens as `var(--primary)` (no fallback argument).
143
143
 
144
- The host skeleton (shown until `UPDATED_APPEARANCE`, or 1.5s after mount if appearance never acks) copies `themeVariables` and resting **`.Input` / `.Label`** declarations (the same allowlisted properties as iframe rules). Its background is `--background`, so it covers the iframe. The iframe stays at opacity 1 and its default pixel height underneath, and is `inert` until reveal, so WebKit lays it out and still runs iframe JS. It does not inject webfonts: it uses `--font-family` / `fontFamily` when that face is already on the host page, and falls back to `ui-sans-serif, system-ui, sans-serif`. Hover, invalid, placeholder, dropdown, and radio rules have no skeleton equivalent. Floating labels sit inside the control, so `.Label` / `.Label--floating` do not change skeleton height.
144
+ The host skeleton (shown until `UPDATED_APPEARANCE`, or 1.5s after mount if appearance never acks) copies `themeVariables` and resting **`.Input` / `.Label`** declarations (the same allowlisted properties as iframe rules). Its background is `--background`, so it covers the iframe. The iframe stays at opacity 1 with an explicit pixel width and height underneath, and is `inert` until reveal, so WebKit lays it out and still runs iframe JS. It does not inject webfonts: it uses `--font-family` / `fontFamily` when that face is already on the host page, and falls back to `ui-sans-serif, system-ui, sans-serif`. Hover, invalid, placeholder, dropdown, and radio rules have no skeleton equivalent. Floating labels sit inside the control, so `.Label` / `.Label--floating` do not change skeleton height.
145
145
 
146
146
  | Selector | Targets |
147
147
  | --- | --- |
@@ -562,7 +562,7 @@ Focus a named control inside the card or bank iframe. No-op if the field is not
562
562
 
563
563
  ### `AmosCreditCardPaymentMethodForm`
564
564
 
565
- Renders the secure credit card iframe form. A field-shaped skeleton with an opaque background is shown immediately (sized from `appearance`, including resting `.Input` / `.Label` rules). The iframe stays at opacity 1 and its default pixel height, and is `inert`, until appearance is applied, or for 1.5s after mount if appearance never acks.
565
+ Renders the secure credit card iframe form. A field-shaped skeleton with an opaque background is shown immediately (sized from `appearance`, including resting `.Input` / `.Label` rules). The iframe stays at opacity 1 with an explicit pixel width and height, and is `inert`, until appearance is applied, or for 1.5s after mount if appearance never acks.
566
566
 
567
567
  **Required props:**
568
568
 
@@ -582,11 +582,11 @@ Renders the secure credit card iframe form. A field-shaped skeleton with an opaq
582
582
 
583
583
  Enter in a card or bank iframe field submits the enclosing host `<form>` via `requestSubmit()` (same as Stripe Elements). Handle that form's `onSubmit` — the parent page cannot see keys typed in the cross-origin iframe. No-op if the component is not inside a `<form>`, or while Plaid Embedded Institution Search is showing.
584
584
 
585
- **Also accepts:** standard iframe props (`React.ComponentProps<"iframe">`), minus `src`, `title`, `name`, and `role` (which are controlled by the SDK).
585
+ **Also accepts:** standard iframe props (`React.ComponentProps<"iframe">`), minus `src`, `title`, `name`, `role`, `allow`, `sandbox`, `width`, and `height`. The SDK sets those. `style.width` and `style.height` are ignored so the frame keeps a definite pixel size. Card and bank frames are sandboxed to forms, scripts, and the embed origin. Wallet frames also allow the payment-sheet popup.
586
586
 
587
587
  ### `AmosBankAccountPaymentMethodForm`
588
588
 
589
- Renders the secure bank account iframe form. A field-shaped skeleton with an opaque background is shown immediately (sized from `appearance`, including resting `.Input` / `.Label` rules). The iframe stays at opacity 1 and its default pixel height, and is `inert`, until appearance is applied, or for 1.5s after mount if appearance never acks.
589
+ Renders the secure bank account iframe form. A field-shaped skeleton with an opaque background is shown immediately (sized from `appearance`, including resting `.Input` / `.Label` rules). The iframe stays at opacity 1 with an explicit pixel width and height, and is `inert`, until appearance is applied, or for 1.5s after mount if appearance never acks.
590
590
 
591
591
  When `requireAchVerification` is true (or `intent` is `"setup"`), and the render token allows verification, the SDK hides the routing/account iframe and mounts [Plaid Embedded Institution Search](https://plaid.com/docs/link/embedded-institution-search/) in the parent. A **350px pulse skeleton** covers that slot until Plaid's `onLoad` (1.5s fallback). Do not overlay a host loader. Hosts do not proxy Pay API (`GET /merchants`, `POST /plaid_link_tokens`); embed does that with `PAY_API_KEY`. Do not put Plaid secrets in the browser.
592
592
 
@@ -619,11 +619,11 @@ Setup (always Plaid, unless the render token disables verification):
619
619
 
620
620
  **CSP:** the parent page must allow Plaid’s script and frames, for example `script-src https://cdn.plaid.com` and `frame-src https://cdn.plaid.com https://*.plaid.com`. Amos never loads `PLAID_SECRET` / `PLAID_CLIENT_ID` in the SDK or embed iframe.
621
621
 
622
- **Also accepts:** standard iframe props.
622
+ **Also accepts:** the same iframe props as the card form. `sandbox`, `width`, and `height` stay under SDK control.
623
623
 
624
624
  ### `AmosGooglePayButton`
625
625
 
626
- Renders the secure Google Pay iframe button (express checkout flow). A button-shaped skeleton with an opaque background is shown immediately. The iframe stays at opacity 1 and its default pixel height, and is `inert`, until appearance is applied, or for 1.5s after mount if appearance never acks.
626
+ Renders the secure Google Pay iframe button (express checkout flow). A button-shaped skeleton with an opaque background is shown immediately. The iframe stays at opacity 1 with an explicit pixel width and height, and is `inert`, until appearance is applied, or for 1.5s after mount if appearance never acks.
627
627
 
628
628
  **Required props:**
629
629
 
@@ -638,7 +638,7 @@ Renders the secure Google Pay iframe button (express checkout flow). A button-sh
638
638
  - `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" } }}`.
639
639
  - `phoneRequired` (`boolean`, defaults to `false`) — collect a phone number in the Google Pay sheet.
640
640
  - `shippingAddressRequired` (`boolean`, defaults to `false`) — collect a shipping postal address. Name, email, and billing address are always required.
641
- - `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.
641
+ - `iframeProps` — applied to the host-page `<iframe>` (e.g. `className`, `style`, `id`). Use CSS lengths with units in `style` (`{ borderRadius: "8px" }`). `sandbox`, `width`, `height`, `style.width`, and `style.height` are ignored. Amos does not ship Tailwind — `className` only works if the host page defines those classes.
642
642
 
643
643
  ```tsx
644
644
  <AmosGooglePayButton
@@ -650,7 +650,7 @@ Renders the secure Google Pay iframe button (express checkout flow). A button-sh
650
650
 
651
651
  ### `AmosApplePayButton`
652
652
 
653
- Renders the secure Apple Pay iframe button (express checkout flow). Same required props and callbacks as `AmosGooglePayButton`. A button-shaped skeleton with an opaque background is shown immediately. The iframe stays at opacity 1 and its default pixel height, and is `inert`, until appearance is applied, or for 1.5s after mount if appearance never acks.
653
+ Renders the secure Apple Pay iframe button (express checkout flow). Same required props and callbacks as `AmosGooglePayButton`. A button-shaped skeleton with an opaque background is shown immediately. The iframe stays at opacity 1 with an explicit pixel width and height, and is `inert`, until appearance is applied, or for 1.5s after mount if appearance never acks.
654
654
 
655
655
  **Optional props:**
656
656
 
@@ -692,7 +692,7 @@ Re-exports of the same advanced helpers exposed by `@amos.com/amos-js`. Most int
692
692
 
693
693
  Re-exports from `@amos.com/amos-js`. Build the iframe `src` URL for each form type. The React components call these for you.
694
694
 
695
- Each URL includes the embed's canonical search params (`token`, `additionalFields`, `billingAddressRequirement`, `intent`) so the embed router does not 307 to fill in defaults. After the iframe `load` event, if `IFRAME_READY` never arrives (stale HTML, missing JS chunk), the SDK rewrites `src` once with `amosReload` so the next document is a real navigation. Appearance is applied after handshake via `UPDATE_APPEARANCE`. A host-page skeleton with an opaque background covers the iframe until then. The iframe stays at opacity 1 and its default pixel height, and is uncovered 1.5s after mount if appearance never acks.
695
+ Each URL includes the embed's canonical search params (`token`, `additionalFields`, `billingAddressRequirement`, `intent`) so the embed router does not 307 to fill in defaults. When the host page URL contains `amosDebug=1`, that flag is copied onto the iframe URL as well. After the iframe `load` event, if `IFRAME_READY` never arrives (stale HTML, missing JS chunk), the SDK rewrites `src` once with `amosReload` so the next document is a real navigation. Appearance is applied after handshake via `UPDATE_APPEARANCE`. A host-page skeleton with an opaque background covers the iframe until then. The iframe stays at opacity 1 with an explicit pixel width and height, and is uncovered 1.5s after mount if appearance never acks.
696
696
 
697
697
  ### `updateDefaultValues({ iframe, defaultValues })`
698
698
 
@@ -704,7 +704,7 @@ Re-export from `@amos.com/amos-js`. Fills omitted Inter `fonts` / `--font-family
704
704
 
705
705
  ### Exported types
706
706
 
707
- `@amos.com/react-amos-js` re-exports everything from `@amos.com/amos-js`, including `ConfirmPaymentResult`, `ConfirmSetupResult`, `isConfirmTimeout`, `CONFIRM_TIMEOUT_MS`, `PaymentMethodFormValidityChangeEvent`, `CardBrand`, `PaymentMethodFormCardBrandChangeEvent`, `PaymentMethodFormPostalCodeChangeEvent`, `FormattedGooglePayPaymentData`, `WalletCustomerCreateAttributes`, `WalletPostalAddress`, `WalletContactRequirements`, `Message`, `Appearance`, `ThemeVariable`, `FontSource`, `CssFontSource`, `CustomFontSource`, `AppearanceRuleSelector`, `AppearanceRuleDeclarations`, `PaymentMethodFormDefaultValues`, `PaymentMethodFormField`, and the per-form `*Options` / `*Controller` types. For OpenAPI schema types (e.g. `PaymentIntent`, `CreatePaymentIntentInput`), import `components` from `@amos.com/node`.
707
+ `@amos.com/react-amos-js` re-exports everything from `@amos.com/amos-js`, including `ConfirmPaymentResult`, `ConfirmSetupResult`, `isConfirmTimeout`, `CONFIRM_TIMEOUT_MS`, `PAYMENT_IFRAME_SANDBOX`, `WALLET_IFRAME_SANDBOX`, `PaymentMethodFormValidityChangeEvent`, `CardBrand`, `PaymentMethodFormCardBrandChangeEvent`, `PaymentMethodFormPostalCodeChangeEvent`, `FormattedGooglePayPaymentData`, `WalletCustomerCreateAttributes`, `WalletPostalAddress`, `WalletContactRequirements`, `Message`, `Appearance`, `ThemeVariable`, `FontSource`, `CssFontSource`, `CustomFontSource`, `AppearanceRuleSelector`, `AppearanceRuleDeclarations`, `PaymentMethodFormDefaultValues`, `PaymentMethodFormField`, and the per-form `*Options` / `*Controller` types. For OpenAPI schema types (e.g. `PaymentIntent`, `CreatePaymentIntentInput`), import `components` from `@amos.com/node`. Copy `PAYMENT_IFRAME_SANDBOX` or `WALLET_IFRAME_SANDBOX` onto a hand-built iframe before setting `src`.
708
708
 
709
709
  ## Notes and potential gotchas
710
710
 
@@ -713,7 +713,8 @@ Re-export from `@amos.com/amos-js`. Fills omitted Inter `fonts` / `--font-family
713
713
  - **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 (`confirmPayment` vs `confirmSetup`).
714
714
  - **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 `onConfirm`), `amount` is a number in cents (e.g. `5000`).
715
715
  - **Embed host / CSP**: iframes load from `https://js.amos.com` (production) and `https://js-sandbox.amos.com` (sandbox) via `getEmbedOrigin`. Parent pages that pin CSP must allow `frame-src https://js.amos.com https://js-sandbox.amos.com` (and `Permissions-Policy payment=` for those origins) **before** upgrading this package. Older SDK versions still load `embed.amos.com` / `embed-sandbox.amos.com`.
716
- - **Iframe handshake**: iframe URLs include canonical search params so the embed does not 307. If the document loads but never posts `IFRAME_READY`, the SDK rewrites `src` once with `amosReload`. Appearance is applied after handshake. The iframe stays at opacity 1 under an opaque skeleton until `UPDATED_APPEARANCE`, or for 1.5s after mount if appearance never acks. Embed messages match on origin plus `iframeName` when `contentWindow` identity changes.
716
+ - **Iframe handshake**: iframe URLs include canonical search params so the embed does not 307. When the host page URL contains `amosDebug=1`, that flag is copied onto the iframe URL. If the document loads but never posts `IFRAME_READY`, the SDK rewrites `src` once with `amosReload`. Appearance is applied after handshake. The iframe stays at opacity 1 under an opaque skeleton, with an explicit pixel width and height, until `UPDATED_APPEARANCE`, or for 1.5s after mount if appearance never acks. Embed messages match on origin plus `iframeName` when `contentWindow` identity changes.
717
+ - **Iframe sandbox**: mount helpers set `sandbox` before `src`. Card and bank frames use `PAYMENT_IFRAME_SANDBOX` (`allow-forms allow-same-origin allow-scripts`). Wallet frames use `WALLET_IFRAME_SANDBOX`, which also allows the payment-sheet popup (`allow-popups allow-popups-to-escape-sandbox`), and set `allow="payment"`. Hand-built iframes should copy the same attribute. Top-level navigation stays blocked. Host `sandbox`, `width`, and `height` props are ignored.
717
718
  - **Plaid Embedded Link (ACH verification)**: load `cdn.plaid.com` from the **parent** document (see CSP on `AmosBankAccountPaymentMethodForm`). Merchants do not proxy Pay API; the bank iframe mints link tokens. Pass `requireAchVerification` when the host wants Plaid, or `intent="setup"` to always show it, unless the render token disables verification. Toggling that prop hides or shows the existing Embedded handler — it does not reload Institution Search. Confirm still goes through the bank iframe so Amos can attach `plaid` to the payment method. While Link loads, the SDK shows a 350px pulse skeleton until `onLoad` (1.5s fallback) — do not overlay a host loader. After success the same slot is a connected-account row (institution name, mask, outline Disconnect) styled with existing `themeVariables`. Disconnect shows Institution Search again.
718
719
  - **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. **Cancel payment** is available until the buyer authorizes; after that the overlay shows **Completing your payment…** with no Cancel, then hides when `onConfirm` settles. Avoid stacking other fixed UI above it.
719
720
  - **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.
package/dist/index.d.ts CHANGED
@@ -66,7 +66,7 @@ export declare function focusField({ iframeRef, field, }: {
66
66
  field: PaymentMethodFormField;
67
67
  }): void;
68
68
  type ForwardedIframeRef = Ref<HTMLIFrameElement> | undefined;
69
- type IframePassthroughProps = Omit<ComponentProps<"iframe">, "src" | "title" | "name" | "role" | "allow">;
69
+ type IframePassthroughProps = Omit<ComponentProps<"iframe">, "src" | "title" | "name" | "role" | "allow" | "sandbox" | "width" | "height">;
70
70
  type AmosCreditCardPaymentMethodFormProps = IframePassthroughProps & {
71
71
  renderToken: string;
72
72
  appearance?: Appearance;
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 resolveIframe(e){var t;return e?(t=e.current)==null?null:t:null}function validateForm({iframeRef:t}){return(0,e.validateForm)({iframe:resolveIframe(t)})}function confirmPayment({iframeRef:t,token:n,defaultValues:r}){return(0,e.confirmPayment)({iframe:resolveIframe(t),token:n,defaultValues:r})}function confirmSetup({iframeRef:t,token:n,defaultValues:r}){return(0,e.confirmSetup)({iframe:resolveIframe(t),token:n,defaultValues:r})}function resetForm({iframeRef:t}){(0,e.resetForm)({iframe:resolveIframe(t)})}function focusField({iframeRef:t,field:n}){(0,e.focusField)({iframe:resolveIframe(t),field:n})}function setForwardedRef(e,t){typeof e==`function`?e(t):e&&(e.current=t)}function applyIframePassthrough(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 useAmosEmbed({containerRef:e,iframeRef:n,mount:r,options:i,remountDeps:a,iframePassthrough:o,updateDeps:s}){let c=(0,t.useRef)(null);(0,t.useLayoutEffect)(()=>{let t=e.current;if(!t)return;let a=r(t,i);return c.current=a,setForwardedRef(n,a.iframe),applyIframePassthrough(a.iframe,o),()=>{a.destroy(),c.current=null,setForwardedRef(n,null)}},[...a]),(0,t.useEffect)(()=>{var e;(e=c.current)==null||e.update(i)},[...s]),(0,t.useEffect)(()=>{var e;let t=(e=c.current)==null?void 0:e.iframe;t&&applyIframePassthrough(t,o)})}var r=`oklch(0.97 0 0)`;function WalletButtonSlot({height:i,borderRadius:a,containerRef:o}){return(0,t.useLayoutEffect)(()=>{(0,e.ensureSkeletonStyles)()},[]),(0,n.jsxs)(`div`,{style:{boxSizing:`border-box`,position:`relative`,width:`100%`,height:i,minHeight:i,overflow:`hidden`},children:[(0,n.jsx)(`div`,{className:`amos-js-form-skeleton-input amos-js-wallet-skeleton`,style:{position:`absolute`,inset:0,height:i,borderRadius:a,background:r,pointerEvents:`none`,zIndex:0},"aria-hidden":!0}),(0,n.jsx)(`div`,{ref:o,style:{position:`absolute`,inset:0,zIndex:1,width:`100%`,height:`100%`}})]})}function AmosCreditCardPaymentMethodForm({ref:r,renderToken:i,appearance:a,onValidityChange:o,onCardBrandChanged:s,onPostalCodeChange:c,onEscapeKeyPressed:l,additionalFields:u={cardholderName:!1},billingAddressRequirement:d=`country`,defaultValues:f,style:p,...m}){let h=(0,t.useRef)(null);return useAmosEmbed({containerRef:h,iframeRef:r,mount:e.mountAmosCreditCardPaymentMethodForm,options:{renderToken:i,appearance:a,additionalFields:u,billingAddressRequirement:d,defaultValues:f,onValidityChange:o,onCardBrandChanged:s,onPostalCodeChange:c,onEscapeKeyPressed:l},remountDeps:[i,u.cardholderName,d],iframePassthrough:{style:p,...m},updateDeps:[a,u,d,f,o,s,c,l]}),(0,n.jsx)(`div`,{ref:h})}function AmosBankAccountPaymentMethodForm({ref:r,renderToken:i,appearance:a,onValidityChange:o,onPostalCodeChange:s,onEscapeKeyPressed:c,billingAddressRequirement:l=`country`,defaultValues:u,requireAchVerification:d=!1,intent:f=`payment`,style:p,...m}){let h=(0,t.useRef)(null);return useAmosEmbed({containerRef:h,iframeRef:r,mount:e.mountAmosBankAccountPaymentMethodForm,options:{renderToken:i,appearance:a,billingAddressRequirement:l,defaultValues:u,requireAchVerification:d,intent:f,onValidityChange:o,onPostalCodeChange:s,onEscapeKeyPressed:c},remountDeps:[i,l,f],iframePassthrough:{style:p,...m},updateDeps:[a,l,u,d,f,o,s,c]}),(0,n.jsx)(`div`,{ref:h})}function AmosGooglePayButton({ref:r,renderToken:i,amount:a,merchantName:o,height:s=`48px`,buttonProps:c,phoneRequired:l,shippingAddressRequired:u,iframeProps:d,onConfirm:f}){let p=(0,t.useRef)(null),m=(0,e.resolveWalletButtonSkeletonBorderRadius)({iframeStyle:d==null?void 0:d.style,buttonProps:c});return useAmosEmbed({containerRef:p,iframeRef:r,mount:e.mountAmosGooglePayButton,options:{renderToken:i,amount:a,merchantName:o,height:s,buttonProps:c,phoneRequired:l,shippingAddressRequired:u,onConfirm:f},remountDeps:[i],iframePassthrough:d==null?{}:d,updateDeps:[a,o,s,c,l,u,f]}),(0,n.jsx)(WalletButtonSlot,{height:s,borderRadius:m,containerRef:p})}function AmosApplePayButton({ref:r,renderToken:i,amount:a,merchantName:o,height:s=`48px`,buttonProps:c,phoneRequired:l,shippingAddressRequired:u,iframeProps:d,onConfirm:f}){let p=(0,t.useRef)(null),m=(0,e.resolveWalletButtonSkeletonBorderRadius)({iframeStyle:d==null?void 0:d.style,buttonProps:c});return useAmosEmbed({containerRef:p,iframeRef:r,mount:e.mountAmosApplePayButton,options:{renderToken:i,amount:a,merchantName:o,height:s,buttonProps:c,phoneRequired:l,shippingAddressRequired:u,onConfirm:f},remountDeps:[i],iframePassthrough:d==null?{}:d,updateDeps:[a,o,s,c,l,u,f]}),(0,n.jsx)(WalletButtonSlot,{height:s,borderRadius:m,containerRef:p})}exports.AmosApplePayButton=AmosApplePayButton,exports.AmosBankAccountPaymentMethodForm=AmosBankAccountPaymentMethodForm,exports.AmosCreditCardPaymentMethodForm=AmosCreditCardPaymentMethodForm,exports.AmosGooglePayButton=AmosGooglePayButton,exports.confirmPayment=confirmPayment,exports.confirmSetup=confirmSetup,exports.focusField=focusField,exports.resetForm=resetForm,exports.validateForm=validateForm,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 resolveIframe(e){var t;return e?(t=e.current)==null?null:t:null}function validateForm({iframeRef:t}){return(0,e.validateForm)({iframe:resolveIframe(t)})}function confirmPayment({iframeRef:t,token:n,defaultValues:r}){return(0,e.confirmPayment)({iframe:resolveIframe(t),token:n,defaultValues:r})}function confirmSetup({iframeRef:t,token:n,defaultValues:r}){return(0,e.confirmSetup)({iframe:resolveIframe(t),token:n,defaultValues:r})}function resetForm({iframeRef:t}){(0,e.resetForm)({iframe:resolveIframe(t)})}function focusField({iframeRef:t,field:n}){(0,e.focusField)({iframe:resolveIframe(t),field:n})}function setForwardedRef(e,t){typeof e==`function`?e(t):e&&(e.current=t)}function applyIframePassthrough(e,{style:t,className:n,id:r,...i}){if(n!=null&&(e.className=n),r!=null&&(e.id=r),t){let n={...t};delete n.width,delete n.height,Object.assign(e.style,n)}for(let[t,n]of Object.entries(i))n!=null&&(t in e?Reflect.set(e,t,n):e.setAttribute(t,String(n)))}function useAmosEmbed({containerRef:e,iframeRef:n,mount:r,options:i,remountDeps:a,iframePassthrough:o,updateDeps:s}){let c=(0,t.useRef)(null);(0,t.useLayoutEffect)(()=>{let t=e.current;if(!t)return;let a=r(t,i);return c.current=a,setForwardedRef(n,a.iframe),applyIframePassthrough(a.iframe,o),()=>{a.destroy(),c.current=null,setForwardedRef(n,null)}},[...a]),(0,t.useEffect)(()=>{var e;(e=c.current)==null||e.update(i)},[...s]),(0,t.useEffect)(()=>{var e;let t=(e=c.current)==null?void 0:e.iframe;t&&applyIframePassthrough(t,o)})}var r=`oklch(0.97 0 0)`;function WalletButtonSlot({height:i,borderRadius:a,containerRef:o}){return(0,t.useLayoutEffect)(()=>{(0,e.ensureSkeletonStyles)()},[]),(0,n.jsxs)(`div`,{style:{boxSizing:`border-box`,position:`relative`,width:`100%`,height:i,minHeight:i,overflow:`hidden`},children:[(0,n.jsx)(`div`,{className:`amos-js-form-skeleton-input amos-js-wallet-skeleton`,style:{position:`absolute`,inset:0,height:i,borderRadius:a,background:r,pointerEvents:`none`,zIndex:0},"aria-hidden":!0}),(0,n.jsx)(`div`,{ref:o,style:{position:`absolute`,inset:0,zIndex:1,width:`100%`,height:`100%`}})]})}function AmosCreditCardPaymentMethodForm({ref:r,renderToken:i,appearance:a,onValidityChange:o,onCardBrandChanged:s,onPostalCodeChange:c,onEscapeKeyPressed:l,additionalFields:u={cardholderName:!1},billingAddressRequirement:d=`country`,defaultValues:f,style:p,...m}){let h=(0,t.useRef)(null);return useAmosEmbed({containerRef:h,iframeRef:r,mount:e.mountAmosCreditCardPaymentMethodForm,options:{renderToken:i,appearance:a,additionalFields:u,billingAddressRequirement:d,defaultValues:f,onValidityChange:o,onCardBrandChanged:s,onPostalCodeChange:c,onEscapeKeyPressed:l},remountDeps:[i,u.cardholderName,d],iframePassthrough:{style:p,...m},updateDeps:[a,u,d,f,o,s,c,l]}),(0,n.jsx)(`div`,{ref:h})}function AmosBankAccountPaymentMethodForm({ref:r,renderToken:i,appearance:a,onValidityChange:o,onPostalCodeChange:s,onEscapeKeyPressed:c,billingAddressRequirement:l=`country`,defaultValues:u,requireAchVerification:d=!1,intent:f=`payment`,style:p,...m}){let h=(0,t.useRef)(null);return useAmosEmbed({containerRef:h,iframeRef:r,mount:e.mountAmosBankAccountPaymentMethodForm,options:{renderToken:i,appearance:a,billingAddressRequirement:l,defaultValues:u,requireAchVerification:d,intent:f,onValidityChange:o,onPostalCodeChange:s,onEscapeKeyPressed:c},remountDeps:[i,l,f],iframePassthrough:{style:p,...m},updateDeps:[a,l,u,d,f,o,s,c]}),(0,n.jsx)(`div`,{ref:h})}function AmosGooglePayButton({ref:r,renderToken:i,amount:a,merchantName:o,height:s=`48px`,buttonProps:c,phoneRequired:l,shippingAddressRequired:u,iframeProps:d,onConfirm:f}){let p=(0,t.useRef)(null),m=(0,e.resolveWalletButtonSkeletonBorderRadius)({iframeStyle:d==null?void 0:d.style,buttonProps:c});return useAmosEmbed({containerRef:p,iframeRef:r,mount:e.mountAmosGooglePayButton,options:{renderToken:i,amount:a,merchantName:o,height:s,buttonProps:c,phoneRequired:l,shippingAddressRequired:u,onConfirm:f},remountDeps:[i],iframePassthrough:d==null?{}:d,updateDeps:[a,o,s,c,l,u,f]}),(0,n.jsx)(WalletButtonSlot,{height:s,borderRadius:m,containerRef:p})}function AmosApplePayButton({ref:r,renderToken:i,amount:a,merchantName:o,height:s=`48px`,buttonProps:c,phoneRequired:l,shippingAddressRequired:u,iframeProps:d,onConfirm:f}){let p=(0,t.useRef)(null),m=(0,e.resolveWalletButtonSkeletonBorderRadius)({iframeStyle:d==null?void 0:d.style,buttonProps:c});return useAmosEmbed({containerRef:p,iframeRef:r,mount:e.mountAmosApplePayButton,options:{renderToken:i,amount:a,merchantName:o,height:s,buttonProps:c,phoneRequired:l,shippingAddressRequired:u,onConfirm:f},remountDeps:[i],iframePassthrough:d==null?{}:d,updateDeps:[a,o,s,c,l,u,f]}),(0,n.jsx)(WalletButtonSlot,{height:s,borderRadius:m,containerRef:p})}exports.AmosApplePayButton=AmosApplePayButton,exports.AmosBankAccountPaymentMethodForm=AmosBankAccountPaymentMethodForm,exports.AmosCreditCardPaymentMethodForm=AmosCreditCardPaymentMethodForm,exports.AmosGooglePayButton=AmosGooglePayButton,exports.confirmPayment=confirmPayment,exports.confirmSetup=confirmSetup,exports.focusField=focusField,exports.resetForm=resetForm,exports.validateForm=validateForm,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
@@ -38,7 +38,10 @@ function setForwardedRef(e, t) {
38
38
  typeof e == "function" ? e(t) : e && (e.current = t);
39
39
  }
40
40
  function applyIframePassthrough(e, { style: t, className: n, id: r, ...i }) {
41
- n != null && (e.className = n), r != null && (e.id = r), Object.assign(e.style, t);
41
+ if (n != null && (e.className = n), r != null && (e.id = r), t) {
42
+ let n = { ...t };
43
+ delete n.width, delete n.height, Object.assign(e.style, n);
44
+ }
42
45
  for (let [t, n] of Object.entries(i)) n != null && (t in e ? Reflect.set(e, t, n) : e.setAttribute(t, String(n)));
43
46
  }
44
47
  function useAmosEmbed({ containerRef: e, iframeRef: t, mount: n, options: r, remountDeps: i, iframePassthrough: a, updateDeps: o }) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amos.com/react-amos-js",
3
- "version": "0.11.26",
3
+ "version": "0.11.28",
4
4
  "main": "dist/index.js",
5
5
  "repository": {
6
6
  "type": "git",
@@ -57,11 +57,11 @@
57
57
  "vite-plugin-dts": "5.1.1"
58
58
  },
59
59
  "dependencies": {
60
- "@amos.com/amos-js": "0.11.28",
60
+ "@amos.com/amos-js": "0.11.30",
61
61
  "@types/googlepay": "0.7.13"
62
62
  },
63
63
  "peerDependencies": {
64
- "react": "^17 || ^18 || ^19",
65
- "@amos.com/node": ">=0.1.65"
64
+ "@amos.com/node": ">=0.1.65",
65
+ "react": "^17 || ^18 || ^19"
66
66
  }
67
67
  }
package/src/index.tsx CHANGED
@@ -161,7 +161,7 @@ function setForwardedRef(
161
161
 
162
162
  type IframePassthroughProps = Omit<
163
163
  ComponentProps<"iframe">,
164
- "src" | "title" | "name" | "role" | "allow"
164
+ "src" | "title" | "name" | "role" | "allow" | "sandbox" | "width" | "height"
165
165
  >;
166
166
 
167
167
  function applyIframePassthrough(
@@ -174,7 +174,14 @@ function applyIframePassthrough(
174
174
  if (id != null) {
175
175
  iframe.id = id;
176
176
  }
177
- Object.assign(iframe.style, style);
177
+ if (style) {
178
+ const chrome = { ...style };
179
+ // amos-js owns the pixel box. A percentage width here makes WebKit
180
+ // treat the frame as indefinite and can pause its layout.
181
+ delete chrome.width;
182
+ delete chrome.height;
183
+ Object.assign(iframe.style, chrome);
184
+ }
178
185
  for (const [key, value] of Object.entries(rest)) {
179
186
  if (value == null) {
180
187
  continue;