@k3-universe/react-kit 0.0.26 → 0.0.27
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.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15979 -15536
- package/dist/kit/builder/form/components/FormBuilder.d.ts.map +1 -1
- package/dist/kit/builder/form/components/FormBuilderField.d.ts.map +1 -1
- package/dist/kit/builder/form/hooks/useFormBuilder.d.ts +15 -0
- package/dist/kit/builder/form/hooks/useFormBuilder.d.ts.map +1 -0
- 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 +1 -1
- package/dist/kit/builder/form/types.d.ts.map +1 -1
- package/dist/kit/components/forminfo/FormInfoError.d.ts +12 -0
- package/dist/kit/components/forminfo/FormInfoError.d.ts.map +1 -0
- package/dist/kit/components/forminfo/index.d.ts +2 -0
- package/dist/kit/components/forminfo/index.d.ts.map +1 -0
- package/dist/kit/themes/base.css +1 -1
- package/dist/kit/themes/clean-slate.css +11 -5
- package/dist/kit/themes/default.css +11 -5
- package/dist/kit/themes/minimal-modern.css +11 -5
- package/dist/kit/themes/spotify.css +11 -5
- package/package.json +11 -8
- package/src/index.ts +1 -0
- package/src/kit/builder/form/components/FormBuilder.tsx +51 -332
- package/src/kit/builder/form/components/FormBuilderField.tsx +12 -4
- package/src/kit/builder/form/hooks/useFormBuilder.ts +399 -0
- package/src/kit/builder/form/index.ts +1 -0
- package/src/kit/builder/form/types.ts +8 -1
- package/src/kit/components/forminfo/FormInfoError.tsx +120 -0
- package/src/kit/components/forminfo/index.ts +1 -0
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import {
|
|
3
|
+
useWatch,
|
|
4
|
+
type FieldValues,
|
|
5
|
+
type Path,
|
|
6
|
+
} from 'react-hook-form';
|
|
5
7
|
import { cn } from '../../../../shadcn/lib/utils';
|
|
6
8
|
import { Button } from '../../../../shadcn/ui/button';
|
|
7
9
|
import SectionBuilder from '../../section/SectionBuilder';
|
|
8
10
|
import { buildSectionNodes } from './sectionNodes';
|
|
9
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
FormBuilderContext,
|
|
13
|
+
type FormBuilderContextValue,
|
|
14
|
+
} from './FormBuilderContext';
|
|
10
15
|
import type {
|
|
11
16
|
FormBuilderProps,
|
|
12
17
|
FormBuilderFieldConfig,
|
|
13
18
|
FormBuilderSectionConfig,
|
|
14
19
|
} from '../types';
|
|
20
|
+
import { useFormBuilder } from '../hooks/useFormBuilder';
|
|
15
21
|
|
|
16
22
|
export function FormBuilder<TFieldValues extends FieldValues = FieldValues>({
|
|
17
23
|
sections,
|
|
@@ -33,323 +39,15 @@ export function FormBuilder<TFieldValues extends FieldValues = FieldValues>({
|
|
|
33
39
|
showActionsSeparator = true,
|
|
34
40
|
form,
|
|
35
41
|
}: FormBuilderProps<TFieldValues>) {
|
|
36
|
-
//
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
field: FormBuilderFieldConfig<TFieldValues, string | Path<TFieldValues>>
|
|
42
|
-
): z.ZodType<unknown> => {
|
|
43
|
-
if (field.validation && field.validation instanceof z.ZodType) {
|
|
44
|
-
return field.validation;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Handle validation object format
|
|
48
|
-
if (
|
|
49
|
-
field.validation &&
|
|
50
|
-
typeof field.validation === 'object' &&
|
|
51
|
-
!(field.validation instanceof z.ZodType)
|
|
52
|
-
) {
|
|
53
|
-
const validationObj = field.validation;
|
|
54
|
-
let baseSchema: z.ZodType<unknown>;
|
|
55
|
-
|
|
56
|
-
// Determine base schema type
|
|
57
|
-
switch (field.type) {
|
|
58
|
-
case 'email':
|
|
59
|
-
baseSchema = z.string().email('Invalid email address');
|
|
60
|
-
break;
|
|
61
|
-
case 'number':
|
|
62
|
-
baseSchema = z.number();
|
|
63
|
-
break;
|
|
64
|
-
case 'file':
|
|
65
|
-
baseSchema = z.array(z.unknown());
|
|
66
|
-
break;
|
|
67
|
-
case 'date_picker':
|
|
68
|
-
case 'month':
|
|
69
|
-
case 'date':
|
|
70
|
-
case 'time':
|
|
71
|
-
case 'date_time':
|
|
72
|
-
baseSchema = z.date();
|
|
73
|
-
break;
|
|
74
|
-
case 'date_range':
|
|
75
|
-
case 'time_range':
|
|
76
|
-
case 'date_time_range':
|
|
77
|
-
baseSchema = z
|
|
78
|
-
.object({ from: z.date().optional().nullable(), to: z.date().optional().nullable() })
|
|
79
|
-
.nullable();
|
|
80
|
-
break;
|
|
81
|
-
case 'month_range':
|
|
82
|
-
baseSchema = z
|
|
83
|
-
.object({ start: z.date().optional().nullable(), end: z.date().optional().nullable() })
|
|
84
|
-
.nullable();
|
|
85
|
-
break;
|
|
86
|
-
case 'autocomplete': {
|
|
87
|
-
const single = z
|
|
88
|
-
.union([z.string(), z.number(), z.object({})])
|
|
89
|
-
.nullable();
|
|
90
|
-
const multi = z.array(
|
|
91
|
-
z.union([z.string(), z.number(), z.object({})])
|
|
92
|
-
);
|
|
93
|
-
baseSchema = field.multiple ? multi : single;
|
|
94
|
-
break;
|
|
95
|
-
}
|
|
96
|
-
case 'checkbox':
|
|
97
|
-
case 'switch':
|
|
98
|
-
baseSchema = z.boolean();
|
|
99
|
-
break;
|
|
100
|
-
case 'custom_field':
|
|
101
|
-
baseSchema = z.any();
|
|
102
|
-
break;
|
|
103
|
-
default:
|
|
104
|
-
baseSchema = z.string();
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Apply validation constraints
|
|
108
|
-
if (validationObj.pattern && baseSchema instanceof z.ZodString) {
|
|
109
|
-
baseSchema = baseSchema.regex(
|
|
110
|
-
validationObj.pattern.value,
|
|
111
|
-
validationObj.pattern.message
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
if (validationObj.min && baseSchema instanceof z.ZodNumber) {
|
|
115
|
-
baseSchema = baseSchema.min(
|
|
116
|
-
validationObj.min.value,
|
|
117
|
-
validationObj.min.message
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
if (validationObj.max && baseSchema instanceof z.ZodNumber) {
|
|
121
|
-
baseSchema = baseSchema.max(
|
|
122
|
-
validationObj.max.value,
|
|
123
|
-
validationObj.max.message
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
if (validationObj.minLength && baseSchema instanceof z.ZodString) {
|
|
127
|
-
baseSchema = baseSchema.min(
|
|
128
|
-
validationObj.minLength.value,
|
|
129
|
-
validationObj.minLength.message
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
if (validationObj.maxLength && baseSchema instanceof z.ZodString) {
|
|
133
|
-
baseSchema = baseSchema.max(
|
|
134
|
-
validationObj.maxLength.value,
|
|
135
|
-
validationObj.maxLength.message
|
|
136
|
-
);
|
|
137
|
-
}
|
|
138
|
-
// Array item count constraints
|
|
139
|
-
if (baseSchema instanceof z.ZodArray) {
|
|
140
|
-
let arr = baseSchema as z.ZodArray<z.ZodTypeAny>;
|
|
141
|
-
if (validationObj.minItems) {
|
|
142
|
-
arr = arr.min(
|
|
143
|
-
validationObj.minItems.value,
|
|
144
|
-
validationObj.minItems.message,
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
if (validationObj.maxItems) {
|
|
148
|
-
arr = arr.max(
|
|
149
|
-
validationObj.maxItems.value,
|
|
150
|
-
validationObj.maxItems.message,
|
|
151
|
-
);
|
|
152
|
-
}
|
|
153
|
-
// If required and file field, enforce at least 1 item when no explicit minItems
|
|
154
|
-
if (field.type === 'file' && field.required && !validationObj.minItems) {
|
|
155
|
-
arr = arr.min(1, `${field.label} requires at least 1 file`);
|
|
156
|
-
}
|
|
157
|
-
baseSchema = arr;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
return field.required ? baseSchema : baseSchema.optional();
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
let fieldSchema: z.ZodType<unknown>;
|
|
164
|
-
|
|
165
|
-
switch (field.type) {
|
|
166
|
-
case 'email':
|
|
167
|
-
fieldSchema = z.string().email('Invalid email address');
|
|
168
|
-
break;
|
|
169
|
-
case 'number':
|
|
170
|
-
fieldSchema = z.number();
|
|
171
|
-
break;
|
|
172
|
-
case 'file': {
|
|
173
|
-
let arr = z.array(z.unknown());
|
|
174
|
-
// If required, ensure at least 1 file
|
|
175
|
-
if (field.required) {
|
|
176
|
-
arr = arr.min(1, `${field.label} requires at least 1 file`);
|
|
177
|
-
}
|
|
178
|
-
fieldSchema = arr;
|
|
179
|
-
break;
|
|
180
|
-
}
|
|
181
|
-
case 'date_picker':
|
|
182
|
-
case 'month':
|
|
183
|
-
case 'date':
|
|
184
|
-
case 'time':
|
|
185
|
-
case 'date_time':
|
|
186
|
-
fieldSchema = z.date();
|
|
187
|
-
break;
|
|
188
|
-
case 'date_range':
|
|
189
|
-
case 'time_range':
|
|
190
|
-
case 'date_time_range':
|
|
191
|
-
fieldSchema = z
|
|
192
|
-
.object({ from: z.date().optional().nullable(), to: z.date().optional().nullable() })
|
|
193
|
-
.nullable();
|
|
194
|
-
break;
|
|
195
|
-
case 'month_range':
|
|
196
|
-
fieldSchema = z
|
|
197
|
-
.object({ start: z.date().optional().nullable(), end: z.date().optional().nullable() })
|
|
198
|
-
.nullable();
|
|
199
|
-
break;
|
|
200
|
-
case 'autocomplete': {
|
|
201
|
-
const single = z
|
|
202
|
-
.union([z.string(), z.number(), z.object({})])
|
|
203
|
-
.nullable();
|
|
204
|
-
const multi = z.array(
|
|
205
|
-
z.union([z.string(), z.number(), z.object({})])
|
|
206
|
-
);
|
|
207
|
-
fieldSchema = field.multiple ? multi : single;
|
|
208
|
-
break;
|
|
209
|
-
}
|
|
210
|
-
case 'checkbox':
|
|
211
|
-
case 'switch':
|
|
212
|
-
fieldSchema = z.boolean();
|
|
213
|
-
break;
|
|
214
|
-
case 'select':
|
|
215
|
-
case 'radio':
|
|
216
|
-
if (field.options && field.options.length > 0) {
|
|
217
|
-
// Build a union of literals to allow specific values, including null if present
|
|
218
|
-
const literals: Array<z.ZodLiteral<string | number | null>> = field.options.map((opt) =>
|
|
219
|
-
z.literal(opt.value as string | number | null)
|
|
220
|
-
);
|
|
221
|
-
if (literals.length === 1) {
|
|
222
|
-
fieldSchema = literals[0];
|
|
223
|
-
} else {
|
|
224
|
-
fieldSchema = z.union(
|
|
225
|
-
literals as [
|
|
226
|
-
z.ZodLiteral<string | number | null>,
|
|
227
|
-
...z.ZodLiteral<string | number | null>[]
|
|
228
|
-
]
|
|
229
|
-
);
|
|
230
|
-
}
|
|
231
|
-
} else {
|
|
232
|
-
fieldSchema = z.string();
|
|
233
|
-
}
|
|
234
|
-
break;
|
|
235
|
-
case 'object':
|
|
236
|
-
if (field.fields) {
|
|
237
|
-
const objectSchema: Record<string, z.ZodType<unknown>> = {};
|
|
238
|
-
for (const subField of field.fields as Array<FormBuilderFieldConfig<TFieldValues, string | Path<TFieldValues>>>) {
|
|
239
|
-
objectSchema[subField.name] = generateFieldSchema(subField);
|
|
240
|
-
}
|
|
241
|
-
fieldSchema = z.object(objectSchema);
|
|
242
|
-
} else {
|
|
243
|
-
fieldSchema = z.object({});
|
|
244
|
-
}
|
|
245
|
-
break;
|
|
246
|
-
case 'array':
|
|
247
|
-
if (field.fields && field.fields.length > 0) {
|
|
248
|
-
const arrayItemSchema =
|
|
249
|
-
field.fields.length === 1
|
|
250
|
-
? generateFieldSchema(field.fields[0] as FormBuilderFieldConfig<TFieldValues, string | Path<TFieldValues>>)
|
|
251
|
-
: z.object(
|
|
252
|
-
(field.fields as Array<FormBuilderFieldConfig<TFieldValues, string | Path<TFieldValues>>>).reduce((acc, subField) => {
|
|
253
|
-
acc[subField.name] = generateFieldSchema(subField);
|
|
254
|
-
return acc;
|
|
255
|
-
}, {} as Record<string, z.ZodType<unknown>>)
|
|
256
|
-
);
|
|
257
|
-
fieldSchema = z.array(arrayItemSchema);
|
|
258
|
-
} else {
|
|
259
|
-
fieldSchema = z.array(z.unknown());
|
|
260
|
-
}
|
|
261
|
-
break;
|
|
262
|
-
case 'custom_field':
|
|
263
|
-
fieldSchema = z.any();
|
|
264
|
-
break;
|
|
265
|
-
default:
|
|
266
|
-
fieldSchema = z.string();
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
return field.required ? fieldSchema : fieldSchema.optional();
|
|
270
|
-
};
|
|
271
|
-
|
|
272
|
-
const schemaObject: Record<string, z.ZodType<unknown>> = {};
|
|
273
|
-
|
|
274
|
-
const forEachField = (secs: FormBuilderSectionConfig<TFieldValues>[]) => {
|
|
275
|
-
for (const section of secs) {
|
|
276
|
-
// Traverse tabs if present
|
|
277
|
-
if (section.tabs && section.tabs.length > 0) {
|
|
278
|
-
for (const tab of section.tabs) {
|
|
279
|
-
forEachField(tab.sections);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
for (const field of (section.fields ?? [])) {
|
|
283
|
-
schemaObject[field.name] = generateFieldSchema(field as FormBuilderFieldConfig<TFieldValues, string | Path<TFieldValues>>);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
forEachField(sections);
|
|
289
|
-
|
|
290
|
-
return z.object(schemaObject) as unknown as z.ZodType<TFieldValues>;
|
|
291
|
-
}, [sections, schema]);
|
|
292
|
-
|
|
293
|
-
// Generate default values from field configs
|
|
294
|
-
const generatedDefaultValues = useMemo(() => {
|
|
295
|
-
const values: Record<string, unknown> = { ...((defaultValues ?? {}) as Record<string, unknown>) };
|
|
296
|
-
|
|
297
|
-
const processFields = (fields: FormBuilderFieldConfig<TFieldValues, string | Path<TFieldValues>>[]) => {
|
|
298
|
-
for (const field of fields) {
|
|
299
|
-
if (
|
|
300
|
-
values[field.name] === undefined &&
|
|
301
|
-
field.defaultValue !== undefined
|
|
302
|
-
) {
|
|
303
|
-
values[field.name] = field.defaultValue;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
if (field.type === 'object' && field.fields) {
|
|
307
|
-
if (!values[field.name]) values[field.name] = {};
|
|
308
|
-
const nestedValues: Record<string, unknown> = {};
|
|
309
|
-
for (const subField of field.fields) {
|
|
310
|
-
if (subField.defaultValue !== undefined) {
|
|
311
|
-
nestedValues[subField.name] = subField.defaultValue;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
const existing =
|
|
315
|
-
values[field.name] && typeof values[field.name] === 'object'
|
|
316
|
-
? (values[field.name] as Record<string, unknown>)
|
|
317
|
-
: {};
|
|
318
|
-
values[field.name] = { ...nestedValues, ...existing };
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
if (field.type === 'array' && field.fields) {
|
|
322
|
-
if (!values[field.name]) {
|
|
323
|
-
values[field.name] = field.defaultValue || [];
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
};
|
|
328
|
-
|
|
329
|
-
const forEachSection = (secs: FormBuilderSectionConfig<TFieldValues>[]) => {
|
|
330
|
-
for (const section of secs) {
|
|
331
|
-
if (section.tabs && section.tabs.length > 0) {
|
|
332
|
-
for (const tab of section.tabs) {
|
|
333
|
-
forEachSection(tab.sections);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
processFields(section.fields ?? []);
|
|
337
|
-
}
|
|
338
|
-
};
|
|
339
|
-
|
|
340
|
-
forEachSection(sections);
|
|
341
|
-
|
|
342
|
-
return values;
|
|
343
|
-
}, [sections, defaultValues]);
|
|
344
|
-
|
|
345
|
-
const internalForm = useForm<TFieldValues>({
|
|
346
|
-
// Dynamic schema shape: cast to any to satisfy resolver generics
|
|
347
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
348
|
-
resolver: zodResolver(generatedSchema as any) as unknown as import('react-hook-form').Resolver<TFieldValues, any, TFieldValues>,
|
|
349
|
-
defaultValues: generatedDefaultValues as unknown as import('react-hook-form').DefaultValues<TFieldValues>,
|
|
42
|
+
// Always call useFormBuilder hook (hooks must be called unconditionally)
|
|
43
|
+
const { form: generatedForm } = useFormBuilder({
|
|
44
|
+
sections,
|
|
45
|
+
schema,
|
|
46
|
+
defaultValues: defaultValues ?? undefined,
|
|
350
47
|
});
|
|
351
48
|
|
|
352
|
-
|
|
49
|
+
// Use provided form or fall back to generated form
|
|
50
|
+
const activeForm = form ?? generatedForm;
|
|
353
51
|
|
|
354
52
|
const { control, handleSubmit, reset, setValue, getValues } = activeForm;
|
|
355
53
|
|
|
@@ -363,7 +61,7 @@ export function FormBuilder<TFieldValues extends FieldValues = FieldValues>({
|
|
|
363
61
|
forEachField(tab.sections);
|
|
364
62
|
}
|
|
365
63
|
}
|
|
366
|
-
for (const f of
|
|
64
|
+
for (const f of section.fields ?? []) {
|
|
367
65
|
for (const d of f.dependencies || []) {
|
|
368
66
|
set.add(d.field);
|
|
369
67
|
}
|
|
@@ -391,12 +89,14 @@ export function FormBuilder<TFieldValues extends FieldValues = FieldValues>({
|
|
|
391
89
|
|
|
392
90
|
// Handle field dependencies
|
|
393
91
|
// Queue dependency-driven value updates to avoid calling setValue during render
|
|
394
|
-
const pendingValueUpdatesRef = useRef<
|
|
395
|
-
|
|
396
|
-
);
|
|
92
|
+
const pendingValueUpdatesRef = useRef<
|
|
93
|
+
Array<{ name: string; value: unknown }>
|
|
94
|
+
>([]);
|
|
397
95
|
|
|
398
96
|
const handleFieldDependencies = useCallback(
|
|
399
|
-
(
|
|
97
|
+
(
|
|
98
|
+
field: FormBuilderFieldConfig<TFieldValues, string | Path<TFieldValues>>
|
|
99
|
+
) => {
|
|
400
100
|
if (!hasDependencies || !field.dependencies) return {};
|
|
401
101
|
|
|
402
102
|
const result: { disabled?: boolean; hidden?: boolean } = {};
|
|
@@ -420,7 +120,9 @@ export function FormBuilder<TFieldValues extends FieldValues = FieldValues>({
|
|
|
420
120
|
break;
|
|
421
121
|
case 'setValue':
|
|
422
122
|
if (conditionMet && dep.value !== undefined) {
|
|
423
|
-
const currentValue = getValues(
|
|
123
|
+
const currentValue = getValues(
|
|
124
|
+
field.name as unknown as Path<TFieldValues>
|
|
125
|
+
);
|
|
424
126
|
if (currentValue !== dep.value) {
|
|
425
127
|
// Defer the update to an effect to prevent state changes during render
|
|
426
128
|
pendingValueUpdatesRef.current.push({
|
|
@@ -486,9 +188,9 @@ export function FormBuilder<TFieldValues extends FieldValues = FieldValues>({
|
|
|
486
188
|
);
|
|
487
189
|
|
|
488
190
|
const handleReset = useCallback(() => {
|
|
489
|
-
reset(
|
|
191
|
+
reset();
|
|
490
192
|
onReset?.();
|
|
491
|
-
}, [reset,
|
|
193
|
+
}, [reset, onReset]);
|
|
492
194
|
|
|
493
195
|
// Build SectionBuilder nodes from form sections/fields
|
|
494
196
|
const sectionNodes = useMemo(
|
|
@@ -501,23 +203,40 @@ export function FormBuilder<TFieldValues extends FieldValues = FieldValues>({
|
|
|
501
203
|
onFieldChange,
|
|
502
204
|
getValues,
|
|
503
205
|
}),
|
|
504
|
-
[
|
|
206
|
+
[
|
|
207
|
+
sections,
|
|
208
|
+
control,
|
|
209
|
+
handleFieldDependencies,
|
|
210
|
+
handleFieldChange,
|
|
211
|
+
onFieldChange,
|
|
212
|
+
getValues,
|
|
213
|
+
]
|
|
505
214
|
);
|
|
506
215
|
|
|
507
216
|
const contextValue = useMemo(
|
|
508
|
-
() =>
|
|
217
|
+
() =>
|
|
218
|
+
({
|
|
219
|
+
control,
|
|
220
|
+
getValues,
|
|
221
|
+
setValue,
|
|
222
|
+
onFieldChange,
|
|
223
|
+
handleFieldDependencies,
|
|
224
|
+
handleFieldChange,
|
|
225
|
+
} satisfies FormBuilderContextValue<TFieldValues>),
|
|
226
|
+
[
|
|
509
227
|
control,
|
|
510
228
|
getValues,
|
|
511
229
|
setValue,
|
|
512
230
|
onFieldChange,
|
|
513
231
|
handleFieldDependencies,
|
|
514
232
|
handleFieldChange,
|
|
515
|
-
|
|
516
|
-
[control, getValues, setValue, onFieldChange, handleFieldDependencies, handleFieldChange],
|
|
233
|
+
]
|
|
517
234
|
);
|
|
518
235
|
|
|
519
236
|
return (
|
|
520
|
-
<FormBuilderContext.Provider
|
|
237
|
+
<FormBuilderContext.Provider
|
|
238
|
+
value={contextValue as unknown as FormBuilderContextValue<FieldValues>}
|
|
239
|
+
>
|
|
521
240
|
<div className={cn('space-y-6', className)}>
|
|
522
241
|
<form
|
|
523
242
|
onSubmit={handleSubmit(handleFormSubmit)}
|
|
@@ -335,7 +335,9 @@ export function FormBuilderField<
|
|
|
335
335
|
<p className="text-sm text-muted-foreground">{field.description}</p>
|
|
336
336
|
)}
|
|
337
337
|
{error && (
|
|
338
|
-
<p className="text-sm text-destructive">
|
|
338
|
+
<p className="text-sm font-medium text-destructive" role="alert" aria-live="polite">
|
|
339
|
+
{error.message}
|
|
340
|
+
</p>
|
|
339
341
|
)}
|
|
340
342
|
</div>
|
|
341
343
|
);
|
|
@@ -351,7 +353,9 @@ export function FormBuilderField<
|
|
|
351
353
|
<p className="text-sm text-muted-foreground">{field.description}</p>
|
|
352
354
|
)}
|
|
353
355
|
{error && (
|
|
354
|
-
<p className="text-sm text-destructive">
|
|
356
|
+
<p className="text-sm font-medium text-destructive" role="alert" aria-live="polite">
|
|
357
|
+
{error.message}
|
|
358
|
+
</p>
|
|
355
359
|
)}
|
|
356
360
|
</div>
|
|
357
361
|
);
|
|
@@ -371,7 +375,9 @@ export function FormBuilderField<
|
|
|
371
375
|
<p className="text-sm text-muted-foreground">{field.description}</p>
|
|
372
376
|
)}
|
|
373
377
|
{error && (
|
|
374
|
-
<p className="text-sm text-destructive">
|
|
378
|
+
<p className="text-sm font-medium text-destructive" role="alert" aria-live="polite">
|
|
379
|
+
{error.message}
|
|
380
|
+
</p>
|
|
375
381
|
)}
|
|
376
382
|
</div>
|
|
377
383
|
);
|
|
@@ -389,7 +395,9 @@ export function FormBuilderField<
|
|
|
389
395
|
<p className="text-sm text-muted-foreground">{field.description}</p>
|
|
390
396
|
)}
|
|
391
397
|
{error && (
|
|
392
|
-
<p className="text-sm text-destructive">
|
|
398
|
+
<p className="text-sm font-medium text-destructive" role="alert" aria-live="polite">
|
|
399
|
+
{error.message}
|
|
400
|
+
</p>
|
|
393
401
|
)}
|
|
394
402
|
</div>
|
|
395
403
|
);
|