@alfadocs/ui-kit-debug 0.45.0 → 0.46.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.
@@ -8,7 +8,7 @@ import { u as X } from "./use-controllable-state-BiY4xTzM.js";
8
8
  import { u as Y } from "./registry-nPAVE19X.js";
9
9
  import { B as I } from "./button-DD_0Xdmr.js";
10
10
  import { P as Z } from "./progress-kzIRcdaq.js";
11
- import { f as $ } from "./payment-form-DqEiEJRO.js";
11
+ import { f as $ } from "./payment-form-BNTx4876.js";
12
12
  import { T as ee } from "./triangle-alert-CBPUIzQo.js";
13
13
  import { C as se } from "./check-DPdL_Sm7.js";
14
14
  const ae = {
@@ -265,4 +265,4 @@ export {
265
265
  te as F,
266
266
  ae as f
267
267
  };
268
- //# sourceMappingURL=freemium-paywall-BYist2sJ.js.map
268
+ //# sourceMappingURL=freemium-paywall-DzpD63WY.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"freemium-paywall-BYist2sJ.js","sources":["../../src/components/freemium-paywall/freemium-paywall.agent.ts","../../src/components/freemium-paywall/freemium-paywall.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — FreemiumPaywall. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { FreemiumPaywallHandle } from './freemium-paywall';\n\nexport const freemiumPaywallAgent: AgentAdapter<FreemiumPaywallHandle> = {\n id: 'freemium-paywall',\n capabilities: ['submit', 'dismiss'],\n state: {\n isOpen: {\n type: 'boolean',\n descriptionKey: 'ui.agent.freemiumPaywall.state.isOpen',\n description: 'True when the paywall dialog is open.',\n read: (handle) => handle.isOpen(),\n },\n selectedPlanId: {\n type: 'string | null',\n descriptionKey: 'ui.agent.freemiumPaywall.state.selectedPlanId',\n description: 'Opaque id of the currently-selected plan.',\n read: (handle) => handle.getSelectedPlanId(),\n },\n },\n actions: {\n upgrade: {\n safety: 'write',\n descriptionKey: 'ui.agent.freemiumPaywall.actions.upgrade',\n description: 'Fire onUpgrade with the currently-selected plan id.',\n invoke: (handle) => {\n handle.upgrade();\n },\n },\n dismiss: {\n safety: 'destructive',\n descriptionKey: 'ui.agent.freemiumPaywall.actions.dismiss',\n description:\n 'Dismiss the paywall via the Not Now action. Irreversible from the same UI.',\n invoke: (handle) => {\n handle.dismiss();\n },\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'freemium-paywall',\n description: 'Marks the FreemiumPaywall dialog content.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n },\n};\n","import {\n forwardRef,\n useId,\n useImperativeHandle,\n useMemo,\n useRef,\n type ReactNode,\n} from 'react';\nimport * as RadixAlertDialog from '@radix-ui/react-alert-dialog';\nimport * as RadixRadioGroup from '@radix-ui/react-radio-group';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { useControllableState } from '../../hooks/use-controllable-state';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { freemiumPaywallAgent } from './freemium-paywall.agent';\nimport { AlertTriangle, Check } from 'lucide-react';\nimport { Button } from '../button';\nimport { Progress } from '../progress';\nimport { formatPaymentAmount } from '../payment-form';\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\n\nexport interface FreemiumPlan {\n id: string;\n /** Translation key for the plan name (e.g. `app.paywall.plans.pro`). */\n nameKey: string;\n /** Amount in minor units (cents, centesimi). */\n priceAmount: number;\n /** ISO 4217 currency code. */\n currency: string;\n /** Translation key for the cadence suffix (e.g. `app.paywall.period.month`). */\n perKey?: string;\n /** Per-line feature translation keys. */\n featuresKeys?: string[];\n}\n\nconst contentVariants = cva(\n [\n 'ds:fixed ds:z-[var(--z-modal)] ds:overflow-auto',\n 'ds:bg-[color:var(--popover)] ds:text-[color:var(--popover-foreground)]',\n 'ds:border ds:border-border ds:shadow-[var(--shadow-lg)]',\n // forced-colors: keep the dialog boundary visible under Windows High\n // Contrast, where `var(--border)` may collapse to system colours.\n 'ds:forced-colors:border-[CanvasText]',\n 'ds:focus:outline-none',\n ].join(' '),\n {\n variants: {\n layout: {\n centered:\n 'ds:start-1/2 ds:top-1/2 ds:-translate-x-1/2 ds:-translate-y-1/2 ds:rtl:translate-x-1/2 ds:rounded-[var(--radius-md)] ds:max-w-[var(--dialog-width-xl)] ds:w-[calc(100vw-2rem)] ds:max-h-[90vh]',\n sheet:\n 'ds:inset-inline-0 ds:bottom-0 ds:w-full ds:max-h-[90vh] ds:rounded-t-[var(--radius-md)]',\n },\n density: {\n compact:\n 'ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)] ds:pt-[var(--spacing-md)] ds:pb-[var(--spacing-md)]',\n full: 'ds:ps-[var(--spacing-lg)] ds:pe-[var(--spacing-lg)] ds:pt-[var(--spacing-lg)] ds:pb-[var(--spacing-lg)]',\n },\n },\n defaultVariants: { layout: 'centered', density: 'full' },\n },\n);\n\n/** Curated imperative handle for agent / external automation. */\nexport interface FreemiumPaywallHandle {\n isOpen: () => boolean;\n getSelectedPlanId: () => string | null;\n upgrade: () => void;\n dismiss: () => void;\n}\n\nexport interface FreemiumPaywallProps extends VariantProps<\n typeof contentVariants\n> {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n plans: FreemiumPlan[];\n /** Currently-selected plan id (controlled) or default. */\n selectedPlanId?: string;\n defaultSelectedPlanId?: string;\n onSelectedPlanChange?: (id: string) => void;\n /** Usage indicator values — omit the object to hide the bar. */\n usage?: { used: number; limit: number };\n /** Fires on upgrade. */\n onUpgrade: (planId: string) => void;\n /** Fires when the user dismisses via Not Now. */\n onCancel?: () => void;\n /** Title override; defaults to t('paywall.title'). */\n title?: ReactNode;\n /** Description override; defaults to t('paywall.description'). */\n description?: ReactNode;\n className?: string;\n}\n\nexport const FreemiumPaywall = forwardRef<HTMLDivElement, FreemiumPaywallProps>(\n (\n {\n open,\n onOpenChange,\n plans,\n selectedPlanId,\n defaultSelectedPlanId,\n onSelectedPlanChange,\n usage,\n onUpgrade,\n onCancel,\n title,\n description,\n layout = 'centered',\n density = 'full',\n className,\n },\n ref,\n ) => {\n const { t, i18n } = useTranslation();\n const titleId = useId();\n const descId = useId();\n\n const [currentSelectedRaw, handleSelectedChange] =\n useControllableState<string>({\n value: selectedPlanId,\n defaultValue: defaultSelectedPlanId ?? plans[0]?.id ?? '',\n onChange: onSelectedPlanChange,\n });\n const currentSelected = currentSelectedRaw ?? '';\n\n const handleCancel = () => {\n onCancel?.();\n onOpenChange(false);\n };\n\n const handleUpgrade = () => {\n if (!currentSelected) return;\n onUpgrade(currentSelected);\n };\n\n const openRef = useRef(open);\n openRef.current = open;\n const selectedRef = useRef<string>(currentSelected);\n selectedRef.current = currentSelected;\n\n const contentRef = useRef<HTMLDivElement>(null);\n useImperativeHandle(ref, () => contentRef.current as HTMLDivElement, []);\n\n const agentHandle = useMemo<FreemiumPaywallHandle>(\n () => ({\n isOpen: () => openRef.current,\n getSelectedPlanId: () => selectedRef.current || null,\n upgrade: () => handleUpgrade(),\n dismiss: () => handleCancel(),\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [],\n );\n useAgentRegistration(freemiumPaywallAgent, agentHandle, undefined);\n\n const usagePercent = usage\n ? Math.min(\n 100,\n Math.max(0, (usage.used / Math.max(1, usage.limit)) * 100),\n )\n : 0;\n const usageFull = usage ? usage.used >= usage.limit : false;\n\n return (\n <RadixAlertDialog.Root open={open} onOpenChange={onOpenChange}>\n <RadixAlertDialog.Portal>\n <RadixAlertDialog.Overlay\n className={[\n 'ds:fixed ds:inset-0 ds:z-[var(--z-modal-backdrop)]',\n 'ds:bg-[color:var(--background)]/70',\n 'ds:motion-safe:data-[state=open]:animate-in ds:motion-safe:data-[state=closed]:animate-out',\n 'ds:[.theme-accessible_&]:animate-none',\n ].join(' ')}\n />\n <RadixAlertDialog.Content\n ref={contentRef}\n aria-labelledby={titleId}\n aria-describedby={descId}\n className={contentVariants({ layout, density, className })}\n data-component=\"freemium-paywall\"\n >\n <RadixAlertDialog.Title id={titleId} asChild>\n <h2 className=\"type-title-card\">{title ?? t('paywall.title')}</h2>\n </RadixAlertDialog.Title>\n <RadixAlertDialog.Description id={descId} asChild>\n <p className=\"ds:mt-[var(--spacing-xs)] ds:text-[color:var(--muted-foreground)]\">\n {description ?? t('paywall.description')}\n </p>\n </RadixAlertDialog.Description>\n\n {usage ? (\n <div className=\"ds:mt-[var(--spacing-md)]\">\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-xs)] ds:mb-[var(--spacing-xs)]\">\n {usageFull ? (\n <AlertTriangle\n aria-hidden=\"true\"\n className=\"ds:size-4 ds:text-[color:var(--destructive)]\"\n />\n ) : null}\n <span\n className={[\n 'type-body-sm',\n usageFull\n ? 'ds:text-[color:var(--destructive)]'\n : 'ds:text-[color:var(--muted-foreground)]',\n ].join(' ')}\n >\n {usageFull\n ? t('paywall.usageFull')\n : t('paywall.usageLabel', {\n used: usage.used,\n limit: usage.limit,\n })}\n </span>\n </div>\n <Progress\n value={usagePercent}\n max={100}\n ariaLabel={t('paywall.usageLabel', {\n used: usage.used,\n limit: usage.limit,\n })}\n className={\n usageFull\n ? 'ds:[&_[role=progressbar]>*]:bg-[color:var(--destructive)]'\n : ''\n }\n />\n </div>\n ) : null}\n\n <RadixRadioGroup.Root\n value={currentSelected}\n onValueChange={handleSelectedChange}\n aria-label={t('paywall.title')}\n className=\"ds:mt-[var(--spacing-md)] ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n {plans.map((plan) => {\n // Reuse the payment-form helper — it knows about\n // zero-decimal currencies (JPY, KRW, VND …) and applies\n // the right divisor. Raw `/ 100` would 100× the price in\n // those currencies.\n const formattedPrice = formatPaymentAmount(\n plan.priceAmount,\n plan.currency,\n i18n.language,\n );\n const period = plan.perKey ? t(plan.perKey) : undefined;\n const priceLine = period\n ? t('paywall.pricePer', { price: formattedPrice, period })\n : formattedPrice;\n const planName = t(plan.nameKey);\n return (\n <RadixRadioGroup.Item\n key={plan.id}\n value={plan.id}\n className={[\n 'ds:group ds:relative ds:flex ds:flex-col ds:items-stretch',\n 'ds:rounded-[var(--radius-md)] ds:border ds:border-[color:var(--card-border)] ds:[.theme-accessible_&]:border-2',\n 'ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)] ds:pt-[var(--spacing-sm)] ds:pb-[var(--spacing-sm)]',\n 'ds:text-start ds:bg-[color:var(--card)] ds:text-[color:var(--card-foreground)]',\n 'ds:data-[state=checked]:border-[color:var(--primary)]',\n 'ds:data-[state=checked]:bg-[color:var(--primary)]/5',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[color:var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n ].join(' ')}\n >\n <span className=\"ds:flex ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)]\">\n <span className=\"ds:font-semibold\">{planName}</span>\n <span className=\"ds:tabular-nums\">{priceLine}</span>\n </span>\n {plan.featuresKeys && plan.featuresKeys.length > 0 ? (\n <ul\n aria-label={t('paywall.features')}\n className=\"ds:mt-[var(--spacing-xs)] ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\"\n >\n {plan.featuresKeys.map((key, i) => (\n <li\n key={i}\n className=\"ds:flex ds:items-start ds:gap-[var(--spacing-xs)] type-body-sm\"\n >\n <Check\n aria-hidden=\"true\"\n className=\"ds:size-4 ds:shrink-0 ds:text-[color:var(--primary)] ds:mt-[1px]\"\n />\n <span>{t(key)}</span>\n </li>\n ))}\n </ul>\n ) : null}\n </RadixRadioGroup.Item>\n );\n })}\n </RadixRadioGroup.Root>\n\n <div className=\"ds:mt-[var(--spacing-lg)] ds:flex ds:items-center ds:gap-[var(--spacing-sm)] ds:justify-end\">\n <RadixAlertDialog.Cancel asChild>\n <Button intent=\"outline\" onClick={handleCancel}>\n {t('paywall.notNow')}\n </Button>\n </RadixAlertDialog.Cancel>\n <RadixAlertDialog.Action asChild>\n <Button intent=\"primary\" onClick={handleUpgrade}>\n {t('paywall.upgrade')}\n </Button>\n </RadixAlertDialog.Action>\n </div>\n </RadixAlertDialog.Content>\n </RadixAlertDialog.Portal>\n </RadixAlertDialog.Root>\n );\n },\n);\n\nFreemiumPaywall.displayName = 'FreemiumPaywall';\n"],"names":["freemiumPaywallAgent","handle","contentVariants","cva","FreemiumPaywall","forwardRef","open","onOpenChange","plans","selectedPlanId","defaultSelectedPlanId","onSelectedPlanChange","usage","onUpgrade","onCancel","title","description","layout","density","className","ref","t","i18n","useTranslation","titleId","useId","descId","currentSelectedRaw","handleSelectedChange","useControllableState","_a","currentSelected","handleCancel","handleUpgrade","openRef","useRef","selectedRef","contentRef","useImperativeHandle","agentHandle","useMemo","useAgentRegistration","usagePercent","usageFull","jsx","RadixAlertDialog","jsxs","AlertTriangle","Progress","RadixRadioGroup","plan","formattedPrice","formatPaymentAmount","period","priceLine","planName","key","i","Check","Button"],"mappings":"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"}
1
+ {"version":3,"file":"freemium-paywall-DzpD63WY.js","sources":["../../src/components/freemium-paywall/freemium-paywall.agent.ts","../../src/components/freemium-paywall/freemium-paywall.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — FreemiumPaywall. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { FreemiumPaywallHandle } from './freemium-paywall';\n\nexport const freemiumPaywallAgent: AgentAdapter<FreemiumPaywallHandle> = {\n id: 'freemium-paywall',\n capabilities: ['submit', 'dismiss'],\n state: {\n isOpen: {\n type: 'boolean',\n descriptionKey: 'ui.agent.freemiumPaywall.state.isOpen',\n description: 'True when the paywall dialog is open.',\n read: (handle) => handle.isOpen(),\n },\n selectedPlanId: {\n type: 'string | null',\n descriptionKey: 'ui.agent.freemiumPaywall.state.selectedPlanId',\n description: 'Opaque id of the currently-selected plan.',\n read: (handle) => handle.getSelectedPlanId(),\n },\n },\n actions: {\n upgrade: {\n safety: 'write',\n descriptionKey: 'ui.agent.freemiumPaywall.actions.upgrade',\n description: 'Fire onUpgrade with the currently-selected plan id.',\n invoke: (handle) => {\n handle.upgrade();\n },\n },\n dismiss: {\n safety: 'destructive',\n descriptionKey: 'ui.agent.freemiumPaywall.actions.dismiss',\n description:\n 'Dismiss the paywall via the Not Now action. Irreversible from the same UI.',\n invoke: (handle) => {\n handle.dismiss();\n },\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'freemium-paywall',\n description: 'Marks the FreemiumPaywall dialog content.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n },\n};\n","import {\n forwardRef,\n useId,\n useImperativeHandle,\n useMemo,\n useRef,\n type ReactNode,\n} from 'react';\nimport * as RadixAlertDialog from '@radix-ui/react-alert-dialog';\nimport * as RadixRadioGroup from '@radix-ui/react-radio-group';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { useControllableState } from '../../hooks/use-controllable-state';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { freemiumPaywallAgent } from './freemium-paywall.agent';\nimport { AlertTriangle, Check } from 'lucide-react';\nimport { Button } from '../button';\nimport { Progress } from '../progress';\nimport { formatPaymentAmount } from '../payment-form';\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\n\nexport interface FreemiumPlan {\n id: string;\n /** Translation key for the plan name (e.g. `app.paywall.plans.pro`). */\n nameKey: string;\n /** Amount in minor units (cents, centesimi). */\n priceAmount: number;\n /** ISO 4217 currency code. */\n currency: string;\n /** Translation key for the cadence suffix (e.g. `app.paywall.period.month`). */\n perKey?: string;\n /** Per-line feature translation keys. */\n featuresKeys?: string[];\n}\n\nconst contentVariants = cva(\n [\n 'ds:fixed ds:z-[var(--z-modal)] ds:overflow-auto',\n 'ds:bg-[color:var(--popover)] ds:text-[color:var(--popover-foreground)]',\n 'ds:border ds:border-border ds:shadow-[var(--shadow-lg)]',\n // forced-colors: keep the dialog boundary visible under Windows High\n // Contrast, where `var(--border)` may collapse to system colours.\n 'ds:forced-colors:border-[CanvasText]',\n 'ds:focus:outline-none',\n ].join(' '),\n {\n variants: {\n layout: {\n centered:\n 'ds:start-1/2 ds:top-1/2 ds:-translate-x-1/2 ds:-translate-y-1/2 ds:rtl:translate-x-1/2 ds:rounded-[var(--radius-md)] ds:max-w-[var(--dialog-width-xl)] ds:w-[calc(100vw-2rem)] ds:max-h-[90vh]',\n sheet:\n 'ds:inset-inline-0 ds:bottom-0 ds:w-full ds:max-h-[90vh] ds:rounded-t-[var(--radius-md)]',\n },\n density: {\n compact:\n 'ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)] ds:pt-[var(--spacing-md)] ds:pb-[var(--spacing-md)]',\n full: 'ds:ps-[var(--spacing-lg)] ds:pe-[var(--spacing-lg)] ds:pt-[var(--spacing-lg)] ds:pb-[var(--spacing-lg)]',\n },\n },\n defaultVariants: { layout: 'centered', density: 'full' },\n },\n);\n\n/** Curated imperative handle for agent / external automation. */\nexport interface FreemiumPaywallHandle {\n isOpen: () => boolean;\n getSelectedPlanId: () => string | null;\n upgrade: () => void;\n dismiss: () => void;\n}\n\nexport interface FreemiumPaywallProps extends VariantProps<\n typeof contentVariants\n> {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n plans: FreemiumPlan[];\n /** Currently-selected plan id (controlled) or default. */\n selectedPlanId?: string;\n defaultSelectedPlanId?: string;\n onSelectedPlanChange?: (id: string) => void;\n /** Usage indicator values — omit the object to hide the bar. */\n usage?: { used: number; limit: number };\n /** Fires on upgrade. */\n onUpgrade: (planId: string) => void;\n /** Fires when the user dismisses via Not Now. */\n onCancel?: () => void;\n /** Title override; defaults to t('paywall.title'). */\n title?: ReactNode;\n /** Description override; defaults to t('paywall.description'). */\n description?: ReactNode;\n className?: string;\n}\n\nexport const FreemiumPaywall = forwardRef<HTMLDivElement, FreemiumPaywallProps>(\n (\n {\n open,\n onOpenChange,\n plans,\n selectedPlanId,\n defaultSelectedPlanId,\n onSelectedPlanChange,\n usage,\n onUpgrade,\n onCancel,\n title,\n description,\n layout = 'centered',\n density = 'full',\n className,\n },\n ref,\n ) => {\n const { t, i18n } = useTranslation();\n const titleId = useId();\n const descId = useId();\n\n const [currentSelectedRaw, handleSelectedChange] =\n useControllableState<string>({\n value: selectedPlanId,\n defaultValue: defaultSelectedPlanId ?? plans[0]?.id ?? '',\n onChange: onSelectedPlanChange,\n });\n const currentSelected = currentSelectedRaw ?? '';\n\n const handleCancel = () => {\n onCancel?.();\n onOpenChange(false);\n };\n\n const handleUpgrade = () => {\n if (!currentSelected) return;\n onUpgrade(currentSelected);\n };\n\n const openRef = useRef(open);\n openRef.current = open;\n const selectedRef = useRef<string>(currentSelected);\n selectedRef.current = currentSelected;\n\n const contentRef = useRef<HTMLDivElement>(null);\n useImperativeHandle(ref, () => contentRef.current as HTMLDivElement, []);\n\n const agentHandle = useMemo<FreemiumPaywallHandle>(\n () => ({\n isOpen: () => openRef.current,\n getSelectedPlanId: () => selectedRef.current || null,\n upgrade: () => handleUpgrade(),\n dismiss: () => handleCancel(),\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [],\n );\n useAgentRegistration(freemiumPaywallAgent, agentHandle, undefined);\n\n const usagePercent = usage\n ? Math.min(\n 100,\n Math.max(0, (usage.used / Math.max(1, usage.limit)) * 100),\n )\n : 0;\n const usageFull = usage ? usage.used >= usage.limit : false;\n\n return (\n <RadixAlertDialog.Root open={open} onOpenChange={onOpenChange}>\n <RadixAlertDialog.Portal>\n <RadixAlertDialog.Overlay\n className={[\n 'ds:fixed ds:inset-0 ds:z-[var(--z-modal-backdrop)]',\n 'ds:bg-[color:var(--background)]/70',\n 'ds:motion-safe:data-[state=open]:animate-in ds:motion-safe:data-[state=closed]:animate-out',\n 'ds:[.theme-accessible_&]:animate-none',\n ].join(' ')}\n />\n <RadixAlertDialog.Content\n ref={contentRef}\n aria-labelledby={titleId}\n aria-describedby={descId}\n className={contentVariants({ layout, density, className })}\n data-component=\"freemium-paywall\"\n >\n <RadixAlertDialog.Title id={titleId} asChild>\n <h2 className=\"type-title-card\">{title ?? t('paywall.title')}</h2>\n </RadixAlertDialog.Title>\n <RadixAlertDialog.Description id={descId} asChild>\n <p className=\"ds:mt-[var(--spacing-xs)] ds:text-[color:var(--muted-foreground)]\">\n {description ?? t('paywall.description')}\n </p>\n </RadixAlertDialog.Description>\n\n {usage ? (\n <div className=\"ds:mt-[var(--spacing-md)]\">\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-xs)] ds:mb-[var(--spacing-xs)]\">\n {usageFull ? (\n <AlertTriangle\n aria-hidden=\"true\"\n className=\"ds:size-4 ds:text-[color:var(--destructive)]\"\n />\n ) : null}\n <span\n className={[\n 'type-body-sm',\n usageFull\n ? 'ds:text-[color:var(--destructive)]'\n : 'ds:text-[color:var(--muted-foreground)]',\n ].join(' ')}\n >\n {usageFull\n ? t('paywall.usageFull')\n : t('paywall.usageLabel', {\n used: usage.used,\n limit: usage.limit,\n })}\n </span>\n </div>\n <Progress\n value={usagePercent}\n max={100}\n ariaLabel={t('paywall.usageLabel', {\n used: usage.used,\n limit: usage.limit,\n })}\n className={\n usageFull\n ? 'ds:[&_[role=progressbar]>*]:bg-[color:var(--destructive)]'\n : ''\n }\n />\n </div>\n ) : null}\n\n <RadixRadioGroup.Root\n value={currentSelected}\n onValueChange={handleSelectedChange}\n aria-label={t('paywall.title')}\n className=\"ds:mt-[var(--spacing-md)] ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n {plans.map((plan) => {\n // Reuse the payment-form helper — it knows about\n // zero-decimal currencies (JPY, KRW, VND …) and applies\n // the right divisor. Raw `/ 100` would 100× the price in\n // those currencies.\n const formattedPrice = formatPaymentAmount(\n plan.priceAmount,\n plan.currency,\n i18n.language,\n );\n const period = plan.perKey ? t(plan.perKey) : undefined;\n const priceLine = period\n ? t('paywall.pricePer', { price: formattedPrice, period })\n : formattedPrice;\n const planName = t(plan.nameKey);\n return (\n <RadixRadioGroup.Item\n key={plan.id}\n value={plan.id}\n className={[\n 'ds:group ds:relative ds:flex ds:flex-col ds:items-stretch',\n 'ds:rounded-[var(--radius-md)] ds:border ds:border-[color:var(--card-border)] ds:[.theme-accessible_&]:border-2',\n 'ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)] ds:pt-[var(--spacing-sm)] ds:pb-[var(--spacing-sm)]',\n 'ds:text-start ds:bg-[color:var(--card)] ds:text-[color:var(--card-foreground)]',\n 'ds:data-[state=checked]:border-[color:var(--primary)]',\n 'ds:data-[state=checked]:bg-[color:var(--primary)]/5',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[color:var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n ].join(' ')}\n >\n <span className=\"ds:flex ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)]\">\n <span className=\"ds:font-semibold\">{planName}</span>\n <span className=\"ds:tabular-nums\">{priceLine}</span>\n </span>\n {plan.featuresKeys && plan.featuresKeys.length > 0 ? (\n <ul\n aria-label={t('paywall.features')}\n className=\"ds:mt-[var(--spacing-xs)] ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\"\n >\n {plan.featuresKeys.map((key, i) => (\n <li\n key={i}\n className=\"ds:flex ds:items-start ds:gap-[var(--spacing-xs)] type-body-sm\"\n >\n <Check\n aria-hidden=\"true\"\n className=\"ds:size-4 ds:shrink-0 ds:text-[color:var(--primary)] ds:mt-[1px]\"\n />\n <span>{t(key)}</span>\n </li>\n ))}\n </ul>\n ) : null}\n </RadixRadioGroup.Item>\n );\n })}\n </RadixRadioGroup.Root>\n\n <div className=\"ds:mt-[var(--spacing-lg)] ds:flex ds:items-center ds:gap-[var(--spacing-sm)] ds:justify-end\">\n <RadixAlertDialog.Cancel asChild>\n <Button intent=\"outline\" onClick={handleCancel}>\n {t('paywall.notNow')}\n </Button>\n </RadixAlertDialog.Cancel>\n <RadixAlertDialog.Action asChild>\n <Button intent=\"primary\" onClick={handleUpgrade}>\n {t('paywall.upgrade')}\n </Button>\n </RadixAlertDialog.Action>\n </div>\n </RadixAlertDialog.Content>\n </RadixAlertDialog.Portal>\n </RadixAlertDialog.Root>\n );\n },\n);\n\nFreemiumPaywall.displayName = 'FreemiumPaywall';\n"],"names":["freemiumPaywallAgent","handle","contentVariants","cva","FreemiumPaywall","forwardRef","open","onOpenChange","plans","selectedPlanId","defaultSelectedPlanId","onSelectedPlanChange","usage","onUpgrade","onCancel","title","description","layout","density","className","ref","t","i18n","useTranslation","titleId","useId","descId","currentSelectedRaw","handleSelectedChange","useControllableState","_a","currentSelected","handleCancel","handleUpgrade","openRef","useRef","selectedRef","contentRef","useImperativeHandle","agentHandle","useMemo","useAgentRegistration","usagePercent","usageFull","jsx","RadixAlertDialog","jsxs","AlertTriangle","Progress","RadixRadioGroup","plan","formattedPrice","formatPaymentAmount","period","priceLine","planName","key","i","Check","Button"],"mappings":"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"}
@@ -1,19 +1,19 @@
1
- import { jsx as t, jsxs as m, Fragment as oe } from "react/jsx-runtime";
2
- import { forwardRef as ie, useState as z, useEffect as D, useRef as q, useMemo as G, useImperativeHandle as de, useId as ce, useCallback as le } from "react";
3
- import { c as R } from "./index-D2ZczOXr.js";
4
- import { useTranslation as K } from "react-i18next";
5
- import { S as re } from "./spinner-OjQNn8oN.js";
6
- import { A as Q } from "./alert-ywPR59NE.js";
7
- import { loadStripe as me } from "@stripe/stripe-js";
8
- import { Elements as ue, useStripe as pe, useElements as fe, PaymentElement as be, AddressElement as ve } from "@stripe/react-stripe-js";
9
- import { u as ye } from "./registry-nPAVE19X.js";
10
- function te() {
1
+ import { jsx as t, jsxs as u, Fragment as ie } from "react/jsx-runtime";
2
+ import { forwardRef as de, useState as _, useEffect as D, useRef as G, useMemo as H, useImperativeHandle as ce, useId as le, useCallback as me } from "react";
3
+ import { c as A } from "./index-D2ZczOXr.js";
4
+ import { useTranslation as W } from "react-i18next";
5
+ import { S as te } from "./spinner-OjQNn8oN.js";
6
+ import { A as ee } from "./alert-ywPR59NE.js";
7
+ import { loadStripe as ue } from "@stripe/stripe-js";
8
+ import { Elements as pe, useStripe as fe, useElements as be, PaymentElement as ye, AddressElement as ge } from "@stripe/react-stripe-js";
9
+ import { u as ve } from "./registry-nPAVE19X.js";
10
+ function ne() {
11
11
  return typeof document < "u" && typeof window < "u";
12
12
  }
13
- function H(r) {
14
- if (!te())
13
+ function O(r) {
14
+ if (!ne())
15
15
  return { theme: "stripe" };
16
- const n = r ?? document.documentElement, s = getComputedStyle(n), e = (a) => s.getPropertyValue(a).trim();
16
+ const n = r ?? document.documentElement, a = getComputedStyle(n), e = (s) => a.getPropertyValue(s).trim();
17
17
  return {
18
18
  theme: n.classList.contains("theme-dark") ? "night" : "stripe",
19
19
  variables: {
@@ -65,24 +65,46 @@ function H(r) {
65
65
  borderColor: e("--primary"),
66
66
  backgroundColor: e("--background"),
67
67
  color: e("--primary")
68
+ },
69
+ // Accordion method rows (the `accordion` layout): keep Stripe's native
70
+ // per-method card structure, restyled with our tokens — our border +
71
+ // radius, our background, `--primary` on the selected row, no extra shadow.
72
+ ".AccordionItem": {
73
+ backgroundColor: e("--background"),
74
+ border: `1px solid ${e("--border")}`,
75
+ borderRadius: e("--radius-md"),
76
+ boxShadow: "none"
77
+ },
78
+ ".AccordionItem--selected": {
79
+ borderColor: e("--primary"),
80
+ backgroundColor: e("--background")
81
+ },
82
+ // Stripe's in-method notice blocks (e.g. PayPal's "you'll be redirected")
83
+ // otherwise render in their own bordered box — a card nested inside the
84
+ // selected method card. Flatten to inline icon + text, no inner box.
85
+ ".Block": {
86
+ border: "none",
87
+ borderRadius: "0",
88
+ boxShadow: "none",
89
+ backgroundColor: "transparent"
68
90
  }
69
91
  }
70
92
  };
71
93
  }
72
- function ge(r, n) {
73
- if (!te()) return () => {
94
+ function he(r, n) {
95
+ if (!ne()) return () => {
74
96
  };
75
- const s = document.documentElement, e = () => r(H(n)), o = new MutationObserver(e);
76
- o.observe(s, {
97
+ const a = document.documentElement, e = () => r(O(n)), o = new MutationObserver(e);
98
+ o.observe(a, {
77
99
  attributes: !0,
78
100
  attributeFilter: ["class", "dir", "lang"]
79
101
  });
80
- const a = window.matchMedia("(prefers-color-scheme: dark)"), c = window.matchMedia("(prefers-reduced-motion: reduce)");
81
- return a.addEventListener("change", e), c.addEventListener("change", e), () => {
82
- o.disconnect(), a.removeEventListener("change", e), c.removeEventListener("change", e);
102
+ const s = window.matchMedia("(prefers-color-scheme: dark)"), c = window.matchMedia("(prefers-reduced-motion: reduce)");
103
+ return s.addEventListener("change", e), c.addEventListener("change", e), () => {
104
+ o.disconnect(), s.removeEventListener("change", e), c.removeEventListener("change", e);
83
105
  };
84
106
  }
85
- const he = {
107
+ const we = {
86
108
  id: "payment-form",
87
109
  capabilities: ["submit"],
88
110
  state: {},
@@ -108,7 +130,7 @@ const he = {
108
130
  description: "Sourced from the id prop."
109
131
  }
110
132
  }
111
- }, we = /* @__PURE__ */ new Set([
133
+ }, xe = /* @__PURE__ */ new Set([
112
134
  "BIF",
113
135
  "CLP",
114
136
  "DJF",
@@ -127,10 +149,10 @@ const he = {
127
149
  "XOF",
128
150
  "XPF"
129
151
  ]);
130
- function O(r, n, s) {
131
- const e = n.toUpperCase(), o = we.has(e) ? r : r / 100;
152
+ function K(r, n, a) {
153
+ const e = n.toUpperCase(), o = xe.has(e) ? r : r / 100;
132
154
  try {
133
- return new Intl.NumberFormat(s, {
155
+ return new Intl.NumberFormat(a, {
134
156
  style: "currency",
135
157
  currency: e
136
158
  }).format(o);
@@ -141,21 +163,21 @@ function O(r, n, s) {
141
163
  }).format(o);
142
164
  }
143
165
  }
144
- function xe(r) {
166
+ function ke(r) {
145
167
  if (r === void 0) return null;
146
168
  const n = r.trim();
147
169
  if (n === "" || typeof window > "u") return null;
148
170
  try {
149
- const s = new URL(n, window.location.href);
150
- return !(/* @__PURE__ */ new Set(["http:", "https:"])).has(s.protocol) || s.origin !== window.location.origin ? null : s.toString();
171
+ const a = new URL(n, window.location.href);
172
+ return !(/* @__PURE__ */ new Set(["http:", "https:"])).has(a.protocol) || a.origin !== window.location.origin ? null : a.toString();
151
173
  } catch {
152
174
  return null;
153
175
  }
154
176
  }
155
- function Ee(r) {
177
+ function Ce(r) {
156
178
  return r && r.replace(/\d{4,}/g, "****");
157
179
  }
158
- function Ne(r) {
180
+ function Ee(r) {
159
181
  switch (r) {
160
182
  case "incorrect_number":
161
183
  case "invalid_number":
@@ -181,20 +203,21 @@ function Ne(r) {
181
203
  return "payment.error.generic";
182
204
  }
183
205
  }
184
- const ke = R(
206
+ const Ie = A(
185
207
  [
186
208
  "ds:payment-form-alfadocs ds:flex ds:flex-col",
187
209
  "ds:gap-[var(--spacing-md)]",
188
- "ds:bg-[var(--background)] ds:text-[var(--foreground)]",
189
- "ds:rounded-[var(--radius-md)] ds:border ds:border-[color:var(--card-border)] ds:shadow-[var(--shadow-card)] ds:[.theme-accessible_&]:border-2",
190
- "ds:p-[var(--spacing-md)]",
210
+ // Transparent, padding-less container — the consuming surface (a Card, the
211
+ // check-in step, a checkout column) owns the card chrome + padding, so the
212
+ // Stripe method boxes never read as cards nested inside another card.
213
+ "ds:text-[var(--foreground)]",
191
214
  "ds:aria-disabled:opacity-[var(--opacity-50)] ds:aria-disabled:cursor-not-allowed"
192
215
  ].join(" ")
193
- ), V = R(
216
+ ), B = A(
194
217
  ["ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]"].join(" ")
195
- ), F = R(
218
+ ), z = A(
196
219
  ["type-label", "ds:text-[var(--foreground)]"].join(" ")
197
- ), ne = R(
220
+ ), ae = A(
198
221
  [
199
222
  "ds:flex ds:items-baseline ds:justify-between",
200
223
  "ds:gap-[var(--spacing-sm)]",
@@ -204,7 +227,7 @@ const ke = R(
204
227
  "ds:rounded-[var(--radius-sm)]",
205
228
  "ds:text-[var(--foreground)]"
206
229
  ].join(" ")
207
- ), se = R(
230
+ ), se = A(
208
231
  [
209
232
  "ds:inline-flex ds:items-center ds:justify-center ds:gap-[var(--spacing-xs)]",
210
233
  "ds:[min-block-size:var(--min-target-size)]",
@@ -224,175 +247,179 @@ const ke = R(
224
247
  "ds:aria-busy:cursor-wait"
225
248
  ].join(" ")
226
249
  );
227
- function Ce(r) {
250
+ function Ne(r) {
228
251
  const {
229
252
  amount: n,
230
- currency: s,
253
+ currency: a,
231
254
  locale: e,
232
255
  billingAddress: o,
233
- returnUrl: a,
256
+ returnUrl: s,
234
257
  clientSecret: c,
235
258
  onCreatePaymentIntent: I,
236
- onSuccess: P,
237
- onError: _
238
- } = r, { t: i } = K(), h = pe(), v = fe(), w = ce(), y = G(
239
- () => `pay-${w.replace(/[^a-zA-Z0-9-_]/g, "")}`,
240
- [w]
241
- ), M = `${y}-payment`, T = `${y}-address`, g = `${y}-error`, [u, x] = z(!1), [L, U] = z(!1), [E, S] = z(null), [j, l] = z(""), d = q(P), N = q(_);
259
+ onSuccess: F,
260
+ onError: N,
261
+ layout: V
262
+ } = r, { t: i } = W(), h = fe(), l = be(), R = le(), g = H(
263
+ () => `pay-${R.replace(/[^a-zA-Z0-9-_]/g, "")}`,
264
+ [R]
265
+ ), M = `${g}-payment`, T = `${g}-address`, v = `${g}-error`, [p, w] = _(!1), [P, U] = _(!1), [x, S] = _(null), [$, m] = _(""), d = G(F), k = G(N);
242
266
  D(() => {
243
- d.current = P, N.current = _;
244
- }, [P, _]);
245
- const B = le(
246
- async (p) => {
247
- var X, Z, J;
248
- if (p && p.preventDefault(), !h || !v || u) return;
249
- x(!0), S(null), l("");
250
- const k = (f, A) => {
251
- var Y;
252
- const b = Ne(f), C = Ee(A ?? "");
253
- S(b), l(i(b)), (Y = N.current) == null || Y.call(N, {
254
- code: f,
255
- translatedMessage: C || i(b)
267
+ d.current = F, k.current = N;
268
+ }, [F, N]);
269
+ const j = me(
270
+ async (f) => {
271
+ var Z, J, Y;
272
+ if (f && f.preventDefault(), !h || !l || p) return;
273
+ w(!0), S(null), m("");
274
+ const C = (b, L) => {
275
+ var Q;
276
+ const y = Ee(b), E = Ce(L ?? "");
277
+ S(y), m(i(y)), (Q = k.current) == null || Q.call(k, {
278
+ code: b,
279
+ translatedMessage: E || i(y)
256
280
  });
257
- }, $ = xe(a);
258
- if (a !== void 0 && $ === null) {
259
- S("payment.error.invalidReturnUrl"), l(i("payment.error.invalidReturnUrl")), (X = N.current) == null || X.call(N, {
281
+ }, q = ke(s);
282
+ if (s !== void 0 && q === null) {
283
+ S("payment.error.invalidReturnUrl"), m(i("payment.error.invalidReturnUrl")), (Z = k.current) == null || Z.call(k, {
260
284
  code: "invalid_return_url",
261
285
  translatedMessage: i("payment.error.invalidReturnUrl")
262
- }), x(!1);
286
+ }), w(!1);
263
287
  return;
264
288
  }
265
- const W = $ ? { return_url: $ } : {};
289
+ const X = q ? { return_url: q } : {};
266
290
  try {
267
291
  if (c !== void 0) {
268
- const C = await h.confirmPayment({
269
- elements: v,
270
- confirmParams: W,
292
+ const E = await h.confirmPayment({
293
+ elements: l,
294
+ confirmParams: X,
271
295
  redirect: "if_required"
272
296
  });
273
- if (C.error) {
274
- k(C.error.code ?? "generic", C.error.message);
297
+ if (E.error) {
298
+ C(E.error.code ?? "generic", E.error.message);
275
299
  return;
276
300
  }
277
- C.paymentIntent && ((Z = d.current) == null || Z.call(d, C.paymentIntent.id));
301
+ E.paymentIntent && ((J = d.current) == null || J.call(d, E.paymentIntent.id));
278
302
  return;
279
303
  }
280
- const { error: f } = await v.submit();
281
- if (f) {
282
- k(f.code ?? "generic", f.message);
304
+ const { error: b } = await l.submit();
305
+ if (b) {
306
+ C(b.code ?? "generic", b.message);
283
307
  return;
284
308
  }
285
309
  if (!I)
286
310
  return;
287
- const A = await I(), b = await h.confirmPayment({
288
- elements: v,
289
- clientSecret: A,
290
- confirmParams: W,
311
+ const L = await I(), y = await h.confirmPayment({
312
+ elements: l,
313
+ clientSecret: L,
314
+ confirmParams: X,
291
315
  redirect: "if_required"
292
316
  });
293
- if (b.error) {
294
- k(b.error.code ?? "generic", b.error.message);
317
+ if (y.error) {
318
+ C(y.error.code ?? "generic", y.error.message);
295
319
  return;
296
320
  }
297
- b.paymentIntent && ((J = d.current) == null || J.call(d, b.paymentIntent.id));
298
- } catch (f) {
299
- const A = f instanceof Error ? f.message : "";
300
- k("unexpected", A);
321
+ y.paymentIntent && ((Y = d.current) == null || Y.call(d, y.paymentIntent.id));
322
+ } catch (b) {
323
+ const L = b instanceof Error ? b.message : "";
324
+ C("unexpected", L);
301
325
  } finally {
302
- x(!1);
326
+ w(!1);
303
327
  }
304
328
  },
305
329
  [
306
330
  h,
307
- v,
308
- u,
309
- a,
331
+ l,
332
+ p,
333
+ s,
310
334
  c,
311
335
  I,
312
336
  i
313
337
  ]
314
338
  );
315
339
  D(() => {
316
- const p = document.getElementById(y);
317
- if (!p) return;
318
- const k = () => {
319
- B();
340
+ const f = document.getElementById(g);
341
+ if (!f) return;
342
+ const C = () => {
343
+ j();
320
344
  };
321
- return p.addEventListener("payment-form:submit", k), () => p.removeEventListener("payment-form:submit", k);
322
- }, [y, B]);
323
- const ae = !h || !v || u || !(c === void 0 && !I) && !L;
345
+ return f.addEventListener("payment-form:submit", C), () => f.removeEventListener("payment-form:submit", C);
346
+ }, [g, j]);
347
+ const oe = !h || !l || p || !(c === void 0 && !I) && !P;
324
348
  return /* @__PURE__ */ t(
325
349
  "form",
326
350
  {
327
- id: y,
328
- onSubmit: B,
351
+ id: g,
352
+ onSubmit: j,
329
353
  "aria-label": i("payment.ariaLabel"),
330
- "aria-busy": u || void 0,
354
+ "aria-busy": p || void 0,
331
355
  noValidate: !0,
332
- children: /* @__PURE__ */ m("div", { className: "ds:flex ds:flex-col ds:gap-[var(--spacing-md)]", children: [
333
- /* @__PURE__ */ m("div", { className: ne(), children: [
334
- /* @__PURE__ */ t("span", { className: F(), children: i("payment.amountLabel") }),
335
- /* @__PURE__ */ t("span", { className: "type-title-card", "data-testid": "payment-amount", children: O(n, s, e) })
356
+ children: /* @__PURE__ */ u("div", { className: "ds:flex ds:flex-col ds:gap-[var(--spacing-md)]", children: [
357
+ /* @__PURE__ */ u("div", { className: ae(), children: [
358
+ /* @__PURE__ */ t("span", { className: z(), children: i("payment.amountLabel") }),
359
+ /* @__PURE__ */ t("span", { className: "type-title-card", "data-testid": "payment-amount", children: K(n, a, e) })
336
360
  ] }),
337
- /* @__PURE__ */ m(
361
+ /* @__PURE__ */ u(
338
362
  "label",
339
363
  {
340
364
  htmlFor: M,
341
- className: V(),
365
+ className: B(),
342
366
  "data-testid": "payment-field",
343
367
  children: [
344
- /* @__PURE__ */ t("span", { className: F(), children: i("payment.fields.card") }),
368
+ /* @__PURE__ */ t("span", { className: z(), children: i("payment.fields.card") }),
345
369
  /* @__PURE__ */ t(
346
- be,
370
+ ye,
347
371
  {
348
372
  id: M,
349
373
  options: {
350
- layout: { type: "accordion", defaultCollapsed: !1 }
374
+ // `tabs` = method tiles (Card selected by default); `accordion`
375
+ // = full-width stacked rows for narrow columns where the tab row
376
+ // clips. Stripe owns overflow + tab alignment either way.
377
+ layout: V === "accordion" ? { type: "accordion", defaultCollapsed: !0 } : { type: "tabs" }
351
378
  },
352
- onChange: (p) => {
353
- U(p.complete === !0), p.complete && (S(null), l(""));
379
+ onChange: (f) => {
380
+ U(f.complete === !0), f.complete && (S(null), m(""));
354
381
  }
355
382
  }
356
383
  )
357
384
  ]
358
385
  }
359
386
  ),
360
- o ? /* @__PURE__ */ m(
387
+ o ? /* @__PURE__ */ u(
361
388
  "label",
362
389
  {
363
390
  htmlFor: T,
364
- className: V(),
391
+ className: B(),
365
392
  "data-testid": "payment-address",
366
393
  children: [
367
- /* @__PURE__ */ t("span", { className: F(), children: i("payment.billingAddress") }),
368
- /* @__PURE__ */ t(ve, { id: T, options: { mode: "billing" } })
394
+ /* @__PURE__ */ t("span", { className: z(), children: i("payment.billingAddress") }),
395
+ /* @__PURE__ */ t(ge, { id: T, options: { mode: "billing" } })
369
396
  ]
370
397
  }
371
398
  ) : null,
372
- E ? /* @__PURE__ */ t(
373
- Q,
399
+ x ? /* @__PURE__ */ t(
400
+ ee,
374
401
  {
375
- id: g,
402
+ id: v,
376
403
  variant: "error",
377
404
  live: "polite",
378
405
  "data-testid": "payment-error",
379
- children: /* @__PURE__ */ t(Q.Description, { children: j })
406
+ children: /* @__PURE__ */ t(ee.Description, { children: $ })
380
407
  }
381
408
  ) : null,
382
409
  /* @__PURE__ */ t(
383
410
  "button",
384
411
  {
385
412
  type: "submit",
386
- "aria-disabled": ae || void 0,
387
- "aria-busy": u || void 0,
388
- "aria-describedby": E ? g : void 0,
413
+ "aria-disabled": oe || void 0,
414
+ "aria-busy": p || void 0,
415
+ "aria-describedby": x ? v : void 0,
389
416
  className: se(),
390
417
  "data-testid": "payment-submit",
391
- children: u ? /* @__PURE__ */ m(oe, { children: [
392
- /* @__PURE__ */ t(re, { size: "sm", label: i("payment.processing") }),
418
+ children: p ? /* @__PURE__ */ u(ie, { children: [
419
+ /* @__PURE__ */ t(te, { size: "sm", label: i("payment.processing") }),
393
420
  /* @__PURE__ */ t("span", { children: i("payment.processing") })
394
421
  ] }) : /* @__PURE__ */ t("span", { children: i("payment.submit", {
395
- amount: O(n, s, e)
422
+ amount: K(n, a, e)
396
423
  }) })
397
424
  }
398
425
  )
@@ -400,7 +427,7 @@ function Ce(r) {
400
427
  }
401
428
  );
402
429
  }
403
- const ee = /* @__PURE__ */ new Set([
430
+ const re = /* @__PURE__ */ new Set([
404
431
  "auto",
405
432
  "ar",
406
433
  "bg",
@@ -452,127 +479,129 @@ const ee = /* @__PURE__ */ new Set([
452
479
  "zh-HK",
453
480
  "zh-TW"
454
481
  ]);
455
- function Ie(r) {
482
+ function Se(r) {
456
483
  if (!r) return "auto";
457
484
  const n = r === "cn" ? "zh" : r;
458
- if (ee.has(n))
485
+ if (re.has(n))
459
486
  return n;
460
- const s = n.split("-")[0];
461
- return ee.has(s) ? s : "auto";
487
+ const a = n.split("-")[0];
488
+ return re.has(a) ? a : "auto";
462
489
  }
463
- const _e = ie(
490
+ const _e = de(
464
491
  ({
465
492
  id: r,
466
493
  clientSecret: n,
467
- mode: s = "payment",
494
+ mode: a = "payment",
468
495
  onCreatePaymentIntent: e,
469
496
  publishableKey: o,
470
- currency: a,
497
+ currency: s,
471
498
  amount: c,
472
499
  onSuccess: I,
473
- onError: P,
474
- billingAddress: _ = !1,
475
- locale: i,
476
- ariaLabel: h,
477
- returnUrl: v,
478
- stripePromise: w,
479
- className: y
500
+ onError: F,
501
+ billingAddress: N = !1,
502
+ locale: V,
503
+ ariaLabel: i,
504
+ returnUrl: h,
505
+ stripePromise: l,
506
+ layout: R = "tabs",
507
+ className: g
480
508
  }, M) => {
481
- const { i18n: T } = K(), g = Ie(i ?? T.language ?? "en"), [u, x] = z(w ?? null);
509
+ const { i18n: T } = W(), v = Se(V ?? T.language ?? "en"), [p, w] = _(l ?? null);
482
510
  D(() => {
483
- if (w !== void 0) {
484
- x(w);
511
+ if (l !== void 0) {
512
+ w(l);
485
513
  return;
486
514
  }
487
515
  if (!o) {
488
- x(null);
516
+ w(null);
489
517
  return;
490
518
  }
491
- x(me(o));
492
- }, [w, o]);
493
- const [L, U] = z(
494
- () => H()
519
+ w(ue(o));
520
+ }, [l, o]);
521
+ const [P, U] = _(
522
+ () => O()
495
523
  );
496
- D(() => (U(H()), ge(U)), []);
497
- const E = q(null), S = G(
524
+ D(() => (U(O()), he(U)), []);
525
+ const x = G(null), S = H(
498
526
  () => ({
499
527
  submit: async () => {
500
528
  var d;
501
- const l = (d = E.current) == null ? void 0 : d.querySelector("form");
502
- l && l.dispatchEvent(
529
+ const m = (d = x.current) == null ? void 0 : d.querySelector("form");
530
+ m && m.dispatchEvent(
503
531
  new CustomEvent("payment-form:submit", { bubbles: !0 })
504
532
  );
505
533
  },
506
534
  reset: () => {
507
535
  var d;
508
- const l = (d = E.current) == null ? void 0 : d.querySelector("form");
509
- l instanceof HTMLFormElement && l.reset();
536
+ const m = (d = x.current) == null ? void 0 : d.querySelector("form");
537
+ m instanceof HTMLFormElement && m.reset();
510
538
  }
511
539
  }),
512
540
  []
513
541
  );
514
- de(M, () => E.current, []), ye(he, S, r);
515
- const j = G(
542
+ ce(M, () => x.current, []), ve(we, S, r);
543
+ const $ = H(
516
544
  () => n !== void 0 ? (
517
545
  // Immediate mode — the consumer already created the intent.
518
- { clientSecret: n, appearance: L, locale: g }
546
+ { clientSecret: n, appearance: P, locale: v }
519
547
  ) : (
520
548
  // Deferred-intent mode — no secret yet; Stripe needs the intent
521
549
  // shape (mode + amount + currency) to render the Payment Element.
522
550
  // Stripe expects a lowercase ISO-4217 currency here.
523
551
  {
524
- mode: s,
552
+ mode: a,
525
553
  amount: c,
526
- currency: a.toLowerCase(),
527
- appearance: L,
528
- locale: g
554
+ currency: s.toLowerCase(),
555
+ appearance: P,
556
+ locale: v
529
557
  }
530
558
  ),
531
- [n, s, c, a, L, g]
559
+ [n, a, c, s, P, v]
532
560
  );
533
561
  return /* @__PURE__ */ t(
534
562
  "div",
535
563
  {
536
- ref: E,
537
- "aria-label": h,
538
- className: [ke(), y].filter(Boolean).join(" "),
564
+ ref: x,
565
+ "aria-label": i,
566
+ className: [Ie(), g].filter(Boolean).join(" "),
539
567
  "data-component": "payment-form",
540
568
  "data-component-id": r,
541
569
  "data-testid": "payment-form-root",
542
- children: u ? (
570
+ children: p ? (
543
571
  // Render the real Payment Element whenever a Stripe instance is
544
572
  // available — in immediate mode (clientSecret present) AND in
545
573
  // deferred mode (no secret). The skeleton is reserved for the
546
574
  // no-Stripe case (missing publishableKey / injected null).
547
575
  /* @__PURE__ */ t(
548
- ue,
576
+ pe,
549
577
  {
550
- stripe: u,
551
- options: j,
578
+ stripe: p,
579
+ options: $,
552
580
  children: /* @__PURE__ */ t(
553
- Ce,
581
+ Ne,
554
582
  {
555
583
  amount: c,
556
- currency: a,
557
- locale: g,
558
- billingAddress: _,
559
- returnUrl: v,
584
+ currency: s,
585
+ locale: v,
586
+ billingAddress: N,
587
+ returnUrl: h,
560
588
  clientSecret: n,
561
589
  onCreatePaymentIntent: e,
562
590
  onSuccess: I,
563
- onError: P
591
+ onError: F,
592
+ layout: R
564
593
  }
565
594
  )
566
595
  },
567
596
  n ?? "deferred"
568
597
  )
569
598
  ) : /* @__PURE__ */ t(
570
- Se,
599
+ ze,
571
600
  {
572
601
  amount: c,
573
- currency: a,
574
- locale: g,
575
- billingAddress: _
602
+ currency: s,
603
+ locale: v,
604
+ billingAddress: N
576
605
  }
577
606
  )
578
607
  }
@@ -580,21 +609,21 @@ const _e = ie(
580
609
  }
581
610
  );
582
611
  _e.displayName = "PaymentForm";
583
- function Se(r) {
584
- const { amount: n, currency: s, locale: e, billingAddress: o } = r, { t: a } = K();
585
- return /* @__PURE__ */ m(
612
+ function ze(r) {
613
+ const { amount: n, currency: a, locale: e, billingAddress: o } = r, { t: s } = W();
614
+ return /* @__PURE__ */ u(
586
615
  "div",
587
616
  {
588
617
  className: "ds:flex ds:flex-col ds:gap-[var(--spacing-md)]",
589
618
  "data-testid": "payment-skeleton",
590
619
  "aria-busy": "true",
591
620
  children: [
592
- /* @__PURE__ */ m("div", { className: ne(), children: [
593
- /* @__PURE__ */ t("span", { className: F(), children: a("payment.amountLabel") }),
594
- /* @__PURE__ */ t("span", { className: "type-title-card", children: O(n, s, e) })
621
+ /* @__PURE__ */ u("div", { className: ae(), children: [
622
+ /* @__PURE__ */ t("span", { className: z(), children: s("payment.amountLabel") }),
623
+ /* @__PURE__ */ t("span", { className: "type-title-card", children: K(n, a, e) })
595
624
  ] }),
596
- /* @__PURE__ */ m("div", { className: V(), children: [
597
- /* @__PURE__ */ t("span", { className: F(), children: a("payment.fields.card") }),
625
+ /* @__PURE__ */ u("div", { className: B(), children: [
626
+ /* @__PURE__ */ t("span", { className: z(), children: s("payment.fields.card") }),
598
627
  /* @__PURE__ */ t(
599
628
  "div",
600
629
  {
@@ -603,8 +632,8 @@ function Se(r) {
603
632
  }
604
633
  )
605
634
  ] }),
606
- o ? /* @__PURE__ */ m("div", { className: V(), "data-testid": "payment-address", children: [
607
- /* @__PURE__ */ t("span", { className: F(), children: a("payment.billingAddress") }),
635
+ o ? /* @__PURE__ */ u("div", { className: B(), "data-testid": "payment-address", children: [
636
+ /* @__PURE__ */ t("span", { className: z(), children: s("payment.billingAddress") }),
608
637
  /* @__PURE__ */ t(
609
638
  "div",
610
639
  {
@@ -613,7 +642,7 @@ function Se(r) {
613
642
  }
614
643
  )
615
644
  ] }) : null,
616
- /* @__PURE__ */ m(
645
+ /* @__PURE__ */ u(
617
646
  "button",
618
647
  {
619
648
  type: "button",
@@ -621,8 +650,8 @@ function Se(r) {
621
650
  className: se(),
622
651
  disabled: !0,
623
652
  children: [
624
- /* @__PURE__ */ t(re, { size: "sm", label: a("payment.processing") }),
625
- /* @__PURE__ */ t("span", { children: a("payment.processing") })
653
+ /* @__PURE__ */ t(te, { size: "sm", label: s("payment.processing") }),
654
+ /* @__PURE__ */ t("span", { children: s("payment.processing") })
626
655
  ]
627
656
  }
628
657
  )
@@ -632,11 +661,11 @@ function Se(r) {
632
661
  }
633
662
  export {
634
663
  _e as P,
635
- ke as a,
636
- Ee as b,
637
- Ne as c,
638
- O as f,
639
- he as p,
664
+ Ie as a,
665
+ Ce as b,
666
+ Ee as c,
667
+ K as f,
668
+ we as p,
640
669
  se as s
641
670
  };
642
- //# sourceMappingURL=payment-form-DqEiEJRO.js.map
671
+ //# sourceMappingURL=payment-form-BNTx4876.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payment-form-BNTx4876.js","sources":["../../src/tokens/themes/bridges/stripe-appearance.ts","../../src/components/payment-form/payment-form.agent.ts","../../src/components/payment-form/payment-form.tsx"],"sourcesContent":["import type { Appearance } from '@stripe/stripe-js';\n\n/**\n * Reads the current design-system tokens from a theme-root element and maps\n * them to Stripe Elements' Appearance API. `root` defaults to\n * `document.documentElement` but consumers can pass a scoped theme wrapper\n * (e.g. a modal with its own `.theme-accessible` override) so that Stripe\n * iframes pick up the right token set.\n *\n * Tokens referenced: --primary, --background, --foreground, --muted,\n * --muted-foreground, --border, --destructive, --radius-md, --font-sans,\n * --font-size-base, --spacing-sm, --animation-duration, --focus-ring-width,\n * --ring.\n *\n * No hex / rgb / hsl literals — every value flows from the token layer.\n */\n\nfunction isBrowser(): boolean {\n return typeof document !== 'undefined' && typeof window !== 'undefined';\n}\n\nexport function getStripeAppearance(root?: HTMLElement): Appearance {\n if (!isBrowser()) {\n return { theme: 'stripe' };\n }\n\n const target = root ?? document.documentElement;\n const styles = getComputedStyle(target);\n const read = (token: string) => styles.getPropertyValue(token).trim();\n const isDark = target.classList.contains('theme-dark');\n\n return {\n theme: isDark ? 'night' : 'stripe',\n variables: {\n colorPrimary: read('--primary'),\n colorBackground: read('--background'),\n colorText: read('--foreground'),\n colorDanger: read('--destructive'),\n colorTextSecondary: read('--muted-foreground'),\n colorTextPlaceholder: read('--muted-foreground'),\n borderRadius: read('--radius-md'),\n fontFamily: read('--font-sans'),\n fontSizeBase: read('--font-size-base'),\n // Stripe multiplies spacingUnit throughout every Element; --spacing-sm\n // gives readable density. Keep this in sync with the JSDoc above.\n spacingUnit: read('--spacing-sm'),\n },\n rules: {\n '.Input': {\n backgroundColor: read('--background'),\n border: `1px solid ${read('--border')}`,\n color: read('--foreground'),\n padding: read('--spacing-sm'),\n transition: `border-color ${read('--animation-duration')} ease-out`,\n },\n '.Input:focus': {\n borderColor: read('--primary'),\n boxShadow: `0 0 0 ${read('--focus-ring-width')} ${read('--ring')}`,\n outline: 'none',\n },\n '.Input--invalid': {\n borderColor: read('--destructive'),\n color: read('--foreground'),\n },\n '.Label': {\n color: read('--foreground'),\n fontWeight: read('--font-weight-medium'),\n fontSize: read('--font-size-sm'),\n },\n '.Error': {\n color: read('--destructive'),\n fontSize: read('--font-size-sm'),\n },\n '.Tab': {\n border: `1px solid ${read('--border')}`,\n backgroundColor: read('--background'),\n color: read('--foreground'),\n },\n '.Tab--selected': {\n borderColor: read('--primary'),\n backgroundColor: read('--background'),\n color: read('--primary'),\n },\n // Accordion method rows (the `accordion` layout): keep Stripe's native\n // per-method card structure, restyled with our tokens — our border +\n // radius, our background, `--primary` on the selected row, no extra shadow.\n '.AccordionItem': {\n backgroundColor: read('--background'),\n border: `1px solid ${read('--border')}`,\n borderRadius: read('--radius-md'),\n boxShadow: 'none',\n },\n '.AccordionItem--selected': {\n borderColor: read('--primary'),\n backgroundColor: read('--background'),\n },\n // Stripe's in-method notice blocks (e.g. PayPal's \"you'll be redirected\")\n // otherwise render in their own bordered box — a card nested inside the\n // selected method card. Flatten to inline icon + text, no inner box.\n '.Block': {\n border: 'none',\n borderRadius: '0',\n boxShadow: 'none',\n backgroundColor: 'transparent',\n },\n },\n };\n}\n\n/**\n * Calls `onChange(getStripeAppearance(root))` whenever the theme root's\n * class list mutates (theme switch) or the user toggles\n * `prefers-color-scheme` / `prefers-reduced-motion`. Returns an\n * unsubscribe function.\n */\nexport function subscribeStripeAppearance(\n onChange: (next: Appearance) => void,\n root?: HTMLElement,\n): () => void {\n if (!isBrowser()) return () => undefined;\n\n const target = root ?? document.documentElement;\n const emit = () => onChange(getStripeAppearance(root));\n\n const observer = new MutationObserver(emit);\n observer.observe(target, {\n attributes: true,\n attributeFilter: ['class', 'dir', 'lang'],\n });\n\n const schemeMql = window.matchMedia('(prefers-color-scheme: dark)');\n const motionMql = window.matchMedia('(prefers-reduced-motion: reduce)');\n schemeMql.addEventListener('change', emit);\n motionMql.addEventListener('change', emit);\n\n return () => {\n observer.disconnect();\n schemeMql.removeEventListener('change', emit);\n motionMql.removeEventListener('change', emit);\n };\n}\n","import type { AgentAdapter } from '../../agent/types';\nimport type { PaymentFormHandle } from './payment-form';\n\nexport const paymentFormAgent: AgentAdapter<PaymentFormHandle> = {\n id: 'payment-form',\n capabilities: ['submit'],\n state: {},\n actions: {\n submit: {\n safety: 'destructive',\n description:\n 'Submit the payment. Charges the configured payment method — irreversible.',\n invoke: (handle) => handle.submit(),\n },\n reset: {\n safety: 'destructive',\n description:\n 'Reset the form to its initial state. Loses any in-progress input.',\n invoke: (handle) => {\n handle.reset();\n },\n },\n },\n domHooks: {\n root: { attr: 'data-component', value: 'payment-form' },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n },\n};\n","/* ------------------------------------------------------------------ */\n/* PaymentForm — Stripe Elements wrapper (PCI DSS SAQ-A). */\n/* */\n/* - Library: `@stripe/react-stripe-js` + `@stripe/stripe-js` (see */\n/* `src/docs/08-third-party.mdx §Payments`). Card number, expiry, */\n/* CVC, and postal code all live inside Stripe-hosted iframes on */\n/* `js.stripe.com` — raw PAN never touches our origin, keeping us */\n/* inside PCI DSS SAQ-A scope. */\n/* */\n/* - Theming: the `stripe-appearance` bridge snapshots our tokens into */\n/* Stripe's Appearance API (`variables`, `rules`). A */\n/* `MutationObserver` on `<html class>` re-runs the snapshot when */\n/* the user flips theme so the embedded iframes repaint. */\n/* */\n/* - Security invariants enforced in this file: */\n/* 1. No `<input type=\"tel\" name=\"card\">` anywhere. */\n/* 2. Error strings are sanitised via `stripCardLikeDigits` before */\n/* forwarding to `onError` (replaces any `\\b\\d{4,}\\b` with */\n/* `****`). */\n/* 3. Element change events are never logged; any dev-only logging */\n/* is gated behind `import.meta.env.DEV` — never runs in prod. */\n/* */\n/* TODO: */\n/* - Stripe's `direction: 'rtl'` is not part of the current */\n/* `Appearance` TypeScript type; we rely on CSS mirroring of our */\n/* chrome via logical properties and let Stripe lay out the iframe */\n/* ltr for now. Revisit when @stripe/stripe-js publishes the type. */\n/* - No `<CardNumberElement>` / split-fields story — `PaymentElement` */\n/* handles tabs + card-only modes via its own `layout` option. */\n/* ------------------------------------------------------------------ */\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type FormEvent,\n type ReactElement,\n} from 'react';\nimport { cva } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { Spinner } from '../spinner';\nimport { Alert } from '../alert';\nimport {\n loadStripe,\n type Stripe,\n type Appearance,\n type StripeElementLocale,\n type StripeElementsOptions,\n} from '@stripe/stripe-js';\nimport {\n Elements,\n PaymentElement,\n AddressElement,\n useElements,\n useStripe,\n} from '@stripe/react-stripe-js';\n\nimport {\n getStripeAppearance,\n subscribeStripeAppearance,\n} from '../../tokens/themes/bridges/stripe-appearance';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { paymentFormAgent } from './payment-form.agent';\n\n/* ------------------------------------------------------------------ */\n/* Public types */\n/* ------------------------------------------------------------------ */\n\nexport type PaymentCurrency = string; // ISO-4217\n\nexport interface PaymentFormProps {\n /** Opaque instance id — emitted as `data-component-id` for the agent registry. */\n id?: string;\n /**\n * Client secret from your server, created via the PaymentIntents API.\n *\n * Omit to use **deferred-intent mode** — the Payment Element renders from\n * just the publishable key (no `clientSecret`, no backend round-trip up\n * front). In deferred mode supply `onCreatePaymentIntent` to actually\n * confirm: your server mints + returns the client secret at submit time.\n */\n clientSecret?: string;\n /**\n * Deferred-intent setup: `'payment'` collects a charge, `'setup'` saves a\n * method for later. Ignored when `clientSecret` is supplied (the secret's\n * own intent type wins). Defaults to `'payment'`.\n */\n mode?: 'payment' | 'setup';\n /**\n * Deferred-confirm callback. Called at submit time (after client-side\n * field validation succeeds) so your server can mint a PaymentIntent and\n * return its `client_secret`. The returned secret is used ONLY to confirm\n * and is never logged or sent to any third-party origin. When omitted in\n * deferred mode the form runs in PREVIEW: fields render + validate, but no\n * charge is attempted.\n */\n onCreatePaymentIntent?: () => Promise<string>;\n /** Stripe publishable key (`pk_test_…` / `pk_live_…`). */\n publishableKey: string;\n /** ISO-4217 currency code (e.g. 'EUR', 'USD', 'JPY'). */\n currency: PaymentCurrency;\n /** Amount in the currency's smallest unit (cents for EUR/USD, yen for JPY). */\n amount: number;\n /** Called with the PaymentIntent id on successful confirmation. */\n onSuccess?: (paymentIntentId: string) => void;\n /** Called with a sanitised error (no PAN digits, no Stripe English strings). */\n onError?: (error: { code: string; translatedMessage: string }) => void;\n /** Show the billing-address collector below the payment fields. */\n billingAddress?: boolean;\n /** Locale override — defaults to the active i18next locale. */\n locale?: string;\n /** Accessible label for the form. */\n ariaLabel?: string;\n /** URL Stripe redirects to when a payment method requires it. */\n returnUrl?: string;\n /** Pre-injected Stripe instance — used by tests + stories to bypass the network. */\n stripePromise?: Promise<Stripe | null> | null;\n /**\n * Payment Element layout. `tabs` (default) renders methods as a tile row —\n * best in wide containers. `accordion` stacks them as full-width rows — use\n * it in narrow columns (< ~400px) where Stripe's tab row clips a partial tile.\n */\n layout?: 'tabs' | 'accordion';\n className?: string;\n}\n\nexport interface PaymentFormHandle {\n /** Programmatically submit the form (same flow as the Pay button). */\n submit: () => Promise<void>;\n /** Reset the form to its initial state. */\n reset: () => void;\n}\n\n/* ------------------------------------------------------------------ */\n/* Currency helpers */\n/* ------------------------------------------------------------------ */\n\n/**\n * Currencies that Stripe bills in their base unit (no decimals). Source:\n * https://stripe.com/docs/currencies#zero-decimal — list pinned per\n * 08-third-party.mdx.\n */\nconst ZERO_DECIMAL_CURRENCIES = new Set<string>([\n 'BIF',\n 'CLP',\n 'DJF',\n 'GNF',\n 'IDR',\n 'JPY',\n 'KMF',\n 'KRW',\n 'MGA',\n 'PYG',\n 'RWF',\n 'UGX',\n 'VND',\n 'VUV',\n 'XAF',\n 'XOF',\n 'XPF',\n]);\n\nexport function formatPaymentAmount(\n amount: number,\n currency: string,\n locale: string,\n): string {\n const iso = currency.toUpperCase();\n const major = ZERO_DECIMAL_CURRENCIES.has(iso) ? amount : amount / 100;\n try {\n return new Intl.NumberFormat(locale, {\n style: 'currency',\n currency: iso,\n }).format(major);\n } catch {\n // Invalid locale/currency pair — fall back to a safe format so we\n // never leak raw amount integers into the UI.\n return new Intl.NumberFormat('en', {\n style: 'currency',\n currency: iso,\n }).format(major);\n }\n}\n\n/* ------------------------------------------------------------------ */\n/* Return URL validation */\n/* ------------------------------------------------------------------ */\n\n/**\n * Resolve `returnUrl` against the current origin. Accepts:\n * - absolute URLs on the same origin as `window.location`\n * - relative paths (resolved against the current origin)\n * Rejects (returns `null`):\n * - cross-origin URLs — would leak `payment_intent_client_secret`\n * - `javascript:` / `data:` / `file:` / `blob:` schemes\n * - SSR contexts (no `window`) — the submit path requires a browser\n * anyway, so rejecting here is the safer default.\n * See security-hardening.mdx.\n */\nexport function validateReturnUrl(\n returnUrl: string | undefined,\n): string | null {\n if (returnUrl === undefined) return null;\n const raw = returnUrl.trim();\n if (raw === '') return null;\n if (typeof window === 'undefined') return null;\n try {\n const resolved = new URL(raw, window.location.href);\n const allowedSchemes = new Set(['http:', 'https:']);\n if (!allowedSchemes.has(resolved.protocol)) return null;\n if (resolved.origin !== window.location.origin) return null;\n return resolved.toString();\n } catch {\n return null;\n }\n}\n\n/* ------------------------------------------------------------------ */\n/* Error sanitisation */\n/* ------------------------------------------------------------------ */\n\n/**\n * Replace any run of 4+ consecutive digits with `****`. Called before any\n * error text leaves the wrapper. Defensive: even though Stripe's error\n * strings don't normally contain PANs, a future SDK change could, and we\n * want a hard guarantee that `console` / analytics / Sentry breadcrumbs\n * stay clear of anything that looks like card data.\n */\nexport function stripCardLikeDigits(message: string): string {\n if (!message) return message;\n // Deliberately no word boundaries: a PAN run embedded between word\n // characters (e.g. \"CARD4242424242424242DECLINED\") must still be masked.\n return message.replace(/\\d{4,}/g, '****');\n}\n\n/**\n * Map a Stripe error code (e.g. `card_declined`, `incorrect_number`) to a\n * translation key under `payment.error.*`. Unknown codes fall through to\n * `payment.error.generic`.\n */\nexport function stripeErrorCodeToI18nKey(code: string | undefined): string {\n switch (code) {\n case 'incorrect_number':\n case 'invalid_number':\n return 'payment.error.cardNumber';\n case 'invalid_expiry_month':\n case 'invalid_expiry_year':\n case 'expired_card':\n return 'payment.error.expiry';\n case 'invalid_cvc':\n case 'incorrect_cvc':\n return 'payment.error.cvc';\n case 'incorrect_zip':\n case 'invalid_zip':\n return 'payment.error.postalCode';\n case 'card_declined':\n case 'do_not_honor':\n case 'generic_decline':\n return 'payment.error.declined';\n case 'network_error':\n case 'api_connection_error':\n return 'payment.error.network';\n default:\n return 'payment.error.generic';\n }\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst formVariants = cva(\n [\n 'ds:payment-form-alfadocs ds:flex ds:flex-col',\n 'ds:gap-[var(--spacing-md)]',\n // Transparent, padding-less container — the consuming surface (a Card, the\n // check-in step, a checkout column) owns the card chrome + padding, so the\n // Stripe method boxes never read as cards nested inside another card.\n 'ds:text-[var(--foreground)]',\n 'ds:aria-disabled:opacity-[var(--opacity-50)] ds:aria-disabled:cursor-not-allowed',\n ].join(' '),\n);\n\nconst fieldLabelVariants = cva(\n ['ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]'].join(' '),\n);\n\nconst labelTextVariants = cva(\n ['type-label', 'ds:text-[var(--foreground)]'].join(' '),\n);\n\nconst amountSummaryVariants = cva(\n [\n 'ds:flex ds:items-baseline ds:justify-between',\n 'ds:gap-[var(--spacing-sm)]',\n 'ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)]',\n 'ds:pt-[var(--spacing-xs)] ds:pb-[var(--spacing-xs)]',\n 'ds:bg-[var(--muted)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:text-[var(--foreground)]',\n ].join(' '),\n);\n\nconst submitButtonVariants = cva(\n [\n 'ds:inline-flex ds:items-center ds:justify-center ds:gap-[var(--spacing-xs)]',\n 'ds:[min-block-size:var(--min-target-size)]',\n 'ds:[min-inline-size:var(--min-target-size)]',\n 'ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:bg-[var(--primary)] ds:text-[var(--primary-foreground)]',\n 'ds:text-[length:var(--font-size-base)] ds:font-medium',\n 'ds:transition-colors ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n 'ds:hover:bg-[var(--primary-hover)]',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)]',\n 'ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)]',\n 'ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n 'ds:aria-disabled:opacity-[var(--opacity-50)] ds:aria-disabled:cursor-not-allowed',\n 'ds:aria-busy:cursor-wait',\n ].join(' '),\n);\n\n/* ------------------------------------------------------------------ */\n/* Inner form — lives inside the <Elements> provider */\n/* ------------------------------------------------------------------ */\n\ninterface InnerPaymentFormProps {\n amount: number;\n currency: string;\n locale: string;\n billingAddress: boolean;\n returnUrl: string | undefined;\n /** Present in immediate mode; `undefined` in deferred mode. */\n clientSecret: string | undefined;\n /** Deferred-confirm callback; `undefined` → preview (validate-only). */\n onCreatePaymentIntent: PaymentFormProps['onCreatePaymentIntent'];\n onSuccess: PaymentFormProps['onSuccess'];\n onError: PaymentFormProps['onError'];\n layout: NonNullable<PaymentFormProps['layout']>;\n}\n\nfunction InnerPaymentForm(props: InnerPaymentFormProps): ReactElement {\n const {\n amount,\n currency,\n locale,\n billingAddress,\n returnUrl,\n clientSecret,\n onCreatePaymentIntent,\n onSuccess,\n onError,\n layout,\n } = props;\n\n const { t } = useTranslation();\n const stripe = useStripe();\n const elements = useElements();\n\n const rawId = useId();\n const idSafe = useMemo(\n () => `pay-${rawId.replace(/[^a-zA-Z0-9-_]/g, '')}`,\n [rawId],\n );\n const paymentFieldId = `${idSafe}-payment`;\n const addressFieldId = `${idSafe}-address`;\n const errorId = `${idSafe}-error`;\n\n const [processing, setProcessing] = useState(false);\n const [elementComplete, setElementComplete] = useState(false);\n const [errorKey, setErrorKey] = useState<string | null>(null);\n const [errorMessage, setErrorMessage] = useState<string>('');\n\n const onSuccessRef = useRef(onSuccess);\n const onErrorRef = useRef(onError);\n useEffect(() => {\n onSuccessRef.current = onSuccess;\n onErrorRef.current = onError;\n }, [onSuccess, onError]);\n\n const handleSubmit = useCallback(\n async (event?: FormEvent<HTMLFormElement>): Promise<void> => {\n if (event) event.preventDefault();\n if (!stripe || !elements) return;\n if (processing) return;\n\n setProcessing(true);\n setErrorKey(null);\n setErrorMessage('');\n\n // The single sanitise → map → setError → onError pipeline. Every error\n // surfaced by either path (immediate or deferred) flows through here so\n // raw Stripe English / PAN-like digit runs can never reach the UI or\n // `onError`. `rawMessage` is sanitised; the i18n key is mapped from\n // the Stripe error code.\n const reportError = (\n code: string,\n rawMessage: string | undefined,\n ): void => {\n const key = stripeErrorCodeToI18nKey(code);\n // CRITICAL: sanitise before storing OR forwarding.\n const safe = stripCardLikeDigits(rawMessage ?? '');\n setErrorKey(key);\n setErrorMessage(t(key));\n onErrorRef.current?.({\n code,\n translatedMessage: safe || t(key),\n });\n };\n\n // Validate returnUrl at the boundary so even a careless consumer\n // cannot leak payment_intent_client_secret to a third-party origin.\n const safeReturnUrl = validateReturnUrl(returnUrl);\n if (returnUrl !== undefined && safeReturnUrl === null) {\n setErrorKey('payment.error.invalidReturnUrl');\n setErrorMessage(t('payment.error.invalidReturnUrl'));\n onErrorRef.current?.({\n code: 'invalid_return_url',\n translatedMessage: t('payment.error.invalidReturnUrl'),\n });\n setProcessing(false);\n return;\n }\n\n const confirmParams = safeReturnUrl ? { return_url: safeReturnUrl } : {};\n\n try {\n if (clientSecret !== undefined) {\n // ----- Immediate mode: the consumer already minted the secret. ---\n const result = await stripe.confirmPayment({\n elements,\n confirmParams,\n redirect: 'if_required',\n });\n\n if (result.error) {\n reportError(result.error.code ?? 'generic', result.error.message);\n return;\n }\n\n // Success path — only the PaymentIntent id leaves the wrapper.\n if (result.paymentIntent) {\n onSuccessRef.current?.(result.paymentIntent.id);\n }\n return;\n }\n\n // ----- Deferred-intent mode: no secret up front. -----------------\n // Run client-side field validation first; on failure we run the\n // SAME sanitise/map/report pipeline and stop (no secret minted).\n const { error: submitError } = await elements.submit();\n if (submitError) {\n reportError(submitError.code ?? 'generic', submitError.message);\n return;\n }\n\n // No confirm callback → PREVIEW mode. The field validation above is\n // the end of the flow: no secret is minted, no charge is attempted,\n // and we surface no error — the fields simply validated.\n if (!onCreatePaymentIntent) {\n return;\n }\n\n // Mint the secret on the consumer's server, then confirm with it.\n // The minted secret is used ONLY here and is never logged or sent to\n // a third-party origin.\n const mintedSecret = await onCreatePaymentIntent();\n const result = await stripe.confirmPayment({\n elements,\n clientSecret: mintedSecret,\n confirmParams,\n redirect: 'if_required',\n });\n\n if (result.error) {\n reportError(result.error.code ?? 'generic', result.error.message);\n return;\n }\n\n if (result.paymentIntent) {\n onSuccessRef.current?.(result.paymentIntent.id);\n }\n } catch (err: unknown) {\n const raw = err instanceof Error ? err.message : '';\n // Generic, sanitised — covers a thrown onCreatePaymentIntent and any\n // unexpected SDK rejection. Never surface the raw thrown text.\n reportError('unexpected', raw);\n } finally {\n setProcessing(false);\n }\n },\n [\n stripe,\n elements,\n processing,\n returnUrl,\n clientSecret,\n onCreatePaymentIntent,\n t,\n ],\n );\n\n // Imperative submit hook used by the outer component's ref handle.\n useEffect(() => {\n const host = document.getElementById(idSafe);\n if (!host) return;\n const submitter = () => {\n void handleSubmit();\n };\n host.addEventListener('payment-form:submit', submitter);\n return () => host.removeEventListener('payment-form:submit', submitter);\n }, [idSafe, handleSubmit]);\n\n // Preview mode = deferred (no clientSecret) with no confirm callback. There\n // no charge happens, so we keep the button enabled even before the fields\n // report complete: clicking it triggers `elements.submit()` validation,\n // which is the entire point of the preview.\n const isPreview = clientSecret === undefined && !onCreatePaymentIntent;\n const submitDisabled =\n !stripe || !elements || processing || (!isPreview && !elementComplete);\n\n return (\n <form\n id={idSafe}\n onSubmit={handleSubmit}\n aria-label={t('payment.ariaLabel')}\n aria-busy={processing || undefined}\n noValidate\n >\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n <div className={amountSummaryVariants()}>\n <span className={labelTextVariants()}>\n {t('payment.amountLabel')}\n </span>\n <span className=\"type-title-card\" data-testid=\"payment-amount\">\n {formatPaymentAmount(amount, currency, locale)}\n </span>\n </div>\n\n <label\n htmlFor={paymentFieldId}\n className={fieldLabelVariants()}\n data-testid=\"payment-field\"\n >\n <span className={labelTextVariants()}>\n {t('payment.fields.card')}\n </span>\n <PaymentElement\n id={paymentFieldId}\n options={{\n // `tabs` = method tiles (Card selected by default); `accordion`\n // = full-width stacked rows for narrow columns where the tab row\n // clips. Stripe owns overflow + tab alignment either way.\n layout:\n layout === 'accordion'\n ? { type: 'accordion', defaultCollapsed: true }\n : { type: 'tabs' },\n }}\n onChange={(ev) => {\n // NOTE: never log `ev` — change events may include hints\n // about field contents. Keep only the boolean completeness.\n setElementComplete(ev.complete === true);\n if (ev.complete) {\n setErrorKey(null);\n setErrorMessage('');\n }\n }}\n />\n </label>\n\n {billingAddress ? (\n <label\n htmlFor={addressFieldId}\n className={fieldLabelVariants()}\n data-testid=\"payment-address\"\n >\n <span className={labelTextVariants()}>\n {t('payment.billingAddress')}\n </span>\n <AddressElement id={addressFieldId} options={{ mode: 'billing' }} />\n </label>\n ) : null}\n\n {errorKey ? (\n <Alert\n id={errorId}\n variant=\"error\"\n live=\"polite\"\n data-testid=\"payment-error\"\n >\n <Alert.Description>{errorMessage}</Alert.Description>\n </Alert>\n ) : null}\n\n <button\n type=\"submit\"\n aria-disabled={submitDisabled || undefined}\n aria-busy={processing || undefined}\n aria-describedby={errorKey ? errorId : undefined}\n className={submitButtonVariants()}\n data-testid=\"payment-submit\"\n >\n {processing ? (\n <>\n <Spinner size=\"sm\" label={t('payment.processing')} />\n <span>{t('payment.processing')}</span>\n </>\n ) : (\n <span>\n {t('payment.submit', {\n amount: formatPaymentAmount(amount, currency, locale),\n })}\n </span>\n )}\n </button>\n </div>\n </form>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* PaymentForm — outer wrapper */\n/* ------------------------------------------------------------------ */\n\n/**\n * Stripe ships a closed union of supported locales; anything outside it\n * must fall through to `'auto'` (Stripe picks the best match from the\n * browser). We also normalise the legacy `cn` code to `zh` per\n * `src/docs/06-i18n.mdx`.\n */\nconst STRIPE_LOCALES = new Set<StripeElementLocale>([\n 'auto',\n 'ar',\n 'bg',\n 'cs',\n 'da',\n 'de',\n 'el',\n 'en',\n 'en-AU',\n 'en-CA',\n 'en-NZ',\n 'en-GB',\n 'es',\n 'es-ES',\n 'es-419',\n 'et',\n 'fi',\n 'fil',\n 'fr',\n 'fr-CA',\n 'fr-FR',\n 'he',\n 'hu',\n 'hr',\n 'id',\n 'it',\n 'it-IT',\n 'ja',\n 'ko',\n 'lt',\n 'lv',\n 'ms',\n 'mt',\n 'nb',\n 'nl',\n 'no',\n 'pl',\n 'pt',\n 'pt-BR',\n 'ro',\n 'ru',\n 'sk',\n 'sl',\n 'sv',\n 'th',\n 'tr',\n 'vi',\n 'zh',\n 'zh-HK',\n 'zh-TW',\n]);\n\nfunction normaliseLocale(input: string): StripeElementLocale {\n if (!input) return 'auto';\n const candidate = input === 'cn' ? 'zh' : input;\n if ((STRIPE_LOCALES as Set<string>).has(candidate)) {\n return candidate as StripeElementLocale;\n }\n // Try stripping region (\"en-US\" → \"en\") before giving up.\n const base = candidate.split('-')[0];\n if ((STRIPE_LOCALES as Set<string>).has(base)) {\n return base as StripeElementLocale;\n }\n return 'auto';\n}\n\nexport const PaymentForm = forwardRef<HTMLDivElement, PaymentFormProps>(\n (\n {\n id,\n clientSecret,\n mode = 'payment',\n onCreatePaymentIntent,\n publishableKey,\n currency,\n amount,\n onSuccess,\n onError,\n billingAddress = false,\n locale,\n ariaLabel,\n returnUrl,\n stripePromise: injectedStripe,\n layout = 'tabs',\n className,\n },\n ref,\n ) => {\n const { i18n } = useTranslation();\n const activeLocale = normaliseLocale(locale ?? i18n.language ?? 'en');\n\n // Stripe instance — pre-injected (tests/stories) or lazily loaded.\n const [stripeInstance, setStripeInstance] =\n useState<Promise<Stripe | null> | null>(injectedStripe ?? null);\n\n useEffect(() => {\n if (injectedStripe !== undefined) {\n setStripeInstance(injectedStripe);\n return;\n }\n if (!publishableKey) {\n setStripeInstance(null);\n return;\n }\n // `loadStripe` is cached by the SDK — safe to call per mount.\n setStripeInstance(loadStripe(publishableKey));\n }, [injectedStripe, publishableKey]);\n\n // Appearance bridge — snapshot + subscribe.\n const [appearance, setAppearance] = useState<Appearance>(() =>\n getStripeAppearance(),\n );\n useEffect(() => {\n setAppearance(getStripeAppearance());\n const unsubscribe = subscribeStripeAppearance(setAppearance);\n return unsubscribe;\n }, []);\n\n // Imperative handle — dispatch a custom event at the inner form so we\n // can trigger the same submit path as the button without leaking refs\n // through the Stripe `<Elements>` provider (which owns its own tree).\n const hostRef = useRef<HTMLDivElement>(null);\n\n const agentHandle = useMemo<PaymentFormHandle>(\n () => ({\n submit: async () => {\n const form = hostRef.current?.querySelector('form');\n if (form) {\n form.dispatchEvent(\n new CustomEvent('payment-form:submit', { bubbles: true }),\n );\n }\n },\n reset: () => {\n const form = hostRef.current?.querySelector('form');\n if (form instanceof HTMLFormElement) {\n form.reset();\n }\n },\n }),\n [],\n );\n useImperativeHandle(ref, () => hostRef.current as HTMLDivElement, []);\n useAgentRegistration(paymentFormAgent, agentHandle, id);\n\n const elementsOptions = useMemo<StripeElementsOptions>(\n () =>\n clientSecret !== undefined\n ? // Immediate mode — the consumer already created the intent.\n { clientSecret, appearance, locale: activeLocale }\n : // Deferred-intent mode — no secret yet; Stripe needs the intent\n // shape (mode + amount + currency) to render the Payment Element.\n // Stripe expects a lowercase ISO-4217 currency here.\n {\n mode,\n amount,\n currency: currency.toLowerCase(),\n appearance,\n locale: activeLocale,\n },\n [clientSecret, mode, amount, currency, appearance, activeLocale],\n );\n\n return (\n <div\n ref={hostRef}\n aria-label={ariaLabel}\n className={[formVariants(), className].filter(Boolean).join(' ')}\n data-component=\"payment-form\"\n data-component-id={id}\n data-testid=\"payment-form-root\"\n >\n {stripeInstance ? (\n // Render the real Payment Element whenever a Stripe instance is\n // available — in immediate mode (clientSecret present) AND in\n // deferred mode (no secret). The skeleton is reserved for the\n // no-Stripe case (missing publishableKey / injected null).\n <Elements\n stripe={stripeInstance}\n options={elementsOptions}\n key={clientSecret ?? 'deferred'}\n >\n <InnerPaymentForm\n amount={amount}\n currency={currency}\n locale={activeLocale}\n billingAddress={billingAddress}\n returnUrl={returnUrl}\n clientSecret={clientSecret}\n onCreatePaymentIntent={onCreatePaymentIntent}\n onSuccess={onSuccess}\n onError={onError}\n layout={layout}\n />\n </Elements>\n ) : (\n <PaymentFormSkeleton\n amount={amount}\n currency={currency}\n locale={activeLocale}\n billingAddress={billingAddress}\n />\n )}\n </div>\n );\n },\n);\n\nPaymentForm.displayName = 'PaymentForm';\n\n/* ------------------------------------------------------------------ */\n/* Skeleton — visual chrome when Stripe hasn't loaded yet */\n/* ------------------------------------------------------------------ */\n\ninterface PaymentFormSkeletonProps {\n amount: number;\n currency: string;\n locale: string;\n billingAddress: boolean;\n}\n\nfunction PaymentFormSkeleton(props: PaymentFormSkeletonProps): ReactElement {\n const { amount, currency, locale, billingAddress } = props;\n const { t } = useTranslation();\n\n return (\n <div\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\"\n data-testid=\"payment-skeleton\"\n aria-busy=\"true\"\n >\n <div className={amountSummaryVariants()}>\n <span className={labelTextVariants()}>{t('payment.amountLabel')}</span>\n <span className=\"type-title-card\">\n {formatPaymentAmount(amount, currency, locale)}\n </span>\n </div>\n <div className={fieldLabelVariants()}>\n <span className={labelTextVariants()}>{t('payment.fields.card')}</span>\n <div\n className=\"ds:[min-block-size:var(--min-target-size)] ds:rounded-[var(--radius-sm)] ds:border ds:border-[color:var(--border)] ds:bg-[var(--muted)]\"\n aria-hidden=\"true\"\n />\n </div>\n {billingAddress ? (\n <div className={fieldLabelVariants()} data-testid=\"payment-address\">\n <span className={labelTextVariants()}>\n {t('payment.billingAddress')}\n </span>\n <div\n className=\"ds:[min-block-size:calc(var(--min-target-size)*2)] ds:rounded-[var(--radius-sm)] ds:border ds:border-[color:var(--border)] ds:bg-[var(--muted)]\"\n aria-hidden=\"true\"\n />\n </div>\n ) : null}\n <button\n type=\"button\"\n aria-disabled=\"true\"\n className={submitButtonVariants()}\n disabled\n >\n <Spinner size=\"sm\" label={t('payment.processing')} />\n <span>{t('payment.processing')}</span>\n </button>\n </div>\n );\n}\n\nexport {\n formVariants as paymentFormVariants,\n submitButtonVariants as paymentSubmitButtonVariants,\n};\n"],"names":["isBrowser","getStripeAppearance","root","target","styles","read","token","subscribeStripeAppearance","onChange","emit","observer","schemeMql","motionMql","paymentFormAgent","handle","ZERO_DECIMAL_CURRENCIES","formatPaymentAmount","amount","currency","locale","iso","major","validateReturnUrl","returnUrl","raw","resolved","stripCardLikeDigits","message","stripeErrorCodeToI18nKey","code","formVariants","cva","fieldLabelVariants","labelTextVariants","amountSummaryVariants","submitButtonVariants","InnerPaymentForm","props","billingAddress","clientSecret","onCreatePaymentIntent","onSuccess","onError","layout","t","useTranslation","stripe","useStripe","elements","useElements","rawId","useId","idSafe","useMemo","paymentFieldId","addressFieldId","errorId","processing","setProcessing","useState","elementComplete","setElementComplete","errorKey","setErrorKey","errorMessage","setErrorMessage","onSuccessRef","useRef","onErrorRef","useEffect","handleSubmit","useCallback","event","reportError","rawMessage","key","safe","_a","safeReturnUrl","confirmParams","result","_b","submitError","mintedSecret","_c","err","host","submitter","submitDisabled","jsx","jsxs","PaymentElement","ev","AddressElement","Alert","Fragment","Spinner","STRIPE_LOCALES","normaliseLocale","input","candidate","base","PaymentForm","forwardRef","id","mode","publishableKey","ariaLabel","injectedStripe","className","ref","i18n","activeLocale","stripeInstance","setStripeInstance","loadStripe","appearance","setAppearance","hostRef","agentHandle","form","useImperativeHandle","useAgentRegistration","elementsOptions","Elements","PaymentFormSkeleton"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "packageVersion": "0.45.0",
3
+ "packageVersion": "0.46.0",
4
4
  "components": [
5
5
  {
6
6
  "kind": "component",
@@ -1,4 +1,4 @@
1
- import { F as m, f as l } from "../../_chunks/freemium-paywall-BYist2sJ.js";
1
+ import { F as m, f as l } from "../../_chunks/freemium-paywall-DzpD63WY.js";
2
2
  export {
3
3
  m as FreemiumPaywall,
4
4
  l as freemiumPaywallAgent
@@ -1,4 +1,4 @@
1
- import { P as r, f as s, p as m, a as e, s as n, b as o, c as i } from "../../_chunks/payment-form-DqEiEJRO.js";
1
+ import { P as r, f as s, p as m, a as e, s as n, b as o, c as i } from "../../_chunks/payment-form-BNTx4876.js";
2
2
  export {
3
3
  r as PaymentForm,
4
4
  s as formatPaymentAmount,
@@ -50,6 +50,12 @@ export interface PaymentFormProps {
50
50
  returnUrl?: string;
51
51
  /** Pre-injected Stripe instance — used by tests + stories to bypass the network. */
52
52
  stripePromise?: Promise<Stripe | null> | null;
53
+ /**
54
+ * Payment Element layout. `tabs` (default) renders methods as a tile row —
55
+ * best in wide containers. `accordion` stacks them as full-width rows — use
56
+ * it in narrow columns (< ~400px) where Stripe's tab row clips a partial tile.
57
+ */
58
+ layout?: 'tabs' | 'accordion';
53
59
  className?: string;
54
60
  }
55
61
  export interface PaymentFormHandle {
@@ -1 +1 @@
1
- {"version":3,"file":"payment-form.d.ts","sourceRoot":"","sources":["../../../src/components/payment-form/payment-form.tsx"],"names":[],"mappings":"AA+CA,OAAO,EAEL,KAAK,MAAM,EAIZ,MAAM,mBAAmB,CAAC;AAoB3B,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC;AAErC,MAAM,WAAW,gBAAgB;IAC/B,kFAAkF;IAClF,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAC3B;;;;;;;OAOG;IACH,qBAAqB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9C,0DAA0D;IAC1D,cAAc,EAAE,MAAM,CAAC;IACvB,yDAAyD;IACzD,QAAQ,EAAE,eAAe,CAAC;IAC1B,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,SAAS,CAAC,EAAE,CAAC,eAAe,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,gFAAgF;IAChF,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACvE,mEAAmE;IACnE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oFAAoF;IACpF,aAAa,CAAC,EAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,sEAAsE;IACtE,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,2CAA2C;IAC3C,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AA+BD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,MAAM,CAgBR;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,GAAG,SAAS,GAC5B,MAAM,GAAG,IAAI,CAcf;AAMD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAK3D;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAyBzE;AAMD,QAAA,MAAM,YAAY,oFASjB,CAAC;AAsBF,QAAA,MAAM,oBAAoB,oFAmBzB,CAAC;AAiXF,eAAO,MAAM,WAAW,6GA0IvB,CAAC;AA8DF,OAAO,EACL,YAAY,IAAI,mBAAmB,EACnC,oBAAoB,IAAI,2BAA2B,GACpD,CAAC"}
1
+ {"version":3,"file":"payment-form.d.ts","sourceRoot":"","sources":["../../../src/components/payment-form/payment-form.tsx"],"names":[],"mappings":"AA+CA,OAAO,EAEL,KAAK,MAAM,EAIZ,MAAM,mBAAmB,CAAC;AAoB3B,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC;AAErC,MAAM,WAAW,gBAAgB;IAC/B,kFAAkF;IAClF,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAC3B;;;;;;;OAOG;IACH,qBAAqB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9C,0DAA0D;IAC1D,cAAc,EAAE,MAAM,CAAC;IACvB,yDAAyD;IACzD,QAAQ,EAAE,eAAe,CAAC;IAC1B,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,SAAS,CAAC,EAAE,CAAC,eAAe,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,gFAAgF;IAChF,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACvE,mEAAmE;IACnE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oFAAoF;IACpF,aAAa,CAAC,EAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAC9C;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,sEAAsE;IACtE,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,2CAA2C;IAC3C,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AA+BD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,MAAM,CAgBR;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,GAAG,SAAS,GAC5B,MAAM,GAAG,IAAI,CAcf;AAMD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAK3D;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAyBzE;AAMD,QAAA,MAAM,YAAY,oFAUjB,CAAC;AAsBF,QAAA,MAAM,oBAAoB,oFAmBzB,CAAC;AAyXF,eAAO,MAAM,WAAW,6GA4IvB,CAAC;AA8DF,OAAO,EACL,YAAY,IAAI,mBAAmB,EACnC,oBAAoB,IAAI,2BAA2B,GACpD,CAAC"}
package/dist/index.js CHANGED
@@ -132,7 +132,7 @@ import { A as rp } from "./_chunks/audio-visualiser-l6zPd0AG.js";
132
132
  import { C as tp, c as sp } from "./_chunks/chat-container-ogB4OskO.js";
133
133
  import { C as ip, c as pp } from "./_chunks/chat-input-CQe7nR_v.js";
134
134
  import { C as lp } from "./_chunks/chat-message-ASgGtj-L.js";
135
- import { F as fp, f as dp } from "./_chunks/freemium-paywall-BYist2sJ.js";
135
+ import { F as fp, f as dp } from "./_chunks/freemium-paywall-DzpD63WY.js";
136
136
  import { S as xp } from "./_chunks/streaming-text-GH07yIYh.js";
137
137
  import { S as up, a as Cp } from "./_chunks/suggestion-chip-C4kxWUIs.js";
138
138
  import { s as Tp } from "./_chunks/suggestion-chip.agent-6sNWFj7m.js";
@@ -144,7 +144,7 @@ import { O as yp, o as wp } from "./_chunks/operator-hero-7LiiP7zi.js";
144
144
  import { P as Vp, p as Gp } from "./_chunks/patient-search-CocVcGJ3.js";
145
145
  import { C as Wp, a as Up, b as Kp, c as Yp } from "./_chunks/contact-profile-card-DHyuAPXM.js";
146
146
  import { P as jp, p as qp } from "./_chunks/practice-results-DDi-kvaD.js";
147
- import { P as Jp, f as Xp, p as Zp, a as $p, s as am, b as em, c as rm } from "./_chunks/payment-form-DqEiEJRO.js";
147
+ import { P as Jp, f as Xp, p as Zp, a as $p, s as am, b as em, c as rm } from "./_chunks/payment-form-BNTx4876.js";
148
148
  import { P as tm, p as sm } from "./_chunks/pdf-viewer-CWEXTlwq.js";
149
149
  import { R as im, r as pm } from "./_chunks/reviews-panel-CPrXu5TX.js";
150
150
  import { R as lm, e as cm, r as fm, t as dm, a as gm, w as xm } from "./_chunks/rich-text-editor-DhGIBd4a.js";
@@ -1 +1 @@
1
- {"version":3,"file":"stripe-appearance.d.ts","sourceRoot":"","sources":["../../../../src/tokens/themes/bridges/stripe-appearance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAqBpD,wBAAgB,mBAAmB,CAAC,IAAI,CAAC,EAAE,WAAW,GAAG,UAAU,CAgElE;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,EACpC,IAAI,CAAC,EAAE,WAAW,GACjB,MAAM,IAAI,CAsBZ"}
1
+ {"version":3,"file":"stripe-appearance.d.ts","sourceRoot":"","sources":["../../../../src/tokens/themes/bridges/stripe-appearance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAqBpD,wBAAgB,mBAAmB,CAAC,IAAI,CAAC,EAAE,WAAW,GAAG,UAAU,CAsFlE;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,EACpC,IAAI,CAAC,EAAE,WAAW,GACjB,MAAM,IAAI,CAsBZ"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alfadocs/ui-kit-debug",
3
- "version": "0.45.0",
3
+ "version": "0.46.0",
4
4
  "type": "module",
5
5
  "description": "AlfaDocs shared design system — tokens, components, patterns, and translations for platform, booking, and alfascribe. (debug build — identical runtime to @alfadocs/ui-kit, ships source maps for symbolication).",
6
6
  "license": "BUSL-1.1",
@@ -1 +0,0 @@
1
- {"version":3,"file":"payment-form-DqEiEJRO.js","sources":["../../src/tokens/themes/bridges/stripe-appearance.ts","../../src/components/payment-form/payment-form.agent.ts","../../src/components/payment-form/payment-form.tsx"],"sourcesContent":["import type { Appearance } from '@stripe/stripe-js';\n\n/**\n * Reads the current design-system tokens from a theme-root element and maps\n * them to Stripe Elements' Appearance API. `root` defaults to\n * `document.documentElement` but consumers can pass a scoped theme wrapper\n * (e.g. a modal with its own `.theme-accessible` override) so that Stripe\n * iframes pick up the right token set.\n *\n * Tokens referenced: --primary, --background, --foreground, --muted,\n * --muted-foreground, --border, --destructive, --radius-md, --font-sans,\n * --font-size-base, --spacing-sm, --animation-duration, --focus-ring-width,\n * --ring.\n *\n * No hex / rgb / hsl literals — every value flows from the token layer.\n */\n\nfunction isBrowser(): boolean {\n return typeof document !== 'undefined' && typeof window !== 'undefined';\n}\n\nexport function getStripeAppearance(root?: HTMLElement): Appearance {\n if (!isBrowser()) {\n return { theme: 'stripe' };\n }\n\n const target = root ?? document.documentElement;\n const styles = getComputedStyle(target);\n const read = (token: string) => styles.getPropertyValue(token).trim();\n const isDark = target.classList.contains('theme-dark');\n\n return {\n theme: isDark ? 'night' : 'stripe',\n variables: {\n colorPrimary: read('--primary'),\n colorBackground: read('--background'),\n colorText: read('--foreground'),\n colorDanger: read('--destructive'),\n colorTextSecondary: read('--muted-foreground'),\n colorTextPlaceholder: read('--muted-foreground'),\n borderRadius: read('--radius-md'),\n fontFamily: read('--font-sans'),\n fontSizeBase: read('--font-size-base'),\n // Stripe multiplies spacingUnit throughout every Element; --spacing-sm\n // gives readable density. Keep this in sync with the JSDoc above.\n spacingUnit: read('--spacing-sm'),\n },\n rules: {\n '.Input': {\n backgroundColor: read('--background'),\n border: `1px solid ${read('--border')}`,\n color: read('--foreground'),\n padding: read('--spacing-sm'),\n transition: `border-color ${read('--animation-duration')} ease-out`,\n },\n '.Input:focus': {\n borderColor: read('--primary'),\n boxShadow: `0 0 0 ${read('--focus-ring-width')} ${read('--ring')}`,\n outline: 'none',\n },\n '.Input--invalid': {\n borderColor: read('--destructive'),\n color: read('--foreground'),\n },\n '.Label': {\n color: read('--foreground'),\n fontWeight: read('--font-weight-medium'),\n fontSize: read('--font-size-sm'),\n },\n '.Error': {\n color: read('--destructive'),\n fontSize: read('--font-size-sm'),\n },\n '.Tab': {\n border: `1px solid ${read('--border')}`,\n backgroundColor: read('--background'),\n color: read('--foreground'),\n },\n '.Tab--selected': {\n borderColor: read('--primary'),\n backgroundColor: read('--background'),\n color: read('--primary'),\n },\n },\n };\n}\n\n/**\n * Calls `onChange(getStripeAppearance(root))` whenever the theme root's\n * class list mutates (theme switch) or the user toggles\n * `prefers-color-scheme` / `prefers-reduced-motion`. Returns an\n * unsubscribe function.\n */\nexport function subscribeStripeAppearance(\n onChange: (next: Appearance) => void,\n root?: HTMLElement,\n): () => void {\n if (!isBrowser()) return () => undefined;\n\n const target = root ?? document.documentElement;\n const emit = () => onChange(getStripeAppearance(root));\n\n const observer = new MutationObserver(emit);\n observer.observe(target, {\n attributes: true,\n attributeFilter: ['class', 'dir', 'lang'],\n });\n\n const schemeMql = window.matchMedia('(prefers-color-scheme: dark)');\n const motionMql = window.matchMedia('(prefers-reduced-motion: reduce)');\n schemeMql.addEventListener('change', emit);\n motionMql.addEventListener('change', emit);\n\n return () => {\n observer.disconnect();\n schemeMql.removeEventListener('change', emit);\n motionMql.removeEventListener('change', emit);\n };\n}\n","import type { AgentAdapter } from '../../agent/types';\nimport type { PaymentFormHandle } from './payment-form';\n\nexport const paymentFormAgent: AgentAdapter<PaymentFormHandle> = {\n id: 'payment-form',\n capabilities: ['submit'],\n state: {},\n actions: {\n submit: {\n safety: 'destructive',\n description:\n 'Submit the payment. Charges the configured payment method — irreversible.',\n invoke: (handle) => handle.submit(),\n },\n reset: {\n safety: 'destructive',\n description:\n 'Reset the form to its initial state. Loses any in-progress input.',\n invoke: (handle) => {\n handle.reset();\n },\n },\n },\n domHooks: {\n root: { attr: 'data-component', value: 'payment-form' },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n },\n};\n","/* ------------------------------------------------------------------ */\n/* PaymentForm — Stripe Elements wrapper (PCI DSS SAQ-A). */\n/* */\n/* - Library: `@stripe/react-stripe-js` + `@stripe/stripe-js` (see */\n/* `src/docs/08-third-party.mdx §Payments`). Card number, expiry, */\n/* CVC, and postal code all live inside Stripe-hosted iframes on */\n/* `js.stripe.com` — raw PAN never touches our origin, keeping us */\n/* inside PCI DSS SAQ-A scope. */\n/* */\n/* - Theming: the `stripe-appearance` bridge snapshots our tokens into */\n/* Stripe's Appearance API (`variables`, `rules`). A */\n/* `MutationObserver` on `<html class>` re-runs the snapshot when */\n/* the user flips theme so the embedded iframes repaint. */\n/* */\n/* - Security invariants enforced in this file: */\n/* 1. No `<input type=\"tel\" name=\"card\">` anywhere. */\n/* 2. Error strings are sanitised via `stripCardLikeDigits` before */\n/* forwarding to `onError` (replaces any `\\b\\d{4,}\\b` with */\n/* `****`). */\n/* 3. Element change events are never logged; any dev-only logging */\n/* is gated behind `import.meta.env.DEV` — never runs in prod. */\n/* */\n/* TODO: */\n/* - Stripe's `direction: 'rtl'` is not part of the current */\n/* `Appearance` TypeScript type; we rely on CSS mirroring of our */\n/* chrome via logical properties and let Stripe lay out the iframe */\n/* ltr for now. Revisit when @stripe/stripe-js publishes the type. */\n/* - No `<CardNumberElement>` / split-fields story — `PaymentElement` */\n/* handles accordion + card-only modes via its own `layout` option.*/\n/* ------------------------------------------------------------------ */\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type FormEvent,\n type ReactElement,\n} from 'react';\nimport { cva } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { Spinner } from '../spinner';\nimport { Alert } from '../alert';\nimport {\n loadStripe,\n type Stripe,\n type Appearance,\n type StripeElementLocale,\n type StripeElementsOptions,\n} from '@stripe/stripe-js';\nimport {\n Elements,\n PaymentElement,\n AddressElement,\n useElements,\n useStripe,\n} from '@stripe/react-stripe-js';\n\nimport {\n getStripeAppearance,\n subscribeStripeAppearance,\n} from '../../tokens/themes/bridges/stripe-appearance';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { paymentFormAgent } from './payment-form.agent';\n\n/* ------------------------------------------------------------------ */\n/* Public types */\n/* ------------------------------------------------------------------ */\n\nexport type PaymentCurrency = string; // ISO-4217\n\nexport interface PaymentFormProps {\n /** Opaque instance id — emitted as `data-component-id` for the agent registry. */\n id?: string;\n /**\n * Client secret from your server, created via the PaymentIntents API.\n *\n * Omit to use **deferred-intent mode** — the Payment Element renders from\n * just the publishable key (no `clientSecret`, no backend round-trip up\n * front). In deferred mode supply `onCreatePaymentIntent` to actually\n * confirm: your server mints + returns the client secret at submit time.\n */\n clientSecret?: string;\n /**\n * Deferred-intent setup: `'payment'` collects a charge, `'setup'` saves a\n * method for later. Ignored when `clientSecret` is supplied (the secret's\n * own intent type wins). Defaults to `'payment'`.\n */\n mode?: 'payment' | 'setup';\n /**\n * Deferred-confirm callback. Called at submit time (after client-side\n * field validation succeeds) so your server can mint a PaymentIntent and\n * return its `client_secret`. The returned secret is used ONLY to confirm\n * and is never logged or sent to any third-party origin. When omitted in\n * deferred mode the form runs in PREVIEW: fields render + validate, but no\n * charge is attempted.\n */\n onCreatePaymentIntent?: () => Promise<string>;\n /** Stripe publishable key (`pk_test_…` / `pk_live_…`). */\n publishableKey: string;\n /** ISO-4217 currency code (e.g. 'EUR', 'USD', 'JPY'). */\n currency: PaymentCurrency;\n /** Amount in the currency's smallest unit (cents for EUR/USD, yen for JPY). */\n amount: number;\n /** Called with the PaymentIntent id on successful confirmation. */\n onSuccess?: (paymentIntentId: string) => void;\n /** Called with a sanitised error (no PAN digits, no Stripe English strings). */\n onError?: (error: { code: string; translatedMessage: string }) => void;\n /** Show the billing-address collector below the payment fields. */\n billingAddress?: boolean;\n /** Locale override — defaults to the active i18next locale. */\n locale?: string;\n /** Accessible label for the form. */\n ariaLabel?: string;\n /** URL Stripe redirects to when a payment method requires it. */\n returnUrl?: string;\n /** Pre-injected Stripe instance — used by tests + stories to bypass the network. */\n stripePromise?: Promise<Stripe | null> | null;\n className?: string;\n}\n\nexport interface PaymentFormHandle {\n /** Programmatically submit the form (same flow as the Pay button). */\n submit: () => Promise<void>;\n /** Reset the form to its initial state. */\n reset: () => void;\n}\n\n/* ------------------------------------------------------------------ */\n/* Currency helpers */\n/* ------------------------------------------------------------------ */\n\n/**\n * Currencies that Stripe bills in their base unit (no decimals). Source:\n * https://stripe.com/docs/currencies#zero-decimal — list pinned per\n * 08-third-party.mdx.\n */\nconst ZERO_DECIMAL_CURRENCIES = new Set<string>([\n 'BIF',\n 'CLP',\n 'DJF',\n 'GNF',\n 'IDR',\n 'JPY',\n 'KMF',\n 'KRW',\n 'MGA',\n 'PYG',\n 'RWF',\n 'UGX',\n 'VND',\n 'VUV',\n 'XAF',\n 'XOF',\n 'XPF',\n]);\n\nexport function formatPaymentAmount(\n amount: number,\n currency: string,\n locale: string,\n): string {\n const iso = currency.toUpperCase();\n const major = ZERO_DECIMAL_CURRENCIES.has(iso) ? amount : amount / 100;\n try {\n return new Intl.NumberFormat(locale, {\n style: 'currency',\n currency: iso,\n }).format(major);\n } catch {\n // Invalid locale/currency pair — fall back to a safe format so we\n // never leak raw amount integers into the UI.\n return new Intl.NumberFormat('en', {\n style: 'currency',\n currency: iso,\n }).format(major);\n }\n}\n\n/* ------------------------------------------------------------------ */\n/* Return URL validation */\n/* ------------------------------------------------------------------ */\n\n/**\n * Resolve `returnUrl` against the current origin. Accepts:\n * - absolute URLs on the same origin as `window.location`\n * - relative paths (resolved against the current origin)\n * Rejects (returns `null`):\n * - cross-origin URLs — would leak `payment_intent_client_secret`\n * - `javascript:` / `data:` / `file:` / `blob:` schemes\n * - SSR contexts (no `window`) — the submit path requires a browser\n * anyway, so rejecting here is the safer default.\n * See security-hardening.mdx.\n */\nexport function validateReturnUrl(\n returnUrl: string | undefined,\n): string | null {\n if (returnUrl === undefined) return null;\n const raw = returnUrl.trim();\n if (raw === '') return null;\n if (typeof window === 'undefined') return null;\n try {\n const resolved = new URL(raw, window.location.href);\n const allowedSchemes = new Set(['http:', 'https:']);\n if (!allowedSchemes.has(resolved.protocol)) return null;\n if (resolved.origin !== window.location.origin) return null;\n return resolved.toString();\n } catch {\n return null;\n }\n}\n\n/* ------------------------------------------------------------------ */\n/* Error sanitisation */\n/* ------------------------------------------------------------------ */\n\n/**\n * Replace any run of 4+ consecutive digits with `****`. Called before any\n * error text leaves the wrapper. Defensive: even though Stripe's error\n * strings don't normally contain PANs, a future SDK change could, and we\n * want a hard guarantee that `console` / analytics / Sentry breadcrumbs\n * stay clear of anything that looks like card data.\n */\nexport function stripCardLikeDigits(message: string): string {\n if (!message) return message;\n // Deliberately no word boundaries: a PAN run embedded between word\n // characters (e.g. \"CARD4242424242424242DECLINED\") must still be masked.\n return message.replace(/\\d{4,}/g, '****');\n}\n\n/**\n * Map a Stripe error code (e.g. `card_declined`, `incorrect_number`) to a\n * translation key under `payment.error.*`. Unknown codes fall through to\n * `payment.error.generic`.\n */\nexport function stripeErrorCodeToI18nKey(code: string | undefined): string {\n switch (code) {\n case 'incorrect_number':\n case 'invalid_number':\n return 'payment.error.cardNumber';\n case 'invalid_expiry_month':\n case 'invalid_expiry_year':\n case 'expired_card':\n return 'payment.error.expiry';\n case 'invalid_cvc':\n case 'incorrect_cvc':\n return 'payment.error.cvc';\n case 'incorrect_zip':\n case 'invalid_zip':\n return 'payment.error.postalCode';\n case 'card_declined':\n case 'do_not_honor':\n case 'generic_decline':\n return 'payment.error.declined';\n case 'network_error':\n case 'api_connection_error':\n return 'payment.error.network';\n default:\n return 'payment.error.generic';\n }\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst formVariants = cva(\n [\n 'ds:payment-form-alfadocs ds:flex ds:flex-col',\n 'ds:gap-[var(--spacing-md)]',\n 'ds:bg-[var(--background)] ds:text-[var(--foreground)]',\n 'ds:rounded-[var(--radius-md)] ds:border ds:border-[color:var(--card-border)] ds:shadow-[var(--shadow-card)] ds:[.theme-accessible_&]:border-2',\n 'ds:p-[var(--spacing-md)]',\n 'ds:aria-disabled:opacity-[var(--opacity-50)] ds:aria-disabled:cursor-not-allowed',\n ].join(' '),\n);\n\nconst fieldLabelVariants = cva(\n ['ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]'].join(' '),\n);\n\nconst labelTextVariants = cva(\n ['type-label', 'ds:text-[var(--foreground)]'].join(' '),\n);\n\nconst amountSummaryVariants = cva(\n [\n 'ds:flex ds:items-baseline ds:justify-between',\n 'ds:gap-[var(--spacing-sm)]',\n 'ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)]',\n 'ds:pt-[var(--spacing-xs)] ds:pb-[var(--spacing-xs)]',\n 'ds:bg-[var(--muted)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:text-[var(--foreground)]',\n ].join(' '),\n);\n\nconst submitButtonVariants = cva(\n [\n 'ds:inline-flex ds:items-center ds:justify-center ds:gap-[var(--spacing-xs)]',\n 'ds:[min-block-size:var(--min-target-size)]',\n 'ds:[min-inline-size:var(--min-target-size)]',\n 'ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:bg-[var(--primary)] ds:text-[var(--primary-foreground)]',\n 'ds:text-[length:var(--font-size-base)] ds:font-medium',\n 'ds:transition-colors ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n 'ds:hover:bg-[var(--primary-hover)]',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)]',\n 'ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)]',\n 'ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n 'ds:aria-disabled:opacity-[var(--opacity-50)] ds:aria-disabled:cursor-not-allowed',\n 'ds:aria-busy:cursor-wait',\n ].join(' '),\n);\n\n/* ------------------------------------------------------------------ */\n/* Inner form — lives inside the <Elements> provider */\n/* ------------------------------------------------------------------ */\n\ninterface InnerPaymentFormProps {\n amount: number;\n currency: string;\n locale: string;\n billingAddress: boolean;\n returnUrl: string | undefined;\n /** Present in immediate mode; `undefined` in deferred mode. */\n clientSecret: string | undefined;\n /** Deferred-confirm callback; `undefined` → preview (validate-only). */\n onCreatePaymentIntent: PaymentFormProps['onCreatePaymentIntent'];\n onSuccess: PaymentFormProps['onSuccess'];\n onError: PaymentFormProps['onError'];\n}\n\nfunction InnerPaymentForm(props: InnerPaymentFormProps): ReactElement {\n const {\n amount,\n currency,\n locale,\n billingAddress,\n returnUrl,\n clientSecret,\n onCreatePaymentIntent,\n onSuccess,\n onError,\n } = props;\n\n const { t } = useTranslation();\n const stripe = useStripe();\n const elements = useElements();\n\n const rawId = useId();\n const idSafe = useMemo(\n () => `pay-${rawId.replace(/[^a-zA-Z0-9-_]/g, '')}`,\n [rawId],\n );\n const paymentFieldId = `${idSafe}-payment`;\n const addressFieldId = `${idSafe}-address`;\n const errorId = `${idSafe}-error`;\n\n const [processing, setProcessing] = useState(false);\n const [elementComplete, setElementComplete] = useState(false);\n const [errorKey, setErrorKey] = useState<string | null>(null);\n const [errorMessage, setErrorMessage] = useState<string>('');\n\n const onSuccessRef = useRef(onSuccess);\n const onErrorRef = useRef(onError);\n useEffect(() => {\n onSuccessRef.current = onSuccess;\n onErrorRef.current = onError;\n }, [onSuccess, onError]);\n\n const handleSubmit = useCallback(\n async (event?: FormEvent<HTMLFormElement>): Promise<void> => {\n if (event) event.preventDefault();\n if (!stripe || !elements) return;\n if (processing) return;\n\n setProcessing(true);\n setErrorKey(null);\n setErrorMessage('');\n\n // The single sanitise → map → setError → onError pipeline. Every error\n // surfaced by either path (immediate or deferred) flows through here so\n // raw Stripe English / PAN-like digit runs can never reach the UI or\n // `onError`. `rawMessage` is sanitised; the i18n key is mapped from\n // the Stripe error code.\n const reportError = (\n code: string,\n rawMessage: string | undefined,\n ): void => {\n const key = stripeErrorCodeToI18nKey(code);\n // CRITICAL: sanitise before storing OR forwarding.\n const safe = stripCardLikeDigits(rawMessage ?? '');\n setErrorKey(key);\n setErrorMessage(t(key));\n onErrorRef.current?.({\n code,\n translatedMessage: safe || t(key),\n });\n };\n\n // Validate returnUrl at the boundary so even a careless consumer\n // cannot leak payment_intent_client_secret to a third-party origin.\n const safeReturnUrl = validateReturnUrl(returnUrl);\n if (returnUrl !== undefined && safeReturnUrl === null) {\n setErrorKey('payment.error.invalidReturnUrl');\n setErrorMessage(t('payment.error.invalidReturnUrl'));\n onErrorRef.current?.({\n code: 'invalid_return_url',\n translatedMessage: t('payment.error.invalidReturnUrl'),\n });\n setProcessing(false);\n return;\n }\n\n const confirmParams = safeReturnUrl ? { return_url: safeReturnUrl } : {};\n\n try {\n if (clientSecret !== undefined) {\n // ----- Immediate mode: the consumer already minted the secret. ---\n const result = await stripe.confirmPayment({\n elements,\n confirmParams,\n redirect: 'if_required',\n });\n\n if (result.error) {\n reportError(result.error.code ?? 'generic', result.error.message);\n return;\n }\n\n // Success path — only the PaymentIntent id leaves the wrapper.\n if (result.paymentIntent) {\n onSuccessRef.current?.(result.paymentIntent.id);\n }\n return;\n }\n\n // ----- Deferred-intent mode: no secret up front. -----------------\n // Run client-side field validation first; on failure we run the\n // SAME sanitise/map/report pipeline and stop (no secret minted).\n const { error: submitError } = await elements.submit();\n if (submitError) {\n reportError(submitError.code ?? 'generic', submitError.message);\n return;\n }\n\n // No confirm callback → PREVIEW mode. The field validation above is\n // the end of the flow: no secret is minted, no charge is attempted,\n // and we surface no error — the fields simply validated.\n if (!onCreatePaymentIntent) {\n return;\n }\n\n // Mint the secret on the consumer's server, then confirm with it.\n // The minted secret is used ONLY here and is never logged or sent to\n // a third-party origin.\n const mintedSecret = await onCreatePaymentIntent();\n const result = await stripe.confirmPayment({\n elements,\n clientSecret: mintedSecret,\n confirmParams,\n redirect: 'if_required',\n });\n\n if (result.error) {\n reportError(result.error.code ?? 'generic', result.error.message);\n return;\n }\n\n if (result.paymentIntent) {\n onSuccessRef.current?.(result.paymentIntent.id);\n }\n } catch (err: unknown) {\n const raw = err instanceof Error ? err.message : '';\n // Generic, sanitised — covers a thrown onCreatePaymentIntent and any\n // unexpected SDK rejection. Never surface the raw thrown text.\n reportError('unexpected', raw);\n } finally {\n setProcessing(false);\n }\n },\n [\n stripe,\n elements,\n processing,\n returnUrl,\n clientSecret,\n onCreatePaymentIntent,\n t,\n ],\n );\n\n // Imperative submit hook used by the outer component's ref handle.\n useEffect(() => {\n const host = document.getElementById(idSafe);\n if (!host) return;\n const submitter = () => {\n void handleSubmit();\n };\n host.addEventListener('payment-form:submit', submitter);\n return () => host.removeEventListener('payment-form:submit', submitter);\n }, [idSafe, handleSubmit]);\n\n // Preview mode = deferred (no clientSecret) with no confirm callback. There\n // no charge happens, so we keep the button enabled even before the fields\n // report complete: clicking it triggers `elements.submit()` validation,\n // which is the entire point of the preview.\n const isPreview = clientSecret === undefined && !onCreatePaymentIntent;\n const submitDisabled =\n !stripe || !elements || processing || (!isPreview && !elementComplete);\n\n return (\n <form\n id={idSafe}\n onSubmit={handleSubmit}\n aria-label={t('payment.ariaLabel')}\n aria-busy={processing || undefined}\n noValidate\n >\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n <div className={amountSummaryVariants()}>\n <span className={labelTextVariants()}>\n {t('payment.amountLabel')}\n </span>\n <span className=\"type-title-card\" data-testid=\"payment-amount\">\n {formatPaymentAmount(amount, currency, locale)}\n </span>\n </div>\n\n <label\n htmlFor={paymentFieldId}\n className={fieldLabelVariants()}\n data-testid=\"payment-field\"\n >\n <span className={labelTextVariants()}>\n {t('payment.fields.card')}\n </span>\n <PaymentElement\n id={paymentFieldId}\n options={{\n layout: { type: 'accordion', defaultCollapsed: false },\n }}\n onChange={(ev) => {\n // NOTE: never log `ev` — change events may include hints\n // about field contents. Keep only the boolean completeness.\n setElementComplete(ev.complete === true);\n if (ev.complete) {\n setErrorKey(null);\n setErrorMessage('');\n }\n }}\n />\n </label>\n\n {billingAddress ? (\n <label\n htmlFor={addressFieldId}\n className={fieldLabelVariants()}\n data-testid=\"payment-address\"\n >\n <span className={labelTextVariants()}>\n {t('payment.billingAddress')}\n </span>\n <AddressElement id={addressFieldId} options={{ mode: 'billing' }} />\n </label>\n ) : null}\n\n {errorKey ? (\n <Alert\n id={errorId}\n variant=\"error\"\n live=\"polite\"\n data-testid=\"payment-error\"\n >\n <Alert.Description>{errorMessage}</Alert.Description>\n </Alert>\n ) : null}\n\n <button\n type=\"submit\"\n aria-disabled={submitDisabled || undefined}\n aria-busy={processing || undefined}\n aria-describedby={errorKey ? errorId : undefined}\n className={submitButtonVariants()}\n data-testid=\"payment-submit\"\n >\n {processing ? (\n <>\n <Spinner size=\"sm\" label={t('payment.processing')} />\n <span>{t('payment.processing')}</span>\n </>\n ) : (\n <span>\n {t('payment.submit', {\n amount: formatPaymentAmount(amount, currency, locale),\n })}\n </span>\n )}\n </button>\n </div>\n </form>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* PaymentForm — outer wrapper */\n/* ------------------------------------------------------------------ */\n\n/**\n * Stripe ships a closed union of supported locales; anything outside it\n * must fall through to `'auto'` (Stripe picks the best match from the\n * browser). We also normalise the legacy `cn` code to `zh` per\n * `src/docs/06-i18n.mdx`.\n */\nconst STRIPE_LOCALES = new Set<StripeElementLocale>([\n 'auto',\n 'ar',\n 'bg',\n 'cs',\n 'da',\n 'de',\n 'el',\n 'en',\n 'en-AU',\n 'en-CA',\n 'en-NZ',\n 'en-GB',\n 'es',\n 'es-ES',\n 'es-419',\n 'et',\n 'fi',\n 'fil',\n 'fr',\n 'fr-CA',\n 'fr-FR',\n 'he',\n 'hu',\n 'hr',\n 'id',\n 'it',\n 'it-IT',\n 'ja',\n 'ko',\n 'lt',\n 'lv',\n 'ms',\n 'mt',\n 'nb',\n 'nl',\n 'no',\n 'pl',\n 'pt',\n 'pt-BR',\n 'ro',\n 'ru',\n 'sk',\n 'sl',\n 'sv',\n 'th',\n 'tr',\n 'vi',\n 'zh',\n 'zh-HK',\n 'zh-TW',\n]);\n\nfunction normaliseLocale(input: string): StripeElementLocale {\n if (!input) return 'auto';\n const candidate = input === 'cn' ? 'zh' : input;\n if ((STRIPE_LOCALES as Set<string>).has(candidate)) {\n return candidate as StripeElementLocale;\n }\n // Try stripping region (\"en-US\" → \"en\") before giving up.\n const base = candidate.split('-')[0];\n if ((STRIPE_LOCALES as Set<string>).has(base)) {\n return base as StripeElementLocale;\n }\n return 'auto';\n}\n\nexport const PaymentForm = forwardRef<HTMLDivElement, PaymentFormProps>(\n (\n {\n id,\n clientSecret,\n mode = 'payment',\n onCreatePaymentIntent,\n publishableKey,\n currency,\n amount,\n onSuccess,\n onError,\n billingAddress = false,\n locale,\n ariaLabel,\n returnUrl,\n stripePromise: injectedStripe,\n className,\n },\n ref,\n ) => {\n const { i18n } = useTranslation();\n const activeLocale = normaliseLocale(locale ?? i18n.language ?? 'en');\n\n // Stripe instance — pre-injected (tests/stories) or lazily loaded.\n const [stripeInstance, setStripeInstance] =\n useState<Promise<Stripe | null> | null>(injectedStripe ?? null);\n\n useEffect(() => {\n if (injectedStripe !== undefined) {\n setStripeInstance(injectedStripe);\n return;\n }\n if (!publishableKey) {\n setStripeInstance(null);\n return;\n }\n // `loadStripe` is cached by the SDK — safe to call per mount.\n setStripeInstance(loadStripe(publishableKey));\n }, [injectedStripe, publishableKey]);\n\n // Appearance bridge — snapshot + subscribe.\n const [appearance, setAppearance] = useState<Appearance>(() =>\n getStripeAppearance(),\n );\n useEffect(() => {\n setAppearance(getStripeAppearance());\n const unsubscribe = subscribeStripeAppearance(setAppearance);\n return unsubscribe;\n }, []);\n\n // Imperative handle — dispatch a custom event at the inner form so we\n // can trigger the same submit path as the button without leaking refs\n // through the Stripe `<Elements>` provider (which owns its own tree).\n const hostRef = useRef<HTMLDivElement>(null);\n\n const agentHandle = useMemo<PaymentFormHandle>(\n () => ({\n submit: async () => {\n const form = hostRef.current?.querySelector('form');\n if (form) {\n form.dispatchEvent(\n new CustomEvent('payment-form:submit', { bubbles: true }),\n );\n }\n },\n reset: () => {\n const form = hostRef.current?.querySelector('form');\n if (form instanceof HTMLFormElement) {\n form.reset();\n }\n },\n }),\n [],\n );\n useImperativeHandle(ref, () => hostRef.current as HTMLDivElement, []);\n useAgentRegistration(paymentFormAgent, agentHandle, id);\n\n const elementsOptions = useMemo<StripeElementsOptions>(\n () =>\n clientSecret !== undefined\n ? // Immediate mode — the consumer already created the intent.\n { clientSecret, appearance, locale: activeLocale }\n : // Deferred-intent mode — no secret yet; Stripe needs the intent\n // shape (mode + amount + currency) to render the Payment Element.\n // Stripe expects a lowercase ISO-4217 currency here.\n {\n mode,\n amount,\n currency: currency.toLowerCase(),\n appearance,\n locale: activeLocale,\n },\n [clientSecret, mode, amount, currency, appearance, activeLocale],\n );\n\n return (\n <div\n ref={hostRef}\n aria-label={ariaLabel}\n className={[formVariants(), className].filter(Boolean).join(' ')}\n data-component=\"payment-form\"\n data-component-id={id}\n data-testid=\"payment-form-root\"\n >\n {stripeInstance ? (\n // Render the real Payment Element whenever a Stripe instance is\n // available — in immediate mode (clientSecret present) AND in\n // deferred mode (no secret). The skeleton is reserved for the\n // no-Stripe case (missing publishableKey / injected null).\n <Elements\n stripe={stripeInstance}\n options={elementsOptions}\n key={clientSecret ?? 'deferred'}\n >\n <InnerPaymentForm\n amount={amount}\n currency={currency}\n locale={activeLocale}\n billingAddress={billingAddress}\n returnUrl={returnUrl}\n clientSecret={clientSecret}\n onCreatePaymentIntent={onCreatePaymentIntent}\n onSuccess={onSuccess}\n onError={onError}\n />\n </Elements>\n ) : (\n <PaymentFormSkeleton\n amount={amount}\n currency={currency}\n locale={activeLocale}\n billingAddress={billingAddress}\n />\n )}\n </div>\n );\n },\n);\n\nPaymentForm.displayName = 'PaymentForm';\n\n/* ------------------------------------------------------------------ */\n/* Skeleton — visual chrome when Stripe hasn't loaded yet */\n/* ------------------------------------------------------------------ */\n\ninterface PaymentFormSkeletonProps {\n amount: number;\n currency: string;\n locale: string;\n billingAddress: boolean;\n}\n\nfunction PaymentFormSkeleton(props: PaymentFormSkeletonProps): ReactElement {\n const { amount, currency, locale, billingAddress } = props;\n const { t } = useTranslation();\n\n return (\n <div\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\"\n data-testid=\"payment-skeleton\"\n aria-busy=\"true\"\n >\n <div className={amountSummaryVariants()}>\n <span className={labelTextVariants()}>{t('payment.amountLabel')}</span>\n <span className=\"type-title-card\">\n {formatPaymentAmount(amount, currency, locale)}\n </span>\n </div>\n <div className={fieldLabelVariants()}>\n <span className={labelTextVariants()}>{t('payment.fields.card')}</span>\n <div\n className=\"ds:[min-block-size:var(--min-target-size)] ds:rounded-[var(--radius-sm)] ds:border ds:border-[color:var(--border)] ds:bg-[var(--muted)]\"\n aria-hidden=\"true\"\n />\n </div>\n {billingAddress ? (\n <div className={fieldLabelVariants()} data-testid=\"payment-address\">\n <span className={labelTextVariants()}>\n {t('payment.billingAddress')}\n </span>\n <div\n className=\"ds:[min-block-size:calc(var(--min-target-size)*2)] ds:rounded-[var(--radius-sm)] ds:border ds:border-[color:var(--border)] ds:bg-[var(--muted)]\"\n aria-hidden=\"true\"\n />\n </div>\n ) : null}\n <button\n type=\"button\"\n aria-disabled=\"true\"\n className={submitButtonVariants()}\n disabled\n >\n <Spinner size=\"sm\" label={t('payment.processing')} />\n <span>{t('payment.processing')}</span>\n </button>\n </div>\n );\n}\n\nexport {\n formVariants as paymentFormVariants,\n submitButtonVariants as paymentSubmitButtonVariants,\n};\n"],"names":["isBrowser","getStripeAppearance","root","target","styles","read","token","subscribeStripeAppearance","onChange","emit","observer","schemeMql","motionMql","paymentFormAgent","handle","ZERO_DECIMAL_CURRENCIES","formatPaymentAmount","amount","currency","locale","iso","major","validateReturnUrl","returnUrl","raw","resolved","stripCardLikeDigits","message","stripeErrorCodeToI18nKey","code","formVariants","cva","fieldLabelVariants","labelTextVariants","amountSummaryVariants","submitButtonVariants","InnerPaymentForm","props","billingAddress","clientSecret","onCreatePaymentIntent","onSuccess","onError","t","useTranslation","stripe","useStripe","elements","useElements","rawId","useId","idSafe","useMemo","paymentFieldId","addressFieldId","errorId","processing","setProcessing","useState","elementComplete","setElementComplete","errorKey","setErrorKey","errorMessage","setErrorMessage","onSuccessRef","useRef","onErrorRef","useEffect","handleSubmit","useCallback","event","reportError","rawMessage","key","safe","_a","safeReturnUrl","confirmParams","result","_b","submitError","mintedSecret","_c","err","host","submitter","submitDisabled","jsx","jsxs","PaymentElement","ev","AddressElement","Alert","Fragment","Spinner","STRIPE_LOCALES","normaliseLocale","input","candidate","base","PaymentForm","forwardRef","id","mode","publishableKey","ariaLabel","injectedStripe","className","ref","i18n","activeLocale","stripeInstance","setStripeInstance","loadStripe","appearance","setAppearance","hostRef","agentHandle","form","useImperativeHandle","useAgentRegistration","elementsOptions","Elements","PaymentFormSkeleton"],"mappings":";;;;;;;;;AAiBA,SAASA,KAAqB;AAC5B,SAAO,OAAO,WAAa,OAAe,OAAO,SAAW;AAC9D;AAEO,SAASC,EAAoBC,GAAgC;AAClE,MAAI,CAACF;AACH,WAAO,EAAE,OAAO,SAAA;AAGlB,QAAMG,IAASD,KAAQ,SAAS,iBAC1BE,IAAS,iBAAiBD,CAAM,GAChCE,IAAO,CAACC,MAAkBF,EAAO,iBAAiBE,CAAK,EAAE,KAAA;AAG/D,SAAO;AAAA,IACL,OAHaH,EAAO,UAAU,SAAS,YAAY,IAGnC,UAAU;AAAA,IAC1B,WAAW;AAAA,MACT,cAAcE,EAAK,WAAW;AAAA,MAC9B,iBAAiBA,EAAK,cAAc;AAAA,MACpC,WAAWA,EAAK,cAAc;AAAA,MAC9B,aAAaA,EAAK,eAAe;AAAA,MACjC,oBAAoBA,EAAK,oBAAoB;AAAA,MAC7C,sBAAsBA,EAAK,oBAAoB;AAAA,MAC/C,cAAcA,EAAK,aAAa;AAAA,MAChC,YAAYA,EAAK,aAAa;AAAA,MAC9B,cAAcA,EAAK,kBAAkB;AAAA;AAAA;AAAA,MAGrC,aAAaA,EAAK,cAAc;AAAA,IAAA;AAAA,IAElC,OAAO;AAAA,MACL,UAAU;AAAA,QACR,iBAAiBA,EAAK,cAAc;AAAA,QACpC,QAAQ,aAAaA,EAAK,UAAU,CAAC;AAAA,QACrC,OAAOA,EAAK,cAAc;AAAA,QAC1B,SAASA,EAAK,cAAc;AAAA,QAC5B,YAAY,gBAAgBA,EAAK,sBAAsB,CAAC;AAAA,MAAA;AAAA,MAE1D,gBAAgB;AAAA,QACd,aAAaA,EAAK,WAAW;AAAA,QAC7B,WAAW,SAASA,EAAK,oBAAoB,CAAC,IAAIA,EAAK,QAAQ,CAAC;AAAA,QAChE,SAAS;AAAA,MAAA;AAAA,MAEX,mBAAmB;AAAA,QACjB,aAAaA,EAAK,eAAe;AAAA,QACjC,OAAOA,EAAK,cAAc;AAAA,MAAA;AAAA,MAE5B,UAAU;AAAA,QACR,OAAOA,EAAK,cAAc;AAAA,QAC1B,YAAYA,EAAK,sBAAsB;AAAA,QACvC,UAAUA,EAAK,gBAAgB;AAAA,MAAA;AAAA,MAEjC,UAAU;AAAA,QACR,OAAOA,EAAK,eAAe;AAAA,QAC3B,UAAUA,EAAK,gBAAgB;AAAA,MAAA;AAAA,MAEjC,QAAQ;AAAA,QACN,QAAQ,aAAaA,EAAK,UAAU,CAAC;AAAA,QACrC,iBAAiBA,EAAK,cAAc;AAAA,QACpC,OAAOA,EAAK,cAAc;AAAA,MAAA;AAAA,MAE5B,kBAAkB;AAAA,QAChB,aAAaA,EAAK,WAAW;AAAA,QAC7B,iBAAiBA,EAAK,cAAc;AAAA,QACpC,OAAOA,EAAK,WAAW;AAAA,MAAA;AAAA,IACzB;AAAA,EACF;AAEJ;AAQO,SAASE,GACdC,GACAN,GACY;AACZ,MAAI,CAACF,KAAa,QAAO;;AAEzB,QAAMG,IAAiB,SAAS,iBAC1BM,IAAO,MAAMD,EAASP,EAAoBC,CAAI,CAAC,GAE/CQ,IAAW,IAAI,iBAAiBD,CAAI;AAC1C,EAAAC,EAAS,QAAQP,GAAQ;AAAA,IACvB,YAAY;AAAA,IACZ,iBAAiB,CAAC,SAAS,OAAO,MAAM;AAAA,EAAA,CACzC;AAED,QAAMQ,IAAY,OAAO,WAAW,8BAA8B,GAC5DC,IAAY,OAAO,WAAW,kCAAkC;AACtE,SAAAD,EAAU,iBAAiB,UAAUF,CAAI,GACzCG,EAAU,iBAAiB,UAAUH,CAAI,GAElC,MAAM;AACX,IAAAC,EAAS,WAAA,GACTC,EAAU,oBAAoB,UAAUF,CAAI,GAC5CG,EAAU,oBAAoB,UAAUH,CAAI;AAAA,EAC9C;AACF;ACnHO,MAAMI,KAAoD;AAAA,EAC/D,IAAI;AAAA,EACJ,cAAc,CAAC,QAAQ;AAAA,EACvB,OAAO,CAAA;AAAA,EACP,SAAS;AAAA,IACP,QAAQ;AAAA,MACN,QAAQ;AAAA,MACR,aACE;AAAA,MACF,QAAQ,CAACC,MAAWA,EAAO,OAAA;AAAA,IAAO;AAAA,IAEpC,OAAO;AAAA,MACL,QAAQ;AAAA,MACR,aACE;AAAA,MACF,QAAQ,CAACA,MAAW;AAClB,QAAAA,EAAO,MAAA;AAAA,MACT;AAAA,IAAA;AAAA,EACF;AAAA,EAEF,UAAU;AAAA,IACR,MAAM,EAAE,MAAM,kBAAkB,OAAO,eAAA;AAAA,IACvC,YAAY;AAAA,MACV,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,aAAa;AAAA,IAAA;AAAA,EACf;AAEJ,GC8GMC,yBAA8B,IAAY;AAAA,EAC9C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,SAASC,EACdC,GACAC,GACAC,GACQ;AACR,QAAMC,IAAMF,EAAS,YAAA,GACfG,IAAQN,GAAwB,IAAIK,CAAG,IAAIH,IAASA,IAAS;AACnE,MAAI;AACF,WAAO,IAAI,KAAK,aAAaE,GAAQ;AAAA,MACnC,OAAO;AAAA,MACP,UAAUC;AAAA,IAAA,CACX,EAAE,OAAOC,CAAK;AAAA,EACjB,QAAQ;AAGN,WAAO,IAAI,KAAK,aAAa,MAAM;AAAA,MACjC,OAAO;AAAA,MACP,UAAUD;AAAA,IAAA,CACX,EAAE,OAAOC,CAAK;AAAA,EACjB;AACF;AAiBO,SAASC,GACdC,GACe;AACf,MAAIA,MAAc,OAAW,QAAO;AACpC,QAAMC,IAAMD,EAAU,KAAA;AAEtB,MADIC,MAAQ,MACR,OAAO,SAAW,IAAa,QAAO;AAC1C,MAAI;AACF,UAAMC,IAAW,IAAI,IAAID,GAAK,OAAO,SAAS,IAAI;AAGlD,WADI,EADmB,oBAAI,IAAI,CAAC,SAAS,QAAQ,CAAC,GAC9B,IAAIC,EAAS,QAAQ,KACrCA,EAAS,WAAW,OAAO,SAAS,SAAe,OAChDA,EAAS,SAAA;AAAA,EAClB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAaO,SAASC,GAAoBC,GAAyB;AAC3D,SAAKA,KAGEA,EAAQ,QAAQ,WAAW,MAAM;AAC1C;AAOO,SAASC,GAAyBC,GAAkC;AACzE,UAAQA,GAAA;AAAA,IACN,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EAAA;AAEb;AAMA,MAAMC,KAAeC;AAAA,EACnB;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,EACA,KAAK,GAAG;AACZ,GAEMC,IAAqBD;AAAA,EACzB,CAAC,gDAAgD,EAAE,KAAK,GAAG;AAC7D,GAEME,IAAoBF;AAAA,EACxB,CAAC,cAAc,6BAA6B,EAAE,KAAK,GAAG;AACxD,GAEMG,KAAwBH;AAAA,EAC5B;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,EACA,KAAK,GAAG;AACZ,GAEMI,KAAuBJ;AAAA,EAC3B;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,EACA,KAAK,GAAG;AACZ;AAoBA,SAASK,GAAiBC,GAA4C;AACpE,QAAM;AAAA,IACJ,QAAApB;AAAA,IACA,UAAAC;AAAA,IACA,QAAAC;AAAA,IACA,gBAAAmB;AAAA,IACA,WAAAf;AAAA,IACA,cAAAgB;AAAA,IACA,uBAAAC;AAAA,IACA,WAAAC;AAAA,IACA,SAAAC;AAAA,EAAA,IACEL,GAEE,EAAE,GAAAM,EAAA,IAAMC,EAAA,GACRC,IAASC,GAAA,GACTC,IAAWC,GAAA,GAEXC,IAAQC,GAAA,GACRC,IAASC;AAAA,IACb,MAAM,OAAOH,EAAM,QAAQ,mBAAmB,EAAE,CAAC;AAAA,IACjD,CAACA,CAAK;AAAA,EAAA,GAEFI,IAAiB,GAAGF,CAAM,YAC1BG,IAAiB,GAAGH,CAAM,YAC1BI,IAAU,GAAGJ,CAAM,UAEnB,CAACK,GAAYC,CAAa,IAAIC,EAAS,EAAK,GAC5C,CAACC,GAAiBC,CAAkB,IAAIF,EAAS,EAAK,GACtD,CAACG,GAAUC,CAAW,IAAIJ,EAAwB,IAAI,GACtD,CAACK,GAAcC,CAAe,IAAIN,EAAiB,EAAE,GAErDO,IAAeC,EAAOzB,CAAS,GAC/B0B,IAAaD,EAAOxB,CAAO;AACjC,EAAA0B,EAAU,MAAM;AACd,IAAAH,EAAa,UAAUxB,GACvB0B,EAAW,UAAUzB;AAAA,EACvB,GAAG,CAACD,GAAWC,CAAO,CAAC;AAEvB,QAAM2B,IAAeC;AAAA,IACnB,OAAOC,MAAsD;;AAG3D,UAFIA,OAAa,eAAA,GACb,CAAC1B,KAAU,CAACE,KACZS,EAAY;AAEhB,MAAAC,EAAc,EAAI,GAClBK,EAAY,IAAI,GAChBE,EAAgB,EAAE;AAOlB,YAAMQ,IAAc,CAClB3C,GACA4C,MACS;;AACT,cAAMC,IAAM9C,GAAyBC,CAAI,GAEnC8C,IAAOjD,GAAoB+C,KAAc,EAAE;AACjD,QAAAX,EAAYY,CAAG,GACfV,EAAgBrB,EAAE+B,CAAG,CAAC,IACtBE,IAAAT,EAAW,YAAX,QAAAS,EAAA,KAAAT,GAAqB;AAAA,UACnB,MAAAtC;AAAA,UACA,mBAAmB8C,KAAQhC,EAAE+B,CAAG;AAAA,QAAA;AAAA,MAEpC,GAIMG,IAAgBvD,GAAkBC,CAAS;AACjD,UAAIA,MAAc,UAAasD,MAAkB,MAAM;AACrD,QAAAf,EAAY,gCAAgC,GAC5CE,EAAgBrB,EAAE,gCAAgC,CAAC,IACnDiC,IAAAT,EAAW,YAAX,QAAAS,EAAA,KAAAT,GAAqB;AAAA,UACnB,MAAM;AAAA,UACN,mBAAmBxB,EAAE,gCAAgC;AAAA,QAAA,IAEvDc,EAAc,EAAK;AACnB;AAAA,MACF;AAEA,YAAMqB,IAAgBD,IAAgB,EAAE,YAAYA,EAAA,IAAkB,CAAA;AAEtE,UAAI;AACF,YAAItC,MAAiB,QAAW;AAE9B,gBAAMwC,IAAS,MAAMlC,EAAO,eAAe;AAAA,YACzC,UAAAE;AAAA,YACA,eAAA+B;AAAA,YACA,UAAU;AAAA,UAAA,CACX;AAED,cAAIC,EAAO,OAAO;AAChB,YAAAP,EAAYO,EAAO,MAAM,QAAQ,WAAWA,EAAO,MAAM,OAAO;AAChE;AAAA,UACF;AAGA,UAAIA,EAAO,mBACTC,IAAAf,EAAa,YAAb,QAAAe,EAAA,KAAAf,GAAuBc,EAAO,cAAc;AAE9C;AAAA,QACF;AAKA,cAAM,EAAE,OAAOE,EAAA,IAAgB,MAAMlC,EAAS,OAAA;AAC9C,YAAIkC,GAAa;AACf,UAAAT,EAAYS,EAAY,QAAQ,WAAWA,EAAY,OAAO;AAC9D;AAAA,QACF;AAKA,YAAI,CAACzC;AACH;AAMF,cAAM0C,IAAe,MAAM1C,EAAA,GACrBuC,IAAS,MAAMlC,EAAO,eAAe;AAAA,UACzC,UAAAE;AAAA,UACA,cAAcmC;AAAA,UACd,eAAAJ;AAAA,UACA,UAAU;AAAA,QAAA,CACX;AAED,YAAIC,EAAO,OAAO;AAChB,UAAAP,EAAYO,EAAO,MAAM,QAAQ,WAAWA,EAAO,MAAM,OAAO;AAChE;AAAA,QACF;AAEA,QAAIA,EAAO,mBACTI,IAAAlB,EAAa,YAAb,QAAAkB,EAAA,KAAAlB,GAAuBc,EAAO,cAAc;AAAA,MAEhD,SAASK,GAAc;AACrB,cAAM5D,IAAM4D,aAAe,QAAQA,EAAI,UAAU;AAGjD,QAAAZ,EAAY,cAAchD,CAAG;AAAA,MAC/B,UAAA;AACE,QAAAiC,EAAc,EAAK;AAAA,MACrB;AAAA,IACF;AAAA,IACA;AAAA,MACEZ;AAAA,MACAE;AAAA,MACAS;AAAA,MACAjC;AAAA,MACAgB;AAAA,MACAC;AAAA,MACAG;AAAA,IAAA;AAAA,EACF;AAIF,EAAAyB,EAAU,MAAM;AACd,UAAMiB,IAAO,SAAS,eAAelC,CAAM;AAC3C,QAAI,CAACkC,EAAM;AACX,UAAMC,IAAY,MAAM;AACtB,MAAKjB,EAAA;AAAA,IACP;AACA,WAAAgB,EAAK,iBAAiB,uBAAuBC,CAAS,GAC/C,MAAMD,EAAK,oBAAoB,uBAAuBC,CAAS;AAAA,EACxE,GAAG,CAACnC,GAAQkB,CAAY,CAAC;AAOzB,QAAMkB,KACJ,CAAC1C,KAAU,CAACE,KAAYS,KAAe,EAFvBjB,MAAiB,UAAa,CAACC,MAEM,CAACmB;AAExD,SACE,gBAAA6B;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,IAAIrC;AAAA,MACJ,UAAUkB;AAAA,MACV,cAAY1B,EAAE,mBAAmB;AAAA,MACjC,aAAWa,KAAc;AAAA,MACzB,YAAU;AAAA,MAEV,UAAA,gBAAAiC,EAAC,OAAA,EAAI,WAAU,kDACb,UAAA;AAAA,QAAA,gBAAAA,EAAC,OAAA,EAAI,WAAWvD,GAAA,GACd,UAAA;AAAA,UAAA,gBAAAsD,EAAC,UAAK,WAAWvD,EAAA,GACd,UAAAU,EAAE,qBAAqB,GAC1B;AAAA,UACA,gBAAA6C,EAAC,QAAA,EAAK,WAAU,mBAAkB,eAAY,kBAC3C,UAAAxE,EAAoBC,GAAQC,GAAUC,CAAM,EAAA,CAC/C;AAAA,QAAA,GACF;AAAA,QAEA,gBAAAsE;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,SAASpC;AAAA,YACT,WAAWrB,EAAA;AAAA,YACX,eAAY;AAAA,YAEZ,UAAA;AAAA,cAAA,gBAAAwD,EAAC,UAAK,WAAWvD,EAAA,GACd,UAAAU,EAAE,qBAAqB,GAC1B;AAAA,cACA,gBAAA6C;AAAA,gBAACE;AAAA,gBAAA;AAAA,kBACC,IAAIrC;AAAA,kBACJ,SAAS;AAAA,oBACP,QAAQ,EAAE,MAAM,aAAa,kBAAkB,GAAA;AAAA,kBAAM;AAAA,kBAEvD,UAAU,CAACsC,MAAO;AAGhB,oBAAA/B,EAAmB+B,EAAG,aAAa,EAAI,GACnCA,EAAG,aACL7B,EAAY,IAAI,GAChBE,EAAgB,EAAE;AAAA,kBAEtB;AAAA,gBAAA;AAAA,cAAA;AAAA,YACF;AAAA,UAAA;AAAA,QAAA;AAAA,QAGD1B,IACC,gBAAAmD;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,SAASnC;AAAA,YACT,WAAWtB,EAAA;AAAA,YACX,eAAY;AAAA,YAEZ,UAAA;AAAA,cAAA,gBAAAwD,EAAC,UAAK,WAAWvD,EAAA,GACd,UAAAU,EAAE,wBAAwB,GAC7B;AAAA,cACA,gBAAA6C,EAACI,MAAe,IAAItC,GAAgB,SAAS,EAAE,MAAM,YAAU,CAAG;AAAA,YAAA;AAAA,UAAA;AAAA,QAAA,IAElE;AAAA,QAEHO,IACC,gBAAA2B;AAAA,UAACK;AAAA,UAAA;AAAA,YACC,IAAItC;AAAA,YACJ,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,eAAY;AAAA,YAEZ,UAAA,gBAAAiC,EAACK,EAAM,aAAN,EAAmB,UAAA9B,EAAA,CAAa;AAAA,UAAA;AAAA,QAAA,IAEjC;AAAA,QAEJ,gBAAAyB;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,MAAK;AAAA,YACL,iBAAeD,MAAkB;AAAA,YACjC,aAAW/B,KAAc;AAAA,YACzB,oBAAkBK,IAAWN,IAAU;AAAA,YACvC,WAAWpB,GAAA;AAAA,YACX,eAAY;AAAA,YAEX,cACC,gBAAAsD,EAAAK,IAAA,EACE,UAAA;AAAA,cAAA,gBAAAN,EAACO,MAAQ,MAAK,MAAK,OAAOpD,EAAE,oBAAoB,GAAG;AAAA,cACnD,gBAAA6C,EAAC,QAAA,EAAM,UAAA7C,EAAE,oBAAoB,EAAA,CAAE;AAAA,YAAA,EAAA,CACjC,IAEA,gBAAA6C,EAAC,QAAA,EACE,UAAA7C,EAAE,kBAAkB;AAAA,cACnB,QAAQ3B,EAAoBC,GAAQC,GAAUC,CAAM;AAAA,YAAA,CACrD,EAAA,CACH;AAAA,UAAA;AAAA,QAAA;AAAA,MAEJ,EAAA,CACF;AAAA,IAAA;AAAA,EAAA;AAGN;AAYA,MAAM6E,yBAAqB,IAAyB;AAAA,EAClD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,SAASC,GAAgBC,GAAoC;AAC3D,MAAI,CAACA,EAAO,QAAO;AACnB,QAAMC,IAAYD,MAAU,OAAO,OAAOA;AAC1C,MAAKF,GAA+B,IAAIG,CAAS;AAC/C,WAAOA;AAGT,QAAMC,IAAOD,EAAU,MAAM,GAAG,EAAE,CAAC;AACnC,SAAKH,GAA+B,IAAII,CAAI,IACnCA,IAEF;AACT;AAEO,MAAMC,KAAcC;AAAA,EACzB,CACE;AAAA,IACE,IAAAC;AAAA,IACA,cAAAhE;AAAA,IACA,MAAAiE,IAAO;AAAA,IACP,uBAAAhE;AAAA,IACA,gBAAAiE;AAAA,IACA,UAAAvF;AAAA,IACA,QAAAD;AAAA,IACA,WAAAwB;AAAA,IACA,SAAAC;AAAA,IACA,gBAAAJ,IAAiB;AAAA,IACjB,QAAAnB;AAAA,IACA,WAAAuF;AAAA,IACA,WAAAnF;AAAA,IACA,eAAeoF;AAAA,IACf,WAAAC;AAAA,EAAA,GAEFC,MACG;AACH,UAAM,EAAE,MAAAC,EAAA,IAASlE,EAAA,GACXmE,IAAed,GAAgB9E,KAAU2F,EAAK,YAAY,IAAI,GAG9D,CAACE,GAAgBC,CAAiB,IACtCvD,EAAwCiD,KAAkB,IAAI;AAEhE,IAAAvC,EAAU,MAAM;AACd,UAAIuC,MAAmB,QAAW;AAChC,QAAAM,EAAkBN,CAAc;AAChC;AAAA,MACF;AACA,UAAI,CAACF,GAAgB;AACnB,QAAAQ,EAAkB,IAAI;AACtB;AAAA,MACF;AAEA,MAAAA,EAAkBC,GAAWT,CAAc,CAAC;AAAA,IAC9C,GAAG,CAACE,GAAgBF,CAAc,CAAC;AAGnC,UAAM,CAACU,GAAYC,CAAa,IAAI1D;AAAA,MAAqB,MACvDzD,EAAA;AAAA,IAAoB;AAEtB,IAAAmE,EAAU,OACRgD,EAAcnH,GAAqB,GACfM,GAA0B6G,CAAa,IAE1D,CAAA,CAAE;AAKL,UAAMC,IAAUnD,EAAuB,IAAI,GAErCoD,IAAclE;AAAA,MAClB,OAAO;AAAA,QACL,QAAQ,YAAY;;AAClB,gBAAMmE,KAAO3C,IAAAyC,EAAQ,YAAR,gBAAAzC,EAAiB,cAAc;AAC5C,UAAI2C,KACFA,EAAK;AAAA,YACH,IAAI,YAAY,uBAAuB,EAAE,SAAS,IAAM;AAAA,UAAA;AAAA,QAG9D;AAAA,QACA,OAAO,MAAM;;AACX,gBAAMA,KAAO3C,IAAAyC,EAAQ,YAAR,gBAAAzC,EAAiB,cAAc;AAC5C,UAAI2C,aAAgB,mBAClBA,EAAK,MAAA;AAAA,QAET;AAAA,MAAA;AAAA,MAEF,CAAA;AAAA,IAAC;AAEH,IAAAC,GAAoBX,GAAK,MAAMQ,EAAQ,SAA2B,CAAA,CAAE,GACpEI,GAAqB5G,IAAkByG,GAAaf,CAAE;AAEtD,UAAMmB,IAAkBtE;AAAA,MACtB,MACEb,MAAiB;AAAA;AAAA,QAEb,EAAE,cAAAA,GAAc,YAAA4E,GAAY,QAAQJ,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAIpC;AAAA,UACE,MAAAP;AAAA,UACA,QAAAvF;AAAA,UACA,UAAUC,EAAS,YAAA;AAAA,UACnB,YAAAiG;AAAA,UACA,QAAQJ;AAAA,QAAA;AAAA;AAAA,MAEhB,CAACxE,GAAciE,GAAMvF,GAAQC,GAAUiG,GAAYJ,CAAY;AAAA,IAAA;AAGjE,WACE,gBAAAvB;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAK6B;AAAA,QACL,cAAYX;AAAA,QACZ,WAAW,CAAC5E,GAAA,GAAgB8E,CAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA,QAC/D,kBAAe;AAAA,QACf,qBAAmBL;AAAA,QACnB,eAAY;AAAA,QAEX,UAAAS;AAAA;AAAA;AAAA;AAAA;AAAA,UAKC,gBAAAxB;AAAA,YAACmC;AAAA,YAAA;AAAA,cACC,QAAQX;AAAA,cACR,SAASU;AAAA,cAGT,UAAA,gBAAAlC;AAAA,gBAACpD;AAAA,gBAAA;AAAA,kBACC,QAAAnB;AAAA,kBACA,UAAAC;AAAA,kBACA,QAAQ6F;AAAA,kBACR,gBAAAzE;AAAA,kBACA,WAAAf;AAAA,kBACA,cAAAgB;AAAA,kBACA,uBAAAC;AAAA,kBACA,WAAAC;AAAA,kBACA,SAAAC;AAAA,gBAAA;AAAA,cAAA;AAAA,YACF;AAAA,YAZKH,KAAgB;AAAA,UAAA;AAAA,YAevB,gBAAAiD;AAAA,UAACoC;AAAA,UAAA;AAAA,YACC,QAAA3G;AAAA,YACA,UAAAC;AAAA,YACA,QAAQ6F;AAAA,YACR,gBAAAzE;AAAA,UAAA;AAAA,QAAA;AAAA,MACF;AAAA,IAAA;AAAA,EAIR;AACF;AAEA+D,GAAY,cAAc;AAa1B,SAASuB,GAAoBvF,GAA+C;AAC1E,QAAM,EAAE,QAAApB,GAAQ,UAAAC,GAAU,QAAAC,GAAQ,gBAAAmB,MAAmBD,GAC/C,EAAE,GAAAM,EAAA,IAAMC,EAAA;AAEd,SACE,gBAAA6C;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAU;AAAA,MACV,eAAY;AAAA,MACZ,aAAU;AAAA,MAEV,UAAA;AAAA,QAAA,gBAAAA,EAAC,OAAA,EAAI,WAAWvD,GAAA,GACd,UAAA;AAAA,UAAA,gBAAAsD,EAAC,UAAK,WAAWvD,EAAA,GAAsB,UAAAU,EAAE,qBAAqB,GAAE;AAAA,UAChE,gBAAA6C,EAAC,UAAK,WAAU,mBACb,YAAoBvE,GAAQC,GAAUC,CAAM,EAAA,CAC/C;AAAA,QAAA,GACF;AAAA,QACA,gBAAAsE,EAAC,OAAA,EAAI,WAAWzD,EAAA,GACd,UAAA;AAAA,UAAA,gBAAAwD,EAAC,UAAK,WAAWvD,EAAA,GAAsB,UAAAU,EAAE,qBAAqB,GAAE;AAAA,UAChE,gBAAA6C;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAU;AAAA,cACV,eAAY;AAAA,YAAA;AAAA,UAAA;AAAA,QACd,GACF;AAAA,QACClD,IACC,gBAAAmD,EAAC,OAAA,EAAI,WAAWzD,KAAsB,eAAY,mBAChD,UAAA;AAAA,UAAA,gBAAAwD,EAAC,UAAK,WAAWvD,EAAA,GACd,UAAAU,EAAE,wBAAwB,GAC7B;AAAA,UACA,gBAAA6C;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAU;AAAA,cACV,eAAY;AAAA,YAAA;AAAA,UAAA;AAAA,QACd,EAAA,CACF,IACE;AAAA,QACJ,gBAAAC;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,MAAK;AAAA,YACL,iBAAc;AAAA,YACd,WAAWtD,GAAA;AAAA,YACX,UAAQ;AAAA,YAER,UAAA;AAAA,cAAA,gBAAAqD,EAACO,MAAQ,MAAK,MAAK,OAAOpD,EAAE,oBAAoB,GAAG;AAAA,cACnD,gBAAA6C,EAAC,QAAA,EAAM,UAAA7C,EAAE,oBAAoB,EAAA,CAAE;AAAA,YAAA;AAAA,UAAA;AAAA,QAAA;AAAA,MACjC;AAAA,IAAA;AAAA,EAAA;AAGN;"}