@alfadocs/ui-kit-debug 1.120.0 → 1.122.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/map-pin@2x.png +0 -0
- package/assets/map-pin@2x.source.json +5 -0
- package/dist/_chunks/addDays-CuE8wLqb.js +9 -0
- package/dist/_chunks/addDays-CuE8wLqb.js.map +1 -0
- package/dist/_chunks/{anamnesis-summary-rows-BbAREK-3.js → anamnesis-summary-rows-CtcULkvc.js} +2 -2
- package/dist/_chunks/{anamnesis-summary-rows-BbAREK-3.js.map → anamnesis-summary-rows-CtcULkvc.js.map} +1 -1
- package/dist/_chunks/{antenatal-schedule-timeline-86YVlMYJ.js → antenatal-schedule-timeline-XHbig8On.js} +3 -3
- package/dist/_chunks/{antenatal-schedule-timeline-86YVlMYJ.js.map → antenatal-schedule-timeline-XHbig8On.js.map} +1 -1
- package/dist/_chunks/{appointment-timeline-CC7nmBOH.js → appointment-timeline-Czd4PBkF.js} +2 -2
- package/dist/_chunks/{appointment-timeline-CC7nmBOH.js.map → appointment-timeline-Czd4PBkF.js.map} +1 -1
- package/dist/_chunks/{balance-badge-cell-DPjab0eJ.js → balance-badge-cell-DtxbGJcA.js} +2 -2
- package/dist/_chunks/{balance-badge-cell-DPjab0eJ.js.map → balance-badge-cell-DtxbGJcA.js.map} +1 -1
- package/dist/_chunks/{bill-line-table-DUMEHnQ4.js → bill-line-table-HrynB7ND.js} +2 -2
- package/dist/_chunks/{bill-line-table-DUMEHnQ4.js.map → bill-line-table-HrynB7ND.js.map} +1 -1
- package/dist/_chunks/{calendar-appointment-editor-dialog-rw02sXGw.js → calendar-appointment-editor-dialog-CiCmsBCH.js} +5 -5
- package/dist/_chunks/{calendar-appointment-editor-dialog-rw02sXGw.js.map → calendar-appointment-editor-dialog-CiCmsBCH.js.map} +1 -1
- package/dist/_chunks/{cycle-calculator-C8nWAeTk.js → cycle-calculator-WFhMfJHt.js} +4 -3
- package/dist/_chunks/{cycle-calculator-C8nWAeTk.js.map → cycle-calculator-WFhMfJHt.js.map} +1 -1
- package/dist/_chunks/{data-grid-Bbf8t4z3.js → data-grid-C71BhGDw.js} +2 -2
- package/dist/_chunks/{data-grid-Bbf8t4z3.js.map → data-grid-C71BhGDw.js.map} +1 -1
- package/dist/_chunks/{date-picker-DBVTj6lO.js → date-picker-BmVBVpVu.js} +3 -3
- package/dist/_chunks/{date-picker-DBVTj6lO.js.map → date-picker-BmVBVpVu.js.map} +1 -1
- package/dist/_chunks/{date-picker-variants-J1EeAhIH.js → date-picker-variants-DmfVRNDB.js} +184 -188
- package/dist/_chunks/date-picker-variants-DmfVRNDB.js.map +1 -0
- package/dist/_chunks/{date-range-panel-CT6nXjRM.js → date-range-panel-CT9Pk-HF.js} +2 -2
- package/dist/_chunks/{date-range-panel-CT6nXjRM.js.map → date-range-panel-CT9Pk-HF.js.map} +1 -1
- package/dist/_chunks/{date-range-picker-PTRpDkXT.js → date-range-picker-2Up_FRrM.js} +40 -39
- package/dist/_chunks/{date-range-picker-PTRpDkXT.js.map → date-range-picker-2Up_FRrM.js.map} +1 -1
- package/dist/_chunks/{date-time-picker-CJnqiQoT.js → date-time-picker-C6b_Vymc.js} +2 -2
- package/dist/_chunks/{date-time-picker-CJnqiQoT.js.map → date-time-picker-C6b_Vymc.js.map} +1 -1
- package/dist/_chunks/{default-tabs-Cxkw1Ws0.js → default-tabs-RvCI5uN0.js} +3 -3
- package/dist/_chunks/{default-tabs-Cxkw1Ws0.js.map → default-tabs-RvCI5uN0.js.map} +1 -1
- package/dist/_chunks/{due-date-calculator-c1NJPw9F.js → due-date-calculator-CALlODZe.js} +4 -4
- package/dist/_chunks/{due-date-calculator-c1NJPw9F.js.map → due-date-calculator-CALlODZe.js.map} +1 -1
- package/dist/_chunks/{gestational-age-calculator-Cg4Gq42R.js → gestational-age-calculator-mB6brTlp.js} +5 -5
- package/dist/_chunks/{gestational-age-calculator-Cg4Gq42R.js.map → gestational-age-calculator-mB6brTlp.js.map} +1 -1
- package/dist/_chunks/{hcg-doubling-BjTa_77t.js → hcg-doubling-Dhdt3Jyd.js} +3 -3
- package/dist/_chunks/{hcg-doubling-BjTa_77t.js.map → hcg-doubling-Dhdt3Jyd.js.map} +1 -1
- package/dist/_chunks/{invoice-upload-list-CsFsRgbt.js → invoice-upload-list-C95s5Q7m.js} +3 -3
- package/dist/_chunks/{invoice-upload-list-CsFsRgbt.js.map → invoice-upload-list-C95s5Q7m.js.map} +1 -1
- package/dist/_chunks/{kit-extensions-C3oL0WTp.js → kit-extensions-DUaIYyMD.js} +4 -4
- package/dist/_chunks/{kit-extensions-C3oL0WTp.js.map → kit-extensions-DUaIYyMD.js.map} +1 -1
- package/dist/_chunks/{link-cell-renderer-NFNGdAGt.js → link-cell-renderer-BEaLczk2.js} +2 -2
- package/dist/_chunks/{link-cell-renderer-NFNGdAGt.js.map → link-cell-renderer-BEaLczk2.js.map} +1 -1
- package/dist/_chunks/{map-view-h6ngp2xi.js → map-view-QWdQLHi9.js} +543 -495
- package/dist/_chunks/map-view-QWdQLHi9.js.map +1 -0
- package/dist/_chunks/{parse-BLBWPIgE.js → parse-BFur8Byx.js} +2 -2
- package/dist/_chunks/{parse-BLBWPIgE.js.map → parse-BFur8Byx.js.map} +1 -1
- package/dist/_chunks/{patient-details-C4dHR4iu.js → patient-details-Cba9HQj_.js} +2 -2
- package/dist/_chunks/{patient-details-C4dHR4iu.js.map → patient-details-Cba9HQj_.js.map} +1 -1
- package/dist/_chunks/{patient-field-row-0QP8KCVp.js → patient-field-row-CtDihADs.js} +2 -2
- package/dist/_chunks/{patient-field-row-0QP8KCVp.js.map → patient-field-row-CtDihADs.js.map} +1 -1
- package/dist/_chunks/{patient-summary-card-x0-AhCyC.js → patient-summary-card-DnLdbtsw.js} +2 -2
- package/dist/_chunks/{patient-summary-card-x0-AhCyC.js.map → patient-summary-card-DnLdbtsw.js.map} +1 -1
- package/dist/_chunks/practice-results-BCLqPdgn.js +2683 -0
- package/dist/_chunks/practice-results-BCLqPdgn.js.map +1 -0
- package/dist/_chunks/{pregnancy-dating-BO6diQMZ.js → pregnancy-dating-BNI32qNw.js} +5 -5
- package/dist/_chunks/{pregnancy-dating-BO6diQMZ.js.map → pregnancy-dating-BNI32qNw.js.map} +1 -1
- package/dist/_chunks/{radiograph-panel.agent-Dcv16n7u.js → radiograph-panel.agent-B-r3BoqU.js} +3 -3
- package/dist/_chunks/{radiograph-panel.agent-Dcv16n7u.js.map → radiograph-panel.agent-B-r3BoqU.js.map} +1 -1
- package/dist/_chunks/{registration-form-CMXefBnC.js → registration-form-CwbhtKcy.js} +180 -165
- package/dist/_chunks/registration-form-CwbhtKcy.js.map +1 -0
- package/dist/_chunks/{reserved.agent-DRSZ8UcL.js → reserved.agent-CCwsOb3M.js} +8 -7
- package/dist/_chunks/{reserved.agent-DRSZ8UcL.js.map → reserved.agent-CCwsOb3M.js.map} +1 -1
- package/dist/_chunks/{send-registration-link-form-DuZQuKnI.js → send-registration-link-form-BjkXr0TD.js} +3 -3
- package/dist/_chunks/{send-registration-link-form-DuZQuKnI.js.map → send-registration-link-form-BjkXr0TD.js.map} +1 -1
- package/dist/_chunks/{slot-grid-b4eZXokb.js → slot-grid-DEZRB4Yb.js} +234 -207
- package/dist/_chunks/slot-grid-DEZRB4Yb.js.map +1 -0
- package/dist/_chunks/subDays-DC99JK7a.js +8 -0
- package/dist/_chunks/{subDays-Bsoy023P.js.map → subDays-DC99JK7a.js.map} +1 -1
- package/dist/_chunks/{task-editor-Czcx9B-3.js → task-editor-C05yx7JJ.js} +2 -2
- package/dist/_chunks/{task-editor-Czcx9B-3.js.map → task-editor-C05yx7JJ.js.map} +1 -1
- package/dist/_chunks/{toolbar-DoKcoE2q.js → toolbar-Dznu_Dou.js} +2 -2
- package/dist/_chunks/{toolbar-DoKcoE2q.js.map → toolbar-Dznu_Dou.js.map} +1 -1
- package/dist/_chunks/{use-appointment-details-read-B-SXnszJ.js → use-appointment-details-read-Bm408XzX.js} +2 -2
- package/dist/_chunks/{use-appointment-details-read-B-SXnszJ.js.map → use-appointment-details-read-Bm408XzX.js.map} +1 -1
- package/dist/_chunks/{workflow-webhook-action-dgUjv9T7.js → workflow-webhook-action-Cae02r_4.js} +264 -289
- package/dist/_chunks/workflow-webhook-action-Cae02r_4.js.map +1 -0
- package/dist/agent-catalog.json +3 -11
- package/dist/agent-i18n/en.json +1 -2
- package/dist/browser-support.js +1 -1
- package/dist/components/appointment-details-panel/index.js +1 -1
- package/dist/components/appointment-timeline/index.js +1 -1
- package/dist/components/bill-line-table/index.js +1 -1
- package/dist/components/bill-table/index.js +1 -1
- package/dist/components/booking/index.js +1 -1
- package/dist/components/cycle-calculator/index.js +1 -1
- package/dist/components/data-grid/index.js +2 -2
- package/dist/components/data-table/index.js +1 -1
- package/dist/components/date-picker/index.js +1 -1
- package/dist/components/date-range-picker/index.js +1 -1
- package/dist/components/date-time-picker/index.js +1 -1
- package/dist/components/due-date-calculator/index.js +2 -2
- package/dist/components/gestational-age-calculator/index.js +1 -1
- package/dist/components/hcg-doubling/index.js +1 -1
- package/dist/components/invoice-upload-list/index.js +1 -1
- package/dist/components/map-view/index.d.ts +1 -1
- package/dist/components/map-view/index.d.ts.map +1 -1
- package/dist/components/map-view/index.js +1 -1
- package/dist/components/map-view/map-view.d.ts +18 -0
- package/dist/components/map-view/map-view.d.ts.map +1 -1
- package/dist/components/patient-details/index.js +1 -1
- package/dist/components/patient-summary-card/index.js +1 -1
- package/dist/components/patient-table/index.js +1 -1
- package/dist/components/practice-results/index.js +1 -1
- package/dist/components/practice-results/practice-results-slot-card.d.ts +38 -0
- package/dist/components/practice-results/practice-results-slot-card.d.ts.map +1 -0
- package/dist/components/practice-results/practice-results.d.ts +32 -2
- package/dist/components/practice-results/practice-results.d.ts.map +1 -1
- package/dist/components/pregnancy-dating/index.js +1 -1
- package/dist/components/radiograph-panel/index.js +1 -1
- package/dist/components/rich-text-editor/index.js +1 -1
- package/dist/components/slot-grid/index.js +1 -1
- package/dist/components/slot-grid/slot-grid.d.ts +19 -0
- package/dist/components/slot-grid/slot-grid.d.ts.map +1 -1
- package/dist/components/task-editor/index.js +1 -1
- package/dist/core.css +1 -1
- package/dist/host-compat.css +9 -1
- package/dist/i18n/locales/ar.d.ts +7 -5
- package/dist/i18n/locales/ar.d.ts.map +1 -1
- package/dist/i18n/locales/ar.js +8 -6
- package/dist/i18n/locales/ar.js.map +1 -1
- package/dist/i18n/locales/de.d.ts +7 -5
- package/dist/i18n/locales/de.d.ts.map +1 -1
- package/dist/i18n/locales/de.js +8 -6
- package/dist/i18n/locales/de.js.map +1 -1
- package/dist/i18n/locales/el.d.ts +7 -5
- package/dist/i18n/locales/el.d.ts.map +1 -1
- package/dist/i18n/locales/el.js +8 -6
- package/dist/i18n/locales/el.js.map +1 -1
- package/dist/i18n/locales/en.d.ts +7 -5
- package/dist/i18n/locales/en.d.ts.map +1 -1
- package/dist/i18n/locales/en.js +7 -5
- package/dist/i18n/locales/en.js.map +1 -1
- package/dist/i18n/locales/es.d.ts +7 -5
- package/dist/i18n/locales/es.d.ts.map +1 -1
- package/dist/i18n/locales/es.js +8 -6
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +7 -5
- package/dist/i18n/locales/fr.d.ts.map +1 -1
- package/dist/i18n/locales/fr.js +8 -6
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hi.d.ts +7 -5
- package/dist/i18n/locales/hi.d.ts.map +1 -1
- package/dist/i18n/locales/hi.js +8 -6
- package/dist/i18n/locales/hi.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +7 -5
- package/dist/i18n/locales/it.d.ts.map +1 -1
- package/dist/i18n/locales/it.js +8 -6
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/ja.d.ts +7 -5
- package/dist/i18n/locales/ja.d.ts.map +1 -1
- package/dist/i18n/locales/ja.js +8 -6
- package/dist/i18n/locales/ja.js.map +1 -1
- package/dist/i18n/locales/nl.d.ts +7 -5
- package/dist/i18n/locales/nl.d.ts.map +1 -1
- package/dist/i18n/locales/nl.js +8 -6
- package/dist/i18n/locales/nl.js.map +1 -1
- package/dist/i18n/locales/pl.d.ts +7 -5
- package/dist/i18n/locales/pl.d.ts.map +1 -1
- package/dist/i18n/locales/pl.js +8 -6
- package/dist/i18n/locales/pl.js.map +1 -1
- package/dist/i18n/locales/pt.d.ts +7 -5
- package/dist/i18n/locales/pt.d.ts.map +1 -1
- package/dist/i18n/locales/pt.js +8 -6
- package/dist/i18n/locales/pt.js.map +1 -1
- package/dist/i18n/locales/ro.d.ts +7 -5
- package/dist/i18n/locales/ro.d.ts.map +1 -1
- package/dist/i18n/locales/ro.js +8 -6
- package/dist/i18n/locales/ro.js.map +1 -1
- package/dist/i18n/locales/ru.d.ts +7 -5
- package/dist/i18n/locales/ru.d.ts.map +1 -1
- package/dist/i18n/locales/ru.js +8 -6
- package/dist/i18n/locales/ru.js.map +1 -1
- package/dist/i18n/locales/sq.d.ts +7 -5
- package/dist/i18n/locales/sq.d.ts.map +1 -1
- package/dist/i18n/locales/sq.js +8 -6
- package/dist/i18n/locales/sq.js.map +1 -1
- package/dist/i18n/locales/sv.d.ts +7 -5
- package/dist/i18n/locales/sv.d.ts.map +1 -1
- package/dist/i18n/locales/sv.js +8 -6
- package/dist/i18n/locales/sv.js.map +1 -1
- package/dist/i18n/locales/tr.d.ts +7 -5
- package/dist/i18n/locales/tr.d.ts.map +1 -1
- package/dist/i18n/locales/tr.js +8 -6
- package/dist/i18n/locales/tr.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +7 -5
- package/dist/i18n/locales/zh.d.ts.map +1 -1
- package/dist/i18n/locales/zh.js +8 -6
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/index.js +32 -32
- package/dist/locales/ar.json +8 -6
- package/dist/locales/de.json +8 -6
- package/dist/locales/el.json +8 -6
- package/dist/locales/en.json +7 -5
- package/dist/locales/es.json +8 -6
- package/dist/locales/fr.json +8 -6
- package/dist/locales/hi.json +8 -6
- package/dist/locales/it.json +8 -6
- package/dist/locales/ja.json +8 -6
- package/dist/locales/nl.json +8 -6
- package/dist/locales/pl.json +8 -6
- package/dist/locales/pt.json +8 -6
- package/dist/locales/ro.json +8 -6
- package/dist/locales/ru.json +8 -6
- package/dist/locales/sq.json +8 -6
- package/dist/locales/sv.json +8 -6
- package/dist/locales/tr.json +8 -6
- package/dist/locales/zh.json +8 -6
- package/dist/patterns/anamnesis/index.js +1 -1
- package/dist/patterns/calendar/index.js +1 -1
- package/dist/patterns/registration-form/index.js +1 -1
- package/dist/patterns/send-registration-link-form/index.js +1 -1
- package/dist/patterns/workflow-webhook-action/index.js +1 -1
- package/dist/patterns/workflow-webhook-action/workflow-webhook-action.d.ts.map +1 -1
- package/dist/tokens.css +1 -1
- package/package.json +1 -1
- package/dist/_chunks/date-picker-variants-J1EeAhIH.js.map +0 -1
- package/dist/_chunks/key-round-DIgsnJSg.js +0 -21
- package/dist/_chunks/key-round-DIgsnJSg.js.map +0 -1
- package/dist/_chunks/map-view-h6ngp2xi.js.map +0 -1
- package/dist/_chunks/practice-results-yCresv86.js +0 -2326
- package/dist/_chunks/practice-results-yCresv86.js.map +0 -1
- package/dist/_chunks/registration-form-CMXefBnC.js.map +0 -1
- package/dist/_chunks/slot-grid-b4eZXokb.js.map +0 -1
- package/dist/_chunks/subDays-Bsoy023P.js +0 -8
- package/dist/_chunks/workflow-webhook-action-dgUjv9T7.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"registration-form-CMXefBnC.js","sources":["../../src/patterns/registration-form/verification-requests.ts","../../src/patterns/registration-form/use-contact-verification.ts","../../src/patterns/registration-form/registration-verification.tsx","../../src/patterns/registration-form/registration-form.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Data-only verification: the kit sends the two requests itself. */\n/* */\n/* A host that renders the form from JSON cannot pass functions. It */\n/* passes `sendUrl` and `verifyUrl`; this file turns them into the two */\n/* callbacks the state machine already takes. */\n/* -------------------------------------------------------------------- */\n\nimport { isDevelopment } from '../../components/_shared/is-development';\nimport { isSameSiteHref } from '../../components/_shared/safe-href';\nimport type {\n RegistrationCodeFailure,\n RegistrationCodeResult,\n RegistrationFieldVerification,\n} from './use-contact-verification';\n\nconst FAILURES: readonly RegistrationCodeFailure[] = [\n 'invalid',\n 'expired',\n 'rate_limited',\n 'error',\n];\n\nconst FAILED: RegistrationCodeResult = { ok: false, reason: 'error' };\n\nconst positiveNumber = (input: unknown): number | undefined =>\n typeof input === 'number' && Number.isFinite(input) && input >= 0\n ? input\n : undefined;\n\n/** Keeps only the fields of a result that the kit reads. */\nfunction toResult(body: unknown): RegistrationCodeResult | null {\n if (typeof body !== 'object' || body === null) return null;\n const raw = body as Record<string, unknown>;\n if (typeof raw.ok !== 'boolean') return null;\n const result: RegistrationCodeResult = { ok: raw.ok };\n if (typeof raw.message === 'string') result.message = raw.message;\n if (FAILURES.includes(raw.reason as RegistrationCodeFailure)) {\n result.reason = raw.reason as RegistrationCodeFailure;\n }\n const retry = positiveNumber(raw.retryAfterSeconds);\n if (retry !== undefined) result.retryAfterSeconds = retry;\n const resend = positiveNumber(raw.resendAfterSeconds);\n if (resend !== undefined) result.resendAfterSeconds = resend;\n if (typeof raw.devCode === 'string') result.devCode = raw.devCode;\n if (typeof raw.value === 'string') result.value = raw.value;\n return result;\n}\n\n/** Seconds from a `Retry-After` header; a date form is not read. */\nfunction retryAfterHeader(response: Response): number | undefined {\n const header = response.headers.get('Retry-After');\n if (!header || !/^\\d+$/.test(header.trim())) return undefined;\n return Number(header.trim());\n}\n\n/** Posts JSON to a path or same-origin URL. Never rejects. */\nexport async function postVerification(\n url: string,\n payload: Record<string, string>,\n): Promise<RegistrationCodeResult> {\n if (!isSameSiteHref(url)) {\n if (isDevelopment()) {\n console.warn(\n `RegistrationForm: verification URL \"${url}\" is not a path or an address on this site, so no request was sent.`,\n );\n }\n return FAILED;\n }\n try {\n const response = await fetch(url, {\n method: 'POST',\n credentials: 'same-origin',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n 'X-Requested-With': 'XMLHttpRequest',\n },\n body: JSON.stringify(payload),\n });\n const limited = response.status === 429;\n // The answer travels in the body on success and on failure; a server\n // error page is not one.\n if (!limited && (response.status < 200 || response.status >= 500)) {\n return FAILED;\n }\n let body: unknown = null;\n try {\n body = await response.json();\n } catch {\n body = null;\n }\n const result = toResult(body);\n if (limited) {\n const base: RegistrationCodeResult = result ?? { ok: false };\n const retry =\n base.retryAfterSeconds ?? retryAfterHeader(response) ?? undefined;\n return {\n ...base,\n ok: false,\n reason: 'rate_limited',\n ...(retry !== undefined ? { retryAfterSeconds: retry } : {}),\n };\n }\n if (!result) return FAILED;\n // A refusal needs a reason; an answer of success on an error status\n // is not trusted.\n if (response.status >= 400) {\n return result.ok\n ? FAILED\n : { ...result, reason: result.reason ?? 'error' };\n }\n return result;\n } catch {\n return FAILED;\n }\n}\n\n/** The two callbacks for a field, whichever way the host configured it. */\nexport function verificationHandlers(config: RegistrationFieldVerification): {\n onSendCode: (value: string) => Promise<RegistrationCodeResult>;\n onVerifyCode: (\n value: string,\n code: string,\n ) => Promise<RegistrationCodeResult>;\n} {\n if ('sendUrl' in config && config.sendUrl !== undefined) {\n const { sendUrl, verifyUrl } = config;\n return {\n onSendCode: (value) => postVerification(sendUrl, { value }),\n onVerifyCode: (value, code) =>\n postVerification(verifyUrl, { value, code }),\n };\n }\n return {\n onSendCode: config.onSendCode as (\n value: string,\n ) => Promise<RegistrationCodeResult>,\n onVerifyCode: config.onVerifyCode as (\n value: string,\n code: string,\n ) => Promise<RegistrationCodeResult>,\n };\n}\n","/* -------------------------------------------------------------------- */\n/* useContactVerification: the state of one field's \"prove it with a */\n/* code\" step in the registration form. */\n/* */\n/* idle -> sending -> sent -> verifying -> verified. There is no way */\n/* back from verified: the server holds the verified value. A change to */\n/* the value before that sends the field back to idle. */\n/* */\n/* Shipped with RegistrationForm; not an export of its own. */\n/* -------------------------------------------------------------------- */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { verificationHandlers } from './verification-requests';\n\n/** The fields that can be verified by a code. */\nexport type RegistrationVerifiableField = 'email' | 'phone';\n\n/** Why a send or a check failed. */\nexport type RegistrationCodeFailure =\n | 'invalid'\n | 'expired'\n | 'rate_limited'\n | 'error';\n\n/** What the host answers when a code is sent or checked. */\nexport interface RegistrationCodeResult {\n ok: boolean;\n /** Already translated by the host. Shown under the field when `ok` is\n * false, instead of the kit's own wording for `reason`. */\n message?: string;\n reason?: RegistrationCodeFailure;\n /** With `rate_limited`: seconds before another send is allowed. */\n retryAfterSeconds?: number;\n /** After a send: seconds before \"Send a new code\" works. Default 30. */\n resendAfterSeconds?: number;\n /** Development only. The host passes it only when its server says this\n * is a development environment; it shows in an info alert. */\n devCode?: string;\n /** After a check: the value the server verified. Informational. */\n value?: string;\n}\n\n/** Options both ways of verifying a field share. */\nexport interface RegistrationFieldVerificationOptions {\n /** Digits in the code. Default 6. */\n codeLength?: number;\n /** True when the server already holds this value as verified, such as\n * a page that reopens after a refused post. */\n verified?: boolean;\n /**\n * With `verified`: the person may still change the value. The field\n * shows as verified with a \"Change\" action; pressing it unlocks the\n * field. Typing back exactly the value that started verified (trimmed,\n * case ignored) is verified again with no code; any other value needs\n * a code. Without it, `verified` locks the field with no way back.\n * A plain boolean, so it works from JSON.\n */\n allowChange?: boolean;\n /** Called with `true` once the code is right. */\n onVerifiedChange?: (verified: boolean) => void;\n}\n\n/** Callbacks: for a React host that calls its own API. */\nexport interface RegistrationFieldVerificationCallbacks extends RegistrationFieldVerificationOptions {\n /** Sends a code to the value. Resolve, never reject: a rejection is\n * shown as a failure with reason `error`. */\n onSendCode: (value: string) => Promise<RegistrationCodeResult>;\n /** Checks the code the person typed for the value. */\n onVerifyCode: (\n value: string,\n code: string,\n ) => Promise<RegistrationCodeResult>;\n sendUrl?: never;\n verifyUrl?: never;\n}\n\n/**\n * URLs: data only, for a host that mounts the form from JSON. The kit\n * POSTs JSON to each (same origin, cookies sent). Send body:\n * `{ \"value\" }`. Verify body: `{ \"value\", \"code\" }`. The answer is a\n * `RegistrationCodeResult` as JSON, on success and on failure. A path or\n * an address on this site only.\n */\nexport interface RegistrationFieldVerificationUrls extends RegistrationFieldVerificationOptions {\n sendUrl: string;\n verifyUrl: string;\n onSendCode?: never;\n onVerifyCode?: never;\n}\n\n/** How one field is verified: both callbacks, or both URLs. */\nexport type RegistrationFieldVerification =\n | RegistrationFieldVerificationCallbacks\n | RegistrationFieldVerificationUrls;\n\nexport type ContactVerificationStatus =\n | 'idle'\n | 'sending'\n | 'sent'\n | 'verifying'\n | 'verified';\n\nexport interface ContactVerificationFailure {\n reason: RegistrationCodeFailure;\n /** The host's own message, when it gave one. */\n message?: string;\n}\n\nexport const DEFAULT_CODE_LENGTH = 6;\nexport const DEFAULT_RESEND_SECONDS = 30;\n\nconst failureOf = (\n result: RegistrationCodeResult,\n): ContactVerificationFailure => ({\n reason: result.reason ?? 'error',\n message: result.message,\n});\n\nexport interface UseContactVerificationOptions {\n /** Undefined: the field is not verified and the hook does nothing. */\n config: RegistrationFieldVerification | undefined;\n /** The value now in the field. */\n value: string;\n}\n\nexport interface UseContactVerificationReturn {\n /** True when the field takes part in verification. */\n enabled: boolean;\n status: ContactVerificationStatus;\n /** True once the server has accepted the value. */\n verified: boolean;\n codeLength: number;\n code: string;\n setCode: (code: string) => void;\n failure: ContactVerificationFailure | null;\n /** Seconds left before a new code may be sent; 0 when it may. */\n cooldown: number;\n devCode: string | undefined;\n /** The value the code went to. */\n sentTo: string;\n send: () => void;\n verify: (code?: string) => void;\n /** Back to idle: the person wants to change the value. */\n reset: () => void;\n /** True when the server's \"verified\" may be changed (`allowChange`)\n * and the field is verified right now. */\n changeable: boolean;\n /** Unlocks a `changeable` field so the value can be edited. */\n unlock: () => void;\n}\n\n/** Runs one field's verification step. */\nexport function useContactVerification({\n config,\n value,\n}: UseContactVerificationOptions): UseContactVerificationReturn {\n const codeLength = config?.codeLength ?? DEFAULT_CODE_LENGTH;\n const [status, setStatus] = useState<ContactVerificationStatus>('idle');\n const [code, setCodeState] = useState('');\n const [failure, setFailure] = useState<ContactVerificationFailure | null>(\n null,\n );\n const [cooldown, setCooldown] = useState(0);\n const [devCode, setDevCode] = useState<string | undefined>();\n const [sentTo, setSentTo] = useState('');\n\n // The latest config and value, so the callbacks below stay stable and\n // never act on a stale host function.\n const latest = useRef({ config, value });\n latest.current = { config, value };\n // Each send or check takes a number; an answer for an older one is\n // dropped, such as one that lands after the person changed the value.\n const request = useRef(0);\n\n // The value the host said was verified, when the page opened.\n const [original] = useState<string | null>(() =>\n config?.verified === true ? value : null,\n );\n const [unlocked, setUnlocked] = useState(false);\n const verifiedByHost = config?.verified === true && !unlocked;\n const verified = verifiedByHost || status === 'verified';\n\n // Tell the host once, when the code is right.\n const told = useRef(false);\n useEffect(() => {\n if (status === 'verified' && !told.current) {\n told.current = true;\n latest.current.config?.onVerifiedChange?.(true);\n }\n }, [status]);\n\n // One tick a second while the wait lasts.\n useEffect(() => {\n if (cooldown <= 0) return undefined;\n const timer = setTimeout(() => setCooldown((left) => left - 1), 1000);\n return () => clearTimeout(timer);\n }, [cooldown]);\n\n const sameValue = (a: string, b: string) =>\n a.trim().toLowerCase() === b.trim().toLowerCase();\n\n // Back to the verified value: verified again, no code.\n useEffect(() => {\n if (unlocked && original !== null && sameValue(value, original)) {\n setUnlocked(false);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- on an edit only, so pressing Change keeps the field open\n }, [value]);\n\n const reset = useCallback(() => {\n request.current += 1;\n setStatus((current) => (current === 'verified' ? current : 'idle'));\n setCodeState('');\n setFailure(null);\n setDevCode(undefined);\n setSentTo('');\n // A new value is not bound by the wait for the old one.\n setCooldown(0);\n }, []);\n\n // Editing the value after a code went out voids that code.\n useEffect(() => {\n if (status === 'verified') return;\n if (\n (status === 'sent' || status === 'verifying' || status === 'sending') &&\n value !== sentTo\n ) {\n reset();\n }\n }, [value, sentTo, status, reset]);\n\n // A failed send was about the old value.\n const lastValue = useRef(value);\n useEffect(() => {\n if (lastValue.current === value) return;\n lastValue.current = value;\n if (status === 'idle') setFailure(null);\n }, [value, status]);\n\n const send = useCallback(() => {\n const { config: current, value: target } = latest.current;\n if (!current) return;\n const id = (request.current += 1);\n setStatus('sending');\n setFailure(null);\n setCodeState('');\n setSentTo(target);\n verificationHandlers(current)\n .onSendCode(target)\n .then(\n (result) => result,\n (): RegistrationCodeResult => ({ ok: false, reason: 'error' }),\n )\n .then((result) => {\n if (id !== request.current) return;\n if (result.ok) {\n setStatus('sent');\n setDevCode(result.devCode);\n setCooldown(result.resendAfterSeconds ?? DEFAULT_RESEND_SECONDS);\n return;\n }\n setStatus('idle');\n setSentTo('');\n setFailure(failureOf(result));\n if (result.reason === 'rate_limited' && result.retryAfterSeconds) {\n setCooldown(result.retryAfterSeconds);\n }\n });\n }, []);\n\n const verify = useCallback(\n (typed?: string) => {\n const { config: current, value: target } = latest.current;\n if (!current) return;\n const length = current.codeLength ?? DEFAULT_CODE_LENGTH;\n const entered = typed ?? code;\n if (entered.length !== length) return;\n const id = (request.current += 1);\n setStatus('verifying');\n setFailure(null);\n verificationHandlers(current)\n .onVerifyCode(target, entered)\n .then(\n (result) => result,\n (): RegistrationCodeResult => ({ ok: false, reason: 'error' }),\n )\n .then((result) => {\n if (id !== request.current) return;\n if (result.ok) {\n setStatus('verified');\n setCodeState('');\n setDevCode(undefined);\n setCooldown(0);\n return;\n }\n setStatus('sent');\n setCodeState('');\n setFailure(failureOf(result));\n if (result.reason === 'rate_limited' && result.retryAfterSeconds) {\n setCooldown(result.retryAfterSeconds);\n }\n // An expired code cannot be retried: only a new one helps.\n if (result.reason === 'expired') setCooldown(0);\n });\n },\n [code],\n );\n\n const changeable = verifiedByHost && config?.allowChange === true;\n const unlock = useCallback(() => {\n request.current += 1;\n setUnlocked(true);\n setStatus('idle');\n setCodeState('');\n setFailure(null);\n setDevCode(undefined);\n setSentTo('');\n setCooldown(0);\n }, []);\n\n const setCode = useCallback((next: string) => {\n setCodeState(next);\n setFailure((current) => (current ? null : current));\n }, []);\n\n return {\n enabled: config !== undefined,\n status: verifiedByHost ? 'verified' : status,\n verified,\n codeLength,\n code,\n setCode,\n failure,\n cooldown,\n devCode,\n sentTo,\n send,\n verify,\n reset,\n changeable,\n unlock,\n };\n}\n","/* -------------------------------------------------------------------- */\n/* The pieces of RegistrationForm's \"prove it with a code\" step. */\n/* */\n/* `VerificationAction` is the button beside the field. `Verification- */\n/* Panel` sits under it: the code box while a code is out, the success */\n/* line once the code is right. Both read the state that */\n/* `useContactVerification` keeps; neither knows the host's server. */\n/* */\n/* Shipped with RegistrationForm; not an export of its own. */\n/* -------------------------------------------------------------------- */\n\nimport { useEffect, useRef, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { CircleCheck, Pencil } from 'lucide-react';\nimport { Alert } from '../../components/alert';\nimport { Button } from '../../components/button';\nimport { FormField } from '../../components/form-field';\nimport { OTPInput } from '../../components/otp-input';\nimport type {\n ContactVerificationFailure,\n RegistrationVerifiableField,\n UseContactVerificationReturn,\n} from './use-contact-verification';\n\n/** The kit's own wording for a failure, when the host gave none. */\nfunction useFailureMessage(\n failure: ContactVerificationFailure | null,\n): string | undefined {\n const { t } = useTranslation('ui');\n if (!failure) return undefined;\n if (failure.message) return failure.message;\n switch (failure.reason) {\n case 'invalid':\n return t('registrationForm.verification.invalidCode');\n case 'expired':\n return t('registrationForm.verification.expiredCode');\n case 'rate_limited':\n return t('registrationForm.verification.rateLimited');\n default:\n return t('registrationForm.verification.sendFailed');\n }\n}\n\n/** The message a failed send leaves under the field. */\nexport function useSendFailureMessage(\n state: UseContactVerificationReturn,\n): string | undefined {\n const message = useFailureMessage(state.failure);\n return state.status === 'idle' ? message : undefined;\n}\n\ninterface VerificationActionProps {\n state: UseContactVerificationReturn;\n /** True when the value could be an address or a number. */\n canSend: boolean;\n}\n\n/** \"Send code\", beside the field. Gone once a code is out. */\nexport function VerificationAction({\n state,\n canSend,\n}: VerificationActionProps) {\n const { t } = useTranslation('ui');\n const sending = state.status === 'sending';\n if (state.status !== 'idle' && !sending) return null;\n const waiting = state.cooldown > 0;\n return (\n <Button\n type=\"button\"\n intent=\"secondary\"\n loading={sending}\n disabled={!canSend}\n // Not native `disabled` for the wait: focus stays on the button.\n aria-disabled={waiting || undefined}\n data-action=\"send-code\"\n className=\"ds:shrink-0\"\n onClick={() => {\n if (!waiting) state.send();\n }}\n >\n {sending\n ? t('registrationForm.verification.sendingCode')\n : waiting\n ? t('registrationForm.verification.resendIn', {\n seconds: state.cooldown,\n })\n : t('registrationForm.verification.sendCode')}\n </Button>\n );\n}\n\ninterface VerificationPanelProps {\n field: RegistrationVerifiableField;\n state: UseContactVerificationReturn;\n /** Hide \"Change email\": the address cannot be edited here. */\n canChange?: boolean;\n /** Show \"Change\" beside the success line of a field that started\n * verified (`allowChange`). The email shows it elsewhere. */\n changeWhenVerified?: boolean;\n /** Called after \"Change\" unlocks the field, to focus it. */\n onUnlocked?: () => void;\n /** Called once when the code is right, to put focus back on the field. */\n onVerified: () => void;\n}\n\n/** What sits under the field: the code box, or the success line. */\nexport function VerificationPanel({\n field,\n state,\n canChange = true,\n changeWhenVerified = false,\n onUnlocked,\n onVerified,\n}: VerificationPanelProps) {\n const { t } = useTranslation('ui');\n const panel = useRef<HTMLDivElement>(null);\n const message = useFailureMessage(state.failure);\n const open = state.status === 'sent' || state.status === 'verifying';\n const verifying = state.status === 'verifying';\n const complete = state.code.length === state.codeLength;\n\n const focusFirstBox = () =>\n panel.current?.querySelector<HTMLInputElement>('input')?.focus();\n\n // Focus follows the step: the code box when a code goes out and when a\n // check fails; the field itself when the code is right.\n const previous = useRef(state.status);\n const lastFailure = useRef(state.failure);\n useEffect(() => {\n const before = previous.current;\n previous.current = state.status;\n if (state.status === 'sent' && before === 'sending') focusFirstBox();\n if (state.status === 'sent' && before === 'verifying' && state.failure) {\n focusFirstBox();\n }\n if (state.status === 'verified' && before === 'verifying') onVerified();\n // eslint-disable-next-line react-hooks/exhaustive-deps -- only on a status change\n }, [state.status]);\n useEffect(() => {\n // A new failure while the box is open (a second wrong code).\n if (\n state.failure &&\n state.failure !== lastFailure.current &&\n state.status === 'sent'\n ) {\n focusFirstBox();\n }\n lastFailure.current = state.failure;\n }, [state.failure, state.status]);\n\n // The wait is shown in the button every second; a screen reader hears\n // it only when it starts and when it ends.\n const [announcement, setAnnouncement] = useState('');\n const waiting = state.cooldown > 0;\n const wasWaiting = useRef(false);\n useEffect(() => {\n if (waiting && !wasWaiting.current) {\n setAnnouncement(\n t('registrationForm.verification.resendIn', {\n seconds: state.cooldown,\n }),\n );\n } else if (!waiting && wasWaiting.current) {\n setAnnouncement(t('registrationForm.verification.resendCode'));\n }\n wasWaiting.current = waiting;\n // eslint-disable-next-line react-hooks/exhaustive-deps -- the start value only\n }, [waiting, t]);\n\n const isEmail = field === 'email';\n const sentText = isEmail\n ? t('registrationForm.verification.codeSentEmail', {\n value: state.sentTo,\n })\n : t('registrationForm.verification.codeSentPhone', {\n value: state.sentTo,\n });\n const changeText = isEmail\n ? t('registrationForm.verification.changeEmail')\n : t('registrationForm.verification.changePhone');\n const verifiedText = isEmail\n ? t('registrationForm.verification.verifiedEmail')\n : t('registrationForm.verification.verifiedPhone');\n\n return (\n <div\n ref={panel}\n data-slot=\"verification\"\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n {/* Always mounted: a live region announces a change, not its first\n content. Holds the success line and the wait announcements. */}\n <div role=\"status\" className={state.verified ? undefined : 'ds:sr-only'}>\n {state.verified ? (\n <p className=\"ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)] type-body-sm ds:text-success\">\n <CircleCheck aria-hidden=\"true\" className=\"ds:size-4 ds:shrink-0\" />\n <span>{verifiedText}</span>\n </p>\n ) : (\n announcement\n )}\n </div>\n\n {changeWhenVerified && state.changeable && (\n <Button\n type=\"button\"\n intent=\"secondary\"\n startIcon={<Pencil aria-hidden=\"true\" />}\n data-action=\"change-value\"\n className=\"ds:self-start\"\n onClick={() => {\n state.unlock();\n onUnlocked?.();\n }}\n >\n {changeText}\n </Button>\n )}\n\n {open && (\n <>\n <p className=\"type-body-sm ds:text-[var(--muted-foreground)]\">\n {sentText}\n </p>\n {state.devCode && (\n <Alert variant=\"info\" announce=\"off\">\n <Alert.Description>\n {t('registrationForm.verification.devCode', {\n code: state.devCode,\n })}\n </Alert.Description>\n </Alert>\n )}\n {/* A field of its own, so the code box has a label and its\n own message slot. */}\n <FormField\n label={t('registrationForm.verification.codeLabel')}\n error={message}\n >\n <OTPInput\n length={state.codeLength}\n mode=\"numeric\"\n webOtp={field === 'phone'}\n value={state.code}\n onChange={state.setCode}\n onComplete={(code) => state.verify(code)}\n disabled={verifying}\n />\n </FormField>\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-sm)]\">\n <Button\n type=\"button\"\n intent=\"primary\"\n size=\"md\"\n loading={verifying}\n aria-disabled={!complete || undefined}\n data-action=\"verify-code\"\n onClick={() => {\n if (complete) state.verify();\n }}\n >\n {verifying\n ? t('registrationForm.verification.verifying')\n : t('registrationForm.verification.verify')}\n </Button>\n <Button\n type=\"button\"\n intent=\"outline\"\n size=\"md\"\n disabled={verifying}\n aria-disabled={waiting || undefined}\n data-action=\"resend-code\"\n onClick={() => {\n if (!waiting) state.send();\n }}\n >\n {waiting\n ? t('registrationForm.verification.resendIn', {\n seconds: state.cooldown,\n })\n : t('registrationForm.verification.resendCode')}\n </Button>\n {canChange && (\n <Button\n type=\"button\"\n intent=\"link\"\n size=\"md\"\n disabled={verifying}\n data-action=\"change-value\"\n onClick={state.reset}\n >\n {changeText}\n </Button>\n )}\n </div>\n </>\n )}\n </div>\n );\n}\n\ninterface ChangeSlotProps {\n field: RegistrationVerifiableField;\n state: UseContactVerificationReturn;\n /** Called after the field is unlocked, to focus it. */\n onUnlocked: () => void;\n}\n\n/**\n * \"Change email\", in the cell where Confirm email sits. A hidden label\n * line above it keeps the action level with the input beside it.\n */\nexport function VerificationChangeSlot({\n field,\n state,\n onUnlocked,\n}: ChangeSlotProps) {\n const { t } = useTranslation('ui');\n return (\n <div\n data-slot=\"change-slot\"\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\"\n >\n {/* Only beside the email; stacked, it would leave a gap. */}\n <span\n aria-hidden=\"true\"\n className=\"type-label ds:invisible ds:hidden ds:@[544px]/registration:block\"\n >\n {'\\u00A0'}\n </span>\n <Button\n type=\"button\"\n intent=\"secondary\"\n startIcon={<Pencil aria-hidden=\"true\" />}\n data-action=\"change-value\"\n className=\"ds:self-start\"\n onClick={() => {\n state.unlock();\n onUnlocked();\n }}\n >\n {field === 'email'\n ? t('registrationForm.verification.changeEmail')\n : t('registrationForm.verification.changePhone')}\n </Button>\n </div>\n );\n}\n","/* -------------------------------------------------------------------- */\n/* RegistrationForm — the registration form card, for doctors and for */\n/* patients. */\n/* */\n/* One export for the card: name, email and password (each with a */\n/* confirm field), phone, speciality, terms and the submit button. The */\n/* host picks the fields: a doctor form shows them all, a patient form */\n/* shows email, password and terms. The host keeps the page around the */\n/* card, the marketing copy and every server rule. The card checks what */\n/* a browser can check and either hands the values to `onSubmit` or */\n/* posts a real form to the host's own field names. */\n/* */\n/* What happens on submit (the busy guard, the reCAPTCHA wait, telling */\n/* a server answer from a re-render) lives in `useRegistrationSubmit`. */\n/* -------------------------------------------------------------------- */\n\nimport {\n Fragment,\n forwardRef,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type HTMLAttributes,\n type ReactNode,\n} from 'react';\nimport { Trans, useTranslation } from 'react-i18next';\nimport { cva } from 'class-variance-authority';\nimport { Check, CircleAlert, KeyRound, LogIn } from 'lucide-react';\n// The same parser PhoneInput uses, for a number that arrives filled in.\nimport { parsePhoneNumberFromString } from 'libphonenumber-js/min';\n// The validator EmailInput itself uses, so the two never disagree.\nimport isEmail from 'validator/lib/isEmail';\nimport { Alert } from '../../components/alert';\nimport { Button } from '../../components/button';\nimport { Card } from '../../components/card';\nimport { Checkbox } from '../../components/checkbox';\nimport { DevBypassButton } from '../../components/dev-bypass-button';\nimport { EmailInput } from '../../components/email-input';\nimport { ErrorSummary } from '../../components/error-summary';\nimport { FormField } from '../../components/form-field';\nimport { List } from '../../components/list';\nimport {\n PasswordInput,\n usePasswordRequirements,\n type UsePasswordRequirementsOptions,\n} from '../../components/password-input';\nimport { PhoneInput } from '../../components/phone-input';\nimport { RecaptchaWidget } from '../../components/recaptcha-widget';\nimport { Select, type SelectOption } from '../../components/select';\nimport { StateBackedTextInput } from '../../components/_shared/state-backed-text-input';\nimport { isDevelopment } from '../../components/_shared/is-development';\nimport { useStateBackedInput } from '../../components/_shared/use-state-backed-input';\nimport { isSafeHref, isSameSiteHref } from '../../components/_shared/safe-href';\nimport { useFieldMatch } from '../../hooks/use-field-match';\nimport { BrandMark, type BrandMarkMotion } from '../_shared/brand-mark';\nimport {\n useErrorSummary,\n useFormMessageAnnounce,\n} from '../_shared/use-error-summary';\nimport { useRegistrationSubmit } from './use-registration-submit';\nimport {\n useContactVerification,\n type RegistrationFieldVerification,\n type RegistrationVerifiableField,\n} from './use-contact-verification';\nimport {\n VerificationAction,\n VerificationChangeSlot,\n VerificationPanel,\n useSendFailureMessage,\n} from './registration-verification';\n\n/* -------------------------------------------------------------------- */\n/* Types */\n/* -------------------------------------------------------------------- */\n\n/** The fields of the form, in the order they appear. */\nexport const REGISTRATION_FORM_FIELDS = [\n 'firstName',\n 'lastName',\n 'email',\n 'emailConfirm',\n 'password',\n 'passwordConfirm',\n 'phone',\n 'branch',\n 'terms',\n] as const;\n\nexport type RegistrationFormField = (typeof REGISTRATION_FORM_FIELDS)[number];\n\n/** The fields built on `TextInput`, which can refuse paste or copy. */\nexport type RegistrationFormTextField = Extract<\n RegistrationFormField,\n | 'firstName'\n | 'lastName'\n | 'email'\n | 'emailConfirm'\n | 'password'\n | 'passwordConfirm'\n>;\n\n/** What `onSubmit` receives once every check has passed. A field the\n * form does not show is empty (`''`, or `false` for the terms). */\nexport interface RegistrationFormValues {\n firstName: string;\n lastName: string;\n email: string;\n /** As typed. It matches `email` apart from case and outer spaces. */\n emailConfirm: string;\n password: string;\n /** Equal to `password` when the confirm field is shown. */\n passwordConfirm: string;\n /** In E.164 form, e.g. `+393331234567`. */\n phone: string;\n /** The chosen `branches` value. */\n branch: string;\n /** True when the terms are shown: the form does not submit without. */\n terms: boolean;\n /** The reCAPTCHA token, when the host passes `recaptchaSiteKey`. */\n captchaToken?: string;\n}\n\n/** Values to show when the form opens. There is no password here, on\n * purpose: a password is never sent back to the browser. */\nexport type RegistrationFormInitialValues = Partial<\n Pick<\n RegistrationFormValues,\n | 'firstName'\n | 'lastName'\n | 'email'\n | 'emailConfirm'\n | 'phone'\n | 'branch'\n | 'terms'\n >\n>;\n\n/**\n * What the development shortcut puts in the fields. Unlike\n * `initialValues` it may carry a password: the host passes it only in\n * development, from its own server, and the kit holds no test data of\n * its own.\n */\nexport type RegistrationFormDevValues = Partial<\n Pick<\n RegistrationFormValues,\n | 'firstName'\n | 'lastName'\n | 'email'\n | 'password'\n | 'phone'\n | 'branch'\n | 'terms'\n >\n>;\n\n/** The development-only shortcut at the top right of the card. */\nexport interface RegistrationFormDevBypass {\n /** What the shortcut does: the button's name and tooltip. */\n label: string;\n /**\n * The values to put in the fields when the button is pressed, as if\n * typed: the checks, the password checklist and the posted values all\n * see them. The confirm fields are filled from the same values, so\n * they match. A field the form does not show is ignored, and a\n * read-only email is kept.\n */\n values?: RegistrationFormDevValues;\n /**\n * True to submit the form right after filling it, through the normal\n * path: the checks still run, reCAPTCHA still runs, a native form\n * still posts. Default false: fill only.\n */\n submit?: boolean;\n /** Called after filling, for a host with a route of its own. */\n onClick?: () => void;\n}\n\n/** Messages from the server, already translated by the host: one per\n * field, plus `form` for a message about the whole form. */\nexport type RegistrationFormErrors = Partial<\n Record<RegistrationFormField | 'form', string>\n>;\n\n/** The data behind the existing-account state of `RegistrationForm`. */\nexport interface RegistrationFormExistingAccount {\n /** Where \"Sign in\" goes. Same tab. An unsafe address is dropped. */\n loginHref: string;\n /** Where \"Reset password\" goes. Optional. Same tab. An unsafe address is dropped. */\n resetPasswordHref?: string;\n}\n\n/** The host's own form field names, for a native form post. `captcha`\n * names the hidden field that carries the reCAPTCHA token. */\nexport type RegistrationFormFieldNames = Partial<\n Record<RegistrationFormField | 'captcha', string>\n>;\n\nexport interface RegistrationFormProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n 'title' | 'onSubmit'\n> {\n /** Replaces the heading \"Create your account\". Pass it translated. */\n title?: string;\n /** A line under the heading, e.g. \"No installation needed\". Pass it\n * translated. */\n description?: string;\n /** The heading's level. Default 2, for a page that has its own `h1`. */\n headingLevel?: 1 | 2 | 3;\n /**\n * Shows the Alfadocs mark above the heading, with the heading and its\n * line centred under it. Default true. With `false` the heading sits\n * at the start edge, for a host that shows its own logo beside the\n * card.\n */\n showLogo?: boolean;\n /**\n * How the mark arrives when the card opens: its pieces come together\n * (`assemble`, the default), it turns once (`spin`), it beats\n * (`pulse`), or it is still (`none`). It plays once and rests, and\n * holds still under reduced motion and in the accessible themes.\n */\n logoMotion?: BrandMarkMotion;\n /**\n * Host content between the heading and the fields, such as a notice\n * or a list of benefits. It sits outside the form, so nothing in it is\n * posted. Keep any heading inside it below the card's own level.\n */\n children?: ReactNode;\n /**\n * A short notice above the fields, as plain text already translated. It\n * shows as an info alert, quiet to screen readers (it is not news). For\n * a server-rendered page that can only pass JSON. Comes before\n * `benefits` and `children`.\n */\n notice?: string;\n /**\n * What the person gets, one short line each, already translated. They\n * show as a compact list with a tick. Comes after `notice` and before\n * `children`.\n */\n benefits?: string[];\n /**\n * The fields to show. Default: all of them, which is the doctor form.\n * A patient form is `['email', 'password', 'passwordConfirm', 'terms']`.\n * Leave out `emailConfirm` or `passwordConfirm` to drop that confirm\n * field. The list picks fields, it does not order them; email and\n * password always show; `branch` also needs `branches`.\n */\n fields?: readonly RegistrationFormField[];\n /** Values to show when the form opens, such as the email from an\n * invite link. Read once. Never a password. */\n initialValues?: RegistrationFormInitialValues;\n /**\n * Messages from the server, already translated. Each shows on its\n * field until the user changes that field; `form` shows above the\n * fields, as does a message for a field the form does not show.\n *\n * Messages present when the form opens (a page the server rendered\n * after a failed post) take focus: the error summary at the top of the\n * form, which lists each field with a message, or the message above the\n * fields when no field has one.\n *\n * On a React host, when the messages change, both password fields\n * are emptied and focus moves as above. Set `submitting` while you\n * send: the form then also notices an answer that says the same as\n * the last one (another address, also taken), which the messages\n * alone cannot show. Any object works, kept in state or rebuilt on\n * each render (`errors={{ email: emailError }}`).\n */\n errors?: RegistrationFormErrors;\n /**\n * Shows the email from `initialValues` read-only, for a person invited\n * with an address they cannot change here. Off by default: choose it\n * only when the server will refuse any other address. The value is\n * still posted and still read out, there is no confirm email field,\n * and the browser does not check it. Ignored when there is no initial\n * email, so the field is never both empty and locked.\n */\n emailReadOnly?: boolean;\n /** A line under the email field, e.g. \"You can change it later in the\n * settings\". Pass it translated. */\n emailDescription?: string;\n /**\n * Fields that refuse paste and drop, so the user types them, e.g.\n * `['passwordConfirm']`. Default: none. Autofill from the browser or a\n * password manager still works. A refused paste is announced and shown\n * under the field. The host decides: see the docs for the WCAG\n * position, which differs between the email and password fields.\n */\n blockPaste?: readonly RegistrationFormTextField[];\n /**\n * Fields that refuse copy, cut and dragging text out. Default: none.\n * Browsers already refuse to copy from a password field while it is\n * hidden. See the docs for the WCAG position.\n */\n blockCopy?: readonly RegistrationFormTextField[];\n /** The specialities to choose from. The field shows, and is required,\n * only when this has entries. */\n branches?: SelectOption[];\n /**\n * The password rules, shown as a live checklist. Keep them equal to\n * the server's. Default: 12 characters with an uppercase letter, a\n * lowercase letter and a number, counting only `A-Z`, `a-z` and `0-9`\n * (`charset: 'ascii'`), which is the platform's rule.\n */\n passwordPolicy?: UsePasswordRequirementsOptions;\n /**\n * Where \"terms of use\" leads. A path on the same site, or an address\n * written in full (`https://…`). Anything else, such as an address\n * that would lead off the site without saying so, shows the words\n * without a link.\n */\n termsHref?: string;\n /** Where \"privacy policy\" leads. Same rule as `termsHref`. */\n privacyHref?: string;\n /**\n * Replaces the sentence beside the terms box (\"I accept the terms of\n * use and the privacy policy\") with the host's own wording and links,\n * already translated. The legal wording is the host's to choose. When\n * set, `termsHref` and `privacyHref` are not used. The box stays\n * required.\n */\n termsLabel?: ReactNode;\n /**\n * `termsLabel` as a string, for a host that can only pass JSON. Already\n * translated. Mark the links with `<terms>…</terms>` and\n * `<privacy>…</privacy>`: they lead to `termsHref` and `privacyHref`\n * (new tab; without a safe address, the words show without a link).\n * Any other tag shows its text only. No marker: plain text. Ignored\n * when `termsLabel` is set.\n */\n termsLabelText?: string;\n /** A line shown with the terms box and read out with it, e.g. \"We\n * will not send you any advertising\". Pass it translated. */\n termsDescription?: ReactNode;\n /** `termsDescription` as a string, with the same markers as\n * `termsLabelText`. Ignored when `termsDescription` is set. */\n termsDescriptionText?: string;\n /** Adds \"Already have an account? Sign in\". Same rule as `termsHref`. */\n loginHref?: string;\n /**\n * The server refused the email because an account already has it. The email\n * field shows the kit's own message, naming the way forward, with a link to\n * sign in and a link to reset the password. Data only, so it works from JSON.\n *\n * The state is read against the email the form opened with\n * (`initialValues.email`, which must not be empty), so it is for a page the\n * server renders again after refusing the post. A React host that answers\n * through `onSubmit` mounts the form again (a new `key`) with\n * `initialValues.email` set to the refused address. Any edit to the email\n * removes the message and the links; typing the opening address back brings\n * them back. While it shows, the card's footer sign-in line is hidden, so\n * there is one \"Sign in\".\n *\n * Privacy: an address in a link's URL lands in server logs and in analytics\n * page URLs. Preferred: keep the address in the host's own session and link\n * plainly (`/login`). Allowed: put it in the query string\n * (`/login?email=...`).\n */\n existingAccount?: RegistrationFormExistingAccount;\n /** A Google reCAPTCHA v2 site key of the invisible type. The check\n * runs when the user submits. Leave it out where the server does not\n * verify a token. */\n recaptchaSiteKey?: string;\n /** Replaces the button's \"Create account\". Pass it translated. */\n submitLabel?: string;\n /** True while the host sends the values: the button shows a spinner\n * and a second submit is ignored. */\n submitting?: boolean;\n /**\n * Shows the development-only shortcut button at the top right of the\n * card: it fills the form with the host's `values`, and submits it\n * when asked to. Pass it only when the server says this is a\n * development environment: the kit never decides that itself, holds\n * no test data, and what the shortcut submits goes through the normal\n * path, so the server's own rules still decide. With neither `values`\n * nor `onClick` there is nothing to do and no button.\n */\n devBypass?: RegistrationFormDevBypass;\n /** For React hosts: called with the values once every check has\n * passed. Not called when `fieldNames` is set. */\n onSubmit?: (values: RegistrationFormValues) => void;\n /**\n * For a native form post: the host's own field names, e.g.\n * `{ email: 'registration[email]' }`. When set, the inputs carry\n * these names and the browser posts the form. A field without a name\n * here is not posted: name a confirm field only if the server's form\n * has one, or it may refuse the post as carrying extra fields.\n */\n fieldNames?: RegistrationFormFieldNames;\n /**\n * Where a native form post goes. Default: the current address, query\n * string included, which is what a page reached through an invite link\n * needs. Only an address on this site is accepted: another site is\n * never sent what the user typed, and the post then goes to the\n * current address instead.\n */\n action?: string;\n /**\n * Extra hidden inputs posted with a native form, by name: a CSRF token\n * or similar. Not used with `onSubmit`. A name that is also one of\n * `fieldNames` is left out: the form's own field wins.\n */\n hiddenFields?: Readonly<Record<string, string>>;\n /**\n * Proves an email or a phone number with a code before the form\n * submits. For each field named here the card shows \"Send code\" beside\n * the field, a code box once a code is out, and locks the field\n * (read-only, still posted) when the code is right. The host sends and\n * checks the codes on its server, which must also refuse the form when\n * the value was not verified: this is a convenience for the person,\n * not the check. Without it the form is unchanged.\n *\n * `Confirm email` stays; leave `emailConfirm` out of `fields` to drop it.\n */\n verification?: Partial<\n Record<RegistrationVerifiableField, RegistrationFieldVerification>\n >;\n /**\n * With `verification`, the form does not submit until every field named\n * there is verified. Default true.\n */\n requireVerification?: boolean;\n}\n\n/* -------------------------------------------------------------------- */\n/* Styles */\n/* -------------------------------------------------------------------- */\n\nconst registrationFormVariants = cva(\n 'ds:@container/registration ds:w-full ds:text-start ds:text-[var(--foreground)]',\n);\n\nconst rowVariants = cva(\n 'ds:grid ds:grid-cols-1 ds:items-start ds:gap-[var(--spacing-md)]',\n {\n variants: {\n columns: {\n /** A field alone in its row takes the full width. */\n one: '',\n /** Two fields side by side once the card is wide enough. */\n two: 'ds:@[544px]/registration:grid-cols-2',\n },\n },\n defaultVariants: { columns: 'two' },\n },\n);\n\n/** The top of the card: the mark, the heading and its line. */\nconst headerVariants = cva('ds:relative ds:flex ds:gap-[var(--spacing-sm)]', {\n variants: {\n logo: {\n /** A centred column under the mark. */\n true: 'ds:flex-col ds:items-center',\n /** The heading at the start edge, the shortcut at the end. */\n false: 'ds:items-start ds:justify-between',\n },\n },\n defaultVariants: { logo: true },\n});\n\nconst headingBlockVariants = cva(\n 'ds:flex ds:min-w-0 ds:flex-col ds:gap-[var(--spacing-xs)]',\n {\n variants: {\n centred: { true: 'ds:items-center ds:text-center', false: '' },\n },\n defaultVariants: { centred: true },\n },\n);\n\n/** Where the development shortcut sits: the top inline-end corner. Out\n * of the flow under the mark, so it cannot push the mark off centre. */\nconst shortcutVariants = cva('ds:shrink-0', {\n variants: {\n corner: { true: 'ds:absolute ds:top-0 ds:end-0', false: '' },\n },\n defaultVariants: { corner: true },\n});\n\n// Links inside the card take the text colour and an underline. The kit\n// Link's own colour (`--primary`) falls just below AA on a card in the\n// dark theme, as the booking form's consent links found.\nconst inlineLinkVariants = cva(\n 'ds:rounded-[var(--radius-sm)] ds:underline ds:underline-offset-4 ds:text-[var(--foreground)] ds:focus-visible:outline-solid ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-[var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n {\n variants: {\n weight: { normal: '', strong: 'ds:font-semibold' },\n },\n defaultVariants: { weight: 'normal' },\n },\n);\n\n// The message above the fields takes focus when there is no field to\n// send the user to, so it shows a ring like anything else that does.\nconst formMessageVariants = cva(\n 'ds:focus-visible:outline-solid ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-[var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n);\n\n/** The `*` beside a required field, as FormField draws it. Decorative:\n * the control itself says it is required. */\nconst requiredMarkVariants = cva(\n 'ds:text-destructive ds:ms-[var(--spacing-xs)]',\n);\n\n/* -------------------------------------------------------------------- */\n/* Helpers */\n/* -------------------------------------------------------------------- */\n\n// The platform's rule is written in ASCII (`[A-Z]`, `[a-z]`, `\\d`), so\n// the checklist counts the same characters and never shows green for a\n// password the server will refuse.\nconst DEFAULT_PASSWORD_POLICY: UsePasswordRequirementsOptions = {\n minLength: 12,\n uppercase: true,\n lowercase: true,\n digit: true,\n charset: 'ascii',\n};\n\n// A brand name, not interface copy: it reads the same in every language,\n// so it has no translation key.\nconst BRAND_NAME = 'Alfadocs';\n\n/** A <terms> or <privacy> span in a host sentence. */\nconst MARKED = /<(terms|privacy)>([\\s\\S]*?)<\\/\\1>/;\n/** Any other tag: its text stays, the tag goes. */\nconst OTHER_TAGS = /<\\/?(?!(?:terms|privacy)\\b)[a-z][^>]*>/gi;\n\n/** An address a link may use, or nothing. */\nconst linkTo = (href: string | undefined): string | undefined =>\n href && isSafeHref(href) ? href : undefined;\n\nconst hasMessage = (errors: RegistrationFormErrors): boolean =>\n Object.values(errors).some(Boolean);\n\n/** Whether a number could be a real one, by its length for its country. */\nconst isPossiblePhone = (e164: string): boolean =>\n parsePhoneNumberFromString(e164)?.isPossible() ?? false;\n\ninterface InlineLinkProps {\n href: string;\n /** Opens in a new tab, so the form keeps what the user has typed. */\n newTab?: boolean;\n weight?: 'normal' | 'strong';\n /** Emitted as `data-action`. */\n action?: string;\n /** The link's text: `Trans` fills it in from the translation. */\n children?: ReactNode;\n}\n\n// `Trans` hands every element it fills a bookkeeping prop of its own, so\n// these two take named props only and pass nothing else on to the DOM.\n\n/** A link inside a sentence. */\nfunction InlineLink({\n href,\n newTab = false,\n weight,\n action,\n children,\n}: InlineLinkProps) {\n const { t } = useTranslation('ui');\n return (\n <a\n href={href}\n target={newTab ? '_blank' : undefined}\n rel={newTab ? 'noopener noreferrer' : undefined}\n data-action={action}\n className={inlineLinkVariants({ weight })}\n >\n {children}\n {newTab && <span className=\"ds:sr-only\">{t('link.opensInNewTab')}</span>}\n </a>\n );\n}\n\n/** The words a link would wrap, when the host gives no address for it. */\nfunction PlainText({ children }: { children?: ReactNode }) {\n return <>{children}</>;\n}\n\n/** What a field's wrapper reports as `data-verification`. */\nfunction verificationStep(\n state: ReturnType<typeof useContactVerification>,\n): 'idle' | 'sent' | 'verified' | undefined {\n if (!state.enabled) return undefined;\n if (state.verified) return 'verified';\n return state.status === 'sent' || state.status === 'verifying'\n ? 'sent'\n : 'idle';\n}\n\ntype FieldFlags = Partial<Record<RegistrationFormField, boolean>>;\n\n/** Where focus can be sent: a field, or the message above the fields. */\ntype FocusTarget = RegistrationFormField | 'form';\n\n/** Every field but the terms, which is a checkbox under the grid. */\ntype GridField = Exclude<RegistrationFormField, 'terms'>;\n\n/** A field sits beside the one it belongs with. */\nconst FIELD_PAIRS: ReadonlyArray<readonly [GridField, GridField]> = [\n ['firstName', 'lastName'],\n ['email', 'emailConfirm'],\n ['password', 'passwordConfirm'],\n ['phone', 'branch'],\n];\n\n/** The rows of the form, for the fields that show. A pair keeps its\n * row; two fields left alone one after the other share a row, so a\n * form of just email and password puts them side by side. */\nfunction layOutRows(shows: (field: GridField) => boolean): GridField[][] {\n const rows: GridField[][] = [];\n for (const pair of FIELD_PAIRS) {\n const row = pair.filter(shows);\n if (row.length === 0) continue;\n const last = rows[rows.length - 1];\n if (row.length === 1 && last?.length === 1) last.push(row[0]);\n else rows.push(row);\n }\n return rows;\n}\n\ninterface FormState {\n firstName: string;\n lastName: string;\n email: string;\n emailConfirm: string;\n password: string;\n passwordConfirm: string;\n phone: string;\n branch: string;\n terms: boolean;\n}\n\n/* -------------------------------------------------------------------- */\n/* RegistrationForm */\n/* -------------------------------------------------------------------- */\n\n/**\n * The registration form card, for doctors and for patients. The host\n * picks the fields, supplies the page around the card and owns every\n * server rule; see the props for the two ways to submit. The card's\n * text follows the kit's language, like every kit component.\n */\nexport const RegistrationForm = forwardRef<\n HTMLDivElement,\n RegistrationFormProps\n>(\n (\n {\n title,\n description,\n headingLevel = 2,\n showLogo = true,\n logoMotion = 'assemble',\n children,\n fields,\n initialValues,\n errors,\n emailReadOnly = false,\n emailDescription,\n blockPaste,\n blockCopy,\n branches,\n passwordPolicy = DEFAULT_PASSWORD_POLICY,\n termsHref,\n privacyHref,\n termsLabel: termsLabelNode,\n termsDescription: termsDescriptionNode,\n termsLabelText,\n termsDescriptionText,\n notice,\n benefits,\n loginHref,\n existingAccount,\n recaptchaSiteKey,\n submitLabel,\n submitting = false,\n devBypass,\n onSubmit,\n fieldNames,\n action,\n hiddenFields,\n verification,\n requireVerification = true,\n className,\n ...rest\n },\n ref,\n ) => {\n const { t, i18n } = useTranslation('ui');\n const titleId = useId();\n const fieldIdBase = useId();\n /** The id of a field's wrapper: where the summary's link leads. */\n const fieldId = (field: RegistrationFormField) => `${fieldIdBase}-${field}`;\n const termsErrorId = useId();\n const termsDescriptionId = useId();\n const formMessageId = useId();\n const native = fieldNames !== undefined;\n const hasBranches = Boolean(branches && branches.length > 0);\n // Locked only when there is an address to lock: an empty read-only\n // field would leave the user with no way forward.\n const [hadEmail] = useState(() => Boolean(initialValues?.email));\n const emailLocked = emailReadOnly && hadEmail;\n\n /** Whether the form shows a field. */\n const shows = (field: RegistrationFormField): boolean => {\n if (field === 'email' || field === 'password') return true;\n if (fields && !fields.includes(field)) return false;\n if (field === 'branch') return hasBranches;\n // Nothing to mistype in an address the user cannot type.\n // Not while the code proves the address: nothing to retype.\n if (field === 'emailConfirm') return !emailLocked && !emailVerified;\n return true;\n };\n\n /* ------------------------------ State ----------------------------- */\n\n // Read once. Passwords always start empty.\n const [values, setValues] = useState<FormState>(() => ({\n firstName: initialValues?.firstName ?? '',\n lastName: initialValues?.lastName ?? '',\n email: initialValues?.email ?? '',\n emailConfirm: initialValues?.emailConfirm ?? '',\n password: '',\n passwordConfirm: '',\n phone: initialValues?.phone ?? '',\n branch: initialValues?.branch ?? '',\n terms: initialValues?.terms ?? false,\n }));\n // PhoneInput says whether a number is possible each time it changes.\n const [phonePossible, setPhonePossible] = useState(() =>\n isPossiblePhone(initialValues?.phone ?? ''),\n );\n // A field the user has left. An email that arrives filled in counts,\n // as it does inside EmailInput: both then flag a bad one at once, so\n // the field is never red without a message.\n const [touched, setTouched] = useState<FieldFlags>(() => ({\n email: Boolean(initialValues?.email),\n }));\n const [submitted, setSubmitted] = useState(false);\n const [serverErrors, setServerErrors] = useState<RegistrationFormErrors>(\n () => errors ?? {},\n );\n\n /* --------------------------- Verification ------------------------- */\n\n const emailVerification = useContactVerification({\n config: verification?.email,\n value: values.email,\n });\n const phoneVerification = useContactVerification({\n config: shows('phone') ? verification?.phone : undefined,\n value: values.phone,\n });\n const emailVerified = emailVerification.verified;\n const phoneVerified = phoneVerification.verified;\n const shown = REGISTRATION_FORM_FIELDS.filter(shows);\n // Where \"Change email\" sits: the Confirm email cell.\n const changeSlot =\n !emailLocked && emailVerified && emailVerification.changeable;\n /** A field the person still has to prove. */\n const emailNeedsCode =\n requireVerification && emailVerification.enabled && !emailVerified;\n const phoneNeedsCode =\n requireVerification && phoneVerification.enabled && !phoneVerified;\n const emailSendFailure = useSendFailureMessage(emailVerification);\n const phoneSendFailure = useSendFailureMessage(phoneVerification);\n\n const set = <K extends keyof FormState>(field: K, value: FormState[K]) => {\n setValues((previous) => ({ ...previous, [field]: value }));\n // The server's message was about the old value.\n setServerErrors((previous) =>\n previous[field] ? { ...previous, [field]: undefined } : previous,\n );\n };\n const leave = (field: RegistrationFormField) =>\n setTouched((previous) =>\n previous[field] ? previous : { ...previous, [field]: true },\n );\n const emptyPasswords = () => {\n setValues((previous) => ({\n ...previous,\n password: '',\n passwordConfirm: '',\n }));\n setTouched((previous) => ({\n ...previous,\n password: false,\n passwordConfirm: false,\n }));\n };\n\n /** The paste and copy switches for one typed field. */\n const clipboard = (field: RegistrationFormTextField) => ({\n blockPaste: blockPaste?.includes(field) ?? false,\n blockCopy: blockCopy?.includes(field) ?? false,\n });\n\n /* ---------------------------- Validation -------------------------- */\n\n const requirements = usePasswordRequirements(passwordPolicy);\n const emailMatch = useFieldMatch({\n value: values.email,\n confirmValue: values.emailConfirm,\n kind: 'email',\n submitted,\n });\n const passwordMatch = useFieldMatch({\n value: values.password,\n confirmValue: values.passwordConfirm,\n kind: 'password',\n submitted,\n });\n\n /** What stops a submit, whether or not the message shows yet. Only\n * a field that shows can stop it. */\n const invalid: Record<RegistrationFormField, boolean> = {\n firstName: shows('firstName') && values.firstName.trim() === '',\n lastName: shows('lastName') && values.lastName.trim() === '',\n // The user cannot fix a locked address, so the server judges it.\n email: (!emailLocked && !isEmail(values.email)) || emailNeedsCode,\n emailConfirm:\n shows('emailConfirm') &&\n (values.emailConfirm === '' || !emailMatch.matches),\n password:\n values.password === '' ||\n !requirements.every((rule) => rule.test(values.password)),\n passwordConfirm:\n shows('passwordConfirm') &&\n (values.passwordConfirm === '' || !passwordMatch.matches),\n phone:\n shows('phone') &&\n (values.phone === '' || !phonePossible || phoneNeedsCode),\n branch: shows('branch') && values.branch === '',\n terms: shows('terms') && !values.terms,\n };\n\n // A message shows once the user has left the field or tried to\n // submit. The terms box waits for a submit: leaving it to follow one\n // of its own links is not a mistake.\n const due = (field: RegistrationFormField) =>\n submitted || (field !== 'terms' && touched[field] === true);\n const required = t('registrationForm.required');\n /** Each grid field's label: on the field, and in the summary. */\n const labels: Record<GridField, string> = {\n firstName: t('registrationForm.firstName'),\n lastName: t('registrationForm.lastName'),\n email: t('registrationForm.email'),\n emailConfirm: t('registrationForm.emailConfirm'),\n password: t('registrationForm.password'),\n passwordConfirm: t('registrationForm.passwordConfirm'),\n phone: t('registrationForm.phone'),\n branch: t('registrationForm.branch'),\n };\n const whenDue = (field: RegistrationFormField, message: string) =>\n due(field) && invalid[field] ? message : undefined;\n\n const ownErrors: Record<RegistrationFormField, string | undefined> = {\n firstName: whenDue('firstName', required),\n lastName: whenDue('lastName', required),\n email:\n due('email') && !emailLocked && !isEmail(values.email)\n ? values.email === ''\n ? required\n : t('inputs.email.invalid')\n : submitted && emailNeedsCode\n ? t('registrationForm.verification.emailRequired')\n : undefined,\n emailConfirm:\n values.emailConfirm === ''\n ? whenDue('emailConfirm', required)\n : emailMatch.error,\n password: whenDue(\n 'password',\n values.password === ''\n ? required\n : t('registrationForm.passwordInvalid'),\n ),\n passwordConfirm:\n values.passwordConfirm === ''\n ? whenDue('passwordConfirm', required)\n : passwordMatch.error,\n phone:\n due('phone') &&\n shows('phone') &&\n (values.phone === '' || !phonePossible)\n ? values.phone === ''\n ? required\n : t('registrationForm.phoneInvalid')\n : submitted && phoneNeedsCode\n ? t('registrationForm.verification.phoneRequired')\n : undefined,\n branch: whenDue('branch', required),\n terms: whenDue('terms', t('registrationForm.termsRequired')),\n };\n const sendFailures: Partial<Record<RegistrationFormField, string>> = {\n email: emailSendFailure,\n phone: phoneSendFailure,\n };\n // The kit's own message, while the email is the one the server refused.\n const [openedEmail] = useState(() => initialValues?.email ?? '');\n const existingNow =\n Boolean(existingAccount) && hadEmail && values.email === openedEmail;\n const existingSignIn = linkTo(existingAccount?.loginHref);\n const existingReset = linkTo(existingAccount?.resetPasswordHref);\n const existingMessage = t(\n existingSignIn && existingReset\n ? 'registrationForm.existingAccount.messageSignInOrReset'\n : existingSignIn\n ? 'registrationForm.existingAccount.messageSignIn'\n : existingReset\n ? 'registrationForm.existingAccount.messageReset'\n : 'registrationForm.existingAccount.message',\n );\n const errorFor = (field: RegistrationFormField) =>\n field === 'email' && existingNow\n ? existingMessage\n : (serverErrors[field] ?? sendFailures[field] ?? ownErrors[field]);\n\n /* ------------------------------ Focus ----------------------------- */\n\n const controls = useRef<\n Partial<Record<RegistrationFormField, HTMLElement | null>>\n >({});\n const control = useMemo(() => {\n const bind =\n (field: RegistrationFormField) => (node: HTMLElement | null) => {\n controls.current[field] = node;\n };\n return {\n firstName: bind('firstName'),\n lastName: bind('lastName'),\n email: bind('email'),\n emailConfirm: bind('emailConfirm'),\n password: bind('password'),\n passwordConfirm: bind('passwordConfirm'),\n phone: bind('phone'),\n branch: bind('branch'),\n terms: bind('terms'),\n };\n }, []);\n // The addresses stay out of the inputs' `value` attributes, where a\n // copied outerHTML or a session replay could read them. The names do\n // too, through StateBackedTextInput.\n const emailField = useStateBackedInput(values.email, control.email);\n const emailConfirmField = useStateBackedInput(\n values.emailConfirm,\n control.emailConfirm,\n );\n const formMessage = useRef<HTMLDivElement>(null);\n\n /** Where to send the user for a set of server messages: the first\n * field on screen that has one, or the message above the fields\n * when only that says something. */\n const focusTargetFor = (\n messages: RegistrationFormErrors,\n ): FocusTarget | undefined =>\n shown.find((field) => messages[field]) ??\n (hasMessage(messages) ? 'form' : undefined);\n\n // Every field with a message after a refused submit, or after a server\n // answer, is listed at the top of the form, and focus goes there. A\n // page the server rendered after a failed post opens that way too: it\n // announces nothing itself.\n // `existingAccount` is a server answer too, with or without `errors.email`.\n const [openedWithFieldMessage] = useState(\n () =>\n shown.some((field) => Boolean(errors?.[field])) ||\n (Boolean(existingAccount) && hadEmail),\n );\n const summary = useErrorSummary(shown, errorFor, openedWithFieldMessage);\n\n // Any other place focus goes: the message above the fields, when no\n // field has one. A new object for each request, so asking twice for the\n // same place moves focus twice. The effect runs after the messages are\n // drawn, so a screen reader lands on something that already says what\n // is wrong.\n const [focusRequest, setFocusRequest] = useState<{\n target: FocusTarget;\n } | null>(() => {\n const target = openedWithFieldMessage\n ? undefined\n : focusTargetFor(errors ?? {});\n return target ? { target } : null;\n });\n useEffect(() => {\n if (!focusRequest) return;\n if (focusRequest.target === 'form') formMessage.current?.focus();\n else controls.current[focusRequest.target]?.focus();\n }, [focusRequest]);\n\n // PhoneInput has no blur event of its own, so listen on its input.\n const showsPhone = shows('phone');\n useEffect(() => {\n const input = controls.current.phone;\n if (!showsPhone || !input) return undefined;\n const onBlur = () =>\n setTouched((previous) =>\n previous.phone ? previous : { ...previous, phone: true },\n );\n input.addEventListener('blur', onBlur);\n return () => input.removeEventListener('blur', onBlur);\n }, [showsPhone]);\n\n /* ------------------------------ Submit ---------------------------- */\n\n const form = useRef<HTMLFormElement>(null);\n const captchaInput = useRef<HTMLInputElement>(null);\n\n /* --------------------- Development shortcut ----------------------- */\n\n // Asks for a submit once the filled values are on the page.\n const [submitRequest, setSubmitRequest] = useState<object | null>(null);\n useEffect(() => {\n if (submitRequest) form.current?.requestSubmit();\n }, [submitRequest]);\n\n const runDevBypass = () => {\n const filled = devBypass?.values;\n if (filled) {\n // Through the same state as the user's typing, and only into\n // fields that show. A locked email keeps its address.\n const email = emailLocked || emailVerified ? undefined : filled.email;\n const next: Partial<FormState> = {};\n if (shows('firstName') && filled.firstName !== undefined)\n next.firstName = filled.firstName;\n if (shows('lastName') && filled.lastName !== undefined)\n next.lastName = filled.lastName;\n if (email !== undefined) next.email = email;\n if (shows('emailConfirm') && email !== undefined)\n next.emailConfirm = email;\n if (filled.password !== undefined) next.password = filled.password;\n if (shows('passwordConfirm') && filled.password !== undefined)\n next.passwordConfirm = filled.password;\n if (shows('phone') && !phoneVerified && filled.phone !== undefined)\n next.phone = filled.phone;\n if (shows('branch') && filled.branch !== undefined)\n next.branch = filled.branch;\n if (shows('terms') && filled.terms !== undefined)\n next.terms = filled.terms;\n setValues((previous) => ({ ...previous, ...next }));\n if (next.phone !== undefined)\n setPhonePossible(isPossiblePhone(next.phone));\n // The server's messages were about the old values.\n setServerErrors((previous) => {\n const kept = { ...previous };\n for (const field of Object.keys(next) as (keyof FormState)[]) {\n kept[field] = undefined;\n }\n return kept;\n });\n if (devBypass.submit) setSubmitRequest({});\n }\n devBypass?.onClick?.();\n };\n\n const submit = useRegistrationSubmit<RegistrationFormField>({\n errors,\n submitting,\n native,\n captcha: Boolean(recaptchaSiteKey),\n firstProblem: () => shown.find((field) => invalid[field]),\n onRefused: (field) => {\n // Every message now shows, listed in the summary, which takes focus.\n setSubmitted(true);\n summary.open(() => setFocusRequest({ target: field }));\n },\n deliver: (captchaToken) => {\n if (native) {\n if (captchaInput.current && captchaToken) {\n captchaInput.current.value = captchaToken;\n }\n form.current?.submit();\n return;\n }\n // A field that does not show is empty, whatever it started with.\n const text = (field: GridField) => (shows(field) ? values[field] : '');\n onSubmit?.({\n firstName: text('firstName'),\n lastName: text('lastName'),\n email: values.email,\n emailConfirm: text('emailConfirm'),\n password: values.password,\n passwordConfirm: text('passwordConfirm'),\n phone: text('phone'),\n branch: text('branch'),\n terms: shows('terms') && values.terms,\n captchaToken,\n });\n },\n onAnswer: (answer) => {\n const next: RegistrationFormErrors = answer;\n setServerErrors(next);\n if (!hasMessage(next)) return;\n // Never keep a password the server did not accept.\n emptyPasswords();\n setSubmitted(false);\n // The summary when a field has a message, else the message above.\n summary.open(() => {\n const target = focusTargetFor(next);\n if (target) setFocusRequest({ target });\n });\n },\n // The page came back from the browser's cache as it was left:\n // the passwords must not come back with it.\n onRestore: emptyPasswords,\n });\n const { busy, captchaFailed } = submit;\n\n // A failed reCAPTCHA check has no field of its own: send the user to\n // the message above the fields, which may be off screen.\n useEffect(() => {\n if (captchaFailed) setFocusRequest({ target: 'form' });\n }, [captchaFailed]);\n\n /* ------------------------------ Render ---------------------------- */\n\n const name = (field: RegistrationFormField) =>\n native ? fieldNames[field] : field;\n const Heading = `h${headingLevel}` as const;\n const termsLink = linkTo(termsHref);\n const privacyLink = linkTo(privacyHref);\n const loginLink = linkTo(loginHref);\n const existingActions =\n existingNow && (existingSignIn || existingReset) ? (\n <>\n {existingSignIn && (\n <Button\n asChild\n intent=\"secondary\"\n startIcon={<LogIn />}\n data-action=\"sign-in\"\n >\n <a href={existingSignIn}>{t('loginForm.submit')}</a>\n </Button>\n )}\n {existingReset && (\n <Button\n asChild\n intent=\"secondary\"\n startIcon={<KeyRound />}\n data-action=\"reset-password\"\n >\n <a href={existingReset}>{t('loginForm.forgot')}</a>\n </Button>\n )}\n </>\n ) : undefined;\n // The host's own sentence as a string: <terms> and <privacy> become\n // links, any other tag shows its text, and no HTML is ever created.\n // Read here, not through i18n: the sentence is already translated.\n const marked = (text: string): ReactNode => {\n const parts = text.replace(OTHER_TAGS, '').split(MARKED);\n return parts.map((part, index) => {\n if (index % 3 !== 0) return null;\n const tag = parts[index + 1];\n const words = parts[index + 2];\n const href = tag === 'terms' ? termsLink : privacyLink;\n return (\n <Fragment key={index}>\n {part}\n {tag === undefined ? null : href ? (\n <InlineLink href={href} newTab>\n {words}\n </InlineLink>\n ) : (\n words\n )}\n </Fragment>\n );\n });\n };\n const termsLabel =\n termsLabelNode ?? (termsLabelText ? marked(termsLabelText) : undefined);\n const termsDescription =\n termsDescriptionNode ??\n (termsDescriptionText ? marked(termsDescriptionText) : undefined);\n const benefitLines = benefits?.filter(Boolean) ?? [];\n const hasHostContent =\n Boolean(notice) || benefitLines.length > 0 || Boolean(children);\n const formAction =\n native && action && isSameSiteHref(action) ? action : undefined;\n // What shows above the fields: the server's message about the whole\n // form, its message about any field that is not on screen (so nothing\n // it says is lost), and a failed reCAPTCHA check.\n const formError =\n [\n serverErrors.form,\n ...REGISTRATION_FORM_FIELDS.filter((field) => !shows(field)).map(\n (field) => serverErrors[field],\n ),\n captchaFailed ? t('inputs.recaptcha.error') : undefined,\n ]\n .filter(Boolean)\n .join(' ') || undefined;\n // Quiet while the summary lists a field: the summary reads it then.\n const formMessageAnnounce = useFormMessageAnnounce(\n formError,\n summary.listed.length > 0,\n );\n const termsError = errorFor('terms');\n const termsDescribedBy =\n [\n termsDescription ? termsDescriptionId : undefined,\n termsError ? termsErrorId : undefined,\n ]\n .filter(Boolean)\n .join(' ') || undefined;\n\n // The host's extra hidden inputs. The form's own fields keep their\n // names: an extra one that asks for the same name is left out.\n const ownNames = new Set(Object.values(fieldNames ?? {}));\n const extraFields = native ? Object.entries(hiddenFields ?? {}) : [];\n const clashes = extraFields\n .filter(([extraName]) => ownNames.has(extraName))\n .map(([extraName]) => extraName)\n .join(', ');\n useEffect(() => {\n if (clashes && isDevelopment()) {\n console.warn(\n `RegistrationForm: hiddenFields \"${clashes}\" is also named in fieldNames and was left out. The form's own field wins.`,\n );\n }\n }, [clashes]);\n\n // Read-only once the code is right, like a locked address.\n const emailReadOnlyNow = emailLocked || emailVerified;\n const emailInput = (\n <EmailInput\n ref={emailField.ref}\n name={name('email')}\n errorMessage={null}\n disableBuiltInValidation={emailReadOnlyNow}\n readOnly={emailReadOnlyNow}\n onChange={emailField.quiet((event) => set('email', event.target.value))}\n onBlur={() => leave('email')}\n {...clipboard('email')}\n />\n );\n const phoneInput = (\n <PhoneInput\n ref={control.phone}\n name={native ? undefined : 'phone'}\n value={values.phone}\n readOnly={phoneVerified}\n onChange={(e164, meta) => {\n set('phone', e164);\n setPhonePossible(meta.isPossible);\n }}\n />\n );\n\n const renderField = (field: GridField): ReactNode => {\n switch (field) {\n case 'firstName':\n return (\n <FormField\n key={field}\n id={fieldId(field)}\n label={labels.firstName}\n required\n error={errorFor('firstName')}\n announceError={!summary.lists('firstName')}\n data-field=\"firstName\"\n >\n <StateBackedTextInput\n ref={control.firstName}\n name={name('firstName')}\n autoComplete=\"given-name\"\n value={values.firstName}\n onChange={(event) => set('firstName', event.target.value)}\n onBlur={() => leave('firstName')}\n {...clipboard('firstName')}\n />\n </FormField>\n );\n case 'lastName':\n return (\n <FormField\n key={field}\n id={fieldId(field)}\n label={labels.lastName}\n required\n error={errorFor('lastName')}\n announceError={!summary.lists('lastName')}\n data-field=\"lastName\"\n >\n <StateBackedTextInput\n ref={control.lastName}\n name={name('lastName')}\n autoComplete=\"family-name\"\n value={values.lastName}\n onChange={(event) => set('lastName', event.target.value)}\n onBlur={() => leave('lastName')}\n {...clipboard('lastName')}\n />\n </FormField>\n );\n case 'email':\n return (\n <FormField\n key={field}\n id={fieldId(field)}\n label={labels.email}\n required={!emailLocked}\n description={emailDescription}\n error={errorFor('email')}\n errorAction={existingActions}\n announceError={!summary.lists('email')}\n data-field=\"email\"\n data-verification={verificationStep(emailVerification)}\n >\n {/* EmailInput still checks the format and marks the input.\n Its message goes through FormField, so there is one\n message, in one place. Read-only, not disabled: the\n address is still posted and still read out. */}\n {emailVerification.enabled ? (\n <div className=\"ds:@container/verify ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n <div className=\"ds:flex ds:flex-col ds:items-start ds:gap-[var(--spacing-sm)] ds:@[384px]/verify:flex-row\">\n <div className=\"ds:min-w-0 ds:w-full ds:@[384px]/verify:w-auto ds:@[384px]/verify:flex-1\">\n {emailInput}\n </div>\n <VerificationAction\n state={emailVerification}\n canSend={isEmail(values.email)}\n />\n </div>\n <VerificationPanel\n field=\"email\"\n state={emailVerification}\n canChange={!emailLocked}\n onVerified={() => controls.current.email?.focus()}\n />\n </div>\n ) : (\n emailInput\n )}\n </FormField>\n );\n case 'emailConfirm':\n if (changeSlot) {\n return (\n <VerificationChangeSlot\n key={field}\n field=\"email\"\n state={emailVerification}\n onUnlocked={() => {\n set('emailConfirm', '');\n controls.current.email?.focus();\n }}\n />\n );\n }\n return (\n <FormField\n key={field}\n id={fieldId(field)}\n label={labels.emailConfirm}\n required\n error={errorFor('emailConfirm')}\n announceError={!summary.lists('emailConfirm')}\n data-field=\"emailConfirm\"\n >\n <EmailInput\n ref={emailConfirmField.ref}\n name={name('emailConfirm')}\n disableBuiltInValidation\n onChange={emailConfirmField.quiet((event) =>\n set('emailConfirm', event.target.value),\n )}\n onBlur={() => {\n leave('emailConfirm');\n emailMatch.confirmProps.onBlur();\n }}\n {...clipboard('emailConfirm')}\n />\n </FormField>\n );\n case 'password':\n return (\n <FormField\n key={field}\n id={fieldId(field)}\n label={labels.password}\n required\n error={errorFor('password')}\n announceError={!summary.lists('password')}\n data-field=\"password\"\n >\n {/* PasswordInput names itself \"password\" when given no\n name; an empty one keeps a field out of the post. */}\n <PasswordInput\n ref={control.password}\n name={name('password') ?? ''}\n autoComplete=\"new-password\"\n requirements={requirements}\n value={values.password}\n onChange={(event) => set('password', event.target.value)}\n onBlur={() => leave('password')}\n {...clipboard('password')}\n />\n </FormField>\n );\n case 'passwordConfirm':\n return (\n <FormField\n key={field}\n id={fieldId(field)}\n label={labels.passwordConfirm}\n required\n error={errorFor('passwordConfirm')}\n announceError={!summary.lists('passwordConfirm')}\n data-field=\"passwordConfirm\"\n >\n <PasswordInput\n ref={control.passwordConfirm}\n name={name('passwordConfirm') ?? ''}\n autoComplete=\"new-password\"\n value={values.passwordConfirm}\n onChange={(event) => set('passwordConfirm', event.target.value)}\n onBlur={() => {\n leave('passwordConfirm');\n passwordMatch.confirmProps.onBlur();\n }}\n {...clipboard('passwordConfirm')}\n />\n </FormField>\n );\n case 'phone':\n return (\n <FormField\n key={field}\n id={fieldId(field)}\n label={labels.phone}\n required\n error={errorFor('phone')}\n announceError={!summary.lists('phone')}\n data-field=\"phone\"\n data-verification={verificationStep(phoneVerification)}\n >\n {/* The visible input holds the number as typed. In a native\n post a hidden input carries the full international\n number instead. */}\n {phoneVerification.enabled ? (\n <div className=\"ds:@container/verify ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n <div className=\"ds:flex ds:flex-col ds:items-start ds:gap-[var(--spacing-sm)] ds:@[384px]/verify:flex-row\">\n <div className=\"ds:min-w-0 ds:w-full ds:@[384px]/verify:w-auto ds:@[384px]/verify:flex-1\">\n {phoneInput}\n </div>\n <VerificationAction\n state={phoneVerification}\n canSend={values.phone !== '' && phonePossible}\n />\n </div>\n <VerificationPanel\n field=\"phone\"\n state={phoneVerification}\n changeWhenVerified\n onUnlocked={() => controls.current.phone?.focus()}\n onVerified={() => controls.current.phone?.focus()}\n />\n </div>\n ) : (\n phoneInput\n )}\n </FormField>\n );\n case 'branch':\n return (\n <FormField\n key={field}\n id={fieldId(field)}\n label={labels.branch}\n required\n error={errorFor('branch')}\n announceError={!summary.lists('branch')}\n data-field=\"branch\"\n >\n <Select\n ref={control.branch}\n name={name('branch')}\n options={branches ?? []}\n value={values.branch}\n onValueChange={(value) => set('branch', value)}\n />\n </FormField>\n );\n }\n };\n\n return (\n <div\n ref={ref}\n {...rest}\n data-component=\"registration-form\"\n className={registrationFormVariants({ className })}\n >\n <Card variant=\"elevated\">\n <Card.Body className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-lg)]\">\n <div className={headerVariants({ logo: showLogo })}>\n <div className={headingBlockVariants({ centred: showLogo })}>\n {/* The page's logo: read out once, before the heading. */}\n {showLogo && (\n <BrandMark motion={logoMotion} label={BRAND_NAME} />\n )}\n <Heading id={titleId} className=\"type-title-card\">\n {title ?? t('registrationForm.title')}\n </Heading>\n {description && (\n <p className=\"type-body-sm ds:text-[var(--muted-foreground)]\">\n {description}\n </p>\n )}\n </div>\n {devBypass && (devBypass.values || devBypass.onClick) && (\n <div className={shortcutVariants({ corner: showLogo })}>\n <DevBypassButton\n label={devBypass.label}\n onClick={runDevBypass}\n />\n </div>\n )}\n </div>\n\n {hasHostContent ? (\n <div\n data-slot=\"host-content\"\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\"\n >\n {notice ? (\n <Alert variant=\"info\" announce=\"off\">\n <Alert.Description>{notice}</Alert.Description>\n </Alert>\n ) : null}\n {benefitLines.length > 0 ? (\n <List density=\"compact\">\n {benefitLines.map((benefit, index) => (\n <List.Item\n key={`${index}-${benefit}`}\n leading={<Check aria-hidden=\"true\" />}\n title={benefit}\n />\n ))}\n </List>\n ) : null}\n {children}\n </div>\n ) : null}\n\n {/* Always POST, in both modes: should the script ever fail to\n run, the browser must not put a password in the address. */}\n <form\n ref={form}\n noValidate\n method=\"post\"\n action={formAction}\n aria-labelledby={titleId}\n aria-busy={busy || undefined}\n onSubmit={submit.handleSubmit}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\"\n >\n <ErrorSummary\n ref={summary.ref}\n headingLevel={(headingLevel + 1) as 2 | 3 | 4}\n // The message about the whole form is read with it.\n aria-describedby={formError ? formMessageId : undefined}\n errors={summary.listed.map((field) => {\n const message = errorFor(field) ?? '';\n return {\n field,\n message,\n // \"This field is required.\" does not say which field:\n // the summary names it.\n label:\n message === required && field !== 'terms'\n ? labels[field]\n : undefined,\n targetId: fieldId(field),\n };\n })}\n />\n\n {formError && (\n <Alert\n ref={formMessage}\n id={formMessageId}\n variant=\"error\"\n announce={formMessageAnnounce}\n tabIndex={-1}\n data-field=\"form\"\n className={formMessageVariants()}\n >\n <Alert.Description>{formError}</Alert.Description>\n </Alert>\n )}\n\n {layOutRows((field) =>\n field === 'emailConfirm'\n ? shows(field) || changeSlot\n : shows(field),\n ).map((row) => (\n <div\n key={row[0]}\n className={rowVariants({\n columns: row.length === 2 ? 'two' : 'one',\n })}\n >\n {row.map(renderField)}\n </div>\n ))}\n {native && showsPhone && fieldNames.phone && (\n <input\n type=\"hidden\"\n name={fieldNames.phone}\n value={values.phone}\n />\n )}\n {native && fieldNames.captcha && (\n <input\n ref={captchaInput}\n type=\"hidden\"\n name={fieldNames.captcha}\n defaultValue=\"\"\n />\n )}\n {extraFields\n .filter(([extraName]) => !ownNames.has(extraName))\n .map(([extraName, value]) => (\n <input\n key={extraName}\n type=\"hidden\"\n name={extraName}\n value={value}\n />\n ))}\n\n {shows('terms') && (\n <div\n id={fieldId('terms')}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\"\n data-field=\"terms\"\n >\n {termsDescription && (\n <p\n id={termsDescriptionId}\n className=\"type-body-sm ds:text-[var(--muted-foreground)]\"\n >\n {termsDescription}\n </p>\n )}\n <Checkbox\n ref={control.terms}\n name={name('terms')}\n value=\"1\"\n checked={values.terms}\n onCheckedChange={(next) => set('terms', next === true)}\n aria-required=\"true\"\n aria-invalid={termsError ? true : undefined}\n aria-describedby={termsDescribedBy}\n label={\n <>\n {termsLabel ?? (\n <Trans\n i18n={i18n}\n ns=\"ui\"\n i18nKey=\"registrationForm.terms\"\n components={{\n terms: termsLink ? (\n <InlineLink href={termsLink} newTab />\n ) : (\n <PlainText />\n ),\n privacy: privacyLink ? (\n <InlineLink href={privacyLink} newTab />\n ) : (\n <PlainText />\n ),\n }}\n />\n )}\n <span\n aria-hidden=\"true\"\n className={requiredMarkVariants()}\n >\n *\n </span>\n </>\n }\n />\n {termsError && (\n <p\n id={termsErrorId}\n // Quiet while the summary lists it: the summary reads it.\n role={summary.lists('terms') ? undefined : 'alert'}\n data-slot=\"error\"\n className=\"ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)] type-body-sm ds:text-destructive\"\n >\n <CircleAlert\n aria-hidden=\"true\"\n className=\"ds:size-4 ds:shrink-0\"\n />\n <span>{termsError}</span>\n </p>\n )}\n </div>\n )}\n\n <Button\n type=\"submit\"\n intent=\"primary\"\n size=\"lg\"\n loading={busy}\n className=\"ds:w-full\"\n data-action=\"submit\"\n // Not native `disabled`: a press still lists what is\n // missing in the summary and moves focus to it.\n aria-disabled={emailNeedsCode || phoneNeedsCode || undefined}\n >\n {submitLabel ?? t('registrationForm.submit')}\n </Button>\n {/* The spinner is decorative and the button is only\n marked unavailable while busy, so say it in words. Always mounted: a live\n region announces a change, not its first content. */}\n <p role=\"status\" className=\"ds:sr-only\">\n {busy ? t('chat.message.status.sending') : ''}\n </p>\n\n {loginLink && !existingNow && (\n <p className=\"type-body-sm ds:text-center ds:text-[var(--muted-foreground)]\">\n <Trans\n i18n={i18n}\n ns=\"ui\"\n i18nKey=\"registrationForm.login\"\n components={{\n login: (\n <InlineLink\n href={loginLink}\n weight=\"strong\"\n action=\"login\"\n />\n ),\n }}\n />\n </p>\n )}\n\n {/* Last, so its badge comes after the button and the login\n link in the tab order. Out of the flow: it takes no\n space, so it must not take a gap either. The card says\n when the check fails, so the widget stays quiet. */}\n {recaptchaSiteKey && (\n <div className=\"ds:absolute\">\n <RecaptchaWidget\n ref={submit.captcha.ref}\n siteKey={recaptchaSiteKey}\n size=\"invisible\"\n announceStatus={false}\n onChange={submit.captcha.onChange}\n onError={submit.captcha.onError}\n />\n </div>\n )}\n </form>\n </Card.Body>\n </Card>\n </div>\n );\n },\n);\nRegistrationForm.displayName = 'RegistrationForm';\n"],"names":["FAILURES","FAILED","positiveNumber","input","toResult","body","raw","result","retry","resend","retryAfterHeader","response","header","postVerification","url","payload","isSameSiteHref","isDevelopment","limited","base","verificationHandlers","config","sendUrl","verifyUrl","value","code","DEFAULT_CODE_LENGTH","DEFAULT_RESEND_SECONDS","failureOf","useContactVerification","codeLength","status","setStatus","useState","setCodeState","failure","setFailure","cooldown","setCooldown","devCode","setDevCode","sentTo","setSentTo","latest","useRef","request","original","unlocked","setUnlocked","verifiedByHost","verified","told","useEffect","_b","_a","timer","left","sameValue","a","b","reset","useCallback","current","lastValue","send","target","id","verify","typed","length","entered","changeable","unlock","setCode","next","useFailureMessage","t","useTranslation","useSendFailureMessage","state","message","VerificationAction","canSend","sending","waiting","jsx","Button","VerificationPanel","field","canChange","changeWhenVerified","onUnlocked","onVerified","panel","open","verifying","complete","focusFirstBox","previous","lastFailure","before","announcement","setAnnouncement","wasWaiting","isEmail","sentText","changeText","verifiedText","jsxs","CircleCheck","Pencil","Fragment","Alert","FormField","OTPInput","VerificationChangeSlot","REGISTRATION_FORM_FIELDS","registrationFormVariants","cva","rowVariants","headerVariants","headingBlockVariants","shortcutVariants","inlineLinkVariants","formMessageVariants","requiredMarkVariants","DEFAULT_PASSWORD_POLICY","BRAND_NAME","MARKED","OTHER_TAGS","linkTo","href","isSafeHref","hasMessage","errors","isPossiblePhone","e164","parsePhoneNumberFromString","InlineLink","newTab","weight","action","children","PlainText","verificationStep","FIELD_PAIRS","layOutRows","shows","rows","pair","row","last","RegistrationForm","forwardRef","title","description","headingLevel","showLogo","logoMotion","fields","initialValues","emailReadOnly","emailDescription","blockPaste","blockCopy","branches","passwordPolicy","termsHref","privacyHref","termsLabelNode","termsDescriptionNode","termsLabelText","termsDescriptionText","notice","benefits","loginHref","existingAccount","recaptchaSiteKey","submitLabel","submitting","devBypass","onSubmit","fieldNames","hiddenFields","verification","requireVerification","className","rest","ref","i18n","titleId","useId","fieldIdBase","fieldId","termsErrorId","termsDescriptionId","formMessageId","native","hasBranches","hadEmail","emailLocked","emailVerified","values","setValues","phonePossible","setPhonePossible","touched","setTouched","submitted","setSubmitted","serverErrors","setServerErrors","emailVerification","phoneVerification","phoneVerified","shown","changeSlot","emailNeedsCode","phoneNeedsCode","emailSendFailure","phoneSendFailure","set","leave","emptyPasswords","clipboard","requirements","usePasswordRequirements","emailMatch","useFieldMatch","passwordMatch","invalid","rule","due","required","labels","whenDue","ownErrors","sendFailures","openedEmail","existingNow","existingSignIn","existingReset","existingMessage","errorFor","controls","control","useMemo","bind","node","emailField","useStateBackedInput","emailConfirmField","formMessage","focusTargetFor","messages","openedWithFieldMessage","summary","useErrorSummary","focusRequest","setFocusRequest","showsPhone","onBlur","form","captchaInput","submitRequest","setSubmitRequest","runDevBypass","filled","email","kept","submit","useRegistrationSubmit","captchaToken","text","answer","busy","captchaFailed","name","Heading","termsLink","privacyLink","loginLink","existingActions","LogIn","KeyRound","marked","parts","part","index","tag","words","termsLabel","termsDescription","benefitLines","hasHostContent","formAction","formError","formMessageAnnounce","useFormMessageAnnounce","termsError","termsDescribedBy","ownNames","extraFields","clashes","extraName","emailReadOnlyNow","emailInput","EmailInput","event","phoneInput","PhoneInput","meta","renderField","StateBackedTextInput","PasswordInput","Select","Card","BrandMark","DevBypassButton","List","benefit","Check","ErrorSummary","Checkbox","Trans","CircleAlert","RecaptchaWidget"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"slot-grid-b4eZXokb.js","sources":["../../src/components/slot-grid/slot-grid.agent.ts","../../src/components/slot-grid/slot-grid.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — SlotGrid. */\n/* */\n/* Multi-day time-slot picker. Selection stays fully CONTROLLED by the */\n/* consumer (`selectedSlotId` + `onSlotSelect`) — the adapter never */\n/* stores a choice, it reports the committed prop and fires the same */\n/* callback a native click would (the `combobox.set_value` contract). */\n/* */\n/* Two channels reach the same component: */\n/* • the registry — `SlotGridHandle` resolved by (`slot-grid`, id), */\n/* which is the ONLY channel the MCP bridge has (PRS §26 §8.1); */\n/* • the DOM — `data-slot-id` on every rendered slot button, for */\n/* DOM-driving tools (browser extension / computer use) that never */\n/* touch the registry. */\n/* */\n/* PHI (§6.1 / §7): a slot id is an AVAILABILITY identifier and a day */\n/* key is a calendar date. SlotGrid is never handed a patient — its */\n/* inputs are `{ id, start, end?, available?, label? }` plus */\n/* `Intl`-formatted time strings — so no state slot can leak PHI. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { SlotGridHandle } from './slot-grid';\n\nexport const slotGridAgent: AgentAdapter<SlotGridHandle> = {\n id: 'slot-grid',\n // pick → `select_slot` + the `selectedSlotId` state slot.\n // range_navigate → `next_days` / `previous_days` + `hasNext` / `hasPrevious`.\n // expand → `show_more_day` + the `expandedDays` state slot.\n //\n // Host-delegated, deliberately WITHOUT an action: the optional\n // \"Next available\" CTA (`showNextAvailable` + `onJumpToNextAvailable`)\n // stays a native click on the toolbar button. It is a consumer-owned\n // jump to a window the grid has not been given, so the agent reaches it\n // through the DOM, or by reading `slotsByDay` and paging with\n // `next_days` until availability appears.\n capabilities: ['pick', 'range_navigate', 'expand'],\n state: {\n status: {\n type: \"'default' | 'loading' | 'disabled' | 'empty'\",\n descriptionKey: 'ui.agent.slotGrid.state.status',\n description:\n 'Visual state of the grid. Read this before concluding \"no availability\" — `loading` means the window has not resolved yet.',\n read: (handle) => handle.getStatus(),\n },\n selectedSlotId: {\n type: 'string | null',\n descriptionKey: 'ui.agent.slotGrid.state.selectedSlotId',\n description:\n 'Id of the slot the consumer has committed as selected, or null. Reflects the controlled `selectedSlotId` prop, not an internal choice.',\n read: (handle) => handle.getSelectedSlotId(),\n },\n visibleDays: {\n type: 'string[]',\n descriptionKey: 'ui.agent.slotGrid.state.visibleDays',\n description:\n 'Calendar days currently rendered as columns, as `yyyy-MM-dd` keys in display order.',\n read: (handle) => handle.getVisibleDays(),\n },\n slotsByDay: {\n type: 'Record<string, string[]>',\n descriptionKey: 'ui.agent.slotGrid.state.slotsByDay',\n description:\n 'Map of day key (`yyyy-MM-dd`) to the ids of that day’s bookable slots. Ids only — never slot or patient objects. Includes slots still collapsed behind \"Show more\".',\n read: (handle) => handle.getSlotsByDay(),\n },\n expandedDays: {\n type: 'string[]',\n descriptionKey: 'ui.agent.slotGrid.state.expandedDays',\n description:\n 'Day keys whose \"Show more\" control has been used, so every slot for that day is rendered.',\n read: (handle) => handle.getExpandedDays(),\n },\n hasPrevious: {\n type: 'boolean',\n descriptionKey: 'ui.agent.slotGrid.state.hasPrevious',\n description:\n 'True when an earlier window of days exists — the \"previous days\" arrow is offered.',\n read: (handle) => handle.getHasPrevious(),\n },\n hasNext: {\n type: 'boolean',\n descriptionKey: 'ui.agent.slotGrid.state.hasNext',\n description:\n 'True when a later window of days exists — the \"next days\" arrow is offered.',\n read: (handle) => handle.getHasNext(),\n },\n },\n actions: {\n select_slot: {\n // Fires the consumer's `onSlotSelect`, exactly as a click on the slot\n // button does. Persistent in the consumer's booking draft, and\n // reversible by selecting another slot — `write`, not `phi`: a slot is\n // availability, not patient data.\n safety: 'write',\n argsType: '{ slotId: string }',\n argsSchema: {\n type: 'object',\n properties: {\n slotId: {\n type: 'string',\n description:\n 'Id of the slot to select. Must be one of the ids returned by the `slotsByDay` state slot.',\n },\n },\n required: ['slotId'],\n },\n idempotent: true,\n returns: 'boolean',\n returnsSchema: {\n type: 'boolean',\n description: 'True when the selection callback fired.',\n },\n errors: [\n 'Returns false when no slot with that id is in the visible window — page with next_days / previous_days first.',\n 'Returns false when the slot is unavailable, or the grid is loading or disabled.',\n ],\n descriptionKey: 'ui.agent.slotGrid.actions.selectSlot',\n description:\n 'Select an available slot by id. Emits the same selection the user would by clicking the slot button.',\n examples: [\n {\n args: { slotId: 'avail-2026-09-01-0930' },\n note: 'Book the 09:30 slot on 1 September.',\n },\n ],\n invoke: (handle, args: { slotId: string }) =>\n handle.selectSlot(args.slotId),\n },\n next_days: {\n // View-window paging only — the consumer fetches, nothing is persisted.\n safety: 'read',\n returns: 'boolean',\n returnsSchema: {\n type: 'boolean',\n description: 'True when the paging callback fired.',\n },\n errors: [\n 'Returns false when `hasNext` is false, or the grid is loading or disabled.',\n ],\n descriptionKey: 'ui.agent.slotGrid.actions.nextDays',\n description:\n 'Page the visible window forward to the next group of days, as the \"next days\" arrow does.',\n invoke: (handle) => handle.nextDays(),\n },\n previous_days: {\n safety: 'read',\n returns: 'boolean',\n returnsSchema: {\n type: 'boolean',\n description: 'True when the paging callback fired.',\n },\n errors: [\n 'Returns false when `hasPrevious` is false, or the grid is loading or disabled.',\n ],\n descriptionKey: 'ui.agent.slotGrid.actions.previousDays',\n description:\n 'Page the visible window back to the previous group of days, as the \"previous days\" arrow does.',\n invoke: (handle) => handle.previousDays(),\n },\n show_more_day: {\n // Reveals slots the grid already holds — ephemeral disclosure state.\n safety: 'read',\n argsType: '{ dayKey: string }',\n argsSchema: {\n type: 'object',\n properties: {\n dayKey: {\n type: 'string',\n pattern: '^\\\\d{4}-\\\\d{2}-\\\\d{2}$',\n description:\n 'Day to expand, as a `yyyy-MM-dd` key from the `visibleDays` state slot.',\n },\n },\n required: ['dayKey'],\n },\n idempotent: true,\n returns: 'boolean',\n returnsSchema: {\n type: 'boolean',\n description: 'True when the day was expanded.',\n },\n errors: [\n 'Returns false when the day key is not one of the visible columns, or the grid is loading or disabled.',\n ],\n descriptionKey: 'ui.agent.slotGrid.actions.showMoreDay',\n description:\n 'Render every slot for one day, as the day’s \"Show more\" button does. Only affects what is on screen — `slotsByDay` already lists collapsed slots.',\n examples: [\n {\n args: { dayKey: '2026-09-01' },\n note: 'Reveal the rest of 1 September so every slot button is clickable.',\n },\n ],\n invoke: (handle, args: { dayKey: string }) =>\n handle.showMoreDay(args.dayKey),\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'slot-grid',\n description:\n 'Marks the SlotGrid region. Emits `data-state` reflecting the public `state` prop (default / loading / disabled / empty).',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description:\n 'Sourced from the `id` prop. Also the registry key — without an `id` the instance does not register, so the handle-driven actions are unreachable and only the DOM channel works.',\n },\n item: {\n attr: 'data-slot-id',\n sourceProp: 'days[].slots[].id',\n description:\n 'Per-slot button identifier sourced from each `SlotGridSlot.id` — an availability id, never a patient id. DOM-driving agents activate a slot via native click on the matching button.',\n },\n },\n};\n","/* ------------------------------------------------------------------ */\n/* SlotGrid — multi-day time-slot picker for patient booking. */\n/* */\n/* Renders N day columns side-by-side. Each column shows a day header */\n/* (formatted via `Intl.DateTimeFormat(locale)`) plus a vertical list */\n/* of slot buttons. Long days collapse to `maxInitialSlotsPerDay` and */\n/* reveal the rest via a \"Show more\" button (progressive disclosure). */\n/* */\n/* Navigation arrows (`onPreviousDays` / `onNextDays`) let the consumer */\n/* page the window of days; the optional \"Next available\" CTA jumps to */\n/* the first day with an open slot. */\n/* */\n/* Purely presentational — no business logic, no data fetching. Date */\n/* comparisons use `date-fns` (never moment.js) and the rendered labels */\n/* come exclusively from `Intl.DateTimeFormat` or the `ui.slotGrid` */\n/* namespace via `useTranslation('ui')`. */\n/* */\n/* Agent surface: `ref` is the outer <div>; a separate `SlotGridHandle` */\n/* (built with `useMemo`, registered via `useAgentRegistration`) gives */\n/* the MCP bridge a read-only view of the visible days + available slot */\n/* ids and the four interactions the UI itself offers. See */\n/* `slot-grid.agent.ts` and PRS §26. */\n/* ------------------------------------------------------------------ */\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type HTMLAttributes,\n type KeyboardEvent,\n type ReactNode,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { format, isSameDay, parseISO } from 'date-fns';\nimport { Button } from '../button/button';\nimport { IconButton } from '../button/icon-button';\nimport { EmptyState } from '../empty-state/empty-state';\nimport { Skeleton } from '../skeleton/skeleton';\nimport { useAgentRegistration } from '../../agent';\nimport { slotGridAgent } from './slot-grid.agent';\n\n/* ------------------------------------------------------------------ */\n/* Public types */\n/* ------------------------------------------------------------------ */\n\nexport type SlotGridState = 'default' | 'loading' | 'disabled' | 'empty';\n\nexport type SlotGridSize = 'sm' | 'md' | 'lg';\n\nexport interface SlotGridSlot {\n /** Stable identity — used by consumers to resolve selection. */\n id: string;\n /** Slot start — ISO string or `Date`. Rendered via `Intl.DateTimeFormat`. */\n start: string | Date;\n /** Optional slot end — if omitted only the start time is announced. */\n end?: string | Date;\n /** Defaults to `true`. Unavailable slots render disabled and are not focusable. */\n available?: boolean;\n /** Override the default `Intl`-formatted time label. */\n label?: string;\n /** Override the accessible name of the slot button. */\n ariaLabel?: string;\n}\n\nexport interface SlotGridDay {\n /** The calendar day the column represents. */\n date: string | Date;\n /** Slots for this day, in chronological order. Empty array ⇒ empty day. */\n slots: SlotGridSlot[];\n /** Override the default `Intl`-formatted day header. */\n label?: string;\n}\n\nexport interface SlotGridProps\n extends\n Omit<HTMLAttributes<HTMLDivElement>, 'aria-label' | 'onSelect'>,\n VariantProps<typeof slotGridVariants> {\n /** Days to render, one column per entry. */\n days: SlotGridDay[];\n /** Visual / interactive state. Defaults to `'default'`. */\n state?: SlotGridState;\n /** Localised guidance below the empty title, for an empty day or range. */\n emptyDescription?: string;\n /** Density of the slot buttons and day headers. Defaults to `'md'`. */\n size?: SlotGridSize;\n /** Id of the currently selected slot (controlled). */\n selectedSlotId?: string;\n /**\n * Initial number of slots to render per day before the \"Show more\"\n * progressive-disclosure control collapses the rest. Defaults to `6`.\n */\n maxInitialSlotsPerDay?: number;\n /**\n * BCP-47 locale tag for `Intl.DateTimeFormat`. Defaults to the active\n * i18next language.\n */\n locale?: string;\n /** IANA time zone for `Intl.DateTimeFormat`. Optional. */\n timeZone?: string;\n /** Whether the \"previous days\" navigation arrow should be enabled. */\n hasPrevious?: boolean;\n /** Whether the \"next days\" navigation arrow should be enabled. */\n hasNext?: boolean;\n /**\n * When `true`, renders the \"Next available\" CTA at the end of the\n * toolbar. Only emits a callback — the consumer owns the navigation.\n */\n showNextAvailable?: boolean;\n /** Accessible label for the outer grid region. */\n ariaLabel?: string;\n /** Fires when the user selects an available slot. */\n onSlotSelect?: (slot: SlotGridSlot, day: SlotGridDay) => void;\n /** Fires when the user clicks the \"previous days\" arrow. */\n onPreviousDays?: () => void;\n /** Fires when the user clicks the \"next days\" arrow. */\n onNextDays?: () => void;\n /** Fires when the user clicks a day's \"Show more\" button. */\n onShowMore?: (day: SlotGridDay) => void;\n /** Fires when the user clicks the \"Next available\" CTA. */\n onJumpToNextAvailable?: () => void;\n}\n\n/**\n * Imperative handle the agent adapter (`slot-grid.agent.ts`) reads and drives.\n *\n * It is NOT the `ref` — `ref` stays the outer `HTMLDivElement` so existing\n * consumers are unaffected. The handle is built with `useMemo` and handed to\n * `useAgentRegistration`, the same shape Autocomplete uses.\n *\n * Every getter returns identifiers and structural state only — availability\n * slot ids, calendar day keys, booleans. Never patient data (PRS §26 §7).\n */\nexport interface SlotGridHandle {\n /** Current visual / interactive state (`default` / `loading` / `disabled` / `empty`). */\n getStatus: () => SlotGridState;\n /** Controlled `selectedSlotId` prop, or `null` when nothing is selected. */\n getSelectedSlotId: () => string | null;\n /** Day keys (`yyyy-MM-dd`) of the currently-rendered columns, in order. */\n getVisibleDays: () => string[];\n /** Day key → ids of that day's AVAILABLE slots (collapsed ones included). */\n getSlotsByDay: () => Record<string, string[]>;\n /** Day keys whose \"Show more\" control has been used. */\n getExpandedDays: () => string[];\n /** Mirrors the `hasPrevious` prop — whether an earlier window exists. */\n getHasPrevious: () => boolean;\n /** Mirrors the `hasNext` prop — whether a later window exists. */\n getHasNext: () => boolean;\n /** Select an available slot by id. Returns `false` when it cannot be selected. */\n selectSlot: (slotId: string) => boolean;\n /** Page the window forward. Returns `false` when the arrow would be disabled. */\n nextDays: () => boolean;\n /** Page the window back. Returns `false` when the arrow would be disabled. */\n previousDays: () => boolean;\n /** Reveal a day's collapsed slots. Returns `false` when the day is not visible. */\n showMoreDay: (dayKey: string) => boolean;\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst slotGridVariants = cva(\n [\n 'ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]',\n 'ds:text-[var(--foreground)]',\n 'ds:w-full',\n ].join(' '),\n {\n variants: {\n size: {\n sm: 'ds:text-[length:var(--font-size-sm)]',\n md: 'ds:text-[length:var(--font-size-base)]',\n lg: 'ds:text-[length:var(--font-size-lg)]',\n },\n },\n defaultVariants: { size: 'md' },\n },\n);\n\nconst toolbarVariants = cva(\n 'ds:flex ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)] ds:w-full',\n);\n\n/**\n * Column-count is dynamic (1–12), so it is declared as a full CVA variant —\n * this keeps every `grid-cols-N` string statically visible to Tailwind's\n * JIT and keeps the variant table inside CVA rather than hand-rolled.\n */\nconst COLS_MAX = 12;\n\nconst columnsVariants = cva(\n 'ds:grid ds:gap-[var(--spacing-sm)] ds:w-full ds:auto-rows-min ds:items-start',\n {\n variants: {\n cols: {\n 1: 'ds:grid-cols-1',\n 2: 'ds:grid-cols-2',\n 3: 'ds:grid-cols-3',\n 4: 'ds:grid-cols-4',\n 5: 'ds:grid-cols-5',\n 6: 'ds:grid-cols-6',\n 7: 'ds:grid-cols-7',\n 8: 'ds:grid-cols-8',\n 9: 'ds:grid-cols-9',\n 10: 'ds:grid-cols-10',\n 11: 'ds:grid-cols-11',\n 12: 'ds:grid-cols-12',\n },\n },\n defaultVariants: { cols: 1 },\n },\n);\n\ntype ColumnsCount = NonNullable<VariantProps<typeof columnsVariants>['cols']>;\n\nfunction clampCols(count: number): ColumnsCount {\n return Math.max(1, Math.min(count, COLS_MAX)) as ColumnsCount;\n}\n\nconst columnVariants = cva(\n [\n 'ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]',\n 'ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)]',\n 'ds:pt-[var(--spacing-sm)] ds:pb-[var(--spacing-sm)]',\n 'ds:rounded-[var(--radius-md)]',\n 'ds:bg-[var(--card)]',\n 'ds:min-w-0',\n ].join(' '),\n);\n\nconst dayHeaderVariants = cva(\n [\n 'ds:font-[var(--font-weight-semibold)]',\n 'ds:text-[var(--foreground)]',\n 'ds:text-start',\n 'ds:truncate',\n ].join(' '),\n {\n variants: {\n size: {\n sm: 'ds:text-[length:var(--font-size-xs)]',\n md: 'ds:text-[length:var(--font-size-sm)]',\n lg: 'ds:text-[length:var(--font-size-base)]',\n },\n },\n defaultVariants: { size: 'md' },\n },\n);\n\nconst slotListVariants = cva(\n 'ds:flex ds:flex-col ds:gap-[var(--spacing-xs)] ds:w-full ds:m-0 ds:p-0 ds:list-none',\n);\n\nconst slotButtonVariants = cva(\n [\n 'ds:inline-flex ds:items-center ds:justify-center',\n 'ds:w-full',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:font-[var(--font-weight-medium)]',\n 'ds:bg-[var(--secondary)]',\n 'ds:shadow-[var(--shadow-sm)]',\n 'ds:text-[var(--foreground)]',\n 'ds:transition-[background-color,color,box-shadow]',\n 'ds:duration-[var(--animation-duration)]',\n 'ds:motion-reduce:transition-none',\n 'ds:focus-visible:outline-[var(--focus-ring-width)]',\n 'ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)]',\n 'ds:focus-visible:outline-offset-[var(--focus-ring-offset)]',\n 'ds:min-h-[var(--min-target-size)]',\n 'ds:disabled:opacity-50 ds:disabled:cursor-not-allowed ds:disabled:shadow-none',\n 'ds:aria-disabled:opacity-50 ds:aria-disabled:cursor-not-allowed ds:aria-disabled:shadow-none',\n 'ds:hover:enabled:shadow-[var(--shadow-md)]',\n 'ds:aria-pressed:bg-[var(--primary)] ds:aria-pressed:text-[var(--primary-foreground)]',\n ].join(' '),\n {\n variants: {\n size: {\n sm: 'ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)] ds:text-[length:var(--font-size-xs)] ds:h-8',\n md: 'ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)] ds:text-[length:var(--font-size-sm)] ds:h-10',\n lg: 'ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)] ds:text-[length:var(--font-size-base)] ds:h-12',\n },\n },\n defaultVariants: { size: 'md' },\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* Helpers */\n/* ------------------------------------------------------------------ */\n\nfunction toDate(value: string | Date): Date {\n return value instanceof Date ? value : parseISO(value);\n}\n\n/**\n * Internal identity for one rendered column. The index guards against a\n * consumer passing the same calendar date twice.\n */\nfunction columnKey(day: SlotGridDay, index: number): string {\n return `${toDate(day.date).toISOString()}-${index}`;\n}\n\n/**\n * Agent-facing key for one column — the local calendar date as `yyyy-MM-dd`.\n * Structural, locale-independent, and carries no patient data.\n */\nfunction dayKeyOf(day: SlotGridDay): string {\n return format(toDate(day.date), 'yyyy-MM-dd');\n}\n\n/** Is `a` the same calendar day as `b`? Uses `date-fns`, locale-agnostic. */\nexport function isSameDate(a: string | Date, b: string | Date): boolean {\n return isSameDay(toDate(a), toDate(b));\n}\n\n/** Find the first day in a list that has at least one available slot. */\nexport function findFirstAvailable(\n days: SlotGridDay[],\n): { day: SlotGridDay; slot: SlotGridSlot } | undefined {\n for (const day of days) {\n const slot = day.slots.find((s) => s.available !== false);\n if (slot) return { day, slot };\n }\n return undefined;\n}\n\nfunction formatDayHeader(\n date: Date,\n locale: string,\n timeZone?: string,\n): string {\n try {\n return new Intl.DateTimeFormat(locale, {\n weekday: 'short',\n month: 'short',\n day: 'numeric',\n timeZone,\n }).format(date);\n } catch {\n return new Intl.DateTimeFormat('en', {\n weekday: 'short',\n month: 'short',\n day: 'numeric',\n }).format(date);\n }\n}\n\nfunction formatSlotTime(\n slot: SlotGridSlot,\n locale: string,\n timeZone?: string,\n): string {\n if (slot.label !== undefined) return slot.label;\n const start = toDate(slot.start);\n try {\n const fmt = new Intl.DateTimeFormat(locale, {\n hour: 'numeric',\n minute: '2-digit',\n timeZone,\n });\n if (slot.end) {\n const end = toDate(slot.end);\n if (typeof fmt.formatRange === 'function') {\n try {\n return fmt.formatRange(start, end);\n } catch {\n /* fall through */\n }\n }\n return `${fmt.format(start)} – ${fmt.format(end)}`;\n }\n return fmt.format(start);\n } catch {\n return start.toISOString();\n }\n}\n\nfunction formatSlotAriaLabel(\n slot: SlotGridSlot,\n day: SlotGridDay,\n locale: string,\n timeZone: string | undefined,\n template: (opts: { time: string; day: string }) => string,\n): string {\n if (slot.ariaLabel !== undefined) return slot.ariaLabel;\n const time = formatSlotTime(slot, locale, timeZone);\n const dayLabel =\n day.label !== undefined\n ? day.label\n : formatDayHeader(toDate(day.date), locale, timeZone);\n return template({ time, day: dayLabel });\n}\n\n/* ------------------------------------------------------------------ */\n/* Glyphs — logical-direction arrows */\n/* ------------------------------------------------------------------ */\n\nfunction ChevronStartIcon() {\n return (\n <svg\n aria-hidden=\"true\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"ds:size-4\"\n >\n <path d=\"M15 18l-6-6 6-6\" />\n </svg>\n );\n}\n\nfunction ChevronEndIcon() {\n return (\n <svg\n aria-hidden=\"true\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"ds:size-4\"\n >\n <path d=\"M9 6l6 6-6 6\" />\n </svg>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\nexport const SlotGrid = forwardRef<HTMLDivElement, SlotGridProps>(\n (\n {\n days,\n state = 'default',\n emptyDescription,\n size = 'md',\n selectedSlotId,\n maxInitialSlotsPerDay = 6,\n locale: localeProp,\n timeZone,\n hasPrevious = false,\n hasNext = false,\n showNextAvailable = false,\n ariaLabel,\n onSlotSelect,\n onPreviousDays,\n onNextDays,\n onShowMore,\n onJumpToNextAvailable,\n className,\n id,\n ...rest\n },\n ref,\n ) => {\n const { t, i18n } = useTranslation('ui');\n const locale = localeProp ?? i18n.language ?? 'en';\n const idBase = useId();\n\n const [expanded, setExpanded] = useState<Record<string, boolean>>({});\n\n const isLoading = state === 'loading';\n const isDisabled = state === 'disabled';\n const isInteractionSuppressed = isLoading || isDisabled;\n const isEmpty =\n state === 'empty' ||\n days.length === 0 ||\n days.every((day) => day.slots.length === 0);\n\n const resolvedAriaLabel = ariaLabel ?? t('slotGrid.ariaLabel');\n\n const handleSlotClick = useCallback(\n (slot: SlotGridSlot, day: SlotGridDay) => {\n if (isInteractionSuppressed) return;\n if (slot.available === false) return;\n onSlotSelect?.(slot, day);\n },\n [isInteractionSuppressed, onSlotSelect],\n );\n\n const handleShowMore = useCallback(\n (day: SlotGridDay, key: string) => {\n setExpanded((prev) => ({ ...prev, [key]: true }));\n onShowMore?.(day);\n },\n [onShowMore],\n );\n\n const handleSlotKeyDown = useCallback(\n (\n event: KeyboardEvent<HTMLButtonElement>,\n slot: SlotGridSlot,\n day: SlotGridDay,\n ) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n handleSlotClick(slot, day);\n }\n },\n [handleSlotClick],\n );\n\n /* ---- Agent handle ---------------------------------------------- */\n /* `ref` stays the outer <div> (unchanged for consumers). The agent */\n /* handle is a separate, memo-stable object — the Autocomplete shape. */\n /* A snapshot ref mirrors props + internal state so the handle reads */\n /* fresh values without re-registering on every render. */\n\n const snapshot = {\n days,\n selectedSlotId,\n hasPrevious,\n hasNext,\n state,\n expanded,\n isInteractionSuppressed,\n onPreviousDays,\n onNextDays,\n handleSlotClick,\n handleShowMore,\n };\n const latest = useRef(snapshot);\n useEffect(() => {\n latest.current = snapshot;\n });\n\n const agentHandle = useMemo<SlotGridHandle>(\n () => ({\n getStatus: () => latest.current.state,\n getSelectedSlotId: () => latest.current.selectedSlotId ?? null,\n getVisibleDays: () => latest.current.days.map(dayKeyOf),\n getSlotsByDay: () => {\n // Ids only — never the slot objects (PRS §26 §7 / auditor A9).\n const byDay: Record<string, string[]> = {};\n for (const day of latest.current.days) {\n const key = dayKeyOf(day);\n const ids = day.slots\n .filter((slot) => slot.available !== false)\n .map((slot) => slot.id);\n byDay[key] = byDay[key] ? [...byDay[key], ...ids] : ids;\n }\n return byDay;\n },\n getExpandedDays: () =>\n latest.current.days\n .filter(\n (day, index) =>\n latest.current.expanded[columnKey(day, index)] === true,\n )\n .map(dayKeyOf),\n getHasPrevious: () => latest.current.hasPrevious,\n getHasNext: () => latest.current.hasNext,\n selectSlot: (slotId) => {\n const current = latest.current;\n if (current.isInteractionSuppressed) return false;\n for (const day of current.days) {\n const slot = day.slots.find((candidate) => candidate.id === slotId);\n if (!slot) continue;\n if (slot.available === false) return false;\n // Same code path as a native click on the slot button.\n current.handleSlotClick(slot, day);\n return true;\n }\n return false;\n },\n nextDays: () => {\n const current = latest.current;\n if (!current.hasNext || current.isInteractionSuppressed) return false;\n if (!current.onNextDays) return false;\n current.onNextDays();\n return true;\n },\n previousDays: () => {\n const current = latest.current;\n if (!current.hasPrevious || current.isInteractionSuppressed) {\n return false;\n }\n if (!current.onPreviousDays) return false;\n current.onPreviousDays();\n return true;\n },\n showMoreDay: (dayKey) => {\n const current = latest.current;\n if (current.isInteractionSuppressed) return false;\n const index = current.days.findIndex(\n (day) => dayKeyOf(day) === dayKey,\n );\n if (index < 0) return false;\n const day = current.days[index];\n current.handleShowMore(day, columnKey(day, index));\n return true;\n },\n }),\n [],\n );\n\n useAgentRegistration(slotGridAgent, agentHandle, id);\n\n const columnCount = clampCols(days.length || 1);\n const columnsClass = columnsVariants({ cols: columnCount });\n\n /* ---- Rendered content ------------------------------------------ */\n\n let body: ReactNode;\n if (isLoading) {\n body = (\n <div\n className={columnsClass}\n data-state=\"loading\"\n role=\"status\"\n aria-live=\"polite\"\n aria-label={t('common.loading')}\n >\n {Array.from({ length: columnCount }, (_, colIdx) => (\n <div key={`loading-col-${colIdx}`} className={columnVariants()}>\n <Skeleton variant=\"text\" size={size} width=\"60%\" />\n <div className={slotListVariants()}>\n {Array.from(\n { length: Math.min(maxInitialSlotsPerDay, 4) },\n (_, rowIdx) => (\n <Skeleton\n key={`loading-slot-${colIdx}-${rowIdx}`}\n variant=\"rounded\"\n size={size}\n height=\"40px\"\n />\n ),\n )}\n </div>\n </div>\n ))}\n </div>\n );\n } else if (isEmpty) {\n body = (\n <div data-state=\"empty\">\n <EmptyState\n variant=\"no-results\"\n title={t('slotGrid.noSlots')}\n description={emptyDescription}\n />\n </div>\n );\n } else {\n const hasEmptyDay = days.some((day) => day.slots.length === 0);\n body = (\n <>\n <div\n className={columnsClass}\n data-state={isDisabled ? 'disabled' : 'default'}\n >\n {days.map((day, dayIdx) => {\n const dayKey = columnKey(day, dayIdx);\n const headerLabel =\n day.label ??\n formatDayHeader(toDate(day.date), locale, timeZone);\n const headerId = `${idBase}-day-${dayIdx}-header`;\n const isExpanded = expanded[dayKey] ?? false;\n const visibleSlots = isExpanded\n ? day.slots\n : day.slots.slice(0, maxInitialSlotsPerDay);\n const hiddenCount = day.slots.length - visibleSlots.length;\n\n const isDayEmpty = day.slots.length === 0;\n\n return (\n // Use a plain <div role=\"group\"> rather than <section> — a\n // <section> with aria-labelledby is a landmark, and nesting many\n // landmarks inside the outer slot-grid landmark fails axe's\n // landmark-unique rule.\n <div\n key={dayKey}\n role=\"group\"\n className={columnVariants()}\n aria-labelledby={headerId}\n data-empty={isDayEmpty || undefined}\n >\n <h3 id={headerId} className={dayHeaderVariants({ size })}>\n {headerLabel}\n </h3>\n {isDayEmpty ? (\n <p className=\"type-body-sm ds:text-[var(--muted-foreground)] ds:m-0\">\n {t('slotGrid.noSlots')}\n </p>\n ) : null}\n <ul className={slotListVariants()}>\n {visibleSlots.map((slot) => {\n const ariaLabelSlot = formatSlotAriaLabel(\n slot,\n day,\n locale,\n timeZone,\n ({ time, day: dayLabel }) =>\n t('slotGrid.slotLabel', { time, day: dayLabel }),\n );\n const isSelected = selectedSlotId === slot.id;\n const isSlotDisabled =\n slot.available === false || isInteractionSuppressed;\n return (\n <li key={slot.id}>\n <button\n type=\"button\"\n className={slotButtonVariants({ size })}\n aria-label={ariaLabelSlot}\n aria-pressed={isSelected}\n disabled={isSlotDisabled}\n aria-disabled={isSlotDisabled || undefined}\n data-slot-id={slot.id}\n onClick={() => handleSlotClick(slot, day)}\n onKeyDown={(event) =>\n handleSlotKeyDown(event, slot, day)\n }\n >\n {formatSlotTime(slot, locale, timeZone)}\n </button>\n </li>\n );\n })}\n </ul>\n {hiddenCount > 0 ? (\n <Button\n intent=\"ghost\"\n size={size === 'lg' ? 'md' : 'sm'}\n onClick={() => handleShowMore(day, dayKey)}\n disabled={isInteractionSuppressed}\n >\n {t('slotGrid.showMore', { count: hiddenCount })}\n </Button>\n ) : null}\n </div>\n );\n })}\n </div>\n {/* One hint for every empty day, plain text after the day groups. */}\n {hasEmptyDay && emptyDescription ? (\n <p\n className=\"type-body-sm ds:text-[var(--muted-foreground)] ds:m-0 ds:text-start\"\n data-slot-grid-hint=\"\"\n >\n {emptyDescription}\n </p>\n ) : null}\n </>\n );\n }\n\n return (\n <div\n ref={ref}\n id={id}\n role=\"region\"\n aria-label={resolvedAriaLabel}\n className={slotGridVariants({ size, className })}\n data-component=\"slot-grid\"\n data-component-id={id}\n data-state={state}\n {...rest}\n >\n <div className={toolbarVariants()}>\n <IconButton\n icon={<ChevronStartIcon />}\n aria-label={t('slotGrid.previousDays')}\n className=\"ds:min-w-[var(--min-target-size)] ds:min-h-[var(--min-target-size)] ds:sm:min-h-[var(--min-target-size)]\"\n size={size === 'lg' ? 'md' : 'sm'}\n intent=\"ghost\"\n flipIconInRtl\n disabled={!hasPrevious || isInteractionSuppressed}\n onClick={onPreviousDays}\n />\n {showNextAvailable ? (\n <Button\n intent=\"secondary\"\n size={size === 'lg' ? 'md' : 'sm'}\n disabled={isInteractionSuppressed}\n onClick={onJumpToNextAvailable}\n >\n {t('slotGrid.nextAvailable')}\n </Button>\n ) : (\n <span aria-hidden=\"true\" />\n )}\n <IconButton\n icon={<ChevronEndIcon />}\n aria-label={t('slotGrid.nextDays')}\n className=\"ds:min-w-[var(--min-target-size)] ds:min-h-[var(--min-target-size)] ds:sm:min-h-[var(--min-target-size)]\"\n size={size === 'lg' ? 'md' : 'sm'}\n intent=\"ghost\"\n flipIconInRtl\n disabled={!hasNext || isInteractionSuppressed}\n onClick={onNextDays}\n />\n </div>\n\n {body}\n </div>\n );\n },\n);\n\nSlotGrid.displayName = 'SlotGrid';\n"],"names":["slotGridAgent","handle","args","slotGridVariants","cva","toolbarVariants","COLS_MAX","columnsVariants","clampCols","count","columnVariants","dayHeaderVariants","slotListVariants","slotButtonVariants","toDate","value","parseISO","columnKey","day","index","dayKeyOf","format","isSameDate","a","b","isSameDay","findFirstAvailable","days","slot","s","formatDayHeader","date","locale","timeZone","formatSlotTime","start","fmt","end","formatSlotAriaLabel","template","time","dayLabel","ChevronStartIcon","jsx","ChevronEndIcon","SlotGrid","forwardRef","state","emptyDescription","size","selectedSlotId","maxInitialSlotsPerDay","localeProp","hasPrevious","hasNext","showNextAvailable","ariaLabel","onSlotSelect","onPreviousDays","onNextDays","onShowMore","onJumpToNextAvailable","className","id","rest","ref","t","i18n","useTranslation","idBase","useId","expanded","setExpanded","useState","isLoading","isDisabled","isInteractionSuppressed","isEmpty","resolvedAriaLabel","handleSlotClick","useCallback","handleShowMore","key","prev","handleSlotKeyDown","event","snapshot","latest","useRef","useEffect","agentHandle","useMemo","byDay","ids","slotId","current","candidate","dayKey","useAgentRegistration","columnCount","columnsClass","body","_","colIdx","jsxs","Skeleton","rowIdx","EmptyState","hasEmptyDay","Fragment","dayIdx","headerLabel","headerId","visibleSlots","hiddenCount","isDayEmpty","ariaLabelSlot","isSelected","isSlotDisabled","Button","IconButton"],"mappings":"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"}
|