@alfadocs/ui-kit-debug 1.36.0 → 1.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/appointment-peek-5S4O1VQP.js +115 -0
- package/dist/_chunks/appointment-peek-5S4O1VQP.js.map +1 -0
- package/dist/_chunks/appointment-peek.agent-C539tNFM.js +17 -0
- package/dist/_chunks/appointment-peek.agent-C539tNFM.js.map +1 -0
- package/dist/_chunks/building-2-D33bLCWL.js +24 -0
- package/dist/_chunks/building-2-D33bLCWL.js.map +1 -0
- package/dist/_chunks/calendar-workspace-BqKBj26r.js +9715 -0
- package/dist/_chunks/calendar-workspace-BqKBj26r.js.map +1 -0
- package/dist/_chunks/{control-room-rail-Ds45_g4f.js → control-room-rail-DQoHdE1U.js} +2 -2
- package/dist/_chunks/{control-room-rail-Ds45_g4f.js.map → control-room-rail-DQoHdE1U.js.map} +1 -1
- package/dist/_chunks/editable-description-BOfAeY3T.js +112 -0
- package/dist/_chunks/editable-description-BOfAeY3T.js.map +1 -0
- package/dist/_chunks/editable-description.agent-Bm_LBV2j.js +21 -0
- package/dist/_chunks/editable-description.agent-Bm_LBV2j.js.map +1 -0
- package/dist/_chunks/{money.agent-Dw55UxUA.js → money-BY-HmKhZ.js} +33 -47
- package/dist/_chunks/money-BY-HmKhZ.js.map +1 -0
- package/dist/_chunks/money.agent-BjJ6gOkx.js +17 -0
- package/dist/_chunks/money.agent-BjJ6gOkx.js.map +1 -0
- package/dist/_chunks/notes-panel-4y5JioWN.js +556 -0
- package/dist/_chunks/notes-panel-4y5JioWN.js.map +1 -0
- package/dist/_chunks/panel-subview-BNXN8OEL.js +160 -0
- package/dist/_chunks/panel-subview-BNXN8OEL.js.map +1 -0
- package/dist/_chunks/panel-subview.agent-BIBvE-IW.js +17 -0
- package/dist/_chunks/panel-subview.agent-BIBvE-IW.js.map +1 -0
- package/dist/_chunks/{patient-details-f7SSXkTJ.js → patient-details-2cIaL-Zb.js} +2 -2
- package/dist/_chunks/{patient-details-f7SSXkTJ.js.map → patient-details-2cIaL-Zb.js.map} +1 -1
- package/dist/_chunks/{patient-field-row-BQZoP4m2.js → patient-field-row-IHb2VFc2.js} +193 -172
- package/dist/_chunks/patient-field-row-IHb2VFc2.js.map +1 -0
- package/dist/_chunks/{patient-summary-card-Bz7KdUin.js → patient-summary-card-BzmJH9a-.js} +2 -2
- package/dist/_chunks/{patient-summary-card-Bz7KdUin.js.map → patient-summary-card-BzmJH9a-.js.map} +1 -1
- package/dist/_chunks/{section-card.agent-W18CHEgX.js → section-card-XR2bW1Ie.js} +20 -34
- package/dist/_chunks/{section-card.agent-W18CHEgX.js.map → section-card-XR2bW1Ie.js.map} +1 -1
- package/dist/_chunks/section-card.agent-Bz1BhM_j.js +17 -0
- package/dist/_chunks/section-card.agent-Bz1BhM_j.js.map +1 -0
- package/dist/_chunks/smartphone-DaPcFw-X.js +32 -0
- package/dist/_chunks/smartphone-DaPcFw-X.js.map +1 -0
- package/dist/_chunks/{task-card-BalrLkSz.js → task-card-qTKD1fIT.js} +39 -57
- package/dist/_chunks/task-card-qTKD1fIT.js.map +1 -0
- package/dist/_chunks/{task-tray-wl9eti6J.js → task-tray-CQ8UAR2j.js} +2 -2
- package/dist/_chunks/{task-tray-wl9eti6J.js.map → task-tray-CQ8UAR2j.js.map} +1 -1
- package/dist/_chunks/{tasks-panel-BDNB7hsZ.js → tasks-panel-CBGMtQ_f.js} +2 -2
- package/dist/_chunks/{tasks-panel-BDNB7hsZ.js.map → tasks-panel-CBGMtQ_f.js.map} +1 -1
- package/dist/_chunks/{tool-rail-Bq5eiFMG.js → tool-rail-BP8sjxCw.js} +310 -231
- package/dist/_chunks/tool-rail-BP8sjxCw.js.map +1 -0
- package/dist/_chunks/treatment-receipt-D4kOLXOk.js +94 -0
- package/dist/_chunks/treatment-receipt-D4kOLXOk.js.map +1 -0
- package/dist/_chunks/treatment-receipt.agent-bpFm2RPH.js +21 -0
- package/dist/_chunks/treatment-receipt.agent-bpFm2RPH.js.map +1 -0
- package/dist/_chunks/use-presence-transition-cDwWUXV-.js +58 -0
- package/dist/_chunks/use-presence-transition-cDwWUXV-.js.map +1 -0
- package/dist/_chunks/{workflow-map-D-LEni11.js → workflow-map-CXdsxvUj.js} +140 -156
- package/dist/_chunks/workflow-map-CXdsxvUj.js.map +1 -0
- package/dist/agent-catalog.json +65 -1
- package/dist/components/appointment-peek/appointment-peek.agent.d.ts +3 -0
- package/dist/components/appointment-peek/appointment-peek.agent.d.ts.map +1 -0
- package/dist/components/appointment-peek/appointment-peek.d.ts +45 -0
- package/dist/components/appointment-peek/appointment-peek.d.ts.map +1 -0
- package/dist/components/appointment-peek/index.d.ts +4 -0
- package/dist/components/appointment-peek/index.d.ts.map +1 -0
- package/dist/components/appointment-peek/index.js +7 -0
- package/dist/components/appointment-peek/index.js.map +1 -0
- package/dist/components/control-room-rail/index.js +1 -1
- package/dist/components/editable-description/editable-description.agent.d.ts +3 -0
- package/dist/components/editable-description/editable-description.agent.d.ts.map +1 -0
- package/dist/components/editable-description/editable-description.d.ts +20 -0
- package/dist/components/editable-description/editable-description.d.ts.map +1 -0
- package/dist/components/editable-description/index.d.ts +4 -0
- package/dist/components/editable-description/index.d.ts.map +1 -0
- package/dist/components/editable-description/index.js +7 -0
- package/dist/components/editable-description/index.js.map +1 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/money/index.js +2 -1
- package/dist/components/money/index.js.map +1 -1
- package/dist/components/notes-panel/index.js +1 -1
- package/dist/components/notes-panel/notes-panel.d.ts +16 -0
- package/dist/components/notes-panel/notes-panel.d.ts.map +1 -1
- package/dist/components/panel-subview/index.d.ts +4 -0
- package/dist/components/panel-subview/index.d.ts.map +1 -0
- package/dist/components/panel-subview/index.js +7 -0
- package/dist/components/panel-subview/index.js.map +1 -0
- package/dist/components/panel-subview/panel-subview.agent.d.ts +3 -0
- package/dist/components/panel-subview/panel-subview.agent.d.ts.map +1 -0
- package/dist/components/panel-subview/panel-subview.d.ts +32 -0
- package/dist/components/panel-subview/panel-subview.d.ts.map +1 -0
- package/dist/components/patient-details/index.js +1 -1
- package/dist/components/patient-summary-card/index.js +1 -1
- package/dist/components/section-card/index.js +4 -3
- package/dist/components/section-card/index.js.map +1 -1
- package/dist/components/task-card/index.js +1 -1
- package/dist/components/task-tray/index.js +1 -1
- package/dist/components/tasks-panel/index.js +1 -1
- package/dist/components/tool-rail/index.js +1 -1
- package/dist/components/tool-rail/tool-rail.d.ts.map +1 -1
- package/dist/components/treatment-receipt/index.d.ts +4 -0
- package/dist/components/treatment-receipt/index.d.ts.map +1 -0
- package/dist/components/treatment-receipt/index.js +7 -0
- package/dist/components/treatment-receipt/index.js.map +1 -0
- package/dist/components/treatment-receipt/treatment-receipt.agent.d.ts +3 -0
- package/dist/components/treatment-receipt/treatment-receipt.agent.d.ts.map +1 -0
- package/dist/components/treatment-receipt/treatment-receipt.d.ts +30 -0
- package/dist/components/treatment-receipt/treatment-receipt.d.ts.map +1 -0
- package/dist/components/workflow/index.js +1 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +9 -7
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/use-presence-transition.d.ts +40 -0
- package/dist/hooks/use-presence-transition.d.ts.map +1 -0
- package/dist/host-compat.css +7 -1
- package/dist/i18n/locales/ar.d.ts +29 -5
- package/dist/i18n/locales/ar.d.ts.map +1 -1
- package/dist/i18n/locales/ar.js +29 -5
- package/dist/i18n/locales/ar.js.map +1 -1
- package/dist/i18n/locales/de.d.ts +29 -5
- package/dist/i18n/locales/de.d.ts.map +1 -1
- package/dist/i18n/locales/de.js +29 -5
- package/dist/i18n/locales/de.js.map +1 -1
- package/dist/i18n/locales/el.d.ts +29 -5
- package/dist/i18n/locales/el.d.ts.map +1 -1
- package/dist/i18n/locales/el.js +29 -5
- package/dist/i18n/locales/el.js.map +1 -1
- package/dist/i18n/locales/en.d.ts +29 -5
- package/dist/i18n/locales/en.d.ts.map +1 -1
- package/dist/i18n/locales/en.js +29 -5
- package/dist/i18n/locales/en.js.map +1 -1
- package/dist/i18n/locales/es.d.ts +29 -5
- package/dist/i18n/locales/es.d.ts.map +1 -1
- package/dist/i18n/locales/es.js +29 -5
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +29 -5
- package/dist/i18n/locales/fr.d.ts.map +1 -1
- package/dist/i18n/locales/fr.js +29 -5
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hi.d.ts +29 -5
- package/dist/i18n/locales/hi.d.ts.map +1 -1
- package/dist/i18n/locales/hi.js +29 -5
- package/dist/i18n/locales/hi.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +29 -5
- package/dist/i18n/locales/it.d.ts.map +1 -1
- package/dist/i18n/locales/it.js +29 -5
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/ja.d.ts +29 -5
- package/dist/i18n/locales/ja.d.ts.map +1 -1
- package/dist/i18n/locales/ja.js +29 -5
- package/dist/i18n/locales/ja.js.map +1 -1
- package/dist/i18n/locales/nl.d.ts +29 -5
- package/dist/i18n/locales/nl.d.ts.map +1 -1
- package/dist/i18n/locales/nl.js +29 -5
- package/dist/i18n/locales/nl.js.map +1 -1
- package/dist/i18n/locales/pl.d.ts +29 -5
- package/dist/i18n/locales/pl.d.ts.map +1 -1
- package/dist/i18n/locales/pl.js +29 -5
- package/dist/i18n/locales/pl.js.map +1 -1
- package/dist/i18n/locales/pt.d.ts +29 -5
- package/dist/i18n/locales/pt.d.ts.map +1 -1
- package/dist/i18n/locales/pt.js +29 -5
- package/dist/i18n/locales/pt.js.map +1 -1
- package/dist/i18n/locales/ro.d.ts +29 -5
- package/dist/i18n/locales/ro.d.ts.map +1 -1
- package/dist/i18n/locales/ro.js +29 -5
- package/dist/i18n/locales/ro.js.map +1 -1
- package/dist/i18n/locales/ru.d.ts +29 -5
- package/dist/i18n/locales/ru.d.ts.map +1 -1
- package/dist/i18n/locales/ru.js +29 -5
- package/dist/i18n/locales/ru.js.map +1 -1
- package/dist/i18n/locales/sq.d.ts +29 -5
- package/dist/i18n/locales/sq.d.ts.map +1 -1
- package/dist/i18n/locales/sq.js +29 -5
- package/dist/i18n/locales/sq.js.map +1 -1
- package/dist/i18n/locales/sv.d.ts +29 -5
- package/dist/i18n/locales/sv.d.ts.map +1 -1
- package/dist/i18n/locales/sv.js +29 -5
- package/dist/i18n/locales/sv.js.map +1 -1
- package/dist/i18n/locales/tr.d.ts +29 -5
- package/dist/i18n/locales/tr.d.ts.map +1 -1
- package/dist/i18n/locales/tr.js +29 -5
- package/dist/i18n/locales/tr.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +29 -5
- package/dist/i18n/locales/zh.d.ts.map +1 -1
- package/dist/i18n/locales/zh.js +29 -5
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/index.js +958 -940
- package/dist/index.js.map +1 -1
- package/dist/locales/ar.json +29 -5
- package/dist/locales/de.json +29 -5
- package/dist/locales/el.json +29 -5
- package/dist/locales/en.json +29 -5
- package/dist/locales/es.json +29 -5
- package/dist/locales/fr.json +29 -5
- package/dist/locales/hi.json +29 -5
- package/dist/locales/it.json +29 -5
- package/dist/locales/ja.json +29 -5
- package/dist/locales/nl.json +29 -5
- package/dist/locales/pl.json +29 -5
- package/dist/locales/pt.json +29 -5
- package/dist/locales/ro.json +29 -5
- package/dist/locales/ru.json +29 -5
- package/dist/locales/sq.json +29 -5
- package/dist/locales/sv.json +29 -5
- package/dist/locales/tr.json +29 -5
- package/dist/locales/zh.json +29 -5
- package/dist/patterns/calendar/calendar-appointment-details.d.ts +15 -6
- package/dist/patterns/calendar/calendar-appointment-details.d.ts.map +1 -1
- package/dist/patterns/calendar/calendar-appointment-details.sections.d.ts +23 -23
- package/dist/patterns/calendar/calendar-appointment-details.sections.d.ts.map +1 -1
- package/dist/patterns/calendar/calendar-info-hover.d.ts +18 -0
- package/dist/patterns/calendar/calendar-info-hover.d.ts.map +1 -0
- package/dist/patterns/calendar/calendar-workspace.d.ts.map +1 -1
- package/dist/patterns/calendar/calendar.journey.d.ts +10 -0
- package/dist/patterns/calendar/calendar.journey.d.ts.map +1 -1
- package/dist/patterns/calendar/calendar.sheets.d.ts +2 -2
- package/dist/patterns/calendar/calendar.sheets.d.ts.map +1 -1
- package/dist/patterns/calendar/calendar.surface.d.ts.map +1 -1
- package/dist/patterns/calendar/index.js +1 -1
- package/dist/tokens.css +1 -1
- package/package.json +17 -1
- package/dist/_chunks/calendar-workspace-Duv_5B4j.js +0 -9471
- package/dist/_chunks/calendar-workspace-Duv_5B4j.js.map +0 -1
- package/dist/_chunks/hourglass-BEAzW1wE.js +0 -26
- package/dist/_chunks/hourglass-BEAzW1wE.js.map +0 -1
- package/dist/_chunks/money.agent-Dw55UxUA.js.map +0 -1
- package/dist/_chunks/notes-panel-Co8D3uDd.js +0 -469
- package/dist/_chunks/notes-panel-Co8D3uDd.js.map +0 -1
- package/dist/_chunks/patient-field-row-BQZoP4m2.js.map +0 -1
- package/dist/_chunks/smartphone-C0rFF2if.js +0 -15
- package/dist/_chunks/smartphone-C0rFF2if.js.map +0 -1
- package/dist/_chunks/task-card-BalrLkSz.js.map +0 -1
- package/dist/_chunks/tool-rail-Bq5eiFMG.js.map +0 -1
- package/dist/_chunks/workflow-map-D-LEni11.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"patient-field-row-BQZoP4m2.js","sources":["../../node_modules/lucide-react/dist/esm/icons/mars.mjs","../../node_modules/lucide-react/dist/esm/icons/venus.mjs","../../src/components/_shared/patient-fields.ts","../../src/components/_shared/field-visibility.ts","../../src/components/_shared/field-visibility-cog.tsx","../../src/components/_shared/field-value.tsx","../../src/components/_shared/patient-field-row.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 [\"path\", { d: \"M16 3h5v5\", key: \"1806ms\" }],\n [\"path\", { d: \"m21 3-6.75 6.75\", key: \"pv0uzu\" }],\n [\"circle\", { cx: \"10\", cy: \"14\", r: \"6\", key: \"1qwbdc\" }]\n];\nconst Mars = createLucideIcon(\"mars\", __iconNode);\n\nexport { __iconNode, Mars as default };\n//# sourceMappingURL=mars.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M12 15v7\", key: \"t2xh3l\" }],\n [\"path\", { d: \"M9 19h6\", key: \"456am0\" }],\n [\"circle\", { cx: \"12\", cy: \"9\", r: \"6\", key: \"1nw4tq\" }]\n];\nconst Venus = createLucideIcon(\"venus\", __iconNode);\n\nexport { __iconNode, Venus as default };\n//# sourceMappingURL=venus.mjs.map\n","import type { ReactElement, ReactNode } from 'react';\n\n/* -------------------------------------------------------------------- */\n/* Shared patient-field model */\n/* */\n/* The single field VOCABULARY every patient surface speaks — consumed */\n/* by both `PatientDetails` (full, inline-editable) and */\n/* `PatientSummaryCard` (compact). Either can surface a \"Customize */\n/* fields\" cog (show/hide + drag-and-drop reorder). The kit owns the */\n/* SHAPE; the CONSUMER owns the registry (which DoctorPatient field maps */\n/* to which id/label/PHI flag). */\n/* */\n/* Visibility + order are PER-CONTEXT, not global: the kit never persists */\n/* them — each PLACEMENT is wired to its own `visibleFieldOrder` / */\n/* `onVisibleFieldsChange`, so the SAME vocabulary can display */\n/* differently in different parts of the app (a care-plan card vs the */\n/* patient folder). The consumer chooses the persistence scope — global */\n/* per-user, or per-surface (PRS §Security; design doc D1/D2). */\n/* -------------------------------------------------------------------- */\n\n/**\n * Canonical field TYPE. When set (and no explicit `value` is supplied), the\n * kit renders the field's canonical chip from the shared `<FieldValue>`\n * registry instead of plain text — so the SAME field type looks the same on\n * every surface. Each chip is a high-contrast neutral pill with a glyph:\n *\n * - `sex` → Venus / Mars / User glyph + localised label\n * - `age` → hourglass glyph + localised, pluralised age\n * - `dob` → calendar glyph + locale-formatted date\n * - `fiscalCode` → hash glyph + monospace code (already mono — no `mono` flag\n * needed; copy + PHI lock stay the row-level affordance via\n * `copyable` / `sensitive`)\n * - `discount` → `TransactionChip` `state=\"discount\"` (the canonical monetary\n * discount chip — magnitude + `currency`, sign owned by the chip)\n * - `email` → a `mailto:` `Link` (the address is both display + target)\n * - `phone` → a `tel:` `Link` (formatted display, target normalised to\n * `+` and digits)\n *\n * The raw datum is read from `editValue` (the same scalar that seeds the\n * editor): a number for `age` / `discount`, an ISO string or `Date` for `dob`,\n * a code string for `sex`, the code string for `fiscalCode`. For the contact\n * link kinds the DISPLAY string is read from `value` (or `editValue`) and the\n * href is derived from it — so a plain-string `value` still becomes a link.\n * For every OTHER kind an explicit `value` ALWAYS wins, so a consumer can still\n * override per placement.\n */\nexport type PatientFieldKind =\n | 'sex'\n | 'age'\n | 'dob'\n | 'fiscalCode'\n | 'discount'\n | 'email'\n | 'phone';\n\n/** Editor control rendered when a field enters inline-edit mode. */\nexport type PatientFieldEditType =\n | 'text'\n | 'textarea'\n | 'select'\n | 'boolean'\n | 'date'\n | 'number'\n // Typed text variants — each renders the kit's dedicated input (validation,\n // formatting, masking) instead of a bare TextInput. Their edited value still\n // serialises to a plain string through the shared save callback.\n | 'email'\n | 'phone'\n | 'fiscalCode'\n // Address / location variants — each renders the dedicated kit picker.\n // `province`/`country`/`city` emit a plain string (UPPER sigla / alpha-2\n // lower / city name); `postalCode` validates the IT CAP format on blur.\n | 'province'\n | 'country'\n | 'postalCode'\n | 'city';\n\n/** A choice for an `editType: 'select'` field. */\nexport interface PatientFieldOption {\n value: string;\n label: string;\n}\n\n/**\n * Raw value seeded into an editor. The kit never inspects this beyond\n * handing it to the matching control and back through a save callback.\n */\nexport type PatientFieldEditValue =\n | string\n | number\n | boolean\n | Date\n | null\n | undefined;\n\n/** One label→value patient field. */\nexport interface PatientField {\n /**\n * Stable field key — drives visibility, ordering, the `data-field-id`\n * hook, and agent addressing. MUST NOT be the value (no PHI in keys).\n */\n id: string;\n /** Display label (already localised by the consumer, or a kit label). */\n label: string;\n /**\n * Display node — formatted by the consumer (Badge / Tag / Link / text).\n * Optional: omit it and set `kind` to let the kit render the field's\n * canonical chip from `editValue`. When present, `value` ALWAYS wins.\n */\n value?: ReactNode;\n /**\n * Canonical field type — when set and `value` is omitted, the kit renders\n * the matching canonical chip from the shared registry. Presentation only;\n * NEVER emitted into any `data-*` attribute (same rule as `sensitive`).\n */\n kind?: PatientFieldKind;\n /** Leading icon (a single lucide element). */\n icon?: ReactElement | null;\n /** Render the copy-to-clipboard affordance (fiscal code, ids). */\n copyable?: boolean;\n /** Text written to the clipboard when `copyable`. */\n copyText?: string;\n /** Render the value monospaced (codes, ids). */\n mono?: boolean;\n /**\n * High-sensitivity PHI marker — renders a lock glyph next to the label.\n * Presentation only; NEVER emitted into any `data-*` attribute.\n */\n sensitive?: boolean;\n /** Whether this field can be inline-edited (consumer gates by permission). */\n editable?: boolean;\n /** Control used in edit mode. Defaults to `'text'`. */\n editType?: PatientFieldEditType;\n /** Options for `editType: 'select'`. */\n options?: PatientFieldOption[];\n /** Value seeded into the editor when editing begins. */\n editValue?: PatientFieldEditValue;\n /** Currency code for `editType: 'number'` (renders a currency input). */\n currency?: string;\n}\n\n/** A labelled, collapsible group of fields. */\nexport interface PatientFieldSection {\n /** Stable section key. */\n id: string;\n /** Section heading. */\n heading: string;\n fields: PatientField[];\n /** Wrap the section in a Collapsible (default `true`). Honoured by PatientDetails. */\n collapsible?: boolean;\n /** Initial open state when `collapsible` (default `true`). */\n defaultOpen?: boolean;\n}\n\n/** The flat declaration-order list of every field id — the \"show everything\" default. */\nexport function patientFieldCatalogue(\n sections: PatientFieldSection[],\n): string[] {\n return sections.flatMap((s) => s.fields.map((f) => f.id));\n}\n\n/** A section paired with its currently-visible fields, in the chosen order. */\nexport interface ResolvedPatientSection {\n section: PatientFieldSection;\n fields: PatientField[];\n}\n\n/**\n * Project `sections` to the visible fields per section, ordered by\n * `visibleFieldOrder`. This is the single piece of visibility logic shared\n * by every patient surface, so the card and the details panel always agree\n * on what is shown and in what order.\n *\n * `visibleFieldOrder` omitted (`undefined`) ⇒ every field visible in\n * declaration order (\"show everything by default\", design doc D3). An explicit\n * empty array `[]` ⇒ NO fields visible — a surface that starts collapsed and\n * reveals fields via the customize-fields cog. Unknown ids are ignored.\n * Sections stay in declaration order; only intra-section field order follows\n * `visibleFieldOrder`.\n */\nexport function resolveVisibleFields(\n sections: PatientFieldSection[],\n visibleFieldOrder?: string[],\n): ResolvedPatientSection[] {\n const order = visibleFieldOrder ?? patientFieldCatalogue(sections);\n const orderIndex = new Map(order.map((id, index) => [id, index]));\n return sections.map((section) => ({\n section,\n fields: section.fields\n .filter((field) => orderIndex.has(field.id))\n .sort(\n (a, b) =>\n (orderIndex.get(a.id) as number) - (orderIndex.get(b.id) as number),\n ),\n }));\n}\n","import { useCallback, useMemo } from 'react';\nimport { useControllableState } from '../../hooks/use-controllable-state';\nimport {\n patientFieldCatalogue,\n type PatientField,\n type PatientFieldSection,\n} from './patient-fields';\n\n/* -------------------------------------------------------------------- */\n/* usePatientFieldVisibility */\n/* */\n/* The single visibility + ordering engine behind the patient field */\n/* picker, shared by every surface that lets a user curate which patient */\n/* fields show and in what order (PatientDetails, PatientSummaryCard). */\n/* */\n/* CONTEXT-SCOPED, not global: the order is a per-INSTANCE prop the kit */\n/* never persists. Each placement (a care-plan card, the patient-folder */\n/* summary, the Control Room details panel) is wired to its OWN */\n/* `value` / `onChange`, so the SAME field vocabulary can be displayed */\n/* differently in different parts of the app. The consumer owns the */\n/* persistence scope — global per-user, or per-context. */\n/* */\n/* Every mutation filters to known field ids, so persisted / agent input */\n/* can never smuggle an unknown key into the visible set. */\n/* -------------------------------------------------------------------- */\n\nexport interface UsePatientFieldVisibilityOptions {\n /** Controlled ordered list of visible field ids. */\n value?: string[];\n /** Uncontrolled initial order. Omit both ⇒ every field, declaration order. */\n defaultValue?: string[];\n /** Fired on any show / hide / reorder, with the next ordered visible set. */\n onChange?: (orderedIds: string[]) => void;\n}\n\nexport interface PatientFieldVisibility {\n /** Current ordered list of visible field ids (filtered to known fields). */\n visible: string[];\n /** Flat declaration-order catalogue of every field id (\"show everything\"). */\n catalogueIds: string[];\n /** field id → its field + owning section id. */\n fieldById: Map<string, { field: PatientField; sectionId: string }>;\n /** Replace the visible set / order (filtered to known fields). */\n setOrder: (orderedIds: string[]) => void;\n /** Show or hide a single field. */\n toggleField: (fieldId: string) => void;\n /** Show or hide every field in a section. */\n toggleSection: (sectionId: string, show: boolean) => void;\n /**\n * Move a field to land at another field's slot, WITHIN its section's\n * visible subsequence. Cross-section moves are ignored — sections stay in\n * declaration order. Drives both pointer drops and keyboard (Alt+Arrow).\n */\n moveFieldOnto: (fromId: string, toId: string) => void;\n /** Reset to `defaultValue` (or the full catalogue when none was given). */\n reset: () => void;\n}\n\nexport function usePatientFieldVisibility(\n sections: PatientFieldSection[],\n { value, defaultValue, onChange }: UsePatientFieldVisibilityOptions = {},\n): PatientFieldVisibility {\n const catalogueIds = useMemo(\n () => patientFieldCatalogue(sections),\n [sections],\n );\n\n const [orderState, setOrderState] = useControllableState<string[]>({\n value,\n defaultValue: defaultValue ?? catalogueIds,\n onChange,\n });\n // `useControllableState` may yield `undefined` before the first write.\n const visible = orderState ?? defaultValue ?? catalogueIds;\n\n const fieldById = useMemo(() => {\n const map = new Map<string, { field: PatientField; sectionId: string }>();\n for (const section of sections) {\n for (const field of section.fields) {\n map.set(field.id, { field, sectionId: section.id });\n }\n }\n return map;\n }, [sections]);\n\n const setOrder = useCallback(\n (next: string[]) => {\n // Drop unknown ids so persisted / agent input can't smuggle keys.\n setOrderState(next.filter((fid) => fieldById.has(fid)));\n },\n [setOrderState, fieldById],\n );\n\n const toggleField = useCallback(\n (fieldId: string) => {\n setOrder(\n visible.includes(fieldId)\n ? visible.filter((fid) => fid !== fieldId)\n : [...visible, fieldId],\n );\n },\n [visible, setOrder],\n );\n\n const toggleSection = useCallback(\n (sectionId: string, show: boolean) => {\n const sectionIds =\n sections.find((s) => s.id === sectionId)?.fields.map((f) => f.id) ?? [];\n const sectionSet = new Set(sectionIds);\n if (show) {\n const missing = sectionIds.filter((fid) => !visible.includes(fid));\n setOrder([...visible, ...missing]);\n } else {\n setOrder(visible.filter((fid) => !sectionSet.has(fid)));\n }\n },\n [sections, visible, setOrder],\n );\n\n const moveFieldOnto = useCallback(\n (fromId: string, toId: string) => {\n if (fromId === toId) return;\n const fromSection = fieldById.get(fromId)?.sectionId;\n const toSection = fieldById.get(toId)?.sectionId;\n if (!fromSection || fromSection !== toSection) return;\n const sectionIds = new Set(\n sections.find((s) => s.id === fromSection)?.fields.map((f) => f.id) ??\n [],\n );\n const siblings = visible.filter((fid) => sectionIds.has(fid));\n const fromIdx = siblings.indexOf(fromId);\n const toIdx = siblings.indexOf(toId);\n if (fromIdx < 0 || toIdx < 0) return;\n const [moved] = siblings.splice(fromIdx, 1);\n siblings.splice(toIdx, 0, moved);\n // Splice the reordered siblings back into their positions in `visible`.\n let k = 0;\n const next = visible.map((fid) =>\n sectionIds.has(fid) ? siblings[k++] : fid,\n );\n setOrder(next);\n },\n [fieldById, sections, visible, setOrder],\n );\n\n const reset = useCallback(() => {\n setOrder(defaultValue ?? catalogueIds);\n }, [defaultValue, catalogueIds, setOrder]);\n\n return {\n visible,\n catalogueIds,\n fieldById,\n setOrder,\n toggleField,\n toggleSection,\n moveFieldOnto,\n reset,\n };\n}\n","import {\n useCallback,\n useMemo,\n useState,\n type HTMLAttributes,\n type ReactNode,\n} from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { GripVertical, Settings } from 'lucide-react';\nimport { Button, IconButton } from '../button';\nimport { Checkbox } from '../checkbox/checkbox';\nimport { Popover } from '../popover/popover';\nimport { Separator } from '../separator/separator';\nimport type { PatientFieldSection } from './patient-fields';\n\n/* -------------------------------------------------------------------- */\n/* FieldVisibilityCog — the patient field picker */\n/* */\n/* The shared \"Customize fields\" cog: a Popover of per-field checkboxes */\n/* (grouped by section, with a section-level toggle-all where the section */\n/* is named), a drag handle per visible field for pointer reordering, and */\n/* the canonical Sidebar keyboard reorder gesture (Alt+Arrow / Alt+Home / */\n/* Alt+End) with an sr-only live announcement. Pure UI — the visibility */\n/* state + reducers live in `usePatientFieldVisibility`, so PatientDetails */\n/* and PatientSummaryCard share ONE picker driving each surface's own */\n/* per-context order. */\n/* */\n/* Native-HTML5 DnD (no library), mirroring data-table's ColumnToggle; */\n/* the grip adds the keyboard channel that pattern lacks. Sections with an */\n/* empty heading render their fields flat with no toggle-all (the card's */\n/* legacy single-section mode) so no empty-named checkbox is emitted. */\n/* -------------------------------------------------------------------- */\n\nexport interface FieldVisibilityCogProps {\n /** The sectioned field catalogue. */\n sections: PatientFieldSection[];\n /** Current ordered visible field ids. */\n visible: string[];\n /** Show / hide a single field. */\n onToggleField: (fieldId: string) => void;\n /** Show / hide every field in a section. */\n onToggleSection: (sectionId: string, show: boolean) => void;\n /** Move a field onto another field's slot within its section. */\n onMoveFieldOnto: (fromId: string, toId: string) => void;\n /** Reset to the default field set / order. */\n onReset: () => void;\n /** Override the cog trigger's accessible name. */\n label?: string;\n}\n\nexport function FieldVisibilityCog({\n sections,\n visible,\n onToggleField,\n onToggleSection,\n onMoveFieldOnto,\n onReset,\n label,\n}: FieldVisibilityCogProps): ReactNode {\n const { t } = useTranslation();\n const visibleSet = useMemo(() => new Set(visible), [visible]);\n\n // Drag-and-drop reorder (pointer). The keyboard channel runs through each\n // grip handle's Alt+Arrow keys; both routes share `onMoveFieldOnto`.\n const [draggingId, setDraggingId] = useState<string | null>(null);\n const [dragOverId, setDragOverId] = useState<string | null>(null);\n const [announcement, setAnnouncement] = useState('');\n\n // Field id → section id and → label: the cross-section drop guard and the\n // move announcement both need the DRAGGED field's section/label, which isn't\n // in the drop row's render scope.\n const { sectionOfField, labelOfField } = useMemo(() => {\n const sectionMap = new Map<string, string>();\n const labelMap = new Map<string, string>();\n for (const section of sections) {\n for (const field of section.fields) {\n sectionMap.set(field.id, section.id);\n labelMap.set(field.id, field.label);\n }\n }\n return { sectionOfField: sectionMap, labelOfField: labelMap };\n }, [sections]);\n\n const draggingSectionId = draggingId\n ? sectionOfField.get(draggingId)\n : undefined;\n\n const clearDrag = useCallback(() => {\n setDraggingId(null);\n setDragOverId(null);\n }, []);\n\n // Announce the moved field's new 1-based position to assistive tech.\n const announceMoved = useCallback(\n (fieldId: string, newIndex: number, count: number) => {\n setAnnouncement(\n t('fieldPicker.moved', {\n field: labelOfField.get(fieldId) ?? '',\n position: newIndex + 1,\n count,\n defaultValue: 'Moved {{field}} to position {{position}} of {{count}}',\n }),\n );\n },\n [t, labelOfField],\n );\n\n return (\n <Popover.Root>\n <Popover.Trigger asChild>\n <IconButton\n size=\"sm\"\n intent=\"outline\"\n icon={<Settings aria-hidden=\"true\" />}\n aria-label={\n label ??\n t('fieldPicker.trigger', { defaultValue: 'Customize fields' })\n }\n className=\"ds:shrink-0\"\n />\n </Popover.Trigger>\n <Popover.Content align=\"end\" size=\"sm\">\n <Popover.Heading>\n {t('fieldPicker.title', { defaultValue: 'Customize fields' })}\n </Popover.Heading>\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)] ds:mt-[var(--spacing-xs)]\">\n {sections.map((section) => {\n const fieldIds = section.fields.map((f) => f.id);\n const shownCount = fieldIds.filter((fid) =>\n visibleSet.has(fid),\n ).length;\n // Visible siblings in display order — the subsequence reordering\n // operates on. The keyboard arrows' no-op bounds key off the\n // field's index HERE, not the full declaration array.\n const orderedVisible = visible.filter((fid) =>\n fieldIds.includes(fid),\n );\n const sectionState: boolean | 'indeterminate' =\n shownCount === 0\n ? false\n : shownCount === fieldIds.length\n ? true\n : 'indeterminate';\n // A named section gets a toggle-all checkbox + indented field list;\n // an unnamed one (the card's single legacy section) renders flat.\n const named = !!section.heading;\n return (\n <div\n key={section.id}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\"\n >\n {named ? (\n <Checkbox\n size=\"sm\"\n label={section.heading}\n checked={sectionState}\n onCheckedChange={(checked) =>\n onToggleSection(section.id, checked === true)\n }\n />\n ) : null}\n <ul\n className={[\n 'ds:m-0 ds:flex ds:list-none ds:flex-col ds:gap-[var(--spacing-2xs)]',\n named ? 'ds:ps-[var(--spacing-md)]' : 'ds:ps-0',\n ].join(' ')}\n >\n {section.fields.map((field) => {\n const shown = visibleSet.has(field.id);\n const visIndex = orderedVisible.indexOf(field.id);\n const count = orderedVisible.length;\n const isDragging = draggingId === field.id;\n const isDragOver =\n dragOverId === field.id &&\n draggingId !== null &&\n draggingId !== field.id &&\n draggingSectionId === section.id;\n\n // Native-HTML5 DnD wiring, applied only to visible rows —\n // a hidden field is neither a drag source nor a drop slot.\n const dragProps: HTMLAttributes<HTMLLIElement> = shown\n ? {\n draggable: true,\n onDragStart: (e) => {\n setDraggingId(field.id);\n e.dataTransfer.effectAllowed = 'move';\n e.dataTransfer.setData('text/plain', field.id);\n },\n onDragOver: (e) => {\n // Same-section drops only; sections stay fixed.\n if (\n draggingId === null ||\n draggingSectionId !== section.id\n )\n return;\n e.preventDefault();\n e.dataTransfer.dropEffect = 'move';\n setDragOverId(field.id);\n },\n onDragLeave: () =>\n setDragOverId((prev) =>\n prev === field.id ? null : prev,\n ),\n onDrop: (e) => {\n e.preventDefault();\n const fromId = e.dataTransfer.getData('text/plain');\n if (\n fromId &&\n fromId !== field.id &&\n sectionOfField.get(fromId) === section.id\n ) {\n onMoveFieldOnto(fromId, field.id);\n announceMoved(fromId, visIndex, count);\n }\n clearDrag();\n },\n onDragEnd: clearDrag,\n }\n : {};\n\n return (\n <li\n key={field.id}\n {...dragProps}\n className={[\n 'ds:flex ds:items-center ds:justify-between ds:gap-[var(--spacing-2xs)] ds:rounded-[var(--radius-sm)] ds:px-[var(--spacing-2xs)] ds:py-[var(--spacing-2xs)] ds:transition-colors ds:motion-reduce:transition-none',\n isDragging ? 'ds:opacity-50' : '',\n isDragOver\n ? 'ds:bg-[color:color-mix(in_srgb,var(--primary)_8%,transparent)]'\n : '',\n ]\n .filter(Boolean)\n .join(' ')}\n >\n <Checkbox\n size=\"sm\"\n label={field.label}\n checked={shown}\n onCheckedChange={() => onToggleField(field.id)}\n />\n {shown ? (\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n icon={<GripVertical aria-hidden=\"true\" />}\n aria-label={t('fieldPicker.reorder', {\n field: field.label,\n defaultValue:\n 'Reorder {{field}}. Press Alt + Up or Alt + Down to move.',\n })}\n aria-keyshortcuts=\"Alt+ArrowUp Alt+ArrowDown Alt+Home Alt+End\"\n className=\"ds:shrink-0 ds:cursor-grab ds:active:cursor-grabbing\"\n onKeyDown={(e) => {\n // Reorder gestures mirror the canonical Sidebar\n // handle: Alt+Arrow (+ Alt+Home / Alt+End). Bare\n // arrows fall through to the browser default.\n if (!e.altKey) return;\n if (e.key === 'ArrowUp') {\n if (visIndex <= 0) return;\n e.preventDefault();\n onMoveFieldOnto(\n field.id,\n orderedVisible[visIndex - 1],\n );\n announceMoved(field.id, visIndex - 1, count);\n } else if (e.key === 'ArrowDown') {\n if (visIndex >= count - 1) return;\n e.preventDefault();\n onMoveFieldOnto(\n field.id,\n orderedVisible[visIndex + 1],\n );\n announceMoved(field.id, visIndex + 1, count);\n } else if (e.key === 'Home') {\n if (visIndex <= 0) return;\n e.preventDefault();\n onMoveFieldOnto(field.id, orderedVisible[0]);\n announceMoved(field.id, 0, count);\n } else if (e.key === 'End') {\n if (visIndex >= count - 1) return;\n e.preventDefault();\n onMoveFieldOnto(\n field.id,\n orderedVisible[count - 1],\n );\n announceMoved(field.id, count - 1, count);\n }\n }}\n />\n ) : null}\n </li>\n );\n })}\n </ul>\n </div>\n );\n })}\n <Separator orientation=\"horizontal\" />\n <Button type=\"button\" size=\"sm\" intent=\"ghost\" onClick={onReset}>\n {t('fieldPicker.reset', { defaultValue: 'Reset to defaults' })}\n </Button>\n </div>\n {/* Reorder announcements for assistive tech (drag drop + arrow keys). */}\n <span role=\"status\" className=\"ds:sr-only\">\n {announcement}\n </span>\n </Popover.Content>\n </Popover.Root>\n );\n}\n","import { cloneElement, type ReactElement, type ReactNode } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { CalendarDays, Hash, Hourglass, Mars, User, Venus } from 'lucide-react';\nimport { Badge } from '../badge/badge';\nimport { Link } from '../link/link';\nimport { TransactionChip } from '../transaction-chip/transaction-chip';\nimport type { PatientField } from './patient-fields';\n\n/* -------------------------------------------------------------------- */\n/* FieldValue — the canonical field-chip registry */\n/* */\n/* Renders ONE patient field's value slot. When the consumer supplies an */\n/* explicit `value` (legacy rows, per-placement overrides) it wins */\n/* verbatim. Otherwise `kind` selects the canonical chip and the raw */\n/* datum is read from `editValue`, so a known field type looks the same */\n/* on every surface (PatientSummaryCard + PatientDetails share this). */\n/* */\n/* The per-type chips (`SexChip` / `AgeChip` / `NeutralChip`) are exported */\n/* so the PatientSummaryCard identity line renders the SAME chips under */\n/* the name. */\n/* */\n/* Pure composition over already-marked kit primitives (Badge / */\n/* TransactionChip) — it mounts no surface of its own, so it carries no */\n/* `data-component` (allowlisted in check-data-component-coverage.mjs). */\n/* -------------------------------------------------------------------- */\n\n// The neutral Badge's own text colour (`--muted-foreground`) is too low\n// contrast for primary demographic data — grey text on the grey pill reads at\n// ~5.8:1. The chip label + glyph are pinned to `--foreground` (~11:1) so the\n// data stays legible on every theme.\nconst STRONG = 'ds:text-[color:var(--foreground)]';\n\n/** Default English labels — real translations live under `patientField.*`. */\nconst SEX_LABEL_DEFAULT: Record<string, string> = {\n m: 'Male',\n f: 'Female',\n x: 'Other',\n};\n\n/** A neutral pill with high-contrast text + an optional leading glyph. */\nexport function NeutralChip({\n icon,\n mono,\n children,\n}: {\n icon?: ReactElement;\n mono?: boolean;\n children: ReactNode;\n}): ReactNode {\n return (\n <Badge\n variant=\"neutral\"\n className={mono ? 'ds:font-mono' : undefined}\n // Clone the glyph (don't wrap it) so it stays Badge's DIRECT <svg> child —\n // Badge's `[&>svg]:size-*` rule only sizes a direct child, so wrapping it\n // left the glyph at lucide's default 24px. The clone also carries `STRONG`.\n leading={\n icon\n ? cloneElement(icon as ReactElement<{ className?: string }>, {\n className: STRONG,\n })\n : undefined\n }\n >\n <span className={STRONG}>{children}</span>\n </Badge>\n );\n}\n\n/** Sex chip — Venus / Mars / User glyph + localised label. Female / male carry a\n * tonal pink / blue FILL; unspecified stays the neutral pill. */\nexport function SexChip({ code }: { code: string }): ReactNode {\n const { t } = useTranslation();\n const c = code.toLowerCase();\n const label = t(`patientField.sex.${c}`, {\n defaultValue: SEX_LABEL_DEFAULT[c] ?? code,\n });\n // The fill carries the colour; Badge sizes + tones the glyph from the variant.\n // `accentSoft` is the kit's tonal magenta (≈ pink); `info` the tonal indigo\n // (≈ blue, the closest the closed palette has to blue). Other → neutral.\n if (c === 'f') {\n return (\n <Badge variant=\"accentSoft\" leading={<Venus />}>\n {label}\n </Badge>\n );\n }\n if (c === 'm') {\n return (\n <Badge variant=\"info\" leading={<Mars />}>\n {label}\n </Badge>\n );\n }\n return <NeutralChip icon={<User />}>{label}</NeutralChip>;\n}\n\n/** Age chip — hourglass glyph + localised, pluralised age. */\nexport function AgeChip({ years }: { years: number }): ReactNode {\n const { t } = useTranslation();\n return (\n <NeutralChip icon={<Hourglass />}>\n {t('patientField.age', {\n count: years,\n defaultValue: '{{count}} years old',\n })}\n </NeutralChip>\n );\n}\n\nexport function FieldValue({ field }: { field: PatientField }): ReactNode {\n const { i18n } = useTranslation();\n\n // Contact kinds render as a mailto:/tel: Link — the display string is read\n // from `value` (or `editValue`), the href is derived from it. Checked BEFORE\n // the explicit-value short-circuit so a plain-string `value` still links.\n if (field.kind === 'email' || field.kind === 'phone') {\n const display =\n typeof field.value === 'string'\n ? field.value\n : (field.copyText ??\n (typeof field.editValue === 'string' ? field.editValue : ''));\n if (display) {\n // mailto: trims surrounding whitespace; tel: keeps only `+` and digits\n // (dialler-safe), leaving the formatted text as the visible label.\n const href =\n field.kind === 'email'\n ? `mailto:${display.trim()}`\n : `tel:${display.replace(/[^+\\d]/g, '')}`;\n return <Link href={href}>{display}</Link>;\n }\n // No string to link — fall through to any explicit node value below.\n }\n\n // An explicit value always wins — legacy rows + per-placement overrides.\n if (field.value != null) {\n return <>{field.value}</>;\n }\n if (!field.kind) {\n return null;\n }\n\n switch (field.kind) {\n case 'sex':\n return <SexChip code={String(field.editValue ?? '')} />;\n case 'age': {\n const years =\n typeof field.editValue === 'number'\n ? field.editValue\n : Number(field.editValue);\n if (!Number.isFinite(years)) {\n return null;\n }\n return <AgeChip years={years} />;\n }\n case 'dob': {\n const raw = field.editValue;\n const date = raw instanceof Date ? raw : new Date(String(raw ?? ''));\n const formatted = Number.isNaN(date.getTime())\n ? String(raw ?? '')\n : new Intl.DateTimeFormat(i18n.language, {\n day: 'numeric',\n month: 'short',\n year: 'numeric',\n }).format(date);\n if (!formatted) {\n return null;\n }\n return <NeutralChip icon={<CalendarDays />}>{formatted}</NeutralChip>;\n }\n case 'fiscalCode': {\n // Copy + PHI lock stay the consumer's row-level affordance (PatientDetails\n // renders them from `copyable` / `sensitive`); the chip is the mono pill.\n const code =\n field.copyText ??\n (typeof field.editValue === 'string' ? field.editValue : '');\n if (!code) {\n return null;\n }\n return (\n <NeutralChip icon={<Hash />} mono>\n {code}\n </NeutralChip>\n );\n }\n case 'discount': {\n // The canonical monetary discount chip — magnitude + currency, the sign\n // (\"−\") and glyph owned by TransactionChip. The row label gives context,\n // so the chip itself shows only the amount (no duplicate state label).\n const amount =\n typeof field.editValue === 'number'\n ? field.editValue\n : Number(field.editValue);\n if (!Number.isFinite(amount)) {\n return null;\n }\n return (\n <TransactionChip\n state=\"discount\"\n amount={Math.abs(amount)}\n currency={field.currency}\n size=\"sm\"\n />\n );\n }\n default:\n return null;\n }\n}\n","/* -------------------------------------------------------------------- */\n/* Patient field row — display ↔ inline edit */\n/* */\n/* The single implementation of an editable patient field, shared by */\n/* every surface that renders the `PatientField` model: PatientDetails */\n/* (the full record panel) and PatientSummaryCard (the compact card). */\n/* */\n/* It lives here rather than in either component because the two must not */\n/* drift: the same field, shown on a card and in the panel, has to offer */\n/* the same edit affordance, the same validation seam, the same optimistic*/\n/* -free save (the row stays in edit mode until the host resolves), and */\n/* the same PHI treatment (`sensitive` renders a lock, and NEVER reaches */\n/* a data-* attribute). */\n/* */\n/* The write path is the host's: the row owns the draft and the control, */\n/* the consumer owns `onFieldSave`. There is no second channel. */\n/* -------------------------------------------------------------------- */\n\nimport {\n useCallback,\n useId,\n useState,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Check, Copy, Lock, Pencil, X } from 'lucide-react';\nimport type { PatientField, PatientFieldEditValue } from './patient-fields';\nimport { DescriptionList } from '../description-list';\nimport { FieldValue } from './field-value';\nimport { IconButton } from '../button/icon-button';\nimport { CityInput } from '../city-input/city-input';\nimport { CountrySelect } from '../country-select/country-select';\nimport { DatePicker } from '../date-picker/date-picker';\nimport { EmailInput } from '../email-input/email-input';\nimport { FiscalCodeInput } from '../fiscal-code-input/fiscal-code-input';\nimport { NumberInput } from '../number-input/number-input';\nimport { PhoneInput } from '../phone-input/phone-input';\nimport { PostalCodeInput } from '../postal-code-input/postal-code-input';\nimport { ProvinceSelect } from '../province-select/province-select';\nimport { Select } from '../select/select';\nimport { Switch } from '../switch/switch';\nimport { TextArea } from '../text-area/text-area';\nimport { TextInput } from '../text-input/text-input';\n\n/* -------------------------------------------------------------------- */\n/* FieldRow — display ↔ inline-edit */\n/* -------------------------------------------------------------------- */\n\nexport interface PatientFieldCellProps {\n field: PatientField;\n /** Master switch — an `editable` field shows its edit affordance. */\n editable: boolean;\n /** The single write channel. Without it, nothing is editable. */\n onFieldSave?: (fieldId: string, value: unknown) => Promise<void>;\n /** Return a message to block the save and keep the row in edit mode. */\n validate?: (fieldId: string, value: unknown) => string | null;\n locale?: string;\n}\n\n/**\n * The LABEL side of a patient field: its text plus the PHI lock when the\n * field is marked sensitive.\n */\nexport function PatientFieldLabel({\n field,\n}: {\n field: PatientField;\n}): ReactNode {\n const { t } = useTranslation();\n return (\n <span className=\"ds:inline-flex ds:items-center ds:gap-[var(--spacing-2xs)]\">\n {field.label}\n {field.sensitive ? (\n <Lock\n aria-label={t('patientDetails.sensitive', {\n defaultValue: 'Sensitive',\n })}\n className=\"ds:size-3 ds:shrink-0 ds:text-[color:var(--muted-foreground)]\"\n />\n ) : null}\n </span>\n );\n}\n\n/**\n * The VALUE side of a patient field: the formatted value, its copy button,\n * and the inline editor once opened. List-shape agnostic on purpose — it\n * carries no row markup, so `PatientDetails` can place it in a\n * `DescriptionList` and `PatientSummaryCard` in a `KeyValueList` while the\n * edit behaviour stays one implementation.\n *\n * The edit affordance reveals on hover / focus of an ancestor marked\n * `ds:group`, so whichever list wraps this must set that class on its row.\n */\nexport function PatientFieldValueCell({\n field,\n editable,\n onFieldSave,\n validate,\n locale,\n}: PatientFieldCellProps): ReactNode {\n const { t } = useTranslation();\n const errorId = useId();\n const canEdit = editable && !!field.editable && !!onFieldSave;\n\n const [editing, setEditing] = useState(false);\n const [draft, setDraft] = useState<PatientFieldEditValue>(field.editValue);\n const [error, setError] = useState<string | null>(null);\n const [saving, setSaving] = useState(false);\n\n const beginEdit = useCallback(() => {\n setDraft(field.editValue);\n setError(null);\n setEditing(true);\n }, [field.editValue]);\n\n const cancelEdit = useCallback(() => {\n setEditing(false);\n setError(null);\n }, []);\n\n const commitEdit = useCallback(async () => {\n if (!onFieldSave) return;\n const validationError = validate?.(field.id, draft) ?? null;\n if (validationError) {\n setError(validationError);\n return;\n }\n setSaving(true);\n setError(null);\n try {\n await onFieldSave(field.id, draft);\n setEditing(false);\n } catch (err) {\n // Keep the row in edit mode + surface the failure; the value the\n // consumer holds is unchanged (no optimistic mutation of `value`).\n setError(\n err instanceof Error && err.message\n ? err.message\n : t('patientDetails.edit.saveFailed', {\n defaultValue: 'Could not save. Try again.',\n }),\n );\n } finally {\n setSaving(false);\n }\n }, [onFieldSave, validate, field.id, draft, t]);\n\n // Best-effort plain text for the truncated value's hover tooltip — the full\n // value also stays reachable via inline edit and (when copyable) the copy button.\n const valueTitle =\n typeof field.value === 'string'\n ? field.value\n : (field.copyText ??\n (typeof field.editValue === 'string' ? field.editValue : undefined));\n\n return editing ? (\n <span className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n <span className=\"ds:flex ds:items-start ds:gap-[var(--spacing-2xs)]\">\n <FieldEditor\n field={field}\n value={draft}\n onChange={setDraft}\n invalid={!!error}\n errorId={error ? errorId : undefined}\n locale={locale}\n disabled={saving}\n />\n <IconButton\n size=\"sm\"\n intent=\"primary\"\n icon={<Check aria-hidden=\"true\" />}\n aria-label={t('patientDetails.edit.save', { defaultValue: 'Save' })}\n loading={saving}\n onClick={commitEdit}\n />\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n icon={<X aria-hidden=\"true\" />}\n aria-label={t('patientDetails.edit.cancel', {\n defaultValue: 'Cancel',\n })}\n disabled={saving}\n onClick={cancelEdit}\n />\n </span>\n {error ? (\n <span\n id={errorId}\n role=\"alert\"\n className=\"type-meta ds:text-[color:var(--destructive)]\"\n >\n {error}\n </span>\n ) : null}\n </span>\n ) : (\n <span className=\"ds:flex ds:items-start ds:gap-[var(--spacing-2xs)] ds:min-w-0\">\n {/* Single-line values truncate so the read row matches the editor height\n (no shift on open); textarea fields keep wrapping. */}\n <span\n className={`ds:min-w-0 ${field.editType === 'textarea' ? '' : 'ds:truncate'}${field.mono ? ' ds:font-mono' : ''}`}\n title={valueTitle}\n >\n <FieldValue field={field} />\n </span>\n {field.copyable && field.copyText ? (\n <CopyButton text={field.copyText} label={field.label} />\n ) : null}\n {canEdit ? (\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n // Reveal on row hover / keyboard focus only — stays in the tab order\n // (opacity, not display) so keyboard + SR users always reach it.\n className=\"ds:shrink-0 ds:opacity-0 ds:transition-opacity ds:motion-reduce:transition-none ds:group-hover:opacity-100 ds:focus-visible:opacity-100\"\n icon={<Pencil aria-hidden=\"true\" />}\n aria-label={t('patientDetails.edit.editField', {\n field: field.label,\n defaultValue: 'Edit {{field}}',\n })}\n onClick={beginEdit}\n />\n ) : null}\n </span>\n );\n}\n\n/**\n * One patient field as a `DescriptionList` row — the shape `PatientDetails`\n * uses. `PatientSummaryCard` composes the same cells into its own list\n * instead, so the two surfaces share the editing behaviour without sharing a\n * list primitive.\n */\nexport function PatientFieldRow({\n field,\n icon,\n ...cell\n}: PatientFieldCellProps & {\n icon?: ReactElement | null;\n}): ReactNode {\n return (\n <DescriptionList.Row\n icon={icon ?? null}\n data-field-id={field.id}\n // `group` is what reveals the edit pencil on hover / focus.\n className=\"ds:group\"\n >\n <DescriptionList.Term>\n <PatientFieldLabel field={field} />\n </DescriptionList.Term>\n <DescriptionList.Detail>\n <PatientFieldValueCell field={field} {...cell} />\n </DescriptionList.Detail>\n </DescriptionList.Row>\n );\n}\n\n/* -------------------------------------------------------------------- */\n/* FieldEditor — the right control per editType */\n/* -------------------------------------------------------------------- */\n\nfunction FieldEditor({\n field,\n value,\n onChange,\n invalid,\n errorId,\n locale,\n disabled,\n}: {\n field: PatientField;\n value: PatientFieldEditValue;\n onChange: (next: PatientFieldEditValue) => void;\n invalid: boolean;\n errorId?: string;\n locale?: string;\n disabled?: boolean;\n}): ReactNode {\n const { t } = useTranslation();\n const tone = invalid ? 'error' : 'default';\n const editType = field.editType ?? 'text';\n\n switch (editType) {\n case 'textarea':\n return (\n <TextArea\n size=\"sm\"\n value={typeof value === 'string' ? value : ''}\n onChange={(e) => onChange(e.target.value)}\n tone={tone}\n aria-label={field.label}\n aria-invalid={invalid || undefined}\n aria-describedby={errorId}\n disabled={disabled}\n className=\"ds:flex-1\"\n />\n );\n case 'select':\n return (\n <Select\n size=\"sm\"\n options={field.options ?? []}\n value={typeof value === 'string' ? value : ''}\n onValueChange={(next) => onChange(next)}\n tone={tone}\n disabled={disabled}\n aria-label={field.label}\n aria-invalid={invalid || undefined}\n aria-describedby={errorId}\n />\n );\n case 'boolean':\n return (\n <Switch\n label={field.label}\n checked={value === true}\n onCheckedChange={(checked) => onChange(checked)}\n disabled={disabled}\n />\n );\n case 'date':\n return (\n <DatePicker\n size=\"sm\"\n value={value instanceof Date ? value : undefined}\n onChange={(next) => onChange(next ?? null)}\n disabled={disabled}\n aria-label={field.label}\n />\n );\n case 'number':\n return (\n <NumberInput\n size=\"sm\"\n value={typeof value === 'number' ? value : null}\n onChange={(next) => onChange(next)}\n mode={field.currency ? 'currency' : 'decimal'}\n currency={field.currency}\n locale={locale}\n tone={tone}\n disabled={disabled}\n aria-label={field.label}\n aria-invalid={invalid || undefined}\n aria-describedby={errorId}\n />\n );\n case 'email':\n return (\n <EmailInput\n size=\"sm\"\n value={typeof value === 'string' ? value : ''}\n onChange={(e) => onChange(e.target.value)}\n // EmailInput owns format validation — it surfaces its own border +\n // \"Invalid email\" message. PatientDetails' `validate` layers on top\n // for business rules (e.g. already-in-use), never format.\n aria-label={field.label}\n aria-invalid={invalid || undefined}\n aria-describedby={errorId}\n disabled={disabled}\n className=\"ds:flex-1\"\n />\n );\n case 'phone':\n return (\n <PhoneInput\n size=\"sm\"\n // E.164 string in / out — the dialling-code split is the input's own\n // internal state, never part of the saved value.\n value={typeof value === 'string' ? value : ''}\n onChange={(e164) => onChange(e164)}\n tone={tone}\n aria-label={field.label}\n aria-invalid={invalid || undefined}\n aria-describedby={errorId}\n disabled={disabled}\n className=\"ds:flex-1\"\n />\n );\n case 'fiscalCode':\n return (\n <FiscalCodeInput\n size=\"sm\"\n // The input normalises (uppercase, strip, ≤16) and hands back the\n // plain string; that normalised value is what we save.\n value={typeof value === 'string' ? value : ''}\n onChange={(raw) => onChange(raw)}\n tone={tone}\n aria-label={field.label}\n aria-invalid={invalid || undefined}\n aria-describedby={errorId}\n disabled={disabled}\n className=\"ds:flex-1\"\n />\n );\n // Address / location pickers. Inline edit has no FormField, so we pass\n // aria-invalid / aria-describedby explicitly (the components fall back to\n // these props outside a FormFieldContext) so the invalid state isn't\n // conveyed by colour alone.\n case 'province':\n return (\n <ProvinceSelect\n size=\"sm\"\n country=\"it\"\n value={typeof value === 'string' ? value : ''}\n onValueChange={(next) => onChange(next)}\n tone={tone}\n disabled={disabled}\n aria-label={field.label}\n aria-invalid={invalid || undefined}\n aria-describedby={errorId}\n className=\"ds:flex-1\"\n />\n );\n case 'country':\n return (\n <CountrySelect\n size=\"sm\"\n value={typeof value === 'string' ? value : ''}\n onValueChange={(next) => onChange(next)}\n tone={tone}\n disabled={disabled}\n aria-label={field.label}\n aria-invalid={invalid || undefined}\n aria-describedby={errorId}\n className=\"ds:flex-1\"\n />\n );\n case 'postalCode':\n // PostalCodeInput owns its tone (derived from CAP-format blur\n // validation), so we don't pass `tone`; it accepts aria-invalid /\n // aria-describedby for the business-rule layer above.\n return (\n <PostalCodeInput\n size=\"sm\"\n country=\"it\"\n value={typeof value === 'string' ? value : ''}\n onValueChange={(next) => onChange(next)}\n aria-label={field.label}\n aria-invalid={invalid || undefined}\n aria-describedby={errorId}\n disabled={disabled}\n className=\"ds:flex-1\"\n />\n );\n case 'city':\n return (\n <CityInput\n size=\"sm\"\n value={typeof value === 'string' ? value : ''}\n onValueChange={(next) => onChange(next)}\n tone={tone}\n disabled={disabled}\n aria-label={field.label}\n aria-invalid={invalid || undefined}\n aria-describedby={errorId}\n className=\"ds:flex-1\"\n />\n );\n case 'text':\n default:\n return (\n <TextInput\n size=\"sm\"\n value={typeof value === 'string' ? value : ''}\n onChange={(e) => onChange(e.target.value)}\n tone={tone}\n aria-label={field.label}\n aria-invalid={invalid || undefined}\n aria-describedby={errorId}\n disabled={disabled}\n clearable\n placeholder={t('patientDetails.edit.placeholder', {\n defaultValue: 'Enter a value',\n })}\n className=\"ds:flex-1\"\n />\n );\n }\n}\n\n/* -------------------------------------------------------------------- */\n/* CopyButton — copy a field value (rendered INSIDE the <dd>) */\n/* */\n/* Rendered inside the Detail so the <dl> grouping <div> contains only */\n/* <dt>/<dd> (the axe `definition-list` rule forbids buttons as siblings */\n/* of dt/dd). Reuses the shared keyValuePair.* copy strings. */\n/* -------------------------------------------------------------------- */\n\nfunction CopyButton({\n text,\n label,\n}: {\n text: string;\n label: string;\n}): ReactNode {\n const { t } = useTranslation();\n const [copied, setCopied] = useState(false);\n const [announcement, setAnnouncement] = useState('');\n\n const handleCopy = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(text);\n setCopied(true);\n setAnnouncement(t('keyValuePair.copied', { defaultValue: 'Copied' }));\n setTimeout(() => {\n setCopied(false);\n setAnnouncement('');\n }, 2000);\n } catch {\n setAnnouncement(\n t('keyValuePair.notAvailable', { defaultValue: 'Copy not available' }),\n );\n setTimeout(() => setAnnouncement(''), 3000);\n }\n }, [text, t]);\n\n return (\n <>\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n icon={\n copied ? <Check aria-hidden=\"true\" /> : <Copy aria-hidden=\"true\" />\n }\n aria-label={t('keyValuePair.copy', {\n label,\n defaultValue: 'Copy {{label}}',\n })}\n onClick={handleCopy}\n />\n <span role=\"status\" className=\"ds:sr-only\">\n {announcement}\n </span>\n </>\n );\n}\n"],"names":["__iconNode","Mars","createLucideIcon","Venus","patientFieldCatalogue","sections","s","f","resolveVisibleFields","visibleFieldOrder","order","orderIndex","id","index","section","field","a","b","usePatientFieldVisibility","value","defaultValue","onChange","catalogueIds","useMemo","orderState","setOrderState","useControllableState","visible","fieldById","map","setOrder","useCallback","next","fid","toggleField","fieldId","toggleSection","sectionId","show","sectionIds","_a","sectionSet","missing","moveFieldOnto","fromId","toId","fromSection","toSection","_b","_c","siblings","fromIdx","toIdx","moved","k","reset","FieldVisibilityCog","onToggleField","onToggleSection","onMoveFieldOnto","onReset","label","t","useTranslation","visibleSet","draggingId","setDraggingId","useState","dragOverId","setDragOverId","announcement","setAnnouncement","sectionOfField","labelOfField","sectionMap","labelMap","draggingSectionId","clearDrag","announceMoved","newIndex","count","jsxs","Popover","jsx","IconButton","Settings","fieldIds","shownCount","orderedVisible","sectionState","named","Checkbox","checked","shown","visIndex","isDragging","isDragOver","e","prev","GripVertical","Separator","Button","STRONG","SEX_LABEL_DEFAULT","NeutralChip","icon","mono","children","Badge","cloneElement","SexChip","code","c","User","AgeChip","years","Hourglass","FieldValue","i18n","display","href","Link","Fragment","raw","date","formatted","CalendarDays","Hash","amount","TransactionChip","PatientFieldLabel","Lock","PatientFieldValueCell","editable","onFieldSave","validate","locale","errorId","useId","canEdit","editing","setEditing","draft","setDraft","error","setError","saving","setSaving","beginEdit","cancelEdit","commitEdit","validationError","err","valueTitle","FieldEditor","Check","X","CopyButton","Pencil","PatientFieldRow","cell","DescriptionList","invalid","disabled","tone","TextArea","Select","Switch","DatePicker","NumberInput","EmailInput","PhoneInput","e164","FiscalCodeInput","ProvinceSelect","CountrySelect","PostalCodeInput","CityInput","TextInput","text","copied","setCopied","handleCopy","Copy"],"mappings":"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","x_google_ignoreList":[0,1]}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { c as t } from "./createLucideIcon-DhHxpK9K.js";
|
|
2
|
-
/**
|
|
3
|
-
* @license lucide-react v1.22.0 - ISC
|
|
4
|
-
*
|
|
5
|
-
* This source code is licensed under the ISC license.
|
|
6
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
7
|
-
*/
|
|
8
|
-
const e = [
|
|
9
|
-
["rect", { width: "14", height: "20", x: "5", y: "2", rx: "2", ry: "2", key: "1yt0o3" }],
|
|
10
|
-
["path", { d: "M12 18h.01", key: "mhygvu" }]
|
|
11
|
-
], r = t("smartphone", e);
|
|
12
|
-
export {
|
|
13
|
-
r as S
|
|
14
|
-
};
|
|
15
|
-
//# sourceMappingURL=smartphone-C0rFF2if.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"smartphone-C0rFF2if.js","sources":["../../node_modules/lucide-react/dist/esm/icons/smartphone.mjs"],"sourcesContent":["/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"rect\", { width: \"14\", height: \"20\", x: \"5\", y: \"2\", rx: \"2\", ry: \"2\", key: \"1yt0o3\" }],\n [\"path\", { d: \"M12 18h.01\", key: \"mhygvu\" }]\n];\nconst Smartphone = createLucideIcon(\"smartphone\", __iconNode);\n\nexport { __iconNode, Smartphone as default };\n//# sourceMappingURL=smartphone.mjs.map\n"],"names":["__iconNode","Smartphone","createLucideIcon"],"mappings":";AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA,MAAMA,IAAa;AAAA,EACjB,CAAC,QAAQ,EAAE,OAAO,MAAM,QAAQ,MAAM,GAAG,KAAK,GAAG,KAAK,IAAI,KAAK,IAAI,KAAK,KAAK,UAAU;AAAA,EACvF,CAAC,QAAQ,EAAE,GAAG,cAAc,KAAK,SAAQ,CAAE;AAC7C,GACMC,IAAaC,EAAiB,cAAcF,CAAU;","x_google_ignoreList":[0]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"task-card-BalrLkSz.js","sources":["../../node_modules/lucide-react/dist/esm/icons/briefcase.mjs","../../node_modules/lucide-react/dist/esm/icons/building-2.mjs","../../src/components/task-card/task-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 [\"path\", { d: \"M16 20V4a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16\", key: \"jecpp\" }],\n [\"rect\", { width: \"20\", height: \"14\", x: \"2\", y: \"6\", rx: \"2\", key: \"i6l2r4\" }]\n];\nconst Briefcase = createLucideIcon(\"briefcase\", __iconNode);\n\nexport { __iconNode, Briefcase as default };\n//# sourceMappingURL=briefcase.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M10 12h4\", key: \"a56b0p\" }],\n [\"path\", { d: \"M10 8h4\", key: \"1sr2af\" }],\n [\"path\", { d: \"M14 21v-3a2 2 0 0 0-4 0v3\", key: \"1rgiei\" }],\n [\n \"path\",\n {\n d: \"M6 10H4a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-2\",\n key: \"secmi2\"\n }\n ],\n [\"path\", { d: \"M6 21V5a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v16\", key: \"16ra0t\" }]\n];\nconst Building2 = createLucideIcon(\"building-2\", __iconNode);\n\nexport { __iconNode, Building2 as default };\n//# sourceMappingURL=building-2.mjs.map\n","import { forwardRef, type HTMLAttributes, type ReactNode } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport {\n CircleAlert,\n Briefcase,\n Building2,\n SquareCheckBig,\n ChevronRight,\n Square,\n User,\n} from 'lucide-react';\nimport { VisuallyHidden } from '../visually-hidden';\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\n\nexport type TaskStatus = 'open' | 'in-progress' | 'done';\nexport type TaskPriority = 'low' | 'normal' | 'high';\n\n/** Which entity the task links to. The platform `DoctorReminder` links to exactly one of these (or none). */\nexport type TaskLinkType = 'patient' | 'company' | 'operator';\n\n/** Linked-entity glyph — patient (person), company (building), operator (briefcase). */\nconst LINK_ICON: Record<TaskLinkType, typeof User> = {\n patient: User,\n company: Building2,\n operator: Briefcase,\n};\n\nexport interface TaskItem {\n /** Unique identifier for the task. */\n id: string;\n /** Title — single line, primary content. */\n title: string;\n /** Optional secondary line (e.g. \"Patient A · Due today\"). */\n description?: string;\n /**\n * Localised due-date hint (e.g. \"Due today\" / \"Tomorrow\"). Rendered as a\n * trailing eyebrow chip when set; consumers compute the bucket and pass\n * the localised string.\n */\n dueLabel?: string;\n /**\n * Linked-entity NAME (the patient / company / operator the task points at) —\n * e.g. \"Mario Rossi\". When `linkType` is set the card renders it as a typed\n * chip (a per-type glyph + an accessible \"Patient/Company/Operator:\" prefix);\n * otherwise it renders as a plain eyebrow line. The consumer composes the\n * name only — no prefix.\n */\n linkedLabel?: string;\n /** Type of the linked entity — drives the leading glyph + the accessible prefix on the linked chip. */\n linkType?: TaskLinkType;\n /** Localised assignee display name (host-composed, e.g. \"Dr. Alfa\"). Renders an assignee chip on the meta line. */\n assigneeLabel?: string;\n /** Free-text note attached to the task — muted body line, clamped. */\n note?: string;\n /** Lifecycle state — drives the leading icon. */\n status?: TaskStatus;\n /** Priority — `high` colours the leading icon as `--destructive`. */\n priority?: TaskPriority;\n /** Optional deep link — when present the row is an anchor. */\n url?: string;\n}\n\nexport interface TaskCardProps\n extends\n Omit<HTMLAttributes<HTMLDivElement>, 'onClick' | 'role' | 'title'>,\n VariantProps<typeof taskCardVariants> {\n /** The task to render. */\n item: TaskItem;\n /** Visual density. `xs` is the compact rail row (Control Room); `sm`/`md` for in-page lists. */\n size?: 'xs' | 'sm' | 'md';\n /** Fires when the row is activated (click / Enter / Space). */\n onActivate?: (item: TaskItem) => void;\n /**\n * Trailing per-row action toolbar (icon buttons: schedule, edit, …).\n * Rendered above the stretched-link overlay so the controls stay\n * clickable inside an interactive row.\n */\n actions?: ReactNode;\n /**\n * Replaces the leading status glyph. Pass a control (the done checkbox)\n * when the row can be completed in place: the glyph alone only reports\n * status, and rendering both a glyph and a matching toggle elsewhere in\n * the row shows the same mark twice, of which only one does anything.\n * Rendered above the stretched-link overlay so it stays clickable.\n */\n leading?: ReactNode;\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst taskCardVariants = cva(\n [\n 'ds:relative ds:flex ds:items-start ds:gap-[var(--spacing-sm)]',\n // Same corner as the elevated Card the note and appointment rows use.\n 'ds:rounded-[var(--radius-lg)]',\n 'ds:transition-colors',\n 'ds:motion-reduce:transition-none',\n 'ds:text-start ds:group',\n 'ds:border ds:border-[color:var(--card-border)] ds:[.theme-accessible_&]:border-2',\n 'ds:forced-colors:border ds:forced-colors:border-[CanvasText]',\n ].join(' '),\n {\n variants: {\n size: {\n xs: 'ds:p-[var(--spacing-xs)]',\n sm: 'ds:p-[var(--spacing-sm)]',\n md: 'ds:p-[var(--spacing-md)]',\n },\n interactive: {\n true: 'ds:hover:bg-[color:var(--muted)]/40 ds:cursor-pointer',\n false: '',\n },\n },\n defaultVariants: {\n size: 'sm',\n interactive: false,\n },\n },\n);\n\nconst stretchedLinkClass = [\n 'ds:focus-visible:outline-none',\n \"ds:after:content-[''] ds:after:absolute ds:after:inset-0 ds:after:rounded-[var(--radius-lg)]\",\n 'ds:after:pointer-events-auto',\n 'ds:focus-visible:after:outline-[length:var(--focus-ring-width)]',\n 'ds:focus-visible:after:outline-solid',\n 'ds:focus-visible:after:outline-[color:var(--ring)]',\n 'ds:focus-visible:after:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:after:outline-[CanvasText]',\n].join(' ');\n\n/* ------------------------------------------------------------------ */\n/* Helpers */\n/* ------------------------------------------------------------------ */\n\nexport function isSafeTaskUrl(url: string): boolean {\n return /^(https?:\\/\\/(?!\\/)|\\/(?!\\/)|#)/.test(url);\n}\n\nfunction StatusIcon({\n status,\n priority,\n}: {\n status?: TaskStatus;\n priority?: TaskPriority;\n}): ReactNode {\n const tone =\n priority === 'high'\n ? 'ds:text-[color:var(--destructive)]'\n : 'ds:text-[color:var(--muted-foreground)]';\n if (status === 'done') {\n return (\n <SquareCheckBig aria-hidden=\"true\" className={`ds:size-4 ${tone}`} />\n );\n }\n if (priority === 'high') {\n return <CircleAlert aria-hidden=\"true\" className={`ds:size-4 ${tone}`} />;\n }\n return <Square aria-hidden=\"true\" className={`ds:size-4 ${tone}`} />;\n}\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\nexport const TaskCard = forwardRef<HTMLDivElement, TaskCardProps>(\n (\n { item, size = 'sm', onActivate, actions, leading, className, ...rest },\n ref,\n ) => {\n const { t } = useTranslation();\n const interactive = !!onActivate;\n const hasSafeUrl = !!item.url && isSafeTaskUrl(item.url);\n const ariaLabel = t('taskCard.itemLabel', {\n title: item.title,\n due: item.dueLabel ?? '',\n defaultValue: '{{title}}{{due, prepend, \" · \"}}',\n });\n\n // Static key lookups so the i18n coverage gate sees each literal key.\n const linkTypeLabels: Record<TaskLinkType, string> = {\n patient: t('taskCard.link.patient'),\n company: t('taskCard.link.company'),\n operator: t('taskCard.link.operator'),\n };\n const LinkIcon = item.linkType ? LINK_ICON[item.linkType] : null;\n // The meta row carries icon-led chips: a typed linked entity + an assignee.\n const showLinkChip = !!item.linkType && !!item.linkedLabel;\n const hasMetaRow = showLinkChip || !!item.assigneeLabel;\n\n const titleNode = (\n <span className=\"ds:flex-1 ds:min-w-0 ds:truncate type-body-sm ds:text-[color:var(--foreground)]\">\n {item.title}\n </span>\n );\n\n let activator: ReactNode;\n if (interactive && hasSafeUrl) {\n activator = (\n <a\n href={item.url}\n aria-label={ariaLabel}\n className={stretchedLinkClass + ' ds:contents'}\n onClick={(e) => {\n if (e.defaultPrevented || e.metaKey || e.ctrlKey || e.shiftKey)\n return;\n onActivate?.(item);\n }}\n >\n {titleNode}\n </a>\n );\n } else if (interactive) {\n activator = (\n <button\n type=\"button\"\n aria-label={ariaLabel}\n className={\n stretchedLinkClass +\n ' ds:contents ds:bg-transparent ds:border-0 ds:p-0 ds:text-start'\n }\n onClick={() => onActivate?.(item)}\n >\n {titleNode}\n </button>\n );\n } else {\n activator = titleNode;\n }\n\n return (\n <div\n ref={ref}\n role=\"listitem\"\n data-component=\"task-card\"\n data-component-id={item.id}\n data-status={item.status ?? 'open'}\n data-priority={item.priority ?? 'normal'}\n className={taskCardVariants({ size, interactive, className })}\n {...rest}\n >\n <span className=\"ds:relative ds:z-[1] ds:mt-[var(--spacing-2xs)] ds:shrink-0\">\n {leading ?? (\n <StatusIcon status={item.status} priority={item.priority} />\n )}\n </span>\n\n <div className=\"ds:flex-1 ds:min-w-0 ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n {activator}\n {item.description ? (\n <span className=\"type-body-sm ds:text-[color:var(--muted-foreground)] ds:truncate\">\n {item.description}\n </span>\n ) : null}\n {item.note ? (\n <span className=\"type-body-sm ds:text-[color:var(--muted-foreground)] ds:line-clamp-2\">\n {item.note}\n </span>\n ) : null}\n {hasMetaRow ? (\n // `type-meta` (not `type-eyebrow`): these chips carry proper-noun\n // values (patient / company / operator name, assignee) that must\n // not be uppercased. Icons are decorative; the type word is exposed\n // to AT via a VisuallyHidden prefix so each chip reads e.g.\n // \"Patient: Mario Rossi\" / \"Assignee: Dr. Alfa\".\n <div className=\"type-meta ds:flex ds:flex-wrap ds:items-center ds:gap-x-[var(--spacing-sm)] ds:gap-y-[var(--spacing-2xs)] ds:text-[color:var(--muted-foreground)]\">\n {item.linkType && item.linkedLabel && LinkIcon ? (\n <span className=\"ds:inline-flex ds:min-w-0 ds:items-center ds:gap-[var(--spacing-2xs)]\">\n <LinkIcon\n aria-hidden=\"true\"\n className=\"ds:size-3 ds:shrink-0\"\n />\n <VisuallyHidden>{`${linkTypeLabels[item.linkType]}: `}</VisuallyHidden>\n <span className=\"ds:truncate\">{item.linkedLabel}</span>\n </span>\n ) : null}\n {item.assigneeLabel ? (\n <span className=\"ds:inline-flex ds:min-w-0 ds:items-center ds:gap-[var(--spacing-2xs)]\">\n <User aria-hidden=\"true\" className=\"ds:size-3 ds:shrink-0\" />\n <VisuallyHidden>{`${t('taskCard.assignee')}: `}</VisuallyHidden>\n <span className=\"ds:truncate\">{item.assigneeLabel}</span>\n </span>\n ) : null}\n </div>\n ) : null}\n {item.linkedLabel && !item.linkType ? (\n <span className=\"type-eyebrow ds:text-[color:var(--muted-foreground)] ds:truncate\">\n {item.linkedLabel}\n </span>\n ) : null}\n {item.dueLabel ? (\n <span className=\"type-eyebrow ds:text-[color:var(--muted-foreground)]\">\n {item.dueLabel}\n </span>\n ) : null}\n </div>\n\n {actions ? (\n // Above the stretched-link overlay so the buttons stay clickable.\n <span className=\"ds:relative ds:z-[1] ds:flex ds:items-center ds:gap-[var(--spacing-2xs)] ds:shrink-0\">\n {actions}\n </span>\n ) : null}\n\n {interactive ? (\n <ChevronRight\n aria-hidden=\"true\"\n className=\"ds:mt-[var(--spacing-2xs)] ds:size-4 ds:shrink-0 ds:text-[color:var(--muted-foreground)] ds:opacity-0 ds:transition-opacity ds:motion-reduce:transition-none ds:group-hover:opacity-100 ds:group-focus-within:opacity-100 ds:rtl:rotate-180\"\n />\n ) : null}\n </div>\n );\n },\n);\n\nTaskCard.displayName = 'TaskCard';\n"],"names":["__iconNode","Briefcase","createLucideIcon","Building2","LINK_ICON","User","taskCardVariants","cva","stretchedLinkClass","isSafeTaskUrl","url","StatusIcon","status","priority","tone","SquareCheckBig","CircleAlert","Square","TaskCard","forwardRef","item","size","onActivate","actions","leading","className","rest","ref","t","useTranslation","interactive","hasSafeUrl","ariaLabel","linkTypeLabels","LinkIcon","hasMetaRow","titleNode","jsx","activator","e","jsxs","VisuallyHidden","ChevronRight"],"mappings":"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","x_google_ignoreList":[0,1]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tool-rail-Bq5eiFMG.js","sources":["../../src/components/tool-rail/tool-rail.agent.ts","../../src/components/tool-rail/tool-rail.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — ToolRail. */\n/* */\n/* Rail-level surface: open / close a tool's panel and read which tool */\n/* is active. State is strictly the active tool id — never any tool's */\n/* panel CONTENT (which may carry PHI). Tool ids + badge counts are */\n/* supplied by the host via props, not derived from panel bodies. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { ToolRailHandle } from './tool-rail';\n\nexport const toolRailAgent: AgentAdapter<ToolRailHandle> = {\n id: 'tool-rail',\n capabilities: ['open', 'close', 'select_single'],\n state: {\n activeToolId: {\n type: 'string | null',\n descriptionKey: 'ui.toolRail.agent.state.activeToolId',\n description:\n 'Id of the tool whose panel is currently open, or null when the rail is collapsed to its strip. No panel content is ever exposed.',\n read: (handle) => handle.getActiveToolId(),\n },\n },\n actions: {\n open: {\n // Pure ephemeral panel state (open) — no data loss, no external effect.\n safety: 'read',\n argsType: '{ id: string }',\n argsSchema: {\n type: 'object',\n properties: { id: { type: 'string' } },\n required: ['id'],\n },\n idempotent: true,\n // descriptionKey shape is intentionally pre-existing — already resolves to\n // real multi-locale translations; do not canonicalise.\n descriptionKey: 'ui.toolRail.agent.actions.open',\n description: \"Open the given tool's panel.\",\n examples: [{ args: { id: 'inbox' }, note: 'Open the inbox tool panel.' }],\n invoke: (handle, args: { id: string }) => {\n handle.open(args.id);\n },\n },\n close: {\n safety: 'read',\n idempotent: true,\n descriptionKey: 'ui.toolRail.agent.actions.close',\n description: 'Collapse the rail to its strip (no active tool).',\n invoke: (handle) => {\n handle.close();\n },\n },\n select_tool: {\n safety: 'read',\n argsType: '{ id: string | null }',\n argsSchema: {\n type: 'object',\n properties: { id: { type: ['string', 'null'] } },\n required: ['id'],\n },\n idempotent: true,\n descriptionKey: 'ui.toolRail.agent.actions.selectTool',\n description:\n 'Set the active tool by id (opens its panel), or pass null to collapse.',\n invoke: (handle, args: { id: string | null }) => {\n handle.setActiveTool(args.id);\n },\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'tool-rail',\n description: 'Marks the ToolRail wrapper.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description:\n 'Sourced from the id prop. Required to address a specific rail from the agent.',\n },\n item: {\n attr: 'data-tool-id',\n description:\n 'Stable tool id emitted on each strip IconButton. The active icon also carries data-active set to its id.',\n },\n },\n};\n","import {\n forwardRef,\n Fragment,\n useCallback,\n useEffect,\n useId,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent as ReactKeyboardEvent,\n type ReactNode,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { IconButton } from '../button/icon-button';\nimport { ScrollArea } from '../scroll-area/scroll-area';\nimport { TooltipProvider } from '../tooltip/tooltip';\nimport { useControllableState } from '../../hooks/use-controllable-state';\nimport { useEdgeResize } from '../../hooks/use-edge-resize';\nimport { useIsomorphicLayoutEffect } from '../../hooks/use-isomorphic-layout-effect';\nimport { REFLOW_ROW_CLASS, useListReflow } from '../../hooks/use-list-reflow';\nimport { useExitTransition } from '../../hooks/use-exit-transition';\nimport { useTheme } from '../../hooks/use-theme';\nimport { useAgentRegistration } from '../../agent/registry';\nimport type { AgentAdapter } from '../../agent/types';\nimport { toolRailAgent } from './tool-rail.agent';\n\n/* ------------------------------------------------------------------ */\n/* Tokenised widths */\n/* */\n/* Fixed + tokenised so the rail stays constraint-compliant — no */\n/* prop-driven inline styles. Bare `[inline-size:…]` is NOT a */\n/* recognised utility under the `ds:` prefix; it must carry the */\n/* prefix or Tailwind emits no rule. Consumers needing a different */\n/* size wrap the rail and override via CSS. */\n/* ------------------------------------------------------------------ */\nconst RAIL_WIDTH = 'ds:[inline-size:3rem]';\n// Panel width rides a consumer-overridable custom property (set\n// `--tool-rail-panel-inline-size` on the rail or a wrapper) so\n// content-heavy tools (e.g. an inbox feed) can widen their panel\n// without inline styles. Defaults to the 22rem tray-family width.\n// `--ai-tools-rail-panel-inline-size` is the deprecated alias var read\n// here as a fallback so external consumers that set the pre-rename name\n// keep working for one release; the resize hook only ever writes the new\n// `--tool-rail-panel-inline-size`.\nconst PANEL_WIDTH =\n 'ds:[inline-size:var(--tool-rail-panel-inline-size,var(--ai-tools-rail-panel-inline-size,22rem))]';\n// The custom property PANEL_WIDTH reads. The resize hook writes the\n// committed px width here (on the panel element, so it beats consumer\n// class overrides on the root) and removes it on reset.\nconst PANEL_SIZE_PROPERTY = '--tool-rail-panel-inline-size';\n// Resize clamp + nominal default, px (352px = the 22rem token default).\n// The ceiling is 880 so a form panel can reach a three-column layout:\n// pairing fields is the only way to shorten a long form without\n// shrinking a 44px target, and that needs real inline size.\nconst PANEL_MIN_SIZE = 288;\nconst PANEL_MAX_SIZE = 880;\nconst PANEL_DEFAULT_SIZE = 352;\n\n/* ------------------------------------------------------------------ */\n/* Public types */\n/* ------------------------------------------------------------------ */\n\nexport interface ToolRailTool {\n /** Stable tool id — used in `data-active`, the imperative handle, and\n * to label the open panel region. */\n id: string;\n /** Accessible name for the strip icon + tooltip, and the open panel's\n * region label. Never rendered as visible body text. */\n label: string;\n /** lucide-react glyph (rendered `aria-hidden` inside the IconButton). */\n icon: ReactNode;\n /** Panel body for this tool. Rendered inline-start of the strip when\n * `side='end'` (mirrored for `'start'`). The consumer composes it. */\n panel: ReactNode;\n /**\n * Optional non-scrolling header for this tool's panel. Rendered pinned at\n * the top of the open panel — above the scroll region — so a tool's title /\n * filters stay visible as the body scrolls. This is the rail-level home for\n * a sticky tool header; every tool gets it for free.\n */\n header?: ReactNode;\n /**\n * When true the panel body is NOT wrapped in the rail's `ScrollArea` — the\n * tool fills the (height-bounded) panel and owns its own scroll/layout.\n * Use for self-scrolling tools (e.g. `AppointmentTimeline`, whose infinite\n * scroll + today-anchoring + edge fades require it to be the scroll\n * container). Default `false` (the rail scrolls the body).\n */\n fill?: boolean;\n /** Optional unseen / notification count shown on the strip icon. */\n badgeCount?: number;\n /** When true the icon is non-interactive and skipped by roving focus. */\n disabled?: boolean;\n /**\n * Scope tier (drives the two-group divider). The two scope values render in\n * array order with a divider at the boundary between them — order the array\n * so the groups stay contiguous. A divider only appears when BOTH groups are\n * present; omit `scope` on every tool for an ungrouped strip (legacy). The\n * rail attaches no meaning beyond grouping — the host decides which value\n * leads (e.g. the Control Room pins favourites first).\n */\n scope?: 'global' | 'contextual';\n /**\n * When true this icon joins the drag-and-drop / `Alt`+Arrow reorder run.\n * The host supplies `onReorder` and owns the resulting order. Moves are\n * confined to the contiguous run of `reorderable` tools — so if EVERY tool\n * is `reorderable` the run is the whole strip and a tool can be dragged\n * across the scope divider; the host's `onReorder` decides what crossing it\n * means (e.g. the Control Room reads it as pin / unpin). Reordering never\n * changes focus roving — focus follows the moved tool to its new slot.\n */\n reorderable?: boolean;\n}\n\n/**\n * Curated imperative handle for ToolRail. Exposed as the forwardRef\n * target so a future agent / MCP UI bridge can drive the rail without\n * touching the DOM. See `tool-rail.agent.ts`.\n *\n * State surfaced here is strictly identifiers + counts — never any\n * tool's panel content (which may carry PHI).\n */\nexport interface ToolRailHandle {\n /** Currently-active tool id, or null when collapsed to strip-only. */\n getActiveToolId: () => string | null;\n /** Activate a tool by id (opens its panel), or null to collapse. */\n setActiveTool: (id: string | null) => void;\n /** Activate a tool by id (opens its panel). */\n open: (id: string) => void;\n /** Collapse to strip-only (no active tool). */\n close: () => void;\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA — `side` drives the dock edge + which shadow faces main content */\n/* ------------------------------------------------------------------ */\n\nconst railVariants = cva(\n ['ds:flex ds:shrink-0 ds:h-full', 'ds:bg-[var(--background)]'].join(' '),\n {\n variants: {\n side: {\n // Strip docks inline-end; the panel mounts inline-start of it\n // (flex-row, panel rendered first). Shadow faces the main area —\n // no border against main (the rail stays line-free; the only seam\n // is the strip↔panel divider on the open panel, see render).\n // Accessible (AAA) theme swaps the soft chrome shadow for a solid 1px\n // border on the content-facing edge (border-s for end-docked).\n end: 'ds:flex-row ds:shadow-[var(--shadow-chrome-start)] ds:[.theme-accessible_&]:border-s ds:[.theme-accessible_&]:border-[var(--border)] ds:[.theme-accessible_&]:shadow-none',\n // Strip docks inline-start; the panel mounts inline-end of it.\n start:\n 'ds:flex-row-reverse ds:shadow-[var(--shadow-chrome-end)] ds:[.theme-accessible_&]:border-e ds:[.theme-accessible_&]:border-[var(--border)] ds:[.theme-accessible_&]:shadow-none',\n },\n },\n defaultVariants: { side: 'end' },\n },\n);\n\nconst stripVariants = cva(\n [\n 'ds:flex ds:shrink-0 ds:flex-col ds:items-center',\n 'ds:pt-[var(--spacing-md)] ds:pb-[var(--spacing-md)]',\n 'ds:gap-[var(--spacing-xs)]',\n RAIL_WIDTH,\n ].join(' '),\n);\n\nconst panelVariants = cva(\n [\n 'ds:relative ds:flex ds:min-h-0 ds:flex-col ds:h-full',\n 'ds:bg-[var(--background)]',\n PANEL_WIDTH,\n // Defensive: the panel doesn't animate its width today, but if a\n // consumer adds a transition on the var, suppress it mid-drag.\n 'ds:data-[resizing]:transition-none',\n ].join(' '),\n);\n\n// Resize handle on the panel's inner edge — mirrors Resizable's Handle\n// (::before hit area to --min-target-size, hover/focus/drag accent, token\n// focus ring) but absolutely positioned over the panel edge. Like the\n// Sidebar's handle it stays TRANSPARENT at rest: the rail root's\n// `shadow-chrome-*` (which faces the main content) carries the resting seam,\n// exactly as the start-docked Sidebar leans on its own shadow — so the rail\n// never shows the constant coloured bar it used to. The strip only tints\n// accent on hover / focus / drag.\nconst panelResizeHandleVariants = cva(\n [\n 'ds:absolute ds:[inset-block:0] ds:z-[1] ds:select-none ds:touch-none',\n 'ds:[inline-size:var(--resizable-handle-size)] ds:cursor-col-resize',\n 'ds:transition-colors ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n 'ds:hover:bg-[var(--accent)] ds:focus-visible:bg-[var(--accent)] ds:data-[resizing]:bg-[var(--accent)]',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[color:var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n \"ds:before:absolute ds:before:content-['']\",\n 'ds:before:[block-size:100%]',\n 'ds:before:[inline-size:var(--min-target-size)]',\n 'ds:before:[inset-block:0]',\n 'ds:before:[inset-inline:calc(0px_-_(var(--min-target-size)_-_var(--resizable-handle-size))_/_2)]',\n ],\n {\n variants: {\n edge: {\n 'inline-start': 'ds:start-0',\n 'inline-end': 'ds:end-0',\n },\n },\n defaultVariants: { edge: 'inline-start' },\n },\n);\n\n// Hand-rolled overlay count chip — mirrors the AliaSidebar / MessageTray\n// badge markup. A <Badge> would re-introduce its own landmark/role; the\n// strip icon already carries the count in its accessible name, so this\n// span is purely decorative (`aria-hidden`).\nconst badgeVariants = cva(\n [\n 'ds:absolute ds:-top-[var(--spacing-xs)] ds:-end-[var(--spacing-xs)]',\n 'ds:inline-flex ds:items-center ds:justify-center',\n 'ds:min-w-[calc(var(--spacing-md)+var(--spacing-xs))]',\n 'ds:h-[calc(var(--spacing-md)+var(--spacing-xs))]',\n 'ds:ps-[calc(var(--spacing-xs)/1.5)] ds:pe-[calc(var(--spacing-xs)/1.5)]',\n 'ds:rounded-[var(--radius-full)]',\n 'ds:bg-[color:var(--destructive)] ds:text-[color:var(--destructive-foreground)]',\n 'ds:text-[length:var(--font-size-xs)] ds:font-semibold ds:leading-none',\n 'ds:pointer-events-none ds:select-none',\n 'ds:forced-colors:outline ds:forced-colors:outline-1 ds:forced-colors:outline-[CanvasText]',\n ].join(' '),\n);\n\n// Per-icon slot — the positioned box that hosts the IconButton, its badge and\n// the optional affordance overlay. CVA carries the drag states: the dragged\n// icon dims; a hovered drop target shows a dashed accent ring (logical offset),\n// mirroring the Sidebar's favourite-row affordance.\nconst toolSlotVariants = cva(\n // `group/rail-tool` lets an affordance overlay (e.g. a pin star) reveal on\n // hover / focus-within of the whole slot.\n ['ds:group/rail-tool ds:relative', 'ds:rounded-[var(--radius-sm)]'],\n {\n variants: {\n dragging: { true: 'ds:opacity-60', false: '' },\n dropTarget: {\n true: 'ds:outline-[length:var(--focus-ring-width)] ds:outline-dashed ds:outline-[var(--accent)] ds:outline-offset-[length:var(--focus-ring-offset)]',\n false: '',\n },\n reorderable: {\n true: 'ds:cursor-grab ds:active:cursor-grabbing',\n false: '',\n },\n },\n defaultVariants: {\n dragging: false,\n dropTarget: false,\n reorderable: false,\n },\n },\n);\n\n/* A departing tool slot fades in place; the reflow hook then slides the\n surviving icons to close the gap. Declared at rest so the transition\n has a value to animate from the moment the leaving class lands. */\nconst toolLeavingClass = 'ds:opacity-0';\nconst toolElevationClass = [\n 'ds:transition-opacity ds:duration-[var(--animation-duration)]',\n 'ds:ease-[var(--ease-out)] ds:motion-reduce:transition-none',\n].join(' ');\n\n/* ------------------------------------------------------------------ */\n/* Props */\n/* ------------------------------------------------------------------ */\n\nexport interface ToolRailProps extends VariantProps<typeof railVariants> {\n /** Stable instance id, surfaced on the root as `data-component-id`. */\n id?: string;\n /** The tools shown as icons on the strip. */\n tools: ToolRailTool[];\n /** Controlled active tool id (null = collapsed / strip-only). */\n activeToolId?: string | null;\n /** Uncontrolled initial active tool id (default null). */\n defaultActiveToolId?: string | null;\n /** Fires whenever the active tool changes (incl. → null on collapse). */\n onActiveToolChange?: (id: string | null) => void;\n /** Which edge the rail docks to. Default `'end'` (inline-end). */\n side?: 'start' | 'end';\n /** Accessible label for the toolbar strip. */\n railLabel?: string;\n /**\n * Opt-in resize affordance for the open tool panel. Renders a\n * `role=\"separator\"` drag handle on the panel's inner edge (the edge\n * facing the main content). The committed width is written to\n * `--tool-rail-panel-inline-size` on the panel element (288–880px);\n * Enter / double-click resets to the token-driven default. Default `false`.\n */\n resizablePanel?: boolean;\n /**\n * Fires when the user reorders the `reorderable` run (drag-drop or\n * `Alt`+Arrow). `from` / `to` are indices into `tools`; the host applies the\n * move to the array it passes back. Reordering is enabled when this callback\n * is supplied AND at least one tool is `reorderable`. When the whole strip is\n * reorderable, `to` may land in the other scope group — the host interprets\n * the crossing (and may treat it as a no-op, e.g. reordering within a\n * host-ordered group).\n */\n onReorder?: (from: number, to: number) => void;\n /**\n * Optional override for the polite live-region message announced after a\n * reorder. Lets the host phrase membership-aware moves (e.g. \"Pinned X to\n * favourites\") instead of the generic \"moved to position N\". Return an empty\n * string to stay silent (e.g. for a move the host treats as a no-op). When\n * omitted, the rail announces the generic run-relative position.\n */\n formatReorderAnnouncement?: (args: {\n tool: ToolRailTool;\n from: number;\n to: number;\n }) => string;\n /**\n * Optional per-icon overlay control, rendered as a sibling of each strip\n * IconButton (the same positioned box the notification badge uses). Use for\n * a small affordance such as a pin toggle — the rail attaches no meaning to\n * what it renders. Receives the tool and its index / active state.\n */\n renderToolAffordance?: (\n tool: ToolRailTool,\n context: { index: number; isActive: boolean; isRovingTarget: boolean },\n ) => ReactNode;\n /**\n * Optional non-scrolling header rendered at the top of the OPEN tool panel,\n * above its scroll region. Host-owned content (e.g. a pin / unpin control) —\n * the rail attaches no meaning. Receives the active tool.\n */\n renderPanelHeader?: (\n tool: ToolRailTool,\n context: { isActive: boolean },\n ) => ReactNode;\n /**\n * Identity override for the root's `data-component` attribute. Defaults to\n * `'tool-rail'`. A product wrapper (e.g. ControlRoomRail) passes its own\n * kebab id so the DOM / cascade boundary — and an agent's `domHooks.root` —\n * can tell its surface apart from a bare ToolRail, without the engine ever\n * importing the wrapper.\n */\n dataComponent?: string;\n /**\n * Agent adapter registered for this rail instance. Defaults to\n * `toolRailAgent`. A wrapper passes its own adapter (matching\n * `dataComponent`) so the rail registers under the wrapper's identity. The\n * instance id is sourced from the `id` prop (also stamped as\n * `data-component-id`).\n */\n agentAdapter?: AgentAdapter<ToolRailHandle>;\n className?: string;\n}\n\n/* ------------------------------------------------------------------ */\n/* Helpers */\n/* ------------------------------------------------------------------ */\n\nfunction formatBadgeCount(count: number, overflowLabel: string): string {\n return count > 99 ? overflowLabel : String(count);\n}\n\n/* ------------------------------------------------------------------ */\n/* Root */\n/* ------------------------------------------------------------------ */\n\nexport const ToolRail = forwardRef<ToolRailHandle, ToolRailProps>(\n (\n {\n id,\n tools,\n activeToolId,\n defaultActiveToolId = null,\n onActiveToolChange,\n side = 'end',\n railLabel,\n resizablePanel = false,\n onReorder,\n formatReorderAnnouncement,\n renderToolAffordance,\n renderPanelHeader,\n dataComponent = 'tool-rail',\n agentAdapter = toolRailAgent,\n className,\n },\n ref,\n ) => {\n const { t } = useTranslation();\n\n // Controlled / uncontrolled bridge — the same hook MessageTray uses.\n const [activeRaw, setActiveRaw] = useControllableState<string | null>({\n value: activeToolId,\n defaultValue: defaultActiveToolId,\n onChange: onActiveToolChange,\n });\n const activeId = activeRaw ?? null;\n\n // Roving-tabindex bookkeeping for the vertical toolbar strip.\n const buttonsRef = useRef<Array<HTMLButtonElement | null>>([]);\n const panelRef = useRef<HTMLElement | null>(null);\n const [focusIndex, setFocusIndex] = useState(0);\n // Distinguishes keyboard activation (auto-focus into the panel) from\n // pointer activation (focus stays on the icon — less jarring).\n const activatedByKeyboardRef = useRef(false);\n // Set on Enter/Space keydown, read by the click handler that follows,\n // cleared on keyup — so a subsequent mouse click never inherits it.\n const keyboardActivateRef = useRef(false);\n\n const activeIndex = useMemo(\n () => tools.findIndex((tl) => tl.id === activeId),\n [tools, activeId],\n );\n const activeTool = activeIndex >= 0 ? tools[activeIndex] : null;\n\n // First non-disabled index — the resting roving stop when none active.\n const firstEnabledIndex = useMemo(\n () => tools.findIndex((tl) => !tl.disabled),\n [tools],\n );\n\n // Scope grouping: a divider marks the boundary between the two scope groups,\n // whichever order they appear in. The array is always grouped (all of one\n // scope, then the other); the divider precedes the first tool whose scope\n // differs from the lead tool's. `boundary > 0` guarantees both groups are\n // present. Render-only (not a `tools[]` member) so roving focus is untouched;\n // a legacy strip with no `scope` set stays ungrouped.\n const scopeDividerIndex = useMemo(() => {\n const lead = tools[0]?.scope;\n if (!lead) return -1;\n return tools.findIndex((tl) => tl.scope && tl.scope !== lead);\n }, [tools]);\n const showScopeDivider = scopeDividerIndex > 0;\n\n /* ---- Reorder (drag-and-drop + Alt+Arrow keyboard) ------------- */\n // The contiguous run of `reorderable` tools — a tool only moves within it.\n const reorderRun = useMemo(() => {\n const first = tools.findIndex((tl) => tl.reorderable);\n if (first < 0) return null;\n let last = first;\n while (last + 1 < tools.length && tools[last + 1]?.reorderable) last += 1;\n return { first, last };\n }, [tools]);\n const reorderEnabled = !!onReorder && reorderRun !== null;\n const reorderInstructionsId = useId();\n\n const [dragIndex, setDragIndex] = useState<number | null>(null);\n const [dropIndex, setDropIndex] = useState<number | null>(null);\n\n /* ---- Strip enter / exit / reflow animations ------------------ */\n /* The same hooks the note/task panels use, applied to the icon strip:\n when a contextual tool appears or disappears (e.g. selecting an\n appointment adds Notes + Details), surviving icons slide to their\n new positions and departing icons fade out in place. */\n const { resolvedTheme } = useTheme();\n const reduceMotion = resolvedTheme.endsWith('-accessible') || undefined;\n\n const { containerRef: reflowRef } = useListReflow<HTMLDivElement>({\n key: tools.map((tl) => tl.id).join(),\n reduceMotion,\n });\n\n const exit = useExitTransition({ reduceMotion });\n\n // Tools that were in the previous render but are gone now, kept around\n // until their exit fade completes. Rendered after the current tools\n // WITHOUT `data-reflow-id` so the reflow hook ignores them — they fade\n // out at the bottom of the strip while the surviving icons reflow.\n const [leavingTools, setLeavingTools] = useState<ToolRailTool[]>([]);\n const prevToolsRef = useRef<ToolRailTool[]>(tools);\n useEffect(() => {\n const prev = prevToolsRef.current;\n const currentIds = new Set(tools.map((tl) => tl.id));\n const removed = prev.filter((tl) => !currentIds.has(tl.id));\n if (removed.length > 0) {\n setLeavingTools((existing) => {\n const existingIds = new Set(existing.map((tl) => tl.id));\n return [\n ...existing,\n ...removed.filter((tl) => !existingIds.has(tl.id)),\n ];\n });\n for (const tl of removed) {\n exit.leave(tl.id, () => {\n setLeavingTools((existing) =>\n existing.filter((item) => item.id !== tl.id),\n );\n });\n }\n }\n prevToolsRef.current = tools;\n }, [tools, exit]);\n\n // sr-only announcement. The zero-width-space toggle forces a re-announce of\n // an identical message (e.g. moving the same item twice) — same technique\n // the Sidebar uses for its reorder live region.\n const [reorderMessage, setReorderMessage] = useState('');\n const announceToggle = useRef(false);\n const commitReorder = useCallback(\n (from: number, to: number) => {\n if (!onReorder || !reorderRun) return;\n const clamped = Math.max(\n reorderRun.first,\n Math.min(reorderRun.last, to),\n );\n if (clamped === from) return;\n onReorder(from, clamped);\n const moved = tools[from];\n if (moved) {\n // The host can phrase membership-aware moves (e.g. pin / unpin) and\n // can return '' to stay silent for a move it treats as a no-op.\n const text = formatReorderAnnouncement\n ? formatReorderAnnouncement({ tool: moved, from, to: clamped })\n : t('toolRail.reorderAnnounce', {\n tool: moved.label,\n to: clamped - reorderRun.first + 1,\n total: reorderRun.last - reorderRun.first + 1,\n defaultValue: '{{tool}} moved to position {{to}} of {{total}}',\n });\n if (text) {\n announceToggle.current = !announceToggle.current;\n setReorderMessage(announceToggle.current ? text : `${text}\\u200b`);\n }\n }\n },\n [onReorder, reorderRun, tools, t, formatReorderAnnouncement],\n );\n\n // The roving tab stop: the active icon when a tool is open, else the\n // index the user last focused, else the first enabled icon.\n const rovingIndex =\n activeIndex >= 0\n ? activeIndex\n : focusIndex >= 0 && !tools[focusIndex]?.disabled\n ? focusIndex\n : firstEnabledIndex;\n\n const selectTool = useCallback(\n (toolId: string, fromKeyboard: boolean) => {\n const tool = tools.find((tl) => tl.id === toolId);\n if (!tool || tool.disabled) return;\n activatedByKeyboardRef.current = fromKeyboard;\n // Clicking / activating the active tool collapses to strip-only.\n setActiveRaw(activeId === toolId ? null : toolId);\n },\n [tools, activeId, setActiveRaw],\n );\n\n /* ---- Roving arrow-key navigation (vertical toolbar) ----------- */\n const handleStripKeyDown = useCallback(\n (event: ReactKeyboardEvent<HTMLDivElement>) => {\n const count = tools.length;\n if (count === 0) return;\n // Alt+Arrow is reserved for reordering (handled on the icon); never\n // let it move focus roving as well.\n if (event.altKey) return;\n\n let next: number | null = null;\n if (event.key === 'ArrowDown') next = (rovingIndex + 1) % count;\n else if (event.key === 'ArrowUp')\n next = (rovingIndex - 1 + count) % count;\n else if (event.key === 'Home') next = 0;\n else if (event.key === 'End') next = count - 1;\n if (next === null) return;\n\n // Skip disabled icons in the travel direction.\n const goingBack = event.key === 'ArrowUp' || event.key === 'End';\n let candidate = next;\n let attempts = 0;\n while (attempts < count && tools[candidate]?.disabled) {\n candidate = goingBack\n ? (candidate - 1 + count) % count\n : (candidate + 1) % count;\n attempts += 1;\n }\n if (tools[candidate]?.disabled) return;\n\n event.preventDefault();\n setFocusIndex(candidate);\n buttonsRef.current[candidate]?.focus();\n },\n [tools, rovingIndex],\n );\n\n /* ---- Esc collapses + returns focus to the active tool's icon -- */\n // Attached imperatively via the root ref (not a JSX onKeyDown on the\n // static container) so the Escape shortcut works from anywhere inside the\n // open panel without an interaction handler on a non-interactive element.\n const rootRef = useRef<HTMLDivElement>(null);\n useEffect(() => {\n const node = rootRef.current;\n if (!node) return undefined;\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key !== 'Escape') return;\n if (activeIndex < 0) return;\n event.preventDefault();\n const returnIndex = activeIndex;\n setActiveRaw(null);\n setFocusIndex(returnIndex);\n // Defer until after the panel unmounts so focus lands cleanly.\n requestAnimationFrame(() => {\n buttonsRef.current[returnIndex]?.focus();\n });\n };\n node.addEventListener('keydown', onKeyDown);\n return () => node.removeEventListener('keydown', onKeyDown);\n }, [activeIndex, setActiveRaw]);\n\n /* ---- Move focus into the panel when opened by keyboard -------- */\n useIsomorphicLayoutEffect(() => {\n if (activeTool && activatedByKeyboardRef.current) {\n panelRef.current?.focus();\n }\n activatedByKeyboardRef.current = false;\n }, [activeTool]);\n\n /* ---- Opt-in panel resize (inner edge) -------------------------- */\n // The handle sits on the edge facing the main content: the panel's\n // inline-start edge for an end-docked rail, inline-end for start.\n const panelEdge = side === 'end' ? 'inline-start' : 'inline-end';\n const { separatorProps, isResizing, isResized } = useEdgeResize({\n edge: panelEdge,\n targetRef: panelRef,\n cssProperty: PANEL_SIZE_PROPERTY,\n minSize: PANEL_MIN_SIZE,\n maxSize: PANEL_MAX_SIZE,\n defaultSize: PANEL_DEFAULT_SIZE,\n disabled: !resizablePanel,\n });\n\n // The aside unmounts on collapse, dropping the hook's inline override.\n // Re-assert the committed width when a panel (re)mounts so a reopened\n // panel keeps the user's chosen size.\n const committedPanelWidth = separatorProps['aria-valuenow'];\n useIsomorphicLayoutEffect(() => {\n if (!resizablePanel || !isResized || !activeTool) return;\n panelRef.current?.style.setProperty(\n PANEL_SIZE_PROPERTY,\n `${committedPanelWidth}px`,\n );\n }, [activeTool, resizablePanel, isResized, committedPanelWidth]);\n\n /* ---- Curated imperative handle for agent integration ---------- */\n const activeIdRef = useRef<string | null>(activeId);\n activeIdRef.current = activeId;\n\n const handle = useMemo<ToolRailHandle>(\n () => ({\n getActiveToolId: () => activeIdRef.current,\n setActiveTool: (toolId) => {\n activatedByKeyboardRef.current = false;\n setActiveRaw(toolId);\n },\n open: (toolId) => {\n const tool = tools.find((tl) => tl.id === toolId);\n if (!tool || tool.disabled) return;\n activatedByKeyboardRef.current = false;\n setActiveRaw(toolId);\n },\n close: () => {\n const returnId = activeIdRef.current;\n activatedByKeyboardRef.current = false;\n setActiveRaw(null);\n // Return focus to the closed tool's strip icon (mirrors Escape) so a\n // close-button / pointer collapse never drops focus to <body>.\n if (returnId != null) {\n requestAnimationFrame(() => {\n rootRef.current\n ?.querySelector<HTMLButtonElement>(\n `[data-tool-id=\"${CSS.escape(returnId)}\"]`,\n )\n ?.focus();\n });\n }\n },\n }),\n [tools, setActiveRaw],\n );\n\n useImperativeHandle(ref, () => handle, [handle]);\n useAgentRegistration(agentAdapter, handle, id);\n\n const overflowLabel = t('toolRail.badgeCountOverflow', {\n defaultValue: '99+',\n });\n\n return (\n <div\n ref={rootRef}\n data-component={dataComponent}\n data-component-id={id}\n data-side={side}\n className={[railVariants({ side }), className]\n .filter(Boolean)\n .join(' ')}\n >\n {/* Reorder a11y: a polite live region announcing each move. Each\n reorderable icon carries its own keyboard instruction (rendered in\n its slot, referenced via aria-describedby). */}\n {reorderEnabled ? (\n <span role=\"status\" aria-live=\"polite\" className=\"ds:sr-only\">\n {reorderMessage}\n </span>\n ) : null}\n {/* The OPEN panel is the single complementary landmark, named by\n the active tool. Rendered only while a tool is active so two\n unnamed regions never coexist. */}\n {activeTool ? (\n <aside\n ref={panelRef}\n tabIndex={-1}\n aria-label={t('toolRail.panelLabel', {\n tool: activeTool.label,\n defaultValue: '{{tool}} panel',\n })}\n data-tool-rail-state=\"expanded\"\n data-active-tool={activeTool.id}\n data-resizing={isResizing ? '' : undefined}\n className={[\n panelVariants(),\n // Subtle shadow — not a line — separating the panel from the\n // icon strip (the tab row). The panel casts a soft chrome\n // shadow toward the strip on its strip-facing edge. `z-[1]`\n // lifts it above the adjacent strip (the panel is already\n // `relative`) so the shadow paints at the seam instead of being\n // covered by the strip's opaque background. Only renders while\n // the panel is open (the aside is unmounted when collapsed), so\n // it never doubles as a rail↔main seam. In the accessible (AAA)\n // theme the soft shadow becomes a solid 1px border on that same\n // strip-facing edge.\n 'ds:z-[1]',\n side === 'end'\n ? 'ds:shadow-[var(--shadow-chrome-end)] ds:[.theme-accessible_&]:border-e ds:[.theme-accessible_&]:border-[var(--border)] ds:[.theme-accessible_&]:shadow-none'\n : 'ds:shadow-[var(--shadow-chrome-start)] ds:[.theme-accessible_&]:border-s ds:[.theme-accessible_&]:border-[var(--border)] ds:[.theme-accessible_&]:shadow-none',\n 'ds:focus-visible:outline-none',\n ].join(' ')}\n >\n {/* Optional host-owned, non-scrolling panel header (e.g. the\n Control Room's add / remove favourite control). Sits above the\n scroll region so it stays put as the panel body scrolls. */}\n {renderPanelHeader\n ? renderPanelHeader(activeTool, { isActive: true })\n : null}\n {/* Optional per-tool pinned header — the rail-level home for a\n sticky tool header (title / filters). Non-scrolling, above the\n body, so it stays visible for every tool. */}\n {activeTool.header ? (\n <div className=\"ds:shrink-0\">{activeTool.header}</div>\n ) : null}\n {/* Body: a self-scrolling `fill` tool owns its own scroll inside\n the height-bounded panel; otherwise the rail scrolls it. */}\n {activeTool.fill ? (\n // data-tool-fill: a self-scrolling panel owns its own native\n // scroll (it can't use the rail's ScrollArea), so a token rule\n // paints its scrollbar to match the 8px overlay. See tokens/index.css.\n <div data-tool-fill=\"\" className=\"ds:flex-1 ds:min-h-0\">\n {activeTool.panel}\n </div>\n ) : (\n <ScrollArea\n orientation=\"vertical\"\n className=\"ds:flex-1 ds:min-h-0\"\n >\n {activeTool.panel}\n </ScrollArea>\n )}\n {/* Inside the aside (so it belongs to the complementary\n landmark) and outside the toolbar strip — the strip's\n roving handlers never see its key events, and Escape\n still bubbles to the root to collapse, as everywhere\n else in the panel. No stopPropagation needed. */}\n {resizablePanel ? (\n <div\n {...separatorProps}\n aria-label={t('toolRail.resizePanel', {\n defaultValue: 'Resize tool panel',\n })}\n data-resizing={isResizing ? '' : undefined}\n className={panelResizeHandleVariants({ edge: panelEdge })}\n />\n ) : null}\n </aside>\n ) : null}\n\n {/* The 3rem icon strip — a vertical toolbar with roving tabindex.\n Self-contained TooltipProvider so consumers needn't mount one;\n Radix providers compose, so a host-level provider still works. */}\n <TooltipProvider>\n <div\n ref={reflowRef}\n role=\"toolbar\"\n aria-orientation=\"vertical\"\n aria-label={\n railLabel ?? t('toolRail.railLabel', { defaultValue: 'Tools' })\n }\n className={stripVariants()}\n onKeyDown={handleStripKeyDown}\n >\n {tools.map((tool, index) => {\n const isActive = tool.id === activeId;\n const showBadge =\n typeof tool.badgeCount === 'number' && tool.badgeCount > 0;\n // Fold the count into the accessible name so SR users hear it\n // without relying on the decorative chip.\n const accessibleName = showBadge\n ? t('toolRail.toolWithCount', {\n tool: tool.label,\n count: tool.badgeCount,\n defaultValue: '{{tool}}, {{count}} updates',\n })\n : tool.label;\n const canReorderTool =\n reorderEnabled && !!tool.reorderable && !tool.disabled;\n const reorderDescId = canReorderTool\n ? `${reorderInstructionsId}-${tool.id}`\n : undefined;\n return (\n <Fragment key={tool.id}>\n {showScopeDivider && index === scopeDividerIndex ? (\n <div\n role=\"separator\"\n aria-orientation=\"horizontal\"\n className=\"ds:my-[var(--spacing-2xs)] ds:h-px ds:w-[var(--spacing-lg)] ds:shrink-0 ds:bg-[var(--border)] ds:forced-colors:bg-[CanvasText]\"\n />\n ) : null}\n <div\n className={[\n toolSlotVariants({\n dragging: dragIndex === index,\n dropTarget: dropIndex === index && dragIndex !== index,\n reorderable: canReorderTool,\n }),\n toolElevationClass,\n REFLOW_ROW_CLASS,\n ]\n .filter(Boolean)\n .join(' ')}\n data-reflow-id={tool.id}\n data-dragging={dragIndex === index ? '' : undefined}\n // Drag the whole slot — the icon button is an unreliable\n // HTML5 drag source across browsers. The button keeps its\n // click + Alt+Arrow keyboard reorder; drag is pointer-only.\n draggable={canReorderTool || undefined}\n onDragStart={\n canReorderTool\n ? (event) => {\n setDragIndex(index);\n event.dataTransfer.effectAllowed = 'move';\n // Firefox needs data set to initiate a drag.\n event.dataTransfer.setData(\n 'text/plain',\n String(index),\n );\n }\n : undefined\n }\n onDragOver={\n canReorderTool\n ? (event) => {\n if (dragIndex === null) return;\n event.preventDefault();\n event.dataTransfer.dropEffect = 'move';\n if (dropIndex !== index) setDropIndex(index);\n }\n : undefined\n }\n onDragLeave={\n canReorderTool\n ? () =>\n setDropIndex((cur) => (cur === index ? null : cur))\n : undefined\n }\n onDrop={\n canReorderTool\n ? (event) => {\n event.preventDefault();\n const from = dragIndex;\n setDropIndex(null);\n setDragIndex(null);\n if (from === null || from === index) return;\n commitReorder(from, index);\n }\n : undefined\n }\n onDragEnd={\n canReorderTool\n ? () => {\n setDragIndex(null);\n setDropIndex(null);\n }\n : undefined\n }\n >\n <IconButton\n ref={(el) => {\n buttonsRef.current[index] = el;\n }}\n icon={tool.icon}\n tooltip={tool.label}\n aria-label={accessibleName}\n intent=\"ghost\"\n size=\"sm\"\n disabled={tool.disabled}\n aria-pressed={isActive}\n aria-expanded={isActive}\n data-active={isActive ? tool.id : undefined}\n data-tool-id={tool.id}\n aria-describedby={reorderDescId}\n aria-keyshortcuts={\n canReorderTool ? 'Alt+ArrowUp Alt+ArrowDown' : undefined\n }\n tabIndex={index === rovingIndex ? 0 : -1}\n onFocus={() => {\n if (!tool.disabled) setFocusIndex(index);\n }}\n onClick={() =>\n selectTool(tool.id, keyboardActivateRef.current)\n }\n onKeyDown={(event) => {\n // Enter/Space activate via the native button's click,\n // which fires AFTER this keydown. Flag the upcoming\n // click as keyboard-driven so focus moves into the\n // panel; reset on keyup so a later mouse click doesn't\n // inherit the flag.\n if (event.key === 'Enter' || event.key === ' ') {\n keyboardActivateRef.current = true;\n return;\n }\n // Alt+Arrow / Alt+Home / Alt+End reorder within the run.\n // Focus follows the moved icon to its new index; roving\n // ignores Alt (see handleStripKeyDown).\n if (canReorderTool && event.altKey && reorderRun) {\n let target: number | null = null;\n if (event.key === 'ArrowUp') target = index - 1;\n else if (event.key === 'ArrowDown')\n target = index + 1;\n else if (event.key === 'Home')\n target = reorderRun.first;\n else if (event.key === 'End')\n target = reorderRun.last;\n if (target !== null) {\n event.preventDefault();\n const dest = Math.max(\n reorderRun.first,\n Math.min(reorderRun.last, target),\n );\n // Focus follows the moved TOOL (by id), not the\n // slot index — so it lands correctly however the\n // host reinterprets the move (reorder, cross-group\n // pin / unpin, or a no-op that leaves it in place).\n const movedId = tool.id;\n commitReorder(index, dest);\n requestAnimationFrame(() => {\n rootRef.current\n ?.querySelector<HTMLButtonElement>(\n `[data-tool-id=\"${CSS.escape(movedId)}\"]`,\n )\n ?.focus();\n });\n }\n }\n }}\n onKeyUp={(event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n keyboardActivateRef.current = false;\n }\n }}\n />\n {showBadge ? (\n <span aria-hidden=\"true\" className={badgeVariants()}>\n {formatBadgeCount(\n tool.badgeCount as number,\n overflowLabel,\n )}\n </span>\n ) : null}\n {renderToolAffordance?.(tool, {\n index,\n isActive,\n isRovingTarget: index === rovingIndex,\n })}\n {reorderDescId ? (\n <span id={reorderDescId} className=\"ds:sr-only\">\n {t('toolRail.reorderInstructions', {\n tool: tool.label,\n defaultValue:\n 'Reorder {{tool}}. Press Alt + Up or Alt + Down to move.',\n })}\n </span>\n ) : null}\n </div>\n </Fragment>\n );\n })}\n {/* Departing tools: rendered without `data-reflow-id` so the\n reflow hook ignores them. They fade out here while the\n surviving icons above reflow to their new positions. */}\n {leavingTools.map((tool) =>\n exit.isLeaving(tool.id) ? (\n <div\n key={tool.id}\n className={[\n toolSlotVariants({\n dragging: false,\n dropTarget: false,\n reorderable: false,\n }),\n toolElevationClass,\n toolLeavingClass,\n ]\n .filter(Boolean)\n .join(' ')}\n aria-hidden=\"true\"\n >\n <IconButton\n icon={tool.icon}\n intent=\"ghost\"\n size=\"sm\"\n disabled\n tabIndex={-1}\n />\n </div>\n ) : null,\n )}\n </div>\n </TooltipProvider>\n </div>\n );\n },\n);\n\nToolRail.displayName = 'ToolRail';\n"],"names":["toolRailAgent","handle","args","RAIL_WIDTH","PANEL_WIDTH","PANEL_SIZE_PROPERTY","PANEL_MIN_SIZE","PANEL_MAX_SIZE","PANEL_DEFAULT_SIZE","railVariants","cva","stripVariants","panelVariants","panelResizeHandleVariants","badgeVariants","toolSlotVariants","toolLeavingClass","toolElevationClass","formatBadgeCount","count","overflowLabel","ToolRail","forwardRef","id","tools","activeToolId","defaultActiveToolId","onActiveToolChange","side","railLabel","resizablePanel","onReorder","formatReorderAnnouncement","renderToolAffordance","renderPanelHeader","dataComponent","agentAdapter","className","ref","t","useTranslation","activeRaw","setActiveRaw","useControllableState","activeId","buttonsRef","useRef","panelRef","focusIndex","setFocusIndex","useState","activatedByKeyboardRef","keyboardActivateRef","activeIndex","useMemo","tl","activeTool","firstEnabledIndex","scopeDividerIndex","lead","_a","showScopeDivider","reorderRun","first","last","reorderEnabled","reorderInstructionsId","useId","dragIndex","setDragIndex","dropIndex","setDropIndex","resolvedTheme","useTheme","reduceMotion","reflowRef","useListReflow","exit","useExitTransition","leavingTools","setLeavingTools","prevToolsRef","useEffect","prev","currentIds","removed","existing","existingIds","item","reorderMessage","setReorderMessage","announceToggle","commitReorder","useCallback","from","to","clamped","moved","text","rovingIndex","selectTool","toolId","fromKeyboard","tool","handleStripKeyDown","event","next","goingBack","candidate","attempts","_b","_c","rootRef","node","onKeyDown","returnIndex","useIsomorphicLayoutEffect","panelEdge","separatorProps","isResizing","isResized","useEdgeResize","committedPanelWidth","activeIdRef","returnId","useImperativeHandle","useAgentRegistration","jsxs","jsx","ScrollArea","TooltipProvider","index","isActive","showBadge","accessibleName","canReorderTool","reorderDescId","Fragment","REFLOW_ROW_CLASS","cur","IconButton","el","target","dest","movedId"],"mappings":"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"}
|