@k3-universe/react-kit 0.0.13 → 0.0.14
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.js +413 -403
- package/dist/kit/builder/data-table/types.d.ts +1 -1
- package/dist/kit/builder/data-table/types.d.ts.map +1 -1
- package/dist/kit/builder/form/components/FormBuilder.d.ts +3 -172
- package/dist/kit/builder/form/components/FormBuilder.d.ts.map +1 -1
- package/dist/kit/builder/form/components/FormBuilderField.d.ts +8 -8
- package/dist/kit/builder/form/components/FormBuilderField.d.ts.map +1 -1
- package/dist/kit/builder/form/components/fields/types.d.ts +3 -3
- package/dist/kit/builder/form/components/fields/types.d.ts.map +1 -1
- package/dist/kit/builder/form/index.d.ts +1 -0
- package/dist/kit/builder/form/index.d.ts.map +1 -1
- package/dist/kit/builder/form/types.d.ts +175 -0
- package/dist/kit/builder/form/types.d.ts.map +1 -0
- package/dist/kit/builder/form/utils/common-forms.d.ts +1 -1
- package/dist/kit/builder/form/utils/common-forms.d.ts.map +1 -1
- package/dist/kit/builder/form/utils/field-factories.d.ts +3 -3
- package/dist/kit/builder/form/utils/field-factories.d.ts.map +1 -1
- package/dist/kit/builder/form/utils/section-factories.d.ts +4 -4
- package/dist/kit/builder/form/utils/section-factories.d.ts.map +1 -1
- package/dist/kit/builder/stack-dialog/provider.d.ts.map +1 -1
- package/dist/kit/builder/stack-dialog/renderer.d.ts.map +1 -1
- package/dist/kit/components/autocomplete/Autocomplete.d.ts +8 -8
- package/dist/kit/components/autocomplete/Autocomplete.d.ts.map +1 -1
- package/dist/kit/components/autocomplete/types.d.ts +6 -4
- package/dist/kit/components/autocomplete/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/kit/builder/data-table/components/DataTable.tsx +1 -1
- package/src/kit/builder/data-table/types.ts +1 -1
- package/src/kit/builder/form/components/FormBuilder.tsx +43 -237
- package/src/kit/builder/form/components/FormBuilderField.tsx +42 -34
- package/src/kit/builder/form/components/fields/AutocompleteField.tsx +2 -2
- package/src/kit/builder/form/components/fields/types.ts +3 -3
- package/src/kit/builder/form/index.ts +1 -0
- package/src/kit/builder/form/types.ts +198 -0
- package/src/kit/builder/form/utils/common-forms.ts +1 -1
- package/src/kit/builder/form/utils/field-factories.ts +5 -5
- package/src/kit/builder/form/utils/section-factories.ts +10 -10
- package/src/kit/builder/stack-dialog/provider.tsx +2 -1
- package/src/kit/builder/stack-dialog/renderer.tsx +6 -7
- package/src/kit/components/autocomplete/Autocomplete.tsx +33 -25
- package/src/kit/components/autocomplete/types.ts +7 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/kit/components/autocomplete/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAAG;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/kit/components/autocomplete/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,CAAC,CAAC,GAAG,OAAO,IAAI;IAC5C,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,qEAAqE;IACrE,GAAG,CAAC,EAAE,CAAC,CAAA;CACR,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,uBAAuB,CAAC,CAAC,GAAG,OAAO,IAAI;IACjD,KAAK,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAA;IAC9B,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IACnC,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,mBAAmB,CAAC,CAAC,GAAG,OAAO,IAAI,CAC7C,MAAM,EAAE,uBAAuB,KAC5B,OAAO,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,CAAA;AAExC,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,QAAQ,CAAA"}
|
package/package.json
CHANGED
|
@@ -20,7 +20,7 @@ import { Button } from '../../../../shadcn/ui/button';
|
|
|
20
20
|
import { Checkbox } from '../../../../shadcn/ui/checkbox';
|
|
21
21
|
import { Skeleton } from '../../../../shadcn/ui/skeleton';
|
|
22
22
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '../../../../shadcn/ui/table';
|
|
23
|
-
import { FormBuilder, type FormBuilderSectionConfig } from '../../form
|
|
23
|
+
import { FormBuilder, type FormBuilderSectionConfig } from '../../form';
|
|
24
24
|
import type { DataTableAction, DataTableBatchAction, DataTableFiltersProp } from '../types';
|
|
25
25
|
import { DataTablePagination } from './DataTablePagination';
|
|
26
26
|
import { DataTableViewOptions } from './DataTableViewOptions';
|
|
@@ -1,221 +1,22 @@
|
|
|
1
|
-
import type React from 'react';
|
|
2
1
|
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
3
|
-
import { useForm, useWatch, type
|
|
2
|
+
import { useForm, useWatch, type FieldValues, type Path } from 'react-hook-form';
|
|
4
3
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
5
4
|
import { z } from 'zod';
|
|
6
5
|
import { cn } from '../../../../shadcn/lib/utils';
|
|
7
6
|
import { Button } from '../../../../shadcn/ui/button';
|
|
8
7
|
import { FormBuilderField } from './FormBuilderField';
|
|
9
8
|
import SectionBuilder from '../../section/SectionBuilder';
|
|
9
|
+
import type { SectionNode } from '../../section/types';
|
|
10
10
|
import type {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
} from '../../section/types';
|
|
16
|
-
import type {
|
|
17
|
-
AutocompleteFetcher,
|
|
18
|
-
AutocompleteOption,
|
|
19
|
-
} from '../../../components/autocomplete/types';
|
|
20
|
-
import type { Accept } from 'react-dropzone';
|
|
21
|
-
import type {
|
|
22
|
-
FileRecord,
|
|
23
|
-
FileUploaderLayout,
|
|
24
|
-
} from '../../../components/fileuploader/types';
|
|
25
|
-
|
|
26
|
-
export interface FormBuilderFieldConfig {
|
|
27
|
-
id?: string; // Optional ID for test fixtures
|
|
28
|
-
name: string;
|
|
29
|
-
label: string;
|
|
30
|
-
type:
|
|
31
|
-
| 'text'
|
|
32
|
-
| 'email'
|
|
33
|
-
| 'password'
|
|
34
|
-
| 'number'
|
|
35
|
-
| 'textarea'
|
|
36
|
-
| 'select'
|
|
37
|
-
| 'autocomplete'
|
|
38
|
-
| 'checkbox'
|
|
39
|
-
| 'switch'
|
|
40
|
-
| 'radio'
|
|
41
|
-
| 'date' // native input date
|
|
42
|
-
| 'date_picker' // UI DatePicker
|
|
43
|
-
| 'date_range' // UI DateRangePicker
|
|
44
|
-
| 'month' // UI MonthPicker (single month Date)
|
|
45
|
-
| 'month_range' // UI MonthRangePicker { start: Date, end: Date }
|
|
46
|
-
| 'time' // UI TimePicker (Date with time part)
|
|
47
|
-
| 'time_range' // UI TimeRangePicker { from: Date, to: Date }
|
|
48
|
-
| 'date_time' // UI DateTimePicker (Date with date+time)
|
|
49
|
-
| 'date_time_range' // UI DateTimeRangePicker { from: Date, to: Date }
|
|
50
|
-
| 'file'
|
|
51
|
-
| 'object'
|
|
52
|
-
| 'array';
|
|
53
|
-
placeholder?: string;
|
|
54
|
-
description?: string;
|
|
55
|
-
required?: boolean;
|
|
56
|
-
disabled?: boolean;
|
|
57
|
-
options?: { label: string; value: string | number | null }[];
|
|
58
|
-
// Autocomplete specific (client/server)
|
|
59
|
-
autocompleteMode?: 'client' | 'server';
|
|
60
|
-
fetcher?: AutocompleteFetcher;
|
|
61
|
-
pageSize?: number;
|
|
62
|
-
searchPlaceholder?: string;
|
|
63
|
-
renderOption?: (
|
|
64
|
-
option: AutocompleteOption,
|
|
65
|
-
selected: boolean
|
|
66
|
-
) => React.ReactNode;
|
|
67
|
-
// New autocomplete features
|
|
68
|
-
multiple?: boolean;
|
|
69
|
-
allowCustomValue?: boolean;
|
|
70
|
-
chipVariant?: 'default' | 'secondary' | 'destructive' | 'outline';
|
|
71
|
-
chipClassName?: string;
|
|
72
|
-
clearable?: boolean;
|
|
73
|
-
initialSelectedOptions?: AutocompleteOption | AutocompleteOption[] | null;
|
|
74
|
-
loadSelected?: (values: Array<string | number>) => Promise<AutocompleteOption[]>;
|
|
75
|
-
validation?:
|
|
76
|
-
| z.ZodType<unknown>
|
|
77
|
-
| {
|
|
78
|
-
pattern?: { value: RegExp; message: string };
|
|
79
|
-
min?: { value: number; message: string };
|
|
80
|
-
max?: { value: number; message: string };
|
|
81
|
-
minLength?: { value: number; message: string };
|
|
82
|
-
maxLength?: { value: number; message: string };
|
|
83
|
-
// For array-like fields (e.g., file uploader)
|
|
84
|
-
minItems?: { value: number; message: string };
|
|
85
|
-
maxItems?: { value: number; message: string };
|
|
86
|
-
};
|
|
87
|
-
defaultValue?: unknown;
|
|
88
|
-
fields?: FormBuilderFieldConfig[]; // For nested object/array fields
|
|
89
|
-
dependencies?: {
|
|
90
|
-
field: string;
|
|
91
|
-
condition: (value: unknown) => boolean;
|
|
92
|
-
action: 'show' | 'hide' | 'enable' | 'disable' | 'setValue';
|
|
93
|
-
value?: unknown;
|
|
94
|
-
}[];
|
|
95
|
-
onChange?: (
|
|
96
|
-
value: unknown,
|
|
97
|
-
setValue: (field: string, value: unknown) => void,
|
|
98
|
-
getValues: () => Record<string, unknown>
|
|
99
|
-
) => void;
|
|
100
|
-
className?: string;
|
|
101
|
-
gridCols?: number;
|
|
102
|
-
rows?: number; // For textarea fields
|
|
103
|
-
itemType?: string; // For array fields
|
|
104
|
-
// Array field layout: default 'card'
|
|
105
|
-
arrayLayout?: 'card' | 'table' | 'custom';
|
|
106
|
-
// Custom renderer for array fields when arrayLayout === 'custom'
|
|
107
|
-
arrayRender?: (params: {
|
|
108
|
-
field: FormBuilderFieldConfig;
|
|
109
|
-
control: Control<FieldValues>;
|
|
110
|
-
fieldPath: string;
|
|
111
|
-
value: unknown;
|
|
112
|
-
onChange: (value: unknown) => void;
|
|
113
|
-
addItem: () => void;
|
|
114
|
-
removeItem: (index: number) => void;
|
|
115
|
-
disabled?: boolean;
|
|
116
|
-
rows?: { id: string }[]; // useFieldArray rows for stable rendering
|
|
117
|
-
}) => React.ReactNode;
|
|
118
|
-
// Optional styling for array layouts (used mainly for 'table')
|
|
119
|
-
arrayColors?: {
|
|
120
|
-
headerBgClass?: string; // e.g. 'bg-teal-700'
|
|
121
|
-
headerTextClass?: string; // e.g. 'text-white'
|
|
122
|
-
rowAltBgClass?: string; // e.g. 'bg-teal-50'
|
|
123
|
-
};
|
|
124
|
-
conditional?: {
|
|
125
|
-
field: string;
|
|
126
|
-
value: unknown;
|
|
127
|
-
}; // For conditional field visibility
|
|
128
|
-
hidden?: boolean; // Declarative hide
|
|
129
|
-
// Label placement control across inputs
|
|
130
|
-
labelPlacement?: 'stacked' | 'inline' | 'hidden';
|
|
131
|
-
// Wrapper container className (applies to the field wrapper, not the input)
|
|
132
|
-
wrapperClassName?: string;
|
|
133
|
-
// Picker-specific optional props (passed through to components when applicable)
|
|
134
|
-
minDate?: Date;
|
|
135
|
-
maxDate?: Date;
|
|
136
|
-
disabledDates?: Array<Date | { from: Date; to: Date }>;
|
|
137
|
-
numberOfMonths?: number;
|
|
138
|
-
popoverSide?: 'top' | 'right' | 'bottom' | 'left';
|
|
139
|
-
showFooter?: boolean;
|
|
140
|
-
cancelLabel?: string;
|
|
141
|
-
applyLabel?: string;
|
|
142
|
-
// Time picker specific
|
|
143
|
-
timePrecision?: 'hour' | 'minute' | 'second';
|
|
144
|
-
hourCycle?: 12 | 24;
|
|
145
|
-
minuteStep?: number;
|
|
146
|
-
secondStep?: number;
|
|
147
|
-
// File uploader specific options
|
|
148
|
-
fileMultiple?: boolean;
|
|
149
|
-
fileMaxFiles?: number;
|
|
150
|
-
fileAccept?: Accept;
|
|
151
|
-
fileLayout?: FileUploaderLayout;
|
|
152
|
-
fileWithDownload?: boolean;
|
|
153
|
-
fileUploader?: (
|
|
154
|
-
file: File,
|
|
155
|
-
onProgress: (pct: number) => void,
|
|
156
|
-
) => Promise<Partial<FileRecord>>;
|
|
157
|
-
fileOnUploadSuccess?: (file: FileRecord) => void;
|
|
158
|
-
fileOnUploadError?: (file: FileRecord, error: unknown) => void;
|
|
159
|
-
fileOnRemove?: (file: FileRecord) => void | Promise<void>;
|
|
160
|
-
fileOnRetry?: (file: FileRecord) => void;
|
|
161
|
-
fileOnRetryAll?: (files: FileRecord[]) => void;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
export interface FormBuilderSectionConfig {
|
|
165
|
-
id?: string;
|
|
166
|
-
title?: string;
|
|
167
|
-
description?: string;
|
|
168
|
-
fields?: FormBuilderFieldConfig[];
|
|
169
|
-
variant?: 'card' | 'separator' | 'plain';
|
|
170
|
-
className?: string;
|
|
171
|
-
collapsible?: boolean;
|
|
172
|
-
defaultCollapsed?: boolean;
|
|
173
|
-
layout?: SectionLayout;
|
|
174
|
-
grid?: SectionGridOptions;
|
|
175
|
-
flex?: SectionFlexOptions;
|
|
176
|
-
hidden?: boolean; // Declarative hide
|
|
177
|
-
// Tabs layout support: when layout === 'tabs', provide tabs instead of direct fields
|
|
178
|
-
tabs?: Array<{
|
|
179
|
-
id: string;
|
|
180
|
-
label: React.ReactNode;
|
|
181
|
-
sections: FormBuilderSectionConfig[];
|
|
182
|
-
className?: string;
|
|
183
|
-
contentClassName?: string;
|
|
184
|
-
}>;
|
|
185
|
-
defaultTabId?: string;
|
|
186
|
-
tabsListClassName?: string;
|
|
187
|
-
tabsContentClassName?: string;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
export interface FormBuilderProps {
|
|
191
|
-
sections: FormBuilderSectionConfig[];
|
|
192
|
-
schema?: z.ZodType<unknown>;
|
|
193
|
-
defaultValues?: Record<string, unknown> | null;
|
|
194
|
-
onSubmit: (data: unknown) => void | Promise<void>;
|
|
195
|
-
onCancel?: () => void;
|
|
196
|
-
onReset?: () => void;
|
|
197
|
-
onFieldChange?: (
|
|
198
|
-
name: string,
|
|
199
|
-
value: unknown,
|
|
200
|
-
allValues: Record<string, unknown>
|
|
201
|
-
) => void;
|
|
202
|
-
submitLabel?: string;
|
|
203
|
-
cancelLabel?: string;
|
|
204
|
-
resetLabel?: string;
|
|
205
|
-
isSubmitting?: boolean;
|
|
206
|
-
className?: string;
|
|
207
|
-
formClassName?: string;
|
|
208
|
-
actionsClassName?: string;
|
|
209
|
-
showActions?: boolean;
|
|
210
|
-
customActions?: React.ReactNode;
|
|
211
|
-
// UI: show a separator line above action buttons
|
|
212
|
-
showActionsSeparator?: boolean;
|
|
213
|
-
}
|
|
11
|
+
FormBuilderProps,
|
|
12
|
+
FormBuilderFieldConfig,
|
|
13
|
+
FormBuilderSectionConfig,
|
|
14
|
+
} from '../types';
|
|
214
15
|
|
|
215
|
-
export function FormBuilder({
|
|
16
|
+
export function FormBuilder<TFieldValues extends FieldValues = FieldValues>({
|
|
216
17
|
sections,
|
|
217
18
|
schema,
|
|
218
|
-
defaultValues
|
|
19
|
+
defaultValues,
|
|
219
20
|
onSubmit,
|
|
220
21
|
onCancel,
|
|
221
22
|
onReset,
|
|
@@ -230,13 +31,13 @@ export function FormBuilder({
|
|
|
230
31
|
showActions = true,
|
|
231
32
|
customActions,
|
|
232
33
|
showActionsSeparator = true,
|
|
233
|
-
}: FormBuilderProps) {
|
|
34
|
+
}: FormBuilderProps<TFieldValues>) {
|
|
234
35
|
// Generate schema from field configs if not provided
|
|
235
36
|
const generatedSchema = useMemo(() => {
|
|
236
37
|
if (schema) return schema;
|
|
237
38
|
|
|
238
39
|
const generateFieldSchema = (
|
|
239
|
-
field: FormBuilderFieldConfig
|
|
40
|
+
field: FormBuilderFieldConfig<TFieldValues, string | Path<TFieldValues>>
|
|
240
41
|
): z.ZodType<unknown> => {
|
|
241
42
|
if (field.validation && field.validation instanceof z.ZodType) {
|
|
242
43
|
return field.validation;
|
|
@@ -430,7 +231,7 @@ export function FormBuilder({
|
|
|
430
231
|
case 'object':
|
|
431
232
|
if (field.fields) {
|
|
432
233
|
const objectSchema: Record<string, z.ZodType<unknown>> = {};
|
|
433
|
-
for (const subField of field.fields) {
|
|
234
|
+
for (const subField of field.fields as Array<FormBuilderFieldConfig<TFieldValues, string | Path<TFieldValues>>>) {
|
|
434
235
|
objectSchema[subField.name] = generateFieldSchema(subField);
|
|
435
236
|
}
|
|
436
237
|
fieldSchema = z.object(objectSchema);
|
|
@@ -442,9 +243,9 @@ export function FormBuilder({
|
|
|
442
243
|
if (field.fields && field.fields.length > 0) {
|
|
443
244
|
const arrayItemSchema =
|
|
444
245
|
field.fields.length === 1
|
|
445
|
-
? generateFieldSchema(field.fields[0])
|
|
246
|
+
? generateFieldSchema(field.fields[0] as FormBuilderFieldConfig<TFieldValues, string | Path<TFieldValues>>)
|
|
446
247
|
: z.object(
|
|
447
|
-
field.fields.reduce((acc, subField) => {
|
|
248
|
+
(field.fields as Array<FormBuilderFieldConfig<TFieldValues, string | Path<TFieldValues>>>).reduce((acc, subField) => {
|
|
448
249
|
acc[subField.name] = generateFieldSchema(subField);
|
|
449
250
|
return acc;
|
|
450
251
|
}, {} as Record<string, z.ZodType<unknown>>)
|
|
@@ -463,7 +264,7 @@ export function FormBuilder({
|
|
|
463
264
|
|
|
464
265
|
const schemaObject: Record<string, z.ZodType<unknown>> = {};
|
|
465
266
|
|
|
466
|
-
const forEachField = (secs: FormBuilderSectionConfig[]) => {
|
|
267
|
+
const forEachField = (secs: FormBuilderSectionConfig<TFieldValues>[]) => {
|
|
467
268
|
for (const section of secs) {
|
|
468
269
|
// Traverse tabs if present
|
|
469
270
|
if (section.tabs && section.tabs.length > 0) {
|
|
@@ -472,21 +273,21 @@ export function FormBuilder({
|
|
|
472
273
|
}
|
|
473
274
|
}
|
|
474
275
|
for (const field of (section.fields ?? [])) {
|
|
475
|
-
schemaObject[field.name] = generateFieldSchema(field);
|
|
276
|
+
schemaObject[field.name] = generateFieldSchema(field as FormBuilderFieldConfig<TFieldValues, string | Path<TFieldValues>>);
|
|
476
277
|
}
|
|
477
278
|
}
|
|
478
279
|
};
|
|
479
280
|
|
|
480
281
|
forEachField(sections);
|
|
481
282
|
|
|
482
|
-
return z.object(schemaObject)
|
|
283
|
+
return z.object(schemaObject) as unknown as z.ZodType<TFieldValues>;
|
|
483
284
|
}, [sections, schema]);
|
|
484
285
|
|
|
485
286
|
// Generate default values from field configs
|
|
486
287
|
const generatedDefaultValues = useMemo(() => {
|
|
487
|
-
const values: Record<string, unknown> = { ...defaultValues };
|
|
288
|
+
const values: Record<string, unknown> = { ...((defaultValues ?? {}) as Record<string, unknown>) };
|
|
488
289
|
|
|
489
|
-
const processFields = (fields: FormBuilderFieldConfig[]) => {
|
|
290
|
+
const processFields = (fields: FormBuilderFieldConfig<TFieldValues, string | Path<TFieldValues>>[]) => {
|
|
490
291
|
for (const field of fields) {
|
|
491
292
|
if (
|
|
492
293
|
values[field.name] === undefined &&
|
|
@@ -518,7 +319,7 @@ export function FormBuilder({
|
|
|
518
319
|
}
|
|
519
320
|
};
|
|
520
321
|
|
|
521
|
-
const forEachSection = (secs: FormBuilderSectionConfig[]) => {
|
|
322
|
+
const forEachSection = (secs: FormBuilderSectionConfig<TFieldValues>[]) => {
|
|
522
323
|
for (const section of secs) {
|
|
523
324
|
if (section.tabs && section.tabs.length > 0) {
|
|
524
325
|
for (const tab of section.tabs) {
|
|
@@ -534,19 +335,19 @@ export function FormBuilder({
|
|
|
534
335
|
return values;
|
|
535
336
|
}, [sections, defaultValues]);
|
|
536
337
|
|
|
537
|
-
const form = useForm<
|
|
338
|
+
const form = useForm<TFieldValues>({
|
|
538
339
|
// Dynamic schema shape: cast to any to satisfy resolver generics
|
|
539
340
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
540
|
-
resolver: zodResolver(generatedSchema as any) as unknown as import('react-hook-form').Resolver<
|
|
541
|
-
defaultValues: generatedDefaultValues as
|
|
341
|
+
resolver: zodResolver(generatedSchema as any) as unknown as import('react-hook-form').Resolver<TFieldValues, any, TFieldValues>,
|
|
342
|
+
defaultValues: generatedDefaultValues as unknown as import('react-hook-form').DefaultValues<TFieldValues>,
|
|
542
343
|
});
|
|
543
344
|
|
|
544
345
|
const { control, handleSubmit, reset, setValue, getValues } = form;
|
|
545
346
|
|
|
546
347
|
// Determine dependency fields to watch
|
|
547
348
|
const dependencyFields = useMemo(() => {
|
|
548
|
-
const set = new Set<
|
|
549
|
-
const forEachField = (secs: FormBuilderSectionConfig[]) => {
|
|
349
|
+
const set = new Set<Path<TFieldValues>>();
|
|
350
|
+
const forEachField = (secs: FormBuilderSectionConfig<TFieldValues>[]) => {
|
|
550
351
|
for (const section of secs) {
|
|
551
352
|
if (section.tabs && section.tabs.length > 0) {
|
|
552
353
|
for (const tab of section.tabs) {
|
|
@@ -586,7 +387,7 @@ export function FormBuilder({
|
|
|
586
387
|
);
|
|
587
388
|
|
|
588
389
|
const handleFieldDependencies = useCallback(
|
|
589
|
-
(field: FormBuilderFieldConfig) => {
|
|
390
|
+
(field: FormBuilderFieldConfig<TFieldValues, string | Path<TFieldValues>>) => {
|
|
590
391
|
if (!hasDependencies || !field.dependencies) return {};
|
|
591
392
|
|
|
592
393
|
const result: { disabled?: boolean; hidden?: boolean } = {};
|
|
@@ -610,11 +411,11 @@ export function FormBuilder({
|
|
|
610
411
|
break;
|
|
611
412
|
case 'setValue':
|
|
612
413
|
if (conditionMet && dep.value !== undefined) {
|
|
613
|
-
const currentValue = getValues(field.name);
|
|
414
|
+
const currentValue = getValues(field.name as unknown as Path<TFieldValues>);
|
|
614
415
|
if (currentValue !== dep.value) {
|
|
615
416
|
// Defer the update to an effect to prevent state changes during render
|
|
616
417
|
pendingValueUpdatesRef.current.push({
|
|
617
|
-
name: field.name,
|
|
418
|
+
name: field.name as unknown as string,
|
|
618
419
|
value: dep.value,
|
|
619
420
|
});
|
|
620
421
|
}
|
|
@@ -638,9 +439,10 @@ export function FormBuilder({
|
|
|
638
439
|
}
|
|
639
440
|
pendingValueUpdatesRef.current = [];
|
|
640
441
|
for (const [name, value] of updatesMap) {
|
|
641
|
-
const
|
|
442
|
+
const pathName = name as unknown as Path<TFieldValues>;
|
|
443
|
+
const current = getValues(pathName);
|
|
642
444
|
if (current !== value) {
|
|
643
|
-
setValue(
|
|
445
|
+
setValue(pathName, value as unknown as never, {
|
|
644
446
|
shouldDirty: false,
|
|
645
447
|
shouldTouch: false,
|
|
646
448
|
shouldValidate: false,
|
|
@@ -651,16 +453,20 @@ export function FormBuilder({
|
|
|
651
453
|
|
|
652
454
|
// Handle field change with custom onChange
|
|
653
455
|
const handleFieldChange = useCallback(
|
|
654
|
-
(
|
|
456
|
+
(
|
|
457
|
+
field: FormBuilderFieldConfig<TFieldValues, string | Path<TFieldValues>>,
|
|
458
|
+
value: unknown,
|
|
459
|
+
...extras: unknown[]
|
|
460
|
+
) => {
|
|
655
461
|
if (field.onChange) {
|
|
656
|
-
field.onChange(value, setValue, getValues);
|
|
462
|
+
field.onChange(value, extras, setValue, getValues);
|
|
657
463
|
}
|
|
658
464
|
},
|
|
659
465
|
[setValue, getValues]
|
|
660
466
|
);
|
|
661
467
|
|
|
662
468
|
const handleFormSubmit = useCallback(
|
|
663
|
-
async (data:
|
|
469
|
+
async (data: TFieldValues) => {
|
|
664
470
|
try {
|
|
665
471
|
await onSubmit(data);
|
|
666
472
|
} catch (error) {
|
|
@@ -671,13 +477,13 @@ export function FormBuilder({
|
|
|
671
477
|
);
|
|
672
478
|
|
|
673
479
|
const handleReset = useCallback(() => {
|
|
674
|
-
reset(generatedDefaultValues);
|
|
480
|
+
reset(generatedDefaultValues as unknown as import('react-hook-form').DefaultValues<TFieldValues>);
|
|
675
481
|
onReset?.();
|
|
676
482
|
}, [reset, generatedDefaultValues, onReset]);
|
|
677
483
|
|
|
678
484
|
// Build SectionBuilder nodes from form sections/fields
|
|
679
485
|
const sectionNodes: SectionNode[] = useMemo(() => {
|
|
680
|
-
const buildLeavesFromFields = (fields?: FormBuilderFieldConfig[]): SectionNode['children'] =>
|
|
486
|
+
const buildLeavesFromFields = (fields?: FormBuilderFieldConfig<TFieldValues, string | Path<TFieldValues>>[]): SectionNode['children'] =>
|
|
681
487
|
(fields ?? [])
|
|
682
488
|
.map((field) => {
|
|
683
489
|
const fieldState = handleFieldDependencies(field);
|
|
@@ -698,9 +504,9 @@ export function FormBuilder({
|
|
|
698
504
|
disabled: field.disabled || fieldState.disabled,
|
|
699
505
|
}}
|
|
700
506
|
control={control}
|
|
701
|
-
onChange={(value) => {
|
|
702
|
-
handleFieldChange(field, value);
|
|
703
|
-
onFieldChange?.(field.name, value, getValues());
|
|
507
|
+
onChange={(value, ...extras) => {
|
|
508
|
+
handleFieldChange(field, value, ...extras);
|
|
509
|
+
onFieldChange?.(field.name as unknown as string, value, getValues());
|
|
704
510
|
}}
|
|
705
511
|
onFieldChange={onFieldChange}
|
|
706
512
|
/>
|
|
@@ -710,7 +516,7 @@ export function FormBuilder({
|
|
|
710
516
|
.filter(Boolean) as SectionNode['children'];
|
|
711
517
|
|
|
712
518
|
const buildSectionNode = (
|
|
713
|
-
section: FormBuilderSectionConfig
|
|
519
|
+
section: FormBuilderSectionConfig<TFieldValues>,
|
|
714
520
|
sectionIndex: number,
|
|
715
521
|
): SectionNode => {
|
|
716
522
|
const baseNode: SectionNode = {
|