formanitor 0.0.10 → 0.0.12
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 +2010 -124
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +251 -4
- package/dist/index.d.ts +251 -4
- package/dist/index.mjs +2008 -128
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
|
-
type FieldType = 'text' | 'number' | 'textarea' | 'select' | 'multiselect' | 'radio' | 'repeatable' | 'checkbox' | 'image_upload' | 'signature' | 'date' | 'datetime' | 'editable_table' | 'static_text' | string;
|
|
3
|
+
type FieldType = 'text' | 'number' | 'textarea' | 'select' | 'multiselect' | 'radio' | 'repeatable' | 'checkbox' | 'image_upload' | 'signature' | 'date' | 'datetime' | 'editable_table' | 'static_text' | 'medications' | 'investigations' | 'procedures' | 'vitals' | 'referral' | 'followup' | string;
|
|
4
4
|
interface ValidationRule {
|
|
5
5
|
min?: number;
|
|
6
6
|
max?: number;
|
|
@@ -42,6 +42,26 @@ interface BaseFieldDef {
|
|
|
42
42
|
disabled?: boolean;
|
|
43
43
|
hidden?: boolean;
|
|
44
44
|
prefill?: FieldPrefill;
|
|
45
|
+
/**
|
|
46
|
+
* High-level column position in SmartForm layout.
|
|
47
|
+
* - "left" and "right" are narrow side columns.
|
|
48
|
+
* - "center" is the main content column and is 2× the width of side columns.
|
|
49
|
+
* Default: "center" when omitted.
|
|
50
|
+
*/
|
|
51
|
+
position?: 'left' | 'center' | 'right';
|
|
52
|
+
/**
|
|
53
|
+
* How many layout columns this field spans horizontally.
|
|
54
|
+
* - 1 = occupies its own column (e.g. just "left", just "center", or just "right")
|
|
55
|
+
* - 2 = spans into an adjacent column (e.g. left+center or center+right)
|
|
56
|
+
* Default: 1.
|
|
57
|
+
*/
|
|
58
|
+
colSpan?: 1 | 2;
|
|
59
|
+
/**
|
|
60
|
+
* Optional theme name for component styling.
|
|
61
|
+
* Renders the field with theme-specific styles (e.g. textarea with "highlight-label"
|
|
62
|
+
* shows the label in a colored block above the input).
|
|
63
|
+
*/
|
|
64
|
+
theme?: string;
|
|
45
65
|
meta?: Record<string, unknown>;
|
|
46
66
|
}
|
|
47
67
|
interface TextFieldDef extends BaseFieldDef {
|
|
@@ -118,7 +138,55 @@ interface StaticTextFieldDef extends BaseFieldDef {
|
|
|
118
138
|
/** Display size. Default: 'regular'. */
|
|
119
139
|
size?: 'regular' | 'large';
|
|
120
140
|
}
|
|
121
|
-
|
|
141
|
+
interface MedicationsFieldDef extends BaseFieldDef {
|
|
142
|
+
type: 'medications';
|
|
143
|
+
}
|
|
144
|
+
interface InvestigationsFieldDef extends BaseFieldDef {
|
|
145
|
+
type: 'investigations';
|
|
146
|
+
}
|
|
147
|
+
interface ProceduresFieldDef extends BaseFieldDef {
|
|
148
|
+
type: 'procedures';
|
|
149
|
+
}
|
|
150
|
+
interface DifferentialDiagnosisFieldDef extends BaseFieldDef {
|
|
151
|
+
type: 'differential_diagnosis';
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* A read-only vitals panel populated by an external API fetch.
|
|
155
|
+
* The consumer provides `onFetch` in `fieldHandlers` for this field ID.
|
|
156
|
+
* The fetched value (raw vitals object) is stored in form state and included in submission.
|
|
157
|
+
*/
|
|
158
|
+
interface VitalsFieldDef extends BaseFieldDef {
|
|
159
|
+
type: 'vitals';
|
|
160
|
+
}
|
|
161
|
+
/** One selected referral. Stored in form state as an array of these. */
|
|
162
|
+
interface ReferralItem {
|
|
163
|
+
specialization: string;
|
|
164
|
+
is_urgent: boolean;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Referral field: label "Referral to" with a multiselect dropdown and chips.
|
|
168
|
+
* Value shape: ReferralItem[] e.g. [{ specialization: "Cardiology", is_urgent: false }, ...].
|
|
169
|
+
* Options via fieldHandlers[fieldId].onFetchOptions (e.g. { specializations: string[] }).
|
|
170
|
+
*/
|
|
171
|
+
interface ReferralFieldDef extends BaseFieldDef {
|
|
172
|
+
type: 'referral';
|
|
173
|
+
options?: SelectOption[];
|
|
174
|
+
}
|
|
175
|
+
/** Stored value for followup field: false/null = no followup; object = one-time followup as number of days from current date. */
|
|
176
|
+
interface FollowupValue {
|
|
177
|
+
followupType: 'one time';
|
|
178
|
+
/** Number of days from (current) date when set; always stored as string. */
|
|
179
|
+
value: string;
|
|
180
|
+
unit: 'days';
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Follow-up field: "No Follow-up" | "One Time" with schedule by duration (e.g. 7 days) or by date.
|
|
184
|
+
* Value shape: false | FollowupValue.
|
|
185
|
+
*/
|
|
186
|
+
interface FollowupFieldDef extends BaseFieldDef {
|
|
187
|
+
type: 'followup';
|
|
188
|
+
}
|
|
189
|
+
type FieldDef = TextFieldDef | NumberFieldDef | SelectFieldDef | RadioFieldDef | CheckboxFieldDef | RepeatableFieldDef | ImageUploadFieldDef | SignatureFieldDef | EditableTableFieldDef | StaticTextFieldDef | MedicationsFieldDef | InvestigationsFieldDef | ProceduresFieldDef | DifferentialDiagnosisFieldDef | VitalsFieldDef | ReferralFieldDef | FollowupFieldDef | BaseFieldDef;
|
|
122
190
|
interface Condition {
|
|
123
191
|
field?: string;
|
|
124
192
|
op: '==' | '!=' | '>' | '<' | '>=' | '<=' | 'in' | 'contains';
|
|
@@ -180,7 +248,25 @@ interface SumComputation {
|
|
|
180
248
|
type: 'sum';
|
|
181
249
|
fields: string[];
|
|
182
250
|
}
|
|
183
|
-
|
|
251
|
+
/** Expression node for formula computation: field ref, number, or binary op. */
|
|
252
|
+
type FormulaExpr = {
|
|
253
|
+
type: 'field';
|
|
254
|
+
field: string;
|
|
255
|
+
} | {
|
|
256
|
+
type: 'number';
|
|
257
|
+
value: number;
|
|
258
|
+
} | {
|
|
259
|
+
type: 'op';
|
|
260
|
+
op: '+' | '-' | '*' | '/' | '**';
|
|
261
|
+
left: FormulaExpr;
|
|
262
|
+
right: FormulaExpr;
|
|
263
|
+
};
|
|
264
|
+
interface FormulaComputation {
|
|
265
|
+
target: string;
|
|
266
|
+
type: 'formula';
|
|
267
|
+
expression: FormulaExpr;
|
|
268
|
+
}
|
|
269
|
+
type Computation = SumComputation | ScoreComputation | FormulaComputation;
|
|
184
270
|
interface FormDef {
|
|
185
271
|
id: string;
|
|
186
272
|
version: number;
|
|
@@ -244,12 +330,14 @@ interface PersistenceProvider {
|
|
|
244
330
|
type Listener = (state: FormState) => void;
|
|
245
331
|
type EventListener = (event: string, payload?: any) => void;
|
|
246
332
|
type UploadHandler = (file: File | Blob, filename: string) => Promise<string>;
|
|
333
|
+
type DraftChangeHandler = (payload: SavedState) => void | Promise<void>;
|
|
247
334
|
interface StoreConfig {
|
|
248
335
|
persistence?: PersistenceProvider;
|
|
249
336
|
prefillData?: Record<string, any>;
|
|
250
337
|
role?: string;
|
|
251
338
|
onEvent?: EventListener;
|
|
252
339
|
onUpload?: UploadHandler;
|
|
340
|
+
onDraftChange?: DraftChangeHandler;
|
|
253
341
|
}
|
|
254
342
|
declare class FormStore {
|
|
255
343
|
private state;
|
|
@@ -260,6 +348,7 @@ declare class FormStore {
|
|
|
260
348
|
private prefillData;
|
|
261
349
|
private config;
|
|
262
350
|
private saveTimeout;
|
|
351
|
+
private draftCallbackTimeout;
|
|
263
352
|
constructor(schema: FormDef, config?: StoreConfig);
|
|
264
353
|
private initializeDefaults;
|
|
265
354
|
getState(): FormState;
|
|
@@ -274,10 +363,20 @@ declare class FormStore {
|
|
|
274
363
|
getFieldDef(fieldId: string): FieldDef | undefined;
|
|
275
364
|
hasPersistence(): boolean;
|
|
276
365
|
setValue(fieldId: string, value: any): void;
|
|
366
|
+
/**
|
|
367
|
+
* Set multiple values at once (e.g. from AI analysis). Only updates keys that
|
|
368
|
+
* exist in the schema. Runs evaluate/notify/save once.
|
|
369
|
+
* @param partial Map of fieldId -> value
|
|
370
|
+
* @param options.touch If false, do not mark fields as touched (e.g. for AI-suggested values)
|
|
371
|
+
*/
|
|
372
|
+
setValues(partial: Record<string, any>, options?: {
|
|
373
|
+
touch?: boolean;
|
|
374
|
+
}): void;
|
|
277
375
|
setTouched(fieldId: string): void;
|
|
278
376
|
setRole(role: string): void;
|
|
279
377
|
load(): Promise<void>;
|
|
280
378
|
private scheduleSave;
|
|
379
|
+
private scheduleDraftCallback;
|
|
281
380
|
save(): Promise<void>;
|
|
282
381
|
/**
|
|
283
382
|
* Prepare values for outbound submission to the backend.
|
|
@@ -334,9 +433,32 @@ interface RuleResult {
|
|
|
334
433
|
}
|
|
335
434
|
declare function evaluateRules(values: FormValues, rules: Rule[], fields: Record<string, FieldDef>): RuleResult;
|
|
336
435
|
|
|
436
|
+
type FieldHandler = {
|
|
437
|
+
onSearch: (query: string) => Promise<any[]>;
|
|
438
|
+
recentlyUsed?: any[];
|
|
439
|
+
/**
|
|
440
|
+
* Called by widgets that display externally-fetched data (e.g. vitals).
|
|
441
|
+
* Invoked once on mount and again when the user hits the refresh button.
|
|
442
|
+
* The resolved value is written directly into the field's form state.
|
|
443
|
+
*/
|
|
444
|
+
onFetch?: () => Promise<any>;
|
|
445
|
+
/**
|
|
446
|
+
* Called by the referral widget to load dropdown options. May return
|
|
447
|
+
* { specializations: string[] } or { label: string; value: any }[].
|
|
448
|
+
*/
|
|
449
|
+
onFetchOptions?: () => Promise<{
|
|
450
|
+
specializations?: string[];
|
|
451
|
+
} | {
|
|
452
|
+
label: string;
|
|
453
|
+
value: any;
|
|
454
|
+
}[]>;
|
|
455
|
+
};
|
|
456
|
+
type FieldHandlersMap = Record<string, FieldHandler>;
|
|
457
|
+
declare function useFieldHandlers(fieldId: string): FieldHandler;
|
|
337
458
|
interface FormProviderProps {
|
|
338
459
|
schema: FormDef;
|
|
339
460
|
config?: StoreConfig;
|
|
461
|
+
fieldHandlers?: FieldHandlersMap;
|
|
340
462
|
children: React.ReactNode;
|
|
341
463
|
}
|
|
342
464
|
declare const FormProvider: React.FC<FormProviderProps>;
|
|
@@ -372,6 +494,35 @@ declare function useField(fieldId: string): {
|
|
|
372
494
|
|
|
373
495
|
declare const DynamicForm: React.FC;
|
|
374
496
|
|
|
497
|
+
/** Shape of one differential diagnosis item from AI (must match form field value) */
|
|
498
|
+
type AIDifferentialDiagnosisItem = {
|
|
499
|
+
category: string;
|
|
500
|
+
condition: string;
|
|
501
|
+
likelihood: string;
|
|
502
|
+
severity: string;
|
|
503
|
+
treatability: string;
|
|
504
|
+
keyFeatures?: string[];
|
|
505
|
+
nextSteps?: string[];
|
|
506
|
+
};
|
|
507
|
+
interface SmartFormProps {
|
|
508
|
+
/**
|
|
509
|
+
* Structured result from AI analysis (e.g. patient-doctor conversation).
|
|
510
|
+
* When this is set or updated, values are applied to the form by field ID.
|
|
511
|
+
* Only keys that exist in the form schema are applied; unknown keys are ignored.
|
|
512
|
+
* Fields are not marked as "touched" so you can distinguish AI-suggested vs user-edited if needed.
|
|
513
|
+
* Listens to both reference and content changes (e.g. streaming updates to the same object).
|
|
514
|
+
*/
|
|
515
|
+
aiAnalysisResult?: Record<string, any> | null;
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* Form view that supports applying AI analysis results after load. Use inside
|
|
519
|
+
* FormProvider like DynamicForm. When aiAnalysisResult is provided (e.g. when
|
|
520
|
+
* AI finishes analyzing conversation), its values are applied to the form in
|
|
521
|
+
* one batch without marking fields as touched. Re-applies when the result
|
|
522
|
+
* reference or content changes (e.g. streaming or incremental AI updates).
|
|
523
|
+
*/
|
|
524
|
+
declare const SmartForm: React.FC<SmartFormProps>;
|
|
525
|
+
|
|
375
526
|
interface FieldRendererProps {
|
|
376
527
|
fieldId: string;
|
|
377
528
|
}
|
|
@@ -457,4 +608,100 @@ interface CreateUploadHandlerOptions {
|
|
|
457
608
|
*/
|
|
458
609
|
declare function createUploadHandler(options: CreateUploadHandlerOptions): (file: File | Blob, filename: string) => Promise<string>;
|
|
459
610
|
|
|
460
|
-
|
|
611
|
+
/** Shape of a medication as returned by AI analysis */
|
|
612
|
+
type AIMedication = {
|
|
613
|
+
id: string | number;
|
|
614
|
+
brand_name: string;
|
|
615
|
+
generic_name: string;
|
|
616
|
+
form?: string;
|
|
617
|
+
strength?: string;
|
|
618
|
+
reason?: string;
|
|
619
|
+
};
|
|
620
|
+
|
|
621
|
+
type MedicationSearchResult = {
|
|
622
|
+
id: number;
|
|
623
|
+
name: string;
|
|
624
|
+
generic_name?: string;
|
|
625
|
+
manufacturer?: string;
|
|
626
|
+
score?: number;
|
|
627
|
+
};
|
|
628
|
+
type Medication = {
|
|
629
|
+
id: number;
|
|
630
|
+
brand_name: string;
|
|
631
|
+
generic_name: string;
|
|
632
|
+
frequency: string;
|
|
633
|
+
is_custom: boolean;
|
|
634
|
+
duration_value: string;
|
|
635
|
+
duration_unit: 'days' | 'weeks' | 'months';
|
|
636
|
+
before_after: 'AFTER FOOD' | 'BEFORE FOOD';
|
|
637
|
+
morning: string;
|
|
638
|
+
afternoon: string;
|
|
639
|
+
night: string;
|
|
640
|
+
notes: string;
|
|
641
|
+
};
|
|
642
|
+
type AddMedicationFieldProps = {
|
|
643
|
+
label?: string;
|
|
644
|
+
value: Medication[];
|
|
645
|
+
onChange: (items: Medication[]) => void;
|
|
646
|
+
onSearch: (query: string) => Promise<MedicationSearchResult[]>;
|
|
647
|
+
recentlyUsed?: MedicationSearchResult[];
|
|
648
|
+
/** AI-suggested medications shown as badges; clicking adds to value */
|
|
649
|
+
suggestedMedications?: AIMedication[];
|
|
650
|
+
};
|
|
651
|
+
declare const AddMedicationField: React.FC<AddMedicationFieldProps>;
|
|
652
|
+
|
|
653
|
+
type InvestigationSearchResult = {
|
|
654
|
+
id: string;
|
|
655
|
+
name: string;
|
|
656
|
+
code?: string;
|
|
657
|
+
description?: string;
|
|
658
|
+
categories?: string[];
|
|
659
|
+
synonyms?: string[];
|
|
660
|
+
sample_type?: string;
|
|
661
|
+
method?: string;
|
|
662
|
+
reference_range?: string;
|
|
663
|
+
sample_unit?: string;
|
|
664
|
+
sample_qty?: number;
|
|
665
|
+
turnaround_time?: number;
|
|
666
|
+
preparation?: string;
|
|
667
|
+
service_type?: string;
|
|
668
|
+
department?: string;
|
|
669
|
+
is_vip_enabled?: boolean;
|
|
670
|
+
is_pacs_enabled?: boolean;
|
|
671
|
+
score?: number;
|
|
672
|
+
};
|
|
673
|
+
type Investigation = InvestigationSearchResult & {
|
|
674
|
+
label: string;
|
|
675
|
+
is_custom: boolean;
|
|
676
|
+
fromAI: boolean;
|
|
677
|
+
};
|
|
678
|
+
type AddInvestigationFieldProps = {
|
|
679
|
+
label?: string;
|
|
680
|
+
value: Investigation[];
|
|
681
|
+
onChange: (items: Investigation[]) => void;
|
|
682
|
+
onSearch: (query: string) => Promise<InvestigationSearchResult[]>;
|
|
683
|
+
recentlyUsed?: InvestigationSearchResult[];
|
|
684
|
+
};
|
|
685
|
+
declare const AddInvestigationField: React.FC<AddInvestigationFieldProps>;
|
|
686
|
+
|
|
687
|
+
type DifferentialDiagnosisItem = {
|
|
688
|
+
category: string;
|
|
689
|
+
condition: string;
|
|
690
|
+
likelihood: string;
|
|
691
|
+
severity: string;
|
|
692
|
+
treatability: string;
|
|
693
|
+
keyFeatures?: string[];
|
|
694
|
+
nextSteps?: string[];
|
|
695
|
+
};
|
|
696
|
+
type DifferentialDiagnosisProps = {
|
|
697
|
+
differentialDiagnosis: DifferentialDiagnosisItem[];
|
|
698
|
+
className?: string;
|
|
699
|
+
height?: string;
|
|
700
|
+
};
|
|
701
|
+
/**
|
|
702
|
+
* - Outer: rounded border [#D0D0D0], highlight label strip (#FEE8EC)
|
|
703
|
+
* - Body: scrollable list of diagnosis cards with accordion expand/collapse
|
|
704
|
+
*/
|
|
705
|
+
declare const DifferentialDiagnosis: React.FC<DifferentialDiagnosisProps>;
|
|
706
|
+
|
|
707
|
+
export { type AIDifferentialDiagnosisItem, AddInvestigationField, type AddInvestigationFieldProps, AddMedicationField, type AddMedicationFieldProps, type BaseFieldDef, type CheckboxFieldDef, type ColumnLayout, type Computation, type Condition, type CreateUploadHandlerOptions, type DataSource, DifferentialDiagnosis, type DifferentialDiagnosisFieldDef, type DifferentialDiagnosisItem, type DifferentialDiagnosisProps, DynamicForm, EMAIL_REGEX, type EditableTableColumnDef, type EditableTableFieldDef, type EventDefinition, type FieldDef, type FieldHandler, type FieldHandlersMap, type FieldPrefill, FieldRenderer, type FieldState, type FieldType, type FollowupFieldDef, type FollowupValue, FormControls, type FormControlsProps, type FormDef, type FormErrors, FormProvider, type FormState, FormStore, type FormValues, type FormulaComputation, type FormulaExpr, type ImageUploadFieldDef, ImageUploadWidget, type Investigation, type InvestigationSearchResult, type InvestigationsFieldDef, type LayoutNode, type Medication, type MedicationSearchResult, type MedicationsFieldDef, type NumberFieldDef, type Permission, type PresignedUploadResponse, type ProceduresFieldDef, type RadioFieldDef, ReadOnlyForm, ReadOnlyImageUpload, ReadOnlySignature, ReadOnlyTable, type ReferralFieldDef, type ReferralItem, type RepeatableFieldDef, type Rule, type RuleAction, type RuleResult, type ScoreComputation, type ScoreRange, type Section, type SectionChild, type SelectFieldDef, type SelectOption, type SignatureFieldDef, SignatureUploadWidget, SmartForm, type SmartFormProps, type StaticTextFieldDef, type StoreConfig, type SubmissionData, type SumComputation, type TextFieldDef, type ValidationRule, type VitalsFieldDef, type WebhookDef, type Workflow, type WorkflowTransition, createUploadHandler, evaluateRules, useField, useFieldHandlers, useForm, useFormStore, validateField, validateForm };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
|
-
type FieldType = 'text' | 'number' | 'textarea' | 'select' | 'multiselect' | 'radio' | 'repeatable' | 'checkbox' | 'image_upload' | 'signature' | 'date' | 'datetime' | 'editable_table' | 'static_text' | string;
|
|
3
|
+
type FieldType = 'text' | 'number' | 'textarea' | 'select' | 'multiselect' | 'radio' | 'repeatable' | 'checkbox' | 'image_upload' | 'signature' | 'date' | 'datetime' | 'editable_table' | 'static_text' | 'medications' | 'investigations' | 'procedures' | 'vitals' | 'referral' | 'followup' | string;
|
|
4
4
|
interface ValidationRule {
|
|
5
5
|
min?: number;
|
|
6
6
|
max?: number;
|
|
@@ -42,6 +42,26 @@ interface BaseFieldDef {
|
|
|
42
42
|
disabled?: boolean;
|
|
43
43
|
hidden?: boolean;
|
|
44
44
|
prefill?: FieldPrefill;
|
|
45
|
+
/**
|
|
46
|
+
* High-level column position in SmartForm layout.
|
|
47
|
+
* - "left" and "right" are narrow side columns.
|
|
48
|
+
* - "center" is the main content column and is 2× the width of side columns.
|
|
49
|
+
* Default: "center" when omitted.
|
|
50
|
+
*/
|
|
51
|
+
position?: 'left' | 'center' | 'right';
|
|
52
|
+
/**
|
|
53
|
+
* How many layout columns this field spans horizontally.
|
|
54
|
+
* - 1 = occupies its own column (e.g. just "left", just "center", or just "right")
|
|
55
|
+
* - 2 = spans into an adjacent column (e.g. left+center or center+right)
|
|
56
|
+
* Default: 1.
|
|
57
|
+
*/
|
|
58
|
+
colSpan?: 1 | 2;
|
|
59
|
+
/**
|
|
60
|
+
* Optional theme name for component styling.
|
|
61
|
+
* Renders the field with theme-specific styles (e.g. textarea with "highlight-label"
|
|
62
|
+
* shows the label in a colored block above the input).
|
|
63
|
+
*/
|
|
64
|
+
theme?: string;
|
|
45
65
|
meta?: Record<string, unknown>;
|
|
46
66
|
}
|
|
47
67
|
interface TextFieldDef extends BaseFieldDef {
|
|
@@ -118,7 +138,55 @@ interface StaticTextFieldDef extends BaseFieldDef {
|
|
|
118
138
|
/** Display size. Default: 'regular'. */
|
|
119
139
|
size?: 'regular' | 'large';
|
|
120
140
|
}
|
|
121
|
-
|
|
141
|
+
interface MedicationsFieldDef extends BaseFieldDef {
|
|
142
|
+
type: 'medications';
|
|
143
|
+
}
|
|
144
|
+
interface InvestigationsFieldDef extends BaseFieldDef {
|
|
145
|
+
type: 'investigations';
|
|
146
|
+
}
|
|
147
|
+
interface ProceduresFieldDef extends BaseFieldDef {
|
|
148
|
+
type: 'procedures';
|
|
149
|
+
}
|
|
150
|
+
interface DifferentialDiagnosisFieldDef extends BaseFieldDef {
|
|
151
|
+
type: 'differential_diagnosis';
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* A read-only vitals panel populated by an external API fetch.
|
|
155
|
+
* The consumer provides `onFetch` in `fieldHandlers` for this field ID.
|
|
156
|
+
* The fetched value (raw vitals object) is stored in form state and included in submission.
|
|
157
|
+
*/
|
|
158
|
+
interface VitalsFieldDef extends BaseFieldDef {
|
|
159
|
+
type: 'vitals';
|
|
160
|
+
}
|
|
161
|
+
/** One selected referral. Stored in form state as an array of these. */
|
|
162
|
+
interface ReferralItem {
|
|
163
|
+
specialization: string;
|
|
164
|
+
is_urgent: boolean;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Referral field: label "Referral to" with a multiselect dropdown and chips.
|
|
168
|
+
* Value shape: ReferralItem[] e.g. [{ specialization: "Cardiology", is_urgent: false }, ...].
|
|
169
|
+
* Options via fieldHandlers[fieldId].onFetchOptions (e.g. { specializations: string[] }).
|
|
170
|
+
*/
|
|
171
|
+
interface ReferralFieldDef extends BaseFieldDef {
|
|
172
|
+
type: 'referral';
|
|
173
|
+
options?: SelectOption[];
|
|
174
|
+
}
|
|
175
|
+
/** Stored value for followup field: false/null = no followup; object = one-time followup as number of days from current date. */
|
|
176
|
+
interface FollowupValue {
|
|
177
|
+
followupType: 'one time';
|
|
178
|
+
/** Number of days from (current) date when set; always stored as string. */
|
|
179
|
+
value: string;
|
|
180
|
+
unit: 'days';
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Follow-up field: "No Follow-up" | "One Time" with schedule by duration (e.g. 7 days) or by date.
|
|
184
|
+
* Value shape: false | FollowupValue.
|
|
185
|
+
*/
|
|
186
|
+
interface FollowupFieldDef extends BaseFieldDef {
|
|
187
|
+
type: 'followup';
|
|
188
|
+
}
|
|
189
|
+
type FieldDef = TextFieldDef | NumberFieldDef | SelectFieldDef | RadioFieldDef | CheckboxFieldDef | RepeatableFieldDef | ImageUploadFieldDef | SignatureFieldDef | EditableTableFieldDef | StaticTextFieldDef | MedicationsFieldDef | InvestigationsFieldDef | ProceduresFieldDef | DifferentialDiagnosisFieldDef | VitalsFieldDef | ReferralFieldDef | FollowupFieldDef | BaseFieldDef;
|
|
122
190
|
interface Condition {
|
|
123
191
|
field?: string;
|
|
124
192
|
op: '==' | '!=' | '>' | '<' | '>=' | '<=' | 'in' | 'contains';
|
|
@@ -180,7 +248,25 @@ interface SumComputation {
|
|
|
180
248
|
type: 'sum';
|
|
181
249
|
fields: string[];
|
|
182
250
|
}
|
|
183
|
-
|
|
251
|
+
/** Expression node for formula computation: field ref, number, or binary op. */
|
|
252
|
+
type FormulaExpr = {
|
|
253
|
+
type: 'field';
|
|
254
|
+
field: string;
|
|
255
|
+
} | {
|
|
256
|
+
type: 'number';
|
|
257
|
+
value: number;
|
|
258
|
+
} | {
|
|
259
|
+
type: 'op';
|
|
260
|
+
op: '+' | '-' | '*' | '/' | '**';
|
|
261
|
+
left: FormulaExpr;
|
|
262
|
+
right: FormulaExpr;
|
|
263
|
+
};
|
|
264
|
+
interface FormulaComputation {
|
|
265
|
+
target: string;
|
|
266
|
+
type: 'formula';
|
|
267
|
+
expression: FormulaExpr;
|
|
268
|
+
}
|
|
269
|
+
type Computation = SumComputation | ScoreComputation | FormulaComputation;
|
|
184
270
|
interface FormDef {
|
|
185
271
|
id: string;
|
|
186
272
|
version: number;
|
|
@@ -244,12 +330,14 @@ interface PersistenceProvider {
|
|
|
244
330
|
type Listener = (state: FormState) => void;
|
|
245
331
|
type EventListener = (event: string, payload?: any) => void;
|
|
246
332
|
type UploadHandler = (file: File | Blob, filename: string) => Promise<string>;
|
|
333
|
+
type DraftChangeHandler = (payload: SavedState) => void | Promise<void>;
|
|
247
334
|
interface StoreConfig {
|
|
248
335
|
persistence?: PersistenceProvider;
|
|
249
336
|
prefillData?: Record<string, any>;
|
|
250
337
|
role?: string;
|
|
251
338
|
onEvent?: EventListener;
|
|
252
339
|
onUpload?: UploadHandler;
|
|
340
|
+
onDraftChange?: DraftChangeHandler;
|
|
253
341
|
}
|
|
254
342
|
declare class FormStore {
|
|
255
343
|
private state;
|
|
@@ -260,6 +348,7 @@ declare class FormStore {
|
|
|
260
348
|
private prefillData;
|
|
261
349
|
private config;
|
|
262
350
|
private saveTimeout;
|
|
351
|
+
private draftCallbackTimeout;
|
|
263
352
|
constructor(schema: FormDef, config?: StoreConfig);
|
|
264
353
|
private initializeDefaults;
|
|
265
354
|
getState(): FormState;
|
|
@@ -274,10 +363,20 @@ declare class FormStore {
|
|
|
274
363
|
getFieldDef(fieldId: string): FieldDef | undefined;
|
|
275
364
|
hasPersistence(): boolean;
|
|
276
365
|
setValue(fieldId: string, value: any): void;
|
|
366
|
+
/**
|
|
367
|
+
* Set multiple values at once (e.g. from AI analysis). Only updates keys that
|
|
368
|
+
* exist in the schema. Runs evaluate/notify/save once.
|
|
369
|
+
* @param partial Map of fieldId -> value
|
|
370
|
+
* @param options.touch If false, do not mark fields as touched (e.g. for AI-suggested values)
|
|
371
|
+
*/
|
|
372
|
+
setValues(partial: Record<string, any>, options?: {
|
|
373
|
+
touch?: boolean;
|
|
374
|
+
}): void;
|
|
277
375
|
setTouched(fieldId: string): void;
|
|
278
376
|
setRole(role: string): void;
|
|
279
377
|
load(): Promise<void>;
|
|
280
378
|
private scheduleSave;
|
|
379
|
+
private scheduleDraftCallback;
|
|
281
380
|
save(): Promise<void>;
|
|
282
381
|
/**
|
|
283
382
|
* Prepare values for outbound submission to the backend.
|
|
@@ -334,9 +433,32 @@ interface RuleResult {
|
|
|
334
433
|
}
|
|
335
434
|
declare function evaluateRules(values: FormValues, rules: Rule[], fields: Record<string, FieldDef>): RuleResult;
|
|
336
435
|
|
|
436
|
+
type FieldHandler = {
|
|
437
|
+
onSearch: (query: string) => Promise<any[]>;
|
|
438
|
+
recentlyUsed?: any[];
|
|
439
|
+
/**
|
|
440
|
+
* Called by widgets that display externally-fetched data (e.g. vitals).
|
|
441
|
+
* Invoked once on mount and again when the user hits the refresh button.
|
|
442
|
+
* The resolved value is written directly into the field's form state.
|
|
443
|
+
*/
|
|
444
|
+
onFetch?: () => Promise<any>;
|
|
445
|
+
/**
|
|
446
|
+
* Called by the referral widget to load dropdown options. May return
|
|
447
|
+
* { specializations: string[] } or { label: string; value: any }[].
|
|
448
|
+
*/
|
|
449
|
+
onFetchOptions?: () => Promise<{
|
|
450
|
+
specializations?: string[];
|
|
451
|
+
} | {
|
|
452
|
+
label: string;
|
|
453
|
+
value: any;
|
|
454
|
+
}[]>;
|
|
455
|
+
};
|
|
456
|
+
type FieldHandlersMap = Record<string, FieldHandler>;
|
|
457
|
+
declare function useFieldHandlers(fieldId: string): FieldHandler;
|
|
337
458
|
interface FormProviderProps {
|
|
338
459
|
schema: FormDef;
|
|
339
460
|
config?: StoreConfig;
|
|
461
|
+
fieldHandlers?: FieldHandlersMap;
|
|
340
462
|
children: React.ReactNode;
|
|
341
463
|
}
|
|
342
464
|
declare const FormProvider: React.FC<FormProviderProps>;
|
|
@@ -372,6 +494,35 @@ declare function useField(fieldId: string): {
|
|
|
372
494
|
|
|
373
495
|
declare const DynamicForm: React.FC;
|
|
374
496
|
|
|
497
|
+
/** Shape of one differential diagnosis item from AI (must match form field value) */
|
|
498
|
+
type AIDifferentialDiagnosisItem = {
|
|
499
|
+
category: string;
|
|
500
|
+
condition: string;
|
|
501
|
+
likelihood: string;
|
|
502
|
+
severity: string;
|
|
503
|
+
treatability: string;
|
|
504
|
+
keyFeatures?: string[];
|
|
505
|
+
nextSteps?: string[];
|
|
506
|
+
};
|
|
507
|
+
interface SmartFormProps {
|
|
508
|
+
/**
|
|
509
|
+
* Structured result from AI analysis (e.g. patient-doctor conversation).
|
|
510
|
+
* When this is set or updated, values are applied to the form by field ID.
|
|
511
|
+
* Only keys that exist in the form schema are applied; unknown keys are ignored.
|
|
512
|
+
* Fields are not marked as "touched" so you can distinguish AI-suggested vs user-edited if needed.
|
|
513
|
+
* Listens to both reference and content changes (e.g. streaming updates to the same object).
|
|
514
|
+
*/
|
|
515
|
+
aiAnalysisResult?: Record<string, any> | null;
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* Form view that supports applying AI analysis results after load. Use inside
|
|
519
|
+
* FormProvider like DynamicForm. When aiAnalysisResult is provided (e.g. when
|
|
520
|
+
* AI finishes analyzing conversation), its values are applied to the form in
|
|
521
|
+
* one batch without marking fields as touched. Re-applies when the result
|
|
522
|
+
* reference or content changes (e.g. streaming or incremental AI updates).
|
|
523
|
+
*/
|
|
524
|
+
declare const SmartForm: React.FC<SmartFormProps>;
|
|
525
|
+
|
|
375
526
|
interface FieldRendererProps {
|
|
376
527
|
fieldId: string;
|
|
377
528
|
}
|
|
@@ -457,4 +608,100 @@ interface CreateUploadHandlerOptions {
|
|
|
457
608
|
*/
|
|
458
609
|
declare function createUploadHandler(options: CreateUploadHandlerOptions): (file: File | Blob, filename: string) => Promise<string>;
|
|
459
610
|
|
|
460
|
-
|
|
611
|
+
/** Shape of a medication as returned by AI analysis */
|
|
612
|
+
type AIMedication = {
|
|
613
|
+
id: string | number;
|
|
614
|
+
brand_name: string;
|
|
615
|
+
generic_name: string;
|
|
616
|
+
form?: string;
|
|
617
|
+
strength?: string;
|
|
618
|
+
reason?: string;
|
|
619
|
+
};
|
|
620
|
+
|
|
621
|
+
type MedicationSearchResult = {
|
|
622
|
+
id: number;
|
|
623
|
+
name: string;
|
|
624
|
+
generic_name?: string;
|
|
625
|
+
manufacturer?: string;
|
|
626
|
+
score?: number;
|
|
627
|
+
};
|
|
628
|
+
type Medication = {
|
|
629
|
+
id: number;
|
|
630
|
+
brand_name: string;
|
|
631
|
+
generic_name: string;
|
|
632
|
+
frequency: string;
|
|
633
|
+
is_custom: boolean;
|
|
634
|
+
duration_value: string;
|
|
635
|
+
duration_unit: 'days' | 'weeks' | 'months';
|
|
636
|
+
before_after: 'AFTER FOOD' | 'BEFORE FOOD';
|
|
637
|
+
morning: string;
|
|
638
|
+
afternoon: string;
|
|
639
|
+
night: string;
|
|
640
|
+
notes: string;
|
|
641
|
+
};
|
|
642
|
+
type AddMedicationFieldProps = {
|
|
643
|
+
label?: string;
|
|
644
|
+
value: Medication[];
|
|
645
|
+
onChange: (items: Medication[]) => void;
|
|
646
|
+
onSearch: (query: string) => Promise<MedicationSearchResult[]>;
|
|
647
|
+
recentlyUsed?: MedicationSearchResult[];
|
|
648
|
+
/** AI-suggested medications shown as badges; clicking adds to value */
|
|
649
|
+
suggestedMedications?: AIMedication[];
|
|
650
|
+
};
|
|
651
|
+
declare const AddMedicationField: React.FC<AddMedicationFieldProps>;
|
|
652
|
+
|
|
653
|
+
type InvestigationSearchResult = {
|
|
654
|
+
id: string;
|
|
655
|
+
name: string;
|
|
656
|
+
code?: string;
|
|
657
|
+
description?: string;
|
|
658
|
+
categories?: string[];
|
|
659
|
+
synonyms?: string[];
|
|
660
|
+
sample_type?: string;
|
|
661
|
+
method?: string;
|
|
662
|
+
reference_range?: string;
|
|
663
|
+
sample_unit?: string;
|
|
664
|
+
sample_qty?: number;
|
|
665
|
+
turnaround_time?: number;
|
|
666
|
+
preparation?: string;
|
|
667
|
+
service_type?: string;
|
|
668
|
+
department?: string;
|
|
669
|
+
is_vip_enabled?: boolean;
|
|
670
|
+
is_pacs_enabled?: boolean;
|
|
671
|
+
score?: number;
|
|
672
|
+
};
|
|
673
|
+
type Investigation = InvestigationSearchResult & {
|
|
674
|
+
label: string;
|
|
675
|
+
is_custom: boolean;
|
|
676
|
+
fromAI: boolean;
|
|
677
|
+
};
|
|
678
|
+
type AddInvestigationFieldProps = {
|
|
679
|
+
label?: string;
|
|
680
|
+
value: Investigation[];
|
|
681
|
+
onChange: (items: Investigation[]) => void;
|
|
682
|
+
onSearch: (query: string) => Promise<InvestigationSearchResult[]>;
|
|
683
|
+
recentlyUsed?: InvestigationSearchResult[];
|
|
684
|
+
};
|
|
685
|
+
declare const AddInvestigationField: React.FC<AddInvestigationFieldProps>;
|
|
686
|
+
|
|
687
|
+
type DifferentialDiagnosisItem = {
|
|
688
|
+
category: string;
|
|
689
|
+
condition: string;
|
|
690
|
+
likelihood: string;
|
|
691
|
+
severity: string;
|
|
692
|
+
treatability: string;
|
|
693
|
+
keyFeatures?: string[];
|
|
694
|
+
nextSteps?: string[];
|
|
695
|
+
};
|
|
696
|
+
type DifferentialDiagnosisProps = {
|
|
697
|
+
differentialDiagnosis: DifferentialDiagnosisItem[];
|
|
698
|
+
className?: string;
|
|
699
|
+
height?: string;
|
|
700
|
+
};
|
|
701
|
+
/**
|
|
702
|
+
* - Outer: rounded border [#D0D0D0], highlight label strip (#FEE8EC)
|
|
703
|
+
* - Body: scrollable list of diagnosis cards with accordion expand/collapse
|
|
704
|
+
*/
|
|
705
|
+
declare const DifferentialDiagnosis: React.FC<DifferentialDiagnosisProps>;
|
|
706
|
+
|
|
707
|
+
export { type AIDifferentialDiagnosisItem, AddInvestigationField, type AddInvestigationFieldProps, AddMedicationField, type AddMedicationFieldProps, type BaseFieldDef, type CheckboxFieldDef, type ColumnLayout, type Computation, type Condition, type CreateUploadHandlerOptions, type DataSource, DifferentialDiagnosis, type DifferentialDiagnosisFieldDef, type DifferentialDiagnosisItem, type DifferentialDiagnosisProps, DynamicForm, EMAIL_REGEX, type EditableTableColumnDef, type EditableTableFieldDef, type EventDefinition, type FieldDef, type FieldHandler, type FieldHandlersMap, type FieldPrefill, FieldRenderer, type FieldState, type FieldType, type FollowupFieldDef, type FollowupValue, FormControls, type FormControlsProps, type FormDef, type FormErrors, FormProvider, type FormState, FormStore, type FormValues, type FormulaComputation, type FormulaExpr, type ImageUploadFieldDef, ImageUploadWidget, type Investigation, type InvestigationSearchResult, type InvestigationsFieldDef, type LayoutNode, type Medication, type MedicationSearchResult, type MedicationsFieldDef, type NumberFieldDef, type Permission, type PresignedUploadResponse, type ProceduresFieldDef, type RadioFieldDef, ReadOnlyForm, ReadOnlyImageUpload, ReadOnlySignature, ReadOnlyTable, type ReferralFieldDef, type ReferralItem, type RepeatableFieldDef, type Rule, type RuleAction, type RuleResult, type ScoreComputation, type ScoreRange, type Section, type SectionChild, type SelectFieldDef, type SelectOption, type SignatureFieldDef, SignatureUploadWidget, SmartForm, type SmartFormProps, type StaticTextFieldDef, type StoreConfig, type SubmissionData, type SumComputation, type TextFieldDef, type ValidationRule, type VitalsFieldDef, type WebhookDef, type Workflow, type WorkflowTransition, createUploadHandler, evaluateRules, useField, useFieldHandlers, useForm, useFormStore, validateField, validateForm };
|