@amos.com/amos-js 0.9.16 → 0.9.17

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
@@ -14,7 +14,7 @@ npm install @amos.com/amos-js
14
14
 
15
15
  - **Types** for the `postMessage` protocol used between your page and the Amos iframe (`Message`, `Appearance`, `ThemeVariable`). OpenAPI schema types (for example `components["schemas"]["PaymentIntent"]`) come from `@amos.com/node`.
16
16
  - **Iframe-targeted helpers** to validate the form, confirm a payment intent, confirm a setup intent, update appearance, etc.
17
- - **Mount functions** (`mountAmosCreditCardPaymentMethodForm`, `mountAmosBankAccountPaymentMethodForm`, `mountAmosGooglePayButton`, `mountAmosApplePayButton`) that create the iframe, wire up its message protocol, manage its height/opacity, show a field-shaped loading skeleton for card/bank forms, and return a small controller for updating options and tearing it down.
17
+ - **Mount functions** (`mountAmosCreditCardPaymentMethodForm`, `mountAmosBankAccountPaymentMethodForm`, `mountAmosGooglePayButton`, `mountAmosApplePayButton`) that create the iframe, wire up its message protocol, manage its height/opacity, show a loading skeleton (field-shaped for card/bank forms, button-shaped for Google Pay / Apple Pay), and return a small controller for updating options and tearing it down.
18
18
  - **Lower-level building blocks** (`getCreditCardFormSrc`, `attachPaymentMethodFormListeners`, `attachGooglePayButtonListeners`, `attachApplePayButtonListeners`, ...) for integrators (such as `@amos.com/react-amos-js`) that want to render the iframe element themselves.
19
19
 
20
20
  > **Note:** A server-side SDK (for example `@amos.com/node`) must be used alongside `@amos.com/amos-js` for end-to-end payment processing. `@amos.com/amos-js` is the client-side half.
@@ -295,7 +295,7 @@ Same shape as `mountAmosCreditCardPaymentMethodForm`, minus `additionalFields`.
295
295
 
296
296
  ### `mountAmosGooglePayButton(container, options)`
297
297
 
298
- Mount the secure Google Pay button (express checkout) into a container element.
298
+ Mount the secure Google Pay button (express checkout) into a container element. A button-shaped skeleton is shown immediately and replaced by the iframe once appearance is applied.
299
299
 
300
300
  **Required `options`:**
301
301
 
@@ -328,11 +328,11 @@ The wallet iframe is flush with its mount container (`width: 100%`, zero margin)
328
328
 
329
329
  **Returns** `AmosGooglePayButtonMountController`:
330
330
 
331
- - `iframe`, `update(patch)`, `destroy()`. Use `update({ amount, merchantName })` to push new values into the iframe. Use `update({ height, buttonProps })` to restyle the button.
331
+ - `iframe`, `update(patch)`, `destroy()`. `destroy()` removes the iframe and any loading skeleton. Use `update({ amount, merchantName })` to push new values into the iframe. Use `update({ height, buttonProps })` to restyle the button.
332
332
 
333
333
  ### `mountAmosApplePayButton(container, options)`
334
334
 
335
- Mount the secure Apple Pay button (express checkout). Same required options and return shape as `mountAmosGooglePayButton`.
335
+ Mount the secure Apple Pay button (express checkout). Same required options and return shape as `mountAmosGooglePayButton`. A button-shaped skeleton is shown immediately and replaced by the iframe once appearance is applied.
336
336
 
337
337
  **Optional visual options:**
338
338
 
@@ -1,5 +1,7 @@
1
1
  import { BillingAddressRequirement, CreditCardAdditionalFields } from './payment-method-form';
2
2
  import { Appearance } from './types';
3
+ export declare const SKELETON_STYLES = "\n.amos-js-form-skeleton {\n box-sizing: border-box;\n container-type: inline-size;\n display: flex;\n flex-direction: column;\n gap: var(--field-gap);\n margin: 0 -4px;\n padding-block: 0.25rem;\n pointer-events: none;\n width: calc(100% + 8px);\n}\n.amos-js-form-skeleton-field {\n display: flex;\n flex: 1 1 0;\n flex-direction: column;\n min-width: 0;\n width: 100%;\n}\n.amos-js-form-skeleton-label {\n flex-shrink: 0;\n font-size: var(--label-font-size);\n height: 1.75rem;\n line-height: 1.75rem;\n}\n.amos-js-form-skeleton-input {\n animation: amos-js-skeleton-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;\n background: var(--accent);\n border-radius: calc(var(--radius) * 0.8);\n box-sizing: border-box;\n height: var(--input-height);\n width: 100%;\n}\n.amos-js-form-skeleton-input-floating {\n height: var(--floating-input-height);\n}\n.amos-js-form-skeleton-row {\n align-items: flex-start;\n display: flex;\n gap: var(--control-gap);\n width: 100%;\n}\n.amos-js-form-skeleton-row-stack {\n display: flex;\n flex-direction: column;\n gap: var(--field-gap);\n width: 100%;\n}\n@container (min-width: 24rem) {\n .amos-js-form-skeleton-row-stack {\n align-items: flex-start;\n flex-direction: row;\n gap: var(--control-gap);\n }\n}\n.amos-js-wallet-skeleton {\n flex: none;\n width: 100%;\n}\n@keyframes amos-js-skeleton-pulse {\n 50% { opacity: 0.5; }\n}\n@media (prefers-reduced-motion: reduce) {\n .amos-js-form-skeleton-input {\n animation: none;\n }\n}\n";
4
+ export declare function ensureSkeletonStyles(): void;
3
5
  export type PaymentMethodFormSkeletonKind = "card" | "bank";
4
6
  export type PaymentMethodFormSkeletonOptions = {
5
7
  kind: PaymentMethodFormSkeletonKind;
@@ -18,3 +20,32 @@ export type PaymentMethodFormSkeleton = {
18
20
  * ready.
19
21
  */
20
22
  export declare function createPaymentMethodFormSkeleton(options: PaymentMethodFormSkeletonOptions): PaymentMethodFormSkeleton;
23
+ export type WalletButtonSkeletonOptions = {
24
+ /** Painted height of the wallet button slot (CSS length). */
25
+ height: string;
26
+ /** Corner radius matching the iframe / native button. */
27
+ borderRadius?: string;
28
+ };
29
+ export type WalletButtonSkeleton = {
30
+ element: HTMLElement;
31
+ update: (options: WalletButtonSkeletonOptions) => void;
32
+ };
33
+ /**
34
+ * Host-page placeholder for Google Pay / Apple Pay: a pulsing bar at
35
+ * the button's height. Shown immediately while the iframe loads, then
36
+ * removed when appearance is ready.
37
+ */
38
+ export declare function createWalletButtonSkeleton(options: WalletButtonSkeletonOptions): WalletButtonSkeleton;
39
+ /**
40
+ * Corner radius for a wallet-button skeleton. Prefers host iframe
41
+ * chrome, then native Google / Apple button radius, then 4px.
42
+ */
43
+ export declare function resolveWalletButtonSkeletonBorderRadius({ iframeStyle, buttonProps, }: {
44
+ iframeStyle?: {
45
+ borderRadius?: string | number;
46
+ };
47
+ buttonProps?: {
48
+ buttonRadius?: number;
49
+ style?: Record<string, string | number | undefined>;
50
+ };
51
+ }): string;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  /// <reference types="googlepay" />
2
2
  export type { ApplePayButtonController, ApplePayButtonListenerOptions, } from './apple-pay';
3
3
  export { attachApplePayButtonListeners, getApplePayButtonInitialHeight, getApplePayButtonSrc, } from './apple-pay';
4
+ export type { PaymentMethodFormSkeleton, PaymentMethodFormSkeletonKind, PaymentMethodFormSkeletonOptions, WalletButtonSkeleton, WalletButtonSkeletonOptions, } from './form-skeleton';
5
+ export { createPaymentMethodFormSkeleton, createWalletButtonSkeleton, ensureSkeletonStyles, resolveWalletButtonSkeletonBorderRadius, SKELETON_STYLES, } from './form-skeleton';
4
6
  export type { FormattedGooglePayPaymentData, GooglePayButtonController, GooglePayButtonListenerOptions, } from './google-pay';
5
7
  export { attachGooglePayButtonListeners, formatGooglePayPaymentData, getGooglePayButtonInitialHeight, getGooglePayButtonSrc, } from './google-pay';
6
8
  export { decodeJwt, getEmbedOrigin } from './jwt';
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=`data-amos-apple-pay-waiting`;function t({onCancel:t}){let n=document.querySelector(`[${e}]`);if(n)return n;let r=document.createElement(`div`);r.setAttribute(e,`true`),r.setAttribute(`role`,`dialog`),r.setAttribute(`aria-modal`,`true`),r.setAttribute(`aria-labelledby`,`amos-apple-pay-waiting-title`),Object.assign(r.style,{position:`fixed`,inset:`0`,zIndex:`2147483646`,display:`flex`,alignItems:`center`,justifyContent:`center`,padding:`24px`,boxSizing:`border-box`,background:`rgba(0, 0, 0, 0.55)`,fontFamily:`-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif`});let i=document.createElement(`div`);Object.assign(i.style,{width:`100%`,maxWidth:`360px`,borderRadius:`12px`,background:`#fff`,padding:`28px 24px 20px`,boxSizing:`border-box`,textAlign:`center`,boxShadow:`0 12px 40px rgba(0, 0, 0, 0.25)`});let a=document.createElement(`div`);a.setAttribute(`aria-hidden`,`true`),Object.assign(a.style,{display:`inline-flex`,alignItems:`center`,justifyContent:`center`,gap:`6px`,marginBottom:`16px`,fontSize:`28px`,fontWeight:`600`,letterSpacing:`-0.02em`,color:`#000`,lineHeight:`1`}),a.innerHTML=`<svg width="22" height="26" viewBox="0 0 814 1000" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M788.1 340.9c-5.8 4.5-108.2 62.2-108.2 190.5 0 148.4 130.3 200.9 134.2 202.2-.6 3.2-20.7 71.9-68.7 141.9-42.8 61.6-87.5 123.1-155.5 123.1s-85.5-39.5-164-39.5c-76.5 0-103.7 40.8-165.9 40.8s-105.6-57-155.5-127C46.7 790.7 0 663 0 541.8c0-194.4 126.4-297.5 250.8-297.5 66.1 0 121.2 43.4 162.7 43.4 39.5 0 101.1-46 176.3-46 28.5 0 130.9 2.6 198.3 99.2zm-234-181.5c31.1-36.9 53.1-88.1 53.1-139.3 0-7.1-.6-14.3-1.9-20.1-50.6 1.9-110.8 33.7-147.1 75.8-28.5 32.4-55.1 83.6-55.1 135.5 0 7.8 1.3 15.6 1.9 18.1 3.2.6 8.4 1.3 13.6 1.3 45.4 0 102.5-30.4 135.5-71.3z"/></svg><span>Pay</span>`;let o=document.createElement(`p`);o.id=`amos-apple-pay-waiting-title`,Object.assign(o.style,{margin:`0 0 20px`,fontSize:`15px`,lineHeight:`1.45`,color:`#1a1a1a`}),o.textContent=`Complete your payment in the open Apple Pay window, or close Apple Pay to continue paying another way.`;let s=document.createElement(`button`);return s.type=`button`,s.textContent=`Cancel payment`,Object.assign(s.style,{display:`block`,width:`100%`,border:`none`,borderRadius:`8px`,padding:`12px 16px`,background:`#2c2c2e`,color:`#fff`,fontSize:`15px`,fontWeight:`500`,cursor:`pointer`}),s.addEventListener(`click`,t),i.append(a,o,s),r.append(i),document.body.append(r),r}function n(){document.querySelector(`[${e}]`)?.remove()}function r(e){let[t=``,n=``,r=``]=e?.split(`.`)??[],i=typeof atob==`function`?atob:e=>Buffer.from(e,`base64`).toString(`utf8`);return{header:JSON.parse(i(t)),payload:JSON.parse(i(n)),signature:r}}function i(e){let{env:t=`sandbox`}=r(e).payload;switch(t){case`production`:return`https://embed.amos.com`;case`sandbox`:return`https://embed-sandbox.amos.com`;default:return`https://embed-sandbox.amos.com`}}function a(e){return e}function o(e){return new URL(e.src).origin}function s(e){e?.contentWindow&&e.contentWindow.postMessage(a({type:`PARENT_ACKNOWLEDGED_IFRAME_READY`}),o(e))}function c({iframe:e,appearance:t={}}){e?.contentWindow&&e.contentWindow.postMessage(a({type:`UPDATE_APPEARANCE`,appearance:t}),o(e))}function l({iframe:e,props:t,height:n}){e?.contentWindow&&e.contentWindow.postMessage(a({type:`UPDATE_APPLE_PAY_BUTTON`,height:n,props:t}),o(e))}function u({iframe:e,props:t,height:n}){e?.contentWindow&&e.contentWindow.postMessage(a({type:`UPDATE_GOOGLE_PAY_BUTTON`,height:n,props:t}),o(e))}function d({iframe:e,amount:t}){e?.contentWindow&&e.contentWindow.postMessage(a({type:`UPDATE_AMOUNT`,amount:t}),o(e))}function f({iframe:e,merchantName:t}){e?.contentWindow&&e.contentWindow.postMessage(a({type:`UPDATE_MERCHANT_NAME`,merchantName:t}),o(e))}function p({iframe:e}){let t=crypto.randomUUID();return new Promise(n=>{e?.contentWindow&&e.contentWindow.postMessage(a({type:`VALIDATE_FORM`,requestId:t}),o(e));let r=setTimeout(()=>{window.removeEventListener(`message`,i),n(!1)},5e3);function i(e){e.data.type===`VALIDATE_FORM`&&e.data.requestId===t&&(window.removeEventListener(`message`,i),clearTimeout(r),n(e.data.isValid??!1))}window.addEventListener(`message`,i)})}function m({iframe:e}){e?.contentWindow&&e.contentWindow.postMessage(a({type:`RESET_FORM`}),o(e))}function h({iframe:e,token:t}){if(!e?.contentWindow)return;let{payment_intent_id:n}=r(t).payload;e.contentWindow.postMessage(a({type:`CONFIRM_PAYMENT_INTENT`,token:t,id:n??void 0}),o(e))}function g({iframe:e,token:t}){if(!e?.contentWindow)return;let{setup_intent_id:n}=r(t).payload;e.contentWindow.postMessage(a({type:`CONFIRM_SETUP_INTENT`,token:t,id:n??void 0}),o(e))}function _({iframe:e,result:t}){e?.contentWindow&&e.contentWindow.postMessage(a({type:`CONFIRMATION_RESULT`,result:t}),o(e))}function v(e){return`${i(e)}/iframe/apple-pay?token=${e}`}function y(){return`48px`}function b(e){e.contentWindow?.postMessage(a({type:`APPLE_PAY_CANCEL`}),o(e))}function x(e,{height:r=`48px`,...i}){let a={...i,height:r};function o(){d({iframe:e,amount:a.amount})}function u(){f({iframe:e,merchantName:a.merchantName})}function p(){l({iframe:e,height:a.height??`48px`,props:a.buttonProps??{}})}function m(r){if(r.source===e.contentWindow)switch(r.data.type){case`IFRAME_READY`:s(e),c({iframe:e,appearance:{}}),o(),u(),p();break;case`UPDATE_HEIGHT`:a.onHeightChange?.(r.data.height);break;case`UPDATE_APPEARANCE`:c({iframe:e,appearance:r.data.appearance});break;case`UPDATED_APPEARANCE`:a.onAppearanceReady?.();break;case`APPLE_PAY_WINDOW_OPEN`:t({onCancel:()=>{b(e),n()}});break;case`APPLE_PAY_WINDOW_CLOSE`:n();break;case`CREATE_PAYMENT_INTENT`:a.onInitiatePaymentIntentRequest({paymentIntentCreateAttributes:r.data.paymentIntentCreateAttributes,customerCreateAttributes:r.data.customerCreateAttributes}).then(t=>{h({iframe:e,token:t})}).catch(e=>{n(),a.onResult({status:`failed`,errorMessage:e instanceof Error?e.message:`Unknown error`})});break;case`CONFIRMATION_RESULT`:n(),a.onResult(r.data.result)}}return window.addEventListener(`message`,m),{update(e){let t=`amount`in e,n=`merchantName`in e,r=`height`in e||`buttonProps`in e;a={...a,...e},t&&o(),n&&u(),r&&p()},destroy(){window.removeEventListener(`message`,m),n()}}}function S(e){return`${i(e)}/iframe/google-pay?token=${e}`}function C(){return`48px`}function w(e,{height:t=`48px`,...n}){let r={...n,height:t};function i(){d({iframe:e,amount:r.amount})}function a(){f({iframe:e,merchantName:r.merchantName})}function o(){u({iframe:e,height:r.height??`48px`,props:r.buttonProps??{}})}function l(t){if(t.source===e.contentWindow)switch(t.data.type){case`IFRAME_READY`:s(e),c({iframe:e,appearance:{}}),i(),a(),o();break;case`UPDATE_HEIGHT`:r.onHeightChange?.(t.data.height);break;case`UPDATE_APPEARANCE`:c({iframe:e,appearance:t.data.appearance});break;case`UPDATED_APPEARANCE`:r.onAppearanceReady?.();break;case`CREATE_PAYMENT_INTENT`:r.onInitiatePaymentIntentRequest({paymentIntentCreateAttributes:t.data.paymentIntentCreateAttributes,customerCreateAttributes:t.data.customerCreateAttributes}).then(t=>{h({iframe:e,token:t})}).catch(e=>{r.onResult({status:`failed`,errorMessage:e instanceof Error?e.message:`Unknown error`})});break;case`CONFIRMATION_RESULT`:r.onResult(t.data.result)}}return window.addEventListener(`message`,l),{update(e){let t=`amount`in e,n=`merchantName`in e,s=`height`in e||`buttonProps`in e;r={...r,...e},t&&i(),n&&a(),s&&o()},destroy(){window.removeEventListener(`message`,l)}}}function T({paymentData:e}){return{paymentMethod:{type:`googlepay`,billing_address_attributes:{name:e.shippingAddress?.name,address_line1:e.shippingAddress?.address1,address_line2:e.shippingAddress?.address2,city:e.shippingAddress?.locality,state:e.shippingAddress?.administrativeArea,postal_code:e.shippingAddress?.postalCode,country:e.shippingAddress?.countryCode,email:e.email,phone:e.shippingAddress?.phoneNumber},card_profile_attributes:{wallet_payload:e.paymentMethodData.tokenizationData.token}}}}var E=`amos-js-form-skeleton-styles`,D={"--accent":`oklch(0.97 0 0)`,"--radius":`0.625rem`,"--input-height":`2.25rem`,"--floating-input-height":`3.25rem`,"--field-gap":`1rem`,"--control-gap":`0.5rem`,"--label-font-size":`0.875rem`},O=`
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=`data-amos-apple-pay-waiting`;function t({onCancel:t}){let n=document.querySelector(`[${e}]`);if(n)return n;let r=document.createElement(`div`);r.setAttribute(e,`true`),r.setAttribute(`role`,`dialog`),r.setAttribute(`aria-modal`,`true`),r.setAttribute(`aria-labelledby`,`amos-apple-pay-waiting-title`),Object.assign(r.style,{position:`fixed`,inset:`0`,zIndex:`2147483646`,display:`flex`,alignItems:`center`,justifyContent:`center`,padding:`24px`,boxSizing:`border-box`,background:`rgba(0, 0, 0, 0.55)`,fontFamily:`-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif`});let i=document.createElement(`div`);Object.assign(i.style,{width:`100%`,maxWidth:`360px`,borderRadius:`12px`,background:`#fff`,padding:`28px 24px 20px`,boxSizing:`border-box`,textAlign:`center`,boxShadow:`0 12px 40px rgba(0, 0, 0, 0.25)`});let a=document.createElement(`div`);a.setAttribute(`aria-hidden`,`true`),Object.assign(a.style,{display:`inline-flex`,alignItems:`center`,justifyContent:`center`,gap:`6px`,marginBottom:`16px`,fontSize:`28px`,fontWeight:`600`,letterSpacing:`-0.02em`,color:`#000`,lineHeight:`1`}),a.innerHTML=`<svg width="22" height="26" viewBox="0 0 814 1000" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M788.1 340.9c-5.8 4.5-108.2 62.2-108.2 190.5 0 148.4 130.3 200.9 134.2 202.2-.6 3.2-20.7 71.9-68.7 141.9-42.8 61.6-87.5 123.1-155.5 123.1s-85.5-39.5-164-39.5c-76.5 0-103.7 40.8-165.9 40.8s-105.6-57-155.5-127C46.7 790.7 0 663 0 541.8c0-194.4 126.4-297.5 250.8-297.5 66.1 0 121.2 43.4 162.7 43.4 39.5 0 101.1-46 176.3-46 28.5 0 130.9 2.6 198.3 99.2zm-234-181.5c31.1-36.9 53.1-88.1 53.1-139.3 0-7.1-.6-14.3-1.9-20.1-50.6 1.9-110.8 33.7-147.1 75.8-28.5 32.4-55.1 83.6-55.1 135.5 0 7.8 1.3 15.6 1.9 18.1 3.2.6 8.4 1.3 13.6 1.3 45.4 0 102.5-30.4 135.5-71.3z"/></svg><span>Pay</span>`;let o=document.createElement(`p`);o.id=`amos-apple-pay-waiting-title`,Object.assign(o.style,{margin:`0 0 20px`,fontSize:`15px`,lineHeight:`1.45`,color:`#1a1a1a`}),o.textContent=`Complete your payment in the open Apple Pay window, or close Apple Pay to continue paying another way.`;let s=document.createElement(`button`);return s.type=`button`,s.textContent=`Cancel payment`,Object.assign(s.style,{display:`block`,width:`100%`,border:`none`,borderRadius:`8px`,padding:`12px 16px`,background:`#2c2c2e`,color:`#fff`,fontSize:`15px`,fontWeight:`500`,cursor:`pointer`}),s.addEventListener(`click`,t),i.append(a,o,s),r.append(i),document.body.append(r),r}function n(){document.querySelector(`[${e}]`)?.remove()}function r(e){let[t=``,n=``,r=``]=e?.split(`.`)??[],i=typeof atob==`function`?atob:e=>Buffer.from(e,`base64`).toString(`utf8`);return{header:JSON.parse(i(t)),payload:JSON.parse(i(n)),signature:r}}function i(e){let{env:t=`sandbox`}=r(e).payload;switch(t){case`production`:return`https://embed.amos.com`;case`sandbox`:return`https://embed-sandbox.amos.com`;default:return`https://embed-sandbox.amos.com`}}function a(e){return e}function o(e){return new URL(e.src).origin}function s(e){e?.contentWindow&&e.contentWindow.postMessage(a({type:`PARENT_ACKNOWLEDGED_IFRAME_READY`}),o(e))}function c({iframe:e,appearance:t={}}){e?.contentWindow&&e.contentWindow.postMessage(a({type:`UPDATE_APPEARANCE`,appearance:t}),o(e))}function l({iframe:e,props:t,height:n}){e?.contentWindow&&e.contentWindow.postMessage(a({type:`UPDATE_APPLE_PAY_BUTTON`,height:n,props:t}),o(e))}function u({iframe:e,props:t,height:n}){e?.contentWindow&&e.contentWindow.postMessage(a({type:`UPDATE_GOOGLE_PAY_BUTTON`,height:n,props:t}),o(e))}function d({iframe:e,amount:t}){e?.contentWindow&&e.contentWindow.postMessage(a({type:`UPDATE_AMOUNT`,amount:t}),o(e))}function f({iframe:e,merchantName:t}){e?.contentWindow&&e.contentWindow.postMessage(a({type:`UPDATE_MERCHANT_NAME`,merchantName:t}),o(e))}function p({iframe:e}){let t=crypto.randomUUID();return new Promise(n=>{e?.contentWindow&&e.contentWindow.postMessage(a({type:`VALIDATE_FORM`,requestId:t}),o(e));let r=setTimeout(()=>{window.removeEventListener(`message`,i),n(!1)},5e3);function i(e){e.data.type===`VALIDATE_FORM`&&e.data.requestId===t&&(window.removeEventListener(`message`,i),clearTimeout(r),n(e.data.isValid??!1))}window.addEventListener(`message`,i)})}function m({iframe:e}){e?.contentWindow&&e.contentWindow.postMessage(a({type:`RESET_FORM`}),o(e))}function h({iframe:e,token:t}){if(!e?.contentWindow)return;let{payment_intent_id:n}=r(t).payload;e.contentWindow.postMessage(a({type:`CONFIRM_PAYMENT_INTENT`,token:t,id:n??void 0}),o(e))}function g({iframe:e,token:t}){if(!e?.contentWindow)return;let{setup_intent_id:n}=r(t).payload;e.contentWindow.postMessage(a({type:`CONFIRM_SETUP_INTENT`,token:t,id:n??void 0}),o(e))}function _({iframe:e,result:t}){e?.contentWindow&&e.contentWindow.postMessage(a({type:`CONFIRMATION_RESULT`,result:t}),o(e))}function v(e){return`${i(e)}/iframe/apple-pay?token=${e}`}function y(){return`48px`}function ee(e){e.contentWindow?.postMessage(a({type:`APPLE_PAY_CANCEL`}),o(e))}function b(e,{height:r=`48px`,...i}){let a={...i,height:r};function o(){d({iframe:e,amount:a.amount})}function u(){f({iframe:e,merchantName:a.merchantName})}function p(){l({iframe:e,height:a.height??`48px`,props:a.buttonProps??{}})}function m(r){if(r.source===e.contentWindow)switch(r.data.type){case`IFRAME_READY`:s(e),c({iframe:e,appearance:{}}),o(),u(),p();break;case`UPDATE_HEIGHT`:a.onHeightChange?.(r.data.height);break;case`UPDATE_APPEARANCE`:c({iframe:e,appearance:r.data.appearance});break;case`UPDATED_APPEARANCE`:a.onAppearanceReady?.();break;case`APPLE_PAY_WINDOW_OPEN`:t({onCancel:()=>{ee(e),n()}});break;case`APPLE_PAY_WINDOW_CLOSE`:n();break;case`CREATE_PAYMENT_INTENT`:a.onInitiatePaymentIntentRequest({paymentIntentCreateAttributes:r.data.paymentIntentCreateAttributes,customerCreateAttributes:r.data.customerCreateAttributes}).then(t=>{h({iframe:e,token:t})}).catch(e=>{n(),a.onResult({status:`failed`,errorMessage:e instanceof Error?e.message:`Unknown error`})});break;case`CONFIRMATION_RESULT`:n(),a.onResult(r.data.result)}}return window.addEventListener(`message`,m),{update(e){let t=`amount`in e,n=`merchantName`in e,r=`height`in e||`buttonProps`in e;a={...a,...e},t&&o(),n&&u(),r&&p()},destroy(){window.removeEventListener(`message`,m),n()}}}var x=`amos-js-form-skeleton-styles`,S={"--accent":`oklch(0.97 0 0)`,"--radius":`0.625rem`,"--input-height":`2.25rem`,"--floating-input-height":`3.25rem`,"--field-gap":`1rem`,"--control-gap":`0.5rem`,"--label-font-size":`0.875rem`},C=`
2
2
  .amos-js-form-skeleton {
3
3
  box-sizing: border-box;
4
4
  container-type: inline-size;
@@ -53,6 +53,10 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=`data-a
53
53
  gap: var(--control-gap);
54
54
  }
55
55
  }
56
+ .amos-js-wallet-skeleton {
57
+ flex: none;
58
+ width: 100%;
59
+ }
56
60
  @keyframes amos-js-skeleton-pulse {
57
61
  50% { opacity: 0.5; }
58
62
  }
@@ -61,4 +65,4 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=`data-a
61
65
  animation: none;
62
66
  }
63
67
  }
64
- `;function k(){if(document.getElementById(E))return;let e=document.createElement(`style`);e.id=E,e.textContent=O,document.head.appendChild(e)}function A(e,t){for(let[t,n]of Object.entries(D))e.style.setProperty(t,n);let n=t?.themeVariables;if(n)for(let[t,r]of Object.entries(n))typeof r==`string`&&r.trim()!==``&&e.style.setProperty(t,r.trim())}function j(e,t){let n=document.createElement(`div`);if(n.className=e,t)for(let e of t)n.appendChild(e);return n}function M(e,t){let n=j(`amos-js-form-skeleton-field`);t!==void 0&&(n.style.flexGrow=String(t)),e===`above`&&n.appendChild(j(`amos-js-form-skeleton-label`));let r=j(`amos-js-form-skeleton-input`);return e===`floating`&&r.classList.add(`amos-js-form-skeleton-input-floating`),n.appendChild(r),n}function N(e,t){return j(t?`amos-js-form-skeleton-row-stack`:`amos-js-form-skeleton-row`,e)}function P({labels:e,requirement:t,wrapCountryZip:n}){return t===`full`?[M(e),M(e),N([M(e,1.4),M(e,.7),M(e,.8)],!1),M(e)]:[N([M(e),M(e)],n)]}function F(e){let t=e.appearance?.labels??`above`,n=e.billingAddressRequirement??`country`;if(e.kind===`card`){let r=[M(t),N([M(t),M(t)],!1)];return e.additionalFields?.cardholderName&&r.push(M(t)),r.push(...P({labels:t,requirement:n,wrapCountryZip:!1})),r}return[M(t),N([M(t),M(t)],!0),M(t),N([M(`above`),M(`above`)],!0),...P({labels:t,requirement:n,wrapCountryZip:!0})]}function I(e){k();let t=j(`amos-js-form-skeleton`);t.setAttribute(`aria-hidden`,`true`);function n(e){A(t,e.appearance),t.replaceChildren(...F(e))}return n(e),{element:t,update:n}}var L={country:212,full:452},R=80,z={country:400,full:640};function B(e,t={cardholderName:!1},n=`country`){let r=Object.entries(t).filter(([,e])=>e).map(([e])=>e).join(`,`),a=new URLSearchParams({token:e,additionalFields:r,billingAddressRequirement:n});return`${i(e)}/iframe/card?${a}`}function V(e,t=`country`){let n=new URLSearchParams({token:e,billingAddressRequirement:t});return`${i(e)}/iframe/bank?${n}`}function H(e={cardholderName:!1},t=`country`){return`${(L[t]??L.country)+(e.cardholderName?R:0)}px`}function U(e=`country`){return`${z[e]??z.country}px`}function W(e,t){let n={...t};function r(t){if(t.source===e.contentWindow)switch(t.data.type){case`IFRAME_READY`:s(e),c({iframe:e,appearance:n.appearance});break;case`UPDATE_HEIGHT`:n.onHeightChange?.(t.data.height);break;case`UPDATE_APPEARANCE`:c({iframe:e,appearance:t.data.appearance});break;case`UPDATED_APPEARANCE`:n.onAppearanceReady?.();break;case`FORM_VALIDITY_CHANGE`:n.onValidityChange?.({isValid:t.data.isValid});break;case`CONFIRMATION_RESULT`:n.onResult(t.data.result)}}return window.addEventListener(`message`,r),{update(t){let r=`appearance`in t;n={...n,...t},r&&c({iframe:e,appearance:n.appearance})},destroy(){window.removeEventListener(`message`,r)}}}function G(e){if(typeof e==`string`){let t=document.querySelector(e);if(!(t instanceof HTMLElement))throw Error(`[amos-js] Container "${e}" did not match any HTMLElement.`);return t}return e}var K={width:`calc(100% + 8px)`,transition:`opacity 150ms ease-in, height 200ms ease-in-out`,margin:`0 -4px`,opacity:`0`,border:`0`},q={width:`100%`,transition:`height 200ms ease-in-out`,margin:`0`,opacity:`0`,border:`0`},J={position:`absolute`,top:`0`,left:`-4px`,width:`calc(100% + 8px)`,height:`100%`,margin:`0`,transition:`none`,pointerEvents:`none`};function Y({src:e,title:t,name:n,height:r,allow:i,className:a,style:o=K}){let s=document.createElement(`iframe`);return s.src=e,s.title=t,s.name=n,s.setAttribute(`role`,`presentation`),s.scrolling=`no`,i&&(s.allow=i),a!=null&&(s.className=a),Object.assign(s.style,o,{height:r}),s}function X({host:e,iframe:t,listenerOptions:n,skeletonOptions:r}){let i=document.createElement(`div`);i.style.position=`relative`,i.style.width=`100%`,i.setAttribute(`aria-busy`,`true`);let a=I(r);Object.assign(t.style,J),i.append(a.element,t),e.appendChild(i);let o=!1,s=!1,c,l=r.appearance,u,d;function f(){return i.getBoundingClientRect().height}function p(){return c?Number.parseFloat(c):NaN}function m(){if(o)return;o=!0,d!==void 0&&(clearTimeout(d),d=void 0);let e=f(),n=p(),r=Number.isFinite(n)?Math.max(n,e):e;t.style.transition=`none`,t.style.position=``,t.style.top=``,t.style.left=``,t.style.margin=K.margin??``,t.style.height=`${r}px`,t.style.opacity=`1`,t.style.pointerEvents=``,a.element.remove(),i.removeAttribute(`aria-busy`),u=setTimeout(()=>{t.style.transition=`height 200ms ease-in-out`},400)}function h(){if(o||!s)return;let e=p(),t=f();Number.isFinite(e)&&e>=t-2&&m()}let g=W(t,{...n,onHeightChange:e=>{c=e,o?t.style.height=e:h(),n.onHeightChange?.(e)},onAppearanceReady:()=>{s=!0,h(),!o&&d===void 0&&(d=setTimeout(()=>{m()},1500)),n.onAppearanceReady?.()}});return{iframe:t,update(e){g.update(e),!o&&`appearance`in e&&(l=e.appearance,a.update({...r,appearance:l}))},destroy(){u!==void 0&&clearTimeout(u),d!==void 0&&clearTimeout(d),g.destroy(),i.remove()}}}function Z(e,t){let n=G(e),{renderToken:r,additionalFields:i={cardholderName:!1},billingAddressRequirement:a=`country`,...o}=t;return X({host:n,iframe:Y({src:B(r,i,a),title:`Secure credit card payment method form powered by Amos`,name:`amos-credit-card-payment-method-form`,height:H(i,a)}),listenerOptions:o,skeletonOptions:{kind:`card`,appearance:o.appearance,additionalFields:i,billingAddressRequirement:a}})}function Q(e,t){let n=G(e),{renderToken:r,billingAddressRequirement:i=`country`,...a}=t;return X({host:n,iframe:Y({src:V(r,i),title:`Secure bank account payment method form powered by Amos`,name:`amos-bank-account-payment-method-form`,height:U(i)}),listenerOptions:a,skeletonOptions:{kind:`bank`,appearance:a.appearance,billingAddressRequirement:i}})}function $(e,t){let n=G(e),{renderToken:r,iframeClassName:i,iframeStyle:a,...o}=t,s=Y({src:S(r),title:`Secure Google Pay button powered by Amos`,name:`amos-google-pay-button`,height:o.height??C(),allow:`payment`,className:i,style:q});Object.assign(s.style,a),n.appendChild(s);let c=w(s,{...o,onHeightChange:e=>{s.style.height=e,o.onHeightChange?.(e)},onAppearanceReady:()=>{s.style.opacity=`1`,o.onAppearanceReady?.()}});return{iframe:s,update:c.update,destroy(){c.destroy(),s.remove()}}}function ee(e,t){let n=G(e),{renderToken:r,iframeClassName:i,iframeStyle:a,...o}=t,s=Y({src:v(r),title:`Secure Apple Pay button powered by Amos`,name:`amos-apple-pay-button`,height:o.height??y(),allow:`payment`,className:i,style:q});Object.assign(s.style,a),n.appendChild(s);let c=x(s,{...o,onHeightChange:e=>{s.style.height=e,o.onHeightChange?.(e)},onAppearanceReady:()=>{s.style.opacity=`1`,o.onAppearanceReady?.()}});return{iframe:s,update:c.update,destroy(){c.destroy(),s.remove()}}}exports.attachApplePayButtonListeners=x,exports.attachGooglePayButtonListeners=w,exports.attachPaymentMethodFormListeners=W,exports.confirmPaymentIntent=h,exports.confirmSetupIntent=g,exports.createMessage=a,exports.decodeJwt=r,exports.formatGooglePayPaymentData=T,exports.getApplePayButtonInitialHeight=y,exports.getApplePayButtonSrc=v,exports.getBankAccountFormInitialHeight=U,exports.getBankAccountFormSrc=V,exports.getCreditCardFormInitialHeight=H,exports.getCreditCardFormSrc=B,exports.getEmbedOrigin=i,exports.getGooglePayButtonInitialHeight=C,exports.getGooglePayButtonSrc=S,exports.mountAmosApplePayButton=ee,exports.mountAmosBankAccountPaymentMethodForm=Q,exports.mountAmosCreditCardPaymentMethodForm=Z,exports.mountAmosGooglePayButton=$,exports.resetForm=m,exports.sendConfirmationResult=_,exports.sendParentReadyMessage=s,exports.updateAmount=d,exports.updateAppearance=c,exports.updateApplePayButton=l,exports.updateGooglePayButton=u,exports.updateMerchantName=f,exports.validateForm=p;
68
+ `;function w(){if(document.getElementById(x))return;let e=document.createElement(`style`);e.id=x,e.textContent=C,document.head.appendChild(e)}function T(e,t){for(let[t,n]of Object.entries(S))e.style.setProperty(t,n);let n=t?.themeVariables;if(n)for(let[t,r]of Object.entries(n))typeof r==`string`&&r.trim()!==``&&e.style.setProperty(t,r.trim())}function E(e,t){let n=document.createElement(`div`);if(n.className=e,t)for(let e of t)n.appendChild(e);return n}function D(e,t){let n=E(`amos-js-form-skeleton-field`);t!==void 0&&(n.style.flexGrow=String(t)),e===`above`&&n.appendChild(E(`amos-js-form-skeleton-label`));let r=E(`amos-js-form-skeleton-input`);return e===`floating`&&r.classList.add(`amos-js-form-skeleton-input-floating`),n.appendChild(r),n}function O(e,t){return E(t?`amos-js-form-skeleton-row-stack`:`amos-js-form-skeleton-row`,e)}function k({labels:e,requirement:t,wrapCountryZip:n}){return t===`full`?[D(e),D(e),O([D(e,1.4),D(e,.7),D(e,.8)],!1),D(e)]:[O([D(e),D(e)],n)]}function A(e){let t=e.appearance?.labels??`above`,n=e.billingAddressRequirement??`country`;if(e.kind===`card`){let r=[D(t),O([D(t),D(t)],!1)];return e.additionalFields?.cardholderName&&r.push(D(t)),r.push(...k({labels:t,requirement:n,wrapCountryZip:!1})),r}return[D(t),O([D(t),D(t)],!0),D(t),O([D(`above`),D(`above`)],!0),...k({labels:t,requirement:n,wrapCountryZip:!0})]}function j(e){w();let t=E(`amos-js-form-skeleton`);t.setAttribute(`aria-hidden`,`true`);function n(e){T(t,e.appearance),t.replaceChildren(...A(e))}return n(e),{element:t,update:n}}function M(e){w();let t=E(`amos-js-form-skeleton-input amos-js-wallet-skeleton`);t.setAttribute(`aria-hidden`,`true`);function n(e){T(t,void 0),t.style.height=e.height,t.style.borderRadius=e.borderRadius??`4px`}return n(e),{element:t,update:n}}function N(e){if(typeof e==`number`&&Number.isFinite(e))return`${e}px`;if(typeof e==`string`&&e.trim()!==``)return e.trim()}function P({iframeStyle:e,buttonProps:t}){return N(e?.borderRadius)??N(t?.buttonRadius)??N(t?.style?.borderRadius)??N(t?.style?.[`--apple-pay-button-border-radius`])??`4px`}function F(e){return`${i(e)}/iframe/google-pay?token=${e}`}function I(){return`48px`}function L(e,{height:t=`48px`,...n}){let r={...n,height:t};function i(){d({iframe:e,amount:r.amount})}function a(){f({iframe:e,merchantName:r.merchantName})}function o(){u({iframe:e,height:r.height??`48px`,props:r.buttonProps??{}})}function l(t){if(t.source===e.contentWindow)switch(t.data.type){case`IFRAME_READY`:s(e),c({iframe:e,appearance:{}}),i(),a(),o();break;case`UPDATE_HEIGHT`:r.onHeightChange?.(t.data.height);break;case`UPDATE_APPEARANCE`:c({iframe:e,appearance:t.data.appearance});break;case`UPDATED_APPEARANCE`:r.onAppearanceReady?.();break;case`CREATE_PAYMENT_INTENT`:r.onInitiatePaymentIntentRequest({paymentIntentCreateAttributes:t.data.paymentIntentCreateAttributes,customerCreateAttributes:t.data.customerCreateAttributes}).then(t=>{h({iframe:e,token:t})}).catch(e=>{r.onResult({status:`failed`,errorMessage:e instanceof Error?e.message:`Unknown error`})});break;case`CONFIRMATION_RESULT`:r.onResult(t.data.result)}}return window.addEventListener(`message`,l),{update(e){let t=`amount`in e,n=`merchantName`in e,s=`height`in e||`buttonProps`in e;r={...r,...e},t&&i(),n&&a(),s&&o()},destroy(){window.removeEventListener(`message`,l)}}}function R({paymentData:e}){return{paymentMethod:{type:`googlepay`,billing_address_attributes:{name:e.shippingAddress?.name,address_line1:e.shippingAddress?.address1,address_line2:e.shippingAddress?.address2,city:e.shippingAddress?.locality,state:e.shippingAddress?.administrativeArea,postal_code:e.shippingAddress?.postalCode,country:e.shippingAddress?.countryCode,email:e.email,phone:e.shippingAddress?.phoneNumber},card_profile_attributes:{wallet_payload:e.paymentMethodData.tokenizationData.token}}}}var z={country:212,full:452},te=80,B={country:400,full:640};function V(e,t={cardholderName:!1},n=`country`){let r=Object.entries(t).filter(([,e])=>e).map(([e])=>e).join(`,`),a=new URLSearchParams({token:e,additionalFields:r,billingAddressRequirement:n});return`${i(e)}/iframe/card?${a}`}function H(e,t=`country`){let n=new URLSearchParams({token:e,billingAddressRequirement:t});return`${i(e)}/iframe/bank?${n}`}function U(e={cardholderName:!1},t=`country`){return`${(z[t]??z.country)+(e.cardholderName?te:0)}px`}function W(e=`country`){return`${B[e]??B.country}px`}function G(e,t){let n={...t};function r(t){if(t.source===e.contentWindow)switch(t.data.type){case`IFRAME_READY`:s(e),c({iframe:e,appearance:n.appearance});break;case`UPDATE_HEIGHT`:n.onHeightChange?.(t.data.height);break;case`UPDATE_APPEARANCE`:c({iframe:e,appearance:t.data.appearance});break;case`UPDATED_APPEARANCE`:n.onAppearanceReady?.();break;case`FORM_VALIDITY_CHANGE`:n.onValidityChange?.({isValid:t.data.isValid});break;case`CONFIRMATION_RESULT`:n.onResult(t.data.result)}}return window.addEventListener(`message`,r),{update(t){let r=`appearance`in t;n={...n,...t},r&&c({iframe:e,appearance:n.appearance})},destroy(){window.removeEventListener(`message`,r)}}}function K(e){if(typeof e==`string`){let t=document.querySelector(e);if(!(t instanceof HTMLElement))throw Error(`[amos-js] Container "${e}" did not match any HTMLElement.`);return t}return e}var q={width:`calc(100% + 8px)`,transition:`opacity 150ms ease-in, height 200ms ease-in-out`,margin:`0 -4px`,opacity:`0`,border:`0`},J={width:`100%`,transition:`height 200ms ease-in-out`,margin:`0`,opacity:`0`,border:`0`},Y={position:`absolute`,top:`0`,left:`0`,width:`100%`,height:`100%`,margin:`0`,opacity:`0`,transition:`none`,pointerEvents:`none`},X={position:`absolute`,top:`0`,left:`-4px`,width:`calc(100% + 8px)`,height:`100%`,margin:`0`,transition:`none`,pointerEvents:`none`};function Z({src:e,title:t,name:n,height:r,allow:i,className:a,style:o=q}){let s=document.createElement(`iframe`);return s.src=e,s.title=t,s.name=n,s.setAttribute(`role`,`presentation`),s.scrolling=`no`,i&&(s.allow=i),a!=null&&(s.className=a),Object.assign(s.style,o,{height:r}),s}function Q({host:e,iframe:t,listenerOptions:n,skeletonOptions:r}){let i=document.createElement(`div`);i.style.position=`relative`,i.style.width=`100%`,i.setAttribute(`aria-busy`,`true`);let a=j(r);Object.assign(t.style,X),i.append(a.element,t),e.appendChild(i);let o=!1,s=!1,c,l=r.appearance,u,d;function f(){return i.getBoundingClientRect().height}function p(){return c?Number.parseFloat(c):NaN}function m(){if(o)return;o=!0,d!==void 0&&(clearTimeout(d),d=void 0);let e=f(),n=p(),r=Number.isFinite(n)?Math.max(n,e):e;t.style.transition=`none`,t.style.position=``,t.style.top=``,t.style.left=``,t.style.margin=q.margin??``,t.style.height=`${r}px`,t.style.opacity=`1`,t.style.pointerEvents=``,a.element.remove(),i.removeAttribute(`aria-busy`),u=setTimeout(()=>{t.style.transition=`height 200ms ease-in-out`},400)}function h(){if(o||!s)return;let e=p(),t=f();Number.isFinite(e)&&e>=t-2&&m()}let g=G(t,{...n,onHeightChange:e=>{c=e,o?t.style.height=e:h(),n.onHeightChange?.(e)},onAppearanceReady:()=>{s=!0,h(),!o&&d===void 0&&(d=setTimeout(()=>{m()},1500)),n.onAppearanceReady?.()}});return{iframe:t,update(e){g.update(e),!o&&`appearance`in e&&(l=e.appearance,a.update({...r,appearance:l}))},destroy(){u!==void 0&&clearTimeout(u),d!==void 0&&clearTimeout(d),g.destroy(),i.remove()}}}function $({host:e,iframe:t,listenerOptions:n,iframeStyle:r,attachListeners:i}){let a={height:n.height??`48px`,borderRadius:P({iframeStyle:r,buttonProps:n.buttonProps})},o=M(a),s=document.createElement(`div`);s.style.position=`relative`,s.style.width=`100%`,s.style.height=a.height,s.style.overflow=`hidden`,s.setAttribute(`aria-busy`,`true`),Object.assign(t.style,Y),t.style.height=`100%`,s.append(o.element,t),e.appendChild(s);let c=!1,l=!1,u,d=n;function f(){c||(c=!0,u!==void 0&&(clearTimeout(u),u=void 0),t.style.opacity=`1`,t.style.pointerEvents=``,o.element.remove(),s.removeAttribute(`aria-busy`))}function p(){c||!l||f()}let m=i(t,{...n,onHeightChange:e=>{d.onHeightChange?.(e)},onAppearanceReady:()=>{l=!0,p(),d.onAppearanceReady?.()}});return u=setTimeout(()=>{f()},1500),{iframe:t,update(e){d={...d,...e};let t={...e};delete t.onAppearanceReady,delete t.onHeightChange,m.update(t),a={height:d.height??a.height,borderRadius:P({iframeStyle:r,buttonProps:d.buttonProps})},s.style.height=a.height,c||o.update(a)},destroy(){u!==void 0&&clearTimeout(u),m.destroy(),s.remove()}}}function ne(e,t){let n=K(e),{renderToken:r,additionalFields:i={cardholderName:!1},billingAddressRequirement:a=`country`,...o}=t;return Q({host:n,iframe:Z({src:V(r,i,a),title:`Secure credit card payment method form powered by Amos`,name:`amos-credit-card-payment-method-form`,height:U(i,a)}),listenerOptions:o,skeletonOptions:{kind:`card`,appearance:o.appearance,additionalFields:i,billingAddressRequirement:a}})}function re(e,t){let n=K(e),{renderToken:r,billingAddressRequirement:i=`country`,...a}=t;return Q({host:n,iframe:Z({src:H(r,i),title:`Secure bank account payment method form powered by Amos`,name:`amos-bank-account-payment-method-form`,height:W(i)}),listenerOptions:a,skeletonOptions:{kind:`bank`,appearance:a.appearance,billingAddressRequirement:i}})}function ie(e,t){let n=K(e),{renderToken:r,iframeClassName:i,iframeStyle:a,...o}=t,s=Z({src:F(r),title:`Secure Google Pay button powered by Amos`,name:`amos-google-pay-button`,height:o.height??I(),allow:`payment`,className:i,style:J});return Object.assign(s.style,a),$({host:n,iframe:s,listenerOptions:o,iframeStyle:a,attachListeners:L})}function ae(e,t){let n=K(e),{renderToken:r,iframeClassName:i,iframeStyle:a,...o}=t,s=Z({src:v(r),title:`Secure Apple Pay button powered by Amos`,name:`amos-apple-pay-button`,height:o.height??y(),allow:`payment`,className:i,style:J});return Object.assign(s.style,a),$({host:n,iframe:s,listenerOptions:o,iframeStyle:a,attachListeners:b})}exports.SKELETON_STYLES=C,exports.attachApplePayButtonListeners=b,exports.attachGooglePayButtonListeners=L,exports.attachPaymentMethodFormListeners=G,exports.confirmPaymentIntent=h,exports.confirmSetupIntent=g,exports.createMessage=a,exports.createPaymentMethodFormSkeleton=j,exports.createWalletButtonSkeleton=M,exports.decodeJwt=r,exports.ensureSkeletonStyles=w,exports.formatGooglePayPaymentData=R,exports.getApplePayButtonInitialHeight=y,exports.getApplePayButtonSrc=v,exports.getBankAccountFormInitialHeight=W,exports.getBankAccountFormSrc=H,exports.getCreditCardFormInitialHeight=U,exports.getCreditCardFormSrc=V,exports.getEmbedOrigin=i,exports.getGooglePayButtonInitialHeight=I,exports.getGooglePayButtonSrc=F,exports.mountAmosApplePayButton=ae,exports.mountAmosBankAccountPaymentMethodForm=re,exports.mountAmosCreditCardPaymentMethodForm=ne,exports.mountAmosGooglePayButton=ie,exports.resetForm=m,exports.resolveWalletButtonSkeletonBorderRadius=P,exports.sendConfirmationResult=_,exports.sendParentReadyMessage=s,exports.updateAmount=d,exports.updateAppearance=c,exports.updateApplePayButton=l,exports.updateGooglePayButton=u,exports.updateMerchantName=f,exports.validateForm=p;
package/dist/index.mjs CHANGED
@@ -178,10 +178,10 @@ function v(e) {
178
178
  function y() {
179
179
  return "48px";
180
180
  }
181
- function b(e) {
181
+ function ee(e) {
182
182
  e.contentWindow?.postMessage(a({ type: "APPLE_PAY_CANCEL" }), o(e));
183
183
  }
184
- function x(e, { height: r = "48px", ...i }) {
184
+ function b(e, { height: r = "48px", ...i }) {
185
185
  let a = {
186
186
  ...i,
187
187
  height: r
@@ -227,7 +227,7 @@ function x(e, { height: r = "48px", ...i }) {
227
227
  break;
228
228
  case "APPLE_PAY_WINDOW_OPEN":
229
229
  t({ onCancel: () => {
230
- b(e), n();
230
+ ee(e), n();
231
231
  } });
232
232
  break;
233
233
  case "APPLE_PAY_WINDOW_CLOSE":
@@ -266,14 +266,114 @@ function x(e, { height: r = "48px", ...i }) {
266
266
  };
267
267
  }
268
268
  //#endregion
269
+ //#region src/form-skeleton.ts
270
+ var x = "amos-js-form-skeleton-styles", S = {
271
+ "--accent": "oklch(0.97 0 0)",
272
+ "--radius": "0.625rem",
273
+ "--input-height": "2.25rem",
274
+ "--floating-input-height": "3.25rem",
275
+ "--field-gap": "1rem",
276
+ "--control-gap": "0.5rem",
277
+ "--label-font-size": "0.875rem"
278
+ }, C = "\n.amos-js-form-skeleton {\n box-sizing: border-box;\n container-type: inline-size;\n display: flex;\n flex-direction: column;\n gap: var(--field-gap);\n margin: 0 -4px;\n padding-block: 0.25rem;\n pointer-events: none;\n width: calc(100% + 8px);\n}\n.amos-js-form-skeleton-field {\n display: flex;\n flex: 1 1 0;\n flex-direction: column;\n min-width: 0;\n width: 100%;\n}\n.amos-js-form-skeleton-label {\n flex-shrink: 0;\n font-size: var(--label-font-size);\n height: 1.75rem;\n line-height: 1.75rem;\n}\n.amos-js-form-skeleton-input {\n animation: amos-js-skeleton-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;\n background: var(--accent);\n border-radius: calc(var(--radius) * 0.8);\n box-sizing: border-box;\n height: var(--input-height);\n width: 100%;\n}\n.amos-js-form-skeleton-input-floating {\n height: var(--floating-input-height);\n}\n.amos-js-form-skeleton-row {\n align-items: flex-start;\n display: flex;\n gap: var(--control-gap);\n width: 100%;\n}\n.amos-js-form-skeleton-row-stack {\n display: flex;\n flex-direction: column;\n gap: var(--field-gap);\n width: 100%;\n}\n@container (min-width: 24rem) {\n .amos-js-form-skeleton-row-stack {\n align-items: flex-start;\n flex-direction: row;\n gap: var(--control-gap);\n }\n}\n.amos-js-wallet-skeleton {\n flex: none;\n width: 100%;\n}\n@keyframes amos-js-skeleton-pulse {\n 50% { opacity: 0.5; }\n}\n@media (prefers-reduced-motion: reduce) {\n .amos-js-form-skeleton-input {\n animation: none;\n }\n}\n";
279
+ function w() {
280
+ if (document.getElementById(x)) return;
281
+ let e = document.createElement("style");
282
+ e.id = x, e.textContent = C, document.head.appendChild(e);
283
+ }
284
+ function T(e, t) {
285
+ for (let [t, n] of Object.entries(S)) e.style.setProperty(t, n);
286
+ let n = t?.themeVariables;
287
+ if (n) for (let [t, r] of Object.entries(n)) typeof r == "string" && r.trim() !== "" && e.style.setProperty(t, r.trim());
288
+ }
289
+ function E(e, t) {
290
+ let n = document.createElement("div");
291
+ if (n.className = e, t) for (let e of t) n.appendChild(e);
292
+ return n;
293
+ }
294
+ function D(e, t) {
295
+ let n = E("amos-js-form-skeleton-field");
296
+ t !== void 0 && (n.style.flexGrow = String(t)), e === "above" && n.appendChild(E("amos-js-form-skeleton-label"));
297
+ let r = E("amos-js-form-skeleton-input");
298
+ return e === "floating" && r.classList.add("amos-js-form-skeleton-input-floating"), n.appendChild(r), n;
299
+ }
300
+ function O(e, t) {
301
+ return E(t ? "amos-js-form-skeleton-row-stack" : "amos-js-form-skeleton-row", e);
302
+ }
303
+ function k({ labels: e, requirement: t, wrapCountryZip: n }) {
304
+ return t === "full" ? [
305
+ D(e),
306
+ D(e),
307
+ O([
308
+ D(e, 1.4),
309
+ D(e, .7),
310
+ D(e, .8)
311
+ ], !1),
312
+ D(e)
313
+ ] : [O([D(e), D(e)], n)];
314
+ }
315
+ function A(e) {
316
+ let t = e.appearance?.labels ?? "above", n = e.billingAddressRequirement ?? "country";
317
+ if (e.kind === "card") {
318
+ let r = [D(t), O([D(t), D(t)], !1)];
319
+ return e.additionalFields?.cardholderName && r.push(D(t)), r.push(...k({
320
+ labels: t,
321
+ requirement: n,
322
+ wrapCountryZip: !1
323
+ })), r;
324
+ }
325
+ return [
326
+ D(t),
327
+ O([D(t), D(t)], !0),
328
+ D(t),
329
+ O([D("above"), D("above")], !0),
330
+ ...k({
331
+ labels: t,
332
+ requirement: n,
333
+ wrapCountryZip: !0
334
+ })
335
+ ];
336
+ }
337
+ function j(e) {
338
+ w();
339
+ let t = E("amos-js-form-skeleton");
340
+ t.setAttribute("aria-hidden", "true");
341
+ function n(e) {
342
+ T(t, e.appearance), t.replaceChildren(...A(e));
343
+ }
344
+ return n(e), {
345
+ element: t,
346
+ update: n
347
+ };
348
+ }
349
+ function M(e) {
350
+ w();
351
+ let t = E("amos-js-form-skeleton-input amos-js-wallet-skeleton");
352
+ t.setAttribute("aria-hidden", "true");
353
+ function n(e) {
354
+ T(t, void 0), t.style.height = e.height, t.style.borderRadius = e.borderRadius ?? "4px";
355
+ }
356
+ return n(e), {
357
+ element: t,
358
+ update: n
359
+ };
360
+ }
361
+ function N(e) {
362
+ if (typeof e == "number" && Number.isFinite(e)) return `${e}px`;
363
+ if (typeof e == "string" && e.trim() !== "") return e.trim();
364
+ }
365
+ function P({ iframeStyle: e, buttonProps: t }) {
366
+ return N(e?.borderRadius) ?? N(t?.buttonRadius) ?? N(t?.style?.borderRadius) ?? N(t?.style?.["--apple-pay-button-border-radius"]) ?? "4px";
367
+ }
368
+ //#endregion
269
369
  //#region src/google-pay.ts
270
- function S(e) {
370
+ function F(e) {
271
371
  return `${i(e)}/iframe/google-pay?token=${e}`;
272
372
  }
273
- function C() {
373
+ function I() {
274
374
  return "48px";
275
375
  }
276
- function w(e, { height: t = "48px", ...n }) {
376
+ function L(e, { height: t = "48px", ...n }) {
277
377
  let r = {
278
378
  ...n,
279
379
  height: t
@@ -349,7 +449,7 @@ function w(e, { height: t = "48px", ...n }) {
349
449
  }
350
450
  };
351
451
  }
352
- function T({ paymentData: e }) {
452
+ function R({ paymentData: e }) {
353
453
  return { paymentMethod: {
354
454
  type: "googlepay",
355
455
  billing_address_attributes: {
@@ -367,96 +467,15 @@ function T({ paymentData: e }) {
367
467
  } };
368
468
  }
369
469
  //#endregion
370
- //#region src/form-skeleton.ts
371
- var E = "amos-js-form-skeleton-styles", D = {
372
- "--accent": "oklch(0.97 0 0)",
373
- "--radius": "0.625rem",
374
- "--input-height": "2.25rem",
375
- "--floating-input-height": "3.25rem",
376
- "--field-gap": "1rem",
377
- "--control-gap": "0.5rem",
378
- "--label-font-size": "0.875rem"
379
- }, O = "\n.amos-js-form-skeleton {\n box-sizing: border-box;\n container-type: inline-size;\n display: flex;\n flex-direction: column;\n gap: var(--field-gap);\n margin: 0 -4px;\n padding-block: 0.25rem;\n pointer-events: none;\n width: calc(100% + 8px);\n}\n.amos-js-form-skeleton-field {\n display: flex;\n flex: 1 1 0;\n flex-direction: column;\n min-width: 0;\n width: 100%;\n}\n.amos-js-form-skeleton-label {\n flex-shrink: 0;\n font-size: var(--label-font-size);\n height: 1.75rem;\n line-height: 1.75rem;\n}\n.amos-js-form-skeleton-input {\n animation: amos-js-skeleton-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;\n background: var(--accent);\n border-radius: calc(var(--radius) * 0.8);\n box-sizing: border-box;\n height: var(--input-height);\n width: 100%;\n}\n.amos-js-form-skeleton-input-floating {\n height: var(--floating-input-height);\n}\n.amos-js-form-skeleton-row {\n align-items: flex-start;\n display: flex;\n gap: var(--control-gap);\n width: 100%;\n}\n.amos-js-form-skeleton-row-stack {\n display: flex;\n flex-direction: column;\n gap: var(--field-gap);\n width: 100%;\n}\n@container (min-width: 24rem) {\n .amos-js-form-skeleton-row-stack {\n align-items: flex-start;\n flex-direction: row;\n gap: var(--control-gap);\n }\n}\n@keyframes amos-js-skeleton-pulse {\n 50% { opacity: 0.5; }\n}\n@media (prefers-reduced-motion: reduce) {\n .amos-js-form-skeleton-input {\n animation: none;\n }\n}\n";
380
- function k() {
381
- if (document.getElementById(E)) return;
382
- let e = document.createElement("style");
383
- e.id = E, e.textContent = O, document.head.appendChild(e);
384
- }
385
- function A(e, t) {
386
- for (let [t, n] of Object.entries(D)) e.style.setProperty(t, n);
387
- let n = t?.themeVariables;
388
- if (n) for (let [t, r] of Object.entries(n)) typeof r == "string" && r.trim() !== "" && e.style.setProperty(t, r.trim());
389
- }
390
- function j(e, t) {
391
- let n = document.createElement("div");
392
- if (n.className = e, t) for (let e of t) n.appendChild(e);
393
- return n;
394
- }
395
- function M(e, t) {
396
- let n = j("amos-js-form-skeleton-field");
397
- t !== void 0 && (n.style.flexGrow = String(t)), e === "above" && n.appendChild(j("amos-js-form-skeleton-label"));
398
- let r = j("amos-js-form-skeleton-input");
399
- return e === "floating" && r.classList.add("amos-js-form-skeleton-input-floating"), n.appendChild(r), n;
400
- }
401
- function N(e, t) {
402
- return j(t ? "amos-js-form-skeleton-row-stack" : "amos-js-form-skeleton-row", e);
403
- }
404
- function P({ labels: e, requirement: t, wrapCountryZip: n }) {
405
- return t === "full" ? [
406
- M(e),
407
- M(e),
408
- N([
409
- M(e, 1.4),
410
- M(e, .7),
411
- M(e, .8)
412
- ], !1),
413
- M(e)
414
- ] : [N([M(e), M(e)], n)];
415
- }
416
- function F(e) {
417
- let t = e.appearance?.labels ?? "above", n = e.billingAddressRequirement ?? "country";
418
- if (e.kind === "card") {
419
- let r = [M(t), N([M(t), M(t)], !1)];
420
- return e.additionalFields?.cardholderName && r.push(M(t)), r.push(...P({
421
- labels: t,
422
- requirement: n,
423
- wrapCountryZip: !1
424
- })), r;
425
- }
426
- return [
427
- M(t),
428
- N([M(t), M(t)], !0),
429
- M(t),
430
- N([M("above"), M("above")], !0),
431
- ...P({
432
- labels: t,
433
- requirement: n,
434
- wrapCountryZip: !0
435
- })
436
- ];
437
- }
438
- function I(e) {
439
- k();
440
- let t = j("amos-js-form-skeleton");
441
- t.setAttribute("aria-hidden", "true");
442
- function n(e) {
443
- A(t, e.appearance), t.replaceChildren(...F(e));
444
- }
445
- return n(e), {
446
- element: t,
447
- update: n
448
- };
449
- }
450
- //#endregion
451
470
  //#region src/payment-method-form.ts
452
- var L = {
471
+ var z = {
453
472
  country: 212,
454
473
  full: 452
455
- }, R = 80, z = {
474
+ }, te = 80, B = {
456
475
  country: 400,
457
476
  full: 640
458
477
  };
459
- function B(e, t = { cardholderName: !1 }, n = "country") {
478
+ function V(e, t = { cardholderName: !1 }, n = "country") {
460
479
  let r = Object.entries(t).filter(([, e]) => e).map(([e]) => e).join(","), a = new URLSearchParams({
461
480
  token: e,
462
481
  additionalFields: r,
@@ -464,20 +483,20 @@ function B(e, t = { cardholderName: !1 }, n = "country") {
464
483
  });
465
484
  return `${i(e)}/iframe/card?${a}`;
466
485
  }
467
- function V(e, t = "country") {
486
+ function H(e, t = "country") {
468
487
  let n = new URLSearchParams({
469
488
  token: e,
470
489
  billingAddressRequirement: t
471
490
  });
472
491
  return `${i(e)}/iframe/bank?${n}`;
473
492
  }
474
- function H(e = { cardholderName: !1 }, t = "country") {
475
- return `${(L[t] ?? L.country) + (e.cardholderName ? R : 0)}px`;
493
+ function U(e = { cardholderName: !1 }, t = "country") {
494
+ return `${(z[t] ?? z.country) + (e.cardholderName ? te : 0)}px`;
476
495
  }
477
- function U(e = "country") {
478
- return `${z[e] ?? z.country}px`;
496
+ function W(e = "country") {
497
+ return `${B[e] ?? B.country}px`;
479
498
  }
480
- function W(e, t) {
499
+ function G(e, t) {
481
500
  let n = { ...t };
482
501
  function r(t) {
483
502
  if (t.source === e.contentWindow) switch (t.data.type) {
@@ -523,7 +542,7 @@ function W(e, t) {
523
542
  }
524
543
  //#endregion
525
544
  //#region src/mount.ts
526
- function G(e) {
545
+ function K(e) {
527
546
  if (typeof e == "string") {
528
547
  let t = document.querySelector(e);
529
548
  if (!(t instanceof HTMLElement)) throw Error(`[amos-js] Container "${e}" did not match any HTMLElement.`);
@@ -531,19 +550,29 @@ function G(e) {
531
550
  }
532
551
  return e;
533
552
  }
534
- var K = {
553
+ var q = {
535
554
  width: "calc(100% + 8px)",
536
555
  transition: "opacity 150ms ease-in, height 200ms ease-in-out",
537
556
  margin: "0 -4px",
538
557
  opacity: "0",
539
558
  border: "0"
540
- }, q = {
559
+ }, J = {
541
560
  width: "100%",
542
561
  transition: "height 200ms ease-in-out",
543
562
  margin: "0",
544
563
  opacity: "0",
545
564
  border: "0"
546
- }, J = {
565
+ }, Y = {
566
+ position: "absolute",
567
+ top: "0",
568
+ left: "0",
569
+ width: "100%",
570
+ height: "100%",
571
+ margin: "0",
572
+ opacity: "0",
573
+ transition: "none",
574
+ pointerEvents: "none"
575
+ }, X = {
547
576
  position: "absolute",
548
577
  top: "0",
549
578
  left: "-4px",
@@ -553,15 +582,15 @@ var K = {
553
582
  transition: "none",
554
583
  pointerEvents: "none"
555
584
  };
556
- function Y({ src: e, title: t, name: n, height: r, allow: i, className: a, style: o = K }) {
585
+ function Z({ src: e, title: t, name: n, height: r, allow: i, className: a, style: o = q }) {
557
586
  let s = document.createElement("iframe");
558
587
  return s.src = e, s.title = t, s.name = n, s.setAttribute("role", "presentation"), s.scrolling = "no", i && (s.allow = i), a != null && (s.className = a), Object.assign(s.style, o, { height: r }), s;
559
588
  }
560
- function X({ host: e, iframe: t, listenerOptions: n, skeletonOptions: r }) {
589
+ function Q({ host: e, iframe: t, listenerOptions: n, skeletonOptions: r }) {
561
590
  let i = document.createElement("div");
562
591
  i.style.position = "relative", i.style.width = "100%", i.setAttribute("aria-busy", "true");
563
- let a = I(r);
564
- Object.assign(t.style, J), i.append(a.element, t), e.appendChild(i);
592
+ let a = j(r);
593
+ Object.assign(t.style, X), i.append(a.element, t), e.appendChild(i);
565
594
  let o = !1, s = !1, c, l = r.appearance, u, d;
566
595
  function f() {
567
596
  return i.getBoundingClientRect().height;
@@ -573,7 +602,7 @@ function X({ host: e, iframe: t, listenerOptions: n, skeletonOptions: r }) {
573
602
  if (o) return;
574
603
  o = !0, d !== void 0 && (clearTimeout(d), d = void 0);
575
604
  let e = f(), n = p(), r = Number.isFinite(n) ? Math.max(n, e) : e;
576
- t.style.transition = "none", t.style.position = "", t.style.top = "", t.style.left = "", t.style.margin = K.margin ?? "", t.style.height = `${r}px`, t.style.opacity = "1", t.style.pointerEvents = "", a.element.remove(), i.removeAttribute("aria-busy"), u = setTimeout(() => {
605
+ t.style.transition = "none", t.style.position = "", t.style.top = "", t.style.left = "", t.style.margin = q.margin ?? "", t.style.height = `${r}px`, t.style.opacity = "1", t.style.pointerEvents = "", a.element.remove(), i.removeAttribute("aria-busy"), u = setTimeout(() => {
577
606
  t.style.transition = "height 200ms ease-in-out";
578
607
  }, 400);
579
608
  }
@@ -582,7 +611,7 @@ function X({ host: e, iframe: t, listenerOptions: n, skeletonOptions: r }) {
582
611
  let e = p(), t = f();
583
612
  Number.isFinite(e) && e >= t - 2 && m();
584
613
  }
585
- let g = W(t, {
614
+ let g = G(t, {
586
615
  ...n,
587
616
  onHeightChange: (e) => {
588
617
  c = e, o ? t.style.height = e : h(), n.onHeightChange?.(e);
@@ -606,15 +635,63 @@ function X({ host: e, iframe: t, listenerOptions: n, skeletonOptions: r }) {
606
635
  }
607
636
  };
608
637
  }
609
- function Z(e, t) {
610
- let n = G(e), { renderToken: r, additionalFields: i = { cardholderName: !1 }, billingAddressRequirement: a = "country", ...o } = t;
611
- return X({
638
+ function $({ host: e, iframe: t, listenerOptions: n, iframeStyle: r, attachListeners: i }) {
639
+ let a = {
640
+ height: n.height ?? "48px",
641
+ borderRadius: P({
642
+ iframeStyle: r,
643
+ buttonProps: n.buttonProps
644
+ })
645
+ }, o = M(a), s = document.createElement("div");
646
+ s.style.position = "relative", s.style.width = "100%", s.style.height = a.height, s.style.overflow = "hidden", s.setAttribute("aria-busy", "true"), Object.assign(t.style, Y), t.style.height = "100%", s.append(o.element, t), e.appendChild(s);
647
+ let c = !1, l = !1, u, d = n;
648
+ function f() {
649
+ c || (c = !0, u !== void 0 && (clearTimeout(u), u = void 0), t.style.opacity = "1", t.style.pointerEvents = "", o.element.remove(), s.removeAttribute("aria-busy"));
650
+ }
651
+ function p() {
652
+ c || !l || f();
653
+ }
654
+ let m = i(t, {
655
+ ...n,
656
+ onHeightChange: (e) => {
657
+ d.onHeightChange?.(e);
658
+ },
659
+ onAppearanceReady: () => {
660
+ l = !0, p(), d.onAppearanceReady?.();
661
+ }
662
+ });
663
+ return u = setTimeout(() => {
664
+ f();
665
+ }, 1500), {
666
+ iframe: t,
667
+ update(e) {
668
+ d = {
669
+ ...d,
670
+ ...e
671
+ };
672
+ let t = { ...e };
673
+ delete t.onAppearanceReady, delete t.onHeightChange, m.update(t), a = {
674
+ height: d.height ?? a.height,
675
+ borderRadius: P({
676
+ iframeStyle: r,
677
+ buttonProps: d.buttonProps
678
+ })
679
+ }, s.style.height = a.height, c || o.update(a);
680
+ },
681
+ destroy() {
682
+ u !== void 0 && clearTimeout(u), m.destroy(), s.remove();
683
+ }
684
+ };
685
+ }
686
+ function ne(e, t) {
687
+ let n = K(e), { renderToken: r, additionalFields: i = { cardholderName: !1 }, billingAddressRequirement: a = "country", ...o } = t;
688
+ return Q({
612
689
  host: n,
613
- iframe: Y({
614
- src: B(r, i, a),
690
+ iframe: Z({
691
+ src: V(r, i, a),
615
692
  title: "Secure credit card payment method form powered by Amos",
616
693
  name: "amos-credit-card-payment-method-form",
617
- height: H(i, a)
694
+ height: U(i, a)
618
695
  }),
619
696
  listenerOptions: o,
620
697
  skeletonOptions: {
@@ -625,15 +702,15 @@ function Z(e, t) {
625
702
  }
626
703
  });
627
704
  }
628
- function Q(e, t) {
629
- let n = G(e), { renderToken: r, billingAddressRequirement: i = "country", ...a } = t;
630
- return X({
705
+ function re(e, t) {
706
+ let n = K(e), { renderToken: r, billingAddressRequirement: i = "country", ...a } = t;
707
+ return Q({
631
708
  host: n,
632
- iframe: Y({
633
- src: V(r, i),
709
+ iframe: Z({
710
+ src: H(r, i),
634
711
  title: "Secure bank account payment method form powered by Amos",
635
712
  name: "amos-bank-account-payment-method-form",
636
- height: U(i)
713
+ height: W(i)
637
714
  }),
638
715
  listenerOptions: a,
639
716
  skeletonOptions: {
@@ -643,61 +720,41 @@ function Q(e, t) {
643
720
  }
644
721
  });
645
722
  }
646
- function $(e, t) {
647
- let n = G(e), { renderToken: r, iframeClassName: i, iframeStyle: a, ...o } = t, s = Y({
648
- src: S(r),
723
+ function ie(e, t) {
724
+ let n = K(e), { renderToken: r, iframeClassName: i, iframeStyle: a, ...o } = t, s = Z({
725
+ src: F(r),
649
726
  title: "Secure Google Pay button powered by Amos",
650
727
  name: "amos-google-pay-button",
651
- height: o.height ?? C(),
728
+ height: o.height ?? I(),
652
729
  allow: "payment",
653
730
  className: i,
654
- style: q
655
- });
656
- Object.assign(s.style, a), n.appendChild(s);
657
- let c = w(s, {
658
- ...o,
659
- onHeightChange: (e) => {
660
- s.style.height = e, o.onHeightChange?.(e);
661
- },
662
- onAppearanceReady: () => {
663
- s.style.opacity = "1", o.onAppearanceReady?.();
664
- }
731
+ style: J
665
732
  });
666
- return {
733
+ return Object.assign(s.style, a), $({
734
+ host: n,
667
735
  iframe: s,
668
- update: c.update,
669
- destroy() {
670
- c.destroy(), s.remove();
671
- }
672
- };
736
+ listenerOptions: o,
737
+ iframeStyle: a,
738
+ attachListeners: L
739
+ });
673
740
  }
674
- function ee(e, t) {
675
- let n = G(e), { renderToken: r, iframeClassName: i, iframeStyle: a, ...o } = t, s = Y({
741
+ function ae(e, t) {
742
+ let n = K(e), { renderToken: r, iframeClassName: i, iframeStyle: a, ...o } = t, s = Z({
676
743
  src: v(r),
677
744
  title: "Secure Apple Pay button powered by Amos",
678
745
  name: "amos-apple-pay-button",
679
746
  height: o.height ?? y(),
680
747
  allow: "payment",
681
748
  className: i,
682
- style: q
749
+ style: J
683
750
  });
684
- Object.assign(s.style, a), n.appendChild(s);
685
- let c = x(s, {
686
- ...o,
687
- onHeightChange: (e) => {
688
- s.style.height = e, o.onHeightChange?.(e);
689
- },
690
- onAppearanceReady: () => {
691
- s.style.opacity = "1", o.onAppearanceReady?.();
692
- }
693
- });
694
- return {
751
+ return Object.assign(s.style, a), $({
752
+ host: n,
695
753
  iframe: s,
696
- update: c.update,
697
- destroy() {
698
- c.destroy(), s.remove();
699
- }
700
- };
754
+ listenerOptions: o,
755
+ iframeStyle: a,
756
+ attachListeners: b
757
+ });
701
758
  }
702
759
  //#endregion
703
- export { x as attachApplePayButtonListeners, w as attachGooglePayButtonListeners, W as attachPaymentMethodFormListeners, h as confirmPaymentIntent, g as confirmSetupIntent, a as createMessage, r as decodeJwt, T as formatGooglePayPaymentData, y as getApplePayButtonInitialHeight, v as getApplePayButtonSrc, U as getBankAccountFormInitialHeight, V as getBankAccountFormSrc, H as getCreditCardFormInitialHeight, B as getCreditCardFormSrc, i as getEmbedOrigin, C as getGooglePayButtonInitialHeight, S as getGooglePayButtonSrc, ee as mountAmosApplePayButton, Q as mountAmosBankAccountPaymentMethodForm, Z as mountAmosCreditCardPaymentMethodForm, $ as mountAmosGooglePayButton, m as resetForm, _ as sendConfirmationResult, s as sendParentReadyMessage, d as updateAmount, c as updateAppearance, l as updateApplePayButton, u as updateGooglePayButton, f as updateMerchantName, p as validateForm };
760
+ export { C as SKELETON_STYLES, b as attachApplePayButtonListeners, L as attachGooglePayButtonListeners, G as attachPaymentMethodFormListeners, h as confirmPaymentIntent, g as confirmSetupIntent, a as createMessage, j as createPaymentMethodFormSkeleton, M as createWalletButtonSkeleton, r as decodeJwt, w as ensureSkeletonStyles, R as formatGooglePayPaymentData, y as getApplePayButtonInitialHeight, v as getApplePayButtonSrc, W as getBankAccountFormInitialHeight, H as getBankAccountFormSrc, U as getCreditCardFormInitialHeight, V as getCreditCardFormSrc, i as getEmbedOrigin, I as getGooglePayButtonInitialHeight, F as getGooglePayButtonSrc, ae as mountAmosApplePayButton, re as mountAmosBankAccountPaymentMethodForm, ne as mountAmosCreditCardPaymentMethodForm, ie as mountAmosGooglePayButton, m as resetForm, P as resolveWalletButtonSkeletonBorderRadius, _ as sendConfirmationResult, s as sendParentReadyMessage, d as updateAmount, c as updateAppearance, l as updateApplePayButton, u as updateGooglePayButton, f as updateMerchantName, p as validateForm };
package/dist/mount.d.ts CHANGED
@@ -116,6 +116,9 @@ export type AmosGooglePayButtonMountController = GooglePayButtonController & {
116
116
  * Mount the secure Google Pay button (express checkout) into a
117
117
  * container element. Returns a controller exposing the underlying
118
118
  * iframe, an `update()` method, and a `destroy()` method.
119
+ *
120
+ * A button-shaped skeleton is shown immediately and replaced by the
121
+ * iframe once appearance is applied.
119
122
  */
120
123
  export declare function mountAmosGooglePayButton(container: Container, options: AmosGooglePayButtonOptions): AmosGooglePayButtonMountController;
121
124
  /**
@@ -150,6 +153,9 @@ export type AmosApplePayButtonMountController = ApplePayButtonController & {
150
153
  * Mount the secure Apple Pay button (express checkout) into a
151
154
  * container element. Returns a controller exposing the underlying
152
155
  * iframe, an `update()` method, and a `destroy()` method.
156
+ *
157
+ * A button-shaped skeleton is shown immediately and replaced by the
158
+ * iframe once appearance is applied.
153
159
  */
154
160
  export declare function mountAmosApplePayButton(container: Container, options: AmosApplePayButtonOptions): AmosApplePayButtonMountController;
155
161
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amos.com/amos-js",
3
- "version": "0.9.16",
3
+ "version": "0.9.17",
4
4
  "main": "dist/index.js",
5
5
  "repository": {
6
6
  "type": "git",
@@ -16,7 +16,7 @@ const SKELETON_THEME_DEFAULTS: Record<string, string> = {
16
16
  "--label-font-size": "0.875rem",
17
17
  };
18
18
 
19
- const SKELETON_STYLES = `
19
+ export const SKELETON_STYLES = `
20
20
  .amos-js-form-skeleton {
21
21
  box-sizing: border-box;
22
22
  container-type: inline-size;
@@ -71,6 +71,10 @@ const SKELETON_STYLES = `
71
71
  gap: var(--control-gap);
72
72
  }
73
73
  }
74
+ .amos-js-wallet-skeleton {
75
+ flex: none;
76
+ width: 100%;
77
+ }
74
78
  @keyframes amos-js-skeleton-pulse {
75
79
  50% { opacity: 0.5; }
76
80
  }
@@ -81,7 +85,7 @@ const SKELETON_STYLES = `
81
85
  }
82
86
  `;
83
87
 
84
- function ensureSkeletonStyles(): void {
88
+ export function ensureSkeletonStyles(): void {
85
89
  if (document.getElementById(STYLE_ID)) {
86
90
  return;
87
91
  }
@@ -242,3 +246,74 @@ export function createPaymentMethodFormSkeleton(
242
246
  update: render,
243
247
  };
244
248
  }
249
+
250
+ export type WalletButtonSkeletonOptions = {
251
+ /** Painted height of the wallet button slot (CSS length). */
252
+ height: string;
253
+ /** Corner radius matching the iframe / native button. */
254
+ borderRadius?: string;
255
+ };
256
+
257
+ export type WalletButtonSkeleton = {
258
+ element: HTMLElement;
259
+ update: (options: WalletButtonSkeletonOptions) => void;
260
+ };
261
+
262
+ /**
263
+ * Host-page placeholder for Google Pay / Apple Pay: a pulsing bar at
264
+ * the button's height. Shown immediately while the iframe loads, then
265
+ * removed when appearance is ready.
266
+ */
267
+ export function createWalletButtonSkeleton(
268
+ options: WalletButtonSkeletonOptions,
269
+ ): WalletButtonSkeleton {
270
+ ensureSkeletonStyles();
271
+ const element = div("amos-js-form-skeleton-input amos-js-wallet-skeleton");
272
+ element.setAttribute("aria-hidden", "true");
273
+
274
+ function render(next: WalletButtonSkeletonOptions): void {
275
+ applyTheme(element, undefined);
276
+ element.style.height = next.height;
277
+ element.style.borderRadius = next.borderRadius ?? "4px";
278
+ }
279
+
280
+ render(options);
281
+
282
+ return {
283
+ element,
284
+ update: render,
285
+ };
286
+ }
287
+
288
+ function cssLength(value: unknown): string | undefined {
289
+ if (typeof value === "number" && Number.isFinite(value)) {
290
+ return `${value}px`;
291
+ }
292
+ if (typeof value === "string" && value.trim() !== "") {
293
+ return value.trim();
294
+ }
295
+ return undefined;
296
+ }
297
+
298
+ /**
299
+ * Corner radius for a wallet-button skeleton. Prefers host iframe
300
+ * chrome, then native Google / Apple button radius, then 4px.
301
+ */
302
+ export function resolveWalletButtonSkeletonBorderRadius({
303
+ iframeStyle,
304
+ buttonProps,
305
+ }: {
306
+ iframeStyle?: { borderRadius?: string | number };
307
+ buttonProps?: {
308
+ buttonRadius?: number;
309
+ style?: Record<string, string | number | undefined>;
310
+ };
311
+ }): string {
312
+ return (
313
+ cssLength(iframeStyle?.borderRadius) ??
314
+ cssLength(buttonProps?.buttonRadius) ??
315
+ cssLength(buttonProps?.style?.["borderRadius"]) ??
316
+ cssLength(buttonProps?.style?.["--apple-pay-button-border-radius"]) ??
317
+ "4px"
318
+ );
319
+ }
package/src/index.ts CHANGED
@@ -9,7 +9,20 @@ export {
9
9
  getApplePayButtonInitialHeight,
10
10
  getApplePayButtonSrc,
11
11
  } from "./apple-pay";
12
-
12
+ export type {
13
+ PaymentMethodFormSkeleton,
14
+ PaymentMethodFormSkeletonKind,
15
+ PaymentMethodFormSkeletonOptions,
16
+ WalletButtonSkeleton,
17
+ WalletButtonSkeletonOptions,
18
+ } from "./form-skeleton";
19
+ export {
20
+ createPaymentMethodFormSkeleton,
21
+ createWalletButtonSkeleton,
22
+ ensureSkeletonStyles,
23
+ resolveWalletButtonSkeletonBorderRadius,
24
+ SKELETON_STYLES,
25
+ } from "./form-skeleton";
13
26
  export type {
14
27
  FormattedGooglePayPaymentData,
15
28
  GooglePayButtonController,
@@ -21,7 +34,6 @@ export {
21
34
  getGooglePayButtonInitialHeight,
22
35
  getGooglePayButtonSrc,
23
36
  } from "./google-pay";
24
-
25
37
  export { decodeJwt, getEmbedOrigin } from "./jwt";
26
38
 
27
39
  export {
package/src/mount.ts CHANGED
@@ -7,7 +7,11 @@ import {
7
7
  } from "./apple-pay";
8
8
  import {
9
9
  createPaymentMethodFormSkeleton,
10
+ createWalletButtonSkeleton,
10
11
  type PaymentMethodFormSkeletonOptions,
12
+ resolveWalletButtonSkeletonBorderRadius,
13
+ type WalletButtonSkeleton,
14
+ type WalletButtonSkeletonOptions,
11
15
  } from "./form-skeleton";
12
16
  import {
13
17
  attachGooglePayButtonListeners,
@@ -59,6 +63,19 @@ const WALLET_IFRAME_STYLE: Partial<CSSStyleDeclaration> = {
59
63
  border: "0",
60
64
  };
61
65
 
66
+ const WALLET_SKELETON_IFRAME_STYLE: Partial<CSSStyleDeclaration> = {
67
+ position: "absolute",
68
+ top: "0",
69
+ left: "0",
70
+ width: "100%",
71
+ height: "100%",
72
+ margin: "0",
73
+ opacity: "0",
74
+ // Do not interpolate opacity while the skeleton is showing.
75
+ transition: "none",
76
+ pointerEvents: "none",
77
+ };
78
+
62
79
  const SKELETON_IFRAME_STYLE: Partial<CSSStyleDeclaration> = {
63
80
  position: "absolute",
64
81
  top: "0",
@@ -231,6 +248,141 @@ function mountPaymentMethodFormWithSkeleton({
231
248
  };
232
249
  }
233
250
 
251
+ type WalletListenerOptions = {
252
+ height?: string;
253
+ onHeightChange?: (height: string) => void;
254
+ onAppearanceReady?: () => void;
255
+ buttonProps?: {
256
+ buttonRadius?: number;
257
+ style?: Record<string, string | number | undefined>;
258
+ };
259
+ };
260
+
261
+ type WalletListenerController<TOptions> = {
262
+ update: (patch: Partial<TOptions>) => void;
263
+ destroy: () => void;
264
+ };
265
+
266
+ function mountWalletButtonWithSkeleton<TOptions extends WalletListenerOptions>({
267
+ host,
268
+ iframe,
269
+ listenerOptions,
270
+ iframeStyle,
271
+ attachListeners,
272
+ }: {
273
+ host: HTMLElement;
274
+ iframe: HTMLIFrameElement;
275
+ listenerOptions: TOptions;
276
+ iframeStyle?: Partial<CSSStyleDeclaration>;
277
+ attachListeners: (
278
+ iframe: HTMLIFrameElement,
279
+ options: TOptions,
280
+ ) => WalletListenerController<TOptions>;
281
+ }): {
282
+ iframe: HTMLIFrameElement;
283
+ update: (patch: Partial<TOptions>) => void;
284
+ destroy: () => void;
285
+ } {
286
+ const initialHeight = listenerOptions.height ?? "48px";
287
+ let skeletonOptions: WalletButtonSkeletonOptions = {
288
+ height: initialHeight,
289
+ borderRadius: resolveWalletButtonSkeletonBorderRadius({
290
+ iframeStyle,
291
+ buttonProps: listenerOptions.buttonProps,
292
+ }),
293
+ };
294
+ const skeleton: WalletButtonSkeleton =
295
+ createWalletButtonSkeleton(skeletonOptions);
296
+
297
+ const wrapper = document.createElement("div");
298
+ wrapper.style.position = "relative";
299
+ wrapper.style.width = "100%";
300
+ wrapper.style.height = skeletonOptions.height;
301
+ wrapper.style.overflow = "hidden";
302
+ wrapper.setAttribute("aria-busy", "true");
303
+
304
+ Object.assign(iframe.style, WALLET_SKELETON_IFRAME_STYLE);
305
+ iframe.style.height = "100%";
306
+
307
+ wrapper.append(skeleton.element, iframe);
308
+ host.appendChild(wrapper);
309
+
310
+ let revealed = false;
311
+ let appearanceReady = false;
312
+ let fallbackRevealTimer: ReturnType<typeof setTimeout> | undefined;
313
+ let currentOptions = listenerOptions;
314
+
315
+ function reveal(): void {
316
+ if (revealed) {
317
+ return;
318
+ }
319
+ revealed = true;
320
+ if (fallbackRevealTimer !== undefined) {
321
+ clearTimeout(fallbackRevealTimer);
322
+ fallbackRevealTimer = undefined;
323
+ }
324
+
325
+ iframe.style.opacity = "1";
326
+ iframe.style.pointerEvents = "";
327
+ skeleton.element.remove();
328
+ wrapper.removeAttribute("aria-busy");
329
+ }
330
+
331
+ function tryReveal(): void {
332
+ if (revealed || !appearanceReady) {
333
+ return;
334
+ }
335
+ reveal();
336
+ }
337
+
338
+ const controller = attachListeners(iframe, {
339
+ ...listenerOptions,
340
+ onHeightChange: (height) => {
341
+ currentOptions.onHeightChange?.(height);
342
+ },
343
+ onAppearanceReady: () => {
344
+ appearanceReady = true;
345
+ tryReveal();
346
+ currentOptions.onAppearanceReady?.();
347
+ },
348
+ } as TOptions);
349
+
350
+ fallbackRevealTimer = setTimeout(() => {
351
+ reveal();
352
+ }, 1500);
353
+
354
+ return {
355
+ iframe,
356
+ update(patch) {
357
+ currentOptions = { ...currentOptions, ...patch };
358
+ // Keep the wrapped reveal listeners. Forwarding these would replace
359
+ // them and leave the iframe at opacity 0.
360
+ const rest = { ...patch };
361
+ delete rest.onAppearanceReady;
362
+ delete rest.onHeightChange;
363
+ controller.update(rest);
364
+ skeletonOptions = {
365
+ height: currentOptions.height ?? skeletonOptions.height,
366
+ borderRadius: resolveWalletButtonSkeletonBorderRadius({
367
+ iframeStyle,
368
+ buttonProps: currentOptions.buttonProps,
369
+ }),
370
+ };
371
+ wrapper.style.height = skeletonOptions.height;
372
+ if (!revealed) {
373
+ skeleton.update(skeletonOptions);
374
+ }
375
+ },
376
+ destroy() {
377
+ if (fallbackRevealTimer !== undefined) {
378
+ clearTimeout(fallbackRevealTimer);
379
+ }
380
+ controller.destroy();
381
+ wrapper.remove();
382
+ },
383
+ };
384
+ }
385
+
234
386
  /**
235
387
  * Options accepted by {@link mountAmosCreditCardPaymentMethodForm}.
236
388
  */
@@ -420,6 +572,9 @@ export type AmosGooglePayButtonMountController = GooglePayButtonController & {
420
572
  * Mount the secure Google Pay button (express checkout) into a
421
573
  * container element. Returns a controller exposing the underlying
422
574
  * iframe, an `update()` method, and a `destroy()` method.
575
+ *
576
+ * A button-shaped skeleton is shown immediately and replaced by the
577
+ * iframe once appearance is applied.
423
578
  */
424
579
  export function mountAmosGooglePayButton(
425
580
  container: Container,
@@ -439,28 +594,14 @@ export function mountAmosGooglePayButton(
439
594
  style: WALLET_IFRAME_STYLE,
440
595
  });
441
596
  Object.assign(iframe.style, iframeStyle);
442
- host.appendChild(iframe);
443
597
 
444
- const controller = attachGooglePayButtonListeners(iframe, {
445
- ...listenerOptions,
446
- onHeightChange: (height) => {
447
- iframe.style.height = height;
448
- listenerOptions.onHeightChange?.(height);
449
- },
450
- onAppearanceReady: () => {
451
- iframe.style.opacity = "1";
452
- listenerOptions.onAppearanceReady?.();
453
- },
454
- });
455
-
456
- return {
598
+ return mountWalletButtonWithSkeleton({
599
+ host,
457
600
  iframe,
458
- update: controller.update,
459
- destroy() {
460
- controller.destroy();
461
- iframe.remove();
462
- },
463
- };
601
+ listenerOptions,
602
+ iframeStyle,
603
+ attachListeners: attachGooglePayButtonListeners,
604
+ });
464
605
  }
465
606
 
466
607
  /**
@@ -497,6 +638,9 @@ export type AmosApplePayButtonMountController = ApplePayButtonController & {
497
638
  * Mount the secure Apple Pay button (express checkout) into a
498
639
  * container element. Returns a controller exposing the underlying
499
640
  * iframe, an `update()` method, and a `destroy()` method.
641
+ *
642
+ * A button-shaped skeleton is shown immediately and replaced by the
643
+ * iframe once appearance is applied.
500
644
  */
501
645
  export function mountAmosApplePayButton(
502
646
  container: Container,
@@ -516,26 +660,12 @@ export function mountAmosApplePayButton(
516
660
  style: WALLET_IFRAME_STYLE,
517
661
  });
518
662
  Object.assign(iframe.style, iframeStyle);
519
- host.appendChild(iframe);
520
-
521
- const controller = attachApplePayButtonListeners(iframe, {
522
- ...listenerOptions,
523
- onHeightChange: (height) => {
524
- iframe.style.height = height;
525
- listenerOptions.onHeightChange?.(height);
526
- },
527
- onAppearanceReady: () => {
528
- iframe.style.opacity = "1";
529
- listenerOptions.onAppearanceReady?.();
530
- },
531
- });
532
663
 
533
- return {
664
+ return mountWalletButtonWithSkeleton({
665
+ host,
534
666
  iframe,
535
- update: controller.update,
536
- destroy() {
537
- controller.destroy();
538
- iframe.remove();
539
- },
540
- };
667
+ listenerOptions,
668
+ iframeStyle,
669
+ attachListeners: attachApplePayButtonListeners,
670
+ });
541
671
  }