@amos.com/amos-js 0.9.9 → 0.9.10

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
@@ -289,15 +289,43 @@ Mount the secure Google Pay button (express checkout) into a container element.
289
289
 
290
290
  - `onResult` (`(result: ConfirmationResult) => void`) — required. Called when the interactive confirmation attempt finishes (`succeeded`, `failed`, or `incomplete` with `reason`). Not settlement proof; verify via webhooks.
291
291
 
292
- **Optional `options`:** `appearance`, `onHeightChange`, `onAppearanceReady`.
292
+ **Optional `options`:** `appearance`, `onHeightChange`, `onAppearanceReady`, plus Google Pay button visual options using the same names as `@google-pay/button-react`:
293
+
294
+ - `buttonType` (`"book" | "buy" | "checkout" | "donate" | "order" | "pay" | "plain" | "subscribe" | "short" | "long"`, defaults to `"short"`)
295
+ - `buttonColor` (`"default" | "black" | "white"`)
296
+ - `buttonRadius` (`number`, 0–20)
297
+ - `buttonSizeMode` (`"static" | "fill"`)
298
+ - `buttonLocale` (`string`, e.g. `"en"`)
299
+ - `buttonBorderType` (`"no_border" | "default_border"`)
300
+ - `style` (`{ [property: string]: string | number }`) — applied to the Google Pay button inside the iframe (e.g. `{ height: "48px", width: "100%" }`). Combined with `buttonSizeMode: "fill"` to stretch the button.
293
301
 
294
302
  **Returns** `AmosGooglePayButtonMountController`:
295
303
 
296
- - `iframe`, `update(patch)`, `destroy()`. Use `update({ amount, merchantName })` to push new values into the iframe.
304
+ - `iframe`, `update(patch)`, `destroy()`. Use `update({ amount, merchantName })` to push new values into the iframe. Use `update({ buttonType, style, ... })` to restyle the button.
297
305
 
298
306
  ### `mountAmosApplePayButton(container, options)`
299
307
 
300
- Mount the secure Apple Pay button (express checkout). Same options and return shape as `mountAmosGooglePayButton`.
308
+ Mount the secure Apple Pay button (express checkout). Same required options and return shape as `mountAmosGooglePayButton`.
309
+
310
+ **Optional visual options** use Apple's `<apple-pay-button>` attribute names:
311
+
312
+ - `buttonstyle` (`"black" | "white" | "white-outline"`, defaults to `"black"`)
313
+ - `type` (`"plain" | "buy" | "set-up" | "donate" | "check-out" | "book" | "subscribe" | "reload" | "add-money" | "top-up" | "order" | "rent" | "support" | "contribute" | "tip"`, defaults to `"plain"`)
314
+ - `locale` (`string`, BCP 47, defaults to `"en-US"`)
315
+ - `style` — applied to the `<apple-pay-button>` inside the iframe. Apple sizes the button with CSS custom properties, not CSS `height`:
316
+
317
+ ```ts
318
+ button.update({
319
+ buttonstyle: "white-outline",
320
+ type: "buy",
321
+ locale: "en-GB",
322
+ style: {
323
+ "--apple-pay-button-height": "48px",
324
+ "--apple-pay-button-width": "100%",
325
+ width: "100%",
326
+ },
327
+ });
328
+ ```
301
329
 
302
330
  ### `validateForm({ iframe })`
303
331
 
@@ -1,5 +1,5 @@
1
1
  import { components } from '@amos.com/node';
2
- import { Appearance, ConfirmationResult } from './types';
2
+ import { Appearance, ApplePayButtonElementProps, ConfirmationResult } from './types';
3
3
  /**
4
4
  * Build the iframe `src` URL for the embedded Apple Pay button.
5
5
  */
@@ -11,7 +11,7 @@ export declare function getApplePayButtonInitialHeight(): string;
11
11
  /**
12
12
  * Options accepted by {@link attachApplePayButtonListeners}.
13
13
  */
14
- export type ApplePayButtonListenerOptions = {
14
+ export type ApplePayButtonListenerOptions = ApplePayButtonElementProps & {
15
15
  /** The amount of the payment, in the same format passed in props. */
16
16
  amount: string;
17
17
  /** A user-visible merchant name. */
@@ -54,7 +54,9 @@ export type ApplePayButtonController = {
54
54
  /**
55
55
  * Update one or more listener options without re-attaching the
56
56
  * message listener. Pass `amount` or `merchantName` to push the new
57
- * value into the iframe; pass `appearance` to update theme variables.
57
+ * value into the iframe; pass `appearance` to update theme variables;
58
+ * pass `buttonstyle`, `type`, `locale`, or `style` to restyle the
59
+ * Apple Pay button.
58
60
  */
59
61
  update: (patch: Partial<ApplePayButtonListenerOptions>) => void;
60
62
  /**
@@ -1,5 +1,5 @@
1
1
  import { components } from '@amos.com/node';
2
- import { Appearance, ConfirmationResult } from './types';
2
+ import { Appearance, ConfirmationResult, GooglePayButtonElementProps } from './types';
3
3
  /**
4
4
  * Build the iframe `src` URL for the embedded Google Pay button.
5
5
  */
@@ -11,7 +11,7 @@ export declare function getGooglePayButtonInitialHeight(): string;
11
11
  /**
12
12
  * Options accepted by {@link attachGooglePayButtonListeners}.
13
13
  */
14
- export type GooglePayButtonListenerOptions = {
14
+ export type GooglePayButtonListenerOptions = GooglePayButtonElementProps & {
15
15
  /** The amount of the payment, in the same format passed in props. */
16
16
  amount: string;
17
17
  /** A user-visible merchant name. */
@@ -54,7 +54,10 @@ export type GooglePayButtonController = {
54
54
  /**
55
55
  * Update one or more listener options without re-attaching the
56
56
  * message listener. Pass `amount` or `merchantName` to push the new
57
- * value into the iframe; pass `appearance` to update theme variables.
57
+ * value into the iframe; pass `appearance` to update theme variables;
58
+ * pass `buttonType`, `buttonColor`, `buttonRadius`, `buttonSizeMode`,
59
+ * `buttonLocale`, `buttonBorderType`, or `style` to restyle the
60
+ * Google Pay button.
58
61
  */
59
62
  update: (patch: Partial<GooglePayButtonListenerOptions>) => void;
60
63
  /**
package/dist/index.d.ts CHANGED
@@ -4,10 +4,10 @@ export { attachApplePayButtonListeners, getApplePayButtonInitialHeight, getApple
4
4
  export type { FormattedGooglePayPaymentData, GooglePayButtonController, GooglePayButtonListenerOptions, } from './google-pay';
5
5
  export { attachGooglePayButtonListeners, formatGooglePayPaymentData, getGooglePayButtonInitialHeight, getGooglePayButtonSrc, } from './google-pay';
6
6
  export { decodeJwt, getEmbedOrigin } from './jwt';
7
- export { confirmPaymentIntent, confirmSetupIntent, resetForm, sendConfirmationResult, sendParentReadyMessage, updateAmount, updateAppearance, updateMerchantName, validateForm, } from './messaging';
7
+ export { confirmPaymentIntent, confirmSetupIntent, resetForm, sendConfirmationResult, sendParentReadyMessage, updateAmount, updateAppearance, updateApplePayButton, updateGooglePayButton, updateMerchantName, validateForm, } from './messaging';
8
8
  export type { AmosApplePayButtonMountController, AmosApplePayButtonOptions, AmosBankAccountPaymentMethodFormOptions, AmosCreditCardPaymentMethodFormOptions, AmosGooglePayButtonMountController, AmosGooglePayButtonOptions, AmosPaymentMethodFormMountController, } from './mount';
9
9
  export { mountAmosApplePayButton, mountAmosBankAccountPaymentMethodForm, mountAmosCreditCardPaymentMethodForm, mountAmosGooglePayButton, } from './mount';
10
10
  export type { BillingAddressRequirement, CreditCardAdditionalFields, PaymentMethodFormController, PaymentMethodFormListenerOptions, } from './payment-method-form';
11
11
  export { attachPaymentMethodFormListeners, getBankAccountFormInitialHeight, getBankAccountFormSrc, getCreditCardFormInitialHeight, getCreditCardFormSrc, } from './payment-method-form';
12
- export type { Appearance, AppearanceLabels, ConfirmationIncompleteReason, ConfirmationResult, Message, ThemeVariable, } from './types';
13
- export { createMessage } from './types';
12
+ export type { Appearance, AppearanceLabels, ApplePayButtonElementProps, ApplePayButtonStyle, ApplePayButtonType, ConfirmationIncompleteReason, ConfirmationResult, GooglePayButtonElementProps, Message, ThemeVariable, WalletButtonStyle, } from './types';
13
+ export { createMessage, pickApplePayButtonElementProps, pickGooglePayButtonElementProps, serializeWalletButtonStyle, } from './types';
package/dist/index.js CHANGED
@@ -1 +1 @@
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,amount:t}){e?.contentWindow&&e.contentWindow.postMessage(a({type:`UPDATE_AMOUNT`,amount:t}),o(e))}function u({iframe:e,merchantName:t}){e?.contentWindow&&e.contentWindow.postMessage(a({type:`UPDATE_MERCHANT_NAME`,merchantName:t}),o(e))}function d({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 f({iframe:e}){e?.contentWindow&&e.contentWindow.postMessage(a({type:`RESET_FORM`}),o(e))}function p({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 m({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 h({iframe:e,result:t}){e?.contentWindow&&e.contentWindow.postMessage(a({type:`CONFIRMATION_RESULT`,result:t}),o(e))}function g(e){return`${i(e)}/iframe/apple-pay?token=${e}`}function _(){return`40px`}function v(e){e.contentWindow?.postMessage(a({type:`APPLE_PAY_CANCEL`}),o(e))}function y(e,r){let i={...r};function a(){l({iframe:e,amount:i.amount})}function o(){u({iframe:e,merchantName:i.merchantName})}function d(r){if(r.source===e.contentWindow)switch(r.data.type){case`IFRAME_READY`:s(e),c({iframe:e,appearance:i.appearance}),a(),o();break;case`UPDATE_HEIGHT`:i.onHeightChange?.(r.data.height);break;case`UPDATE_APPEARANCE`:c({iframe:e,appearance:r.data.appearance});break;case`UPDATED_APPEARANCE`:i.onAppearanceReady?.();break;case`APPLE_PAY_WINDOW_OPEN`:t({onCancel:()=>{v(e),n()}});break;case`APPLE_PAY_WINDOW_CLOSE`:n();break;case`CREATE_PAYMENT_INTENT`:i.onInitiatePaymentIntentRequest({paymentIntentCreateAttributes:r.data.paymentIntentCreateAttributes,customerCreateAttributes:r.data.customerCreateAttributes}).then(t=>{p({iframe:e,token:t})}).catch(e=>{n(),i.onResult({status:`failed`,errorMessage:e instanceof Error?e.message:`Unknown error`})});break;case`CONFIRMATION_RESULT`:n(),i.onResult(r.data.result)}}return window.addEventListener(`message`,d),{update(t){let n=`appearance`in t,r=`amount`in t,s=`merchantName`in t;i={...i,...t},n&&c({iframe:e,appearance:i.appearance}),r&&a(),s&&o()},destroy(){window.removeEventListener(`message`,d),n()}}}function b(e){return`${i(e)}/iframe/google-pay?token=${e}`}function x(){return`40px`}function S(e,t){let n={...t};function r(){l({iframe:e,amount:n.amount})}function i(){u({iframe:e,merchantName:n.merchantName})}function a(t){if(t.source===e.contentWindow)switch(t.data.type){case`IFRAME_READY`:s(e),c({iframe:e,appearance:n.appearance}),r(),i();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`CREATE_PAYMENT_INTENT`:n.onInitiatePaymentIntentRequest({paymentIntentCreateAttributes:t.data.paymentIntentCreateAttributes,customerCreateAttributes:t.data.customerCreateAttributes}).then(t=>{p({iframe:e,token:t})}).catch(e=>{n.onResult({status:`failed`,errorMessage:e instanceof Error?e.message:`Unknown error`})});break;case`CONFIRMATION_RESULT`:n.onResult(t.data.result)}}return window.addEventListener(`message`,a),{update(t){let a=`appearance`in t,o=`amount`in t,s=`merchantName`in t;n={...n,...t},a&&c({iframe:e,appearance:n.appearance}),o&&r(),s&&i()},destroy(){window.removeEventListener(`message`,a)}}}function C({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 w={country:212,full:452},T=80,E={country:400,full:640};function D(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 O(e,t=`country`){let n=new URLSearchParams({token:e,billingAddressRequirement:t});return`${i(e)}/iframe/bank?${n}`}function k(e={cardholderName:!1},t=`country`){return`${(w[t]??w.country)+(e.cardholderName?T:0)}px`}function A(e=`country`){return`${E[e]??E.country}px`}function j(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`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 M(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 N={width:`calc(100% + 8px)`,transition:`opacity 150ms ease-in, height 200ms ease-in-out`,margin:`0 -4px`,opacity:`0`,border:`0`};function P({src:e,title:t,name:n,height:r,allow:i}){let a=document.createElement(`iframe`);return a.src=e,a.title=t,a.name=n,a.setAttribute(`role`,`presentation`),a.scrolling=`no`,i&&(a.allow=i),Object.assign(a.style,N,{height:r}),a}function F(e,t){let n=M(e),{renderToken:r,additionalFields:i={cardholderName:!1},billingAddressRequirement:a=`country`,...o}=t,s=P({src:D(r,i,a),title:`Secure credit card payment method form powered by Amos`,name:`amos-credit-card-payment-method-form`,height:k(i,a)});n.appendChild(s);let c=j(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 I(e,t){let n=M(e),{renderToken:r,billingAddressRequirement:i=`country`,...a}=t,o=P({src:O(r,i),title:`Secure bank account payment method form powered by Amos`,name:`amos-bank-account-payment-method-form`,height:A(i)});n.appendChild(o);let s=j(o,{...a,onHeightChange:e=>{o.style.height=e,a.onHeightChange?.(e)},onAppearanceReady:()=>{o.style.opacity=`1`,a.onAppearanceReady?.()}});return{iframe:o,update:s.update,destroy(){s.destroy(),o.remove()}}}function L(e,t){let n=M(e),{renderToken:r,...i}=t,a=P({src:b(r),title:`Secure Google Pay button powered by Amos`,name:`amos-google-pay-button`,height:x(),allow:`payment`});n.appendChild(a);let o=S(a,{...i,onHeightChange:e=>{a.style.height=e,i.onHeightChange?.(e)},onAppearanceReady:()=>{a.style.opacity=`1`,i.onAppearanceReady?.()}});return{iframe:a,update:o.update,destroy(){o.destroy(),a.remove()}}}function R(e,t){let n=M(e),{renderToken:r,...i}=t,a=P({src:g(r),title:`Secure Apple Pay button powered by Amos`,name:`amos-apple-pay-button`,height:_(),allow:`payment`});n.appendChild(a);let o=y(a,{...i,onHeightChange:e=>{a.style.height=e,i.onHeightChange?.(e)},onAppearanceReady:()=>{a.style.opacity=`1`,i.onAppearanceReady?.()}});return{iframe:a,update:o.update,destroy(){o.destroy(),a.remove()}}}exports.attachApplePayButtonListeners=y,exports.attachGooglePayButtonListeners=S,exports.attachPaymentMethodFormListeners=j,exports.confirmPaymentIntent=p,exports.confirmSetupIntent=m,exports.createMessage=a,exports.decodeJwt=r,exports.formatGooglePayPaymentData=C,exports.getApplePayButtonInitialHeight=_,exports.getApplePayButtonSrc=g,exports.getBankAccountFormInitialHeight=A,exports.getBankAccountFormSrc=O,exports.getCreditCardFormInitialHeight=k,exports.getCreditCardFormSrc=D,exports.getEmbedOrigin=i,exports.getGooglePayButtonInitialHeight=x,exports.getGooglePayButtonSrc=b,exports.mountAmosApplePayButton=R,exports.mountAmosBankAccountPaymentMethodForm=I,exports.mountAmosCreditCardPaymentMethodForm=F,exports.mountAmosGooglePayButton=L,exports.resetForm=f,exports.sendConfirmationResult=h,exports.sendParentReadyMessage=s,exports.updateAmount=l,exports.updateAppearance=c,exports.updateMerchantName=u,exports.validateForm=d;
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){if(!e||typeof e!=`object`)return;let t={};for(let[n,r]of Object.entries(e)){if(typeof r==`string`){if(r.length===0)continue;t[n]=r;continue}typeof r==`number`&&Number.isFinite(r)&&(t[n]=r)}return Object.keys(t).length>0?t:void 0}function o(e){let t={};if(e.buttonstyle!==void 0&&(t.buttonstyle=e.buttonstyle),e.type!==void 0&&(t.type=e.type),e.locale!==void 0&&(t.locale=e.locale),e.style!==void 0){let n=a(e.style);n&&(t.style=n)}return t}function s(e){let t={};if(e.buttonType!==void 0&&(t.buttonType=e.buttonType),e.buttonColor!==void 0&&(t.buttonColor=e.buttonColor),e.buttonRadius!==void 0&&(t.buttonRadius=e.buttonRadius),e.buttonSizeMode!==void 0&&(t.buttonSizeMode=e.buttonSizeMode),e.buttonLocale!==void 0&&(t.buttonLocale=e.buttonLocale),e.buttonBorderType!==void 0&&(t.buttonBorderType=e.buttonBorderType),e.style!==void 0){let n=a(e.style);n&&(t.style=n)}return t}function c(e){return e}function l(e){return new URL(e.src).origin}function u(e){e?.contentWindow&&e.contentWindow.postMessage(c({type:`PARENT_ACKNOWLEDGED_IFRAME_READY`}),l(e))}function d({iframe:e,appearance:t={}}){e?.contentWindow&&e.contentWindow.postMessage(c({type:`UPDATE_APPEARANCE`,appearance:t}),l(e))}function f({iframe:e,props:t}){e?.contentWindow&&e.contentWindow.postMessage(c({type:`UPDATE_APPLE_PAY_BUTTON`,props:o(t)}),l(e))}function p({iframe:e,props:t}){e?.contentWindow&&e.contentWindow.postMessage(c({type:`UPDATE_GOOGLE_PAY_BUTTON`,props:s(t)}),l(e))}function m({iframe:e,amount:t}){e?.contentWindow&&e.contentWindow.postMessage(c({type:`UPDATE_AMOUNT`,amount:t}),l(e))}function h({iframe:e,merchantName:t}){e?.contentWindow&&e.contentWindow.postMessage(c({type:`UPDATE_MERCHANT_NAME`,merchantName:t}),l(e))}function g({iframe:e}){let t=crypto.randomUUID();return new Promise(n=>{e?.contentWindow&&e.contentWindow.postMessage(c({type:`VALIDATE_FORM`,requestId:t}),l(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 _({iframe:e}){e?.contentWindow&&e.contentWindow.postMessage(c({type:`RESET_FORM`}),l(e))}function v({iframe:e,token:t}){if(!e?.contentWindow)return;let{payment_intent_id:n}=r(t).payload;e.contentWindow.postMessage(c({type:`CONFIRM_PAYMENT_INTENT`,token:t,id:n??void 0}),l(e))}function y({iframe:e,token:t}){if(!e?.contentWindow)return;let{setup_intent_id:n}=r(t).payload;e.contentWindow.postMessage(c({type:`CONFIRM_SETUP_INTENT`,token:t,id:n??void 0}),l(e))}function b({iframe:e,result:t}){e?.contentWindow&&e.contentWindow.postMessage(c({type:`CONFIRMATION_RESULT`,result:t}),l(e))}function x(e){return`${i(e)}/iframe/apple-pay?token=${e}`}function S(){return`40px`}function C(e){e.contentWindow?.postMessage(c({type:`APPLE_PAY_CANCEL`}),l(e))}function w(e,r){let i={...r};function a(){m({iframe:e,amount:i.amount})}function o(){h({iframe:e,merchantName:i.merchantName})}function s(){f({iframe:e,props:i})}function c(r){if(r.source===e.contentWindow)switch(r.data.type){case`IFRAME_READY`:u(e),d({iframe:e,appearance:i.appearance}),a(),o(),s();break;case`UPDATE_HEIGHT`:i.onHeightChange?.(r.data.height);break;case`UPDATE_APPEARANCE`:d({iframe:e,appearance:r.data.appearance});break;case`UPDATED_APPEARANCE`:i.onAppearanceReady?.();break;case`APPLE_PAY_WINDOW_OPEN`:t({onCancel:()=>{C(e),n()}});break;case`APPLE_PAY_WINDOW_CLOSE`:n();break;case`CREATE_PAYMENT_INTENT`:i.onInitiatePaymentIntentRequest({paymentIntentCreateAttributes:r.data.paymentIntentCreateAttributes,customerCreateAttributes:r.data.customerCreateAttributes}).then(t=>{v({iframe:e,token:t})}).catch(e=>{n(),i.onResult({status:`failed`,errorMessage:e instanceof Error?e.message:`Unknown error`})});break;case`CONFIRMATION_RESULT`:n(),i.onResult(r.data.result)}}return window.addEventListener(`message`,c),{update(t){let n=`appearance`in t,r=`amount`in t,c=`merchantName`in t,l=`buttonstyle`in t||`type`in t||`locale`in t||`style`in t;i={...i,...t},n&&d({iframe:e,appearance:i.appearance}),r&&a(),c&&o(),l&&s()},destroy(){window.removeEventListener(`message`,c),n()}}}function T(e){return`${i(e)}/iframe/google-pay?token=${e}`}function E(){return`40px`}function D(e,t){let n={...t};function r(){m({iframe:e,amount:n.amount})}function i(){h({iframe:e,merchantName:n.merchantName})}function a(){p({iframe:e,props:n})}function o(t){if(t.source===e.contentWindow)switch(t.data.type){case`IFRAME_READY`:u(e),d({iframe:e,appearance:n.appearance}),r(),i(),a();break;case`UPDATE_HEIGHT`:n.onHeightChange?.(t.data.height);break;case`UPDATE_APPEARANCE`:d({iframe:e,appearance:t.data.appearance});break;case`UPDATED_APPEARANCE`:n.onAppearanceReady?.();break;case`CREATE_PAYMENT_INTENT`:n.onInitiatePaymentIntentRequest({paymentIntentCreateAttributes:t.data.paymentIntentCreateAttributes,customerCreateAttributes:t.data.customerCreateAttributes}).then(t=>{v({iframe:e,token:t})}).catch(e=>{n.onResult({status:`failed`,errorMessage:e instanceof Error?e.message:`Unknown error`})});break;case`CONFIRMATION_RESULT`:n.onResult(t.data.result)}}return window.addEventListener(`message`,o),{update(t){let o=`appearance`in t,s=`amount`in t,c=`merchantName`in t,l=`buttonType`in t||`buttonColor`in t||`buttonRadius`in t||`buttonSizeMode`in t||`buttonLocale`in t||`buttonBorderType`in t||`style`in t;n={...n,...t},o&&d({iframe:e,appearance:n.appearance}),s&&r(),c&&i(),l&&a()},destroy(){window.removeEventListener(`message`,o)}}}function O({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 k={country:212,full:452},A=80,j={country:400,full:640};function M(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 N(e,t=`country`){let n=new URLSearchParams({token:e,billingAddressRequirement:t});return`${i(e)}/iframe/bank?${n}`}function P(e={cardholderName:!1},t=`country`){return`${(k[t]??k.country)+(e.cardholderName?A:0)}px`}function F(e=`country`){return`${j[e]??j.country}px`}function I(e,t){let n={...t};function r(t){if(t.source===e.contentWindow)switch(t.data.type){case`IFRAME_READY`:u(e),d({iframe:e,appearance:n.appearance});break;case`UPDATE_HEIGHT`:n.onHeightChange?.(t.data.height);break;case`UPDATE_APPEARANCE`:d({iframe:e,appearance:t.data.appearance});break;case`UPDATED_APPEARANCE`:n.onAppearanceReady?.();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&&d({iframe:e,appearance:n.appearance})},destroy(){window.removeEventListener(`message`,r)}}}function L(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 R={width:`calc(100% + 8px)`,transition:`opacity 150ms ease-in, height 200ms ease-in-out`,margin:`0 -4px`,opacity:`0`,border:`0`};function z({src:e,title:t,name:n,height:r,allow:i}){let a=document.createElement(`iframe`);return a.src=e,a.title=t,a.name=n,a.setAttribute(`role`,`presentation`),a.scrolling=`no`,i&&(a.allow=i),Object.assign(a.style,R,{height:r}),a}function B(e,t){let n=L(e),{renderToken:r,additionalFields:i={cardholderName:!1},billingAddressRequirement:a=`country`,...o}=t,s=z({src:M(r,i,a),title:`Secure credit card payment method form powered by Amos`,name:`amos-credit-card-payment-method-form`,height:P(i,a)});n.appendChild(s);let c=I(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 V(e,t){let n=L(e),{renderToken:r,billingAddressRequirement:i=`country`,...a}=t,o=z({src:N(r,i),title:`Secure bank account payment method form powered by Amos`,name:`amos-bank-account-payment-method-form`,height:F(i)});n.appendChild(o);let s=I(o,{...a,onHeightChange:e=>{o.style.height=e,a.onHeightChange?.(e)},onAppearanceReady:()=>{o.style.opacity=`1`,a.onAppearanceReady?.()}});return{iframe:o,update:s.update,destroy(){s.destroy(),o.remove()}}}function H(e,t){let n=L(e),{renderToken:r,...i}=t,a=z({src:T(r),title:`Secure Google Pay button powered by Amos`,name:`amos-google-pay-button`,height:E(),allow:`payment`});n.appendChild(a);let o=D(a,{...i,onHeightChange:e=>{a.style.height=e,i.onHeightChange?.(e)},onAppearanceReady:()=>{a.style.opacity=`1`,i.onAppearanceReady?.()}});return{iframe:a,update:o.update,destroy(){o.destroy(),a.remove()}}}function U(e,t){let n=L(e),{renderToken:r,...i}=t,a=z({src:x(r),title:`Secure Apple Pay button powered by Amos`,name:`amos-apple-pay-button`,height:S(),allow:`payment`});n.appendChild(a);let o=w(a,{...i,onHeightChange:e=>{a.style.height=e,i.onHeightChange?.(e)},onAppearanceReady:()=>{a.style.opacity=`1`,i.onAppearanceReady?.()}});return{iframe:a,update:o.update,destroy(){o.destroy(),a.remove()}}}exports.attachApplePayButtonListeners=w,exports.attachGooglePayButtonListeners=D,exports.attachPaymentMethodFormListeners=I,exports.confirmPaymentIntent=v,exports.confirmSetupIntent=y,exports.createMessage=c,exports.decodeJwt=r,exports.formatGooglePayPaymentData=O,exports.getApplePayButtonInitialHeight=S,exports.getApplePayButtonSrc=x,exports.getBankAccountFormInitialHeight=F,exports.getBankAccountFormSrc=N,exports.getCreditCardFormInitialHeight=P,exports.getCreditCardFormSrc=M,exports.getEmbedOrigin=i,exports.getGooglePayButtonInitialHeight=E,exports.getGooglePayButtonSrc=T,exports.mountAmosApplePayButton=U,exports.mountAmosBankAccountPaymentMethodForm=V,exports.mountAmosCreditCardPaymentMethodForm=B,exports.mountAmosGooglePayButton=H,exports.pickApplePayButtonElementProps=o,exports.pickGooglePayButtonElementProps=s,exports.resetForm=_,exports.sendConfirmationResult=b,exports.sendParentReadyMessage=u,exports.serializeWalletButtonStyle=a,exports.updateAmount=m,exports.updateAppearance=d,exports.updateApplePayButton=f,exports.updateGooglePayButton=p,exports.updateMerchantName=h,exports.validateForm=g;
package/dist/index.mjs CHANGED
@@ -85,41 +85,82 @@ function i(e) {
85
85
  //#endregion
86
86
  //#region src/types.ts
87
87
  function a(e) {
88
+ if (!e || typeof e != "object") return;
89
+ let t = {};
90
+ for (let [n, r] of Object.entries(e)) {
91
+ if (typeof r == "string") {
92
+ if (r.length === 0) continue;
93
+ t[n] = r;
94
+ continue;
95
+ }
96
+ typeof r == "number" && Number.isFinite(r) && (t[n] = r);
97
+ }
98
+ return Object.keys(t).length > 0 ? t : void 0;
99
+ }
100
+ function o(e) {
101
+ let t = {};
102
+ if (e.buttonstyle !== void 0 && (t.buttonstyle = e.buttonstyle), e.type !== void 0 && (t.type = e.type), e.locale !== void 0 && (t.locale = e.locale), e.style !== void 0) {
103
+ let n = a(e.style);
104
+ n && (t.style = n);
105
+ }
106
+ return t;
107
+ }
108
+ function s(e) {
109
+ let t = {};
110
+ if (e.buttonType !== void 0 && (t.buttonType = e.buttonType), e.buttonColor !== void 0 && (t.buttonColor = e.buttonColor), e.buttonRadius !== void 0 && (t.buttonRadius = e.buttonRadius), e.buttonSizeMode !== void 0 && (t.buttonSizeMode = e.buttonSizeMode), e.buttonLocale !== void 0 && (t.buttonLocale = e.buttonLocale), e.buttonBorderType !== void 0 && (t.buttonBorderType = e.buttonBorderType), e.style !== void 0) {
111
+ let n = a(e.style);
112
+ n && (t.style = n);
113
+ }
114
+ return t;
115
+ }
116
+ function c(e) {
88
117
  return e;
89
118
  }
90
119
  //#endregion
91
120
  //#region src/messaging.ts
92
- function o(e) {
121
+ function l(e) {
93
122
  return new URL(e.src).origin;
94
123
  }
95
- function s(e) {
96
- e?.contentWindow && e.contentWindow.postMessage(a({ type: "PARENT_ACKNOWLEDGED_IFRAME_READY" }), o(e));
124
+ function u(e) {
125
+ e?.contentWindow && e.contentWindow.postMessage(c({ type: "PARENT_ACKNOWLEDGED_IFRAME_READY" }), l(e));
97
126
  }
98
- function c({ iframe: e, appearance: t = {} }) {
99
- e?.contentWindow && e.contentWindow.postMessage(a({
127
+ function d({ iframe: e, appearance: t = {} }) {
128
+ e?.contentWindow && e.contentWindow.postMessage(c({
100
129
  type: "UPDATE_APPEARANCE",
101
130
  appearance: t
102
- }), o(e));
103
- }
104
- function l({ iframe: e, amount: t }) {
105
- e?.contentWindow && e.contentWindow.postMessage(a({
131
+ }), l(e));
132
+ }
133
+ function f({ iframe: e, props: t }) {
134
+ e?.contentWindow && e.contentWindow.postMessage(c({
135
+ type: "UPDATE_APPLE_PAY_BUTTON",
136
+ props: o(t)
137
+ }), l(e));
138
+ }
139
+ function p({ iframe: e, props: t }) {
140
+ e?.contentWindow && e.contentWindow.postMessage(c({
141
+ type: "UPDATE_GOOGLE_PAY_BUTTON",
142
+ props: s(t)
143
+ }), l(e));
144
+ }
145
+ function m({ iframe: e, amount: t }) {
146
+ e?.contentWindow && e.contentWindow.postMessage(c({
106
147
  type: "UPDATE_AMOUNT",
107
148
  amount: t
108
- }), o(e));
149
+ }), l(e));
109
150
  }
110
- function u({ iframe: e, merchantName: t }) {
111
- e?.contentWindow && e.contentWindow.postMessage(a({
151
+ function h({ iframe: e, merchantName: t }) {
152
+ e?.contentWindow && e.contentWindow.postMessage(c({
112
153
  type: "UPDATE_MERCHANT_NAME",
113
154
  merchantName: t
114
- }), o(e));
155
+ }), l(e));
115
156
  }
116
- function d({ iframe: e }) {
157
+ function g({ iframe: e }) {
117
158
  let t = crypto.randomUUID();
118
159
  return new Promise((n) => {
119
- e?.contentWindow && e.contentWindow.postMessage(a({
160
+ e?.contentWindow && e.contentWindow.postMessage(c({
120
161
  type: "VALIDATE_FORM",
121
162
  requestId: t
122
- }), o(e));
163
+ }), l(e));
123
164
  let r = setTimeout(() => {
124
165
  window.removeEventListener("message", i), n(!1);
125
166
  }, 5e3);
@@ -129,71 +170,77 @@ function d({ iframe: e }) {
129
170
  window.addEventListener("message", i);
130
171
  });
131
172
  }
132
- function f({ iframe: e }) {
133
- e?.contentWindow && e.contentWindow.postMessage(a({ type: "RESET_FORM" }), o(e));
173
+ function _({ iframe: e }) {
174
+ e?.contentWindow && e.contentWindow.postMessage(c({ type: "RESET_FORM" }), l(e));
134
175
  }
135
- function p({ iframe: e, token: t }) {
176
+ function v({ iframe: e, token: t }) {
136
177
  if (!e?.contentWindow) return;
137
178
  let { payment_intent_id: n } = r(t).payload;
138
- e.contentWindow.postMessage(a({
179
+ e.contentWindow.postMessage(c({
139
180
  type: "CONFIRM_PAYMENT_INTENT",
140
181
  token: t,
141
182
  id: n ?? void 0
142
- }), o(e));
183
+ }), l(e));
143
184
  }
144
- function m({ iframe: e, token: t }) {
185
+ function y({ iframe: e, token: t }) {
145
186
  if (!e?.contentWindow) return;
146
187
  let { setup_intent_id: n } = r(t).payload;
147
- e.contentWindow.postMessage(a({
188
+ e.contentWindow.postMessage(c({
148
189
  type: "CONFIRM_SETUP_INTENT",
149
190
  token: t,
150
191
  id: n ?? void 0
151
- }), o(e));
192
+ }), l(e));
152
193
  }
153
- function h({ iframe: e, result: t }) {
154
- e?.contentWindow && e.contentWindow.postMessage(a({
194
+ function b({ iframe: e, result: t }) {
195
+ e?.contentWindow && e.contentWindow.postMessage(c({
155
196
  type: "CONFIRMATION_RESULT",
156
197
  result: t
157
- }), o(e));
198
+ }), l(e));
158
199
  }
159
200
  //#endregion
160
201
  //#region src/apple-pay.ts
161
- function g(e) {
202
+ function x(e) {
162
203
  return `${i(e)}/iframe/apple-pay?token=${e}`;
163
204
  }
164
- function _() {
205
+ function S() {
165
206
  return "40px";
166
207
  }
167
- function v(e) {
168
- e.contentWindow?.postMessage(a({ type: "APPLE_PAY_CANCEL" }), o(e));
208
+ function C(e) {
209
+ e.contentWindow?.postMessage(c({ type: "APPLE_PAY_CANCEL" }), l(e));
169
210
  }
170
- function y(e, r) {
211
+ function w(e, r) {
171
212
  let i = { ...r };
172
213
  function a() {
173
- l({
214
+ m({
174
215
  iframe: e,
175
216
  amount: i.amount
176
217
  });
177
218
  }
178
219
  function o() {
179
- u({
220
+ h({
180
221
  iframe: e,
181
222
  merchantName: i.merchantName
182
223
  });
183
224
  }
184
- function d(r) {
225
+ function s() {
226
+ f({
227
+ iframe: e,
228
+ props: i
229
+ });
230
+ }
231
+ function c(r) {
185
232
  if (r.source === e.contentWindow) switch (r.data.type) {
186
233
  case "IFRAME_READY":
187
- s(e), c({
234
+ u(e), d({
188
235
  iframe: e,
189
236
  appearance: i.appearance
190
- }), a(), o();
237
+ }), a(), o(), s();
191
238
  break;
192
239
  case "UPDATE_HEIGHT":
193
240
  i.onHeightChange?.(r.data.height);
194
241
  break;
195
242
  case "UPDATE_APPEARANCE":
196
- c({
243
+ d({
197
244
  iframe: e,
198
245
  appearance: r.data.appearance
199
246
  });
@@ -203,7 +250,7 @@ function y(e, r) {
203
250
  break;
204
251
  case "APPLE_PAY_WINDOW_OPEN":
205
252
  t({ onCancel: () => {
206
- v(e), n();
253
+ C(e), n();
207
254
  } });
208
255
  break;
209
256
  case "APPLE_PAY_WINDOW_CLOSE":
@@ -214,7 +261,7 @@ function y(e, r) {
214
261
  paymentIntentCreateAttributes: r.data.paymentIntentCreateAttributes,
215
262
  customerCreateAttributes: r.data.customerCreateAttributes
216
263
  }).then((t) => {
217
- p({
264
+ v({
218
265
  iframe: e,
219
266
  token: t
220
267
  });
@@ -228,57 +275,63 @@ function y(e, r) {
228
275
  case "CONFIRMATION_RESULT": n(), i.onResult(r.data.result);
229
276
  }
230
277
  }
231
- return window.addEventListener("message", d), {
278
+ return window.addEventListener("message", c), {
232
279
  update(t) {
233
- let n = "appearance" in t, r = "amount" in t, s = "merchantName" in t;
280
+ let n = "appearance" in t, r = "amount" in t, c = "merchantName" in t, l = "buttonstyle" in t || "type" in t || "locale" in t || "style" in t;
234
281
  i = {
235
282
  ...i,
236
283
  ...t
237
- }, n && c({
284
+ }, n && d({
238
285
  iframe: e,
239
286
  appearance: i.appearance
240
- }), r && a(), s && o();
287
+ }), r && a(), c && o(), l && s();
241
288
  },
242
289
  destroy() {
243
- window.removeEventListener("message", d), n();
290
+ window.removeEventListener("message", c), n();
244
291
  }
245
292
  };
246
293
  }
247
294
  //#endregion
248
295
  //#region src/google-pay.ts
249
- function b(e) {
296
+ function T(e) {
250
297
  return `${i(e)}/iframe/google-pay?token=${e}`;
251
298
  }
252
- function x() {
299
+ function E() {
253
300
  return "40px";
254
301
  }
255
- function S(e, t) {
302
+ function D(e, t) {
256
303
  let n = { ...t };
257
304
  function r() {
258
- l({
305
+ m({
259
306
  iframe: e,
260
307
  amount: n.amount
261
308
  });
262
309
  }
263
310
  function i() {
264
- u({
311
+ h({
265
312
  iframe: e,
266
313
  merchantName: n.merchantName
267
314
  });
268
315
  }
269
- function a(t) {
316
+ function a() {
317
+ p({
318
+ iframe: e,
319
+ props: n
320
+ });
321
+ }
322
+ function o(t) {
270
323
  if (t.source === e.contentWindow) switch (t.data.type) {
271
324
  case "IFRAME_READY":
272
- s(e), c({
325
+ u(e), d({
273
326
  iframe: e,
274
327
  appearance: n.appearance
275
- }), r(), i();
328
+ }), r(), i(), a();
276
329
  break;
277
330
  case "UPDATE_HEIGHT":
278
331
  n.onHeightChange?.(t.data.height);
279
332
  break;
280
333
  case "UPDATE_APPEARANCE":
281
- c({
334
+ d({
282
335
  iframe: e,
283
336
  appearance: t.data.appearance
284
337
  });
@@ -291,7 +344,7 @@ function S(e, t) {
291
344
  paymentIntentCreateAttributes: t.data.paymentIntentCreateAttributes,
292
345
  customerCreateAttributes: t.data.customerCreateAttributes
293
346
  }).then((t) => {
294
- p({
347
+ v({
295
348
  iframe: e,
296
349
  token: t
297
350
  });
@@ -305,23 +358,23 @@ function S(e, t) {
305
358
  case "CONFIRMATION_RESULT": n.onResult(t.data.result);
306
359
  }
307
360
  }
308
- return window.addEventListener("message", a), {
361
+ return window.addEventListener("message", o), {
309
362
  update(t) {
310
- let a = "appearance" in t, o = "amount" in t, s = "merchantName" in t;
363
+ let o = "appearance" in t, s = "amount" in t, c = "merchantName" in t, l = "buttonType" in t || "buttonColor" in t || "buttonRadius" in t || "buttonSizeMode" in t || "buttonLocale" in t || "buttonBorderType" in t || "style" in t;
311
364
  n = {
312
365
  ...n,
313
366
  ...t
314
- }, a && c({
367
+ }, o && d({
315
368
  iframe: e,
316
369
  appearance: n.appearance
317
- }), o && r(), s && i();
370
+ }), s && r(), c && i(), l && a();
318
371
  },
319
372
  destroy() {
320
- window.removeEventListener("message", a);
373
+ window.removeEventListener("message", o);
321
374
  }
322
375
  };
323
376
  }
324
- function C({ paymentData: e }) {
377
+ function O({ paymentData: e }) {
325
378
  return { paymentMethod: {
326
379
  type: "googlepay",
327
380
  billing_address_attributes: {
@@ -340,14 +393,14 @@ function C({ paymentData: e }) {
340
393
  }
341
394
  //#endregion
342
395
  //#region src/payment-method-form.ts
343
- var w = {
396
+ var k = {
344
397
  country: 212,
345
398
  full: 452
346
- }, T = 80, E = {
399
+ }, A = 80, j = {
347
400
  country: 400,
348
401
  full: 640
349
402
  };
350
- function D(e, t = { cardholderName: !1 }, n = "country") {
403
+ function M(e, t = { cardholderName: !1 }, n = "country") {
351
404
  let r = Object.entries(t).filter(([, e]) => e).map(([e]) => e).join(","), a = new URLSearchParams({
352
405
  token: e,
353
406
  additionalFields: r,
@@ -355,25 +408,25 @@ function D(e, t = { cardholderName: !1 }, n = "country") {
355
408
  });
356
409
  return `${i(e)}/iframe/card?${a}`;
357
410
  }
358
- function O(e, t = "country") {
411
+ function N(e, t = "country") {
359
412
  let n = new URLSearchParams({
360
413
  token: e,
361
414
  billingAddressRequirement: t
362
415
  });
363
416
  return `${i(e)}/iframe/bank?${n}`;
364
417
  }
365
- function k(e = { cardholderName: !1 }, t = "country") {
366
- return `${(w[t] ?? w.country) + (e.cardholderName ? T : 0)}px`;
418
+ function P(e = { cardholderName: !1 }, t = "country") {
419
+ return `${(k[t] ?? k.country) + (e.cardholderName ? A : 0)}px`;
367
420
  }
368
- function A(e = "country") {
369
- return `${E[e] ?? E.country}px`;
421
+ function F(e = "country") {
422
+ return `${j[e] ?? j.country}px`;
370
423
  }
371
- function j(e, t) {
424
+ function I(e, t) {
372
425
  let n = { ...t };
373
426
  function r(t) {
374
427
  if (t.source === e.contentWindow) switch (t.data.type) {
375
428
  case "IFRAME_READY":
376
- s(e), c({
429
+ u(e), d({
377
430
  iframe: e,
378
431
  appearance: n.appearance
379
432
  });
@@ -382,7 +435,7 @@ function j(e, t) {
382
435
  n.onHeightChange?.(t.data.height);
383
436
  break;
384
437
  case "UPDATE_APPEARANCE":
385
- c({
438
+ d({
386
439
  iframe: e,
387
440
  appearance: t.data.appearance
388
441
  });
@@ -399,7 +452,7 @@ function j(e, t) {
399
452
  n = {
400
453
  ...n,
401
454
  ...t
402
- }, r && c({
455
+ }, r && d({
403
456
  iframe: e,
404
457
  appearance: n.appearance
405
458
  });
@@ -411,7 +464,7 @@ function j(e, t) {
411
464
  }
412
465
  //#endregion
413
466
  //#region src/mount.ts
414
- function M(e) {
467
+ function L(e) {
415
468
  if (typeof e == "string") {
416
469
  let t = document.querySelector(e);
417
470
  if (!(t instanceof HTMLElement)) throw Error(`[amos-js] Container "${e}" did not match any HTMLElement.`);
@@ -419,26 +472,26 @@ function M(e) {
419
472
  }
420
473
  return e;
421
474
  }
422
- var N = {
475
+ var R = {
423
476
  width: "calc(100% + 8px)",
424
477
  transition: "opacity 150ms ease-in, height 200ms ease-in-out",
425
478
  margin: "0 -4px",
426
479
  opacity: "0",
427
480
  border: "0"
428
481
  };
429
- function P({ src: e, title: t, name: n, height: r, allow: i }) {
482
+ function z({ src: e, title: t, name: n, height: r, allow: i }) {
430
483
  let a = document.createElement("iframe");
431
- return a.src = e, a.title = t, a.name = n, a.setAttribute("role", "presentation"), a.scrolling = "no", i && (a.allow = i), Object.assign(a.style, N, { height: r }), a;
484
+ return a.src = e, a.title = t, a.name = n, a.setAttribute("role", "presentation"), a.scrolling = "no", i && (a.allow = i), Object.assign(a.style, R, { height: r }), a;
432
485
  }
433
- function F(e, t) {
434
- let n = M(e), { renderToken: r, additionalFields: i = { cardholderName: !1 }, billingAddressRequirement: a = "country", ...o } = t, s = P({
435
- src: D(r, i, a),
486
+ function B(e, t) {
487
+ let n = L(e), { renderToken: r, additionalFields: i = { cardholderName: !1 }, billingAddressRequirement: a = "country", ...o } = t, s = z({
488
+ src: M(r, i, a),
436
489
  title: "Secure credit card payment method form powered by Amos",
437
490
  name: "amos-credit-card-payment-method-form",
438
- height: k(i, a)
491
+ height: P(i, a)
439
492
  });
440
493
  n.appendChild(s);
441
- let c = j(s, {
494
+ let c = I(s, {
442
495
  ...o,
443
496
  onHeightChange: (e) => {
444
497
  s.style.height = e, o.onHeightChange?.(e);
@@ -455,15 +508,15 @@ function F(e, t) {
455
508
  }
456
509
  };
457
510
  }
458
- function I(e, t) {
459
- let n = M(e), { renderToken: r, billingAddressRequirement: i = "country", ...a } = t, o = P({
460
- src: O(r, i),
511
+ function V(e, t) {
512
+ let n = L(e), { renderToken: r, billingAddressRequirement: i = "country", ...a } = t, o = z({
513
+ src: N(r, i),
461
514
  title: "Secure bank account payment method form powered by Amos",
462
515
  name: "amos-bank-account-payment-method-form",
463
- height: A(i)
516
+ height: F(i)
464
517
  });
465
518
  n.appendChild(o);
466
- let s = j(o, {
519
+ let s = I(o, {
467
520
  ...a,
468
521
  onHeightChange: (e) => {
469
522
  o.style.height = e, a.onHeightChange?.(e);
@@ -480,16 +533,16 @@ function I(e, t) {
480
533
  }
481
534
  };
482
535
  }
483
- function L(e, t) {
484
- let n = M(e), { renderToken: r, ...i } = t, a = P({
485
- src: b(r),
536
+ function H(e, t) {
537
+ let n = L(e), { renderToken: r, ...i } = t, a = z({
538
+ src: T(r),
486
539
  title: "Secure Google Pay button powered by Amos",
487
540
  name: "amos-google-pay-button",
488
- height: x(),
541
+ height: E(),
489
542
  allow: "payment"
490
543
  });
491
544
  n.appendChild(a);
492
- let o = S(a, {
545
+ let o = D(a, {
493
546
  ...i,
494
547
  onHeightChange: (e) => {
495
548
  a.style.height = e, i.onHeightChange?.(e);
@@ -506,16 +559,16 @@ function L(e, t) {
506
559
  }
507
560
  };
508
561
  }
509
- function R(e, t) {
510
- let n = M(e), { renderToken: r, ...i } = t, a = P({
511
- src: g(r),
562
+ function U(e, t) {
563
+ let n = L(e), { renderToken: r, ...i } = t, a = z({
564
+ src: x(r),
512
565
  title: "Secure Apple Pay button powered by Amos",
513
566
  name: "amos-apple-pay-button",
514
- height: _(),
567
+ height: S(),
515
568
  allow: "payment"
516
569
  });
517
570
  n.appendChild(a);
518
- let o = y(a, {
571
+ let o = w(a, {
519
572
  ...i,
520
573
  onHeightChange: (e) => {
521
574
  a.style.height = e, i.onHeightChange?.(e);
@@ -533,4 +586,4 @@ function R(e, t) {
533
586
  };
534
587
  }
535
588
  //#endregion
536
- export { y as attachApplePayButtonListeners, S as attachGooglePayButtonListeners, j as attachPaymentMethodFormListeners, p as confirmPaymentIntent, m as confirmSetupIntent, a as createMessage, r as decodeJwt, C as formatGooglePayPaymentData, _ as getApplePayButtonInitialHeight, g as getApplePayButtonSrc, A as getBankAccountFormInitialHeight, O as getBankAccountFormSrc, k as getCreditCardFormInitialHeight, D as getCreditCardFormSrc, i as getEmbedOrigin, x as getGooglePayButtonInitialHeight, b as getGooglePayButtonSrc, R as mountAmosApplePayButton, I as mountAmosBankAccountPaymentMethodForm, F as mountAmosCreditCardPaymentMethodForm, L as mountAmosGooglePayButton, f as resetForm, h as sendConfirmationResult, s as sendParentReadyMessage, l as updateAmount, c as updateAppearance, u as updateMerchantName, d as validateForm };
589
+ export { w as attachApplePayButtonListeners, D as attachGooglePayButtonListeners, I as attachPaymentMethodFormListeners, v as confirmPaymentIntent, y as confirmSetupIntent, c as createMessage, r as decodeJwt, O as formatGooglePayPaymentData, S as getApplePayButtonInitialHeight, x as getApplePayButtonSrc, F as getBankAccountFormInitialHeight, N as getBankAccountFormSrc, P as getCreditCardFormInitialHeight, M as getCreditCardFormSrc, i as getEmbedOrigin, E as getGooglePayButtonInitialHeight, T as getGooglePayButtonSrc, U as mountAmosApplePayButton, V as mountAmosBankAccountPaymentMethodForm, B as mountAmosCreditCardPaymentMethodForm, H as mountAmosGooglePayButton, o as pickApplePayButtonElementProps, s as pickGooglePayButtonElementProps, _ as resetForm, b as sendConfirmationResult, u as sendParentReadyMessage, a as serializeWalletButtonStyle, m as updateAmount, d as updateAppearance, f as updateApplePayButton, p as updateGooglePayButton, h as updateMerchantName, g as validateForm };
@@ -1,5 +1,5 @@
1
1
  import { components } from '@amos.com/node';
2
- import { Appearance, Message } from './types';
2
+ import { Appearance, ApplePayButtonElementProps, GooglePayButtonElementProps, Message } from './types';
3
3
  type Iframe = HTMLIFrameElement | null | undefined;
4
4
  /**
5
5
  * Resolve the Amos embed origin from an iframe's configured `src`.
@@ -26,6 +26,20 @@ export declare function updateAppearance({ iframe, appearance, }: {
26
26
  iframe: Iframe;
27
27
  appearance?: Appearance;
28
28
  }): void;
29
+ /**
30
+ * Push Apple Pay button visual options into the embedded iframe.
31
+ */
32
+ export declare function updateApplePayButton({ iframe, props, }: {
33
+ iframe: Iframe;
34
+ props: ApplePayButtonElementProps;
35
+ }): void;
36
+ /**
37
+ * Push Google Pay button visual options into the embedded iframe.
38
+ */
39
+ export declare function updateGooglePayButton({ iframe, props, }: {
40
+ iframe: Iframe;
41
+ props: GooglePayButtonElementProps;
42
+ }): void;
29
43
  /**
30
44
  * Push the express-checkout amount into the embedded Google Pay iframe.
31
45
  */
package/dist/types.d.ts CHANGED
@@ -69,6 +69,99 @@ export type Appearance = {
69
69
  */
70
70
  labels?: AppearanceLabels;
71
71
  };
72
+ /**
73
+ * Inline style bag sent through `postMessage` to the wallet-button iframe.
74
+ *
75
+ * Matches the serializable subset of a CSSStyleDeclaration / React
76
+ * `CSSProperties` object (string or number values). Custom properties such
77
+ * as `--apple-pay-button-height` are allowed.
78
+ */
79
+ export type WalletButtonStyle = {
80
+ [property: string]: string | number | undefined;
81
+ };
82
+ /**
83
+ * `buttonstyle` attribute on Apple's `<apple-pay-button>`.
84
+ *
85
+ * @see https://developer.apple.com/documentation/apple_pay_on_the_web/apple-pay-button
86
+ */
87
+ export type ApplePayButtonStyle = "black" | "white" | "white-outline";
88
+ /**
89
+ * `type` attribute on Apple's `<apple-pay-button>`.
90
+ *
91
+ * @see https://developer.apple.com/documentation/apple_pay_on_the_web/apple-pay-button
92
+ */
93
+ export type ApplePayButtonType = "plain" | "buy" | "set-up" | "donate" | "check-out" | "book" | "subscribe" | "reload" | "add-money" | "top-up" | "order" | "rent" | "support" | "contribute" | "tip";
94
+ /**
95
+ * Visual props for Apple's `<apple-pay-button>`, using Apple's attribute
96
+ * names. Applied inside the Amos embed iframe.
97
+ *
98
+ * @see https://developer.apple.com/documentation/apple_pay_on_the_web/apple-pay-button
99
+ */
100
+ export type ApplePayButtonElementProps = {
101
+ /**
102
+ * Apple Pay button color.
103
+ *
104
+ * @default "black"
105
+ */
106
+ buttonstyle?: ApplePayButtonStyle;
107
+ /**
108
+ * Apple Pay button label / verb.
109
+ *
110
+ * @default "plain"
111
+ */
112
+ type?: ApplePayButtonType;
113
+ /**
114
+ * BCP 47 locale for the button label (e.g. `"en-US"`).
115
+ *
116
+ * @default "en-US"
117
+ */
118
+ locale?: string;
119
+ /**
120
+ * Inline style for the `<apple-pay-button>`. Height is controlled with
121
+ * `--apple-pay-button-height` (Apple ignores CSS `height`). Width uses
122
+ * `--apple-pay-button-width` or CSS `width`.
123
+ */
124
+ style?: WalletButtonStyle;
125
+ };
126
+ /**
127
+ * Visual props for Google's Pay button, using `@google-pay/button-react`
128
+ * / Google Pay API names. Applied inside the Amos embed iframe.
129
+ *
130
+ * @see https://developers.google.com/pay/api/web/guides/resources/customize
131
+ */
132
+ export type GooglePayButtonElementProps = {
133
+ /**
134
+ * Button label / verb.
135
+ *
136
+ * @default "short"
137
+ */
138
+ buttonType?: google.payments.api.ButtonType;
139
+ /** Button color. */
140
+ buttonColor?: google.payments.api.ButtonColor;
141
+ /** Corner radius in pixels (0–20). */
142
+ buttonRadius?: number;
143
+ /**
144
+ * `"fill"` stretches the button to the container width; `"static"`
145
+ * uses Google's default size.
146
+ */
147
+ buttonSizeMode?: google.payments.api.ButtonSizeMode;
148
+ /** BCP 47 locale for the button label (e.g. `"en"`). */
149
+ buttonLocale?: string;
150
+ /** Whether the button draws a border. */
151
+ buttonBorderType?: google.payments.api.ButtonBorderType;
152
+ /**
153
+ * Inline style for the Google Pay button wrapper. Use `height` /
154
+ * `width` here (unlike Apple Pay, Google honors CSS `height`).
155
+ */
156
+ style?: WalletButtonStyle;
157
+ };
158
+ /**
159
+ * Keep only JSON-cloneable string/number declarations from a style object
160
+ * before sending it through `postMessage`.
161
+ */
162
+ export declare function serializeWalletButtonStyle(style: WalletButtonStyle | undefined): Record<string, string | number> | undefined;
163
+ export declare function pickApplePayButtonElementProps(options: ApplePayButtonElementProps): ApplePayButtonElementProps;
164
+ export declare function pickGooglePayButtonElementProps(options: GooglePayButtonElementProps): GooglePayButtonElementProps;
72
165
  /**
73
166
  * Typed `postMessage` payloads exchanged between the host page and the
74
167
  * embedded Amos iframe.
@@ -95,6 +188,18 @@ export type Message = {
95
188
  /** Parent → embed: push appearance overrides into the iframe. */
96
189
  type: "UPDATE_APPEARANCE";
97
190
  appearance: Appearance;
191
+ } | {
192
+ /**
193
+ * Parent → embed: visual options for the Apple Pay button. Nested
194
+ * under `props` so Apple's `type` attribute does not collide with
195
+ * this message discriminant.
196
+ */
197
+ type: "UPDATE_APPLE_PAY_BUTTON";
198
+ props: ApplePayButtonElementProps;
199
+ } | {
200
+ /** Parent → embed: visual options for the Google Pay button. */
201
+ type: "UPDATE_GOOGLE_PAY_BUTTON";
202
+ props: GooglePayButtonElementProps;
98
203
  } | {
99
204
  /**
100
205
  * Parent → embed: validate form inputs (`requestId` only).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amos.com/amos-js",
3
- "version": "0.9.9",
3
+ "version": "0.9.10",
4
4
  "main": "dist/index.js",
5
5
  "repository": {
6
6
  "type": "git",
package/src/apple-pay.ts CHANGED
@@ -10,10 +10,12 @@ import {
10
10
  sendParentReadyMessage,
11
11
  updateAmount as sendUpdateAmount,
12
12
  updateAppearance as sendUpdateAppearance,
13
+ updateApplePayButton as sendUpdateApplePayButton,
13
14
  updateMerchantName as sendUpdateMerchantName,
14
15
  } from "./messaging";
15
16
  import {
16
17
  type Appearance,
18
+ type ApplePayButtonElementProps,
17
19
  type ConfirmationResult,
18
20
  createMessage,
19
21
  type Message,
@@ -36,7 +38,7 @@ export function getApplePayButtonInitialHeight(): string {
36
38
  /**
37
39
  * Options accepted by {@link attachApplePayButtonListeners}.
38
40
  */
39
- export type ApplePayButtonListenerOptions = {
41
+ export type ApplePayButtonListenerOptions = ApplePayButtonElementProps & {
40
42
  /** The amount of the payment, in the same format passed in props. */
41
43
  amount: string;
42
44
  /** A user-visible merchant name. */
@@ -83,7 +85,9 @@ export type ApplePayButtonController = {
83
85
  /**
84
86
  * Update one or more listener options without re-attaching the
85
87
  * message listener. Pass `amount` or `merchantName` to push the new
86
- * value into the iframe; pass `appearance` to update theme variables.
88
+ * value into the iframe; pass `appearance` to update theme variables;
89
+ * pass `buttonstyle`, `type`, `locale`, or `style` to restyle the
90
+ * Apple Pay button.
87
91
  */
88
92
  update: (patch: Partial<ApplePayButtonListenerOptions>) => void;
89
93
  /**
@@ -126,6 +130,10 @@ export function attachApplePayButtonListeners(
126
130
  sendUpdateMerchantName({ iframe, merchantName: current.merchantName });
127
131
  }
128
132
 
133
+ function pushButtonProps() {
134
+ sendUpdateApplePayButton({ iframe, props: current });
135
+ }
136
+
129
137
  function handleMessage(event: MessageEvent<Message>) {
130
138
  // Ignore messages from other frames / windows.
131
139
  if (event.source !== iframe.contentWindow) {
@@ -138,6 +146,7 @@ export function attachApplePayButtonListeners(
138
146
  sendUpdateAppearance({ iframe, appearance: current.appearance });
139
147
  pushAmount();
140
148
  pushMerchantName();
149
+ pushButtonProps();
141
150
  break;
142
151
 
143
152
  case "UPDATE_HEIGHT":
@@ -199,6 +208,11 @@ export function attachApplePayButtonListeners(
199
208
  const hadAppearance = "appearance" in patch;
200
209
  const hadAmount = "amount" in patch;
201
210
  const hadMerchantName = "merchantName" in patch;
211
+ const hadButtonProps =
212
+ "buttonstyle" in patch ||
213
+ "type" in patch ||
214
+ "locale" in patch ||
215
+ "style" in patch;
202
216
  current = { ...current, ...patch };
203
217
  if (hadAppearance) {
204
218
  sendUpdateAppearance({ iframe, appearance: current.appearance });
@@ -209,6 +223,9 @@ export function attachApplePayButtonListeners(
209
223
  if (hadMerchantName) {
210
224
  pushMerchantName();
211
225
  }
226
+ if (hadButtonProps) {
227
+ pushButtonProps();
228
+ }
212
229
  },
213
230
  destroy() {
214
231
  window.removeEventListener("message", handleMessage);
package/src/google-pay.ts CHANGED
@@ -7,9 +7,15 @@ import {
7
7
  sendParentReadyMessage,
8
8
  updateAmount as sendUpdateAmount,
9
9
  updateAppearance as sendUpdateAppearance,
10
+ updateGooglePayButton as sendUpdateGooglePayButton,
10
11
  updateMerchantName as sendUpdateMerchantName,
11
12
  } from "./messaging";
12
- import type { Appearance, ConfirmationResult, Message } from "./types";
13
+ import type {
14
+ Appearance,
15
+ ConfirmationResult,
16
+ GooglePayButtonElementProps,
17
+ Message,
18
+ } from "./types";
13
19
 
14
20
  /**
15
21
  * Build the iframe `src` URL for the embedded Google Pay button.
@@ -28,7 +34,7 @@ export function getGooglePayButtonInitialHeight(): string {
28
34
  /**
29
35
  * Options accepted by {@link attachGooglePayButtonListeners}.
30
36
  */
31
- export type GooglePayButtonListenerOptions = {
37
+ export type GooglePayButtonListenerOptions = GooglePayButtonElementProps & {
32
38
  /** The amount of the payment, in the same format passed in props. */
33
39
  amount: string;
34
40
  /** A user-visible merchant name. */
@@ -75,7 +81,10 @@ export type GooglePayButtonController = {
75
81
  /**
76
82
  * Update one or more listener options without re-attaching the
77
83
  * message listener. Pass `amount` or `merchantName` to push the new
78
- * value into the iframe; pass `appearance` to update theme variables.
84
+ * value into the iframe; pass `appearance` to update theme variables;
85
+ * pass `buttonType`, `buttonColor`, `buttonRadius`, `buttonSizeMode`,
86
+ * `buttonLocale`, `buttonBorderType`, or `style` to restyle the
87
+ * Google Pay button.
79
88
  */
80
89
  update: (patch: Partial<GooglePayButtonListenerOptions>) => void;
81
90
  /**
@@ -106,6 +115,10 @@ export function attachGooglePayButtonListeners(
106
115
  sendUpdateMerchantName({ iframe, merchantName: current.merchantName });
107
116
  }
108
117
 
118
+ function pushButtonProps() {
119
+ sendUpdateGooglePayButton({ iframe, props: current });
120
+ }
121
+
109
122
  function handleMessage(event: MessageEvent<Message>) {
110
123
  if (event.source !== iframe.contentWindow) {
111
124
  return;
@@ -117,6 +130,7 @@ export function attachGooglePayButtonListeners(
117
130
  sendUpdateAppearance({ iframe, appearance: current.appearance });
118
131
  pushAmount();
119
132
  pushMerchantName();
133
+ pushButtonProps();
120
134
  break;
121
135
 
122
136
  case "UPDATE_HEIGHT":
@@ -163,6 +177,14 @@ export function attachGooglePayButtonListeners(
163
177
  const hadAppearance = "appearance" in patch;
164
178
  const hadAmount = "amount" in patch;
165
179
  const hadMerchantName = "merchantName" in patch;
180
+ const hadButtonProps =
181
+ "buttonType" in patch ||
182
+ "buttonColor" in patch ||
183
+ "buttonRadius" in patch ||
184
+ "buttonSizeMode" in patch ||
185
+ "buttonLocale" in patch ||
186
+ "buttonBorderType" in patch ||
187
+ "style" in patch;
166
188
  current = { ...current, ...patch };
167
189
  if (hadAppearance) {
168
190
  sendUpdateAppearance({ iframe, appearance: current.appearance });
@@ -173,6 +195,9 @@ export function attachGooglePayButtonListeners(
173
195
  if (hadMerchantName) {
174
196
  pushMerchantName();
175
197
  }
198
+ if (hadButtonProps) {
199
+ pushButtonProps();
200
+ }
176
201
  },
177
202
  destroy() {
178
203
  window.removeEventListener("message", handleMessage);
package/src/index.ts CHANGED
@@ -32,6 +32,8 @@ export {
32
32
  sendParentReadyMessage,
33
33
  updateAmount,
34
34
  updateAppearance,
35
+ updateApplePayButton,
36
+ updateGooglePayButton,
35
37
  updateMerchantName,
36
38
  validateForm,
37
39
  } from "./messaging";
@@ -66,9 +68,19 @@ export {
66
68
  export type {
67
69
  Appearance,
68
70
  AppearanceLabels,
71
+ ApplePayButtonElementProps,
72
+ ApplePayButtonStyle,
73
+ ApplePayButtonType,
69
74
  ConfirmationIncompleteReason,
70
75
  ConfirmationResult,
76
+ GooglePayButtonElementProps,
71
77
  Message,
72
78
  ThemeVariable,
79
+ WalletButtonStyle,
80
+ } from "./types";
81
+ export {
82
+ createMessage,
83
+ pickApplePayButtonElementProps,
84
+ pickGooglePayButtonElementProps,
85
+ serializeWalletButtonStyle,
73
86
  } from "./types";
74
- export { createMessage } from "./types";
package/src/messaging.ts CHANGED
@@ -1,6 +1,14 @@
1
1
  import type { components } from "@amos.com/node";
2
2
  import { decodeJwt } from "./jwt";
3
- import { type Appearance, createMessage, type Message } from "./types";
3
+ import {
4
+ type Appearance,
5
+ type ApplePayButtonElementProps,
6
+ createMessage,
7
+ type GooglePayButtonElementProps,
8
+ type Message,
9
+ pickApplePayButtonElementProps,
10
+ pickGooglePayButtonElementProps,
11
+ } from "./types";
4
12
 
5
13
  type Iframe = HTMLIFrameElement | null | undefined;
6
14
 
@@ -55,6 +63,52 @@ export function updateAppearance({
55
63
  );
56
64
  }
57
65
 
66
+ /**
67
+ * Push Apple Pay button visual options into the embedded iframe.
68
+ */
69
+ export function updateApplePayButton({
70
+ iframe,
71
+ props,
72
+ }: {
73
+ iframe: Iframe;
74
+ props: ApplePayButtonElementProps;
75
+ }): void {
76
+ if (!iframe?.contentWindow) {
77
+ return;
78
+ }
79
+
80
+ iframe.contentWindow.postMessage(
81
+ createMessage({
82
+ type: "UPDATE_APPLE_PAY_BUTTON",
83
+ props: pickApplePayButtonElementProps(props),
84
+ }),
85
+ getIframeTargetOrigin(iframe),
86
+ );
87
+ }
88
+
89
+ /**
90
+ * Push Google Pay button visual options into the embedded iframe.
91
+ */
92
+ export function updateGooglePayButton({
93
+ iframe,
94
+ props,
95
+ }: {
96
+ iframe: Iframe;
97
+ props: GooglePayButtonElementProps;
98
+ }): void {
99
+ if (!iframe?.contentWindow) {
100
+ return;
101
+ }
102
+
103
+ iframe.contentWindow.postMessage(
104
+ createMessage({
105
+ type: "UPDATE_GOOGLE_PAY_BUTTON",
106
+ props: pickGooglePayButtonElementProps(props),
107
+ }),
108
+ getIframeTargetOrigin(iframe),
109
+ );
110
+ }
111
+
58
112
  /**
59
113
  * Push the express-checkout amount into the embedded Google Pay iframe.
60
114
  */
package/src/types.ts CHANGED
@@ -1,3 +1,5 @@
1
+ /// <reference types="googlepay" />
2
+
1
3
  import type { components } from "@amos.com/node";
2
4
 
3
5
  /**
@@ -303,6 +305,193 @@ export type Appearance = {
303
305
  labels?: AppearanceLabels;
304
306
  };
305
307
 
308
+ /**
309
+ * Inline style bag sent through `postMessage` to the wallet-button iframe.
310
+ *
311
+ * Matches the serializable subset of a CSSStyleDeclaration / React
312
+ * `CSSProperties` object (string or number values). Custom properties such
313
+ * as `--apple-pay-button-height` are allowed.
314
+ */
315
+ export type WalletButtonStyle = {
316
+ [property: string]: string | number | undefined;
317
+ };
318
+
319
+ /**
320
+ * `buttonstyle` attribute on Apple's `<apple-pay-button>`.
321
+ *
322
+ * @see https://developer.apple.com/documentation/apple_pay_on_the_web/apple-pay-button
323
+ */
324
+ export type ApplePayButtonStyle = "black" | "white" | "white-outline";
325
+
326
+ /**
327
+ * `type` attribute on Apple's `<apple-pay-button>`.
328
+ *
329
+ * @see https://developer.apple.com/documentation/apple_pay_on_the_web/apple-pay-button
330
+ */
331
+ export type ApplePayButtonType =
332
+ | "plain"
333
+ | "buy"
334
+ | "set-up"
335
+ | "donate"
336
+ | "check-out"
337
+ | "book"
338
+ | "subscribe"
339
+ | "reload"
340
+ | "add-money"
341
+ | "top-up"
342
+ | "order"
343
+ | "rent"
344
+ | "support"
345
+ | "contribute"
346
+ | "tip";
347
+
348
+ /**
349
+ * Visual props for Apple's `<apple-pay-button>`, using Apple's attribute
350
+ * names. Applied inside the Amos embed iframe.
351
+ *
352
+ * @see https://developer.apple.com/documentation/apple_pay_on_the_web/apple-pay-button
353
+ */
354
+ export type ApplePayButtonElementProps = {
355
+ /**
356
+ * Apple Pay button color.
357
+ *
358
+ * @default "black"
359
+ */
360
+ buttonstyle?: ApplePayButtonStyle;
361
+ /**
362
+ * Apple Pay button label / verb.
363
+ *
364
+ * @default "plain"
365
+ */
366
+ type?: ApplePayButtonType;
367
+ /**
368
+ * BCP 47 locale for the button label (e.g. `"en-US"`).
369
+ *
370
+ * @default "en-US"
371
+ */
372
+ locale?: string;
373
+ /**
374
+ * Inline style for the `<apple-pay-button>`. Height is controlled with
375
+ * `--apple-pay-button-height` (Apple ignores CSS `height`). Width uses
376
+ * `--apple-pay-button-width` or CSS `width`.
377
+ */
378
+ style?: WalletButtonStyle;
379
+ };
380
+
381
+ /**
382
+ * Visual props for Google's Pay button, using `@google-pay/button-react`
383
+ * / Google Pay API names. Applied inside the Amos embed iframe.
384
+ *
385
+ * @see https://developers.google.com/pay/api/web/guides/resources/customize
386
+ */
387
+ export type GooglePayButtonElementProps = {
388
+ /**
389
+ * Button label / verb.
390
+ *
391
+ * @default "short"
392
+ */
393
+ buttonType?: google.payments.api.ButtonType;
394
+ /** Button color. */
395
+ buttonColor?: google.payments.api.ButtonColor;
396
+ /** Corner radius in pixels (0–20). */
397
+ buttonRadius?: number;
398
+ /**
399
+ * `"fill"` stretches the button to the container width; `"static"`
400
+ * uses Google's default size.
401
+ */
402
+ buttonSizeMode?: google.payments.api.ButtonSizeMode;
403
+ /** BCP 47 locale for the button label (e.g. `"en"`). */
404
+ buttonLocale?: string;
405
+ /** Whether the button draws a border. */
406
+ buttonBorderType?: google.payments.api.ButtonBorderType;
407
+ /**
408
+ * Inline style for the Google Pay button wrapper. Use `height` /
409
+ * `width` here (unlike Apple Pay, Google honors CSS `height`).
410
+ */
411
+ style?: WalletButtonStyle;
412
+ };
413
+
414
+ /**
415
+ * Keep only JSON-cloneable string/number declarations from a style object
416
+ * before sending it through `postMessage`.
417
+ */
418
+ export function serializeWalletButtonStyle(
419
+ style: WalletButtonStyle | undefined,
420
+ ): Record<string, string | number> | undefined {
421
+ if (!style || typeof style !== "object") {
422
+ return undefined;
423
+ }
424
+
425
+ const result: Record<string, string | number> = {};
426
+ for (const [key, value] of Object.entries(style)) {
427
+ if (typeof value === "string") {
428
+ if (value.length === 0) {
429
+ continue;
430
+ }
431
+ result[key] = value;
432
+ continue;
433
+ }
434
+ if (typeof value === "number" && Number.isFinite(value)) {
435
+ result[key] = value;
436
+ }
437
+ }
438
+
439
+ return Object.keys(result).length > 0 ? result : undefined;
440
+ }
441
+
442
+ export function pickApplePayButtonElementProps(
443
+ options: ApplePayButtonElementProps,
444
+ ): ApplePayButtonElementProps {
445
+ const props: ApplePayButtonElementProps = {};
446
+ if (options.buttonstyle !== undefined) {
447
+ props.buttonstyle = options.buttonstyle;
448
+ }
449
+ if (options.type !== undefined) {
450
+ props.type = options.type;
451
+ }
452
+ if (options.locale !== undefined) {
453
+ props.locale = options.locale;
454
+ }
455
+ if (options.style !== undefined) {
456
+ const style = serializeWalletButtonStyle(options.style);
457
+ if (style) {
458
+ props.style = style;
459
+ }
460
+ }
461
+ return props;
462
+ }
463
+
464
+ export function pickGooglePayButtonElementProps(
465
+ options: GooglePayButtonElementProps,
466
+ ): GooglePayButtonElementProps {
467
+ const props: GooglePayButtonElementProps = {};
468
+ if (options.buttonType !== undefined) {
469
+ props.buttonType = options.buttonType;
470
+ }
471
+ if (options.buttonColor !== undefined) {
472
+ props.buttonColor = options.buttonColor;
473
+ }
474
+ if (options.buttonRadius !== undefined) {
475
+ props.buttonRadius = options.buttonRadius;
476
+ }
477
+ if (options.buttonSizeMode !== undefined) {
478
+ props.buttonSizeMode = options.buttonSizeMode;
479
+ }
480
+ if (options.buttonLocale !== undefined) {
481
+ props.buttonLocale = options.buttonLocale;
482
+ }
483
+ if (options.buttonBorderType !== undefined) {
484
+ props.buttonBorderType = options.buttonBorderType;
485
+ }
486
+ if (options.style !== undefined) {
487
+ const style = serializeWalletButtonStyle(options.style);
488
+ if (style) {
489
+ props.style = style;
490
+ }
491
+ }
492
+ return props;
493
+ }
494
+
306
495
  /**
307
496
  * Typed `postMessage` payloads exchanged between the host page and the
308
497
  * embedded Amos iframe.
@@ -336,6 +525,20 @@ export type Message =
336
525
  type: "UPDATE_APPEARANCE";
337
526
  appearance: Appearance;
338
527
  }
528
+ | {
529
+ /**
530
+ * Parent → embed: visual options for the Apple Pay button. Nested
531
+ * under `props` so Apple's `type` attribute does not collide with
532
+ * this message discriminant.
533
+ */
534
+ type: "UPDATE_APPLE_PAY_BUTTON";
535
+ props: ApplePayButtonElementProps;
536
+ }
537
+ | {
538
+ /** Parent → embed: visual options for the Google Pay button. */
539
+ type: "UPDATE_GOOGLE_PAY_BUTTON";
540
+ props: GooglePayButtonElementProps;
541
+ }
339
542
  | {
340
543
  /**
341
544
  * Parent → embed: validate form inputs (`requestId` only).