formanitor 0.1.10 → 0.2.0
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/AddInvestigationWidget-G7NPTSFY.cjs +32 -0
- package/dist/AddInvestigationWidget-G7NPTSFY.cjs.map +1 -0
- package/dist/AddInvestigationWidget-TQUKTGAW.mjs +30 -0
- package/dist/AddInvestigationWidget-TQUKTGAW.mjs.map +1 -0
- package/dist/AddMedicationWidget-26RHKIA6.cjs +32 -0
- package/dist/AddMedicationWidget-26RHKIA6.cjs.map +1 -0
- package/dist/AddMedicationWidget-I5UIT3WG.mjs +30 -0
- package/dist/AddMedicationWidget-I5UIT3WG.mjs.map +1 -0
- package/dist/AddProcedureWidget-B6OUF3BM.cjs +278 -0
- package/dist/AddProcedureWidget-B6OUF3BM.cjs.map +1 -0
- package/dist/AddProcedureWidget-NB46COB6.mjs +276 -0
- package/dist/AddProcedureWidget-NB46COB6.mjs.map +1 -0
- package/dist/BiometryIolWorkupWidget-F7HRYMOJ.mjs +298 -0
- package/dist/BiometryIolWorkupWidget-F7HRYMOJ.mjs.map +1 -0
- package/dist/BiometryIolWorkupWidget-TCU4MMVI.cjs +300 -0
- package/dist/BiometryIolWorkupWidget-TCU4MMVI.cjs.map +1 -0
- package/dist/DateTimeWidget-72YUK7PX.cjs +61 -0
- package/dist/DateTimeWidget-72YUK7PX.cjs.map +1 -0
- package/dist/DateTimeWidget-WKQIEQSA.mjs +59 -0
- package/dist/DateTimeWidget-WKQIEQSA.mjs.map +1 -0
- package/dist/DateWidget-K2TVTZ7Z.mjs +72 -0
- package/dist/DateWidget-K2TVTZ7Z.mjs.map +1 -0
- package/dist/DateWidget-SYDMSGWO.cjs +74 -0
- package/dist/DateWidget-SYDMSGWO.cjs.map +1 -0
- package/dist/DiagnosisTextareaWidget-RD65PGDY.mjs +184 -0
- package/dist/DiagnosisTextareaWidget-RD65PGDY.mjs.map +1 -0
- package/dist/DiagnosisTextareaWidget-UKWLE2SQ.cjs +190 -0
- package/dist/DiagnosisTextareaWidget-UKWLE2SQ.cjs.map +1 -0
- package/dist/DifferentialDiagnosisWidget-FENJP245.mjs +15 -0
- package/dist/DifferentialDiagnosisWidget-FENJP245.mjs.map +1 -0
- package/dist/DifferentialDiagnosisWidget-ZGFXP2BH.cjs +17 -0
- package/dist/DifferentialDiagnosisWidget-ZGFXP2BH.cjs.map +1 -0
- package/dist/DischargeMedicationOrdersWidget-26ALTGJM.mjs +161 -0
- package/dist/DischargeMedicationOrdersWidget-26ALTGJM.mjs.map +1 -0
- package/dist/DischargeMedicationOrdersWidget-B4CJQ3QS.cjs +163 -0
- package/dist/DischargeMedicationOrdersWidget-B4CJQ3QS.cjs.map +1 -0
- package/dist/EditableTable-LPAYCK36.mjs +279 -0
- package/dist/EditableTable-LPAYCK36.mjs.map +1 -0
- package/dist/EditableTable-YB4IC3ZK.cjs +281 -0
- package/dist/EditableTable-YB4IC3ZK.cjs.map +1 -0
- package/dist/FollowupWidget-EEKOI2TW.cjs +285 -0
- package/dist/FollowupWidget-EEKOI2TW.cjs.map +1 -0
- package/dist/FollowupWidget-NJ4QDBOG.mjs +283 -0
- package/dist/FollowupWidget-NJ4QDBOG.mjs.map +1 -0
- package/dist/FunctionalImpairmentScoreWidget-HAAPCMIS.cjs +93 -0
- package/dist/FunctionalImpairmentScoreWidget-HAAPCMIS.cjs.map +1 -0
- package/dist/FunctionalImpairmentScoreWidget-ZNLKKBYN.mjs +91 -0
- package/dist/FunctionalImpairmentScoreWidget-ZNLKKBYN.mjs.map +1 -0
- package/dist/GsExaminationWidget-EX6C3EF5.cjs +528 -0
- package/dist/GsExaminationWidget-EX6C3EF5.cjs.map +1 -0
- package/dist/GsExaminationWidget-MEIUHRQQ.mjs +526 -0
- package/dist/GsExaminationWidget-MEIUHRQQ.mjs.map +1 -0
- package/dist/GsGradingWidget-4UPOEYNL.mjs +90 -0
- package/dist/GsGradingWidget-4UPOEYNL.mjs.map +1 -0
- package/dist/GsGradingWidget-IV3UF63W.cjs +92 -0
- package/dist/GsGradingWidget-IV3UF63W.cjs.map +1 -0
- package/dist/GsSmartHistoryWidget-7QNJZEI4.cjs +398 -0
- package/dist/GsSmartHistoryWidget-7QNJZEI4.cjs.map +1 -0
- package/dist/GsSmartHistoryWidget-LGN7W2AV.mjs +396 -0
- package/dist/GsSmartHistoryWidget-LGN7W2AV.mjs.map +1 -0
- package/dist/HiddenVitalsWidget-AMH32HT2.cjs +55 -0
- package/dist/HiddenVitalsWidget-AMH32HT2.cjs.map +1 -0
- package/dist/HiddenVitalsWidget-W23IFSEF.mjs +53 -0
- package/dist/HiddenVitalsWidget-W23IFSEF.mjs.map +1 -0
- package/dist/LensAssessmentWidget-LSHBUTT5.cjs +234 -0
- package/dist/LensAssessmentWidget-LSHBUTT5.cjs.map +1 -0
- package/dist/LensAssessmentWidget-SJ6YUTSN.mjs +232 -0
- package/dist/LensAssessmentWidget-SJ6YUTSN.mjs.map +1 -0
- package/dist/MarMedicationOrdersWidget-IKMAFPRG.mjs +74 -0
- package/dist/MarMedicationOrdersWidget-IKMAFPRG.mjs.map +1 -0
- package/dist/MarMedicationOrdersWidget-ZKZLSZRN.cjs +76 -0
- package/dist/MarMedicationOrdersWidget-ZKZLSZRN.cjs.map +1 -0
- package/dist/OBGExaminationWidget-BK4ERETW.mjs +213 -0
- package/dist/OBGExaminationWidget-BK4ERETW.mjs.map +1 -0
- package/dist/OBGExaminationWidget-SMFZ2WCL.cjs +215 -0
- package/dist/OBGExaminationWidget-SMFZ2WCL.cjs.map +1 -0
- package/dist/OBGPathwayWidget-5YTUDBEH.cjs +519 -0
- package/dist/OBGPathwayWidget-5YTUDBEH.cjs.map +1 -0
- package/dist/OBGPathwayWidget-U5BCAESB.mjs +517 -0
- package/dist/OBGPathwayWidget-U5BCAESB.mjs.map +1 -0
- package/dist/ObstetricHistoryWidget-GC63CB3U.cjs +1115 -0
- package/dist/ObstetricHistoryWidget-GC63CB3U.cjs.map +1 -0
- package/dist/ObstetricHistoryWidget-WD572Q7H.mjs +1113 -0
- package/dist/ObstetricHistoryWidget-WD572Q7H.mjs.map +1 -0
- package/dist/OphthalDiagnosisWidget-QXFK446I.cjs +91 -0
- package/dist/OphthalDiagnosisWidget-QXFK446I.cjs.map +1 -0
- package/dist/OphthalDiagnosisWidget-Y3AHD6AG.mjs +89 -0
- package/dist/OphthalDiagnosisWidget-Y3AHD6AG.mjs.map +1 -0
- package/dist/OphthalmologyWidget-CRQMN5QU.mjs +1329 -0
- package/dist/OphthalmologyWidget-CRQMN5QU.mjs.map +1 -0
- package/dist/OphthalmologyWidget-U2HQMZ4J.cjs +1331 -0
- package/dist/OphthalmologyWidget-U2HQMZ4J.cjs.map +1 -0
- package/dist/OrthopedicExamWidget-LP7VN3W5.cjs +368 -0
- package/dist/OrthopedicExamWidget-LP7VN3W5.cjs.map +1 -0
- package/dist/OrthopedicExamWidget-PAOIVU6Z.mjs +366 -0
- package/dist/OrthopedicExamWidget-PAOIVU6Z.mjs.map +1 -0
- package/dist/PainScaleFlagsWidget-IBNGVVHD.cjs +153 -0
- package/dist/PainScaleFlagsWidget-IBNGVVHD.cjs.map +1 -0
- package/dist/PainScaleFlagsWidget-MRMQ7HPJ.mjs +151 -0
- package/dist/PainScaleFlagsWidget-MRMQ7HPJ.mjs.map +1 -0
- package/dist/ReadOnlyTable-4Y2XW4MX.mjs +6 -0
- package/dist/ReadOnlyTable-4Y2XW4MX.mjs.map +1 -0
- package/dist/ReadOnlyTable-L7G6GWEJ.cjs +15 -0
- package/dist/ReadOnlyTable-L7G6GWEJ.cjs.map +1 -0
- package/dist/ReferralWidget-IYTS32TS.mjs +169 -0
- package/dist/ReferralWidget-IYTS32TS.mjs.map +1 -0
- package/dist/ReferralWidget-PDNEKHFO.cjs +171 -0
- package/dist/ReferralWidget-PDNEKHFO.cjs.map +1 -0
- package/dist/RichTextWidget-5OOJ2LJN.mjs +11 -0
- package/dist/RichTextWidget-5OOJ2LJN.mjs.map +1 -0
- package/dist/RichTextWidget-XWLOHKLE.cjs +24 -0
- package/dist/RichTextWidget-XWLOHKLE.cjs.map +1 -0
- package/dist/SmartTextarea-L7Q4CORK.cjs +19 -0
- package/dist/SmartTextarea-L7Q4CORK.cjs.map +1 -0
- package/dist/SmartTextarea-ZCXGMZLG.mjs +10 -0
- package/dist/SmartTextarea-ZCXGMZLG.mjs.map +1 -0
- package/dist/SuggestionTextareaWidget-2TEITBPF.cjs +226 -0
- package/dist/SuggestionTextareaWidget-2TEITBPF.cjs.map +1 -0
- package/dist/SuggestionTextareaWidget-RN5LZYFC.mjs +215 -0
- package/dist/SuggestionTextareaWidget-RN5LZYFC.mjs.map +1 -0
- package/dist/SurgicalRiskFlagsWidget-DBICX4MB.mjs +144 -0
- package/dist/SurgicalRiskFlagsWidget-DBICX4MB.mjs.map +1 -0
- package/dist/SurgicalRiskFlagsWidget-JCSL3GWS.cjs +146 -0
- package/dist/SurgicalRiskFlagsWidget-JCSL3GWS.cjs.map +1 -0
- package/dist/UrologyExaminationWidget-74L3IN2X.cjs +273 -0
- package/dist/UrologyExaminationWidget-74L3IN2X.cjs.map +1 -0
- package/dist/UrologyExaminationWidget-IQEBP6CI.mjs +271 -0
- package/dist/UrologyExaminationWidget-IQEBP6CI.mjs.map +1 -0
- package/dist/UrologyPathwayWidget-S4QY6RD6.mjs +153 -0
- package/dist/UrologyPathwayWidget-S4QY6RD6.mjs.map +1 -0
- package/dist/UrologyPathwayWidget-UJY5EW2G.cjs +155 -0
- package/dist/UrologyPathwayWidget-UJY5EW2G.cjs.map +1 -0
- package/dist/UrologySmartHistoryWidget-NFTHHK6A.mjs +469 -0
- package/dist/UrologySmartHistoryWidget-NFTHHK6A.mjs.map +1 -0
- package/dist/UrologySmartHistoryWidget-XKZF63BV.cjs +471 -0
- package/dist/UrologySmartHistoryWidget-XKZF63BV.cjs.map +1 -0
- package/dist/VitalsWidget-44UWQGIF.cjs +208 -0
- package/dist/VitalsWidget-44UWQGIF.cjs.map +1 -0
- package/dist/VitalsWidget-MBYDGC7U.mjs +187 -0
- package/dist/VitalsWidget-MBYDGC7U.mjs.map +1 -0
- package/dist/chunk-4BAKQIPJ.mjs +27 -0
- package/dist/chunk-4BAKQIPJ.mjs.map +1 -0
- package/dist/chunk-4KSZUIJE.cjs +143 -0
- package/dist/chunk-4KSZUIJE.cjs.map +1 -0
- package/dist/chunk-4PMNVBJD.mjs +121 -0
- package/dist/chunk-4PMNVBJD.mjs.map +1 -0
- package/dist/chunk-5E3APMY6.cjs +54 -0
- package/dist/chunk-5E3APMY6.cjs.map +1 -0
- package/dist/chunk-AIZ3XYEZ.cjs +551 -0
- package/dist/chunk-AIZ3XYEZ.cjs.map +1 -0
- package/dist/chunk-AZHTIUOL.mjs +116 -0
- package/dist/chunk-AZHTIUOL.mjs.map +1 -0
- package/dist/chunk-AZSAPO2V.cjs +174 -0
- package/dist/chunk-AZSAPO2V.cjs.map +1 -0
- package/dist/chunk-AZVJU7NZ.mjs +137 -0
- package/dist/chunk-AZVJU7NZ.mjs.map +1 -0
- package/dist/chunk-B3GBIAHZ.mjs +285 -0
- package/dist/chunk-B3GBIAHZ.mjs.map +1 -0
- package/dist/chunk-BMNY7F6H.mjs +148 -0
- package/dist/chunk-BMNY7F6H.mjs.map +1 -0
- package/dist/chunk-BU4ZEAAP.mjs +102 -0
- package/dist/chunk-BU4ZEAAP.mjs.map +1 -0
- package/dist/chunk-CTW65YW2.cjs +388 -0
- package/dist/chunk-CTW65YW2.cjs.map +1 -0
- package/dist/chunk-DE7VZVKR.cjs +140 -0
- package/dist/chunk-DE7VZVKR.cjs.map +1 -0
- package/dist/chunk-DZYV47QC.mjs +54 -0
- package/dist/chunk-DZYV47QC.mjs.map +1 -0
- package/dist/chunk-E7WUDHSA.cjs +127 -0
- package/dist/chunk-E7WUDHSA.cjs.map +1 -0
- package/dist/chunk-FHHISVCH.cjs +13 -0
- package/dist/chunk-FHHISVCH.cjs.map +1 -0
- package/dist/chunk-FZEEWRW3.cjs +77 -0
- package/dist/chunk-FZEEWRW3.cjs.map +1 -0
- package/dist/chunk-GFDE2KZC.mjs +228 -0
- package/dist/chunk-GFDE2KZC.mjs.map +1 -0
- package/dist/chunk-GNZWSVTB.mjs +29 -0
- package/dist/chunk-GNZWSVTB.mjs.map +1 -0
- package/dist/chunk-GXXWMHAA.mjs +49 -0
- package/dist/chunk-GXXWMHAA.mjs.map +1 -0
- package/dist/chunk-GZPCYSJK.mjs +104 -0
- package/dist/chunk-GZPCYSJK.mjs.map +1 -0
- package/dist/chunk-HEFZA2AH.mjs +22 -0
- package/dist/chunk-HEFZA2AH.mjs.map +1 -0
- package/dist/chunk-I4AV6BQF.mjs +10 -0
- package/dist/chunk-I4AV6BQF.mjs.map +1 -0
- package/dist/chunk-IDSBJOFY.cjs +1885 -0
- package/dist/chunk-IDSBJOFY.cjs.map +1 -0
- package/dist/chunk-IFMQKLNW.mjs +39 -0
- package/dist/chunk-IFMQKLNW.mjs.map +1 -0
- package/dist/chunk-IFSKLIS2.cjs +12 -0
- package/dist/chunk-IFSKLIS2.cjs.map +1 -0
- package/dist/chunk-IKAKE7TR.mjs +527 -0
- package/dist/chunk-IKAKE7TR.mjs.map +1 -0
- package/dist/chunk-JE6VXRWW.cjs +86 -0
- package/dist/chunk-JE6VXRWW.cjs.map +1 -0
- package/dist/chunk-JMGUUFOJ.cjs +45 -0
- package/dist/chunk-JMGUUFOJ.cjs.map +1 -0
- package/dist/chunk-JNVSA77L.cjs +236 -0
- package/dist/chunk-JNVSA77L.cjs.map +1 -0
- package/dist/chunk-KJA5BLGX.cjs +31 -0
- package/dist/chunk-KJA5BLGX.cjs.map +1 -0
- package/dist/chunk-KMJOTMUQ.cjs +109 -0
- package/dist/chunk-KMJOTMUQ.cjs.map +1 -0
- package/dist/chunk-KPGTPJDH.cjs +32 -0
- package/dist/chunk-KPGTPJDH.cjs.map +1 -0
- package/dist/chunk-LBWB7MYU.cjs +287 -0
- package/dist/chunk-LBWB7MYU.cjs.map +1 -0
- package/dist/chunk-LGGOBIEA.mjs +61 -0
- package/dist/chunk-LGGOBIEA.mjs.map +1 -0
- package/dist/chunk-LQYWMYEC.mjs +28 -0
- package/dist/chunk-LQYWMYEC.mjs.map +1 -0
- package/dist/chunk-MIUUO4CI.mjs +361 -0
- package/dist/chunk-MIUUO4CI.mjs.map +1 -0
- package/dist/chunk-N4L76SHJ.cjs +65 -0
- package/dist/chunk-N4L76SHJ.cjs.map +1 -0
- package/dist/chunk-NJJTIL3U.cjs +73 -0
- package/dist/chunk-NJJTIL3U.cjs.map +1 -0
- package/dist/chunk-O3VQBPEW.cjs +72 -0
- package/dist/chunk-O3VQBPEW.cjs.map +1 -0
- package/dist/chunk-P62377LB.cjs +27 -0
- package/dist/chunk-P62377LB.cjs.map +1 -0
- package/dist/chunk-PHADAQSH.cjs +49 -0
- package/dist/chunk-PHADAQSH.cjs.map +1 -0
- package/dist/chunk-PZBJYPWW.cjs +52 -0
- package/dist/chunk-PZBJYPWW.cjs.map +1 -0
- package/dist/chunk-QKJ7BQSR.cjs +538 -0
- package/dist/chunk-QKJ7BQSR.cjs.map +1 -0
- package/dist/chunk-QS6WG2XJ.cjs +56 -0
- package/dist/chunk-QS6WG2XJ.cjs.map +1 -0
- package/dist/chunk-S7EMPE2D.cjs +104 -0
- package/dist/chunk-S7EMPE2D.cjs.map +1 -0
- package/dist/chunk-SCMXLRX5.mjs +42 -0
- package/dist/chunk-SCMXLRX5.mjs.map +1 -0
- package/dist/chunk-TJHG5WHX.cjs +47 -0
- package/dist/chunk-TJHG5WHX.cjs.map +1 -0
- package/dist/chunk-UGGUIXUS.cjs +41 -0
- package/dist/chunk-UGGUIXUS.cjs.map +1 -0
- package/dist/chunk-UULLSS4O.mjs +82 -0
- package/dist/chunk-UULLSS4O.mjs.map +1 -0
- package/dist/chunk-VNFBUAZD.mjs +25 -0
- package/dist/chunk-VNFBUAZD.mjs.map +1 -0
- package/dist/chunk-VPU66PI6.mjs +11 -0
- package/dist/chunk-VPU66PI6.mjs.map +1 -0
- package/dist/chunk-WYVXXEZI.mjs +46 -0
- package/dist/chunk-WYVXXEZI.mjs.map +1 -0
- package/dist/chunk-XDUVO3IZ.mjs +547 -0
- package/dist/chunk-XDUVO3IZ.mjs.map +1 -0
- package/dist/chunk-XR2ZM654.mjs +30 -0
- package/dist/chunk-XR2ZM654.mjs.map +1 -0
- package/dist/chunk-Y7TIWH4I.mjs +25 -0
- package/dist/chunk-Y7TIWH4I.mjs.map +1 -0
- package/dist/chunk-YEFM2ERQ.cjs +143 -0
- package/dist/chunk-YEFM2ERQ.cjs.map +1 -0
- package/dist/chunk-YYPMIUDW.mjs +69 -0
- package/dist/chunk-YYPMIUDW.mjs.map +1 -0
- package/dist/chunk-ZGPHTPAN.mjs +1851 -0
- package/dist/chunk-ZGPHTPAN.mjs.map +1 -0
- package/dist/chunk-ZSOIQVB3.mjs +75 -0
- package/dist/chunk-ZSOIQVB3.mjs.map +1 -0
- package/dist/index.cjs +1596 -14537
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -767
- package/dist/index.d.ts +4 -767
- package/dist/index.mjs +1358 -14346
- package/dist/index.mjs.map +1 -1
- package/dist/read-only-table.cjs +15 -0
- package/dist/read-only-table.cjs.map +1 -0
- package/dist/read-only-table.d.cts +10 -0
- package/dist/read-only-table.d.ts +10 -0
- package/dist/read-only-table.mjs +6 -0
- package/dist/read-only-table.mjs.map +1 -0
- package/dist/rich-text.cjs +24 -0
- package/dist/rich-text.cjs.map +1 -0
- package/dist/rich-text.d.cts +8 -0
- package/dist/rich-text.d.ts +8 -0
- package/dist/rich-text.mjs +11 -0
- package/dist/rich-text.mjs.map +1 -0
- package/dist/richTextClassName--8wkuHkW.d.cts +10 -0
- package/dist/richTextClassName--8wkuHkW.d.ts +10 -0
- package/dist/smart.cjs +23 -0
- package/dist/smart.cjs.map +1 -0
- package/dist/smart.d.cts +23 -0
- package/dist/smart.d.ts +23 -0
- package/dist/smart.mjs +10 -0
- package/dist/smart.mjs.map +1 -0
- package/dist/types-D0iYXUOo.d.cts +736 -0
- package/dist/types-D0iYXUOo.d.ts +736 -0
- package/package.json +20 -2
- package/src/styles/index.css +35 -2
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { SelectWidget, TextWidget } from './chunk-AZVJU7NZ.mjs';
|
|
2
|
+
import { fetchOptions } from './chunk-IFMQKLNW.mjs';
|
|
3
|
+
import { Textarea } from './chunk-4BAKQIPJ.mjs';
|
|
4
|
+
import { getThemeConfig } from './chunk-Y7TIWH4I.mjs';
|
|
5
|
+
import { VoiceMicButton } from './chunk-ZSOIQVB3.mjs';
|
|
6
|
+
import { fieldControlClass, FieldRequiredIndicator, isLabelVisible, fieldLabelClass, fieldDescriptionClass, fieldErrorClass, fieldWrapperClass } from './chunk-WYVXXEZI.mjs';
|
|
7
|
+
import { useForm } from './chunk-XR2ZM654.mjs';
|
|
8
|
+
import './chunk-VNFBUAZD.mjs';
|
|
9
|
+
import './chunk-AZHTIUOL.mjs';
|
|
10
|
+
import { getSuggestionTokensFromText, useField, useFormStore, toggleSuggestionTokenInText } from './chunk-ZGPHTPAN.mjs';
|
|
11
|
+
export { getSuggestionTokensFromText, toggleSuggestionTokenInText } from './chunk-ZGPHTPAN.mjs';
|
|
12
|
+
import { Label } from './chunk-HEFZA2AH.mjs';
|
|
13
|
+
import { cn } from './chunk-VPU66PI6.mjs';
|
|
14
|
+
import { useState, useMemo, useEffect } from 'react';
|
|
15
|
+
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
16
|
+
|
|
17
|
+
var DEFAULT_TOKEN_SEPARATOR = ", ";
|
|
18
|
+
function getAppendSeparator(def) {
|
|
19
|
+
const raw = def.meta && typeof def.meta.appendSeparator === "string" ? def.meta.appendSeparator : DEFAULT_TOKEN_SEPARATOR;
|
|
20
|
+
return raw;
|
|
21
|
+
}
|
|
22
|
+
function isTokenSelected(text, optionValue) {
|
|
23
|
+
const t = String(optionValue).trim();
|
|
24
|
+
if (!t) return false;
|
|
25
|
+
return getSuggestionTokensFromText(text).some((p) => p === t);
|
|
26
|
+
}
|
|
27
|
+
function deriveKnownSuggestionChipValues(text, options) {
|
|
28
|
+
if (!options.length) return [];
|
|
29
|
+
const allowed = new Map(options.map((o) => [String(o.value), o.value]));
|
|
30
|
+
const tokens = getSuggestionTokensFromText(text);
|
|
31
|
+
const out = [];
|
|
32
|
+
const seen = /* @__PURE__ */ new Set();
|
|
33
|
+
for (const t of tokens) {
|
|
34
|
+
if (!allowed.has(t) || seen.has(t)) continue;
|
|
35
|
+
seen.add(t);
|
|
36
|
+
out.push(allowed.get(t));
|
|
37
|
+
}
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
function parallelChipArraysEqual(a, b) {
|
|
41
|
+
if (!Array.isArray(a) || !Array.isArray(b)) return false;
|
|
42
|
+
if (a.length !== b.length) return false;
|
|
43
|
+
for (let i = 0; i < a.length; i++) {
|
|
44
|
+
if (a[i] !== b[i]) return false;
|
|
45
|
+
}
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
function isSuggestionField(type) {
|
|
49
|
+
return type === "suggestion_textarea" || type === "complaint_chips";
|
|
50
|
+
}
|
|
51
|
+
function EmbeddedSchemaField({ fieldId }) {
|
|
52
|
+
const store = useFormStore();
|
|
53
|
+
const fieldDef = store.getFieldDef(fieldId);
|
|
54
|
+
if (!fieldDef) return null;
|
|
55
|
+
switch (fieldDef.type) {
|
|
56
|
+
case "text":
|
|
57
|
+
case "number":
|
|
58
|
+
case "textarea":
|
|
59
|
+
return /* @__PURE__ */ jsx(TextWidget, { fieldId });
|
|
60
|
+
case "select":
|
|
61
|
+
return /* @__PURE__ */ jsx(SelectWidget, { fieldId });
|
|
62
|
+
default:
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
var SuggestionTextareaWidget = ({ fieldId }) => {
|
|
67
|
+
const { fieldDef, value, setValue, setTouched, error, disabled, touched } = useField(fieldId);
|
|
68
|
+
const { state } = useForm();
|
|
69
|
+
const store = useFormStore();
|
|
70
|
+
const hasVoice = !!(fieldDef?.voice && store.getVoice());
|
|
71
|
+
const [options, setOptions] = useState([]);
|
|
72
|
+
const [loading, setLoading] = useState(false);
|
|
73
|
+
const showError = !!error && (touched || state.submitAttempted);
|
|
74
|
+
const def = fieldDef && isSuggestionField(fieldDef.type) ? fieldDef : void 0;
|
|
75
|
+
const textValue = value == null || typeof value === "string" ? value || "" : String(value);
|
|
76
|
+
const parallelChipFieldId = def?.meta && typeof def.meta.parallelChipFieldId === "string" ? def.meta.parallelChipFieldId.trim() : void 0;
|
|
77
|
+
const embeddedFieldIds = useMemo(() => {
|
|
78
|
+
const raw = def?.meta && Array.isArray(def.meta.embeddedFieldIds) ? def.meta.embeddedFieldIds : [];
|
|
79
|
+
return raw.filter((id) => typeof id === "string" && id.trim().length > 0).map((id) => id.trim()).filter((id) => store.getFieldDef(id));
|
|
80
|
+
}, [def?.meta, store]);
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
if (!def) {
|
|
83
|
+
setOptions([]);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (def.options?.length) {
|
|
87
|
+
setOptions(def.options);
|
|
88
|
+
} else if (def.dataSource) {
|
|
89
|
+
setLoading(true);
|
|
90
|
+
fetchOptions(def.dataSource.source, def.dataSource.params).then((opts) => setOptions(opts)).finally(() => setLoading(false));
|
|
91
|
+
} else {
|
|
92
|
+
setOptions([]);
|
|
93
|
+
}
|
|
94
|
+
}, [def]);
|
|
95
|
+
const chipAllowedSet = useMemo(
|
|
96
|
+
() => new Set(options.map((o) => String(o.value).trim()).filter(Boolean)),
|
|
97
|
+
[options]
|
|
98
|
+
);
|
|
99
|
+
useEffect(() => {
|
|
100
|
+
if (!parallelChipFieldId) return;
|
|
101
|
+
const parallelDef = store.getFieldDef(parallelChipFieldId);
|
|
102
|
+
if (!parallelDef || parallelDef.type !== "multiselect") return;
|
|
103
|
+
const next = deriveKnownSuggestionChipValues(textValue, options);
|
|
104
|
+
const prev = store.getFieldState(parallelChipFieldId).value;
|
|
105
|
+
if (parallelChipArraysEqual(prev, next)) return;
|
|
106
|
+
store.setValues({ [parallelChipFieldId]: next }, { touch: false });
|
|
107
|
+
}, [def, parallelChipFieldId, textValue, options, store]);
|
|
108
|
+
if (!def) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
const appendSeparator = getAppendSeparator(def);
|
|
112
|
+
const suggestionsAria = def.meta && typeof def.meta.suggestionsAriaLabel === "string" ? def.meta.suggestionsAriaLabel : "Quick suggestions";
|
|
113
|
+
const theme = getThemeConfig("textarea", def.theme);
|
|
114
|
+
const wrapperClass = theme?.wrapperClassName ?? "space-y-2";
|
|
115
|
+
const labelClass = theme?.labelClassName;
|
|
116
|
+
const inputClass = cn(theme?.inputClassName, showError && "border-red-500");
|
|
117
|
+
const inputWithStyle = fieldControlClass(def, inputClass);
|
|
118
|
+
const height = def.height != null ? typeof def.height === "string" ? Number(def.height) || void 0 : def.height : void 0;
|
|
119
|
+
const labelContent = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
120
|
+
def.label,
|
|
121
|
+
" ",
|
|
122
|
+
/* @__PURE__ */ jsx(FieldRequiredIndicator, { fieldDef: def })
|
|
123
|
+
] });
|
|
124
|
+
const showLabel = isLabelVisible(def);
|
|
125
|
+
const labelEl = showLabel ? theme ? /* @__PURE__ */ jsx(Label, { className: fieldLabelClass(def, labelClass), children: labelContent }) : /* @__PURE__ */ jsx(Label, { className: fieldLabelClass(def), children: labelContent }) : null;
|
|
126
|
+
const onChipClick = (optValue) => {
|
|
127
|
+
if (disabled) return;
|
|
128
|
+
setValue(toggleSuggestionTokenInText(textValue, String(optValue), appendSeparator, chipAllowedSet));
|
|
129
|
+
};
|
|
130
|
+
const hasSuggestions = options.length > 0;
|
|
131
|
+
const hasEmbedded = embeddedFieldIds.length > 0;
|
|
132
|
+
const hasShell = hasSuggestions || hasEmbedded;
|
|
133
|
+
const isHighlightLabel = def.theme === "highlight-label";
|
|
134
|
+
const suggestionShellClass = cn(
|
|
135
|
+
"flex min-w-0 flex-col overflow-hidden",
|
|
136
|
+
hasShell && (isHighlightLabel ? "-mt-1 rounded-b-md border-[#D0D0D0] bg-white" : "rounded-md border border-input bg-background")
|
|
137
|
+
);
|
|
138
|
+
const chipsRowClass = cn(
|
|
139
|
+
"flex flex-wrap gap-2 px-3 pb-2 pt-3",
|
|
140
|
+
hasSuggestions && (isHighlightLabel ? "" : "border-b border-input/70"),
|
|
141
|
+
disabled && "pointer-events-none opacity-50"
|
|
142
|
+
);
|
|
143
|
+
const embeddedRowClass = cn(
|
|
144
|
+
"grid gap-3 px-3 sm:grid-cols-3",
|
|
145
|
+
hasEmbedded && (hasSuggestions ? cn("py-2", isHighlightLabel && "border-t border-input/70") : "border-b border-input/70 py-3"),
|
|
146
|
+
disabled && "pointer-events-none opacity-50"
|
|
147
|
+
);
|
|
148
|
+
const textareaShellClass = cn(
|
|
149
|
+
inputWithStyle,
|
|
150
|
+
hasShell && cn(
|
|
151
|
+
"mt-0 rounded-t-none rounded-b-md border-0 shadow-none focus-visible:ring-offset-0",
|
|
152
|
+
isHighlightLabel ? "border-t-0" : "min-h-[80px]"
|
|
153
|
+
)
|
|
154
|
+
);
|
|
155
|
+
const suggestionButtons = loading ? /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "Loading suggestions\u2026" }) : options.map((opt) => {
|
|
156
|
+
const on = isTokenSelected(textValue, opt.value);
|
|
157
|
+
return /* @__PURE__ */ jsx(
|
|
158
|
+
"button",
|
|
159
|
+
{
|
|
160
|
+
type: "button",
|
|
161
|
+
onClick: () => onChipClick(opt.value),
|
|
162
|
+
className: cn(
|
|
163
|
+
"inline-flex min-h-8 items-center rounded-full border px-3 py-1 text-xs font-medium leading-none transition-colors",
|
|
164
|
+
on ? "border-primary bg-primary/10 text-primary" : "border-muted-foreground/30 bg-background hover:bg-muted/60"
|
|
165
|
+
),
|
|
166
|
+
children: opt.label
|
|
167
|
+
},
|
|
168
|
+
String(opt.value)
|
|
169
|
+
);
|
|
170
|
+
});
|
|
171
|
+
return /* @__PURE__ */ jsxs("div", { className: fieldWrapperClass(def, wrapperClass), children: [
|
|
172
|
+
hasVoice ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
173
|
+
labelEl,
|
|
174
|
+
/* @__PURE__ */ jsx(VoiceMicButton, { fieldId, onTranscriptReady: setValue })
|
|
175
|
+
] }) : labelEl,
|
|
176
|
+
def.description && /* @__PURE__ */ jsx("p", { className: fieldDescriptionClass(def, "text-xs text-muted-foreground"), children: def.description }),
|
|
177
|
+
hasShell ? /* @__PURE__ */ jsxs("div", { className: suggestionShellClass, children: [
|
|
178
|
+
hasSuggestions && /* @__PURE__ */ jsx("div", { className: chipsRowClass, role: "group", "aria-label": suggestionsAria, children: suggestionButtons }),
|
|
179
|
+
hasEmbedded && /* @__PURE__ */ jsx("div", { className: embeddedRowClass, children: embeddedFieldIds.map((id) => /* @__PURE__ */ jsx(EmbeddedSchemaField, { fieldId: id }, id)) }),
|
|
180
|
+
/* @__PURE__ */ jsx(
|
|
181
|
+
Textarea,
|
|
182
|
+
{
|
|
183
|
+
id: fieldId,
|
|
184
|
+
value: textValue,
|
|
185
|
+
onChange: (e) => setValue(e.target.value),
|
|
186
|
+
onBlur: setTouched,
|
|
187
|
+
disabled,
|
|
188
|
+
className: textareaShellClass,
|
|
189
|
+
placeholder: def.placeholder,
|
|
190
|
+
style: height != null && Number.isFinite(height) ? { minHeight: height } : void 0,
|
|
191
|
+
"aria-label": !showLabel ? def.label : void 0
|
|
192
|
+
}
|
|
193
|
+
)
|
|
194
|
+
] }) : /* @__PURE__ */ jsx(
|
|
195
|
+
Textarea,
|
|
196
|
+
{
|
|
197
|
+
id: fieldId,
|
|
198
|
+
value: textValue,
|
|
199
|
+
onChange: (e) => setValue(e.target.value),
|
|
200
|
+
onBlur: setTouched,
|
|
201
|
+
disabled,
|
|
202
|
+
className: inputWithStyle,
|
|
203
|
+
placeholder: def.placeholder,
|
|
204
|
+
style: height != null && Number.isFinite(height) ? { minHeight: height } : void 0,
|
|
205
|
+
"aria-label": !showLabel ? def.label : void 0
|
|
206
|
+
}
|
|
207
|
+
),
|
|
208
|
+
showError && /* @__PURE__ */ jsx("p", { className: fieldErrorClass(def, "text-xs text-red-500"), children: error })
|
|
209
|
+
] });
|
|
210
|
+
};
|
|
211
|
+
var ComplaintChipsWidget = SuggestionTextareaWidget;
|
|
212
|
+
|
|
213
|
+
export { ComplaintChipsWidget, SuggestionTextareaWidget, deriveKnownSuggestionChipValues };
|
|
214
|
+
//# sourceMappingURL=SuggestionTextareaWidget-RN5LZYFC.mjs.map
|
|
215
|
+
//# sourceMappingURL=SuggestionTextareaWidget-RN5LZYFC.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ui/widgets/SuggestionTextareaWidget.tsx"],"names":[],"mappings":"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","file":"SuggestionTextareaWidget-RN5LZYFC.mjs","sourcesContent":["import React, { useEffect, useMemo, useState } from 'react';\nimport { useField } from '../../react/useField';\nimport { useForm } from '../../react/useForm';\nimport { useFormStore } from '../../react/FormProvider';\nimport { VoiceMicButton } from '../../react/VoiceMicButton';\nimport { Label } from '../shadcn/label';\nimport { Textarea } from '../shadcn/textarea';\nimport { getThemeConfig } from '../themes';\nimport { fetchOptions } from '../../core/asyncOptions';\nimport { cn } from '../../core/utils';\nimport type { SelectOption, SuggestionTextareaFieldDef } from '../../core/types';\nimport {\n FieldRequiredIndicator,\n fieldControlClass,\n fieldDescriptionClass,\n fieldErrorClass,\n fieldLabelClass,\n fieldWrapperClass,\n isLabelVisible,\n} from '../../react/fieldStyle';\nimport { TextWidget } from './Text';\nimport { SelectWidget } from './Select';\n\nimport { getSuggestionTokensFromText, toggleSuggestionTokenInText } from '../../core/suggestionTokens';\n\nexport { getSuggestionTokensFromText, toggleSuggestionTokenInText };\n\nconst DEFAULT_TOKEN_SEPARATOR = ', ';\n\nfunction getAppendSeparator(def: SuggestionTextareaFieldDef): string {\n const raw = def.meta && typeof (def.meta as { appendSeparator?: unknown }).appendSeparator === 'string'\n ? (def.meta as { appendSeparator: string }).appendSeparator\n : DEFAULT_TOKEN_SEPARATOR;\n return raw;\n}\n\nfunction isTokenSelected(text: string, optionValue: unknown): boolean {\n const t = String(optionValue).trim();\n if (!t) return false;\n return getSuggestionTokensFromText(text).some((p) => p === t);\n}\n\n/**\n * Chip option values present in `text` as comma-separated tokens (same typing as schema `options[].value`).\n * Order follows left-to-right token order; duplicates in text only appear once.\n */\nexport function deriveKnownSuggestionChipValues(text: string, options: SelectOption[]): unknown[] {\n if (!options.length) return [];\n const allowed = new Map<string, unknown>(options.map((o) => [String(o.value), o.value] as const));\n const tokens = getSuggestionTokensFromText(text);\n const out: unknown[] = [];\n const seen = new Set<string>();\n for (const t of tokens) {\n if (!allowed.has(t) || seen.has(t)) continue;\n seen.add(t);\n out.push(allowed.get(t)!);\n }\n return out;\n}\n\nfunction parallelChipArraysEqual(a: unknown, b: unknown): boolean {\n if (!Array.isArray(a) || !Array.isArray(b)) return false;\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n}\n\nfunction isSuggestionField(type: string | undefined): type is SuggestionTextareaFieldDef['type'] {\n return type === 'suggestion_textarea' || type === 'complaint_chips';\n}\n\n/**\n * Renders a sibling schema field inside the suggestion textarea shell. Uses concrete widgets\n * (not FieldRenderer) so `hidden` layout fields still render here without circular imports.\n * Supported: text, number, textarea, select.\n */\nfunction EmbeddedSchemaField({ fieldId }: { fieldId: string }) {\n const store = useFormStore();\n const fieldDef = store.getFieldDef(fieldId);\n if (!fieldDef) return null;\n switch (fieldDef.type) {\n case 'text':\n case 'number':\n case 'textarea':\n return <TextWidget fieldId={fieldId} />;\n case 'select':\n return <SelectWidget fieldId={fieldId} />;\n default:\n return null;\n }\n}\n\n/**\n * Reusable textarea with schema-driven **suggestion chips** inside the input area (same white\n * shell as the textarea). The field value is a **single string**: clicking a chip **appends**\n * that option’s `value` or **removes** it if already selected. When chip options are loaded,\n * slugs are kept on the **last line** (comma + space by default), with prose above separated by\n * a newline. Optional `meta.parallelChipFieldId` mirrors chip selections into a sibling\n * **`multiselect`** array. Free typing is still allowed.\n */\nexport const SuggestionTextareaWidget: React.FC<{ fieldId: string }> = ({ fieldId }) => {\n const { fieldDef, value, setValue, setTouched, error, disabled, touched } = useField(fieldId);\n const { state } = useForm();\n const store = useFormStore();\n const hasVoice = !!(fieldDef?.voice && store.getVoice());\n\n const [options, setOptions] = useState<SelectOption[]>([]);\n const [loading, setLoading] = useState(false);\n const showError = !!error && (touched || state.submitAttempted);\n\n const def =\n fieldDef && isSuggestionField(fieldDef.type) ? (fieldDef as SuggestionTextareaFieldDef) : undefined;\n\n const textValue = value == null || typeof value === 'string' ? value || '' : String(value);\n\n const parallelChipFieldId =\n def?.meta &&\n typeof (def.meta as { parallelChipFieldId?: unknown }).parallelChipFieldId === 'string'\n ? (def.meta as { parallelChipFieldId: string }).parallelChipFieldId.trim()\n : undefined;\n\n const embeddedFieldIds = useMemo(() => {\n const raw = def?.meta && Array.isArray((def.meta as { embeddedFieldIds?: unknown }).embeddedFieldIds)\n ? (def.meta as { embeddedFieldIds: unknown[] }).embeddedFieldIds\n : [];\n return raw\n .filter((id): id is string => typeof id === 'string' && id.trim().length > 0)\n .map((id) => id.trim())\n .filter((id) => store.getFieldDef(id));\n }, [def?.meta, store]);\n\n useEffect(() => {\n if (!def) {\n setOptions([]);\n return;\n }\n if (def.options?.length) {\n setOptions(def.options);\n } else if (def.dataSource) {\n setLoading(true);\n fetchOptions(def.dataSource.source, def.dataSource.params)\n .then((opts) => setOptions(opts as SelectOption[]))\n .finally(() => setLoading(false));\n } else {\n setOptions([]);\n }\n }, [def]);\n\n const chipAllowedSet = useMemo(\n () => new Set(options.map((o) => String(o.value).trim()).filter(Boolean)),\n [options],\n );\n\n useEffect(() => {\n if (!parallelChipFieldId) return;\n const parallelDef = store.getFieldDef(parallelChipFieldId);\n if (!parallelDef || parallelDef.type !== 'multiselect') return;\n const next = deriveKnownSuggestionChipValues(textValue, options);\n const prev = store.getFieldState(parallelChipFieldId).value;\n if (parallelChipArraysEqual(prev, next)) return;\n store.setValues({ [parallelChipFieldId]: next }, { touch: false });\n }, [def, parallelChipFieldId, textValue, options, store]);\n\n if (!def) {\n return null;\n }\n\n const appendSeparator = getAppendSeparator(def);\n const suggestionsAria =\n def.meta && typeof (def.meta as { suggestionsAriaLabel?: string }).suggestionsAriaLabel === 'string'\n ? (def.meta as { suggestionsAriaLabel: string }).suggestionsAriaLabel\n : 'Quick suggestions';\n\n const theme = getThemeConfig('textarea', def.theme);\n const wrapperClass = theme?.wrapperClassName ?? 'space-y-2';\n const labelClass = theme?.labelClassName;\n const inputClass = cn(theme?.inputClassName, showError && 'border-red-500');\n const inputWithStyle = fieldControlClass(def, inputClass);\n const height =\n def.height != null\n ? typeof def.height === 'string'\n ? Number(def.height) || undefined\n : def.height\n : undefined;\n\n const labelContent = (\n <>\n {def.label}{' '}\n <FieldRequiredIndicator fieldDef={def} />\n </>\n );\n\n const showLabel = isLabelVisible(def);\n\n const labelEl = showLabel ? (\n theme ? (\n <Label className={fieldLabelClass(def, labelClass)}>{labelContent}</Label>\n ) : (\n <Label className={fieldLabelClass(def)}>{labelContent}</Label>\n )\n ) : null;\n\n const onChipClick = (optValue: unknown) => {\n if (disabled) return;\n setValue(toggleSuggestionTokenInText(textValue, String(optValue), appendSeparator, chipAllowedSet));\n };\n\n const hasSuggestions = options.length > 0;\n const hasEmbedded = embeddedFieldIds.length > 0;\n const hasShell = hasSuggestions || hasEmbedded;\n const isHighlightLabel = def.theme === 'highlight-label';\n\n const suggestionShellClass = cn(\n 'flex min-w-0 flex-col overflow-hidden',\n hasShell &&\n (isHighlightLabel\n ? '-mt-1 rounded-b-md border-[#D0D0D0] bg-white'\n : 'rounded-md border border-input bg-background'),\n );\n\n const chipsRowClass = cn(\n 'flex flex-wrap gap-2 px-3 pb-2 pt-3',\n hasSuggestions &&\n (isHighlightLabel ? '' : 'border-b border-input/70'),\n disabled && 'pointer-events-none opacity-50',\n );\n\n const embeddedRowClass = cn(\n 'grid gap-3 px-3 sm:grid-cols-3',\n hasEmbedded &&\n (hasSuggestions\n ? cn('py-2', isHighlightLabel && 'border-t border-input/70')\n : 'border-b border-input/70 py-3'),\n disabled && 'pointer-events-none opacity-50',\n );\n\n const textareaShellClass = cn(\n inputWithStyle,\n hasShell &&\n cn(\n 'mt-0 rounded-t-none rounded-b-md border-0 shadow-none focus-visible:ring-offset-0',\n isHighlightLabel ? 'border-t-0' : 'min-h-[80px]',\n ),\n );\n\n const suggestionButtons =\n loading ? (\n <span className=\"text-xs text-muted-foreground\">Loading suggestions…</span>\n ) : (\n options.map((opt) => {\n const on = isTokenSelected(textValue, opt.value);\n return (\n <button\n key={String(opt.value)}\n type=\"button\"\n onClick={() => onChipClick(opt.value)}\n className={cn(\n 'inline-flex min-h-8 items-center rounded-full border px-3 py-1 text-xs font-medium leading-none transition-colors',\n on\n ? 'border-primary bg-primary/10 text-primary'\n : 'border-muted-foreground/30 bg-background hover:bg-muted/60',\n )}\n >\n {opt.label}\n </button>\n );\n })\n );\n\n return (\n <div className={fieldWrapperClass(def, wrapperClass)}>\n {hasVoice ? (\n <div className=\"flex items-center justify-between\">\n {labelEl}\n <VoiceMicButton fieldId={fieldId} onTranscriptReady={setValue} />\n </div>\n ) : (\n labelEl\n )}\n\n {def.description && (\n <p className={fieldDescriptionClass(def, 'text-xs text-muted-foreground')}>\n {def.description}\n </p>\n )}\n\n {hasShell ? (\n <div className={suggestionShellClass}>\n {hasSuggestions && (\n <div className={chipsRowClass} role=\"group\" aria-label={suggestionsAria}>\n {suggestionButtons}\n </div>\n )}\n {hasEmbedded && (\n <div className={embeddedRowClass}>\n {embeddedFieldIds.map((id) => (\n <EmbeddedSchemaField key={id} fieldId={id} />\n ))}\n </div>\n )}\n <Textarea\n id={fieldId}\n value={textValue}\n onChange={(e) => setValue(e.target.value)}\n onBlur={setTouched}\n disabled={disabled}\n className={textareaShellClass}\n placeholder={def.placeholder}\n style={height != null && Number.isFinite(height) ? { minHeight: height } : undefined}\n aria-label={!showLabel ? def.label : undefined}\n />\n </div>\n ) : (\n <Textarea\n id={fieldId}\n value={textValue}\n onChange={(e) => setValue(e.target.value)}\n onBlur={setTouched}\n disabled={disabled}\n className={inputWithStyle}\n placeholder={def.placeholder}\n style={height != null && Number.isFinite(height) ? { minHeight: height } : undefined}\n aria-label={!showLabel ? def.label : undefined}\n />\n )}\n\n {showError && (\n <p className={fieldErrorClass(def, 'text-xs text-red-500')}>{error}</p>\n )}\n </div>\n );\n};\n\n/** @deprecated Use `SuggestionTextareaWidget`. Kept for schema compatibility. */\nexport const ComplaintChipsWidget = SuggestionTextareaWidget;\n"]}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { useForm } from './chunk-XR2ZM654.mjs';
|
|
2
|
+
import { useField } from './chunk-ZGPHTPAN.mjs';
|
|
3
|
+
import { cn } from './chunk-VPU66PI6.mjs';
|
|
4
|
+
import 'react';
|
|
5
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
var RISKS = [
|
|
8
|
+
"Small pupil",
|
|
9
|
+
"Pseudoexfoliation",
|
|
10
|
+
"Diabetes",
|
|
11
|
+
"Shallow AC",
|
|
12
|
+
"Previous ocular surgery",
|
|
13
|
+
"Zonular weakness",
|
|
14
|
+
"Mature/white cataract"
|
|
15
|
+
];
|
|
16
|
+
var DIABETES = "Diabetes";
|
|
17
|
+
function parseValue(raw) {
|
|
18
|
+
const empty = { OD: [], OS: [] };
|
|
19
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return empty;
|
|
20
|
+
const o = raw;
|
|
21
|
+
const arr = (x) => Array.isArray(x) ? x.filter((i) => typeof i === "string") : [];
|
|
22
|
+
let OD = arr(o.OD);
|
|
23
|
+
let OS = arr(o.OS);
|
|
24
|
+
const odD = OD.includes(DIABETES);
|
|
25
|
+
const osD = OS.includes(DIABETES);
|
|
26
|
+
if (odD !== osD) {
|
|
27
|
+
if (odD && !osD) OS = [...OS, DIABETES];
|
|
28
|
+
else if (osD && !odD) OD = [...OD, DIABETES];
|
|
29
|
+
}
|
|
30
|
+
return { OD, OS };
|
|
31
|
+
}
|
|
32
|
+
function riskTierForCount(n) {
|
|
33
|
+
if (n === 0) return "Low";
|
|
34
|
+
if (n <= 2) return "Moderate";
|
|
35
|
+
return "High";
|
|
36
|
+
}
|
|
37
|
+
function tierBadgeClass(tier) {
|
|
38
|
+
if (tier === "High") return "bg-red-600 text-white";
|
|
39
|
+
if (tier === "Moderate") return "bg-amber-500 text-white";
|
|
40
|
+
return "bg-emerald-600 text-white";
|
|
41
|
+
}
|
|
42
|
+
var DEFAULT_TITLE = "Surgical Risk Flags (Stage 11)";
|
|
43
|
+
function RiskCol({
|
|
44
|
+
eye,
|
|
45
|
+
value,
|
|
46
|
+
disabled,
|
|
47
|
+
onToggle
|
|
48
|
+
}) {
|
|
49
|
+
const selected = new Set(value[eye]);
|
|
50
|
+
const tier = riskTierForCount(selected.size);
|
|
51
|
+
return /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
52
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between gap-2", children: [
|
|
53
|
+
/* @__PURE__ */ jsx("div", { className: "text-xs font-semibold text-foreground", children: eye === "OD" ? "Right Eye (OD)" : "Left Eye (OS)" }),
|
|
54
|
+
/* @__PURE__ */ jsxs(
|
|
55
|
+
"span",
|
|
56
|
+
{
|
|
57
|
+
className: cn(
|
|
58
|
+
"whitespace-nowrap rounded-full px-2 py-0.5 text-[11px] font-medium",
|
|
59
|
+
tierBadgeClass(tier)
|
|
60
|
+
),
|
|
61
|
+
children: [
|
|
62
|
+
tier,
|
|
63
|
+
" risk"
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
)
|
|
67
|
+
] }),
|
|
68
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-1.5", children: RISKS.map((r) => /* @__PURE__ */ jsxs(
|
|
69
|
+
"label",
|
|
70
|
+
{
|
|
71
|
+
className: "flex cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs hover:bg-muted/50",
|
|
72
|
+
children: [
|
|
73
|
+
/* @__PURE__ */ jsx(
|
|
74
|
+
"input",
|
|
75
|
+
{
|
|
76
|
+
type: "checkbox",
|
|
77
|
+
className: "shrink-0",
|
|
78
|
+
checked: selected.has(r),
|
|
79
|
+
disabled,
|
|
80
|
+
onChange: () => onToggle(eye, r)
|
|
81
|
+
}
|
|
82
|
+
),
|
|
83
|
+
/* @__PURE__ */ jsx("span", { children: r })
|
|
84
|
+
]
|
|
85
|
+
},
|
|
86
|
+
r
|
|
87
|
+
)) })
|
|
88
|
+
] });
|
|
89
|
+
}
|
|
90
|
+
var SurgicalRiskFlagsWidget = ({ fieldId }) => {
|
|
91
|
+
const { fieldDef, value, setValue, error, disabled, touched } = useField(fieldId);
|
|
92
|
+
const { state } = useForm();
|
|
93
|
+
const showError = !!error && (touched || state.submitAttempted);
|
|
94
|
+
if (!fieldDef || fieldDef.type !== "surgical_risk_flags") {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
const def = fieldDef;
|
|
98
|
+
const v = parseValue(value);
|
|
99
|
+
const title = def.meta?.cardTitle?.trim() || (def.label?.trim() ? def.label : DEFAULT_TITLE);
|
|
100
|
+
const toggleRisk = (eye, risk) => {
|
|
101
|
+
const next = {
|
|
102
|
+
OD: [...v.OD],
|
|
103
|
+
OS: [...v.OS]
|
|
104
|
+
};
|
|
105
|
+
if (risk === DIABETES) {
|
|
106
|
+
const had = next.OD.includes(DIABETES) || next.OS.includes(DIABETES);
|
|
107
|
+
if (had) {
|
|
108
|
+
next.OD = next.OD.filter((x) => x !== DIABETES);
|
|
109
|
+
next.OS = next.OS.filter((x) => x !== DIABETES);
|
|
110
|
+
} else {
|
|
111
|
+
if (!next.OD.includes(DIABETES)) next.OD.push(DIABETES);
|
|
112
|
+
if (!next.OS.includes(DIABETES)) next.OS.push(DIABETES);
|
|
113
|
+
}
|
|
114
|
+
setValue(next);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const list = next[eye];
|
|
118
|
+
const i = list.indexOf(risk);
|
|
119
|
+
if (i === -1) list.push(risk);
|
|
120
|
+
else list.splice(i, 1);
|
|
121
|
+
setValue(next);
|
|
122
|
+
};
|
|
123
|
+
return /* @__PURE__ */ jsxs(
|
|
124
|
+
"div",
|
|
125
|
+
{
|
|
126
|
+
id: `surgical-risk-flags-${fieldId}`,
|
|
127
|
+
className: "w-full min-w-0 max-w-full rounded-lg border border-border bg-card p-3 text-card-foreground shadow-sm",
|
|
128
|
+
children: [
|
|
129
|
+
/* @__PURE__ */ jsx("h3", { className: "mb-3 text-sm font-semibold leading-tight text-foreground", children: title }),
|
|
130
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-6", children: [
|
|
131
|
+
/* @__PURE__ */ jsx(RiskCol, { eye: "OD", value: v, disabled, onToggle: toggleRisk }),
|
|
132
|
+
/* @__PURE__ */ jsx("div", { className: "w-px shrink-0 bg-border", "aria-hidden": true }),
|
|
133
|
+
/* @__PURE__ */ jsx(RiskCol, { eye: "OS", value: v, disabled, onToggle: toggleRisk })
|
|
134
|
+
] }),
|
|
135
|
+
def.description && /* @__PURE__ */ jsx("p", { className: "mt-2 text-xs text-muted-foreground", children: def.description }),
|
|
136
|
+
showError && /* @__PURE__ */ jsx("p", { className: "mt-2 text-xs text-red-500", children: error })
|
|
137
|
+
]
|
|
138
|
+
}
|
|
139
|
+
);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export { SurgicalRiskFlagsWidget };
|
|
143
|
+
//# sourceMappingURL=SurgicalRiskFlagsWidget-DBICX4MB.mjs.map
|
|
144
|
+
//# sourceMappingURL=SurgicalRiskFlagsWidget-DBICX4MB.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ui/widgets/SurgicalRiskFlagsWidget.tsx"],"names":[],"mappings":"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","file":"SurgicalRiskFlagsWidget-DBICX4MB.mjs","sourcesContent":["import React from 'react';\nimport { useField } from '../../react/useField';\nimport { useForm } from '../../react/useForm';\nimport { cn } from '../../core/utils';\nimport type { SurgicalRiskFlagsFieldDef, SurgicalRiskFlagsValue } from '../../core/types';\n\nconst RISKS = [\n 'Small pupil',\n 'Pseudoexfoliation',\n 'Diabetes',\n 'Shallow AC',\n 'Previous ocular surgery',\n 'Zonular weakness',\n 'Mature/white cataract',\n] as const;\n\ntype Eye = 'OD' | 'OS';\n\nconst DIABETES = 'Diabetes';\n\nfunction parseValue(raw: unknown): SurgicalRiskFlagsValue {\n const empty: SurgicalRiskFlagsValue = { OD: [], OS: [] };\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return empty;\n const o = raw as Record<string, unknown>;\n const arr = (x: unknown): string[] =>\n Array.isArray(x) ? x.filter((i): i is string => typeof i === 'string') : [];\n let OD = arr(o.OD);\n let OS = arr(o.OS);\n const odD = OD.includes(DIABETES);\n const osD = OS.includes(DIABETES);\n if (odD !== osD) {\n if (odD && !osD) OS = [...OS, DIABETES];\n else if (osD && !odD) OD = [...OD, DIABETES];\n }\n return { OD, OS };\n}\n\n/** Heuristic tier from number of flags checked for that eye. */\nfunction riskTierForCount(n: number): 'High' | 'Moderate' | 'Low' {\n if (n === 0) return 'Low';\n if (n <= 2) return 'Moderate';\n return 'High';\n}\n\nfunction tierBadgeClass(tier: 'High' | 'Moderate' | 'Low'): string {\n if (tier === 'High') return 'bg-red-600 text-white';\n if (tier === 'Moderate') return 'bg-amber-500 text-white';\n return 'bg-emerald-600 text-white';\n}\n\nconst DEFAULT_TITLE = 'Surgical Risk Flags (Stage 11)';\n\nfunction RiskCol({\n eye,\n value,\n disabled,\n onToggle,\n}: {\n eye: Eye;\n value: SurgicalRiskFlagsValue;\n disabled?: boolean;\n onToggle: (eye: Eye, risk: string) => void;\n}) {\n const selected = new Set(value[eye]);\n const tier = riskTierForCount(selected.size);\n\n return (\n <div className=\"min-w-0 flex-1\">\n <div className=\"mb-2 flex items-center justify-between gap-2\">\n <div className=\"text-xs font-semibold text-foreground\">\n {eye === 'OD' ? 'Right Eye (OD)' : 'Left Eye (OS)'}\n </div>\n <span\n className={cn(\n 'whitespace-nowrap rounded-full px-2 py-0.5 text-[11px] font-medium',\n tierBadgeClass(tier),\n )}\n >\n {tier} risk\n </span>\n </div>\n <div className=\"space-y-1.5\">\n {RISKS.map((r) => (\n <label\n key={r}\n className=\"flex cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs hover:bg-muted/50\"\n >\n <input\n type=\"checkbox\"\n className=\"shrink-0\"\n checked={selected.has(r)}\n disabled={disabled}\n onChange={() => onToggle(eye, r)}\n />\n <span>{r}</span>\n </label>\n ))}\n </div>\n </div>\n );\n}\n\nexport const SurgicalRiskFlagsWidget: React.FC<{ fieldId: string }> = ({ fieldId }) => {\n const { fieldDef, value, setValue, error, disabled, touched } = useField(fieldId);\n const { state } = useForm();\n const showError = !!error && (touched || state.submitAttempted);\n\n if (!fieldDef || fieldDef.type !== 'surgical_risk_flags') {\n return null;\n }\n\n const def = fieldDef as SurgicalRiskFlagsFieldDef;\n const v = parseValue(value);\n const title =\n (def.meta?.cardTitle as string | undefined)?.trim() ||\n (def.label?.trim() ? def.label : DEFAULT_TITLE);\n\n const toggleRisk = (eye: Eye, risk: string) => {\n const next: SurgicalRiskFlagsValue = {\n OD: [...v.OD],\n OS: [...v.OS],\n };\n\n if (risk === DIABETES) {\n const had = next.OD.includes(DIABETES) || next.OS.includes(DIABETES);\n if (had) {\n next.OD = next.OD.filter((x) => x !== DIABETES);\n next.OS = next.OS.filter((x) => x !== DIABETES);\n } else {\n if (!next.OD.includes(DIABETES)) next.OD.push(DIABETES);\n if (!next.OS.includes(DIABETES)) next.OS.push(DIABETES);\n }\n setValue(next);\n return;\n }\n\n const list = next[eye];\n const i = list.indexOf(risk);\n if (i === -1) list.push(risk);\n else list.splice(i, 1);\n setValue(next);\n };\n\n return (\n <div\n id={`surgical-risk-flags-${fieldId}`}\n className=\"w-full min-w-0 max-w-full rounded-lg border border-border bg-card p-3 text-card-foreground shadow-sm\"\n >\n <h3 className=\"mb-3 text-sm font-semibold leading-tight text-foreground\">{title}</h3>\n\n <div className=\"flex gap-6\">\n <RiskCol eye=\"OD\" value={v} disabled={disabled} onToggle={toggleRisk} />\n <div className=\"w-px shrink-0 bg-border\" aria-hidden />\n <RiskCol eye=\"OS\" value={v} disabled={disabled} onToggle={toggleRisk} />\n </div>\n\n {def.description && <p className=\"mt-2 text-xs text-muted-foreground\">{def.description}</p>}\n\n {showError && <p className=\"mt-2 text-xs text-red-500\">{error}</p>}\n </div>\n );\n};\n"]}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkKPGTPJDH_cjs = require('./chunk-KPGTPJDH.cjs');
|
|
4
|
+
var chunkIDSBJOFY_cjs = require('./chunk-IDSBJOFY.cjs');
|
|
5
|
+
var chunkFHHISVCH_cjs = require('./chunk-FHHISVCH.cjs');
|
|
6
|
+
require('react');
|
|
7
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
8
|
+
|
|
9
|
+
var RISKS = [
|
|
10
|
+
"Small pupil",
|
|
11
|
+
"Pseudoexfoliation",
|
|
12
|
+
"Diabetes",
|
|
13
|
+
"Shallow AC",
|
|
14
|
+
"Previous ocular surgery",
|
|
15
|
+
"Zonular weakness",
|
|
16
|
+
"Mature/white cataract"
|
|
17
|
+
];
|
|
18
|
+
var DIABETES = "Diabetes";
|
|
19
|
+
function parseValue(raw) {
|
|
20
|
+
const empty = { OD: [], OS: [] };
|
|
21
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return empty;
|
|
22
|
+
const o = raw;
|
|
23
|
+
const arr = (x) => Array.isArray(x) ? x.filter((i) => typeof i === "string") : [];
|
|
24
|
+
let OD = arr(o.OD);
|
|
25
|
+
let OS = arr(o.OS);
|
|
26
|
+
const odD = OD.includes(DIABETES);
|
|
27
|
+
const osD = OS.includes(DIABETES);
|
|
28
|
+
if (odD !== osD) {
|
|
29
|
+
if (odD && !osD) OS = [...OS, DIABETES];
|
|
30
|
+
else if (osD && !odD) OD = [...OD, DIABETES];
|
|
31
|
+
}
|
|
32
|
+
return { OD, OS };
|
|
33
|
+
}
|
|
34
|
+
function riskTierForCount(n) {
|
|
35
|
+
if (n === 0) return "Low";
|
|
36
|
+
if (n <= 2) return "Moderate";
|
|
37
|
+
return "High";
|
|
38
|
+
}
|
|
39
|
+
function tierBadgeClass(tier) {
|
|
40
|
+
if (tier === "High") return "bg-red-600 text-white";
|
|
41
|
+
if (tier === "Moderate") return "bg-amber-500 text-white";
|
|
42
|
+
return "bg-emerald-600 text-white";
|
|
43
|
+
}
|
|
44
|
+
var DEFAULT_TITLE = "Surgical Risk Flags (Stage 11)";
|
|
45
|
+
function RiskCol({
|
|
46
|
+
eye,
|
|
47
|
+
value,
|
|
48
|
+
disabled,
|
|
49
|
+
onToggle
|
|
50
|
+
}) {
|
|
51
|
+
const selected = new Set(value[eye]);
|
|
52
|
+
const tier = riskTierForCount(selected.size);
|
|
53
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
54
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-2 flex items-center justify-between gap-2", children: [
|
|
55
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-semibold text-foreground", children: eye === "OD" ? "Right Eye (OD)" : "Left Eye (OS)" }),
|
|
56
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
57
|
+
"span",
|
|
58
|
+
{
|
|
59
|
+
className: chunkFHHISVCH_cjs.cn(
|
|
60
|
+
"whitespace-nowrap rounded-full px-2 py-0.5 text-[11px] font-medium",
|
|
61
|
+
tierBadgeClass(tier)
|
|
62
|
+
),
|
|
63
|
+
children: [
|
|
64
|
+
tier,
|
|
65
|
+
" risk"
|
|
66
|
+
]
|
|
67
|
+
}
|
|
68
|
+
)
|
|
69
|
+
] }),
|
|
70
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5", children: RISKS.map((r) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
71
|
+
"label",
|
|
72
|
+
{
|
|
73
|
+
className: "flex cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs hover:bg-muted/50",
|
|
74
|
+
children: [
|
|
75
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
76
|
+
"input",
|
|
77
|
+
{
|
|
78
|
+
type: "checkbox",
|
|
79
|
+
className: "shrink-0",
|
|
80
|
+
checked: selected.has(r),
|
|
81
|
+
disabled,
|
|
82
|
+
onChange: () => onToggle(eye, r)
|
|
83
|
+
}
|
|
84
|
+
),
|
|
85
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: r })
|
|
86
|
+
]
|
|
87
|
+
},
|
|
88
|
+
r
|
|
89
|
+
)) })
|
|
90
|
+
] });
|
|
91
|
+
}
|
|
92
|
+
var SurgicalRiskFlagsWidget = ({ fieldId }) => {
|
|
93
|
+
const { fieldDef, value, setValue, error, disabled, touched } = chunkIDSBJOFY_cjs.useField(fieldId);
|
|
94
|
+
const { state } = chunkKPGTPJDH_cjs.useForm();
|
|
95
|
+
const showError = !!error && (touched || state.submitAttempted);
|
|
96
|
+
if (!fieldDef || fieldDef.type !== "surgical_risk_flags") {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
const def = fieldDef;
|
|
100
|
+
const v = parseValue(value);
|
|
101
|
+
const title = def.meta?.cardTitle?.trim() || (def.label?.trim() ? def.label : DEFAULT_TITLE);
|
|
102
|
+
const toggleRisk = (eye, risk) => {
|
|
103
|
+
const next = {
|
|
104
|
+
OD: [...v.OD],
|
|
105
|
+
OS: [...v.OS]
|
|
106
|
+
};
|
|
107
|
+
if (risk === DIABETES) {
|
|
108
|
+
const had = next.OD.includes(DIABETES) || next.OS.includes(DIABETES);
|
|
109
|
+
if (had) {
|
|
110
|
+
next.OD = next.OD.filter((x) => x !== DIABETES);
|
|
111
|
+
next.OS = next.OS.filter((x) => x !== DIABETES);
|
|
112
|
+
} else {
|
|
113
|
+
if (!next.OD.includes(DIABETES)) next.OD.push(DIABETES);
|
|
114
|
+
if (!next.OS.includes(DIABETES)) next.OS.push(DIABETES);
|
|
115
|
+
}
|
|
116
|
+
setValue(next);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const list = next[eye];
|
|
120
|
+
const i = list.indexOf(risk);
|
|
121
|
+
if (i === -1) list.push(risk);
|
|
122
|
+
else list.splice(i, 1);
|
|
123
|
+
setValue(next);
|
|
124
|
+
};
|
|
125
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
126
|
+
"div",
|
|
127
|
+
{
|
|
128
|
+
id: `surgical-risk-flags-${fieldId}`,
|
|
129
|
+
className: "w-full min-w-0 max-w-full rounded-lg border border-border bg-card p-3 text-card-foreground shadow-sm",
|
|
130
|
+
children: [
|
|
131
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mb-3 text-sm font-semibold leading-tight text-foreground", children: title }),
|
|
132
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-6", children: [
|
|
133
|
+
/* @__PURE__ */ jsxRuntime.jsx(RiskCol, { eye: "OD", value: v, disabled, onToggle: toggleRisk }),
|
|
134
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px shrink-0 bg-border", "aria-hidden": true }),
|
|
135
|
+
/* @__PURE__ */ jsxRuntime.jsx(RiskCol, { eye: "OS", value: v, disabled, onToggle: toggleRisk })
|
|
136
|
+
] }),
|
|
137
|
+
def.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-xs text-muted-foreground", children: def.description }),
|
|
138
|
+
showError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-xs text-red-500", children: error })
|
|
139
|
+
]
|
|
140
|
+
}
|
|
141
|
+
);
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
exports.SurgicalRiskFlagsWidget = SurgicalRiskFlagsWidget;
|
|
145
|
+
//# sourceMappingURL=SurgicalRiskFlagsWidget-JCSL3GWS.cjs.map
|
|
146
|
+
//# sourceMappingURL=SurgicalRiskFlagsWidget-JCSL3GWS.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ui/widgets/SurgicalRiskFlagsWidget.tsx"],"names":["jsxs","jsx","cn","useField","useForm"],"mappings":"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","file":"SurgicalRiskFlagsWidget-JCSL3GWS.cjs","sourcesContent":["import React from 'react';\nimport { useField } from '../../react/useField';\nimport { useForm } from '../../react/useForm';\nimport { cn } from '../../core/utils';\nimport type { SurgicalRiskFlagsFieldDef, SurgicalRiskFlagsValue } from '../../core/types';\n\nconst RISKS = [\n 'Small pupil',\n 'Pseudoexfoliation',\n 'Diabetes',\n 'Shallow AC',\n 'Previous ocular surgery',\n 'Zonular weakness',\n 'Mature/white cataract',\n] as const;\n\ntype Eye = 'OD' | 'OS';\n\nconst DIABETES = 'Diabetes';\n\nfunction parseValue(raw: unknown): SurgicalRiskFlagsValue {\n const empty: SurgicalRiskFlagsValue = { OD: [], OS: [] };\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return empty;\n const o = raw as Record<string, unknown>;\n const arr = (x: unknown): string[] =>\n Array.isArray(x) ? x.filter((i): i is string => typeof i === 'string') : [];\n let OD = arr(o.OD);\n let OS = arr(o.OS);\n const odD = OD.includes(DIABETES);\n const osD = OS.includes(DIABETES);\n if (odD !== osD) {\n if (odD && !osD) OS = [...OS, DIABETES];\n else if (osD && !odD) OD = [...OD, DIABETES];\n }\n return { OD, OS };\n}\n\n/** Heuristic tier from number of flags checked for that eye. */\nfunction riskTierForCount(n: number): 'High' | 'Moderate' | 'Low' {\n if (n === 0) return 'Low';\n if (n <= 2) return 'Moderate';\n return 'High';\n}\n\nfunction tierBadgeClass(tier: 'High' | 'Moderate' | 'Low'): string {\n if (tier === 'High') return 'bg-red-600 text-white';\n if (tier === 'Moderate') return 'bg-amber-500 text-white';\n return 'bg-emerald-600 text-white';\n}\n\nconst DEFAULT_TITLE = 'Surgical Risk Flags (Stage 11)';\n\nfunction RiskCol({\n eye,\n value,\n disabled,\n onToggle,\n}: {\n eye: Eye;\n value: SurgicalRiskFlagsValue;\n disabled?: boolean;\n onToggle: (eye: Eye, risk: string) => void;\n}) {\n const selected = new Set(value[eye]);\n const tier = riskTierForCount(selected.size);\n\n return (\n <div className=\"min-w-0 flex-1\">\n <div className=\"mb-2 flex items-center justify-between gap-2\">\n <div className=\"text-xs font-semibold text-foreground\">\n {eye === 'OD' ? 'Right Eye (OD)' : 'Left Eye (OS)'}\n </div>\n <span\n className={cn(\n 'whitespace-nowrap rounded-full px-2 py-0.5 text-[11px] font-medium',\n tierBadgeClass(tier),\n )}\n >\n {tier} risk\n </span>\n </div>\n <div className=\"space-y-1.5\">\n {RISKS.map((r) => (\n <label\n key={r}\n className=\"flex cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs hover:bg-muted/50\"\n >\n <input\n type=\"checkbox\"\n className=\"shrink-0\"\n checked={selected.has(r)}\n disabled={disabled}\n onChange={() => onToggle(eye, r)}\n />\n <span>{r}</span>\n </label>\n ))}\n </div>\n </div>\n );\n}\n\nexport const SurgicalRiskFlagsWidget: React.FC<{ fieldId: string }> = ({ fieldId }) => {\n const { fieldDef, value, setValue, error, disabled, touched } = useField(fieldId);\n const { state } = useForm();\n const showError = !!error && (touched || state.submitAttempted);\n\n if (!fieldDef || fieldDef.type !== 'surgical_risk_flags') {\n return null;\n }\n\n const def = fieldDef as SurgicalRiskFlagsFieldDef;\n const v = parseValue(value);\n const title =\n (def.meta?.cardTitle as string | undefined)?.trim() ||\n (def.label?.trim() ? def.label : DEFAULT_TITLE);\n\n const toggleRisk = (eye: Eye, risk: string) => {\n const next: SurgicalRiskFlagsValue = {\n OD: [...v.OD],\n OS: [...v.OS],\n };\n\n if (risk === DIABETES) {\n const had = next.OD.includes(DIABETES) || next.OS.includes(DIABETES);\n if (had) {\n next.OD = next.OD.filter((x) => x !== DIABETES);\n next.OS = next.OS.filter((x) => x !== DIABETES);\n } else {\n if (!next.OD.includes(DIABETES)) next.OD.push(DIABETES);\n if (!next.OS.includes(DIABETES)) next.OS.push(DIABETES);\n }\n setValue(next);\n return;\n }\n\n const list = next[eye];\n const i = list.indexOf(risk);\n if (i === -1) list.push(risk);\n else list.splice(i, 1);\n setValue(next);\n };\n\n return (\n <div\n id={`surgical-risk-flags-${fieldId}`}\n className=\"w-full min-w-0 max-w-full rounded-lg border border-border bg-card p-3 text-card-foreground shadow-sm\"\n >\n <h3 className=\"mb-3 text-sm font-semibold leading-tight text-foreground\">{title}</h3>\n\n <div className=\"flex gap-6\">\n <RiskCol eye=\"OD\" value={v} disabled={disabled} onToggle={toggleRisk} />\n <div className=\"w-px shrink-0 bg-border\" aria-hidden />\n <RiskCol eye=\"OS\" value={v} disabled={disabled} onToggle={toggleRisk} />\n </div>\n\n {def.description && <p className=\"mt-2 text-xs text-muted-foreground\">{def.description}</p>}\n\n {showError && <p className=\"mt-2 text-xs text-red-500\">{error}</p>}\n </div>\n );\n};\n"]}
|