@alfadocs/ui-kit-debug 0.78.0 → 0.80.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/dist/_chunks/{alia-sidebar-w6B0TEx7.js → alia-sidebar-DzNz1gDf.js} +2 -2
- package/dist/_chunks/{alia-sidebar-w6B0TEx7.js.map → alia-sidebar-DzNz1gDf.js.map} +1 -1
- package/dist/_chunks/calendar-4dXTvsCz.js +1136 -0
- package/dist/_chunks/calendar-4dXTvsCz.js.map +1 -0
- package/dist/_chunks/calendar-event-card-C6qGtywL.js +257 -0
- package/dist/_chunks/calendar-event-card-C6qGtywL.js.map +1 -0
- package/dist/_chunks/{chat-input-BTCDqUDX.js → chat-input-QpHxBEnN.js} +32 -31
- package/dist/_chunks/chat-input-QpHxBEnN.js.map +1 -0
- package/dist/_chunks/{fiscal-code-input-DWA6C8x8.js → fiscal-code-input-QP9gkyDE.js} +2 -2
- package/dist/_chunks/fiscal-code-input-QP9gkyDE.js.map +1 -0
- package/dist/_chunks/{patient-details-zy76MRh7.js → patient-details-COvYWp2e.js} +2 -2
- package/dist/_chunks/{patient-details-zy76MRh7.js.map → patient-details-COvYWp2e.js.map} +1 -1
- package/dist/_chunks/signature-request-CEOrCDyk.js +341 -0
- package/dist/_chunks/signature-request-CEOrCDyk.js.map +1 -0
- package/dist/agent-catalog.json +1 -1
- package/dist/components/_shared/contrast-warning.d.ts +46 -0
- package/dist/components/_shared/contrast-warning.d.ts.map +1 -0
- package/dist/components/calendar/calendar.d.ts +284 -7
- package/dist/components/calendar/calendar.d.ts.map +1 -1
- package/dist/components/calendar/index.d.ts +1 -1
- package/dist/components/calendar/index.d.ts.map +1 -1
- package/dist/components/calendar/index.js +1 -1
- package/dist/components/calendar-event-card/calendar-event-card.d.ts +103 -0
- package/dist/components/calendar-event-card/calendar-event-card.d.ts.map +1 -0
- package/dist/components/calendar-event-card/index.d.ts +3 -0
- package/dist/components/calendar-event-card/index.d.ts.map +1 -0
- package/dist/components/calendar-event-card/index.js +5 -0
- package/dist/components/calendar-event-card/index.js.map +1 -0
- package/dist/components/chat-input/chat-input.d.ts.map +1 -1
- package/dist/components/chat-input/index.js +1 -1
- package/dist/components/fiscal-code-input/index.js +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/patient-details/index.js +1 -1
- package/dist/index.js +252 -250
- package/dist/index.js.map +1 -1
- package/dist/patterns/alia-assistant/index.js +1 -1
- package/dist/patterns/signature-request/index.js +1 -1
- package/dist/patterns/signature-request/signature-request.d.ts +7 -0
- package/dist/patterns/signature-request/signature-request.d.ts.map +1 -1
- package/dist/tokens.css +8 -5
- package/package.json +5 -1
- package/dist/_chunks/calendar-DeAlFPsF.js +0 -1050
- package/dist/_chunks/calendar-DeAlFPsF.js.map +0 -1
- package/dist/_chunks/chat-input-BTCDqUDX.js.map +0 -1
- package/dist/_chunks/fiscal-code-input-DWA6C8x8.js.map +0 -1
- package/dist/_chunks/signature-request-C-mskXwi.js +0 -318
- package/dist/_chunks/signature-request-C-mskXwi.js.map +0 -1
- package/dist/components/calendar/contrast-warning.d.ts +0 -20
- package/dist/components/calendar/contrast-warning.d.ts.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calendar-event-card-C6qGtywL.js","sources":["../../node_modules/lucide-react/dist/esm/icons/ban.mjs","../../node_modules/lucide-react/dist/esm/icons/euro.mjs","../../node_modules/lucide-react/dist/esm/icons/thumbs-up.mjs","../../node_modules/lucide-react/dist/esm/icons/zap.mjs","../../src/components/_shared/contrast-warning.ts","../../src/components/calendar-event-card/calendar-event-card.tsx"],"sourcesContent":["/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"path\", { d: \"M4.929 4.929 19.07 19.071\", key: \"196cmz\" }]\n];\nconst Ban = createLucideIcon(\"ban\", __iconNode);\n\nexport { __iconNode, Ban as default };\n//# sourceMappingURL=ban.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M4 10h12\", key: \"1y6xl8\" }],\n [\"path\", { d: \"M4 14h9\", key: \"1loblj\" }],\n [\n \"path\",\n {\n d: \"M19 6a7.7 7.7 0 0 0-5.2-2A7.9 7.9 0 0 0 6 12c0 4.4 3.5 8 7.8 8 2 0 3.8-.8 5.2-2\",\n key: \"1j6lzo\"\n }\n ]\n];\nconst Euro = createLucideIcon(\"euro\", __iconNode);\n\nexport { __iconNode, Euro as default };\n//# sourceMappingURL=euro.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z\",\n key: \"emmmcr\"\n }\n ],\n [\"path\", { d: \"M7 10v12\", key: \"1qc93n\" }]\n];\nconst ThumbsUp = createLucideIcon(\"thumbs-up\", __iconNode);\n\nexport { __iconNode, ThumbsUp as default };\n//# sourceMappingURL=thumbs-up.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z\",\n key: \"1xq2db\"\n }\n ]\n];\nconst Zap = createLucideIcon(\"zap\", __iconNode);\n\nexport { __iconNode, Zap as default };\n//# sourceMappingURL=zap.mjs.map\n","/* ------------------------------------------------------------------ */\n/* Shared contrast guardrail — Calendar + CalendarEventCard */\n/* */\n/* The consuming app supplies runtime hex pairs at several surfaces: */\n/* - event.backgroundColor / event.textColor (+ event.borderColor) */\n/* - modeBannerColor / modeBannerTextColor */\n/* - resource.color / resource.shortTitleTextColor */\n/* */\n/* When the text half of the pair is also a hex (i.e. both halves come */\n/* from the caller), we can validate them synchronously and warn the */\n/* consuming-app developer during DEV if the pair fails WCAG AA normal */\n/* text (4.5:1). When only the background half is supplied, */\n/* `resolveInk` derives a provably AA-safe black/white ink for it. */\n/* Every helper is a no-op in production builds. */\n/* ------------------------------------------------------------------ */\n\n/* Module-level dedup set — keyed on the (bg, fg, context) tuple so the\n same bad pair moving around the calendar only warns once per session.\n Exposed via `resetContrastWarnings()` for test isolation. */\nconst warnedTuples = new Set<string>();\n\n/** Reset the dedup set — intended for use between tests. */\nexport function resetContrastWarnings(): void {\n warnedTuples.clear();\n}\n\n/**\n * Parse a 3-char or 6-char `#RRGGBB` hex string into a linear sRGB\n * triple in the [0,1] range. Returns `null` for any input the caller\n * can't parse (malformed prefix, bad length, non-hex characters) —\n * the helper stays silent in that case rather than emitting noise.\n */\nfunction parseHex(hex: string): [number, number, number] | null {\n if (typeof hex !== 'string') return null;\n const trimmed = hex.trim();\n if (!trimmed.startsWith('#')) return null;\n const body = trimmed.slice(1);\n let r: number;\n let g: number;\n let b: number;\n if (body.length === 3) {\n if (!/^[0-9a-f]{3}$/i.test(body)) return null;\n r = parseInt(body[0] + body[0], 16);\n g = parseInt(body[1] + body[1], 16);\n b = parseInt(body[2] + body[2], 16);\n } else if (body.length === 6) {\n if (!/^[0-9a-f]{6}$/i.test(body)) return null;\n r = parseInt(body.slice(0, 2), 16);\n g = parseInt(body.slice(2, 4), 16);\n b = parseInt(body.slice(4, 6), 16);\n } else {\n return null;\n }\n return [r / 255, g / 255, b / 255];\n}\n\n/**\n * WCAG 2.1 relative luminance. Each channel is gamma-corrected then\n * weighted against the CIE photopic sensitivity of the human eye.\n * https://www.w3.org/TR/WCAG21/#dfn-relative-luminance\n */\nfunction relativeLuminance([r, g, b]: [number, number, number]): number {\n const lin = (c: number): number =>\n c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);\n return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);\n}\n\n/**\n * WCAG 2.1 contrast ratio. Always returns a value in [1, 21]; the\n * relative-luminance lighter-over-darker convention is applied here.\n */\nfunction contrastRatio(\n bg: [number, number, number],\n fg: [number, number, number],\n): number {\n const l1 = relativeLuminance(bg);\n const l2 = relativeLuminance(fg);\n const lighter = Math.max(l1, l2);\n const darker = Math.min(l1, l2);\n return (lighter + 0.05) / (darker + 0.05);\n}\n\n/**\n * DEV-only WCAG AA guardrail for caller-supplied hex pairs.\n *\n * - No-op when `import.meta.env.DEV` is false.\n * - No-op when either half of the pair is missing (the \"fg missing →\n * inherits DS token\" case is a docs concern; the DS token isn't a\n * hex at runtime so we can't check it here).\n * - No-op when either hex can't be parsed (silent — not the helper's\n * concern to police malformed input).\n * - Deduplicated by `(bgHex, fgHex, contextLabel)` tuple so moving a\n * ratio-bad event around the calendar doesn't spam the console.\n *\n * @param bgHex - Caller-supplied background hex (e.g. `'#c2185b'`)\n * @param fgHex - Caller-supplied foreground hex (e.g. `'#ffffff'`)\n * @param contextLabel - Short description for the warning (e.g. `'event e1'`).\n */\nexport function warnLowContrast(\n bgHex: string | undefined,\n fgHex: string | undefined,\n contextLabel: string,\n): void {\n if (!import.meta.env.DEV) return;\n if (!bgHex || !fgHex) return;\n\n const bg = parseHex(bgHex);\n const fg = parseHex(fgHex);\n if (!bg || !fg) return;\n\n const ratio = contrastRatio(bg, fg);\n if (ratio >= 4.5) return;\n\n const key = `${bgHex}|${fgHex}|${contextLabel}`;\n if (warnedTuples.has(key)) return;\n warnedTuples.add(key);\n\n /* `bg` parsed successfully above, so `resolveInk(bgHex)` is guaranteed\n to produce a compliant ink — the omit-textColor hint is always valid\n at this point. */\n console.warn(\n `[Calendar] Low contrast on ${contextLabel}: ${bgHex} / ${fgHex} (ratio ${ratio.toFixed(\n 2,\n )}, target 4.5). Pass a matching textColor/fgHex, pick a higher-contrast background, or omit textColor to let the kit choose a compliant ink.`,\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Ink derivation — bg-only caller colours */\n/* ------------------------------------------------------------------ */\n\nexport type EventInk = 'on-light' | 'on-dark';\n\n/**\n * Pick the ink for an arbitrary opaque bg hex. Returns `null` when the\n * input can't be parsed (`#rgb` / `#rrggbb` only).\n *\n * The threshold 0.1791 is the relative luminance at which\n * `contrast(bg, #fff) === contrast(bg, #000)`; the better of the two\n * always yields ≥ 4.58:1 (the minimum, at a mid-grey ≈ `#757575`) —\n * provably WCAG AA-safe for any opaque background.\n */\nexport function resolveInk(bgHex: string): EventInk | null {\n const bg = parseHex(bgHex);\n if (!bg) return null;\n // threshold where contrast(bg, #fff) === contrast(bg, #000)\n return relativeLuminance(bg) > 0.1791 ? 'on-light' : 'on-dark';\n}\n\n/**\n * DEV-only, one-shot warning for a caller `backgroundColor` the kit can't\n * parse (`rgb(…)`, keywords, malformed hex). The browser can still paint\n * it, but the text falls back to the token default and contrast can't be\n * verified. Deduplicated by `(bgHex, contextLabel)`.\n */\nexport function warnUnparseableBackground(\n bgHex: string,\n contextLabel: string,\n): void {\n if (!import.meta.env.DEV) return;\n if (parseHex(bgHex)) return;\n\n const key = `unparseable|${bgHex}|${contextLabel}`;\n if (warnedTuples.has(key)) return;\n warnedTuples.add(key);\n\n console.warn(\n `[Calendar] Unparseable backgroundColor on ${contextLabel}: \"${bgHex}\". ` +\n `Expected #rgb or #rrggbb — contrast cannot be verified and the text ` +\n `colour falls back to the token default.`,\n );\n}\n\n/**\n * DEV-only, one-shot warning for a near-white `backgroundColor`\n * (relative luminance > 0.9) supplied without a `borderColor` — the\n * event may be invisible against the calendar grid. The kit warns, it\n * does not repaint (delineation is decorative under WCAG 1.4.11 and the\n * consumer owns the picker colour). Deduplicated by `(bgHex, contextLabel)`.\n */\nexport function warnLowDelineation(bgHex: string, contextLabel: string): void {\n if (!import.meta.env.DEV) return;\n\n const bg = parseHex(bgHex);\n if (!bg) return;\n if (relativeLuminance(bg) <= 0.9) return;\n\n const key = `delineation|${bgHex}|${contextLabel}`;\n if (warnedTuples.has(key)) return;\n warnedTuples.add(key);\n\n console.warn(\n `[Calendar] Light backgroundColor without borderColor on ${contextLabel}: ` +\n `${bgHex} may be invisible against the grid — pass a borderColor ` +\n `(the platform convention sends a light-grey border for white backgrounds).`,\n );\n}\n","/* ------------------------------------------------------------------ */\n/* CalendarEventCard — the single painted surface of a calendar event. */\n/* */\n/* Colour model (platform parity): the caller's picker hex */\n/* (backgroundColor / textColor / borderColor) is the ONLY thing that */\n/* paints the card. `status` never paints the surface — it selects an */\n/* icon, an optional decorative accent bar, and (for `cancelled`) a */\n/* line-through. When no picker colour is supplied the surface falls */\n/* back to the theme's --primary / --primary-foreground pair. */\n/* */\n/* Non-interactive by design: inside FullCalendar the outer harness */\n/* anchor owns click/drag/focus; standalone consumers wrap the card in */\n/* their own button/link. No onClick in the contract. */\n/* ------------------------------------------------------------------ */\n\nimport { forwardRef } from 'react';\nimport type { CSSProperties, HTMLAttributes } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { cva } from 'class-variance-authority';\nimport {\n ThumbsUp,\n Clock,\n Stethoscope,\n Check,\n Ban,\n Zap,\n Globe,\n AlertTriangle,\n HeartPulse,\n Euro,\n Video,\n type LucideIcon,\n} from 'lucide-react';\n// Type-only import — erased at build, no runtime cycle with calendar.tsx's\n// runtime import of this card. Do NOT convert to a value import.\nimport type { CalendarEventStatus } from '../calendar/calendar';\nimport {\n warnLowContrast,\n resolveInk,\n warnUnparseableBackground,\n warnLowDelineation,\n} from '../_shared/contrast-warning';\n\n/* ------------------------------------------------------------------ */\n/* Status lookups */\n/* ------------------------------------------------------------------ */\n\nconst STATUS_ICON: Record<CalendarEventStatus, LucideIcon> = {\n confirmed: ThumbsUp,\n waiting: Clock,\n in_care: Stethoscope,\n done: Check,\n cancelled: Ban,\n absent: Zap,\n};\n\n/* Status → i18n key lookup. Kept as a literal object (not a template)\n so static-analysis extractors can find every key. Keys already exist\n in all 18 locale bundles — do not add new ones here. */\nconst STATUS_LABEL_KEYS: Record<CalendarEventStatus, string> = {\n confirmed: 'calendar.status.confirmed',\n waiting: 'calendar.status.waiting',\n in_care: 'calendar.status.inCare',\n done: 'calendar.status.done',\n cancelled: 'calendar.status.cancelled',\n absent: 'calendar.status.absent',\n};\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst calendarEventCardVariants = cva(\n [\n // layout — verbatim from the Calendar's former eventCardVariants base,\n // plus ds:relative for the accent bar's positioning context\n 'ds:relative ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]',\n 'ds:w-full ds:h-full',\n 'ds:ps-[var(--spacing-xs)] ds:pe-[var(--spacing-xs)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:text-[length:var(--font-size-sm)]',\n 'ds:font-[var(--font-weight-medium)]',\n 'ds:overflow-hidden',\n // kept verbatim from the former base (inert on a non-focusable div\n // inside FC; harmless)\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)]',\n 'ds:focus-visible:outline-[var(--ring)]',\n 'ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n // SINGLE PAINTED SURFACE — always present, never conditional. One\n // declaration per paint channel; value chain = \"caller custom prop,\n // else token\". This structurally eliminates the CVA-vs-override\n // specificity race (the old double-paint bug) — stylesheet order\n // becomes irrelevant.\n 'ds:[background-color:var(--calendar-event-bg,var(--primary))]',\n 'ds:[color:var(--calendar-event-text,var(--primary-foreground))]',\n 'ds:border ds:[border-color:var(--calendar-event-border,transparent)]',\n ].join(' '),\n {\n variants: {\n // Do not add colour classes to this axis — status is icon + accent\n // + aria only; a unit test asserts identical computed background\n // across all six statuses.\n status: {\n none: '',\n confirmed: '',\n waiting: '',\n in_care: '',\n done: '',\n cancelled: 'ds:line-through',\n absent: '',\n },\n bookedOnline: {\n // class name kept as a stable inert DOM hook; the stripe paint\n // lives here (moved from fullcalendar-theme.css) so it works in\n // the card's own stories, outside .fc-theme-alfadocs.\n // currentcolor = resolved ink, so stripes stay visible over any\n // picker colour.\n true: 'event-booked-online ds:bg-[image:repeating-linear-gradient(45deg,transparent,transparent_4px,color-mix(in_srgb,currentcolor_10%,transparent)_4px,color-mix(in_srgb,currentcolor_10%,transparent)_8px)]',\n false: '',\n },\n },\n defaultVariants: { status: 'none', bookedOnline: false },\n },\n);\n\n/* Status accent — a SEPARATE absolutely-positioned decorative element,\n not a border, so it can never collide with the caller's borderColor on\n the inline-start edge. The 3px width literal is the same\n decorative-geometry category as the former done-variant border-s-[3px]. */\nconst statusAccentVariants = cva(\n 'ds:absolute ds:inset-y-0 ds:start-0 ds:w-[3px]',\n {\n variants: {\n status: {\n confirmed: 'ds:[background-color:var(--success)]',\n waiting: 'ds:[background-color:var(--info)]',\n in_care: 'ds:[background-color:var(--primary)]',\n done: 'ds:[background-color:var(--success)]',\n cancelled: 'ds:[background-color:var(--destructive)]',\n absent: 'ds:[background-color:var(--warning)]',\n },\n },\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* Props */\n/* ------------------------------------------------------------------ */\n\n/**\n * The single painted surface of a calendar event.\n *\n * Colour model (platform parity): the caller's picker hex\n * (`backgroundColor` / `textColor` / `borderColor`) is the ONLY thing that\n * paints the card. `status` never paints the surface — it selects an icon,\n * an optional decorative accent bar, and (for `cancelled`) a line-through.\n *\n * Non-interactive by design: inside FullCalendar the outer harness anchor\n * owns click/drag/focus; standalone consumers wrap the card in their own\n * button/link. No onClick in the contract.\n */\nexport interface CalendarEventCardProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n 'title'\n> {\n /**\n * Primary line. Pass the ALREADY-MASKED title when privacy applies — the\n * card never receives a name it must not render, so it cannot leak it\n * (visually or via the composed aria-label).\n */\n title: string;\n /**\n * Secondary description line, normal weight, truncated. Note: the\n * Calendar's privacy mode does NOT mask the suffix (current behaviour,\n * preserved deliberately).\n */\n suffix?: string;\n /**\n * Pre-formatted, localised time range (e.g. \"09:00 – 09:45\"). The\n * Calendar adapter computes it via Intl.DateTimeFormat.formatRange.\n * Included in the composed aria-label whenever present (even when the\n * visual time line is suppressed via showTime/allDay — matches today's\n * Calendar behaviour byte-for-byte).\n */\n rangeText?: string;\n /**\n * Gates the VISUAL time line only (aria keeps rangeText). Mirrors\n * CalendarProps.showTime. @default true\n */\n showTime?: boolean;\n /**\n * All-day events suppress the visual time line (aria keeps rangeText).\n * @default false\n */\n allDay?: boolean;\n\n /**\n * Lifecycle state (6-state, matches the platform DoctorAppointment\n * lifecycle) → status icon + optional accent bar + line-through for\n * `cancelled` + localised label in the aria-label. NEVER paints the\n * card surface.\n */\n status?: CalendarEventStatus;\n /**\n * Render the 3px inline-start accent bar in the status's semantic token\n * colour. Purely decorative (aria-hidden) — the icon and aria-label carry\n * status regardless. The platform (colour = picker, status = icons only)\n * passes false via CalendarProps.eventStatusAccent. @default true\n */\n statusAccent?: boolean;\n\n /**\n * Runtime hex (#rgb or #rrggbb) from the consumer's colour picker — THE\n * painted surface. Injected as `--calendar-event-bg` via the sanctioned\n * inline custom-property pattern (23-constraints §inline-style exception).\n */\n backgroundColor?: string;\n /**\n * Runtime hex paired with backgroundColor. When omitted while\n * backgroundColor is set, the card auto-derives black/white ink by\n * luminance (provably WCAG AA ≥ 4.58:1 for any opaque colour).\n */\n textColor?: string;\n /**\n * Runtime hex border for delineating light surfaces. The platform sends\n * '#cccccc' when backgroundColor is '#ffffff' and omits it otherwise.\n * Falls back to transparent; border-width is constant (1px always\n * rendered), so toggling never shifts layout and event boundaries\n * survive forced-colors / Windows High Contrast for free.\n */\n borderColor?: string;\n\n /* Indicator icons — names identical to CalendarEvent fields (1:1 map). */\n /** Globe icon + diagonal stripe overlay. */\n isBookedOnline?: boolean;\n /** AlertTriangle icon. */\n hasUnassignedPatient?: boolean;\n /** HeartPulse icon. */\n hasHighlightedAnamnesis?: boolean;\n /** Euro icon. */\n hasBillableAmount?: boolean;\n /** Video icon. */\n isTelehealth?: boolean;\n\n /**\n * Resource title (chair/operator) woven into the composed aria-label\n * only — never rendered visually. The Calendar adapter resolves\n * resourceId → title before passing it.\n */\n resourceLabel?: string;\n /**\n * Stable event id → emitted as `data-event-id` (Calendar.focusEvent\n * targets it) and used as the contrast-warning dedup context.\n */\n eventId?: string;\n}\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\nexport const CalendarEventCard = forwardRef<\n HTMLDivElement,\n CalendarEventCardProps\n>(\n (\n {\n title,\n suffix,\n rangeText,\n showTime = true,\n allDay = false,\n status,\n statusAccent = true,\n backgroundColor,\n textColor,\n borderColor,\n isBookedOnline = false,\n hasUnassignedPatient,\n hasHighlightedAnamnesis,\n hasBillableAmount,\n isTelehealth,\n resourceLabel,\n eventId,\n className,\n style,\n 'aria-label': ariaLabelProp,\n ...rest\n },\n ref,\n ) => {\n const { t } = useTranslation();\n\n const StatusIcon = status ? STATUS_ICON[status] : null;\n const statusLabel = status ? t(STATUS_LABEL_KEYS[status]) : undefined;\n\n /* Accessible name — exactly the Calendar's historical composition.\n An explicit consumer-supplied aria-label wins. rangeText is always\n included when present, even when the visual time line is hidden. */\n const ariaLabel =\n ariaLabelProp ??\n [title, rangeText, resourceLabel, statusLabel].filter(Boolean).join(', ');\n\n /* Ink derivation — only when the caller paints the surface without\n pairing a text colour. */\n const ink =\n !textColor && backgroundColor ? resolveInk(backgroundColor) : null;\n\n /* DEV-only guardrails — every helper no-ops in production and dedupes\n per session, so calling during render is safe. */\n const warnContext = eventId ? `event ${eventId}` : 'calendar-event-card';\n warnLowContrast(backgroundColor, textColor, warnContext);\n if (backgroundColor && !textColor) {\n // no-ops when the hex is parseable (i.e. when resolveInk succeeded)\n warnUnparseableBackground(backgroundColor, warnContext);\n }\n if (backgroundColor && !borderColor) {\n // no-ops unless the background is near-white (luminance > 0.9)\n warnLowDelineation(backgroundColor, warnContext);\n }\n\n /* Per-event colour override: the consuming app passes runtime hex from\n its colour picker. 23-constraints permits inline `style` only as a\n CSS custom-property setter for runtime values that can't be\n enumerated at build time — the consuming background-color / color /\n border-color declarations live in the CVA base as Tailwind arbitrary\n values with token fallbacks. */\n const colourOverrides: CSSProperties | undefined =\n backgroundColor || textColor || borderColor\n ? ({\n ...(backgroundColor\n ? { '--calendar-event-bg': backgroundColor }\n : {}),\n ...(textColor\n ? { '--calendar-event-text': textColor }\n : ink === 'on-light'\n ? { '--calendar-event-text': 'var(--event-ink-on-light)' }\n : ink === 'on-dark'\n ? { '--calendar-event-text': 'var(--event-ink-on-dark)' }\n : {}),\n ...(borderColor ? { '--calendar-event-border': borderColor } : {}),\n } as CSSProperties)\n : undefined;\n\n const mergedStyle: CSSProperties | undefined =\n style || colourOverrides ? { ...style, ...colourOverrides } : undefined;\n\n return (\n <div\n ref={ref}\n {...rest}\n className={calendarEventCardVariants({\n status: status ?? 'none',\n bookedOnline: isBookedOnline,\n className,\n })}\n // eslint-disable-next-line react/forbid-dom-props -- caller-supplied event bg/text/border hex injected via CSS variables (23-constraints §inline-style exception)\n style={mergedStyle}\n aria-label={ariaLabel}\n data-component=\"calendar-event-card\"\n data-event-id={eventId}\n data-status={status ?? 'none'}\n data-contrast={textColor ? 'custom' : (ink ?? 'default')}\n >\n {status && statusAccent ? (\n <span\n aria-hidden=\"true\"\n data-slot=\"status-accent\"\n className={statusAccentVariants({ status })}\n />\n ) : null}\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-xs)] ds:self-end\">\n {/* All icons render in currentcolor — they inherit the resolved\n ink, so the ≥ 4.5:1 text guarantee makes every icon exceed the\n 3:1 graphics minimum (WCAG 1.4.11) on any picker surface.\n Never tint icons with status colours. */}\n {StatusIcon ? <StatusIcon size={14} aria-hidden=\"true\" /> : null}\n {isBookedOnline ? <Globe size={12} aria-hidden=\"true\" /> : null}\n {hasUnassignedPatient ? (\n <AlertTriangle size={12} aria-hidden=\"true\" />\n ) : null}\n {hasHighlightedAnamnesis ? (\n <HeartPulse size={12} aria-hidden=\"true\" />\n ) : null}\n {hasBillableAmount ? <Euro size={12} aria-hidden=\"true\" /> : null}\n {isTelehealth ? <Video size={12} aria-hidden=\"true\" /> : null}\n </div>\n {showTime && !allDay && rangeText ? (\n // No opacity here — composing 70% over saturated bgs drops\n // effective contrast below WCAG AA. The smaller font-size-xs vs\n // the title's font-weight-semibold provides sufficient visual\n // hierarchy.\n <span className=\"ds:text-[length:var(--font-size-xs)]\">\n {rangeText}\n </span>\n ) : null}\n <span className=\"ds:font-[var(--font-weight-semibold)] ds:truncate ds:text-start\">\n {title}\n </span>\n {suffix ? (\n <span className=\"ds:truncate ds:text-start ds:text-[length:var(--font-size-xs)]\">\n {suffix}\n </span>\n ) : null}\n </div>\n );\n },\n);\nCalendarEventCard.displayName = 'CalendarEventCard';\n"],"names":["__iconNode","Ban","createLucideIcon","Euro","ThumbsUp","Zap","parseHex","hex","trimmed","body","r","g","b","relativeLuminance","lin","c","warnLowContrast","bgHex","fgHex","contextLabel","resolveInk","bg","STATUS_ICON","Clock","Stethoscope","Check","STATUS_LABEL_KEYS","calendarEventCardVariants","cva","statusAccentVariants","CalendarEventCard","forwardRef","title","suffix","rangeText","showTime","allDay","status","statusAccent","backgroundColor","textColor","borderColor","isBookedOnline","hasUnassignedPatient","hasHighlightedAnamnesis","hasBillableAmount","isTelehealth","resourceLabel","eventId","className","style","ariaLabelProp","rest","ref","t","useTranslation","StatusIcon","statusLabel","ariaLabel","ink","colourOverrides","mergedStyle","jsxs","jsx","Globe","AlertTriangle","HeartPulse","Video"],"mappings":"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","x_google_ignoreList":[0,1,2,3]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsxs as v, jsx as i, Fragment as ge } from "react/jsx-runtime";
|
|
2
|
-
import { forwardRef as ve, useId as ye, useRef as
|
|
2
|
+
import { forwardRef as ve, useId as ye, useRef as w, useCallback as W, useImperativeHandle as be, useMemo as xe } from "react";
|
|
3
3
|
import { c as Ie } from "./index-D2ZczOXr.js";
|
|
4
4
|
import { useTranslation as ke } from "react-i18next";
|
|
5
5
|
import { I as q } from "./icon-button-C_kbcd7I.js";
|
|
@@ -132,9 +132,9 @@ function Me(t, n) {
|
|
|
132
132
|
if (typeof Intl < "u" && typeof Intl.Segmenter == "function")
|
|
133
133
|
try {
|
|
134
134
|
const l = new Intl.Segmenter(n, { granularity: "grapheme" });
|
|
135
|
-
let
|
|
136
|
-
for (const y of l.segment(t))
|
|
137
|
-
return
|
|
135
|
+
let r = 0;
|
|
136
|
+
for (const y of l.segment(t)) r += 1;
|
|
137
|
+
return r;
|
|
138
138
|
} catch {
|
|
139
139
|
}
|
|
140
140
|
return Array.from(t).length;
|
|
@@ -149,15 +149,15 @@ function Fe(t, n, l) {
|
|
|
149
149
|
return d.length === t.length ? t : d;
|
|
150
150
|
} catch {
|
|
151
151
|
}
|
|
152
|
-
const
|
|
153
|
-
return
|
|
152
|
+
const r = Array.from(t);
|
|
153
|
+
return r.length <= n ? t : r.slice(0, n).join("");
|
|
154
154
|
}
|
|
155
155
|
const Ke = ve(
|
|
156
156
|
({
|
|
157
157
|
size: t = "md",
|
|
158
158
|
value: n,
|
|
159
159
|
defaultValue: l,
|
|
160
|
-
maxLength:
|
|
160
|
+
maxLength: r,
|
|
161
161
|
submitOnEnter: y = !1,
|
|
162
162
|
minRows: o = 1,
|
|
163
163
|
maxRows: d = 8,
|
|
@@ -169,22 +169,22 @@ const Ke = ve(
|
|
|
169
169
|
label: T,
|
|
170
170
|
placeholder: U,
|
|
171
171
|
className: Y,
|
|
172
|
-
onChange:
|
|
173
|
-
onKeyDown:
|
|
174
|
-
onCompositionStart:
|
|
175
|
-
onCompositionEnd:
|
|
176
|
-
id:
|
|
172
|
+
onChange: C,
|
|
173
|
+
onKeyDown: N,
|
|
174
|
+
onCompositionStart: V,
|
|
175
|
+
onCompositionEnd: j,
|
|
176
|
+
id: z,
|
|
177
177
|
...J
|
|
178
178
|
}, L) => {
|
|
179
|
-
const { t: c, i18n: E } = ke(), O = ye(), p =
|
|
180
|
-
|
|
179
|
+
const { t: c, i18n: E } = ke(), O = ye(), p = w(!1), M = w(null), I = w(null), Q = W((e) => {
|
|
180
|
+
I.current = e;
|
|
181
181
|
}, []), [X, m] = we({
|
|
182
182
|
value: n === void 0 ? void 0 : String(n),
|
|
183
183
|
defaultValue: String(l ?? "")
|
|
184
|
-
}), a = X ?? "", H = Me(a, E.language), f = typeof
|
|
185
|
-
const e =
|
|
184
|
+
}), a = X ?? "", H = Me(a, E.language), f = typeof r == "number" && r > 0, Z = f ? Math.max(0, r - H) : 0, D = f && H > r * 0.9, h = f && H >= r, F = W(() => {
|
|
185
|
+
const e = I.current;
|
|
186
186
|
if (!e) return;
|
|
187
|
-
const
|
|
187
|
+
const s = window.getComputedStyle(e), k = parseFloat(s.lineHeight) || 24, de = parseFloat(s.paddingTop) || 0, ue = parseFloat(s.paddingBottom) || 0, pe = parseFloat(s.borderTopWidth) || 0, me = parseFloat(s.borderBottomWidth) || 0, _ = de + ue + pe + me, fe = k * o + _, $ = k * d + _;
|
|
188
188
|
e.style.height = "auto";
|
|
189
189
|
const he = Math.max(fe, Math.min(e.scrollHeight, $));
|
|
190
190
|
e.style.height = `${he}px`, e.style.overflowY = e.scrollHeight > $ ? "auto" : "hidden";
|
|
@@ -193,15 +193,16 @@ const Ke = ve(
|
|
|
193
193
|
F();
|
|
194
194
|
}, [F, a]);
|
|
195
195
|
const ee = (e) => {
|
|
196
|
-
let
|
|
197
|
-
f && !p.current && (
|
|
196
|
+
let s = e.target.value;
|
|
197
|
+
f && !p.current && (s = Fe(s, r, E.language)), m(s), !p.current && (C == null || C(e));
|
|
198
198
|
}, te = (e) => {
|
|
199
|
-
p.current = !0,
|
|
199
|
+
p.current = !0, V == null || V(e);
|
|
200
200
|
}, se = (e) => {
|
|
201
|
-
p.current = !1,
|
|
201
|
+
p.current = !1, j == null || j(e);
|
|
202
202
|
}, re = (e) => e.nativeEvent.isComposing || e.keyCode === 229 || p.current, S = () => {
|
|
203
|
-
|
|
204
|
-
|
|
203
|
+
var s;
|
|
204
|
+
!a.trim() || x || h || (u == null || u(a), m(""), (s = I.current) == null || s.focus());
|
|
205
|
+
}, K = w(null);
|
|
205
206
|
be(L, () => K.current, []);
|
|
206
207
|
const ne = xe(
|
|
207
208
|
() => ({
|
|
@@ -218,7 +219,7 @@ const Ke = ve(
|
|
|
218
219
|
},
|
|
219
220
|
focus: () => {
|
|
220
221
|
var e;
|
|
221
|
-
(e =
|
|
222
|
+
(e = I.current) == null || e.focus();
|
|
222
223
|
}
|
|
223
224
|
}),
|
|
224
225
|
// `submit` is a local closure that always sees the latest currentValue
|
|
@@ -227,24 +228,24 @@ const Ke = ve(
|
|
|
227
228
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
228
229
|
[a, m]
|
|
229
230
|
);
|
|
230
|
-
Ne(Te, ne,
|
|
231
|
+
Ne(Te, ne, z);
|
|
231
232
|
const ae = (e) => {
|
|
232
|
-
if (
|
|
233
|
-
const
|
|
234
|
-
(
|
|
233
|
+
if (N == null || N(e), !e.defaultPrevented && !re(e) && e.key === "Enter") {
|
|
234
|
+
const s = e.metaKey || e.ctrlKey, k = y && !e.shiftKey;
|
|
235
|
+
(s || k) && (e.preventDefault(), S());
|
|
235
236
|
}
|
|
236
237
|
}, ie = () => {
|
|
237
238
|
var e;
|
|
238
239
|
(e = M.current) == null || e.click();
|
|
239
240
|
}, oe = (e) => {
|
|
240
241
|
e.target.files && e.target.files.length > 0 && (b == null || b(e.target.files)), e.target.value = "";
|
|
241
|
-
}, g =
|
|
242
|
+
}, g = z ?? O, R = `${g}-label`, B = f ? `${g}-counter` : void 0, P = `${g}-hint`, ce = U ?? c("chat.input.placeholder"), le = T ?? c("chat.prompt");
|
|
242
243
|
return /* @__PURE__ */ v(
|
|
243
244
|
"div",
|
|
244
245
|
{
|
|
245
246
|
ref: K,
|
|
246
247
|
"data-component": "chat-input",
|
|
247
|
-
"data-component-id":
|
|
248
|
+
"data-component-id": z,
|
|
248
249
|
className: Ee({ size: t, className: Y }),
|
|
249
250
|
children: [
|
|
250
251
|
/* @__PURE__ */ i(
|
|
@@ -365,4 +366,4 @@ export {
|
|
|
365
366
|
Se as P,
|
|
366
367
|
Te as c
|
|
367
368
|
};
|
|
368
|
-
//# sourceMappingURL=chat-input-
|
|
369
|
+
//# sourceMappingURL=chat-input-QpHxBEnN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-input-QpHxBEnN.js","sources":["../../node_modules/lucide-react/dist/esm/icons/paperclip.mjs","../../src/components/chat-input/chat-input.agent.ts","../../src/components/chat-input/chat-input.tsx"],"sourcesContent":["/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"m16 6-8.414 8.586a2 2 0 0 0 2.829 2.829l8.414-8.586a4 4 0 1 0-5.657-5.657l-8.379 8.551a6 6 0 1 0 8.485 8.485l8.379-8.551\",\n key: \"1miecu\"\n }\n ]\n];\nconst Paperclip = createLucideIcon(\"paperclip\", __iconNode);\n\nexport { __iconNode, Paperclip as default };\n//# sourceMappingURL=paperclip.mjs.map\n","/* -------------------------------------------------------------------- */\n/* Agent adapter — ChatInput. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { ChatInputHandle } from './chat-input';\n\nexport const chatInputAgent: AgentAdapter<ChatInputHandle> = {\n id: 'chat-input',\n capabilities: ['edit_inline', 'submit'],\n state: {\n value: {\n type: 'string',\n descriptionKey: 'ui.agent.chatInput.state.value',\n description: 'Current text in the composer.',\n read: (handle) => handle.getValue(),\n },\n isEmpty: {\n type: 'boolean',\n descriptionKey: 'ui.agent.chatInput.state.isEmpty',\n description: 'True when the composer has no text.',\n read: (handle) => handle.isEmpty(),\n },\n },\n actions: {\n set_value: {\n safety: 'write',\n argsType: '{ value: string }',\n argsSchema: {\n type: 'object',\n properties: {\n value: {\n type: 'string',\n description: 'New composer text, replacing the current value.',\n },\n },\n required: ['value'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.chatInput.actions.setValue',\n description: 'Replace the composer text.',\n invoke: (handle, args: { value: string }) => {\n handle.setValue(args.value);\n },\n },\n clear: {\n // Discards whatever the user has typed — irreversible from this UI.\n safety: 'destructive',\n idempotent: true,\n descriptionKey: 'ui.agent.chatInput.actions.clear',\n description: 'Clear the composer. Irreversible from the same UI.',\n invoke: (handle) => {\n handle.clear();\n },\n },\n submit: {\n safety: 'write',\n // Hands the composer text to the host `onSubmit` callback, which sends\n // the message to a backend / model — an external side effect.\n openWorld: true,\n descriptionKey: 'ui.agent.chatInput.actions.submit',\n description: 'Submit the current composer state via onSubmit.',\n invoke: (handle) => {\n handle.submit();\n },\n },\n focus: {\n safety: 'read',\n descriptionKey: 'ui.agent.chatInput.actions.focus',\n description: 'Move keyboard focus into the textarea.',\n invoke: (handle) => {\n handle.focus();\n },\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'chat-input',\n description: 'Marks the ChatInput wrapper.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n },\n};\n","import {\n forwardRef,\n useCallback,\n useId,\n useImperativeHandle,\n useMemo,\n useRef,\n type ChangeEvent,\n type CompositionEvent,\n type KeyboardEvent,\n type ReactNode,\n type TextareaHTMLAttributes,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { AlertCircle, Paperclip, Send } from 'lucide-react';\nimport { IconButton } from '../button';\nimport { useControllableState } from '../../hooks/use-controllable-state';\nimport { useIsomorphicLayoutEffect } from '../../hooks/use-isomorphic-layout-effect';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { chatInputAgent } from './chat-input.agent';\n\nconst rootVariants = cva(\n [\n 'ds:flex ds:flex-col ds:gap-[var(--spacing-xs)] ds:w-full',\n // Uses the kit's shared input-chrome tokens — `--input` for fill,\n // `--shadow-input` for the halo. Border stays at 1px (`--border`,\n // softened to `grey-700` in light) so the focus-within override and\n // forced-colors fallback both still paint a visible edge.\n 'ds:rounded-[var(--radius-md)] ds:border ds:border-border',\n 'ds:bg-input ds:shadow-[var(--shadow-input)]',\n 'ds:focus-within:border-[color:var(--primary)]',\n 'ds:transition-[border-color,box-shadow] ds:duration-[var(--animation-duration)]',\n 'ds:motion-reduce:transition-none',\n 'ds:forced-colors:border-[CanvasText]',\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\ntype NativeTextareaProps = Omit<\n TextareaHTMLAttributes<HTMLTextAreaElement>,\n 'size' | 'onSubmit' | 'children'\n>;\n\n/** Curated imperative handle for agent / external automation. */\nexport interface ChatInputHandle {\n getValue: () => string;\n isEmpty: () => boolean;\n setValue: (value: string) => void;\n clear: () => void;\n submit: () => void;\n focus: () => void;\n}\n\nexport interface ChatInputProps\n extends NativeTextareaProps, VariantProps<typeof rootVariants> {\n /** Invoked when the user submits (Cmd/Ctrl+Enter, or send button). */\n onSubmit?: (text: string) => void;\n /** Maximum allowed characters (grapheme clusters via Intl.Segmenter when available). */\n maxLength?: number;\n /** When true, plain Enter submits and Shift+Enter inserts a newline.\n * Default false (Enter inserts newline; Cmd/Ctrl+Enter submits). */\n submitOnEnter?: boolean;\n /** Minimum visible rows. Default 1. */\n minRows?: number;\n /** Maximum visible rows before the field scrolls. Default 8. */\n maxRows?: number;\n /** Optional attachment handler — when provided, renders the attachment button. */\n onAttach?: (files: FileList) => void;\n /** `accept` forwarded to the hidden file input. */\n accept?: string;\n /** Controls whether the textarea is disabled and submit is blocked. */\n disabled?: boolean;\n /** Optional slot placed between the textarea and the send button. */\n toolbar?: ReactNode;\n /** Visible label above the textarea. When omitted, a visually-hidden label is used. */\n label?: string;\n}\n\nfunction graphemeCount(value: string, locale: string): number {\n if (typeof Intl !== 'undefined' && typeof Intl.Segmenter === 'function') {\n try {\n const seg = new Intl.Segmenter(locale, { granularity: 'grapheme' });\n let n = 0;\n for (const _s of seg.segment(value)) n += 1;\n return n;\n } catch {\n /* fall through to Array.from */\n }\n }\n return Array.from(value).length;\n}\n\n/** Truncate `value` to at most `max` graphemes. Returns the original\n * string when it already fits so callers can compare references. */\nfunction truncateToGraphemes(\n value: string,\n max: number,\n locale: string,\n): string {\n if (typeof Intl !== 'undefined' && typeof Intl.Segmenter === 'function') {\n try {\n const seg = new Intl.Segmenter(locale, { granularity: 'grapheme' });\n const parts: string[] = [];\n for (const s of seg.segment(value)) {\n parts.push(s.segment);\n if (parts.length >= max) break;\n }\n const joined = parts.join('');\n return joined.length === value.length ? value : joined;\n } catch {\n /* fall through to code-point split */\n }\n }\n const cps = Array.from(value);\n return cps.length <= max ? value : cps.slice(0, max).join('');\n}\n\nexport const ChatInput = forwardRef<HTMLDivElement, ChatInputProps>(\n (\n {\n size = 'md',\n value,\n defaultValue,\n maxLength,\n submitOnEnter = false,\n minRows = 1,\n maxRows = 8,\n onSubmit,\n onAttach,\n accept,\n disabled,\n toolbar,\n label,\n placeholder,\n className,\n onChange,\n onKeyDown,\n onCompositionStart,\n onCompositionEnd,\n id,\n ...rest\n },\n ref,\n ) => {\n const { t, i18n } = useTranslation();\n const textareaId = useId();\n const composingRef = useRef(false);\n const fileInputRef = useRef<HTMLInputElement>(null);\n const innerRef = useRef<HTMLTextAreaElement | null>(null);\n\n const setRefs = useCallback((node: HTMLTextAreaElement | null) => {\n innerRef.current = node;\n }, []);\n\n const [currentValueRaw, setChatValue] = useControllableState<string>({\n value: value === undefined ? undefined : String(value),\n defaultValue: String(defaultValue ?? ''),\n });\n const currentValue = currentValueRaw ?? '';\n\n const count = graphemeCount(currentValue, i18n.language);\n const hasMaxLength = typeof maxLength === 'number' && maxLength > 0;\n const remaining = hasMaxLength ? Math.max(0, maxLength - count) : 0;\n const showCounter = hasMaxLength && count > (maxLength as number) * 0.9;\n const atLimit = hasMaxLength && count >= maxLength;\n\n /* Auto-grow — compute height from scrollHeight, clamped to [minRows, maxRows].\n Imperative `.style` write is permitted per 23-constraints\n §Runtime-computed dimensions (textarea scrollHeight measurement). */\n const resize = useCallback(() => {\n const el = innerRef.current;\n if (!el) return;\n const styles = window.getComputedStyle(el);\n const lineHeight = parseFloat(styles.lineHeight) || 24;\n const padTop = parseFloat(styles.paddingTop) || 0;\n const padBot = parseFloat(styles.paddingBottom) || 0;\n const borderTop = parseFloat(styles.borderTopWidth) || 0;\n const borderBot = parseFloat(styles.borderBottomWidth) || 0;\n const chrome = padTop + padBot + borderTop + borderBot;\n const minH = lineHeight * minRows + chrome;\n const maxH = lineHeight * maxRows + chrome;\n el.style.height = 'auto';\n const next = Math.max(minH, Math.min(el.scrollHeight, maxH));\n el.style.height = `${next}px`;\n el.style.overflowY = el.scrollHeight > maxH ? 'auto' : 'hidden';\n }, [minRows, maxRows]);\n\n useIsomorphicLayoutEffect(() => {\n resize();\n }, [resize, currentValue]);\n\n const handleChange = (e: ChangeEvent<HTMLTextAreaElement>) => {\n let next = e.target.value;\n // Enforce a grapheme cap so emoji like 👨👩👧 (1 grapheme, 11 UTF-16\n // units) stay aligned with the visible counter. Skip during IME\n // composition so the in-progress text is preserved verbatim.\n if (hasMaxLength && !composingRef.current) {\n next = truncateToGraphemes(next, maxLength as number, i18n.language);\n }\n setChatValue(next);\n if (composingRef.current) return;\n onChange?.(e);\n };\n\n const handleCompositionStart = (\n e: CompositionEvent<HTMLTextAreaElement>,\n ) => {\n composingRef.current = true;\n onCompositionStart?.(e);\n };\n const handleCompositionEnd = (e: CompositionEvent<HTMLTextAreaElement>) => {\n composingRef.current = false;\n onCompositionEnd?.(e);\n };\n\n const isIMEKey = (e: KeyboardEvent<HTMLTextAreaElement>) =>\n e.nativeEvent.isComposing || e.keyCode === 229 || composingRef.current;\n\n const submit = () => {\n const text = currentValue.trim();\n if (!text || disabled || atLimit) return;\n onSubmit?.(currentValue);\n setChatValue('');\n // Keep focus in the composer after a send. Activating the Send *button*\n // (click, or keyboard Enter/Space) otherwise strands focus: clearing the\n // value re-disables the button on the next render, so focus falls to\n // <body> and a keyboard user must re-traverse back to the textarea.\n // Refocusing leaves the composer ready for the next message — a no-op for\n // the Enter-to-send path, where focus is already in the textarea.\n innerRef.current?.focus();\n };\n\n const rootRef = useRef<HTMLDivElement>(null);\n useImperativeHandle(ref, () => rootRef.current as HTMLDivElement, []);\n\n const agentHandle = useMemo<ChatInputHandle>(\n () => ({\n getValue: () => currentValue,\n isEmpty: () => !currentValue.trim(),\n setValue: (next: string) => {\n setChatValue(next);\n },\n clear: () => {\n setChatValue('');\n },\n submit: () => {\n submit();\n },\n focus: () => {\n innerRef.current?.focus();\n },\n }),\n // `submit` is a local closure that always sees the latest currentValue\n // via React's render cycle — depend on currentValue so the handle\n // picks up new values across renders.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [currentValue, setChatValue],\n );\n useAgentRegistration(chatInputAgent, agentHandle, id);\n\n const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {\n onKeyDown?.(e);\n if (e.defaultPrevented) return;\n if (isIMEKey(e)) return;\n\n if (e.key === 'Enter') {\n const explicitSubmit = e.metaKey || e.ctrlKey;\n const plainEnterSubmits = submitOnEnter && !e.shiftKey;\n if (explicitSubmit || plainEnterSubmits) {\n e.preventDefault();\n submit();\n }\n }\n };\n\n const handleAttach = () => {\n fileInputRef.current?.click();\n };\n\n const handleFilePick = (e: ChangeEvent<HTMLInputElement>) => {\n if (e.target.files && e.target.files.length > 0) {\n onAttach?.(e.target.files);\n }\n // Reset so picking the same file twice still fires change.\n e.target.value = '';\n };\n\n const effectiveId = id ?? textareaId;\n const labelId = `${effectiveId}-label`;\n const counterId = hasMaxLength ? `${effectiveId}-counter` : undefined;\n const hintId = `${effectiveId}-hint`;\n\n const resolvedPlaceholder = placeholder ?? t('chat.input.placeholder');\n const resolvedLabel = label ?? t('chat.prompt');\n\n return (\n <div\n ref={rootRef}\n data-component=\"chat-input\"\n data-component-id={id}\n className={rootVariants({ size, className })}\n >\n <label\n id={labelId}\n htmlFor={effectiveId}\n className={\n label\n ? 'type-label ds:ps-[var(--spacing-sm)] ds:pt-[var(--spacing-sm)]'\n : 'ds:sr-only'\n }\n >\n {resolvedLabel}\n </label>\n <textarea\n ref={setRefs}\n id={effectiveId}\n value={currentValue}\n disabled={disabled}\n rows={minRows}\n placeholder={resolvedPlaceholder}\n aria-labelledby={labelId}\n aria-describedby={\n [counterId, hintId].filter(Boolean).join(' ') || undefined\n }\n aria-invalid={atLimit || undefined}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n onCompositionStart={handleCompositionStart}\n onCompositionEnd={handleCompositionEnd}\n className={[\n 'ds:w-full ds:resize-none ds:bg-transparent',\n 'ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)] ds:pt-[var(--spacing-sm)] ds:pb-[var(--spacing-xs)]',\n 'ds:placeholder:text-[color:var(--muted-foreground)]',\n 'ds:leading-[var(--line-height-base)]',\n 'ds:disabled:opacity-50 ds:disabled:cursor-not-allowed',\n // Tokenised focus ring on the textarea itself — the 1px border\n // shift on the wrapper alone fails the 3px accessible-theme\n // requirement. See a11y-critical-fixes.mdx.\n 'ds:outline-none',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[color:var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n ].join(' ')}\n {...rest}\n />\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-xs)] ds:ps-[var(--spacing-xs)] ds:pe-[var(--spacing-xs)] ds:pb-[var(--spacing-xs)]\">\n {onAttach ? (\n <>\n <input\n ref={fileInputRef}\n type=\"file\"\n className=\"ds:sr-only\"\n multiple\n accept={accept}\n onChange={handleFilePick}\n aria-label={t('chat.input.attach')}\n tabIndex={-1}\n />\n <IconButton\n icon={<Paperclip />}\n aria-label={t('chat.input.attach')}\n intent=\"ghost\"\n size=\"sm\"\n onClick={handleAttach}\n disabled={disabled}\n />\n </>\n ) : null}\n {toolbar}\n <div className=\"ds:ms-auto ds:inline-flex ds:items-center ds:gap-[var(--spacing-sm)]\">\n {showCounter ? (\n <span\n id={counterId}\n aria-live=\"polite\"\n className={[\n 'ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)]',\n 'type-meta ds:tabular-nums',\n atLimit\n ? 'ds:text-[color:var(--destructive)]'\n : 'ds:text-[color:var(--muted-foreground)]',\n ].join(' ')}\n >\n {atLimit ? (\n // Icon pairs with --destructive colour so the at-limit\n // state is not conveyed by hue alone (WCAG 1.4.1).\n <AlertCircle aria-hidden=\"true\" className=\"ds:size-3.5\" />\n ) : null}\n {t('chat.input.remaining', { count: remaining })}\n </span>\n ) : null}\n <span id={hintId} className=\"ds:sr-only\">\n {t('chat.input.sendHint')}\n </span>\n <IconButton\n icon={<Send />}\n aria-label={t('chat.send')}\n intent=\"primary\"\n size=\"sm\"\n disabled={disabled || !currentValue.trim() || atLimit}\n onClick={submit}\n aria-keyshortcuts=\"Meta+Enter Control+Enter\"\n />\n </div>\n </div>\n </div>\n );\n },\n);\n\nChatInput.displayName = 'ChatInput';\n"],"names":["__iconNode","Paperclip","createLucideIcon","chatInputAgent","handle","args","rootVariants","cva","graphemeCount","value","locale","seg","n","_s","truncateToGraphemes","max","parts","s","joined","cps","ChatInput","forwardRef","size","defaultValue","maxLength","submitOnEnter","minRows","maxRows","onSubmit","onAttach","accept","disabled","toolbar","label","placeholder","className","onChange","onKeyDown","onCompositionStart","onCompositionEnd","id","rest","ref","t","i18n","useTranslation","textareaId","useId","composingRef","useRef","fileInputRef","innerRef","setRefs","useCallback","node","currentValueRaw","setChatValue","useControllableState","currentValue","count","hasMaxLength","remaining","showCounter","atLimit","resize","el","styles","lineHeight","padTop","padBot","borderTop","borderBot","chrome","minH","maxH","next","useIsomorphicLayoutEffect","handleChange","handleCompositionStart","handleCompositionEnd","isIMEKey","submit","_a","rootRef","useImperativeHandle","agentHandle","useMemo","useAgentRegistration","handleKeyDown","explicitSubmit","plainEnterSubmits","handleAttach","handleFilePick","effectiveId","labelId","counterId","hintId","resolvedPlaceholder","resolvedLabel","jsxs","jsx","Fragment","IconButton","AlertCircle","Send"],"mappings":"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","x_google_ignoreList":[0]}
|
|
@@ -212,7 +212,7 @@ const pe = /* @__PURE__ */ new Set(["A", "E", "I", "O", "U"]), ft = [
|
|
|
212
212
|
"T"
|
|
213
213
|
];
|
|
214
214
|
function me(e) {
|
|
215
|
-
return e.normalize("NFD").replace(/[
|
|
215
|
+
return e.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toUpperCase().replace(/[^A-Z]/g, "");
|
|
216
216
|
}
|
|
217
217
|
function he(e) {
|
|
218
218
|
return [...e].filter((t) => !pe.has(t)).join("");
|
|
@@ -550,4 +550,4 @@ export {
|
|
|
550
550
|
Ut as i,
|
|
551
551
|
vt as w
|
|
552
552
|
};
|
|
553
|
-
//# sourceMappingURL=fiscal-code-input-
|
|
553
|
+
//# sourceMappingURL=fiscal-code-input-QP9gkyDE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fiscal-code-input-QP9gkyDE.js","sources":["../../node_modules/lucide-react/dist/esm/icons/calculator.mjs","../../src/components/fiscal-code-input/fiscal-code-input.agent.ts","../../src/components/fiscal-code-input/is-valid-codice-fiscale.ts","../../src/components/fiscal-code-input/calculate-codice-fiscale.ts","../../src/components/fiscal-code-input/fiscal-code-input.tsx"],"sourcesContent":["/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"rect\", { width: \"16\", height: \"20\", x: \"4\", y: \"2\", rx: \"2\", key: \"1nb95v\" }],\n [\"line\", { x1: \"8\", x2: \"16\", y1: \"6\", y2: \"6\", key: \"x4nwl0\" }],\n [\"line\", { x1: \"16\", x2: \"16\", y1: \"14\", y2: \"18\", key: \"wjye3r\" }],\n [\"path\", { d: \"M16 10h.01\", key: \"1m94wz\" }],\n [\"path\", { d: \"M12 10h.01\", key: \"1nrarc\" }],\n [\"path\", { d: \"M8 10h.01\", key: \"19clt8\" }],\n [\"path\", { d: \"M12 14h.01\", key: \"1etili\" }],\n [\"path\", { d: \"M8 14h.01\", key: \"6423bh\" }],\n [\"path\", { d: \"M12 18h.01\", key: \"mhygvu\" }],\n [\"path\", { d: \"M8 18h.01\", key: \"lrp35t\" }]\n];\nconst Calculator = createLucideIcon(\"calculator\", __iconNode);\n\nexport { __iconNode, Calculator as default };\n//# sourceMappingURL=calculator.mjs.map\n","/* -------------------------------------------------------------------- */\n/* Agent adapter — FiscalCodeInput. */\n/* */\n/* See `src/docs/26-agent-readiness.mdx` for the contract. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { FiscalCodeInputHandle } from './fiscal-code-input';\n\nexport const fiscalCodeInputAgent: AgentAdapter<FiscalCodeInputHandle> = {\n id: 'fiscal-code-input',\n capabilities: ['set_value'],\n state: {\n value: {\n type: 'string',\n descriptionKey: 'ui.agent.fiscalCodeInput.state.value',\n description:\n 'Current codice fiscale, normalised (uppercased, 0–16 [A-Z0-9] characters).',\n read: (handle) => handle.getValue(),\n },\n isValid: {\n type: 'boolean',\n descriptionKey: 'ui.agent.fiscalCodeInput.state.isValid',\n description:\n 'Whether the value is 16 structurally-sound characters with a matching control character.',\n read: (handle) => handle.isValid(),\n },\n },\n actions: {\n set_value: {\n safety: 'write',\n argsType: '{ value: string }',\n argsSchema: {\n type: 'object',\n properties: { value: { type: 'string' } },\n required: ['value'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.fiscalCodeInput.actions.setValue',\n description:\n 'Replace the codice fiscale. The value is uppercased and stripped to [A-Z0-9], capped at 16 characters.',\n examples: [\n {\n args: { value: 'RSSMRA85T10A562S' },\n note: 'A complete, structurally-sound codice fiscale.',\n },\n ],\n invoke: (handle, args: { value: string }) => {\n handle.setValue(args.value);\n },\n },\n clear: {\n safety: 'destructive',\n idempotent: true,\n descriptionKey: 'ui.agent.fiscalCodeInput.actions.clear',\n description: 'Empty the input. Loses any typed value.',\n invoke: (handle) => {\n handle.clear();\n },\n },\n focus: {\n safety: 'read',\n descriptionKey: 'ui.agent.fiscalCodeInput.actions.focus',\n description: 'Move keyboard focus to the codice fiscale input.',\n invoke: (handle) => {\n handle.focus();\n },\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'fiscal-code-input',\n description: 'Marks the FiscalCodeInput wrapper.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n },\n};\n","/* ------------------------------------------------------------------ */\n/* Codice Fiscale (Italian fiscal code) — client-side structural + */\n/* control-character checksum validator. */\n/* */\n/* SCOPE: this is a CLIENT MIRROR of the platform's */\n/* ValidateFiscalCodeService used ONLY to give instant feedback. It */\n/* validates two things and nothing more: */\n/* 1. The structural shape — 15 alphanumerics followed by 1 control */\n/* letter, where each position obeys its letter/digit class */\n/* (/^[A-Z0-9]{15}[A-Z]$/ plus the per-position class pattern). */\n/* 2. The 16th control character, derived from the first 15 via the */\n/* official odd/even per-position weighted-sum mod-26 algorithm. */\n/* */\n/* OUT OF SCOPE (server stays source of truth): birth-date / comune */\n/* Belfiore-code cross-checks and omocodia digit-substitution. A */\n/* structurally-correct code with a valid control character can still */\n/* be rejected by the server — the client never hard-blocks submit on */\n/* its own verdict. */\n/* ------------------------------------------------------------------ */\n\n/** Outcome of a structural + checksum check on a 16-char candidate. */\nexport type FiscalCodeReason =\n | 'empty'\n | 'incomplete'\n | 'badFormat'\n | 'badChecksum'\n | 'valid';\n\n/**\n * Position classes for the 15 informative characters. Positions are\n * 0-indexed. Letter positions accept A–Z; digit positions accept 0–9.\n * The 16th (control) character is a letter and validated separately.\n *\n * Standard layout (ignoring omocodia substitution, which the SERVER\n * handles): surname (0–2 letters), name (3–5 letters), year (6–7\n * digits), month (8 letter), day (9–10 digits), comune (11 letter +\n * 12–14 digits). For client structural feedback we accept the canonical\n * non-omocodic layout; omocodic variants surface as `badFormat` here and\n * are resolved server-side — documented as an accepted client limitation.\n */\nconst LETTER_POSITIONS = new Set([0, 1, 2, 3, 4, 5, 8, 11]);\nconst DIGIT_POSITIONS = new Set([6, 7, 9, 10, 12, 13, 14]);\n\nconst ODD_MAP: Readonly<Record<string, number>> = Object.freeze({\n '0': 1,\n '1': 0,\n '2': 5,\n '3': 7,\n '4': 9,\n '5': 13,\n '6': 15,\n '7': 17,\n '8': 19,\n '9': 21,\n A: 1,\n B: 0,\n C: 5,\n D: 7,\n E: 9,\n F: 13,\n G: 15,\n H: 17,\n I: 19,\n J: 21,\n K: 2,\n L: 4,\n M: 18,\n N: 20,\n O: 11,\n P: 3,\n Q: 6,\n R: 8,\n S: 12,\n T: 14,\n U: 16,\n V: 10,\n W: 22,\n X: 25,\n Y: 24,\n Z: 23,\n});\n\nconst EVEN_MAP: Readonly<Record<string, number>> = Object.freeze({\n '0': 0,\n '1': 1,\n '2': 2,\n '3': 3,\n '4': 4,\n '5': 5,\n '6': 6,\n '7': 7,\n '8': 8,\n '9': 9,\n A: 0,\n B: 1,\n C: 2,\n D: 3,\n E: 4,\n F: 5,\n G: 6,\n H: 7,\n I: 8,\n J: 9,\n K: 10,\n L: 11,\n M: 12,\n N: 13,\n O: 14,\n P: 15,\n Q: 16,\n R: 17,\n S: 18,\n T: 19,\n U: 20,\n V: 21,\n W: 22,\n X: 23,\n Y: 24,\n Z: 25,\n});\n\nconst REMAINDER_TO_CONTROL = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';\n\n/** True when every informative position matches its letter/digit class. */\nfunction hasValidStructure(code: string): boolean {\n if (!/^[A-Z0-9]{15}[A-Z]$/.test(code)) return false;\n for (let i = 0; i < 15; i += 1) {\n const ch = code[i];\n const isDigit = ch >= '0' && ch <= '9';\n if (LETTER_POSITIONS.has(i) && isDigit) return false;\n if (DIGIT_POSITIONS.has(i) && !isDigit) return false;\n }\n return true;\n}\n\n/**\n * Compute the expected 16th control character from the first 15\n * informative characters. The input MUST already be 15 uppercase\n * `[A-Z0-9]` characters (callers guard with `hasValidStructure`).\n */\nexport function computeControlChar(first15: string): string {\n let sum = 0;\n for (let i = 0; i < 15; i += 1) {\n const ch = first15[i];\n // Per the official spec, odd POSITIONS (1st, 3rd, … — i.e. 0-indexed\n // even i) use the ODD weight table; even positions use the EVEN table.\n sum += i % 2 === 0 ? ODD_MAP[ch] : EVEN_MAP[ch];\n }\n return REMAINDER_TO_CONTROL[sum % 26];\n}\n\n/**\n * Classify a normalised (uppercased, `[A-Z0-9]`-only) candidate.\n *\n * - `empty` — no characters.\n * - `incomplete` — fewer than 16 characters.\n * - `badFormat` — 16 characters but the position-class pattern fails.\n * - `badChecksum` — 16 well-formed characters but the control char is wrong.\n * - `valid` — structurally sound and the control char matches.\n */\nexport function classifyCodiceFiscale(raw: string): FiscalCodeReason {\n if (raw.length === 0) return 'empty';\n if (raw.length < 16) return 'incomplete';\n // raw is normalised to at most 16 chars by the component; guard anyway.\n const code = raw.slice(0, 16);\n if (!hasValidStructure(code)) return 'badFormat';\n if (computeControlChar(code.slice(0, 15)) !== code[15]) return 'badChecksum';\n return 'valid';\n}\n\n/** Convenience boolean: structurally sound AND control character matches. */\nexport function isValidCodiceFiscale(raw: string): boolean {\n return classifyCodiceFiscale(raw) === 'valid';\n}\n","/* ------------------------------------------------------------------ */\n/* Codice Fiscale (Italian fiscal code) — client-side DERIVATION. */\n/* */\n/* SCOPE: a pure, self-contained function that computes the 16-char */\n/* codice fiscale from a person's identity data when the caller already */\n/* holds it. This is a CONVENIENCE so a form that knows surname / name */\n/* / birth date / sex / birthplace can pre-fill the field — the server */\n/* (ValidateFiscalCodeService) remains the source of truth. */\n/* */\n/* OUT OF SCOPE: municipality-name → Belfiore (cadastral) code lookup. */\n/* That mapping requires a ~8000-row table the kit must not bundle, so */\n/* the caller supplies the 4-character `belfioreCode` directly. */\n/* Omocodia digit-substitution (used only when two people would share a */\n/* code) is also out of scope — the base, non-omocodic code is emitted. */\n/* ------------------------------------------------------------------ */\n\nimport { computeControlChar } from './is-valid-codice-fiscale';\n\n/** Identity inputs needed to derive the (non-omocodic) codice fiscale. */\nexport interface CodiceFiscaleInput {\n /** Family name (cognome). Diacritics are folded; non-letters ignored. */\n surname: string;\n /** Given name (nome). Diacritics are folded; non-letters ignored. */\n name: string;\n /** Date of birth — a `Date` or an ISO `YYYY-MM-DD` (or full ISO) string. */\n birthDate: Date | string;\n /** Biological sex as recorded for the fiscal code: 'M' or 'F'. */\n sex: 'M' | 'F';\n /** 4-character cadastral / Belfiore code of the birthplace (e.g. H501). */\n belfioreCode: string;\n}\n\nconst VOWELS = new Set(['A', 'E', 'I', 'O', 'U']);\n\n/** Month → fiscal-code letter (Jan→A … Dec→T), 0-indexed by month. */\nconst MONTH_LETTERS = [\n 'A',\n 'B',\n 'C',\n 'D',\n 'E',\n 'H',\n 'L',\n 'M',\n 'P',\n 'R',\n 'S',\n 'T',\n] as const;\n\n/**\n * Fold a free-text name to bare uppercase A–Z: strip diacritics via NFD,\n * drop combining marks, uppercase, and keep only A–Z. Spaces / apostrophes\n * in compound names collapse away (the algorithm treats the name as one run\n * of letters).\n */\nfunction foldToLetters(input: string): string {\n return input\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .toUpperCase()\n .replace(/[^A-Z]/g, '');\n}\n\nfunction consonantsOf(letters: string): string {\n return [...letters].filter((c) => !VOWELS.has(c)).join('');\n}\n\nfunction vowelsOf(letters: string): string {\n return [...letters].filter((c) => VOWELS.has(c)).join('');\n}\n\n/**\n * Surname triple: consonants first, then vowels, right-padded with 'X'.\n * (e.g. \"Rossi\" → R S S; \"Fo\" → F O X.)\n */\nfunction surnameCode(surname: string): string {\n const letters = foldToLetters(surname);\n const code = consonantsOf(letters) + vowelsOf(letters);\n return (code + 'XXX').slice(0, 3);\n}\n\n/**\n * Name triple. With 4+ consonants, take the 1st, 3rd and 4th (the standard\n * \"skip the 2nd consonant\" rule); otherwise consonants then vowels,\n * right-padded with 'X'. (e.g. \"Mario\" → M R A; \"Maria\" → M RA → MRA;\n * \"Gianfranco\" → G F R.)\n */\nfunction nameCode(name: string): string {\n const letters = foldToLetters(name);\n const cons = consonantsOf(letters);\n if (cons.length >= 4) {\n return cons[0] + cons[2] + cons[3];\n }\n const code = cons + vowelsOf(letters);\n return (code + 'XXX').slice(0, 3);\n}\n\n/** Coerce a `Date` or ISO string to a `Date`; throws on an unparseable value. */\nfunction toDate(birthDate: Date | string): Date {\n const d = birthDate instanceof Date ? birthDate : new Date(birthDate);\n if (Number.isNaN(d.getTime())) {\n throw new Error(`calculateCodiceFiscale: invalid birthDate \"${birthDate}\"`);\n }\n return d;\n}\n\n/**\n * Two-digit zero-padded value. The fiscal code uses LOCAL calendar fields\n * (a birth date is a calendar date, not an instant), so we read the UTC\n * fields of a date-only ISO string consistently — see the date handling\n * below.\n */\nfunction pad2(n: number): string {\n return String(n).padStart(2, '0');\n}\n\n/**\n * Birth-date triple: 2-digit year + month letter + 2-digit day (+40 for\n * female). Returns the 5 characters `YYMDD`.\n *\n * Date fields are read in UTC so a date-only string like \"1980-01-01\"\n * (parsed by `Date` as UTC midnight) yields day 01 regardless of the\n * runtime timezone. Callers passing a `Date` built from local components\n * should construct it at UTC midnight (e.g. `new Date('1980-01-01')`).\n */\nfunction birthCode(birthDate: Date | string, sex: 'M' | 'F'): string {\n const d = toDate(birthDate);\n const yy = pad2(d.getUTCFullYear() % 100);\n const monthLetter = MONTH_LETTERS[d.getUTCMonth()];\n const day = d.getUTCDate() + (sex === 'F' ? 40 : 0);\n return yy + monthLetter + pad2(day);\n}\n\n/**\n * Compute the full 16-character (non-omocodic) codice fiscale from a\n * person's identity data. The caller supplies the 4-char Belfiore code of\n * the birthplace (the kit does not bundle the municipality table).\n *\n * Throws if `birthDate` is unparseable or `belfioreCode` is not 4\n * `[A-Z][0-9]{3}`-shaped characters — i.e. a letter followed by 3 digits,\n * the canonical Belfiore shape.\n */\nexport function calculateCodiceFiscale(input: CodiceFiscaleInput): string {\n const { surname, name, birthDate, sex, belfioreCode } = input;\n\n const belfiore = belfioreCode.trim().toUpperCase();\n if (!/^[A-Z][0-9]{3}$/.test(belfiore)) {\n throw new Error(\n `calculateCodiceFiscale: belfioreCode must be a letter + 3 digits (e.g. \"H501\"), got \"${belfioreCode}\"`,\n );\n }\n\n const first15 =\n surnameCode(surname) +\n nameCode(name) +\n birthCode(birthDate, sex) +\n belfiore;\n\n return first15 + computeControlChar(first15);\n}\n","import {\n forwardRef,\n useCallback,\n useContext,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type ChangeEvent,\n type ClipboardEvent,\n type CompositionEvent,\n} from 'react';\nimport { cva } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { AlertCircle, CheckCircle2, Calculator } from 'lucide-react';\nimport {\n FormFieldContext,\n useFormField,\n} from '../form-field/form-field-context';\nimport {\n INPUT_SURFACE_CHROME,\n INPUT_SURFACE_HEIGHT,\n INPUT_SURFACE_TEXT,\n INPUT_SURFACE_TONE,\n} from '../_shared/input-surface';\nimport { composeRefs } from '../_shared/compose-refs';\nimport { useIsomorphicLayoutEffect } from '../../hooks/use-isomorphic-layout-effect';\nimport { useAgentRegistration } from '../../agent';\nimport { IconButton } from '../button';\nimport { fiscalCodeInputAgent } from './fiscal-code-input.agent';\nimport {\n classifyCodiceFiscale,\n type FiscalCodeReason,\n} from './is-valid-codice-fiscale';\nimport {\n calculateCodiceFiscale,\n type CodiceFiscaleInput,\n} from './calculate-codice-fiscale';\n\n/** Agent-readiness curated handle for FiscalCodeInput. */\nexport interface FiscalCodeInputHandle {\n getValue: () => string;\n setValue: (value: string) => void;\n clear: () => void;\n focus: () => void;\n isValid: () => boolean;\n}\n\n/** Structured payload emitted on every keystroke alongside the raw value. */\nexport interface FiscalCodeChangeMeta {\n /** Structurally sound AND control character matches (always 16 chars). */\n isValid: boolean;\n /** Whether all 16 characters are present (regardless of validity). */\n isComplete: boolean;\n /** Why the value is (in)valid — drives consumer messaging. */\n reason: FiscalCodeReason;\n}\n\nexport interface FiscalCodeInputProps {\n /** Controlled value (raw, uppercased, no spaces). Pair with onChange. */\n value?: string;\n /** Uncontrolled initial value. Normalised on mount. */\n defaultValue?: string;\n /** Fires on every keystroke with the normalised raw string + meta. */\n onChange?: (raw: string, meta: FiscalCodeChangeMeta) => void;\n size?: 'sm' | 'md' | 'lg';\n tone?: 'default' | 'error';\n /** When the invalid tone + error string surface. Never marks partial input invalid. */\n validateOn?: 'change' | 'blur' | 'submit';\n /** Controlled escape hatch to force the invalid state (e.g. server rejection). */\n showError?: boolean;\n /** Overrides the kit's default i18n error string. */\n errorMessage?: string;\n disabled?: boolean;\n readOnly?: boolean;\n required?: boolean;\n placeholder?: string;\n /** Render the \"16 characters\" caption when NOT inside a FormField. */\n showFormatHint?: boolean;\n /**\n * OPT-IN. When the consuming form already holds the person's identity\n * data, supply it here to render an inline \"calculate\" affordance: a\n * small icon button that derives the codice fiscale and fills the field.\n * The caller supplies the 4-char `belfioreCode` of the birthplace — the\n * kit does not bundle the municipality lookup table. Omit to render\n * nothing extra (no behavioural change). Ignored when readOnly/disabled.\n */\n calculateFrom?: CodiceFiscaleInput;\n id?: string;\n name?: string;\n className?: string;\n 'aria-label'?: string;\n}\n\nconst MAX_LEN = 16;\n\nconst wrapperVariants = cva(\n ['ds:relative ds:flex ds:items-center ds:w-full', INPUT_SURFACE_CHROME].join(\n ' ',\n ),\n {\n variants: {\n size: {\n sm: INPUT_SURFACE_HEIGHT.sm,\n md: INPUT_SURFACE_HEIGHT.md,\n lg: INPUT_SURFACE_HEIGHT.lg,\n },\n tone: {\n default: INPUT_SURFACE_TONE.default,\n error: `${INPUT_SURFACE_TONE.error} ds:focus-within:outline-destructive`,\n },\n },\n defaultVariants: { size: 'md', tone: 'default' },\n },\n);\n\nconst inputVariants = cva(\n [\n // dir=\"ltr\" + tabular-nums keep the alphanumeric code rendering\n // left-to-right and evenly spaced even under an RTL/CJK surrounding\n // UI — this is a value-RENDERING concern (the code is never mirrored),\n // not a layout-direction violation, so logical-prop rules don't apply\n // to the code glyphs themselves.\n 'ds:w-full ds:min-w-0 ds:bg-transparent ds:text-foreground ds:placeholder:text-muted-foreground',\n 'ds:border-0 ds:outline-none ds:tabular-nums ds:uppercase ds:tracking-wide',\n 'ds:disabled:cursor-not-allowed',\n 'ds:read-only:cursor-default',\n ].join(' '),\n {\n variants: {\n size: {\n sm: `ds:pe-3 ${INPUT_SURFACE_TEXT.sm}`,\n md: `ds:pe-3 ${INPUT_SURFACE_TEXT.md}`,\n lg: `ds:pe-4 ${INPUT_SURFACE_TEXT.lg}`,\n },\n // When the calculate affordance is shown, the input text starts after\n // the inline-start icon button (mirrors `hasEnd`'s pe-10 reservation).\n hasStart: {\n true: 'ds:ps-10',\n false: '',\n },\n hasEnd: {\n true: 'ds:pe-10',\n false: '',\n },\n },\n compoundVariants: [\n { size: 'sm', hasStart: false, class: 'ds:ps-3' },\n { size: 'md', hasStart: false, class: 'ds:ps-3' },\n { size: 'lg', hasStart: false, class: 'ds:ps-4' },\n ],\n defaultVariants: { size: 'md', hasStart: false, hasEnd: false },\n },\n);\n\nconst adornmentEnd =\n 'ds:absolute ds:inset-y-0 ds:end-0 ds:pe-3 ds:flex ds:items-center ds:pointer-events-none ds:[&_svg]:size-4';\n\n// Inline-start wrapper for the calculate icon button. Positioned over the\n// reserved `ps-10` gutter; the button itself remains pointer-interactive.\nconst adornmentStart =\n 'ds:absolute ds:inset-y-0 ds:start-0 ds:ps-1 ds:flex ds:items-center';\n\nconst captionBase = 'type-body-sm ds:mt-[var(--spacing-xs)]';\n\n/** Uppercase, strip non-[A-Z0-9], normalise full-width / Eastern-Arabic\n * digits, and cap at 16 characters. */\nfunction normaliseFiscalCode(input: string): string {\n return (\n input\n .normalize('NFKC')\n // Eastern-Arabic & Extended-Arabic-Indic digits → ASCII (otp-input precedent).\n .replace(/[٠-٩]/g, (c) => String(c.charCodeAt(0) - 0x0660))\n .replace(/[۰-۹]/g, (c) => String(c.charCodeAt(0) - 0x06f0))\n .toUpperCase()\n .replace(/[^A-Z0-9]/g, '')\n .slice(0, MAX_LEN)\n );\n}\n\n/** Count [A-Z0-9] characters before `position` in the RAW (pre-normalise)\n * string, so the caret can be restored after re-normalising. */\nfunction countKeptBefore(str: string, position: number): number {\n let kept = 0;\n for (let i = 0; i < position && i < str.length; i += 1) {\n const c = str[i];\n if (\n (c >= '0' && c <= '9') ||\n (c >= 'A' && c <= 'Z') ||\n (c >= 'a' && c <= 'z')\n ) {\n kept += 1;\n }\n }\n return kept;\n}\n\nexport const FiscalCodeInput = forwardRef<\n HTMLInputElement,\n FiscalCodeInputProps\n>(function FiscalCodeInput(\n {\n value,\n defaultValue,\n onChange,\n size = 'md',\n tone = 'default',\n validateOn = 'blur',\n showError,\n errorMessage,\n disabled,\n readOnly,\n required,\n placeholder,\n showFormatHint = true,\n calculateFrom,\n id,\n name,\n className,\n 'aria-label': ariaLabel,\n },\n ref,\n) {\n const { t } = useTranslation();\n const ctx = useFormField();\n const inFormField = useContext(FormFieldContext) !== null;\n\n const isControlled = value !== undefined;\n const [internalValue, setInternalValue] = useState<string>(() =>\n normaliseFiscalCode(defaultValue ?? ''),\n );\n const currentValue = isControlled\n ? normaliseFiscalCode(value ?? '')\n : internalValue;\n\n const [blurred, setBlurred] = useState(false);\n const composingRef = useRef(false);\n const pendingCaretRef = useRef<number | null>(null);\n\n const inputRef = useRef<HTMLInputElement | null>(null);\n const composedRef = composeRefs(ref, inputRef);\n\n const reactId = useId();\n const generatedHintId = `${reactId}-hint`;\n const generatedStatusId = `${reactId}-status`;\n const generatedErrorId = `${reactId}-error`;\n\n // DEV-time guard: a standalone field with no visible label needs an\n // aria-label, mirroring Button's icon-only guard. No-op in production.\n useEffect(() => {\n const isDev =\n typeof import.meta !== 'undefined' &&\n typeof import.meta.env !== 'undefined' &&\n import.meta.env.DEV === true;\n if (isDev && !inFormField && !ariaLabel) {\n // eslint-disable-next-line no-console\n console.warn(\n '[FiscalCodeInput] No FormField/label and no `aria-label` — the field has no accessible name. Wrap it in a FormField or pass `aria-label`.',\n );\n }\n }, [inFormField, ariaLabel]);\n\n const reason = useMemo(\n () => classifyCodiceFiscale(currentValue),\n [currentValue],\n );\n const isComplete = currentValue.length === MAX_LEN;\n const isValid = reason === 'valid';\n\n const effectiveDisabled =\n (inFormField ? ctx.disabled : false) || Boolean(disabled);\n const effectiveRequired =\n (inFormField ? ctx.required : false) || Boolean(required);\n\n // Whether the component's OWN feedback should surface.\n //\n // `showError` is a controlled escape hatch (e.g. the server rejected the\n // code on submit): it forces the error regardless of completeness or the\n // client's own verdict. Otherwise the client only flags a COMPLETE\n // (16-char) code that fails its structural/checksum check — never a\n // partially-typed code — and `validateOn` governs the trigger.\n const ownFeedbackActive =\n !readOnly &&\n (Boolean(showError) ||\n (isComplete &&\n !isValid &&\n (validateOn === 'change' || (validateOn === 'blur' && blurred))));\n\n // When inside a FormField with its own error, FormField's role=alert wins\n // and this component stays silent (no double message / duplicate\n // aria-describedby target).\n const formFieldHasError = inFormField && ctx.invalid;\n const showOwnError = ownFeedbackActive && !formFieldHasError;\n\n const effectiveInvalid = formFieldHasError || showOwnError;\n const effectiveTone: 'default' | 'error' =\n effectiveInvalid || tone === 'error' ? 'error' : 'default';\n\n const ownErrorText = useMemo(() => {\n if (errorMessage) return errorMessage;\n if (reason === 'badChecksum') return t('inputs.fiscalCode.errorChecksum');\n if (reason === 'badFormat') return t('inputs.fiscalCode.errorFormat');\n return t('inputs.fiscalCode.errorIncomplete');\n }, [errorMessage, reason, t]);\n\n // Standalone (no FormField) describedby: format hint + the live region that\n // is currently surfacing. When the component is showing its OWN error we\n // point at the assertive error node; otherwise at the polite status node\n // (valid affordance / typing progress). Inside a FormField, the FormField\n // owns describedBy entirely.\n const wantsHint = !inFormField && showFormatHint && !readOnly;\n const standaloneDescribedBy = inFormField\n ? undefined\n : [\n wantsHint ? generatedHintId : null,\n showOwnError ? generatedErrorId : generatedStatusId,\n ]\n .filter(Boolean)\n .join(' ') || undefined;\n const describedBy = inFormField\n ? ctx.describedBy || undefined\n : standaloneDescribedBy;\n\n const inputId = id ?? ctx.id;\n\n const emit = useCallback(\n (next: string) => {\n const nextReason = classifyCodiceFiscale(next);\n onChange?.(next, {\n isValid: nextReason === 'valid',\n isComplete: next.length === MAX_LEN,\n reason: nextReason,\n });\n },\n [onChange],\n );\n\n const commit = useCallback(\n (next: string) => {\n if (!isControlled) setInternalValue(next);\n emit(next);\n },\n [isControlled, emit],\n );\n\n // Restore caret after a normalising re-render that may have changed the\n // string length (mid-string edit / paste). Mirrors phone-input's caret\n // discipline.\n useIsomorphicLayoutEffect(() => {\n if (pendingCaretRef.current == null) return;\n const pos = pendingCaretRef.current;\n pendingCaretRef.current = null;\n const node = inputRef.current;\n if (node && document.activeElement === node) {\n // Re-clamp against the value the input ACTUALLY rendered this pass, not\n // the value we committed: a controlled parent may transform or reject\n // the emitted change so the echoed value diverges. Clamping to the live\n // DOM length keeps the caret inside the rendered string.\n const safePos = Math.min(pos, node.value.length);\n node.setSelectionRange(safePos, safePos);\n }\n });\n\n const handleChange = (event: ChangeEvent<HTMLInputElement>) => {\n if (readOnly) return;\n // Don't re-mask mid-IME composition or the user loses input; the\n // uppercase mask is re-applied on composition end / next change.\n if (composingRef.current) return;\n const target = event.target;\n const raw = target.value;\n const caret = target.selectionStart ?? raw.length;\n const keptBefore = countKeptBefore(raw, caret);\n const next = normaliseFiscalCode(raw);\n pendingCaretRef.current = Math.min(keptBefore, next.length);\n commit(next);\n };\n\n const handleCompositionStart = () => {\n composingRef.current = true;\n };\n\n const handleCompositionEnd = (event: CompositionEvent<HTMLInputElement>) => {\n composingRef.current = false;\n if (readOnly) return;\n const next = normaliseFiscalCode(event.currentTarget.value);\n pendingCaretRef.current = next.length;\n commit(next);\n };\n\n const handlePaste = (event: ClipboardEvent<HTMLInputElement>) => {\n if (readOnly) return;\n const text = event.clipboardData.getData('text');\n event.preventDefault();\n const node = inputRef.current;\n const selStart = node?.selectionStart ?? currentValue.length;\n const selEnd = node?.selectionEnd ?? currentValue.length;\n const cleaned = normaliseFiscalCode(text);\n const before = currentValue.slice(0, selStart);\n const after = currentValue.slice(selEnd);\n const next = normaliseFiscalCode(before + cleaned + after);\n pendingCaretRef.current = Math.min((before + cleaned).length, next.length);\n commit(next);\n };\n\n const handleBlur = () => {\n if (validateOn === 'blur') setBlurred(true);\n };\n\n // Opt-in derivation. Compute the CF from the supplied identity data and\n // route it through the SAME commit path as typing/paste so the controlled\n // / uncontrolled contract, the validation verdict, and the live-region\n // announcement all behave identically to a user-entered value.\n const handleCalculate = () => {\n if (!calculateFrom || readOnly || effectiveDisabled) return;\n let computed: string;\n try {\n computed = calculateCodiceFiscale(calculateFrom);\n } catch {\n // Bad identity data (unparseable date / malformed Belfiore code) is a\n // caller error, not a user action — fail quietly rather than throwing\n // out of an event handler and leave the field untouched.\n return;\n }\n const next = normaliseFiscalCode(computed);\n // After a successful derivation the value is complete: let blur-gated\n // validation surface immediately (the derived code is valid by\n // construction, so this confirms rather than errors).\n if (validateOn === 'blur') setBlurred(true);\n commit(next);\n inputRef.current?.focus();\n };\n\n const agentHandle = useMemo<FiscalCodeInputHandle>(\n () => ({\n getValue: () => currentValue,\n setValue: (next) => {\n const normalised = normaliseFiscalCode(next);\n if (!isControlled) setInternalValue(normalised);\n emit(normalised);\n inputRef.current?.focus();\n },\n clear: () => {\n if (!isControlled) setInternalValue('');\n emit('');\n inputRef.current?.focus();\n },\n focus: () => inputRef.current?.focus(),\n isValid: () => classifyCodiceFiscale(currentValue) === 'valid',\n }),\n [currentValue, isControlled, emit],\n );\n useAgentRegistration(fiscalCodeInputAgent, agentHandle, id);\n\n const resolvedPlaceholder = placeholder ?? t('inputs.fiscalCode.placeholder');\n\n // Polite status text (role=status). Carries ONLY non-error affordances:\n // the valid confirmation and, while typing an incomplete code, the live\n // character-count progress. Errors the user must act on are announced\n // assertively via the separate role=alert node below — never here.\n // Gated on !inFormField (matching showEndIcon): inside a FormField the\n // FormField owns every helper/status/error slot, so this stays silent.\n const statusMessage =\n readOnly || inFormField\n ? ''\n : isValid\n ? t('inputs.fiscalCode.valid')\n : currentValue.length > 0 && !isComplete\n ? t('inputs.fiscalCode.charactersEntered', {\n count: currentValue.length,\n })\n : '';\n\n // Assertive error text (role=alert) — surfaces only the component's own\n // actionable validation error, mirroring FormField's error <p>.\n const errorText = showOwnError ? ownErrorText : '';\n\n const showEndIcon = !readOnly && (showOwnError || (isValid && !inFormField));\n\n // Opt-in calculate affordance: only when identity data is supplied AND the\n // field is editable. Disabled/read-only fields render nothing extra.\n const showCalculate =\n Boolean(calculateFrom) && !readOnly && !effectiveDisabled;\n\n return (\n <div\n className=\"ds:flex ds:flex-col\"\n data-component=\"fiscal-code-input\"\n data-component-id={id}\n >\n <div\n data-slot=\"fiscal-code-input\"\n className={wrapperVariants({ size, tone: effectiveTone, className })}\n >\n {showCalculate ? (\n <span className={adornmentStart}>\n <IconButton\n type=\"button\"\n size=\"sm\"\n intent=\"ghost\"\n icon={<Calculator />}\n aria-label={t('inputs.fiscalCode.calculate')}\n onClick={handleCalculate}\n />\n </span>\n ) : null}\n <input\n ref={composedRef}\n id={inputId}\n name={name}\n // dir=\"ltr\": the codice fiscale glyphs render LTR even under an\n // RTL surrounding UI — a value-rendering concern, not a layout\n // direction violation (see inputVariants comment).\n dir=\"ltr\"\n type=\"text\"\n inputMode=\"text\"\n autoCapitalize=\"characters\"\n autoCorrect=\"off\"\n autoComplete=\"off\"\n spellCheck={false}\n maxLength={MAX_LEN}\n // Loose structural mirror: 15 [A-Z0-9] + a final letter control\n // char (value is always uppercased). The real position-class /\n // checksum rule is enforced in classifyCodiceFiscale; this native\n // pattern is only a non-JS fallback.\n pattern=\"[A-Z0-9]{15}[A-Z]\"\n value={currentValue}\n placeholder={resolvedPlaceholder}\n disabled={effectiveDisabled}\n readOnly={readOnly}\n aria-label={ariaLabel}\n aria-describedby={describedBy}\n aria-invalid={effectiveInvalid || undefined}\n aria-required={effectiveRequired || undefined}\n onChange={handleChange}\n onCompositionStart={handleCompositionStart}\n onCompositionEnd={handleCompositionEnd}\n onPaste={handlePaste}\n onBlur={handleBlur}\n className={inputVariants({\n size,\n hasStart: showCalculate,\n hasEnd: showEndIcon,\n })}\n />\n {showEndIcon ? (\n <span\n aria-hidden=\"true\"\n className={`${adornmentEnd} ${\n showOwnError ? 'ds:text-destructive' : 'ds:text-success'\n }`}\n >\n {showOwnError ? <AlertCircle /> : <CheckCircle2 />}\n </span>\n ) : null}\n </div>\n\n {wantsHint ? (\n <p\n id={generatedHintId}\n className={`${captionBase} ds:text-muted-foreground`}\n >\n {t('inputs.fiscalCode.formatHint')}\n </p>\n ) : null}\n\n {/* Polite live region (role=status): announces the valid affordance\n and the typing-progress count as TEXT, satisfying 1.4.1 (never\n colour-only). Never carries an actionable error — that goes to the\n assertive node below, mirroring the kit's input-error convention. */}\n <p\n id={generatedStatusId}\n role=\"status\"\n aria-live=\"polite\"\n className={`${captionBase} ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)] ${\n isValid ? 'ds:text-success' : 'ds:text-muted-foreground'\n } ${statusMessage ? '' : 'ds:sr-only'}`}\n >\n {statusMessage ? (\n <>\n {isValid ? (\n <CheckCircle2\n aria-hidden=\"true\"\n className=\"ds:size-4 ds:shrink-0\"\n />\n ) : null}\n <span>{statusMessage}</span>\n </>\n ) : null}\n </p>\n\n {/* Assertive error region (role=alert): a validation error the user\n must correct is announced assertively, mirroring FormField's error\n <p> (form-field.tsx). Rendered only when the component owns the\n error — inside a FormField, FormField's role=alert wins. */}\n {errorText ? (\n <p\n id={generatedErrorId}\n role=\"alert\"\n className={`${captionBase} ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)] ds:text-destructive`}\n >\n <AlertCircle aria-hidden=\"true\" className=\"ds:size-4 ds:shrink-0\" />\n <span>{errorText}</span>\n </p>\n ) : null}\n </div>\n );\n});\n\nFiscalCodeInput.displayName = 'FiscalCodeInput';\n\nexport { wrapperVariants as fiscalCodeWrapperVariants };\n"],"names":["__iconNode","Calculator","createLucideIcon","fiscalCodeInputAgent","handle","args","LETTER_POSITIONS","DIGIT_POSITIONS","ODD_MAP","EVEN_MAP","REMAINDER_TO_CONTROL","hasValidStructure","code","i","ch","isDigit","computeControlChar","first15","sum","classifyCodiceFiscale","raw","isValidCodiceFiscale","VOWELS","MONTH_LETTERS","foldToLetters","input","consonantsOf","letters","c","vowelsOf","surnameCode","surname","nameCode","name","cons","toDate","birthDate","d","pad2","n","birthCode","sex","yy","monthLetter","day","calculateCodiceFiscale","belfioreCode","belfiore","MAX_LEN","wrapperVariants","cva","INPUT_SURFACE_CHROME","INPUT_SURFACE_HEIGHT","INPUT_SURFACE_TONE","inputVariants","INPUT_SURFACE_TEXT","adornmentEnd","adornmentStart","captionBase","normaliseFiscalCode","countKeptBefore","str","position","kept","FiscalCodeInput","forwardRef","value","defaultValue","onChange","size","tone","validateOn","showError","errorMessage","disabled","readOnly","required","placeholder","showFormatHint","calculateFrom","id","className","ariaLabel","ref","t","useTranslation","ctx","useFormField","inFormField","useContext","FormFieldContext","isControlled","internalValue","setInternalValue","useState","currentValue","blurred","setBlurred","composingRef","useRef","pendingCaretRef","inputRef","composedRef","composeRefs","reactId","useId","generatedHintId","generatedStatusId","generatedErrorId","useEffect","reason","useMemo","isComplete","isValid","effectiveDisabled","effectiveRequired","ownFeedbackActive","formFieldHasError","showOwnError","effectiveInvalid","effectiveTone","ownErrorText","wantsHint","standaloneDescribedBy","describedBy","inputId","emit","useCallback","next","nextReason","commit","useIsomorphicLayoutEffect","pos","node","safePos","handleChange","event","target","caret","keptBefore","handleCompositionStart","handleCompositionEnd","handlePaste","text","selStart","selEnd","cleaned","before","after","handleBlur","handleCalculate","computed","_a","agentHandle","normalised","useAgentRegistration","resolvedPlaceholder","statusMessage","errorText","showEndIcon","showCalculate","jsxs","jsx","IconButton","AlertCircle","CheckCircle2","Fragment"],"mappings":"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","x_google_ignoreList":[0]}
|
|
@@ -9,7 +9,7 @@ import { C as ne, b as le, a as oe } from "./collapsible-BrnRiCC6.js";
|
|
|
9
9
|
import { D as de } from "./date-picker-DzQS8mvt.js";
|
|
10
10
|
import { D as S } from "./description-list-ClNLdRMy.js";
|
|
11
11
|
import { E as ce } from "./email-input-Dpe63k0K.js";
|
|
12
|
-
import { F as pe } from "./fiscal-code-input-
|
|
12
|
+
import { F as pe } from "./fiscal-code-input-QP9gkyDE.js";
|
|
13
13
|
import { N as ue } from "./number-input-DjWzmlEY.js";
|
|
14
14
|
import { P as me } from "./panel-header-D313n_9-.js";
|
|
15
15
|
import { P as fe } from "./phone-input-D00ZBAm-.js";
|
|
@@ -775,4 +775,4 @@ export {
|
|
|
775
775
|
Ae as P,
|
|
776
776
|
je as p
|
|
777
777
|
};
|
|
778
|
-
//# sourceMappingURL=patient-details-
|
|
778
|
+
//# sourceMappingURL=patient-details-COvYWp2e.js.map
|