formanitor 0.0.40 → 0.0.42

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
@@ -260,8 +260,21 @@ var defaultGeneralSurgerySmartHistory = () => ({
260
260
  gi: { appetite: "", weightLoss: "", bowelHabits: "", checks: [] },
261
261
  breast: { lumpDuration: "", nippleDischarge: "", checks: [] },
262
262
  ano: { checks: [] },
263
- thyroid: { swellingDuration: "", checks: [] },
264
- systemic: ""
263
+ thyroid: { swellingDuration: "", checks: [] }
264
+ });
265
+ var defaultBreastExamSide = () => ({
266
+ size: "",
267
+ quadrant: "",
268
+ tenderness: "",
269
+ fixity: "",
270
+ skinInvolvement: "",
271
+ consistency: "",
272
+ axillaryNodes: false,
273
+ nippleAreolarComplex: false
274
+ });
275
+ var defaultBreastExaminationBlock = () => ({
276
+ left: defaultBreastExamSide(),
277
+ right: defaultBreastExamSide()
265
278
  });
266
279
  var defaultGeneralSurgeryExamination = () => ({
267
280
  general: [],
@@ -274,7 +287,7 @@ var defaultGeneralSurgeryExamination = () => ({
274
287
  bowelSounds: "none"
275
288
  },
276
289
  hernia: { site: "", reducible: false, coughImpulse: false, tenderness: false },
277
- breast: { lumpSizeCm: "", mobile: false, skinInvolvement: false, axillaryNodes: false },
290
+ breast: defaultBreastExaminationBlock(),
278
291
  thyroid: { size: "", mobileDeglutition: false, nodules: false, cervicalNodes: false },
279
292
  anorectal: { inspection: "", dreDone: false, proctoscopyDone: false, notes: "" },
280
293
  limb: { dilatedVeins: false, ulcer: false, oedema: false }
@@ -370,8 +383,32 @@ function normalizeGeneralSurgerySmartHistory(raw) {
370
383
  thyroid: {
371
384
  swellingDuration: str2(thy.swellingDuration),
372
385
  checks: strArr(thy.checks)
373
- },
374
- systemic: typeof v.systemic === "string" ? v.systemic : d.systemic
386
+ }
387
+ };
388
+ }
389
+ function normalizeBreastExamSide(partial) {
390
+ const e = defaultBreastExamSide();
391
+ const str2 = (x) => typeof x === "string" ? x : "";
392
+ const bool = (x) => x === true;
393
+ if (!partial || typeof partial !== "object") return e;
394
+ const p = partial;
395
+ 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)
404
+ };
405
+ }
406
+ function normalizeBreastExaminationBlock(raw) {
407
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return defaultBreastExaminationBlock();
408
+ const br = raw;
409
+ return {
410
+ left: normalizeBreastExamSide(br.left),
411
+ right: normalizeBreastExamSide(br.right)
375
412
  };
376
413
  }
377
414
  function normalizeGeneralSurgeryExamination(raw) {
@@ -404,12 +441,7 @@ function normalizeGeneralSurgeryExamination(raw) {
404
441
  coughImpulse: bool(hb.coughImpulse),
405
442
  tenderness: bool(hb.tenderness)
406
443
  },
407
- breast: {
408
- lumpSizeCm: typeof br.lumpSizeCm === "string" ? br.lumpSizeCm : "",
409
- mobile: bool(br.mobile),
410
- skinInvolvement: bool(br.skinInvolvement),
411
- axillaryNodes: bool(br.axillaryNodes)
412
- },
444
+ breast: normalizeBreastExaminationBlock(br),
413
445
  thyroid: {
414
446
  size: typeof th.size === "string" ? th.size : "",
415
447
  mobileDeglutition: bool(th.mobileDeglutition),
@@ -447,6 +479,259 @@ function gsGradingRowVisible(cond, chips, regions, grade) {
447
479
  if (t.regions.some((r) => regions.includes(r))) return true;
448
480
  return false;
449
481
  }
482
+ var SWELLING_OPT_LABELS = {
483
+ reducible_hernia: "Reducible (hernia)",
484
+ cough_impulse: "Cough impulse",
485
+ skin_changes: "Skin changes"
486
+ };
487
+ var GI_OPT_LABELS = {
488
+ bleeding_pr: "Bleeding PR",
489
+ vomiting: "Vomiting",
490
+ haematemesis: "Haematemesis"
491
+ };
492
+ var BREAST_OPT_LABELS = {
493
+ pain: "Pain",
494
+ fh_ca_breast: "Family history of Ca breast"
495
+ };
496
+ var ANO_OPT_LABELS = {
497
+ pain_defecation: "Pain during defecation",
498
+ bleeding: "Bleeding",
499
+ constipation: "Constipation",
500
+ discharge: "Discharge"
501
+ };
502
+ var THYROID_OPT_LABELS = {
503
+ dysphagia: "Dysphagia",
504
+ voice_change: "Voice change",
505
+ thyrotoxicosis: "Thyrotoxicosis symptoms"
506
+ };
507
+ var SOCRATES_LABELS = {
508
+ site: "Site",
509
+ onset: "Onset",
510
+ character: "Character",
511
+ radiation: "Radiation",
512
+ associated: "Associated",
513
+ timing: "Timing",
514
+ exacerbating: "Exacerbating / relieving"
515
+ };
516
+ var GENERAL_EXAM_LABELS = {
517
+ pallor: "Pallor",
518
+ icterus: "Icterus",
519
+ cyanosis: "Cyanosis",
520
+ clubbing: "Clubbing",
521
+ lymphadenopathy: "Lymphadenopathy",
522
+ oedema: "Oedema"
523
+ };
524
+ var REGION_EXAM_LABELS = {
525
+ abdomen: "Abdomen",
526
+ hernia: "Hernia",
527
+ breast: "Breast",
528
+ thyroid: "Thyroid",
529
+ anorectal: "Anorectal",
530
+ limb: "Limb / varicose"
531
+ };
532
+ var ABD_INSP_LABELS = {
533
+ distension: "Distension",
534
+ scars: "Scars",
535
+ visible_peristalsis: "Visible peristalsis"
536
+ };
537
+ var ABD_PALP_LABELS = {
538
+ tenderness: "Tenderness",
539
+ guarding: "Guarding",
540
+ rigidity: "Rigidity",
541
+ mass: "Palpable mass"
542
+ };
543
+ var ABD_PERC_LABELS = {
544
+ tympany: "Tympany",
545
+ shifting_dullness: "Shifting dullness"
546
+ };
547
+ function trimLine(s) {
548
+ return s.replace(/\s+/g, " ").trim();
549
+ }
550
+ var SK_ORDER = ["site", "onset", "character", "radiation", "associated", "timing", "exacerbating"];
551
+ function formatGeneralSurgerySmartHistoryToNarrative(v, chips) {
552
+ const blocks = [];
553
+ const showPain = chips.includes("pain");
554
+ const showSwelling = chips.includes("swelling_lump");
555
+ const showGI = chips.includes("bleeding") || chips.includes("obstruction");
556
+ const showBreast = chips.includes("breast");
557
+ const showAno = chips.includes("anorectal");
558
+ const showThyroid = chips.includes("thyroid");
559
+ if (showPain) {
560
+ const painLines = [];
561
+ for (const key of SK_ORDER) {
562
+ const raw = v.pain[key];
563
+ if (typeof raw === "string" && raw.trim()) {
564
+ painLines.push(`${SOCRATES_LABELS[key]}: ${trimLine(raw)}`);
565
+ }
566
+ }
567
+ if (v.pain.severity > 0) {
568
+ painLines.push(`Severity (0\u201310): ${v.pain.severity}`);
569
+ }
570
+ if (painLines.length > 0) {
571
+ blocks.push(["SOCRATES \u2014 pain", ...painLines.map((l) => `\u2022 ${l}`)].join("\n"));
572
+ }
573
+ }
574
+ if (showSwelling) {
575
+ const parts = [];
576
+ if (v.swelling.duration.trim()) parts.push(`Duration: ${trimLine(v.swelling.duration)}`);
577
+ if (v.swelling.sizeProgression.trim())
578
+ parts.push(`Size progression: ${trimLine(v.swelling.sizeProgression)}`);
579
+ if (v.swelling.painfulPainless.trim())
580
+ parts.push(`Painful / painless: ${trimLine(v.swelling.painfulPainless)}`);
581
+ for (const c of v.swelling.checks) {
582
+ const lb = SWELLING_OPT_LABELS[c] ?? c;
583
+ parts.push(lb);
584
+ }
585
+ if (parts.length > 0) {
586
+ blocks.push(["Swelling history", ...parts.map((p) => `\u2022 ${p}`)].join("\n"));
587
+ }
588
+ }
589
+ if (showGI) {
590
+ const parts = [];
591
+ if (v.gi.appetite.trim()) parts.push(`Appetite: ${trimLine(v.gi.appetite)}`);
592
+ if (v.gi.weightLoss.trim()) parts.push(`Weight loss: ${trimLine(v.gi.weightLoss)}`);
593
+ if (v.gi.bowelHabits.trim()) parts.push(`Bowel habits: ${trimLine(v.gi.bowelHabits)}`);
594
+ for (const c of v.gi.checks) {
595
+ parts.push(GI_OPT_LABELS[c] ?? c);
596
+ }
597
+ if (parts.length > 0) {
598
+ blocks.push(["GI history", ...parts.map((p) => `\u2022 ${p}`)].join("\n"));
599
+ }
600
+ }
601
+ if (showBreast) {
602
+ const parts = [];
603
+ if (v.breast.lumpDuration.trim()) parts.push(`Lump duration: ${trimLine(v.breast.lumpDuration)}`);
604
+ if (v.breast.nippleDischarge.trim())
605
+ parts.push(`Nipple discharge: ${trimLine(v.breast.nippleDischarge)}`);
606
+ for (const c of v.breast.checks) {
607
+ parts.push(BREAST_OPT_LABELS[c] ?? c);
608
+ }
609
+ if (parts.length > 0) {
610
+ blocks.push(["Breast history", ...parts.map((p) => `\u2022 ${p}`)].join("\n"));
611
+ }
612
+ }
613
+ if (showAno) {
614
+ const parts = [];
615
+ for (const c of v.ano.checks) {
616
+ parts.push(ANO_OPT_LABELS[c] ?? c);
617
+ }
618
+ if (parts.length > 0) {
619
+ blocks.push(["Anorectal history", ...parts.map((p) => `\u2022 ${p}`)].join("\n"));
620
+ }
621
+ }
622
+ if (showThyroid) {
623
+ const parts = [];
624
+ if (v.thyroid.swellingDuration.trim())
625
+ parts.push(`Swelling duration: ${trimLine(v.thyroid.swellingDuration)}`);
626
+ for (const c of v.thyroid.checks) {
627
+ parts.push(THYROID_OPT_LABELS[c] ?? c);
628
+ }
629
+ if (parts.length > 0) {
630
+ blocks.push(["Thyroid history", ...parts.map((p) => `\u2022 ${p}`)].join("\n"));
631
+ }
632
+ }
633
+ return blocks.join("\n\n");
634
+ }
635
+ var BOWEL_SOUND_LABELS = {
636
+ none: "\u2014",
637
+ normal: "Normal",
638
+ up: "Increased (\u2191)",
639
+ down: "Decreased (\u2193)",
640
+ absent: "Absent"
641
+ };
642
+ function formatGeneralSurgeryExaminationToNarrative(v) {
643
+ const blocks = [];
644
+ const generalPositive = v.general.map((k) => GENERAL_EXAM_LABELS[k] ?? k).filter(Boolean);
645
+ if (generalPositive.length > 0) {
646
+ blocks.push(
647
+ ["General examination", ...generalPositive.map((g) => `\u2022 ${g}`)].join("\n")
648
+ );
649
+ }
650
+ if (v.regions.length > 0) {
651
+ const names = v.regions.map((r) => REGION_EXAM_LABELS[r] ?? r);
652
+ blocks.push(`Regional examination: ${names.join(", ")}`);
653
+ }
654
+ if (v.regions.includes("abdomen")) {
655
+ const sub = [];
656
+ const ins = v.abdomen.inspection.map((x) => ABD_INSP_LABELS[x] ?? x);
657
+ const pal = v.abdomen.palpation.map((x) => ABD_PALP_LABELS[x] ?? x);
658
+ const per = v.abdomen.percussion.map((x) => ABD_PERC_LABELS[x] ?? x);
659
+ if (ins.length) sub.push(`Inspection: ${ins.join(", ")}`);
660
+ if (pal.length) sub.push(`Palpation: ${pal.join(", ")}`);
661
+ if (v.abdomen.massNotes.trim()) sub.push(`Mass / mobility: ${trimLine(v.abdomen.massNotes)}`);
662
+ if (per.length) sub.push(`Percussion: ${per.join(", ")}`);
663
+ const bs = BOWEL_SOUND_LABELS[v.abdomen.bowelSounds];
664
+ if (v.abdomen.bowelSounds !== "none") {
665
+ sub.push(`Bowel sounds: ${bs}`);
666
+ }
667
+ if (sub.length > 0) {
668
+ blocks.push(["Abdomen", ...sub.map((s) => `\u2022 ${s}`)].join("\n"));
669
+ }
670
+ }
671
+ if (v.regions.includes("hernia")) {
672
+ const sub = [];
673
+ if (v.hernia.site.trim()) sub.push(`Site: ${trimLine(v.hernia.site)}`);
674
+ if (v.hernia.reducible) sub.push("Reducible");
675
+ if (v.hernia.coughImpulse) sub.push("Cough impulse positive");
676
+ if (v.hernia.tenderness) sub.push("Tenderness");
677
+ if (sub.length > 0) {
678
+ blocks.push(["Hernia", ...sub.map((s) => `\u2022 ${s}`)].join("\n"));
679
+ }
680
+ }
681
+ if (v.regions.includes("breast")) {
682
+ const sub = [];
683
+ const appendSide = (label, s) => {
684
+ const lines = [];
685
+ if (s.size.trim()) lines.push(`Size: ${trimLine(s.size)}`);
686
+ if (s.quadrant.trim()) lines.push(`Quadrant: ${trimLine(s.quadrant)}`);
687
+ if (s.tenderness.trim()) lines.push(`Tenderness: ${trimLine(s.tenderness)}`);
688
+ if (s.fixity.trim()) lines.push(`Fixity: ${trimLine(s.fixity)}`);
689
+ if (s.skinInvolvement.trim()) lines.push(`Skin involvement: ${trimLine(s.skinInvolvement)}`);
690
+ if (s.consistency.trim()) lines.push(`Consistency: ${trimLine(s.consistency)}`);
691
+ if (s.axillaryNodes) lines.push("Axillary nodes");
692
+ if (s.nippleAreolarComplex) lines.push("Nipple-areolar complex");
693
+ if (lines.length > 0) {
694
+ sub.push(`${label}: ${lines.join("; ")}`);
695
+ }
696
+ };
697
+ appendSide("Left breast", v.breast.left);
698
+ appendSide("Right breast", v.breast.right);
699
+ if (sub.length > 0) {
700
+ blocks.push(["Breast", ...sub.map((s) => `\u2022 ${s}`)].join("\n"));
701
+ }
702
+ }
703
+ if (v.regions.includes("thyroid")) {
704
+ const sub = [];
705
+ if (v.thyroid.size.trim()) sub.push(`Size: ${trimLine(v.thyroid.size)}`);
706
+ if (v.thyroid.mobileDeglutition) sub.push("Mobile with deglutition");
707
+ if (v.thyroid.nodules) sub.push("Nodules");
708
+ if (v.thyroid.cervicalNodes) sub.push("Cervical lymph nodes");
709
+ if (sub.length > 0) {
710
+ blocks.push(["Thyroid", ...sub.map((s) => `\u2022 ${s}`)].join("\n"));
711
+ }
712
+ }
713
+ if (v.regions.includes("anorectal")) {
714
+ const sub = [];
715
+ if (v.anorectal.inspection.trim())
716
+ sub.push(`Inspection: ${trimLine(v.anorectal.inspection)}`);
717
+ if (v.anorectal.dreDone) sub.push("DRE done");
718
+ if (v.anorectal.proctoscopyDone) sub.push("Proctoscopy done");
719
+ if (v.anorectal.notes.trim()) sub.push(`DRE / proctoscopy notes: ${trimLine(v.anorectal.notes)}`);
720
+ if (sub.length > 0) {
721
+ blocks.push(["Anorectal", ...sub.map((s) => `\u2022 ${s}`)].join("\n"));
722
+ }
723
+ }
724
+ if (v.regions.includes("limb")) {
725
+ const sub = [];
726
+ if (v.limb.dilatedVeins) sub.push("Dilated veins");
727
+ if (v.limb.ulcer) sub.push("Ulcer");
728
+ if (v.limb.oedema) sub.push("Oedema");
729
+ if (sub.length > 0) {
730
+ blocks.push(["Limb / varicose", ...sub.map((s) => `\u2022 ${s}`)].join("\n"));
731
+ }
732
+ }
733
+ return blocks.join("\n\n");
734
+ }
450
735
 
451
736
  // src/core/painScaleFlags.ts
452
737
  function normalizePainScaleFlags(raw, bounds) {
@@ -9271,6 +9556,7 @@ var SliderWidget = ({ fieldId }) => {
9271
9556
  ] });
9272
9557
  };
9273
9558
  var CHIEF_CHIPS_FIELD = "chief_complaints_chips";
9559
+ var GS_SYMPTOMS_FIELD = "symptoms";
9274
9560
  var SWELLING_OPTS = [
9275
9561
  { value: "reducible_hernia", label: "Reducible (hernia)" },
9276
9562
  { value: "cough_impulse", label: "Cough impulse" },
@@ -9311,16 +9597,26 @@ function Panel({ title, children }) {
9311
9597
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3", children })
9312
9598
  ] });
9313
9599
  }
9314
- function chipList(state) {
9315
- const raw = state.values[CHIEF_CHIPS_FIELD];
9600
+ function chipListFromRaw(raw) {
9316
9601
  return Array.isArray(raw) ? raw.filter((x) => typeof x === "string") : [];
9317
9602
  }
9318
9603
  var GsSmartHistoryWidget = ({ fieldId }) => {
9319
9604
  const { fieldDef, value, setValue, setTouched, error, touched, disabled } = useField(fieldId);
9605
+ const hopcField = useField(GS_SYMPTOMS_FIELD);
9320
9606
  const { state } = useForm();
9321
9607
  const showError = !!error && (touched || state.submitAttempted);
9322
9608
  const safe = React15.useMemo(() => normalizeGeneralSurgerySmartHistory(value), [value]);
9323
- const chips = React15.useMemo(() => chipList(state), [state]);
9609
+ const chiefChipsRaw = state.values[CHIEF_CHIPS_FIELD];
9610
+ const chips = React15.useMemo(() => chipListFromRaw(chiefChipsRaw), [chiefChipsRaw]);
9611
+ const [hopcNarrativeLocked, setHopcNarrativeLocked] = React15.useState(false);
9612
+ React15.useEffect(() => {
9613
+ if (hopcNarrativeLocked) return;
9614
+ const next = formatGeneralSurgerySmartHistoryToNarrative(
9615
+ normalizeGeneralSurgerySmartHistory(value),
9616
+ chips
9617
+ );
9618
+ hopcField.setValue(next);
9619
+ }, [value, chips, hopcNarrativeLocked]);
9324
9620
  const showPain = chips.includes("pain");
9325
9621
  const showSwelling = chips.includes("swelling_lump");
9326
9622
  const showGI = chips.includes("bleeding") || chips.includes("obstruction");
@@ -9586,15 +9882,51 @@ var GsSmartHistoryWidget = ({ fieldId }) => {
9586
9882
  ] }, o.value)) })
9587
9883
  ] }) : null,
9588
9884
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
9589
- /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "text-xs font-medium text-slate-700", children: "Systemic surgical screening" }),
9885
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
9886
+ /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "text-xs font-semibold text-slate-700", children: hopcField.fieldDef?.label ?? "History of presenting complaint" }),
9887
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
9888
+ 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: [
9889
+ "You edited this summary. Use",
9890
+ " ",
9891
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "italic", children: "'Regenerate'" }),
9892
+ " ",
9893
+ "to update it from the form."
9894
+ ] }) : null,
9895
+ hopcNarrativeLocked ? /* @__PURE__ */ jsxRuntime.jsx(
9896
+ Button,
9897
+ {
9898
+ type: "button",
9899
+ variant: "outline",
9900
+ size: "sm",
9901
+ className: "h-7 shrink-0 px-2 text-xs",
9902
+ disabled: disabled || hopcField.disabled,
9903
+ onClick: () => {
9904
+ setHopcNarrativeLocked(false);
9905
+ hopcField.setValue(
9906
+ formatGeneralSurgerySmartHistoryToNarrative(
9907
+ normalizeGeneralSurgerySmartHistory(value),
9908
+ chips
9909
+ )
9910
+ );
9911
+ },
9912
+ children: "Regenerate"
9913
+ }
9914
+ ) : null
9915
+ ] })
9916
+ ] }),
9917
+ 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,
9590
9918
  /* @__PURE__ */ jsxRuntime.jsx(
9591
9919
  Textarea,
9592
9920
  {
9593
- className: "min-h-[72px] rounded-md border border-input bg-white text-sm",
9594
- placeholder: "Fever, weight loss, appetite loss, fatigue, malignancy red flags\u2026",
9595
- value: safe.systemic,
9596
- onChange: (e) => update({ ...safe, systemic: e.target.value }),
9597
- disabled
9921
+ className: "min-h-[88px] rounded-md border border-input bg-white text-sm",
9922
+ placeholder: "Onset, progression, associated symptoms, relevant negatives\u2026",
9923
+ value: typeof hopcField.value === "string" ? hopcField.value : hopcField.value == null ? "" : String(hopcField.value),
9924
+ onChange: (e) => {
9925
+ setHopcNarrativeLocked(true);
9926
+ hopcField.setValue(e.target.value);
9927
+ hopcField.setTouched();
9928
+ },
9929
+ disabled: disabled || hopcField.disabled
9598
9930
  }
9599
9931
  )
9600
9932
  ] })
@@ -9646,12 +9978,72 @@ function RegionCard({ title, children }) {
9646
9978
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3", children })
9647
9979
  ] });
9648
9980
  }
9981
+ var BREAST_TEXT_KEYS = [
9982
+ { key: "size", label: "Size" },
9983
+ { key: "quadrant", label: "Quadrant" },
9984
+ { key: "tenderness", label: "Tenderness" },
9985
+ { key: "fixity", label: "Fixity" },
9986
+ { key: "skinInvolvement", label: "Skin involvement" },
9987
+ { key: "consistency", label: "Consistency" }
9988
+ ];
9989
+ function BreastLumpColumn({
9990
+ title,
9991
+ data,
9992
+ onChange,
9993
+ disabled
9994
+ }) {
9995
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 rounded-md border border-[#D0D0D0] bg-slate-50/50 p-3", children: [
9996
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: title }),
9997
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: BREAST_TEXT_KEYS.map(({ key, label }) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block", children: [
9998
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-1 block font-medium", children: label }),
9999
+ /* @__PURE__ */ jsxRuntime.jsx(
10000
+ Input,
10001
+ {
10002
+ className: "h-8 text-xs",
10003
+ value: data[key],
10004
+ onChange: (e) => onChange({ [key]: e.target.value }),
10005
+ disabled
10006
+ }
10007
+ )
10008
+ ] }, key)) }),
10009
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-x-4 gap-y-2 pt-1", children: [
10010
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
10011
+ /* @__PURE__ */ jsxRuntime.jsx(
10012
+ Checkbox,
10013
+ {
10014
+ checked: data.axillaryNodes,
10015
+ onCheckedChange: (c) => onChange({ axillaryNodes: c === true }),
10016
+ disabled
10017
+ }
10018
+ ),
10019
+ "Axillary nodes"
10020
+ ] }),
10021
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
10022
+ /* @__PURE__ */ jsxRuntime.jsx(
10023
+ Checkbox,
10024
+ {
10025
+ checked: data.nippleAreolarComplex,
10026
+ onCheckedChange: (c) => onChange({ nippleAreolarComplex: c === true }),
10027
+ disabled
10028
+ }
10029
+ ),
10030
+ "Nipple-areolar complex"
10031
+ ] })
10032
+ ] })
10033
+ ] });
10034
+ }
9649
10035
  var GsExaminationWidget = ({ fieldId }) => {
9650
10036
  const { fieldDef, value, setValue, setTouched, error, touched, disabled } = useField(fieldId);
9651
10037
  const clinicalField = useField(GS_CLINICAL_EXAMINATION_FIELD);
9652
10038
  const { state } = useForm();
9653
10039
  const showError = !!error && (touched || state.submitAttempted);
9654
10040
  const safe = React15.useMemo(() => normalizeGeneralSurgeryExamination(value), [value]);
10041
+ const [clinicalNarrativeLocked, setClinicalNarrativeLocked] = React15.useState(false);
10042
+ React15.useEffect(() => {
10043
+ if (clinicalNarrativeLocked) return;
10044
+ const next = formatGeneralSurgeryExaminationToNarrative(normalizeGeneralSurgeryExamination(value));
10045
+ clinicalField.setValue(next);
10046
+ }, [value, clinicalNarrativeLocked]);
9655
10047
  const update = (next) => {
9656
10048
  setValue(next);
9657
10049
  setTouched();
@@ -9843,52 +10235,31 @@ var GsExaminationWidget = ({ fieldId }) => {
9843
10235
  "Tenderness"
9844
10236
  ] })
9845
10237
  ] }) }) : null,
9846
- has("breast") ? /* @__PURE__ */ jsxRuntime.jsx(RegionCard, { title: "Breast exam", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-3 text-xs md:grid-cols-4", children: [
9847
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block", children: [
9848
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-1 block font-medium", children: "Lump size (cm)" }),
9849
- /* @__PURE__ */ jsxRuntime.jsx(
9850
- Input,
9851
- {
9852
- className: "h-8 text-xs",
9853
- value: safe.breast.lumpSizeCm,
9854
- onChange: (e) => update({ ...safe, breast: { ...safe.breast, lumpSizeCm: e.target.value } }),
9855
- disabled
9856
- }
9857
- )
9858
- ] }),
9859
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
9860
- /* @__PURE__ */ jsxRuntime.jsx(
9861
- Checkbox,
9862
- {
9863
- checked: safe.breast.mobile,
9864
- onCheckedChange: (c) => update({ ...safe, breast: { ...safe.breast, mobile: c === true } }),
9865
- disabled
9866
- }
9867
- ),
9868
- "Mobile"
9869
- ] }),
9870
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
9871
- /* @__PURE__ */ jsxRuntime.jsx(
9872
- Checkbox,
9873
- {
9874
- checked: safe.breast.skinInvolvement,
9875
- onCheckedChange: (c) => update({ ...safe, breast: { ...safe.breast, skinInvolvement: c === true } }),
9876
- disabled
9877
- }
9878
- ),
9879
- "Skin involvement"
9880
- ] }),
9881
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
9882
- /* @__PURE__ */ jsxRuntime.jsx(
9883
- Checkbox,
9884
- {
9885
- checked: safe.breast.axillaryNodes,
9886
- onCheckedChange: (c) => update({ ...safe, breast: { ...safe.breast, axillaryNodes: c === true } }),
9887
- disabled
9888
- }
9889
- ),
9890
- "Axillary nodes"
9891
- ] })
10238
+ has("breast") ? /* @__PURE__ */ jsxRuntime.jsx(RegionCard, { title: "Breast exam", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-4 text-xs md:grid-cols-2", children: [
10239
+ /* @__PURE__ */ jsxRuntime.jsx(
10240
+ BreastLumpColumn,
10241
+ {
10242
+ title: "Left breast",
10243
+ data: safe.breast.left,
10244
+ onChange: (p) => update({
10245
+ ...safe,
10246
+ breast: { ...safe.breast, left: { ...safe.breast.left, ...p } }
10247
+ }),
10248
+ disabled
10249
+ }
10250
+ ),
10251
+ /* @__PURE__ */ jsxRuntime.jsx(
10252
+ BreastLumpColumn,
10253
+ {
10254
+ title: "Right breast",
10255
+ data: safe.breast.right,
10256
+ onChange: (p) => update({
10257
+ ...safe,
10258
+ breast: { ...safe.breast, right: { ...safe.breast.right, ...p } }
10259
+ }),
10260
+ disabled
10261
+ }
10262
+ )
9892
10263
  ] }) }) : null,
9893
10264
  has("thyroid") ? /* @__PURE__ */ jsxRuntime.jsx(RegionCard, { title: "Thyroid exam", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-3 text-xs md:grid-cols-4", children: [
9894
10265
  /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block", children: [
@@ -10023,13 +10394,43 @@ var GsExaminationWidget = ({ fieldId }) => {
10023
10394
  ] }) }) : null
10024
10395
  ] }),
10025
10396
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
10026
- /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "text-xs font-semibold text-slate-700", children: clinicalField.fieldDef?.label ?? "Clinical examination" }),
10397
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
10398
+ /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "text-xs font-semibold text-slate-700", children: clinicalField.fieldDef?.label ?? "Clinical examination" }),
10399
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
10400
+ 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: [
10401
+ "You edited this summary. Use",
10402
+ " ",
10403
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "italic", children: "'Regenerate'" }),
10404
+ " ",
10405
+ "to update it from the form."
10406
+ ] }) : null,
10407
+ clinicalNarrativeLocked ? /* @__PURE__ */ jsxRuntime.jsx(
10408
+ Button,
10409
+ {
10410
+ type: "button",
10411
+ variant: "outline",
10412
+ size: "sm",
10413
+ className: "h-7 shrink-0 px-2 text-xs",
10414
+ disabled: disabled || clinicalField.disabled,
10415
+ onClick: () => {
10416
+ setClinicalNarrativeLocked(false);
10417
+ clinicalField.setValue(
10418
+ formatGeneralSurgeryExaminationToNarrative(normalizeGeneralSurgeryExamination(value))
10419
+ );
10420
+ },
10421
+ children: "Regenerate"
10422
+ }
10423
+ ) : null
10424
+ ] })
10425
+ ] }),
10426
+ 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,
10027
10427
  /* @__PURE__ */ jsxRuntime.jsx(
10028
10428
  Textarea,
10029
10429
  {
10030
10430
  className: "min-h-[88px] rounded-md border border-input bg-white text-sm",
10031
10431
  value: typeof clinicalField.value === "string" ? clinicalField.value : clinicalField.value == null ? "" : String(clinicalField.value),
10032
10432
  onChange: (e) => {
10433
+ setClinicalNarrativeLocked(true);
10033
10434
  clinicalField.setValue(e.target.value);
10034
10435
  clinicalField.setTouched();
10035
10436
  },
@@ -10043,7 +10444,7 @@ var GsExaminationWidget = ({ fieldId }) => {
10043
10444
  };
10044
10445
  var CHIEF_CHIPS_FIELD2 = "chief_complaints_chips";
10045
10446
  var GS_EXAMINATION_FIELD = "gs_examination";
10046
- function chipList2(state) {
10447
+ function chipList(state) {
10047
10448
  const raw = state.values[CHIEF_CHIPS_FIELD2];
10048
10449
  return Array.isArray(raw) ? raw.filter((x) => typeof x === "string") : [];
10049
10450
  }
@@ -10057,7 +10458,7 @@ var GsGradingWidget = ({ fieldId }) => {
10057
10458
  const { state } = useForm();
10058
10459
  const showError = !!error && (touched || state.submitAttempted);
10059
10460
  const safe = React15.useMemo(() => normalizeGeneralSurgeryGrading(value), [value]);
10060
- const chips = React15.useMemo(() => chipList2(state), [state]);
10461
+ const chips = React15.useMemo(() => chipList(state), [state]);
10061
10462
  const regions = React15.useMemo(() => regionList(state), [state]);
10062
10463
  const visibleRows = React15.useMemo(() => {
10063
10464
  return ALL_GS_CONDITIONS.filter(
@@ -11156,7 +11557,19 @@ var ReadOnlyFieldRenderer = ({
11156
11557
  ].join("\n");
11157
11558
  return /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyText, { fieldDef, value: lines });
11158
11559
  }
11159
- case "general_surgery_smart_history":
11560
+ case "general_surgery_smart_history": {
11561
+ const structuredDisplay = value && typeof value === "object" ? JSON.stringify(normalizeGeneralSurgerySmartHistory(value), null, 2) : value == null || value === "" ? "\u2014" : String(value);
11562
+ const hopcDef = resolveFieldDef?.("symptoms");
11563
+ const hopcRaw = allValues?.["symptoms"];
11564
+ const hopcStr = typeof hopcRaw === "string" ? hopcRaw : hopcRaw != null && hopcRaw !== "" ? String(hopcRaw) : "";
11565
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
11566
+ /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyText, { fieldDef, value: structuredDisplay }),
11567
+ hopcDef ? /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyText, { fieldDef: hopcDef, value: hopcStr }) : hopcStr ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
11568
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-700", children: "History of presenting complaint" }),
11569
+ /* @__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 })
11570
+ ] }) : null
11571
+ ] });
11572
+ }
11160
11573
  case "general_surgery_grading":
11161
11574
  return /* @__PURE__ */ jsxRuntime.jsx(
11162
11575
  ReadOnlyText,