@mieweb/ui 0.11.0-dev.29 → 0.11.0-dev.30

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.
Files changed (116) hide show
  1. package/MIGRATION.md +67 -0
  2. package/README.md +10 -0
  3. package/dist/EncounterMdyEditor-3SQY4MK2.js +286 -0
  4. package/dist/EncounterMdyEditor-3SQY4MK2.js.map +1 -0
  5. package/dist/EncounterMdyEditor-73PTTIRY.cjs +288 -0
  6. package/dist/EncounterMdyEditor-73PTTIRY.cjs.map +1 -0
  7. package/dist/chunk-25MPUVTM.js +339 -0
  8. package/dist/chunk-25MPUVTM.js.map +1 -0
  9. package/dist/{chunk-2VISTX7O.js → chunk-3NOVISM6.js} +3 -3
  10. package/dist/{chunk-2VISTX7O.js.map → chunk-3NOVISM6.js.map} +1 -1
  11. package/dist/{chunk-6GKIISNZ.cjs → chunk-3Y3ZCDNF.cjs} +176 -63
  12. package/dist/chunk-3Y3ZCDNF.cjs.map +1 -0
  13. package/dist/{chunk-AK4LHJPC.js → chunk-4JXO5JTE.js} +84 -3
  14. package/dist/chunk-4JXO5JTE.js.map +1 -0
  15. package/dist/chunk-4NB4WOGU.cjs +666 -0
  16. package/dist/chunk-4NB4WOGU.cjs.map +1 -0
  17. package/dist/{chunk-434L5RYF.js → chunk-4P27Y52M.js} +3 -3
  18. package/dist/{chunk-434L5RYF.js.map → chunk-4P27Y52M.js.map} +1 -1
  19. package/dist/{chunk-PRA2V5BP.cjs → chunk-5KGYTNOA.cjs} +7 -7
  20. package/dist/{chunk-PRA2V5BP.cjs.map → chunk-5KGYTNOA.cjs.map} +1 -1
  21. package/dist/chunk-5LNLB2XT.js +634 -0
  22. package/dist/chunk-5LNLB2XT.js.map +1 -0
  23. package/dist/chunk-5YOT4DVH.js +31 -0
  24. package/dist/chunk-5YOT4DVH.js.map +1 -0
  25. package/dist/chunk-7HFZL5V5.js +2425 -0
  26. package/dist/chunk-7HFZL5V5.js.map +1 -0
  27. package/dist/{chunk-XZNHS7YQ.cjs → chunk-7XC6E4BT.cjs} +3 -3
  28. package/dist/{chunk-XZNHS7YQ.cjs.map → chunk-7XC6E4BT.cjs.map} +1 -1
  29. package/dist/{chunk-JM4YFLO4.js → chunk-AIJYZP7M.js} +3 -3
  30. package/dist/{chunk-JM4YFLO4.js.map → chunk-AIJYZP7M.js.map} +1 -1
  31. package/dist/chunk-BBLEGF5L.js +66 -0
  32. package/dist/chunk-BBLEGF5L.js.map +1 -0
  33. package/dist/{chunk-MBDT2MGR.js → chunk-BIQIE3VW.js} +4 -4
  34. package/dist/{chunk-MBDT2MGR.js.map → chunk-BIQIE3VW.js.map} +1 -1
  35. package/dist/chunk-FSLI5IKP.cjs +54 -0
  36. package/dist/chunk-FSLI5IKP.cjs.map +1 -0
  37. package/dist/chunk-GADJASST.js +3 -0
  38. package/dist/chunk-GADJASST.js.map +1 -0
  39. package/dist/chunk-IXUIOR4K.cjs +2457 -0
  40. package/dist/chunk-IXUIOR4K.cjs.map +1 -0
  41. package/dist/chunk-K2BY7YPJ.cjs +4 -0
  42. package/dist/chunk-K2BY7YPJ.cjs.map +1 -0
  43. package/dist/{chunk-H3P7POFC.cjs → chunk-MA3Y6AYA.cjs} +3 -3
  44. package/dist/{chunk-H3P7POFC.cjs.map → chunk-MA3Y6AYA.cjs.map} +1 -1
  45. package/dist/chunk-QO4A6U73.cjs +342 -0
  46. package/dist/chunk-QO4A6U73.cjs.map +1 -0
  47. package/dist/{chunk-43QBEF6N.js → chunk-QR7B6UPR.js} +176 -63
  48. package/dist/chunk-QR7B6UPR.js.map +1 -0
  49. package/dist/chunk-SMPLM6K3.js +4107 -0
  50. package/dist/chunk-SMPLM6K3.js.map +1 -0
  51. package/dist/chunk-SV6YGK4U.cjs +88 -0
  52. package/dist/chunk-SV6YGK4U.cjs.map +1 -0
  53. package/dist/{chunk-MQ5WJ3NO.js → chunk-UDUYZDTA.js} +14 -72
  54. package/dist/chunk-UDUYZDTA.js.map +1 -0
  55. package/dist/{chunk-ZLBNYCYT.cjs → chunk-XPVQI3MM.cjs} +84 -3
  56. package/dist/chunk-XPVQI3MM.cjs.map +1 -0
  57. package/dist/{chunk-AQUHEKXL.cjs → chunk-XQHDQ64G.cjs} +4 -4
  58. package/dist/{chunk-AQUHEKXL.cjs.map → chunk-XQHDQ64G.cjs.map} +1 -1
  59. package/dist/chunk-Z2OOJGHL.cjs +4155 -0
  60. package/dist/chunk-Z2OOJGHL.cjs.map +1 -0
  61. package/dist/{chunk-QKW2QCGI.cjs → chunk-ZK2R6UGF.cjs} +13 -72
  62. package/dist/chunk-ZK2R6UGF.cjs.map +1 -0
  63. package/dist/components/ActionPlan/index.cjs +4 -4
  64. package/dist/components/ActionPlan/index.js +2 -2
  65. package/dist/components/AlertDialog/index.d.cts +1 -1
  66. package/dist/components/AlertDialog/index.d.ts +1 -1
  67. package/dist/components/EmailEditor/index.cjs +13 -12
  68. package/dist/components/EmailEditor/index.js +4 -3
  69. package/dist/components/MediaEditor/index.cjs +7 -7
  70. package/dist/components/MediaEditor/index.js +2 -2
  71. package/dist/components/RichTextEditor/index.cjs +5 -4
  72. package/dist/components/RichTextEditor/index.d.cts +34 -0
  73. package/dist/components/RichTextEditor/index.d.ts +34 -0
  74. package/dist/components/RichTextEditor/index.js +2 -1
  75. package/dist/components/SuperChat/index.cjs +10 -9
  76. package/dist/components/SuperChat/index.cjs.map +1 -1
  77. package/dist/components/SuperChat/index.js +2 -1
  78. package/dist/components/SuperChat/index.js.map +1 -1
  79. package/dist/components/Textarea/index.cjs +6 -5
  80. package/dist/components/Textarea/index.js +3 -2
  81. package/dist/esheet.cjs +4237 -25
  82. package/dist/esheet.cjs.map +1 -1
  83. package/dist/esheet.d.cts +753 -6
  84. package/dist/esheet.d.ts +753 -6
  85. package/dist/esheet.js +4099 -21
  86. package/dist/esheet.js.map +1 -1
  87. package/dist/index.cjs +204 -3072
  88. package/dist/index.cjs.map +1 -1
  89. package/dist/index.d.cts +71 -9
  90. package/dist/index.d.ts +71 -9
  91. package/dist/index.js +38 -2968
  92. package/dist/index.js.map +1 -1
  93. package/dist/kerebron.cjs +7 -268
  94. package/dist/kerebron.cjs.map +1 -1
  95. package/dist/kerebron.d.cts +7 -1
  96. package/dist/kerebron.d.ts +7 -1
  97. package/dist/kerebron.js +6 -270
  98. package/dist/kerebron.js.map +1 -1
  99. package/dist/model-WFFZRQMY.js +18 -0
  100. package/dist/model-WFFZRQMY.js.map +1 -0
  101. package/dist/model-Y7WRIGGA.cjs +79 -0
  102. package/dist/model-Y7WRIGGA.cjs.map +1 -0
  103. package/dist/styles.css +1 -1
  104. package/dist/tailwind-preset.cjs +4 -4
  105. package/dist/tailwind-preset.js +1 -1
  106. package/package.json +30 -9
  107. package/dist/chunk-43QBEF6N.js.map +0 -1
  108. package/dist/chunk-6GKIISNZ.cjs.map +0 -1
  109. package/dist/chunk-AK4LHJPC.js.map +0 -1
  110. package/dist/chunk-MQ5WJ3NO.js.map +0 -1
  111. package/dist/chunk-QKW2QCGI.cjs.map +0 -1
  112. package/dist/chunk-SFSBYC46.js +0 -1596
  113. package/dist/chunk-SFSBYC46.js.map +0 -1
  114. package/dist/chunk-ZIJMLRI3.cjs +0 -1633
  115. package/dist/chunk-ZIJMLRI3.cjs.map +0 -1
  116. package/dist/chunk-ZLBNYCYT.cjs.map +0 -1
@@ -1,1596 +0,0 @@
1
- import { Tooltip } from './chunk-YFWDS6MX.js';
2
- import { RadioGroup, Radio } from './chunk-EPSB4WTL.js';
3
- import { Label } from './chunk-I3WGZPI6.js';
4
- import { DateInput } from './chunk-I6Y2KLTZ.js';
5
- import { Textarea } from './chunk-2VISTX7O.js';
6
- import { Select } from './chunk-VCI2Y7ST.js';
7
- import { Card, CardHeader, CardContent } from './chunk-QYSUYB3S.js';
8
- import { Modal, ModalHeader, ModalTitle, ModalClose, ModalBody, ModalFooter } from './chunk-TWQSMUE6.js';
9
- import { Input } from './chunk-3IMM2PM4.js';
10
- import { useDragReorder, dragIndicatorClasses } from './chunk-YUMOM3KE.js';
11
- import { useLiveAnnouncement } from './chunk-HNXLLDPN.js';
12
- import { AlertCircle, Plus, GripVertical, StickyNote, Ban, Pencil, CalendarCheck, ExternalLink, ThumbsUp, HandMetal, ThumbsDown, HelpCircle, ChevronDown, ChevronUp, RefreshCw } from './chunk-BKSPDTX4.js';
13
- import { isRtl } from './chunk-YVKBXNPK.js';
14
- import { Badge } from './chunk-522WJIVI.js';
15
- import { Button } from './chunk-WFBUBT54.js';
16
- import { cn } from './chunk-TQONQSJO.js';
17
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
18
- import * as React3 from 'react';
19
-
20
- function toolbarKeyNav(e) {
21
- if (e.altKey || e.ctrlKey || e.metaKey) return;
22
- if (!["ArrowLeft", "ArrowRight", "Home", "End"].includes(e.key)) return;
23
- const buttons = Array.from(
24
- e.currentTarget.querySelectorAll(
25
- "button:not([disabled])"
26
- )
27
- );
28
- const i = buttons.indexOf(document.activeElement);
29
- if (i === -1 || buttons.length === 0) return;
30
- e.preventDefault();
31
- e.stopPropagation();
32
- let key = e.key;
33
- if (isRtl(e.currentTarget)) {
34
- if (key === "ArrowRight") key = "ArrowLeft";
35
- else if (key === "ArrowLeft") key = "ArrowRight";
36
- }
37
- const next = key === "ArrowLeft" ? (i - 1 + buttons.length) % buttons.length : key === "ArrowRight" ? (i + 1) % buttons.length : key === "Home" ? 0 : buttons.length - 1;
38
- buttons[next]?.focus();
39
- }
40
- var ALIGN = {
41
- /** Vertically centered on the row's right edge (single-line rows). */
42
- center: "pointer-fine:top-1/2 pointer-fine:end-0 pointer-fine:-translate-y-1/2",
43
- /** Pinned near the row's top-right corner (multi-line rows). */
44
- top: "pointer-fine:top-1.5 pointer-fine:end-1.5"
45
- };
46
- var REVEAL = {
47
- row: cn(
48
- "group-hover:pointer-events-auto group-hover:opacity-100",
49
- "group-focus-within:pointer-events-auto group-focus-within:opacity-100",
50
- "group-focus:pointer-events-auto group-focus:opacity-100"
51
- ),
52
- order: cn(
53
- "group-hover/order:pointer-events-auto group-hover/order:opacity-100",
54
- "group-focus-within/order:pointer-events-auto group-focus-within/order:opacity-100",
55
- "group-focus/order:pointer-events-auto group-focus/order:opacity-100"
56
- ),
57
- grid: cn(
58
- "[.wcdv-tr:hover_&]:pointer-events-auto [.wcdv-tr:hover_&]:opacity-100",
59
- "[.wcdv-tr:focus-within_&]:pointer-events-auto [.wcdv-tr:focus-within_&]:opacity-100"
60
- )
61
- };
62
- function RowActionToolbar({
63
- label,
64
- align = "center",
65
- group = "row",
66
- className,
67
- children
68
- }) {
69
- return /* @__PURE__ */ jsx(
70
- "div",
71
- {
72
- role: "toolbar",
73
- "aria-label": label,
74
- onKeyDown: toolbarKeyNav,
75
- className: cn(
76
- "z-10 ms-auto flex items-center gap-0.5 transition-opacity",
77
- // Inside a grid cell the column already reserves the space, so the
78
- // toolbar stays in flow — no absolute overlay. It keeps the card
79
- // chrome, though: pair with a `sticky end-0` actions column and it
80
- // floats over scrolled-under content at the grid's right edge.
81
- group !== "grid" && [
82
- "pointer-fine:absolute",
83
- ALIGN[align],
84
- "pointer-fine:bg-card pointer-fine:border-border pointer-fine:rounded-md pointer-fine:border pointer-fine:p-0.5 pointer-fine:shadow-sm"
85
- ],
86
- group === "grid" && "bg-card border-border rounded-md border p-0.5 shadow-sm",
87
- "pointer-fine:pointer-events-none pointer-fine:opacity-0",
88
- REVEAL[group],
89
- "focus-within:pointer-events-auto focus-within:opacity-100",
90
- className
91
- ),
92
- children
93
- }
94
- );
95
- }
96
- function RowIconButton({
97
- label,
98
- icon: Icon,
99
- onClick,
100
- active,
101
- expanded,
102
- controls,
103
- size = "md"
104
- }) {
105
- return /* @__PURE__ */ jsx(Tooltip, { content: label, children: /* @__PURE__ */ jsx(
106
- Button,
107
- {
108
- type: "button",
109
- variant: "ghost",
110
- size: "icon",
111
- "aria-label": label,
112
- "aria-pressed": active,
113
- "aria-expanded": expanded,
114
- "aria-controls": controls,
115
- onClick: (e) => {
116
- e.stopPropagation();
117
- onClick();
118
- },
119
- className: cn(
120
- size === "sm" ? "h-7 w-7" : "h-8 w-8",
121
- "shrink-0",
122
- (active || expanded) && "bg-primary-50 text-primary-700 dark:bg-primary-950 dark:text-primary-400"
123
- ),
124
- children: /* @__PURE__ */ jsx(Icon, { size: size === "sm" ? 14 : 16 })
125
- }
126
- ) });
127
- }
128
- var TYPE_ORDER = ["drug", "food", "environmental", "other"];
129
- var ALLERGY_TYPE_LABELS = {
130
- drug: "Drug",
131
- food: "Food",
132
- environmental: "Environmental",
133
- other: "Other"
134
- };
135
- var SEVERITY_BADGE = {
136
- severe: "danger",
137
- moderate: "warning",
138
- mild: "secondary"
139
- };
140
- var DEFAULT_ACTIONS = ["correct", "note", "remove"];
141
- var ACTION_META = {
142
- correct: { label: "Correct", icon: Pencil },
143
- note: { label: "Notes", icon: StickyNote },
144
- remove: { label: "Remove", icon: Ban }
145
- };
146
- function AllergyRow({
147
- allergy,
148
- actions,
149
- readOnly,
150
- drag,
151
- onMove,
152
- onAction
153
- }) {
154
- const handleRowKeyDown = (e) => {
155
- if (e.target !== e.currentTarget) return;
156
- if (e.altKey && (e.key === "ArrowUp" || e.key === "ArrowDown")) {
157
- e.preventDefault();
158
- onMove?.(allergy, e.key === "ArrowUp" ? -1 : 1);
159
- } else if (e.key === "ArrowUp" || e.key === "ArrowDown") {
160
- e.preventDefault();
161
- const list = e.currentTarget.closest("ul");
162
- if (!list) return;
163
- const rows = Array.from(
164
- list.querySelectorAll("li[data-allergy-id]")
165
- );
166
- const i = rows.indexOf(e.currentTarget);
167
- rows[e.key === "ArrowUp" ? Math.max(0, i - 1) : Math.min(rows.length - 1, i + 1)]?.focus();
168
- }
169
- };
170
- return (
171
- // Rows are focus stops when reordering is enabled so drag & drop has a
172
- // keyboard equivalent (Alt+↑/↓) — 508.
173
- /* eslint-disable jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/no-noninteractive-tabindex */
174
- /* @__PURE__ */ jsxs(
175
- "li",
176
- {
177
- "data-slot": "clinical-list-row",
178
- "data-allergy-id": allergy.id,
179
- tabIndex: drag.enabled ? 0 : void 0,
180
- onKeyDown: drag.enabled ? handleRowKeyDown : void 0,
181
- "aria-label": drag.enabled ? `${allergy.allergen}. Alt plus arrow keys to reorder.` : void 0,
182
- ...drag.rowProps(allergy.id),
183
- className: cn(
184
- "group border-border/60 relative flex min-h-11 flex-wrap items-center gap-x-2 gap-y-1 border-b px-1 py-2",
185
- "focus-visible:ring-ring focus-visible:ring-2 focus-visible:outline-none",
186
- drag.enabled && "cursor-grab active:cursor-grabbing",
187
- dragIndicatorClasses(drag, allergy.id)
188
- ),
189
- children: [
190
- drag.enabled ? /* @__PURE__ */ jsx(
191
- GripVertical,
192
- {
193
- size: 14,
194
- "aria-hidden": true,
195
- className: "text-muted-foreground/50 shrink-0"
196
- }
197
- ) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/60 select-none", children: "\u2022" }),
198
- /* @__PURE__ */ jsx(
199
- "span",
200
- {
201
- className: cn(
202
- "text-foreground font-medium",
203
- allergy.inactive && "text-muted-foreground line-through"
204
- ),
205
- children: allergy.allergen
206
- }
207
- ),
208
- allergy.code && /* @__PURE__ */ jsxs(
209
- "span",
210
- {
211
- className: "text-muted-foreground/70 text-xs",
212
- title: allergy.code.display,
213
- children: [
214
- allergy.code.system,
215
- " ",
216
- allergy.code.code
217
- ]
218
- }
219
- ),
220
- allergy.severity && /* @__PURE__ */ jsx(Badge, { variant: SEVERITY_BADGE[allergy.severity], size: "sm", children: allergy.severity }),
221
- allergy.kind === "intolerance" && /* @__PURE__ */ jsx(Badge, { variant: "secondary", size: "sm", children: "intolerance" }),
222
- allergy.reaction && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground text-sm", children: [
223
- "\u2014 ",
224
- allergy.reaction
225
- ] }),
226
- allergy.onsetDate && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground text-xs", children: [
227
- "since ",
228
- allergy.onsetDate
229
- ] }),
230
- allergy.inactive && /* @__PURE__ */ jsx(Badge, { variant: "secondary", size: "sm", children: "inactive" }),
231
- allergy.note && /* @__PURE__ */ jsxs("span", { className: "flex w-full basis-full items-center gap-1.5 ps-4", children: [
232
- /* @__PURE__ */ jsx(StickyNote, { size: 12, className: "text-muted-foreground" }),
233
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs", children: allergy.note })
234
- ] }),
235
- !readOnly && actions.length > 0 && /* @__PURE__ */ jsx(RowActionToolbar, { label: `Actions for ${allergy.allergen}`, children: actions.map((action) => /* @__PURE__ */ jsx(
236
- RowIconButton,
237
- {
238
- label: ACTION_META[action].label,
239
- icon: ACTION_META[action].icon,
240
- onClick: () => onAction?.(allergy, action)
241
- },
242
- action
243
- )) })
244
- ]
245
- }
246
- )
247
- );
248
- }
249
- var AllergyList = React3.forwardRef(
250
- ({
251
- allergies,
252
- noKnownAllergies,
253
- onNoKnownAllergiesChange,
254
- title = "Allergies",
255
- actions = DEFAULT_ACTIONS,
256
- onAction,
257
- onReorder,
258
- addSearch,
259
- onAdd,
260
- readOnly = false,
261
- className,
262
- "data-testid": dataTestId,
263
- ...props
264
- }, ref) => {
265
- const [announcement, setAnnouncement] = useLiveAnnouncement();
266
- const groups = TYPE_ORDER.map((type) => ({
267
- type,
268
- label: ALLERGY_TYPE_LABELS[type],
269
- items: allergies.filter((a) => (a.type ?? "other") === type)
270
- })).filter((g) => g.items.length > 0);
271
- const empty = allergies.length === 0;
272
- const typeOf = React3.useCallback(
273
- (id) => allergies.find((a) => a.id === id)?.type ?? "other",
274
- [allergies]
275
- );
276
- const drag = useDragReorder({
277
- ids: allergies.map((a) => a.id),
278
- onReorder: readOnly || !onReorder ? void 0 : (ids) => {
279
- setAnnouncement("Allergy list reordered");
280
- onReorder(ids);
281
- },
282
- canDropOn: (dragged, target) => typeOf(dragged) === typeOf(target)
283
- });
284
- const moveAllergy = React3.useCallback(
285
- (allergy, dir) => {
286
- if (readOnly || !onReorder) return;
287
- const ids = allergies.map((a) => a.id);
288
- const from = ids.indexOf(allergy.id);
289
- let to = from + dir;
290
- while (to >= 0 && to < allergies.length && (allergies[to].type ?? "other") !== (allergy.type ?? "other")) {
291
- to += dir;
292
- }
293
- if (to < 0 || to >= allergies.length) return;
294
- [ids[from], ids[to]] = [ids[to], ids[from]];
295
- setAnnouncement(
296
- `${allergy.allergen} moved ${dir === -1 ? "up" : "down"}`
297
- );
298
- onReorder(ids);
299
- },
300
- [allergies, onReorder, readOnly, setAnnouncement]
301
- );
302
- return /* @__PURE__ */ jsxs(
303
- Card,
304
- {
305
- ref,
306
- padding: "none",
307
- className: cn("w-full", className),
308
- "data-testid": dataTestId,
309
- ...props,
310
- children: [
311
- title !== null && /* @__PURE__ */ jsx(CardHeader, { className: "border-border bg-muted/50 border-b px-4 py-3", children: /* @__PURE__ */ jsxs("h3", { className: "text-foreground flex items-center gap-2 text-sm font-semibold tracking-wide uppercase", children: [
312
- /* @__PURE__ */ jsx(
313
- AlertCircle,
314
- {
315
- size: 16,
316
- className: "text-red-600 dark:text-red-400"
317
- }
318
- ),
319
- title
320
- ] }) }),
321
- /* @__PURE__ */ jsxs(CardContent, { className: "space-y-5 px-4 py-4", children: [
322
- empty ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
323
- noKnownAllergies ? /* @__PURE__ */ jsxs("p", { className: "text-foreground flex items-center gap-1.5 text-sm", children: [
324
- /* @__PURE__ */ jsx(Badge, { variant: "success", size: "sm", children: "\u2713" }),
325
- "No known allergies (NKA)"
326
- ] }) : /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: "Allergy status not recorded." }),
327
- !readOnly && onNoKnownAllergiesChange && /* @__PURE__ */ jsx(
328
- Button,
329
- {
330
- variant: noKnownAllergies ? "secondary" : "outline",
331
- size: "sm",
332
- onClick: () => onNoKnownAllergiesChange(!noKnownAllergies),
333
- children: noKnownAllergies ? "Clear no-known-allergies" : "Confirm: no known allergies"
334
- }
335
- )
336
- ] }) : groups.map(({ type, label, items }) => /* @__PURE__ */ jsxs("section", { "aria-label": label, children: [
337
- /* @__PURE__ */ jsx(
338
- "h4",
339
- {
340
- "data-slot": "clinical-list-heading",
341
- className: "border-border text-foreground border-b pb-1 text-sm font-semibold tracking-wide uppercase",
342
- children: label
343
- }
344
- ),
345
- /* @__PURE__ */ jsx("ul", { className: "mt-1", children: items.map((allergy) => /* @__PURE__ */ jsx(
346
- AllergyRow,
347
- {
348
- allergy,
349
- actions,
350
- readOnly,
351
- drag,
352
- onMove: moveAllergy,
353
- onAction
354
- },
355
- allergy.id
356
- )) })
357
- ] }, type)),
358
- !readOnly && (addSearch || onAdd) && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
359
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs font-semibold tracking-wide uppercase", children: "Add allergy" }),
360
- addSearch,
361
- onAdd && /* @__PURE__ */ jsx(
362
- Button,
363
- {
364
- variant: "outline",
365
- size: "sm",
366
- onClick: onAdd,
367
- leftIcon: /* @__PURE__ */ jsx(Plus, { size: 12 }),
368
- className: "h-auto rounded-full px-2.5 py-1 text-xs",
369
- children: "Add allergy\u2026"
370
- }
371
- )
372
- ] })
373
- ] }),
374
- /* @__PURE__ */ jsx("div", { "aria-live": "polite", className: "sr-only", children: announcement })
375
- ]
376
- }
377
- );
378
- }
379
- );
380
- AllergyList.displayName = "AllergyList";
381
- var CodeLookupContext = React3.createContext(
382
- null
383
- );
384
- function CodeLookupProvider({
385
- component,
386
- indexUrl = "/codify",
387
- locale = "en",
388
- memory,
389
- children
390
- }) {
391
- const value = React3.useMemo(
392
- () => ({ component, indexUrl, locale, memory }),
393
- [component, indexUrl, locale, memory]
394
- );
395
- return /* @__PURE__ */ jsx(CodeLookupContext.Provider, { value, children });
396
- }
397
- function useCodeLookupConfig() {
398
- return React3.useContext(CodeLookupContext);
399
- }
400
- function newId() {
401
- return `alg-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
402
- }
403
- var TYPE_OPTIONS = [
404
- { value: "drug", label: "Drug" },
405
- { value: "food", label: "Food" },
406
- { value: "environmental", label: "Environmental" },
407
- { value: "other", label: "Other" }
408
- ];
409
- function AllergyEditor({
410
- allergy,
411
- codeLookup,
412
- onClose,
413
- onSave
414
- }) {
415
- const [draft, setDraft] = React3.useState(
416
- () => allergy ?? { id: newId(), allergen: "", type: "drug" }
417
- );
418
- const patch = (p) => setDraft((prev) => ({ ...prev, ...p }));
419
- const bodyRef = React3.useRef(null);
420
- React3.useEffect(() => {
421
- bodyRef.current?.querySelector("input")?.focus();
422
- }, []);
423
- const canSave = draft.allergen.trim().length > 0;
424
- const isDrug = (draft.type ?? "drug") === "drug";
425
- return /* @__PURE__ */ jsxs(Modal, { open: true, onOpenChange: (o) => !o && onClose(), size: "md", children: [
426
- /* @__PURE__ */ jsxs(ModalHeader, { children: [
427
- /* @__PURE__ */ jsx(ModalTitle, { children: allergy ? "Correct Allergy" : "Add Allergy" }),
428
- /* @__PURE__ */ jsx(ModalClose, {})
429
- ] }),
430
- /* @__PURE__ */ jsx(ModalBody, { className: "space-y-4", children: /* @__PURE__ */ jsxs("div", { ref: bodyRef, className: "contents", children: [
431
- /* @__PURE__ */ jsxs(
432
- RadioGroup,
433
- {
434
- name: "alg-kind",
435
- label: "Mechanism",
436
- description: "A true immune-mediated allergy, or a non-immune intolerance (e.g. GI upset)",
437
- value: draft.kind ?? "allergy",
438
- onValueChange: (v) => patch({ kind: v }),
439
- orientation: "horizontal",
440
- size: "sm",
441
- children: [
442
- /* @__PURE__ */ jsx(Radio, { value: "allergy", label: "Allergy" }),
443
- /* @__PURE__ */ jsx(Radio, { value: "intolerance", label: "Intolerance" })
444
- ]
445
- }
446
- ),
447
- /* @__PURE__ */ jsx(
448
- Select,
449
- {
450
- label: "Type",
451
- options: TYPE_OPTIONS,
452
- value: draft.type ?? "drug",
453
- onValueChange: (v) => {
454
- const type = v;
455
- patch({
456
- type,
457
- ...type !== "drug" && { code: void 0 }
458
- });
459
- }
460
- }
461
- ),
462
- isDrug && codeLookup ? /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
463
- /* @__PURE__ */ jsx(Label, { htmlFor: "alg-search", children: "Allergen" }),
464
- /* @__PURE__ */ jsx(
465
- codeLookup.component,
466
- {
467
- indexUrl: codeLookup.indexUrl,
468
- locale: codeLookup.locale,
469
- domains: ["med"],
470
- bare: true,
471
- clearOnSelect: false,
472
- placeholder: "Search drug allergens \u2014 e.g. penicillin",
473
- onSelect: (result) => patch({
474
- allergen: result.label,
475
- code: {
476
- system: result.codetype,
477
- code: result.fullcode,
478
- display: result.label
479
- }
480
- }),
481
- onFreeText: (text) => patch({ allergen: text, code: void 0 })
482
- }
483
- ),
484
- /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-xs", children: draft.code ? `Coded: ${draft.code.system} ${draft.code.code}` : draft.allergen ? `Uncoded free text: "${draft.allergen}"` : "Pick a result to code the allergen, or press Enter for free text" })
485
- ] }) : /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
486
- /* @__PURE__ */ jsx(Label, { htmlFor: "alg-name", children: "Allergen" }),
487
- /* @__PURE__ */ jsx(
488
- Input,
489
- {
490
- id: "alg-name",
491
- value: draft.allergen,
492
- onChange: (e) => patch({ allergen: e.target.value })
493
- }
494
- )
495
- ] }),
496
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
497
- /* @__PURE__ */ jsx(Label, { htmlFor: "alg-reaction", children: "Reaction" }),
498
- /* @__PURE__ */ jsx(
499
- Input,
500
- {
501
- id: "alg-reaction",
502
- value: draft.reaction ?? "",
503
- onChange: (e) => patch({ reaction: e.target.value })
504
- }
505
- )
506
- ] }),
507
- /* @__PURE__ */ jsxs(
508
- RadioGroup,
509
- {
510
- name: "alg-severity",
511
- label: "Severity",
512
- value: draft.severity ?? "",
513
- onValueChange: (v) => patch({ severity: v || void 0 }),
514
- orientation: "horizontal",
515
- size: "sm",
516
- children: [
517
- /* @__PURE__ */ jsx(Radio, { value: "mild", label: "Mild" }),
518
- /* @__PURE__ */ jsx(Radio, { value: "moderate", label: "Moderate" }),
519
- /* @__PURE__ */ jsx(Radio, { value: "severe", label: "Severe" })
520
- ]
521
- }
522
- ),
523
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
524
- /* @__PURE__ */ jsx(Label, { htmlFor: "alg-onset", children: "Onset date" }),
525
- /* @__PURE__ */ jsx(
526
- DateInput,
527
- {
528
- id: "alg-onset",
529
- value: draft.onsetDate ?? "",
530
- onChange: (v) => patch({ onsetDate: v })
531
- }
532
- )
533
- ] }),
534
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
535
- /* @__PURE__ */ jsx(Label, { htmlFor: "alg-note", children: "Note" }),
536
- /* @__PURE__ */ jsx(
537
- Textarea,
538
- {
539
- id: "alg-note",
540
- value: draft.note ?? "",
541
- onChange: (e) => patch({ note: e.target.value }),
542
- rows: 2
543
- }
544
- )
545
- ] })
546
- ] }) }),
547
- /* @__PURE__ */ jsxs(ModalFooter, { children: [
548
- /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: onClose, children: "Cancel" }),
549
- /* @__PURE__ */ jsx(
550
- Button,
551
- {
552
- onClick: () => {
553
- onSave({ ...draft, allergen: draft.allergen.trim() });
554
- onClose();
555
- },
556
- disabled: !canSave,
557
- children: "Save"
558
- }
559
- )
560
- ] })
561
- ] });
562
- }
563
- function AllergyManager({
564
- allergies: controlled,
565
- defaultAllergies,
566
- onChange,
567
- noKnownAllergies,
568
- onNoKnownAllergiesChange,
569
- title = "Allergies",
570
- codeLookup,
571
- inlineAddSearch = false,
572
- readOnly = false,
573
- className,
574
- "data-testid": dataTestId
575
- }) {
576
- const isControlled = controlled !== void 0;
577
- const [internal, setInternal] = React3.useState(
578
- defaultAllergies ?? []
579
- );
580
- const allergies = isControlled ? controlled : internal;
581
- const ambientCodeLookup = useCodeLookupConfig();
582
- const effectiveCodeLookup = codeLookup === false ? void 0 : codeLookup ?? ambientCodeLookup ?? void 0;
583
- const [dialog, setDialog] = React3.useState(null);
584
- const [noteDraft, setNoteDraft] = React3.useState("");
585
- const commit = (next) => {
586
- if (!isControlled) setInternal(next);
587
- onChange?.(next);
588
- if (next.length > 0 && noKnownAllergies) {
589
- onNoKnownAllergiesChange?.(false);
590
- }
591
- };
592
- const handleAction = (allergy, action) => {
593
- switch (action) {
594
- case "remove":
595
- commit(allergies.filter((a) => a.id !== allergy.id));
596
- break;
597
- case "correct":
598
- setDialog({ kind: "correct", allergy });
599
- break;
600
- case "note":
601
- setNoteDraft(allergy.note ?? "");
602
- setDialog({ kind: "note", allergy });
603
- break;
604
- }
605
- };
606
- const addSearch = inlineAddSearch && effectiveCodeLookup && !readOnly ? /* @__PURE__ */ jsx(
607
- effectiveCodeLookup.component,
608
- {
609
- indexUrl: effectiveCodeLookup.indexUrl,
610
- locale: effectiveCodeLookup.locale,
611
- domains: ["med"],
612
- bare: true,
613
- clearOnSelect: true,
614
- placeholder: "Search drug allergens to add \u2014 use Add allergy\u2026 for food/environmental",
615
- onSelect: (result) => commit([
616
- ...allergies,
617
- {
618
- id: newId(),
619
- allergen: result.label,
620
- type: "drug",
621
- code: {
622
- system: result.codetype,
623
- code: result.fullcode,
624
- display: result.label
625
- }
626
- }
627
- ]),
628
- onFreeText: (text) => (
629
- // this search bar is explicitly for drug allergens — free-text
630
- // entries carry type 'drug' like the coded path
631
- commit([...allergies, { id: newId(), allergen: text, type: "drug" }])
632
- )
633
- }
634
- ) : void 0;
635
- return /* @__PURE__ */ jsxs(Fragment, { children: [
636
- /* @__PURE__ */ jsx(
637
- AllergyList,
638
- {
639
- allergies,
640
- noKnownAllergies,
641
- onNoKnownAllergiesChange,
642
- title,
643
- onAction: handleAction,
644
- onReorder: (ids) => commit(
645
- [...allergies].sort((a, b) => ids.indexOf(a.id) - ids.indexOf(b.id))
646
- ),
647
- addSearch,
648
- onAdd: () => setDialog({ kind: "add" }),
649
- readOnly,
650
- className,
651
- "data-testid": dataTestId
652
- }
653
- ),
654
- dialog && (dialog.kind === "correct" || dialog.kind === "add") && /* @__PURE__ */ jsx(
655
- AllergyEditor,
656
- {
657
- allergy: dialog.kind === "correct" ? dialog.allergy : void 0,
658
- codeLookup: effectiveCodeLookup,
659
- onClose: () => setDialog(null),
660
- onSave: (saved) => {
661
- if (dialog.kind === "correct") {
662
- commit(allergies.map((a) => a.id === saved.id ? saved : a));
663
- } else {
664
- commit([...allergies, saved]);
665
- }
666
- }
667
- },
668
- dialog.kind === "correct" ? dialog.allergy.id : "add"
669
- ),
670
- dialog?.kind === "note" && /* @__PURE__ */ jsxs(Modal, { open: true, onOpenChange: (o) => !o && setDialog(null), size: "md", children: [
671
- /* @__PURE__ */ jsxs(ModalHeader, { children: [
672
- /* @__PURE__ */ jsx(ModalTitle, { children: "Allergy Notes" }),
673
- /* @__PURE__ */ jsx(ModalClose, {})
674
- ] }),
675
- /* @__PURE__ */ jsxs(ModalBody, { className: "space-y-4", children: [
676
- /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: dialog.allergy.allergen }),
677
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
678
- /* @__PURE__ */ jsx(Label, { htmlFor: "alg-note-dlg", children: "Note" }),
679
- /* @__PURE__ */ jsx(
680
- Textarea,
681
- {
682
- id: "alg-note-dlg",
683
- value: noteDraft,
684
- onChange: (e) => setNoteDraft(e.target.value),
685
- rows: 4
686
- }
687
- )
688
- ] })
689
- ] }),
690
- /* @__PURE__ */ jsxs(ModalFooter, { children: [
691
- /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => setDialog(null), children: "Cancel" }),
692
- /* @__PURE__ */ jsx(
693
- Button,
694
- {
695
- onClick: () => {
696
- commit(
697
- allergies.map(
698
- (a) => a.id === dialog.allergy.id ? { ...a, note: noteDraft.trim() || void 0 } : a
699
- )
700
- );
701
- setDialog(null);
702
- },
703
- children: "Save"
704
- }
705
- )
706
- ] })
707
- ] })
708
- ] });
709
- }
710
- var GROUP_ORDER = [
711
- "unreconciled",
712
- "taking",
713
- "taking-noncompliant",
714
- "not-taking",
715
- "unknown"
716
- ];
717
- var MEDICATION_STATUS_LABELS = {
718
- unreconciled: "Unreconciled",
719
- taking: "Taking as Directed",
720
- "taking-noncompliant": "Not Taking as Directed",
721
- "not-taking": "Not Taking",
722
- unknown: "Unknown"
723
- };
724
- var DEFAULT_ACTIONS2 = [
725
- "open",
726
- "correct",
727
- "refill",
728
- "add-task",
729
- "note",
730
- "remove"
731
- ];
732
- var ACTION_META2 = {
733
- open: { label: "Open", icon: ExternalLink },
734
- correct: { label: "Correct", icon: Pencil },
735
- refill: { label: "Refill", icon: RefreshCw },
736
- "add-task": { label: "Add Task", icon: CalendarCheck },
737
- note: { label: "Notes", icon: StickyNote },
738
- remove: { label: "Remove", icon: Ban },
739
- "move-up": { label: "Move Up", icon: ChevronUp },
740
- "move-down": { label: "Move Down", icon: ChevronDown }
741
- };
742
- var STATUS_BUTTON_META = [
743
- { status: "taking", label: "Taking", icon: ThumbsUp },
744
- {
745
- status: "taking-noncompliant",
746
- label: "Taking \u2013 Noncompliant",
747
- icon: HandMetal
748
- },
749
- { status: "not-taking", label: "Not Taking", icon: ThumbsDown },
750
- { status: "unknown", label: "Unknown", icon: HelpCircle }
751
- ];
752
- function MedicationRow({
753
- medication,
754
- actions,
755
- readOnly,
756
- drag,
757
- onMove,
758
- onStatusChange,
759
- onAction
760
- }) {
761
- const handleRowKeyDown = (e) => {
762
- if (e.target !== e.currentTarget) return;
763
- if (e.altKey && (e.key === "ArrowUp" || e.key === "ArrowDown")) {
764
- e.preventDefault();
765
- onMove?.(medication, e.key === "ArrowUp" ? -1 : 1);
766
- } else if (e.key === "ArrowUp" || e.key === "ArrowDown") {
767
- e.preventDefault();
768
- const list = e.currentTarget.closest("ul");
769
- if (!list) return;
770
- const rows = Array.from(
771
- list.querySelectorAll("li[data-medication-id]")
772
- );
773
- const i = rows.indexOf(e.currentTarget);
774
- rows[e.key === "ArrowUp" ? Math.max(0, i - 1) : Math.min(rows.length - 1, i + 1)]?.focus();
775
- }
776
- };
777
- return (
778
- // Rows are focus stops when reordering is enabled so drag & drop has a
779
- // keyboard equivalent (Alt+↑/↓) — 508.
780
- /* eslint-disable jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/no-noninteractive-tabindex */
781
- /* @__PURE__ */ jsxs(
782
- "li",
783
- {
784
- "data-slot": "clinical-list-row",
785
- "data-medication-id": medication.id,
786
- tabIndex: drag.enabled ? 0 : void 0,
787
- onKeyDown: drag.enabled ? handleRowKeyDown : void 0,
788
- "aria-label": drag.enabled ? `${medication.name}. Alt plus arrow keys to reorder.` : void 0,
789
- ...drag.rowProps(medication.id),
790
- className: cn(
791
- "group border-border/60 relative flex min-h-11 flex-wrap items-center gap-x-2 gap-y-1 border-b px-1 py-2",
792
- "focus-visible:ring-ring focus-visible:ring-2 focus-visible:outline-none",
793
- drag.enabled && "cursor-grab active:cursor-grabbing",
794
- dragIndicatorClasses(drag, medication.id)
795
- ),
796
- children: [
797
- drag.enabled ? /* @__PURE__ */ jsx(
798
- GripVertical,
799
- {
800
- size: 14,
801
- "aria-hidden": true,
802
- className: "text-muted-foreground/50 shrink-0"
803
- }
804
- ) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/60 select-none", children: "\u2022" }),
805
- /* @__PURE__ */ jsx("span", { className: "text-foreground font-medium", children: medication.name }),
806
- medication.code && /* @__PURE__ */ jsxs(
807
- "span",
808
- {
809
- className: "text-muted-foreground/70 text-xs",
810
- title: medication.code.display,
811
- children: [
812
- medication.code.system,
813
- " ",
814
- medication.code.code
815
- ]
816
- }
817
- ),
818
- medication.sig && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm", children: medication.sig }),
819
- medication.expired && /* @__PURE__ */ jsx("span", { className: "text-sm font-bold text-red-600 dark:text-red-400", children: "EXPIRED" }),
820
- medication.discontinuedDate && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground text-sm", children: [
821
- "Discontinued on: ",
822
- medication.discontinuedDate
823
- ] }),
824
- (medication.note || medication.task) && /* @__PURE__ */ jsxs("span", { className: "flex w-full basis-full flex-col gap-0.5 ps-4", children: [
825
- medication.note && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground flex items-center gap-1.5 text-xs", children: [
826
- /* @__PURE__ */ jsx(StickyNote, { size: 12 }),
827
- medication.note
828
- ] }),
829
- medication.task && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground flex items-center gap-1.5 text-xs", children: [
830
- /* @__PURE__ */ jsx(CalendarCheck, { size: 12 }),
831
- "Task: ",
832
- medication.task
833
- ] })
834
- ] }),
835
- !readOnly && /* @__PURE__ */ jsxs(RowActionToolbar, { label: `Actions for ${medication.name}`, children: [
836
- actions.includes("open") && /* @__PURE__ */ jsx(
837
- RowIconButton,
838
- {
839
- label: ACTION_META2.open.label,
840
- icon: ACTION_META2.open.icon,
841
- onClick: () => onAction?.(medication, "open")
842
- }
843
- ),
844
- STATUS_BUTTON_META.map(({ status, label, icon }) => /* @__PURE__ */ jsx(
845
- RowIconButton,
846
- {
847
- label,
848
- icon,
849
- active: medication.status === status,
850
- onClick: () => onStatusChange?.(medication, status)
851
- },
852
- status
853
- )),
854
- actions.filter((a) => a !== "open").map((action) => /* @__PURE__ */ jsx(
855
- RowIconButton,
856
- {
857
- label: ACTION_META2[action].label,
858
- icon: ACTION_META2[action].icon,
859
- onClick: () => onAction?.(medication, action)
860
- },
861
- action
862
- ))
863
- ] })
864
- ]
865
- }
866
- )
867
- );
868
- }
869
- var MedicationList = React3.forwardRef(
870
- ({
871
- medications,
872
- title = "Presenting medications",
873
- onStatusChange,
874
- onAction,
875
- onReorder,
876
- actions = DEFAULT_ACTIONS2,
877
- quickAddOptions,
878
- onQuickAdd,
879
- onAddOther,
880
- readOnly = false,
881
- reconciledMessage = "All medications reconciled.",
882
- emptyMessage = "No medications recorded.",
883
- addSearch,
884
- className,
885
- "data-testid": dataTestId,
886
- ...props
887
- }, ref) => {
888
- const [announcement, setAnnouncement] = useLiveAnnouncement();
889
- const handleStatusChange = React3.useCallback(
890
- (medication, status) => {
891
- setAnnouncement(
892
- `${medication.name} marked ${MEDICATION_STATUS_LABELS[status]}`
893
- );
894
- onStatusChange?.(medication, status);
895
- },
896
- [onStatusChange, setAnnouncement]
897
- );
898
- const groups = GROUP_ORDER.map((status) => ({
899
- status,
900
- label: MEDICATION_STATUS_LABELS[status],
901
- items: medications.filter((m) => m.status === status)
902
- })).filter((g) => g.items.length > 0 || g.status === "unreconciled");
903
- const statusById = React3.useMemo(
904
- () => new Map(medications.map((m) => [m.id, m.status])),
905
- [medications]
906
- );
907
- const statusOf = React3.useCallback(
908
- (id) => statusById.get(id),
909
- [statusById]
910
- );
911
- const drag = useDragReorder({
912
- ids: medications.map((m) => m.id),
913
- onReorder: readOnly || !onReorder ? void 0 : (ids) => {
914
- setAnnouncement("Medication list reordered");
915
- onReorder(ids);
916
- },
917
- canDropOn: (dragged, target) => statusOf(dragged) === statusOf(target)
918
- });
919
- const moveMedication = React3.useCallback(
920
- (medication, dir) => {
921
- if (readOnly || !onReorder) return;
922
- const ids = medications.map((m) => m.id);
923
- const from = ids.indexOf(medication.id);
924
- let to = from + dir;
925
- while (to >= 0 && to < medications.length && medications[to].status !== medication.status) {
926
- to += dir;
927
- }
928
- if (to < 0 || to >= medications.length) return;
929
- [ids[from], ids[to]] = [ids[to], ids[from]];
930
- setAnnouncement(
931
- `${medication.name} moved ${dir === -1 ? "up" : "down"}`
932
- );
933
- onReorder(ids);
934
- },
935
- [medications, onReorder, readOnly, setAnnouncement]
936
- );
937
- return /* @__PURE__ */ jsxs(
938
- Card,
939
- {
940
- ref,
941
- padding: "none",
942
- className: cn("w-full", className),
943
- "data-testid": dataTestId,
944
- ...props,
945
- children: [
946
- title !== null && /* @__PURE__ */ jsx(CardHeader, { className: "border-border bg-muted/50 border-b px-4 py-3", children: /* @__PURE__ */ jsx("h3", { className: "text-foreground text-sm font-semibold tracking-wide uppercase", children: title }) }),
947
- /* @__PURE__ */ jsxs(CardContent, { className: "space-y-6 px-4 py-4", children: [
948
- groups.map(({ status, label, items }) => /* @__PURE__ */ jsxs("section", { "aria-label": label, children: [
949
- /* @__PURE__ */ jsx(
950
- "h4",
951
- {
952
- "data-slot": "clinical-list-heading",
953
- className: "border-border text-foreground border-b pb-1 text-sm font-semibold tracking-wide uppercase",
954
- children: label
955
- }
956
- ),
957
- items.length > 0 ? /* @__PURE__ */ jsx("ul", { className: "mt-1", children: items.map((medication) => /* @__PURE__ */ jsx(
958
- MedicationRow,
959
- {
960
- medication,
961
- actions,
962
- readOnly,
963
- drag,
964
- onMove: moveMedication,
965
- onStatusChange: handleStatusChange,
966
- onAction
967
- },
968
- medication.id
969
- )) }) : medications.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-muted-foreground mt-2 text-sm", children: emptyMessage }) : /* @__PURE__ */ jsxs("p", { className: "text-muted-foreground mt-2 flex items-center gap-1.5 text-sm", children: [
970
- /* @__PURE__ */ jsx(Badge, { variant: "success", size: "sm", children: "\u2713" }),
971
- reconciledMessage
972
- ] })
973
- ] }, status)),
974
- !readOnly && (addSearch || quickAddOptions?.length || onAddOther) && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
975
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs font-semibold tracking-wide uppercase", children: "Add medication" }),
976
- addSearch,
977
- (quickAddOptions?.length || onAddOther) && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [
978
- quickAddOptions?.map((name) => /* @__PURE__ */ jsx(
979
- Button,
980
- {
981
- variant: "ghost",
982
- size: "sm",
983
- onClick: () => onQuickAdd?.(name),
984
- leftIcon: /* @__PURE__ */ jsx(Plus, { size: 12 }),
985
- className: "border-border h-auto rounded-full border px-2.5 py-1 text-xs",
986
- children: name
987
- },
988
- name
989
- )),
990
- onAddOther && /* @__PURE__ */ jsx(
991
- Button,
992
- {
993
- variant: "outline",
994
- size: "sm",
995
- onClick: onAddOther,
996
- leftIcon: /* @__PURE__ */ jsx(Plus, { size: 12 }),
997
- className: "h-auto rounded-full px-2.5 py-1 text-xs",
998
- children: "Other\u2026"
999
- }
1000
- )
1001
- ] })
1002
- ] })
1003
- ] }),
1004
- /* @__PURE__ */ jsx("div", { "aria-live": "polite", className: "sr-only", children: announcement })
1005
- ]
1006
- }
1007
- );
1008
- }
1009
- );
1010
- MedicationList.displayName = "MedicationList";
1011
- var DOSE_FORMS = [
1012
- "tablet",
1013
- "capsule",
1014
- "solution",
1015
- "suspension",
1016
- "syrup",
1017
- "cream",
1018
- "ointment",
1019
- "gel",
1020
- "patch",
1021
- "suppository",
1022
- "spray",
1023
- "drops",
1024
- "inhaler",
1025
- "injection",
1026
- "lozenge",
1027
- "powder",
1028
- "film"
1029
- ];
1030
- var FORM_TO_UNIT = {
1031
- tablet: "tablet",
1032
- capsule: "capsule",
1033
- solution: "milliliter",
1034
- suspension: "milliliter",
1035
- syrup: "milliliter",
1036
- cream: "gram",
1037
- ointment: "gram",
1038
- gel: "gram",
1039
- patch: "patch",
1040
- suppository: "suppository",
1041
- spray: "spray",
1042
- drops: "milliliter",
1043
- inhaler: "each",
1044
- injection: "milliliter",
1045
- lozenge: "each",
1046
- powder: "gram",
1047
- film: "each"
1048
- };
1049
- function parseMedicationLabel(label) {
1050
- const lower = label.toLowerCase();
1051
- const strengthMatch = lower.match(
1052
- /(\d{1,7}(?:\.\d{1,4})?(?:\s{0,4}\/\s{0,4}\d{1,7}(?:\.\d{1,4})?)?)\s{0,4}(mg\/ml|mcg\/ml|mg|mcg|g|ml|units?|%|meq)\b/
1053
- );
1054
- const doseForm = DOSE_FORMS.find((f) => lower.includes(f));
1055
- return {
1056
- strength: strengthMatch ? `${strengthMatch[1].replace(/\s+/g, "")} ${strengthMatch[2]}` : void 0,
1057
- doseForm
1058
- };
1059
- }
1060
- var SIG_ROUTES = [
1061
- [/\bby mouth\b|\boral(ly)?\b|\bpo\b/, "oral"],
1062
- [/\bsublingual(ly)?\b|\bunder the tongue\b|\bsl\b/, "sublingual"],
1063
- [/\bsubcutaneous(ly)?\b|\bsubq\b|\bsc\b|\bsq\b/, "subcutaneous"],
1064
- [/\bintramuscular(ly)?\b|\bim\b/, "intramuscular"],
1065
- [/\bintravenous(ly)?\b|\biv\b/, "intravenous"],
1066
- [/\binhal(e|ation|ed)\b|\bpuffs?\b|\bnebuliz/, "inhalation"],
1067
- [/\beyes?\b|\bophthalmic\b/, "ophthalmic"],
1068
- [/\bears?\b|\botic\b/, "otic"],
1069
- [/\bnostrils?\b|\bnasal(ly)?\b|\bintranasal/, "nasal"],
1070
- [/\brectal(ly)?\b|\bpr\b/, "rectal"],
1071
- [/\btransdermal\b|\bto (the )?skin\b|\bapply\b|\btopical(ly)?\b/, "topical"]
1072
- ];
1073
- var SIG_FREQUENCIES = [
1074
- [/\bevery other day\b|\bqod\b/, "Every other day"],
1075
- [/\btwice (a |per )?day\b|\btwice daily\b|\bbid\b/, "Twice daily"],
1076
- [
1077
- /\b(three times|3 times)( a| per)? day\b|\b(three times|3 times) daily\b|\btid\b/,
1078
- "Three times daily"
1079
- ],
1080
- [
1081
- /\b(four times|4 times)( a| per)? day\b|\b(four times|4 times) daily\b|\bqid\b/,
1082
- "Four times daily"
1083
- ],
1084
- [/\bevery morning\b|\bqam\b/, "Every morning"],
1085
- [/\b(at )?bedtime\b|\bqhs\b|\bat night\b/, "Every bedtime"],
1086
- [/\bweekly\b|\bonce a week\b|\bevery week\b/, "Weekly"],
1087
- [
1088
- /\bonce (a |per )?day\b|\bonce daily\b|\bdaily\b|\bevery day\b|\bqd\b/,
1089
- "Once daily"
1090
- ]
1091
- ];
1092
- function parseSig(sig) {
1093
- const lower = sig.toLowerCase();
1094
- const route = SIG_ROUTES.find(([re]) => re.test(lower))?.[1];
1095
- const frequency = SIG_FREQUENCIES.find(([re]) => re.test(lower))?.[1];
1096
- const prn = /\bas needed\b|\bprn\b/.test(lower);
1097
- return { route, frequency, prn };
1098
- }
1099
- function labelToMedicationFields(label) {
1100
- const { strength, doseForm } = parseMedicationLabel(label);
1101
- return {
1102
- ...strength && { strength },
1103
- ...doseForm && {
1104
- doseForm,
1105
- quantityUnit: FORM_TO_UNIT[doseForm] ?? doseForm
1106
- }
1107
- };
1108
- }
1109
- function lookupToMedicationFields(result) {
1110
- return {
1111
- name: result.label,
1112
- code: {
1113
- system: result.codetype,
1114
- code: result.fullcode,
1115
- display: result.label
1116
- },
1117
- ...labelToMedicationFields(result.label)
1118
- };
1119
- }
1120
- function newId2() {
1121
- return `med-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
1122
- }
1123
- function MedicationEditor({
1124
- open,
1125
- medication,
1126
- codeLookup,
1127
- onClose,
1128
- onSave
1129
- }) {
1130
- const ambientCodeLookup = useCodeLookupConfig();
1131
- const effectiveCodeLookup = codeLookup === false ? void 0 : codeLookup ?? ambientCodeLookup ?? void 0;
1132
- const [draft, setDraft] = React3.useState(
1133
- () => medication ?? {
1134
- id: newId2(),
1135
- name: "",
1136
- status: "unreconciled"
1137
- }
1138
- );
1139
- const bodyRef = React3.useRef(null);
1140
- React3.useEffect(() => {
1141
- const input = bodyRef.current?.querySelector("input");
1142
- input?.focus();
1143
- }, []);
1144
- const patch = (p) => setDraft((prev) => ({ ...prev, ...p }));
1145
- const handleCodeSelect = (result) => {
1146
- patch(lookupToMedicationFields(result));
1147
- };
1148
- const handleSigChange = (sig) => {
1149
- const { route, frequency, prn } = parseSig(sig);
1150
- patch({ sig, route, frequency, prn: prn || void 0 });
1151
- };
1152
- const canSave = draft.name.trim().length > 0;
1153
- if (!open) return null;
1154
- return /* @__PURE__ */ jsxs(Modal, { open: true, onOpenChange: (o) => !o && onClose(), size: "lg", children: [
1155
- /* @__PURE__ */ jsxs(ModalHeader, { children: [
1156
- /* @__PURE__ */ jsx(ModalTitle, { children: medication ? "Correct Medication" : "Add Medication" }),
1157
- /* @__PURE__ */ jsx(ModalClose, {})
1158
- ] }),
1159
- /* @__PURE__ */ jsx(ModalBody, { className: "space-y-5", children: /* @__PURE__ */ jsxs("div", { ref: bodyRef, className: "contents", children: [
1160
- /* @__PURE__ */ jsxs("section", { className: "space-y-3", "aria-label": "Medication", children: [
1161
- effectiveCodeLookup ? /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1162
- /* @__PURE__ */ jsx(Label, { htmlFor: "med-search", children: "Medication" }),
1163
- /* @__PURE__ */ jsx(
1164
- effectiveCodeLookup.component,
1165
- {
1166
- indexUrl: effectiveCodeLookup.indexUrl,
1167
- locale: effectiveCodeLookup.locale,
1168
- domains: ["med"],
1169
- bare: true,
1170
- clearOnSelect: false,
1171
- placeholder: "Search RxNorm / FDB \u2014 e.g. lisinopril",
1172
- initialQuery: medication?.name || void 0,
1173
- initialSearch: medication ? !medication.code : void 0,
1174
- onSelect: handleCodeSelect,
1175
- onFreeText: (text) => patch({ name: text, code: void 0 })
1176
- }
1177
- ),
1178
- /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-xs", children: draft.code ? `Coded: ${draft.code.system} ${draft.code.code}` : draft.name ? `Uncoded free text: "${draft.name}" \u2014 pick a result to code it` : "Pick a result to code the medication, or press Enter for free text" })
1179
- ] }) : /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1180
- /* @__PURE__ */ jsx(Label, { htmlFor: "med-name", children: "Medication" }),
1181
- /* @__PURE__ */ jsx(
1182
- Input,
1183
- {
1184
- id: "med-name",
1185
- value: draft.name,
1186
- onChange: (e) => patch({ name: e.target.value })
1187
- }
1188
- )
1189
- ] }),
1190
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3", children: [
1191
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1192
- /* @__PURE__ */ jsx(Label, { htmlFor: "med-strength", children: "Strength" }),
1193
- /* @__PURE__ */ jsx(
1194
- Input,
1195
- {
1196
- id: "med-strength",
1197
- value: draft.strength ?? "",
1198
- onChange: (e) => patch({ strength: e.target.value })
1199
- }
1200
- )
1201
- ] }),
1202
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1203
- /* @__PURE__ */ jsx(Label, { htmlFor: "med-form", children: "Dose form" }),
1204
- /* @__PURE__ */ jsx(
1205
- Input,
1206
- {
1207
- id: "med-form",
1208
- value: draft.doseForm ?? "",
1209
- onChange: (e) => {
1210
- const doseForm = e.target.value;
1211
- const normalized = doseForm.toLowerCase().trim();
1212
- patch({
1213
- doseForm,
1214
- quantityUnit: (FORM_TO_UNIT[normalized] ?? normalized) || void 0
1215
- });
1216
- }
1217
- }
1218
- )
1219
- ] })
1220
- ] })
1221
- ] }),
1222
- /* @__PURE__ */ jsxs("section", { className: "space-y-3", "aria-label": "Dispensing", children: [
1223
- /* @__PURE__ */ jsx("h4", { className: "text-muted-foreground text-xs font-semibold tracking-wide uppercase", children: "Dispensing" }),
1224
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-3 gap-3", children: [
1225
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1226
- /* @__PURE__ */ jsxs(Label, { htmlFor: "med-qty", children: [
1227
- "Quantity",
1228
- draft.quantityUnit ? ` (${draft.quantityUnit}s)` : ""
1229
- ] }),
1230
- /* @__PURE__ */ jsx(
1231
- Input,
1232
- {
1233
- id: "med-qty",
1234
- inputMode: "decimal",
1235
- value: draft.quantity ?? "",
1236
- onChange: (e) => patch({ quantity: e.target.value })
1237
- }
1238
- )
1239
- ] }),
1240
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1241
- /* @__PURE__ */ jsx(Label, { htmlFor: "med-days", children: "Days supply" }),
1242
- /* @__PURE__ */ jsx(
1243
- Input,
1244
- {
1245
- id: "med-days",
1246
- inputMode: "numeric",
1247
- value: draft.daysSupply ?? "",
1248
- onChange: (e) => patch({ daysSupply: e.target.value })
1249
- }
1250
- )
1251
- ] }),
1252
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1253
- /* @__PURE__ */ jsx(Label, { htmlFor: "med-refills", children: "Refills" }),
1254
- /* @__PURE__ */ jsx(
1255
- Input,
1256
- {
1257
- id: "med-refills",
1258
- inputMode: "numeric",
1259
- value: draft.refills ?? "",
1260
- onChange: (e) => patch({ refills: e.target.value })
1261
- }
1262
- )
1263
- ] })
1264
- ] }),
1265
- /* @__PURE__ */ jsxs(
1266
- RadioGroup,
1267
- {
1268
- name: "med-substitution",
1269
- label: "Substitution",
1270
- value: draft.substitution ?? "0",
1271
- onValueChange: (v) => patch({ substitution: v }),
1272
- orientation: "horizontal",
1273
- size: "sm",
1274
- children: [
1275
- /* @__PURE__ */ jsx(Radio, { value: "0", label: "Substitution permitted" }),
1276
- /* @__PURE__ */ jsx(Radio, { value: "1", label: "Dispense as written (DAW)" })
1277
- ]
1278
- }
1279
- )
1280
- ] }),
1281
- /* @__PURE__ */ jsxs("section", { className: "space-y-3", "aria-label": "Directions", children: [
1282
- /* @__PURE__ */ jsx("h4", { className: "text-muted-foreground text-xs font-semibold tracking-wide uppercase", children: "Directions" }),
1283
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1284
- /* @__PURE__ */ jsx(Label, { htmlFor: "med-sig", children: "Sig (patient directions)" }),
1285
- /* @__PURE__ */ jsx(
1286
- Textarea,
1287
- {
1288
- id: "med-sig",
1289
- value: draft.sig ?? "",
1290
- onChange: (e) => handleSigChange(e.target.value),
1291
- rows: 2
1292
- }
1293
- ),
1294
- /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-xs", "aria-live": "polite", children: draft.route || draft.frequency || draft.prn ? /* @__PURE__ */ jsxs(Fragment, { children: [
1295
- "Derived:",
1296
- " ",
1297
- [
1298
- draft.route && `route ${draft.route}`,
1299
- draft.frequency && draft.frequency.toLowerCase(),
1300
- draft.prn && "PRN (as needed)"
1301
- ].filter(Boolean).join(" \xB7 ")
1302
- ] }) : "Route, frequency, and PRN are derived from the directions" })
1303
- ] })
1304
- ] }),
1305
- /* @__PURE__ */ jsxs("section", { className: "space-y-3", "aria-label": "Dates and context", children: [
1306
- /* @__PURE__ */ jsx("h4", { className: "text-muted-foreground text-xs font-semibold tracking-wide uppercase", children: "Dates & context" }),
1307
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3", children: [
1308
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1309
- /* @__PURE__ */ jsx(Label, { htmlFor: "med-start", children: "Start date" }),
1310
- /* @__PURE__ */ jsx(
1311
- DateInput,
1312
- {
1313
- id: "med-start",
1314
- value: draft.startDate ?? "",
1315
- onChange: (v) => patch({ startDate: v })
1316
- }
1317
- )
1318
- ] }),
1319
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1320
- /* @__PURE__ */ jsx(Label, { htmlFor: "med-end", children: "End date" }),
1321
- /* @__PURE__ */ jsx(
1322
- DateInput,
1323
- {
1324
- id: "med-end",
1325
- value: draft.endDate ?? "",
1326
- onChange: (v) => patch({ endDate: v })
1327
- }
1328
- )
1329
- ] })
1330
- ] }),
1331
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1332
- /* @__PURE__ */ jsx(Label, { htmlFor: "med-indication", children: "Indication" }),
1333
- /* @__PURE__ */ jsx(
1334
- Input,
1335
- {
1336
- id: "med-indication",
1337
- value: draft.indication ?? "",
1338
- onChange: (e) => patch({ indication: e.target.value })
1339
- }
1340
- )
1341
- ] }),
1342
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1343
- /* @__PURE__ */ jsx(Label, { htmlFor: "med-pharmacy-notes", children: "Pharmacy notes" }),
1344
- /* @__PURE__ */ jsx(
1345
- Textarea,
1346
- {
1347
- id: "med-pharmacy-notes",
1348
- value: draft.pharmacyNotes ?? "",
1349
- onChange: (e) => patch({ pharmacyNotes: e.target.value }),
1350
- rows: 2
1351
- }
1352
- )
1353
- ] })
1354
- ] })
1355
- ] }) }),
1356
- /* @__PURE__ */ jsxs(ModalFooter, { children: [
1357
- /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: onClose, children: "Cancel" }),
1358
- /* @__PURE__ */ jsx(
1359
- Button,
1360
- {
1361
- onClick: () => {
1362
- onSave({ ...draft, name: draft.name.trim() });
1363
- onClose();
1364
- },
1365
- disabled: !canSave,
1366
- children: "Save"
1367
- }
1368
- )
1369
- ] })
1370
- ] });
1371
- }
1372
- var MANAGED_ACTIONS = [
1373
- "correct",
1374
- "add-task",
1375
- "note",
1376
- "remove"
1377
- ];
1378
- function newId3() {
1379
- return `med-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
1380
- }
1381
- function MedicationDialog({
1382
- dialog,
1383
- onClose,
1384
- onSave
1385
- }) {
1386
- const [form, setForm] = React3.useState(
1387
- () => dialog.kind === "note" ? { note: dialog.medication.note ?? "" } : { task: dialog.medication.task ?? "" }
1388
- );
1389
- const set = (key) => (e) => setForm((prev) => ({ ...prev, [key]: e.target.value }));
1390
- const handleSave = () => {
1391
- onSave(form);
1392
- onClose();
1393
- };
1394
- return /* @__PURE__ */ jsxs(Modal, { open: true, onOpenChange: (open) => !open && onClose(), size: "md", children: [
1395
- /* @__PURE__ */ jsxs(ModalHeader, { children: [
1396
- /* @__PURE__ */ jsx(ModalTitle, { children: dialog.kind === "note" ? "Medication Notes" : "Add Task" }),
1397
- /* @__PURE__ */ jsx(ModalClose, {})
1398
- ] }),
1399
- /* @__PURE__ */ jsxs(ModalBody, { className: "space-y-4", children: [
1400
- /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: dialog.medication.name }),
1401
- dialog.kind === "note" ? /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1402
- /* @__PURE__ */ jsx(Label, { htmlFor: "med-note", children: "Note" }),
1403
- /* @__PURE__ */ jsx(
1404
- Textarea,
1405
- {
1406
- id: "med-note",
1407
- value: form.note,
1408
- onChange: set("note"),
1409
- rows: 4
1410
- }
1411
- )
1412
- ] }) : /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1413
- /* @__PURE__ */ jsx(Label, { htmlFor: "med-task", children: "Task" }),
1414
- /* @__PURE__ */ jsx(
1415
- Textarea,
1416
- {
1417
- id: "med-task",
1418
- value: form.task,
1419
- onChange: set("task"),
1420
- rows: 3,
1421
- placeholder: "Follow-up task for this medication"
1422
- }
1423
- )
1424
- ] })
1425
- ] }),
1426
- /* @__PURE__ */ jsxs(ModalFooter, { children: [
1427
- /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: onClose, children: "Cancel" }),
1428
- /* @__PURE__ */ jsx(Button, { onClick: handleSave, children: "Save" })
1429
- ] })
1430
- ] });
1431
- }
1432
- function MedicationReconciliation({
1433
- medications: controlledMedications,
1434
- defaultMedications,
1435
- onChange,
1436
- title = "Presenting medications",
1437
- quickAddOptions,
1438
- actions = MANAGED_ACTIONS,
1439
- onAction,
1440
- codeLookup,
1441
- inlineAddSearch = false,
1442
- readOnly = false,
1443
- reconciledMessage,
1444
- emptyMessage,
1445
- className,
1446
- "data-testid": dataTestId
1447
- }) {
1448
- const isControlled = controlledMedications !== void 0;
1449
- const [internal, setInternal] = React3.useState(
1450
- defaultMedications ?? []
1451
- );
1452
- const medications = isControlled ? controlledMedications : internal;
1453
- const ambientCodeLookup = useCodeLookupConfig();
1454
- const effectiveCodeLookup = codeLookup === false ? void 0 : codeLookup ?? ambientCodeLookup ?? void 0;
1455
- const [dialog, setDialog] = React3.useState(null);
1456
- const commit = (next) => {
1457
- if (!isControlled) setInternal(next);
1458
- onChange?.(next);
1459
- };
1460
- const patchMedication = (id, patch) => {
1461
- commit(medications.map((m) => m.id === id ? { ...m, ...patch } : m));
1462
- };
1463
- const moveMedication = (med, direction) => {
1464
- const meds = [...medications];
1465
- const group = meds.filter((m) => m.status === med.status);
1466
- const groupIndex = group.findIndex((m) => m.id === med.id);
1467
- const swapWith = group[groupIndex + direction];
1468
- if (!swapWith) return;
1469
- const i = meds.findIndex((m) => m.id === med.id);
1470
- const j = meds.findIndex((m) => m.id === swapWith.id);
1471
- [meds[i], meds[j]] = [meds[j], meds[i]];
1472
- commit(meds);
1473
- };
1474
- const handleAction = (med, action) => {
1475
- switch (action) {
1476
- case "remove":
1477
- commit(medications.filter((m) => m.id !== med.id));
1478
- break;
1479
- case "move-up":
1480
- moveMedication(med, -1);
1481
- break;
1482
- case "move-down":
1483
- moveMedication(med, 1);
1484
- break;
1485
- case "correct":
1486
- case "note":
1487
- case "add-task":
1488
- setDialog({ kind: action, medication: med });
1489
- break;
1490
- default:
1491
- onAction?.(med, action);
1492
- break;
1493
- }
1494
- };
1495
- const addMedication = (name, sig) => {
1496
- commit([
1497
- ...medications,
1498
- { id: newId3(), name, sig: void 0, status: "unreconciled" }
1499
- ]);
1500
- };
1501
- const handleDialogSave = (form) => {
1502
- if (!dialog) return;
1503
- switch (dialog.kind) {
1504
- case "note":
1505
- patchMedication(dialog.medication.id, {
1506
- note: form.note.trim() || void 0
1507
- });
1508
- break;
1509
- case "add-task":
1510
- patchMedication(dialog.medication.id, {
1511
- task: form.task.trim() || void 0
1512
- });
1513
- break;
1514
- }
1515
- };
1516
- const editorOpen = dialog?.kind === "correct" || dialog?.kind === "add";
1517
- const editorTarget = dialog?.kind === "correct" ? dialog.medication : void 0;
1518
- const handleEditorSave = (med) => {
1519
- if (dialog?.kind === "correct") {
1520
- commit(medications.map((m) => m.id === med.id ? med : m));
1521
- } else {
1522
- commit([...medications, { ...med, status: "unreconciled" }]);
1523
- }
1524
- };
1525
- const addSearch = inlineAddSearch && effectiveCodeLookup && !readOnly ? /* @__PURE__ */ jsx(
1526
- effectiveCodeLookup.component,
1527
- {
1528
- indexUrl: effectiveCodeLookup.indexUrl,
1529
- locale: effectiveCodeLookup.locale,
1530
- domains: ["med"],
1531
- bare: true,
1532
- clearOnSelect: true,
1533
- placeholder: "Search medications to add",
1534
- onSelect: (result) => commit([
1535
- ...medications,
1536
- {
1537
- id: newId3(),
1538
- name: result.label,
1539
- status: "unreconciled",
1540
- ...lookupToMedicationFields(result)
1541
- }
1542
- ]),
1543
- onFreeText: (text) => addMedication(text)
1544
- }
1545
- ) : void 0;
1546
- return /* @__PURE__ */ jsxs(Fragment, { children: [
1547
- /* @__PURE__ */ jsx(
1548
- MedicationList,
1549
- {
1550
- medications,
1551
- title,
1552
- readOnly,
1553
- actions,
1554
- onStatusChange: (med, status) => patchMedication(med.id, { status }),
1555
- onAction: handleAction,
1556
- onReorder: (ids) => commit(
1557
- [...medications].sort(
1558
- (a, b) => ids.indexOf(a.id) - ids.indexOf(b.id)
1559
- )
1560
- ),
1561
- quickAddOptions,
1562
- onQuickAdd: (name) => addMedication(name),
1563
- onAddOther: () => setDialog({ kind: "add" }),
1564
- addSearch,
1565
- reconciledMessage,
1566
- emptyMessage,
1567
- className,
1568
- "data-testid": dataTestId
1569
- }
1570
- ),
1571
- dialog && (dialog.kind === "note" || dialog.kind === "add-task") && /* @__PURE__ */ jsx(
1572
- MedicationDialog,
1573
- {
1574
- dialog,
1575
- onClose: () => setDialog(null),
1576
- onSave: handleDialogSave
1577
- },
1578
- dialog.kind + dialog.medication.id
1579
- ),
1580
- editorOpen && /* @__PURE__ */ jsx(
1581
- MedicationEditor,
1582
- {
1583
- open: true,
1584
- medication: editorTarget,
1585
- codeLookup: codeLookup === false ? false : effectiveCodeLookup,
1586
- onClose: () => setDialog(null),
1587
- onSave: handleEditorSave
1588
- },
1589
- editorTarget?.id ?? "add"
1590
- )
1591
- ] });
1592
- }
1593
-
1594
- export { ALLERGY_TYPE_LABELS, AllergyList, AllergyManager, CodeLookupProvider, MEDICATION_STATUS_LABELS, MedicationEditor, MedicationList, MedicationReconciliation, RowActionToolbar, RowIconButton, labelToMedicationFields, lookupToMedicationFields, parseMedicationLabel, parseSig, toolbarKeyNav, useCodeLookupConfig };
1595
- //# sourceMappingURL=chunk-SFSBYC46.js.map
1596
- //# sourceMappingURL=chunk-SFSBYC46.js.map