@dekin_dev/react-checkout 0.1.0 → 0.2.0
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 +25 -4
- package/dist/index.d.ts +34 -5
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +275 -245
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -196,7 +196,26 @@ Gateway webhook ─────────────▶ Merchant backend
|
|
|
196
196
|
Concretely:
|
|
197
197
|
|
|
198
198
|
- None of the built-in providers (Hubtel, Moolre, PaySwitch) have a **documented** `postMessage` protocol for a plain embedded checkout URL, so `onSuccess`/`onFailure`/`onCancel` never fire for them today — this package does not invent gateway behavior that isn't verified. Use `onClose` to prompt the user, then poll or subscribe for your backend's own confirmation (which it gets from the gateway's webhook).
|
|
199
|
-
- For a `custom` provider where you control the checkout page and its `postMessage` contract, `onSuccess`/`onFailure`/`onCancel` fire
|
|
199
|
+
- For a `custom` provider where you control the checkout page and its `postMessage` contract, a message that your `messageHandler` normalizes to `type: "success" | "failure" | "cancel"` automatically swaps the iframe for a **built-in result screen** (✓/✕/↩ + a visible Close button) — you don't need to close the modal yourself. `onSuccess`/`onFailure`/`onCancel` still fire alongside it, but purely as side-effect hooks (refetch order status, analytics, etc.), not as the thing responsible for closing the UI. Still verify server-side before fulfilling an order — a compromised or buggy checkout page could otherwise "confirm" a payment that never happened.
|
|
200
|
+
|
|
201
|
+
### The built-in result screen
|
|
202
|
+
|
|
203
|
+
```tsx
|
|
204
|
+
<Checkout
|
|
205
|
+
provider={{ name: "my-gateway", allowedOrigins: ["https://checkout.mygateway.com"] }}
|
|
206
|
+
checkoutUrl={checkoutUrl}
|
|
207
|
+
open={open}
|
|
208
|
+
onClose={() => setOpen(false)}
|
|
209
|
+
onSuccess={() => refetchOrderStatus()} // side effect only — the modal already shows a result screen
|
|
210
|
+
autoCloseDelay={4000} // optional: close automatically 4s after the result appears
|
|
211
|
+
resultComponent={(result) => <MyResultScreen type={result.type} />} // optional: fully custom UI
|
|
212
|
+
/>
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
- With no configuration at all, a normalized success/failure/cancel message shows a built-in screen with a manual "Close" button — the modal never gets stuck open with no way out.
|
|
216
|
+
- `autoCloseDelay` (milliseconds) is opt-in and unset by default: auto-closing a failure/cancel message before the user has read it can be worse than requiring one click.
|
|
217
|
+
- `resultComponent` fully replaces the built-in screen — it receives the `CheckoutResult` (`{ type: "success" | "failure" | "cancel", message }`) so you can render your own UI per outcome, or one shared view.
|
|
218
|
+
- This only activates for a `custom` provider with `allowedOrigins`/`messageHandler` configured — see the note above about Hubtel/Moolre/PaySwitch having no verified `postMessage` protocol to trigger it from.
|
|
200
219
|
|
|
201
220
|
## Styling — plain CSS or Tailwind
|
|
202
221
|
|
|
@@ -271,7 +290,8 @@ The primary component is `<Checkout />`:
|
|
|
271
290
|
| `provider` | `"hubtel" \| "moolre" \| "payswitch" \| "custom" \| CheckoutProviderConfig` | `"custom"` | |
|
|
272
291
|
| `providerConfig` | `Partial<CheckoutProviderConfig>` | — | overrides merged over the preset |
|
|
273
292
|
| `onOpen` / `onClose` / `onLoad` / `onError` | functions | — | lifecycle callbacks |
|
|
274
|
-
| `onMessage`
|
|
293
|
+
| `onMessage` | function | — | fires for every origin-validated, provider-normalized message |
|
|
294
|
+
| `onSuccess` / `onFailure` / `onCancel` | functions | — | side-effect hooks — the built-in result screen (see above) already handles the UI, these don't need to close the modal |
|
|
275
295
|
| `title` / `description` | `string` | provider default / — | |
|
|
276
296
|
| `showCloseButton` | `boolean` | `true` | |
|
|
277
297
|
| `closeOnOverlayClick` | `boolean` | `true` | |
|
|
@@ -283,12 +303,13 @@ The primary component is `<Checkout />`:
|
|
|
283
303
|
| `zIndex` | `number` | — | |
|
|
284
304
|
| `allow` | `string` | `"payment *"` | iframe `allow` attribute |
|
|
285
305
|
| `sandbox` | `string` | unset | iframe `sandbox` attribute — see note below |
|
|
286
|
-
| `loadingComponent` / `errorComponent` | `ReactNode` \| function | built-in views | |
|
|
306
|
+
| `loadingComponent` / `errorComponent` / `resultComponent` | `ReactNode` \| function | built-in views | `resultComponent` receives a `CheckoutResult` |
|
|
307
|
+
| `autoCloseDelay` | `number` (ms) | unset | auto-close this long after a success/failure/cancel result is shown |
|
|
287
308
|
| `allowInsecureHttp` | `boolean` | `false` | dev-only override for non-HTTPS URLs |
|
|
288
309
|
|
|
289
310
|
`sandbox` is left unset by default because an overly restrictive sandbox (e.g. missing `allow-forms` or `allow-popups` for a bank redirect) can silently break a gateway's checkout flow. Only set it if you've confirmed your gateway's checkout page works within the restrictions you choose.
|
|
290
311
|
|
|
291
|
-
All exported types (`CheckoutProps`, `CheckoutProvider`, `CheckoutProviderConfig`, `CheckoutError`, `CheckoutMessage`, `CheckoutTheme`) and the `validateCheckoutUrl` utility are available from the package root.
|
|
312
|
+
All exported types (`CheckoutProps`, `CheckoutProvider`, `CheckoutProviderConfig`, `CheckoutError`, `CheckoutMessage`, `CheckoutResult`, `CheckoutTheme`) and the `validateCheckoutUrl` utility are available from the package root.
|
|
292
313
|
|
|
293
314
|
## Accessibility
|
|
294
315
|
|
package/dist/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { ReactNode } from 'react';
|
|
|
10
10
|
* events here (including `onSuccess`) must not be treated as final proof
|
|
11
11
|
* of payment.
|
|
12
12
|
*/
|
|
13
|
-
export declare function Checkout({ open, checkoutUrl, provider, providerConfig: providerConfigOverrides, onClose, onOpen, onLoad, onError, onMessage, onSuccess, onFailure, onCancel, title, description, showCloseButton, closeOnOverlayClick, closeOnEscape, width, height, maxWidth, maxHeight, className, iframeClassName, overlayClassName, theme, zIndex, allow, sandbox, loadingComponent, errorComponent, allowInsecureHttp, id, children, }: CheckoutProps): JSX.Element | null;
|
|
13
|
+
export declare function Checkout({ open, checkoutUrl, provider, providerConfig: providerConfigOverrides, onClose, onOpen, onLoad, onError, onMessage, onSuccess, onFailure, onCancel, title, description, showCloseButton, closeOnOverlayClick, closeOnEscape, width, height, maxWidth, maxHeight, className, iframeClassName, overlayClassName, theme, zIndex, allow, sandbox, loadingComponent, errorComponent, resultComponent, autoCloseDelay, allowInsecureHttp, id, children, }: CheckoutProps): JSX.Element | null;
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Convenience wrapper that owns its own `open` state: renders a trigger
|
|
@@ -65,13 +65,16 @@ export declare interface CheckoutProps {
|
|
|
65
65
|
/**
|
|
66
66
|
* Fires only when a provider's `messageHandler` normalizes a message to
|
|
67
67
|
* type `"success"`. No built-in provider does this today — see
|
|
68
|
-
* `src/providers/*.ts`.
|
|
69
|
-
*
|
|
68
|
+
* `src/providers/*.ts`. This is a side-effect hook (refetch order status,
|
|
69
|
+
* analytics, etc.) — the modal already shows a built-in result screen and
|
|
70
|
+
* closes itself (see `resultComponent`/`autoCloseDelay`), so you do not
|
|
71
|
+
* need to call your own close handler here. Never treat this as final
|
|
72
|
+
* proof of payment; verify with your backend.
|
|
70
73
|
*/
|
|
71
74
|
onSuccess?: (message: CheckoutMessage) => void;
|
|
72
|
-
/** Fires only when a provider normalizes a message to type `"failure"`. */
|
|
75
|
+
/** Fires only when a provider normalizes a message to type `"failure"`. Side-effect hook — see `onSuccess`. */
|
|
73
76
|
onFailure?: (message: CheckoutMessage) => void;
|
|
74
|
-
/** Fires only when a provider normalizes a message to type `"cancel"`. */
|
|
77
|
+
/** Fires only when a provider normalizes a message to type `"cancel"`. Side-effect hook — see `onSuccess`. */
|
|
75
78
|
onCancel?: (message: CheckoutMessage) => void;
|
|
76
79
|
title?: string;
|
|
77
80
|
description?: string;
|
|
@@ -93,6 +96,20 @@ export declare interface CheckoutProps {
|
|
|
93
96
|
sandbox?: string;
|
|
94
97
|
loadingComponent?: ReactNode;
|
|
95
98
|
errorComponent?: ReactNode | ((error: CheckoutError) => ReactNode);
|
|
99
|
+
/**
|
|
100
|
+
* Overrides the built-in success/failure/cancel screen shown when a
|
|
101
|
+
* `custom` provider's `messageHandler` reports a terminal outcome. Receive
|
|
102
|
+
* the {@link CheckoutResult} so you can branch on `result.type` yourself,
|
|
103
|
+
* or render one view for all three.
|
|
104
|
+
*/
|
|
105
|
+
resultComponent?: ReactNode | ((result: CheckoutResult) => ReactNode);
|
|
106
|
+
/**
|
|
107
|
+
* Milliseconds to show the result screen before closing automatically.
|
|
108
|
+
* Unset by default — the built-in screen always has a manual close
|
|
109
|
+
* button, and auto-closing a failure/cancel message before the user has
|
|
110
|
+
* read it can be worse than requiring one click.
|
|
111
|
+
*/
|
|
112
|
+
autoCloseDelay?: number;
|
|
96
113
|
/**
|
|
97
114
|
* Allow non-HTTPS checkout URLs. Intended for local development only —
|
|
98
115
|
* never enable this in production.
|
|
@@ -148,6 +165,18 @@ export declare interface CheckoutProviderConfig {
|
|
|
148
165
|
*/
|
|
149
166
|
export declare type CheckoutProviderName = "hubtel" | "moolre" | "payswitch" | "custom";
|
|
150
167
|
|
|
168
|
+
/**
|
|
169
|
+
* A terminal outcome reported by a provider's `messageHandler` (only
|
|
170
|
+
* `custom` providers do this today — see `src/providers/*.ts`). When one of
|
|
171
|
+
* these arrives, the modal automatically swaps the iframe for a result view
|
|
172
|
+
* instead of leaving the developer to close it manually — see
|
|
173
|
+
* `resultComponent`/`autoCloseDelay` on {@link CheckoutProps}.
|
|
174
|
+
*/
|
|
175
|
+
export declare interface CheckoutResult {
|
|
176
|
+
type: "success" | "failure" | "cancel";
|
|
177
|
+
message: CheckoutMessage;
|
|
178
|
+
}
|
|
179
|
+
|
|
151
180
|
export declare type CheckoutTheme = "light" | "dark" | "auto";
|
|
152
181
|
|
|
153
182
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("react/jsx-runtime"),n=require("react"),me=require("react-dom"),C={name:"hubtel",defaultTitle:"Complete Payment",supportsPostMessage:!1,iframeAllow:"payment *"},F={name:"moolre",defaultTitle:"Complete Payment",supportsPostMessage:!1,iframeAllow:"payment *"},K={name:"payswitch",defaultTitle:"Complete Payment",supportsPostMessage:!1,iframeAllow:"payment *"},x={name:"custom",defaultTitle:"Complete Payment",supportsPostMessage:!1},ye={hubtel:C,moolre:F,payswitch:K,custom:x};function V(e,o){let t;return e?typeof e=="string"?t=ye[e]??{...x,name:e}:t={...x,...e}:t=x,o?{...t,...o}:t}const pe=new Set(["javascript:","data:","vbscript:","file:","blob:"]);function G(e,o={}){if(!e||typeof e!="string")return{valid:!1,reason:"A checkoutUrl is required."};let t;try{t=new URL(e)}catch{return{valid:!1,reason:`"${e}" is not a valid URL.`}}return pe.has(t.protocol)?{valid:!1,reason:`Unsafe URL protocol "${t.protocol}" is not allowed.`}:t.protocol!=="https:"&&t.protocol!=="http:"?{valid:!1,reason:`Unsupported URL protocol "${t.protocol}".`}:t.protocol==="http:"&&!o.allowInsecureHttp?{valid:!1,reason:"checkoutUrl must use HTTPS. Pass allowInsecureHttp to override for local development only."}:{valid:!0}}function ve(e,o){return!o||o.length===0?!1:o.some(t=>{try{return new URL(t).origin===e}catch{return t===e}})}function ke(e,o){return function(r){if(!!e.allowedOrigins&&e.allowedOrigins.length>0){if(!ve(r.origin,e.allowedOrigins))return}else if(!e.supportsPostMessage)return;let c=null;if(e.messageHandler)try{c=e.messageHandler(r)}catch{return}else if(r.data&&typeof r.data=="object"){const s=r.data;c={type:typeof s.type=="string"?s.type:"message",provider:e.name,payload:r.data,origin:r.origin}}c&&o({...c,origin:r.origin,raw:r})}}const H=typeof window<"u"&&typeof document<"u";function N(...e){return e.filter(Boolean).join(" ")}let L=0,X="",J="";function be(){if(H){if(L===0){const e=window.innerWidth-document.documentElement.clientWidth;X=document.body.style.overflow,J=document.body.style.paddingRight,document.body.style.overflow="hidden",e>0&&(document.body.style.paddingRight=`${e}px`)}L+=1}}function ge(){H&&(L=Math.max(0,L-1),L===0&&(document.body.style.overflow=X,document.body.style.paddingRight=J))}const we=["a[href]","button:not([disabled])","textarea:not([disabled])","input:not([disabled])","select:not([disabled])","iframe",'[tabindex]:not([tabindex="-1"])'].join(",");function z(e){return Array.from(e.querySelectorAll(we))}function xe(e){return function(t){if(t.key!=="Tab")return;const r=z(e);if(r.length===0){t.preventDefault();return}const i=r[0],c=r[r.length-1],s=document.activeElement;t.shiftKey?(s===i||!e.contains(s))&&(t.preventDefault(),c.focus()):(s===c||!e.contains(s))&&(t.preventDefault(),i.focus())}}function q(e){return typeof e=="number"?`${e}px`:e}function Le({id:e,title:o,description:t,showCloseButton:r,closeOnOverlayClick:i,closeOnEscape:c,onClose:s,width:l,height:f,maxWidth:u,maxHeight:p,className:h,overlayClassName:b,theme:g,zIndex:R,children:I}){const w=n.useRef(null),j=n.useRef(null);n.useEffect(()=>{be(),j.current=document.activeElement;const d=w.current;return d&&(z(d)[0]??d).focus(),()=>{var m,T;ge(),(T=(m=j.current)==null?void 0:m.focus)==null||T.call(m)}},[]),n.useEffect(()=>{if(!c)return;function d(m){m.key==="Escape"&&(m.stopPropagation(),s==null||s())}return document.addEventListener("keydown",d),()=>document.removeEventListener("keydown",d)},[c,s]);function U(d){d.key==="Tab"&&w.current&&xe(w.current)(d.nativeEvent)}function M(d){i&&d.target===d.currentTarget&&(s==null||s())}const E=`${e}-title`,P=t?`${e}-description`:void 0;return a.jsx("div",{className:"vq-checkout-root","data-theme":g,children:a.jsx("div",{className:N("vq-checkout-overlay",b),onMouseDown:M,style:R!==void 0?{zIndex:R}:void 0,children:a.jsxs("div",{ref:w,id:e,role:"dialog","aria-modal":"true","aria-labelledby":o?E:void 0,"aria-label":o?void 0:"Checkout","aria-describedby":P,className:N("vq-checkout-modal",h),style:{width:q(l),height:q(f),maxWidth:q(u),maxHeight:q(p)},tabIndex:-1,onKeyDown:U,children:[(o||t||r)&&a.jsxs("div",{className:"vq-checkout-header",children:[a.jsxs("div",{className:"vq-checkout-heading",children:[o&&a.jsx("h2",{id:E,className:"vq-checkout-title",children:o}),t&&a.jsx("p",{id:P,className:"vq-checkout-description",children:t})]}),r&&a.jsx("button",{type:"button",className:"vq-checkout-close","aria-label":"Close checkout",onClick:()=>s==null?void 0:s(),children:a.jsx("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none","aria-hidden":"true",children:a.jsx("path",{d:"M2 2L14 14M14 2L2 14",stroke:"currentColor",strokeWidth:"1.6",strokeLinecap:"round"})})})]}),a.jsx("div",{className:"vq-checkout-body",children:I})]})})})}function Re({src:e,title:o,className:t,allow:r,sandbox:i,hidden:c,onLoad:s,onError:l}){const f=n.useRef(null),u=n.useRef(s),p=n.useRef(l);return u.current=s,p.current=l,n.useEffect(()=>{const h=f.current;if(!h)return;const b=()=>u.current(),g=()=>p.current();return h.addEventListener("load",b),h.addEventListener("error",g),()=>{h.removeEventListener("load",b),h.removeEventListener("error",g)}},[e]),a.jsx("iframe",{ref:f,src:e,title:o,className:N("vq-checkout-iframe",t),allow:r,sandbox:i,style:c?{position:"absolute",width:0,height:0,opacity:0}:void 0})}function je(){return a.jsxs("div",{className:"vq-checkout-state",role:"status","aria-live":"polite",children:[a.jsx("div",{className:"vq-checkout-spinner","aria-hidden":"true"}),a.jsx("span",{children:"Loading secure checkout..."})]})}function Ee({error:e}){return a.jsxs("div",{className:"vq-checkout-state",role:"alert",children:[a.jsx("div",{className:"vq-checkout-error-icon","aria-hidden":"true",children:"!"}),a.jsx("p",{className:"vq-checkout-error-message",children:e.message})]})}const Pe="min(95vw, 500px)",Te="min(90vh, 750px)",Ae="500px",De="750px",qe="payment *";function B({open:e,checkoutUrl:o,provider:t,providerConfig:r,onClose:i,onOpen:c,onLoad:s,onError:l,onMessage:f,onSuccess:u,onFailure:p,onCancel:h,title:b,description:g,showCloseButton:R=!0,closeOnOverlayClick:I=!0,closeOnEscape:w=!0,width:j=Pe,height:U=Te,maxWidth:M=Ae,maxHeight:E=De,className:P,iframeClassName:d,overlayClassName:m,theme:T="light",zIndex:Q,allow:Y,sandbox:Z,loadingComponent:ee,errorComponent:S,allowInsecureHttp:W,id:te,children:re}){const se=n.useId(),oe=te??`vq-checkout-${se}`,[ne,ae]=n.useState(!1),[A,D]=n.useState("loading"),[_,O]=n.useState(null),$=n.useRef(!1),v=n.useMemo(()=>V(t,r),[t,JSON.stringify(r??{})]);n.useEffect(()=>{ae(!0)},[]),n.useEffect(()=>{e&&!$.current&&(c==null||c()),$.current=e},[e]),n.useEffect(()=>{if(!e)return;const k=G(o,{allowInsecureHttp:W});if(!k.valid){const y={code:"INVALID_URL",message:k.reason??"The provided checkoutUrl is invalid.",provider:v.name};D("error"),O(y),l==null||l(y);return}D("loading"),O(null)},[e,o,W]),n.useEffect(()=>{if(!e||!H)return;const k=ke(v,y=>{f==null||f(y),y.type==="success"?u==null||u(y):y.type==="failure"?p==null||p(y):y.type==="cancel"&&(h==null||h(y))});return window.addEventListener("message",k),()=>window.removeEventListener("message",k)},[e,v,f,u,p,h]);const ce=n.useCallback(()=>{D("loaded"),s==null||s()},[s]),ie=n.useCallback(()=>{const k={code:"IFRAME_LOAD_ERROR",message:"The checkout page could not be loaded.",provider:v.name};D("error"),O(k),l==null||l(k)},[l,v.name]),le=n.useCallback(()=>{i==null||i()},[i]);if(!e||!ne)return null;const ue=b??v.defaultTitle??"Checkout",de=Y??v.iframeAllow??qe,fe=Z??v.iframeSandbox,he=a.jsxs(Le,{id:oe,title:b??v.defaultTitle,description:g,showCloseButton:R,closeOnOverlayClick:I,closeOnEscape:w,onClose:le,width:j,height:U,maxWidth:M,maxHeight:E,className:P,overlayClassName:m,theme:T,zIndex:Q,children:[A==="loading"&&(ee??a.jsx(je,{})),A==="error"&&_&&(typeof S=="function"?S(_):S??a.jsx(Ee,{error:_})),A!=="error"&&a.jsx(Re,{src:o,title:ue,className:d,allow:de,sandbox:fe,hidden:A==="loading",onLoad:ce,onError:ie}),re]});return me.createPortal(he,document.body)}function Ne({children:e,buttonClassName:o,buttonProps:t,onClose:r,...i}){const[c,s]=n.useState(!1);return a.jsxs(a.Fragment,{children:[a.jsx("button",{type:"button",className:N("vq-checkout-trigger",o),onClick:()=>s(!0),...t,children:e}),a.jsx(B,{...i,open:c,onClose:()=>{s(!1),r==null||r()}})]})}function Ie(e){const[o,t]=n.useState(!1),[r,i]=n.useState(null),c=n.useRef(e);c.current=e;const s=n.useCallback(u=>{i({...c.current,...u}),t(!0)},[]),l=n.useCallback(()=>t(!1),[]),f=n.useCallback(()=>r?a.jsx(B,{...r,open:o,onClose:()=>{var u;(u=r.onClose)==null||u.call(r),t(!1)}}):null,[r,o]);return n.useMemo(()=>({openCheckout:s,closeCheckout:l,isOpen:o,CheckoutModal:f}),[s,l,o,f])}exports.Checkout=B;exports.CheckoutButton=Ne;exports.customProviderDefaults=x;exports.hubtelProvider=C;exports.moolreProvider=F;exports.payswitchProvider=K;exports.resolveProviderConfig=V;exports.useCheckout=Ie;exports.validateCheckoutUrl=G;
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("react/jsx-runtime"),a=require("react"),ke=require("react-dom"),J={name:"hubtel",defaultTitle:"Complete Payment",supportsPostMessage:!1,iframeAllow:"payment *"},Y={name:"moolre",defaultTitle:"Complete Payment",supportsPostMessage:!1,iframeAllow:"payment *"},z={name:"payswitch",defaultTitle:"Complete Payment",supportsPostMessage:!1,iframeAllow:"payment *"},j={name:"custom",defaultTitle:"Complete Payment",supportsPostMessage:!1},be={hubtel:J,moolre:Y,payswitch:z,custom:j};function Q(e,r){let t;return e?typeof e=="string"?t=be[e]??{...j,name:e}:t={...j,...e}:t=j,r?{...t,...r}:t}const xe=new Set(["javascript:","data:","vbscript:","file:","blob:"]);function Z(e,r={}){if(!e||typeof e!="string")return{valid:!1,reason:"A checkoutUrl is required."};let t;try{t=new URL(e)}catch{return{valid:!1,reason:`"${e}" is not a valid URL.`}}return xe.has(t.protocol)?{valid:!1,reason:`Unsafe URL protocol "${t.protocol}" is not allowed.`}:t.protocol!=="https:"&&t.protocol!=="http:"?{valid:!1,reason:`Unsupported URL protocol "${t.protocol}".`}:t.protocol==="http:"&&!r.allowInsecureHttp?{valid:!1,reason:"checkoutUrl must use HTTPS. Pass allowInsecureHttp to override for local development only."}:{valid:!0}}function ge(e,r){return!r||r.length===0?!1:r.some(t=>{try{return new URL(t).origin===e}catch{return t===e}})}function we(e,r){return function(c){if(!!e.allowedOrigins&&e.allowedOrigins.length>0){if(!ge(c.origin,e.allowedOrigins))return}else if(!e.supportsPostMessage)return;let o=null;if(e.messageHandler)try{o=e.messageHandler(c)}catch{return}else if(c.data&&typeof c.data=="object"){const n=c.data;o={type:typeof n.type=="string"?n.type:"message",provider:e.name,payload:c.data,origin:c.origin}}o&&r({...o,origin:c.origin,raw:c})}}const W=typeof window<"u"&&typeof document<"u";function U(...e){return e.filter(Boolean).join(" ")}let R=0,C="",ee="";function je(){if(W){if(R===0){const e=window.innerWidth-document.documentElement.clientWidth;C=document.body.style.overflow,ee=document.body.style.paddingRight,document.body.style.overflow="hidden",e>0&&(document.body.style.paddingRight=`${e}px`)}R+=1}}function Re(){W&&(R=Math.max(0,R-1),R===0&&(document.body.style.overflow=C,document.body.style.paddingRight=ee))}const Le=["a[href]","button:not([disabled])","textarea:not([disabled])","input:not([disabled])","select:not([disabled])","iframe",'[tabindex]:not([tabindex="-1"])'].join(",");function te(e){return Array.from(e.querySelectorAll(Le))}function Ee(e){return function(t){if(t.key!=="Tab")return;const c=te(e);if(c.length===0){t.preventDefault();return}const i=c[0],o=c[c.length-1],n=document.activeElement;t.shiftKey?(n===i||!e.contains(n))&&(t.preventDefault(),o.focus()):(n===o||!e.contains(n))&&(t.preventDefault(),i.focus())}}function I(e){return typeof e=="number"?`${e}px`:e}function Pe({id:e,title:r,description:t,showCloseButton:c,closeOnOverlayClick:i,closeOnEscape:o,onClose:n,width:l,height:h,maxWidth:u,maxHeight:p,className:m,overlayClassName:b,theme:x,zIndex:L,children:S}){const g=a.useRef(null),E=a.useRef(null);a.useEffect(()=>{je(),E.current=document.activeElement;const d=g.current;return d&&(te(d)[0]??d).focus(),()=>{var v,q;Re(),(q=(v=E.current)==null?void 0:v.focus)==null||q.call(v)}},[]),a.useEffect(()=>{if(!o)return;function d(v){v.key==="Escape"&&(v.stopPropagation(),n==null||n())}return document.addEventListener("keydown",d),()=>document.removeEventListener("keydown",d)},[o,n]);function M(d){d.key==="Tab"&&g.current&&Ee(g.current)(d.nativeEvent)}function O(d){i&&d.target===d.currentTarget&&(n==null||n())}const P=`${e}-title`,T=t?`${e}-description`:void 0;return s.jsx("div",{className:"vq-checkout-root","data-theme":x,children:s.jsx("div",{className:U("vq-checkout-overlay",b),onMouseDown:O,style:L!==void 0?{zIndex:L}:void 0,children:s.jsxs("div",{ref:g,id:e,role:"dialog","aria-modal":"true","aria-labelledby":r?P:void 0,"aria-label":r?void 0:"Checkout","aria-describedby":T,className:U("vq-checkout-modal",m),style:{width:I(l),height:I(h),maxWidth:I(u),maxHeight:I(p)},tabIndex:-1,onKeyDown:M,children:[(r||t||c)&&s.jsxs("div",{className:"vq-checkout-header",children:[s.jsxs("div",{className:"vq-checkout-heading",children:[r&&s.jsx("h2",{id:P,className:"vq-checkout-title",children:r}),t&&s.jsx("p",{id:T,className:"vq-checkout-description",children:t})]}),c&&s.jsx("button",{type:"button",className:"vq-checkout-close","aria-label":"Close checkout",onClick:()=>n==null?void 0:n(),children:s.jsx("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none","aria-hidden":"true",children:s.jsx("path",{d:"M2 2L14 14M14 2L2 14",stroke:"currentColor",strokeWidth:"1.6",strokeLinecap:"round"})})})]}),s.jsx("div",{className:"vq-checkout-body",children:S})]})})})}function Te({src:e,title:r,className:t,allow:c,sandbox:i,hidden:o,onLoad:n,onError:l}){const h=a.useRef(null),u=a.useRef(n),p=a.useRef(l);return u.current=n,p.current=l,a.useEffect(()=>{const m=h.current;if(!m)return;const b=()=>u.current(),x=()=>p.current();return m.addEventListener("load",b),m.addEventListener("error",x),()=>{m.removeEventListener("load",b),m.removeEventListener("error",x)}},[e]),s.jsx("iframe",{ref:h,src:e,title:r,className:U("vq-checkout-iframe",t),allow:c,sandbox:i,style:o?{position:"absolute",width:0,height:0,opacity:0}:void 0})}function qe(){return s.jsxs("div",{className:"vq-checkout-state",role:"status","aria-live":"polite",children:[s.jsx("div",{className:"vq-checkout-spinner","aria-hidden":"true"}),s.jsx("span",{children:"Loading secure checkout..."})]})}function Ne({error:e}){return s.jsxs("div",{className:"vq-checkout-state",role:"alert",children:[s.jsx("div",{className:"vq-checkout-error-icon","aria-hidden":"true",children:"!"}),s.jsx("p",{className:"vq-checkout-error-message",children:e.message})]})}const Ae={success:{icon:"✓",title:"Payment successful",tone:"success"},failure:{icon:"✕",title:"Payment failed",tone:"failure"},cancel:{icon:"↩",title:"Checkout cancelled",tone:"cancel"}};function De({result:e,onClose:r}){const t=Ae[e.type];return s.jsxs("div",{className:"vq-checkout-state",role:e.type==="failure"?"alert":"status","aria-live":"polite",children:[s.jsx("div",{className:`vq-checkout-result-icon vq-checkout-result-icon--${t.tone}`,"aria-hidden":"true",children:t.icon}),s.jsx("p",{className:"vq-checkout-error-message",children:t.title}),s.jsx("button",{type:"button",className:"vq-checkout-result-action",onClick:()=>r==null?void 0:r(),children:"Close"})]})}const Ie="min(95vw, 500px)",Ue="min(90vh, 750px)",Se="500px",Me="750px",Oe="payment *";function K({open:e,checkoutUrl:r,provider:t,providerConfig:c,onClose:i,onOpen:o,onLoad:n,onError:l,onMessage:h,onSuccess:u,onFailure:p,onCancel:m,title:b,description:x,showCloseButton:L=!0,closeOnOverlayClick:S=!0,closeOnEscape:g=!0,width:E=Ie,height:M=Ue,maxWidth:O=Se,maxHeight:P=Me,className:T,iframeClassName:d,overlayClassName:v,theme:q="light",zIndex:re,allow:se,sandbox:ce,loadingComponent:ne,errorComponent:_,resultComponent:H,autoCloseDelay:$,allowInsecureHttp:V,id:ae,children:oe}){const ie=a.useId(),le=ae??`vq-checkout-${ie}`,[ue,de]=a.useState(!1),[N,A]=a.useState("loading"),[B,F]=a.useState(null),[w,D]=a.useState(null),G=a.useRef(!1),k=a.useMemo(()=>Q(t,c),[t,JSON.stringify(c??{})]);a.useEffect(()=>{de(!0)},[]),a.useEffect(()=>{e&&!G.current&&(o==null||o()),G.current=e},[e]),a.useEffect(()=>{if(!e)return;D(null);const y=Z(r,{allowInsecureHttp:V});if(!y.valid){const f={code:"INVALID_URL",message:y.reason??"The provided checkoutUrl is invalid.",provider:k.name};A("error"),F(f),l==null||l(f);return}A("loading"),F(null)},[e,r,V]),a.useEffect(()=>{if(!e||!W)return;const y=we(k,f=>{h==null||h(f),f.type==="success"?(D({type:"success",message:f}),u==null||u(f)):f.type==="failure"?(D({type:"failure",message:f}),p==null||p(f)):f.type==="cancel"&&(D({type:"cancel",message:f}),m==null||m(f))});return window.addEventListener("message",y),()=>window.removeEventListener("message",y)},[e,k,h,u,p,m]);const fe=a.useCallback(()=>{A("loaded"),n==null||n()},[n]),he=a.useCallback(()=>{const y={code:"IFRAME_LOAD_ERROR",message:"The checkout page could not be loaded.",provider:k.name};A("error"),F(y),l==null||l(y)},[l,k.name]),X=a.useCallback(()=>{i==null||i()},[i]);if(a.useEffect(()=>{if(!w||$===void 0)return;const y=setTimeout(()=>i==null?void 0:i(),$);return()=>clearTimeout(y)},[w,$,i]),!e||!ue)return null;const me=b??k.defaultTitle??"Checkout",ve=se??k.iframeAllow??Oe,ye=ce??k.iframeSandbox,pe=s.jsxs(Pe,{id:le,title:b??k.defaultTitle,description:x,showCloseButton:L,closeOnOverlayClick:S,closeOnEscape:g,onClose:X,width:E,height:M,maxWidth:O,maxHeight:P,className:T,overlayClassName:v,theme:q,zIndex:re,children:[w?typeof H=="function"?H(w):H??s.jsx(De,{result:w,onClose:X}):s.jsxs(s.Fragment,{children:[N==="loading"&&(ne??s.jsx(qe,{})),N==="error"&&B&&(typeof _=="function"?_(B):_??s.jsx(Ne,{error:B})),N!=="error"&&s.jsx(Te,{src:r,title:me,className:d,allow:ve,sandbox:ye,hidden:N==="loading",onLoad:fe,onError:he})]}),oe]});return ke.createPortal(pe,document.body)}function _e({children:e,buttonClassName:r,buttonProps:t,onClose:c,...i}){const[o,n]=a.useState(!1);return s.jsxs(s.Fragment,{children:[s.jsx("button",{type:"button",className:U("vq-checkout-trigger",r),onClick:()=>n(!0),...t,children:e}),s.jsx(K,{...i,open:o,onClose:()=>{n(!1),c==null||c()}})]})}function He(e){const[r,t]=a.useState(!1),[c,i]=a.useState(null),o=a.useRef(e);o.current=e;const n=a.useCallback(u=>{i({...o.current,...u}),t(!0)},[]),l=a.useCallback(()=>t(!1),[]),h=a.useCallback(()=>c?s.jsx(K,{...c,open:r,onClose:()=>{var u;(u=c.onClose)==null||u.call(c),t(!1)}}):null,[c,r]);return a.useMemo(()=>({openCheckout:n,closeCheckout:l,isOpen:r,CheckoutModal:h}),[n,l,r,h])}exports.Checkout=K;exports.CheckoutButton=_e;exports.customProviderDefaults=j;exports.hubtelProvider=J;exports.moolreProvider=Y;exports.payswitchProvider=z;exports.resolveProviderConfig=Q;exports.useCheckout=He;exports.validateCheckoutUrl=Z;
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/providers/hubtel.ts","../src/providers/moolre.ts","../src/providers/payswitch.ts","../src/providers/custom.ts","../src/providers/index.ts","../src/utils/url.ts","../src/utils/messages.ts","../src/utils/browser.ts","../src/utils/classNames.ts","../src/utils/bodyScroll.ts","../src/utils/focusTrap.ts","../src/components/CheckoutModal.tsx","../src/components/CheckoutIframe.tsx","../src/components/CheckoutLoader.tsx","../src/components/CheckoutErrorView.tsx","../src/components/Checkout.tsx","../src/components/CheckoutButton.tsx","../src/hooks/useCheckout.tsx"],"sourcesContent":["import type { CheckoutProviderConfig } from \"../types\";\n\n/**\n * Hubtel — Online Checkout.\n *\n * Verified (from Hubtel's public API reference for the checkout-URL\n * initiation endpoint): the checkout URL flow is redirect + server webhook\n * based. The merchant backend calls Hubtel's initiate endpoint with a\n * `callbackUrl` (server-to-server webhook) and a `returnUrl` /\n * `cancellationUrl` (browser redirect targets), then sends the customer to\n * the resulting checkout URL.\n *\n * UNVERIFIED: Hubtel's public docs do not document a `window.postMessage`\n * protocol for a checkout URL embedded via a plain iframe (as opposed to\n * their separate `@hubteljs/checkout` SDK, which manages its own iframe and\n * bridge internally and is a different integration path from \"embed a URL\n * you already have\"). `supportsPostMessage` is therefore left `false` here\n * — do not flip it on without a citation. Rely on `returnUrl`/`callbackUrl`\n * plus backend verification instead of any frontend \"success\" signal.\n */\nexport const hubtelProvider: CheckoutProviderConfig = {\n name: \"hubtel\",\n defaultTitle: \"Complete Payment\",\n supportsPostMessage: false,\n iframeAllow: \"payment *\",\n};\n","import type { CheckoutProviderConfig } from \"../types\";\n\n/**\n * Moolre — Checkout / Collections.\n *\n * UNVERIFIED: Moolre's public API docs (docs.moolre.com) were not\n * accessible as static, readable content at the time this adapter was\n * written, so no `postMessage` protocol, allowed origins, or iframe\n * embedding policy could be confirmed. `supportsPostMessage` is left\n * `false` and no `messageHandler` is provided — do not assume behavior that\n * hasn't been verified against Moolre's own documentation. Rely on the\n * redirect/callback URLs you configure server-side plus backend\n * verification instead of any frontend \"success\" signal.\n */\nexport const moolreProvider: CheckoutProviderConfig = {\n name: \"moolre\",\n defaultTitle: \"Complete Payment\",\n supportsPostMessage: false,\n iframeAllow: \"payment *\",\n};\n","import type { CheckoutProviderConfig } from \"../types\";\n\n/**\n * PaySwitch — PayLink / hosted checkout.\n *\n * UNVERIFIED: PaySwitch's public docs describe PayLink (payment links/QR)\n * and the TheTeller processing API, but no `postMessage` protocol, allowed\n * origins, or iframe embedding policy for a generically embedded checkout\n * URL could be confirmed from accessible documentation. `supportsPostMessage`\n * is left `false` — do not assume behavior that hasn't been verified. Rely\n * on the redirect/callback URLs you configure server-side plus backend\n * verification instead of any frontend \"success\" signal.\n */\nexport const payswitchProvider: CheckoutProviderConfig = {\n name: \"payswitch\",\n defaultTitle: \"Complete Payment\",\n supportsPostMessage: false,\n iframeAllow: \"payment *\",\n};\n","import type { CheckoutProviderConfig } from \"../types\";\n\n/**\n * Fallback used for `provider=\"custom\"` with no inline config, and as the\n * base merged under any user-supplied {@link CheckoutProviderConfig}.\n * Intentionally trusts nothing by default: no allowed origins and\n * `supportsPostMessage: false`, so postMessage events are ignored unless the\n * developer explicitly configures otherwise.\n */\nexport const customProviderDefaults: CheckoutProviderConfig = {\n name: \"custom\",\n defaultTitle: \"Complete Payment\",\n supportsPostMessage: false,\n};\n","import type { CheckoutProvider, CheckoutProviderConfig } from \"../types\";\nimport { hubtelProvider } from \"./hubtel\";\nimport { moolreProvider } from \"./moolre\";\nimport { payswitchProvider } from \"./payswitch\";\nimport { customProviderDefaults } from \"./custom\";\n\nconst BUILT_IN_PROVIDERS: Record<string, CheckoutProviderConfig> = {\n hubtel: hubtelProvider,\n moolre: moolreProvider,\n payswitch: payswitchProvider,\n custom: customProviderDefaults,\n};\n\n/**\n * Resolves the `provider` + `providerConfig` props into one concrete\n * {@link CheckoutProviderConfig}. Accepts either a built-in preset name or\n * an inline config object (for gateways that aren't built in), and merges\n * any `providerConfig` overrides on top.\n */\nexport function resolveProviderConfig(\n provider: CheckoutProvider | undefined,\n overrides?: Partial<CheckoutProviderConfig>,\n): CheckoutProviderConfig {\n let base: CheckoutProviderConfig;\n\n if (!provider) {\n base = customProviderDefaults;\n } else if (typeof provider === \"string\") {\n base = BUILT_IN_PROVIDERS[provider] ?? { ...customProviderDefaults, name: provider };\n } else {\n base = { ...customProviderDefaults, ...provider };\n }\n\n return overrides ? { ...base, ...overrides } : base;\n}\n\nexport { hubtelProvider, moolreProvider, payswitchProvider, customProviderDefaults };\nexport type { CheckoutProvider, CheckoutProviderConfig } from \"../types\";\n","export interface UrlValidationOptions {\n /** Allow `http:` URLs. Intended for local development only. */\n allowInsecureHttp?: boolean;\n}\n\nexport interface UrlValidationResult {\n valid: boolean;\n reason?: string;\n}\n\nconst UNSAFE_PROTOCOLS = new Set([\"javascript:\", \"data:\", \"vbscript:\", \"file:\", \"blob:\"]);\n\n/**\n * Validates a gateway checkout URL before it is ever placed in an iframe's\n * `src`. Rejects non-URLs, script-injection protocols, and (by default)\n * plain `http:` URLs.\n */\nexport function validateCheckoutUrl(\n url: string,\n options: UrlValidationOptions = {},\n): UrlValidationResult {\n if (!url || typeof url !== \"string\") {\n return { valid: false, reason: \"A checkoutUrl is required.\" };\n }\n\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return { valid: false, reason: `\"${url}\" is not a valid URL.` };\n }\n\n if (UNSAFE_PROTOCOLS.has(parsed.protocol)) {\n return { valid: false, reason: `Unsafe URL protocol \"${parsed.protocol}\" is not allowed.` };\n }\n\n if (parsed.protocol !== \"https:\" && parsed.protocol !== \"http:\") {\n return { valid: false, reason: `Unsupported URL protocol \"${parsed.protocol}\".` };\n }\n\n if (parsed.protocol === \"http:\" && !options.allowInsecureHttp) {\n return {\n valid: false,\n reason:\n 'checkoutUrl must use HTTPS. Pass allowInsecureHttp to override for local development only.',\n };\n }\n\n return { valid: true };\n}\n\n/** Compares an event origin against a provider's allow-list of origins. */\nexport function isOriginAllowed(origin: string, allowedOrigins?: string[]): boolean {\n if (!allowedOrigins || allowedOrigins.length === 0) return false;\n\n return allowedOrigins.some((allowed) => {\n try {\n return new URL(allowed).origin === origin;\n } catch {\n return allowed === origin;\n }\n });\n}\n","import type { CheckoutMessage, CheckoutProviderConfig } from \"../types\";\nimport { isOriginAllowed } from \"./url\";\n\n/**\n * Builds a `message` event handler scoped to one provider config. Never\n * treat an unvalidated message as a payment outcome:\n *\n * - If the provider declares `allowedOrigins`, messages from any other\n * origin are dropped silently.\n * - If it declares no `allowedOrigins` AND does not set\n * `supportsPostMessage: true`, ALL messages are dropped — an unconfigured\n * provider must opt in before we trust anything it says.\n * - The provider's own `messageHandler` decides how to normalize (or\n * reject, by returning `null`) the raw event payload.\n */\nexport function createMessageListener(\n providerConfig: CheckoutProviderConfig,\n onMessage: (message: CheckoutMessage) => void,\n): (event: MessageEvent) => void {\n return function handleMessage(event: MessageEvent): void {\n const hasAllowList = !!providerConfig.allowedOrigins && providerConfig.allowedOrigins.length > 0;\n\n if (hasAllowList) {\n if (!isOriginAllowed(event.origin, providerConfig.allowedOrigins)) return;\n } else if (!providerConfig.supportsPostMessage) {\n return;\n }\n\n let normalized: CheckoutMessage | null = null;\n\n if (providerConfig.messageHandler) {\n try {\n normalized = providerConfig.messageHandler(event);\n } catch {\n return;\n }\n } else if (event.data && typeof event.data === \"object\") {\n const data = event.data as Record<string, unknown>;\n normalized = {\n type: typeof data.type === \"string\" ? data.type : \"message\",\n provider: providerConfig.name,\n payload: event.data,\n origin: event.origin,\n };\n }\n\n if (!normalized) return;\n\n onMessage({ ...normalized, origin: event.origin, raw: event });\n };\n}\n","/**\n * `true` only when running in an environment with a real DOM. Safe to read\n * at module scope (no SSR crash) — never gate behavior on `window`/`document`\n * directly outside effects or event handlers.\n */\nexport const isBrowser: boolean = typeof window !== \"undefined\" && typeof document !== \"undefined\";\n","export function cx(...classes: Array<string | false | null | undefined>): string {\n return classes.filter(Boolean).join(\" \");\n}\n","import { isBrowser } from \"./browser\";\n\nlet lockCount = 0;\nlet originalOverflow = \"\";\nlet originalPaddingRight = \"\";\n\n/**\n * Locks page scroll while a checkout modal is open. Reference-counted so\n * multiple modals (or re-renders) nest safely — the original styles are\n * only restored once every lock has been released.\n */\nexport function lockBodyScroll(): void {\n if (!isBrowser) return;\n\n if (lockCount === 0) {\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n originalOverflow = document.body.style.overflow;\n originalPaddingRight = document.body.style.paddingRight;\n document.body.style.overflow = \"hidden\";\n if (scrollbarWidth > 0) {\n document.body.style.paddingRight = `${scrollbarWidth}px`;\n }\n }\n\n lockCount += 1;\n}\n\nexport function unlockBodyScroll(): void {\n if (!isBrowser) return;\n\n lockCount = Math.max(0, lockCount - 1);\n\n if (lockCount === 0) {\n document.body.style.overflow = originalOverflow;\n document.body.style.paddingRight = originalPaddingRight;\n }\n}\n","const FOCUSABLE_SELECTOR = [\n \"a[href]\",\n \"button:not([disabled])\",\n \"textarea:not([disabled])\",\n \"input:not([disabled])\",\n \"select:not([disabled])\",\n \"iframe\",\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(\",\");\n\n/** Returns focusable descendants of `container`, in DOM order. */\nexport function getFocusableElements(container: HTMLElement): HTMLElement[] {\n return Array.from(container.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR));\n}\n\n/**\n * Keeps Tab/Shift+Tab cycling within `container`. Returns a keydown handler\n * to attach to the container; does nothing for non-Tab keys.\n */\nexport function createFocusTrapHandler(container: HTMLElement) {\n return function handleKeyDown(event: KeyboardEvent): void {\n if (event.key !== \"Tab\") return;\n\n const focusable = getFocusableElements(container);\n if (focusable.length === 0) {\n event.preventDefault();\n return;\n }\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n const active = document.activeElement;\n\n if (event.shiftKey) {\n if (active === first || !container.contains(active)) {\n event.preventDefault();\n last.focus();\n }\n } else if (active === last || !container.contains(active)) {\n event.preventDefault();\n first.focus();\n }\n };\n}\n","import { useEffect, useRef, type ReactNode } from \"react\";\nimport { cx } from \"../utils/classNames\";\nimport { lockBodyScroll, unlockBodyScroll } from \"../utils/bodyScroll\";\nimport { createFocusTrapHandler, getFocusableElements } from \"../utils/focusTrap\";\nimport type { CheckoutTheme } from \"../types\";\n\nexport interface CheckoutModalProps {\n id: string;\n title?: string;\n description?: string;\n showCloseButton: boolean;\n closeOnOverlayClick: boolean;\n closeOnEscape: boolean;\n onClose?: () => void;\n width: string | number;\n height: string | number;\n maxWidth: string | number;\n maxHeight: string | number;\n className?: string;\n overlayClassName?: string;\n theme: CheckoutTheme;\n zIndex?: number;\n children: ReactNode;\n}\n\nfunction toDimension(value: string | number): string {\n return typeof value === \"number\" ? `${value}px` : value;\n}\n\nexport function CheckoutModal({\n id,\n title,\n description,\n showCloseButton,\n closeOnOverlayClick,\n closeOnEscape,\n onClose,\n width,\n height,\n maxWidth,\n maxHeight,\n className,\n overlayClassName,\n theme,\n zIndex,\n children,\n}: CheckoutModalProps): JSX.Element {\n const modalRef = useRef<HTMLDivElement>(null);\n const previouslyFocusedRef = useRef<HTMLElement | null>(null);\n\n useEffect(() => {\n lockBodyScroll();\n previouslyFocusedRef.current = document.activeElement as HTMLElement | null;\n\n const container = modalRef.current;\n if (container) {\n const focusable = getFocusableElements(container);\n (focusable[0] ?? container).focus();\n }\n\n return () => {\n unlockBodyScroll();\n previouslyFocusedRef.current?.focus?.();\n };\n }, []);\n\n useEffect(() => {\n if (!closeOnEscape) return;\n\n function handleKeyDown(event: KeyboardEvent): void {\n if (event.key === \"Escape\") {\n event.stopPropagation();\n onClose?.();\n }\n }\n\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [closeOnEscape, onClose]);\n\n function handleContainerKeyDown(event: React.KeyboardEvent<HTMLDivElement>): void {\n if (event.key === \"Tab\" && modalRef.current) {\n createFocusTrapHandler(modalRef.current)(event.nativeEvent);\n }\n }\n\n function handleOverlayMouseDown(event: React.MouseEvent<HTMLDivElement>): void {\n if (closeOnOverlayClick && event.target === event.currentTarget) {\n onClose?.();\n }\n }\n\n const titleId = `${id}-title`;\n const descriptionId = description ? `${id}-description` : undefined;\n\n return (\n <div className=\"vq-checkout-root\" data-theme={theme}>\n <div\n className={cx(\"vq-checkout-overlay\", overlayClassName)}\n onMouseDown={handleOverlayMouseDown}\n style={zIndex !== undefined ? { zIndex } : undefined}\n >\n <div\n ref={modalRef}\n id={id}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={title ? titleId : undefined}\n aria-label={title ? undefined : \"Checkout\"}\n aria-describedby={descriptionId}\n className={cx(\"vq-checkout-modal\", className)}\n style={{\n width: toDimension(width),\n height: toDimension(height),\n maxWidth: toDimension(maxWidth),\n maxHeight: toDimension(maxHeight),\n }}\n tabIndex={-1}\n onKeyDown={handleContainerKeyDown}\n >\n {(title || description || showCloseButton) && (\n <div className=\"vq-checkout-header\">\n <div className=\"vq-checkout-heading\">\n {title && (\n <h2 id={titleId} className=\"vq-checkout-title\">\n {title}\n </h2>\n )}\n {description && (\n <p id={descriptionId} className=\"vq-checkout-description\">\n {description}\n </p>\n )}\n </div>\n {showCloseButton && (\n <button\n type=\"button\"\n className=\"vq-checkout-close\"\n aria-label=\"Close checkout\"\n onClick={() => onClose?.()}\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M2 2L14 14M14 2L2 14\"\n stroke=\"currentColor\"\n strokeWidth=\"1.6\"\n strokeLinecap=\"round\"\n />\n </svg>\n </button>\n )}\n </div>\n )}\n <div className=\"vq-checkout-body\">{children}</div>\n </div>\n </div>\n </div>\n );\n}\n","import { useEffect, useRef } from \"react\";\nimport { cx } from \"../utils/classNames\";\n\nexport interface CheckoutIframeProps {\n src: string;\n title: string;\n className?: string;\n allow?: string;\n sandbox?: string;\n hidden?: boolean;\n onLoad: () => void;\n onError: () => void;\n}\n\n/**\n * React never attaches a listener for the native `error` event on\n * `<iframe>` (it only special-cases `img`/`source`/`link` for `error`, and\n * `iframe`/`object`/`embed` only get `load` — see react-dom's\n * `setInitialProperties`). An `onError` prop here would therefore silently\n * never fire in any browser, so both events are wired via a native\n * `addEventListener` on the underlying node instead.\n */\nexport function CheckoutIframe({\n src,\n title,\n className,\n allow,\n sandbox,\n hidden,\n onLoad,\n onError,\n}: CheckoutIframeProps): JSX.Element {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const onLoadRef = useRef(onLoad);\n const onErrorRef = useRef(onError);\n onLoadRef.current = onLoad;\n onErrorRef.current = onError;\n\n useEffect(() => {\n const iframe = iframeRef.current;\n if (!iframe) return;\n\n const handleLoad = () => onLoadRef.current();\n const handleError = () => onErrorRef.current();\n\n iframe.addEventListener(\"load\", handleLoad);\n iframe.addEventListener(\"error\", handleError);\n\n return () => {\n iframe.removeEventListener(\"load\", handleLoad);\n iframe.removeEventListener(\"error\", handleError);\n };\n }, [src]);\n\n return (\n <iframe\n ref={iframeRef}\n src={src}\n title={title}\n className={cx(\"vq-checkout-iframe\", className)}\n allow={allow}\n sandbox={sandbox}\n style={hidden ? { position: \"absolute\", width: 0, height: 0, opacity: 0 } : undefined}\n />\n );\n}\n","export function CheckoutLoader(): JSX.Element {\n return (\n <div className=\"vq-checkout-state\" role=\"status\" aria-live=\"polite\">\n <div className=\"vq-checkout-spinner\" aria-hidden=\"true\" />\n <span>Loading secure checkout...</span>\n </div>\n );\n}\n","import type { CheckoutError } from \"../types\";\n\nexport interface CheckoutErrorViewProps {\n error: CheckoutError;\n}\n\nexport function CheckoutErrorView({ error }: CheckoutErrorViewProps): JSX.Element {\n return (\n <div className=\"vq-checkout-state\" role=\"alert\">\n <div className=\"vq-checkout-error-icon\" aria-hidden=\"true\">\n !\n </div>\n <p className=\"vq-checkout-error-message\">{error.message}</p>\n </div>\n );\n}\n","import { useCallback, useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport type { CheckoutError, CheckoutProps } from \"../types\";\nimport { resolveProviderConfig } from \"../providers\";\nimport { validateCheckoutUrl } from \"../utils/url\";\nimport { createMessageListener } from \"../utils/messages\";\nimport { isBrowser } from \"../utils/browser\";\nimport { CheckoutModal } from \"./CheckoutModal\";\nimport { CheckoutIframe } from \"./CheckoutIframe\";\nimport { CheckoutLoader } from \"./CheckoutLoader\";\nimport { CheckoutErrorView } from \"./CheckoutErrorView\";\n\ntype Status = \"loading\" | \"loaded\" | \"error\";\n\nconst DEFAULT_WIDTH = \"min(95vw, 500px)\";\nconst DEFAULT_HEIGHT = \"min(90vh, 750px)\";\nconst DEFAULT_MAX_WIDTH = \"500px\";\nconst DEFAULT_MAX_HEIGHT = \"750px\";\nconst DEFAULT_ALLOW = \"payment *\";\n\n/**\n * A modal/iframe checkout for embedding a gateway-hosted checkout page.\n *\n * `checkoutUrl` must come from your backend's own integration with the\n * payment provider's API — this component never talks to a gateway\n * directly and never needs API keys. See the README for why frontend\n * events here (including `onSuccess`) must not be treated as final proof\n * of payment.\n */\nexport function Checkout({\n open,\n checkoutUrl,\n provider,\n providerConfig: providerConfigOverrides,\n onClose,\n onOpen,\n onLoad,\n onError,\n onMessage,\n onSuccess,\n onFailure,\n onCancel,\n title,\n description,\n showCloseButton = true,\n closeOnOverlayClick = true,\n closeOnEscape = true,\n width = DEFAULT_WIDTH,\n height = DEFAULT_HEIGHT,\n maxWidth = DEFAULT_MAX_WIDTH,\n maxHeight = DEFAULT_MAX_HEIGHT,\n className,\n iframeClassName,\n overlayClassName,\n theme = \"light\",\n zIndex,\n allow,\n sandbox,\n loadingComponent,\n errorComponent,\n allowInsecureHttp,\n id,\n children,\n}: CheckoutProps): JSX.Element | null {\n const generatedId = useId();\n const modalId = id ?? `vq-checkout-${generatedId}`;\n\n const [mounted, setMounted] = useState(false);\n const [status, setStatus] = useState<Status>(\"loading\");\n const [error, setError] = useState<CheckoutError | null>(null);\n const wasOpenRef = useRef(false);\n\n const resolvedProvider = useMemo(\n () => resolveProviderConfig(provider, providerConfigOverrides),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [provider, JSON.stringify(providerConfigOverrides ?? {})],\n );\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n if (open && !wasOpenRef.current) {\n onOpen?.();\n }\n wasOpenRef.current = open;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open]);\n\n useEffect(() => {\n if (!open) return;\n\n const result = validateCheckoutUrl(checkoutUrl, { allowInsecureHttp });\n if (!result.valid) {\n const invalidUrlError: CheckoutError = {\n code: \"INVALID_URL\",\n message: result.reason ?? \"The provided checkoutUrl is invalid.\",\n provider: resolvedProvider.name,\n };\n setStatus(\"error\");\n setError(invalidUrlError);\n onError?.(invalidUrlError);\n return;\n }\n\n setStatus(\"loading\");\n setError(null);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open, checkoutUrl, allowInsecureHttp]);\n\n useEffect(() => {\n if (!open || !isBrowser) return;\n\n const listener = createMessageListener(resolvedProvider, (message) => {\n onMessage?.(message);\n if (message.type === \"success\") onSuccess?.(message);\n else if (message.type === \"failure\") onFailure?.(message);\n else if (message.type === \"cancel\") onCancel?.(message);\n });\n\n window.addEventListener(\"message\", listener);\n return () => window.removeEventListener(\"message\", listener);\n }, [open, resolvedProvider, onMessage, onSuccess, onFailure, onCancel]);\n\n const handleIframeLoad = useCallback(() => {\n setStatus(\"loaded\");\n onLoad?.();\n }, [onLoad]);\n\n const handleIframeError = useCallback(() => {\n const loadError: CheckoutError = {\n code: \"IFRAME_LOAD_ERROR\",\n message: \"The checkout page could not be loaded.\",\n provider: resolvedProvider.name,\n };\n setStatus(\"error\");\n setError(loadError);\n onError?.(loadError);\n }, [onError, resolvedProvider.name]);\n\n const handleClose = useCallback(() => {\n onClose?.();\n }, [onClose]);\n\n if (!open || !mounted) return null;\n\n const iframeTitle = title ?? resolvedProvider.defaultTitle ?? \"Checkout\";\n const resolvedAllow = allow ?? resolvedProvider.iframeAllow ?? DEFAULT_ALLOW;\n const resolvedSandbox = sandbox ?? resolvedProvider.iframeSandbox;\n\n const modal = (\n <CheckoutModal\n id={modalId}\n title={title ?? resolvedProvider.defaultTitle}\n description={description}\n showCloseButton={showCloseButton}\n closeOnOverlayClick={closeOnOverlayClick}\n closeOnEscape={closeOnEscape}\n onClose={handleClose}\n width={width}\n height={height}\n maxWidth={maxWidth}\n maxHeight={maxHeight}\n className={className}\n overlayClassName={overlayClassName}\n theme={theme}\n zIndex={zIndex}\n >\n {status === \"loading\" && (loadingComponent ?? <CheckoutLoader />)}\n {status === \"error\" &&\n error &&\n (typeof errorComponent === \"function\"\n ? errorComponent(error)\n : errorComponent ?? <CheckoutErrorView error={error} />)}\n {status !== \"error\" && (\n <CheckoutIframe\n src={checkoutUrl}\n title={iframeTitle}\n className={iframeClassName}\n allow={resolvedAllow}\n sandbox={resolvedSandbox}\n hidden={status === \"loading\"}\n onLoad={handleIframeLoad}\n onError={handleIframeError}\n />\n )}\n {children}\n </CheckoutModal>\n );\n\n return createPortal(modal, document.body);\n}\n","import { useState, type ButtonHTMLAttributes, type ReactNode } from \"react\";\nimport { cx } from \"../utils/classNames\";\nimport { Checkout } from \"./Checkout\";\nimport type { CheckoutProps } from \"../types\";\n\nexport interface CheckoutButtonProps extends Omit<CheckoutProps, \"open\"> {\n children: ReactNode;\n buttonClassName?: string;\n buttonProps?: Omit<ButtonHTMLAttributes<HTMLButtonElement>, \"onClick\" | \"type\" | \"className\">;\n}\n\n/**\n * Convenience wrapper that owns its own `open` state: renders a trigger\n * button and the {@link Checkout} modal together, for when you don't need\n * to control the open state yourself.\n */\nexport function CheckoutButton({\n children,\n buttonClassName,\n buttonProps,\n onClose,\n ...checkoutProps\n}: CheckoutButtonProps): JSX.Element {\n const [open, setOpen] = useState(false);\n\n return (\n <>\n <button\n type=\"button\"\n className={cx(\"vq-checkout-trigger\", buttonClassName)}\n onClick={() => setOpen(true)}\n {...buttonProps}\n >\n {children}\n </button>\n <Checkout\n {...checkoutProps}\n open={open}\n onClose={() => {\n setOpen(false);\n onClose?.();\n }}\n />\n </>\n );\n}\n","import { useCallback, useMemo, useRef, useState } from \"react\";\nimport { Checkout } from \"../components/Checkout\";\nimport type { CheckoutProps } from \"../types\";\n\nexport type OpenCheckoutOptions = Omit<CheckoutProps, \"open\">;\n\nexport interface UseCheckoutResult {\n /** Opens the checkout modal with the given options. */\n openCheckout: (options: OpenCheckoutOptions) => void;\n closeCheckout: () => void;\n isOpen: boolean;\n /** Render this once, wherever the modal should live in the tree. */\n CheckoutModal: () => JSX.Element | null;\n}\n\n/**\n * Imperative alternative to rendering `<Checkout open={...} />` yourself.\n * Keeps the simple `<Checkout />` component as the primary API — this is an\n * optional convenience for call-site-driven flows (e.g. \"Pay Now\" inside a\n * list where mounting a modal per row would be wasteful).\n */\nexport function useCheckout(defaultOptions?: Partial<OpenCheckoutOptions>): UseCheckoutResult {\n const [isOpen, setIsOpen] = useState(false);\n const [options, setOptions] = useState<OpenCheckoutOptions | null>(null);\n const defaultsRef = useRef(defaultOptions);\n defaultsRef.current = defaultOptions;\n\n const openCheckout = useCallback((next: OpenCheckoutOptions) => {\n setOptions({ ...defaultsRef.current, ...next });\n setIsOpen(true);\n }, []);\n\n const closeCheckout = useCallback(() => setIsOpen(false), []);\n\n const CheckoutModalComponent = useCallback((): JSX.Element | null => {\n if (!options) return null;\n\n return (\n <Checkout\n {...options}\n open={isOpen}\n onClose={() => {\n options.onClose?.();\n setIsOpen(false);\n }}\n />\n );\n }, [options, isOpen]);\n\n return useMemo(\n () => ({ openCheckout, closeCheckout, isOpen, CheckoutModal: CheckoutModalComponent }),\n [openCheckout, closeCheckout, isOpen, CheckoutModalComponent],\n );\n}\n"],"names":["hubtelProvider","moolreProvider","payswitchProvider","customProviderDefaults","BUILT_IN_PROVIDERS","resolveProviderConfig","provider","overrides","base","UNSAFE_PROTOCOLS","validateCheckoutUrl","url","options","parsed","isOriginAllowed","origin","allowedOrigins","allowed","createMessageListener","providerConfig","onMessage","event","normalized","data","isBrowser","cx","classes","lockCount","originalOverflow","originalPaddingRight","lockBodyScroll","scrollbarWidth","unlockBodyScroll","FOCUSABLE_SELECTOR","getFocusableElements","container","createFocusTrapHandler","focusable","first","last","active","toDimension","value","CheckoutModal","id","title","description","showCloseButton","closeOnOverlayClick","closeOnEscape","onClose","width","height","maxWidth","maxHeight","className","overlayClassName","theme","zIndex","children","modalRef","useRef","previouslyFocusedRef","useEffect","_b","_a","handleKeyDown","handleContainerKeyDown","handleOverlayMouseDown","titleId","descriptionId","jsx","jsxs","CheckoutIframe","src","allow","sandbox","hidden","onLoad","onError","iframeRef","onLoadRef","onErrorRef","iframe","handleLoad","handleError","CheckoutLoader","CheckoutErrorView","error","DEFAULT_WIDTH","DEFAULT_HEIGHT","DEFAULT_MAX_WIDTH","DEFAULT_MAX_HEIGHT","DEFAULT_ALLOW","Checkout","open","checkoutUrl","providerConfigOverrides","onOpen","onSuccess","onFailure","onCancel","iframeClassName","loadingComponent","errorComponent","allowInsecureHttp","generatedId","useId","modalId","mounted","setMounted","useState","status","setStatus","setError","wasOpenRef","resolvedProvider","useMemo","result","invalidUrlError","listener","message","handleIframeLoad","useCallback","handleIframeError","loadError","handleClose","iframeTitle","resolvedAllow","resolvedSandbox","modal","createPortal","CheckoutButton","buttonClassName","buttonProps","checkoutProps","setOpen","Fragment","useCheckout","defaultOptions","isOpen","setIsOpen","setOptions","defaultsRef","openCheckout","next","closeCheckout","CheckoutModalComponent"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/providers/hubtel.ts","../src/providers/moolre.ts","../src/providers/payswitch.ts","../src/providers/custom.ts","../src/providers/index.ts","../src/utils/url.ts","../src/utils/messages.ts","../src/utils/browser.ts","../src/utils/classNames.ts","../src/utils/bodyScroll.ts","../src/utils/focusTrap.ts","../src/components/CheckoutModal.tsx","../src/components/CheckoutIframe.tsx","../src/components/CheckoutLoader.tsx","../src/components/CheckoutErrorView.tsx","../src/components/CheckoutResultView.tsx","../src/components/Checkout.tsx","../src/components/CheckoutButton.tsx","../src/hooks/useCheckout.tsx"],"sourcesContent":["import type { CheckoutProviderConfig } from \"../types\";\n\n/**\n * Hubtel — Online Checkout.\n *\n * Verified (from Hubtel's public API reference for the checkout-URL\n * initiation endpoint): the checkout URL flow is redirect + server webhook\n * based. The merchant backend calls Hubtel's initiate endpoint with a\n * `callbackUrl` (server-to-server webhook) and a `returnUrl` /\n * `cancellationUrl` (browser redirect targets), then sends the customer to\n * the resulting checkout URL.\n *\n * UNVERIFIED: Hubtel's public docs do not document a `window.postMessage`\n * protocol for a checkout URL embedded via a plain iframe (as opposed to\n * their separate `@hubteljs/checkout` SDK, which manages its own iframe and\n * bridge internally and is a different integration path from \"embed a URL\n * you already have\"). `supportsPostMessage` is therefore left `false` here\n * — do not flip it on without a citation. Rely on `returnUrl`/`callbackUrl`\n * plus backend verification instead of any frontend \"success\" signal.\n */\nexport const hubtelProvider: CheckoutProviderConfig = {\n name: \"hubtel\",\n defaultTitle: \"Complete Payment\",\n supportsPostMessage: false,\n iframeAllow: \"payment *\",\n};\n","import type { CheckoutProviderConfig } from \"../types\";\n\n/**\n * Moolre — Checkout / Collections.\n *\n * UNVERIFIED: Moolre's public API docs (docs.moolre.com) were not\n * accessible as static, readable content at the time this adapter was\n * written, so no `postMessage` protocol, allowed origins, or iframe\n * embedding policy could be confirmed. `supportsPostMessage` is left\n * `false` and no `messageHandler` is provided — do not assume behavior that\n * hasn't been verified against Moolre's own documentation. Rely on the\n * redirect/callback URLs you configure server-side plus backend\n * verification instead of any frontend \"success\" signal.\n */\nexport const moolreProvider: CheckoutProviderConfig = {\n name: \"moolre\",\n defaultTitle: \"Complete Payment\",\n supportsPostMessage: false,\n iframeAllow: \"payment *\",\n};\n","import type { CheckoutProviderConfig } from \"../types\";\n\n/**\n * PaySwitch — PayLink / hosted checkout.\n *\n * UNVERIFIED: PaySwitch's public docs describe PayLink (payment links/QR)\n * and the TheTeller processing API, but no `postMessage` protocol, allowed\n * origins, or iframe embedding policy for a generically embedded checkout\n * URL could be confirmed from accessible documentation. `supportsPostMessage`\n * is left `false` — do not assume behavior that hasn't been verified. Rely\n * on the redirect/callback URLs you configure server-side plus backend\n * verification instead of any frontend \"success\" signal.\n */\nexport const payswitchProvider: CheckoutProviderConfig = {\n name: \"payswitch\",\n defaultTitle: \"Complete Payment\",\n supportsPostMessage: false,\n iframeAllow: \"payment *\",\n};\n","import type { CheckoutProviderConfig } from \"../types\";\n\n/**\n * Fallback used for `provider=\"custom\"` with no inline config, and as the\n * base merged under any user-supplied {@link CheckoutProviderConfig}.\n * Intentionally trusts nothing by default: no allowed origins and\n * `supportsPostMessage: false`, so postMessage events are ignored unless the\n * developer explicitly configures otherwise.\n */\nexport const customProviderDefaults: CheckoutProviderConfig = {\n name: \"custom\",\n defaultTitle: \"Complete Payment\",\n supportsPostMessage: false,\n};\n","import type { CheckoutProvider, CheckoutProviderConfig } from \"../types\";\nimport { hubtelProvider } from \"./hubtel\";\nimport { moolreProvider } from \"./moolre\";\nimport { payswitchProvider } from \"./payswitch\";\nimport { customProviderDefaults } from \"./custom\";\n\nconst BUILT_IN_PROVIDERS: Record<string, CheckoutProviderConfig> = {\n hubtel: hubtelProvider,\n moolre: moolreProvider,\n payswitch: payswitchProvider,\n custom: customProviderDefaults,\n};\n\n/**\n * Resolves the `provider` + `providerConfig` props into one concrete\n * {@link CheckoutProviderConfig}. Accepts either a built-in preset name or\n * an inline config object (for gateways that aren't built in), and merges\n * any `providerConfig` overrides on top.\n */\nexport function resolveProviderConfig(\n provider: CheckoutProvider | undefined,\n overrides?: Partial<CheckoutProviderConfig>,\n): CheckoutProviderConfig {\n let base: CheckoutProviderConfig;\n\n if (!provider) {\n base = customProviderDefaults;\n } else if (typeof provider === \"string\") {\n base = BUILT_IN_PROVIDERS[provider] ?? { ...customProviderDefaults, name: provider };\n } else {\n base = { ...customProviderDefaults, ...provider };\n }\n\n return overrides ? { ...base, ...overrides } : base;\n}\n\nexport { hubtelProvider, moolreProvider, payswitchProvider, customProviderDefaults };\nexport type { CheckoutProvider, CheckoutProviderConfig } from \"../types\";\n","export interface UrlValidationOptions {\n /** Allow `http:` URLs. Intended for local development only. */\n allowInsecureHttp?: boolean;\n}\n\nexport interface UrlValidationResult {\n valid: boolean;\n reason?: string;\n}\n\nconst UNSAFE_PROTOCOLS = new Set([\"javascript:\", \"data:\", \"vbscript:\", \"file:\", \"blob:\"]);\n\n/**\n * Validates a gateway checkout URL before it is ever placed in an iframe's\n * `src`. Rejects non-URLs, script-injection protocols, and (by default)\n * plain `http:` URLs.\n */\nexport function validateCheckoutUrl(\n url: string,\n options: UrlValidationOptions = {},\n): UrlValidationResult {\n if (!url || typeof url !== \"string\") {\n return { valid: false, reason: \"A checkoutUrl is required.\" };\n }\n\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return { valid: false, reason: `\"${url}\" is not a valid URL.` };\n }\n\n if (UNSAFE_PROTOCOLS.has(parsed.protocol)) {\n return { valid: false, reason: `Unsafe URL protocol \"${parsed.protocol}\" is not allowed.` };\n }\n\n if (parsed.protocol !== \"https:\" && parsed.protocol !== \"http:\") {\n return { valid: false, reason: `Unsupported URL protocol \"${parsed.protocol}\".` };\n }\n\n if (parsed.protocol === \"http:\" && !options.allowInsecureHttp) {\n return {\n valid: false,\n reason:\n 'checkoutUrl must use HTTPS. Pass allowInsecureHttp to override for local development only.',\n };\n }\n\n return { valid: true };\n}\n\n/** Compares an event origin against a provider's allow-list of origins. */\nexport function isOriginAllowed(origin: string, allowedOrigins?: string[]): boolean {\n if (!allowedOrigins || allowedOrigins.length === 0) return false;\n\n return allowedOrigins.some((allowed) => {\n try {\n return new URL(allowed).origin === origin;\n } catch {\n return allowed === origin;\n }\n });\n}\n","import type { CheckoutMessage, CheckoutProviderConfig } from \"../types\";\nimport { isOriginAllowed } from \"./url\";\n\n/**\n * Builds a `message` event handler scoped to one provider config. Never\n * treat an unvalidated message as a payment outcome:\n *\n * - If the provider declares `allowedOrigins`, messages from any other\n * origin are dropped silently.\n * - If it declares no `allowedOrigins` AND does not set\n * `supportsPostMessage: true`, ALL messages are dropped — an unconfigured\n * provider must opt in before we trust anything it says.\n * - The provider's own `messageHandler` decides how to normalize (or\n * reject, by returning `null`) the raw event payload.\n */\nexport function createMessageListener(\n providerConfig: CheckoutProviderConfig,\n onMessage: (message: CheckoutMessage) => void,\n): (event: MessageEvent) => void {\n return function handleMessage(event: MessageEvent): void {\n const hasAllowList = !!providerConfig.allowedOrigins && providerConfig.allowedOrigins.length > 0;\n\n if (hasAllowList) {\n if (!isOriginAllowed(event.origin, providerConfig.allowedOrigins)) return;\n } else if (!providerConfig.supportsPostMessage) {\n return;\n }\n\n let normalized: CheckoutMessage | null = null;\n\n if (providerConfig.messageHandler) {\n try {\n normalized = providerConfig.messageHandler(event);\n } catch {\n return;\n }\n } else if (event.data && typeof event.data === \"object\") {\n const data = event.data as Record<string, unknown>;\n normalized = {\n type: typeof data.type === \"string\" ? data.type : \"message\",\n provider: providerConfig.name,\n payload: event.data,\n origin: event.origin,\n };\n }\n\n if (!normalized) return;\n\n onMessage({ ...normalized, origin: event.origin, raw: event });\n };\n}\n","/**\n * `true` only when running in an environment with a real DOM. Safe to read\n * at module scope (no SSR crash) — never gate behavior on `window`/`document`\n * directly outside effects or event handlers.\n */\nexport const isBrowser: boolean = typeof window !== \"undefined\" && typeof document !== \"undefined\";\n","export function cx(...classes: Array<string | false | null | undefined>): string {\n return classes.filter(Boolean).join(\" \");\n}\n","import { isBrowser } from \"./browser\";\n\nlet lockCount = 0;\nlet originalOverflow = \"\";\nlet originalPaddingRight = \"\";\n\n/**\n * Locks page scroll while a checkout modal is open. Reference-counted so\n * multiple modals (or re-renders) nest safely — the original styles are\n * only restored once every lock has been released.\n */\nexport function lockBodyScroll(): void {\n if (!isBrowser) return;\n\n if (lockCount === 0) {\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n originalOverflow = document.body.style.overflow;\n originalPaddingRight = document.body.style.paddingRight;\n document.body.style.overflow = \"hidden\";\n if (scrollbarWidth > 0) {\n document.body.style.paddingRight = `${scrollbarWidth}px`;\n }\n }\n\n lockCount += 1;\n}\n\nexport function unlockBodyScroll(): void {\n if (!isBrowser) return;\n\n lockCount = Math.max(0, lockCount - 1);\n\n if (lockCount === 0) {\n document.body.style.overflow = originalOverflow;\n document.body.style.paddingRight = originalPaddingRight;\n }\n}\n","const FOCUSABLE_SELECTOR = [\n \"a[href]\",\n \"button:not([disabled])\",\n \"textarea:not([disabled])\",\n \"input:not([disabled])\",\n \"select:not([disabled])\",\n \"iframe\",\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(\",\");\n\n/** Returns focusable descendants of `container`, in DOM order. */\nexport function getFocusableElements(container: HTMLElement): HTMLElement[] {\n return Array.from(container.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR));\n}\n\n/**\n * Keeps Tab/Shift+Tab cycling within `container`. Returns a keydown handler\n * to attach to the container; does nothing for non-Tab keys.\n */\nexport function createFocusTrapHandler(container: HTMLElement) {\n return function handleKeyDown(event: KeyboardEvent): void {\n if (event.key !== \"Tab\") return;\n\n const focusable = getFocusableElements(container);\n if (focusable.length === 0) {\n event.preventDefault();\n return;\n }\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n const active = document.activeElement;\n\n if (event.shiftKey) {\n if (active === first || !container.contains(active)) {\n event.preventDefault();\n last.focus();\n }\n } else if (active === last || !container.contains(active)) {\n event.preventDefault();\n first.focus();\n }\n };\n}\n","import { useEffect, useRef, type ReactNode } from \"react\";\nimport { cx } from \"../utils/classNames\";\nimport { lockBodyScroll, unlockBodyScroll } from \"../utils/bodyScroll\";\nimport { createFocusTrapHandler, getFocusableElements } from \"../utils/focusTrap\";\nimport type { CheckoutTheme } from \"../types\";\n\nexport interface CheckoutModalProps {\n id: string;\n title?: string;\n description?: string;\n showCloseButton: boolean;\n closeOnOverlayClick: boolean;\n closeOnEscape: boolean;\n onClose?: () => void;\n width: string | number;\n height: string | number;\n maxWidth: string | number;\n maxHeight: string | number;\n className?: string;\n overlayClassName?: string;\n theme: CheckoutTheme;\n zIndex?: number;\n children: ReactNode;\n}\n\nfunction toDimension(value: string | number): string {\n return typeof value === \"number\" ? `${value}px` : value;\n}\n\nexport function CheckoutModal({\n id,\n title,\n description,\n showCloseButton,\n closeOnOverlayClick,\n closeOnEscape,\n onClose,\n width,\n height,\n maxWidth,\n maxHeight,\n className,\n overlayClassName,\n theme,\n zIndex,\n children,\n}: CheckoutModalProps): JSX.Element {\n const modalRef = useRef<HTMLDivElement>(null);\n const previouslyFocusedRef = useRef<HTMLElement | null>(null);\n\n useEffect(() => {\n lockBodyScroll();\n previouslyFocusedRef.current = document.activeElement as HTMLElement | null;\n\n const container = modalRef.current;\n if (container) {\n const focusable = getFocusableElements(container);\n (focusable[0] ?? container).focus();\n }\n\n return () => {\n unlockBodyScroll();\n previouslyFocusedRef.current?.focus?.();\n };\n }, []);\n\n useEffect(() => {\n if (!closeOnEscape) return;\n\n function handleKeyDown(event: KeyboardEvent): void {\n if (event.key === \"Escape\") {\n event.stopPropagation();\n onClose?.();\n }\n }\n\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [closeOnEscape, onClose]);\n\n function handleContainerKeyDown(event: React.KeyboardEvent<HTMLDivElement>): void {\n if (event.key === \"Tab\" && modalRef.current) {\n createFocusTrapHandler(modalRef.current)(event.nativeEvent);\n }\n }\n\n function handleOverlayMouseDown(event: React.MouseEvent<HTMLDivElement>): void {\n if (closeOnOverlayClick && event.target === event.currentTarget) {\n onClose?.();\n }\n }\n\n const titleId = `${id}-title`;\n const descriptionId = description ? `${id}-description` : undefined;\n\n return (\n <div className=\"vq-checkout-root\" data-theme={theme}>\n <div\n className={cx(\"vq-checkout-overlay\", overlayClassName)}\n onMouseDown={handleOverlayMouseDown}\n style={zIndex !== undefined ? { zIndex } : undefined}\n >\n <div\n ref={modalRef}\n id={id}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={title ? titleId : undefined}\n aria-label={title ? undefined : \"Checkout\"}\n aria-describedby={descriptionId}\n className={cx(\"vq-checkout-modal\", className)}\n style={{\n width: toDimension(width),\n height: toDimension(height),\n maxWidth: toDimension(maxWidth),\n maxHeight: toDimension(maxHeight),\n }}\n tabIndex={-1}\n onKeyDown={handleContainerKeyDown}\n >\n {(title || description || showCloseButton) && (\n <div className=\"vq-checkout-header\">\n <div className=\"vq-checkout-heading\">\n {title && (\n <h2 id={titleId} className=\"vq-checkout-title\">\n {title}\n </h2>\n )}\n {description && (\n <p id={descriptionId} className=\"vq-checkout-description\">\n {description}\n </p>\n )}\n </div>\n {showCloseButton && (\n <button\n type=\"button\"\n className=\"vq-checkout-close\"\n aria-label=\"Close checkout\"\n onClick={() => onClose?.()}\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M2 2L14 14M14 2L2 14\"\n stroke=\"currentColor\"\n strokeWidth=\"1.6\"\n strokeLinecap=\"round\"\n />\n </svg>\n </button>\n )}\n </div>\n )}\n <div className=\"vq-checkout-body\">{children}</div>\n </div>\n </div>\n </div>\n );\n}\n","import { useEffect, useRef } from \"react\";\nimport { cx } from \"../utils/classNames\";\n\nexport interface CheckoutIframeProps {\n src: string;\n title: string;\n className?: string;\n allow?: string;\n sandbox?: string;\n hidden?: boolean;\n onLoad: () => void;\n onError: () => void;\n}\n\n/**\n * React never attaches a listener for the native `error` event on\n * `<iframe>` (it only special-cases `img`/`source`/`link` for `error`, and\n * `iframe`/`object`/`embed` only get `load` — see react-dom's\n * `setInitialProperties`). An `onError` prop here would therefore silently\n * never fire in any browser, so both events are wired via a native\n * `addEventListener` on the underlying node instead.\n */\nexport function CheckoutIframe({\n src,\n title,\n className,\n allow,\n sandbox,\n hidden,\n onLoad,\n onError,\n}: CheckoutIframeProps): JSX.Element {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const onLoadRef = useRef(onLoad);\n const onErrorRef = useRef(onError);\n onLoadRef.current = onLoad;\n onErrorRef.current = onError;\n\n useEffect(() => {\n const iframe = iframeRef.current;\n if (!iframe) return;\n\n const handleLoad = () => onLoadRef.current();\n const handleError = () => onErrorRef.current();\n\n iframe.addEventListener(\"load\", handleLoad);\n iframe.addEventListener(\"error\", handleError);\n\n return () => {\n iframe.removeEventListener(\"load\", handleLoad);\n iframe.removeEventListener(\"error\", handleError);\n };\n }, [src]);\n\n return (\n <iframe\n ref={iframeRef}\n src={src}\n title={title}\n className={cx(\"vq-checkout-iframe\", className)}\n allow={allow}\n sandbox={sandbox}\n style={hidden ? { position: \"absolute\", width: 0, height: 0, opacity: 0 } : undefined}\n />\n );\n}\n","export function CheckoutLoader(): JSX.Element {\n return (\n <div className=\"vq-checkout-state\" role=\"status\" aria-live=\"polite\">\n <div className=\"vq-checkout-spinner\" aria-hidden=\"true\" />\n <span>Loading secure checkout...</span>\n </div>\n );\n}\n","import type { CheckoutError } from \"../types\";\n\nexport interface CheckoutErrorViewProps {\n error: CheckoutError;\n}\n\nexport function CheckoutErrorView({ error }: CheckoutErrorViewProps): JSX.Element {\n return (\n <div className=\"vq-checkout-state\" role=\"alert\">\n <div className=\"vq-checkout-error-icon\" aria-hidden=\"true\">\n !\n </div>\n <p className=\"vq-checkout-error-message\">{error.message}</p>\n </div>\n );\n}\n","import type { CheckoutResult } from \"../types\";\n\nexport interface CheckoutResultViewProps {\n result: CheckoutResult;\n onClose?: () => void;\n}\n\nconst COPY: Record<CheckoutResult[\"type\"], { icon: string; title: string; tone: \"success\" | \"failure\" | \"cancel\" }> = {\n success: { icon: \"✓\", title: \"Payment successful\", tone: \"success\" },\n failure: { icon: \"✕\", title: \"Payment failed\", tone: \"failure\" },\n cancel: { icon: \"↩\", title: \"Checkout cancelled\", tone: \"cancel\" },\n};\n\nexport function CheckoutResultView({ result, onClose }: CheckoutResultViewProps): JSX.Element {\n const copy = COPY[result.type];\n\n return (\n <div\n className=\"vq-checkout-state\"\n role={result.type === \"failure\" ? \"alert\" : \"status\"}\n aria-live=\"polite\"\n >\n <div className={`vq-checkout-result-icon vq-checkout-result-icon--${copy.tone}`} aria-hidden=\"true\">\n {copy.icon}\n </div>\n <p className=\"vq-checkout-error-message\">{copy.title}</p>\n <button type=\"button\" className=\"vq-checkout-result-action\" onClick={() => onClose?.()}>\n Close\n </button>\n </div>\n );\n}\n","import { useCallback, useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport type { CheckoutError, CheckoutProps, CheckoutResult } from \"../types\";\nimport { resolveProviderConfig } from \"../providers\";\nimport { validateCheckoutUrl } from \"../utils/url\";\nimport { createMessageListener } from \"../utils/messages\";\nimport { isBrowser } from \"../utils/browser\";\nimport { CheckoutModal } from \"./CheckoutModal\";\nimport { CheckoutIframe } from \"./CheckoutIframe\";\nimport { CheckoutLoader } from \"./CheckoutLoader\";\nimport { CheckoutErrorView } from \"./CheckoutErrorView\";\nimport { CheckoutResultView } from \"./CheckoutResultView\";\n\ntype Status = \"loading\" | \"loaded\" | \"error\";\n\nconst DEFAULT_WIDTH = \"min(95vw, 500px)\";\nconst DEFAULT_HEIGHT = \"min(90vh, 750px)\";\nconst DEFAULT_MAX_WIDTH = \"500px\";\nconst DEFAULT_MAX_HEIGHT = \"750px\";\nconst DEFAULT_ALLOW = \"payment *\";\n\n/**\n * A modal/iframe checkout for embedding a gateway-hosted checkout page.\n *\n * `checkoutUrl` must come from your backend's own integration with the\n * payment provider's API — this component never talks to a gateway\n * directly and never needs API keys. See the README for why frontend\n * events here (including `onSuccess`) must not be treated as final proof\n * of payment.\n */\nexport function Checkout({\n open,\n checkoutUrl,\n provider,\n providerConfig: providerConfigOverrides,\n onClose,\n onOpen,\n onLoad,\n onError,\n onMessage,\n onSuccess,\n onFailure,\n onCancel,\n title,\n description,\n showCloseButton = true,\n closeOnOverlayClick = true,\n closeOnEscape = true,\n width = DEFAULT_WIDTH,\n height = DEFAULT_HEIGHT,\n maxWidth = DEFAULT_MAX_WIDTH,\n maxHeight = DEFAULT_MAX_HEIGHT,\n className,\n iframeClassName,\n overlayClassName,\n theme = \"light\",\n zIndex,\n allow,\n sandbox,\n loadingComponent,\n errorComponent,\n resultComponent,\n autoCloseDelay,\n allowInsecureHttp,\n id,\n children,\n}: CheckoutProps): JSX.Element | null {\n const generatedId = useId();\n const modalId = id ?? `vq-checkout-${generatedId}`;\n\n const [mounted, setMounted] = useState(false);\n const [status, setStatus] = useState<Status>(\"loading\");\n const [error, setError] = useState<CheckoutError | null>(null);\n const [result, setResult] = useState<CheckoutResult | null>(null);\n const wasOpenRef = useRef(false);\n\n const resolvedProvider = useMemo(\n () => resolveProviderConfig(provider, providerConfigOverrides),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [provider, JSON.stringify(providerConfigOverrides ?? {})],\n );\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n if (open && !wasOpenRef.current) {\n onOpen?.();\n }\n wasOpenRef.current = open;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open]);\n\n useEffect(() => {\n if (!open) return;\n\n setResult(null);\n\n const validation = validateCheckoutUrl(checkoutUrl, { allowInsecureHttp });\n if (!validation.valid) {\n const invalidUrlError: CheckoutError = {\n code: \"INVALID_URL\",\n message: validation.reason ?? \"The provided checkoutUrl is invalid.\",\n provider: resolvedProvider.name,\n };\n setStatus(\"error\");\n setError(invalidUrlError);\n onError?.(invalidUrlError);\n return;\n }\n\n setStatus(\"loading\");\n setError(null);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open, checkoutUrl, allowInsecureHttp]);\n\n useEffect(() => {\n if (!open || !isBrowser) return;\n\n const listener = createMessageListener(resolvedProvider, (message) => {\n onMessage?.(message);\n if (message.type === \"success\") {\n setResult({ type: \"success\", message });\n onSuccess?.(message);\n } else if (message.type === \"failure\") {\n setResult({ type: \"failure\", message });\n onFailure?.(message);\n } else if (message.type === \"cancel\") {\n setResult({ type: \"cancel\", message });\n onCancel?.(message);\n }\n });\n\n window.addEventListener(\"message\", listener);\n return () => window.removeEventListener(\"message\", listener);\n }, [open, resolvedProvider, onMessage, onSuccess, onFailure, onCancel]);\n\n const handleIframeLoad = useCallback(() => {\n setStatus(\"loaded\");\n onLoad?.();\n }, [onLoad]);\n\n const handleIframeError = useCallback(() => {\n const loadError: CheckoutError = {\n code: \"IFRAME_LOAD_ERROR\",\n message: \"The checkout page could not be loaded.\",\n provider: resolvedProvider.name,\n };\n setStatus(\"error\");\n setError(loadError);\n onError?.(loadError);\n }, [onError, resolvedProvider.name]);\n\n const handleClose = useCallback(() => {\n onClose?.();\n }, [onClose]);\n\n useEffect(() => {\n if (!result || autoCloseDelay === undefined) return;\n\n const timer = setTimeout(() => onClose?.(), autoCloseDelay);\n return () => clearTimeout(timer);\n }, [result, autoCloseDelay, onClose]);\n\n if (!open || !mounted) return null;\n\n const iframeTitle = title ?? resolvedProvider.defaultTitle ?? \"Checkout\";\n const resolvedAllow = allow ?? resolvedProvider.iframeAllow ?? DEFAULT_ALLOW;\n const resolvedSandbox = sandbox ?? resolvedProvider.iframeSandbox;\n\n const modal = (\n <CheckoutModal\n id={modalId}\n title={title ?? resolvedProvider.defaultTitle}\n description={description}\n showCloseButton={showCloseButton}\n closeOnOverlayClick={closeOnOverlayClick}\n closeOnEscape={closeOnEscape}\n onClose={handleClose}\n width={width}\n height={height}\n maxWidth={maxWidth}\n maxHeight={maxHeight}\n className={className}\n overlayClassName={overlayClassName}\n theme={theme}\n zIndex={zIndex}\n >\n {result ? (\n typeof resultComponent === \"function\" ? (\n resultComponent(result)\n ) : (\n resultComponent ?? <CheckoutResultView result={result} onClose={handleClose} />\n )\n ) : (\n <>\n {status === \"loading\" && (loadingComponent ?? <CheckoutLoader />)}\n {status === \"error\" &&\n error &&\n (typeof errorComponent === \"function\"\n ? errorComponent(error)\n : errorComponent ?? <CheckoutErrorView error={error} />)}\n {status !== \"error\" && (\n <CheckoutIframe\n src={checkoutUrl}\n title={iframeTitle}\n className={iframeClassName}\n allow={resolvedAllow}\n sandbox={resolvedSandbox}\n hidden={status === \"loading\"}\n onLoad={handleIframeLoad}\n onError={handleIframeError}\n />\n )}\n </>\n )}\n {children}\n </CheckoutModal>\n );\n\n return createPortal(modal, document.body);\n}\n","import { useState, type ButtonHTMLAttributes, type ReactNode } from \"react\";\nimport { cx } from \"../utils/classNames\";\nimport { Checkout } from \"./Checkout\";\nimport type { CheckoutProps } from \"../types\";\n\nexport interface CheckoutButtonProps extends Omit<CheckoutProps, \"open\"> {\n children: ReactNode;\n buttonClassName?: string;\n buttonProps?: Omit<ButtonHTMLAttributes<HTMLButtonElement>, \"onClick\" | \"type\" | \"className\">;\n}\n\n/**\n * Convenience wrapper that owns its own `open` state: renders a trigger\n * button and the {@link Checkout} modal together, for when you don't need\n * to control the open state yourself.\n */\nexport function CheckoutButton({\n children,\n buttonClassName,\n buttonProps,\n onClose,\n ...checkoutProps\n}: CheckoutButtonProps): JSX.Element {\n const [open, setOpen] = useState(false);\n\n return (\n <>\n <button\n type=\"button\"\n className={cx(\"vq-checkout-trigger\", buttonClassName)}\n onClick={() => setOpen(true)}\n {...buttonProps}\n >\n {children}\n </button>\n <Checkout\n {...checkoutProps}\n open={open}\n onClose={() => {\n setOpen(false);\n onClose?.();\n }}\n />\n </>\n );\n}\n","import { useCallback, useMemo, useRef, useState } from \"react\";\nimport { Checkout } from \"../components/Checkout\";\nimport type { CheckoutProps } from \"../types\";\n\nexport type OpenCheckoutOptions = Omit<CheckoutProps, \"open\">;\n\nexport interface UseCheckoutResult {\n /** Opens the checkout modal with the given options. */\n openCheckout: (options: OpenCheckoutOptions) => void;\n closeCheckout: () => void;\n isOpen: boolean;\n /** Render this once, wherever the modal should live in the tree. */\n CheckoutModal: () => JSX.Element | null;\n}\n\n/**\n * Imperative alternative to rendering `<Checkout open={...} />` yourself.\n * Keeps the simple `<Checkout />` component as the primary API — this is an\n * optional convenience for call-site-driven flows (e.g. \"Pay Now\" inside a\n * list where mounting a modal per row would be wasteful).\n */\nexport function useCheckout(defaultOptions?: Partial<OpenCheckoutOptions>): UseCheckoutResult {\n const [isOpen, setIsOpen] = useState(false);\n const [options, setOptions] = useState<OpenCheckoutOptions | null>(null);\n const defaultsRef = useRef(defaultOptions);\n defaultsRef.current = defaultOptions;\n\n const openCheckout = useCallback((next: OpenCheckoutOptions) => {\n setOptions({ ...defaultsRef.current, ...next });\n setIsOpen(true);\n }, []);\n\n const closeCheckout = useCallback(() => setIsOpen(false), []);\n\n const CheckoutModalComponent = useCallback((): JSX.Element | null => {\n if (!options) return null;\n\n return (\n <Checkout\n {...options}\n open={isOpen}\n onClose={() => {\n options.onClose?.();\n setIsOpen(false);\n }}\n />\n );\n }, [options, isOpen]);\n\n return useMemo(\n () => ({ openCheckout, closeCheckout, isOpen, CheckoutModal: CheckoutModalComponent }),\n [openCheckout, closeCheckout, isOpen, CheckoutModalComponent],\n );\n}\n"],"names":["hubtelProvider","moolreProvider","payswitchProvider","customProviderDefaults","BUILT_IN_PROVIDERS","resolveProviderConfig","provider","overrides","base","UNSAFE_PROTOCOLS","validateCheckoutUrl","url","options","parsed","isOriginAllowed","origin","allowedOrigins","allowed","createMessageListener","providerConfig","onMessage","event","normalized","data","isBrowser","cx","classes","lockCount","originalOverflow","originalPaddingRight","lockBodyScroll","scrollbarWidth","unlockBodyScroll","FOCUSABLE_SELECTOR","getFocusableElements","container","createFocusTrapHandler","focusable","first","last","active","toDimension","value","CheckoutModal","id","title","description","showCloseButton","closeOnOverlayClick","closeOnEscape","onClose","width","height","maxWidth","maxHeight","className","overlayClassName","theme","zIndex","children","modalRef","useRef","previouslyFocusedRef","useEffect","_b","_a","handleKeyDown","handleContainerKeyDown","handleOverlayMouseDown","titleId","descriptionId","jsx","jsxs","CheckoutIframe","src","allow","sandbox","hidden","onLoad","onError","iframeRef","onLoadRef","onErrorRef","iframe","handleLoad","handleError","CheckoutLoader","CheckoutErrorView","error","COPY","CheckoutResultView","result","copy","DEFAULT_WIDTH","DEFAULT_HEIGHT","DEFAULT_MAX_WIDTH","DEFAULT_MAX_HEIGHT","DEFAULT_ALLOW","Checkout","open","checkoutUrl","providerConfigOverrides","onOpen","onSuccess","onFailure","onCancel","iframeClassName","loadingComponent","errorComponent","resultComponent","autoCloseDelay","allowInsecureHttp","generatedId","useId","modalId","mounted","setMounted","useState","status","setStatus","setError","setResult","wasOpenRef","resolvedProvider","useMemo","validation","invalidUrlError","listener","message","handleIframeLoad","useCallback","handleIframeError","loadError","handleClose","timer","iframeTitle","resolvedAllow","resolvedSandbox","modal","Fragment","createPortal","CheckoutButton","buttonClassName","buttonProps","checkoutProps","setOpen","useCheckout","defaultOptions","isOpen","setIsOpen","setOptions","defaultsRef","openCheckout","next","closeCheckout","CheckoutModalComponent"],"mappings":"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"}
|