@alfadocs/ui-kit-debug 1.90.1 → 1.90.2
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/address-autocomplete-DR4Xn23Z.js +519 -0
- package/dist/_chunks/address-autocomplete-DR4Xn23Z.js.map +1 -0
- package/dist/_chunks/{address-fields-CfnXK8RT.js → address-fields-qxQkGwPf.js} +5 -5
- package/dist/_chunks/{address-fields-CfnXK8RT.js.map → address-fields-qxQkGwPf.js.map} +1 -1
- package/dist/_chunks/{ai-permission-notice-CoW22jx1.js → ai-permission-notice-VNh3W57L.js} +2 -2
- package/dist/_chunks/{ai-permission-notice-CoW22jx1.js.map → ai-permission-notice-VNh3W57L.js.map} +1 -1
- package/dist/_chunks/{anamnesis-summary-rows-fbEQwcuW.js → anamnesis-summary-rows-EKPfVCmh.js} +2 -2
- package/dist/_chunks/{anamnesis-summary-rows-fbEQwcuW.js.map → anamnesis-summary-rows-EKPfVCmh.js.map} +1 -1
- package/dist/_chunks/autocomplete-BXMcNoa3.js +562 -0
- package/dist/_chunks/autocomplete-BXMcNoa3.js.map +1 -0
- package/dist/_chunks/{balance-badge-cell-C4FYwmrZ.js → balance-badge-cell-D9VhFp0L.js} +3 -3
- package/dist/_chunks/{balance-badge-cell-C4FYwmrZ.js.map → balance-badge-cell-D9VhFp0L.js.map} +1 -1
- package/dist/_chunks/{booking-C0FoW8Yx.js → booking-CcE_oviI.js} +1896 -1859
- package/dist/_chunks/booking-CcE_oviI.js.map +1 -0
- package/dist/_chunks/{calendar-appointment-editor-dialog-C1v2MNE4.js → calendar-appointment-editor-dialog-CiAGAX2t.js} +7 -7
- package/dist/_chunks/{calendar-appointment-editor-dialog-C1v2MNE4.js.map → calendar-appointment-editor-dialog-CiAGAX2t.js.map} +1 -1
- package/dist/_chunks/{checkbox-BjDv-r3o.js → checkbox-a7Sh-dXb.js} +32 -31
- package/dist/_chunks/checkbox-a7Sh-dXb.js.map +1 -0
- package/dist/_chunks/{checkbox-group-Cw2H5qaq.js → checkbox-group-eGdv9fZc.js} +2 -2
- package/dist/_chunks/{checkbox-group-Cw2H5qaq.js.map → checkbox-group-eGdv9fZc.js.map} +1 -1
- package/dist/_chunks/{city-input-CJVGswxp.js → city-input-CA59CjnV.js} +2 -2
- package/dist/_chunks/{city-input-CJVGswxp.js.map → city-input-CA59CjnV.js.map} +1 -1
- package/dist/_chunks/{combobox-CDPm_n0p.js → combobox-D-gpgEDy.js} +314 -294
- package/dist/_chunks/combobox-D-gpgEDy.js.map +1 -0
- package/dist/_chunks/{country-select-DQ8q7ypA.js → country-select-BfmX9y5i.js} +2 -2
- package/dist/_chunks/{country-select-DQ8q7ypA.js.map → country-select-BfmX9y5i.js.map} +1 -1
- package/dist/_chunks/{data-table-B_IcS0Ke.js → data-table-CqQgoNsU.js} +2 -2
- package/dist/_chunks/{data-table-B_IcS0Ke.js.map → data-table-CqQgoNsU.js.map} +1 -1
- package/dist/_chunks/{face-scheme-BgJGFDTa.js → face-scheme-BKSE98bo.js} +2 -2
- package/dist/_chunks/{face-scheme-BgJGFDTa.js.map → face-scheme-BKSE98bo.js.map} +1 -1
- package/dist/_chunks/{file-manager-C9YOT-Dn.js → file-manager-BnI1ZWZu.js} +2 -2
- package/dist/_chunks/{file-manager-C9YOT-Dn.js.map → file-manager-BnI1ZWZu.js.map} +1 -1
- package/dist/_chunks/{header-settings-BVhjndtV.js → header-settings-BeA2fnol.js} +24 -23
- package/dist/_chunks/header-settings-BeA2fnol.js.map +1 -0
- package/dist/_chunks/{heatmap-HTz3Jvzy.js → heatmap-fCxwNz2o.js} +2 -2
- package/dist/_chunks/{heatmap-HTz3Jvzy.js.map → heatmap-fCxwNz2o.js.map} +1 -1
- package/dist/_chunks/{link-cell-renderer-C0ynDik7.js → link-cell-renderer-CnCgudvq.js} +3 -3
- package/dist/_chunks/{link-cell-renderer-C0ynDik7.js.map → link-cell-renderer-CnCgudvq.js.map} +1 -1
- package/dist/_chunks/{login-dev-card-DYwbL5sD.js → login-dev-card-BZBR58mu.js} +2 -2
- package/dist/_chunks/{login-dev-card-DYwbL5sD.js.map → login-dev-card-BZBR58mu.js.map} +1 -1
- package/dist/_chunks/{map-view-Bvi06RVh.js → map-view-UrNgxBy3.js} +260 -237
- package/dist/_chunks/map-view-UrNgxBy3.js.map +1 -0
- package/dist/_chunks/{index.modern-BeRXQVdc.js → maps-core-gate-DkNqGkm3.js} +360 -319
- package/dist/_chunks/maps-core-gate-DkNqGkm3.js.map +1 -0
- package/dist/_chunks/{marketplace-app-shell-x_abo_ye.js → marketplace-app-shell-CmZx0Oam.js} +2 -2
- package/dist/_chunks/{marketplace-app-shell-x_abo_ye.js.map → marketplace-app-shell-CmZx0Oam.js.map} +1 -1
- package/dist/_chunks/{notes-panel-CZO1qsD-.js → notes-panel-Dywo6R55.js} +2 -2
- package/dist/_chunks/{notes-panel-CZO1qsD-.js.map → notes-panel-Dywo6R55.js.map} +1 -1
- package/dist/_chunks/{patient-details-D0P5eog5.js → patient-details-BUr7Oemx.js} +2 -2
- package/dist/_chunks/{patient-details-D0P5eog5.js.map → patient-details-BUr7Oemx.js.map} +1 -1
- package/dist/_chunks/{patient-field-row-R73dZJY6.js → patient-field-row-bJk8Q_qr.js} +5 -5
- package/dist/_chunks/{patient-field-row-R73dZJY6.js.map → patient-field-row-bJk8Q_qr.js.map} +1 -1
- package/dist/_chunks/patient-search-Ca9j5cWb.js +1306 -0
- package/dist/_chunks/patient-search-Ca9j5cWb.js.map +1 -0
- package/dist/_chunks/{patient-summary-card-6U74-ivO.js → patient-summary-card-CCQZ8X37.js} +2 -2
- package/dist/_chunks/{patient-summary-card-6U74-ivO.js.map → patient-summary-card-CCQZ8X37.js.map} +1 -1
- package/dist/_chunks/{periodontal-diagnosis-B9YmmVmM.js → periodontal-diagnosis-DD3hrg9X.js} +2 -2
- package/dist/_chunks/{periodontal-diagnosis-B9YmmVmM.js.map → periodontal-diagnosis-DD3hrg9X.js.map} +1 -1
- package/dist/_chunks/{permission-matrix-BoQjENGV.js → permission-matrix-BJ6sg3Zp.js} +3 -3
- package/dist/_chunks/{permission-matrix-BoQjENGV.js.map → permission-matrix-BJ6sg3Zp.js.map} +1 -1
- package/dist/_chunks/{practice-results-B61krlwu.js → practice-results-DQuOfqej.js} +2 -2
- package/dist/_chunks/{practice-results-B61krlwu.js.map → practice-results-DQuOfqej.js.map} +1 -1
- package/dist/_chunks/{province-select-CPdTwEob.js → province-select-D64whw0m.js} +2 -2
- package/dist/_chunks/{province-select-CPdTwEob.js.map → province-select-D64whw0m.js.map} +1 -1
- package/dist/_chunks/{registration-form-DmP3YUfp.js → registration-form-CRm6DaB9.js} +2 -2
- package/dist/_chunks/{registration-form-DmP3YUfp.js.map → registration-form-CRm6DaB9.js.map} +1 -1
- package/dist/_chunks/{reviews-panel-UzQQLb-z.js → reviews-panel-B7InBORU.js} +42 -41
- package/dist/_chunks/reviews-panel-B7InBORU.js.map +1 -0
- package/dist/_chunks/{rich-text-editor-BZTyxQBd.js → rich-text-editor-BfEu57dk.js} +3 -3
- package/dist/_chunks/{rich-text-editor-BZTyxQBd.js.map → rich-text-editor-BfEu57dk.js.map} +1 -1
- package/dist/_chunks/{slot-grid-Bb13H9Rl.js → slot-grid-DrwynKeN.js} +91 -89
- package/dist/_chunks/{slot-grid-Bb13H9Rl.js.map → slot-grid-DrwynKeN.js.map} +1 -1
- package/dist/_chunks/{task-editor-BOETWbjU.js → task-editor-CI1SKUNc.js} +2 -2
- package/dist/_chunks/{task-editor-BOETWbjU.js.map → task-editor-CI1SKUNc.js.map} +1 -1
- package/dist/_chunks/{use-appointment-details-read-CWN-nJCZ.js → use-appointment-details-read-BytPq3Ux.js} +2 -2
- package/dist/_chunks/{use-appointment-details-read-CWN-nJCZ.js.map → use-appointment-details-read-BytPq3Ux.js.map} +1 -1
- package/dist/_chunks/{voice-control-panel-BziKE-KK.js → voice-control-panel-BP0otrID.js} +2 -2
- package/dist/_chunks/{voice-control-panel-BziKE-KK.js.map → voice-control-panel-BP0otrID.js.map} +1 -1
- package/dist/_chunks/{workflow-webhook-action-DulCpCRz.js → workflow-webhook-action-B_nBJ_ht.js} +2 -2
- package/dist/_chunks/{workflow-webhook-action-DulCpCRz.js.map → workflow-webhook-action-B_nBJ_ht.js.map} +1 -1
- package/dist/agent-catalog.json +2 -2
- package/dist/agent-i18n/en.json +1 -1
- package/dist/components/_shared/maps-core-gate.d.ts +18 -0
- package/dist/components/_shared/maps-core-gate.d.ts.map +1 -0
- package/dist/components/address-autocomplete/address-autocomplete.d.ts.map +1 -1
- package/dist/components/address-autocomplete/index.js +1 -1
- package/dist/components/address-fields/index.js +1 -1
- package/dist/components/ai-permission-notice/index.js +1 -1
- package/dist/components/appointment-details-panel/index.js +1 -1
- package/dist/components/autocomplete/autocomplete.agent.d.ts.map +1 -1
- package/dist/components/autocomplete/autocomplete.d.ts.map +1 -1
- package/dist/components/autocomplete/index.js +1 -1
- package/dist/components/booking/booking.d.ts.map +1 -1
- package/dist/components/booking/details-form.d.ts.map +1 -1
- package/dist/components/booking/index.js +1 -1
- package/dist/components/checkbox/checkbox.d.ts.map +1 -1
- package/dist/components/checkbox/index.js +1 -1
- package/dist/components/checkbox-group/index.js +1 -1
- package/dist/components/city-input/index.js +1 -1
- package/dist/components/combobox/combobox.d.ts.map +1 -1
- package/dist/components/combobox/index.js +1 -1
- package/dist/components/country-select/index.js +1 -1
- package/dist/components/data-table/index.js +2 -2
- package/dist/components/face-scheme/index.js +1 -1
- package/dist/components/file-manager/index.js +1 -1
- package/dist/components/header-settings/header-settings.d.ts +2 -1
- package/dist/components/header-settings/header-settings.d.ts.map +1 -1
- package/dist/components/header-settings/index.js +1 -1
- package/dist/components/heatmap/index.js +1 -1
- package/dist/components/map-view/index.js +1 -1
- package/dist/components/map-view/map-view.d.ts.map +1 -1
- package/dist/components/notes-panel/index.js +1 -1
- package/dist/components/patient-details/index.js +1 -1
- package/dist/components/patient-search/index.js +1 -1
- package/dist/components/patient-search/patient-search.d.ts.map +1 -1
- package/dist/components/patient-summary-card/index.js +1 -1
- package/dist/components/patient-table/index.js +1 -1
- package/dist/components/periodontal-diagnosis/index.js +1 -1
- package/dist/components/permission-matrix/index.js +1 -1
- package/dist/components/practice-results/index.js +1 -1
- package/dist/components/province-select/index.js +1 -1
- package/dist/components/reviews-panel/index.js +1 -1
- package/dist/components/reviews-panel/reviews-panel.d.ts.map +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.map +1 -1
- package/dist/components/task-editor/index.js +1 -1
- package/dist/components/voice-control-panel/index.js +1 -1
- package/dist/host-compat.css +1 -10
- package/dist/index.js +37 -37
- package/dist/patterns/anamnesis/index.js +1 -1
- package/dist/patterns/calendar/index.js +1 -1
- package/dist/patterns/login-form/index.js +1 -1
- package/dist/patterns/marketplace-app-shell/index.js +1 -1
- package/dist/patterns/registration-form/index.js +1 -1
- package/dist/patterns/workflow-webhook-action/index.js +1 -1
- package/dist/tokens.css +1 -1
- package/package.json +1 -1
- package/dist/_chunks/address-autocomplete-bPR2mNBt.js +0 -498
- package/dist/_chunks/address-autocomplete-bPR2mNBt.js.map +0 -1
- package/dist/_chunks/autocomplete-CnB1mHGc.js +0 -539
- package/dist/_chunks/autocomplete-CnB1mHGc.js.map +0 -1
- package/dist/_chunks/booking-C0FoW8Yx.js.map +0 -1
- package/dist/_chunks/checkbox-BjDv-r3o.js.map +0 -1
- package/dist/_chunks/combobox-CDPm_n0p.js.map +0 -1
- package/dist/_chunks/header-settings-BVhjndtV.js.map +0 -1
- package/dist/_chunks/index.modern-BeRXQVdc.js.map +0 -1
- package/dist/_chunks/map-view-Bvi06RVh.js.map +0 -1
- package/dist/_chunks/patient-search-CCOUZABE.js +0 -1196
- package/dist/_chunks/patient-search-CCOUZABE.js.map +0 -1
- package/dist/_chunks/reviews-panel-UzQQLb-z.js.map +0 -1
package/dist/_chunks/{patient-summary-card-6U74-ivO.js.map → patient-summary-card-CCQZ8X37.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"patient-summary-card-6U74-ivO.js","sources":["../../node_modules/lucide-react/dist/esm/icons/file-exclamation-point.mjs","../../node_modules/lucide-react/dist/esm/icons/message-square-warning.mjs","../../src/components/patient-summary-card/patient-summary-card.agent.ts","../../src/components/patient-summary-card/patient-summary-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 [\n \"path\",\n {\n d: \"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z\",\n key: \"1oefj6\"\n }\n ],\n [\"path\", { d: \"M12 9v4\", key: \"juzpu7\" }],\n [\"path\", { d: \"M12 17h.01\", key: \"p32p05\" }]\n];\nconst FileExclamationPoint = createLucideIcon(\"file-exclamation-point\", __iconNode);\n\nexport { __iconNode, FileExclamationPoint as default };\n//# sourceMappingURL=file-exclamation-point.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: \"M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z\",\n key: \"18887p\"\n }\n ],\n [\"path\", { d: \"M12 15h.01\", key: \"q59x07\" }],\n [\"path\", { d: \"M12 7v4\", key: \"xawao1\" }]\n];\nconst MessageSquareWarning = createLucideIcon(\"message-square-warning\", __iconNode);\n\nexport { __iconNode, MessageSquareWarning as default };\n//# sourceMappingURL=message-square-warning.mjs.map\n","import type { AgentAdapter } from '../../agent/types';\nimport type { PatientSummaryCardHandle } from './patient-summary-card';\n\n/* -------------------------------------------------------------------- */\n/* Agent adapter — PatientSummaryCard */\n/* */\n/* Read-only adapter. Surfaces a STRUCTURAL snapshot of the patient */\n/* overview — counts, flags, and the consumer id only. Never the patient */\n/* name, age, contact details, or any clinical content, so an agent / */\n/* MCP runtime can answer \"does this patient have unpaid balances / */\n/* unsigned documents / AI consent?\" without re-parsing the DOM and */\n/* without leaking PHI (PRS §Security). */\n/* -------------------------------------------------------------------- */\n\nexport const patientSummaryCardAgent: AgentAdapter<PatientSummaryCardHandle> = {\n id: 'patient-summary-card',\n // The agent surface is a structural snapshot only — the single handle method\n // is a getSummary projection. The card MAY be human-customized (the optional\n // per-context \"Customize fields\" cog), but that field reordering is a UI\n // concern and is deliberately NOT exposed as an agent action; programmatic\n // field-set control lives on PatientDetails' adapter (set_field_order).\n capabilities: [],\n state: {\n summary: {\n type: '{ id?: string; hasUnpaid: boolean; unsignedDocumentsCount: number; highlightedAnamnesisCount: number; aiConsentGranted: boolean }',\n descriptionKey: 'ui.agent.patientSummaryCard.state.summary',\n description:\n 'Structural summary of the patient card — identifiers, counts, and consent flags only. Never patient identity or clinical content.',\n read: (handle) => handle.getSummary(),\n },\n },\n actions: {},\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'patient-summary-card',\n description: 'Marks the PatientSummaryCard root region.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n },\n};\n","import {\n forwardRef,\n useId,\n useMemo,\n type ComponentPropsWithoutRef,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport {\n ArrowUpRight,\n CalendarDays,\n FileExclamationPoint,\n Mail,\n MapPin,\n MessageSquareWarning,\n Phone,\n ShieldCheck,\n Astroid,\n Users,\n type LucideIcon,\n} from 'lucide-react';\nimport { Avatar } from '../avatar/avatar';\nimport { Badge } from '../badge/badge';\nimport { IconButton } from '../button/icon-button';\nimport { Card } from '../card/card';\nimport { KeyValueList, KeyValuePair } from '../key-value-pair/key-value-pair';\nimport { Link } from '../link/link';\nimport { Skeleton } from '../skeleton/skeleton';\nimport { Tag } from '../tag/tag';\nimport { TransactionChip } from '../transaction-chip/transaction-chip';\nimport { Tooltip } from '../tooltip';\nimport { HoverCard } from '../hover-card';\nimport { isSafeEntityUrl } from '../_shared/is-safe-url';\nimport {\n resolveVisibleFields,\n type PatientField,\n type PatientFieldSection,\n} from '../_shared/patient-fields';\nimport { usePatientFieldVisibility } from '../_shared/field-visibility';\nimport { FieldVisibilityCog } from '../_shared/field-visibility-cog';\nimport { AgeChip, NeutralChip, SexChip } from '../_shared/field-value';\nimport {\n PatientFieldLabel,\n PatientFieldValueCell,\n} from '../_shared/patient-field-row';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { patientSummaryCardAgent } from './patient-summary-card.agent';\n\n/** A section list reference that stays stable across renders (legacy mode). */\nconst NO_SECTIONS: PatientFieldSection[] = [];\n\n/* -------------------------------------------------------------------- */\n/* PatientSummaryCard */\n/* */\n/* The patient-overview profile card every AlfaDocs in-app surface */\n/* composes by hand today (platform patient header, alfascribe patient */\n/* sidebar, check-in landing). Templated on ContactProfileCard: composes */\n/* Card + Avatar + KeyValueList + KeyValuePair + Badge + Tag + */\n/* TransactionChip + Link so the contact rows share a column and every */\n/* row uses the same lucide icon family. */\n/* */\n/* The kit owns the ORDER, ICONS, and LABELS — consumers pass data. No */\n/* free-text clinical content (anamnesis notes, diagnoses) ever lives */\n/* here: only counts/flags/relations are surfaced, so the card stays */\n/* PHI-light and the agent state can be derived without leaking patient */\n/* identity. */\n/* */\n/* All visible text flows through `useTranslation('ui')` against the */\n/* `patientSummaryCard.*` namespace. */\n/* -------------------------------------------------------------------- */\n\n/* -------------------------------------------------------------------- */\n/* CVA — root */\n/* -------------------------------------------------------------------- */\n\nconst rootVariants = cva('ds:w-full ds:text-[color:var(--foreground)]', {\n variants: {\n // Matches the kit's other `surface` props (ContactProfileCard,\n // OperatorHero). `'elevated'` wraps the content in `<Card>`.\n surface: {\n flat: '',\n elevated: '',\n },\n // Density tunes the avatar size + body padding. `comfortable` reads\n // as a page header; `compact` fits an embedded sidebar / aside.\n density: {\n comfortable: '',\n compact: '',\n },\n },\n defaultVariants: {\n surface: 'elevated',\n density: 'comfortable',\n },\n});\n\n/* -------------------------------------------------------------------- */\n/* Public types */\n/* -------------------------------------------------------------------- */\n\n/** Patient phone number — already formatted for display by the consumer. */\nexport interface PatientSummaryCardPhone {\n /** Display string, e.g. `\"+39 055 123 4567\"`. Compiled into a `tel:` link. */\n prefixAndNumber: string;\n /** Optional label that distinguishes this number (e.g. \"Mobile\"). */\n label?: string;\n /** Whether SMS is enabled for this number — shows a small \"SMS\" chip. */\n smsEnabled?: boolean;\n}\n\n/** A family relation row — links one patient to another. */\nexport interface PatientSummaryCardFamilyRelation {\n /** Localised relation label, consumer-supplied (e.g. \"Mother\", \"Child\"). */\n relation: string;\n /** The related patient — name + optional in-app profile URL. */\n relatedPatient: {\n name: string;\n url?: string;\n };\n}\n\n/** Operator the patient is assigned to. */\nexport interface PatientSummaryCardAssignee {\n name: string;\n avatarUrl?: string;\n}\n\n/** AI-consent grant metadata — structural only, never the consented content. */\nexport interface PatientSummaryCardAiConsent {\n /** ISO-8601 / display string of when consent was granted. */\n grantedAt: string;\n /** Optional name of who recorded the grant. */\n grantedBy?: string;\n}\n\n/** Addressable attention flags — the keys `onFlagActivate` accepts. */\nexport type PatientSummaryCardFlagId =\n | 'highlightedAnamnesis'\n | 'unsignedDocuments'\n | 'unpaid';\n\n/** Status flags rendered as glyph badges (counts / amounts only — no PHI). */\nexport interface PatientSummaryCardFlags {\n /** Number of anamnesis answers highlighted for clinical attention. */\n highlightedAnamnesisCount?: number;\n /** Outstanding balance in the smallest currency unit (cents). */\n unpaidAmountCents?: number;\n /** Number of documents awaiting the patient's signature. */\n unsignedDocumentsCount?: number;\n}\n\n/** Marketing-consent tri-state. */\nexport type PatientSummaryCardMarketingConsent = 'no' | 'yes' | 'not_specified';\n\nexport interface PatientSummaryCardHandle {\n /** Structural snapshot — identifiers and counts only, never patient identity. */\n getSummary: () => {\n id?: string;\n hasUnpaid: boolean;\n unsignedDocumentsCount: number;\n highlightedAnamnesisCount: number;\n aiConsentGranted: boolean;\n };\n}\n\nexport interface PatientSummaryCardProps extends Omit<\n ComponentPropsWithoutRef<'div'>,\n 'aria-label' | 'children'\n> {\n /** Patient display name. Rendered as the heading. */\n name: string;\n /** Honorific — `'mr'` / `'ms'`. Prepended to the name in the heading. */\n title?: 'mr' | 'ms';\n /** Patient age in whole years — rendered in the identity line. */\n ageYears?: number;\n /** Date of birth — already formatted for display by the consumer. */\n dateOfBirth?: string;\n /** Biological sex marker — `'m'` / `'f'`. Drives the identity-line glyph copy. */\n gender?: 'm' | 'f';\n /** Optional avatar / photo URL. Falls back to initials. */\n avatarUrl?: string;\n /**\n * In-app patient profile URL. When safe, the heading becomes a link.\n * Guarded by the shared `isSafeEntityUrl` allow-list — unsafe URLs are\n * dropped and the heading renders as plain text.\n */\n patientUrl?: string;\n\n /* ----- Shared field model (preferred) ----- */\n\n /**\n * Patient fields in the shared model — the SAME `sections` shape\n * `PatientDetails` consumes (`@alfadocs/ui-kit` `PatientFieldSection`).\n * When provided, the card renders these (honouring `visibleFieldOrder`)\n * instead of the legacy contact props, so a consumer defines its patient-\n * field registry once and reuses it across every patient surface.\n *\n * The card renders each field's `label`, `value`, and `icon` only — it is\n * flat (section headings are not shown in the body) and never inline-edits;\n * `sensitive` / `copyable` / `mono` / `editable` are honoured by\n * `PatientDetails`, not the card (so the PHI lock glyph does not appear here).\n *\n * Pass `onVisibleFieldsChange` alongside `sections` to make THIS placement\n * self-curating (a \"Customize fields\" cog appears — show/hide + drag-and-drop\n * reorder).\n */\n sections?: PatientFieldSection[];\n /**\n * Ordered visible field ids for THIS placement. The order is a\n * per-INSTANCE, per-CONTEXT preference the kit never persists — wire it to\n * whatever scope the consumer wants (e.g. a global per-user setting, or a\n * different config in the care-plan view vs the patient folder). The same\n * field vocabulary can therefore display differently in different parts of\n * the app. Omit (`undefined`) ⇒ show every field; an explicit empty array\n * `[]` ⇒ show none (a card that starts collapsed to name + identity chips and\n * reveals fields via the cog). Also applied to the legacy contact rows (ids\n * `email` / `phone` / `cityProvince` / `marketingConsent` / `aiConsent` /\n * `assignedTo`).\n */\n visibleFieldOrder?: string[];\n /**\n * Make this card's field set user-customizable. When provided alongside\n * `sections`, a \"Customize fields\" cog renders in the header (show/hide +\n * drag-and-drop / Alt+Arrow reorder), and this fires with the next ordered\n * visible set. The consumer owns persistence + its scope — editing here\n * writes only THIS context's preference, never a shared/global one.\n */\n onVisibleFieldsChange?: (orderedIds: string[]) => void;\n\n /* ----- Contact rows (legacy — prefer `sections`) ----- */\n\n /** @deprecated Pass via `sections`. Patient email — `mailto:` link when `emailEnabled`. */\n email?: string;\n /** Whether email contact is enabled — gates the `mailto:` link. */\n emailEnabled?: boolean;\n /** Phone number block. Compiled into a `tel:` link. */\n phone?: PatientSummaryCardPhone;\n /** City / province display string. */\n cityProvince?: string;\n\n /* ----- Consent ----- */\n\n /** Marketing-consent tri-state. */\n marketingConsent?: PatientSummaryCardMarketingConsent;\n /** AI-consent grant metadata. When present, an \"AI consent\" row renders. */\n aiConsent?: PatientSummaryCardAiConsent;\n\n /* ----- Status flags ----- */\n\n /** Counts / amounts surfaced as glyph badges. */\n flags?: PatientSummaryCardFlags;\n\n /* ----- Relations & assignment ----- */\n\n /** Family relations — rendered as `<Tag>` chips, optionally linked. */\n familyRelations?: PatientSummaryCardFamilyRelation[];\n /** Operator the patient is assigned to. */\n assignedTo?: PatientSummaryCardAssignee;\n\n /* ----- Formatting ----- */\n\n /** ISO-4217 currency code for the unpaid-amount chip. Defaults to `EUR`. */\n currency?: string;\n /** BCP-47 locale override. Defaults to the active i18next language. */\n locale?: string;\n\n /* ----- States ----- */\n\n /** Render the skeleton loading placeholder. */\n loading?: boolean;\n\n /* ----- Slots & callbacks ----- */\n\n /** Rendered at the inline-end of the heading row (e.g. an action menu). */\n actionSlot?: ReactNode;\n\n /**\n * Make an attention chip actionable. A handler turns that chip into a\n * button — \"2 unsigned documents\" opens the signing flow, the unpaid\n * balance opens invoicing. Without a handler the chip stays a read-only\n * badge, which is the default: most surfaces have nowhere to send the\n * reader.\n */\n onFlagActivate?: Partial<Record<PatientSummaryCardFlagId, () => void>>;\n /**\n * Explain a chip on hover / focus. The chip states WHAT (\"2 unsigned\n * documents\"); this states what the reader cannot see — how the signature\n * was requested, why the balance is outstanding.\n *\n * A string renders a `Tooltip`; a node renders a `HoverCard` with that node\n * as its content, for a host that wants the fuller card grammar (an eyebrow,\n * fact rows, a hint line). Either way the chip's own text stays the\n * accessible name and the surface only describes it.\n */\n flagHover?: Partial<Record<PatientSummaryCardFlagId, ReactNode>>;\n /**\n * Accessible name for the open button a hover CARD shows in its top-end\n * corner. The button appears only where the flag has BOTH a card and an\n * `onFlagActivate` handler — it mirrors the chip's own click so a pointer\n * that has travelled into the card can still act. Name the destination\n * (\"Open signing\"), not the gesture.\n *\n * Without a label there is no button: a card that merely describes should\n * not sprout an affordance the chip does not have.\n */\n flagOpenLabel?: Partial<Record<PatientSummaryCardFlagId, string>>;\n /**\n * Extra chips appended to the attention row, for signals the CARD cannot\n * model because they do not belong to the patient. An appointment panel\n * adds its own to-invoice and paid-online chips here; the card keeps its\n * patient-level flags and does not grow an appointment vocabulary.\n */\n extraChips?: ReactNode;\n\n /* ----- Inline editing (kit-owned controls, consumer-owned write) ----- */\n\n /**\n * Master switch — show the edit affordance on fields marked `editable` in\n * `sections`. The card edits through the SAME shared control as\n * `PatientDetails`, so a field offers the same affordance and the same\n * validation wherever it is shown.\n */\n editable?: boolean;\n /**\n * The single write channel. A rejected promise keeps the row in edit mode\n * and shows the message inline — the card never optimistically mutates the\n * value it was given.\n */\n onFieldSave?: (fieldId: string, value: unknown) => Promise<void>;\n /** Return a message to block the save and keep the row in edit mode. */\n validateField?: (fieldId: string, value: unknown) => string | null;\n /** Fires when the whole card / heading is activated. */\n onActivate?: () => void;\n\n /* ----- Styling ----- */\n\n /** `'elevated'` (default) wraps in `<Card>`; `'flat'` drops the chrome. */\n surface?: 'flat' | 'elevated';\n /** `'comfortable'` (default) reads as a header; `'compact'` for asides. */\n density?: 'comfortable' | 'compact';\n\n /* ----- a11y ----- */\n\n /** Override the default region aria-label. */\n 'aria-label'?: string;\n /** Agent-readiness consumer id, surfaced as `data-component-id`. */\n id?: string;\n}\n\n/* -------------------------------------------------------------------- */\n/* Helpers */\n/* -------------------------------------------------------------------- */\n\n/** Strip everything except digits + leading `+` for `tel:` URLs. */\nfunction normalisePhone(raw: string): string {\n return raw.replace(/[^\\d+]/g, '');\n}\n\n/* -------------------------------------------------------------------- */\n/* Flag glyphs — the closed set of status indicators */\n/* -------------------------------------------------------------------- */\n\n/** The closed set of status-flag keys (icon + tonal variant defined below). */\ntype FlagKey = 'highlightedAnamnesis' | 'unsignedDocuments';\n\nconst FLAG_ICON: Record<FlagKey, LucideIcon> = {\n highlightedAnamnesis: MessageSquareWarning,\n unsignedDocuments: FileExclamationPoint,\n};\n\nconst FLAG_VARIANT: Record<FlagKey, 'warning' | 'error'> = {\n highlightedAnamnesis: 'warning',\n unsignedDocuments: 'error',\n};\n\n/** English fallbacks for the flag badge accessible names (count-interpolated). */\nconst FLAG_LABEL_DEFAULTS: Record<FlagKey, string> = {\n highlightedAnamnesis: '{{count}} highlighted anamnesis answers',\n unsignedDocuments: '{{count}} unsigned documents',\n};\n\n/** English fallbacks for the marketing-consent tri-state chip. */\nconst MARKETING_CONSENT_DEFAULTS: Record<\n PatientSummaryCardMarketingConsent,\n string\n> = {\n yes: 'Yes',\n no: 'No',\n not_specified: 'Not specified',\n};\n\n/* -------------------------------------------------------------------- */\n/* Component */\n/* -------------------------------------------------------------------- */\n\nexport const PatientSummaryCard = forwardRef<\n HTMLDivElement,\n PatientSummaryCardProps\n>(\n (\n {\n name,\n title,\n ageYears,\n dateOfBirth,\n gender,\n avatarUrl,\n patientUrl,\n sections,\n visibleFieldOrder,\n onVisibleFieldsChange,\n email,\n emailEnabled = false,\n phone,\n cityProvince,\n marketingConsent,\n aiConsent,\n flags,\n familyRelations,\n assignedTo,\n currency = 'EUR',\n locale,\n loading = false,\n actionSlot,\n onFlagActivate,\n flagHover,\n flagOpenLabel,\n extraChips,\n editable = false,\n onFieldSave,\n validateField,\n onActivate,\n surface = 'elevated',\n density = 'comfortable',\n 'aria-label': ariaLabel,\n id,\n className,\n ...rest\n },\n ref,\n ) => {\n // Pinned to `ui` as a guard for a host that inits i18next with its own\n // `defaultNS`: the flag badges pass a defaultValue, so a miss is silent.\n const { t, i18n } = useTranslation('ui');\n const headingId = useId();\n const activeLocale = locale ?? i18n.language ?? 'en';\n\n const unpaidAmountCents = flags?.unpaidAmountCents;\n const unsignedDocumentsCount = flags?.unsignedDocumentsCount ?? 0;\n const highlightedAnamnesisCount = flags?.highlightedAnamnesisCount ?? 0;\n const hasUnpaid = unpaidAmountCents != null && unpaidAmountCents > 0;\n\n // Imperative handle — structural snapshot only (counts/flags/ids),\n // never the patient name or any clinical content.\n const handle = useMemo<PatientSummaryCardHandle>(\n () => ({\n getSummary: () => ({\n id,\n hasUnpaid,\n unsignedDocumentsCount,\n highlightedAnamnesisCount,\n aiConsentGranted: aiConsent != null,\n }),\n }),\n [\n id,\n hasUnpaid,\n unsignedDocumentsCount,\n highlightedAnamnesisCount,\n aiConsent,\n ],\n );\n useAgentRegistration(patientSummaryCardAgent, handle, id);\n\n // Per-context field visibility. The cog (and live reordering) only engages\n // with the shared `sections` model AND an `onVisibleFieldsChange` handler;\n // legacy contact-prop cards stay read-only. The order is this placement's\n // own preference — never shared across surfaces.\n const customizable = !!sections && !!onVisibleFieldsChange;\n const fieldVisibility = usePatientFieldVisibility(sections ?? NO_SECTIONS, {\n value: visibleFieldOrder,\n onChange: onVisibleFieldsChange,\n });\n\n const resolvedAriaLabel =\n ariaLabel ??\n t('patientSummaryCard.regionLabel', { defaultValue: 'Patient overview' });\n\n // Heading text: optional honorific prefix + name.\n const TITLE_DEFAULTS: Record<'mr' | 'ms', string> = {\n mr: 'Mr.',\n ms: 'Ms.',\n };\n const honorific = title\n ? t(`patientSummaryCard.title.${title}`, {\n defaultValue: TITLE_DEFAULTS[title],\n })\n : undefined;\n // A translated PATTERN, not a hardcoded `${honorific} ${name}` join:\n // several of the 18 locales order or punctuate a name-with-title\n // differently (or drop it) — a locale can override the pattern\n // without touching this component.\n const headingText = honorific\n ? t('patientSummaryCard.nameWithHonorific', {\n honorific,\n name,\n defaultValue: '{{honorific}} {{name}}',\n })\n : name;\n\n // Identity line: the canonical sex / age / dob chips below the name — the\n // SAME chips the field model renders, so the header and the field rows\n // agree. Each chip is added only when its prop is present. (`dateOfBirth`\n // is a consumer-preformatted display string, so it goes through NeutralChip\n // directly rather than the date-parsing `dob` kind.)\n const identityChips: ReactNode[] = [];\n if (gender) {\n identityChips.push(<SexChip key=\"sex\" code={gender} />);\n }\n if (ageYears != null) {\n identityChips.push(<AgeChip key=\"age\" years={ageYears} />);\n }\n if (dateOfBirth) {\n identityChips.push(\n <NeutralChip key=\"dob\" icon={<CalendarDays />}>\n {dateOfBirth}\n </NeutralChip>,\n );\n }\n\n const isUrlSafe = !!patientUrl && isSafeEntityUrl(patientUrl);\n\n const avatarSize = density === 'comfortable' ? 'xl' : 'lg';\n const headingClass =\n density === 'comfortable' ? 'type-title-card' : 'type-title-item';\n const bodyGapClass =\n density === 'comfortable'\n ? 'ds:gap-[var(--spacing-md)]'\n : 'ds:gap-[var(--spacing-sm)]';\n\n /* ---------------------------------------------------------------- */\n /* Contact rows */\n /* ---------------------------------------------------------------- */\n\n const rows: Array<{\n key: string;\n icon: ReactElement;\n label: string;\n value: ReactNode;\n }> = [];\n\n if (email) {\n rows.push({\n key: 'email',\n icon: <Mail aria-hidden=\"true\" />,\n label: t('patientSummaryCard.label.email', { defaultValue: 'Email' }),\n value: emailEnabled ? (\n <Link\n href={`mailto:${email}`}\n intent=\"default\"\n onClick={onActivate}\n dir=\"ltr\"\n >\n {email}\n </Link>\n ) : (\n <span className=\"ds:text-[color:var(--muted-foreground)]\" dir=\"ltr\">\n {email}\n </span>\n ),\n });\n }\n\n if (phone) {\n rows.push({\n key: 'phone',\n icon: <Phone aria-hidden=\"true\" />,\n label:\n phone.label ??\n t('patientSummaryCard.label.phone', { defaultValue: 'Phone' }),\n value: (\n <span className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-2xs)]\">\n <Link\n href={`tel:${normalisePhone(phone.prefixAndNumber)}`}\n intent=\"default\"\n dir=\"ltr\"\n >\n {phone.prefixAndNumber}\n </Link>\n {phone.smsEnabled ? (\n <Badge variant=\"success\" size=\"sm\">\n {t('patientSummaryCard.value.smsEnabled', {\n defaultValue: 'SMS',\n })}\n </Badge>\n ) : null}\n </span>\n ),\n });\n }\n\n if (cityProvince) {\n rows.push({\n key: 'cityProvince',\n icon: <MapPin aria-hidden=\"true\" />,\n label: t('patientSummaryCard.label.cityProvince', {\n defaultValue: 'City / province',\n }),\n value: cityProvince,\n });\n }\n\n if (marketingConsent) {\n rows.push({\n key: 'marketingConsent',\n icon: <ShieldCheck aria-hidden=\"true\" />,\n label: t('patientSummaryCard.label.marketingConsent', {\n defaultValue: 'Marketing consent',\n }),\n value: (\n <Badge\n variant={\n marketingConsent === 'yes'\n ? 'success'\n : marketingConsent === 'no'\n ? 'error'\n : 'neutral'\n }\n size=\"sm\"\n withDot\n >\n {t(`patientSummaryCard.marketingConsent.${marketingConsent}`, {\n defaultValue: MARKETING_CONSENT_DEFAULTS[marketingConsent],\n })}\n </Badge>\n ),\n });\n }\n\n if (aiConsent) {\n rows.push({\n key: 'aiConsent',\n icon: <Astroid aria-hidden=\"true\" />,\n label: t('patientSummaryCard.label.aiConsent', {\n defaultValue: 'AI consent',\n }),\n value: aiConsent.grantedBy\n ? t('patientSummaryCard.value.aiConsentGrantedBy', {\n date: aiConsent.grantedAt,\n by: aiConsent.grantedBy,\n defaultValue: 'Granted {{date}} by {{by}}',\n })\n : t('patientSummaryCard.value.aiConsentGrantedAt', {\n date: aiConsent.grantedAt,\n defaultValue: 'Granted {{date}}',\n }),\n });\n }\n\n if (assignedTo) {\n rows.push({\n key: 'assignedTo',\n icon: <Users aria-hidden=\"true\" />,\n label: t('patientSummaryCard.label.assignedTo', {\n defaultValue: 'Assigned to',\n }),\n value: (\n <span className=\"ds:flex ds:items-center ds:gap-[var(--spacing-xs)]\">\n <Avatar\n size=\"xs\"\n name={assignedTo.name}\n src={assignedTo.avatarUrl}\n />\n <span>{assignedTo.name}</span>\n </span>\n ),\n });\n }\n\n /* ---------------------------------------------------------------- */\n /* Attention-flag chips (VERBOSE — shown in the identity line) */\n /* */\n /* The unpaid balance + warning counts sit in the chip row under the */\n /* name, BEFORE the sex / age chips, each as a self-describing chip */\n /* (\"2 unsigned documents\") rather than a collapsed count badge in a */\n /* separate strip — the attention signals lead the patient's chips. */\n /* ---------------------------------------------------------------- */\n\n const flagBadges: Array<{ key: FlagKey; count: number }> = [];\n if (highlightedAnamnesisCount > 0) {\n flagBadges.push({\n key: 'highlightedAnamnesis',\n count: highlightedAnamnesisCount,\n });\n }\n if (unsignedDocumentsCount > 0) {\n flagBadges.push({\n key: 'unsignedDocuments',\n count: unsignedDocumentsCount,\n });\n }\n\n /* A chip becomes a BUTTON only when the host gave it somewhere to go.\n The chip's own text is already its accessible name, so the wrapper adds\n no label of its own and contributes no padding — the strip's rhythm is\n identical whether or not a chip is actionable. */\n /* A chip becomes a CONTROL when it has something to reveal or somewhere\n to go, and the trigger is always a real <button> — `asChild` on a bare\n <span> badge stamps `aria-haspopup` onto something a keyboard can never\n reach, which is both a dead end and an axe violation.\n\n The division of labour is the same on every chip: the chip opens its\n card (hover, or click / Enter for keyboard and touch), and the card's\n own top-end button performs the action. One gesture to learn, and no\n chip that acts differently from its neighbour. */\n const asAction = (id: PatientSummaryCardFlagId, chip: ReactNode) => {\n const onActivateFlag = onFlagActivate?.[id];\n const hover = flagHover?.[id];\n if (hover == null && !onActivateFlag) return chip;\n\n const triggerClasses =\n 'ds:inline-flex ds:cursor-pointer ds:rounded-[var(--radius-full)] ds:p-0 ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid ds:focus-visible:outline-[color:var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]';\n\n // No card: the chip itself is the action.\n if (hover == null) {\n return (\n <button\n key={id}\n type=\"button\"\n data-flag-action={id}\n onClick={onActivateFlag}\n className={triggerClasses}\n >\n {chip}\n </button>\n );\n }\n\n const trigger = (\n <button\n key={id}\n type=\"button\"\n data-flag-action={onActivateFlag ? id : undefined}\n data-flag-hover={id}\n className={triggerClasses}\n >\n {chip}\n </button>\n );\n\n // A string still renders a plain Tooltip, for a chip that needs naming\n // rather than a card.\n if (typeof hover === 'string') {\n return (\n <Tooltip key={id} label={hover} side=\"bottom\">\n {trigger}\n </Tooltip>\n );\n }\n\n return (\n <HoverCard key={id}>\n <HoverCard.Trigger asChild>{trigger}</HoverCard.Trigger>\n <HoverCard.Content\n side=\"bottom\"\n align=\"start\"\n size=\"sm\"\n headerAction={\n onActivateFlag && flagOpenLabel?.[id] ? (\n <IconButton\n icon={<ArrowUpRight />}\n /* Outline, not ghost: the card's own surface is already\n light, so a borderless glyph reads as decoration rather\n than a control. */\n intent=\"outline\"\n background=\"surface\"\n size=\"sm\"\n aria-label={flagOpenLabel[id] as string}\n onClick={onActivateFlag}\n />\n ) : undefined\n }\n >\n {hover}\n </HoverCard.Content>\n </HoverCard>\n );\n };\n\n const attentionChips: ReactNode[] = [];\n if (hasUnpaid) {\n attentionChips.push(\n asAction(\n 'unpaid',\n <TransactionChip\n key=\"unpaid\"\n state=\"debt\"\n amount={(unpaidAmountCents as number) / 100}\n currency={currency}\n locale={activeLocale}\n size=\"md\"\n showLabel\n />,\n ),\n );\n }\n flagBadges.forEach(({ key, count }) => {\n const FlagIcon = FLAG_ICON[key];\n // The Badge's visible text IS the count-interpolated label, so it's its\n // own accessible name — the leading glyph is decorative (aria-hidden).\n attentionChips.push(\n asAction(\n key,\n <Badge\n key={key}\n variant={FLAG_VARIANT[key]}\n size=\"md\"\n leading={<FlagIcon aria-hidden=\"true\" />}\n >\n {t(`patientSummaryCard.flag.${key}`, {\n count,\n defaultValue: FLAG_LABEL_DEFAULTS[key],\n })}\n </Badge>,\n ),\n );\n });\n if (extraChips) attentionChips.push(extraChips);\n\n /* ---------------------------------------------------------------- */\n /* Loading skeleton */\n /* ---------------------------------------------------------------- */\n\n const skeletonBody = (\n <div className={`ds:flex ds:flex-col ${bodyGapClass}`}>\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-md)]\">\n <Skeleton variant=\"circular\" size=\"lg\" />\n <div className=\"ds:flex ds:flex-1 ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <Skeleton variant=\"text\" width=\"60%\" />\n <Skeleton variant=\"text\" width=\"40%\" />\n </div>\n </div>\n <Skeleton variant=\"text\" lines={3} />\n </div>\n );\n\n /* ---------------------------------------------------------------- */\n /* Header */\n /* ---------------------------------------------------------------- */\n\n const heading = isUrlSafe ? (\n <Link\n href={patientUrl as string}\n intent=\"default\"\n weight=\"strong\"\n onClick={onActivate}\n className={`${headingClass} ds:no-underline`}\n >\n <span id={headingId}>{headingText}</span>\n </Link>\n ) : (\n <span\n id={headingId}\n className={`${headingClass} ds:text-[color:var(--foreground)]`}\n >\n {headingText}\n </span>\n );\n\n const header = (\n <div className=\"ds:flex ds:items-start ds:gap-[var(--spacing-md)]\">\n <Avatar\n size={avatarSize}\n name={name}\n src={avatarUrl}\n className=\"ds:shrink-0\"\n />\n <div className=\"ds:flex ds:min-w-0 ds:flex-1 ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n {heading}\n {attentionChips.length > 0 || identityChips.length > 0 ? (\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)]\">\n {/* Attention flags lead, then the sex / age / dob identity chips. */}\n {attentionChips}\n {identityChips}\n </div>\n ) : null}\n </div>\n {customizable || actionSlot ? (\n <div className=\"ds:ms-auto ds:flex ds:shrink-0 ds:items-center ds:gap-[var(--spacing-xs)]\">\n {customizable && sections ? (\n <FieldVisibilityCog\n sections={sections}\n visible={fieldVisibility.visible}\n onToggleField={fieldVisibility.toggleField}\n onToggleSection={fieldVisibility.toggleSection}\n onMoveFieldOnto={fieldVisibility.moveFieldOnto}\n onReset={fieldVisibility.reset}\n />\n ) : null}\n {actionSlot}\n </div>\n ) : null}\n </div>\n );\n\n /* ---------------------------------------------------------------- */\n /* Family relations */\n /* ---------------------------------------------------------------- */\n\n const familyBlock =\n familyRelations && familyRelations.length > 0 ? (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <span className=\"type-label ds:text-[color:var(--muted-foreground)]\">\n {t('patientSummaryCard.label.familyRelations', {\n defaultValue: 'Family relations',\n })}\n </span>\n <div className=\"ds:flex ds:flex-wrap ds:gap-[var(--spacing-2xs)]\">\n {familyRelations.map((rel, index) => {\n const safeUrl =\n !!rel.relatedPatient.url &&\n isSafeEntityUrl(rel.relatedPatient.url);\n const tagLabel = t('patientSummaryCard.value.familyRelation', {\n relation: rel.relation,\n name: rel.relatedPatient.name,\n defaultValue: '{{relation}}: {{name}}',\n });\n return safeUrl ? (\n <Link\n key={`${rel.relation}-${index}`}\n href={rel.relatedPatient.url as string}\n intent=\"default\"\n className=\"ds:no-underline\"\n >\n <Tag label={tagLabel} variant=\"neutral\" />\n </Link>\n ) : (\n <Tag\n key={`${rel.relation}-${index}`}\n label={tagLabel}\n variant=\"neutral\"\n />\n );\n })}\n </div>\n </div>\n ) : null;\n\n /* ---------------------------------------------------------------- */\n /* Body */\n /* ---------------------------------------------------------------- */\n\n // Field rows resolve through the SHARED model: when the consumer passes\n // `sections` (preferred), render those; otherwise wrap the legacy contact\n // rows as a single section. Either way `resolveVisibleFields` applies the\n // shared `visibleFieldOrder` preference, so the card and PatientDetails\n // always show the same fields, honouring the same per-user choice.\n const legacyFields: PatientField[] = rows.map((row) => ({\n id: row.key,\n label: row.label,\n value: row.value,\n icon: row.icon,\n }));\n const effectiveSections: PatientFieldSection[] = sections ?? [\n { id: 'contact', heading: '', fields: legacyFields },\n ];\n // With the shared `sections` model the order comes from the visibility hook\n // (so a cog reorder reflects live); legacy contact rows honour the raw\n // `visibleFieldOrder` prop.\n const order = sections ? fieldVisibility.visible : visibleFieldOrder;\n const visibleFields = resolveVisibleFields(\n effectiveSections,\n order,\n ).flatMap((resolved) => resolved.fields);\n\n const body = (\n <div className={`ds:flex ds:flex-col ${bodyGapClass}`}>\n {header}\n {visibleFields.length > 0 ? (\n // Container-queried so the fields flow into two columns when the\n // card is wide enough (the banner spans the full folder width), and\n // stay single-column in a narrow rail. The list's KeyValuePair\n // children already `col-span-3`; doubling the parent to six tracks\n // (`repeat(2, …)`) lets grid auto-flow place two fields per row while\n // each column keeps its own subgrid label/value alignment.\n // 672px, not the `@2xl` rem alias: container-query `rem` follows the\n // host root font-size, so a non-16px root moves the threshold.\n // Each label column stops at 20% of the card (every field has an\n // icon, so labels sit in the middle track of each group): a long\n // label wraps instead of squeezing its value, as KeyValueList's\n // single-column cap does at 40%.\n <div className=\"ds:@container/pfields\">\n <KeyValueList\n rowGap=\"sm\"\n className=\"ds:@[672px]/pfields:grid-cols-[repeat(2,auto_fit-content(20%)_minmax(0,1fr))]\"\n >\n {visibleFields.map((field) => (\n <KeyValuePair\n key={field.id}\n icon={field.icon ?? undefined}\n label={field.label}\n labelNode={<PatientFieldLabel field={field} />}\n // `group` is what reveals the edit pencil on hover / focus;\n // the cell itself carries no row markup.\n className=\"ds:group\"\n data-field-id={field.id}\n value={\n <PatientFieldValueCell\n field={field}\n editable={editable}\n onFieldSave={onFieldSave}\n validate={validateField}\n locale={locale}\n />\n }\n />\n ))}\n </KeyValueList>\n </div>\n ) : null}\n {familyBlock}\n </div>\n );\n\n const inner = loading ? skeletonBody : body;\n\n return (\n <div\n ref={ref}\n role=\"region\"\n // When the heading is rendered, the patient name (via\n // aria-labelledby) is the region's accessible name — the more\n // meaningful label than a generic \"Patient overview\". A consumer\n // aria-label still wins; the generic fallback only applies when\n // there is no heading to point at (loading state).\n aria-label={loading || ariaLabel ? resolvedAriaLabel : undefined}\n aria-labelledby={loading || ariaLabel ? undefined : headingId}\n aria-busy={loading || undefined}\n data-component=\"patient-summary-card\"\n data-component-id={id}\n data-density={density}\n id={id}\n className={rootVariants({ surface, density, className })}\n {...rest}\n >\n {surface === 'elevated' ? (\n <Card variant=\"elevated\">\n <Card.Body>{inner}</Card.Body>\n </Card>\n ) : (\n inner\n )}\n </div>\n );\n },\n);\n\nPatientSummaryCard.displayName = 'PatientSummaryCard';\n\n/** Variant unions re-exported for downstream typing. */\nexport type PatientSummaryCardSurface = NonNullable<\n VariantProps<typeof rootVariants>['surface']\n>;\nexport type PatientSummaryCardDensity = NonNullable<\n VariantProps<typeof rootVariants>['density']\n>;\n"],"names":["__iconNode","FileExclamationPoint","createLucideIcon","MessageSquareWarning","patientSummaryCardAgent","handle","NO_SECTIONS","rootVariants","cva","normalisePhone","raw","FLAG_ICON","FLAG_VARIANT","FLAG_LABEL_DEFAULTS","MARKETING_CONSENT_DEFAULTS","PatientSummaryCard","forwardRef","name","title","ageYears","dateOfBirth","gender","avatarUrl","patientUrl","sections","visibleFieldOrder","onVisibleFieldsChange","email","emailEnabled","phone","cityProvince","marketingConsent","aiConsent","flags","familyRelations","assignedTo","currency","locale","loading","actionSlot","onFlagActivate","flagHover","flagOpenLabel","extraChips","editable","onFieldSave","validateField","onActivate","surface","density","ariaLabel","id","className","rest","ref","i18n","useTranslation","headingId","useId","activeLocale","unpaidAmountCents","unsignedDocumentsCount","highlightedAnamnesisCount","hasUnpaid","useMemo","useAgentRegistration","customizable","fieldVisibility","usePatientFieldVisibility","resolvedAriaLabel","TITLE_DEFAULTS","honorific","headingText","identityChips","jsx","SexChip","AgeChip","NeutralChip","CalendarDays","isUrlSafe","isSafeEntityUrl","avatarSize","headingClass","bodyGapClass","rows","Mail","Link","Phone","jsxs","Badge","MapPin","ShieldCheck","Astroid","Users","Avatar","flagBadges","asAction","chip","onActivateFlag","hover","triggerClasses","trigger","Tooltip","HoverCard","IconButton","ArrowUpRight","attentionChips","TransactionChip","key","count","FlagIcon","skeletonBody","Skeleton","heading","header","FieldVisibilityCog","familyBlock","rel","index","safeUrl","tagLabel","Tag","legacyFields","row","effectiveSections","order","visibleFields","resolveVisibleFields","resolved","body","KeyValueList","field","KeyValuePair","PatientFieldLabel","PatientFieldValueCell","inner","Card"],"mappings":"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","x_google_ignoreList":[0,1]}
|
|
1
|
+
{"version":3,"file":"patient-summary-card-CCQZ8X37.js","sources":["../../node_modules/lucide-react/dist/esm/icons/file-exclamation-point.mjs","../../node_modules/lucide-react/dist/esm/icons/message-square-warning.mjs","../../src/components/patient-summary-card/patient-summary-card.agent.ts","../../src/components/patient-summary-card/patient-summary-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 [\n \"path\",\n {\n d: \"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z\",\n key: \"1oefj6\"\n }\n ],\n [\"path\", { d: \"M12 9v4\", key: \"juzpu7\" }],\n [\"path\", { d: \"M12 17h.01\", key: \"p32p05\" }]\n];\nconst FileExclamationPoint = createLucideIcon(\"file-exclamation-point\", __iconNode);\n\nexport { __iconNode, FileExclamationPoint as default };\n//# sourceMappingURL=file-exclamation-point.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: \"M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z\",\n key: \"18887p\"\n }\n ],\n [\"path\", { d: \"M12 15h.01\", key: \"q59x07\" }],\n [\"path\", { d: \"M12 7v4\", key: \"xawao1\" }]\n];\nconst MessageSquareWarning = createLucideIcon(\"message-square-warning\", __iconNode);\n\nexport { __iconNode, MessageSquareWarning as default };\n//# sourceMappingURL=message-square-warning.mjs.map\n","import type { AgentAdapter } from '../../agent/types';\nimport type { PatientSummaryCardHandle } from './patient-summary-card';\n\n/* -------------------------------------------------------------------- */\n/* Agent adapter — PatientSummaryCard */\n/* */\n/* Read-only adapter. Surfaces a STRUCTURAL snapshot of the patient */\n/* overview — counts, flags, and the consumer id only. Never the patient */\n/* name, age, contact details, or any clinical content, so an agent / */\n/* MCP runtime can answer \"does this patient have unpaid balances / */\n/* unsigned documents / AI consent?\" without re-parsing the DOM and */\n/* without leaking PHI (PRS §Security). */\n/* -------------------------------------------------------------------- */\n\nexport const patientSummaryCardAgent: AgentAdapter<PatientSummaryCardHandle> = {\n id: 'patient-summary-card',\n // The agent surface is a structural snapshot only — the single handle method\n // is a getSummary projection. The card MAY be human-customized (the optional\n // per-context \"Customize fields\" cog), but that field reordering is a UI\n // concern and is deliberately NOT exposed as an agent action; programmatic\n // field-set control lives on PatientDetails' adapter (set_field_order).\n capabilities: [],\n state: {\n summary: {\n type: '{ id?: string; hasUnpaid: boolean; unsignedDocumentsCount: number; highlightedAnamnesisCount: number; aiConsentGranted: boolean }',\n descriptionKey: 'ui.agent.patientSummaryCard.state.summary',\n description:\n 'Structural summary of the patient card — identifiers, counts, and consent flags only. Never patient identity or clinical content.',\n read: (handle) => handle.getSummary(),\n },\n },\n actions: {},\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'patient-summary-card',\n description: 'Marks the PatientSummaryCard root region.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n },\n};\n","import {\n forwardRef,\n useId,\n useMemo,\n type ComponentPropsWithoutRef,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport {\n ArrowUpRight,\n CalendarDays,\n FileExclamationPoint,\n Mail,\n MapPin,\n MessageSquareWarning,\n Phone,\n ShieldCheck,\n Astroid,\n Users,\n type LucideIcon,\n} from 'lucide-react';\nimport { Avatar } from '../avatar/avatar';\nimport { Badge } from '../badge/badge';\nimport { IconButton } from '../button/icon-button';\nimport { Card } from '../card/card';\nimport { KeyValueList, KeyValuePair } from '../key-value-pair/key-value-pair';\nimport { Link } from '../link/link';\nimport { Skeleton } from '../skeleton/skeleton';\nimport { Tag } from '../tag/tag';\nimport { TransactionChip } from '../transaction-chip/transaction-chip';\nimport { Tooltip } from '../tooltip';\nimport { HoverCard } from '../hover-card';\nimport { isSafeEntityUrl } from '../_shared/is-safe-url';\nimport {\n resolveVisibleFields,\n type PatientField,\n type PatientFieldSection,\n} from '../_shared/patient-fields';\nimport { usePatientFieldVisibility } from '../_shared/field-visibility';\nimport { FieldVisibilityCog } from '../_shared/field-visibility-cog';\nimport { AgeChip, NeutralChip, SexChip } from '../_shared/field-value';\nimport {\n PatientFieldLabel,\n PatientFieldValueCell,\n} from '../_shared/patient-field-row';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { patientSummaryCardAgent } from './patient-summary-card.agent';\n\n/** A section list reference that stays stable across renders (legacy mode). */\nconst NO_SECTIONS: PatientFieldSection[] = [];\n\n/* -------------------------------------------------------------------- */\n/* PatientSummaryCard */\n/* */\n/* The patient-overview profile card every AlfaDocs in-app surface */\n/* composes by hand today (platform patient header, alfascribe patient */\n/* sidebar, check-in landing). Templated on ContactProfileCard: composes */\n/* Card + Avatar + KeyValueList + KeyValuePair + Badge + Tag + */\n/* TransactionChip + Link so the contact rows share a column and every */\n/* row uses the same lucide icon family. */\n/* */\n/* The kit owns the ORDER, ICONS, and LABELS — consumers pass data. No */\n/* free-text clinical content (anamnesis notes, diagnoses) ever lives */\n/* here: only counts/flags/relations are surfaced, so the card stays */\n/* PHI-light and the agent state can be derived without leaking patient */\n/* identity. */\n/* */\n/* All visible text flows through `useTranslation('ui')` against the */\n/* `patientSummaryCard.*` namespace. */\n/* -------------------------------------------------------------------- */\n\n/* -------------------------------------------------------------------- */\n/* CVA — root */\n/* -------------------------------------------------------------------- */\n\nconst rootVariants = cva('ds:w-full ds:text-[color:var(--foreground)]', {\n variants: {\n // Matches the kit's other `surface` props (ContactProfileCard,\n // OperatorHero). `'elevated'` wraps the content in `<Card>`.\n surface: {\n flat: '',\n elevated: '',\n },\n // Density tunes the avatar size + body padding. `comfortable` reads\n // as a page header; `compact` fits an embedded sidebar / aside.\n density: {\n comfortable: '',\n compact: '',\n },\n },\n defaultVariants: {\n surface: 'elevated',\n density: 'comfortable',\n },\n});\n\n/* -------------------------------------------------------------------- */\n/* Public types */\n/* -------------------------------------------------------------------- */\n\n/** Patient phone number — already formatted for display by the consumer. */\nexport interface PatientSummaryCardPhone {\n /** Display string, e.g. `\"+39 055 123 4567\"`. Compiled into a `tel:` link. */\n prefixAndNumber: string;\n /** Optional label that distinguishes this number (e.g. \"Mobile\"). */\n label?: string;\n /** Whether SMS is enabled for this number — shows a small \"SMS\" chip. */\n smsEnabled?: boolean;\n}\n\n/** A family relation row — links one patient to another. */\nexport interface PatientSummaryCardFamilyRelation {\n /** Localised relation label, consumer-supplied (e.g. \"Mother\", \"Child\"). */\n relation: string;\n /** The related patient — name + optional in-app profile URL. */\n relatedPatient: {\n name: string;\n url?: string;\n };\n}\n\n/** Operator the patient is assigned to. */\nexport interface PatientSummaryCardAssignee {\n name: string;\n avatarUrl?: string;\n}\n\n/** AI-consent grant metadata — structural only, never the consented content. */\nexport interface PatientSummaryCardAiConsent {\n /** ISO-8601 / display string of when consent was granted. */\n grantedAt: string;\n /** Optional name of who recorded the grant. */\n grantedBy?: string;\n}\n\n/** Addressable attention flags — the keys `onFlagActivate` accepts. */\nexport type PatientSummaryCardFlagId =\n | 'highlightedAnamnesis'\n | 'unsignedDocuments'\n | 'unpaid';\n\n/** Status flags rendered as glyph badges (counts / amounts only — no PHI). */\nexport interface PatientSummaryCardFlags {\n /** Number of anamnesis answers highlighted for clinical attention. */\n highlightedAnamnesisCount?: number;\n /** Outstanding balance in the smallest currency unit (cents). */\n unpaidAmountCents?: number;\n /** Number of documents awaiting the patient's signature. */\n unsignedDocumentsCount?: number;\n}\n\n/** Marketing-consent tri-state. */\nexport type PatientSummaryCardMarketingConsent = 'no' | 'yes' | 'not_specified';\n\nexport interface PatientSummaryCardHandle {\n /** Structural snapshot — identifiers and counts only, never patient identity. */\n getSummary: () => {\n id?: string;\n hasUnpaid: boolean;\n unsignedDocumentsCount: number;\n highlightedAnamnesisCount: number;\n aiConsentGranted: boolean;\n };\n}\n\nexport interface PatientSummaryCardProps extends Omit<\n ComponentPropsWithoutRef<'div'>,\n 'aria-label' | 'children'\n> {\n /** Patient display name. Rendered as the heading. */\n name: string;\n /** Honorific — `'mr'` / `'ms'`. Prepended to the name in the heading. */\n title?: 'mr' | 'ms';\n /** Patient age in whole years — rendered in the identity line. */\n ageYears?: number;\n /** Date of birth — already formatted for display by the consumer. */\n dateOfBirth?: string;\n /** Biological sex marker — `'m'` / `'f'`. Drives the identity-line glyph copy. */\n gender?: 'm' | 'f';\n /** Optional avatar / photo URL. Falls back to initials. */\n avatarUrl?: string;\n /**\n * In-app patient profile URL. When safe, the heading becomes a link.\n * Guarded by the shared `isSafeEntityUrl` allow-list — unsafe URLs are\n * dropped and the heading renders as plain text.\n */\n patientUrl?: string;\n\n /* ----- Shared field model (preferred) ----- */\n\n /**\n * Patient fields in the shared model — the SAME `sections` shape\n * `PatientDetails` consumes (`@alfadocs/ui-kit` `PatientFieldSection`).\n * When provided, the card renders these (honouring `visibleFieldOrder`)\n * instead of the legacy contact props, so a consumer defines its patient-\n * field registry once and reuses it across every patient surface.\n *\n * The card renders each field's `label`, `value`, and `icon` only — it is\n * flat (section headings are not shown in the body) and never inline-edits;\n * `sensitive` / `copyable` / `mono` / `editable` are honoured by\n * `PatientDetails`, not the card (so the PHI lock glyph does not appear here).\n *\n * Pass `onVisibleFieldsChange` alongside `sections` to make THIS placement\n * self-curating (a \"Customize fields\" cog appears — show/hide + drag-and-drop\n * reorder).\n */\n sections?: PatientFieldSection[];\n /**\n * Ordered visible field ids for THIS placement. The order is a\n * per-INSTANCE, per-CONTEXT preference the kit never persists — wire it to\n * whatever scope the consumer wants (e.g. a global per-user setting, or a\n * different config in the care-plan view vs the patient folder). The same\n * field vocabulary can therefore display differently in different parts of\n * the app. Omit (`undefined`) ⇒ show every field; an explicit empty array\n * `[]` ⇒ show none (a card that starts collapsed to name + identity chips and\n * reveals fields via the cog). Also applied to the legacy contact rows (ids\n * `email` / `phone` / `cityProvince` / `marketingConsent` / `aiConsent` /\n * `assignedTo`).\n */\n visibleFieldOrder?: string[];\n /**\n * Make this card's field set user-customizable. When provided alongside\n * `sections`, a \"Customize fields\" cog renders in the header (show/hide +\n * drag-and-drop / Alt+Arrow reorder), and this fires with the next ordered\n * visible set. The consumer owns persistence + its scope — editing here\n * writes only THIS context's preference, never a shared/global one.\n */\n onVisibleFieldsChange?: (orderedIds: string[]) => void;\n\n /* ----- Contact rows (legacy — prefer `sections`) ----- */\n\n /** @deprecated Pass via `sections`. Patient email — `mailto:` link when `emailEnabled`. */\n email?: string;\n /** Whether email contact is enabled — gates the `mailto:` link. */\n emailEnabled?: boolean;\n /** Phone number block. Compiled into a `tel:` link. */\n phone?: PatientSummaryCardPhone;\n /** City / province display string. */\n cityProvince?: string;\n\n /* ----- Consent ----- */\n\n /** Marketing-consent tri-state. */\n marketingConsent?: PatientSummaryCardMarketingConsent;\n /** AI-consent grant metadata. When present, an \"AI consent\" row renders. */\n aiConsent?: PatientSummaryCardAiConsent;\n\n /* ----- Status flags ----- */\n\n /** Counts / amounts surfaced as glyph badges. */\n flags?: PatientSummaryCardFlags;\n\n /* ----- Relations & assignment ----- */\n\n /** Family relations — rendered as `<Tag>` chips, optionally linked. */\n familyRelations?: PatientSummaryCardFamilyRelation[];\n /** Operator the patient is assigned to. */\n assignedTo?: PatientSummaryCardAssignee;\n\n /* ----- Formatting ----- */\n\n /** ISO-4217 currency code for the unpaid-amount chip. Defaults to `EUR`. */\n currency?: string;\n /** BCP-47 locale override. Defaults to the active i18next language. */\n locale?: string;\n\n /* ----- States ----- */\n\n /** Render the skeleton loading placeholder. */\n loading?: boolean;\n\n /* ----- Slots & callbacks ----- */\n\n /** Rendered at the inline-end of the heading row (e.g. an action menu). */\n actionSlot?: ReactNode;\n\n /**\n * Make an attention chip actionable. A handler turns that chip into a\n * button — \"2 unsigned documents\" opens the signing flow, the unpaid\n * balance opens invoicing. Without a handler the chip stays a read-only\n * badge, which is the default: most surfaces have nowhere to send the\n * reader.\n */\n onFlagActivate?: Partial<Record<PatientSummaryCardFlagId, () => void>>;\n /**\n * Explain a chip on hover / focus. The chip states WHAT (\"2 unsigned\n * documents\"); this states what the reader cannot see — how the signature\n * was requested, why the balance is outstanding.\n *\n * A string renders a `Tooltip`; a node renders a `HoverCard` with that node\n * as its content, for a host that wants the fuller card grammar (an eyebrow,\n * fact rows, a hint line). Either way the chip's own text stays the\n * accessible name and the surface only describes it.\n */\n flagHover?: Partial<Record<PatientSummaryCardFlagId, ReactNode>>;\n /**\n * Accessible name for the open button a hover CARD shows in its top-end\n * corner. The button appears only where the flag has BOTH a card and an\n * `onFlagActivate` handler — it mirrors the chip's own click so a pointer\n * that has travelled into the card can still act. Name the destination\n * (\"Open signing\"), not the gesture.\n *\n * Without a label there is no button: a card that merely describes should\n * not sprout an affordance the chip does not have.\n */\n flagOpenLabel?: Partial<Record<PatientSummaryCardFlagId, string>>;\n /**\n * Extra chips appended to the attention row, for signals the CARD cannot\n * model because they do not belong to the patient. An appointment panel\n * adds its own to-invoice and paid-online chips here; the card keeps its\n * patient-level flags and does not grow an appointment vocabulary.\n */\n extraChips?: ReactNode;\n\n /* ----- Inline editing (kit-owned controls, consumer-owned write) ----- */\n\n /**\n * Master switch — show the edit affordance on fields marked `editable` in\n * `sections`. The card edits through the SAME shared control as\n * `PatientDetails`, so a field offers the same affordance and the same\n * validation wherever it is shown.\n */\n editable?: boolean;\n /**\n * The single write channel. A rejected promise keeps the row in edit mode\n * and shows the message inline — the card never optimistically mutates the\n * value it was given.\n */\n onFieldSave?: (fieldId: string, value: unknown) => Promise<void>;\n /** Return a message to block the save and keep the row in edit mode. */\n validateField?: (fieldId: string, value: unknown) => string | null;\n /** Fires when the whole card / heading is activated. */\n onActivate?: () => void;\n\n /* ----- Styling ----- */\n\n /** `'elevated'` (default) wraps in `<Card>`; `'flat'` drops the chrome. */\n surface?: 'flat' | 'elevated';\n /** `'comfortable'` (default) reads as a header; `'compact'` for asides. */\n density?: 'comfortable' | 'compact';\n\n /* ----- a11y ----- */\n\n /** Override the default region aria-label. */\n 'aria-label'?: string;\n /** Agent-readiness consumer id, surfaced as `data-component-id`. */\n id?: string;\n}\n\n/* -------------------------------------------------------------------- */\n/* Helpers */\n/* -------------------------------------------------------------------- */\n\n/** Strip everything except digits + leading `+` for `tel:` URLs. */\nfunction normalisePhone(raw: string): string {\n return raw.replace(/[^\\d+]/g, '');\n}\n\n/* -------------------------------------------------------------------- */\n/* Flag glyphs — the closed set of status indicators */\n/* -------------------------------------------------------------------- */\n\n/** The closed set of status-flag keys (icon + tonal variant defined below). */\ntype FlagKey = 'highlightedAnamnesis' | 'unsignedDocuments';\n\nconst FLAG_ICON: Record<FlagKey, LucideIcon> = {\n highlightedAnamnesis: MessageSquareWarning,\n unsignedDocuments: FileExclamationPoint,\n};\n\nconst FLAG_VARIANT: Record<FlagKey, 'warning' | 'error'> = {\n highlightedAnamnesis: 'warning',\n unsignedDocuments: 'error',\n};\n\n/** English fallbacks for the flag badge accessible names (count-interpolated). */\nconst FLAG_LABEL_DEFAULTS: Record<FlagKey, string> = {\n highlightedAnamnesis: '{{count}} highlighted anamnesis answers',\n unsignedDocuments: '{{count}} unsigned documents',\n};\n\n/** English fallbacks for the marketing-consent tri-state chip. */\nconst MARKETING_CONSENT_DEFAULTS: Record<\n PatientSummaryCardMarketingConsent,\n string\n> = {\n yes: 'Yes',\n no: 'No',\n not_specified: 'Not specified',\n};\n\n/* -------------------------------------------------------------------- */\n/* Component */\n/* -------------------------------------------------------------------- */\n\nexport const PatientSummaryCard = forwardRef<\n HTMLDivElement,\n PatientSummaryCardProps\n>(\n (\n {\n name,\n title,\n ageYears,\n dateOfBirth,\n gender,\n avatarUrl,\n patientUrl,\n sections,\n visibleFieldOrder,\n onVisibleFieldsChange,\n email,\n emailEnabled = false,\n phone,\n cityProvince,\n marketingConsent,\n aiConsent,\n flags,\n familyRelations,\n assignedTo,\n currency = 'EUR',\n locale,\n loading = false,\n actionSlot,\n onFlagActivate,\n flagHover,\n flagOpenLabel,\n extraChips,\n editable = false,\n onFieldSave,\n validateField,\n onActivate,\n surface = 'elevated',\n density = 'comfortable',\n 'aria-label': ariaLabel,\n id,\n className,\n ...rest\n },\n ref,\n ) => {\n // Pinned to `ui` as a guard for a host that inits i18next with its own\n // `defaultNS`: the flag badges pass a defaultValue, so a miss is silent.\n const { t, i18n } = useTranslation('ui');\n const headingId = useId();\n const activeLocale = locale ?? i18n.language ?? 'en';\n\n const unpaidAmountCents = flags?.unpaidAmountCents;\n const unsignedDocumentsCount = flags?.unsignedDocumentsCount ?? 0;\n const highlightedAnamnesisCount = flags?.highlightedAnamnesisCount ?? 0;\n const hasUnpaid = unpaidAmountCents != null && unpaidAmountCents > 0;\n\n // Imperative handle — structural snapshot only (counts/flags/ids),\n // never the patient name or any clinical content.\n const handle = useMemo<PatientSummaryCardHandle>(\n () => ({\n getSummary: () => ({\n id,\n hasUnpaid,\n unsignedDocumentsCount,\n highlightedAnamnesisCount,\n aiConsentGranted: aiConsent != null,\n }),\n }),\n [\n id,\n hasUnpaid,\n unsignedDocumentsCount,\n highlightedAnamnesisCount,\n aiConsent,\n ],\n );\n useAgentRegistration(patientSummaryCardAgent, handle, id);\n\n // Per-context field visibility. The cog (and live reordering) only engages\n // with the shared `sections` model AND an `onVisibleFieldsChange` handler;\n // legacy contact-prop cards stay read-only. The order is this placement's\n // own preference — never shared across surfaces.\n const customizable = !!sections && !!onVisibleFieldsChange;\n const fieldVisibility = usePatientFieldVisibility(sections ?? NO_SECTIONS, {\n value: visibleFieldOrder,\n onChange: onVisibleFieldsChange,\n });\n\n const resolvedAriaLabel =\n ariaLabel ??\n t('patientSummaryCard.regionLabel', { defaultValue: 'Patient overview' });\n\n // Heading text: optional honorific prefix + name.\n const TITLE_DEFAULTS: Record<'mr' | 'ms', string> = {\n mr: 'Mr.',\n ms: 'Ms.',\n };\n const honorific = title\n ? t(`patientSummaryCard.title.${title}`, {\n defaultValue: TITLE_DEFAULTS[title],\n })\n : undefined;\n // A translated PATTERN, not a hardcoded `${honorific} ${name}` join:\n // several of the 18 locales order or punctuate a name-with-title\n // differently (or drop it) — a locale can override the pattern\n // without touching this component.\n const headingText = honorific\n ? t('patientSummaryCard.nameWithHonorific', {\n honorific,\n name,\n defaultValue: '{{honorific}} {{name}}',\n })\n : name;\n\n // Identity line: the canonical sex / age / dob chips below the name — the\n // SAME chips the field model renders, so the header and the field rows\n // agree. Each chip is added only when its prop is present. (`dateOfBirth`\n // is a consumer-preformatted display string, so it goes through NeutralChip\n // directly rather than the date-parsing `dob` kind.)\n const identityChips: ReactNode[] = [];\n if (gender) {\n identityChips.push(<SexChip key=\"sex\" code={gender} />);\n }\n if (ageYears != null) {\n identityChips.push(<AgeChip key=\"age\" years={ageYears} />);\n }\n if (dateOfBirth) {\n identityChips.push(\n <NeutralChip key=\"dob\" icon={<CalendarDays />}>\n {dateOfBirth}\n </NeutralChip>,\n );\n }\n\n const isUrlSafe = !!patientUrl && isSafeEntityUrl(patientUrl);\n\n const avatarSize = density === 'comfortable' ? 'xl' : 'lg';\n const headingClass =\n density === 'comfortable' ? 'type-title-card' : 'type-title-item';\n const bodyGapClass =\n density === 'comfortable'\n ? 'ds:gap-[var(--spacing-md)]'\n : 'ds:gap-[var(--spacing-sm)]';\n\n /* ---------------------------------------------------------------- */\n /* Contact rows */\n /* ---------------------------------------------------------------- */\n\n const rows: Array<{\n key: string;\n icon: ReactElement;\n label: string;\n value: ReactNode;\n }> = [];\n\n if (email) {\n rows.push({\n key: 'email',\n icon: <Mail aria-hidden=\"true\" />,\n label: t('patientSummaryCard.label.email', { defaultValue: 'Email' }),\n value: emailEnabled ? (\n <Link\n href={`mailto:${email}`}\n intent=\"default\"\n onClick={onActivate}\n dir=\"ltr\"\n >\n {email}\n </Link>\n ) : (\n <span className=\"ds:text-[color:var(--muted-foreground)]\" dir=\"ltr\">\n {email}\n </span>\n ),\n });\n }\n\n if (phone) {\n rows.push({\n key: 'phone',\n icon: <Phone aria-hidden=\"true\" />,\n label:\n phone.label ??\n t('patientSummaryCard.label.phone', { defaultValue: 'Phone' }),\n value: (\n <span className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-2xs)]\">\n <Link\n href={`tel:${normalisePhone(phone.prefixAndNumber)}`}\n intent=\"default\"\n dir=\"ltr\"\n >\n {phone.prefixAndNumber}\n </Link>\n {phone.smsEnabled ? (\n <Badge variant=\"success\" size=\"sm\">\n {t('patientSummaryCard.value.smsEnabled', {\n defaultValue: 'SMS',\n })}\n </Badge>\n ) : null}\n </span>\n ),\n });\n }\n\n if (cityProvince) {\n rows.push({\n key: 'cityProvince',\n icon: <MapPin aria-hidden=\"true\" />,\n label: t('patientSummaryCard.label.cityProvince', {\n defaultValue: 'City / province',\n }),\n value: cityProvince,\n });\n }\n\n if (marketingConsent) {\n rows.push({\n key: 'marketingConsent',\n icon: <ShieldCheck aria-hidden=\"true\" />,\n label: t('patientSummaryCard.label.marketingConsent', {\n defaultValue: 'Marketing consent',\n }),\n value: (\n <Badge\n variant={\n marketingConsent === 'yes'\n ? 'success'\n : marketingConsent === 'no'\n ? 'error'\n : 'neutral'\n }\n size=\"sm\"\n withDot\n >\n {t(`patientSummaryCard.marketingConsent.${marketingConsent}`, {\n defaultValue: MARKETING_CONSENT_DEFAULTS[marketingConsent],\n })}\n </Badge>\n ),\n });\n }\n\n if (aiConsent) {\n rows.push({\n key: 'aiConsent',\n icon: <Astroid aria-hidden=\"true\" />,\n label: t('patientSummaryCard.label.aiConsent', {\n defaultValue: 'AI consent',\n }),\n value: aiConsent.grantedBy\n ? t('patientSummaryCard.value.aiConsentGrantedBy', {\n date: aiConsent.grantedAt,\n by: aiConsent.grantedBy,\n defaultValue: 'Granted {{date}} by {{by}}',\n })\n : t('patientSummaryCard.value.aiConsentGrantedAt', {\n date: aiConsent.grantedAt,\n defaultValue: 'Granted {{date}}',\n }),\n });\n }\n\n if (assignedTo) {\n rows.push({\n key: 'assignedTo',\n icon: <Users aria-hidden=\"true\" />,\n label: t('patientSummaryCard.label.assignedTo', {\n defaultValue: 'Assigned to',\n }),\n value: (\n <span className=\"ds:flex ds:items-center ds:gap-[var(--spacing-xs)]\">\n <Avatar\n size=\"xs\"\n name={assignedTo.name}\n src={assignedTo.avatarUrl}\n />\n <span>{assignedTo.name}</span>\n </span>\n ),\n });\n }\n\n /* ---------------------------------------------------------------- */\n /* Attention-flag chips (VERBOSE — shown in the identity line) */\n /* */\n /* The unpaid balance + warning counts sit in the chip row under the */\n /* name, BEFORE the sex / age chips, each as a self-describing chip */\n /* (\"2 unsigned documents\") rather than a collapsed count badge in a */\n /* separate strip — the attention signals lead the patient's chips. */\n /* ---------------------------------------------------------------- */\n\n const flagBadges: Array<{ key: FlagKey; count: number }> = [];\n if (highlightedAnamnesisCount > 0) {\n flagBadges.push({\n key: 'highlightedAnamnesis',\n count: highlightedAnamnesisCount,\n });\n }\n if (unsignedDocumentsCount > 0) {\n flagBadges.push({\n key: 'unsignedDocuments',\n count: unsignedDocumentsCount,\n });\n }\n\n /* A chip becomes a BUTTON only when the host gave it somewhere to go.\n The chip's own text is already its accessible name, so the wrapper adds\n no label of its own and contributes no padding — the strip's rhythm is\n identical whether or not a chip is actionable. */\n /* A chip becomes a CONTROL when it has something to reveal or somewhere\n to go, and the trigger is always a real <button> — `asChild` on a bare\n <span> badge stamps `aria-haspopup` onto something a keyboard can never\n reach, which is both a dead end and an axe violation.\n\n The division of labour is the same on every chip: the chip opens its\n card (hover, or click / Enter for keyboard and touch), and the card's\n own top-end button performs the action. One gesture to learn, and no\n chip that acts differently from its neighbour. */\n const asAction = (id: PatientSummaryCardFlagId, chip: ReactNode) => {\n const onActivateFlag = onFlagActivate?.[id];\n const hover = flagHover?.[id];\n if (hover == null && !onActivateFlag) return chip;\n\n const triggerClasses =\n 'ds:inline-flex ds:cursor-pointer ds:rounded-[var(--radius-full)] ds:p-0 ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid ds:focus-visible:outline-[color:var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]';\n\n // No card: the chip itself is the action.\n if (hover == null) {\n return (\n <button\n key={id}\n type=\"button\"\n data-flag-action={id}\n onClick={onActivateFlag}\n className={triggerClasses}\n >\n {chip}\n </button>\n );\n }\n\n const trigger = (\n <button\n key={id}\n type=\"button\"\n data-flag-action={onActivateFlag ? id : undefined}\n data-flag-hover={id}\n className={triggerClasses}\n >\n {chip}\n </button>\n );\n\n // A string still renders a plain Tooltip, for a chip that needs naming\n // rather than a card.\n if (typeof hover === 'string') {\n return (\n <Tooltip key={id} label={hover} side=\"bottom\">\n {trigger}\n </Tooltip>\n );\n }\n\n return (\n <HoverCard key={id}>\n <HoverCard.Trigger asChild>{trigger}</HoverCard.Trigger>\n <HoverCard.Content\n side=\"bottom\"\n align=\"start\"\n size=\"sm\"\n headerAction={\n onActivateFlag && flagOpenLabel?.[id] ? (\n <IconButton\n icon={<ArrowUpRight />}\n /* Outline, not ghost: the card's own surface is already\n light, so a borderless glyph reads as decoration rather\n than a control. */\n intent=\"outline\"\n background=\"surface\"\n size=\"sm\"\n aria-label={flagOpenLabel[id] as string}\n onClick={onActivateFlag}\n />\n ) : undefined\n }\n >\n {hover}\n </HoverCard.Content>\n </HoverCard>\n );\n };\n\n const attentionChips: ReactNode[] = [];\n if (hasUnpaid) {\n attentionChips.push(\n asAction(\n 'unpaid',\n <TransactionChip\n key=\"unpaid\"\n state=\"debt\"\n amount={(unpaidAmountCents as number) / 100}\n currency={currency}\n locale={activeLocale}\n size=\"md\"\n showLabel\n />,\n ),\n );\n }\n flagBadges.forEach(({ key, count }) => {\n const FlagIcon = FLAG_ICON[key];\n // The Badge's visible text IS the count-interpolated label, so it's its\n // own accessible name — the leading glyph is decorative (aria-hidden).\n attentionChips.push(\n asAction(\n key,\n <Badge\n key={key}\n variant={FLAG_VARIANT[key]}\n size=\"md\"\n leading={<FlagIcon aria-hidden=\"true\" />}\n >\n {t(`patientSummaryCard.flag.${key}`, {\n count,\n defaultValue: FLAG_LABEL_DEFAULTS[key],\n })}\n </Badge>,\n ),\n );\n });\n if (extraChips) attentionChips.push(extraChips);\n\n /* ---------------------------------------------------------------- */\n /* Loading skeleton */\n /* ---------------------------------------------------------------- */\n\n const skeletonBody = (\n <div className={`ds:flex ds:flex-col ${bodyGapClass}`}>\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-md)]\">\n <Skeleton variant=\"circular\" size=\"lg\" />\n <div className=\"ds:flex ds:flex-1 ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <Skeleton variant=\"text\" width=\"60%\" />\n <Skeleton variant=\"text\" width=\"40%\" />\n </div>\n </div>\n <Skeleton variant=\"text\" lines={3} />\n </div>\n );\n\n /* ---------------------------------------------------------------- */\n /* Header */\n /* ---------------------------------------------------------------- */\n\n const heading = isUrlSafe ? (\n <Link\n href={patientUrl as string}\n intent=\"default\"\n weight=\"strong\"\n onClick={onActivate}\n className={`${headingClass} ds:no-underline`}\n >\n <span id={headingId}>{headingText}</span>\n </Link>\n ) : (\n <span\n id={headingId}\n className={`${headingClass} ds:text-[color:var(--foreground)]`}\n >\n {headingText}\n </span>\n );\n\n const header = (\n <div className=\"ds:flex ds:items-start ds:gap-[var(--spacing-md)]\">\n <Avatar\n size={avatarSize}\n name={name}\n src={avatarUrl}\n className=\"ds:shrink-0\"\n />\n <div className=\"ds:flex ds:min-w-0 ds:flex-1 ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n {heading}\n {attentionChips.length > 0 || identityChips.length > 0 ? (\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)]\">\n {/* Attention flags lead, then the sex / age / dob identity chips. */}\n {attentionChips}\n {identityChips}\n </div>\n ) : null}\n </div>\n {customizable || actionSlot ? (\n <div className=\"ds:ms-auto ds:flex ds:shrink-0 ds:items-center ds:gap-[var(--spacing-xs)]\">\n {customizable && sections ? (\n <FieldVisibilityCog\n sections={sections}\n visible={fieldVisibility.visible}\n onToggleField={fieldVisibility.toggleField}\n onToggleSection={fieldVisibility.toggleSection}\n onMoveFieldOnto={fieldVisibility.moveFieldOnto}\n onReset={fieldVisibility.reset}\n />\n ) : null}\n {actionSlot}\n </div>\n ) : null}\n </div>\n );\n\n /* ---------------------------------------------------------------- */\n /* Family relations */\n /* ---------------------------------------------------------------- */\n\n const familyBlock =\n familyRelations && familyRelations.length > 0 ? (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <span className=\"type-label ds:text-[color:var(--muted-foreground)]\">\n {t('patientSummaryCard.label.familyRelations', {\n defaultValue: 'Family relations',\n })}\n </span>\n <div className=\"ds:flex ds:flex-wrap ds:gap-[var(--spacing-2xs)]\">\n {familyRelations.map((rel, index) => {\n const safeUrl =\n !!rel.relatedPatient.url &&\n isSafeEntityUrl(rel.relatedPatient.url);\n const tagLabel = t('patientSummaryCard.value.familyRelation', {\n relation: rel.relation,\n name: rel.relatedPatient.name,\n defaultValue: '{{relation}}: {{name}}',\n });\n return safeUrl ? (\n <Link\n key={`${rel.relation}-${index}`}\n href={rel.relatedPatient.url as string}\n intent=\"default\"\n className=\"ds:no-underline\"\n >\n <Tag label={tagLabel} variant=\"neutral\" />\n </Link>\n ) : (\n <Tag\n key={`${rel.relation}-${index}`}\n label={tagLabel}\n variant=\"neutral\"\n />\n );\n })}\n </div>\n </div>\n ) : null;\n\n /* ---------------------------------------------------------------- */\n /* Body */\n /* ---------------------------------------------------------------- */\n\n // Field rows resolve through the SHARED model: when the consumer passes\n // `sections` (preferred), render those; otherwise wrap the legacy contact\n // rows as a single section. Either way `resolveVisibleFields` applies the\n // shared `visibleFieldOrder` preference, so the card and PatientDetails\n // always show the same fields, honouring the same per-user choice.\n const legacyFields: PatientField[] = rows.map((row) => ({\n id: row.key,\n label: row.label,\n value: row.value,\n icon: row.icon,\n }));\n const effectiveSections: PatientFieldSection[] = sections ?? [\n { id: 'contact', heading: '', fields: legacyFields },\n ];\n // With the shared `sections` model the order comes from the visibility hook\n // (so a cog reorder reflects live); legacy contact rows honour the raw\n // `visibleFieldOrder` prop.\n const order = sections ? fieldVisibility.visible : visibleFieldOrder;\n const visibleFields = resolveVisibleFields(\n effectiveSections,\n order,\n ).flatMap((resolved) => resolved.fields);\n\n const body = (\n <div className={`ds:flex ds:flex-col ${bodyGapClass}`}>\n {header}\n {visibleFields.length > 0 ? (\n // Container-queried so the fields flow into two columns when the\n // card is wide enough (the banner spans the full folder width), and\n // stay single-column in a narrow rail. The list's KeyValuePair\n // children already `col-span-3`; doubling the parent to six tracks\n // (`repeat(2, …)`) lets grid auto-flow place two fields per row while\n // each column keeps its own subgrid label/value alignment.\n // 672px, not the `@2xl` rem alias: container-query `rem` follows the\n // host root font-size, so a non-16px root moves the threshold.\n // Each label column stops at 20% of the card (every field has an\n // icon, so labels sit in the middle track of each group): a long\n // label wraps instead of squeezing its value, as KeyValueList's\n // single-column cap does at 40%.\n <div className=\"ds:@container/pfields\">\n <KeyValueList\n rowGap=\"sm\"\n className=\"ds:@[672px]/pfields:grid-cols-[repeat(2,auto_fit-content(20%)_minmax(0,1fr))]\"\n >\n {visibleFields.map((field) => (\n <KeyValuePair\n key={field.id}\n icon={field.icon ?? undefined}\n label={field.label}\n labelNode={<PatientFieldLabel field={field} />}\n // `group` is what reveals the edit pencil on hover / focus;\n // the cell itself carries no row markup.\n className=\"ds:group\"\n data-field-id={field.id}\n value={\n <PatientFieldValueCell\n field={field}\n editable={editable}\n onFieldSave={onFieldSave}\n validate={validateField}\n locale={locale}\n />\n }\n />\n ))}\n </KeyValueList>\n </div>\n ) : null}\n {familyBlock}\n </div>\n );\n\n const inner = loading ? skeletonBody : body;\n\n return (\n <div\n ref={ref}\n role=\"region\"\n // When the heading is rendered, the patient name (via\n // aria-labelledby) is the region's accessible name — the more\n // meaningful label than a generic \"Patient overview\". A consumer\n // aria-label still wins; the generic fallback only applies when\n // there is no heading to point at (loading state).\n aria-label={loading || ariaLabel ? resolvedAriaLabel : undefined}\n aria-labelledby={loading || ariaLabel ? undefined : headingId}\n aria-busy={loading || undefined}\n data-component=\"patient-summary-card\"\n data-component-id={id}\n data-density={density}\n id={id}\n className={rootVariants({ surface, density, className })}\n {...rest}\n >\n {surface === 'elevated' ? (\n <Card variant=\"elevated\">\n <Card.Body>{inner}</Card.Body>\n </Card>\n ) : (\n inner\n )}\n </div>\n );\n },\n);\n\nPatientSummaryCard.displayName = 'PatientSummaryCard';\n\n/** Variant unions re-exported for downstream typing. */\nexport type PatientSummaryCardSurface = NonNullable<\n VariantProps<typeof rootVariants>['surface']\n>;\nexport type PatientSummaryCardDensity = NonNullable<\n VariantProps<typeof rootVariants>['density']\n>;\n"],"names":["__iconNode","FileExclamationPoint","createLucideIcon","MessageSquareWarning","patientSummaryCardAgent","handle","NO_SECTIONS","rootVariants","cva","normalisePhone","raw","FLAG_ICON","FLAG_VARIANT","FLAG_LABEL_DEFAULTS","MARKETING_CONSENT_DEFAULTS","PatientSummaryCard","forwardRef","name","title","ageYears","dateOfBirth","gender","avatarUrl","patientUrl","sections","visibleFieldOrder","onVisibleFieldsChange","email","emailEnabled","phone","cityProvince","marketingConsent","aiConsent","flags","familyRelations","assignedTo","currency","locale","loading","actionSlot","onFlagActivate","flagHover","flagOpenLabel","extraChips","editable","onFieldSave","validateField","onActivate","surface","density","ariaLabel","id","className","rest","ref","i18n","useTranslation","headingId","useId","activeLocale","unpaidAmountCents","unsignedDocumentsCount","highlightedAnamnesisCount","hasUnpaid","useMemo","useAgentRegistration","customizable","fieldVisibility","usePatientFieldVisibility","resolvedAriaLabel","TITLE_DEFAULTS","honorific","headingText","identityChips","jsx","SexChip","AgeChip","NeutralChip","CalendarDays","isUrlSafe","isSafeEntityUrl","avatarSize","headingClass","bodyGapClass","rows","Mail","Link","Phone","jsxs","Badge","MapPin","ShieldCheck","Astroid","Users","Avatar","flagBadges","asAction","chip","onActivateFlag","hover","triggerClasses","trigger","Tooltip","HoverCard","IconButton","ArrowUpRight","attentionChips","TransactionChip","key","count","FlagIcon","skeletonBody","Skeleton","heading","header","FieldVisibilityCog","familyBlock","rel","index","safeUrl","tagLabel","Tag","legacyFields","row","effectiveSections","order","visibleFields","resolveVisibleFields","resolved","body","KeyValueList","field","KeyValuePair","PatientFieldLabel","PatientFieldValueCell","inner","Card"],"mappings":"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","x_google_ignoreList":[0,1]}
|
package/dist/_chunks/{periodontal-diagnosis-B9YmmVmM.js → periodontal-diagnosis-DD3hrg9X.js}
RENAMED
|
@@ -4,7 +4,7 @@ import { c as Z } from "./index-D2ZczOXr.js";
|
|
|
4
4
|
import { useTranslation as ee } from "react-i18next";
|
|
5
5
|
import { B as te } from "./badge-BUk4RjTS.js";
|
|
6
6
|
import { C as j } from "./card-BA4Ig_kn.js";
|
|
7
|
-
import { C as ae } from "./checkbox-
|
|
7
|
+
import { C as ae } from "./checkbox-a7Sh-dXb.js";
|
|
8
8
|
import { R as y } from "./radio-BZQs6_36.js";
|
|
9
9
|
import { R as D } from "./radio-group-ChIKyeSJ.js";
|
|
10
10
|
import { u as oe } from "./registry-DvAUVLHh.js";
|
|
@@ -342,4 +342,4 @@ export {
|
|
|
342
342
|
k as i,
|
|
343
343
|
ne as p
|
|
344
344
|
};
|
|
345
|
-
//# sourceMappingURL=periodontal-diagnosis-
|
|
345
|
+
//# sourceMappingURL=periodontal-diagnosis-DD3hrg9X.js.map
|
package/dist/_chunks/{periodontal-diagnosis-B9YmmVmM.js.map → periodontal-diagnosis-DD3hrg9X.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"periodontal-diagnosis-B9YmmVmM.js","sources":["../../src/components/periodontal-diagnosis/periodontal-diagnosis.agent.ts","../../src/components/periodontal-diagnosis/periodontal-diagnosis-data.ts","../../src/components/periodontal-diagnosis/periodontal-diagnosis.tsx"],"sourcesContent":["import type { AgentAdapter } from '../../agent/types';\nimport type { PeriodontalDiagnosisHandle } from './periodontal-diagnosis';\nimport type {\n PeriodontitisExtent,\n PeriodontitisGrade,\n PeriodontitisStage,\n} from './periodontal-diagnosis-data';\n\n/* -------------------------------------------------------------------- */\n/* PeriodontalDiagnosis — agent adapter */\n/* */\n/* Agents can read the recorded stage / grade / extent / factors and the */\n/* worded summary, and can set each field. The free-text clinician note */\n/* (PHI) is never exposed — getDiagnosis() strips it. */\n/* -------------------------------------------------------------------- */\n\nconst STAGE_SCHEMA = {\n enum: [1, 2, 3, 4],\n description: 'Periodontitis stage I–IV, as the integers 1–4.',\n} as const;\nconst GRADE_SCHEMA = {\n enum: ['A', 'B', 'C'],\n description: 'Periodontitis grade A–C (rate of progression).',\n} as const;\nconst EXTENT_SCHEMA = {\n enum: ['localised', 'generalised', 'molarIncisor'],\n description:\n 'Distribution: localised (<30%), generalised (≥30%), or molar-incisor.',\n} as const;\n\nexport const periodontalDiagnosisAgent: AgentAdapter<PeriodontalDiagnosisHandle> =\n {\n id: 'periodontal-diagnosis',\n // set_value — set stage / grade / extent / a factor. Each set_* action's\n // enum argsSchema already conveys that the field is a closed choice.\n capabilities: ['set_value'],\n state: {\n diagnosis: {\n type: 'object',\n descriptionKey: 'ui.agent.periodontalDiagnosis.state.diagnosis',\n description:\n 'Recorded stage (1–4), grade (A–C), extent, and ticked contributing-factor ids. The free-text note is never included.',\n read: (handle) => handle.getDiagnosis(),\n },\n summary: {\n type: 'string',\n descriptionKey: 'ui.agent.periodontalDiagnosis.state.summary',\n description:\n 'The composed, localised diagnosis sentence (e.g. \"Periodontitis — Stage III · Grade B · generalised\").',\n read: (handle) => handle.getSummary(),\n },\n complete: {\n type: 'boolean',\n descriptionKey: 'ui.agent.periodontalDiagnosis.state.complete',\n description: 'True once both a stage and a grade are recorded.',\n read: (handle) => handle.isComplete(),\n },\n },\n actions: {\n get_diagnosis: {\n safety: 'read',\n argsType: '{}',\n argsSchema: { type: 'object', properties: {} },\n returns: 'object',\n returnsSchema: { type: 'object' },\n idempotent: true,\n descriptionKey: 'ui.agent.periodontalDiagnosis.actions.getDiagnosis',\n description:\n 'Read the recorded stage / grade / extent / factors. The note is never returned.',\n invoke: (handle) => handle.getDiagnosis(),\n },\n set_stage: {\n safety: 'write',\n argsType: '{ stage: 1 | 2 | 3 | 4 }',\n argsSchema: {\n type: 'object',\n properties: { stage: STAGE_SCHEMA },\n required: ['stage'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.periodontalDiagnosis.actions.setStage',\n description: 'Record the periodontitis stage (I–IV).',\n invoke: (handle, args: { stage: PeriodontitisStage }) => {\n handle.setStage(args.stage);\n },\n },\n set_grade: {\n safety: 'write',\n argsType: \"{ grade: 'A' | 'B' | 'C' }\",\n argsSchema: {\n type: 'object',\n properties: { grade: GRADE_SCHEMA },\n required: ['grade'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.periodontalDiagnosis.actions.setGrade',\n description: 'Record the periodontitis grade (A–C).',\n invoke: (handle, args: { grade: PeriodontitisGrade }) => {\n handle.setGrade(args.grade);\n },\n },\n set_extent: {\n safety: 'write',\n argsType: \"{ extent: 'localised' | 'generalised' | 'molarIncisor' }\",\n argsSchema: {\n type: 'object',\n properties: { extent: EXTENT_SCHEMA },\n required: ['extent'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.periodontalDiagnosis.actions.setExtent',\n description: 'Record the distribution / extent.',\n invoke: (handle, args: { extent: PeriodontitisExtent }) => {\n handle.setExtent(args.extent);\n },\n },\n toggle_factor: {\n safety: 'write',\n argsType: '{ id: string; value: boolean }',\n argsSchema: {\n type: 'object',\n properties: {\n id: { type: 'string', description: 'Contributing-factor id.' },\n value: { type: 'boolean' },\n },\n required: ['id', 'value'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.periodontalDiagnosis.actions.toggleFactor',\n description: 'Tick or clear a contributing factor.',\n invoke: (handle, args: { id: string; value: boolean }) => {\n handle.toggleFactor(args.id, args.value);\n },\n },\n clear_diagnosis: {\n safety: 'destructive',\n argsType: '{}',\n argsSchema: { type: 'object', properties: {} },\n idempotent: true,\n descriptionKey: 'ui.agent.periodontalDiagnosis.actions.clearDiagnosis',\n description: 'Reset the whole diagnosis to empty.',\n invoke: (handle) => {\n handle.clear();\n },\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'periodontal-diagnosis',\n description: 'Marks the PeriodontalDiagnosis root group.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n },\n };\n","/* -------------------------------------------------------------------- */\n/* PeriodontalDiagnosis — data model */\n/* */\n/* The 2017 World Workshop / EFP periodontitis classification: a stage */\n/* (I–IV, severity + complexity), a grade (A–C, rate of progression) and */\n/* an extent (localised / generalised / molar-incisor). The jurisdiction- */\n/* specific *algorithm* that derives stage & grade from clinical findings */\n/* stays in the consumer; this component is the reusable, controllable */\n/* form + summary. A curated checklist of contributing factors gives the */\n/* clinician context without baking one country's logic into the kit. */\n/* -------------------------------------------------------------------- */\n\nexport type PeriodontitisStage = 1 | 2 | 3 | 4;\nexport type PeriodontitisGrade = 'A' | 'B' | 'C';\nexport type PeriodontitisExtent = 'localised' | 'generalised' | 'molarIncisor';\n\nexport const PERIODONTITIS_STAGES: readonly PeriodontitisStage[] = [1, 2, 3, 4];\nexport const PERIODONTITIS_GRADES: readonly PeriodontitisGrade[] = [\n 'A',\n 'B',\n 'C',\n];\nexport const PERIODONTITIS_EXTENTS: readonly PeriodontitisExtent[] = [\n 'localised',\n 'generalised',\n 'molarIncisor',\n];\n\n/** Roman numeral for a stage — matches the WHO / EFP notation. */\nexport const STAGE_ROMAN: Record<PeriodontitisStage, string> = {\n 1: 'I',\n 2: 'II',\n 3: 'III',\n 4: 'IV',\n};\n\n/**\n * The default contributing-factor checklist — the staging (severity) and\n * grading (progression) drivers of the 2017 classification. Consumers can\n * pass their own list of ids to localise the questionnaire.\n */\nexport const DEFAULT_DIAGNOSIS_FACTORS = [\n 'interdentalCal',\n 'radiographicBoneLoss',\n 'toothLossPerio',\n 'probingDepth6',\n 'boneLossAgeOver1',\n 'smoker',\n 'diabetes',\n] as const;\n\nexport type PeriodontalDiagnosisFactor =\n (typeof DEFAULT_DIAGNOSIS_FACTORS)[number];\n\n/** The recorded diagnosis. `note` is free-text PHI and never leaves the UI. */\nexport interface PeriodontalDiagnosisValue {\n stage?: PeriodontitisStage;\n grade?: PeriodontitisGrade;\n extent?: PeriodontitisExtent;\n /** Ids of the ticked contributing factors. */\n factors?: string[];\n /** Free-text clinician note — PHI; excluded from the agent adapter. */\n note?: string;\n}\n\n/** A diagnosis needs at least a stage and a grade to read as complete. */\nexport function isDiagnosisComplete(value: PeriodontalDiagnosisValue): boolean {\n return value.stage != null && value.grade != null;\n}\n\n/** A fresh, empty diagnosis. */\nexport function emptyDiagnosis(): PeriodontalDiagnosisValue {\n return {};\n}\n","import {\n forwardRef,\n useId,\n useRef,\n useState,\n type ComponentPropsWithoutRef,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { Badge } from '../badge/badge';\nimport { Card } from '../card/card';\nimport { Checkbox } from '../checkbox/checkbox';\nimport { Radio } from '../radio-group/radio';\nimport { RadioGroup } from '../radio-group/radio-group';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { periodontalDiagnosisAgent } from './periodontal-diagnosis.agent';\nimport {\n DEFAULT_DIAGNOSIS_FACTORS,\n emptyDiagnosis,\n isDiagnosisComplete,\n PERIODONTITIS_EXTENTS,\n PERIODONTITIS_GRADES,\n PERIODONTITIS_STAGES,\n STAGE_ROMAN,\n type PeriodontalDiagnosisValue,\n type PeriodontitisExtent,\n type PeriodontitisGrade,\n type PeriodontitisStage,\n} from './periodontal-diagnosis-data';\n\n/* -------------------------------------------------------------------- */\n/* PeriodontalDiagnosis */\n/* */\n/* The 2017 World Workshop / EFP periodontitis classification form: */\n/* stage (I–IV), grade (A–C), extent, and a curated checklist of the */\n/* staging/grading contributing factors. Controlled or uncontrolled. */\n/* The composed summary (\"Periodontitis — Stage III · Grade B · */\n/* generalised\") is the worded, non-colour source of truth. */\n/* -------------------------------------------------------------------- */\n\nconst rootVariants = cva('ds:w-full ds:text-[color:var(--foreground)]', {\n variants: {\n surface: { flat: '', elevated: '' },\n },\n defaultVariants: { surface: 'elevated' },\n});\n\n/* -------------------------------------------------------------------- */\n/* Types */\n/* -------------------------------------------------------------------- */\n\nexport interface PeriodontalDiagnosisHandle {\n /** The recorded stage / grade / extent / factors — never the free-text note. */\n getDiagnosis: () => Omit<PeriodontalDiagnosisValue, 'note'>;\n /** The composed, localised summary sentence. */\n getSummary: () => string;\n /** True once both a stage and a grade are recorded. */\n isComplete: () => boolean;\n setStage: (stage: PeriodontitisStage) => void;\n setGrade: (grade: PeriodontitisGrade) => void;\n setExtent: (extent: PeriodontitisExtent) => void;\n toggleFactor: (id: string, on?: boolean) => void;\n /** Reset to an empty diagnosis. */\n clear: () => void;\n}\n\nexport interface PeriodontalDiagnosisProps extends Omit<\n ComponentPropsWithoutRef<'div'>,\n 'aria-label' | 'children' | 'onChange' | 'defaultValue'\n> {\n /** Controlled value. */\n value?: PeriodontalDiagnosisValue;\n /** Uncontrolled initial value. */\n defaultValue?: PeriodontalDiagnosisValue;\n /** Fires with the next diagnosis whenever the clinician changes a field. */\n onChange?: (value: PeriodontalDiagnosisValue) => void;\n /** `'interactive'` (default) renders the form; `'display'` is read-only. */\n mode?: 'interactive' | 'display';\n /** Disable every control. */\n disabled?: boolean;\n /** Contributing-factor ids for the checklist. Defaults to the WHO-2017 set. */\n factors?: readonly string[];\n /** `'elevated'` (default) wraps in a Card; `'flat'` drops the chrome. */\n surface?: 'flat' | 'elevated';\n /** Override the default region aria-label. */\n 'aria-label'?: string;\n /** Agent-readiness consumer id, surfaced as `data-component-id`. */\n id?: string;\n}\n\n/* -------------------------------------------------------------------- */\n/* Component */\n/* -------------------------------------------------------------------- */\n\nexport const PeriodontalDiagnosis = forwardRef<\n HTMLDivElement,\n PeriodontalDiagnosisProps\n>(\n (\n {\n value,\n defaultValue,\n onChange,\n mode = 'interactive',\n disabled = false,\n factors = DEFAULT_DIAGNOSIS_FACTORS,\n surface = 'elevated',\n 'aria-label': ariaLabel,\n id,\n className,\n ...rest\n },\n ref,\n ) => {\n const { t } = useTranslation('ui');\n const headingId = useId();\n\n const isControlled = value !== undefined;\n const [internal, setInternal] = useState<PeriodontalDiagnosisValue>(\n defaultValue ?? emptyDiagnosis(),\n );\n const current = isControlled ? value : internal;\n\n // Latest committed value — so an agent making several edits in one tick\n // always builds on the previous edit, not a stale render snapshot.\n const valueRef = useRef(current);\n valueRef.current = current;\n\n const commit = (next: PeriodontalDiagnosisValue) => {\n valueRef.current = next;\n if (!isControlled) setInternal(next);\n onChange?.(next);\n };\n\n const setStage = (stage: PeriodontitisStage) =>\n commit({ ...valueRef.current, stage });\n const setGrade = (grade: PeriodontitisGrade) =>\n commit({ ...valueRef.current, grade });\n const setExtent = (extent: PeriodontitisExtent) =>\n commit({ ...valueRef.current, extent });\n const toggleFactor = (factorId: string, on?: boolean) => {\n const set = new Set(valueRef.current.factors ?? []);\n const next = on ?? !set.has(factorId);\n if (next) set.add(factorId);\n else set.delete(factorId);\n commit({ ...valueRef.current, factors: [...set] });\n };\n const clear = () => commit(emptyDiagnosis());\n\n const complete = isDiagnosisComplete(current);\n const activeFactors = current.factors ?? [];\n\n const stageLabel = (s: PeriodontitisStage) =>\n t(`periodontalDiagnosis.stage.option`, {\n roman: STAGE_ROMAN[s],\n defaultValue: `Stage ${STAGE_ROMAN[s]}`,\n });\n const gradeLabel = (g: PeriodontitisGrade) =>\n t(`periodontalDiagnosis.grade.option`, {\n grade: g,\n defaultValue: `Grade ${g}`,\n });\n const extentLabel = (e: PeriodontitisExtent) =>\n t(`periodontalDiagnosis.extent.${e}`, {\n defaultValue:\n e === 'localised'\n ? 'Localised'\n : e === 'generalised'\n ? 'Generalised'\n : 'Molar-incisor',\n });\n const factorLabel = (fid: string) =>\n t(`periodontalDiagnosis.factor.${fid}`, { defaultValue: fid });\n\n // Worded summary sentence — the accessible source of truth.\n const chips: string[] = [];\n if (current.stage != null)\n chips.push(\n t('periodontalDiagnosis.summary.stage', {\n roman: STAGE_ROMAN[current.stage],\n defaultValue: `Stage ${STAGE_ROMAN[current.stage]}`,\n }),\n );\n if (current.grade != null)\n chips.push(\n t('periodontalDiagnosis.summary.grade', {\n grade: current.grade,\n defaultValue: `Grade ${current.grade}`,\n }),\n );\n if (current.extent != null) chips.push(extentLabel(current.extent));\n const summary = chips.length\n ? `${t('periodontalDiagnosis.term', 'Periodontitis')} — ${chips.join(' · ')}`\n : t('periodontalDiagnosis.summary.none', 'No diagnosis recorded yet');\n\n useAgentRegistration(\n periodontalDiagnosisAgent,\n {\n getDiagnosis: () => {\n const { note: _note, ...rest2 } = valueRef.current;\n return rest2;\n },\n getSummary: () => summary,\n isComplete: () => isDiagnosisComplete(valueRef.current),\n setStage,\n setGrade,\n setExtent,\n toggleFactor,\n clear,\n },\n id,\n );\n\n const heading = t('periodontalDiagnosis.heading', 'Periodontal diagnosis');\n const resolvedAriaLabel = ariaLabel ?? heading;\n\n const readonlyView = (\n <dl className=\"type-body-sm ds:grid ds:grid-cols-[auto_1fr] ds:gap-x-[var(--spacing-md)] ds:gap-y-[var(--spacing-2xs)] ds:m-0\">\n <dt className=\"ds:text-[color:var(--muted-foreground)]\">\n {t('periodontalDiagnosis.stage.label', 'Staging')}\n </dt>\n <dd className=\"ds:m-0\">\n {current.stage != null\n ? stageLabel(current.stage)\n : t('periodontalDiagnosis.unset', '—')}\n </dd>\n <dt className=\"ds:text-[color:var(--muted-foreground)]\">\n {t('periodontalDiagnosis.grade.label', 'Grading')}\n </dt>\n <dd className=\"ds:m-0\">\n {current.grade != null\n ? gradeLabel(current.grade)\n : t('periodontalDiagnosis.unset', '—')}\n </dd>\n <dt className=\"ds:text-[color:var(--muted-foreground)]\">\n {t('periodontalDiagnosis.extent.label', 'Extent')}\n </dt>\n <dd className=\"ds:m-0\">\n {current.extent != null\n ? extentLabel(current.extent)\n : t('periodontalDiagnosis.unset', '—')}\n </dd>\n <dt className=\"ds:text-[color:var(--muted-foreground)]\">\n {t('periodontalDiagnosis.factors.label', 'Contributing factors')}\n </dt>\n <dd className=\"ds:m-0\">\n {activeFactors.length\n ? activeFactors.map((fid) => factorLabel(fid)).join(', ')\n : t('periodontalDiagnosis.unset', '—')}\n </dd>\n </dl>\n );\n\n const formView = (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-lg)]\">\n <RadioGroup\n variant=\"horizontal\"\n label={t('periodontalDiagnosis.stage.label', 'Staging')}\n description={t(\n 'periodontalDiagnosis.stage.description',\n 'Severity and complexity of management.',\n )}\n value={current.stage != null ? String(current.stage) : ''}\n onValueChange={(v) => setStage(Number(v) as PeriodontitisStage)}\n disabled={disabled}\n >\n {PERIODONTITIS_STAGES.map((s) => (\n <Radio key={s} value={String(s)} label={stageLabel(s)} />\n ))}\n </RadioGroup>\n\n <RadioGroup\n variant=\"horizontal\"\n label={t('periodontalDiagnosis.grade.label', 'Grading')}\n description={t(\n 'periodontalDiagnosis.grade.description',\n 'Rate of progression.',\n )}\n value={current.grade ?? ''}\n onValueChange={(v) => setGrade(v as PeriodontitisGrade)}\n disabled={disabled}\n >\n {PERIODONTITIS_GRADES.map((g) => (\n <Radio key={g} value={g} label={gradeLabel(g)} />\n ))}\n </RadioGroup>\n\n <RadioGroup\n variant=\"horizontal\"\n label={t('periodontalDiagnosis.extent.label', 'Extent')}\n value={current.extent ?? ''}\n onValueChange={(v) => setExtent(v as PeriodontitisExtent)}\n disabled={disabled}\n >\n {PERIODONTITIS_EXTENTS.map((e) => (\n <Radio key={e} value={e} label={extentLabel(e)} />\n ))}\n </RadioGroup>\n\n <fieldset className=\"ds:m-0 ds:border-0 ds:p-0\">\n <legend className=\"type-label ds:mb-[var(--spacing-xs)] ds:p-0 ds:text-[color:var(--foreground)]\">\n {t('periodontalDiagnosis.factors.label', 'Contributing factors')}\n </legend>\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n {factors.map((fid) => (\n <Checkbox\n key={fid}\n label={factorLabel(fid)}\n checked={activeFactors.includes(fid)}\n onCheckedChange={(c) => toggleFactor(fid, c === true)}\n disabled={disabled}\n />\n ))}\n </div>\n </fieldset>\n </div>\n );\n\n const inner = (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-lg)]\">\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)]\">\n <h2\n id={headingId}\n className=\"type-title-card ds:m-0 ds:text-[color:var(--foreground)]\"\n >\n {heading}\n </h2>\n <Badge variant={complete ? 'brand' : 'neutral'} size=\"md\">\n {complete\n ? t('periodontalDiagnosis.status.complete', 'Complete')\n : t('periodontalDiagnosis.status.incomplete', 'Incomplete')}\n </Badge>\n </div>\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--foreground)]\">\n {summary}\n </p>\n {mode === 'display' ? readonlyView : formView}\n </div>\n );\n\n return (\n <div\n ref={ref}\n role=\"group\"\n aria-label={resolvedAriaLabel}\n data-component=\"periodontal-diagnosis\"\n data-component-id={id}\n id={id}\n className={rootVariants({ surface, className })}\n {...rest}\n >\n {surface === 'elevated' ? (\n <Card variant=\"elevated\">\n <Card.Body>{inner}</Card.Body>\n </Card>\n ) : (\n inner\n )}\n </div>\n );\n },\n);\n\nPeriodontalDiagnosis.displayName = 'PeriodontalDiagnosis';\n\nexport type PeriodontalDiagnosisSurface = NonNullable<\n VariantProps<typeof rootVariants>['surface']\n>;\n"],"names":["STAGE_SCHEMA","GRADE_SCHEMA","EXTENT_SCHEMA","periodontalDiagnosisAgent","handle","args","PERIODONTITIS_STAGES","PERIODONTITIS_GRADES","PERIODONTITIS_EXTENTS","STAGE_ROMAN","DEFAULT_DIAGNOSIS_FACTORS","isDiagnosisComplete","value","emptyDiagnosis","rootVariants","cva","PeriodontalDiagnosis","forwardRef","defaultValue","onChange","mode","disabled","factors","surface","ariaLabel","id","className","rest","ref","useTranslation","headingId","useId","isControlled","internal","setInternal","useState","current","valueRef","useRef","commit","next","setStage","stage","setGrade","grade","setExtent","extent","toggleFactor","factorId","on","set","clear","complete","activeFactors","stageLabel","s","gradeLabel","g","extentLabel","factorLabel","fid","chips","summary","useAgentRegistration","_note","rest2","heading","resolvedAriaLabel","readonlyView","jsxs","jsx","formView","RadioGroup","v","Radio","Checkbox","c","inner","Badge","Card"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"periodontal-diagnosis-DD3hrg9X.js","sources":["../../src/components/periodontal-diagnosis/periodontal-diagnosis.agent.ts","../../src/components/periodontal-diagnosis/periodontal-diagnosis-data.ts","../../src/components/periodontal-diagnosis/periodontal-diagnosis.tsx"],"sourcesContent":["import type { AgentAdapter } from '../../agent/types';\nimport type { PeriodontalDiagnosisHandle } from './periodontal-diagnosis';\nimport type {\n PeriodontitisExtent,\n PeriodontitisGrade,\n PeriodontitisStage,\n} from './periodontal-diagnosis-data';\n\n/* -------------------------------------------------------------------- */\n/* PeriodontalDiagnosis — agent adapter */\n/* */\n/* Agents can read the recorded stage / grade / extent / factors and the */\n/* worded summary, and can set each field. The free-text clinician note */\n/* (PHI) is never exposed — getDiagnosis() strips it. */\n/* -------------------------------------------------------------------- */\n\nconst STAGE_SCHEMA = {\n enum: [1, 2, 3, 4],\n description: 'Periodontitis stage I–IV, as the integers 1–4.',\n} as const;\nconst GRADE_SCHEMA = {\n enum: ['A', 'B', 'C'],\n description: 'Periodontitis grade A–C (rate of progression).',\n} as const;\nconst EXTENT_SCHEMA = {\n enum: ['localised', 'generalised', 'molarIncisor'],\n description:\n 'Distribution: localised (<30%), generalised (≥30%), or molar-incisor.',\n} as const;\n\nexport const periodontalDiagnosisAgent: AgentAdapter<PeriodontalDiagnosisHandle> =\n {\n id: 'periodontal-diagnosis',\n // set_value — set stage / grade / extent / a factor. Each set_* action's\n // enum argsSchema already conveys that the field is a closed choice.\n capabilities: ['set_value'],\n state: {\n diagnosis: {\n type: 'object',\n descriptionKey: 'ui.agent.periodontalDiagnosis.state.diagnosis',\n description:\n 'Recorded stage (1–4), grade (A–C), extent, and ticked contributing-factor ids. The free-text note is never included.',\n read: (handle) => handle.getDiagnosis(),\n },\n summary: {\n type: 'string',\n descriptionKey: 'ui.agent.periodontalDiagnosis.state.summary',\n description:\n 'The composed, localised diagnosis sentence (e.g. \"Periodontitis — Stage III · Grade B · generalised\").',\n read: (handle) => handle.getSummary(),\n },\n complete: {\n type: 'boolean',\n descriptionKey: 'ui.agent.periodontalDiagnosis.state.complete',\n description: 'True once both a stage and a grade are recorded.',\n read: (handle) => handle.isComplete(),\n },\n },\n actions: {\n get_diagnosis: {\n safety: 'read',\n argsType: '{}',\n argsSchema: { type: 'object', properties: {} },\n returns: 'object',\n returnsSchema: { type: 'object' },\n idempotent: true,\n descriptionKey: 'ui.agent.periodontalDiagnosis.actions.getDiagnosis',\n description:\n 'Read the recorded stage / grade / extent / factors. The note is never returned.',\n invoke: (handle) => handle.getDiagnosis(),\n },\n set_stage: {\n safety: 'write',\n argsType: '{ stage: 1 | 2 | 3 | 4 }',\n argsSchema: {\n type: 'object',\n properties: { stage: STAGE_SCHEMA },\n required: ['stage'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.periodontalDiagnosis.actions.setStage',\n description: 'Record the periodontitis stage (I–IV).',\n invoke: (handle, args: { stage: PeriodontitisStage }) => {\n handle.setStage(args.stage);\n },\n },\n set_grade: {\n safety: 'write',\n argsType: \"{ grade: 'A' | 'B' | 'C' }\",\n argsSchema: {\n type: 'object',\n properties: { grade: GRADE_SCHEMA },\n required: ['grade'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.periodontalDiagnosis.actions.setGrade',\n description: 'Record the periodontitis grade (A–C).',\n invoke: (handle, args: { grade: PeriodontitisGrade }) => {\n handle.setGrade(args.grade);\n },\n },\n set_extent: {\n safety: 'write',\n argsType: \"{ extent: 'localised' | 'generalised' | 'molarIncisor' }\",\n argsSchema: {\n type: 'object',\n properties: { extent: EXTENT_SCHEMA },\n required: ['extent'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.periodontalDiagnosis.actions.setExtent',\n description: 'Record the distribution / extent.',\n invoke: (handle, args: { extent: PeriodontitisExtent }) => {\n handle.setExtent(args.extent);\n },\n },\n toggle_factor: {\n safety: 'write',\n argsType: '{ id: string; value: boolean }',\n argsSchema: {\n type: 'object',\n properties: {\n id: { type: 'string', description: 'Contributing-factor id.' },\n value: { type: 'boolean' },\n },\n required: ['id', 'value'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.periodontalDiagnosis.actions.toggleFactor',\n description: 'Tick or clear a contributing factor.',\n invoke: (handle, args: { id: string; value: boolean }) => {\n handle.toggleFactor(args.id, args.value);\n },\n },\n clear_diagnosis: {\n safety: 'destructive',\n argsType: '{}',\n argsSchema: { type: 'object', properties: {} },\n idempotent: true,\n descriptionKey: 'ui.agent.periodontalDiagnosis.actions.clearDiagnosis',\n description: 'Reset the whole diagnosis to empty.',\n invoke: (handle) => {\n handle.clear();\n },\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'periodontal-diagnosis',\n description: 'Marks the PeriodontalDiagnosis root group.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n },\n };\n","/* -------------------------------------------------------------------- */\n/* PeriodontalDiagnosis — data model */\n/* */\n/* The 2017 World Workshop / EFP periodontitis classification: a stage */\n/* (I–IV, severity + complexity), a grade (A–C, rate of progression) and */\n/* an extent (localised / generalised / molar-incisor). The jurisdiction- */\n/* specific *algorithm* that derives stage & grade from clinical findings */\n/* stays in the consumer; this component is the reusable, controllable */\n/* form + summary. A curated checklist of contributing factors gives the */\n/* clinician context without baking one country's logic into the kit. */\n/* -------------------------------------------------------------------- */\n\nexport type PeriodontitisStage = 1 | 2 | 3 | 4;\nexport type PeriodontitisGrade = 'A' | 'B' | 'C';\nexport type PeriodontitisExtent = 'localised' | 'generalised' | 'molarIncisor';\n\nexport const PERIODONTITIS_STAGES: readonly PeriodontitisStage[] = [1, 2, 3, 4];\nexport const PERIODONTITIS_GRADES: readonly PeriodontitisGrade[] = [\n 'A',\n 'B',\n 'C',\n];\nexport const PERIODONTITIS_EXTENTS: readonly PeriodontitisExtent[] = [\n 'localised',\n 'generalised',\n 'molarIncisor',\n];\n\n/** Roman numeral for a stage — matches the WHO / EFP notation. */\nexport const STAGE_ROMAN: Record<PeriodontitisStage, string> = {\n 1: 'I',\n 2: 'II',\n 3: 'III',\n 4: 'IV',\n};\n\n/**\n * The default contributing-factor checklist — the staging (severity) and\n * grading (progression) drivers of the 2017 classification. Consumers can\n * pass their own list of ids to localise the questionnaire.\n */\nexport const DEFAULT_DIAGNOSIS_FACTORS = [\n 'interdentalCal',\n 'radiographicBoneLoss',\n 'toothLossPerio',\n 'probingDepth6',\n 'boneLossAgeOver1',\n 'smoker',\n 'diabetes',\n] as const;\n\nexport type PeriodontalDiagnosisFactor =\n (typeof DEFAULT_DIAGNOSIS_FACTORS)[number];\n\n/** The recorded diagnosis. `note` is free-text PHI and never leaves the UI. */\nexport interface PeriodontalDiagnosisValue {\n stage?: PeriodontitisStage;\n grade?: PeriodontitisGrade;\n extent?: PeriodontitisExtent;\n /** Ids of the ticked contributing factors. */\n factors?: string[];\n /** Free-text clinician note — PHI; excluded from the agent adapter. */\n note?: string;\n}\n\n/** A diagnosis needs at least a stage and a grade to read as complete. */\nexport function isDiagnosisComplete(value: PeriodontalDiagnosisValue): boolean {\n return value.stage != null && value.grade != null;\n}\n\n/** A fresh, empty diagnosis. */\nexport function emptyDiagnosis(): PeriodontalDiagnosisValue {\n return {};\n}\n","import {\n forwardRef,\n useId,\n useRef,\n useState,\n type ComponentPropsWithoutRef,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { Badge } from '../badge/badge';\nimport { Card } from '../card/card';\nimport { Checkbox } from '../checkbox/checkbox';\nimport { Radio } from '../radio-group/radio';\nimport { RadioGroup } from '../radio-group/radio-group';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { periodontalDiagnosisAgent } from './periodontal-diagnosis.agent';\nimport {\n DEFAULT_DIAGNOSIS_FACTORS,\n emptyDiagnosis,\n isDiagnosisComplete,\n PERIODONTITIS_EXTENTS,\n PERIODONTITIS_GRADES,\n PERIODONTITIS_STAGES,\n STAGE_ROMAN,\n type PeriodontalDiagnosisValue,\n type PeriodontitisExtent,\n type PeriodontitisGrade,\n type PeriodontitisStage,\n} from './periodontal-diagnosis-data';\n\n/* -------------------------------------------------------------------- */\n/* PeriodontalDiagnosis */\n/* */\n/* The 2017 World Workshop / EFP periodontitis classification form: */\n/* stage (I–IV), grade (A–C), extent, and a curated checklist of the */\n/* staging/grading contributing factors. Controlled or uncontrolled. */\n/* The composed summary (\"Periodontitis — Stage III · Grade B · */\n/* generalised\") is the worded, non-colour source of truth. */\n/* -------------------------------------------------------------------- */\n\nconst rootVariants = cva('ds:w-full ds:text-[color:var(--foreground)]', {\n variants: {\n surface: { flat: '', elevated: '' },\n },\n defaultVariants: { surface: 'elevated' },\n});\n\n/* -------------------------------------------------------------------- */\n/* Types */\n/* -------------------------------------------------------------------- */\n\nexport interface PeriodontalDiagnosisHandle {\n /** The recorded stage / grade / extent / factors — never the free-text note. */\n getDiagnosis: () => Omit<PeriodontalDiagnosisValue, 'note'>;\n /** The composed, localised summary sentence. */\n getSummary: () => string;\n /** True once both a stage and a grade are recorded. */\n isComplete: () => boolean;\n setStage: (stage: PeriodontitisStage) => void;\n setGrade: (grade: PeriodontitisGrade) => void;\n setExtent: (extent: PeriodontitisExtent) => void;\n toggleFactor: (id: string, on?: boolean) => void;\n /** Reset to an empty diagnosis. */\n clear: () => void;\n}\n\nexport interface PeriodontalDiagnosisProps extends Omit<\n ComponentPropsWithoutRef<'div'>,\n 'aria-label' | 'children' | 'onChange' | 'defaultValue'\n> {\n /** Controlled value. */\n value?: PeriodontalDiagnosisValue;\n /** Uncontrolled initial value. */\n defaultValue?: PeriodontalDiagnosisValue;\n /** Fires with the next diagnosis whenever the clinician changes a field. */\n onChange?: (value: PeriodontalDiagnosisValue) => void;\n /** `'interactive'` (default) renders the form; `'display'` is read-only. */\n mode?: 'interactive' | 'display';\n /** Disable every control. */\n disabled?: boolean;\n /** Contributing-factor ids for the checklist. Defaults to the WHO-2017 set. */\n factors?: readonly string[];\n /** `'elevated'` (default) wraps in a Card; `'flat'` drops the chrome. */\n surface?: 'flat' | 'elevated';\n /** Override the default region aria-label. */\n 'aria-label'?: string;\n /** Agent-readiness consumer id, surfaced as `data-component-id`. */\n id?: string;\n}\n\n/* -------------------------------------------------------------------- */\n/* Component */\n/* -------------------------------------------------------------------- */\n\nexport const PeriodontalDiagnosis = forwardRef<\n HTMLDivElement,\n PeriodontalDiagnosisProps\n>(\n (\n {\n value,\n defaultValue,\n onChange,\n mode = 'interactive',\n disabled = false,\n factors = DEFAULT_DIAGNOSIS_FACTORS,\n surface = 'elevated',\n 'aria-label': ariaLabel,\n id,\n className,\n ...rest\n },\n ref,\n ) => {\n const { t } = useTranslation('ui');\n const headingId = useId();\n\n const isControlled = value !== undefined;\n const [internal, setInternal] = useState<PeriodontalDiagnosisValue>(\n defaultValue ?? emptyDiagnosis(),\n );\n const current = isControlled ? value : internal;\n\n // Latest committed value — so an agent making several edits in one tick\n // always builds on the previous edit, not a stale render snapshot.\n const valueRef = useRef(current);\n valueRef.current = current;\n\n const commit = (next: PeriodontalDiagnosisValue) => {\n valueRef.current = next;\n if (!isControlled) setInternal(next);\n onChange?.(next);\n };\n\n const setStage = (stage: PeriodontitisStage) =>\n commit({ ...valueRef.current, stage });\n const setGrade = (grade: PeriodontitisGrade) =>\n commit({ ...valueRef.current, grade });\n const setExtent = (extent: PeriodontitisExtent) =>\n commit({ ...valueRef.current, extent });\n const toggleFactor = (factorId: string, on?: boolean) => {\n const set = new Set(valueRef.current.factors ?? []);\n const next = on ?? !set.has(factorId);\n if (next) set.add(factorId);\n else set.delete(factorId);\n commit({ ...valueRef.current, factors: [...set] });\n };\n const clear = () => commit(emptyDiagnosis());\n\n const complete = isDiagnosisComplete(current);\n const activeFactors = current.factors ?? [];\n\n const stageLabel = (s: PeriodontitisStage) =>\n t(`periodontalDiagnosis.stage.option`, {\n roman: STAGE_ROMAN[s],\n defaultValue: `Stage ${STAGE_ROMAN[s]}`,\n });\n const gradeLabel = (g: PeriodontitisGrade) =>\n t(`periodontalDiagnosis.grade.option`, {\n grade: g,\n defaultValue: `Grade ${g}`,\n });\n const extentLabel = (e: PeriodontitisExtent) =>\n t(`periodontalDiagnosis.extent.${e}`, {\n defaultValue:\n e === 'localised'\n ? 'Localised'\n : e === 'generalised'\n ? 'Generalised'\n : 'Molar-incisor',\n });\n const factorLabel = (fid: string) =>\n t(`periodontalDiagnosis.factor.${fid}`, { defaultValue: fid });\n\n // Worded summary sentence — the accessible source of truth.\n const chips: string[] = [];\n if (current.stage != null)\n chips.push(\n t('periodontalDiagnosis.summary.stage', {\n roman: STAGE_ROMAN[current.stage],\n defaultValue: `Stage ${STAGE_ROMAN[current.stage]}`,\n }),\n );\n if (current.grade != null)\n chips.push(\n t('periodontalDiagnosis.summary.grade', {\n grade: current.grade,\n defaultValue: `Grade ${current.grade}`,\n }),\n );\n if (current.extent != null) chips.push(extentLabel(current.extent));\n const summary = chips.length\n ? `${t('periodontalDiagnosis.term', 'Periodontitis')} — ${chips.join(' · ')}`\n : t('periodontalDiagnosis.summary.none', 'No diagnosis recorded yet');\n\n useAgentRegistration(\n periodontalDiagnosisAgent,\n {\n getDiagnosis: () => {\n const { note: _note, ...rest2 } = valueRef.current;\n return rest2;\n },\n getSummary: () => summary,\n isComplete: () => isDiagnosisComplete(valueRef.current),\n setStage,\n setGrade,\n setExtent,\n toggleFactor,\n clear,\n },\n id,\n );\n\n const heading = t('periodontalDiagnosis.heading', 'Periodontal diagnosis');\n const resolvedAriaLabel = ariaLabel ?? heading;\n\n const readonlyView = (\n <dl className=\"type-body-sm ds:grid ds:grid-cols-[auto_1fr] ds:gap-x-[var(--spacing-md)] ds:gap-y-[var(--spacing-2xs)] ds:m-0\">\n <dt className=\"ds:text-[color:var(--muted-foreground)]\">\n {t('periodontalDiagnosis.stage.label', 'Staging')}\n </dt>\n <dd className=\"ds:m-0\">\n {current.stage != null\n ? stageLabel(current.stage)\n : t('periodontalDiagnosis.unset', '—')}\n </dd>\n <dt className=\"ds:text-[color:var(--muted-foreground)]\">\n {t('periodontalDiagnosis.grade.label', 'Grading')}\n </dt>\n <dd className=\"ds:m-0\">\n {current.grade != null\n ? gradeLabel(current.grade)\n : t('periodontalDiagnosis.unset', '—')}\n </dd>\n <dt className=\"ds:text-[color:var(--muted-foreground)]\">\n {t('periodontalDiagnosis.extent.label', 'Extent')}\n </dt>\n <dd className=\"ds:m-0\">\n {current.extent != null\n ? extentLabel(current.extent)\n : t('periodontalDiagnosis.unset', '—')}\n </dd>\n <dt className=\"ds:text-[color:var(--muted-foreground)]\">\n {t('periodontalDiagnosis.factors.label', 'Contributing factors')}\n </dt>\n <dd className=\"ds:m-0\">\n {activeFactors.length\n ? activeFactors.map((fid) => factorLabel(fid)).join(', ')\n : t('periodontalDiagnosis.unset', '—')}\n </dd>\n </dl>\n );\n\n const formView = (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-lg)]\">\n <RadioGroup\n variant=\"horizontal\"\n label={t('periodontalDiagnosis.stage.label', 'Staging')}\n description={t(\n 'periodontalDiagnosis.stage.description',\n 'Severity and complexity of management.',\n )}\n value={current.stage != null ? String(current.stage) : ''}\n onValueChange={(v) => setStage(Number(v) as PeriodontitisStage)}\n disabled={disabled}\n >\n {PERIODONTITIS_STAGES.map((s) => (\n <Radio key={s} value={String(s)} label={stageLabel(s)} />\n ))}\n </RadioGroup>\n\n <RadioGroup\n variant=\"horizontal\"\n label={t('periodontalDiagnosis.grade.label', 'Grading')}\n description={t(\n 'periodontalDiagnosis.grade.description',\n 'Rate of progression.',\n )}\n value={current.grade ?? ''}\n onValueChange={(v) => setGrade(v as PeriodontitisGrade)}\n disabled={disabled}\n >\n {PERIODONTITIS_GRADES.map((g) => (\n <Radio key={g} value={g} label={gradeLabel(g)} />\n ))}\n </RadioGroup>\n\n <RadioGroup\n variant=\"horizontal\"\n label={t('periodontalDiagnosis.extent.label', 'Extent')}\n value={current.extent ?? ''}\n onValueChange={(v) => setExtent(v as PeriodontitisExtent)}\n disabled={disabled}\n >\n {PERIODONTITIS_EXTENTS.map((e) => (\n <Radio key={e} value={e} label={extentLabel(e)} />\n ))}\n </RadioGroup>\n\n <fieldset className=\"ds:m-0 ds:border-0 ds:p-0\">\n <legend className=\"type-label ds:mb-[var(--spacing-xs)] ds:p-0 ds:text-[color:var(--foreground)]\">\n {t('periodontalDiagnosis.factors.label', 'Contributing factors')}\n </legend>\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n {factors.map((fid) => (\n <Checkbox\n key={fid}\n label={factorLabel(fid)}\n checked={activeFactors.includes(fid)}\n onCheckedChange={(c) => toggleFactor(fid, c === true)}\n disabled={disabled}\n />\n ))}\n </div>\n </fieldset>\n </div>\n );\n\n const inner = (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-lg)]\">\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)]\">\n <h2\n id={headingId}\n className=\"type-title-card ds:m-0 ds:text-[color:var(--foreground)]\"\n >\n {heading}\n </h2>\n <Badge variant={complete ? 'brand' : 'neutral'} size=\"md\">\n {complete\n ? t('periodontalDiagnosis.status.complete', 'Complete')\n : t('periodontalDiagnosis.status.incomplete', 'Incomplete')}\n </Badge>\n </div>\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--foreground)]\">\n {summary}\n </p>\n {mode === 'display' ? readonlyView : formView}\n </div>\n );\n\n return (\n <div\n ref={ref}\n role=\"group\"\n aria-label={resolvedAriaLabel}\n data-component=\"periodontal-diagnosis\"\n data-component-id={id}\n id={id}\n className={rootVariants({ surface, className })}\n {...rest}\n >\n {surface === 'elevated' ? (\n <Card variant=\"elevated\">\n <Card.Body>{inner}</Card.Body>\n </Card>\n ) : (\n inner\n )}\n </div>\n );\n },\n);\n\nPeriodontalDiagnosis.displayName = 'PeriodontalDiagnosis';\n\nexport type PeriodontalDiagnosisSurface = NonNullable<\n VariantProps<typeof rootVariants>['surface']\n>;\n"],"names":["STAGE_SCHEMA","GRADE_SCHEMA","EXTENT_SCHEMA","periodontalDiagnosisAgent","handle","args","PERIODONTITIS_STAGES","PERIODONTITIS_GRADES","PERIODONTITIS_EXTENTS","STAGE_ROMAN","DEFAULT_DIAGNOSIS_FACTORS","isDiagnosisComplete","value","emptyDiagnosis","rootVariants","cva","PeriodontalDiagnosis","forwardRef","defaultValue","onChange","mode","disabled","factors","surface","ariaLabel","id","className","rest","ref","useTranslation","headingId","useId","isControlled","internal","setInternal","useState","current","valueRef","useRef","commit","next","setStage","stage","setGrade","grade","setExtent","extent","toggleFactor","factorId","on","set","clear","complete","activeFactors","stageLabel","s","gradeLabel","g","extentLabel","factorLabel","fid","chips","summary","useAgentRegistration","_note","rest2","heading","resolvedAriaLabel","readonlyView","jsxs","jsx","formView","RadioGroup","v","Radio","Checkbox","c","inner","Badge","Card"],"mappings":";;;;;;;;;;AAgBA,MAAMA,KAAe;AAAA,EACnB,MAAM,CAAC,GAAG,GAAG,GAAG,CAAC;AAAA,EACjB,aAAa;AACf,GACMC,KAAe;AAAA,EACnB,MAAM,CAAC,KAAK,KAAK,GAAG;AAAA,EACpB,aAAa;AACf,GACMC,KAAgB;AAAA,EACpB,MAAM,CAAC,aAAa,eAAe,cAAc;AAAA,EACjD,aACE;AACJ,GAEaC,KACX;AAAA,EACE,IAAI;AAAA;AAAA;AAAA,EAGJ,cAAc,CAAC,WAAW;AAAA,EAC1B,OAAO;AAAA,IACL,WAAW;AAAA,MACT,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,aACE;AAAA,MACF,MAAM,CAACC,MAAWA,EAAO,aAAA;AAAA,IAAa;AAAA,IAExC,SAAS;AAAA,MACP,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,aACE;AAAA,MACF,MAAM,CAACA,MAAWA,EAAO,WAAA;AAAA,IAAW;AAAA,IAEtC,UAAU;AAAA,MACR,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,aAAa;AAAA,MACb,MAAM,CAACA,MAAWA,EAAO,WAAA;AAAA,IAAW;AAAA,EACtC;AAAA,EAEF,SAAS;AAAA,IACP,eAAe;AAAA,MACb,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,YAAY,EAAE,MAAM,UAAU,YAAY,CAAA,EAAC;AAAA,MAC3C,SAAS;AAAA,MACT,eAAe,EAAE,MAAM,SAAA;AAAA,MACvB,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,aACE;AAAA,MACF,QAAQ,CAACA,MAAWA,EAAO,aAAA;AAAA,IAAa;AAAA,IAE1C,WAAW;AAAA,MACT,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,YAAY;AAAA,QACV,MAAM;AAAA,QACN,YAAY,EAAE,OAAOJ,GAAA;AAAA,QACrB,UAAU,CAAC,OAAO;AAAA,MAAA;AAAA,MAEpB,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,aAAa;AAAA,MACb,QAAQ,CAACI,GAAQC,MAAwC;AACvD,QAAAD,EAAO,SAASC,EAAK,KAAK;AAAA,MAC5B;AAAA,IAAA;AAAA,IAEF,WAAW;AAAA,MACT,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,YAAY;AAAA,QACV,MAAM;AAAA,QACN,YAAY,EAAE,OAAOJ,GAAA;AAAA,QACrB,UAAU,CAAC,OAAO;AAAA,MAAA;AAAA,MAEpB,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,aAAa;AAAA,MACb,QAAQ,CAACG,GAAQC,MAAwC;AACvD,QAAAD,EAAO,SAASC,EAAK,KAAK;AAAA,MAC5B;AAAA,IAAA;AAAA,IAEF,YAAY;AAAA,MACV,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,YAAY;AAAA,QACV,MAAM;AAAA,QACN,YAAY,EAAE,QAAQH,GAAA;AAAA,QACtB,UAAU,CAAC,QAAQ;AAAA,MAAA;AAAA,MAErB,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,aAAa;AAAA,MACb,QAAQ,CAACE,GAAQC,MAA0C;AACzD,QAAAD,EAAO,UAAUC,EAAK,MAAM;AAAA,MAC9B;AAAA,IAAA;AAAA,IAEF,eAAe;AAAA,MACb,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,YAAY;AAAA,QACV,MAAM;AAAA,QACN,YAAY;AAAA,UACV,IAAI,EAAE,MAAM,UAAU,aAAa,0BAAA;AAAA,UACnC,OAAO,EAAE,MAAM,UAAA;AAAA,QAAU;AAAA,QAE3B,UAAU,CAAC,MAAM,OAAO;AAAA,MAAA;AAAA,MAE1B,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,aAAa;AAAA,MACb,QAAQ,CAACD,GAAQC,MAAyC;AACxD,QAAAD,EAAO,aAAaC,EAAK,IAAIA,EAAK,KAAK;AAAA,MACzC;AAAA,IAAA;AAAA,IAEF,iBAAiB;AAAA,MACf,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,YAAY,EAAE,MAAM,UAAU,YAAY,CAAA,EAAC;AAAA,MAC3C,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,aAAa;AAAA,MACb,QAAQ,CAACD,MAAW;AAClB,QAAAA,EAAO,MAAA;AAAA,MACT;AAAA,IAAA;AAAA,EACF;AAAA,EAEF,UAAU;AAAA,IACR,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aAAa;AAAA,IAAA;AAAA,IAEf,YAAY;AAAA,MACV,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,aAAa;AAAA,IAAA;AAAA,EACf;AAEJ,GC9IWE,KAAsD,CAAC,GAAG,GAAG,GAAG,CAAC,GACjEC,KAAsD;AAAA,EACjE;AAAA,EACA;AAAA,EACA;AACF,GACaC,KAAwD;AAAA,EACnE;AAAA,EACA;AAAA,EACA;AACF,GAGaC,IAAkD;AAAA,EAC7D,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AACL,GAOaC,KAA4B;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAiBO,SAASC,EAAoBC,GAA2C;AAC7E,SAAOA,EAAM,SAAS,QAAQA,EAAM,SAAS;AAC/C;AAGO,SAASC,IAA4C;AAC1D,SAAO,CAAA;AACT;ACjCA,MAAMC,KAAeC,EAAI,+CAA+C;AAAA,EACtE,UAAU;AAAA,IACR,SAAS,EAAE,MAAM,IAAI,UAAU,GAAA;AAAA,EAAG;AAAA,EAEpC,iBAAiB,EAAE,SAAS,WAAA;AAC9B,CAAC,GAiDYC,KAAuBC;AAAA,EAIlC,CACE;AAAA,IACE,OAAAL;AAAA,IACA,cAAAM;AAAA,IACA,UAAAC;AAAA,IACA,MAAAC,IAAO;AAAA,IACP,UAAAC,IAAW;AAAA,IACX,SAAAC,IAAUZ;AAAA,IACV,SAAAa,IAAU;AAAA,IACV,cAAcC;AAAA,IACd,IAAAC;AAAA,IACA,WAAAC;AAAA,IACA,GAAGC;AAAA,EAAA,GAELC,MACG;AACH,UAAM,EAAE,EAAA,IAAMC,GAAe,IAAI,GAC3BC,IAAYC,EAAA,GAEZC,IAAepB,MAAU,QACzB,CAACqB,GAAUC,CAAW,IAAIC;AAAA,MAC9BjB,KAAgBL,EAAA;AAAA,IAAe,GAE3BuB,IAAUJ,IAAepB,IAAQqB,GAIjCI,IAAWC,EAAOF,CAAO;AAC/B,IAAAC,EAAS,UAAUD;AAEnB,UAAMG,IAAS,CAACC,MAAoC;AAClD,MAAAH,EAAS,UAAUG,GACdR,KAAcE,EAAYM,CAAI,GACnCrB,KAAA,QAAAA,EAAWqB;AAAA,IACb,GAEMC,IAAW,CAACC,MAChBH,EAAO,EAAE,GAAGF,EAAS,SAAS,OAAAK,GAAO,GACjCC,IAAW,CAACC,MAChBL,EAAO,EAAE,GAAGF,EAAS,SAAS,OAAAO,GAAO,GACjCC,IAAY,CAACC,MACjBP,EAAO,EAAE,GAAGF,EAAS,SAAS,QAAAS,GAAQ,GAClCC,IAAe,CAACC,GAAkBC,MAAiB;AACvD,YAAMC,IAAM,IAAI,IAAIb,EAAS,QAAQ,WAAW,EAAE;AAElD,MADaY,KAAM,CAACC,EAAI,IAAIF,CAAQ,IAC1BE,EAAI,IAAIF,CAAQ,IACrBE,EAAI,OAAOF,CAAQ,GACxBT,EAAO,EAAE,GAAGF,EAAS,SAAS,SAAS,CAAC,GAAGa,CAAG,GAAG;AAAA,IACnD,GACMC,IAAQ,MAAMZ,EAAO1B,GAAgB,GAErCuC,IAAWzC,EAAoByB,CAAO,GACtCiB,IAAgBjB,EAAQ,WAAW,CAAA,GAEnCkB,IAAa,CAACC,MAClB,EAAE,qCAAqC;AAAA,MACrC,OAAO9C,EAAY8C,CAAC;AAAA,MACpB,cAAc,SAAS9C,EAAY8C,CAAC,CAAC;AAAA,IAAA,CACtC,GACGC,IAAa,CAACC,MAClB,EAAE,qCAAqC;AAAA,MACrC,OAAOA;AAAA,MACP,cAAc,SAASA,CAAC;AAAA,IAAA,CACzB,GACGC,IAAc,CAAC,MACnB,EAAE,+BAA+B,CAAC,IAAI;AAAA,MACpC,cACE,MAAM,cACF,cACA,MAAM,gBACJ,gBACA;AAAA,IAAA,CACT,GACGC,IAAc,CAACC,MACnB,EAAE,+BAA+BA,CAAG,IAAI,EAAE,cAAcA,GAAK,GAGzDC,IAAkB,CAAA;AACxB,IAAIzB,EAAQ,SAAS,QACnByB,EAAM;AAAA,MACJ,EAAE,sCAAsC;AAAA,QACtC,OAAOpD,EAAY2B,EAAQ,KAAK;AAAA,QAChC,cAAc,SAAS3B,EAAY2B,EAAQ,KAAK,CAAC;AAAA,MAAA,CAClD;AAAA,IAAA,GAEDA,EAAQ,SAAS,QACnByB,EAAM;AAAA,MACJ,EAAE,sCAAsC;AAAA,QACtC,OAAOzB,EAAQ;AAAA,QACf,cAAc,SAASA,EAAQ,KAAK;AAAA,MAAA,CACrC;AAAA,IAAA,GAEDA,EAAQ,UAAU,QAAMyB,EAAM,KAAKH,EAAYtB,EAAQ,MAAM,CAAC;AAClE,UAAM0B,IAAUD,EAAM,SAClB,GAAG,EAAE,6BAA6B,eAAe,CAAC,MAAMA,EAAM,KAAK,KAAK,CAAC,KACzE,EAAE,qCAAqC,2BAA2B;AAEtE,IAAAE;AAAA,MACE5D;AAAA,MACA;AAAA,QACE,cAAc,MAAM;AAClB,gBAAM,EAAE,MAAM6D,GAAO,GAAGC,EAAA,IAAU5B,EAAS;AAC3C,iBAAO4B;AAAA,QACT;AAAA,QACA,YAAY,MAAMH;AAAA,QAClB,YAAY,MAAMnD,EAAoB0B,EAAS,OAAO;AAAA,QACtD,UAAAI;AAAA,QACA,UAAAE;AAAA,QACA,WAAAE;AAAA,QACA,cAAAE;AAAA,QACA,OAAAI;AAAA,MAAA;AAAA,MAEF1B;AAAA,IAAA;AAGF,UAAMyC,IAAU,EAAE,gCAAgC,uBAAuB,GACnEC,IAAoB3C,KAAa0C,GAEjCE,IACJ,gBAAAC,EAAC,MAAA,EAAG,WAAU,kHACZ,UAAA;AAAA,MAAA,gBAAAC,EAAC,QAAG,WAAU,2CACX,UAAA,EAAE,oCAAoC,SAAS,GAClD;AAAA,MACA,gBAAAA,EAAC,MAAA,EAAG,WAAU,UACX,YAAQ,SAAS,OACdhB,EAAWlB,EAAQ,KAAK,IACxB,EAAE,8BAA8B,GAAG,GACzC;AAAA,wBACC,MAAA,EAAG,WAAU,2CACX,UAAA,EAAE,oCAAoC,SAAS,GAClD;AAAA,MACA,gBAAAkC,EAAC,MAAA,EAAG,WAAU,UACX,YAAQ,SAAS,OACdd,EAAWpB,EAAQ,KAAK,IACxB,EAAE,8BAA8B,GAAG,GACzC;AAAA,wBACC,MAAA,EAAG,WAAU,2CACX,UAAA,EAAE,qCAAqC,QAAQ,GAClD;AAAA,MACA,gBAAAkC,EAAC,MAAA,EAAG,WAAU,UACX,YAAQ,UAAU,OACfZ,EAAYtB,EAAQ,MAAM,IAC1B,EAAE,8BAA8B,GAAG,GACzC;AAAA,wBACC,MAAA,EAAG,WAAU,2CACX,UAAA,EAAE,sCAAsC,sBAAsB,GACjE;AAAA,MACA,gBAAAkC,EAAC,QAAG,WAAU,UACX,YAAc,SACXjB,EAAc,IAAI,CAACO,MAAQD,EAAYC,CAAG,CAAC,EAAE,KAAK,IAAI,IACtD,EAAE,8BAA8B,GAAG,EAAA,CACzC;AAAA,IAAA,GACF,GAGIW,IACJ,gBAAAF,EAAC,OAAA,EAAI,WAAU,kDACb,UAAA;AAAA,MAAA,gBAAAC;AAAA,QAACE;AAAA,QAAA;AAAA,UACC,SAAQ;AAAA,UACR,OAAO,EAAE,oCAAoC,SAAS;AAAA,UACtD,aAAa;AAAA,YACX;AAAA,YACA;AAAA,UAAA;AAAA,UAEF,OAAOpC,EAAQ,SAAS,OAAO,OAAOA,EAAQ,KAAK,IAAI;AAAA,UACvD,eAAe,CAACqC,MAAMhC,EAAS,OAAOgC,CAAC,CAAuB;AAAA,UAC9D,UAAApD;AAAA,UAEC,UAAAf,GAAqB,IAAI,CAACiD,wBACxBmB,GAAA,EAAc,OAAO,OAAOnB,CAAC,GAAG,OAAOD,EAAWC,CAAC,EAAA,GAAxCA,CAA2C,CACxD;AAAA,QAAA;AAAA,MAAA;AAAA,MAGH,gBAAAe;AAAA,QAACE;AAAA,QAAA;AAAA,UACC,SAAQ;AAAA,UACR,OAAO,EAAE,oCAAoC,SAAS;AAAA,UACtD,aAAa;AAAA,YACX;AAAA,YACA;AAAA,UAAA;AAAA,UAEF,OAAOpC,EAAQ,SAAS;AAAA,UACxB,eAAe,CAACqC,MAAM9B,EAAS8B,CAAuB;AAAA,UACtD,UAAApD;AAAA,UAEC,UAAAd,GAAqB,IAAI,CAACkD,MACzB,gBAAAa,EAACI,GAAA,EAAc,OAAOjB,GAAG,OAAOD,EAAWC,CAAC,EAAA,GAAhCA,CAAmC,CAChD;AAAA,QAAA;AAAA,MAAA;AAAA,MAGH,gBAAAa;AAAA,QAACE;AAAA,QAAA;AAAA,UACC,SAAQ;AAAA,UACR,OAAO,EAAE,qCAAqC,QAAQ;AAAA,UACtD,OAAOpC,EAAQ,UAAU;AAAA,UACzB,eAAe,CAACqC,MAAM5B,EAAU4B,CAAwB;AAAA,UACxD,UAAApD;AAAA,UAEC,UAAAb,GAAsB,IAAI,CAAC,MAC1B,gBAAA8D,EAACI,GAAA,EAAc,OAAO,GAAG,OAAOhB,EAAY,CAAC,EAAA,GAAjC,CAAoC,CACjD;AAAA,QAAA;AAAA,MAAA;AAAA,MAGH,gBAAAW,EAAC,YAAA,EAAS,WAAU,6BAClB,UAAA;AAAA,QAAA,gBAAAC,EAAC,YAAO,WAAU,iFACf,UAAA,EAAE,sCAAsC,sBAAsB,GACjE;AAAA,0BACC,OAAA,EAAI,WAAU,kDACZ,UAAAhD,EAAQ,IAAI,CAACsC,MACZ,gBAAAU;AAAA,UAACK;AAAA,UAAA;AAAA,YAEC,OAAOhB,EAAYC,CAAG;AAAA,YACtB,SAASP,EAAc,SAASO,CAAG;AAAA,YACnC,iBAAiB,CAACgB,MAAM7B,EAAaa,GAAKgB,MAAM,EAAI;AAAA,YACpD,UAAAvD;AAAA,UAAA;AAAA,UAJKuC;AAAA,QAAA,CAMR,EAAA,CACH;AAAA,MAAA,EAAA,CACF;AAAA,IAAA,GACF,GAGIiB,IACJ,gBAAAR,EAAC,OAAA,EAAI,WAAU,kDACb,UAAA;AAAA,MAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,sFACb,UAAA;AAAA,QAAA,gBAAAC;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,IAAIxC;AAAA,YACJ,WAAU;AAAA,YAET,UAAAoC;AAAA,UAAA;AAAA,QAAA;AAAA,0BAEFY,IAAA,EAAM,SAAS1B,IAAW,UAAU,WAAW,MAAK,MAClD,UAAAA,IACG,EAAE,wCAAwC,UAAU,IACpD,EAAE,0CAA0C,YAAY,EAAA,CAC9D;AAAA,MAAA,GACF;AAAA,MACA,gBAAAkB,EAAC,KAAA,EAAE,WAAU,yDACV,UAAAR,GACH;AAAA,MACC1C,MAAS,YAAYgD,IAAeG;AAAA,IAAA,GACvC;AAGF,WACE,gBAAAD;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAA1C;AAAA,QACA,MAAK;AAAA,QACL,cAAYuC;AAAA,QACZ,kBAAe;AAAA,QACf,qBAAmB1C;AAAA,QACnB,IAAAA;AAAA,QACA,WAAWX,GAAa,EAAE,SAAAS,GAAS,WAAAG,GAAW;AAAA,QAC7C,GAAGC;AAAA,QAEH,UAAAJ,MAAY,aACX,gBAAA+C,EAACS,GAAA,EAAK,SAAQ,YACZ,UAAA,gBAAAT,EAACS,EAAK,MAAL,EAAW,UAAAF,EAAA,CAAM,EAAA,CACpB,IAEAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEA7D,GAAqB,cAAc;"}
|
|
@@ -2,8 +2,8 @@ import { jsx as a, jsxs as K } from "react/jsx-runtime";
|
|
|
2
2
|
import { forwardRef as U, useMemo as h, useRef as d } from "react";
|
|
3
3
|
import { c as V } from "./index-D2ZczOXr.js";
|
|
4
4
|
import { useTranslation as A } from "react-i18next";
|
|
5
|
-
import { C as H } from "./checkbox-group-
|
|
6
|
-
import { C as T } from "./checkbox-
|
|
5
|
+
import { C as H } from "./checkbox-group-eGdv9fZc.js";
|
|
6
|
+
import { C as T } from "./checkbox-a7Sh-dXb.js";
|
|
7
7
|
import { u as _ } from "./registry-DvAUVLHh.js";
|
|
8
8
|
import { L as q } from "./lock-ClAFG1gy.js";
|
|
9
9
|
const z = {
|
|
@@ -171,4 +171,4 @@ export {
|
|
|
171
171
|
I as a,
|
|
172
172
|
z as p
|
|
173
173
|
};
|
|
174
|
-
//# sourceMappingURL=permission-matrix-
|
|
174
|
+
//# sourceMappingURL=permission-matrix-BJ6sg3Zp.js.map
|
package/dist/_chunks/{permission-matrix-BoQjENGV.js.map → permission-matrix-BJ6sg3Zp.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permission-matrix-BoQjENGV.js","sources":["../../src/components/permission-matrix/permission-matrix.agent.ts","../../src/components/permission-matrix/permission-matrix.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — PermissionMatrix. */\n/* */\n/* See `src/docs/26-agent-readiness.mdx` for the contract. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { PermissionMatrixHandle } from './permission-matrix';\n\nexport const permissionMatrixAgent: AgentAdapter<PermissionMatrixHandle> = {\n id: 'permission-matrix',\n capabilities: ['select_multiple'],\n state: {\n selection: {\n type: 'string[]',\n descriptionKey: 'ui.agent.permissionMatrix.state.selection',\n description:\n 'Ids of currently-granted editable permissions. Locked owner permissions are excluded.',\n read: (handle) => handle.getSelection(),\n },\n },\n actions: {\n set_selection: {\n safety: 'write',\n argsType: '{ values: string[] }',\n argsSchema: {\n type: 'object',\n properties: { values: { type: 'array', items: { type: 'string' } } },\n required: ['values'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.permissionMatrix.actions.setSelection',\n description:\n 'Replace the granted permissions with the given ids. Locked and unknown ids are ignored.',\n examples: [\n {\n args: { values: ['patients.view', 'billing.view'] },\n note: 'Grant exactly the view permissions for patients and billing.',\n },\n ],\n invoke: (handle, args: { values: string[] }) => {\n handle.setSelection(args.values);\n },\n },\n clear: {\n safety: 'destructive',\n idempotent: true,\n descriptionKey: 'ui.agent.permissionMatrix.actions.clear',\n description:\n 'Revoke every editable permission. Locked owner permissions are unaffected.',\n invoke: (handle) => {\n handle.clear();\n },\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'permission-matrix',\n description: 'Marks the PermissionMatrix root group.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n },\n};\n","import { forwardRef, useMemo, useRef, type ReactNode } from 'react';\nimport { cva } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { Lock } from 'lucide-react';\nimport { CheckboxGroup } from '../checkbox-group/checkbox-group';\nimport { Checkbox } from '../checkbox/checkbox';\nimport { useAgentRegistration } from '../../agent';\nimport { permissionMatrixAgent } from './permission-matrix.agent';\n\n/** A single togglable permission within a group. Labels are pre-localised. */\nexport interface PermissionMatrixPermission {\n id: string;\n label: string;\n}\n\n/** One category of permissions, rendered as a labelled group. */\nexport interface PermissionMatrixGroup {\n id: string;\n label: string;\n permissions: PermissionMatrixPermission[];\n}\n\n/** Agent-readiness curated handle for PermissionMatrix. */\nexport interface PermissionMatrixHandle {\n /** Ids of currently-granted editable permissions (locked items excluded). */\n getSelection: () => string[];\n /** Replace the granted set. Locked and unknown ids are ignored. */\n setSelection: (values: string[]) => void;\n /** Revoke every editable permission. Locked items are untouched. */\n clear: () => void;\n}\n\nexport interface PermissionMatrixProps {\n /** Categories of permissions. All labels are already localised by the consumer. */\n groups: PermissionMatrixGroup[];\n /** Ids of granted permissions (controlled). Locked ids belong in `lockedItems`, not here. */\n value: string[];\n /** Fires with the next full granted-id array whenever an editable toggle changes. */\n onChange: (next: string[]) => void;\n /**\n * Permission ids that render checked + disabled with a lock affordance — the\n * owner always holds them. They never appear in `onChange` payloads.\n */\n lockedItems?: string[];\n /** Disable every toggle in the matrix. */\n disabled?: boolean;\n /** Accessible suffix announced on locked rows. Defaults to the kit's \"Locked\" string. */\n lockedLabel?: string;\n /** Stable id — addresses this instance from the agent runtime. */\n id?: string;\n className?: string;\n 'aria-label'?: string;\n}\n\nconst permissionMatrixVariants = cva(\n 'ds:flex ds:flex-col ds:gap-[var(--spacing-lg)] ds:min-w-0',\n {\n variants: {\n disabled: {\n true: 'ds:cursor-not-allowed',\n false: '',\n },\n },\n defaultVariants: { disabled: false },\n },\n);\n\nconst lockedLabelClasses =\n 'ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)]';\n\nexport const PermissionMatrix = forwardRef<\n HTMLDivElement,\n PermissionMatrixProps\n>(function PermissionMatrix(\n {\n groups,\n value,\n onChange,\n lockedItems,\n disabled = false,\n lockedLabel,\n id,\n className,\n 'aria-label': ariaLabel,\n },\n ref,\n) {\n const { t } = useTranslation('ui');\n\n const lockedSet = useMemo(() => new Set(lockedItems ?? []), [lockedItems]);\n const allPermIds = useMemo(\n () => groups.flatMap((group) => group.permissions.map((p) => p.id)),\n [groups],\n );\n\n const resolvedLockedLabel =\n lockedLabel ?? t('inputs.permissionMatrix.locked', 'Locked');\n\n // Stable agent handle — reads/writes the latest controlled value via refs\n // so the handle identity never changes (mirrors CheckboxGroup).\n const valueRef = useRef<string[]>(value);\n valueRef.current = value;\n const lockedRef = useRef<Set<string>>(lockedSet);\n lockedRef.current = lockedSet;\n const allPermIdsRef = useRef<string[]>(allPermIds);\n allPermIdsRef.current = allPermIds;\n const onChangeRef = useRef<(next: string[]) => void>(onChange);\n onChangeRef.current = onChange;\n\n const agentHandle = useMemo<PermissionMatrixHandle>(\n () => ({\n getSelection: () =>\n valueRef.current.filter((permId) => !lockedRef.current.has(permId)),\n setSelection: (values) => {\n const allowed = new Set(allPermIdsRef.current);\n onChangeRef.current(\n values.filter(\n (permId) => allowed.has(permId) && !lockedRef.current.has(permId),\n ),\n );\n },\n clear: () => onChangeRef.current([]),\n }),\n [],\n );\n useAgentRegistration(permissionMatrixAgent, agentHandle, id);\n\n const handleGroupChange =\n (group: PermissionMatrixGroup) =>\n (nextGroupValue: string[]): void => {\n const nextSet = new Set(nextGroupValue);\n const groupUnlockedIds = group.permissions\n .map((p) => p.id)\n .filter((permId) => !lockedSet.has(permId));\n const groupUnlockedSet = new Set(groupUnlockedIds);\n // The next selection for THIS group's editable permissions.\n const selectedUnlocked = groupUnlockedIds.filter((permId) =>\n nextSet.has(permId),\n );\n // Everything outside this group, with any locked id stripped so the\n // emitted array only ever carries editable grants.\n const remaining = value.filter(\n (permId) => !groupUnlockedSet.has(permId) && !lockedSet.has(permId),\n );\n onChange([...remaining, ...selectedUnlocked]);\n };\n\n return (\n <div\n ref={ref}\n role=\"group\"\n aria-label={ariaLabel}\n data-component=\"permission-matrix\"\n data-component-id={id}\n className={permissionMatrixVariants({ disabled, className })}\n >\n {groups.map((group) => {\n // Locked ids are forced into the group's checked set so they render\n // checked; being disabled, they can never be toggled back off.\n const groupCheckedValue = group.permissions\n .map((p) => p.id)\n .filter((permId) => lockedSet.has(permId) || value.includes(permId));\n\n return (\n <CheckboxGroup\n key={group.id}\n label={group.label}\n value={groupCheckedValue}\n onChange={handleGroupChange(group)}\n disabled={disabled}\n >\n {group.permissions.map((permission) => {\n const isLocked = lockedSet.has(permission.id);\n const label: ReactNode = isLocked ? (\n <span className={lockedLabelClasses}>\n <span>{permission.label}</span>\n <Lock\n aria-hidden=\"true\"\n className=\"ds:size-3.5 ds:shrink-0 ds:text-muted-foreground\"\n />\n <span className=\"ds:sr-only\">{resolvedLockedLabel}</span>\n </span>\n ) : (\n permission.label\n );\n\n return (\n <Checkbox\n key={permission.id}\n value={permission.id}\n label={label}\n disabled={disabled || isLocked}\n />\n );\n })}\n </CheckboxGroup>\n );\n })}\n </div>\n );\n});\n\nPermissionMatrix.displayName = 'PermissionMatrix';\n\nexport { permissionMatrixVariants };\n"],"names":["permissionMatrixAgent","handle","args","permissionMatrixVariants","cva","lockedLabelClasses","PermissionMatrix","forwardRef","groups","value","onChange","lockedItems","disabled","lockedLabel","id","className","ariaLabel","ref","t","useTranslation","lockedSet","useMemo","allPermIds","group","p","resolvedLockedLabel","valueRef","useRef","lockedRef","allPermIdsRef","onChangeRef","agentHandle","permId","values","allowed","useAgentRegistration","handleGroupChange","nextGroupValue","nextSet","groupUnlockedIds","groupUnlockedSet","selectedUnlocked","remaining","jsx","groupCheckedValue","CheckboxGroup","permission","isLocked","label","jsxs","Lock","Checkbox"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"permission-matrix-BJ6sg3Zp.js","sources":["../../src/components/permission-matrix/permission-matrix.agent.ts","../../src/components/permission-matrix/permission-matrix.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — PermissionMatrix. */\n/* */\n/* See `src/docs/26-agent-readiness.mdx` for the contract. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { PermissionMatrixHandle } from './permission-matrix';\n\nexport const permissionMatrixAgent: AgentAdapter<PermissionMatrixHandle> = {\n id: 'permission-matrix',\n capabilities: ['select_multiple'],\n state: {\n selection: {\n type: 'string[]',\n descriptionKey: 'ui.agent.permissionMatrix.state.selection',\n description:\n 'Ids of currently-granted editable permissions. Locked owner permissions are excluded.',\n read: (handle) => handle.getSelection(),\n },\n },\n actions: {\n set_selection: {\n safety: 'write',\n argsType: '{ values: string[] }',\n argsSchema: {\n type: 'object',\n properties: { values: { type: 'array', items: { type: 'string' } } },\n required: ['values'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.permissionMatrix.actions.setSelection',\n description:\n 'Replace the granted permissions with the given ids. Locked and unknown ids are ignored.',\n examples: [\n {\n args: { values: ['patients.view', 'billing.view'] },\n note: 'Grant exactly the view permissions for patients and billing.',\n },\n ],\n invoke: (handle, args: { values: string[] }) => {\n handle.setSelection(args.values);\n },\n },\n clear: {\n safety: 'destructive',\n idempotent: true,\n descriptionKey: 'ui.agent.permissionMatrix.actions.clear',\n description:\n 'Revoke every editable permission. Locked owner permissions are unaffected.',\n invoke: (handle) => {\n handle.clear();\n },\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'permission-matrix',\n description: 'Marks the PermissionMatrix root group.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n },\n};\n","import { forwardRef, useMemo, useRef, type ReactNode } from 'react';\nimport { cva } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { Lock } from 'lucide-react';\nimport { CheckboxGroup } from '../checkbox-group/checkbox-group';\nimport { Checkbox } from '../checkbox/checkbox';\nimport { useAgentRegistration } from '../../agent';\nimport { permissionMatrixAgent } from './permission-matrix.agent';\n\n/** A single togglable permission within a group. Labels are pre-localised. */\nexport interface PermissionMatrixPermission {\n id: string;\n label: string;\n}\n\n/** One category of permissions, rendered as a labelled group. */\nexport interface PermissionMatrixGroup {\n id: string;\n label: string;\n permissions: PermissionMatrixPermission[];\n}\n\n/** Agent-readiness curated handle for PermissionMatrix. */\nexport interface PermissionMatrixHandle {\n /** Ids of currently-granted editable permissions (locked items excluded). */\n getSelection: () => string[];\n /** Replace the granted set. Locked and unknown ids are ignored. */\n setSelection: (values: string[]) => void;\n /** Revoke every editable permission. Locked items are untouched. */\n clear: () => void;\n}\n\nexport interface PermissionMatrixProps {\n /** Categories of permissions. All labels are already localised by the consumer. */\n groups: PermissionMatrixGroup[];\n /** Ids of granted permissions (controlled). Locked ids belong in `lockedItems`, not here. */\n value: string[];\n /** Fires with the next full granted-id array whenever an editable toggle changes. */\n onChange: (next: string[]) => void;\n /**\n * Permission ids that render checked + disabled with a lock affordance — the\n * owner always holds them. They never appear in `onChange` payloads.\n */\n lockedItems?: string[];\n /** Disable every toggle in the matrix. */\n disabled?: boolean;\n /** Accessible suffix announced on locked rows. Defaults to the kit's \"Locked\" string. */\n lockedLabel?: string;\n /** Stable id — addresses this instance from the agent runtime. */\n id?: string;\n className?: string;\n 'aria-label'?: string;\n}\n\nconst permissionMatrixVariants = cva(\n 'ds:flex ds:flex-col ds:gap-[var(--spacing-lg)] ds:min-w-0',\n {\n variants: {\n disabled: {\n true: 'ds:cursor-not-allowed',\n false: '',\n },\n },\n defaultVariants: { disabled: false },\n },\n);\n\nconst lockedLabelClasses =\n 'ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)]';\n\nexport const PermissionMatrix = forwardRef<\n HTMLDivElement,\n PermissionMatrixProps\n>(function PermissionMatrix(\n {\n groups,\n value,\n onChange,\n lockedItems,\n disabled = false,\n lockedLabel,\n id,\n className,\n 'aria-label': ariaLabel,\n },\n ref,\n) {\n const { t } = useTranslation('ui');\n\n const lockedSet = useMemo(() => new Set(lockedItems ?? []), [lockedItems]);\n const allPermIds = useMemo(\n () => groups.flatMap((group) => group.permissions.map((p) => p.id)),\n [groups],\n );\n\n const resolvedLockedLabel =\n lockedLabel ?? t('inputs.permissionMatrix.locked', 'Locked');\n\n // Stable agent handle — reads/writes the latest controlled value via refs\n // so the handle identity never changes (mirrors CheckboxGroup).\n const valueRef = useRef<string[]>(value);\n valueRef.current = value;\n const lockedRef = useRef<Set<string>>(lockedSet);\n lockedRef.current = lockedSet;\n const allPermIdsRef = useRef<string[]>(allPermIds);\n allPermIdsRef.current = allPermIds;\n const onChangeRef = useRef<(next: string[]) => void>(onChange);\n onChangeRef.current = onChange;\n\n const agentHandle = useMemo<PermissionMatrixHandle>(\n () => ({\n getSelection: () =>\n valueRef.current.filter((permId) => !lockedRef.current.has(permId)),\n setSelection: (values) => {\n const allowed = new Set(allPermIdsRef.current);\n onChangeRef.current(\n values.filter(\n (permId) => allowed.has(permId) && !lockedRef.current.has(permId),\n ),\n );\n },\n clear: () => onChangeRef.current([]),\n }),\n [],\n );\n useAgentRegistration(permissionMatrixAgent, agentHandle, id);\n\n const handleGroupChange =\n (group: PermissionMatrixGroup) =>\n (nextGroupValue: string[]): void => {\n const nextSet = new Set(nextGroupValue);\n const groupUnlockedIds = group.permissions\n .map((p) => p.id)\n .filter((permId) => !lockedSet.has(permId));\n const groupUnlockedSet = new Set(groupUnlockedIds);\n // The next selection for THIS group's editable permissions.\n const selectedUnlocked = groupUnlockedIds.filter((permId) =>\n nextSet.has(permId),\n );\n // Everything outside this group, with any locked id stripped so the\n // emitted array only ever carries editable grants.\n const remaining = value.filter(\n (permId) => !groupUnlockedSet.has(permId) && !lockedSet.has(permId),\n );\n onChange([...remaining, ...selectedUnlocked]);\n };\n\n return (\n <div\n ref={ref}\n role=\"group\"\n aria-label={ariaLabel}\n data-component=\"permission-matrix\"\n data-component-id={id}\n className={permissionMatrixVariants({ disabled, className })}\n >\n {groups.map((group) => {\n // Locked ids are forced into the group's checked set so they render\n // checked; being disabled, they can never be toggled back off.\n const groupCheckedValue = group.permissions\n .map((p) => p.id)\n .filter((permId) => lockedSet.has(permId) || value.includes(permId));\n\n return (\n <CheckboxGroup\n key={group.id}\n label={group.label}\n value={groupCheckedValue}\n onChange={handleGroupChange(group)}\n disabled={disabled}\n >\n {group.permissions.map((permission) => {\n const isLocked = lockedSet.has(permission.id);\n const label: ReactNode = isLocked ? (\n <span className={lockedLabelClasses}>\n <span>{permission.label}</span>\n <Lock\n aria-hidden=\"true\"\n className=\"ds:size-3.5 ds:shrink-0 ds:text-muted-foreground\"\n />\n <span className=\"ds:sr-only\">{resolvedLockedLabel}</span>\n </span>\n ) : (\n permission.label\n );\n\n return (\n <Checkbox\n key={permission.id}\n value={permission.id}\n label={label}\n disabled={disabled || isLocked}\n />\n );\n })}\n </CheckboxGroup>\n );\n })}\n </div>\n );\n});\n\nPermissionMatrix.displayName = 'PermissionMatrix';\n\nexport { permissionMatrixVariants };\n"],"names":["permissionMatrixAgent","handle","args","permissionMatrixVariants","cva","lockedLabelClasses","PermissionMatrix","forwardRef","groups","value","onChange","lockedItems","disabled","lockedLabel","id","className","ariaLabel","ref","t","useTranslation","lockedSet","useMemo","allPermIds","group","p","resolvedLockedLabel","valueRef","useRef","lockedRef","allPermIdsRef","onChangeRef","agentHandle","permId","values","allowed","useAgentRegistration","handleGroupChange","nextGroupValue","nextSet","groupUnlockedIds","groupUnlockedSet","selectedUnlocked","remaining","jsx","groupCheckedValue","CheckboxGroup","permission","isLocked","label","jsxs","Lock","Checkbox"],"mappings":";;;;;;;;AASO,MAAMA,IAA8D;AAAA,EACzE,IAAI;AAAA,EACJ,cAAc,CAAC,iBAAiB;AAAA,EAChC,OAAO;AAAA,IACL,WAAW;AAAA,MACT,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,aACE;AAAA,MACF,MAAM,CAACC,MAAWA,EAAO,aAAA;AAAA,IAAa;AAAA,EACxC;AAAA,EAEF,SAAS;AAAA,IACP,eAAe;AAAA,MACb,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,YAAY;AAAA,QACV,MAAM;AAAA,QACN,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,SAAA,IAAW;AAAA,QACjE,UAAU,CAAC,QAAQ;AAAA,MAAA;AAAA,MAErB,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,aACE;AAAA,MACF,UAAU;AAAA,QACR;AAAA,UACE,MAAM,EAAE,QAAQ,CAAC,iBAAiB,cAAc,EAAA;AAAA,UAChD,MAAM;AAAA,QAAA;AAAA,MACR;AAAA,MAEF,QAAQ,CAACA,GAAQC,MAA+B;AAC9C,QAAAD,EAAO,aAAaC,EAAK,MAAM;AAAA,MACjC;AAAA,IAAA;AAAA,IAEF,OAAO;AAAA,MACL,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,aACE;AAAA,MACF,QAAQ,CAACD,MAAW;AAClB,QAAAA,EAAO,MAAA;AAAA,MACT;AAAA,IAAA;AAAA,EACF;AAAA,EAEF,UAAU;AAAA,IACR,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aAAa;AAAA,IAAA;AAAA,IAEf,YAAY;AAAA,MACV,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,aAAa;AAAA,IAAA;AAAA,EACf;AAEJ,GCbME,IAA2BC;AAAA,EAC/B;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,UAAU;AAAA,QACR,MAAM;AAAA,QACN,OAAO;AAAA,MAAA;AAAA,IACT;AAAA,IAEF,iBAAiB,EAAE,UAAU,GAAA;AAAA,EAAM;AAEvC,GAEMC,IACJ,6DAEWC,IAAmBC,EAG9B,SACA;AAAA,EACE,QAAAC;AAAA,EACA,OAAAC;AAAA,EACA,UAAAC;AAAA,EACA,aAAAC;AAAA,EACA,UAAAC,IAAW;AAAA,EACX,aAAAC;AAAA,EACA,IAAAC;AAAA,EACA,WAAAC;AAAA,EACA,cAAcC;AAChB,GACAC,GACA;AACA,QAAM,EAAE,GAAAC,EAAA,IAAMC,EAAe,IAAI,GAE3BC,IAAYC,EAAQ,MAAM,IAAI,IAAIV,KAAe,CAAA,CAAE,GAAG,CAACA,CAAW,CAAC,GACnEW,IAAaD;AAAA,IACjB,MAAMb,EAAO,QAAQ,CAACe,MAAUA,EAAM,YAAY,IAAI,CAACC,MAAMA,EAAE,EAAE,CAAC;AAAA,IAClE,CAAChB,CAAM;AAAA,EAAA,GAGHiB,IACJZ,KAAeK,EAAE,kCAAkC,QAAQ,GAIvDQ,IAAWC,EAAiBlB,CAAK;AACvC,EAAAiB,EAAS,UAAUjB;AACnB,QAAMmB,IAAYD,EAAoBP,CAAS;AAC/C,EAAAQ,EAAU,UAAUR;AACpB,QAAMS,IAAgBF,EAAiBL,CAAU;AACjD,EAAAO,EAAc,UAAUP;AACxB,QAAMQ,IAAcH,EAAiCjB,CAAQ;AAC7D,EAAAoB,EAAY,UAAUpB;AAEtB,QAAMqB,IAAcV;AAAA,IAClB,OAAO;AAAA,MACL,cAAc,MACZK,EAAS,QAAQ,OAAO,CAACM,MAAW,CAACJ,EAAU,QAAQ,IAAII,CAAM,CAAC;AAAA,MACpE,cAAc,CAACC,MAAW;AACxB,cAAMC,IAAU,IAAI,IAAIL,EAAc,OAAO;AAC7C,QAAAC,EAAY;AAAA,UACVG,EAAO;AAAA,YACL,CAACD,MAAWE,EAAQ,IAAIF,CAAM,KAAK,CAACJ,EAAU,QAAQ,IAAII,CAAM;AAAA,UAAA;AAAA,QAClE;AAAA,MAEJ;AAAA,MACA,OAAO,MAAMF,EAAY,QAAQ,CAAA,CAAE;AAAA,IAAA;AAAA,IAErC,CAAA;AAAA,EAAC;AAEH,EAAAK,EAAqBnC,GAAuB+B,GAAajB,CAAE;AAE3D,QAAMsB,IACJ,CAACb,MACD,CAACc,MAAmC;AAClC,UAAMC,IAAU,IAAI,IAAID,CAAc,GAChCE,IAAmBhB,EAAM,YAC5B,IAAI,CAACC,MAAMA,EAAE,EAAE,EACf,OAAO,CAACQ,MAAW,CAACZ,EAAU,IAAIY,CAAM,CAAC,GACtCQ,IAAmB,IAAI,IAAID,CAAgB,GAE3CE,IAAmBF,EAAiB;AAAA,MAAO,CAACP,MAChDM,EAAQ,IAAIN,CAAM;AAAA,IAAA,GAIdU,IAAYjC,EAAM;AAAA,MACtB,CAACuB,MAAW,CAACQ,EAAiB,IAAIR,CAAM,KAAK,CAACZ,EAAU,IAAIY,CAAM;AAAA,IAAA;AAEpE,IAAAtB,EAAS,CAAC,GAAGgC,GAAW,GAAGD,CAAgB,CAAC;AAAA,EAC9C;AAEF,SACE,gBAAAE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAA1B;AAAA,MACA,MAAK;AAAA,MACL,cAAYD;AAAA,MACZ,kBAAe;AAAA,MACf,qBAAmBF;AAAA,MACnB,WAAWX,EAAyB,EAAE,UAAAS,GAAU,WAAAG,GAAW;AAAA,MAE1D,UAAAP,EAAO,IAAI,CAACe,MAAU;AAGrB,cAAMqB,IAAoBrB,EAAM,YAC7B,IAAI,CAACC,MAAMA,EAAE,EAAE,EACf,OAAO,CAACQ,MAAWZ,EAAU,IAAIY,CAAM,KAAKvB,EAAM,SAASuB,CAAM,CAAC;AAErE,eACE,gBAAAW;AAAA,UAACE;AAAA,UAAA;AAAA,YAEC,OAAOtB,EAAM;AAAA,YACb,OAAOqB;AAAA,YACP,UAAUR,EAAkBb,CAAK;AAAA,YACjC,UAAAX;AAAA,YAEC,UAAAW,EAAM,YAAY,IAAI,CAACuB,MAAe;AACrC,oBAAMC,IAAW3B,EAAU,IAAI0B,EAAW,EAAE,GACtCE,IAAmBD,IACvB,gBAAAE,EAAC,QAAA,EAAK,WAAW5C,GACf,UAAA;AAAA,gBAAA,gBAAAsC,EAAC,QAAA,EAAM,YAAW,MAAA,CAAM;AAAA,gBACxB,gBAAAA;AAAA,kBAACO;AAAA,kBAAA;AAAA,oBACC,eAAY;AAAA,oBACZ,WAAU;AAAA,kBAAA;AAAA,gBAAA;AAAA,gBAEZ,gBAAAP,EAAC,QAAA,EAAK,WAAU,cAAc,UAAAlB,EAAA,CAAoB;AAAA,cAAA,EAAA,CACpD,IAEAqB,EAAW;AAGb,qBACE,gBAAAH;AAAA,gBAACQ;AAAA,gBAAA;AAAA,kBAEC,OAAOL,EAAW;AAAA,kBAClB,OAAAE;AAAA,kBACA,UAAUpC,KAAYmC;AAAA,gBAAA;AAAA,gBAHjBD,EAAW;AAAA,cAAA;AAAA,YAMtB,CAAC;AAAA,UAAA;AAAA,UA7BIvB,EAAM;AAAA,QAAA;AAAA,MAgCjB,CAAC;AAAA,IAAA;AAAA,EAAA;AAGP,CAAC;AAEDjB,EAAiB,cAAc;"}
|