@alfadocs/ui-kit-debug 1.36.1 → 1.38.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/{agenda-tray-DYGCTIWB.js → agenda-tray-CG6jUjKc.js} +2 -2
- package/dist/_chunks/{agenda-tray-DYGCTIWB.js.map → agenda-tray-CG6jUjKc.js.map} +1 -1
- package/dist/_chunks/{anamnesis-summary-card-GYHa7VGp.js → anamnesis-summary-card-CclBbiXg.js} +2 -2
- package/dist/_chunks/{anamnesis-summary-card-GYHa7VGp.js.map → anamnesis-summary-card-CclBbiXg.js.map} +1 -1
- 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/{appointment-timeline-ByfovxqR.js → appointment-timeline-D-rNwKpS.js} +2 -2
- package/dist/_chunks/{appointment-timeline-ByfovxqR.js.map → appointment-timeline-D-rNwKpS.js.map} +1 -1
- package/dist/_chunks/{appointment-tray-D6UyJHej.js → appointment-tray-CK2CULg_.js} +2 -2
- package/dist/_chunks/{appointment-tray-D6UyJHej.js.map → appointment-tray-CK2CULg_.js.map} +1 -1
- package/dist/_chunks/{balance-badge-cell-B0Z8Dwn8.js → balance-badge-cell-DHs5p0bA.js} +2 -2
- package/dist/_chunks/{balance-badge-cell-B0Z8Dwn8.js.map → balance-badge-cell-DHs5p0bA.js.map} +1 -1
- package/dist/_chunks/{booking-Dp-9qR6F.js → booking-x3J7sS2G.js} +3 -3
- package/dist/_chunks/{booking-Dp-9qR6F.js.map → booking-x3J7sS2G.js.map} +1 -1
- package/dist/_chunks/building-2-D33bLCWL.js +24 -0
- package/dist/_chunks/building-2-D33bLCWL.js.map +1 -0
- package/dist/_chunks/calendar-workspace-Cc1LRVWY.js +9900 -0
- package/dist/_chunks/calendar-workspace-Cc1LRVWY.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/{data-table-BYGK-gUJ.js → data-table-Dy1lyumT.js} +2 -2
- package/dist/_chunks/{data-table-BYGK-gUJ.js.map → data-table-Dy1lyumT.js.map} +1 -1
- package/dist/_chunks/editable-description-7ptNpJEg.js +142 -0
- package/dist/_chunks/editable-description-7ptNpJEg.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/{file-manager-DvkFgj7d.js → file-manager-UlcYQv8n.js} +3 -3
- package/dist/_chunks/{file-manager-DvkFgj7d.js.map → file-manager-UlcYQv8n.js.map} +1 -1
- package/dist/_chunks/{message-tray-BcLyaO-G.js → message-tray-CXjVsKqp.js} +2 -2
- package/dist/_chunks/{message-tray-BcLyaO-G.js.map → message-tray-CXjVsKqp.js.map} +1 -1
- 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/{note-timeline-CXfSV3yX.js → note-timeline-D2oPuQP6.js} +134 -73
- package/dist/_chunks/note-timeline-D2oPuQP6.js.map +1 -0
- package/dist/_chunks/notes-panel-CkbfDDzj.js +614 -0
- package/dist/_chunks/notes-panel-CkbfDDzj.js.map +1 -0
- package/dist/_chunks/{notification-tray-CJ8jOe-U.js → notification-tray-_NoChRKi.js} +2 -2
- package/dist/_chunks/{notification-tray-CJ8jOe-U.js.map → notification-tray-_NoChRKi.js.map} +1 -1
- 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-B131Q7Bp.js} +3 -3
- package/dist/_chunks/{patient-summary-card-Bz7KdUin.js.map → patient-summary-card-B131Q7Bp.js.map} +1 -1
- package/dist/_chunks/{practice-results-DOcORTkP.js → practice-results-CBNRJNnY.js} +2 -2
- package/dist/_chunks/{practice-results-DOcORTkP.js.map → practice-results-CBNRJNnY.js.map} +1 -1
- package/dist/_chunks/{product-hub-panel-C0TO69P7.js → product-hub-panel-C3bMjscm.js} +2 -2
- package/dist/_chunks/{product-hub-panel-C0TO69P7.js.map → product-hub-panel-C3bMjscm.js.map} +1 -1
- package/dist/_chunks/{reviews-panel-BaHZb_ai.js → reviews-panel-Cy969x7q.js} +2 -2
- package/dist/_chunks/{reviews-panel-BaHZb_ai.js.map → reviews-panel-Cy969x7q.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/{signature-request-Dej2g86d.js → signature-request-b-86AGlT.js} +2 -2
- package/dist/_chunks/{signature-request-Dej2g86d.js.map → signature-request-b-86AGlT.js.map} +1 -1
- package/dist/_chunks/{skeleton-CZbwyJAA.js → skeleton-B1KTdJ4N.js} +46 -33
- package/dist/_chunks/skeleton-B1KTdJ4N.js.map +1 -0
- package/dist/_chunks/{slot-grid-8Ko6thzz.js → slot-grid-Bk3GZL1p.js} +2 -2
- package/dist/_chunks/{slot-grid-8Ko6thzz.js.map → slot-grid-Bk3GZL1p.js.map} +1 -1
- 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-5co9Jr2L.js} +3 -3
- package/dist/_chunks/{task-tray-wl9eti6J.js.map → task-tray-5co9Jr2L.js.map} +1 -1
- package/dist/_chunks/{tasks-panel-BDNB7hsZ.js → tasks-panel-BpH-x7U3.js} +3 -3
- package/dist/_chunks/{tasks-panel-BDNB7hsZ.js.map → tasks-panel-BpH-x7U3.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-dUm99mdn.js +160 -0
- package/dist/_chunks/treatment-receipt-dUm99mdn.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/agenda-tray/index.js +1 -1
- package/dist/components/anamnesis-summary-card/index.js +1 -1
- package/dist/components/appointment-card/index.js +1 -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/appointment-timeline/index.js +1 -1
- package/dist/components/booking/index.js +1 -1
- package/dist/components/control-room-rail/index.js +1 -1
- package/dist/components/data-table/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 +26 -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/file-manager/index.js +1 -1
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/message-tray/index.js +1 -1
- package/dist/components/money/index.js +2 -1
- package/dist/components/money/index.js.map +1 -1
- package/dist/components/note-timeline/index.js +1 -1
- package/dist/components/note-timeline/note-timeline.d.ts +8 -0
- package/dist/components/note-timeline/note-timeline.d.ts.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/notification-tray/index.js +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/patient-table/index.js +1 -1
- package/dist/components/practice-results/index.js +1 -1
- package/dist/components/product-hub-tray/index.js +1 -1
- package/dist/components/reviews-panel/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/skeleton/index.d.ts +1 -1
- package/dist/components/skeleton/index.d.ts.map +1 -1
- package/dist/components/skeleton/index.js +3 -2
- package/dist/components/skeleton/skeleton.d.ts +12 -0
- package/dist/components/skeleton/skeleton.d.ts.map +1 -1
- package/dist/components/slot-grid/index.js +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 +38 -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 +959 -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 +16 -7
- 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-editor-hydration.d.ts +0 -2
- package/dist/patterns/calendar/calendar-editor-hydration.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/patterns/signature-request/index.js +1 -1
- package/dist/tokens.css +1 -1
- package/package.json +17 -1
- package/dist/_chunks/calendar-workspace-BYwQK7fz.js +0 -9478
- package/dist/_chunks/calendar-workspace-BYwQK7fz.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/note-timeline-CXfSV3yX.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/skeleton-CZbwyJAA.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":"notes-panel-Co8D3uDd.js","sources":["../../src/components/_shared/get-error-message.ts","../../src/components/notes-panel/notes-panel.agent.ts","../../src/components/notes-panel/notes-panel.tsx"],"sourcesContent":["/** Read host error messages without relying on the host's JavaScript realm. */\nexport function getErrorMessage(error: unknown, fallback: string): string {\n if (\n typeof error === 'object' &&\n error !== null &&\n 'message' in error &&\n typeof error.message === 'string' &&\n error.message.trim()\n ) {\n return error.message;\n }\n return fallback;\n}\n","/* -------------------------------------------------------------------- */\n/* Agent adapter — NotesPanel. */\n/* */\n/* The Notes tool: a composer over a note timeline. The agent reads the */\n/* timeline STRUCTURE (note ids + pinned / flagged / clinical flags — */\n/* never the note body or author, both PHI), composes and commits a new */\n/* note, and toggles a note's pinned / flagged state. `add_note` carries */\n/* the `phi` safety class: a note body is patient-identifiable clinical */\n/* content, so the host gates it behind the same confirm-before-act as a */\n/* destructive write and never auto-confirms. A clinical submission also */\n/* requires the host's `practice_add_clinical_note` permission (the */\n/* handle drops it when the gate is closed). Host-owned per-note */\n/* `noteActions` (edit, delete…) sit outside this handle — an agent */\n/* reaches them through the host's own adapters. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { NotesPanelHandle } from './notes-panel';\n\nexport const notesPanelAgent: AgentAdapter<NotesPanelHandle> = {\n id: 'notes-panel',\n // 'submit' backs add_note (compose + commit a note). pin / flag are toggles\n // with no dedicated capability in the closed vocabulary.\n capabilities: ['submit'],\n state: {\n notes: {\n type: 'Array<{ id?: string; pinned: boolean; flagged: boolean; clinical: boolean }>',\n descriptionKey: 'ui.agent.notesPanel.state.notes',\n description:\n 'Timeline note ids + pinned / flagged / clinical flags. Never the note body or author (both PHI).',\n read: (handle) => handle.getNotes(),\n },\n canAddClinical: {\n type: 'boolean',\n descriptionKey: 'ui.agent.notesPanel.state.canAddClinical',\n description:\n 'Whether the current user may write clinical notes (the practice_add_clinical_note permission gate).',\n read: (handle) => handle.canAddClinical(),\n },\n currentNoteId: {\n type: 'string | null',\n descriptionKey: 'ui.agent.notesPanel.state.currentNoteId',\n description:\n 'Id of the note the host has addressed — the one marked, scrolled to and focused. Null when none is. An id only, never note content.',\n read: (handle) => handle.getCurrentNoteId(),\n },\n },\n actions: {\n add_note: {\n // Writes a clinical/admin note body — patient-identifiable content. PHI.\n safety: 'phi',\n argsType: '{ content: string; clinical: boolean }',\n argsSchema: {\n type: 'object',\n properties: {\n content: {\n type: 'string',\n description:\n 'Note body. Rich HTML for the rich composer, else plain text.',\n },\n clinical: {\n type: 'boolean',\n description:\n 'Whether the note is clinical. Requires the clinical-note permission; the submission is dropped when the gate is closed.',\n },\n },\n required: ['content', 'clinical'],\n },\n openWorld: true,\n descriptionKey: 'ui.agent.notesPanel.actions.addNote',\n description:\n 'Compose and commit a new note. A clinical note requires the clinical-note permission (read canAddClinical first).',\n examples: [\n {\n args: { content: 'Patient reported improvement.', clinical: true },\n note: 'Add a clinical note.',\n },\n ],\n invoke: (handle, args: { content: string; clinical: boolean }) => {\n return handle.addNote(args);\n },\n },\n toggle_pin: {\n // Re-orders the timeline (pinned notes lead) — reversible view write.\n safety: 'write',\n argsType: '{ id: string }',\n argsSchema: {\n type: 'object',\n properties: { id: { type: 'string' } },\n required: ['id'],\n },\n idempotent: false,\n descriptionKey: 'ui.agent.notesPanel.actions.togglePin',\n description:\n 'Toggle the pinned state of the note with the given id. Refused for a deleted note or one whose actions.pin is false.',\n invoke: (handle, args: { id: string }) => {\n handle.togglePin(args.id);\n },\n },\n toggle_flag: {\n safety: 'write',\n argsType: '{ id: string }',\n argsSchema: {\n type: 'object',\n properties: { id: { type: 'string' } },\n required: ['id'],\n },\n idempotent: false,\n descriptionKey: 'ui.agent.notesPanel.actions.toggleFlag',\n description: 'Toggle the flagged state of the note with the given id.',\n invoke: (handle, args: { id: string }) => {\n handle.toggleFlag(args.id);\n },\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'notes-panel',\n description: 'Marks the NotesPanel region.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description:\n 'Sourced from the id prop. Required to address a specific notes panel from the agent.',\n },\n },\n};\n","import {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type HTMLAttributes,\n type ReactNode,\n} from 'react';\nimport { cva } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { getErrorMessage } from '../_shared/get-error-message';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { notesPanelAgent } from './notes-panel.agent';\nimport { ClinicalNoteCard } from '../clinical-note-card';\nimport type { ClinicalNoteCardProps } from '../clinical-note-card';\nimport { RichTextEditor } from '../rich-text-editor';\nimport type {\n RichTextEditorHandle,\n RichTextEditorProps,\n RichTextEditorToolbar,\n RedactorFactory,\n} from '../rich-text-editor';\nimport { TextArea } from '../text-area';\nimport { Alert } from '../alert';\nimport { Button, IconButton } from '../button';\nimport { Checkbox } from '../checkbox';\nimport { Spinner } from '../spinner';\nimport { Dialog } from '../dialog';\nimport { NotebookPen, Trash2 } from 'lucide-react';\nimport { PanelHeader } from '../panel-header';\nimport { REFLOW_ROW_CLASS, useListReflow } from '../../hooks/use-list-reflow';\nimport { useExitTransition } from '../../hooks/use-exit-transition';\nimport { useTheme } from '../../hooks/use-theme';\n\n/* ------------------------------------------------------------------ */\n/* NotesPanel — the Notes tool for the Control Room rail. */\n/* */\n/* A composer over an elevated ClinicalNoteCard timeline. Drops */\n/* into a ControlRoomRail tool `panel`, the patient profile, or the */\n/* care-plan editor — anywhere notes about the open entity belong. */\n/* The composer is the kit RichTextEditor by default (degrades to a */\n/* textarea where Redactor is absent), carries a permission-gated */\n/* \"clinical note\" toggle, and forwards the editor's AI affordances. */\n/* The note attaches to whatever entity the host is showing — the */\n/* host owns the attachment; the panel only emits content + clinical. */\n/* Pinned notes lead; pin / flag are inline per-note toggles. */\n/* ------------------------------------------------------------------ */\n\n/**\n * One note in the panel — the data subset of `ClinicalNoteCard`.\n *\n * `aria-label` names the card for assistive tech. Set it whenever a row is not\n * a clinical note: the card's fallback name is \"Clinical note\", so an entry\n * that is something else (a dated event, an import) is announced as one.\n */\nexport type NotesPanelNote = Pick<\n ClinicalNoteCardProps,\n | 'id'\n | 'dateIso'\n | 'createdAtIso'\n | 'author'\n | 'clinical'\n | 'attachedTo'\n | 'content'\n | 'contentFormat'\n | 'pinned'\n | 'flagged'\n | 'aria-label'\n | 'deleted'\n | 'operatorName'\n> & {\n /** What the host lets the reader do with this note. */\n actions?: NotesPanelNoteActions;\n};\n\n/** Per-note write permissions; an absent key means allowed. The panel hides\n * the pin toggle on `pin: false` and on a deleted note. */\nexport type NotesPanelNoteActions = {\n edit?: boolean;\n delete?: boolean;\n pin?: boolean;\n};\n\n/**\n * Curated agent handle for NotesPanel. Reads the note timeline's STRUCTURE\n * (ids + pinned / flagged / clinical flags — never the note body or author,\n * both PHI) and drives the composer + per-note toggles. See\n * `notes-panel.agent.ts`.\n */\nexport interface NotesPanelHandle {\n /** Timeline snapshot — ids + flags only, never note content (PHI). */\n getNotes: () => Array<{\n id?: string;\n pinned: boolean;\n flagged: boolean;\n clinical: boolean;\n }>;\n /** Whether the composer is mounted (onAddNote is wired). */\n canAddNote: () => boolean;\n /** Whether clinical notes may be written (the permission gate). */\n canAddClinical: () => boolean;\n /** Id of the note the host has addressed, or null when none is. */\n getCurrentNoteId: () => string | null;\n /** Commit a new note with explicit content (mirrors the composer's submit). */\n addNote: (submission: NotesPanelSubmission) => void | Promise<void>;\n /** Toggle a note's pinned state (mirrors onTogglePin, with its gate). */\n togglePin: (id: string) => void;\n /** Toggle a note's flagged state (mirrors onToggleFlag). */\n toggleFlag: (id: string) => void;\n}\n\n/** Payload handed to `onAddNote` when the composer commits. */\nexport interface NotesPanelSubmission {\n /** The note body — rich HTML (`composer='rich'`) or plain text. */\n content: string;\n /** Whether the \"clinical note\" toggle was set. */\n clinical: boolean;\n}\n\nexport interface NotesPanelProps extends Omit<\n HTMLAttributes<HTMLElement>,\n 'title' | 'children'\n> {\n /**\n * Stable instance id. Surfaced on the root as `data-component-id` so an\n * agent / MCP UI bridge can address this specific notes panel.\n */\n id?: string;\n /** Notes to render, newest-first by convention. Pinned notes lead. */\n notes: NotesPanelNote[];\n /**\n * Commit a new note. Omit to hide the composer (read-only timeline). Return\n * a promise to keep the draft until the host has saved it: the draft clears\n * when it resolves, and a rejection keeps it and shows the error's message.\n */\n onAddNote?: (submission: NotesPanelSubmission) => void | Promise<void>;\n /** The host's notes read. `'loading'` and `'error'` never show the empty\n * text; notes already held still render. Default `'ready'`. */\n status?: 'ready' | 'loading' | 'error';\n /** Retry a failed read. Renders a retry button in the error state. */\n onRetry?: () => void;\n /**\n * The note the reader ASKED for, addressed by id from somewhere else in the\n * record — a marker in a chart, a row in a grid, an agent. The panel marks\n * it, scrolls it to the middle of its own scroll region and moves focus to\n * it, and renders it unclamped so the thing that was asked for is readable\n * in full without a second click.\n *\n * Opening a panel is not the same as answering a question: a rail's\n * `setActiveTool` moves no focus and announces nothing, so a control whose\n * name promises \"in the notes panel\" produces no perceivable change for a\n * keyboard or screen-reader reader unless the panel lands them on the note.\n * That is what this prop is for; without it, a host has to reach into the\n * panel's DOM to do the same job.\n *\n * Marked on three channels, never colour alone (WCAG 1.4.1): a solid\n * inline-start bar the other notes do not have, a tinted gutter, and\n * `aria-current` plus a visually-hidden sentence naming the mark.\n *\n * Ids that match no note are ignored. To address the SAME note twice — the\n * reader pressing the same marker again after scrolling away — bump\n * `currentNoteKey` alongside it; this prop alone is a value, not a request.\n */\n currentNoteId?: string;\n /**\n * Bump on every address to re-scroll and re-focus the note in `currentNoteId`\n * even when the id has not changed.\n *\n * Addressing is a request, not a value: a reader who presses the same marker\n * a second time (having scrolled away, or having moved focus off the note) is\n * asking to be taken back, and a control whose name promises the notes panel\n * must do something perceivable every time it is pressed. Without this the\n * second press is inert — the panel is already showing that note, so nothing\n * re-runs. Hosts increment a counter in the same handler that opens the tool.\n */\n currentNoteKey?: string | number;\n\n /* ----- Composer ----- */\n /**\n * `'rich'` (default) mounts the kit `RichTextEditor` (Redactor; degrades to a\n * textarea where Redactor is absent). `'plain'` keeps a simple `TextArea` for\n * lightweight surfaces / deterministic tests.\n */\n composer?: 'rich' | 'plain';\n /** Toolbar preset for the rich composer. Defaults to `'standard'`. */\n editorToolbar?: RichTextEditorToolbar;\n /** Inject the Redactor factory for the rich composer (else `window.$R`). */\n redactor?: RedactorFactory;\n /** Consumer image-upload endpoint for the rich composer. */\n imageUploadUrl?: string;\n\n /* ----- Clinical flag (permission-gated) ----- */\n /** Show the \"clinical note\" toggle in the composer. Default `true`. */\n showClinicalToggle?: boolean;\n /**\n * Permission gate — when `false` the clinical toggle is disabled and shows\n * `clinicalGatedReason` on hover/focus. Mirrors platform's\n * `practice_add_clinical_note` permission. Default `true`.\n */\n canAddClinicalNote?: boolean;\n /** Tooltip shown when the clinical toggle is gated off. */\n clinicalGatedReason?: string;\n /** Initial state of the clinical toggle. Default `false`. */\n defaultClinical?: boolean;\n\n /* ----- AI assistance (forwarded to RichTextEditor) ----- */\n onRequestAiDraft?: RichTextEditorProps['onRequestAiDraft'];\n aiDraftFormat?: RichTextEditorProps['aiDraftFormat'];\n aiPrivacyNotice?: RichTextEditorProps['aiPrivacyNotice'];\n onDictate?: RichTextEditorProps['onDictate'];\n onProofread?: RichTextEditorProps['onProofread'];\n onAutoFormat?: RichTextEditorProps['onAutoFormat'];\n\n /* ----- Per-note actions ----- */\n /** Toggle a note's pinned state — renders an inline pin button per note. */\n onTogglePin?: (id: string) => void;\n /** Toggle a note's flagged state — renders an inline flag button per note. */\n onToggleFlag?: (id: string) => void;\n /**\n * Host-owned actions for each note (edit, delete, share…), rendered by\n * the note card beside its pin and flag,\n * aligned to the inline end. The host supplies labelled controls and owns\n * what they do — the panel stays a timeline and never edits a note itself.\n */\n noteActions?: (note: NotesPanelNote) => ReactNode;\n /**\n * Request the host to delete a note. When provided, the panel holds the\n * row on screen long enough to fade it out before calling this, so the\n * removal reads as a removal rather than a vanish. Omit to let the host\n * own the timing entirely (the reflow animation still closes the gap).\n */\n onDeleteNote?: (id: string) => void;\n /**\n * Show a confirmation dialog before calling `onDeleteNote`. When `true`\n * (the default when `onDeleteNote` is provided), the built-in delete\n * button opens an alert dialog first; the exit fade only starts after\n * the user confirms. Pass `false` to delete immediately on click.\n */\n confirmDelete?: boolean;\n\n /* ----- Labels / chrome ----- */\n /** Panel heading. Defaults to the localised \"Notes\". */\n title?: string;\n /** Composer placeholder. */\n composerPlaceholder?: string;\n /** Save-button label. */\n addNoteLabel?: string;\n /** Rendered when there are no notes. */\n emptyState?: ReactNode;\n /** Accessible name for the panel region (defaults to `title`). */\n 'aria-label'?: string;\n}\n\n/* The timeline row. The addressed note wears a solid inline-start bar the\n others do not — a shape channel, so the mark is not colour alone. Every row\n reserves the bar's width in `transparent`, so marking one shifts nothing. */\nconst noteItemVariants = cva(\n 'ds:flex ds:flex-col ds:rounded-[var(--radius-md)] ds:border-s-2 ds:ps-[var(--spacing-sm)]',\n {\n variants: {\n current: {\n true: 'ds:border-[color:var(--info)] ds:bg-[color:var(--info)]/10 ds:focus:outline-[length:var(--focus-ring-width)] ds:focus:outline-solid ds:focus:outline-[color:var(--ring)] ds:focus:outline-offset-[length:var(--focus-ring-offset)]',\n false: 'ds:border-transparent',\n },\n },\n defaultVariants: { current: false },\n },\n);\n\n/* A row on its way out fades in place; the reflow hook then slides the\n rows below up to close the gap. Declared at rest so the transition has\n a value to animate from the moment the leaving class lands. */\nconst noteLeavingClass = 'ds:opacity-0';\nconst noteElevationClass = [\n 'ds:transition-opacity ds:duration-[var(--animation-duration)]',\n 'ds:ease-[var(--ease-out)] ds:motion-reduce:transition-none',\n].join(' ');\n\n/** Strip tags / entities to test whether a rich draft holds real content. */\nfunction hasRichContent(html: string): boolean {\n if (!html) return false;\n if (/<img\\b/i.test(html)) return true;\n return (\n html\n .replace(/<[^>]*>/g, '')\n .replace(/ /gi, ' ')\n .trim().length > 0\n );\n}\n\nexport const NotesPanel = forwardRef<HTMLElement, NotesPanelProps>(\n function NotesPanel(\n {\n id,\n notes,\n onAddNote,\n status = 'ready',\n onRetry,\n currentNoteId,\n currentNoteKey,\n composer = 'rich',\n editorToolbar = 'standard',\n redactor,\n imageUploadUrl,\n showClinicalToggle = true,\n canAddClinicalNote = true,\n clinicalGatedReason,\n defaultClinical = false,\n onRequestAiDraft,\n aiDraftFormat,\n aiPrivacyNotice,\n onDictate,\n onProofread,\n onAutoFormat,\n onTogglePin,\n onToggleFlag,\n noteActions,\n onDeleteNote,\n confirmDelete = true,\n title,\n composerPlaceholder,\n addNoteLabel,\n emptyState,\n className,\n 'aria-label': ariaLabel,\n ...rest\n },\n ref,\n ) {\n const { t } = useTranslation();\n const editorRef = useRef<RichTextEditorHandle>(null);\n const [draft, setDraft] = useState('');\n const [clinical, setClinical] = useState(defaultClinical);\n const [pending, setPending] = useState(false);\n const [addError, setAddError] = useState<string | null>(null);\n\n const heading = title ?? t('notesPanel.title', { defaultValue: 'Notes' });\n const headingId = useId();\n const placeholder =\n composerPlaceholder ??\n t('notesPanel.placeholder', { defaultValue: 'Add a note…' });\n const composerLabel = t('notesPanel.composerLabel', {\n defaultValue: 'New note',\n });\n\n // Live content check: plain reads the draft directly; rich strips the draft\n // (debounced) for the disabled state but commits from the editor handle.\n const hasContent =\n composer === 'rich' ? hasRichContent(draft) : draft.trim().length > 0;\n\n const commit = useCallback(() => {\n if (!onAddNote || pending) return;\n const rich = composer === 'rich';\n const content = rich\n ? (editorRef.current?.getHTML() ?? draft)\n : draft.trim();\n if (rich ? !hasRichContent(content) : !content) return;\n const reset = () => {\n if (rich) editorRef.current?.clear();\n setDraft('');\n setClinical(defaultClinical);\n };\n setAddError(null);\n let result: void | Promise<void>;\n try {\n result = onAddNote({ content, clinical });\n } catch (error: unknown) {\n setAddError(getErrorMessage(error, t('notesPanel.addFailed')));\n return;\n }\n if (!result || typeof result.then !== 'function') return reset();\n // A failed save keeps the draft, so nothing typed is lost.\n setPending(true);\n Promise.resolve(result)\n .then(reset, (error: unknown) =>\n setAddError(getErrorMessage(error, t('notesPanel.addFailed'))),\n )\n .finally(() => setPending(false));\n }, [composer, draft, clinical, defaultClinical, onAddNote, pending, t]);\n\n // Pinned notes lead; order within each group is preserved.\n const ordered = [...notes].sort(\n (a, b) => Number(b.pinned ?? false) - Number(a.pinned ?? false),\n );\n\n /* The accessible theme zeroes `--animation-duration`, so its CSS plays\n nothing — the JS must agree, or a row would sit still for the delay\n and then vanish anyway. `undefined` leaves the media query in charge. */\n const { resolvedTheme } = useTheme();\n const reduceMotion = resolvedTheme.endsWith('-accessible') || undefined;\n\n /* Closing the gap a removed row leaves: the rows below slide up rather\n than jumping, so the eye keeps its place in the list. Fires on add,\n delete, and re-order (pinning) — any change to the visible id\n sequence. */\n const { containerRef: reflowRef } = useListReflow<HTMLUListElement>({\n key: ordered.map((n) => n.id).join(),\n reduceMotion,\n });\n\n /* A note leaving the list fades out before the host drops it, so the\n removal reads as a removal rather than a vanish. The reflow hook\n then slides the rows below up to close the gap. */\n const deleteExit = useExitTransition({ reduceMotion });\n const [pendingDelete, setPendingDelete] = useState<string | null>(null);\n const handleDeleteNote = useCallback(\n (noteId: string) => {\n if (!onDeleteNote) return;\n if (confirmDelete) {\n setPendingDelete(noteId);\n } else {\n deleteExit.leave(noteId, () => onDeleteNote(noteId));\n }\n },\n [confirmDelete, deleteExit, onDeleteNote],\n );\n const confirmDeleteNote = useCallback(() => {\n if (!pendingDelete || !onDeleteNote) return;\n const noteId = pendingDelete;\n setPendingDelete(null);\n deleteExit.leave(noteId, () => onDeleteNote(noteId));\n }, [pendingDelete, onDeleteNote, deleteExit]);\n\n /* ----- The addressed note (see `currentNoteId`) ----- */\n const currentItemRef = useRef<HTMLLIElement>(null);\n useEffect(() => {\n if (!currentNoteId) return;\n // `center`, not `nearest`: nearest parks the note flush against the edge\n // of the scroll region, which is the least readable place to land.\n currentItemRef.current?.scrollIntoView({ block: 'center' });\n currentItemRef.current?.focus();\n // `currentNoteKey` is in the deps so a REPEAT address of the same note\n // re-runs — see the prop doc. Addressing is a request, not a value.\n }, [currentNoteId, currentNoteKey]);\n\n /* ----- Agent handle (structural reads + composer / toggles) ----- */\n const notesRef = useRef(notes);\n notesRef.current = notes;\n const onAddNoteRef = useRef(onAddNote);\n onAddNoteRef.current = onAddNote;\n const onTogglePinRef = useRef(onTogglePin);\n onTogglePinRef.current = onTogglePin;\n const onToggleFlagRef = useRef(onToggleFlag);\n onToggleFlagRef.current = onToggleFlag;\n const canAddClinicalRef = useRef(canAddClinicalNote);\n canAddClinicalRef.current = canAddClinicalNote;\n const currentNoteIdRef = useRef(currentNoteId);\n currentNoteIdRef.current = currentNoteId;\n\n const rootRef = useRef<HTMLElement>(null);\n useImperativeHandle(ref, () => rootRef.current as HTMLElement, []);\n\n const handle = useMemo<NotesPanelHandle>(\n () => ({\n // Ids + flags only — never the note body or author (both PHI).\n getNotes: () =>\n notesRef.current.map((n) => ({\n id: n.id,\n pinned: !!n.pinned,\n flagged: !!n.flagged,\n clinical: !!n.clinical,\n })),\n canAddNote: () => !!onAddNoteRef.current,\n canAddClinical: () => canAddClinicalRef.current,\n getCurrentNoteId: () => currentNoteIdRef.current ?? null,\n addNote: (submission) => {\n // A clinical submission requires the permission gate to be open.\n if (submission.clinical && !canAddClinicalRef.current) return;\n return onAddNoteRef.current?.(submission);\n },\n togglePin: (noteId) => {\n const note = notesRef.current.find((n) => n.id === noteId);\n if (note && (note.deleted || note.actions?.pin === false)) return;\n onTogglePinRef.current?.(noteId);\n },\n toggleFlag: (noteId) => onToggleFlagRef.current?.(noteId),\n }),\n [],\n );\n useAgentRegistration(notesPanelAgent, handle, id);\n\n return (\n <section\n ref={rootRef}\n data-component=\"notes-panel\"\n data-component-id={id}\n aria-labelledby={ariaLabel ? undefined : headingId}\n aria-label={ariaLabel}\n className={['ds:flex ds:flex-col', className].filter(Boolean).join(' ')}\n {...rest}\n >\n {/* Shared rail header — pins to the top of the panel's scroll region\n while the composer + note timeline scroll beneath it. The rail\n injects the favourite / close actions via PanelHeaderActionsProvider. */}\n <PanelHeader\n title={heading}\n icon={<NotebookPen aria-hidden=\"true\" />}\n headingId={ariaLabel ? undefined : headingId}\n sticky\n divider\n />\n\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)] ds:p-[var(--spacing-md)]\">\n {onAddNote ? (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {composer === 'rich' ? (\n <RichTextEditor\n ref={editorRef}\n ariaLabel={composerLabel}\n placeholder={placeholder}\n toolbar={editorToolbar}\n minHeight=\"fill\"\n redactor={redactor}\n imageUploadUrl={imageUploadUrl}\n readOnly={pending}\n onChange={({ html }) => setDraft(html)}\n onRequestAiDraft={onRequestAiDraft}\n aiDraftFormat={aiDraftFormat}\n aiPrivacyNotice={aiPrivacyNotice}\n onDictate={onDictate}\n onProofread={onProofread}\n onAutoFormat={onAutoFormat}\n />\n ) : (\n <TextArea\n value={draft}\n readOnly={pending}\n onChange={(event) => setDraft(event.target.value)}\n placeholder={placeholder}\n autoResize\n minRows={2}\n maxRows={6}\n aria-label={composerLabel}\n />\n )}\n <div\n className={[\n 'ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-sm)]',\n showClinicalToggle ? 'ds:justify-between' : 'ds:justify-end',\n ].join(' ')}\n >\n {showClinicalToggle ? (\n <Checkbox\n size=\"sm\"\n label={t('notesPanel.clinicalToggle', {\n defaultValue: 'Clinical note',\n })}\n checked={clinical}\n onCheckedChange={(next) => setClinical(next === true)}\n disabled={pending || !canAddClinicalNote}\n disabledReason={\n canAddClinicalNote\n ? undefined\n : (clinicalGatedReason ??\n t('notesPanel.clinicalGated', {\n defaultValue:\n 'You do not have permission to write clinical notes.',\n }))\n }\n />\n ) : null}\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={commit}\n disabled={!hasContent}\n loading={pending}\n >\n {addNoteLabel ??\n t('notesPanel.add', { defaultValue: 'Add note' })}\n </Button>\n </div>\n {addError ? (\n <Alert variant=\"error\">\n <Alert.Description>{addError}</Alert.Description>\n </Alert>\n ) : null}\n </div>\n ) : null}\n\n {status === 'loading' ? (\n <p className=\"ds:m-0 ds:flex ds:items-center ds:gap-[var(--spacing-xs)] type-body-sm ds:text-[color:var(--muted-foreground)]\">\n <Spinner size=\"sm\" label={t('notesPanel.loading')} />\n <span aria-hidden=\"true\">{t('notesPanel.loading')}</span>\n </p>\n ) : status === 'error' ? (\n <Alert variant=\"error\">\n <Alert.Description>{t('notesPanel.loadError')}</Alert.Description>\n {onRetry ? (\n <Alert.Action>\n <Button intent=\"secondary\" size=\"sm\" onClick={onRetry}>\n {t('notesPanel.retry')}\n </Button>\n </Alert.Action>\n ) : null}\n </Alert>\n ) : null}\n\n {ordered.length > 0 ? (\n <ul\n ref={reflowRef}\n className=\"ds:m-0 ds:flex ds:list-none ds:flex-col ds:gap-[var(--spacing-sm)] ds:p-0\"\n >\n {ordered.map(({ actions, ...note }, index) => {\n const isCurrent =\n currentNoteId != null && note.id === currentNoteId;\n const noteId = note.id as string | undefined;\n const leaving = noteId != null && deleteExit.isLeaving(noteId);\n return (\n <li\n key={note.id ?? index}\n ref={isCurrent ? currentItemRef : undefined}\n // Focus lands on the row, not inside the card, so the\n // sentence below and `aria-current` are read out before the\n // note — and the rail's own Escape still bubbles.\n tabIndex={isCurrent ? -1 : undefined}\n aria-current={isCurrent ? 'true' : undefined}\n data-reflow-id={noteId}\n data-leaving={leaving ? '' : undefined}\n className={[\n noteItemVariants({ current: isCurrent }),\n noteElevationClass,\n REFLOW_ROW_CLASS,\n leaving ? noteLeavingClass : '',\n ]\n .filter(Boolean)\n .join(' ')}\n >\n {isCurrent ? (\n <span className=\"ds:sr-only\">\n {t('notesPanel.current', {\n defaultValue: 'Current note',\n })}\n </span>\n ) : null}\n {/* Elevated card per note; the list gap (not a separator)\n spaces them. Bodies clamp to five lines with read-more —\n except the addressed one, which is what the reader came\n for and opens in full. */}\n <ClinicalNoteCard\n surface=\"elevated\"\n truncate={!isCurrent}\n headerActions={\n <>\n {noteActions\n ? noteActions({ ...note, actions })\n : null}\n {onDeleteNote && noteId && !note.deleted ? (\n <IconButton\n icon={<Trash2 />}\n intent=\"ghost\"\n size=\"sm\"\n aria-label={t('notesPanel.delete', {\n defaultValue: 'Delete note',\n })}\n onClick={() => handleDeleteNote(noteId)}\n />\n ) : null}\n </>\n }\n {...note}\n onTogglePin={\n onTogglePin &&\n note.id &&\n actions?.pin !== false &&\n !note.deleted\n ? () => onTogglePin(note.id as string)\n : undefined\n }\n onToggleFlag={\n onToggleFlag && note.id\n ? () => onToggleFlag(note.id as string)\n : undefined\n }\n />\n </li>\n );\n })}\n </ul>\n ) : status !== 'ready' ? null : (\n (emptyState ?? (\n <p className=\"ds:m-0 type-body-sm ds:text-[color:var(--muted-foreground)]\">\n {t('notesPanel.empty', { defaultValue: 'No notes yet.' })}\n </p>\n ))\n )}\n </div>\n\n {onDeleteNote && confirmDelete ? (\n <Dialog\n open={pendingDelete !== null}\n onOpenChange={(next) => !next && setPendingDelete(null)}\n >\n <Dialog.Content variant=\"alert\" size=\"sm\">\n <Dialog.Header>\n <Dialog.Title>\n {t('notesPanel.deleteConfirmTitle', {\n defaultValue: 'Delete this note?',\n })}\n </Dialog.Title>\n </Dialog.Header>\n <Dialog.Body>\n <Dialog.Description>\n {t('notesPanel.deleteConfirmBody', {\n defaultValue: 'The note will be removed from the record.',\n })}\n </Dialog.Description>\n </Dialog.Body>\n <Dialog.Footer>\n <Dialog.Close asChild>\n <Button\n intent=\"secondary\"\n size=\"sm\"\n onClick={() => setPendingDelete(null)}\n >\n {t('notesPanel.deleteConfirmCancel', {\n defaultValue: 'Cancel',\n })}\n </Button>\n </Dialog.Close>\n <Button\n intent=\"destructive\"\n size=\"sm\"\n onClick={confirmDeleteNote}\n >\n {t('notesPanel.deleteConfirmAction', {\n defaultValue: 'Delete',\n })}\n </Button>\n </Dialog.Footer>\n </Dialog.Content>\n </Dialog>\n ) : null}\n </section>\n );\n },\n);\n"],"names":["getErrorMessage","error","fallback","notesPanelAgent","handle","args","noteItemVariants","cva","noteLeavingClass","noteElevationClass","hasRichContent","html","NotesPanel","forwardRef","id","notes","onAddNote","status","onRetry","currentNoteId","currentNoteKey","composer","editorToolbar","redactor","imageUploadUrl","showClinicalToggle","canAddClinicalNote","clinicalGatedReason","defaultClinical","onRequestAiDraft","aiDraftFormat","aiPrivacyNotice","onDictate","onProofread","onAutoFormat","onTogglePin","onToggleFlag","noteActions","onDeleteNote","confirmDelete","title","composerPlaceholder","addNoteLabel","emptyState","className","ariaLabel","rest","ref","t","useTranslation","editorRef","useRef","draft","setDraft","useState","clinical","setClinical","pending","setPending","addError","setAddError","heading","headingId","useId","placeholder","composerLabel","hasContent","commit","useCallback","rich","content","_a","reset","result","ordered","a","b","resolvedTheme","useTheme","reduceMotion","reflowRef","useListReflow","n","deleteExit","useExitTransition","pendingDelete","setPendingDelete","handleDeleteNote","noteId","confirmDeleteNote","currentItemRef","useEffect","_b","notesRef","onAddNoteRef","onTogglePinRef","onToggleFlagRef","canAddClinicalRef","currentNoteIdRef","rootRef","useImperativeHandle","useMemo","submission","note","useAgentRegistration","jsxs","jsx","PanelHeader","NotebookPen","RichTextEditor","TextArea","event","Checkbox","next","Button","Alert","Spinner","actions","index","isCurrent","leaving","REFLOW_ROW_CLASS","ClinicalNoteCard","Fragment","IconButton","Trash2","Dialog"],"mappings":"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"}
|
|
@@ -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 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"skeleton-CZbwyJAA.js","sources":["../../src/components/skeleton/skeleton.tsx"],"sourcesContent":["import { forwardRef, type CSSProperties, type HTMLAttributes } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\n\nconst skeletonVariants = cva(\n [\n 'ds:bg-[var(--muted)]',\n 'ds:motion-reduce:animate-none',\n 'ds:forced-colors:bg-[GrayText]',\n 'ds:forced-colors:outline',\n 'ds:forced-colors:outline-1',\n 'ds:forced-colors:outline-[CanvasText]',\n 'ds:forced-colors:animate-none',\n ].join(' '),\n {\n variants: {\n variant: {\n text: 'ds:rounded-[var(--radius-sm)] ds:w-full',\n circular:\n 'ds:rounded-[var(--radius-full)] ds:aspect-square ds:shrink-0',\n rectangular: 'ds:rounded-none',\n rounded: 'ds:rounded-[var(--radius-md)]',\n },\n size: {\n sm: '',\n md: '',\n lg: '',\n },\n },\n compoundVariants: [\n { variant: 'text', size: 'sm', class: 'ds:h-3' },\n { variant: 'text', size: 'md', class: 'ds:h-4' },\n { variant: 'text', size: 'lg', class: 'ds:h-5' },\n { variant: 'circular', size: 'sm', class: 'ds:h-8 ds:w-8' },\n { variant: 'circular', size: 'md', class: 'ds:h-10 ds:w-10' },\n { variant: 'circular', size: 'lg', class: 'ds:h-12 ds:w-12' },\n { variant: 'rectangular', size: 'sm', class: 'ds:h-16' },\n { variant: 'rectangular', size: 'md', class: 'ds:h-24' },\n { variant: 'rectangular', size: 'lg', class: 'ds:h-40' },\n { variant: 'rounded', size: 'sm', class: 'ds:h-16' },\n { variant: 'rounded', size: 'md', class: 'ds:h-24' },\n { variant: 'rounded', size: 'lg', class: 'ds:h-40' },\n ],\n defaultVariants: {\n variant: 'text',\n size: 'md',\n },\n },\n);\n\nconst ANIMATION_CLASS =\n 'ds:animate-[skeleton-pulse_calc(var(--animation-duration)*8)_ease-in-out_infinite]';\n\nexport interface SkeletonProps\n extends\n Omit<HTMLAttributes<HTMLDivElement>, 'aria-hidden' | 'style'>,\n VariantProps<typeof skeletonVariants> {\n variant?: 'text' | 'circular' | 'rectangular' | 'rounded';\n size?: 'sm' | 'md' | 'lg';\n /** Number of stacked text lines — only applies when variant='text' */\n lines?: number;\n /**\n * Width override — accepts any CSS value.\n * Exception to constraint §4: skeleton dimensions are consumer-specified\n * and cannot be expressed as static Tailwind classes.\n */\n width?: string;\n /**\n * Height override — accepts any CSS value.\n * Exception to constraint §4: skeleton dimensions are consumer-specified\n * and cannot be expressed as static Tailwind classes.\n */\n height?: string;\n /** Whether to animate the pulse */\n animate?: boolean;\n}\n\nexport const Skeleton = forwardRef<HTMLDivElement, SkeletonProps>(\n (\n {\n variant = 'text',\n size = 'md',\n lines,\n width,\n height,\n animate = true,\n className,\n ...props\n },\n ref,\n ) => {\n // Exception to constraint §4: width/height are consumer-specified dimensions\n // that cannot be expressed as static Tailwind classes.\n const inlineStyle: CSSProperties | undefined =\n width !== undefined || height !== undefined\n ? {\n ...(width !== undefined && { width }),\n ...(height !== undefined && { height }),\n }\n : undefined;\n\n const atomClass = [\n skeletonVariants({ variant, size }),\n animate && ANIMATION_CLASS,\n ]\n .filter(Boolean)\n .join(' ');\n\n if (lines !== undefined && lines > 1) {\n return (\n <div\n ref={ref}\n aria-hidden=\"true\"\n data-component=\"skeleton\"\n className={[\n 'ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]',\n className,\n ]\n .filter(Boolean)\n .join(' ')}\n // eslint-disable-next-line react/forbid-dom-props -- caller-supplied skeleton width/height, runtime-computed\n style={inlineStyle}\n {...props}\n >\n {Array.from({ length: lines }, (_, i) => (\n <div\n key={`skeleton-line-${i}`}\n aria-hidden=\"true\"\n className={[atomClass, i === lines - 1 && 'ds:w-3/5']\n .filter(Boolean)\n .join(' ')}\n />\n ))}\n </div>\n );\n }\n\n return (\n <div\n ref={ref}\n aria-hidden=\"true\"\n data-component=\"skeleton\"\n className={[atomClass, className].filter(Boolean).join(' ')}\n // eslint-disable-next-line react/forbid-dom-props -- caller-supplied skeleton width/height, runtime-computed\n style={inlineStyle}\n {...props}\n />\n );\n },\n);\n\nSkeleton.displayName = 'Skeleton';\n"],"names":["skeletonVariants","cva","ANIMATION_CLASS","Skeleton","forwardRef","variant","size","lines","width","height","animate","className","props","ref","inlineStyle","atomClass","jsx","_","i"],"mappings":"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"}
|
|
@@ -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]}
|