formanitor 0.0.26 → 0.0.28
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 +196 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -3
- package/dist/index.d.ts +35 -3
- package/dist/index.mjs +196 -17
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -430,6 +430,11 @@ var FormStore = class {
|
|
|
430
430
|
result[field.id] = raw?.text ?? null;
|
|
431
431
|
return;
|
|
432
432
|
}
|
|
433
|
+
if (field.type === "diagnosis_textarea") {
|
|
434
|
+
const raw = values[field.id];
|
|
435
|
+
result[field.id] = typeof raw === "string" ? raw : raw && typeof raw === "object" ? raw.text ?? null : null;
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
433
438
|
if (field.type === "ophthal_diagnosis") {
|
|
434
439
|
const raw = values[field.id];
|
|
435
440
|
const formatEye = (eyeData, eyeLabel) => {
|
|
@@ -3360,8 +3365,9 @@ var AddInvestigationField = ({
|
|
|
3360
3365
|
const debounceRef = React13.useRef(null);
|
|
3361
3366
|
const valueRef = React13.useRef([]);
|
|
3362
3367
|
const searchInputRef = React13.useRef(null);
|
|
3363
|
-
|
|
3364
|
-
|
|
3368
|
+
const safeValue = Array.isArray(value) ? value : [];
|
|
3369
|
+
valueRef.current = safeValue;
|
|
3370
|
+
const addedIds = new Set(safeValue.map((inv) => inv.id));
|
|
3365
3371
|
React13.useEffect(() => {
|
|
3366
3372
|
if (!open) {
|
|
3367
3373
|
setQuery("");
|
|
@@ -3404,7 +3410,7 @@ var AddInvestigationField = ({
|
|
|
3404
3410
|
}, ADD_FEEDBACK_MS2);
|
|
3405
3411
|
}
|
|
3406
3412
|
function removeInvestigation(id) {
|
|
3407
|
-
onChange(
|
|
3413
|
+
onChange(safeValue.filter((inv) => inv.id !== id));
|
|
3408
3414
|
}
|
|
3409
3415
|
function handleRecentlyUsedToggle(result) {
|
|
3410
3416
|
if (addedIds.has(result.id)) {
|
|
@@ -3416,10 +3422,10 @@ var AddInvestigationField = ({
|
|
|
3416
3422
|
async function handleFrequentItemToggle(item) {
|
|
3417
3423
|
const id = String(item.id);
|
|
3418
3424
|
const addedById = addedIds.has(id);
|
|
3419
|
-
const addedByName =
|
|
3425
|
+
const addedByName = safeValue.some((inv) => inv.name === item.name);
|
|
3420
3426
|
if (addedById || addedByName) {
|
|
3421
3427
|
if (addedById) removeInvestigation(id);
|
|
3422
|
-
else onChange(
|
|
3428
|
+
else onChange(safeValue.filter((inv) => inv.name !== item.name));
|
|
3423
3429
|
return;
|
|
3424
3430
|
}
|
|
3425
3431
|
setAddingFrequentId(id);
|
|
@@ -3455,7 +3461,7 @@ var AddInvestigationField = ({
|
|
|
3455
3461
|
const limitedFrequentItems = frequentItems.slice(0, 25);
|
|
3456
3462
|
const frequentItemChips = limitedFrequentItems.length > 0 ? limitedFrequentItems.map((item) => {
|
|
3457
3463
|
const id = String(item.id);
|
|
3458
|
-
const isAdded =
|
|
3464
|
+
const isAdded = safeValue.some((inv) => inv.id === id) || safeValue.some((inv) => inv.name === item.name);
|
|
3459
3465
|
const isAdding = addingFrequentId === id;
|
|
3460
3466
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3461
3467
|
"button",
|
|
@@ -3489,7 +3495,7 @@ var AddInvestigationField = ({
|
|
|
3489
3495
|
}
|
|
3490
3496
|
)
|
|
3491
3497
|
] }),
|
|
3492
|
-
|
|
3498
|
+
safeValue.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-border rounded-lg border border-border overflow-hidden", children: safeValue.map((inv) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3493
3499
|
"div",
|
|
3494
3500
|
{
|
|
3495
3501
|
className: "flex items-center justify-between px-3 py-2 bg-white hover:bg-gray-50",
|
|
@@ -3556,10 +3562,11 @@ var AddInvestigationWidget = ({ fieldId }) => {
|
|
|
3556
3562
|
const { value, setValue } = useField(fieldId);
|
|
3557
3563
|
const handlers = useFieldHandlers(fieldId);
|
|
3558
3564
|
const { investigations: frequentInvestigations } = useFrequentItems();
|
|
3565
|
+
const safeValue = Array.isArray(value) ? value : [];
|
|
3559
3566
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3560
3567
|
AddInvestigationField,
|
|
3561
3568
|
{
|
|
3562
|
-
value:
|
|
3569
|
+
value: safeValue,
|
|
3563
3570
|
onChange: setValue,
|
|
3564
3571
|
onSearch: handlers.onSearch,
|
|
3565
3572
|
recentlyUsed: handlers.recentlyUsed,
|
|
@@ -3596,9 +3603,10 @@ var AddProcedureField = ({
|
|
|
3596
3603
|
const debounceRef = React13.useRef(null);
|
|
3597
3604
|
const valueRef = React13.useRef([]);
|
|
3598
3605
|
const searchInputRef = React13.useRef(null);
|
|
3599
|
-
|
|
3606
|
+
const safeValue = Array.isArray(value) ? value : [];
|
|
3607
|
+
valueRef.current = safeValue;
|
|
3600
3608
|
const addedIds = new Set(
|
|
3601
|
-
|
|
3609
|
+
safeValue.filter((proc) => !proc.is_custom).map((proc) => proc.id)
|
|
3602
3610
|
);
|
|
3603
3611
|
React13.useEffect(() => {
|
|
3604
3612
|
if (!open) {
|
|
@@ -3642,10 +3650,10 @@ var AddProcedureField = ({
|
|
|
3642
3650
|
}, ADD_FEEDBACK_MS3);
|
|
3643
3651
|
}
|
|
3644
3652
|
function removeAt(index) {
|
|
3645
|
-
onChange(
|
|
3653
|
+
onChange(safeValue.filter((_, i) => i !== index));
|
|
3646
3654
|
}
|
|
3647
3655
|
function removeBySearchId(id) {
|
|
3648
|
-
onChange(
|
|
3656
|
+
onChange(safeValue.filter((proc) => proc.is_custom || proc.id !== id));
|
|
3649
3657
|
}
|
|
3650
3658
|
function handleAddCustom() {
|
|
3651
3659
|
const trimmed = query.trim();
|
|
@@ -3665,10 +3673,10 @@ var AddProcedureField = ({
|
|
|
3665
3673
|
async function handleFrequentItemToggle(item) {
|
|
3666
3674
|
const id = String(item.id);
|
|
3667
3675
|
const addedById = addedIds.has(id);
|
|
3668
|
-
const addedByName =
|
|
3676
|
+
const addedByName = safeValue.some((proc) => proc.name === item.name);
|
|
3669
3677
|
if (addedById || addedByName) {
|
|
3670
3678
|
if (addedById) removeBySearchId(id);
|
|
3671
|
-
else onChange(
|
|
3679
|
+
else onChange(safeValue.filter((proc) => proc.name !== item.name));
|
|
3672
3680
|
return;
|
|
3673
3681
|
}
|
|
3674
3682
|
setAddingFrequentId(id);
|
|
@@ -3704,7 +3712,7 @@ var AddProcedureField = ({
|
|
|
3704
3712
|
const limitedFrequentItems = frequentItems.slice(0, 25);
|
|
3705
3713
|
const frequentItemChips = limitedFrequentItems.length > 0 ? limitedFrequentItems.map((item) => {
|
|
3706
3714
|
const id = String(item.id);
|
|
3707
|
-
const isAdded =
|
|
3715
|
+
const isAdded = safeValue.some((proc) => !proc.is_custom && proc.id === id) || safeValue.some((proc) => proc.name === item.name);
|
|
3708
3716
|
const isAdding = addingFrequentId === id;
|
|
3709
3717
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3710
3718
|
"button",
|
|
@@ -3738,7 +3746,7 @@ var AddProcedureField = ({
|
|
|
3738
3746
|
}
|
|
3739
3747
|
)
|
|
3740
3748
|
] }),
|
|
3741
|
-
|
|
3749
|
+
safeValue.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-border rounded-lg border border-border overflow-hidden", children: safeValue.map((proc, index) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3742
3750
|
"div",
|
|
3743
3751
|
{
|
|
3744
3752
|
className: "flex items-center justify-between px-3 py-2 bg-white hover:bg-gray-50",
|
|
@@ -3818,10 +3826,11 @@ var AddProcedureWidget = ({ fieldId }) => {
|
|
|
3818
3826
|
const { value, setValue } = useField(fieldId);
|
|
3819
3827
|
const handlers = useFieldHandlers(fieldId);
|
|
3820
3828
|
const { procedures: frequentProcedures } = useFrequentItems();
|
|
3829
|
+
const safeValue = Array.isArray(value) ? value : [];
|
|
3821
3830
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3822
3831
|
AddProcedureField,
|
|
3823
3832
|
{
|
|
3824
|
-
value:
|
|
3833
|
+
value: safeValue,
|
|
3825
3834
|
onChange: setValue,
|
|
3826
3835
|
onSearch: handlers.onSearch,
|
|
3827
3836
|
recentlyUsed: handlers.recentlyUsed,
|
|
@@ -4790,6 +4799,174 @@ var SmartTextareaWidget = ({ fieldId }) => {
|
|
|
4790
4799
|
showError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-red-500", children: error })
|
|
4791
4800
|
] });
|
|
4792
4801
|
};
|
|
4802
|
+
function normalizeDiagnosisGrades(payload) {
|
|
4803
|
+
const result = [];
|
|
4804
|
+
const pushGroup = (conditionRaw, gradesRaw) => {
|
|
4805
|
+
const condition = typeof conditionRaw === "string" ? conditionRaw.trim() : "";
|
|
4806
|
+
if (!condition) return;
|
|
4807
|
+
if (!Array.isArray(gradesRaw)) return;
|
|
4808
|
+
const grades = Array.from(
|
|
4809
|
+
new Set(
|
|
4810
|
+
gradesRaw.map((grade) => typeof grade === "string" ? grade.trim() : "").filter(Boolean)
|
|
4811
|
+
)
|
|
4812
|
+
);
|
|
4813
|
+
if (grades.length === 0) return;
|
|
4814
|
+
result.push({ condition, grades });
|
|
4815
|
+
};
|
|
4816
|
+
const asArrayResponse = payload;
|
|
4817
|
+
if (Array.isArray(asArrayResponse?.diagnosisGrades)) {
|
|
4818
|
+
asArrayResponse.diagnosisGrades.forEach((item) => {
|
|
4819
|
+
pushGroup(item?.condition, item?.grades);
|
|
4820
|
+
});
|
|
4821
|
+
return result;
|
|
4822
|
+
}
|
|
4823
|
+
const asMapResponse = payload;
|
|
4824
|
+
const mapLike = asMapResponse?.field === "diagnosisgrade" && asMapResponse?.value && typeof asMapResponse.value === "object" ? asMapResponse.value : null;
|
|
4825
|
+
if (mapLike) {
|
|
4826
|
+
Object.entries(mapLike).forEach(([condition, grades]) => {
|
|
4827
|
+
pushGroup(condition, grades);
|
|
4828
|
+
});
|
|
4829
|
+
}
|
|
4830
|
+
return result;
|
|
4831
|
+
}
|
|
4832
|
+
var DiagnosisTextareaWidget = ({ fieldId }) => {
|
|
4833
|
+
const { fieldDef, value, setValue, setTouched, error, disabled, touched } = useField(fieldId);
|
|
4834
|
+
const { state } = useForm();
|
|
4835
|
+
const handler = useFieldHandlers(fieldId);
|
|
4836
|
+
const def = fieldDef;
|
|
4837
|
+
const [gradeGroups, setGradeGroups] = React13__namespace.default.useState([]);
|
|
4838
|
+
const [isLoadingGrades, setIsLoadingGrades] = React13__namespace.default.useState(false);
|
|
4839
|
+
const normalized = React13__namespace.default.useMemo(() => {
|
|
4840
|
+
const raw = value;
|
|
4841
|
+
if (typeof raw === "string") {
|
|
4842
|
+
return { text: raw, selectedGradesByCondition: {} };
|
|
4843
|
+
}
|
|
4844
|
+
if (!raw || typeof raw !== "object") {
|
|
4845
|
+
return { text: "", selectedGradesByCondition: {} };
|
|
4846
|
+
}
|
|
4847
|
+
const text = typeof raw.text === "string" ? raw.text : "";
|
|
4848
|
+
const mapRaw = raw.selectedGradesByCondition;
|
|
4849
|
+
let selectedGradesByCondition = {};
|
|
4850
|
+
if (mapRaw && typeof mapRaw === "object" && !Array.isArray(mapRaw)) {
|
|
4851
|
+
const entries = Object.entries(mapRaw);
|
|
4852
|
+
for (const [condition, gradeRaw] of entries) {
|
|
4853
|
+
if (typeof condition !== "string") continue;
|
|
4854
|
+
if (typeof gradeRaw === "string" && gradeRaw.trim()) {
|
|
4855
|
+
selectedGradesByCondition[condition] = gradeRaw;
|
|
4856
|
+
}
|
|
4857
|
+
}
|
|
4858
|
+
}
|
|
4859
|
+
const sg = raw.selectedGrade;
|
|
4860
|
+
if (sg && typeof sg === "object" && typeof sg.condition === "string" && typeof sg.grade === "string") {
|
|
4861
|
+
const condition = sg.condition.trim();
|
|
4862
|
+
const grade = sg.grade.trim();
|
|
4863
|
+
if (condition && grade && !selectedGradesByCondition[condition]) {
|
|
4864
|
+
selectedGradesByCondition = { ...selectedGradesByCondition, [condition]: grade };
|
|
4865
|
+
}
|
|
4866
|
+
}
|
|
4867
|
+
return { text, selectedGradesByCondition };
|
|
4868
|
+
}, [value]);
|
|
4869
|
+
const textValue = normalized.text;
|
|
4870
|
+
const showError = !!error && (touched || state.submitAttempted);
|
|
4871
|
+
React13__namespace.default.useEffect(() => {
|
|
4872
|
+
const query = textValue.trim();
|
|
4873
|
+
const fetchGrades = handler.onFetchDiagnosisGrades;
|
|
4874
|
+
const debounceMs = def?.debounceDelay ?? 1e3;
|
|
4875
|
+
if (!query || !fetchGrades) {
|
|
4876
|
+
setGradeGroups([]);
|
|
4877
|
+
setIsLoadingGrades(false);
|
|
4878
|
+
return;
|
|
4879
|
+
}
|
|
4880
|
+
let isActive = true;
|
|
4881
|
+
const timer = window.setTimeout(async () => {
|
|
4882
|
+
setIsLoadingGrades(true);
|
|
4883
|
+
try {
|
|
4884
|
+
const response = await fetchGrades(query);
|
|
4885
|
+
if (!isActive) return;
|
|
4886
|
+
setGradeGroups(normalizeDiagnosisGrades(response));
|
|
4887
|
+
} catch {
|
|
4888
|
+
if (!isActive) return;
|
|
4889
|
+
setGradeGroups([]);
|
|
4890
|
+
} finally {
|
|
4891
|
+
if (isActive) setIsLoadingGrades(false);
|
|
4892
|
+
}
|
|
4893
|
+
}, debounceMs);
|
|
4894
|
+
return () => {
|
|
4895
|
+
isActive = false;
|
|
4896
|
+
window.clearTimeout(timer);
|
|
4897
|
+
};
|
|
4898
|
+
}, [textValue, handler.onFetchDiagnosisGrades, def?.debounceDelay]);
|
|
4899
|
+
if (!def) return null;
|
|
4900
|
+
const theme = getThemeConfig("textarea", def.theme);
|
|
4901
|
+
const wrapperClass = theme?.wrapperClassName ?? "space-y-2";
|
|
4902
|
+
const labelClass = theme?.labelClassName;
|
|
4903
|
+
const inputClass = cn(theme?.inputClassName, showError && "border-red-500");
|
|
4904
|
+
const toggleSelectedGrade = (condition, grade) => {
|
|
4905
|
+
if (disabled) return;
|
|
4906
|
+
const current = normalized.selectedGradesByCondition[condition];
|
|
4907
|
+
const nextForCondition = current === grade ? "" : grade;
|
|
4908
|
+
const nextMap = { ...normalized.selectedGradesByCondition };
|
|
4909
|
+
if (!nextForCondition) {
|
|
4910
|
+
delete nextMap[condition];
|
|
4911
|
+
} else {
|
|
4912
|
+
nextMap[condition] = nextForCondition;
|
|
4913
|
+
}
|
|
4914
|
+
setValue({ text: normalized.text, selectedGradesByCondition: nextMap });
|
|
4915
|
+
setTouched();
|
|
4916
|
+
};
|
|
4917
|
+
const labelContent = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4918
|
+
def.label,
|
|
4919
|
+
" ",
|
|
4920
|
+
def.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500", children: "*" })
|
|
4921
|
+
] });
|
|
4922
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: wrapperClass, children: [
|
|
4923
|
+
theme ? /* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: fieldId, className: labelClass, children: labelContent }) : /* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: fieldId, children: labelContent }),
|
|
4924
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4925
|
+
Textarea,
|
|
4926
|
+
{
|
|
4927
|
+
id: fieldId,
|
|
4928
|
+
value: textValue,
|
|
4929
|
+
onChange: (e) => setValue({ text: e.target.value, selectedGradesByCondition: normalized.selectedGradesByCondition }),
|
|
4930
|
+
onBlur: setTouched,
|
|
4931
|
+
disabled,
|
|
4932
|
+
placeholder: def.placeholder,
|
|
4933
|
+
className: inputClass,
|
|
4934
|
+
...def.height != null ? { height: def.height } : {}
|
|
4935
|
+
}
|
|
4936
|
+
),
|
|
4937
|
+
isLoadingGrades && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-xs text-muted-foreground", children: "Checking diagnosis grades..." }),
|
|
4938
|
+
!isLoadingGrades && gradeGroups.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4939
|
+
"div",
|
|
4940
|
+
{
|
|
4941
|
+
className: "mt-2 space-y-3 rounded-lg border border-border bg-muted/30 p-3",
|
|
4942
|
+
role: "group",
|
|
4943
|
+
"aria-label": "Diagnosis grade options",
|
|
4944
|
+
children: gradeGroups.map((group) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
4945
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-medium leading-none text-muted-foreground", children: [
|
|
4946
|
+
group.condition,
|
|
4947
|
+
":"
|
|
4948
|
+
] }),
|
|
4949
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: group.grades.map((grade) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4950
|
+
"button",
|
|
4951
|
+
{
|
|
4952
|
+
type: "button",
|
|
4953
|
+
onClick: () => toggleSelectedGrade(group.condition, grade),
|
|
4954
|
+
disabled,
|
|
4955
|
+
className: cn(
|
|
4956
|
+
"inline-flex min-h-8 items-center rounded-full border px-3 py-1 text-xs font-medium leading-none transition-colors",
|
|
4957
|
+
normalized.selectedGradesByCondition[group.condition] === grade ? "border-primary bg-primary/15 text-primary shadow-sm" : "border-border/80 bg-background text-foreground hover:bg-muted/80",
|
|
4958
|
+
disabled && "cursor-not-allowed opacity-60"
|
|
4959
|
+
),
|
|
4960
|
+
children: grade
|
|
4961
|
+
},
|
|
4962
|
+
`${group.condition}-${grade}`
|
|
4963
|
+
)) })
|
|
4964
|
+
] }, group.condition))
|
|
4965
|
+
}
|
|
4966
|
+
),
|
|
4967
|
+
showError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-red-500", children: error })
|
|
4968
|
+
] });
|
|
4969
|
+
};
|
|
4793
4970
|
var DEFAULT_DRAFT = {
|
|
4794
4971
|
gpal: { G: 0, P: 0, A: 0, L: 0 },
|
|
4795
4972
|
lmp: "",
|
|
@@ -7143,6 +7320,8 @@ var FieldRenderer = ({ fieldId }) => {
|
|
|
7143
7320
|
return /* @__PURE__ */ jsxRuntime.jsx(FollowupWidget, { fieldId });
|
|
7144
7321
|
case "smart_textarea":
|
|
7145
7322
|
return /* @__PURE__ */ jsxRuntime.jsx(SmartTextareaWidget, { fieldId });
|
|
7323
|
+
case "diagnosis_textarea":
|
|
7324
|
+
return /* @__PURE__ */ jsxRuntime.jsx(DiagnosisTextareaWidget, { fieldId });
|
|
7146
7325
|
case "obstetric_history":
|
|
7147
7326
|
return /* @__PURE__ */ jsxRuntime.jsx(ObstetricHistoryWidget, { fieldId });
|
|
7148
7327
|
case "eye_prescription":
|