formanitor 0.0.42 → 0.0.43

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
@@ -102,12 +102,82 @@ function validateForm(values, fields) {
102
102
  return errors;
103
103
  }
104
104
 
105
+ // src/core/suggestionTokens.ts
106
+ function getSuggestionTokensFromText(text) {
107
+ return text.split(/[,\n\r]+/).map((p) => p.trim()).filter(Boolean);
108
+ }
109
+ var DEFAULT_TOKEN_SEPARATOR = ", ";
110
+ function commaSplitLine(line) {
111
+ return line.split(",").map((p) => p.trim()).filter(Boolean);
112
+ }
113
+ function dedupeChipOrder(chips) {
114
+ const seen = /* @__PURE__ */ new Set();
115
+ const out = [];
116
+ for (const c of chips) {
117
+ if (seen.has(c)) continue;
118
+ seen.add(c);
119
+ out.push(c);
120
+ }
121
+ return out;
122
+ }
123
+ function parseProseAndChipTokens(text, allowed) {
124
+ const normalized = text.replace(/\r\n/g, "\n");
125
+ let lines = normalized.split("\n");
126
+ while (lines.length > 0 && lines[lines.length - 1] === "") {
127
+ lines.pop();
128
+ }
129
+ if (lines.length === 0) return { prose: "", chips: [] };
130
+ let chipStart = lines.length;
131
+ for (let i = lines.length - 1; i >= 0; i--) {
132
+ const toks = commaSplitLine(lines[i]);
133
+ if (toks.length === 0) break;
134
+ if (!toks.every((t) => allowed.has(t))) break;
135
+ chipStart = i;
136
+ }
137
+ if (chipStart < lines.length) {
138
+ const chipLines = lines.slice(chipStart);
139
+ const prose = lines.slice(0, chipStart).join("\n");
140
+ const chips = dedupeChipOrder(chipLines.flatMap(commaSplitLine));
141
+ return { prose, chips };
142
+ }
143
+ const parts = getSuggestionTokensFromText(normalized);
144
+ const chipsFallback = dedupeChipOrder(parts.filter((t) => allowed.has(t)));
145
+ const proseParts = parts.filter((t) => !allowed.has(t));
146
+ return { prose: proseParts.join(DEFAULT_TOKEN_SEPARATOR), chips: chipsFallback };
147
+ }
148
+ function composeProseAndChips(prose, chips, separator = DEFAULT_TOKEN_SEPARATOR) {
149
+ const chipStr = dedupeChipOrder(chips).join(separator);
150
+ const p = prose.replace(/\s+$/, "");
151
+ if (p && chipStr) return `${p}
152
+ ${chipStr}`;
153
+ if (chipStr) return chipStr;
154
+ return p;
155
+ }
156
+ function toggleSuggestionTokenInText(current, token, separator = DEFAULT_TOKEN_SEPARATOR, allowedChipValues) {
157
+ const t = String(token).trim();
158
+ if (!t) return current;
159
+ if (!allowedChipValues || allowedChipValues.size === 0) {
160
+ const parts = getSuggestionTokensFromText(current);
161
+ const i = parts.findIndex((p) => p === t);
162
+ if (i >= 0) parts.splice(i, 1);
163
+ else parts.push(t);
164
+ return parts.join(separator);
165
+ }
166
+ if (!allowedChipValues.has(t)) return current;
167
+ let { prose, chips } = parseProseAndChipTokens(current, allowedChipValues);
168
+ const idx = chips.indexOf(t);
169
+ if (idx >= 0) chips.splice(idx, 1);
170
+ else chips.push(t);
171
+ chips = dedupeChipOrder(chips);
172
+ return composeProseAndChips(prose, chips, separator);
173
+ }
174
+
105
175
  // src/core/rules.ts
106
176
  function tokenListContainsString(text, needle) {
107
177
  if (typeof text !== "string") return false;
108
178
  const want = String(needle).trim();
109
179
  if (!want) return false;
110
- const parts = text.split(",").map((p) => p.trim()).filter(Boolean);
180
+ const parts = getSuggestionTokensFromText(text);
111
181
  return parts.includes(want);
112
182
  }
113
183
  function evaluateCondition(value, condition) {
@@ -318,7 +388,7 @@ function normalizeGeneralSurgerySmartHistory(raw) {
318
388
  ...painIn,
319
389
  severity: Number.isFinite(sev) ? Math.min(10, Math.max(0, Math.round(sev))) : d.pain.severity
320
390
  };
321
- const str2 = (x) => typeof x === "string" ? x : "";
391
+ const str4 = (x) => typeof x === "string" ? x : "";
322
392
  const strArr = (x) => Array.isArray(x) ? x.filter((i) => typeof i === "string") : [];
323
393
  const swell = v.swelling && typeof v.swelling === "object" ? v.swelling : {};
324
394
  const gi = v.gi && typeof v.gi === "object" ? v.gi : {};
@@ -328,44 +398,44 @@ function normalizeGeneralSurgerySmartHistory(raw) {
328
398
  return {
329
399
  pain,
330
400
  swelling: {
331
- duration: str2(swell.duration),
332
- sizeProgression: str2(swell.sizeProgression),
333
- painfulPainless: str2(swell.painfulPainless),
401
+ duration: str4(swell.duration),
402
+ sizeProgression: str4(swell.sizeProgression),
403
+ painfulPainless: str4(swell.painfulPainless),
334
404
  checks: strArr(swell.checks)
335
405
  },
336
406
  gi: {
337
- appetite: str2(gi.appetite),
338
- weightLoss: str2(gi.weightLoss),
339
- bowelHabits: str2(gi.bowelHabits),
407
+ appetite: str4(gi.appetite),
408
+ weightLoss: str4(gi.weightLoss),
409
+ bowelHabits: str4(gi.bowelHabits),
340
410
  checks: strArr(gi.checks)
341
411
  },
342
412
  breast: {
343
- lumpDuration: str2(breast.lumpDuration),
344
- nippleDischarge: str2(breast.nippleDischarge),
413
+ lumpDuration: str4(breast.lumpDuration),
414
+ nippleDischarge: str4(breast.nippleDischarge),
345
415
  checks: strArr(breast.checks)
346
416
  },
347
417
  ano: { checks: strArr(ano.checks) },
348
418
  thyroid: {
349
- swellingDuration: str2(thy.swellingDuration),
419
+ swellingDuration: str4(thy.swellingDuration),
350
420
  checks: strArr(thy.checks)
351
421
  }
352
422
  };
353
423
  }
354
424
  function normalizeBreastExamSide(partial) {
355
425
  const e = defaultBreastExamSide();
356
- const str2 = (x) => typeof x === "string" ? x : "";
357
- const bool = (x) => x === true;
426
+ const str4 = (x) => typeof x === "string" ? x : "";
427
+ const bool2 = (x) => x === true;
358
428
  if (!partial || typeof partial !== "object") return e;
359
429
  const p = partial;
360
430
  return {
361
- size: str2(p.size),
362
- quadrant: str2(p.quadrant),
363
- tenderness: str2(p.tenderness),
364
- fixity: str2(p.fixity),
365
- skinInvolvement: str2(p.skinInvolvement),
366
- consistency: str2(p.consistency),
367
- axillaryNodes: bool(p.axillaryNodes),
368
- nippleAreolarComplex: bool(p.nippleAreolarComplex)
431
+ size: str4(p.size),
432
+ quadrant: str4(p.quadrant),
433
+ tenderness: str4(p.tenderness),
434
+ fixity: str4(p.fixity),
435
+ skinInvolvement: str4(p.skinInvolvement),
436
+ consistency: str4(p.consistency),
437
+ axillaryNodes: bool2(p.axillaryNodes),
438
+ nippleAreolarComplex: bool2(p.nippleAreolarComplex)
369
439
  };
370
440
  }
371
441
  function normalizeBreastExaminationBlock(raw) {
@@ -389,7 +459,7 @@ function normalizeGeneralSurgeryExamination(raw) {
389
459
  const th = v.thyroid && typeof v.thyroid === "object" ? v.thyroid : {};
390
460
  const ar = v.anorectal && typeof v.anorectal === "object" ? v.anorectal : {};
391
461
  const lm = v.limb && typeof v.limb === "object" ? v.limb : {};
392
- const bool = (x) => x === true;
462
+ const bool2 = (x) => x === true;
393
463
  return {
394
464
  general: strArr(v.general),
395
465
  regions: strArr(v.regions),
@@ -402,27 +472,27 @@ function normalizeGeneralSurgeryExamination(raw) {
402
472
  },
403
473
  hernia: {
404
474
  site: typeof hb.site === "string" ? hb.site : "",
405
- reducible: bool(hb.reducible),
406
- coughImpulse: bool(hb.coughImpulse),
407
- tenderness: bool(hb.tenderness)
475
+ reducible: bool2(hb.reducible),
476
+ coughImpulse: bool2(hb.coughImpulse),
477
+ tenderness: bool2(hb.tenderness)
408
478
  },
409
479
  breast: normalizeBreastExaminationBlock(br),
410
480
  thyroid: {
411
481
  size: typeof th.size === "string" ? th.size : "",
412
- mobileDeglutition: bool(th.mobileDeglutition),
413
- nodules: bool(th.nodules),
414
- cervicalNodes: bool(th.cervicalNodes)
482
+ mobileDeglutition: bool2(th.mobileDeglutition),
483
+ nodules: bool2(th.nodules),
484
+ cervicalNodes: bool2(th.cervicalNodes)
415
485
  },
416
486
  anorectal: {
417
487
  inspection: typeof ar.inspection === "string" ? ar.inspection : "",
418
- dreDone: bool(ar.dreDone),
419
- proctoscopyDone: bool(ar.proctoscopyDone),
488
+ dreDone: bool2(ar.dreDone),
489
+ proctoscopyDone: bool2(ar.proctoscopyDone),
420
490
  notes: typeof ar.notes === "string" ? ar.notes : ""
421
491
  },
422
492
  limb: {
423
- dilatedVeins: bool(lm.dilatedVeins),
424
- ulcer: bool(lm.ulcer),
425
- oedema: bool(lm.oedema)
493
+ dilatedVeins: bool2(lm.dilatedVeins),
494
+ ulcer: bool2(lm.ulcer),
495
+ oedema: bool2(lm.oedema)
426
496
  }
427
497
  };
428
498
  }
@@ -698,6 +768,375 @@ function formatGeneralSurgeryExaminationToNarrative(v) {
698
768
  return blocks.join("\n\n");
699
769
  }
700
770
 
771
+ // src/core/urologyPathway.ts
772
+ function defaultUrologySmartHistory() {
773
+ return {
774
+ socrates: {
775
+ site: "",
776
+ onset: "",
777
+ character: "",
778
+ radiation: "",
779
+ associated: "",
780
+ timing: "",
781
+ exacerbating: "",
782
+ severity: 0
783
+ },
784
+ ipss: {
785
+ incomplete: 0,
786
+ frequency: 0,
787
+ intermittency: 0,
788
+ urgency: 0,
789
+ weakStream: 0,
790
+ straining: 0,
791
+ nocturia: 0
792
+ },
793
+ ipssQoL: 0,
794
+ haematuria: {
795
+ present: false,
796
+ timing: "none",
797
+ painful: false,
798
+ clots: false
799
+ },
800
+ sexual: {
801
+ erectile: "none",
802
+ libido: "none",
803
+ ejaculation: "none",
804
+ infertilityMonths: 0
805
+ },
806
+ pastNotes: ""
807
+ };
808
+ }
809
+ function defaultUrologyExamination() {
810
+ return {
811
+ regions: [],
812
+ general: {
813
+ pallor: false,
814
+ oedema: false,
815
+ icterus: false,
816
+ lymphadenopathy: false
817
+ },
818
+ abdomen: {
819
+ distension: false,
820
+ scars: false,
821
+ mass: false,
822
+ kidneyPalpable: false,
823
+ bladderPalpable: false,
824
+ renalAngleTender: false,
825
+ bladderDull: false
826
+ },
827
+ gu: {
828
+ meatusAbnormal: false,
829
+ phimosis: false,
830
+ lesions: false,
831
+ scrotalSwelling: false,
832
+ transilluminant: false,
833
+ tenderTestis: false,
834
+ hydrocele: false,
835
+ varicocele: false,
836
+ suspiciousMass: false
837
+ },
838
+ dre: {
839
+ done: false,
840
+ sizeGrams: 0,
841
+ consistency: "",
842
+ medianSulcus: "",
843
+ tenderness: false
844
+ },
845
+ examinationNotes: ""
846
+ };
847
+ }
848
+ function defaultUrologyPathway() {
849
+ return {
850
+ stoneSizeMm: 0,
851
+ hydronephrosis: false,
852
+ prostateVolumeCc: 0,
853
+ psaNgMl: 0,
854
+ uroflowQmaxMlSec: 0,
855
+ risk: {
856
+ ckd: false,
857
+ diabetes: false,
858
+ anticoagulants: false,
859
+ activeInfection: false
860
+ }
861
+ };
862
+ }
863
+ function ipssItem(v) {
864
+ const n = Number(v);
865
+ if (!Number.isFinite(n)) return 0;
866
+ return Math.min(5, Math.max(0, Math.round(n)));
867
+ }
868
+ function urologyIpssSevenTotal(ipss) {
869
+ return ipss.incomplete + ipss.frequency + ipss.intermittency + ipss.urgency + ipss.weakStream + ipss.straining + ipss.nocturia;
870
+ }
871
+ function urologyIpssBand(total) {
872
+ if (total <= 7) return "Mild";
873
+ if (total <= 19) return "Moderate";
874
+ return "Severe";
875
+ }
876
+ function hopcMeaningfulStr(x) {
877
+ if (typeof x !== "string") return "";
878
+ const t = x.trim();
879
+ if (!t || t.toLowerCase() === "none") return "";
880
+ return t;
881
+ }
882
+ function hopcNonEmpty(lines) {
883
+ return lines.map((s) => (s ?? "").trim()).filter(Boolean);
884
+ }
885
+ function formatUrologySmartHistoryToSymptomsNarrative(safe, flags) {
886
+ const { showPain, showLUTS, showHaem, showSex } = flags;
887
+ const parts = [];
888
+ if (showPain) {
889
+ const s = safe.socrates;
890
+ const painLines = hopcNonEmpty([
891
+ s.site ? `Site: ${s.site}` : "",
892
+ s.onset ? `Onset: ${s.onset}` : "",
893
+ s.character ? `Character: ${s.character}` : "",
894
+ s.radiation ? `Radiation: ${s.radiation}` : "",
895
+ s.associated ? `Associated: ${s.associated}` : "",
896
+ s.timing ? `Timing: ${s.timing}` : "",
897
+ s.exacerbating ? `Exacerbating/relieving: ${s.exacerbating}` : "",
898
+ `Severity: ${s.severity}/10`
899
+ ]);
900
+ const hasNonDefaultPain = painLines.length > 1 || painLines.length === 1 && painLines[0] !== "Severity: 0/10";
901
+ if (hasNonDefaultPain) parts.push(`SOCRATES:
902
+ ${painLines.join("\n")}`);
903
+ }
904
+ if (showLUTS) {
905
+ const ip = safe.ipss;
906
+ const any = ip.incomplete || ip.frequency || ip.intermittency || ip.urgency || ip.weakStream || ip.straining || ip.nocturia || safe.ipssQoL;
907
+ if (any) {
908
+ const ipssTotal = urologyIpssSevenTotal(safe.ipss);
909
+ const ipssBandLabel = urologyIpssBand(ipssTotal);
910
+ parts.push(`IPSS: ${ipssTotal}/35 (${ipssBandLabel}) \xB7 QoL ${safe.ipssQoL}/6`);
911
+ }
912
+ }
913
+ if (showHaem) {
914
+ const h = safe.haematuria;
915
+ const timing = hopcMeaningfulStr(h.timing);
916
+ const haemLines = hopcNonEmpty([
917
+ h.present ? "Haematuria present" : "",
918
+ timing ? `Timing: ${timing}` : "",
919
+ h.painful ? "Painful" : "",
920
+ h.clots ? "Clots" : ""
921
+ ]);
922
+ if (haemLines.length) parts.push(`Haematuria:
923
+ ${haemLines.join("\n")}`);
924
+ }
925
+ if (showSex) {
926
+ const sx = safe.sexual;
927
+ const infertility = sx.infertilityMonths;
928
+ const sexLines = hopcNonEmpty([
929
+ hopcMeaningfulStr(sx.erectile) ? `Erectile function: ${hopcMeaningfulStr(sx.erectile)}` : "",
930
+ hopcMeaningfulStr(sx.libido) ? `Libido: ${hopcMeaningfulStr(sx.libido)}` : "",
931
+ hopcMeaningfulStr(sx.ejaculation) ? `Ejaculation: ${hopcMeaningfulStr(sx.ejaculation)}` : "",
932
+ Number.isFinite(infertility) && infertility > 0 ? `Infertility: ${infertility} months` : ""
933
+ ]);
934
+ if (sexLines.length) parts.push(`Sexual/reproductive:
935
+ ${sexLines.join("\n")}`);
936
+ }
937
+ return parts.join("\n\n").trim();
938
+ }
939
+ function formatUrologyExaminationToClinicalExamination(v) {
940
+ const sections = [];
941
+ const generalLabels = {
942
+ pallor: "Pallor (chronic dz)",
943
+ oedema: "Oedema (renal)",
944
+ icterus: "Icterus",
945
+ lymphadenopathy: "Lymphadenopathy"
946
+ };
947
+ const general = Object.keys(generalLabels).filter((k) => v.general[k]).map((k) => generalLabels[k]);
948
+ if (general.length) sections.push(`General: ${general.join(", ")}`);
949
+ const abdLabels = {
950
+ distension: "Distension",
951
+ scars: "Surgical scars",
952
+ mass: "Visible mass",
953
+ kidneyPalpable: "Kidney palpable",
954
+ bladderPalpable: "Bladder palpable",
955
+ renalAngleTender: "Renal angle tender",
956
+ bladderDull: "Bladder dullness (retention)"
957
+ };
958
+ const abd = Object.keys(abdLabels).filter((k) => v.abdomen[k]).map((k) => abdLabels[k]);
959
+ if (abd.length) sections.push(`Abdomen: ${abd.join(", ")}`);
960
+ const guLabels = {
961
+ meatusAbnormal: "Meatus abnormal (hypospadias?)",
962
+ phimosis: "Phimosis / paraphimosis",
963
+ lesions: "Penile lesions / ulcers",
964
+ scrotalSwelling: "Scrotal swelling",
965
+ transilluminant: "Transilluminant",
966
+ tenderTestis: "Tender testis",
967
+ hydrocele: "Hydrocele",
968
+ varicocele: "Varicocele",
969
+ suspiciousMass: "Suspicious mass"
970
+ };
971
+ const gu = Object.keys(guLabels).filter((k) => v.gu[k]).map((k) => guLabels[k]);
972
+ if (gu.length) sections.push(`GU: ${gu.join(", ")}`);
973
+ const dreBits = hopcNonEmpty([
974
+ v.dre.done ? "Performed" : "",
975
+ v.dre.sizeGrams > 0 ? `Size ~${v.dre.sizeGrams} g` : "",
976
+ v.dre.consistency ? `Consistency: ${v.dre.consistency}` : "",
977
+ v.dre.medianSulcus ? `Median sulcus: ${v.dre.medianSulcus}` : "",
978
+ v.dre.tenderness ? "Tenderness" : ""
979
+ ]);
980
+ if (dreBits.length) sections.push(`DRE: ${dreBits.join(", ")}`);
981
+ return sections.join("\n");
982
+ }
983
+ function str(x) {
984
+ return typeof x === "string" ? x : "";
985
+ }
986
+ function bool(x) {
987
+ return x === true;
988
+ }
989
+ function nonNegInt(x) {
990
+ const n = Number(x);
991
+ if (!Number.isFinite(n)) return 0;
992
+ return Math.max(0, Math.round(n));
993
+ }
994
+ function normalizeUrologySmartHistory(raw) {
995
+ const base = defaultUrologySmartHistory();
996
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return base;
997
+ const r = raw;
998
+ const soc = r.socrates && typeof r.socrates === "object" && !Array.isArray(r.socrates) ? r.socrates : {};
999
+ const socObj = soc;
1000
+ const sev = Number(socObj.severity);
1001
+ const socrates = {
1002
+ site: str(socObj.site),
1003
+ onset: str(socObj.onset),
1004
+ character: str(socObj.character),
1005
+ radiation: str(socObj.radiation),
1006
+ associated: str(socObj.associated),
1007
+ timing: str(socObj.timing),
1008
+ exacerbating: str(socObj.exacerbating),
1009
+ severity: Number.isFinite(sev) ? Math.min(10, Math.max(0, Math.round(sev))) : 0
1010
+ };
1011
+ const ipRaw = r.ipss && typeof r.ipss === "object" && !Array.isArray(r.ipss) ? r.ipss : {};
1012
+ const ip = ipRaw;
1013
+ const ipss = {
1014
+ incomplete: ipssItem(ip.incomplete),
1015
+ frequency: ipssItem(ip.frequency),
1016
+ intermittency: ipssItem(ip.intermittency),
1017
+ urgency: ipssItem(ip.urgency),
1018
+ weakStream: ipssItem(ip.weakStream ?? ip.weak_stream),
1019
+ straining: ipssItem(ip.straining),
1020
+ nocturia: ipssItem(ip.nocturia)
1021
+ };
1022
+ const qolRaw = Number(r.ipssQoL);
1023
+ const ipssQoL = Number.isFinite(qolRaw) ? Math.min(6, Math.max(0, Math.round(qolRaw))) : 0;
1024
+ const haRaw = r.haematuria && typeof r.haematuria === "object" && !Array.isArray(r.haematuria) ? r.haematuria : {};
1025
+ const ha = haRaw;
1026
+ const haematuria = {
1027
+ present: bool(ha.present),
1028
+ timing: str(ha.timing) || "none",
1029
+ painful: bool(ha.painful),
1030
+ clots: bool(ha.clots)
1031
+ };
1032
+ const sxRaw = r.sexual && typeof r.sexual === "object" && !Array.isArray(r.sexual) ? r.sexual : {};
1033
+ const sx = sxRaw;
1034
+ const infertilityMonths = nonNegInt(sx.infertilityMonths);
1035
+ const sexual = {
1036
+ erectile: str(sx.erectile) || "none",
1037
+ libido: str(sx.libido) || "none",
1038
+ ejaculation: str(sx.ejaculation) || "none",
1039
+ infertilityMonths
1040
+ };
1041
+ const pastNotes = str(r.pastNotes);
1042
+ return {
1043
+ socrates,
1044
+ ipss,
1045
+ ipssQoL,
1046
+ haematuria,
1047
+ sexual,
1048
+ pastNotes
1049
+ };
1050
+ }
1051
+ function dreSelectStr(x) {
1052
+ const t = str(x).trim();
1053
+ if (!t || t.toLowerCase() === "none") return "";
1054
+ return t;
1055
+ }
1056
+ function normalizeUrologyExamination(raw) {
1057
+ const base = defaultUrologyExamination();
1058
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return base;
1059
+ const r = raw;
1060
+ const regions = Array.isArray(r.regions) ? r.regions.filter((x) => typeof x === "string") : [];
1061
+ const g = r.general && typeof r.general === "object" && !Array.isArray(r.general) ? r.general : {};
1062
+ const gObj = g;
1063
+ const general = {
1064
+ pallor: bool(gObj.pallor),
1065
+ oedema: bool(gObj.oedema),
1066
+ icterus: bool(gObj.icterus),
1067
+ lymphadenopathy: bool(gObj.lymphadenopathy)
1068
+ };
1069
+ const ab = r.abdomen && typeof r.abdomen === "object" && !Array.isArray(r.abdomen) ? r.abdomen : {};
1070
+ const abObj = ab;
1071
+ const abdomen = {
1072
+ distension: bool(abObj.distension),
1073
+ scars: bool(abObj.scars),
1074
+ mass: bool(abObj.mass),
1075
+ kidneyPalpable: bool(abObj.kidneyPalpable),
1076
+ bladderPalpable: bool(abObj.bladderPalpable),
1077
+ renalAngleTender: bool(abObj.renalAngleTender),
1078
+ bladderDull: bool(abObj.bladderDull)
1079
+ };
1080
+ const guRaw = r.gu && typeof r.gu === "object" && !Array.isArray(r.gu) ? r.gu : {};
1081
+ const guObj = guRaw;
1082
+ const gu = {
1083
+ meatusAbnormal: bool(guObj.meatusAbnormal),
1084
+ phimosis: bool(guObj.phimosis),
1085
+ lesions: bool(guObj.lesions),
1086
+ scrotalSwelling: bool(guObj.scrotalSwelling),
1087
+ transilluminant: bool(guObj.transilluminant),
1088
+ tenderTestis: bool(guObj.tenderTestis),
1089
+ hydrocele: bool(guObj.hydrocele),
1090
+ varicocele: bool(guObj.varicocele),
1091
+ suspiciousMass: bool(guObj.suspiciousMass)
1092
+ };
1093
+ const dr = r.dre && typeof r.dre === "object" && !Array.isArray(r.dre) ? r.dre : {};
1094
+ const drObj = dr;
1095
+ const sizeG = Number(drObj.sizeGrams);
1096
+ const dre = {
1097
+ done: bool(drObj.done),
1098
+ sizeGrams: Number.isFinite(sizeG) && sizeG >= 0 ? Math.round(sizeG) : 0,
1099
+ consistency: dreSelectStr(drObj.consistency),
1100
+ medianSulcus: dreSelectStr(drObj.medianSulcus),
1101
+ tenderness: bool(drObj.tenderness)
1102
+ };
1103
+ const examinationNotes = str(r.examinationNotes);
1104
+ return {
1105
+ regions,
1106
+ general,
1107
+ abdomen,
1108
+ gu,
1109
+ dre,
1110
+ examinationNotes
1111
+ };
1112
+ }
1113
+ function normalizeUrologyPathway(raw) {
1114
+ const base = defaultUrologyPathway();
1115
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return base;
1116
+ const r = raw;
1117
+ const stoneSizeMm = nonNegInt(r.stoneSizeMm);
1118
+ const hydronephrosis = bool(r.hydronephrosis);
1119
+ const prostateVolumeCc = Math.max(0, Number(r.prostateVolumeCc) || 0);
1120
+ const psaNgMl = Math.max(0, Number(r.psaNgMl) || 0);
1121
+ const uroflowQmaxMlSec = Math.max(0, Number(r.uroflowQmaxMlSec) || 0);
1122
+ const riskRaw = r.risk && typeof r.risk === "object" && !Array.isArray(r.risk) ? r.risk : {};
1123
+ const rk = riskRaw;
1124
+ const risk = {
1125
+ ckd: bool(rk.ckd),
1126
+ diabetes: bool(rk.diabetes),
1127
+ anticoagulants: bool(rk.anticoagulants),
1128
+ activeInfection: bool(rk.activeInfection)
1129
+ };
1130
+ return {
1131
+ stoneSizeMm,
1132
+ hydronephrosis,
1133
+ prostateVolumeCc,
1134
+ psaNgMl,
1135
+ uroflowQmaxMlSec,
1136
+ risk
1137
+ };
1138
+ }
1139
+
701
1140
  // src/core/painScaleFlags.ts
702
1141
  function normalizePainScaleFlags(raw, bounds) {
703
1142
  const min = bounds?.min ?? 0;
@@ -810,6 +1249,12 @@ var FormStore = class {
810
1249
  values[field.id] = field.defaultValue ?? defaultGeneralSurgeryExamination();
811
1250
  } else if (field.type === "general_surgery_grading") {
812
1251
  values[field.id] = field.defaultValue ?? defaultGeneralSurgeryGrading();
1252
+ } else if (field.type === "urology_smart_history") {
1253
+ values[field.id] = field.defaultValue ?? defaultUrologySmartHistory();
1254
+ } else if (field.type === "urology_examination") {
1255
+ values[field.id] = field.defaultValue ?? defaultUrologyExamination();
1256
+ } else if (field.type === "urology_pathway") {
1257
+ values[field.id] = field.defaultValue ?? defaultUrologyPathway();
813
1258
  } else if (field.type === "pain_scale_flags") {
814
1259
  const f = field;
815
1260
  values[field.id] = normalizePainScaleFlags(
@@ -8523,26 +8968,11 @@ var DischargeMedicationOrdersWidget = ({ fieldId }) => {
8523
8968
  showError && /* @__PURE__ */ jsx("p", { className: "text-xs text-red-500", children: error })
8524
8969
  ] });
8525
8970
  };
8526
- var DEFAULT_TOKEN_SEPARATOR = ", ";
8971
+ var DEFAULT_TOKEN_SEPARATOR2 = ", ";
8527
8972
  function getAppendSeparator(def) {
8528
- const raw = def.meta && typeof def.meta.appendSeparator === "string" ? def.meta.appendSeparator : DEFAULT_TOKEN_SEPARATOR;
8973
+ const raw = def.meta && typeof def.meta.appendSeparator === "string" ? def.meta.appendSeparator : DEFAULT_TOKEN_SEPARATOR2;
8529
8974
  return raw;
8530
8975
  }
8531
- function getSuggestionTokensFromText(text) {
8532
- return text.split(",").map((p) => p.trim()).filter(Boolean);
8533
- }
8534
- function toggleSuggestionTokenInText(current, token, separator = DEFAULT_TOKEN_SEPARATOR) {
8535
- const t = String(token).trim();
8536
- if (!t) return current;
8537
- const parts = getSuggestionTokensFromText(current);
8538
- const i = parts.findIndex((p) => p === t);
8539
- if (i >= 0) {
8540
- parts.splice(i, 1);
8541
- } else {
8542
- parts.push(t);
8543
- }
8544
- return parts.join(separator);
8545
- }
8546
8976
  function isTokenSelected(text, optionValue) {
8547
8977
  const t = String(optionValue).trim();
8548
8978
  if (!t) return false;
@@ -8616,8 +9046,11 @@ var SuggestionTextareaWidget = ({ fieldId }) => {
8616
9046
  setOptions([]);
8617
9047
  }
8618
9048
  }, [def]);
9049
+ const chipAllowedSet = useMemo(
9050
+ () => new Set(options.map((o) => String(o.value).trim()).filter(Boolean)),
9051
+ [options]
9052
+ );
8619
9053
  useEffect(() => {
8620
- if (!parallelChipFieldId || !def) return;
8621
9054
  const parallelDef = store.getFieldDef(parallelChipFieldId);
8622
9055
  if (!parallelDef || parallelDef.type !== "multiselect") return;
8623
9056
  const next = deriveKnownSuggestionChipValues(textValue, options);
@@ -8643,7 +9076,7 @@ var SuggestionTextareaWidget = ({ fieldId }) => {
8643
9076
  const labelEl = theme ? /* @__PURE__ */ jsx(Label, { className: labelClass, children: labelContent }) : /* @__PURE__ */ jsx(Label, { children: labelContent });
8644
9077
  const onChipClick = (optValue) => {
8645
9078
  if (disabled) return;
8646
- setValue(toggleSuggestionTokenInText(textValue, String(optValue), appendSeparator));
9079
+ setValue(toggleSuggestionTokenInText(textValue, String(optValue), appendSeparator, chipAllowedSet));
8647
9080
  };
8648
9081
  const hasSuggestions = options.length > 0;
8649
9082
  const hasEmbedded = embeddedFieldIds.length > 0;
@@ -9082,7 +9515,7 @@ var EMPTY = {
9082
9515
  specularMicroscopyDone: false,
9083
9516
  endothelialCount: ""
9084
9517
  };
9085
- function str(x) {
9518
+ function str2(x) {
9086
9519
  return typeof x === "string" ? x : "";
9087
9520
  }
9088
9521
  function parseValue2(raw) {
@@ -9090,24 +9523,24 @@ function parseValue2(raw) {
9090
9523
  const o = raw;
9091
9524
  const m = o.method;
9092
9525
  const method = m === "ascan_immersion" || m === "ascan_contact" || m === "optical_biometry" ? m : "optical_biometry";
9093
- const formula = str(o.formula);
9526
+ const formula = str2(o.formula);
9094
9527
  return {
9095
9528
  ...EMPTY,
9096
- axialLengthOD: str(o.axialLengthOD),
9097
- axialLengthOS: str(o.axialLengthOS),
9098
- k1k2AxisOD: str(o.k1k2AxisOD),
9099
- k1k2AxisOS: str(o.k1k2AxisOS),
9100
- anteriorChamberDepthOD: str(o.anteriorChamberDepthOD),
9101
- anteriorChamberDepthOS: str(o.anteriorChamberDepthOS),
9102
- iolPowerOD: str(o.iolPowerOD),
9103
- iolPowerOS: str(o.iolPowerOS),
9104
- targetRefractionOD: str(o.targetRefractionOD),
9105
- targetRefractionOS: str(o.targetRefractionOS),
9529
+ axialLengthOD: str2(o.axialLengthOD),
9530
+ axialLengthOS: str2(o.axialLengthOS),
9531
+ k1k2AxisOD: str2(o.k1k2AxisOD),
9532
+ k1k2AxisOS: str2(o.k1k2AxisOS),
9533
+ anteriorChamberDepthOD: str2(o.anteriorChamberDepthOD),
9534
+ anteriorChamberDepthOS: str2(o.anteriorChamberDepthOS),
9535
+ iolPowerOD: str2(o.iolPowerOD),
9536
+ iolPowerOS: str2(o.iolPowerOS),
9537
+ targetRefractionOD: str2(o.targetRefractionOD),
9538
+ targetRefractionOS: str2(o.targetRefractionOS),
9106
9539
  formula: formula || "SRK/T",
9107
9540
  method,
9108
9541
  cornealTopoUploaded: o.cornealTopoUploaded === true,
9109
9542
  specularMicroscopyDone: o.specularMicroscopyDone === true,
9110
- endothelialCount: str(o.endothelialCount)
9543
+ endothelialCount: str2(o.endothelialCount)
9111
9544
  };
9112
9545
  }
9113
9546
  var paramCell = "emr-biometry-param text-[11px] font-semibold leading-snug text-foreground sm:text-xs py-2";
@@ -10578,172 +11011,1020 @@ var PainScaleFlagsWidget = ({ fieldId }) => {
10578
11011
  showError && /* @__PURE__ */ jsx("p", { className: "text-xs text-red-500", children: error })
10579
11012
  ] });
10580
11013
  };
10581
- var FieldRenderer = ({ fieldId }) => {
10582
- const { fieldDef, visible } = useField(fieldId);
10583
- if (!visible || !fieldDef) {
10584
- return null;
10585
- }
10586
- return renderWidget(fieldId, fieldDef);
11014
+ var CHIEF_CHIPS_FIELD3 = "chief_complaints_chips";
11015
+ var ACTIVE_SYNDROME_FIELD = "uro_active_syndrome";
11016
+ var CHIEF_TEXT_FIELD = "chief_complaints";
11017
+ var SYMPTOMS_FIELD = "symptoms";
11018
+ var DIAGNOSIS_FIELD = "diagnosis";
11019
+ var URO_DURATION_FIELD = "uro_chief_duration";
11020
+ var URO_ONSET_FIELD = "uro_chief_onset";
11021
+ var URO_PROGRESSION_FIELD = "uro_chief_progression";
11022
+ var SYNDROME_LABELS = {
11023
+ luts: "LUTS / BPH",
11024
+ stone: "Urolithiasis (stone)",
11025
+ haematuria: "Haematuria",
11026
+ scrotal: "Scrotal swelling",
11027
+ retention: "Acute retention",
11028
+ ed_infertility: "ED / Infertility",
11029
+ uti: "UTI / infection"
10587
11030
  };
10588
- function renderWidget(fieldId, fieldDef) {
10589
- switch (fieldDef.type) {
10590
- case "text":
10591
- case "number":
10592
- return /* @__PURE__ */ jsx(TextWidget, { fieldId });
10593
- case "slider":
10594
- return /* @__PURE__ */ jsx(SliderWidget, { fieldId });
10595
- case "textarea":
10596
- if (fieldMetaRequestsMarMedicationOrdersButton(fieldDef.meta)) {
10597
- return /* @__PURE__ */ jsx(MarMedicationOrdersWidget, { fieldId });
10598
- }
10599
- return /* @__PURE__ */ jsx(TextWidget, { fieldId });
10600
- case "richtext":
10601
- return /* @__PURE__ */ jsx(RichTextWidget, { fieldId });
10602
- case "date":
10603
- return /* @__PURE__ */ jsx(DateWidget, { fieldId });
10604
- case "datetime":
10605
- return /* @__PURE__ */ jsx(DateTimeWidget, { fieldId });
10606
- case "select":
10607
- return /* @__PURE__ */ jsx(SelectWidget, { fieldId });
10608
- case "radio":
10609
- return /* @__PURE__ */ jsx(RadioWidget, { fieldId });
10610
- case "checkbox":
10611
- return /* @__PURE__ */ jsx(CheckboxWidget, { fieldId });
10612
- case "multiselect":
10613
- return /* @__PURE__ */ jsx(MultiSelectWidget, { fieldId });
10614
- case "repeatable":
10615
- return /* @__PURE__ */ jsx(RepeatableWidget, { fieldId });
10616
- case "image_upload":
10617
- return /* @__PURE__ */ jsx(ImageUploadWidget, { fieldId });
10618
- case "media_upload":
10619
- return /* @__PURE__ */ jsx(MediaUploadWidget, { fieldId });
10620
- case "signature":
10621
- return /* @__PURE__ */ jsx(SignatureUploadWidget, { fieldId });
10622
- case "editable_table":
10623
- return /* @__PURE__ */ jsx(EditableTableWidget, { fieldId });
10624
- case "medications":
10625
- return /* @__PURE__ */ jsx(AddMedicationWidget, { fieldId });
10626
- case "discharge_medication_orders":
10627
- return /* @__PURE__ */ jsx(DischargeMedicationOrdersWidget, { fieldId });
10628
- case "investigations":
10629
- return /* @__PURE__ */ jsx(AddInvestigationWidget, { fieldId });
10630
- case "procedures":
10631
- return /* @__PURE__ */ jsx(AddProcedureWidget, { fieldId });
10632
- case "differential_diagnosis":
10633
- return /* @__PURE__ */ jsx(DifferentialDiagnosisWidget, { fieldId });
10634
- case "vitals":
10635
- return /* @__PURE__ */ jsx(VitalsWidget, { fieldId });
10636
- case "hidden_vitals":
10637
- return /* @__PURE__ */ jsx(HiddenVitalsWidget, { fieldId });
10638
- case "referral":
10639
- return /* @__PURE__ */ jsx(ReferralWidget, { fieldId });
10640
- case "followup":
10641
- return /* @__PURE__ */ jsx(FollowupWidget, { fieldId });
10642
- case "smart_textarea":
10643
- return /* @__PURE__ */ jsx(SmartTextareaWidget, { fieldId });
10644
- case "diagnosis_textarea":
10645
- return /* @__PURE__ */ jsx(DiagnosisTextareaWidget, { fieldId });
10646
- case "obstetric_history":
10647
- return /* @__PURE__ */ jsx(ObstetricHistoryWidget, { fieldId });
10648
- case "eye_prescription":
10649
- return /* @__PURE__ */ jsx(OphthalmologyWidget, { fieldId });
10650
- case "ophthal_diagnosis":
10651
- return /* @__PURE__ */ jsx(OphthalDiagnosisWidget, { fieldId });
10652
- case "orthopedic_exam":
10653
- return /* @__PURE__ */ jsx(OrthopedicExamWidget, { fieldId });
10654
- case "general_surgery_smart_history":
10655
- return /* @__PURE__ */ jsx(GsSmartHistoryWidget, { fieldId });
10656
- case "general_surgery_examination":
10657
- return /* @__PURE__ */ jsx(GsExaminationWidget, { fieldId });
10658
- case "general_surgery_grading":
10659
- return /* @__PURE__ */ jsx(GsGradingWidget, { fieldId });
10660
- case "pain_scale_flags":
10661
- return /* @__PURE__ */ jsx(PainScaleFlagsWidget, { fieldId });
10662
- case "toggle": {
10663
- const { value, setValue, setTouched, disabled } = useField(fieldId);
10664
- const store = useFormStore();
10665
- const excludes = fieldDef.excludes ?? [];
10666
- return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
10667
- /* @__PURE__ */ jsx(
10668
- Switch,
10669
- {
10670
- checked: value === true,
10671
- disabled,
10672
- onCheckedChange: (checked) => {
10673
- setValue(checked);
10674
- setTouched();
10675
- if (checked) excludes.forEach((id) => store.setValue(id, false));
10676
- }
10677
- }
10678
- ),
10679
- /* @__PURE__ */ jsx(Label, { className: "text-sm font-medium leading-none cursor-pointer select-none", children: fieldDef.label })
10680
- ] });
10681
- }
10682
- case "suggestion_textarea":
10683
- case "complaint_chips":
10684
- return /* @__PURE__ */ jsx(SuggestionTextareaWidget, { fieldId });
10685
- case "lens_assessment":
10686
- return /* @__PURE__ */ jsx(LensAssessmentWidget, { fieldId });
10687
- case "functional_impairment_score":
10688
- return /* @__PURE__ */ jsx(FunctionalImpairmentScoreWidget, { fieldId });
10689
- case "biometry_iol_workup":
10690
- return /* @__PURE__ */ jsx(BiometryIolWorkupWidget, { fieldId });
10691
- case "surgical_risk_flags":
10692
- return /* @__PURE__ */ jsx(SurgicalRiskFlagsWidget, { fieldId });
10693
- case "static_text": {
10694
- const def = fieldDef;
10695
- const size = def.size ?? "regular";
10696
- const labelClass = size === "large" ? "text-base" : "text-sm";
10697
- const descClass = size === "large" ? "text-sm" : "text-xs";
10698
- return /* @__PURE__ */ jsxs("div", { className: `${labelClass} text-muted-foreground`, children: [
10699
- def.label,
10700
- def.description && /* @__PURE__ */ jsx("p", { className: `mt-1 ${descClass} opacity-90`, children: def.description })
10701
- ] });
10702
- }
10703
- default:
10704
- return /* @__PURE__ */ jsxs("div", { className: "text-red-500", children: [
10705
- "Unknown field type: ",
10706
- fieldDef.type
10707
- ] });
10708
- }
11031
+ function chipList2(state) {
11032
+ const raw = state.values[CHIEF_CHIPS_FIELD3];
11033
+ return Array.isArray(raw) ? raw.filter((x) => typeof x === "string") : [];
10709
11034
  }
10710
- var Section = ({ title, children }) => {
10711
- const [expanded, setExpanded] = useState(true);
10712
- const handleToggle = () => setExpanded((prev) => !prev);
10713
- const contentClassName = cn(
10714
- "overflow-hidden transition-[height] duration-200 ease-in-out",
10715
- !expanded && "hidden"
10716
- );
10717
- return /* @__PURE__ */ jsxs("div", { className: "mb-6 border rounded-lg bg-white shadow-sm overflow-hidden", children: [
10718
- /* @__PURE__ */ jsxs(
10719
- "button",
10720
- {
10721
- type: "button",
10722
- onClick: handleToggle,
10723
- className: "w-full flex items-center justify-between gap-2 p-4 text-left border-b hover:bg-gray-50/80 transition-colors",
10724
- children: [
10725
- /* @__PURE__ */ jsx("h3", { className: "text-lg font-medium", children: title }),
10726
- /* @__PURE__ */ jsx("span", { className: "flex-shrink-0 text-muted-foreground", "aria-hidden": true, children: expanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "h-5 w-5" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "h-5 w-5" }) })
10727
- ]
10728
- }
10729
- ),
10730
- /* @__PURE__ */ jsx("div", { className: contentClassName, children: /* @__PURE__ */ jsx("div", { className: "p-4 pt-4 space-y-4 border-t-0", children }) })
10731
- ] });
11035
+ function str3(x) {
11036
+ return typeof x === "string" ? x : "";
11037
+ }
11038
+ function chiefOptionalFieldDisplay(x) {
11039
+ const s = str3(x).trim();
11040
+ if (!s || s.toLowerCase() === "none") return "";
11041
+ return s;
11042
+ }
11043
+ function nonEmptyLines(lines) {
11044
+ return lines.map((s) => (s ?? "").trim()).filter(Boolean);
11045
+ }
11046
+ var IPSS_LABELS = {
11047
+ incomplete: "Incomplete emptying",
11048
+ frequency: "Frequency (<2h)",
11049
+ intermittency: "Intermittency",
11050
+ urgency: "Urgency",
11051
+ weakStream: "Weak stream",
11052
+ straining: "Straining",
11053
+ nocturia: "Nocturia (\xD7/night)"
10732
11054
  };
10733
- var ColumnLayout = ({
10734
- columns,
10735
- label,
11055
+ var SOCRATES_KEYS2 = [
11056
+ "site",
11057
+ "onset",
11058
+ "character",
11059
+ "radiation",
11060
+ "associated",
11061
+ "timing",
11062
+ "exacerbating"
11063
+ ];
11064
+ function Panel2({
11065
+ title,
11066
+ right,
10736
11067
  children
10737
- }) => {
10738
- const gridCols = Math.max(1, Math.min(columns, 12));
10739
- const gridClass = `grid gap-4 w-full`;
10740
- const style = {
10741
- gridTemplateColumns: `repeat(${gridCols}, minmax(0, 1fr))`
10742
- };
10743
- return /* @__PURE__ */ jsxs("div", { className: "mb-6", children: [
10744
- label != null && label !== "" && /* @__PURE__ */ jsx("div", { className: "mb-2 text-sm font-medium text-gray-700", children: label }),
10745
- /* @__PURE__ */ jsx("div", { className: gridClass, style, children })
10746
- ] });
11068
+ }) {
11069
+ return /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-md border border-[#D0D0D0] bg-white", children: [
11070
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b border-[#D0D0D0] bg-[#FEE8EC]/50 px-3 py-1.5", children: [
11071
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-slate-700", children: title }),
11072
+ right
11073
+ ] }),
11074
+ /* @__PURE__ */ jsx("div", { className: "p-3", children })
11075
+ ] });
11076
+ }
11077
+ var UrologySmartHistoryWidget = ({ fieldId }) => {
11078
+ const { fieldDef, value, setValue, setTouched, error, touched, disabled } = useField(fieldId);
11079
+ const hopcField = useField(SYMPTOMS_FIELD);
11080
+ const syndromeField = useField(ACTIVE_SYNDROME_FIELD);
11081
+ const { state } = useForm();
11082
+ const store = useFormStore();
11083
+ const showError = !!error && (touched || state.submitAttempted);
11084
+ const safe = useMemo(() => normalizeUrologySmartHistory(value), [value]);
11085
+ const chips = useMemo(() => chipList2(state), [state]);
11086
+ const rawSyndrome = syndromeField.value ?? state.values[ACTIVE_SYNDROME_FIELD];
11087
+ const syndrome = typeof rawSyndrome === "string" && rawSyndrome !== "" && rawSyndrome !== "none" ? rawSyndrome : "none";
11088
+ const showPain = chips.includes("pain abdomen flank") || chips.includes("scrotal swelling pain") || syndrome === "stone" || syndrome === "scrotal";
11089
+ const showLUTS = syndrome === "luts" || syndrome === "retention" || chips.includes("frequency urgency") || chips.includes("poor stream") || chips.includes("acute retention");
11090
+ const showHaem = syndrome === "haematuria" || chips.includes("haematuria");
11091
+ const showSex = syndrome === "ed_infertility" || chips.includes("erectile dysfunction") || chips.includes("infertility concern");
11092
+ const update = (next) => {
11093
+ setValue(next);
11094
+ setTouched();
11095
+ };
11096
+ const ipssTotal = urologyIpssSevenTotal(safe.ipss);
11097
+ const ipssBandLabel = urologyIpssBand(ipssTotal);
11098
+ const bandClass = ipssBandLabel === "Severe" ? "bg-red-500/15 text-red-700" : ipssBandLabel === "Moderate" ? "bg-amber-500/15 text-amber-800" : "bg-emerald-500/15 text-emerald-800";
11099
+ const setSocrates = (key, v) => {
11100
+ if (key === "severity") {
11101
+ const n = typeof v === "number" ? v : Number(v);
11102
+ const sev = Number.isFinite(n) ? Math.min(10, Math.max(0, Math.round(n))) : 0;
11103
+ update({ ...safe, socrates: { ...safe.socrates, severity: sev } });
11104
+ return;
11105
+ }
11106
+ update({ ...safe, socrates: { ...safe.socrates, [key]: String(v) } });
11107
+ };
11108
+ const setIpss = (key, v) => {
11109
+ update({ ...safe, ipss: { ...safe.ipss, [key]: v } });
11110
+ };
11111
+ const [hopcNarrativeLocked, setHopcNarrativeLocked] = useState(false);
11112
+ useEffect(() => {
11113
+ if (hopcNarrativeLocked || disabled) return;
11114
+ const next = formatUrologySmartHistoryToSymptomsNarrative(normalizeUrologySmartHistory(value), {
11115
+ showPain,
11116
+ showLUTS,
11117
+ showHaem,
11118
+ showSex
11119
+ });
11120
+ hopcField.setValue(next);
11121
+ }, [value, hopcNarrativeLocked, showPain, showLUTS, showHaem, showSex, disabled]);
11122
+ useEffect(() => {
11123
+ if (disabled) return;
11124
+ const label = syndrome && syndrome !== "none" ? SYNDROME_LABELS[syndrome] ?? syndrome : "";
11125
+ const prev = store.getFieldState(DIAGNOSIS_FIELD)?.value;
11126
+ const prevText = typeof prev === "string" ? prev : "";
11127
+ const syndromeLabels = new Set(Object.values(SYNDROME_LABELS));
11128
+ const keptLines = prevText.split("\n").map((l) => l.trim()).filter(Boolean).filter((l) => !syndromeLabels.has(l));
11129
+ const nextLines = label ? [...keptLines, label] : keptLines;
11130
+ const next = nextLines.join("\n");
11131
+ if (prevText.trim() === next.trim()) return;
11132
+ store.setValues({ [DIAGNOSIS_FIELD]: next }, { touch: false });
11133
+ }, [disabled, store, syndrome]);
11134
+ useEffect(() => {
11135
+ if (disabled) return;
11136
+ const duration = chiefOptionalFieldDisplay(state.values[URO_DURATION_FIELD]);
11137
+ const onset = chiefOptionalFieldDisplay(state.values[URO_ONSET_FIELD]);
11138
+ const progression = chiefOptionalFieldDisplay(state.values[URO_PROGRESSION_FIELD]);
11139
+ const prev = store.getFieldState(CHIEF_TEXT_FIELD)?.value;
11140
+ const prevText = typeof prev === "string" ? prev : "";
11141
+ const kept = prevText.split(",").map((t) => t.trim()).filter(Boolean).filter((t) => {
11142
+ const lower = t.toLowerCase();
11143
+ return !lower.startsWith("duration:") && !lower.startsWith("onset:") && !lower.startsWith("progression:");
11144
+ });
11145
+ const extra = nonEmptyLines([
11146
+ duration ? `Duration: ${duration}` : "",
11147
+ onset ? `Onset: ${onset}` : "",
11148
+ progression ? `Progression: ${progression}` : ""
11149
+ ]);
11150
+ const next = [...kept, ...extra].join(", ").trim();
11151
+ if (prevText.trim() === next.trim()) return;
11152
+ store.setValues({ [CHIEF_TEXT_FIELD]: next }, { touch: false });
11153
+ }, [
11154
+ disabled,
11155
+ state.values[URO_DURATION_FIELD],
11156
+ state.values[URO_ONSET_FIELD],
11157
+ state.values[URO_PROGRESSION_FIELD],
11158
+ store
11159
+ ]);
11160
+ if (!fieldDef) return null;
11161
+ const theme = getThemeConfig("textarea", fieldDef.theme);
11162
+ const wrapperClass = theme?.wrapperClassName ?? "rounded-md overflow-hidden flex flex-col border border-[#D0D0D0]";
11163
+ const labelClass = theme?.labelClassName;
11164
+ const labelContent = /* @__PURE__ */ jsxs(Fragment, { children: [
11165
+ fieldDef.label,
11166
+ fieldDef.required ? /* @__PURE__ */ jsx("span", { className: "ml-1 text-red-500", children: "*" }) : null
11167
+ ] });
11168
+ const labelEl = theme ? /* @__PURE__ */ jsx(Label, { className: labelClass, children: labelContent }) : /* @__PURE__ */ jsx(Label, { className: "text-sm font-medium", children: labelContent });
11169
+ const bodyClass = cn(
11170
+ "-mt-1 flex min-w-0 flex-col gap-3 border-t border-[#D0D0D0] bg-white px-3 py-3",
11171
+ disabled && "pointer-events-none opacity-60"
11172
+ );
11173
+ return /* @__PURE__ */ jsxs("div", { className: cn("w-full min-w-0", wrapperClass), children: [
11174
+ labelEl,
11175
+ /* @__PURE__ */ jsxs("div", { className: bodyClass, children: [
11176
+ /* @__PURE__ */ jsx("p", { className: "text-[11px] text-muted-foreground", children: "Panels follow chief complaint chips and active syndrome (Clearsight SmartHistoryUro)." }),
11177
+ showPain ? /* @__PURE__ */ jsx(Panel2, { title: "SOCRATES \u2014 Pain (flank / suprapubic / testicular)", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2 md:grid-cols-4", children: [
11178
+ SOCRATES_KEYS2.map((k) => /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
11179
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: k }),
11180
+ /* @__PURE__ */ jsx(
11181
+ Input,
11182
+ {
11183
+ className: "h-8 text-xs",
11184
+ value: safe.socrates[k],
11185
+ onChange: (e) => setSocrates(k, e.target.value),
11186
+ placeholder: k === "radiation" ? "e.g. groin \u2192 ureteric" : k === "character" ? "colicky / dull" : "",
11187
+ disabled
11188
+ }
11189
+ )
11190
+ ] }, k)),
11191
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
11192
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: "Severity 0\u201310" }),
11193
+ /* @__PURE__ */ jsx(
11194
+ Input,
11195
+ {
11196
+ type: "number",
11197
+ min: 0,
11198
+ max: 10,
11199
+ className: "h-8 text-xs",
11200
+ value: safe.socrates.severity,
11201
+ onChange: (e) => setSocrates("severity", e.target.value),
11202
+ disabled
11203
+ }
11204
+ )
11205
+ ] })
11206
+ ] }) }) : null,
11207
+ showLUTS ? /* @__PURE__ */ jsxs(
11208
+ Panel2,
11209
+ {
11210
+ title: "IPSS \u2014 International Prostate Symptom Score",
11211
+ right: /* @__PURE__ */ jsxs("span", { className: `rounded-full px-2 py-0.5 text-[10px] font-medium ${bandClass}`, children: [
11212
+ ipssTotal,
11213
+ "/35 \u2014 ",
11214
+ ipssBandLabel
11215
+ ] }),
11216
+ children: [
11217
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2 md:grid-cols-4", children: [
11218
+ Object.keys(IPSS_LABELS).map((k) => /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
11219
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] uppercase tracking-wide text-muted-foreground", children: IPSS_LABELS[k] }),
11220
+ /* @__PURE__ */ jsxs(
11221
+ Select,
11222
+ {
11223
+ value: String(safe.ipss[k]),
11224
+ onValueChange: (val) => setIpss(k, Number(val)),
11225
+ disabled,
11226
+ children: [
11227
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
11228
+ /* @__PURE__ */ jsx(SelectContent, { children: [0, 1, 2, 3, 4, 5].map((n) => /* @__PURE__ */ jsx(SelectItem, { value: String(n), children: n }, n)) })
11229
+ ]
11230
+ }
11231
+ )
11232
+ ] }, k)),
11233
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
11234
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] uppercase tracking-wide text-muted-foreground", children: "QoL (0\u20136)" }),
11235
+ /* @__PURE__ */ jsxs(
11236
+ Select,
11237
+ {
11238
+ value: String(safe.ipssQoL),
11239
+ onValueChange: (val) => update({ ...safe, ipssQoL: Math.min(6, Math.max(0, Number(val))) }),
11240
+ disabled,
11241
+ children: [
11242
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
11243
+ /* @__PURE__ */ jsx(SelectContent, { children: [0, 1, 2, 3, 4, 5, 6].map((n) => /* @__PURE__ */ jsx(SelectItem, { value: String(n), children: n }, n)) })
11244
+ ]
11245
+ }
11246
+ )
11247
+ ] })
11248
+ ] }),
11249
+ /* @__PURE__ */ jsxs("p", { className: "mt-2 text-[10px] text-muted-foreground", children: [
11250
+ "Bands: 0\u20137 mild \xB7 8\u201319 moderate \xB7 20\u201335 severe.",
11251
+ " ",
11252
+ /* @__PURE__ */ jsx("span", { className: "font-semibold text-foreground", children: "IPSS \u2265 20 \u2192 consider surgical intervention." })
11253
+ ] })
11254
+ ]
11255
+ }
11256
+ ) : null,
11257
+ showHaem ? /* @__PURE__ */ jsxs(Panel2, { title: "Haematuria profile", children: [
11258
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3 text-xs md:grid-cols-4", children: [
11259
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
11260
+ /* @__PURE__ */ jsx(
11261
+ Checkbox,
11262
+ {
11263
+ checked: safe.haematuria.present,
11264
+ onCheckedChange: (c) => update({
11265
+ ...safe,
11266
+ haematuria: { ...safe.haematuria, present: c === true }
11267
+ }),
11268
+ disabled
11269
+ }
11270
+ ),
11271
+ "Present"
11272
+ ] }),
11273
+ /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
11274
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: "Timing" }),
11275
+ /* @__PURE__ */ jsxs(
11276
+ Select,
11277
+ {
11278
+ value: safe.haematuria.timing || "none",
11279
+ onValueChange: (val) => update({
11280
+ ...safe,
11281
+ haematuria: { ...safe.haematuria, timing: val === "none" ? "" : val }
11282
+ }),
11283
+ disabled,
11284
+ children: [
11285
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "\u2014" }) }),
11286
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
11287
+ /* @__PURE__ */ jsx(SelectItem, { value: "none", children: "\u2014" }),
11288
+ /* @__PURE__ */ jsx(SelectItem, { value: "Initial", children: "Initial" }),
11289
+ /* @__PURE__ */ jsx(SelectItem, { value: "Terminal", children: "Terminal" }),
11290
+ /* @__PURE__ */ jsx(SelectItem, { value: "Total", children: "Total" })
11291
+ ] })
11292
+ ]
11293
+ }
11294
+ )
11295
+ ] }),
11296
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
11297
+ /* @__PURE__ */ jsx(
11298
+ Checkbox,
11299
+ {
11300
+ checked: safe.haematuria.painful,
11301
+ onCheckedChange: (c) => update({ ...safe, haematuria: { ...safe.haematuria, painful: c === true } }),
11302
+ disabled
11303
+ }
11304
+ ),
11305
+ "Painful"
11306
+ ] }),
11307
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
11308
+ /* @__PURE__ */ jsx(
11309
+ Checkbox,
11310
+ {
11311
+ checked: safe.haematuria.clots,
11312
+ onCheckedChange: (c) => update({ ...safe, haematuria: { ...safe.haematuria, clots: c === true } }),
11313
+ disabled
11314
+ }
11315
+ ),
11316
+ "Clots"
11317
+ ] })
11318
+ ] }),
11319
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-[10px] text-red-600", children: "Painless haematuria = malignancy until proven otherwise." })
11320
+ ] }) : null,
11321
+ showSex ? /* @__PURE__ */ jsx(Panel2, { title: "Sexual & reproductive history", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3 text-xs md:grid-cols-4", children: [
11322
+ /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
11323
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: "Erectile function" }),
11324
+ /* @__PURE__ */ jsxs(
11325
+ Select,
11326
+ {
11327
+ value: safe.sexual.erectile || "none",
11328
+ onValueChange: (val) => update({
11329
+ ...safe,
11330
+ sexual: { ...safe.sexual, erectile: val === "none" ? "" : val }
11331
+ }),
11332
+ disabled,
11333
+ children: [
11334
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "\u2014" }) }),
11335
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
11336
+ /* @__PURE__ */ jsx(SelectItem, { value: "none", children: "\u2014" }),
11337
+ /* @__PURE__ */ jsx(SelectItem, { value: "Normal", children: "Normal" }),
11338
+ /* @__PURE__ */ jsx(SelectItem, { value: "Mild", children: "Mild" }),
11339
+ /* @__PURE__ */ jsx(SelectItem, { value: "Moderate", children: "Moderate" }),
11340
+ /* @__PURE__ */ jsx(SelectItem, { value: "Severe", children: "Severe" })
11341
+ ] })
11342
+ ]
11343
+ }
11344
+ )
11345
+ ] }),
11346
+ /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
11347
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: "Libido" }),
11348
+ /* @__PURE__ */ jsxs(
11349
+ Select,
11350
+ {
11351
+ value: safe.sexual.libido || "none",
11352
+ onValueChange: (val) => update({
11353
+ ...safe,
11354
+ sexual: { ...safe.sexual, libido: val === "none" ? "" : val }
11355
+ }),
11356
+ disabled,
11357
+ children: [
11358
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "\u2014" }) }),
11359
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
11360
+ /* @__PURE__ */ jsx(SelectItem, { value: "none", children: "\u2014" }),
11361
+ /* @__PURE__ */ jsx(SelectItem, { value: "Normal", children: "Normal" }),
11362
+ /* @__PURE__ */ jsx(SelectItem, { value: "Reduced", children: "Reduced" })
11363
+ ] })
11364
+ ]
11365
+ }
11366
+ )
11367
+ ] }),
11368
+ /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
11369
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: "Ejaculation" }),
11370
+ /* @__PURE__ */ jsxs(
11371
+ Select,
11372
+ {
11373
+ value: safe.sexual.ejaculation || "none",
11374
+ onValueChange: (val) => update({
11375
+ ...safe,
11376
+ sexual: { ...safe.sexual, ejaculation: val === "none" ? "" : val }
11377
+ }),
11378
+ disabled,
11379
+ children: [
11380
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "\u2014" }) }),
11381
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
11382
+ /* @__PURE__ */ jsx(SelectItem, { value: "none", children: "\u2014" }),
11383
+ /* @__PURE__ */ jsx(SelectItem, { value: "Normal", children: "Normal" }),
11384
+ /* @__PURE__ */ jsx(SelectItem, { value: "Premature", children: "Premature" }),
11385
+ /* @__PURE__ */ jsx(SelectItem, { value: "Retrograde", children: "Retrograde" }),
11386
+ /* @__PURE__ */ jsx(SelectItem, { value: "Anejaculation", children: "Anejaculation" })
11387
+ ] })
11388
+ ]
11389
+ }
11390
+ )
11391
+ ] }),
11392
+ /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
11393
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: "Infertility (months)" }),
11394
+ /* @__PURE__ */ jsx(
11395
+ Input,
11396
+ {
11397
+ type: "number",
11398
+ min: 0,
11399
+ className: "h-8 text-xs",
11400
+ value: safe.sexual.infertilityMonths,
11401
+ onChange: (e) => update({
11402
+ ...safe,
11403
+ sexual: {
11404
+ ...safe.sexual,
11405
+ infertilityMonths: Math.max(0, Math.round(Number(e.target.value)) || 0)
11406
+ }
11407
+ }),
11408
+ disabled
11409
+ }
11410
+ )
11411
+ ] })
11412
+ ] }) }) : null,
11413
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
11414
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
11415
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-semibold text-slate-700", children: hopcField.fieldDef?.label ?? "History of presenting complaint" }),
11416
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
11417
+ hopcNarrativeLocked ? /* @__PURE__ */ jsxs("span", { className: "rounded bg-amber-50 px-1.5 py-0.5 text-[10px] font-medium text-amber-900 ring-1 ring-amber-200/80", children: [
11418
+ "You edited this summary. Use",
11419
+ " ",
11420
+ /* @__PURE__ */ jsx("span", { className: "italic", children: "'Regenerate'" }),
11421
+ " to update it from the form."
11422
+ ] }) : null,
11423
+ hopcNarrativeLocked ? /* @__PURE__ */ jsx(
11424
+ Button,
11425
+ {
11426
+ type: "button",
11427
+ variant: "outline",
11428
+ size: "sm",
11429
+ className: "h-7 shrink-0 px-2 text-xs",
11430
+ disabled: disabled || hopcField.disabled,
11431
+ onClick: () => {
11432
+ setHopcNarrativeLocked(false);
11433
+ hopcField.setValue(
11434
+ formatUrologySmartHistoryToSymptomsNarrative(
11435
+ normalizeUrologySmartHistory(value),
11436
+ { showPain, showLUTS, showHaem, showSex }
11437
+ )
11438
+ );
11439
+ },
11440
+ children: "Regenerate"
11441
+ }
11442
+ ) : null
11443
+ ] })
11444
+ ] }),
11445
+ hopcNarrativeLocked ? /* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground", children: "Edit this box anytime. Use Regenerate to replace with fresh text from the structured fields." }) : null,
11446
+ /* @__PURE__ */ jsx(
11447
+ Textarea,
11448
+ {
11449
+ className: "min-h-[88px] rounded-md border border-input bg-white text-sm",
11450
+ placeholder: "Auto-filled from chief complaints + smart history\u2026",
11451
+ value: typeof hopcField.value === "string" ? hopcField.value : hopcField.value == null ? "" : String(hopcField.value),
11452
+ onChange: (e) => {
11453
+ setHopcNarrativeLocked(true);
11454
+ hopcField.setValue(e.target.value);
11455
+ hopcField.setTouched();
11456
+ },
11457
+ disabled: disabled || hopcField.disabled
11458
+ }
11459
+ )
11460
+ ] })
11461
+ ] }),
11462
+ showError ? /* @__PURE__ */ jsx("p", { className: "px-3 pb-2 text-xs text-red-500", children: error }) : null
11463
+ ] });
11464
+ };
11465
+ var URO_CLINICAL_EXAMINATION_FIELD = "clinical_examination";
11466
+ var GENERAL_ROWS = [
11467
+ { key: "pallor", label: "Pallor (chronic dz)" },
11468
+ { key: "oedema", label: "Oedema (renal)" },
11469
+ { key: "icterus", label: "Icterus" },
11470
+ { key: "lymphadenopathy", label: "Lymphadenopathy" }
11471
+ ];
11472
+ var ABD_ROWS = [
11473
+ { key: "distension", label: "Distension" },
11474
+ { key: "scars", label: "Surgical scars" },
11475
+ { key: "mass", label: "Visible mass" },
11476
+ { key: "kidneyPalpable", label: "Kidney palpable" },
11477
+ { key: "bladderPalpable", label: "Bladder palpable" },
11478
+ { key: "renalAngleTender", label: "Renal angle tender" },
11479
+ { key: "bladderDull", label: "Bladder dullness (retention)" }
11480
+ ];
11481
+ var GU_ROWS = [
11482
+ { key: "meatusAbnormal", label: "Meatus abnormal (hypospadias?)" },
11483
+ { key: "phimosis", label: "Phimosis / paraphimosis" },
11484
+ { key: "lesions", label: "Penile lesions / ulcers" },
11485
+ { key: "scrotalSwelling", label: "Scrotal swelling" },
11486
+ { key: "transilluminant", label: "Transilluminant" },
11487
+ { key: "tenderTestis", label: "Tender testis" },
11488
+ { key: "hydrocele", label: "Hydrocele" },
11489
+ { key: "varicocele", label: "Varicocele" },
11490
+ { key: "suspiciousMass", label: "Suspicious mass" }
11491
+ ];
11492
+ var DRE_CONSISTENCY = ["none", "Soft (benign)", "Firm", "Hard / nodular (malignancy?)"];
11493
+ var DRE_SULCUS = ["none", "Preserved", "Obliterated"];
11494
+ var UrologyExaminationWidget = ({ fieldId }) => {
11495
+ const { fieldDef, value, setValue, setTouched, error, touched, disabled } = useField(fieldId);
11496
+ const clinicalField = useField(URO_CLINICAL_EXAMINATION_FIELD);
11497
+ const { state } = useForm();
11498
+ const showError = !!error && (touched || state.submitAttempted);
11499
+ const safe = useMemo(() => normalizeUrologyExamination(value), [value]);
11500
+ const [clinicalNarrativeLocked, setClinicalNarrativeLocked] = useState(false);
11501
+ useEffect(() => {
11502
+ if (clinicalNarrativeLocked || disabled) return;
11503
+ const norm = normalizeUrologyExamination(value);
11504
+ const next = formatUrologyExaminationToClinicalExamination(norm);
11505
+ clinicalField.setValue(next);
11506
+ if (norm.examinationNotes !== next) {
11507
+ setValue({ ...norm, examinationNotes: next });
11508
+ }
11509
+ }, [value, clinicalNarrativeLocked, disabled]);
11510
+ const bump = (next) => {
11511
+ setValue(next);
11512
+ setTouched();
11513
+ };
11514
+ const toggleGeneral = (key) => {
11515
+ bump({ ...safe, general: { ...safe.general, [key]: !safe.general[key] } });
11516
+ };
11517
+ const toggleAbdomen = (key) => {
11518
+ bump({ ...safe, abdomen: { ...safe.abdomen, [key]: !safe.abdomen[key] } });
11519
+ };
11520
+ const toggleGu = (key) => {
11521
+ bump({ ...safe, gu: { ...safe.gu, [key]: !safe.gu[key] } });
11522
+ };
11523
+ if (!fieldDef) return null;
11524
+ const theme = getThemeConfig("textarea", fieldDef.theme);
11525
+ const wrapperClass = theme?.wrapperClassName ?? "rounded-md overflow-hidden flex flex-col border border-[#D0D0D0]";
11526
+ const labelClass = theme?.labelClassName;
11527
+ const labelContent = /* @__PURE__ */ jsxs(Fragment, { children: [
11528
+ fieldDef.label,
11529
+ fieldDef.required ? /* @__PURE__ */ jsx("span", { className: "ml-1 text-red-500", children: "*" }) : null
11530
+ ] });
11531
+ const labelEl = theme ? /* @__PURE__ */ jsx(Label, { className: labelClass, children: labelContent }) : /* @__PURE__ */ jsx(Label, { className: "text-sm font-medium", children: labelContent });
11532
+ const bodyClass = cn(
11533
+ "-mt-1 flex min-w-0 flex-col gap-3 border-t border-[#D0D0D0] bg-white px-3 py-3",
11534
+ disabled && "pointer-events-none opacity-60"
11535
+ );
11536
+ return /* @__PURE__ */ jsxs("div", { className: cn("w-full min-w-0", wrapperClass), children: [
11537
+ labelEl,
11538
+ /* @__PURE__ */ jsxs("div", { className: bodyClass, children: [
11539
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-3 text-xs md:grid-cols-2 xl:grid-cols-4", children: [
11540
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
11541
+ /* @__PURE__ */ jsx("p", { className: "font-semibold text-slate-800", children: "General" }),
11542
+ GENERAL_ROWS.map((r) => /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
11543
+ /* @__PURE__ */ jsx(
11544
+ Checkbox,
11545
+ {
11546
+ checked: safe.general[r.key],
11547
+ onCheckedChange: () => toggleGeneral(r.key),
11548
+ disabled
11549
+ }
11550
+ ),
11551
+ r.label
11552
+ ] }, r.key))
11553
+ ] }),
11554
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
11555
+ /* @__PURE__ */ jsx("p", { className: "font-semibold text-slate-800", children: "Abdomen" }),
11556
+ ABD_ROWS.map((r) => /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
11557
+ /* @__PURE__ */ jsx(
11558
+ Checkbox,
11559
+ {
11560
+ checked: safe.abdomen[r.key],
11561
+ onCheckedChange: () => toggleAbdomen(r.key),
11562
+ disabled
11563
+ }
11564
+ ),
11565
+ r.label
11566
+ ] }, r.key))
11567
+ ] }),
11568
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
11569
+ /* @__PURE__ */ jsx("p", { className: "font-semibold text-slate-800", children: "External genitalia / scrotum" }),
11570
+ GU_ROWS.map((r) => /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
11571
+ /* @__PURE__ */ jsx(
11572
+ Checkbox,
11573
+ {
11574
+ checked: safe.gu[r.key],
11575
+ onCheckedChange: () => toggleGu(r.key),
11576
+ disabled
11577
+ }
11578
+ ),
11579
+ r.key === "suspiciousMass" ? /* @__PURE__ */ jsx("span", { className: "font-medium text-red-600", children: r.label }) : r.label
11580
+ ] }, r.key))
11581
+ ] }),
11582
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
11583
+ /* @__PURE__ */ jsx("p", { className: "font-semibold text-slate-800", children: "DRE \u2014 Prostate" }),
11584
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
11585
+ /* @__PURE__ */ jsx(
11586
+ Checkbox,
11587
+ {
11588
+ checked: safe.dre.done,
11589
+ onCheckedChange: (c) => bump({ ...safe, dre: { ...safe.dre, done: c === true } }),
11590
+ disabled
11591
+ }
11592
+ ),
11593
+ "DRE performed"
11594
+ ] }),
11595
+ /* @__PURE__ */ jsxs("label", { className: "block", children: [
11596
+ /* @__PURE__ */ jsx("span", { className: "mb-1 block font-medium", children: "Estimated size (g)" }),
11597
+ /* @__PURE__ */ jsx(
11598
+ Input,
11599
+ {
11600
+ type: "number",
11601
+ min: 0,
11602
+ className: "h-8 text-xs",
11603
+ value: safe.dre.sizeGrams,
11604
+ onChange: (e) => {
11605
+ const n = Number(e.target.value);
11606
+ bump({
11607
+ ...safe,
11608
+ dre: {
11609
+ ...safe.dre,
11610
+ sizeGrams: Number.isFinite(n) && n >= 0 ? Math.round(n) : 0
11611
+ }
11612
+ });
11613
+ },
11614
+ disabled
11615
+ }
11616
+ )
11617
+ ] }),
11618
+ /* @__PURE__ */ jsxs("label", { className: "block", children: [
11619
+ /* @__PURE__ */ jsx("span", { className: "mb-1 block font-medium", children: "Consistency" }),
11620
+ /* @__PURE__ */ jsxs(
11621
+ Select,
11622
+ {
11623
+ value: safe.dre.consistency || "none",
11624
+ onValueChange: (val) => bump({
11625
+ ...safe,
11626
+ dre: { ...safe.dre, consistency: val === "none" ? "" : val }
11627
+ }),
11628
+ disabled,
11629
+ children: [
11630
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "\u2014" }) }),
11631
+ /* @__PURE__ */ jsx(SelectContent, { children: DRE_CONSISTENCY.map((opt) => /* @__PURE__ */ jsx(SelectItem, { value: opt, children: opt === "none" ? "\u2014" : opt }, opt)) })
11632
+ ]
11633
+ }
11634
+ )
11635
+ ] }),
11636
+ /* @__PURE__ */ jsxs("label", { className: "block", children: [
11637
+ /* @__PURE__ */ jsx("span", { className: "mb-1 block font-medium", children: "Median sulcus" }),
11638
+ /* @__PURE__ */ jsxs(
11639
+ Select,
11640
+ {
11641
+ value: safe.dre.medianSulcus || "none",
11642
+ onValueChange: (val) => bump({
11643
+ ...safe,
11644
+ dre: { ...safe.dre, medianSulcus: val === "none" ? "" : val }
11645
+ }),
11646
+ disabled,
11647
+ children: [
11648
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "\u2014" }) }),
11649
+ /* @__PURE__ */ jsx(SelectContent, { children: DRE_SULCUS.map((opt) => /* @__PURE__ */ jsx(SelectItem, { value: opt, children: opt === "none" ? "\u2014" : opt }, opt)) })
11650
+ ]
11651
+ }
11652
+ )
11653
+ ] }),
11654
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
11655
+ /* @__PURE__ */ jsx(
11656
+ Checkbox,
11657
+ {
11658
+ checked: safe.dre.tenderness,
11659
+ onCheckedChange: (c) => bump({ ...safe, dre: { ...safe.dre, tenderness: c === true } }),
11660
+ disabled
11661
+ }
11662
+ ),
11663
+ "Tender (prostatitis?)"
11664
+ ] })
11665
+ ] })
11666
+ ] }),
11667
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
11668
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
11669
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-semibold text-slate-700", children: clinicalField.fieldDef?.label ?? "Clinical examination" }),
11670
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
11671
+ clinicalNarrativeLocked ? /* @__PURE__ */ jsxs("span", { className: "rounded bg-amber-50 px-1.5 py-0.5 text-[10px] font-medium text-amber-900 ring-1 ring-amber-200/80", children: [
11672
+ "You edited this summary. Use",
11673
+ " ",
11674
+ /* @__PURE__ */ jsx("span", { className: "italic", children: "'Regenerate'" }),
11675
+ " to update it from the form."
11676
+ ] }) : null,
11677
+ clinicalNarrativeLocked ? /* @__PURE__ */ jsx(
11678
+ Button,
11679
+ {
11680
+ type: "button",
11681
+ variant: "outline",
11682
+ size: "sm",
11683
+ className: "h-7 shrink-0 px-2 text-xs",
11684
+ disabled: disabled || clinicalField.disabled,
11685
+ onClick: () => {
11686
+ setClinicalNarrativeLocked(false);
11687
+ const norm = normalizeUrologyExamination(value);
11688
+ clinicalField.setValue(formatUrologyExaminationToClinicalExamination(norm));
11689
+ },
11690
+ children: "Regenerate"
11691
+ }
11692
+ ) : null
11693
+ ] })
11694
+ ] }),
11695
+ clinicalNarrativeLocked ? /* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground", children: "Edit this box anytime. Use Regenerate to replace with fresh text from the structured examination." }) : null,
11696
+ /* @__PURE__ */ jsx(
11697
+ Textarea,
11698
+ {
11699
+ className: "min-h-[88px] rounded-md border border-input bg-white text-sm",
11700
+ placeholder: "Auto-filled from selections above\u2026",
11701
+ value: typeof clinicalField.value === "string" ? clinicalField.value : clinicalField.value == null ? "" : String(clinicalField.value),
11702
+ onChange: (e) => {
11703
+ setClinicalNarrativeLocked(true);
11704
+ const t = e.target.value;
11705
+ clinicalField.setValue(t);
11706
+ clinicalField.setTouched();
11707
+ setValue({ ...safe, examinationNotes: t });
11708
+ setTouched();
11709
+ },
11710
+ disabled: disabled || clinicalField.disabled
11711
+ }
11712
+ )
11713
+ ] })
11714
+ ] }),
11715
+ showError ? /* @__PURE__ */ jsx("p", { className: "px-3 pb-2 text-xs text-red-500", children: error }) : null
11716
+ ] });
11717
+ };
11718
+ var RISK_ROWS = [
11719
+ { key: "ckd", label: "Chronic kidney disease" },
11720
+ { key: "diabetes", label: "Diabetes" },
11721
+ { key: "anticoagulants", label: "Anticoagulants" },
11722
+ { key: "activeInfection", label: "Active infection" }
11723
+ ];
11724
+ var UrologyPathwayWidget = ({ fieldId }) => {
11725
+ const { fieldDef, value, setValue, setTouched, error, touched, disabled } = useField(fieldId);
11726
+ const { state } = useForm();
11727
+ const showError = !!error && (touched || state.submitAttempted);
11728
+ const safe = useMemo(() => normalizeUrologyPathway(value), [value]);
11729
+ const update = (next) => {
11730
+ setValue(next);
11731
+ setTouched();
11732
+ };
11733
+ const setNum = (key, raw) => {
11734
+ const n = Number(raw);
11735
+ const v = Number.isFinite(n) && n >= 0 ? n : 0;
11736
+ if (key === "stoneSizeMm") {
11737
+ update({ ...safe, stoneSizeMm: Math.round(v) });
11738
+ return;
11739
+ }
11740
+ update({ ...safe, [key]: v });
11741
+ };
11742
+ const toggleRisk = (key) => {
11743
+ update({
11744
+ ...safe,
11745
+ risk: { ...safe.risk, [key]: !safe.risk[key] }
11746
+ });
11747
+ };
11748
+ if (!fieldDef) return null;
11749
+ const theme = getThemeConfig("textarea", fieldDef.theme);
11750
+ const wrapperClass = theme?.wrapperClassName ?? "rounded-md overflow-hidden flex flex-col border border-[#D0D0D0]";
11751
+ const labelClass = theme?.labelClassName;
11752
+ const subtitle = fieldDef.meta && typeof fieldDef.meta === "object" && fieldDef.meta !== null ? String(fieldDef.meta.subtitle ?? "") : "";
11753
+ const labelContent = /* @__PURE__ */ jsxs(Fragment, { children: [
11754
+ fieldDef.label,
11755
+ fieldDef.required ? /* @__PURE__ */ jsx("span", { className: "ml-1 text-red-500", children: "*" }) : null
11756
+ ] });
11757
+ const labelEl = theme ? /* @__PURE__ */ jsx(Label, { className: labelClass, children: labelContent }) : /* @__PURE__ */ jsx(Label, { className: "text-sm font-medium", children: labelContent });
11758
+ const bodyClass = cn(
11759
+ "-mt-1 flex min-w-0 flex-col gap-4 border-t border-[#D0D0D0] bg-white px-3 py-3",
11760
+ disabled && "pointer-events-none opacity-60"
11761
+ );
11762
+ return /* @__PURE__ */ jsxs("div", { className: cn("w-full min-w-0", wrapperClass), children: [
11763
+ labelEl,
11764
+ subtitle ? /* @__PURE__ */ jsx("p", { className: "px-3 pt-2 text-[11px] text-muted-foreground", children: subtitle }) : null,
11765
+ /* @__PURE__ */ jsxs("div", { className: bodyClass, children: [
11766
+ showError ? /* @__PURE__ */ jsx("p", { className: "text-xs text-red-600", children: error }) : null,
11767
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-3 md:grid-cols-2", children: [
11768
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1 text-xs", children: [
11769
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: "Stone size (mm)" }),
11770
+ /* @__PURE__ */ jsx(
11771
+ Input,
11772
+ {
11773
+ type: "number",
11774
+ min: 0,
11775
+ className: "h-8 text-xs",
11776
+ value: safe.stoneSizeMm,
11777
+ onChange: (e) => setNum("stoneSizeMm", e.target.value),
11778
+ disabled
11779
+ }
11780
+ )
11781
+ ] }),
11782
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 pt-6 text-xs", children: [
11783
+ /* @__PURE__ */ jsx(
11784
+ Checkbox,
11785
+ {
11786
+ checked: safe.hydronephrosis,
11787
+ onCheckedChange: (c) => update({ ...safe, hydronephrosis: c === true }),
11788
+ disabled
11789
+ }
11790
+ ),
11791
+ "Hydronephrosis on imaging"
11792
+ ] }),
11793
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1 text-xs", children: [
11794
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: "Prostate volume (cc)" }),
11795
+ /* @__PURE__ */ jsx(
11796
+ Input,
11797
+ {
11798
+ type: "number",
11799
+ min: 0,
11800
+ step: 0.1,
11801
+ className: "h-8 text-xs",
11802
+ value: safe.prostateVolumeCc,
11803
+ onChange: (e) => setNum("prostateVolumeCc", e.target.value),
11804
+ disabled
11805
+ }
11806
+ )
11807
+ ] }),
11808
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1 text-xs", children: [
11809
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: "PSA (ng/mL)" }),
11810
+ /* @__PURE__ */ jsx(
11811
+ Input,
11812
+ {
11813
+ type: "number",
11814
+ min: 0,
11815
+ step: 0.01,
11816
+ className: "h-8 text-xs",
11817
+ value: safe.psaNgMl,
11818
+ onChange: (e) => setNum("psaNgMl", e.target.value),
11819
+ disabled
11820
+ }
11821
+ )
11822
+ ] }),
11823
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1 text-xs md:col-span-2", children: [
11824
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: "Uroflow Qmax (mL/s)" }),
11825
+ /* @__PURE__ */ jsx(
11826
+ Input,
11827
+ {
11828
+ type: "number",
11829
+ min: 0,
11830
+ step: 0.1,
11831
+ className: "h-8 text-xs",
11832
+ value: safe.uroflowQmaxMlSec,
11833
+ onChange: (e) => setNum("uroflowQmaxMlSec", e.target.value),
11834
+ disabled
11835
+ }
11836
+ )
11837
+ ] })
11838
+ ] }),
11839
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2 border-t border-muted-foreground/20 pt-3", children: [
11840
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-semibold text-slate-800", children: "Risk stratification" }),
11841
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: RISK_ROWS.map((r) => /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-xs", children: [
11842
+ /* @__PURE__ */ jsx(
11843
+ Checkbox,
11844
+ {
11845
+ checked: safe.risk[r.key],
11846
+ onCheckedChange: () => toggleRisk(r.key),
11847
+ disabled
11848
+ }
11849
+ ),
11850
+ r.label
11851
+ ] }, r.key)) })
11852
+ ] })
11853
+ ] })
11854
+ ] });
11855
+ };
11856
+ var FieldRenderer = ({ fieldId }) => {
11857
+ const { fieldDef, visible } = useField(fieldId);
11858
+ if (!visible || !fieldDef) {
11859
+ return null;
11860
+ }
11861
+ return renderWidget(fieldId, fieldDef);
11862
+ };
11863
+ function renderWidget(fieldId, fieldDef) {
11864
+ switch (fieldDef.type) {
11865
+ case "text":
11866
+ case "number":
11867
+ return /* @__PURE__ */ jsx(TextWidget, { fieldId });
11868
+ case "slider":
11869
+ return /* @__PURE__ */ jsx(SliderWidget, { fieldId });
11870
+ case "textarea":
11871
+ if (fieldMetaRequestsMarMedicationOrdersButton(fieldDef.meta)) {
11872
+ return /* @__PURE__ */ jsx(MarMedicationOrdersWidget, { fieldId });
11873
+ }
11874
+ return /* @__PURE__ */ jsx(TextWidget, { fieldId });
11875
+ case "richtext":
11876
+ return /* @__PURE__ */ jsx(RichTextWidget, { fieldId });
11877
+ case "date":
11878
+ return /* @__PURE__ */ jsx(DateWidget, { fieldId });
11879
+ case "datetime":
11880
+ return /* @__PURE__ */ jsx(DateTimeWidget, { fieldId });
11881
+ case "select":
11882
+ return /* @__PURE__ */ jsx(SelectWidget, { fieldId });
11883
+ case "radio":
11884
+ return /* @__PURE__ */ jsx(RadioWidget, { fieldId });
11885
+ case "checkbox":
11886
+ return /* @__PURE__ */ jsx(CheckboxWidget, { fieldId });
11887
+ case "multiselect":
11888
+ return /* @__PURE__ */ jsx(MultiSelectWidget, { fieldId });
11889
+ case "repeatable":
11890
+ return /* @__PURE__ */ jsx(RepeatableWidget, { fieldId });
11891
+ case "image_upload":
11892
+ return /* @__PURE__ */ jsx(ImageUploadWidget, { fieldId });
11893
+ case "media_upload":
11894
+ return /* @__PURE__ */ jsx(MediaUploadWidget, { fieldId });
11895
+ case "signature":
11896
+ return /* @__PURE__ */ jsx(SignatureUploadWidget, { fieldId });
11897
+ case "editable_table":
11898
+ return /* @__PURE__ */ jsx(EditableTableWidget, { fieldId });
11899
+ case "medications":
11900
+ return /* @__PURE__ */ jsx(AddMedicationWidget, { fieldId });
11901
+ case "discharge_medication_orders":
11902
+ return /* @__PURE__ */ jsx(DischargeMedicationOrdersWidget, { fieldId });
11903
+ case "investigations":
11904
+ return /* @__PURE__ */ jsx(AddInvestigationWidget, { fieldId });
11905
+ case "procedures":
11906
+ return /* @__PURE__ */ jsx(AddProcedureWidget, { fieldId });
11907
+ case "differential_diagnosis":
11908
+ return /* @__PURE__ */ jsx(DifferentialDiagnosisWidget, { fieldId });
11909
+ case "vitals":
11910
+ return /* @__PURE__ */ jsx(VitalsWidget, { fieldId });
11911
+ case "hidden_vitals":
11912
+ return /* @__PURE__ */ jsx(HiddenVitalsWidget, { fieldId });
11913
+ case "referral":
11914
+ return /* @__PURE__ */ jsx(ReferralWidget, { fieldId });
11915
+ case "followup":
11916
+ return /* @__PURE__ */ jsx(FollowupWidget, { fieldId });
11917
+ case "smart_textarea":
11918
+ return /* @__PURE__ */ jsx(SmartTextareaWidget, { fieldId });
11919
+ case "diagnosis_textarea":
11920
+ return /* @__PURE__ */ jsx(DiagnosisTextareaWidget, { fieldId });
11921
+ case "obstetric_history":
11922
+ return /* @__PURE__ */ jsx(ObstetricHistoryWidget, { fieldId });
11923
+ case "eye_prescription":
11924
+ return /* @__PURE__ */ jsx(OphthalmologyWidget, { fieldId });
11925
+ case "ophthal_diagnosis":
11926
+ return /* @__PURE__ */ jsx(OphthalDiagnosisWidget, { fieldId });
11927
+ case "orthopedic_exam":
11928
+ return /* @__PURE__ */ jsx(OrthopedicExamWidget, { fieldId });
11929
+ case "general_surgery_smart_history":
11930
+ return /* @__PURE__ */ jsx(GsSmartHistoryWidget, { fieldId });
11931
+ case "general_surgery_examination":
11932
+ return /* @__PURE__ */ jsx(GsExaminationWidget, { fieldId });
11933
+ case "general_surgery_grading":
11934
+ return /* @__PURE__ */ jsx(GsGradingWidget, { fieldId });
11935
+ case "pain_scale_flags":
11936
+ return /* @__PURE__ */ jsx(PainScaleFlagsWidget, { fieldId });
11937
+ case "urology_smart_history":
11938
+ return /* @__PURE__ */ jsx(UrologySmartHistoryWidget, { fieldId });
11939
+ case "urology_examination":
11940
+ return /* @__PURE__ */ jsx(UrologyExaminationWidget, { fieldId });
11941
+ case "urology_pathway":
11942
+ return /* @__PURE__ */ jsx(UrologyPathwayWidget, { fieldId });
11943
+ case "toggle": {
11944
+ const { value, setValue, setTouched, disabled } = useField(fieldId);
11945
+ const store = useFormStore();
11946
+ const excludes = fieldDef.excludes ?? [];
11947
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
11948
+ /* @__PURE__ */ jsx(
11949
+ Switch,
11950
+ {
11951
+ checked: value === true,
11952
+ disabled,
11953
+ onCheckedChange: (checked) => {
11954
+ setValue(checked);
11955
+ setTouched();
11956
+ if (checked) excludes.forEach((id) => store.setValue(id, false));
11957
+ }
11958
+ }
11959
+ ),
11960
+ /* @__PURE__ */ jsx(Label, { className: "text-sm font-medium leading-none cursor-pointer select-none", children: fieldDef.label })
11961
+ ] });
11962
+ }
11963
+ case "suggestion_textarea":
11964
+ case "complaint_chips":
11965
+ return /* @__PURE__ */ jsx(SuggestionTextareaWidget, { fieldId });
11966
+ case "lens_assessment":
11967
+ return /* @__PURE__ */ jsx(LensAssessmentWidget, { fieldId });
11968
+ case "functional_impairment_score":
11969
+ return /* @__PURE__ */ jsx(FunctionalImpairmentScoreWidget, { fieldId });
11970
+ case "biometry_iol_workup":
11971
+ return /* @__PURE__ */ jsx(BiometryIolWorkupWidget, { fieldId });
11972
+ case "surgical_risk_flags":
11973
+ return /* @__PURE__ */ jsx(SurgicalRiskFlagsWidget, { fieldId });
11974
+ case "static_text": {
11975
+ const def = fieldDef;
11976
+ const size = def.size ?? "regular";
11977
+ const labelClass = size === "large" ? "text-base" : "text-sm";
11978
+ const descClass = size === "large" ? "text-sm" : "text-xs";
11979
+ return /* @__PURE__ */ jsxs("div", { className: `${labelClass} text-muted-foreground`, children: [
11980
+ def.label,
11981
+ def.description && /* @__PURE__ */ jsx("p", { className: `mt-1 ${descClass} opacity-90`, children: def.description })
11982
+ ] });
11983
+ }
11984
+ default:
11985
+ return /* @__PURE__ */ jsxs("div", { className: "text-red-500", children: [
11986
+ "Unknown field type: ",
11987
+ fieldDef.type
11988
+ ] });
11989
+ }
11990
+ }
11991
+ var Section = ({ title, children }) => {
11992
+ const [expanded, setExpanded] = useState(true);
11993
+ const handleToggle = () => setExpanded((prev) => !prev);
11994
+ const contentClassName = cn(
11995
+ "overflow-hidden transition-[height] duration-200 ease-in-out",
11996
+ !expanded && "hidden"
11997
+ );
11998
+ return /* @__PURE__ */ jsxs("div", { className: "mb-6 border rounded-lg bg-white shadow-sm overflow-hidden", children: [
11999
+ /* @__PURE__ */ jsxs(
12000
+ "button",
12001
+ {
12002
+ type: "button",
12003
+ onClick: handleToggle,
12004
+ className: "w-full flex items-center justify-between gap-2 p-4 text-left border-b hover:bg-gray-50/80 transition-colors",
12005
+ children: [
12006
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-medium", children: title }),
12007
+ /* @__PURE__ */ jsx("span", { className: "flex-shrink-0 text-muted-foreground", "aria-hidden": true, children: expanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "h-5 w-5" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "h-5 w-5" }) })
12008
+ ]
12009
+ }
12010
+ ),
12011
+ /* @__PURE__ */ jsx("div", { className: contentClassName, children: /* @__PURE__ */ jsx("div", { className: "p-4 pt-4 space-y-4 border-t-0", children }) })
12012
+ ] });
12013
+ };
12014
+ var ColumnLayout = ({
12015
+ columns,
12016
+ label,
12017
+ children
12018
+ }) => {
12019
+ const gridCols = Math.max(1, Math.min(columns, 12));
12020
+ const gridClass = `grid gap-4 w-full`;
12021
+ const style = {
12022
+ gridTemplateColumns: `repeat(${gridCols}, minmax(0, 1fr))`
12023
+ };
12024
+ return /* @__PURE__ */ jsxs("div", { className: "mb-6", children: [
12025
+ label != null && label !== "" && /* @__PURE__ */ jsx("div", { className: "mb-2 text-sm font-medium text-gray-700", children: label }),
12026
+ /* @__PURE__ */ jsx("div", { className: gridClass, style, children })
12027
+ ] });
10747
12028
  };
10748
12029
  var DynamicForm = () => {
10749
12030
  const store = useFormStore();
@@ -11522,6 +12803,40 @@ var ReadOnlyFieldRenderer = ({
11522
12803
  ].join("\n");
11523
12804
  return /* @__PURE__ */ jsx(ReadOnlyText, { fieldDef, value: lines });
11524
12805
  }
12806
+ case "urology_smart_history": {
12807
+ const structuredDisplay = value && typeof value === "object" ? JSON.stringify(normalizeUrologySmartHistory(value), null, 2) : value == null || value === "" ? "\u2014" : String(value);
12808
+ const hopcDef = resolveFieldDef?.("symptoms");
12809
+ const hopcRaw = allValues?.["symptoms"];
12810
+ const hopcStr = typeof hopcRaw === "string" ? hopcRaw : hopcRaw != null && hopcRaw !== "" ? String(hopcRaw) : "";
12811
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
12812
+ /* @__PURE__ */ jsx(ReadOnlyText, { fieldDef, value: structuredDisplay }),
12813
+ hopcDef ? /* @__PURE__ */ jsx(ReadOnlyText, { fieldDef: hopcDef, value: hopcStr }) : hopcStr ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
12814
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-gray-700", children: "History of presenting complaint" }),
12815
+ /* @__PURE__ */ jsx("div", { className: "text-gray-900 border border-gray-200 rounded-md p-3 bg-gray-50 min-h-[2.5rem] whitespace-pre-wrap", children: hopcStr })
12816
+ ] }) : null
12817
+ ] });
12818
+ }
12819
+ case "urology_examination": {
12820
+ const structuredDisplay = value && typeof value === "object" ? JSON.stringify(value, null, 2) : value == null || value === "" ? "\u2014" : String(value);
12821
+ const clinicalDef = resolveFieldDef?.("clinical_examination");
12822
+ const clinicalRaw = allValues?.["clinical_examination"];
12823
+ const clinicalStr = typeof clinicalRaw === "string" ? clinicalRaw : clinicalRaw != null && clinicalRaw !== "" ? String(clinicalRaw) : "";
12824
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
12825
+ /* @__PURE__ */ jsx(ReadOnlyText, { fieldDef, value: structuredDisplay }),
12826
+ clinicalDef ? /* @__PURE__ */ jsx(ReadOnlyText, { fieldDef: clinicalDef, value: clinicalStr }) : clinicalStr ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
12827
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-gray-700", children: "Clinical examination" }),
12828
+ /* @__PURE__ */ jsx("div", { className: "text-gray-900 border border-gray-200 rounded-md p-3 bg-gray-50 min-h-[2.5rem] whitespace-pre-wrap", children: clinicalStr })
12829
+ ] }) : null
12830
+ ] });
12831
+ }
12832
+ case "urology_pathway":
12833
+ return /* @__PURE__ */ jsx(
12834
+ ReadOnlyText,
12835
+ {
12836
+ fieldDef,
12837
+ value: value && typeof value === "object" ? JSON.stringify(value, null, 2) : value == null || value === "" ? "\u2014" : String(value)
12838
+ }
12839
+ );
11525
12840
  case "general_surgery_smart_history": {
11526
12841
  const structuredDisplay = value && typeof value === "object" ? JSON.stringify(normalizeGeneralSurgerySmartHistory(value), null, 2) : value == null || value === "" ? "\u2014" : String(value);
11527
12842
  const hopcDef = resolveFieldDef?.("symptoms");