@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/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","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.mjs","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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"}
|
package/dist/styles.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.vq-checkout-root{--vq-overlay-bg: rgba(15, 17, 21, .55);--vq-surface-bg: #ffffff;--vq-surface-fg: #14161a;--vq-muted-fg: #6b7280;--vq-border-color: rgba(15, 17, 21, .08);--vq-radius: 16px;--vq-shadow: 0 20px 60px rgba(15, 17, 21, .25), 0 2px 8px rgba(15, 17, 21, .08);--vq-focus-ring: #2563eb;--vq-close-hover-bg: rgba(15, 17, 21, .06);--vq-z-index: 2147483000;--vq-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;position:fixed;top:0;right:0;bottom:0;left:0;z-index:var(--vq-z-index);font-family:var(--vq-font)}.vq-checkout-root[data-theme=dark]{--vq-overlay-bg: rgba(0, 0, 0, .7);--vq-surface-bg: #17191d;--vq-surface-fg: #f3f4f6;--vq-muted-fg: #9ca3af;--vq-border-color: rgba(255, 255, 255, .08);--vq-shadow: 0 20px 60px rgba(0, 0, 0, .5), 0 2px 8px rgba(0, 0, 0, .3);--vq-close-hover-bg: rgba(255, 255, 255, .08)}@media (prefers-color-scheme: dark){.vq-checkout-root[data-theme=auto]{--vq-overlay-bg: rgba(0, 0, 0, .7);--vq-surface-bg: #17191d;--vq-surface-fg: #f3f4f6;--vq-muted-fg: #9ca3af;--vq-border-color: rgba(255, 255, 255, .08);--vq-shadow: 0 20px 60px rgba(0, 0, 0, .5), 0 2px 8px rgba(0, 0, 0, .3);--vq-close-hover-bg: rgba(255, 255, 255, .08)}}.vq-checkout-overlay{position:absolute;top:0;right:0;bottom:0;left:0;background:var(--vq-overlay-bg);display:flex;align-items:center;justify-content:center;padding:16px;animation:vq-fade-in .18s ease-out}.vq-checkout-modal{position:relative;display:flex;flex-direction:column;width:100%;background:var(--vq-surface-bg);color:var(--vq-surface-fg);border-radius:var(--vq-radius);box-shadow:var(--vq-shadow);overflow:hidden;animation:vq-scale-in .22s cubic-bezier(.16,1,.3,1)}.vq-checkout-header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:18px 20px;border-bottom:1px solid var(--vq-border-color);flex-shrink:0}.vq-checkout-heading{display:flex;flex-direction:column;gap:2px;min-width:0}.vq-checkout-title{margin:0;font-size:16px;font-weight:600;line-height:1.3;color:var(--vq-surface-fg)}.vq-checkout-description{margin:0;font-size:13px;line-height:1.4;color:var(--vq-muted-fg)}.vq-checkout-close{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;flex-shrink:0;border:none;border-radius:999px;background:transparent;color:var(--vq-muted-fg);cursor:pointer;transition:background-color .12s ease,color .12s ease}.vq-checkout-close:hover{background:var(--vq-close-hover-bg);color:var(--vq-surface-fg)}.vq-checkout-close:focus-visible,.vq-checkout-modal :focus-visible{outline:2px solid var(--vq-focus-ring);outline-offset:2px}.vq-checkout-body{position:relative;flex:1;min-height:0;display:flex}.vq-checkout-iframe{width:100%;height:100%;border:none;background:var(--vq-surface-bg);display:block}.vq-checkout-state{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;padding:32px;text-align:center;background:var(--vq-surface-bg);color:var(--vq-muted-fg);font-size:14px}.vq-checkout-spinner{width:32px;height:32px;border-radius:999px;border:3px solid var(--vq-border-color);border-top-color:var(--vq-focus-ring);animation:vq-spin .8s linear infinite}.vq-checkout-error-icon{width:36px;height:36px;border-radius:999px;display:flex;align-items:center;justify-content:center;background:#dc26261a;color:#dc2626;font-size:18px;font-weight:700}.vq-checkout-error-message{color:var(--vq-surface-fg);font-weight:500;max-width:32ch}@keyframes vq-fade-in{0%{opacity:0}to{opacity:1}}@keyframes vq-scale-in{0%{opacity:0;transform:scale(.96) translateY(8px)}to{opacity:1;transform:scale(1) translateY(0)}}@keyframes vq-spin{to{transform:rotate(360deg)}}@media (max-width: 640px){.vq-checkout-overlay{padding:0}.vq-checkout-modal{width:100vw!important;height:100dvh!important;max-width:100vw!important;max-height:100dvh!important;border-radius:0}}@media (prefers-reduced-motion: reduce){.vq-checkout-overlay,.vq-checkout-modal,.vq-checkout-spinner{animation-duration:.01ms!important}}.vq-checkout-trigger{font-family:var(--vq-font, inherit)}
|
|
1
|
+
.vq-checkout-root{--vq-overlay-bg: rgba(15, 17, 21, .55);--vq-surface-bg: #ffffff;--vq-surface-fg: #14161a;--vq-muted-fg: #6b7280;--vq-border-color: rgba(15, 17, 21, .08);--vq-radius: 16px;--vq-shadow: 0 20px 60px rgba(15, 17, 21, .25), 0 2px 8px rgba(15, 17, 21, .08);--vq-focus-ring: #2563eb;--vq-close-hover-bg: rgba(15, 17, 21, .06);--vq-z-index: 2147483000;--vq-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;position:fixed;top:0;right:0;bottom:0;left:0;z-index:var(--vq-z-index);font-family:var(--vq-font)}.vq-checkout-root[data-theme=dark]{--vq-overlay-bg: rgba(0, 0, 0, .7);--vq-surface-bg: #17191d;--vq-surface-fg: #f3f4f6;--vq-muted-fg: #9ca3af;--vq-border-color: rgba(255, 255, 255, .08);--vq-shadow: 0 20px 60px rgba(0, 0, 0, .5), 0 2px 8px rgba(0, 0, 0, .3);--vq-close-hover-bg: rgba(255, 255, 255, .08)}@media (prefers-color-scheme: dark){.vq-checkout-root[data-theme=auto]{--vq-overlay-bg: rgba(0, 0, 0, .7);--vq-surface-bg: #17191d;--vq-surface-fg: #f3f4f6;--vq-muted-fg: #9ca3af;--vq-border-color: rgba(255, 255, 255, .08);--vq-shadow: 0 20px 60px rgba(0, 0, 0, .5), 0 2px 8px rgba(0, 0, 0, .3);--vq-close-hover-bg: rgba(255, 255, 255, .08)}}.vq-checkout-overlay{position:absolute;top:0;right:0;bottom:0;left:0;background:var(--vq-overlay-bg);display:flex;align-items:center;justify-content:center;padding:16px;animation:vq-fade-in .18s ease-out}.vq-checkout-modal{position:relative;display:flex;flex-direction:column;width:100%;background:var(--vq-surface-bg);color:var(--vq-surface-fg);border-radius:var(--vq-radius);box-shadow:var(--vq-shadow);overflow:hidden;animation:vq-scale-in .22s cubic-bezier(.16,1,.3,1)}.vq-checkout-header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:18px 20px;border-bottom:1px solid var(--vq-border-color);flex-shrink:0}.vq-checkout-heading{display:flex;flex-direction:column;gap:2px;min-width:0}.vq-checkout-title{margin:0;font-size:16px;font-weight:600;line-height:1.3;color:var(--vq-surface-fg)}.vq-checkout-description{margin:0;font-size:13px;line-height:1.4;color:var(--vq-muted-fg)}.vq-checkout-close{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;flex-shrink:0;border:none;border-radius:999px;background:transparent;color:var(--vq-muted-fg);cursor:pointer;transition:background-color .12s ease,color .12s ease}.vq-checkout-close:hover{background:var(--vq-close-hover-bg);color:var(--vq-surface-fg)}.vq-checkout-close:focus-visible,.vq-checkout-modal :focus-visible{outline:2px solid var(--vq-focus-ring);outline-offset:2px}.vq-checkout-body{position:relative;flex:1;min-height:0;display:flex}.vq-checkout-iframe{width:100%;height:100%;border:none;background:var(--vq-surface-bg);display:block}.vq-checkout-state{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;padding:32px;text-align:center;background:var(--vq-surface-bg);color:var(--vq-muted-fg);font-size:14px}.vq-checkout-spinner{width:32px;height:32px;border-radius:999px;border:3px solid var(--vq-border-color);border-top-color:var(--vq-focus-ring);animation:vq-spin .8s linear infinite}.vq-checkout-error-icon{width:36px;height:36px;border-radius:999px;display:flex;align-items:center;justify-content:center;background:#dc26261a;color:#dc2626;font-size:18px;font-weight:700}.vq-checkout-error-message{color:var(--vq-surface-fg);font-weight:500;max-width:32ch}.vq-checkout-result-icon{width:36px;height:36px;border-radius:999px;display:flex;align-items:center;justify-content:center;font-size:18px;font-weight:700}.vq-checkout-result-icon--success{background:#16a34a1a;color:#16a34a}.vq-checkout-result-icon--failure{background:#dc26261a;color:#dc2626}.vq-checkout-result-icon--cancel{background:#6b72801f;color:#6b7280}.vq-checkout-result-action{border:none;border-radius:8px;background:var(--vq-surface-fg);color:var(--vq-surface-bg);font-size:13px;font-weight:600;padding:9px 20px;cursor:pointer}.vq-checkout-result-action:hover{opacity:.9}@keyframes vq-fade-in{0%{opacity:0}to{opacity:1}}@keyframes vq-scale-in{0%{opacity:0;transform:scale(.96) translateY(8px)}to{opacity:1;transform:scale(1) translateY(0)}}@keyframes vq-spin{to{transform:rotate(360deg)}}@media (max-width: 640px){.vq-checkout-overlay{padding:0}.vq-checkout-modal{width:100vw!important;height:100dvh!important;max-width:100vw!important;max-height:100dvh!important;border-radius:0}}@media (prefers-reduced-motion: reduce){.vq-checkout-overlay,.vq-checkout-modal,.vq-checkout-spinner{animation-duration:.01ms!important}}.vq-checkout-trigger{font-family:var(--vq-font, inherit)}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dekin_dev/react-checkout",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "A lightweight, provider-agnostic React modal/iframe checkout for embedding hosted payment pages (Hubtel, Moolre, PaySwitch, and custom gateways).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -50,7 +50,8 @@
|
|
|
50
50
|
"lint": "eslint .",
|
|
51
51
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
52
52
|
"release": "npm run typecheck && npm run lint && npm run test && npm run build",
|
|
53
|
-
"demo": "npm run dev --workspace demo"
|
|
53
|
+
"demo": "npm run dev --workspace demo",
|
|
54
|
+
"publish": "npm run build && npm publish --access public"
|
|
54
55
|
},
|
|
55
56
|
"workspaces": [
|
|
56
57
|
"demo"
|