@alfadocs/ui-kit-debug 0.2.0 → 0.2.1

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.
Files changed (57) hide show
  1. package/dist/_chunks/{combobox-DCNXqbC7.js → combobox-BLWruOxK.js} +74 -75
  2. package/dist/_chunks/combobox-BLWruOxK.js.map +1 -0
  3. package/dist/_chunks/{freemium-paywall-CnvceDav.js → freemium-paywall-CrVefV0M.js} +2 -2
  4. package/dist/_chunks/{freemium-paywall-CnvceDav.js.map → freemium-paywall-CrVefV0M.js.map} +1 -1
  5. package/dist/_chunks/{link-8QmFjIz2.js → link-BcYW1eNM.js} +48 -32
  6. package/dist/_chunks/link-BcYW1eNM.js.map +1 -0
  7. package/dist/_chunks/{message-card-ChCX9Iv6.js → message-card-DjvsB_3U.js} +12 -12
  8. package/dist/_chunks/message-card-DjvsB_3U.js.map +1 -0
  9. package/dist/_chunks/{message-tray-n8q9ITXI.js → message-tray-BbnAzlLH.js} +23 -23
  10. package/dist/_chunks/{message-tray-n8q9ITXI.js.map → message-tray-BbnAzlLH.js.map} +1 -1
  11. package/dist/_chunks/{notification-card-hBlPN1-c.js → notification-card-uTPEvAQS.js} +21 -21
  12. package/dist/_chunks/notification-card-uTPEvAQS.js.map +1 -0
  13. package/dist/_chunks/{notification-tray-C5cnXbl9.js → notification-tray-PGtMqXbP.js} +56 -56
  14. package/dist/_chunks/{notification-tray-C5cnXbl9.js.map → notification-tray-PGtMqXbP.js.map} +1 -1
  15. package/dist/_chunks/{payment-form-C3vT_npe.js → payment-form-B_BdHwjb.js} +21 -21
  16. package/dist/_chunks/{payment-form-C3vT_npe.js.map → payment-form-B_BdHwjb.js.map} +1 -1
  17. package/dist/_chunks/transaction-chip-DE6DITun.js +196 -0
  18. package/dist/_chunks/transaction-chip-DE6DITun.js.map +1 -0
  19. package/dist/agent-catalog.json +15 -1
  20. package/dist/components/combobox/combobox.d.ts.map +1 -1
  21. package/dist/components/combobox/index.js +1 -1
  22. package/dist/components/freemium-paywall/index.js +1 -1
  23. package/dist/components/index.d.ts +1 -0
  24. package/dist/components/index.d.ts.map +1 -1
  25. package/dist/components/link/index.js +1 -1
  26. package/dist/components/link/link.d.ts +1 -0
  27. package/dist/components/link/link.d.ts.map +1 -1
  28. package/dist/components/message-card/index.js +1 -1
  29. package/dist/components/message-card/message-card.d.ts.map +1 -1
  30. package/dist/components/message-tray/index.js +1 -1
  31. package/dist/components/message-tray/message-tray.d.ts.map +1 -1
  32. package/dist/components/notification-card/index.js +1 -1
  33. package/dist/components/notification-card/notification-card.d.ts.map +1 -1
  34. package/dist/components/notification-tray/index.js +1 -1
  35. package/dist/components/notification-tray/notification-tray.d.ts.map +1 -1
  36. package/dist/components/payment-form/index.js +1 -1
  37. package/dist/components/transaction-chip/index.d.ts +3 -0
  38. package/dist/components/transaction-chip/index.d.ts.map +1 -0
  39. package/dist/components/transaction-chip/index.js +5 -0
  40. package/dist/components/transaction-chip/index.js.map +1 -0
  41. package/dist/components/transaction-chip/transaction-chip.d.ts +30 -0
  42. package/dist/components/transaction-chip/transaction-chip.d.ts.map +1 -0
  43. package/dist/i18n/config.js +36 -0
  44. package/dist/i18n/config.js.map +1 -1
  45. package/dist/i18n/resources.d.ts +36 -0
  46. package/dist/i18n/resources.d.ts.map +1 -1
  47. package/dist/index.js +33 -31
  48. package/dist/index.js.map +1 -1
  49. package/dist/locales/de.json +12 -0
  50. package/dist/locales/en.json +12 -0
  51. package/dist/locales/it.json +12 -0
  52. package/dist/tokens.css +1 -1
  53. package/package.json +1 -1
  54. package/dist/_chunks/combobox-DCNXqbC7.js.map +0 -1
  55. package/dist/_chunks/link-8QmFjIz2.js.map +0 -1
  56. package/dist/_chunks/message-card-ChCX9Iv6.js.map +0 -1
  57. package/dist/_chunks/notification-card-hBlPN1-c.js.map +0 -1
@@ -82,7 +82,7 @@ function be(r, n) {
82
82
  i.disconnect(), a.removeEventListener("change", e), f.removeEventListener("change", e);
83
83
  };
84
84
  }
85
- const ge = {
85
+ const ye = {
86
86
  id: "payment-form",
87
87
  capabilities: ["submit"],
88
88
  state: {},
@@ -108,7 +108,7 @@ const ge = {
108
108
  description: "Sourced from the id prop."
109
109
  }
110
110
  }
111
- }, ye = /* @__PURE__ */ new Set([
111
+ }, ge = /* @__PURE__ */ new Set([
112
112
  "BIF",
113
113
  "CLP",
114
114
  "DJF",
@@ -128,7 +128,7 @@ const ge = {
128
128
  "XPF"
129
129
  ]);
130
130
  function $(r, n, s) {
131
- const e = n.toUpperCase(), i = ye.has(e) ? r : r / 100;
131
+ const e = n.toUpperCase(), i = ge.has(e) ? r : r / 100;
132
132
  try {
133
133
  return new Intl.NumberFormat(s, {
134
134
  style: "currency",
@@ -233,9 +233,9 @@ function xe(r) {
233
233
  returnUrl: a,
234
234
  onSuccess: f,
235
235
  onError: N
236
- } = r, { t: o } = q(), k = le(), S = me(), y = oe(), b = j(
237
- () => `pay-${y.replace(/[^a-zA-Z0-9-_]/g, "")}`,
238
- [y]
236
+ } = r, { t: o } = q(), k = le(), S = me(), g = oe(), b = j(
237
+ () => `pay-${g.replace(/[^a-zA-Z0-9-_]/g, "")}`,
238
+ [g]
239
239
  ), F = `${b}-payment`, L = `${b}-address`, v = `${b}-error`, [u, h] = E(!1), [A, P] = E(!1), [w, x] = E(null), [U, d] = E(""), c = V(f), l = V(N);
240
240
  R(() => {
241
241
  c.current = f, l.current = N;
@@ -254,22 +254,22 @@ function xe(r) {
254
254
  return;
255
255
  }
256
256
  try {
257
- const g = await k.confirmPayment({
257
+ const y = await k.confirmPayment({
258
258
  elements: S,
259
259
  confirmParams: C ? { return_url: C } : {},
260
260
  redirect: "if_required"
261
261
  });
262
- if (g.error) {
263
- const M = g.error.code ?? "generic", I = he(M), te = X(g.error.message ?? "");
262
+ if (y.error) {
263
+ const M = y.error.code ?? "generic", I = he(M), te = X(y.error.message ?? "");
264
264
  x(I), d(o(I)), (H = l.current) == null || H.call(l, {
265
265
  code: M,
266
266
  translatedMessage: te || o(I)
267
267
  });
268
268
  return;
269
269
  }
270
- g.paymentIntent && ((O = c.current) == null || O.call(c, g.paymentIntent.id));
271
- } catch (g) {
272
- const M = g instanceof Error ? g.message : "", I = X(M);
270
+ y.paymentIntent && ((O = c.current) == null || O.call(c, y.paymentIntent.id));
271
+ } catch (y) {
272
+ const M = y instanceof Error ? y.message : "", I = X(M);
273
273
  x("payment.error.generic"), d(o("payment.error.generic")), (K = l.current) == null || K.call(l, {
274
274
  code: "unexpected",
275
275
  translatedMessage: I || o("payment.error.generic")
@@ -441,13 +441,13 @@ const ke = se(
441
441
  locale: o,
442
442
  ariaLabel: k,
443
443
  returnUrl: S,
444
- stripePromise: y,
444
+ stripePromise: g,
445
445
  className: b
446
446
  }, F) => {
447
- const { i18n: L } = q(), v = Ne(o ?? L.language ?? "en"), [u, h] = E(y ?? null);
447
+ const { i18n: L } = q(), v = Ne(o ?? L.language ?? "en"), [u, h] = E(g ?? null);
448
448
  R(() => {
449
- if (y !== void 0) {
450
- h(y);
449
+ if (g !== void 0) {
450
+ h(g);
451
451
  return;
452
452
  }
453
453
  if (!s) {
@@ -455,7 +455,7 @@ const ke = se(
455
455
  return;
456
456
  }
457
457
  h(de(s));
458
- }, [y, s]);
458
+ }, [g, s]);
459
459
  const [A, P] = E(
460
460
  () => B()
461
461
  );
@@ -477,7 +477,7 @@ const ke = se(
477
477
  }),
478
478
  []
479
479
  );
480
- ae(F, () => w.current, []), fe(ge, x, r);
480
+ ae(F, () => w.current, []), fe(ye, x, r);
481
481
  const U = j(
482
482
  () => ({
483
483
  clientSecret: n,
@@ -551,7 +551,7 @@ function Se(r) {
551
551
  }
552
552
  )
553
553
  ] }),
554
- i ? /* @__PURE__ */ m("div", { className: T(), children: [
554
+ i ? /* @__PURE__ */ m("div", { className: T(), "data-testid": "payment-address", children: [
555
555
  /* @__PURE__ */ t("span", { className: _(), children: a("payment.billingAddress") }),
556
556
  /* @__PURE__ */ t(
557
557
  "div",
@@ -584,7 +584,7 @@ export {
584
584
  X as b,
585
585
  he as c,
586
586
  $ as f,
587
- ge as p,
587
+ ye as p,
588
588
  ee as s
589
589
  };
590
- //# sourceMappingURL=payment-form-C3vT_npe.js.map
590
+ //# sourceMappingURL=payment-form-B_BdHwjb.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"payment-form-C3vT_npe.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} 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} 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 /** Required — from your server, created via the PaymentIntents API. */\n clientSecret: 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(--border)]',\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 onSuccess: PaymentFormProps['onSuccess'];\n onError: PaymentFormProps['onError'];\n}\n\nfunction InnerPaymentForm(props: InnerPaymentFormProps): JSX.Element {\n const {\n amount,\n currency,\n locale,\n billingAddress,\n returnUrl,\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 // 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 try {\n const result = await stripe.confirmPayment({\n elements,\n confirmParams: safeReturnUrl ? { return_url: safeReturnUrl } : {},\n redirect: 'if_required',\n });\n\n if (result.error) {\n const code = result.error.code ?? 'generic';\n const key = stripeErrorCodeToI18nKey(code);\n // CRITICAL: sanitise before storing OR forwarding.\n const safe = stripCardLikeDigits(result.error.message ?? '');\n setErrorKey(key);\n setErrorMessage(t(key));\n onErrorRef.current?.({\n code,\n translatedMessage: safe || t(key),\n });\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 } catch (err: unknown) {\n const raw = err instanceof Error ? err.message : '';\n const safe = stripCardLikeDigits(raw);\n setErrorKey('payment.error.generic');\n setErrorMessage(t('payment.error.generic'));\n onErrorRef.current?.({\n code: 'unexpected',\n translatedMessage: safe || t('payment.error.generic'),\n });\n } finally {\n setProcessing(false);\n }\n },\n [stripe, elements, processing, returnUrl, t],\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 const submitDisabled = !stripe || !elements || !elementComplete || processing;\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 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(\n () => ({\n clientSecret,\n appearance,\n locale: activeLocale,\n }),\n [clientSecret, 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 && clientSecret ? (\n <Elements\n stripe={stripeInstance}\n options={elementsOptions}\n key={clientSecret}\n >\n <InnerPaymentForm\n amount={amount}\n currency={currency}\n locale={activeLocale}\n billingAddress={billingAddress}\n returnUrl={returnUrl}\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): JSX.Element {\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()}>\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","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","safeReturnUrl","_a","result","key","safe","_b","_c","err","_d","host","submitter","submitDisabled","jsx","jsxs","PaymentElement","ev","AddressElement","Alert","Fragment","Spinner","STRIPE_LOCALES","normaliseLocale","input","candidate","base","PaymentForm","forwardRef","id","clientSecret","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
+ {"version":3,"file":"payment-form-B_BdHwjb.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} 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} 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 /** Required — from your server, created via the PaymentIntents API. */\n clientSecret: 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(--border)]',\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 onSuccess: PaymentFormProps['onSuccess'];\n onError: PaymentFormProps['onError'];\n}\n\nfunction InnerPaymentForm(props: InnerPaymentFormProps): JSX.Element {\n const {\n amount,\n currency,\n locale,\n billingAddress,\n returnUrl,\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 // 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 try {\n const result = await stripe.confirmPayment({\n elements,\n confirmParams: safeReturnUrl ? { return_url: safeReturnUrl } : {},\n redirect: 'if_required',\n });\n\n if (result.error) {\n const code = result.error.code ?? 'generic';\n const key = stripeErrorCodeToI18nKey(code);\n // CRITICAL: sanitise before storing OR forwarding.\n const safe = stripCardLikeDigits(result.error.message ?? '');\n setErrorKey(key);\n setErrorMessage(t(key));\n onErrorRef.current?.({\n code,\n translatedMessage: safe || t(key),\n });\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 } catch (err: unknown) {\n const raw = err instanceof Error ? err.message : '';\n const safe = stripCardLikeDigits(raw);\n setErrorKey('payment.error.generic');\n setErrorMessage(t('payment.error.generic'));\n onErrorRef.current?.({\n code: 'unexpected',\n translatedMessage: safe || t('payment.error.generic'),\n });\n } finally {\n setProcessing(false);\n }\n },\n [stripe, elements, processing, returnUrl, t],\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 const submitDisabled = !stripe || !elements || !elementComplete || processing;\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 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(\n () => ({\n clientSecret,\n appearance,\n locale: activeLocale,\n }),\n [clientSecret, 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 && clientSecret ? (\n <Elements\n stripe={stripeInstance}\n options={elementsOptions}\n key={clientSecret}\n >\n <InnerPaymentForm\n amount={amount}\n currency={currency}\n locale={activeLocale}\n billingAddress={billingAddress}\n returnUrl={returnUrl}\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): JSX.Element {\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","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","safeReturnUrl","_a","result","key","safe","_b","_c","err","_d","host","submitter","submitDisabled","jsx","jsxs","PaymentElement","ev","AddressElement","Alert","Fragment","Spinner","STRIPE_LOCALES","normaliseLocale","input","candidate","base","PaymentForm","forwardRef","id","clientSecret","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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"}
@@ -0,0 +1,196 @@
1
+ import { jsxs as z, jsx as s } from "react/jsx-runtime";
2
+ import { forwardRef as N } from "react";
3
+ import { c as l } from "./index-D2ZczOXr.js";
4
+ import { useTranslation as T } from "react-i18next";
5
+ import { C as M } from "./check-DPdL_Sm7.js";
6
+ import { c as t } from "./createLucideIcon-CrFbzy84.js";
7
+ import { F as _ } from "./file-text-DSNuv2B8.js";
8
+ /**
9
+ * @license lucide-react v1.8.0 - ISC
10
+ *
11
+ * This source code is licensed under the ISC license.
12
+ * See the LICENSE file in the root directory of this source tree.
13
+ */
14
+ const I = [
15
+ ["path", { d: "M17 7 7 17", key: "15tmo1" }],
16
+ ["path", { d: "M17 17H7V7", key: "1org7z" }]
17
+ ], C = t("arrow-down-left", I);
18
+ /**
19
+ * @license lucide-react v1.8.0 - ISC
20
+ *
21
+ * This source code is licensed under the ISC license.
22
+ * See the LICENSE file in the root directory of this source tree.
23
+ */
24
+ const A = [
25
+ ["path", { d: "M7 7h10v10", key: "1tivn9" }],
26
+ ["path", { d: "M7 17 17 7", key: "1vkiza" }]
27
+ ], E = t("arrow-up-right", A);
28
+ /**
29
+ * @license lucide-react v1.8.0 - ISC
30
+ *
31
+ * This source code is licensed under the ISC license.
32
+ * See the LICENSE file in the root directory of this source tree.
33
+ */
34
+ const L = [
35
+ ["path", { d: "M16 14v2.2l1.6 1", key: "fo4ql5" }],
36
+ ["path", { d: "M16 2v4", key: "4m81vk" }],
37
+ ["path", { d: "M21 7.5V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h3.5", key: "1osxxc" }],
38
+ ["path", { d: "M3 10h5", key: "r794hk" }],
39
+ ["path", { d: "M8 2v4", key: "1cmpym" }],
40
+ ["circle", { cx: "16", cy: "16", r: "6", key: "qoo3c4" }]
41
+ ], R = t("calendar-clock", L), S = {
42
+ debt: "debt",
43
+ credit: "credit",
44
+ "to-invoice": "toInvoice",
45
+ "to-deliver": "toDeliver",
46
+ settled: "settled"
47
+ }, V = {
48
+ debt: C,
49
+ credit: E,
50
+ "to-invoice": _,
51
+ "to-deliver": R,
52
+ settled: M
53
+ }, F = {
54
+ debt: "−",
55
+ credit: "+",
56
+ "to-invoice": "",
57
+ "to-deliver": "",
58
+ settled: ""
59
+ }, D = {
60
+ debt: -1,
61
+ credit: 1,
62
+ "to-invoice": 1,
63
+ "to-deliver": 1,
64
+ settled: 1
65
+ }, U = "EUR", j = l(
66
+ [
67
+ "ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)]",
68
+ "ds:rounded-[var(--radius-full)] ds:border",
69
+ "ds:whitespace-nowrap ds:align-middle",
70
+ "ds:focus-visible:outline-none",
71
+ "ds:focus-visible:ring-[length:var(--focus-ring-width)]",
72
+ "ds:focus-visible:ring-[color:var(--ring)]",
73
+ "ds:focus-visible:ring-offset-[length:var(--focus-ring-offset)]"
74
+ ].join(" "),
75
+ {
76
+ variants: {
77
+ state: {
78
+ // Text uses the deeper `*-foreground` token (matching Badge / Tag) so
79
+ // small chip text clears WCAG AA (4.5:1) against the 10% tinted
80
+ // background. The surface and border use the lighter alias.
81
+ debt: "ds:bg-destructive/10 ds:text-[color:var(--error-foreground)] ds:border-destructive/20",
82
+ credit: "ds:bg-success/10 ds:text-[color:var(--success-foreground)] ds:border-success/20",
83
+ // The orange "to-invoice" tint has no kit-wide semantic alias — see
84
+ // src/tokens/index.css §Transaction-chip-scoped tokens. The component
85
+ // owns the alias because the customer-anchored "Da fatturare" orange
86
+ // is distinct from `--warning` (yellow) and from `--destructive`.
87
+ "to-invoice": "ds:bg-transaction-chip-to-invoice/10 ds:text-[color:var(--transaction-chip-to-invoice-foreground)] ds:border-transaction-chip-to-invoice/20",
88
+ "to-deliver": "ds:bg-info/10 ds:text-[color:var(--info-foreground)] ds:border-info/20",
89
+ settled: "ds:bg-muted/30 ds:text-muted-foreground ds:border-muted/40"
90
+ },
91
+ size: {
92
+ // Heights tuned for table-cell density (sm), default app surfaces (md),
93
+ // and header / summary cards (lg). `--type-eyebrow-size` flows into the
94
+ // optional label span, keeping its typography in step with the chip.
95
+ sm: "ds:h-5 ds:ps-[var(--spacing-xs)] ds:pe-[var(--spacing-sm)] ds:text-[length:var(--font-size-2xs)] ds:[--type-eyebrow-size:var(--font-size-2xs)]",
96
+ md: "ds:h-6 ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)] ds:text-[length:var(--font-size-xs)] ds:[--type-eyebrow-size:var(--font-size-2xs)]",
97
+ lg: "ds:h-7 ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-md)] ds:text-[length:var(--font-size-sm)] ds:[--type-eyebrow-size:var(--font-size-xs)]"
98
+ },
99
+ bold: {
100
+ // `settled` is the terminal resting state — see compound variant below.
101
+ true: "ds:font-semibold",
102
+ false: "ds:font-medium"
103
+ }
104
+ },
105
+ defaultVariants: {
106
+ state: "debt",
107
+ size: "md",
108
+ bold: !0
109
+ },
110
+ compoundVariants: [
111
+ // `settled` always renders at the lighter weight, regardless of the
112
+ // resolved default. Mirrors PR #523's follow-up where the resting branch
113
+ // dropped from bold to medium to recede visually.
114
+ { state: "settled", class: "ds:font-medium" }
115
+ ]
116
+ }
117
+ ), $ = l(
118
+ "ds:shrink-0 ds:[&>svg]:block ds:rtl:[&>svg]:-scale-x-100",
119
+ {
120
+ variants: {
121
+ size: {
122
+ sm: "ds:[&>svg]:size-3",
123
+ md: "ds:[&>svg]:size-3.5",
124
+ lg: "ds:[&>svg]:size-4"
125
+ }
126
+ },
127
+ defaultVariants: { size: "md" }
128
+ }
129
+ ), q = N(
130
+ ({
131
+ state: e,
132
+ amount: v,
133
+ currency: o = U,
134
+ locale: m,
135
+ size: r = "md",
136
+ showLabel: p = !1,
137
+ className: f,
138
+ "aria-label": u,
139
+ ...g
140
+ }, h) => {
141
+ const { t: a, i18n: b } = T(), i = m ?? b.language ?? "en", y = V[e], n = F[e], d = Math.abs(v), x = new Intl.NumberFormat(i, {
142
+ style: "currency",
143
+ currency: o,
144
+ signDisplay: "never"
145
+ }).format(d), c = a(`ui.financial.state.${S[e]}`), k = new Intl.NumberFormat(i, {
146
+ style: "currency",
147
+ currency: o,
148
+ signDisplay: e === "debt" ? "always" : "auto"
149
+ }).format(d * D[e]), w = u ?? a("ui.financial.aria.label", {
150
+ state: c,
151
+ amount: k
152
+ });
153
+ return /* @__PURE__ */ z(
154
+ "span",
155
+ {
156
+ ref: h,
157
+ role: "img",
158
+ "aria-label": w,
159
+ "data-component": "transaction-chip",
160
+ "data-state": e,
161
+ className: j({
162
+ state: e,
163
+ size: r,
164
+ bold: e !== "settled",
165
+ className: f
166
+ }),
167
+ ...g,
168
+ children: [
169
+ /* @__PURE__ */ s("span", { "aria-hidden": "true", className: $({ size: r }), children: /* @__PURE__ */ s(y, {}) }),
170
+ p && /* @__PURE__ */ s("span", { "aria-hidden": "true", className: "type-eyebrow", children: c }),
171
+ n && /* @__PURE__ */ s(
172
+ "span",
173
+ {
174
+ "aria-hidden": "true",
175
+ className: "ds:[font-variant-numeric:var(--font-feature-tabular)]",
176
+ children: n
177
+ }
178
+ ),
179
+ /* @__PURE__ */ s(
180
+ "span",
181
+ {
182
+ "aria-hidden": "true",
183
+ className: "ds:[font-variant-numeric:var(--font-feature-tabular)]",
184
+ children: x
185
+ }
186
+ )
187
+ ]
188
+ }
189
+ );
190
+ }
191
+ );
192
+ q.displayName = "TransactionChip";
193
+ export {
194
+ q as T
195
+ };
196
+ //# sourceMappingURL=transaction-chip-DE6DITun.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transaction-chip-DE6DITun.js","sources":["../../node_modules/lucide-react/dist/esm/icons/arrow-down-left.js","../../node_modules/lucide-react/dist/esm/icons/arrow-up-right.js","../../node_modules/lucide-react/dist/esm/icons/calendar-clock.js","../../src/components/transaction-chip/transaction-chip.tsx"],"sourcesContent":["/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\"path\", { d: \"M17 7 7 17\", key: \"15tmo1\" }],\n [\"path\", { d: \"M17 17H7V7\", key: \"1org7z\" }]\n];\nconst ArrowDownLeft = createLucideIcon(\"arrow-down-left\", __iconNode);\n\nexport { __iconNode, ArrowDownLeft as default };\n//# sourceMappingURL=arrow-down-left.js.map\n","/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\"path\", { d: \"M7 7h10v10\", key: \"1tivn9\" }],\n [\"path\", { d: \"M7 17 17 7\", key: \"1vkiza\" }]\n];\nconst ArrowUpRight = createLucideIcon(\"arrow-up-right\", __iconNode);\n\nexport { __iconNode, ArrowUpRight as default };\n//# sourceMappingURL=arrow-up-right.js.map\n","/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\"path\", { d: \"M16 14v2.2l1.6 1\", key: \"fo4ql5\" }],\n [\"path\", { d: \"M16 2v4\", key: \"4m81vk\" }],\n [\"path\", { d: \"M21 7.5V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h3.5\", key: \"1osxxc\" }],\n [\"path\", { d: \"M3 10h5\", key: \"r794hk\" }],\n [\"path\", { d: \"M8 2v4\", key: \"1cmpym\" }],\n [\"circle\", { cx: \"16\", cy: \"16\", r: \"6\", key: \"qoo3c4\" }]\n];\nconst CalendarClock = createLucideIcon(\"calendar-clock\", __iconNode);\n\nexport { __iconNode, CalendarClock as default };\n//# sourceMappingURL=calendar-clock.js.map\n","import { forwardRef, type HTMLAttributes } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport {\n ArrowDownLeft,\n ArrowUpRight,\n CalendarClock,\n Check,\n FileText,\n type LucideIcon,\n} from 'lucide-react';\n\n/* ------------------------------------------------------------------ */\n/* State vocabulary */\n/* ------------------------------------------------------------------ */\n\nexport type TransactionState =\n | 'debt'\n | 'credit'\n | 'to-invoice'\n | 'to-deliver'\n | 'settled';\n\n// State → translation-key segment. Hyphenated state names are flattened to\n// camelCase so the i18next bundle stays consistent with the rest of `ui.*`.\nconst STATE_KEY: Record<TransactionState, string> = {\n debt: 'debt',\n credit: 'credit',\n 'to-invoice': 'toInvoice',\n 'to-deliver': 'toDeliver',\n settled: 'settled',\n};\n\nconst STATE_ICON: Record<TransactionState, LucideIcon> = {\n debt: ArrowDownLeft,\n credit: ArrowUpRight,\n 'to-invoice': FileText,\n 'to-deliver': CalendarClock,\n settled: Check,\n};\n\n// U+2212 MINUS SIGN — matches PR alfadocs/platform#523's typographic minus.\n// Hyphen-minus would render visually narrower next to the currency glyph.\nconst STATE_SIGN: Record<TransactionState, '' | '+' | '−'> = {\n debt: '−',\n credit: '+',\n 'to-invoice': '',\n 'to-deliver': '',\n settled: '',\n};\n\n// Multiplier used when composing the screen-reader announcement so SR users\n// hear the signed amount Intl produces (\"minus one thousand…\") rather than\n// the magnitude plus a separate sign glyph.\nconst SIGN_MULTIPLIER: Record<TransactionState, -1 | 1> = {\n debt: -1,\n credit: 1,\n 'to-invoice': 1,\n 'to-deliver': 1,\n settled: 1,\n};\n\nconst DEFAULT_CURRENCY = 'EUR';\n\n/* ------------------------------------------------------------------ */\n/* CVA — chip root */\n/* ------------------------------------------------------------------ */\n\nconst chipVariants = cva(\n [\n 'ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)]',\n 'ds:rounded-[var(--radius-full)] ds:border',\n 'ds:whitespace-nowrap ds:align-middle',\n 'ds:focus-visible:outline-none',\n 'ds:focus-visible:ring-[length:var(--focus-ring-width)]',\n 'ds:focus-visible:ring-[color:var(--ring)]',\n 'ds:focus-visible:ring-offset-[length:var(--focus-ring-offset)]',\n ].join(' '),\n {\n variants: {\n state: {\n // Text uses the deeper `*-foreground` token (matching Badge / Tag) so\n // small chip text clears WCAG AA (4.5:1) against the 10% tinted\n // background. The surface and border use the lighter alias.\n debt:\n 'ds:bg-destructive/10 ds:text-[color:var(--error-foreground)] ds:border-destructive/20',\n credit:\n 'ds:bg-success/10 ds:text-[color:var(--success-foreground)] ds:border-success/20',\n // The orange \"to-invoice\" tint has no kit-wide semantic alias — see\n // src/tokens/index.css §Transaction-chip-scoped tokens. The component\n // owns the alias because the customer-anchored \"Da fatturare\" orange\n // is distinct from `--warning` (yellow) and from `--destructive`.\n 'to-invoice':\n 'ds:bg-transaction-chip-to-invoice/10 ds:text-[color:var(--transaction-chip-to-invoice-foreground)] ds:border-transaction-chip-to-invoice/20',\n 'to-deliver':\n 'ds:bg-info/10 ds:text-[color:var(--info-foreground)] ds:border-info/20',\n settled:\n 'ds:bg-muted/30 ds:text-muted-foreground ds:border-muted/40',\n },\n size: {\n // Heights tuned for table-cell density (sm), default app surfaces (md),\n // and header / summary cards (lg). `--type-eyebrow-size` flows into the\n // optional label span, keeping its typography in step with the chip.\n sm: 'ds:h-5 ds:ps-[var(--spacing-xs)] ds:pe-[var(--spacing-sm)] ds:text-[length:var(--font-size-2xs)] ds:[--type-eyebrow-size:var(--font-size-2xs)]',\n md: 'ds:h-6 ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)] ds:text-[length:var(--font-size-xs)] ds:[--type-eyebrow-size:var(--font-size-2xs)]',\n lg: 'ds:h-7 ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-md)] ds:text-[length:var(--font-size-sm)] ds:[--type-eyebrow-size:var(--font-size-xs)]',\n },\n bold: {\n // `settled` is the terminal resting state — see compound variant below.\n true: 'ds:font-semibold',\n false: 'ds:font-medium',\n },\n },\n defaultVariants: {\n state: 'debt',\n size: 'md',\n bold: true,\n },\n compoundVariants: [\n // `settled` always renders at the lighter weight, regardless of the\n // resolved default. Mirrors PR #523's follow-up where the resting branch\n // dropped from bold to medium to recede visually.\n { state: 'settled', class: 'ds:font-medium' },\n ],\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* CVA — icon wrapper */\n/* ------------------------------------------------------------------ */\n\n// `ArrowDownLeft` (debt) and `ArrowUpRight` (credit) are direction-encoded\n// glyphs — their physical orientation carries the semantic (\"money coming\n// in\" / \"money going out\"). PRS §05 RTL: directional icons flip in RTL.\n// The non-directional glyphs (FileText, CalendarClock, Check) are unaffected.\nconst iconWrapperVariants = cva(\n 'ds:shrink-0 ds:[&>svg]:block ds:rtl:[&>svg]:-scale-x-100',\n {\n variants: {\n size: {\n sm: 'ds:[&>svg]:size-3',\n md: 'ds:[&>svg]:size-3.5',\n lg: 'ds:[&>svg]:size-4',\n },\n },\n defaultVariants: { size: 'md' },\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* Props */\n/* ------------------------------------------------------------------ */\n\nexport interface TransactionChipProps\n extends Omit<HTMLAttributes<HTMLSpanElement>, 'children'>,\n Pick<VariantProps<typeof chipVariants>, 'size'> {\n /** Financial state — drives colour, icon, sign, and label. */\n state: TransactionState;\n /**\n * Magnitude of the amount as a non-negative number. The sign is rendered\n * separately based on `state` — callers must never pass a negative value.\n */\n amount: number;\n /**\n * ISO 4217 currency code. Defaults to `EUR` for the Italian-anchored\n * release. Required at the type level so consumers can't silently render\n * a different currency than they intended.\n */\n currency?: string;\n /** BCP 47 locale override. Defaults to the active i18next language. */\n locale?: string;\n /** Render the state label (e.g. \"Da incassare\") before the amount. */\n showLabel?: boolean;\n}\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\nexport const TransactionChip = forwardRef<HTMLSpanElement, TransactionChipProps>(\n (\n {\n state,\n amount,\n currency = DEFAULT_CURRENCY,\n locale,\n size = 'md',\n showLabel = false,\n className,\n 'aria-label': ariaLabelProp,\n ...rest\n },\n ref,\n ) => {\n const { t, i18n } = useTranslation();\n const activeLocale = locale ?? i18n.language ?? 'en';\n\n const StateIcon = STATE_ICON[state];\n const sign = STATE_SIGN[state];\n const magnitude = Math.abs(amount);\n\n // The visible amount is rendered without a sign; the leading sign glyph\n // (or its absence) is owned by the state, not the formatter.\n const formattedAmount = new Intl.NumberFormat(activeLocale, {\n style: 'currency',\n currency,\n signDisplay: 'never',\n }).format(magnitude);\n\n // The accessible name uses Intl's own signed output so screen readers\n // announce the locale-correct \"minus\" / \"negative\" phrasing instead of\n // skipping the U+2212 glyph or speaking it as \"hyphen\".\n const stateLabel = t(`ui.financial.state.${STATE_KEY[state]}`);\n const signedAmountForSR = new Intl.NumberFormat(activeLocale, {\n style: 'currency',\n currency,\n signDisplay: state === 'debt' ? 'always' : 'auto',\n }).format(magnitude * SIGN_MULTIPLIER[state]);\n const ariaLabel =\n ariaLabelProp ??\n t('ui.financial.aria.label', {\n state: stateLabel,\n amount: signedAmountForSR,\n });\n\n return (\n <span\n ref={ref}\n role=\"img\"\n aria-label={ariaLabel}\n data-component=\"transaction-chip\"\n data-state={state}\n className={chipVariants({\n state,\n size,\n bold: state !== 'settled',\n className,\n })}\n {...rest}\n >\n <span aria-hidden=\"true\" className={iconWrapperVariants({ size })}>\n <StateIcon />\n </span>\n {showLabel && (\n <span aria-hidden=\"true\" className=\"type-eyebrow\">\n {stateLabel}\n </span>\n )}\n {sign && (\n <span\n aria-hidden=\"true\"\n className=\"ds:[font-variant-numeric:var(--font-feature-tabular)]\"\n >\n {sign}\n </span>\n )}\n <span\n aria-hidden=\"true\"\n className=\"ds:[font-variant-numeric:var(--font-feature-tabular)]\"\n >\n {formattedAmount}\n </span>\n </span>\n );\n },\n);\n\nTransactionChip.displayName = 'TransactionChip';\n"],"names":["__iconNode","ArrowDownLeft","createLucideIcon","ArrowUpRight","CalendarClock","STATE_KEY","STATE_ICON","FileText","Check","STATE_SIGN","SIGN_MULTIPLIER","DEFAULT_CURRENCY","chipVariants","cva","iconWrapperVariants","TransactionChip","forwardRef","state","amount","currency","locale","size","showLabel","className","ariaLabelProp","rest","ref","t","i18n","useTranslation","activeLocale","StateIcon","sign","magnitude","formattedAmount","stateLabel","signedAmountForSR","ariaLabel","jsxs","jsx"],"mappings":"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","x_google_ignoreList":[0,1,2]}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "packageVersion": "0.2.0",
3
+ "packageVersion": "0.2.1",
4
4
  "components": [
5
5
  {
6
6
  "kind": "component",
@@ -3773,6 +3773,20 @@
3773
3773
  }
3774
3774
  }
3775
3775
  },
3776
+ {
3777
+ "kind": "component",
3778
+ "id": "transaction-chip",
3779
+ "capabilities": [],
3780
+ "state": [],
3781
+ "actions": [],
3782
+ "domHooks": {
3783
+ "root": {
3784
+ "attr": "data-component",
3785
+ "value": "transaction-chip",
3786
+ "description": "Marks the element as a kit TransactionChip."
3787
+ }
3788
+ }
3789
+ },
3776
3790
  {
3777
3791
  "kind": "component",
3778
3792
  "id": "transcript-panel",