formanitor 0.0.27 → 0.0.29

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/index.mjs CHANGED
@@ -1,6 +1,7 @@
1
- import * as React13 from 'react';
2
- import React13__default, { createContext, useContext, useRef, useEffect, useState, useMemo, useCallback, useReducer } from 'react';
1
+ import * as React15 from 'react';
2
+ import React15__default, { createContext, useContext, useRef, useEffect, useState, useMemo, useCallback, useReducer } from 'react';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
+ import { ChevronDown, ChevronUp, Check, Circle, X, Image, Upload, Trash2, Plus, Loader2, PenTool, Mic, Undo, Redo, ChevronRight, Calendar as Calendar$1, ChevronLeft, RefreshCw, Clock, Bold, Italic, Underline as Underline$1, Strikethrough, List, ListOrdered } from 'lucide-react';
4
5
  import { clsx } from 'clsx';
5
6
  import { twMerge } from 'tailwind-merge';
6
7
  import * as LabelPrimitive from '@radix-ui/react-label';
@@ -9,7 +10,6 @@ import { useEditor, EditorContent } from '@tiptap/react';
9
10
  import StarterKit from '@tiptap/starter-kit';
10
11
  import Placeholder from '@tiptap/extension-placeholder';
11
12
  import Underline from '@tiptap/extension-underline';
12
- import { ChevronDown, ChevronUp, Check, Circle, X, Image, Upload, Trash2, Plus, Loader2, PenTool, Undo, Redo, ChevronRight, Calendar as Calendar$1, ChevronLeft, RefreshCw, Clock, Bold, Italic, Underline as Underline$1, Strikethrough, List, ListOrdered } from 'lucide-react';
13
13
  import { Slot } from '@radix-ui/react-slot';
14
14
  import * as SeparatorPrimitive from '@radix-ui/react-separator';
15
15
  import * as SelectPrimitive from '@radix-ui/react-select';
@@ -251,6 +251,9 @@ var FormStore = class {
251
251
  getFieldDef(fieldId) {
252
252
  return this.fieldMap[fieldId];
253
253
  }
254
+ getVoice() {
255
+ return this.config.voice;
256
+ }
254
257
  hasPersistence() {
255
258
  return this.persistence !== NO_OP_PROVIDER;
256
259
  }
@@ -395,6 +398,11 @@ var FormStore = class {
395
398
  result[field.id] = raw?.text ?? null;
396
399
  return;
397
400
  }
401
+ if (field.type === "diagnosis_textarea") {
402
+ const raw = values[field.id];
403
+ result[field.id] = typeof raw === "string" ? raw : raw && typeof raw === "object" ? raw.text ?? null : null;
404
+ return;
405
+ }
398
406
  if (field.type === "ophthal_diagnosis") {
399
407
  const raw = values[field.id];
400
408
  const formatEye = (eyeData, eyeLabel) => {
@@ -598,6 +606,7 @@ var FormStore = class {
598
606
  if (next.onUpload !== void 0) this.config.onUpload = next.onUpload;
599
607
  if (next.onEvent !== void 0) this.config.onEvent = next.onEvent;
600
608
  if (next.onDraftChange !== void 0) this.config.onDraftChange = next.onDraftChange;
609
+ if (next.voice !== void 0) this.config.voice = next.voice;
601
610
  if (next.role !== void 0 && next.role !== this.config.role) {
602
611
  this.config.role = next.role;
603
612
  needsReeval = true;
@@ -659,6 +668,21 @@ var FormStore = class {
659
668
  this.listeners.forEach((l) => l(this.state));
660
669
  }
661
670
  };
671
+ var VoiceContext = createContext({
672
+ activeFieldId: null,
673
+ setActiveFieldId: () => {
674
+ }
675
+ });
676
+ function useVoiceContext() {
677
+ return useContext(VoiceContext);
678
+ }
679
+ function VoiceContextProvider({ children }) {
680
+ const [activeFieldId, setActiveFieldIdState] = useState(null);
681
+ const setActiveFieldId = useCallback((id) => {
682
+ setActiveFieldIdState(id);
683
+ }, []);
684
+ return /* @__PURE__ */ jsx(VoiceContext.Provider, { value: { activeFieldId, setActiveFieldId }, children });
685
+ }
662
686
  var FormContext = createContext(null);
663
687
  var emptyFrequentItems = {
664
688
  medications: [],
@@ -694,7 +718,7 @@ var FormProvider = ({
694
718
  storeRef.current?.load();
695
719
  }, []);
696
720
  const frequentItemsValue = frequentItems ?? emptyFrequentItems;
697
- return /* @__PURE__ */ jsx(FormContext.Provider, { value: storeRef.current, children: /* @__PURE__ */ jsx(FieldHandlersContext.Provider, { value: fieldHandlers ?? {}, children: /* @__PURE__ */ jsx(FrequentItemsContext.Provider, { value: frequentItemsValue, children }) }) });
721
+ return /* @__PURE__ */ jsx(FormContext.Provider, { value: storeRef.current, children: /* @__PURE__ */ jsx(FieldHandlersContext.Provider, { value: fieldHandlers ?? {}, children: /* @__PURE__ */ jsx(FrequentItemsContext.Provider, { value: frequentItemsValue, children: /* @__PURE__ */ jsx(VoiceContextProvider, { children }) }) }) });
698
722
  };
699
723
  function useFormStore() {
700
724
  const context = useContext(FormContext);
@@ -751,10 +775,76 @@ function useField(fieldId) {
751
775
  setTouched
752
776
  };
753
777
  }
778
+ function RecordingWave() {
779
+ const bars = [
780
+ { dur: "0.6s", values: "3;10;3", yValues: "4.5;0;4.5", delay: "0s" },
781
+ { dur: "0.6s", values: "8;3;8", yValues: "2;4.5;2", delay: "0.1s" },
782
+ { dur: "0.6s", values: "5;11;5", yValues: "3.5;0.5;3.5", delay: "0.05s" },
783
+ { dur: "0.6s", values: "10;4;10", yValues: "1;4;1", delay: "0.15s" }
784
+ ];
785
+ return /* @__PURE__ */ jsx("svg", { width: "16", height: "12", viewBox: "0 0 18 12", "aria-hidden": true, children: bars.map((b, i) => /* @__PURE__ */ jsxs("rect", { x: i * 4 + 1, width: "2.5", rx: "1.25", fill: "currentColor", y: "0", height: "12", children: [
786
+ /* @__PURE__ */ jsx("animate", { attributeName: "height", values: b.values, dur: b.dur, begin: b.delay, repeatCount: "indefinite" }),
787
+ /* @__PURE__ */ jsx("animate", { attributeName: "y", values: b.yValues, dur: b.dur, begin: b.delay, repeatCount: "indefinite" })
788
+ ] }, i)) });
789
+ }
790
+ function VoiceMicButton({ fieldId, onTranscriptReady }) {
791
+ const store = useFormStore();
792
+ const { activeFieldId, setActiveFieldId } = useVoiceContext();
793
+ const [status, setStatus] = useState("idle");
794
+ const voice = store.getVoice();
795
+ const isActive = activeFieldId === fieldId;
796
+ const isRecording = status === "recording" && isActive;
797
+ const isTranscribing = status === "transcribing" && isActive;
798
+ const isBlocked = activeFieldId !== null && !isActive;
799
+ const handleClick = useCallback(async () => {
800
+ if (!voice || isBlocked || isTranscribing) return;
801
+ if (isRecording) {
802
+ setStatus("transcribing");
803
+ try {
804
+ const transcript = await voice.stopRecording();
805
+ if (transcript) onTranscriptReady(transcript);
806
+ } catch {
807
+ } finally {
808
+ setStatus("idle");
809
+ setActiveFieldId(null);
810
+ }
811
+ } else {
812
+ setActiveFieldId(fieldId);
813
+ setStatus("recording");
814
+ try {
815
+ await voice.startRecording();
816
+ } catch {
817
+ setStatus("idle");
818
+ setActiveFieldId(null);
819
+ }
820
+ }
821
+ }, [voice, isBlocked, isTranscribing, isRecording, fieldId, onTranscriptReady, setActiveFieldId]);
822
+ const title = isTranscribing ? "Processing\u2026" : isRecording ? "Stop recording" : "Dictate this field";
823
+ return /* @__PURE__ */ jsx(
824
+ "button",
825
+ {
826
+ type: "button",
827
+ onClick: handleClick,
828
+ disabled: isBlocked || isTranscribing,
829
+ title,
830
+ className: [
831
+ "flex items-center gap-1 rounded px-1 py-0.5",
832
+ "text-[11px] font-medium transition-opacity",
833
+ isBlocked ? "pointer-events-none opacity-30" : "",
834
+ isTranscribing ? "cursor-wait opacity-50" : "",
835
+ !isBlocked && !isTranscribing ? "hover:opacity-70" : ""
836
+ ].filter(Boolean).join(" "),
837
+ children: isTranscribing ? /* @__PURE__ */ jsx(Loader2, { className: "h-3.5 w-3.5 animate-spin text-slate-400" }) : isRecording ? /* @__PURE__ */ jsxs(Fragment, { children: [
838
+ /* @__PURE__ */ jsx("span", { className: "text-rose-400", children: /* @__PURE__ */ jsx(RecordingWave, {}) }),
839
+ /* @__PURE__ */ jsx("span", { className: "text-rose-400", children: "Stop" })
840
+ ] }) : /* @__PURE__ */ jsx(Mic, { className: "h-4 w-4 text-slate-400" })
841
+ }
842
+ );
843
+ }
754
844
  function cn(...inputs) {
755
845
  return twMerge(clsx(inputs));
756
846
  }
757
- var Input = React13.forwardRef(
847
+ var Input = React15.forwardRef(
758
848
  ({ className, type, ...props }, ref) => {
759
849
  return /* @__PURE__ */ jsx(
760
850
  "input",
@@ -774,7 +864,7 @@ Input.displayName = "Input";
774
864
  var labelVariants = cva(
775
865
  "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
776
866
  );
777
- var Label = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
867
+ var Label = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
778
868
  LabelPrimitive.Root,
779
869
  {
780
870
  ref,
@@ -783,7 +873,7 @@ var Label = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
783
873
  }
784
874
  ));
785
875
  Label.displayName = LabelPrimitive.Root.displayName;
786
- var Textarea = React13.forwardRef(
876
+ var Textarea = React15.forwardRef(
787
877
  ({ className, height, style, ...props }, ref) => {
788
878
  return /* @__PURE__ */ jsx(
789
879
  "textarea",
@@ -827,6 +917,8 @@ function getThemeConfig(fieldType, themeName) {
827
917
  var TextWidget = ({ fieldId }) => {
828
918
  const { fieldDef, value, setValue, setTouched, error, disabled, touched } = useField(fieldId);
829
919
  const { state } = useForm();
920
+ const store = useFormStore();
921
+ const hasVoice = !!(fieldDef?.voice && store.getVoice());
830
922
  const showError = !!error && (touched || state.submitAttempted);
831
923
  if (!fieldDef) return null;
832
924
  const Component = fieldDef.type === "textarea" ? Textarea : Input;
@@ -844,8 +936,12 @@ var TextWidget = ({ fieldId }) => {
844
936
  " ",
845
937
  fieldDef.required && /* @__PURE__ */ jsx("span", { className: "text-red-500", children: "*" })
846
938
  ] });
939
+ const labelEl = theme ? /* @__PURE__ */ jsx(Label, { htmlFor: fieldId, className: labelClass, children: labelContent }) : /* @__PURE__ */ jsx(Label, { htmlFor: fieldId, children: labelContent });
847
940
  return /* @__PURE__ */ jsxs("div", { className: wrapperClass, children: [
848
- theme ? /* @__PURE__ */ jsx(Label, { htmlFor: fieldId, className: labelClass, children: labelContent }) : /* @__PURE__ */ jsx(Label, { htmlFor: fieldId, children: labelContent }),
941
+ hasVoice ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
942
+ labelEl,
943
+ /* @__PURE__ */ jsx(VoiceMicButton, { fieldId, onTranscriptReady: setValue })
944
+ ] }) : labelEl,
849
945
  /* @__PURE__ */ jsx(
850
946
  Component,
851
947
  {
@@ -887,7 +983,7 @@ var buttonVariants = cva(
887
983
  }
888
984
  }
889
985
  );
890
- var Button = React13.forwardRef(
986
+ var Button = React15.forwardRef(
891
987
  ({ className, variant, size, asChild = false, ...props }, ref) => {
892
988
  const Comp = asChild ? Slot : "button";
893
989
  return /* @__PURE__ */ jsx(
@@ -901,7 +997,7 @@ var Button = React13.forwardRef(
901
997
  }
902
998
  );
903
999
  Button.displayName = "Button";
904
- var Separator = React13.forwardRef(
1000
+ var Separator = React15.forwardRef(
905
1001
  ({ className, orientation = "horizontal", decorative = true, ...props }, ref) => /* @__PURE__ */ jsx(
906
1002
  SeparatorPrimitive.Root,
907
1003
  {
@@ -1033,6 +1129,8 @@ function RichTextToolbar({
1033
1129
  var RichTextWidget = ({ fieldId }) => {
1034
1130
  const { fieldDef, value, setValue, setTouched, error, disabled, touched } = useField(fieldId);
1035
1131
  const { state } = useForm();
1132
+ const store = useFormStore();
1133
+ const hasVoice = !!(fieldDef?.voice && store.getVoice());
1036
1134
  const showError = !!error && (touched || state.submitAttempted);
1037
1135
  const def = fieldDef;
1038
1136
  const placeholder = def?.placeholder ?? "Start typing\u2026";
@@ -1114,8 +1212,12 @@ var RichTextWidget = ({ fieldId }) => {
1114
1212
  " ",
1115
1213
  fieldDef.required && /* @__PURE__ */ jsx("span", { className: "text-red-500", children: "*" })
1116
1214
  ] });
1215
+ const labelEl = /* @__PURE__ */ jsx(Label, { htmlFor: fieldId, children: labelContent });
1117
1216
  return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
1118
- /* @__PURE__ */ jsx(Label, { htmlFor: fieldId, children: labelContent }),
1217
+ hasVoice ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1218
+ labelEl,
1219
+ /* @__PURE__ */ jsx(VoiceMicButton, { fieldId, onTranscriptReady: setValue })
1220
+ ] }) : labelEl,
1119
1221
  /* @__PURE__ */ jsxs(
1120
1222
  "div",
1121
1223
  {
@@ -1153,7 +1255,7 @@ var RichTextWidget = ({ fieldId }) => {
1153
1255
  };
1154
1256
  var Select = SelectPrimitive.Root;
1155
1257
  var SelectValue = SelectPrimitive.Value;
1156
- var SelectTrigger = React13.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
1258
+ var SelectTrigger = React15.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
1157
1259
  SelectPrimitive.Trigger,
1158
1260
  {
1159
1261
  ref,
@@ -1169,7 +1271,7 @@ var SelectTrigger = React13.forwardRef(({ className, children, ...props }, ref)
1169
1271
  }
1170
1272
  ));
1171
1273
  SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
1172
- var SelectScrollUpButton = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1274
+ var SelectScrollUpButton = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1173
1275
  SelectPrimitive.ScrollUpButton,
1174
1276
  {
1175
1277
  ref,
@@ -1182,7 +1284,7 @@ var SelectScrollUpButton = React13.forwardRef(({ className, ...props }, ref) =>
1182
1284
  }
1183
1285
  ));
1184
1286
  SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
1185
- var SelectScrollDownButton = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1287
+ var SelectScrollDownButton = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1186
1288
  SelectPrimitive.ScrollDownButton,
1187
1289
  {
1188
1290
  ref,
@@ -1195,7 +1297,7 @@ var SelectScrollDownButton = React13.forwardRef(({ className, ...props }, ref) =
1195
1297
  }
1196
1298
  ));
1197
1299
  SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
1198
- var SelectContent = React13.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
1300
+ var SelectContent = React15.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
1199
1301
  SelectPrimitive.Content,
1200
1302
  {
1201
1303
  ref,
@@ -1223,7 +1325,7 @@ var SelectContent = React13.forwardRef(({ className, children, position = "poppe
1223
1325
  }
1224
1326
  ) }));
1225
1327
  SelectContent.displayName = SelectPrimitive.Content.displayName;
1226
- var SelectLabel = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1328
+ var SelectLabel = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1227
1329
  SelectPrimitive.Label,
1228
1330
  {
1229
1331
  ref,
@@ -1232,7 +1334,7 @@ var SelectLabel = React13.forwardRef(({ className, ...props }, ref) => /* @__PUR
1232
1334
  }
1233
1335
  ));
1234
1336
  SelectLabel.displayName = SelectPrimitive.Label.displayName;
1235
- var SelectItem = React13.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
1337
+ var SelectItem = React15.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
1236
1338
  SelectPrimitive.Item,
1237
1339
  {
1238
1340
  ref,
@@ -1248,7 +1350,7 @@ var SelectItem = React13.forwardRef(({ className, children, ...props }, ref) =>
1248
1350
  }
1249
1351
  ));
1250
1352
  SelectItem.displayName = SelectPrimitive.Item.displayName;
1251
- var SelectSeparator = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1353
+ var SelectSeparator = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1252
1354
  SelectPrimitive.Separator,
1253
1355
  {
1254
1356
  ref,
@@ -1337,7 +1439,7 @@ var SelectWidget = ({ fieldId }) => {
1337
1439
  showError && /* @__PURE__ */ jsx("p", { className: "text-xs text-red-500", children: error })
1338
1440
  ] });
1339
1441
  };
1340
- var Checkbox = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1442
+ var Checkbox = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1341
1443
  CheckboxPrimitive.Root,
1342
1444
  {
1343
1445
  ref,
@@ -1411,7 +1513,7 @@ var MultiSelectWidget = ({ fieldId }) => {
1411
1513
  showError && /* @__PURE__ */ jsx("p", { className: "text-xs text-red-500", children: error })
1412
1514
  ] });
1413
1515
  };
1414
- var Table = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ jsx(
1516
+ var Table = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ jsx(
1415
1517
  "table",
1416
1518
  {
1417
1519
  ref,
@@ -1420,9 +1522,9 @@ var Table = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
1420
1522
  }
1421
1523
  ) }));
1422
1524
  Table.displayName = "Table";
1423
- var TableHeader = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("thead", { ref, className: cn("[&_tr]:border-b", className), ...props }));
1525
+ var TableHeader = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("thead", { ref, className: cn("[&_tr]:border-b", className), ...props }));
1424
1526
  TableHeader.displayName = "TableHeader";
1425
- var TableBody = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1527
+ var TableBody = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1426
1528
  "tbody",
1427
1529
  {
1428
1530
  ref,
@@ -1431,7 +1533,7 @@ var TableBody = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE_
1431
1533
  }
1432
1534
  ));
1433
1535
  TableBody.displayName = "TableBody";
1434
- var TableFooter = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1536
+ var TableFooter = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1435
1537
  "tfoot",
1436
1538
  {
1437
1539
  ref,
@@ -1443,7 +1545,7 @@ var TableFooter = React13.forwardRef(({ className, ...props }, ref) => /* @__PUR
1443
1545
  }
1444
1546
  ));
1445
1547
  TableFooter.displayName = "TableFooter";
1446
- var TableRow = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1548
+ var TableRow = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1447
1549
  "tr",
1448
1550
  {
1449
1551
  ref,
@@ -1455,7 +1557,7 @@ var TableRow = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__
1455
1557
  }
1456
1558
  ));
1457
1559
  TableRow.displayName = "TableRow";
1458
- var TableHead = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1560
+ var TableHead = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1459
1561
  "th",
1460
1562
  {
1461
1563
  ref,
@@ -1467,7 +1569,7 @@ var TableHead = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE_
1467
1569
  }
1468
1570
  ));
1469
1571
  TableHead.displayName = "TableHead";
1470
- var TableCell = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1572
+ var TableCell = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1471
1573
  "td",
1472
1574
  {
1473
1575
  ref,
@@ -1476,7 +1578,7 @@ var TableCell = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE_
1476
1578
  }
1477
1579
  ));
1478
1580
  TableCell.displayName = "TableCell";
1479
- var TableCaption = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1581
+ var TableCaption = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1480
1582
  "caption",
1481
1583
  {
1482
1584
  ref,
@@ -1492,7 +1594,7 @@ var RepeatableWidget = ({
1492
1594
  if (!fieldDef || fieldDef.type !== "repeatable") return null;
1493
1595
  const def = fieldDef;
1494
1596
  const rows = Array.isArray(value) ? value : [];
1495
- const [hasInteracted, setHasInteracted] = React13__default.useState(false);
1597
+ const [hasInteracted, setHasInteracted] = React15__default.useState(false);
1496
1598
  const showError = !!error && (touched || hasInteracted);
1497
1599
  const addRow = () => {
1498
1600
  setValue([...rows, {}]);
@@ -1661,7 +1763,7 @@ function Calendar({
1661
1763
  Calendar.displayName = "Calendar";
1662
1764
  var Popover = PopoverPrimitive.Root;
1663
1765
  var PopoverTrigger = PopoverPrimitive.Trigger;
1664
- var PopoverContent = React13.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(
1766
+ var PopoverContent = React15.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(
1665
1767
  PopoverPrimitive.Content,
1666
1768
  {
1667
1769
  ref,
@@ -1740,14 +1842,14 @@ function DateTimePicker({
1740
1842
  className,
1741
1843
  placeholder = "Pick date & time"
1742
1844
  }) {
1743
- const [internalDate, setInternalDate] = React13.useState(dateTime);
1744
- const [timeString, setTimeString] = React13.useState(() => {
1845
+ const [internalDate, setInternalDate] = React15.useState(dateTime);
1846
+ const [timeString, setTimeString] = React15.useState(() => {
1745
1847
  if (!dateTime) return "";
1746
1848
  const hours = dateTime.getHours().toString().padStart(2, "0");
1747
1849
  const minutes = dateTime.getMinutes().toString().padStart(2, "0");
1748
1850
  return `${hours}:${minutes}`;
1749
1851
  });
1750
- React13.useEffect(() => {
1852
+ React15.useEffect(() => {
1751
1853
  setInternalDate(dateTime);
1752
1854
  if (!dateTime) {
1753
1855
  setTimeString("");
@@ -1891,7 +1993,7 @@ var ImageUploadWidget = ({ fieldId }) => {
1891
1993
  /* @__PURE__ */ jsx("div", { className: "border-2 border-red-300 rounded-lg p-4 bg-red-50", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-red-600", children: "Upload handler not configured. Please provide an onUpload function in FormProvider config." }) })
1892
1994
  ] });
1893
1995
  }
1894
- React13__default.useEffect(() => {
1996
+ React15__default.useEffect(() => {
1895
1997
  if (value && typeof value === "string") {
1896
1998
  setPreview(value);
1897
1999
  } else {
@@ -2530,7 +2632,7 @@ var EditableTableWidget = ({
2530
2632
  ] })
2531
2633
  ] });
2532
2634
  };
2533
- var RadioGroup = React13.forwardRef(({ className, ...props }, ref) => {
2635
+ var RadioGroup = React15.forwardRef(({ className, ...props }, ref) => {
2534
2636
  return /* @__PURE__ */ jsx(
2535
2637
  RadioGroupPrimitive.Root,
2536
2638
  {
@@ -2541,7 +2643,7 @@ var RadioGroup = React13.forwardRef(({ className, ...props }, ref) => {
2541
2643
  );
2542
2644
  });
2543
2645
  RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;
2544
- var RadioGroupItem = React13.forwardRef(({ className, ...props }, ref) => {
2646
+ var RadioGroupItem = React15.forwardRef(({ className, ...props }, ref) => {
2545
2647
  return /* @__PURE__ */ jsx(
2546
2648
  RadioGroupPrimitive.Item,
2547
2649
  {
@@ -2688,7 +2790,7 @@ function useAISuggestions() {
2688
2790
  var AISuggestionsProvider = AISuggestionsContext.Provider;
2689
2791
  var Dialog = DialogPrimitive.Root;
2690
2792
  var DialogPortal = DialogPrimitive.Portal;
2691
- var DialogOverlay = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2793
+ var DialogOverlay = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2692
2794
  DialogPrimitive.Overlay,
2693
2795
  {
2694
2796
  ref,
@@ -2700,7 +2802,7 @@ var DialogOverlay = React13.forwardRef(({ className, ...props }, ref) => /* @__P
2700
2802
  }
2701
2803
  ));
2702
2804
  DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
2703
- var DialogContent = React13.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(DialogPortal, { children: [
2805
+ var DialogContent = React15.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(DialogPortal, { children: [
2704
2806
  /* @__PURE__ */ jsx(DialogOverlay, {}),
2705
2807
  /* @__PURE__ */ jsxs(
2706
2808
  DialogPrimitive.Content,
@@ -2736,7 +2838,7 @@ var DialogHeader = ({
2736
2838
  }
2737
2839
  );
2738
2840
  DialogHeader.displayName = "DialogHeader";
2739
- var DialogTitle = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2841
+ var DialogTitle = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2740
2842
  DialogPrimitive.Title,
2741
2843
  {
2742
2844
  ref,
@@ -2748,7 +2850,7 @@ var DialogTitle = React13.forwardRef(({ className, ...props }, ref) => /* @__PUR
2748
2850
  }
2749
2851
  ));
2750
2852
  DialogTitle.displayName = DialogPrimitive.Title.displayName;
2751
- var DialogDescription = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2853
+ var DialogDescription = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2752
2854
  DialogPrimitive.Description,
2753
2855
  {
2754
2856
  ref,
@@ -3896,7 +3998,7 @@ var DifferentialDiagnosisWidget = ({ fieldId }) => {
3896
3998
  const items = Array.isArray(value) ? value : [];
3897
3999
  return /* @__PURE__ */ jsx(DifferentialDiagnosis, { differentialDiagnosis: items });
3898
4000
  };
3899
- var Spinner2 = React13.forwardRef(
4001
+ var Spinner2 = React15.forwardRef(
3900
4002
  ({ className, size = "md", ...props }, ref) => {
3901
4003
  const sizeClasses = {
3902
4004
  sm: "h-4 w-4 border-2",
@@ -4252,7 +4354,7 @@ var ReferralWidget = ({ fieldId }) => {
4252
4354
  showError && /* @__PURE__ */ jsx("p", { className: "text-xs text-red-500", children: error })
4253
4355
  ] });
4254
4356
  };
4255
- var Card = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4357
+ var Card = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4256
4358
  "div",
4257
4359
  {
4258
4360
  ref,
@@ -4264,7 +4366,7 @@ var Card = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
4264
4366
  }
4265
4367
  ));
4266
4368
  Card.displayName = "Card";
4267
- var CardHeader = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4369
+ var CardHeader = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4268
4370
  "div",
4269
4371
  {
4270
4372
  ref,
@@ -4273,7 +4375,7 @@ var CardHeader = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE
4273
4375
  }
4274
4376
  ));
4275
4377
  CardHeader.displayName = "CardHeader";
4276
- var CardTitle = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4378
+ var CardTitle = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4277
4379
  "h3",
4278
4380
  {
4279
4381
  ref,
@@ -4285,7 +4387,7 @@ var CardTitle = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE_
4285
4387
  }
4286
4388
  ));
4287
4389
  CardTitle.displayName = "CardTitle";
4288
- var CardDescription = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4390
+ var CardDescription = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4289
4391
  "p",
4290
4392
  {
4291
4393
  ref,
@@ -4294,9 +4396,9 @@ var CardDescription = React13.forwardRef(({ className, ...props }, ref) => /* @_
4294
4396
  }
4295
4397
  ));
4296
4398
  CardDescription.displayName = "CardDescription";
4297
- var CardContent = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("p-6 pt-0", className), ...props }));
4399
+ var CardContent = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("p-6 pt-0", className), ...props }));
4298
4400
  CardContent.displayName = "CardContent";
4299
- var CardFooter = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4401
+ var CardFooter = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4300
4402
  "div",
4301
4403
  {
4302
4404
  ref,
@@ -4718,7 +4820,7 @@ var SmartTextareaWidget = ({ fieldId }) => {
4718
4820
  },
4719
4821
  [setValue]
4720
4822
  );
4721
- React13__default.useEffect(() => {
4823
+ React15__default.useEffect(() => {
4722
4824
  if (nextKeywords !== currentKeywords) {
4723
4825
  writeValue(textValue, nextKeywords);
4724
4826
  }
@@ -4759,6 +4861,174 @@ var SmartTextareaWidget = ({ fieldId }) => {
4759
4861
  showError && /* @__PURE__ */ jsx("p", { className: "text-xs text-red-500", children: error })
4760
4862
  ] });
4761
4863
  };
4864
+ function normalizeDiagnosisGrades(payload) {
4865
+ const result = [];
4866
+ const pushGroup = (conditionRaw, gradesRaw) => {
4867
+ const condition = typeof conditionRaw === "string" ? conditionRaw.trim() : "";
4868
+ if (!condition) return;
4869
+ if (!Array.isArray(gradesRaw)) return;
4870
+ const grades = Array.from(
4871
+ new Set(
4872
+ gradesRaw.map((grade) => typeof grade === "string" ? grade.trim() : "").filter(Boolean)
4873
+ )
4874
+ );
4875
+ if (grades.length === 0) return;
4876
+ result.push({ condition, grades });
4877
+ };
4878
+ const asArrayResponse = payload;
4879
+ if (Array.isArray(asArrayResponse?.diagnosisGrades)) {
4880
+ asArrayResponse.diagnosisGrades.forEach((item) => {
4881
+ pushGroup(item?.condition, item?.grades);
4882
+ });
4883
+ return result;
4884
+ }
4885
+ const asMapResponse = payload;
4886
+ const mapLike = asMapResponse?.field === "diagnosisgrade" && asMapResponse?.value && typeof asMapResponse.value === "object" ? asMapResponse.value : null;
4887
+ if (mapLike) {
4888
+ Object.entries(mapLike).forEach(([condition, grades]) => {
4889
+ pushGroup(condition, grades);
4890
+ });
4891
+ }
4892
+ return result;
4893
+ }
4894
+ var DiagnosisTextareaWidget = ({ fieldId }) => {
4895
+ const { fieldDef, value, setValue, setTouched, error, disabled, touched } = useField(fieldId);
4896
+ const { state } = useForm();
4897
+ const handler = useFieldHandlers(fieldId);
4898
+ const def = fieldDef;
4899
+ const [gradeGroups, setGradeGroups] = React15__default.useState([]);
4900
+ const [isLoadingGrades, setIsLoadingGrades] = React15__default.useState(false);
4901
+ const normalized = React15__default.useMemo(() => {
4902
+ const raw = value;
4903
+ if (typeof raw === "string") {
4904
+ return { text: raw, selectedGradesByCondition: {} };
4905
+ }
4906
+ if (!raw || typeof raw !== "object") {
4907
+ return { text: "", selectedGradesByCondition: {} };
4908
+ }
4909
+ const text = typeof raw.text === "string" ? raw.text : "";
4910
+ const mapRaw = raw.selectedGradesByCondition;
4911
+ let selectedGradesByCondition = {};
4912
+ if (mapRaw && typeof mapRaw === "object" && !Array.isArray(mapRaw)) {
4913
+ const entries = Object.entries(mapRaw);
4914
+ for (const [condition, gradeRaw] of entries) {
4915
+ if (typeof condition !== "string") continue;
4916
+ if (typeof gradeRaw === "string" && gradeRaw.trim()) {
4917
+ selectedGradesByCondition[condition] = gradeRaw;
4918
+ }
4919
+ }
4920
+ }
4921
+ const sg = raw.selectedGrade;
4922
+ if (sg && typeof sg === "object" && typeof sg.condition === "string" && typeof sg.grade === "string") {
4923
+ const condition = sg.condition.trim();
4924
+ const grade = sg.grade.trim();
4925
+ if (condition && grade && !selectedGradesByCondition[condition]) {
4926
+ selectedGradesByCondition = { ...selectedGradesByCondition, [condition]: grade };
4927
+ }
4928
+ }
4929
+ return { text, selectedGradesByCondition };
4930
+ }, [value]);
4931
+ const textValue = normalized.text;
4932
+ const showError = !!error && (touched || state.submitAttempted);
4933
+ React15__default.useEffect(() => {
4934
+ const query = textValue.trim();
4935
+ const fetchGrades = handler.onFetchDiagnosisGrades;
4936
+ const debounceMs = def?.debounceDelay ?? 1e3;
4937
+ if (!query || !fetchGrades) {
4938
+ setGradeGroups([]);
4939
+ setIsLoadingGrades(false);
4940
+ return;
4941
+ }
4942
+ let isActive = true;
4943
+ const timer = window.setTimeout(async () => {
4944
+ setIsLoadingGrades(true);
4945
+ try {
4946
+ const response = await fetchGrades(query);
4947
+ if (!isActive) return;
4948
+ setGradeGroups(normalizeDiagnosisGrades(response));
4949
+ } catch {
4950
+ if (!isActive) return;
4951
+ setGradeGroups([]);
4952
+ } finally {
4953
+ if (isActive) setIsLoadingGrades(false);
4954
+ }
4955
+ }, debounceMs);
4956
+ return () => {
4957
+ isActive = false;
4958
+ window.clearTimeout(timer);
4959
+ };
4960
+ }, [textValue, handler.onFetchDiagnosisGrades, def?.debounceDelay]);
4961
+ if (!def) return null;
4962
+ const theme = getThemeConfig("textarea", def.theme);
4963
+ const wrapperClass = theme?.wrapperClassName ?? "space-y-2";
4964
+ const labelClass = theme?.labelClassName;
4965
+ const inputClass = cn(theme?.inputClassName, showError && "border-red-500");
4966
+ const toggleSelectedGrade = (condition, grade) => {
4967
+ if (disabled) return;
4968
+ const current = normalized.selectedGradesByCondition[condition];
4969
+ const nextForCondition = current === grade ? "" : grade;
4970
+ const nextMap = { ...normalized.selectedGradesByCondition };
4971
+ if (!nextForCondition) {
4972
+ delete nextMap[condition];
4973
+ } else {
4974
+ nextMap[condition] = nextForCondition;
4975
+ }
4976
+ setValue({ text: normalized.text, selectedGradesByCondition: nextMap });
4977
+ setTouched();
4978
+ };
4979
+ const labelContent = /* @__PURE__ */ jsxs(Fragment, { children: [
4980
+ def.label,
4981
+ " ",
4982
+ def.required && /* @__PURE__ */ jsx("span", { className: "text-red-500", children: "*" })
4983
+ ] });
4984
+ return /* @__PURE__ */ jsxs("div", { className: wrapperClass, children: [
4985
+ theme ? /* @__PURE__ */ jsx(Label, { htmlFor: fieldId, className: labelClass, children: labelContent }) : /* @__PURE__ */ jsx(Label, { htmlFor: fieldId, children: labelContent }),
4986
+ /* @__PURE__ */ jsx(
4987
+ Textarea,
4988
+ {
4989
+ id: fieldId,
4990
+ value: textValue,
4991
+ onChange: (e) => setValue({ text: e.target.value, selectedGradesByCondition: normalized.selectedGradesByCondition }),
4992
+ onBlur: setTouched,
4993
+ disabled,
4994
+ placeholder: def.placeholder,
4995
+ className: inputClass,
4996
+ ...def.height != null ? { height: def.height } : {}
4997
+ }
4998
+ ),
4999
+ isLoadingGrades && /* @__PURE__ */ jsx("p", { className: "mt-2 text-xs text-muted-foreground", children: "Checking diagnosis grades..." }),
5000
+ !isLoadingGrades && gradeGroups.length > 0 && /* @__PURE__ */ jsx(
5001
+ "div",
5002
+ {
5003
+ className: "mt-2 space-y-3 rounded-lg border border-border bg-muted/30 p-3",
5004
+ role: "group",
5005
+ "aria-label": "Diagnosis grade options",
5006
+ children: gradeGroups.map((group) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
5007
+ /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium leading-none text-muted-foreground", children: [
5008
+ group.condition,
5009
+ ":"
5010
+ ] }),
5011
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: group.grades.map((grade) => /* @__PURE__ */ jsx(
5012
+ "button",
5013
+ {
5014
+ type: "button",
5015
+ onClick: () => toggleSelectedGrade(group.condition, grade),
5016
+ disabled,
5017
+ className: cn(
5018
+ "inline-flex min-h-8 items-center rounded-full border px-3 py-1 text-xs font-medium leading-none transition-colors",
5019
+ normalized.selectedGradesByCondition[group.condition] === grade ? "border-primary bg-primary/15 text-primary shadow-sm" : "border-border/80 bg-background text-foreground hover:bg-muted/80",
5020
+ disabled && "cursor-not-allowed opacity-60"
5021
+ ),
5022
+ children: grade
5023
+ },
5024
+ `${group.condition}-${grade}`
5025
+ )) })
5026
+ ] }, group.condition))
5027
+ }
5028
+ ),
5029
+ showError && /* @__PURE__ */ jsx("p", { className: "text-xs text-red-500", children: error })
5030
+ ] });
5031
+ };
4762
5032
  var DEFAULT_DRAFT = {
4763
5033
  gpal: { G: 0, P: 0, A: 0, L: 0 },
4764
5034
  lmp: "",
@@ -6678,7 +6948,7 @@ var OphthalDiagnosisWidget = ({ fieldId }) => {
6678
6948
  ] })
6679
6949
  ] });
6680
6950
  };
6681
- var Slider = React13.forwardRef(({ className, trackClassName, thumbClassName, ...props }, ref) => /* @__PURE__ */ jsxs(
6951
+ var Slider = React15.forwardRef(({ className, trackClassName, thumbClassName, ...props }, ref) => /* @__PURE__ */ jsxs(
6682
6952
  SliderPrimitive.Root,
6683
6953
  {
6684
6954
  ref,
@@ -7066,6 +7336,9 @@ var FieldRenderer = ({ fieldId }) => {
7066
7336
  if (!visible || !fieldDef) {
7067
7337
  return null;
7068
7338
  }
7339
+ return renderWidget(fieldId, fieldDef);
7340
+ };
7341
+ function renderWidget(fieldId, fieldDef) {
7069
7342
  switch (fieldDef.type) {
7070
7343
  case "text":
7071
7344
  case "number":
@@ -7112,6 +7385,8 @@ var FieldRenderer = ({ fieldId }) => {
7112
7385
  return /* @__PURE__ */ jsx(FollowupWidget, { fieldId });
7113
7386
  case "smart_textarea":
7114
7387
  return /* @__PURE__ */ jsx(SmartTextareaWidget, { fieldId });
7388
+ case "diagnosis_textarea":
7389
+ return /* @__PURE__ */ jsx(DiagnosisTextareaWidget, { fieldId });
7115
7390
  case "obstetric_history":
7116
7391
  return /* @__PURE__ */ jsx(ObstetricHistoryWidget, { fieldId });
7117
7392
  case "eye_prescription":
@@ -7136,7 +7411,7 @@ var FieldRenderer = ({ fieldId }) => {
7136
7411
  fieldDef.type
7137
7412
  ] });
7138
7413
  }
7139
- };
7414
+ }
7140
7415
  var Section = ({ title, children }) => {
7141
7416
  const [expanded, setExpanded] = useState(true);
7142
7417
  const handleToggle = () => setExpanded((prev) => !prev);
@@ -7191,7 +7466,7 @@ var DynamicForm = () => {
7191
7466
  children: child.children.map((fieldId) => /* @__PURE__ */ jsx(FieldRenderer, { fieldId }, fieldId))
7192
7467
  },
7193
7468
  child.id
7194
- ) : /* @__PURE__ */ jsx(React13__default.Fragment, {}, child.id ?? index)
7469
+ ) : /* @__PURE__ */ jsx(React15__default.Fragment, {}, child.id ?? index)
7195
7470
  ) }, node.id);
7196
7471
  }
7197
7472
  if (node.type === "column_layout") {
@@ -7775,7 +8050,7 @@ var ReadOnlyForm = ({ schema, submission }) => {
7775
8050
  child.id
7776
8051
  );
7777
8052
  }
7778
- return /* @__PURE__ */ jsx(React13__default.Fragment, {}, child.id ?? index);
8053
+ return /* @__PURE__ */ jsx(React15__default.Fragment, {}, child.id ?? index);
7779
8054
  };
7780
8055
  const hasContent = node.children.some(
7781
8056
  (child) => typeof child === "string" ? fieldMap.has(child) : child.type === "column_layout" && child.children?.some((id) => fieldMap.has(id))