@adia-ai/web-modules 0.8.36 → 0.8.38

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 (90) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +4 -4
  3. package/agent-admin/admin-roster/admin-roster.js +1 -1
  4. package/agent-admin/admin-settings/admin-settings.js +1 -1
  5. package/agent-admin/agent-admin/agent-admin.js +1 -1
  6. package/billing/billing-overview/billing-overview.a2ui.json +281 -0
  7. package/billing/billing-overview/billing-overview.class.js +838 -0
  8. package/billing/billing-overview/billing-overview.css +223 -0
  9. package/billing/billing-overview/billing-overview.js +16 -0
  10. package/billing/billing-overview/billing-overview.yaml +441 -0
  11. package/billing/index.js +21 -0
  12. package/billing/invoice-detail/invoice-detail.a2ui.json +276 -0
  13. package/billing/invoice-detail/invoice-detail.class.js +711 -0
  14. package/billing/invoice-detail/invoice-detail.css +305 -0
  15. package/billing/invoice-detail/invoice-detail.js +16 -0
  16. package/billing/invoice-detail/invoice-detail.yaml +411 -0
  17. package/billing/invoice-history/invoice-history.a2ui.json +315 -0
  18. package/billing/invoice-history/invoice-history.class.js +672 -0
  19. package/billing/invoice-history/invoice-history.css +130 -0
  20. package/billing/invoice-history/invoice-history.js +16 -0
  21. package/billing/invoice-history/invoice-history.yaml +398 -0
  22. package/billing/payment-method-form/payment-method-form.a2ui.json +310 -0
  23. package/billing/payment-method-form/payment-method-form.class.js +886 -0
  24. package/billing/payment-method-form/payment-method-form.css +149 -0
  25. package/billing/payment-method-form/payment-method-form.js +16 -0
  26. package/billing/payment-method-form/payment-method-form.yaml +430 -0
  27. package/billing/payment-method-list/payment-method-list.a2ui.json +283 -0
  28. package/billing/payment-method-list/payment-method-list.class.js +705 -0
  29. package/billing/payment-method-list/payment-method-list.css +128 -0
  30. package/billing/payment-method-list/payment-method-list.js +16 -0
  31. package/billing/payment-method-list/payment-method-list.yaml +355 -0
  32. package/billing/plan-picker/plan-picker.a2ui.json +349 -0
  33. package/billing/plan-picker/plan-picker.class.js +635 -0
  34. package/billing/plan-picker/plan-picker.css +227 -0
  35. package/billing/plan-picker/plan-picker.js +16 -0
  36. package/billing/plan-picker/plan-picker.yaml +453 -0
  37. package/chat/README.md +2 -2
  38. package/chat/chat-composer/chat-composer.js +2 -2
  39. package/chat/chat-empty/chat-empty.js +2 -2
  40. package/chat/chat-shell/chat-shell.js +6 -6
  41. package/chat/chat-sidebar/chat-sidebar.js +2 -2
  42. package/chat/chat-surfaces/chat-surfaces.js +3 -3
  43. package/chat/chat-thread/chat-thread.js +2 -2
  44. package/dashboard/dashboard-layout/dashboard-layout.a2ui.json +254 -0
  45. package/dashboard/dashboard-layout/dashboard-layout.css +190 -0
  46. package/dashboard/dashboard-layout/dashboard-layout.js +289 -0
  47. package/dashboard/dashboard-layout/dashboard-layout.yaml +374 -0
  48. package/dashboard/date-range-selector/date-range-selector.a2ui.json +236 -0
  49. package/dashboard/date-range-selector/date-range-selector.css +84 -0
  50. package/dashboard/date-range-selector/date-range-selector.js +686 -0
  51. package/dashboard/date-range-selector/date-range-selector.yaml +358 -0
  52. package/dashboard/index.js +14 -0
  53. package/dist/chat/chat-shell.min.js +1 -1
  54. package/dist/everything.min.js +121 -102
  55. package/editor/editor-canvas/editor-canvas.js +2 -2
  56. package/editor/editor-shell/editor-shell.js +2 -2
  57. package/editor/editor-sidebar/editor-sidebar.js +2 -2
  58. package/editor/editor-toolbar/editor-toolbar.js +2 -2
  59. package/feedback/confirm-dialog/confirm-dialog.a2ui.json +206 -0
  60. package/feedback/confirm-dialog/confirm-dialog.css +157 -0
  61. package/feedback/confirm-dialog/confirm-dialog.js +383 -0
  62. package/feedback/confirm-dialog/confirm-dialog.yaml +297 -0
  63. package/feedback/index.js +10 -0
  64. package/form/form-popover/form-popover.js +1 -1
  65. package/generative/index.d.ts +1 -1
  66. package/generative/index.js +2 -2
  67. package/onboarding/index.js +1 -0
  68. package/onboarding/onboarding-checklist/onboarding-checklist.a2ui.json +263 -0
  69. package/onboarding/onboarding-checklist/onboarding-checklist.css +157 -0
  70. package/onboarding/onboarding-checklist/onboarding-checklist.js +428 -0
  71. package/onboarding/onboarding-checklist/onboarding-checklist.yaml +236 -0
  72. package/package.json +99 -6
  73. package/runtime/a2ui-root/a2ui-root.js +3 -3
  74. package/runtime/gen-root/gen-root.js +5 -5
  75. package/settings/index.js +12 -0
  76. package/settings/integrations-page/integrations-page.a2ui.json +274 -0
  77. package/settings/integrations-page/integrations-page.css +177 -0
  78. package/settings/integrations-page/integrations-page.d.ts +77 -0
  79. package/settings/integrations-page/integrations-page.js +413 -0
  80. package/settings/integrations-page/integrations-page.yaml +317 -0
  81. package/settings/notification-preferences/notification-preferences.a2ui.json +245 -0
  82. package/settings/notification-preferences/notification-preferences.css +204 -0
  83. package/settings/notification-preferences/notification-preferences.js +622 -0
  84. package/settings/notification-preferences/notification-preferences.yaml +358 -0
  85. package/shell/admin-command/admin-command.js +2 -2
  86. package/shell/admin-shell/admin-shell.js +2 -2
  87. package/shell/admin-sidebar/admin-sidebar.js +2 -2
  88. package/shell/embed-shell/embed-shell.js +3 -3
  89. package/simple/simple-shell/simple-shell.js +1 -1
  90. package/theme/theme-panel/theme-panel.js +2 -2
@@ -0,0 +1,149 @@
1
+ /* ═══════════════════════════════════════════════════════════════
2
+ <payment-method-form-ui> — Form-participating payment-method composite.
3
+
4
+ Stamps a grid of <field-ui> + <input-ui> + <select-ui> sub-controls
5
+ for collecting card number, expiry, CVC, name, billing address, and
6
+ country. Form chrome + structured validation; tokenization is the
7
+ consumer's job (Stripe Elements / Braintree / Adyen).
8
+
9
+ SPEC: docs/specs/implementation-ready/SPEC-009-payment-method-form.md
10
+ Two-block @scope pattern per docs/specs/component-token-contract.md.
11
+ Zero raw color values (repo hard rule); rem only.
12
+ ═══════════════════════════════════════════════════════════════ */
13
+
14
+ /* ── Block 1: TOKEN DECLARATIONS ───────────────────────────────── */
15
+
16
+ payment-method-form-ui {
17
+ --payment-method-form-gap: var(--a-space-3);
18
+ --payment-method-form-grid-template: "name name" "card card" "expiry cvc" "country postal";
19
+ --payment-method-form-grid-template-billing:
20
+ "name name" "card card" "expiry cvc" "address1 address1" "address2 address2" "country postal";
21
+
22
+ --payment-method-form-brand-icon-size: 1.25em;
23
+
24
+ --payment-method-form-alert-mb: var(--a-space-3);
25
+
26
+ --payment-method-form-summary-bg: var(--a-bg-muted);
27
+ --payment-method-form-summary-border: 1px solid var(--md-sys-color-neutral-outline);
28
+ --payment-method-form-summary-radius: var(--a-radius-md);
29
+ --payment-method-form-summary-px: var(--a-space-4);
30
+ --payment-method-form-summary-py: var(--a-space-3);
31
+
32
+ --payment-method-form-legal-fg: var(--a-fg-muted);
33
+ --payment-method-form-legal-size: var(--a-text-xs, 0.75rem);
34
+
35
+ --payment-method-form-disabled-opacity: var(--a-opacity-disabled, 0.5);
36
+ }
37
+
38
+ /* ── Block 2: SCOPED LAYOUT ────────────────────────────────────── */
39
+
40
+ @scope (payment-method-form-ui) {
41
+
42
+ :scope {
43
+ display: flex;
44
+ flex-direction: column;
45
+ gap: var(--payment-method-form-gap);
46
+ }
47
+
48
+ /* ── Host-level error alert ── */
49
+ :scope > [data-alert] {
50
+ margin-block-end: var(--payment-method-form-alert-mb);
51
+ }
52
+ :scope > [data-alert][hidden] {
53
+ display: none;
54
+ }
55
+
56
+ /* ── Saved-card summary row ── */
57
+ :scope > [data-summary] {
58
+ display: flex;
59
+ align-items: center;
60
+ gap: var(--a-space-3);
61
+ background: var(--payment-method-form-summary-bg);
62
+ border: var(--payment-method-form-summary-border);
63
+ border-radius: var(--payment-method-form-summary-radius);
64
+ padding-inline: var(--payment-method-form-summary-px);
65
+ padding-block: var(--payment-method-form-summary-py);
66
+ }
67
+ :scope > [data-summary][hidden] {
68
+ display: none;
69
+ }
70
+ :scope > [data-summary] > [data-summary-icon] {
71
+ --a-icon-size: 1.25rem;
72
+ color: var(--a-fg-muted);
73
+ flex-shrink: 0;
74
+ }
75
+ :scope > [data-summary] > [data-summary-text] {
76
+ flex: 1;
77
+ color: var(--md-sys-color-neutral-on-surface);
78
+ font-size: var(--a-text-sm, 0.875rem);
79
+ }
80
+ :scope > [data-summary] > [data-summary-edit] {
81
+ flex-shrink: 0;
82
+ }
83
+
84
+ /* ── Field grid ── */
85
+ :scope > [data-grid] {
86
+ display: grid;
87
+ grid-template-columns: 1fr 1fr;
88
+ grid-template-areas: var(--payment-method-form-grid-template);
89
+ gap: var(--payment-method-form-gap);
90
+ }
91
+ :scope > [data-grid][hidden] {
92
+ display: none;
93
+ }
94
+
95
+ :scope[require-billing-address] > [data-grid] {
96
+ grid-template-areas: var(--payment-method-form-grid-template-billing);
97
+ }
98
+
99
+ /* Hidden rows (address lines when require-billing-address is unset)
100
+ collapse out of the grid without affecting sibling cell flow. */
101
+ :scope > [data-grid] > field-ui[hidden] {
102
+ display: none;
103
+ }
104
+
105
+ /* ── Brand badge in card-number trailing slot ── */
106
+ :scope [data-brand-badge] {
107
+ display: inline-flex;
108
+ align-items: center;
109
+ font-size: var(--payment-method-form-brand-icon-size);
110
+ color: var(--a-fg-muted);
111
+ letter-spacing: 0.025em;
112
+ text-transform: uppercase;
113
+ }
114
+ :scope [data-brand-badge] > [data-brand] {
115
+ font-weight: var(--a-weight-semibold, 600);
116
+ color: var(--md-sys-color-neutral-on-surface);
117
+ font-size: var(--a-text-xs, 0.75rem);
118
+ padding-inline: var(--a-space-2);
119
+ padding-block: var(--a-space-1);
120
+ border-radius: var(--a-radius-sm);
121
+ background: var(--a-bg-muted);
122
+ }
123
+ :scope [data-brand-badge] > [data-brand="visa"] { color: var(--a-info-fg, var(--md-sys-color-neutral-on-surface)); }
124
+ :scope [data-brand-badge] > [data-brand="mastercard"] { color: var(--a-warning-fg, var(--md-sys-color-neutral-on-surface)); }
125
+ :scope [data-brand-badge] > [data-brand="amex"] { color: var(--a-primary-fg, var(--md-sys-color-neutral-on-surface)); }
126
+ :scope [data-brand-badge] > [data-brand="discover"] { color: var(--a-success-fg, var(--md-sys-color-neutral-on-surface)); }
127
+
128
+ /* ── Slotted legal copy ── */
129
+ :scope > [data-legal] {
130
+ color: var(--payment-method-form-legal-fg);
131
+ font-size: var(--payment-method-form-legal-size);
132
+ line-height: 1.5;
133
+ }
134
+ :scope > [data-legal]:empty {
135
+ display: none;
136
+ }
137
+
138
+ /* ── Disabled state ── */
139
+ :scope[disabled] {
140
+ opacity: var(--payment-method-form-disabled-opacity);
141
+ pointer-events: none;
142
+ }
143
+
144
+ /* ── Focus-within outline (group-level affordance) ── */
145
+ :scope:focus-within {
146
+ /* Visually delegated to per-field controls; the host-level outline
147
+ would double-up against field-ui's focus styling. */
148
+ }
149
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * `<payment-method-form-ui>` — auto-registers the tag on import.
3
+ *
4
+ * For a non-side-effect class import (test isolation, tag override),
5
+ * use the class export from `./payment-method-form.class.js`:
6
+ *
7
+ * import { UIPaymentMethodForm } from '@adia-ai/web-modules/billing/payment-method-form/class';
8
+ */
9
+
10
+ import { UIPaymentMethodForm } from './payment-method-form.class.js';
11
+
12
+ if (!customElements.get('payment-method-form-ui')) {
13
+ customElements.define('payment-method-form-ui', UIPaymentMethodForm);
14
+ }
15
+
16
+ export { UIPaymentMethodForm };
@@ -0,0 +1,430 @@
1
+ # Edit this file; run `npm run build:components` to regenerate a2ui.json.
2
+ $schema: ../../../../scripts/schemas/component.yaml.schema.json
3
+ name: UIPaymentMethodForm
4
+ tag: payment-method-form-ui
5
+ status: experimental
6
+ component: PaymentMethodForm
7
+ category: input
8
+ version: 1
9
+ description: |
10
+ Form-participating composite for capturing a payment method —
11
+ card number, expiry, CVC, name on card, billing address (optional),
12
+ and country. The form chrome + structured validation + a single
13
+ normalized emit event; it does NOT integrate with Stripe Elements
14
+ or a tokenization SDK directly (consumer responsibility).
15
+
16
+ Each sub-field is a <field-ui> wrapper around an <input-ui> (or
17
+ <select-ui> for country). Card number is Luhn-validated; expiry is
18
+ parsed as MM/YY with month + year bounds; CVC is 3-4 digits.
19
+ Brand detection (visa / mastercard / amex / discover) runs against
20
+ a small regex map and surfaces via the `change` event detail.
21
+
22
+ Form value is a JSON-encoded payload of normalized field values
23
+ serialized through ElementInternals under [name] (default
24
+ "paymentMethod"). On submit, the host fires
25
+ `submit-payment-method` with a flat detail
26
+ `{ token, last4, brand, expMonth, expYear, name, country }`.
27
+ `token` is a synthetic local-mode token (sha-like opaque string);
28
+ consumers integrating with a real processor handle tokenization
29
+ in their own submit listener using `last4` / `brand` / etc.
30
+
31
+ Spec: .claude/docs/specs/implementation-ready/SPEC-009-payment-method-form.md.
32
+
33
+ # Per ADR-0027 — composites do NOT auto-import the primitives they
34
+ # stamp in connected()/render(). The consumer (or this primitive's
35
+ # .html demo shell) must explicitly side-effect-import each one.
36
+ composes:
37
+ - field-ui
38
+ - input-ui
39
+ - select-ui
40
+ - alert-ui
41
+ - icon-ui
42
+ - button-ui
43
+
44
+ props:
45
+ name:
46
+ description: |
47
+ Form field name. The composite's serialized form value lives
48
+ under this key in any wrapping <form>. Defaults to
49
+ "paymentMethod".
50
+ type: string
51
+ default: "paymentMethod"
52
+ reflect: true
53
+
54
+ value:
55
+ description: |
56
+ Resolved payment-method token. Read-only externally — the
57
+ composite writes it after a successful tokenize() call. Setting
58
+ this to a non-empty string is treated as "prefilled from a
59
+ saved payment method" and renders the form in
60
+ read-only-summary mode (last4 + brand + expiry shown).
61
+ type: string
62
+ default: ""
63
+ reflect: true
64
+ dynamic: true
65
+
66
+ prefill:
67
+ description: |
68
+ JSON-encoded prefill payload `{last4, brand, expMonth, expYear,
69
+ name, country}`. When set, the summary row renders with the
70
+ saved-card chrome and the rest of the form is hidden behind an
71
+ "Edit card" button. Useful for "update saved payment method"
72
+ flows.
73
+ type: string
74
+ default: ""
75
+ attribute: prefill
76
+
77
+ countries:
78
+ description: |
79
+ Allowed billing countries, ISO 3166-1 alpha-2 codes. Drives
80
+ the <select-ui> dropdown's options. Empty array uses a
81
+ default short list (US, CA, GB, DE, FR, AU).
82
+ type: array
83
+ default: []
84
+ dynamic: true
85
+
86
+ default-country:
87
+ description: |
88
+ Default selected country (ISO 3166-1 alpha-2). Falls back to
89
+ the first entry in `countries` (or "US" when empty).
90
+ type: string
91
+ default: "US"
92
+ reflect: true
93
+ attribute: default-country
94
+
95
+ require-billing-address:
96
+ description: |
97
+ When set, renders the billing-address sub-fields (address line
98
+ 1, optional line 2, postal code). When unset, only postal code
99
+ + country are collected for the address-verification check.
100
+ type: boolean
101
+ default: false
102
+ reflect: true
103
+ attribute: require-billing-address
104
+
105
+ disabled:
106
+ description: |
107
+ Forwarded to every sub-control. Pointer-events:none on the
108
+ composite host as a belt-and-suspenders.
109
+ type: boolean
110
+ default: false
111
+ reflect: true
112
+ dynamic: true
113
+
114
+ required:
115
+ description: |
116
+ Form-validation gate. When set, an empty composite fails
117
+ checkValidity() with "Payment method required.".
118
+ type: boolean
119
+ default: false
120
+ reflect: true
121
+
122
+ error:
123
+ description: |
124
+ Externally-set error message (e.g. server-rejected card). When
125
+ non-empty, the composite renders an <alert-ui variant="danger">
126
+ at the top of the form and sets aria-invalid=true on the host.
127
+ type: string
128
+ default: ""
129
+ reflect: true
130
+ dynamic: true
131
+
132
+ tokenizing:
133
+ description: |
134
+ tokenize() in flight — set internally by the composite (and
135
+ cleared on settle), same read-only-externally convention as
136
+ `value`. Declared here (mirroring the `states:` entry below) so
137
+ the in-flight visual state is representable in authored/generated
138
+ markup for documentation and storyboard fixtures.
139
+ type: boolean
140
+ default: false
141
+ reflect: true
142
+
143
+ autofocus:
144
+ description: |
145
+ When set, the first sub-field (Name on card) receives focus on
146
+ first connect. Convention parity with native form elements.
147
+ type: boolean
148
+ default: false
149
+ reflect: true
150
+
151
+ events:
152
+ submit-payment-method:
153
+ description: |
154
+ Fired when tokenize() resolves — either via an outer <form>
155
+ submission or an explicit tokenize() call. Detail carries the
156
+ normalized payload that downstream code POSTs to the billing
157
+ service. Bubbles.
158
+ detail:
159
+ token:
160
+ type: string
161
+ description: Synthetic local-mode token (sha-like opaque string).
162
+ last4:
163
+ type: string
164
+ description: Last 4 digits of the card number.
165
+ brand:
166
+ type: string
167
+ description: Detected brand — `visa`, `mastercard`, `amex`, `discover`, or `unknown`.
168
+ expMonth:
169
+ type: integer
170
+ description: Expiry month (1-12).
171
+ expYear:
172
+ type: integer
173
+ description: Expiry year (4-digit).
174
+ name:
175
+ type: string
176
+ description: Name on card.
177
+ country:
178
+ type: string
179
+ description: ISO 3166-1 alpha-2 billing country.
180
+
181
+ payment-method-error:
182
+ description: |
183
+ Fired when tokenize() fails — either constraint validation
184
+ surfaced one or more field errors, or a Luhn / expiry / CVC
185
+ check failed. Bubbles.
186
+ detail:
187
+ message:
188
+ type: string
189
+ description: Human-readable error message.
190
+ code:
191
+ type: string
192
+ description: Error code — one of `validation-failed`, `card-invalid`, `expired`, `cvc-invalid`.
193
+ field:
194
+ type: string
195
+ description: Field name that surfaced the error (`cardNumber` / `expiry` / `cvc` / `name` / `postalCode` / `country` / null).
196
+
197
+ change:
198
+ description: |
199
+ Fired on every sub-field input. Detail carries a snapshot of
200
+ the current form validity + detected card brand. Bubbles.
201
+ detail:
202
+ valid:
203
+ type: boolean
204
+ description: Whether the form currently passes all constraints.
205
+ brand:
206
+ type: string
207
+ description: Detected brand (`visa` / `mastercard` / `amex` / `discover` / `unknown`).
208
+
209
+ slots:
210
+ legal:
211
+ description: |
212
+ Optional content rendered below the form fields — typically a
213
+ terms-of-storage acknowledgement string with link(s).
214
+
215
+ states:
216
+ - name: idle
217
+ description: Default; ready for input.
218
+ - name: tokenizing
219
+ description: tokenize() in flight.
220
+ attribute: tokenizing
221
+ - name: error
222
+ description: A field-level or host-level error is present.
223
+ attribute: error
224
+ - name: prefilled
225
+ description: A saved payment method is displayed; form is hidden.
226
+ attribute: prefilled
227
+ - name: disabled
228
+ description: All sub-fields non-interactive.
229
+ attribute: disabled
230
+
231
+ traits: []
232
+
233
+ tokens:
234
+ --payment-method-form-gap:
235
+ description: Gap between rows of the form grid.
236
+ default: var(--a-space-3)
237
+ --payment-method-form-grid-template:
238
+ description: |
239
+ Grid-template-areas for the field layout. Defaults to a
240
+ 4-row template — name spans both columns, card number spans
241
+ both, expiry + cvc share row 3, country + postal share row 4.
242
+ Address rows append when `require-billing-address` is set.
243
+ default: '"name name" "card card" "expiry cvc" "country postal"'
244
+ --payment-method-form-brand-icon-size:
245
+ description: Inline brand-badge icon size in the card-number suffix.
246
+ default: 1.25em
247
+ --payment-method-form-alert-mb:
248
+ description: Margin-block-end on the host-level error alert.
249
+ default: var(--a-space-3)
250
+ --payment-method-form-summary-bg:
251
+ description: Background of the saved-card summary row.
252
+ default: var(--a-bg-muted)
253
+ --payment-method-form-summary-border:
254
+ description: Border on the saved-card summary row.
255
+ default: 1px solid var(--a-border)
256
+ --payment-method-form-summary-radius:
257
+ description: Corner radius on the saved-card summary row.
258
+ default: var(--a-radius-md)
259
+ --payment-method-form-summary-px:
260
+ description: Horizontal padding inside the saved-card summary row.
261
+ default: var(--a-space-4)
262
+ --payment-method-form-summary-py:
263
+ description: Vertical padding inside the saved-card summary row.
264
+ default: var(--a-space-3)
265
+ --payment-method-form-legal-fg:
266
+ description: Foreground color of the slotted legal copy.
267
+ default: var(--a-fg-muted)
268
+ --payment-method-form-legal-size:
269
+ description: Font size of the slotted legal copy.
270
+ default: var(--a-text-xs, 0.75rem)
271
+ --payment-method-form-disabled-opacity:
272
+ description: Opacity applied to the host when [disabled].
273
+ default: var(--a-opacity-disabled, 0.5)
274
+
275
+ requiredIcons:
276
+ - credit-card
277
+ - lock-key
278
+ - warning-circle
279
+
280
+ a2ui:
281
+ rules:
282
+ - >-
283
+ PaymentMethodForm SHOULD be wrapped in a <Form> so its
284
+ form-value (the resolved token) is delivered on submission.
285
+ Standalone use requires the consumer wire `tokenize()` from a
286
+ custom submit handler.
287
+ - >-
288
+ PaymentMethodForm MUST NOT receive a `value` prop carrying raw
289
+ card digits. The form value is the tokenized output; raw card
290
+ digits live only inside the form's sub-fields and are never
291
+ mirrored to `value`.
292
+ - >-
293
+ PaymentMethodForm SHOULD only be used in test / demo / non-PCI
294
+ surfaces. Production card-capture flows MUST tokenize via a
295
+ real payment processor (Stripe Elements, Braintree, Adyen)
296
+ and consume only the resulting token — this primitive is the
297
+ form chrome + structured validation, not a tokenization
298
+ provider.
299
+ - >-
300
+ Wrapping PaymentMethodForm inside <Field> duplicates the label
301
+ and corrupts the grid layout. PaymentMethodForm IS a field
302
+ group; the host carries `aria-label` directly.
303
+ - >-
304
+ `countries` SHOULD list every ISO 3166-1 alpha-2 code your
305
+ product accepts. Empty arrays fall back to a default short
306
+ list (US, CA, GB, DE, FR, AU) suitable for early-stage demos
307
+ only — production deployments should set this explicitly.
308
+
309
+ anti_patterns:
310
+ - wrong: |
311
+ <payment-method-form-ui value="4242 4242 4242 4242"></payment-method-form-ui>
312
+ why: |
313
+ Raw card digits in `value`. The composite's value is the
314
+ tokenized output, never the input. Raw digits leak through
315
+ reflection back to the attribute and end up in DOM snapshots /
316
+ browser history / analytics.
317
+ fix: |
318
+ <payment-method-form-ui name="paymentMethod" required></payment-method-form-ui>
319
+ - wrong: |
320
+ <field-ui label="Card details">
321
+ <payment-method-form-ui></payment-method-form-ui>
322
+ </field-ui>
323
+ why: |
324
+ PaymentMethodForm IS itself a labeled field group; nesting in
325
+ Field duplicates the label and breaks the internal grid
326
+ layout. Field's auto-id stamping confuses the composite's
327
+ first-focusable lookup.
328
+ fix: |
329
+ <payment-method-form-ui aria-label="Card details"></payment-method-form-ui>
330
+ - wrong: |
331
+ <form>
332
+ <payment-method-form-ui></payment-method-form-ui>
333
+ <button-ui type="submit" text="Save"></button-ui>
334
+ </form>
335
+ <script>
336
+ form.addEventListener('submit', (e) => fetch('/charge', { body: new FormData(form) }));
337
+ </script>
338
+ why: |
339
+ Posting the form's serialized token directly to /charge skips
340
+ tokenization — the synthetic local-mode token is opaque but
341
+ NOT a real payment token. A real processor must mint the
342
+ token before the charge call.
343
+ fix: |
344
+ <form>
345
+ <payment-method-form-ui id="pm"></payment-method-form-ui>
346
+ <button-ui type="submit" text="Save"></button-ui>
347
+ </form>
348
+ <script>
349
+ form.addEventListener('submit', async (e) => {
350
+ e.preventDefault();
351
+ const detail = await pm.tokenize();
352
+ // Hand `detail.last4` / `detail.brand` to your processor SDK
353
+ // to mint a real token; POST the resulting token to /charge.
354
+ });
355
+ </script>
356
+
357
+ examples:
358
+ - name: default
359
+ description: Empty form, all sub-fields visible, required.
360
+ a2ui: |
361
+ [
362
+ {
363
+ "id": "pm-1",
364
+ "component": "PaymentMethodForm",
365
+ "name": "paymentMethod",
366
+ "required": true
367
+ }
368
+ ]
369
+ - name: prefilled-saved-card
370
+ description: |
371
+ Edit-saved-card flow — summary row renders with the saved
372
+ card; "Edit card" CTA reveals the full form.
373
+ a2ui: |
374
+ [
375
+ {
376
+ "id": "pm-2",
377
+ "component": "PaymentMethodForm",
378
+ "name": "paymentMethod",
379
+ "prefill": "{\"last4\":\"4242\",\"brand\":\"visa\",\"expMonth\":12,\"expYear\":2027,\"name\":\"Pat Doe\",\"country\":\"US\"}"
380
+ }
381
+ ]
382
+ - name: with-billing-address
383
+ description: |
384
+ Full form including billing address lines + postal + country.
385
+ a2ui: |
386
+ [
387
+ {
388
+ "id": "pm-3",
389
+ "component": "PaymentMethodForm",
390
+ "name": "paymentMethod",
391
+ "requireBillingAddress": true,
392
+ "countries": ["US", "CA", "GB", "DE"]
393
+ }
394
+ ]
395
+
396
+ keywords:
397
+ - payment-method
398
+ - card
399
+ - billing
400
+ - checkout
401
+ - card-capture
402
+ - payment
403
+ - credit-card
404
+ - debit-card
405
+ - save-payment-method
406
+ - update-payment-method
407
+ - add-card
408
+
409
+ synonyms:
410
+ payment-method:
411
+ - card
412
+ - card-on-file
413
+ - billing
414
+ card:
415
+ - payment-card
416
+ - credit-card
417
+ - debit-card
418
+ billing:
419
+ - billing-info
420
+ - payment-method
421
+ - card
422
+
423
+ related:
424
+ - Form
425
+ - Field
426
+ - Input
427
+ - Select
428
+ - Alert
429
+ - PlanPicker
430
+ - Button