formanitor 0.0.28 → 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.d.cts CHANGED
@@ -63,6 +63,12 @@ interface BaseFieldDef {
63
63
  */
64
64
  theme?: string;
65
65
  meta?: Record<string, unknown>;
66
+ /**
67
+ * When true, a microphone button is rendered alongside this field so the
68
+ * user can dictate its value via speech. Requires `StoreConfig.voice` to
69
+ * be wired up with an `onTranscribe` callback.
70
+ */
71
+ voice?: boolean;
66
72
  }
67
73
  interface TextFieldDef extends BaseFieldDef {
68
74
  type: 'text' | 'textarea';
@@ -448,6 +454,17 @@ interface StoreConfig {
448
454
  onEvent?: EventListener;
449
455
  onUpload?: UploadHandler;
450
456
  onDraftChange?: DraftChangeHandler;
457
+ /**
458
+ * Voice dictation support. When provided, fields marked with `voice: true`
459
+ * in the schema will display a microphone button.
460
+ * The host app owns all recording logic and supplies two callbacks:
461
+ * - `startRecording` — begin capturing audio
462
+ * - `stopRecording` — stop capturing, transcribe, and return the transcript
463
+ */
464
+ voice?: {
465
+ startRecording: () => Promise<void>;
466
+ stopRecording: () => Promise<string>;
467
+ };
451
468
  }
452
469
  declare class FormStore {
453
470
  private state;
@@ -471,6 +488,7 @@ declare class FormStore {
471
488
  };
472
489
  getSchema(): FormDef;
473
490
  getFieldDef(fieldId: string): FieldDef | undefined;
491
+ getVoice(): StoreConfig['voice'];
474
492
  hasPersistence(): boolean;
475
493
  setValue(fieldId: string, value: any): void;
476
494
  /**
package/dist/index.d.ts CHANGED
@@ -63,6 +63,12 @@ interface BaseFieldDef {
63
63
  */
64
64
  theme?: string;
65
65
  meta?: Record<string, unknown>;
66
+ /**
67
+ * When true, a microphone button is rendered alongside this field so the
68
+ * user can dictate its value via speech. Requires `StoreConfig.voice` to
69
+ * be wired up with an `onTranscribe` callback.
70
+ */
71
+ voice?: boolean;
66
72
  }
67
73
  interface TextFieldDef extends BaseFieldDef {
68
74
  type: 'text' | 'textarea';
@@ -448,6 +454,17 @@ interface StoreConfig {
448
454
  onEvent?: EventListener;
449
455
  onUpload?: UploadHandler;
450
456
  onDraftChange?: DraftChangeHandler;
457
+ /**
458
+ * Voice dictation support. When provided, fields marked with `voice: true`
459
+ * in the schema will display a microphone button.
460
+ * The host app owns all recording logic and supplies two callbacks:
461
+ * - `startRecording` — begin capturing audio
462
+ * - `stopRecording` — stop capturing, transcribe, and return the transcript
463
+ */
464
+ voice?: {
465
+ startRecording: () => Promise<void>;
466
+ stopRecording: () => Promise<string>;
467
+ };
451
468
  }
452
469
  declare class FormStore {
453
470
  private state;
@@ -471,6 +488,7 @@ declare class FormStore {
471
488
  };
472
489
  getSchema(): FormDef;
473
490
  getFieldDef(fieldId: string): FieldDef | undefined;
491
+ getVoice(): StoreConfig['voice'];
474
492
  hasPersistence(): boolean;
475
493
  setValue(fieldId: string, value: any): void;
476
494
  /**
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
  }
@@ -603,6 +606,7 @@ var FormStore = class {
603
606
  if (next.onUpload !== void 0) this.config.onUpload = next.onUpload;
604
607
  if (next.onEvent !== void 0) this.config.onEvent = next.onEvent;
605
608
  if (next.onDraftChange !== void 0) this.config.onDraftChange = next.onDraftChange;
609
+ if (next.voice !== void 0) this.config.voice = next.voice;
606
610
  if (next.role !== void 0 && next.role !== this.config.role) {
607
611
  this.config.role = next.role;
608
612
  needsReeval = true;
@@ -664,6 +668,21 @@ var FormStore = class {
664
668
  this.listeners.forEach((l) => l(this.state));
665
669
  }
666
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
+ }
667
686
  var FormContext = createContext(null);
668
687
  var emptyFrequentItems = {
669
688
  medications: [],
@@ -699,7 +718,7 @@ var FormProvider = ({
699
718
  storeRef.current?.load();
700
719
  }, []);
701
720
  const frequentItemsValue = frequentItems ?? emptyFrequentItems;
702
- 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 }) }) }) });
703
722
  };
704
723
  function useFormStore() {
705
724
  const context = useContext(FormContext);
@@ -756,10 +775,76 @@ function useField(fieldId) {
756
775
  setTouched
757
776
  };
758
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
+ }
759
844
  function cn(...inputs) {
760
845
  return twMerge(clsx(inputs));
761
846
  }
762
- var Input = React13.forwardRef(
847
+ var Input = React15.forwardRef(
763
848
  ({ className, type, ...props }, ref) => {
764
849
  return /* @__PURE__ */ jsx(
765
850
  "input",
@@ -779,7 +864,7 @@ Input.displayName = "Input";
779
864
  var labelVariants = cva(
780
865
  "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
781
866
  );
782
- var Label = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
867
+ var Label = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
783
868
  LabelPrimitive.Root,
784
869
  {
785
870
  ref,
@@ -788,7 +873,7 @@ var Label = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
788
873
  }
789
874
  ));
790
875
  Label.displayName = LabelPrimitive.Root.displayName;
791
- var Textarea = React13.forwardRef(
876
+ var Textarea = React15.forwardRef(
792
877
  ({ className, height, style, ...props }, ref) => {
793
878
  return /* @__PURE__ */ jsx(
794
879
  "textarea",
@@ -832,6 +917,8 @@ function getThemeConfig(fieldType, themeName) {
832
917
  var TextWidget = ({ fieldId }) => {
833
918
  const { fieldDef, value, setValue, setTouched, error, disabled, touched } = useField(fieldId);
834
919
  const { state } = useForm();
920
+ const store = useFormStore();
921
+ const hasVoice = !!(fieldDef?.voice && store.getVoice());
835
922
  const showError = !!error && (touched || state.submitAttempted);
836
923
  if (!fieldDef) return null;
837
924
  const Component = fieldDef.type === "textarea" ? Textarea : Input;
@@ -849,8 +936,12 @@ var TextWidget = ({ fieldId }) => {
849
936
  " ",
850
937
  fieldDef.required && /* @__PURE__ */ jsx("span", { className: "text-red-500", children: "*" })
851
938
  ] });
939
+ const labelEl = theme ? /* @__PURE__ */ jsx(Label, { htmlFor: fieldId, className: labelClass, children: labelContent }) : /* @__PURE__ */ jsx(Label, { htmlFor: fieldId, children: labelContent });
852
940
  return /* @__PURE__ */ jsxs("div", { className: wrapperClass, children: [
853
- 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,
854
945
  /* @__PURE__ */ jsx(
855
946
  Component,
856
947
  {
@@ -892,7 +983,7 @@ var buttonVariants = cva(
892
983
  }
893
984
  }
894
985
  );
895
- var Button = React13.forwardRef(
986
+ var Button = React15.forwardRef(
896
987
  ({ className, variant, size, asChild = false, ...props }, ref) => {
897
988
  const Comp = asChild ? Slot : "button";
898
989
  return /* @__PURE__ */ jsx(
@@ -906,7 +997,7 @@ var Button = React13.forwardRef(
906
997
  }
907
998
  );
908
999
  Button.displayName = "Button";
909
- var Separator = React13.forwardRef(
1000
+ var Separator = React15.forwardRef(
910
1001
  ({ className, orientation = "horizontal", decorative = true, ...props }, ref) => /* @__PURE__ */ jsx(
911
1002
  SeparatorPrimitive.Root,
912
1003
  {
@@ -1038,6 +1129,8 @@ function RichTextToolbar({
1038
1129
  var RichTextWidget = ({ fieldId }) => {
1039
1130
  const { fieldDef, value, setValue, setTouched, error, disabled, touched } = useField(fieldId);
1040
1131
  const { state } = useForm();
1132
+ const store = useFormStore();
1133
+ const hasVoice = !!(fieldDef?.voice && store.getVoice());
1041
1134
  const showError = !!error && (touched || state.submitAttempted);
1042
1135
  const def = fieldDef;
1043
1136
  const placeholder = def?.placeholder ?? "Start typing\u2026";
@@ -1119,8 +1212,12 @@ var RichTextWidget = ({ fieldId }) => {
1119
1212
  " ",
1120
1213
  fieldDef.required && /* @__PURE__ */ jsx("span", { className: "text-red-500", children: "*" })
1121
1214
  ] });
1215
+ const labelEl = /* @__PURE__ */ jsx(Label, { htmlFor: fieldId, children: labelContent });
1122
1216
  return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
1123
- /* @__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,
1124
1221
  /* @__PURE__ */ jsxs(
1125
1222
  "div",
1126
1223
  {
@@ -1158,7 +1255,7 @@ var RichTextWidget = ({ fieldId }) => {
1158
1255
  };
1159
1256
  var Select = SelectPrimitive.Root;
1160
1257
  var SelectValue = SelectPrimitive.Value;
1161
- var SelectTrigger = React13.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
1258
+ var SelectTrigger = React15.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
1162
1259
  SelectPrimitive.Trigger,
1163
1260
  {
1164
1261
  ref,
@@ -1174,7 +1271,7 @@ var SelectTrigger = React13.forwardRef(({ className, children, ...props }, ref)
1174
1271
  }
1175
1272
  ));
1176
1273
  SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
1177
- var SelectScrollUpButton = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1274
+ var SelectScrollUpButton = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1178
1275
  SelectPrimitive.ScrollUpButton,
1179
1276
  {
1180
1277
  ref,
@@ -1187,7 +1284,7 @@ var SelectScrollUpButton = React13.forwardRef(({ className, ...props }, ref) =>
1187
1284
  }
1188
1285
  ));
1189
1286
  SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
1190
- var SelectScrollDownButton = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1287
+ var SelectScrollDownButton = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1191
1288
  SelectPrimitive.ScrollDownButton,
1192
1289
  {
1193
1290
  ref,
@@ -1200,7 +1297,7 @@ var SelectScrollDownButton = React13.forwardRef(({ className, ...props }, ref) =
1200
1297
  }
1201
1298
  ));
1202
1299
  SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
1203
- 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(
1204
1301
  SelectPrimitive.Content,
1205
1302
  {
1206
1303
  ref,
@@ -1228,7 +1325,7 @@ var SelectContent = React13.forwardRef(({ className, children, position = "poppe
1228
1325
  }
1229
1326
  ) }));
1230
1327
  SelectContent.displayName = SelectPrimitive.Content.displayName;
1231
- var SelectLabel = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1328
+ var SelectLabel = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1232
1329
  SelectPrimitive.Label,
1233
1330
  {
1234
1331
  ref,
@@ -1237,7 +1334,7 @@ var SelectLabel = React13.forwardRef(({ className, ...props }, ref) => /* @__PUR
1237
1334
  }
1238
1335
  ));
1239
1336
  SelectLabel.displayName = SelectPrimitive.Label.displayName;
1240
- var SelectItem = React13.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
1337
+ var SelectItem = React15.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
1241
1338
  SelectPrimitive.Item,
1242
1339
  {
1243
1340
  ref,
@@ -1253,7 +1350,7 @@ var SelectItem = React13.forwardRef(({ className, children, ...props }, ref) =>
1253
1350
  }
1254
1351
  ));
1255
1352
  SelectItem.displayName = SelectPrimitive.Item.displayName;
1256
- var SelectSeparator = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1353
+ var SelectSeparator = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1257
1354
  SelectPrimitive.Separator,
1258
1355
  {
1259
1356
  ref,
@@ -1342,7 +1439,7 @@ var SelectWidget = ({ fieldId }) => {
1342
1439
  showError && /* @__PURE__ */ jsx("p", { className: "text-xs text-red-500", children: error })
1343
1440
  ] });
1344
1441
  };
1345
- var Checkbox = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1442
+ var Checkbox = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1346
1443
  CheckboxPrimitive.Root,
1347
1444
  {
1348
1445
  ref,
@@ -1416,7 +1513,7 @@ var MultiSelectWidget = ({ fieldId }) => {
1416
1513
  showError && /* @__PURE__ */ jsx("p", { className: "text-xs text-red-500", children: error })
1417
1514
  ] });
1418
1515
  };
1419
- 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(
1420
1517
  "table",
1421
1518
  {
1422
1519
  ref,
@@ -1425,9 +1522,9 @@ var Table = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
1425
1522
  }
1426
1523
  ) }));
1427
1524
  Table.displayName = "Table";
1428
- 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 }));
1429
1526
  TableHeader.displayName = "TableHeader";
1430
- var TableBody = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1527
+ var TableBody = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1431
1528
  "tbody",
1432
1529
  {
1433
1530
  ref,
@@ -1436,7 +1533,7 @@ var TableBody = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE_
1436
1533
  }
1437
1534
  ));
1438
1535
  TableBody.displayName = "TableBody";
1439
- var TableFooter = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1536
+ var TableFooter = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1440
1537
  "tfoot",
1441
1538
  {
1442
1539
  ref,
@@ -1448,7 +1545,7 @@ var TableFooter = React13.forwardRef(({ className, ...props }, ref) => /* @__PUR
1448
1545
  }
1449
1546
  ));
1450
1547
  TableFooter.displayName = "TableFooter";
1451
- var TableRow = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1548
+ var TableRow = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1452
1549
  "tr",
1453
1550
  {
1454
1551
  ref,
@@ -1460,7 +1557,7 @@ var TableRow = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__
1460
1557
  }
1461
1558
  ));
1462
1559
  TableRow.displayName = "TableRow";
1463
- var TableHead = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1560
+ var TableHead = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1464
1561
  "th",
1465
1562
  {
1466
1563
  ref,
@@ -1472,7 +1569,7 @@ var TableHead = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE_
1472
1569
  }
1473
1570
  ));
1474
1571
  TableHead.displayName = "TableHead";
1475
- var TableCell = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1572
+ var TableCell = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1476
1573
  "td",
1477
1574
  {
1478
1575
  ref,
@@ -1481,7 +1578,7 @@ var TableCell = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE_
1481
1578
  }
1482
1579
  ));
1483
1580
  TableCell.displayName = "TableCell";
1484
- var TableCaption = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1581
+ var TableCaption = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1485
1582
  "caption",
1486
1583
  {
1487
1584
  ref,
@@ -1497,7 +1594,7 @@ var RepeatableWidget = ({
1497
1594
  if (!fieldDef || fieldDef.type !== "repeatable") return null;
1498
1595
  const def = fieldDef;
1499
1596
  const rows = Array.isArray(value) ? value : [];
1500
- const [hasInteracted, setHasInteracted] = React13__default.useState(false);
1597
+ const [hasInteracted, setHasInteracted] = React15__default.useState(false);
1501
1598
  const showError = !!error && (touched || hasInteracted);
1502
1599
  const addRow = () => {
1503
1600
  setValue([...rows, {}]);
@@ -1666,7 +1763,7 @@ function Calendar({
1666
1763
  Calendar.displayName = "Calendar";
1667
1764
  var Popover = PopoverPrimitive.Root;
1668
1765
  var PopoverTrigger = PopoverPrimitive.Trigger;
1669
- 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(
1670
1767
  PopoverPrimitive.Content,
1671
1768
  {
1672
1769
  ref,
@@ -1745,14 +1842,14 @@ function DateTimePicker({
1745
1842
  className,
1746
1843
  placeholder = "Pick date & time"
1747
1844
  }) {
1748
- const [internalDate, setInternalDate] = React13.useState(dateTime);
1749
- const [timeString, setTimeString] = React13.useState(() => {
1845
+ const [internalDate, setInternalDate] = React15.useState(dateTime);
1846
+ const [timeString, setTimeString] = React15.useState(() => {
1750
1847
  if (!dateTime) return "";
1751
1848
  const hours = dateTime.getHours().toString().padStart(2, "0");
1752
1849
  const minutes = dateTime.getMinutes().toString().padStart(2, "0");
1753
1850
  return `${hours}:${minutes}`;
1754
1851
  });
1755
- React13.useEffect(() => {
1852
+ React15.useEffect(() => {
1756
1853
  setInternalDate(dateTime);
1757
1854
  if (!dateTime) {
1758
1855
  setTimeString("");
@@ -1896,7 +1993,7 @@ var ImageUploadWidget = ({ fieldId }) => {
1896
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." }) })
1897
1994
  ] });
1898
1995
  }
1899
- React13__default.useEffect(() => {
1996
+ React15__default.useEffect(() => {
1900
1997
  if (value && typeof value === "string") {
1901
1998
  setPreview(value);
1902
1999
  } else {
@@ -2535,7 +2632,7 @@ var EditableTableWidget = ({
2535
2632
  ] })
2536
2633
  ] });
2537
2634
  };
2538
- var RadioGroup = React13.forwardRef(({ className, ...props }, ref) => {
2635
+ var RadioGroup = React15.forwardRef(({ className, ...props }, ref) => {
2539
2636
  return /* @__PURE__ */ jsx(
2540
2637
  RadioGroupPrimitive.Root,
2541
2638
  {
@@ -2546,7 +2643,7 @@ var RadioGroup = React13.forwardRef(({ className, ...props }, ref) => {
2546
2643
  );
2547
2644
  });
2548
2645
  RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;
2549
- var RadioGroupItem = React13.forwardRef(({ className, ...props }, ref) => {
2646
+ var RadioGroupItem = React15.forwardRef(({ className, ...props }, ref) => {
2550
2647
  return /* @__PURE__ */ jsx(
2551
2648
  RadioGroupPrimitive.Item,
2552
2649
  {
@@ -2693,7 +2790,7 @@ function useAISuggestions() {
2693
2790
  var AISuggestionsProvider = AISuggestionsContext.Provider;
2694
2791
  var Dialog = DialogPrimitive.Root;
2695
2792
  var DialogPortal = DialogPrimitive.Portal;
2696
- var DialogOverlay = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2793
+ var DialogOverlay = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2697
2794
  DialogPrimitive.Overlay,
2698
2795
  {
2699
2796
  ref,
@@ -2705,7 +2802,7 @@ var DialogOverlay = React13.forwardRef(({ className, ...props }, ref) => /* @__P
2705
2802
  }
2706
2803
  ));
2707
2804
  DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
2708
- 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: [
2709
2806
  /* @__PURE__ */ jsx(DialogOverlay, {}),
2710
2807
  /* @__PURE__ */ jsxs(
2711
2808
  DialogPrimitive.Content,
@@ -2741,7 +2838,7 @@ var DialogHeader = ({
2741
2838
  }
2742
2839
  );
2743
2840
  DialogHeader.displayName = "DialogHeader";
2744
- var DialogTitle = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2841
+ var DialogTitle = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2745
2842
  DialogPrimitive.Title,
2746
2843
  {
2747
2844
  ref,
@@ -2753,7 +2850,7 @@ var DialogTitle = React13.forwardRef(({ className, ...props }, ref) => /* @__PUR
2753
2850
  }
2754
2851
  ));
2755
2852
  DialogTitle.displayName = DialogPrimitive.Title.displayName;
2756
- var DialogDescription = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2853
+ var DialogDescription = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2757
2854
  DialogPrimitive.Description,
2758
2855
  {
2759
2856
  ref,
@@ -3901,7 +3998,7 @@ var DifferentialDiagnosisWidget = ({ fieldId }) => {
3901
3998
  const items = Array.isArray(value) ? value : [];
3902
3999
  return /* @__PURE__ */ jsx(DifferentialDiagnosis, { differentialDiagnosis: items });
3903
4000
  };
3904
- var Spinner2 = React13.forwardRef(
4001
+ var Spinner2 = React15.forwardRef(
3905
4002
  ({ className, size = "md", ...props }, ref) => {
3906
4003
  const sizeClasses = {
3907
4004
  sm: "h-4 w-4 border-2",
@@ -4257,7 +4354,7 @@ var ReferralWidget = ({ fieldId }) => {
4257
4354
  showError && /* @__PURE__ */ jsx("p", { className: "text-xs text-red-500", children: error })
4258
4355
  ] });
4259
4356
  };
4260
- var Card = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4357
+ var Card = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4261
4358
  "div",
4262
4359
  {
4263
4360
  ref,
@@ -4269,7 +4366,7 @@ var Card = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
4269
4366
  }
4270
4367
  ));
4271
4368
  Card.displayName = "Card";
4272
- var CardHeader = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4369
+ var CardHeader = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4273
4370
  "div",
4274
4371
  {
4275
4372
  ref,
@@ -4278,7 +4375,7 @@ var CardHeader = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE
4278
4375
  }
4279
4376
  ));
4280
4377
  CardHeader.displayName = "CardHeader";
4281
- var CardTitle = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4378
+ var CardTitle = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4282
4379
  "h3",
4283
4380
  {
4284
4381
  ref,
@@ -4290,7 +4387,7 @@ var CardTitle = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE_
4290
4387
  }
4291
4388
  ));
4292
4389
  CardTitle.displayName = "CardTitle";
4293
- var CardDescription = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4390
+ var CardDescription = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4294
4391
  "p",
4295
4392
  {
4296
4393
  ref,
@@ -4299,9 +4396,9 @@ var CardDescription = React13.forwardRef(({ className, ...props }, ref) => /* @_
4299
4396
  }
4300
4397
  ));
4301
4398
  CardDescription.displayName = "CardDescription";
4302
- 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 }));
4303
4400
  CardContent.displayName = "CardContent";
4304
- var CardFooter = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4401
+ var CardFooter = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4305
4402
  "div",
4306
4403
  {
4307
4404
  ref,
@@ -4723,7 +4820,7 @@ var SmartTextareaWidget = ({ fieldId }) => {
4723
4820
  },
4724
4821
  [setValue]
4725
4822
  );
4726
- React13__default.useEffect(() => {
4823
+ React15__default.useEffect(() => {
4727
4824
  if (nextKeywords !== currentKeywords) {
4728
4825
  writeValue(textValue, nextKeywords);
4729
4826
  }
@@ -4799,9 +4896,9 @@ var DiagnosisTextareaWidget = ({ fieldId }) => {
4799
4896
  const { state } = useForm();
4800
4897
  const handler = useFieldHandlers(fieldId);
4801
4898
  const def = fieldDef;
4802
- const [gradeGroups, setGradeGroups] = React13__default.useState([]);
4803
- const [isLoadingGrades, setIsLoadingGrades] = React13__default.useState(false);
4804
- const normalized = React13__default.useMemo(() => {
4899
+ const [gradeGroups, setGradeGroups] = React15__default.useState([]);
4900
+ const [isLoadingGrades, setIsLoadingGrades] = React15__default.useState(false);
4901
+ const normalized = React15__default.useMemo(() => {
4805
4902
  const raw = value;
4806
4903
  if (typeof raw === "string") {
4807
4904
  return { text: raw, selectedGradesByCondition: {} };
@@ -4833,7 +4930,7 @@ var DiagnosisTextareaWidget = ({ fieldId }) => {
4833
4930
  }, [value]);
4834
4931
  const textValue = normalized.text;
4835
4932
  const showError = !!error && (touched || state.submitAttempted);
4836
- React13__default.useEffect(() => {
4933
+ React15__default.useEffect(() => {
4837
4934
  const query = textValue.trim();
4838
4935
  const fetchGrades = handler.onFetchDiagnosisGrades;
4839
4936
  const debounceMs = def?.debounceDelay ?? 1e3;
@@ -6851,7 +6948,7 @@ var OphthalDiagnosisWidget = ({ fieldId }) => {
6851
6948
  ] })
6852
6949
  ] });
6853
6950
  };
6854
- var Slider = React13.forwardRef(({ className, trackClassName, thumbClassName, ...props }, ref) => /* @__PURE__ */ jsxs(
6951
+ var Slider = React15.forwardRef(({ className, trackClassName, thumbClassName, ...props }, ref) => /* @__PURE__ */ jsxs(
6855
6952
  SliderPrimitive.Root,
6856
6953
  {
6857
6954
  ref,
@@ -7239,6 +7336,9 @@ var FieldRenderer = ({ fieldId }) => {
7239
7336
  if (!visible || !fieldDef) {
7240
7337
  return null;
7241
7338
  }
7339
+ return renderWidget(fieldId, fieldDef);
7340
+ };
7341
+ function renderWidget(fieldId, fieldDef) {
7242
7342
  switch (fieldDef.type) {
7243
7343
  case "text":
7244
7344
  case "number":
@@ -7311,7 +7411,7 @@ var FieldRenderer = ({ fieldId }) => {
7311
7411
  fieldDef.type
7312
7412
  ] });
7313
7413
  }
7314
- };
7414
+ }
7315
7415
  var Section = ({ title, children }) => {
7316
7416
  const [expanded, setExpanded] = useState(true);
7317
7417
  const handleToggle = () => setExpanded((prev) => !prev);
@@ -7366,7 +7466,7 @@ var DynamicForm = () => {
7366
7466
  children: child.children.map((fieldId) => /* @__PURE__ */ jsx(FieldRenderer, { fieldId }, fieldId))
7367
7467
  },
7368
7468
  child.id
7369
- ) : /* @__PURE__ */ jsx(React13__default.Fragment, {}, child.id ?? index)
7469
+ ) : /* @__PURE__ */ jsx(React15__default.Fragment, {}, child.id ?? index)
7370
7470
  ) }, node.id);
7371
7471
  }
7372
7472
  if (node.type === "column_layout") {
@@ -7950,7 +8050,7 @@ var ReadOnlyForm = ({ schema, submission }) => {
7950
8050
  child.id
7951
8051
  );
7952
8052
  }
7953
- return /* @__PURE__ */ jsx(React13__default.Fragment, {}, child.id ?? index);
8053
+ return /* @__PURE__ */ jsx(React15__default.Fragment, {}, child.id ?? index);
7954
8054
  };
7955
8055
  const hasContent = node.children.some(
7956
8056
  (child) => typeof child === "string" ? fieldMap.has(child) : child.type === "column_layout" && child.children?.some((id) => fieldMap.has(id))