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.cjs CHANGED
@@ -137,12 +137,82 @@ function validateForm(values, fields) {
137
137
  return errors;
138
138
  }
139
139
 
140
+ // src/core/suggestionTokens.ts
141
+ function getSuggestionTokensFromText(text) {
142
+ return text.split(/[,\n\r]+/).map((p) => p.trim()).filter(Boolean);
143
+ }
144
+ var DEFAULT_TOKEN_SEPARATOR = ", ";
145
+ function commaSplitLine(line) {
146
+ return line.split(",").map((p) => p.trim()).filter(Boolean);
147
+ }
148
+ function dedupeChipOrder(chips) {
149
+ const seen = /* @__PURE__ */ new Set();
150
+ const out = [];
151
+ for (const c of chips) {
152
+ if (seen.has(c)) continue;
153
+ seen.add(c);
154
+ out.push(c);
155
+ }
156
+ return out;
157
+ }
158
+ function parseProseAndChipTokens(text, allowed) {
159
+ const normalized = text.replace(/\r\n/g, "\n");
160
+ let lines = normalized.split("\n");
161
+ while (lines.length > 0 && lines[lines.length - 1] === "") {
162
+ lines.pop();
163
+ }
164
+ if (lines.length === 0) return { prose: "", chips: [] };
165
+ let chipStart = lines.length;
166
+ for (let i = lines.length - 1; i >= 0; i--) {
167
+ const toks = commaSplitLine(lines[i]);
168
+ if (toks.length === 0) break;
169
+ if (!toks.every((t) => allowed.has(t))) break;
170
+ chipStart = i;
171
+ }
172
+ if (chipStart < lines.length) {
173
+ const chipLines = lines.slice(chipStart);
174
+ const prose = lines.slice(0, chipStart).join("\n");
175
+ const chips = dedupeChipOrder(chipLines.flatMap(commaSplitLine));
176
+ return { prose, chips };
177
+ }
178
+ const parts = getSuggestionTokensFromText(normalized);
179
+ const chipsFallback = dedupeChipOrder(parts.filter((t) => allowed.has(t)));
180
+ const proseParts = parts.filter((t) => !allowed.has(t));
181
+ return { prose: proseParts.join(DEFAULT_TOKEN_SEPARATOR), chips: chipsFallback };
182
+ }
183
+ function composeProseAndChips(prose, chips, separator = DEFAULT_TOKEN_SEPARATOR) {
184
+ const chipStr = dedupeChipOrder(chips).join(separator);
185
+ const p = prose.replace(/\s+$/, "");
186
+ if (p && chipStr) return `${p}
187
+ ${chipStr}`;
188
+ if (chipStr) return chipStr;
189
+ return p;
190
+ }
191
+ function toggleSuggestionTokenInText(current, token, separator = DEFAULT_TOKEN_SEPARATOR, allowedChipValues) {
192
+ const t = String(token).trim();
193
+ if (!t) return current;
194
+ if (!allowedChipValues || allowedChipValues.size === 0) {
195
+ const parts = getSuggestionTokensFromText(current);
196
+ const i = parts.findIndex((p) => p === t);
197
+ if (i >= 0) parts.splice(i, 1);
198
+ else parts.push(t);
199
+ return parts.join(separator);
200
+ }
201
+ if (!allowedChipValues.has(t)) return current;
202
+ let { prose, chips } = parseProseAndChipTokens(current, allowedChipValues);
203
+ const idx = chips.indexOf(t);
204
+ if (idx >= 0) chips.splice(idx, 1);
205
+ else chips.push(t);
206
+ chips = dedupeChipOrder(chips);
207
+ return composeProseAndChips(prose, chips, separator);
208
+ }
209
+
140
210
  // src/core/rules.ts
141
211
  function tokenListContainsString(text, needle) {
142
212
  if (typeof text !== "string") return false;
143
213
  const want = String(needle).trim();
144
214
  if (!want) return false;
145
- const parts = text.split(",").map((p) => p.trim()).filter(Boolean);
215
+ const parts = getSuggestionTokensFromText(text);
146
216
  return parts.includes(want);
147
217
  }
148
218
  function evaluateCondition(value, condition) {
@@ -353,7 +423,7 @@ function normalizeGeneralSurgerySmartHistory(raw) {
353
423
  ...painIn,
354
424
  severity: Number.isFinite(sev) ? Math.min(10, Math.max(0, Math.round(sev))) : d.pain.severity
355
425
  };
356
- const str2 = (x) => typeof x === "string" ? x : "";
426
+ const str4 = (x) => typeof x === "string" ? x : "";
357
427
  const strArr = (x) => Array.isArray(x) ? x.filter((i) => typeof i === "string") : [];
358
428
  const swell = v.swelling && typeof v.swelling === "object" ? v.swelling : {};
359
429
  const gi = v.gi && typeof v.gi === "object" ? v.gi : {};
@@ -363,44 +433,44 @@ function normalizeGeneralSurgerySmartHistory(raw) {
363
433
  return {
364
434
  pain,
365
435
  swelling: {
366
- duration: str2(swell.duration),
367
- sizeProgression: str2(swell.sizeProgression),
368
- painfulPainless: str2(swell.painfulPainless),
436
+ duration: str4(swell.duration),
437
+ sizeProgression: str4(swell.sizeProgression),
438
+ painfulPainless: str4(swell.painfulPainless),
369
439
  checks: strArr(swell.checks)
370
440
  },
371
441
  gi: {
372
- appetite: str2(gi.appetite),
373
- weightLoss: str2(gi.weightLoss),
374
- bowelHabits: str2(gi.bowelHabits),
442
+ appetite: str4(gi.appetite),
443
+ weightLoss: str4(gi.weightLoss),
444
+ bowelHabits: str4(gi.bowelHabits),
375
445
  checks: strArr(gi.checks)
376
446
  },
377
447
  breast: {
378
- lumpDuration: str2(breast.lumpDuration),
379
- nippleDischarge: str2(breast.nippleDischarge),
448
+ lumpDuration: str4(breast.lumpDuration),
449
+ nippleDischarge: str4(breast.nippleDischarge),
380
450
  checks: strArr(breast.checks)
381
451
  },
382
452
  ano: { checks: strArr(ano.checks) },
383
453
  thyroid: {
384
- swellingDuration: str2(thy.swellingDuration),
454
+ swellingDuration: str4(thy.swellingDuration),
385
455
  checks: strArr(thy.checks)
386
456
  }
387
457
  };
388
458
  }
389
459
  function normalizeBreastExamSide(partial) {
390
460
  const e = defaultBreastExamSide();
391
- const str2 = (x) => typeof x === "string" ? x : "";
392
- const bool = (x) => x === true;
461
+ const str4 = (x) => typeof x === "string" ? x : "";
462
+ const bool2 = (x) => x === true;
393
463
  if (!partial || typeof partial !== "object") return e;
394
464
  const p = partial;
395
465
  return {
396
- size: str2(p.size),
397
- quadrant: str2(p.quadrant),
398
- tenderness: str2(p.tenderness),
399
- fixity: str2(p.fixity),
400
- skinInvolvement: str2(p.skinInvolvement),
401
- consistency: str2(p.consistency),
402
- axillaryNodes: bool(p.axillaryNodes),
403
- nippleAreolarComplex: bool(p.nippleAreolarComplex)
466
+ size: str4(p.size),
467
+ quadrant: str4(p.quadrant),
468
+ tenderness: str4(p.tenderness),
469
+ fixity: str4(p.fixity),
470
+ skinInvolvement: str4(p.skinInvolvement),
471
+ consistency: str4(p.consistency),
472
+ axillaryNodes: bool2(p.axillaryNodes),
473
+ nippleAreolarComplex: bool2(p.nippleAreolarComplex)
404
474
  };
405
475
  }
406
476
  function normalizeBreastExaminationBlock(raw) {
@@ -424,7 +494,7 @@ function normalizeGeneralSurgeryExamination(raw) {
424
494
  const th = v.thyroid && typeof v.thyroid === "object" ? v.thyroid : {};
425
495
  const ar = v.anorectal && typeof v.anorectal === "object" ? v.anorectal : {};
426
496
  const lm = v.limb && typeof v.limb === "object" ? v.limb : {};
427
- const bool = (x) => x === true;
497
+ const bool2 = (x) => x === true;
428
498
  return {
429
499
  general: strArr(v.general),
430
500
  regions: strArr(v.regions),
@@ -437,27 +507,27 @@ function normalizeGeneralSurgeryExamination(raw) {
437
507
  },
438
508
  hernia: {
439
509
  site: typeof hb.site === "string" ? hb.site : "",
440
- reducible: bool(hb.reducible),
441
- coughImpulse: bool(hb.coughImpulse),
442
- tenderness: bool(hb.tenderness)
510
+ reducible: bool2(hb.reducible),
511
+ coughImpulse: bool2(hb.coughImpulse),
512
+ tenderness: bool2(hb.tenderness)
443
513
  },
444
514
  breast: normalizeBreastExaminationBlock(br),
445
515
  thyroid: {
446
516
  size: typeof th.size === "string" ? th.size : "",
447
- mobileDeglutition: bool(th.mobileDeglutition),
448
- nodules: bool(th.nodules),
449
- cervicalNodes: bool(th.cervicalNodes)
517
+ mobileDeglutition: bool2(th.mobileDeglutition),
518
+ nodules: bool2(th.nodules),
519
+ cervicalNodes: bool2(th.cervicalNodes)
450
520
  },
451
521
  anorectal: {
452
522
  inspection: typeof ar.inspection === "string" ? ar.inspection : "",
453
- dreDone: bool(ar.dreDone),
454
- proctoscopyDone: bool(ar.proctoscopyDone),
523
+ dreDone: bool2(ar.dreDone),
524
+ proctoscopyDone: bool2(ar.proctoscopyDone),
455
525
  notes: typeof ar.notes === "string" ? ar.notes : ""
456
526
  },
457
527
  limb: {
458
- dilatedVeins: bool(lm.dilatedVeins),
459
- ulcer: bool(lm.ulcer),
460
- oedema: bool(lm.oedema)
528
+ dilatedVeins: bool2(lm.dilatedVeins),
529
+ ulcer: bool2(lm.ulcer),
530
+ oedema: bool2(lm.oedema)
461
531
  }
462
532
  };
463
533
  }
@@ -733,6 +803,375 @@ function formatGeneralSurgeryExaminationToNarrative(v) {
733
803
  return blocks.join("\n\n");
734
804
  }
735
805
 
806
+ // src/core/urologyPathway.ts
807
+ function defaultUrologySmartHistory() {
808
+ return {
809
+ socrates: {
810
+ site: "",
811
+ onset: "",
812
+ character: "",
813
+ radiation: "",
814
+ associated: "",
815
+ timing: "",
816
+ exacerbating: "",
817
+ severity: 0
818
+ },
819
+ ipss: {
820
+ incomplete: 0,
821
+ frequency: 0,
822
+ intermittency: 0,
823
+ urgency: 0,
824
+ weakStream: 0,
825
+ straining: 0,
826
+ nocturia: 0
827
+ },
828
+ ipssQoL: 0,
829
+ haematuria: {
830
+ present: false,
831
+ timing: "none",
832
+ painful: false,
833
+ clots: false
834
+ },
835
+ sexual: {
836
+ erectile: "none",
837
+ libido: "none",
838
+ ejaculation: "none",
839
+ infertilityMonths: 0
840
+ },
841
+ pastNotes: ""
842
+ };
843
+ }
844
+ function defaultUrologyExamination() {
845
+ return {
846
+ regions: [],
847
+ general: {
848
+ pallor: false,
849
+ oedema: false,
850
+ icterus: false,
851
+ lymphadenopathy: false
852
+ },
853
+ abdomen: {
854
+ distension: false,
855
+ scars: false,
856
+ mass: false,
857
+ kidneyPalpable: false,
858
+ bladderPalpable: false,
859
+ renalAngleTender: false,
860
+ bladderDull: false
861
+ },
862
+ gu: {
863
+ meatusAbnormal: false,
864
+ phimosis: false,
865
+ lesions: false,
866
+ scrotalSwelling: false,
867
+ transilluminant: false,
868
+ tenderTestis: false,
869
+ hydrocele: false,
870
+ varicocele: false,
871
+ suspiciousMass: false
872
+ },
873
+ dre: {
874
+ done: false,
875
+ sizeGrams: 0,
876
+ consistency: "",
877
+ medianSulcus: "",
878
+ tenderness: false
879
+ },
880
+ examinationNotes: ""
881
+ };
882
+ }
883
+ function defaultUrologyPathway() {
884
+ return {
885
+ stoneSizeMm: 0,
886
+ hydronephrosis: false,
887
+ prostateVolumeCc: 0,
888
+ psaNgMl: 0,
889
+ uroflowQmaxMlSec: 0,
890
+ risk: {
891
+ ckd: false,
892
+ diabetes: false,
893
+ anticoagulants: false,
894
+ activeInfection: false
895
+ }
896
+ };
897
+ }
898
+ function ipssItem(v) {
899
+ const n = Number(v);
900
+ if (!Number.isFinite(n)) return 0;
901
+ return Math.min(5, Math.max(0, Math.round(n)));
902
+ }
903
+ function urologyIpssSevenTotal(ipss) {
904
+ return ipss.incomplete + ipss.frequency + ipss.intermittency + ipss.urgency + ipss.weakStream + ipss.straining + ipss.nocturia;
905
+ }
906
+ function urologyIpssBand(total) {
907
+ if (total <= 7) return "Mild";
908
+ if (total <= 19) return "Moderate";
909
+ return "Severe";
910
+ }
911
+ function hopcMeaningfulStr(x) {
912
+ if (typeof x !== "string") return "";
913
+ const t = x.trim();
914
+ if (!t || t.toLowerCase() === "none") return "";
915
+ return t;
916
+ }
917
+ function hopcNonEmpty(lines) {
918
+ return lines.map((s) => (s ?? "").trim()).filter(Boolean);
919
+ }
920
+ function formatUrologySmartHistoryToSymptomsNarrative(safe, flags) {
921
+ const { showPain, showLUTS, showHaem, showSex } = flags;
922
+ const parts = [];
923
+ if (showPain) {
924
+ const s = safe.socrates;
925
+ const painLines = hopcNonEmpty([
926
+ s.site ? `Site: ${s.site}` : "",
927
+ s.onset ? `Onset: ${s.onset}` : "",
928
+ s.character ? `Character: ${s.character}` : "",
929
+ s.radiation ? `Radiation: ${s.radiation}` : "",
930
+ s.associated ? `Associated: ${s.associated}` : "",
931
+ s.timing ? `Timing: ${s.timing}` : "",
932
+ s.exacerbating ? `Exacerbating/relieving: ${s.exacerbating}` : "",
933
+ `Severity: ${s.severity}/10`
934
+ ]);
935
+ const hasNonDefaultPain = painLines.length > 1 || painLines.length === 1 && painLines[0] !== "Severity: 0/10";
936
+ if (hasNonDefaultPain) parts.push(`SOCRATES:
937
+ ${painLines.join("\n")}`);
938
+ }
939
+ if (showLUTS) {
940
+ const ip = safe.ipss;
941
+ const any = ip.incomplete || ip.frequency || ip.intermittency || ip.urgency || ip.weakStream || ip.straining || ip.nocturia || safe.ipssQoL;
942
+ if (any) {
943
+ const ipssTotal = urologyIpssSevenTotal(safe.ipss);
944
+ const ipssBandLabel = urologyIpssBand(ipssTotal);
945
+ parts.push(`IPSS: ${ipssTotal}/35 (${ipssBandLabel}) \xB7 QoL ${safe.ipssQoL}/6`);
946
+ }
947
+ }
948
+ if (showHaem) {
949
+ const h = safe.haematuria;
950
+ const timing = hopcMeaningfulStr(h.timing);
951
+ const haemLines = hopcNonEmpty([
952
+ h.present ? "Haematuria present" : "",
953
+ timing ? `Timing: ${timing}` : "",
954
+ h.painful ? "Painful" : "",
955
+ h.clots ? "Clots" : ""
956
+ ]);
957
+ if (haemLines.length) parts.push(`Haematuria:
958
+ ${haemLines.join("\n")}`);
959
+ }
960
+ if (showSex) {
961
+ const sx = safe.sexual;
962
+ const infertility = sx.infertilityMonths;
963
+ const sexLines = hopcNonEmpty([
964
+ hopcMeaningfulStr(sx.erectile) ? `Erectile function: ${hopcMeaningfulStr(sx.erectile)}` : "",
965
+ hopcMeaningfulStr(sx.libido) ? `Libido: ${hopcMeaningfulStr(sx.libido)}` : "",
966
+ hopcMeaningfulStr(sx.ejaculation) ? `Ejaculation: ${hopcMeaningfulStr(sx.ejaculation)}` : "",
967
+ Number.isFinite(infertility) && infertility > 0 ? `Infertility: ${infertility} months` : ""
968
+ ]);
969
+ if (sexLines.length) parts.push(`Sexual/reproductive:
970
+ ${sexLines.join("\n")}`);
971
+ }
972
+ return parts.join("\n\n").trim();
973
+ }
974
+ function formatUrologyExaminationToClinicalExamination(v) {
975
+ const sections = [];
976
+ const generalLabels = {
977
+ pallor: "Pallor (chronic dz)",
978
+ oedema: "Oedema (renal)",
979
+ icterus: "Icterus",
980
+ lymphadenopathy: "Lymphadenopathy"
981
+ };
982
+ const general = Object.keys(generalLabels).filter((k) => v.general[k]).map((k) => generalLabels[k]);
983
+ if (general.length) sections.push(`General: ${general.join(", ")}`);
984
+ const abdLabels = {
985
+ distension: "Distension",
986
+ scars: "Surgical scars",
987
+ mass: "Visible mass",
988
+ kidneyPalpable: "Kidney palpable",
989
+ bladderPalpable: "Bladder palpable",
990
+ renalAngleTender: "Renal angle tender",
991
+ bladderDull: "Bladder dullness (retention)"
992
+ };
993
+ const abd = Object.keys(abdLabels).filter((k) => v.abdomen[k]).map((k) => abdLabels[k]);
994
+ if (abd.length) sections.push(`Abdomen: ${abd.join(", ")}`);
995
+ const guLabels = {
996
+ meatusAbnormal: "Meatus abnormal (hypospadias?)",
997
+ phimosis: "Phimosis / paraphimosis",
998
+ lesions: "Penile lesions / ulcers",
999
+ scrotalSwelling: "Scrotal swelling",
1000
+ transilluminant: "Transilluminant",
1001
+ tenderTestis: "Tender testis",
1002
+ hydrocele: "Hydrocele",
1003
+ varicocele: "Varicocele",
1004
+ suspiciousMass: "Suspicious mass"
1005
+ };
1006
+ const gu = Object.keys(guLabels).filter((k) => v.gu[k]).map((k) => guLabels[k]);
1007
+ if (gu.length) sections.push(`GU: ${gu.join(", ")}`);
1008
+ const dreBits = hopcNonEmpty([
1009
+ v.dre.done ? "Performed" : "",
1010
+ v.dre.sizeGrams > 0 ? `Size ~${v.dre.sizeGrams} g` : "",
1011
+ v.dre.consistency ? `Consistency: ${v.dre.consistency}` : "",
1012
+ v.dre.medianSulcus ? `Median sulcus: ${v.dre.medianSulcus}` : "",
1013
+ v.dre.tenderness ? "Tenderness" : ""
1014
+ ]);
1015
+ if (dreBits.length) sections.push(`DRE: ${dreBits.join(", ")}`);
1016
+ return sections.join("\n");
1017
+ }
1018
+ function str(x) {
1019
+ return typeof x === "string" ? x : "";
1020
+ }
1021
+ function bool(x) {
1022
+ return x === true;
1023
+ }
1024
+ function nonNegInt(x) {
1025
+ const n = Number(x);
1026
+ if (!Number.isFinite(n)) return 0;
1027
+ return Math.max(0, Math.round(n));
1028
+ }
1029
+ function normalizeUrologySmartHistory(raw) {
1030
+ const base = defaultUrologySmartHistory();
1031
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return base;
1032
+ const r = raw;
1033
+ const soc = r.socrates && typeof r.socrates === "object" && !Array.isArray(r.socrates) ? r.socrates : {};
1034
+ const socObj = soc;
1035
+ const sev = Number(socObj.severity);
1036
+ const socrates = {
1037
+ site: str(socObj.site),
1038
+ onset: str(socObj.onset),
1039
+ character: str(socObj.character),
1040
+ radiation: str(socObj.radiation),
1041
+ associated: str(socObj.associated),
1042
+ timing: str(socObj.timing),
1043
+ exacerbating: str(socObj.exacerbating),
1044
+ severity: Number.isFinite(sev) ? Math.min(10, Math.max(0, Math.round(sev))) : 0
1045
+ };
1046
+ const ipRaw = r.ipss && typeof r.ipss === "object" && !Array.isArray(r.ipss) ? r.ipss : {};
1047
+ const ip = ipRaw;
1048
+ const ipss = {
1049
+ incomplete: ipssItem(ip.incomplete),
1050
+ frequency: ipssItem(ip.frequency),
1051
+ intermittency: ipssItem(ip.intermittency),
1052
+ urgency: ipssItem(ip.urgency),
1053
+ weakStream: ipssItem(ip.weakStream ?? ip.weak_stream),
1054
+ straining: ipssItem(ip.straining),
1055
+ nocturia: ipssItem(ip.nocturia)
1056
+ };
1057
+ const qolRaw = Number(r.ipssQoL);
1058
+ const ipssQoL = Number.isFinite(qolRaw) ? Math.min(6, Math.max(0, Math.round(qolRaw))) : 0;
1059
+ const haRaw = r.haematuria && typeof r.haematuria === "object" && !Array.isArray(r.haematuria) ? r.haematuria : {};
1060
+ const ha = haRaw;
1061
+ const haematuria = {
1062
+ present: bool(ha.present),
1063
+ timing: str(ha.timing) || "none",
1064
+ painful: bool(ha.painful),
1065
+ clots: bool(ha.clots)
1066
+ };
1067
+ const sxRaw = r.sexual && typeof r.sexual === "object" && !Array.isArray(r.sexual) ? r.sexual : {};
1068
+ const sx = sxRaw;
1069
+ const infertilityMonths = nonNegInt(sx.infertilityMonths);
1070
+ const sexual = {
1071
+ erectile: str(sx.erectile) || "none",
1072
+ libido: str(sx.libido) || "none",
1073
+ ejaculation: str(sx.ejaculation) || "none",
1074
+ infertilityMonths
1075
+ };
1076
+ const pastNotes = str(r.pastNotes);
1077
+ return {
1078
+ socrates,
1079
+ ipss,
1080
+ ipssQoL,
1081
+ haematuria,
1082
+ sexual,
1083
+ pastNotes
1084
+ };
1085
+ }
1086
+ function dreSelectStr(x) {
1087
+ const t = str(x).trim();
1088
+ if (!t || t.toLowerCase() === "none") return "";
1089
+ return t;
1090
+ }
1091
+ function normalizeUrologyExamination(raw) {
1092
+ const base = defaultUrologyExamination();
1093
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return base;
1094
+ const r = raw;
1095
+ const regions = Array.isArray(r.regions) ? r.regions.filter((x) => typeof x === "string") : [];
1096
+ const g = r.general && typeof r.general === "object" && !Array.isArray(r.general) ? r.general : {};
1097
+ const gObj = g;
1098
+ const general = {
1099
+ pallor: bool(gObj.pallor),
1100
+ oedema: bool(gObj.oedema),
1101
+ icterus: bool(gObj.icterus),
1102
+ lymphadenopathy: bool(gObj.lymphadenopathy)
1103
+ };
1104
+ const ab = r.abdomen && typeof r.abdomen === "object" && !Array.isArray(r.abdomen) ? r.abdomen : {};
1105
+ const abObj = ab;
1106
+ const abdomen = {
1107
+ distension: bool(abObj.distension),
1108
+ scars: bool(abObj.scars),
1109
+ mass: bool(abObj.mass),
1110
+ kidneyPalpable: bool(abObj.kidneyPalpable),
1111
+ bladderPalpable: bool(abObj.bladderPalpable),
1112
+ renalAngleTender: bool(abObj.renalAngleTender),
1113
+ bladderDull: bool(abObj.bladderDull)
1114
+ };
1115
+ const guRaw = r.gu && typeof r.gu === "object" && !Array.isArray(r.gu) ? r.gu : {};
1116
+ const guObj = guRaw;
1117
+ const gu = {
1118
+ meatusAbnormal: bool(guObj.meatusAbnormal),
1119
+ phimosis: bool(guObj.phimosis),
1120
+ lesions: bool(guObj.lesions),
1121
+ scrotalSwelling: bool(guObj.scrotalSwelling),
1122
+ transilluminant: bool(guObj.transilluminant),
1123
+ tenderTestis: bool(guObj.tenderTestis),
1124
+ hydrocele: bool(guObj.hydrocele),
1125
+ varicocele: bool(guObj.varicocele),
1126
+ suspiciousMass: bool(guObj.suspiciousMass)
1127
+ };
1128
+ const dr = r.dre && typeof r.dre === "object" && !Array.isArray(r.dre) ? r.dre : {};
1129
+ const drObj = dr;
1130
+ const sizeG = Number(drObj.sizeGrams);
1131
+ const dre = {
1132
+ done: bool(drObj.done),
1133
+ sizeGrams: Number.isFinite(sizeG) && sizeG >= 0 ? Math.round(sizeG) : 0,
1134
+ consistency: dreSelectStr(drObj.consistency),
1135
+ medianSulcus: dreSelectStr(drObj.medianSulcus),
1136
+ tenderness: bool(drObj.tenderness)
1137
+ };
1138
+ const examinationNotes = str(r.examinationNotes);
1139
+ return {
1140
+ regions,
1141
+ general,
1142
+ abdomen,
1143
+ gu,
1144
+ dre,
1145
+ examinationNotes
1146
+ };
1147
+ }
1148
+ function normalizeUrologyPathway(raw) {
1149
+ const base = defaultUrologyPathway();
1150
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return base;
1151
+ const r = raw;
1152
+ const stoneSizeMm = nonNegInt(r.stoneSizeMm);
1153
+ const hydronephrosis = bool(r.hydronephrosis);
1154
+ const prostateVolumeCc = Math.max(0, Number(r.prostateVolumeCc) || 0);
1155
+ const psaNgMl = Math.max(0, Number(r.psaNgMl) || 0);
1156
+ const uroflowQmaxMlSec = Math.max(0, Number(r.uroflowQmaxMlSec) || 0);
1157
+ const riskRaw = r.risk && typeof r.risk === "object" && !Array.isArray(r.risk) ? r.risk : {};
1158
+ const rk = riskRaw;
1159
+ const risk = {
1160
+ ckd: bool(rk.ckd),
1161
+ diabetes: bool(rk.diabetes),
1162
+ anticoagulants: bool(rk.anticoagulants),
1163
+ activeInfection: bool(rk.activeInfection)
1164
+ };
1165
+ return {
1166
+ stoneSizeMm,
1167
+ hydronephrosis,
1168
+ prostateVolumeCc,
1169
+ psaNgMl,
1170
+ uroflowQmaxMlSec,
1171
+ risk
1172
+ };
1173
+ }
1174
+
736
1175
  // src/core/painScaleFlags.ts
737
1176
  function normalizePainScaleFlags(raw, bounds) {
738
1177
  const min = bounds?.min ?? 0;
@@ -845,6 +1284,12 @@ var FormStore = class {
845
1284
  values[field.id] = field.defaultValue ?? defaultGeneralSurgeryExamination();
846
1285
  } else if (field.type === "general_surgery_grading") {
847
1286
  values[field.id] = field.defaultValue ?? defaultGeneralSurgeryGrading();
1287
+ } else if (field.type === "urology_smart_history") {
1288
+ values[field.id] = field.defaultValue ?? defaultUrologySmartHistory();
1289
+ } else if (field.type === "urology_examination") {
1290
+ values[field.id] = field.defaultValue ?? defaultUrologyExamination();
1291
+ } else if (field.type === "urology_pathway") {
1292
+ values[field.id] = field.defaultValue ?? defaultUrologyPathway();
848
1293
  } else if (field.type === "pain_scale_flags") {
849
1294
  const f = field;
850
1295
  values[field.id] = normalizePainScaleFlags(
@@ -8558,26 +9003,11 @@ var DischargeMedicationOrdersWidget = ({ fieldId }) => {
8558
9003
  showError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-red-500", children: error })
8559
9004
  ] });
8560
9005
  };
8561
- var DEFAULT_TOKEN_SEPARATOR = ", ";
9006
+ var DEFAULT_TOKEN_SEPARATOR2 = ", ";
8562
9007
  function getAppendSeparator(def) {
8563
- const raw = def.meta && typeof def.meta.appendSeparator === "string" ? def.meta.appendSeparator : DEFAULT_TOKEN_SEPARATOR;
9008
+ const raw = def.meta && typeof def.meta.appendSeparator === "string" ? def.meta.appendSeparator : DEFAULT_TOKEN_SEPARATOR2;
8564
9009
  return raw;
8565
9010
  }
8566
- function getSuggestionTokensFromText(text) {
8567
- return text.split(",").map((p) => p.trim()).filter(Boolean);
8568
- }
8569
- function toggleSuggestionTokenInText(current, token, separator = DEFAULT_TOKEN_SEPARATOR) {
8570
- const t = String(token).trim();
8571
- if (!t) return current;
8572
- const parts = getSuggestionTokensFromText(current);
8573
- const i = parts.findIndex((p) => p === t);
8574
- if (i >= 0) {
8575
- parts.splice(i, 1);
8576
- } else {
8577
- parts.push(t);
8578
- }
8579
- return parts.join(separator);
8580
- }
8581
9011
  function isTokenSelected(text, optionValue) {
8582
9012
  const t = String(optionValue).trim();
8583
9013
  if (!t) return false;
@@ -8651,8 +9081,11 @@ var SuggestionTextareaWidget = ({ fieldId }) => {
8651
9081
  setOptions([]);
8652
9082
  }
8653
9083
  }, [def]);
9084
+ const chipAllowedSet = React15.useMemo(
9085
+ () => new Set(options.map((o) => String(o.value).trim()).filter(Boolean)),
9086
+ [options]
9087
+ );
8654
9088
  React15.useEffect(() => {
8655
- if (!parallelChipFieldId || !def) return;
8656
9089
  const parallelDef = store.getFieldDef(parallelChipFieldId);
8657
9090
  if (!parallelDef || parallelDef.type !== "multiselect") return;
8658
9091
  const next = deriveKnownSuggestionChipValues(textValue, options);
@@ -8678,7 +9111,7 @@ var SuggestionTextareaWidget = ({ fieldId }) => {
8678
9111
  const labelEl = theme ? /* @__PURE__ */ jsxRuntime.jsx(Label, { className: labelClass, children: labelContent }) : /* @__PURE__ */ jsxRuntime.jsx(Label, { children: labelContent });
8679
9112
  const onChipClick = (optValue) => {
8680
9113
  if (disabled) return;
8681
- setValue(toggleSuggestionTokenInText(textValue, String(optValue), appendSeparator));
9114
+ setValue(toggleSuggestionTokenInText(textValue, String(optValue), appendSeparator, chipAllowedSet));
8682
9115
  };
8683
9116
  const hasSuggestions = options.length > 0;
8684
9117
  const hasEmbedded = embeddedFieldIds.length > 0;
@@ -9117,7 +9550,7 @@ var EMPTY = {
9117
9550
  specularMicroscopyDone: false,
9118
9551
  endothelialCount: ""
9119
9552
  };
9120
- function str(x) {
9553
+ function str2(x) {
9121
9554
  return typeof x === "string" ? x : "";
9122
9555
  }
9123
9556
  function parseValue2(raw) {
@@ -9125,24 +9558,24 @@ function parseValue2(raw) {
9125
9558
  const o = raw;
9126
9559
  const m = o.method;
9127
9560
  const method = m === "ascan_immersion" || m === "ascan_contact" || m === "optical_biometry" ? m : "optical_biometry";
9128
- const formula = str(o.formula);
9561
+ const formula = str2(o.formula);
9129
9562
  return {
9130
9563
  ...EMPTY,
9131
- axialLengthOD: str(o.axialLengthOD),
9132
- axialLengthOS: str(o.axialLengthOS),
9133
- k1k2AxisOD: str(o.k1k2AxisOD),
9134
- k1k2AxisOS: str(o.k1k2AxisOS),
9135
- anteriorChamberDepthOD: str(o.anteriorChamberDepthOD),
9136
- anteriorChamberDepthOS: str(o.anteriorChamberDepthOS),
9137
- iolPowerOD: str(o.iolPowerOD),
9138
- iolPowerOS: str(o.iolPowerOS),
9139
- targetRefractionOD: str(o.targetRefractionOD),
9140
- targetRefractionOS: str(o.targetRefractionOS),
9564
+ axialLengthOD: str2(o.axialLengthOD),
9565
+ axialLengthOS: str2(o.axialLengthOS),
9566
+ k1k2AxisOD: str2(o.k1k2AxisOD),
9567
+ k1k2AxisOS: str2(o.k1k2AxisOS),
9568
+ anteriorChamberDepthOD: str2(o.anteriorChamberDepthOD),
9569
+ anteriorChamberDepthOS: str2(o.anteriorChamberDepthOS),
9570
+ iolPowerOD: str2(o.iolPowerOD),
9571
+ iolPowerOS: str2(o.iolPowerOS),
9572
+ targetRefractionOD: str2(o.targetRefractionOD),
9573
+ targetRefractionOS: str2(o.targetRefractionOS),
9141
9574
  formula: formula || "SRK/T",
9142
9575
  method,
9143
9576
  cornealTopoUploaded: o.cornealTopoUploaded === true,
9144
9577
  specularMicroscopyDone: o.specularMicroscopyDone === true,
9145
- endothelialCount: str(o.endothelialCount)
9578
+ endothelialCount: str2(o.endothelialCount)
9146
9579
  };
9147
9580
  }
9148
9581
  var paramCell = "emr-biometry-param text-[11px] font-semibold leading-snug text-foreground sm:text-xs py-2";
@@ -10613,172 +11046,1020 @@ var PainScaleFlagsWidget = ({ fieldId }) => {
10613
11046
  showError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-red-500", children: error })
10614
11047
  ] });
10615
11048
  };
10616
- var FieldRenderer = ({ fieldId }) => {
10617
- const { fieldDef, visible } = useField(fieldId);
10618
- if (!visible || !fieldDef) {
10619
- return null;
10620
- }
10621
- return renderWidget(fieldId, fieldDef);
11049
+ var CHIEF_CHIPS_FIELD3 = "chief_complaints_chips";
11050
+ var ACTIVE_SYNDROME_FIELD = "uro_active_syndrome";
11051
+ var CHIEF_TEXT_FIELD = "chief_complaints";
11052
+ var SYMPTOMS_FIELD = "symptoms";
11053
+ var DIAGNOSIS_FIELD = "diagnosis";
11054
+ var URO_DURATION_FIELD = "uro_chief_duration";
11055
+ var URO_ONSET_FIELD = "uro_chief_onset";
11056
+ var URO_PROGRESSION_FIELD = "uro_chief_progression";
11057
+ var SYNDROME_LABELS = {
11058
+ luts: "LUTS / BPH",
11059
+ stone: "Urolithiasis (stone)",
11060
+ haematuria: "Haematuria",
11061
+ scrotal: "Scrotal swelling",
11062
+ retention: "Acute retention",
11063
+ ed_infertility: "ED / Infertility",
11064
+ uti: "UTI / infection"
10622
11065
  };
10623
- function renderWidget(fieldId, fieldDef) {
10624
- switch (fieldDef.type) {
10625
- case "text":
10626
- case "number":
10627
- return /* @__PURE__ */ jsxRuntime.jsx(TextWidget, { fieldId });
10628
- case "slider":
10629
- return /* @__PURE__ */ jsxRuntime.jsx(SliderWidget, { fieldId });
10630
- case "textarea":
10631
- if (fieldMetaRequestsMarMedicationOrdersButton(fieldDef.meta)) {
10632
- return /* @__PURE__ */ jsxRuntime.jsx(MarMedicationOrdersWidget, { fieldId });
10633
- }
10634
- return /* @__PURE__ */ jsxRuntime.jsx(TextWidget, { fieldId });
10635
- case "richtext":
10636
- return /* @__PURE__ */ jsxRuntime.jsx(RichTextWidget, { fieldId });
10637
- case "date":
10638
- return /* @__PURE__ */ jsxRuntime.jsx(DateWidget, { fieldId });
10639
- case "datetime":
10640
- return /* @__PURE__ */ jsxRuntime.jsx(DateTimeWidget, { fieldId });
10641
- case "select":
10642
- return /* @__PURE__ */ jsxRuntime.jsx(SelectWidget, { fieldId });
10643
- case "radio":
10644
- return /* @__PURE__ */ jsxRuntime.jsx(RadioWidget, { fieldId });
10645
- case "checkbox":
10646
- return /* @__PURE__ */ jsxRuntime.jsx(CheckboxWidget, { fieldId });
10647
- case "multiselect":
10648
- return /* @__PURE__ */ jsxRuntime.jsx(MultiSelectWidget, { fieldId });
10649
- case "repeatable":
10650
- return /* @__PURE__ */ jsxRuntime.jsx(RepeatableWidget, { fieldId });
10651
- case "image_upload":
10652
- return /* @__PURE__ */ jsxRuntime.jsx(ImageUploadWidget, { fieldId });
10653
- case "media_upload":
10654
- return /* @__PURE__ */ jsxRuntime.jsx(MediaUploadWidget, { fieldId });
10655
- case "signature":
10656
- return /* @__PURE__ */ jsxRuntime.jsx(SignatureUploadWidget, { fieldId });
10657
- case "editable_table":
10658
- return /* @__PURE__ */ jsxRuntime.jsx(EditableTableWidget, { fieldId });
10659
- case "medications":
10660
- return /* @__PURE__ */ jsxRuntime.jsx(AddMedicationWidget, { fieldId });
10661
- case "discharge_medication_orders":
10662
- return /* @__PURE__ */ jsxRuntime.jsx(DischargeMedicationOrdersWidget, { fieldId });
10663
- case "investigations":
10664
- return /* @__PURE__ */ jsxRuntime.jsx(AddInvestigationWidget, { fieldId });
10665
- case "procedures":
10666
- return /* @__PURE__ */ jsxRuntime.jsx(AddProcedureWidget, { fieldId });
10667
- case "differential_diagnosis":
10668
- return /* @__PURE__ */ jsxRuntime.jsx(DifferentialDiagnosisWidget, { fieldId });
10669
- case "vitals":
10670
- return /* @__PURE__ */ jsxRuntime.jsx(VitalsWidget, { fieldId });
10671
- case "hidden_vitals":
10672
- return /* @__PURE__ */ jsxRuntime.jsx(HiddenVitalsWidget, { fieldId });
10673
- case "referral":
10674
- return /* @__PURE__ */ jsxRuntime.jsx(ReferralWidget, { fieldId });
10675
- case "followup":
10676
- return /* @__PURE__ */ jsxRuntime.jsx(FollowupWidget, { fieldId });
10677
- case "smart_textarea":
10678
- return /* @__PURE__ */ jsxRuntime.jsx(SmartTextareaWidget, { fieldId });
10679
- case "diagnosis_textarea":
10680
- return /* @__PURE__ */ jsxRuntime.jsx(DiagnosisTextareaWidget, { fieldId });
10681
- case "obstetric_history":
10682
- return /* @__PURE__ */ jsxRuntime.jsx(ObstetricHistoryWidget, { fieldId });
10683
- case "eye_prescription":
10684
- return /* @__PURE__ */ jsxRuntime.jsx(OphthalmologyWidget, { fieldId });
10685
- case "ophthal_diagnosis":
10686
- return /* @__PURE__ */ jsxRuntime.jsx(OphthalDiagnosisWidget, { fieldId });
10687
- case "orthopedic_exam":
10688
- return /* @__PURE__ */ jsxRuntime.jsx(OrthopedicExamWidget, { fieldId });
10689
- case "general_surgery_smart_history":
10690
- return /* @__PURE__ */ jsxRuntime.jsx(GsSmartHistoryWidget, { fieldId });
10691
- case "general_surgery_examination":
10692
- return /* @__PURE__ */ jsxRuntime.jsx(GsExaminationWidget, { fieldId });
10693
- case "general_surgery_grading":
10694
- return /* @__PURE__ */ jsxRuntime.jsx(GsGradingWidget, { fieldId });
10695
- case "pain_scale_flags":
10696
- return /* @__PURE__ */ jsxRuntime.jsx(PainScaleFlagsWidget, { fieldId });
10697
- case "toggle": {
10698
- const { value, setValue, setTouched, disabled } = useField(fieldId);
10699
- const store = useFormStore();
10700
- const excludes = fieldDef.excludes ?? [];
10701
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
10702
- /* @__PURE__ */ jsxRuntime.jsx(
10703
- Switch,
10704
- {
10705
- checked: value === true,
10706
- disabled,
10707
- onCheckedChange: (checked) => {
10708
- setValue(checked);
10709
- setTouched();
10710
- if (checked) excludes.forEach((id) => store.setValue(id, false));
10711
- }
10712
- }
10713
- ),
10714
- /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "text-sm font-medium leading-none cursor-pointer select-none", children: fieldDef.label })
10715
- ] });
10716
- }
10717
- case "suggestion_textarea":
10718
- case "complaint_chips":
10719
- return /* @__PURE__ */ jsxRuntime.jsx(SuggestionTextareaWidget, { fieldId });
10720
- case "lens_assessment":
10721
- return /* @__PURE__ */ jsxRuntime.jsx(LensAssessmentWidget, { fieldId });
10722
- case "functional_impairment_score":
10723
- return /* @__PURE__ */ jsxRuntime.jsx(FunctionalImpairmentScoreWidget, { fieldId });
10724
- case "biometry_iol_workup":
10725
- return /* @__PURE__ */ jsxRuntime.jsx(BiometryIolWorkupWidget, { fieldId });
10726
- case "surgical_risk_flags":
10727
- return /* @__PURE__ */ jsxRuntime.jsx(SurgicalRiskFlagsWidget, { fieldId });
10728
- case "static_text": {
10729
- const def = fieldDef;
10730
- const size = def.size ?? "regular";
10731
- const labelClass = size === "large" ? "text-base" : "text-sm";
10732
- const descClass = size === "large" ? "text-sm" : "text-xs";
10733
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${labelClass} text-muted-foreground`, children: [
10734
- def.label,
10735
- def.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: `mt-1 ${descClass} opacity-90`, children: def.description })
10736
- ] });
10737
- }
10738
- default:
10739
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-red-500", children: [
10740
- "Unknown field type: ",
10741
- fieldDef.type
10742
- ] });
10743
- }
11066
+ function chipList2(state) {
11067
+ const raw = state.values[CHIEF_CHIPS_FIELD3];
11068
+ return Array.isArray(raw) ? raw.filter((x) => typeof x === "string") : [];
10744
11069
  }
10745
- var Section = ({ title, children }) => {
10746
- const [expanded, setExpanded] = React15.useState(true);
10747
- const handleToggle = () => setExpanded((prev) => !prev);
10748
- const contentClassName = cn(
10749
- "overflow-hidden transition-[height] duration-200 ease-in-out",
10750
- !expanded && "hidden"
10751
- );
10752
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-6 border rounded-lg bg-white shadow-sm overflow-hidden", children: [
10753
- /* @__PURE__ */ jsxRuntime.jsxs(
10754
- "button",
10755
- {
10756
- type: "button",
10757
- onClick: handleToggle,
10758
- className: "w-full flex items-center justify-between gap-2 p-4 text-left border-b hover:bg-gray-50/80 transition-colors",
10759
- children: [
10760
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-medium", children: title }),
10761
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0 text-muted-foreground", "aria-hidden": true, children: expanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-5 w-5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-5 w-5" }) })
10762
- ]
10763
- }
10764
- ),
10765
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: contentClassName, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 pt-4 space-y-4 border-t-0", children }) })
10766
- ] });
11070
+ function str3(x) {
11071
+ return typeof x === "string" ? x : "";
11072
+ }
11073
+ function chiefOptionalFieldDisplay(x) {
11074
+ const s = str3(x).trim();
11075
+ if (!s || s.toLowerCase() === "none") return "";
11076
+ return s;
11077
+ }
11078
+ function nonEmptyLines(lines) {
11079
+ return lines.map((s) => (s ?? "").trim()).filter(Boolean);
11080
+ }
11081
+ var IPSS_LABELS = {
11082
+ incomplete: "Incomplete emptying",
11083
+ frequency: "Frequency (<2h)",
11084
+ intermittency: "Intermittency",
11085
+ urgency: "Urgency",
11086
+ weakStream: "Weak stream",
11087
+ straining: "Straining",
11088
+ nocturia: "Nocturia (\xD7/night)"
10767
11089
  };
10768
- var ColumnLayout = ({
10769
- columns,
10770
- label,
11090
+ var SOCRATES_KEYS2 = [
11091
+ "site",
11092
+ "onset",
11093
+ "character",
11094
+ "radiation",
11095
+ "associated",
11096
+ "timing",
11097
+ "exacerbating"
11098
+ ];
11099
+ function Panel2({
11100
+ title,
11101
+ right,
10771
11102
  children
10772
- }) => {
10773
- const gridCols = Math.max(1, Math.min(columns, 12));
10774
- const gridClass = `grid gap-4 w-full`;
10775
- const style = {
10776
- gridTemplateColumns: `repeat(${gridCols}, minmax(0, 1fr))`
10777
- };
10778
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-6", children: [
10779
- label != null && label !== "" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-2 text-sm font-medium text-gray-700", children: label }),
10780
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: gridClass, style, children })
10781
- ] });
11103
+ }) {
11104
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "overflow-hidden rounded-md border border-[#D0D0D0] bg-white", children: [
11105
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between border-b border-[#D0D0D0] bg-[#FEE8EC]/50 px-3 py-1.5", children: [
11106
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-semibold text-slate-700", children: title }),
11107
+ right
11108
+ ] }),
11109
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3", children })
11110
+ ] });
11111
+ }
11112
+ var UrologySmartHistoryWidget = ({ fieldId }) => {
11113
+ const { fieldDef, value, setValue, setTouched, error, touched, disabled } = useField(fieldId);
11114
+ const hopcField = useField(SYMPTOMS_FIELD);
11115
+ const syndromeField = useField(ACTIVE_SYNDROME_FIELD);
11116
+ const { state } = useForm();
11117
+ const store = useFormStore();
11118
+ const showError = !!error && (touched || state.submitAttempted);
11119
+ const safe = React15.useMemo(() => normalizeUrologySmartHistory(value), [value]);
11120
+ const chips = React15.useMemo(() => chipList2(state), [state]);
11121
+ const rawSyndrome = syndromeField.value ?? state.values[ACTIVE_SYNDROME_FIELD];
11122
+ const syndrome = typeof rawSyndrome === "string" && rawSyndrome !== "" && rawSyndrome !== "none" ? rawSyndrome : "none";
11123
+ const showPain = chips.includes("pain abdomen flank") || chips.includes("scrotal swelling pain") || syndrome === "stone" || syndrome === "scrotal";
11124
+ const showLUTS = syndrome === "luts" || syndrome === "retention" || chips.includes("frequency urgency") || chips.includes("poor stream") || chips.includes("acute retention");
11125
+ const showHaem = syndrome === "haematuria" || chips.includes("haematuria");
11126
+ const showSex = syndrome === "ed_infertility" || chips.includes("erectile dysfunction") || chips.includes("infertility concern");
11127
+ const update = (next) => {
11128
+ setValue(next);
11129
+ setTouched();
11130
+ };
11131
+ const ipssTotal = urologyIpssSevenTotal(safe.ipss);
11132
+ const ipssBandLabel = urologyIpssBand(ipssTotal);
11133
+ 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";
11134
+ const setSocrates = (key, v) => {
11135
+ if (key === "severity") {
11136
+ const n = typeof v === "number" ? v : Number(v);
11137
+ const sev = Number.isFinite(n) ? Math.min(10, Math.max(0, Math.round(n))) : 0;
11138
+ update({ ...safe, socrates: { ...safe.socrates, severity: sev } });
11139
+ return;
11140
+ }
11141
+ update({ ...safe, socrates: { ...safe.socrates, [key]: String(v) } });
11142
+ };
11143
+ const setIpss = (key, v) => {
11144
+ update({ ...safe, ipss: { ...safe.ipss, [key]: v } });
11145
+ };
11146
+ const [hopcNarrativeLocked, setHopcNarrativeLocked] = React15.useState(false);
11147
+ React15.useEffect(() => {
11148
+ if (hopcNarrativeLocked || disabled) return;
11149
+ const next = formatUrologySmartHistoryToSymptomsNarrative(normalizeUrologySmartHistory(value), {
11150
+ showPain,
11151
+ showLUTS,
11152
+ showHaem,
11153
+ showSex
11154
+ });
11155
+ hopcField.setValue(next);
11156
+ }, [value, hopcNarrativeLocked, showPain, showLUTS, showHaem, showSex, disabled]);
11157
+ React15.useEffect(() => {
11158
+ if (disabled) return;
11159
+ const label = syndrome && syndrome !== "none" ? SYNDROME_LABELS[syndrome] ?? syndrome : "";
11160
+ const prev = store.getFieldState(DIAGNOSIS_FIELD)?.value;
11161
+ const prevText = typeof prev === "string" ? prev : "";
11162
+ const syndromeLabels = new Set(Object.values(SYNDROME_LABELS));
11163
+ const keptLines = prevText.split("\n").map((l) => l.trim()).filter(Boolean).filter((l) => !syndromeLabels.has(l));
11164
+ const nextLines = label ? [...keptLines, label] : keptLines;
11165
+ const next = nextLines.join("\n");
11166
+ if (prevText.trim() === next.trim()) return;
11167
+ store.setValues({ [DIAGNOSIS_FIELD]: next }, { touch: false });
11168
+ }, [disabled, store, syndrome]);
11169
+ React15.useEffect(() => {
11170
+ if (disabled) return;
11171
+ const duration = chiefOptionalFieldDisplay(state.values[URO_DURATION_FIELD]);
11172
+ const onset = chiefOptionalFieldDisplay(state.values[URO_ONSET_FIELD]);
11173
+ const progression = chiefOptionalFieldDisplay(state.values[URO_PROGRESSION_FIELD]);
11174
+ const prev = store.getFieldState(CHIEF_TEXT_FIELD)?.value;
11175
+ const prevText = typeof prev === "string" ? prev : "";
11176
+ const kept = prevText.split(",").map((t) => t.trim()).filter(Boolean).filter((t) => {
11177
+ const lower = t.toLowerCase();
11178
+ return !lower.startsWith("duration:") && !lower.startsWith("onset:") && !lower.startsWith("progression:");
11179
+ });
11180
+ const extra = nonEmptyLines([
11181
+ duration ? `Duration: ${duration}` : "",
11182
+ onset ? `Onset: ${onset}` : "",
11183
+ progression ? `Progression: ${progression}` : ""
11184
+ ]);
11185
+ const next = [...kept, ...extra].join(", ").trim();
11186
+ if (prevText.trim() === next.trim()) return;
11187
+ store.setValues({ [CHIEF_TEXT_FIELD]: next }, { touch: false });
11188
+ }, [
11189
+ disabled,
11190
+ state.values[URO_DURATION_FIELD],
11191
+ state.values[URO_ONSET_FIELD],
11192
+ state.values[URO_PROGRESSION_FIELD],
11193
+ store
11194
+ ]);
11195
+ if (!fieldDef) return null;
11196
+ const theme = getThemeConfig("textarea", fieldDef.theme);
11197
+ const wrapperClass = theme?.wrapperClassName ?? "rounded-md overflow-hidden flex flex-col border border-[#D0D0D0]";
11198
+ const labelClass = theme?.labelClassName;
11199
+ const labelContent = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
11200
+ fieldDef.label,
11201
+ fieldDef.required ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1 text-red-500", children: "*" }) : null
11202
+ ] });
11203
+ const labelEl = theme ? /* @__PURE__ */ jsxRuntime.jsx(Label, { className: labelClass, children: labelContent }) : /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "text-sm font-medium", children: labelContent });
11204
+ const bodyClass = cn(
11205
+ "-mt-1 flex min-w-0 flex-col gap-3 border-t border-[#D0D0D0] bg-white px-3 py-3",
11206
+ disabled && "pointer-events-none opacity-60"
11207
+ );
11208
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("w-full min-w-0", wrapperClass), children: [
11209
+ labelEl,
11210
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: bodyClass, children: [
11211
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] text-muted-foreground", children: "Panels follow chief complaint chips and active syndrome (Clearsight SmartHistoryUro)." }),
11212
+ showPain ? /* @__PURE__ */ jsxRuntime.jsx(Panel2, { title: "SOCRATES \u2014 Pain (flank / suprapubic / testicular)", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-2 md:grid-cols-4", children: [
11213
+ SOCRATES_KEYS2.map((k) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
11214
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: k }),
11215
+ /* @__PURE__ */ jsxRuntime.jsx(
11216
+ Input,
11217
+ {
11218
+ className: "h-8 text-xs",
11219
+ value: safe.socrates[k],
11220
+ onChange: (e) => setSocrates(k, e.target.value),
11221
+ placeholder: k === "radiation" ? "e.g. groin \u2192 ureteric" : k === "character" ? "colicky / dull" : "",
11222
+ disabled
11223
+ }
11224
+ )
11225
+ ] }, k)),
11226
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
11227
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: "Severity 0\u201310" }),
11228
+ /* @__PURE__ */ jsxRuntime.jsx(
11229
+ Input,
11230
+ {
11231
+ type: "number",
11232
+ min: 0,
11233
+ max: 10,
11234
+ className: "h-8 text-xs",
11235
+ value: safe.socrates.severity,
11236
+ onChange: (e) => setSocrates("severity", e.target.value),
11237
+ disabled
11238
+ }
11239
+ )
11240
+ ] })
11241
+ ] }) }) : null,
11242
+ showLUTS ? /* @__PURE__ */ jsxRuntime.jsxs(
11243
+ Panel2,
11244
+ {
11245
+ title: "IPSS \u2014 International Prostate Symptom Score",
11246
+ right: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `rounded-full px-2 py-0.5 text-[10px] font-medium ${bandClass}`, children: [
11247
+ ipssTotal,
11248
+ "/35 \u2014 ",
11249
+ ipssBandLabel
11250
+ ] }),
11251
+ children: [
11252
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-2 md:grid-cols-4", children: [
11253
+ Object.keys(IPSS_LABELS).map((k) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
11254
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] uppercase tracking-wide text-muted-foreground", children: IPSS_LABELS[k] }),
11255
+ /* @__PURE__ */ jsxRuntime.jsxs(
11256
+ Select,
11257
+ {
11258
+ value: String(safe.ipss[k]),
11259
+ onValueChange: (val) => setIpss(k, Number(val)),
11260
+ disabled,
11261
+ children: [
11262
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, {}) }),
11263
+ /* @__PURE__ */ jsxRuntime.jsx(SelectContent, { children: [0, 1, 2, 3, 4, 5].map((n) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: String(n), children: n }, n)) })
11264
+ ]
11265
+ }
11266
+ )
11267
+ ] }, k)),
11268
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
11269
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] uppercase tracking-wide text-muted-foreground", children: "QoL (0\u20136)" }),
11270
+ /* @__PURE__ */ jsxRuntime.jsxs(
11271
+ Select,
11272
+ {
11273
+ value: String(safe.ipssQoL),
11274
+ onValueChange: (val) => update({ ...safe, ipssQoL: Math.min(6, Math.max(0, Number(val))) }),
11275
+ disabled,
11276
+ children: [
11277
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, {}) }),
11278
+ /* @__PURE__ */ jsxRuntime.jsx(SelectContent, { children: [0, 1, 2, 3, 4, 5, 6].map((n) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: String(n), children: n }, n)) })
11279
+ ]
11280
+ }
11281
+ )
11282
+ ] })
11283
+ ] }),
11284
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-2 text-[10px] text-muted-foreground", children: [
11285
+ "Bands: 0\u20137 mild \xB7 8\u201319 moderate \xB7 20\u201335 severe.",
11286
+ " ",
11287
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-foreground", children: "IPSS \u2265 20 \u2192 consider surgical intervention." })
11288
+ ] })
11289
+ ]
11290
+ }
11291
+ ) : null,
11292
+ showHaem ? /* @__PURE__ */ jsxRuntime.jsxs(Panel2, { title: "Haematuria profile", children: [
11293
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-3 text-xs md:grid-cols-4", children: [
11294
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
11295
+ /* @__PURE__ */ jsxRuntime.jsx(
11296
+ Checkbox,
11297
+ {
11298
+ checked: safe.haematuria.present,
11299
+ onCheckedChange: (c) => update({
11300
+ ...safe,
11301
+ haematuria: { ...safe.haematuria, present: c === true }
11302
+ }),
11303
+ disabled
11304
+ }
11305
+ ),
11306
+ "Present"
11307
+ ] }),
11308
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1", children: [
11309
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Timing" }),
11310
+ /* @__PURE__ */ jsxRuntime.jsxs(
11311
+ Select,
11312
+ {
11313
+ value: safe.haematuria.timing || "none",
11314
+ onValueChange: (val) => update({
11315
+ ...safe,
11316
+ haematuria: { ...safe.haematuria, timing: val === "none" ? "" : val }
11317
+ }),
11318
+ disabled,
11319
+ children: [
11320
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "\u2014" }) }),
11321
+ /* @__PURE__ */ jsxRuntime.jsxs(SelectContent, { children: [
11322
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "none", children: "\u2014" }),
11323
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "Initial", children: "Initial" }),
11324
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "Terminal", children: "Terminal" }),
11325
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "Total", children: "Total" })
11326
+ ] })
11327
+ ]
11328
+ }
11329
+ )
11330
+ ] }),
11331
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
11332
+ /* @__PURE__ */ jsxRuntime.jsx(
11333
+ Checkbox,
11334
+ {
11335
+ checked: safe.haematuria.painful,
11336
+ onCheckedChange: (c) => update({ ...safe, haematuria: { ...safe.haematuria, painful: c === true } }),
11337
+ disabled
11338
+ }
11339
+ ),
11340
+ "Painful"
11341
+ ] }),
11342
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
11343
+ /* @__PURE__ */ jsxRuntime.jsx(
11344
+ Checkbox,
11345
+ {
11346
+ checked: safe.haematuria.clots,
11347
+ onCheckedChange: (c) => update({ ...safe, haematuria: { ...safe.haematuria, clots: c === true } }),
11348
+ disabled
11349
+ }
11350
+ ),
11351
+ "Clots"
11352
+ ] })
11353
+ ] }),
11354
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-[10px] text-red-600", children: "Painless haematuria = malignancy until proven otherwise." })
11355
+ ] }) : null,
11356
+ showSex ? /* @__PURE__ */ jsxRuntime.jsx(Panel2, { title: "Sexual & reproductive history", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-3 text-xs md:grid-cols-4", children: [
11357
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1", children: [
11358
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Erectile function" }),
11359
+ /* @__PURE__ */ jsxRuntime.jsxs(
11360
+ Select,
11361
+ {
11362
+ value: safe.sexual.erectile || "none",
11363
+ onValueChange: (val) => update({
11364
+ ...safe,
11365
+ sexual: { ...safe.sexual, erectile: val === "none" ? "" : val }
11366
+ }),
11367
+ disabled,
11368
+ children: [
11369
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "\u2014" }) }),
11370
+ /* @__PURE__ */ jsxRuntime.jsxs(SelectContent, { children: [
11371
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "none", children: "\u2014" }),
11372
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "Normal", children: "Normal" }),
11373
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "Mild", children: "Mild" }),
11374
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "Moderate", children: "Moderate" }),
11375
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "Severe", children: "Severe" })
11376
+ ] })
11377
+ ]
11378
+ }
11379
+ )
11380
+ ] }),
11381
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1", children: [
11382
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Libido" }),
11383
+ /* @__PURE__ */ jsxRuntime.jsxs(
11384
+ Select,
11385
+ {
11386
+ value: safe.sexual.libido || "none",
11387
+ onValueChange: (val) => update({
11388
+ ...safe,
11389
+ sexual: { ...safe.sexual, libido: val === "none" ? "" : val }
11390
+ }),
11391
+ disabled,
11392
+ children: [
11393
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "\u2014" }) }),
11394
+ /* @__PURE__ */ jsxRuntime.jsxs(SelectContent, { children: [
11395
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "none", children: "\u2014" }),
11396
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "Normal", children: "Normal" }),
11397
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "Reduced", children: "Reduced" })
11398
+ ] })
11399
+ ]
11400
+ }
11401
+ )
11402
+ ] }),
11403
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1", children: [
11404
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Ejaculation" }),
11405
+ /* @__PURE__ */ jsxRuntime.jsxs(
11406
+ Select,
11407
+ {
11408
+ value: safe.sexual.ejaculation || "none",
11409
+ onValueChange: (val) => update({
11410
+ ...safe,
11411
+ sexual: { ...safe.sexual, ejaculation: val === "none" ? "" : val }
11412
+ }),
11413
+ disabled,
11414
+ children: [
11415
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "\u2014" }) }),
11416
+ /* @__PURE__ */ jsxRuntime.jsxs(SelectContent, { children: [
11417
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "none", children: "\u2014" }),
11418
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "Normal", children: "Normal" }),
11419
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "Premature", children: "Premature" }),
11420
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "Retrograde", children: "Retrograde" }),
11421
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "Anejaculation", children: "Anejaculation" })
11422
+ ] })
11423
+ ]
11424
+ }
11425
+ )
11426
+ ] }),
11427
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1", children: [
11428
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Infertility (months)" }),
11429
+ /* @__PURE__ */ jsxRuntime.jsx(
11430
+ Input,
11431
+ {
11432
+ type: "number",
11433
+ min: 0,
11434
+ className: "h-8 text-xs",
11435
+ value: safe.sexual.infertilityMonths,
11436
+ onChange: (e) => update({
11437
+ ...safe,
11438
+ sexual: {
11439
+ ...safe.sexual,
11440
+ infertilityMonths: Math.max(0, Math.round(Number(e.target.value)) || 0)
11441
+ }
11442
+ }),
11443
+ disabled
11444
+ }
11445
+ )
11446
+ ] })
11447
+ ] }) }) : null,
11448
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
11449
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
11450
+ /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "text-xs font-semibold text-slate-700", children: hopcField.fieldDef?.label ?? "History of presenting complaint" }),
11451
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
11452
+ hopcNarrativeLocked ? /* @__PURE__ */ jsxRuntime.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: [
11453
+ "You edited this summary. Use",
11454
+ " ",
11455
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "italic", children: "'Regenerate'" }),
11456
+ " to update it from the form."
11457
+ ] }) : null,
11458
+ hopcNarrativeLocked ? /* @__PURE__ */ jsxRuntime.jsx(
11459
+ Button,
11460
+ {
11461
+ type: "button",
11462
+ variant: "outline",
11463
+ size: "sm",
11464
+ className: "h-7 shrink-0 px-2 text-xs",
11465
+ disabled: disabled || hopcField.disabled,
11466
+ onClick: () => {
11467
+ setHopcNarrativeLocked(false);
11468
+ hopcField.setValue(
11469
+ formatUrologySmartHistoryToSymptomsNarrative(
11470
+ normalizeUrologySmartHistory(value),
11471
+ { showPain, showLUTS, showHaem, showSex }
11472
+ )
11473
+ );
11474
+ },
11475
+ children: "Regenerate"
11476
+ }
11477
+ ) : null
11478
+ ] })
11479
+ ] }),
11480
+ hopcNarrativeLocked ? /* @__PURE__ */ jsxRuntime.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,
11481
+ /* @__PURE__ */ jsxRuntime.jsx(
11482
+ Textarea,
11483
+ {
11484
+ className: "min-h-[88px] rounded-md border border-input bg-white text-sm",
11485
+ placeholder: "Auto-filled from chief complaints + smart history\u2026",
11486
+ value: typeof hopcField.value === "string" ? hopcField.value : hopcField.value == null ? "" : String(hopcField.value),
11487
+ onChange: (e) => {
11488
+ setHopcNarrativeLocked(true);
11489
+ hopcField.setValue(e.target.value);
11490
+ hopcField.setTouched();
11491
+ },
11492
+ disabled: disabled || hopcField.disabled
11493
+ }
11494
+ )
11495
+ ] })
11496
+ ] }),
11497
+ showError ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-3 pb-2 text-xs text-red-500", children: error }) : null
11498
+ ] });
11499
+ };
11500
+ var URO_CLINICAL_EXAMINATION_FIELD = "clinical_examination";
11501
+ var GENERAL_ROWS = [
11502
+ { key: "pallor", label: "Pallor (chronic dz)" },
11503
+ { key: "oedema", label: "Oedema (renal)" },
11504
+ { key: "icterus", label: "Icterus" },
11505
+ { key: "lymphadenopathy", label: "Lymphadenopathy" }
11506
+ ];
11507
+ var ABD_ROWS = [
11508
+ { key: "distension", label: "Distension" },
11509
+ { key: "scars", label: "Surgical scars" },
11510
+ { key: "mass", label: "Visible mass" },
11511
+ { key: "kidneyPalpable", label: "Kidney palpable" },
11512
+ { key: "bladderPalpable", label: "Bladder palpable" },
11513
+ { key: "renalAngleTender", label: "Renal angle tender" },
11514
+ { key: "bladderDull", label: "Bladder dullness (retention)" }
11515
+ ];
11516
+ var GU_ROWS = [
11517
+ { key: "meatusAbnormal", label: "Meatus abnormal (hypospadias?)" },
11518
+ { key: "phimosis", label: "Phimosis / paraphimosis" },
11519
+ { key: "lesions", label: "Penile lesions / ulcers" },
11520
+ { key: "scrotalSwelling", label: "Scrotal swelling" },
11521
+ { key: "transilluminant", label: "Transilluminant" },
11522
+ { key: "tenderTestis", label: "Tender testis" },
11523
+ { key: "hydrocele", label: "Hydrocele" },
11524
+ { key: "varicocele", label: "Varicocele" },
11525
+ { key: "suspiciousMass", label: "Suspicious mass" }
11526
+ ];
11527
+ var DRE_CONSISTENCY = ["none", "Soft (benign)", "Firm", "Hard / nodular (malignancy?)"];
11528
+ var DRE_SULCUS = ["none", "Preserved", "Obliterated"];
11529
+ var UrologyExaminationWidget = ({ fieldId }) => {
11530
+ const { fieldDef, value, setValue, setTouched, error, touched, disabled } = useField(fieldId);
11531
+ const clinicalField = useField(URO_CLINICAL_EXAMINATION_FIELD);
11532
+ const { state } = useForm();
11533
+ const showError = !!error && (touched || state.submitAttempted);
11534
+ const safe = React15.useMemo(() => normalizeUrologyExamination(value), [value]);
11535
+ const [clinicalNarrativeLocked, setClinicalNarrativeLocked] = React15.useState(false);
11536
+ React15.useEffect(() => {
11537
+ if (clinicalNarrativeLocked || disabled) return;
11538
+ const norm = normalizeUrologyExamination(value);
11539
+ const next = formatUrologyExaminationToClinicalExamination(norm);
11540
+ clinicalField.setValue(next);
11541
+ if (norm.examinationNotes !== next) {
11542
+ setValue({ ...norm, examinationNotes: next });
11543
+ }
11544
+ }, [value, clinicalNarrativeLocked, disabled]);
11545
+ const bump = (next) => {
11546
+ setValue(next);
11547
+ setTouched();
11548
+ };
11549
+ const toggleGeneral = (key) => {
11550
+ bump({ ...safe, general: { ...safe.general, [key]: !safe.general[key] } });
11551
+ };
11552
+ const toggleAbdomen = (key) => {
11553
+ bump({ ...safe, abdomen: { ...safe.abdomen, [key]: !safe.abdomen[key] } });
11554
+ };
11555
+ const toggleGu = (key) => {
11556
+ bump({ ...safe, gu: { ...safe.gu, [key]: !safe.gu[key] } });
11557
+ };
11558
+ if (!fieldDef) return null;
11559
+ const theme = getThemeConfig("textarea", fieldDef.theme);
11560
+ const wrapperClass = theme?.wrapperClassName ?? "rounded-md overflow-hidden flex flex-col border border-[#D0D0D0]";
11561
+ const labelClass = theme?.labelClassName;
11562
+ const labelContent = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
11563
+ fieldDef.label,
11564
+ fieldDef.required ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1 text-red-500", children: "*" }) : null
11565
+ ] });
11566
+ const labelEl = theme ? /* @__PURE__ */ jsxRuntime.jsx(Label, { className: labelClass, children: labelContent }) : /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "text-sm font-medium", children: labelContent });
11567
+ const bodyClass = cn(
11568
+ "-mt-1 flex min-w-0 flex-col gap-3 border-t border-[#D0D0D0] bg-white px-3 py-3",
11569
+ disabled && "pointer-events-none opacity-60"
11570
+ );
11571
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("w-full min-w-0", wrapperClass), children: [
11572
+ labelEl,
11573
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: bodyClass, children: [
11574
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-3 text-xs md:grid-cols-2 xl:grid-cols-4", children: [
11575
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
11576
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold text-slate-800", children: "General" }),
11577
+ GENERAL_ROWS.map((r) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
11578
+ /* @__PURE__ */ jsxRuntime.jsx(
11579
+ Checkbox,
11580
+ {
11581
+ checked: safe.general[r.key],
11582
+ onCheckedChange: () => toggleGeneral(r.key),
11583
+ disabled
11584
+ }
11585
+ ),
11586
+ r.label
11587
+ ] }, r.key))
11588
+ ] }),
11589
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
11590
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold text-slate-800", children: "Abdomen" }),
11591
+ ABD_ROWS.map((r) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
11592
+ /* @__PURE__ */ jsxRuntime.jsx(
11593
+ Checkbox,
11594
+ {
11595
+ checked: safe.abdomen[r.key],
11596
+ onCheckedChange: () => toggleAbdomen(r.key),
11597
+ disabled
11598
+ }
11599
+ ),
11600
+ r.label
11601
+ ] }, r.key))
11602
+ ] }),
11603
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
11604
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold text-slate-800", children: "External genitalia / scrotum" }),
11605
+ GU_ROWS.map((r) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
11606
+ /* @__PURE__ */ jsxRuntime.jsx(
11607
+ Checkbox,
11608
+ {
11609
+ checked: safe.gu[r.key],
11610
+ onCheckedChange: () => toggleGu(r.key),
11611
+ disabled
11612
+ }
11613
+ ),
11614
+ r.key === "suspiciousMass" ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-red-600", children: r.label }) : r.label
11615
+ ] }, r.key))
11616
+ ] }),
11617
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
11618
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold text-slate-800", children: "DRE \u2014 Prostate" }),
11619
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
11620
+ /* @__PURE__ */ jsxRuntime.jsx(
11621
+ Checkbox,
11622
+ {
11623
+ checked: safe.dre.done,
11624
+ onCheckedChange: (c) => bump({ ...safe, dre: { ...safe.dre, done: c === true } }),
11625
+ disabled
11626
+ }
11627
+ ),
11628
+ "DRE performed"
11629
+ ] }),
11630
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block", children: [
11631
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-1 block font-medium", children: "Estimated size (g)" }),
11632
+ /* @__PURE__ */ jsxRuntime.jsx(
11633
+ Input,
11634
+ {
11635
+ type: "number",
11636
+ min: 0,
11637
+ className: "h-8 text-xs",
11638
+ value: safe.dre.sizeGrams,
11639
+ onChange: (e) => {
11640
+ const n = Number(e.target.value);
11641
+ bump({
11642
+ ...safe,
11643
+ dre: {
11644
+ ...safe.dre,
11645
+ sizeGrams: Number.isFinite(n) && n >= 0 ? Math.round(n) : 0
11646
+ }
11647
+ });
11648
+ },
11649
+ disabled
11650
+ }
11651
+ )
11652
+ ] }),
11653
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block", children: [
11654
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-1 block font-medium", children: "Consistency" }),
11655
+ /* @__PURE__ */ jsxRuntime.jsxs(
11656
+ Select,
11657
+ {
11658
+ value: safe.dre.consistency || "none",
11659
+ onValueChange: (val) => bump({
11660
+ ...safe,
11661
+ dre: { ...safe.dre, consistency: val === "none" ? "" : val }
11662
+ }),
11663
+ disabled,
11664
+ children: [
11665
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "\u2014" }) }),
11666
+ /* @__PURE__ */ jsxRuntime.jsx(SelectContent, { children: DRE_CONSISTENCY.map((opt) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: opt, children: opt === "none" ? "\u2014" : opt }, opt)) })
11667
+ ]
11668
+ }
11669
+ )
11670
+ ] }),
11671
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block", children: [
11672
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-1 block font-medium", children: "Median sulcus" }),
11673
+ /* @__PURE__ */ jsxRuntime.jsxs(
11674
+ Select,
11675
+ {
11676
+ value: safe.dre.medianSulcus || "none",
11677
+ onValueChange: (val) => bump({
11678
+ ...safe,
11679
+ dre: { ...safe.dre, medianSulcus: val === "none" ? "" : val }
11680
+ }),
11681
+ disabled,
11682
+ children: [
11683
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "\u2014" }) }),
11684
+ /* @__PURE__ */ jsxRuntime.jsx(SelectContent, { children: DRE_SULCUS.map((opt) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: opt, children: opt === "none" ? "\u2014" : opt }, opt)) })
11685
+ ]
11686
+ }
11687
+ )
11688
+ ] }),
11689
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
11690
+ /* @__PURE__ */ jsxRuntime.jsx(
11691
+ Checkbox,
11692
+ {
11693
+ checked: safe.dre.tenderness,
11694
+ onCheckedChange: (c) => bump({ ...safe, dre: { ...safe.dre, tenderness: c === true } }),
11695
+ disabled
11696
+ }
11697
+ ),
11698
+ "Tender (prostatitis?)"
11699
+ ] })
11700
+ ] })
11701
+ ] }),
11702
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
11703
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
11704
+ /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "text-xs font-semibold text-slate-700", children: clinicalField.fieldDef?.label ?? "Clinical examination" }),
11705
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
11706
+ clinicalNarrativeLocked ? /* @__PURE__ */ jsxRuntime.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: [
11707
+ "You edited this summary. Use",
11708
+ " ",
11709
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "italic", children: "'Regenerate'" }),
11710
+ " to update it from the form."
11711
+ ] }) : null,
11712
+ clinicalNarrativeLocked ? /* @__PURE__ */ jsxRuntime.jsx(
11713
+ Button,
11714
+ {
11715
+ type: "button",
11716
+ variant: "outline",
11717
+ size: "sm",
11718
+ className: "h-7 shrink-0 px-2 text-xs",
11719
+ disabled: disabled || clinicalField.disabled,
11720
+ onClick: () => {
11721
+ setClinicalNarrativeLocked(false);
11722
+ const norm = normalizeUrologyExamination(value);
11723
+ clinicalField.setValue(formatUrologyExaminationToClinicalExamination(norm));
11724
+ },
11725
+ children: "Regenerate"
11726
+ }
11727
+ ) : null
11728
+ ] })
11729
+ ] }),
11730
+ clinicalNarrativeLocked ? /* @__PURE__ */ jsxRuntime.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,
11731
+ /* @__PURE__ */ jsxRuntime.jsx(
11732
+ Textarea,
11733
+ {
11734
+ className: "min-h-[88px] rounded-md border border-input bg-white text-sm",
11735
+ placeholder: "Auto-filled from selections above\u2026",
11736
+ value: typeof clinicalField.value === "string" ? clinicalField.value : clinicalField.value == null ? "" : String(clinicalField.value),
11737
+ onChange: (e) => {
11738
+ setClinicalNarrativeLocked(true);
11739
+ const t = e.target.value;
11740
+ clinicalField.setValue(t);
11741
+ clinicalField.setTouched();
11742
+ setValue({ ...safe, examinationNotes: t });
11743
+ setTouched();
11744
+ },
11745
+ disabled: disabled || clinicalField.disabled
11746
+ }
11747
+ )
11748
+ ] })
11749
+ ] }),
11750
+ showError ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-3 pb-2 text-xs text-red-500", children: error }) : null
11751
+ ] });
11752
+ };
11753
+ var RISK_ROWS = [
11754
+ { key: "ckd", label: "Chronic kidney disease" },
11755
+ { key: "diabetes", label: "Diabetes" },
11756
+ { key: "anticoagulants", label: "Anticoagulants" },
11757
+ { key: "activeInfection", label: "Active infection" }
11758
+ ];
11759
+ var UrologyPathwayWidget = ({ fieldId }) => {
11760
+ const { fieldDef, value, setValue, setTouched, error, touched, disabled } = useField(fieldId);
11761
+ const { state } = useForm();
11762
+ const showError = !!error && (touched || state.submitAttempted);
11763
+ const safe = React15.useMemo(() => normalizeUrologyPathway(value), [value]);
11764
+ const update = (next) => {
11765
+ setValue(next);
11766
+ setTouched();
11767
+ };
11768
+ const setNum = (key, raw) => {
11769
+ const n = Number(raw);
11770
+ const v = Number.isFinite(n) && n >= 0 ? n : 0;
11771
+ if (key === "stoneSizeMm") {
11772
+ update({ ...safe, stoneSizeMm: Math.round(v) });
11773
+ return;
11774
+ }
11775
+ update({ ...safe, [key]: v });
11776
+ };
11777
+ const toggleRisk = (key) => {
11778
+ update({
11779
+ ...safe,
11780
+ risk: { ...safe.risk, [key]: !safe.risk[key] }
11781
+ });
11782
+ };
11783
+ if (!fieldDef) return null;
11784
+ const theme = getThemeConfig("textarea", fieldDef.theme);
11785
+ const wrapperClass = theme?.wrapperClassName ?? "rounded-md overflow-hidden flex flex-col border border-[#D0D0D0]";
11786
+ const labelClass = theme?.labelClassName;
11787
+ const subtitle = fieldDef.meta && typeof fieldDef.meta === "object" && fieldDef.meta !== null ? String(fieldDef.meta.subtitle ?? "") : "";
11788
+ const labelContent = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
11789
+ fieldDef.label,
11790
+ fieldDef.required ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1 text-red-500", children: "*" }) : null
11791
+ ] });
11792
+ const labelEl = theme ? /* @__PURE__ */ jsxRuntime.jsx(Label, { className: labelClass, children: labelContent }) : /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "text-sm font-medium", children: labelContent });
11793
+ const bodyClass = cn(
11794
+ "-mt-1 flex min-w-0 flex-col gap-4 border-t border-[#D0D0D0] bg-white px-3 py-3",
11795
+ disabled && "pointer-events-none opacity-60"
11796
+ );
11797
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("w-full min-w-0", wrapperClass), children: [
11798
+ labelEl,
11799
+ subtitle ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-3 pt-2 text-[11px] text-muted-foreground", children: subtitle }) : null,
11800
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: bodyClass, children: [
11801
+ showError ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-red-600", children: error }) : null,
11802
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-3 md:grid-cols-2", children: [
11803
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block space-y-1 text-xs", children: [
11804
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Stone size (mm)" }),
11805
+ /* @__PURE__ */ jsxRuntime.jsx(
11806
+ Input,
11807
+ {
11808
+ type: "number",
11809
+ min: 0,
11810
+ className: "h-8 text-xs",
11811
+ value: safe.stoneSizeMm,
11812
+ onChange: (e) => setNum("stoneSizeMm", e.target.value),
11813
+ disabled
11814
+ }
11815
+ )
11816
+ ] }),
11817
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2 pt-6 text-xs", children: [
11818
+ /* @__PURE__ */ jsxRuntime.jsx(
11819
+ Checkbox,
11820
+ {
11821
+ checked: safe.hydronephrosis,
11822
+ onCheckedChange: (c) => update({ ...safe, hydronephrosis: c === true }),
11823
+ disabled
11824
+ }
11825
+ ),
11826
+ "Hydronephrosis on imaging"
11827
+ ] }),
11828
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block space-y-1 text-xs", children: [
11829
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Prostate volume (cc)" }),
11830
+ /* @__PURE__ */ jsxRuntime.jsx(
11831
+ Input,
11832
+ {
11833
+ type: "number",
11834
+ min: 0,
11835
+ step: 0.1,
11836
+ className: "h-8 text-xs",
11837
+ value: safe.prostateVolumeCc,
11838
+ onChange: (e) => setNum("prostateVolumeCc", e.target.value),
11839
+ disabled
11840
+ }
11841
+ )
11842
+ ] }),
11843
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block space-y-1 text-xs", children: [
11844
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "PSA (ng/mL)" }),
11845
+ /* @__PURE__ */ jsxRuntime.jsx(
11846
+ Input,
11847
+ {
11848
+ type: "number",
11849
+ min: 0,
11850
+ step: 0.01,
11851
+ className: "h-8 text-xs",
11852
+ value: safe.psaNgMl,
11853
+ onChange: (e) => setNum("psaNgMl", e.target.value),
11854
+ disabled
11855
+ }
11856
+ )
11857
+ ] }),
11858
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block space-y-1 text-xs md:col-span-2", children: [
11859
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Uroflow Qmax (mL/s)" }),
11860
+ /* @__PURE__ */ jsxRuntime.jsx(
11861
+ Input,
11862
+ {
11863
+ type: "number",
11864
+ min: 0,
11865
+ step: 0.1,
11866
+ className: "h-8 text-xs",
11867
+ value: safe.uroflowQmaxMlSec,
11868
+ onChange: (e) => setNum("uroflowQmaxMlSec", e.target.value),
11869
+ disabled
11870
+ }
11871
+ )
11872
+ ] })
11873
+ ] }),
11874
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 border-t border-muted-foreground/20 pt-3", children: [
11875
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold text-slate-800", children: "Risk stratification" }),
11876
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: RISK_ROWS.map((r) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2 text-xs", children: [
11877
+ /* @__PURE__ */ jsxRuntime.jsx(
11878
+ Checkbox,
11879
+ {
11880
+ checked: safe.risk[r.key],
11881
+ onCheckedChange: () => toggleRisk(r.key),
11882
+ disabled
11883
+ }
11884
+ ),
11885
+ r.label
11886
+ ] }, r.key)) })
11887
+ ] })
11888
+ ] })
11889
+ ] });
11890
+ };
11891
+ var FieldRenderer = ({ fieldId }) => {
11892
+ const { fieldDef, visible } = useField(fieldId);
11893
+ if (!visible || !fieldDef) {
11894
+ return null;
11895
+ }
11896
+ return renderWidget(fieldId, fieldDef);
11897
+ };
11898
+ function renderWidget(fieldId, fieldDef) {
11899
+ switch (fieldDef.type) {
11900
+ case "text":
11901
+ case "number":
11902
+ return /* @__PURE__ */ jsxRuntime.jsx(TextWidget, { fieldId });
11903
+ case "slider":
11904
+ return /* @__PURE__ */ jsxRuntime.jsx(SliderWidget, { fieldId });
11905
+ case "textarea":
11906
+ if (fieldMetaRequestsMarMedicationOrdersButton(fieldDef.meta)) {
11907
+ return /* @__PURE__ */ jsxRuntime.jsx(MarMedicationOrdersWidget, { fieldId });
11908
+ }
11909
+ return /* @__PURE__ */ jsxRuntime.jsx(TextWidget, { fieldId });
11910
+ case "richtext":
11911
+ return /* @__PURE__ */ jsxRuntime.jsx(RichTextWidget, { fieldId });
11912
+ case "date":
11913
+ return /* @__PURE__ */ jsxRuntime.jsx(DateWidget, { fieldId });
11914
+ case "datetime":
11915
+ return /* @__PURE__ */ jsxRuntime.jsx(DateTimeWidget, { fieldId });
11916
+ case "select":
11917
+ return /* @__PURE__ */ jsxRuntime.jsx(SelectWidget, { fieldId });
11918
+ case "radio":
11919
+ return /* @__PURE__ */ jsxRuntime.jsx(RadioWidget, { fieldId });
11920
+ case "checkbox":
11921
+ return /* @__PURE__ */ jsxRuntime.jsx(CheckboxWidget, { fieldId });
11922
+ case "multiselect":
11923
+ return /* @__PURE__ */ jsxRuntime.jsx(MultiSelectWidget, { fieldId });
11924
+ case "repeatable":
11925
+ return /* @__PURE__ */ jsxRuntime.jsx(RepeatableWidget, { fieldId });
11926
+ case "image_upload":
11927
+ return /* @__PURE__ */ jsxRuntime.jsx(ImageUploadWidget, { fieldId });
11928
+ case "media_upload":
11929
+ return /* @__PURE__ */ jsxRuntime.jsx(MediaUploadWidget, { fieldId });
11930
+ case "signature":
11931
+ return /* @__PURE__ */ jsxRuntime.jsx(SignatureUploadWidget, { fieldId });
11932
+ case "editable_table":
11933
+ return /* @__PURE__ */ jsxRuntime.jsx(EditableTableWidget, { fieldId });
11934
+ case "medications":
11935
+ return /* @__PURE__ */ jsxRuntime.jsx(AddMedicationWidget, { fieldId });
11936
+ case "discharge_medication_orders":
11937
+ return /* @__PURE__ */ jsxRuntime.jsx(DischargeMedicationOrdersWidget, { fieldId });
11938
+ case "investigations":
11939
+ return /* @__PURE__ */ jsxRuntime.jsx(AddInvestigationWidget, { fieldId });
11940
+ case "procedures":
11941
+ return /* @__PURE__ */ jsxRuntime.jsx(AddProcedureWidget, { fieldId });
11942
+ case "differential_diagnosis":
11943
+ return /* @__PURE__ */ jsxRuntime.jsx(DifferentialDiagnosisWidget, { fieldId });
11944
+ case "vitals":
11945
+ return /* @__PURE__ */ jsxRuntime.jsx(VitalsWidget, { fieldId });
11946
+ case "hidden_vitals":
11947
+ return /* @__PURE__ */ jsxRuntime.jsx(HiddenVitalsWidget, { fieldId });
11948
+ case "referral":
11949
+ return /* @__PURE__ */ jsxRuntime.jsx(ReferralWidget, { fieldId });
11950
+ case "followup":
11951
+ return /* @__PURE__ */ jsxRuntime.jsx(FollowupWidget, { fieldId });
11952
+ case "smart_textarea":
11953
+ return /* @__PURE__ */ jsxRuntime.jsx(SmartTextareaWidget, { fieldId });
11954
+ case "diagnosis_textarea":
11955
+ return /* @__PURE__ */ jsxRuntime.jsx(DiagnosisTextareaWidget, { fieldId });
11956
+ case "obstetric_history":
11957
+ return /* @__PURE__ */ jsxRuntime.jsx(ObstetricHistoryWidget, { fieldId });
11958
+ case "eye_prescription":
11959
+ return /* @__PURE__ */ jsxRuntime.jsx(OphthalmologyWidget, { fieldId });
11960
+ case "ophthal_diagnosis":
11961
+ return /* @__PURE__ */ jsxRuntime.jsx(OphthalDiagnosisWidget, { fieldId });
11962
+ case "orthopedic_exam":
11963
+ return /* @__PURE__ */ jsxRuntime.jsx(OrthopedicExamWidget, { fieldId });
11964
+ case "general_surgery_smart_history":
11965
+ return /* @__PURE__ */ jsxRuntime.jsx(GsSmartHistoryWidget, { fieldId });
11966
+ case "general_surgery_examination":
11967
+ return /* @__PURE__ */ jsxRuntime.jsx(GsExaminationWidget, { fieldId });
11968
+ case "general_surgery_grading":
11969
+ return /* @__PURE__ */ jsxRuntime.jsx(GsGradingWidget, { fieldId });
11970
+ case "pain_scale_flags":
11971
+ return /* @__PURE__ */ jsxRuntime.jsx(PainScaleFlagsWidget, { fieldId });
11972
+ case "urology_smart_history":
11973
+ return /* @__PURE__ */ jsxRuntime.jsx(UrologySmartHistoryWidget, { fieldId });
11974
+ case "urology_examination":
11975
+ return /* @__PURE__ */ jsxRuntime.jsx(UrologyExaminationWidget, { fieldId });
11976
+ case "urology_pathway":
11977
+ return /* @__PURE__ */ jsxRuntime.jsx(UrologyPathwayWidget, { fieldId });
11978
+ case "toggle": {
11979
+ const { value, setValue, setTouched, disabled } = useField(fieldId);
11980
+ const store = useFormStore();
11981
+ const excludes = fieldDef.excludes ?? [];
11982
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
11983
+ /* @__PURE__ */ jsxRuntime.jsx(
11984
+ Switch,
11985
+ {
11986
+ checked: value === true,
11987
+ disabled,
11988
+ onCheckedChange: (checked) => {
11989
+ setValue(checked);
11990
+ setTouched();
11991
+ if (checked) excludes.forEach((id) => store.setValue(id, false));
11992
+ }
11993
+ }
11994
+ ),
11995
+ /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "text-sm font-medium leading-none cursor-pointer select-none", children: fieldDef.label })
11996
+ ] });
11997
+ }
11998
+ case "suggestion_textarea":
11999
+ case "complaint_chips":
12000
+ return /* @__PURE__ */ jsxRuntime.jsx(SuggestionTextareaWidget, { fieldId });
12001
+ case "lens_assessment":
12002
+ return /* @__PURE__ */ jsxRuntime.jsx(LensAssessmentWidget, { fieldId });
12003
+ case "functional_impairment_score":
12004
+ return /* @__PURE__ */ jsxRuntime.jsx(FunctionalImpairmentScoreWidget, { fieldId });
12005
+ case "biometry_iol_workup":
12006
+ return /* @__PURE__ */ jsxRuntime.jsx(BiometryIolWorkupWidget, { fieldId });
12007
+ case "surgical_risk_flags":
12008
+ return /* @__PURE__ */ jsxRuntime.jsx(SurgicalRiskFlagsWidget, { fieldId });
12009
+ case "static_text": {
12010
+ const def = fieldDef;
12011
+ const size = def.size ?? "regular";
12012
+ const labelClass = size === "large" ? "text-base" : "text-sm";
12013
+ const descClass = size === "large" ? "text-sm" : "text-xs";
12014
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${labelClass} text-muted-foreground`, children: [
12015
+ def.label,
12016
+ def.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: `mt-1 ${descClass} opacity-90`, children: def.description })
12017
+ ] });
12018
+ }
12019
+ default:
12020
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-red-500", children: [
12021
+ "Unknown field type: ",
12022
+ fieldDef.type
12023
+ ] });
12024
+ }
12025
+ }
12026
+ var Section = ({ title, children }) => {
12027
+ const [expanded, setExpanded] = React15.useState(true);
12028
+ const handleToggle = () => setExpanded((prev) => !prev);
12029
+ const contentClassName = cn(
12030
+ "overflow-hidden transition-[height] duration-200 ease-in-out",
12031
+ !expanded && "hidden"
12032
+ );
12033
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-6 border rounded-lg bg-white shadow-sm overflow-hidden", children: [
12034
+ /* @__PURE__ */ jsxRuntime.jsxs(
12035
+ "button",
12036
+ {
12037
+ type: "button",
12038
+ onClick: handleToggle,
12039
+ className: "w-full flex items-center justify-between gap-2 p-4 text-left border-b hover:bg-gray-50/80 transition-colors",
12040
+ children: [
12041
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-medium", children: title }),
12042
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0 text-muted-foreground", "aria-hidden": true, children: expanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-5 w-5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-5 w-5" }) })
12043
+ ]
12044
+ }
12045
+ ),
12046
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: contentClassName, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 pt-4 space-y-4 border-t-0", children }) })
12047
+ ] });
12048
+ };
12049
+ var ColumnLayout = ({
12050
+ columns,
12051
+ label,
12052
+ children
12053
+ }) => {
12054
+ const gridCols = Math.max(1, Math.min(columns, 12));
12055
+ const gridClass = `grid gap-4 w-full`;
12056
+ const style = {
12057
+ gridTemplateColumns: `repeat(${gridCols}, minmax(0, 1fr))`
12058
+ };
12059
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-6", children: [
12060
+ label != null && label !== "" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-2 text-sm font-medium text-gray-700", children: label }),
12061
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: gridClass, style, children })
12062
+ ] });
10782
12063
  };
10783
12064
  var DynamicForm = () => {
10784
12065
  const store = useFormStore();
@@ -11557,6 +12838,40 @@ var ReadOnlyFieldRenderer = ({
11557
12838
  ].join("\n");
11558
12839
  return /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyText, { fieldDef, value: lines });
11559
12840
  }
12841
+ case "urology_smart_history": {
12842
+ const structuredDisplay = value && typeof value === "object" ? JSON.stringify(normalizeUrologySmartHistory(value), null, 2) : value == null || value === "" ? "\u2014" : String(value);
12843
+ const hopcDef = resolveFieldDef?.("symptoms");
12844
+ const hopcRaw = allValues?.["symptoms"];
12845
+ const hopcStr = typeof hopcRaw === "string" ? hopcRaw : hopcRaw != null && hopcRaw !== "" ? String(hopcRaw) : "";
12846
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
12847
+ /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyText, { fieldDef, value: structuredDisplay }),
12848
+ hopcDef ? /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyText, { fieldDef: hopcDef, value: hopcStr }) : hopcStr ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
12849
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-700", children: "History of presenting complaint" }),
12850
+ /* @__PURE__ */ jsxRuntime.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 })
12851
+ ] }) : null
12852
+ ] });
12853
+ }
12854
+ case "urology_examination": {
12855
+ const structuredDisplay = value && typeof value === "object" ? JSON.stringify(value, null, 2) : value == null || value === "" ? "\u2014" : String(value);
12856
+ const clinicalDef = resolveFieldDef?.("clinical_examination");
12857
+ const clinicalRaw = allValues?.["clinical_examination"];
12858
+ const clinicalStr = typeof clinicalRaw === "string" ? clinicalRaw : clinicalRaw != null && clinicalRaw !== "" ? String(clinicalRaw) : "";
12859
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
12860
+ /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyText, { fieldDef, value: structuredDisplay }),
12861
+ clinicalDef ? /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyText, { fieldDef: clinicalDef, value: clinicalStr }) : clinicalStr ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
12862
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-700", children: "Clinical examination" }),
12863
+ /* @__PURE__ */ jsxRuntime.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 })
12864
+ ] }) : null
12865
+ ] });
12866
+ }
12867
+ case "urology_pathway":
12868
+ return /* @__PURE__ */ jsxRuntime.jsx(
12869
+ ReadOnlyText,
12870
+ {
12871
+ fieldDef,
12872
+ value: value && typeof value === "object" ? JSON.stringify(value, null, 2) : value == null || value === "" ? "\u2014" : String(value)
12873
+ }
12874
+ );
11560
12875
  case "general_surgery_smart_history": {
11561
12876
  const structuredDisplay = value && typeof value === "object" ? JSON.stringify(normalizeGeneralSurgerySmartHistory(value), null, 2) : value == null || value === "" ? "\u2014" : String(value);
11562
12877
  const hopcDef = resolveFieldDef?.("symptoms");