rhf-dynamic-forms 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +692 -0
- package/dist/index.cjs +1611 -0
- package/dist/index.d.cts +1124 -0
- package/dist/index.d.mts +1124 -0
- package/dist/index.mjs +1557 -0
- package/package.json +82 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,1124 @@
|
|
|
1
|
+
import * as react0 from "react";
|
|
2
|
+
import React$1, { CSSProperties, ReactNode } from "react";
|
|
3
|
+
import { ControllerFieldState, ControllerRenderProps, FieldErrors, FieldPath, FieldValues, Resolver, UseFormReturn } from "react-hook-form";
|
|
4
|
+
import { ZodObject, ZodRawShape, ZodTypeAny, z } from "zod";
|
|
5
|
+
|
|
6
|
+
//#region src/types/validation.d.ts
|
|
7
|
+
/**
|
|
8
|
+
* JSON Logic rule type - a generic record for JSON Logic expressions.
|
|
9
|
+
* Used for visibility and validation conditions.
|
|
10
|
+
*/
|
|
11
|
+
type JsonLogicRule = Record<string, unknown>;
|
|
12
|
+
/**
|
|
13
|
+
* Validation configuration for form fields.
|
|
14
|
+
* Phase 1 supports: required, minLength, maxLength, pattern
|
|
15
|
+
* Phase 3 will add: condition (JSON Logic)
|
|
16
|
+
*/
|
|
17
|
+
interface ValidationConfig {
|
|
18
|
+
/** Field is required - must have a non-empty value */
|
|
19
|
+
required?: boolean;
|
|
20
|
+
/** Type-specific validation (for future use) */
|
|
21
|
+
type?: "number" | "email" | "date";
|
|
22
|
+
/** Minimum length for text fields */
|
|
23
|
+
minLength?: number;
|
|
24
|
+
/** Maximum length for text fields */
|
|
25
|
+
maxLength?: number;
|
|
26
|
+
/** Regular expression pattern for validation */
|
|
27
|
+
pattern?: string;
|
|
28
|
+
/** Custom error message for pattern/condition failure */
|
|
29
|
+
message?: string;
|
|
30
|
+
/** JSON Logic condition for complex validation (Phase 3) */
|
|
31
|
+
condition?: JsonLogicRule;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Controls validation behavior for invisible fields.
|
|
35
|
+
* - 'skip': Do not validate invisible fields (default)
|
|
36
|
+
* - 'validate': Validate all fields regardless of visibility
|
|
37
|
+
* - 'warn': Validate but treat errors as warnings (non-blocking)
|
|
38
|
+
*/
|
|
39
|
+
type InvisibleFieldValidation = "skip" | "validate" | "warn";
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/types/elements.d.ts
|
|
42
|
+
/**
|
|
43
|
+
* All supported element types in the form configuration.
|
|
44
|
+
* Phase 1: text, email, boolean, phone, date, custom
|
|
45
|
+
* Phase 2 adds: container, column
|
|
46
|
+
* Phase 3 adds: select, array
|
|
47
|
+
*/
|
|
48
|
+
type ElementType = "text" | "email" | "boolean" | "phone" | "date" | "select" | "array" | "container" | "column" | "custom";
|
|
49
|
+
/**
|
|
50
|
+
* Field types that render input controls.
|
|
51
|
+
*/
|
|
52
|
+
type FieldType = "text" | "email" | "boolean" | "phone" | "date" | "select" | "array";
|
|
53
|
+
/**
|
|
54
|
+
* Base interface for all field elements.
|
|
55
|
+
*/
|
|
56
|
+
interface BaseFieldElement {
|
|
57
|
+
type: ElementType;
|
|
58
|
+
/** Unique identifier for form data binding (supports dot notation like 'source.name') */
|
|
59
|
+
name: string;
|
|
60
|
+
/** Display label for the field */
|
|
61
|
+
label?: string;
|
|
62
|
+
/** Placeholder text (for text-based inputs) */
|
|
63
|
+
placeholder?: string;
|
|
64
|
+
/** Default value for the field (arrays for multi-select, records for complex fields) */
|
|
65
|
+
defaultValue?: string | number | boolean | null | unknown[] | Record<string, unknown>;
|
|
66
|
+
/** Validation configuration */
|
|
67
|
+
validation?: ValidationConfig;
|
|
68
|
+
/** Conditional visibility rules using JSON Logic (Phase 4) */
|
|
69
|
+
visible?: JsonLogicRule;
|
|
70
|
+
/** Field path this field depends on (for cascading selects, etc.) */
|
|
71
|
+
dependsOn?: string;
|
|
72
|
+
/** Reset this field when parent changes (default: true) */
|
|
73
|
+
resetOnParentChange?: boolean;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Text input field element.
|
|
77
|
+
*/
|
|
78
|
+
interface TextFieldElement extends BaseFieldElement {
|
|
79
|
+
type: "text";
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Email input field element.
|
|
83
|
+
*/
|
|
84
|
+
interface EmailFieldElement extends BaseFieldElement {
|
|
85
|
+
type: "email";
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Boolean (checkbox/toggle) field element.
|
|
89
|
+
*/
|
|
90
|
+
interface BooleanFieldElement extends BaseFieldElement {
|
|
91
|
+
type: "boolean";
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Phone number input field element.
|
|
95
|
+
*/
|
|
96
|
+
interface PhoneFieldElement extends BaseFieldElement {
|
|
97
|
+
type: "phone";
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Date picker field element.
|
|
101
|
+
*/
|
|
102
|
+
interface DateFieldElement extends BaseFieldElement {
|
|
103
|
+
type: "date";
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Option for select field elements.
|
|
107
|
+
*/
|
|
108
|
+
interface SelectOption {
|
|
109
|
+
/** Option value (stored in form data) */
|
|
110
|
+
value: string | number;
|
|
111
|
+
/** Display label */
|
|
112
|
+
label: string;
|
|
113
|
+
/** Disable this option */
|
|
114
|
+
disabled?: boolean;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Static options source - use config.options directly.
|
|
118
|
+
*/
|
|
119
|
+
interface StaticOptionsSource {
|
|
120
|
+
type: "static";
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Map options source - lookup from provided options map.
|
|
124
|
+
*/
|
|
125
|
+
interface MapOptionsSource {
|
|
126
|
+
type: "map";
|
|
127
|
+
/** Key in the options map */
|
|
128
|
+
key: string;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* API options source - fetch from endpoint.
|
|
132
|
+
*/
|
|
133
|
+
interface ApiOptionsSource {
|
|
134
|
+
type: "api";
|
|
135
|
+
/** API endpoint URL */
|
|
136
|
+
endpoint: string;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Search options source - search as you type.
|
|
140
|
+
*/
|
|
141
|
+
interface SearchOptionsSource {
|
|
142
|
+
type: "search";
|
|
143
|
+
/** API endpoint for search */
|
|
144
|
+
endpoint: string;
|
|
145
|
+
/** Minimum characters before searching (default: 2) */
|
|
146
|
+
minChars?: number;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Resolver options source - custom resolver function.
|
|
150
|
+
*/
|
|
151
|
+
interface ResolverOptionsSource {
|
|
152
|
+
type: "resolver";
|
|
153
|
+
/** Name of the registered resolver */
|
|
154
|
+
name: string;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Describes how to resolve options for a select field.
|
|
158
|
+
* This is declarative - describes intent, not implementation.
|
|
159
|
+
* Actual data fetching is done by field component.
|
|
160
|
+
*/
|
|
161
|
+
type OptionsSource = StaticOptionsSource | MapOptionsSource | ApiOptionsSource | SearchOptionsSource | ResolverOptionsSource;
|
|
162
|
+
/**
|
|
163
|
+
* Select field element for dropdowns and multi-selects.
|
|
164
|
+
*/
|
|
165
|
+
interface SelectFieldElement extends BaseFieldElement {
|
|
166
|
+
type: "select";
|
|
167
|
+
/** Available options (required when optionsSource is not provided) */
|
|
168
|
+
options?: SelectOption[];
|
|
169
|
+
/** Describes how to resolve options (when provided, options become optional) */
|
|
170
|
+
optionsSource?: OptionsSource;
|
|
171
|
+
/** Allow selecting multiple values (default: false) */
|
|
172
|
+
multiple?: boolean;
|
|
173
|
+
/** Allow clearing selection (default: true) */
|
|
174
|
+
clearable?: boolean;
|
|
175
|
+
/** Allow searching/filtering options (default: false) */
|
|
176
|
+
searchable?: boolean;
|
|
177
|
+
/** Allow creating new options not in the list (default: false) */
|
|
178
|
+
creatable?: boolean;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Custom component field element.
|
|
182
|
+
* Allows rendering user-defined components.
|
|
183
|
+
*/
|
|
184
|
+
interface CustomFieldElement extends BaseFieldElement {
|
|
185
|
+
type: "custom";
|
|
186
|
+
/** Name of the registered custom component */
|
|
187
|
+
component: string;
|
|
188
|
+
/** Props to pass to the custom component */
|
|
189
|
+
componentProps?: Record<string, unknown>;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Array/repeater field element.
|
|
193
|
+
* Contains repeatable group of fields.
|
|
194
|
+
*/
|
|
195
|
+
interface ArrayFieldElement extends BaseFieldElement {
|
|
196
|
+
type: "array";
|
|
197
|
+
/** Fields template for each item (can contain any field type) */
|
|
198
|
+
itemFields: FieldElement[];
|
|
199
|
+
/** Minimum items required */
|
|
200
|
+
minItems?: number;
|
|
201
|
+
/** Maximum items allowed */
|
|
202
|
+
maxItems?: number;
|
|
203
|
+
/** Label for add button */
|
|
204
|
+
addButtonLabel?: string;
|
|
205
|
+
/** Allow reordering items */
|
|
206
|
+
sortable?: boolean;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Container element for grouping fields in columns (Phase 2).
|
|
210
|
+
*/
|
|
211
|
+
interface ContainerElement {
|
|
212
|
+
type: "container";
|
|
213
|
+
/** Array of column elements */
|
|
214
|
+
columns: ColumnElement[];
|
|
215
|
+
/** Conditional visibility rules using JSON Logic */
|
|
216
|
+
visible?: JsonLogicRule;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Column element within a container (Phase 2).
|
|
220
|
+
*/
|
|
221
|
+
interface ColumnElement {
|
|
222
|
+
type: "column";
|
|
223
|
+
/** Column width (e.g., '50%', '200px') */
|
|
224
|
+
width: string;
|
|
225
|
+
/** Nested elements within the column */
|
|
226
|
+
elements: FormElement[];
|
|
227
|
+
/** Conditional visibility rules using JSON Logic */
|
|
228
|
+
visible?: JsonLogicRule;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Union of all field element types.
|
|
232
|
+
*/
|
|
233
|
+
type FieldElement = TextFieldElement | EmailFieldElement | BooleanFieldElement | PhoneFieldElement | DateFieldElement | SelectFieldElement | ArrayFieldElement | CustomFieldElement;
|
|
234
|
+
/**
|
|
235
|
+
* Union of all layout element types.
|
|
236
|
+
*/
|
|
237
|
+
type LayoutElement = ContainerElement | ColumnElement;
|
|
238
|
+
/**
|
|
239
|
+
* Union of all form element types.
|
|
240
|
+
*/
|
|
241
|
+
type FormElement = FieldElement | LayoutElement;
|
|
242
|
+
/**
|
|
243
|
+
* Type guard to check if an element is a field element.
|
|
244
|
+
*/
|
|
245
|
+
declare const isFieldElement: (element: FormElement) => element is FieldElement;
|
|
246
|
+
/**
|
|
247
|
+
* Type guard to check if an element is an array field element.
|
|
248
|
+
*/
|
|
249
|
+
declare const isArrayFieldElement: (element: FormElement) => element is ArrayFieldElement;
|
|
250
|
+
/**
|
|
251
|
+
* Type guard to check if an element is a container element.
|
|
252
|
+
*/
|
|
253
|
+
declare const isContainerElement: (element: FormElement) => element is ContainerElement;
|
|
254
|
+
/**
|
|
255
|
+
* Type guard to check if an element is a column element.
|
|
256
|
+
*/
|
|
257
|
+
declare const isColumnElement: (element: FormElement) => element is ColumnElement;
|
|
258
|
+
/**
|
|
259
|
+
* Type guard to check if an element is a custom field element.
|
|
260
|
+
*/
|
|
261
|
+
declare const isCustomFieldElement: (element: FormElement) => element is CustomFieldElement;
|
|
262
|
+
//#endregion
|
|
263
|
+
//#region src/types/events.d.ts
|
|
264
|
+
/**
|
|
265
|
+
* Form data type - a generic record for form values.
|
|
266
|
+
* Values are nested according to dot-notation field names.
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* ```typescript
|
|
270
|
+
* // For field name "source.name", data will be:
|
|
271
|
+
* { source: { name: "John" } }
|
|
272
|
+
* ```
|
|
273
|
+
*/
|
|
274
|
+
type FormData = Record<string, unknown>;
|
|
275
|
+
/**
|
|
276
|
+
* Handler called when form is submitted with valid data.
|
|
277
|
+
*/
|
|
278
|
+
type OnSubmitHandler = (data: FormData) => void | Promise<void>;
|
|
279
|
+
/**
|
|
280
|
+
* Handler called when form values change.
|
|
281
|
+
*
|
|
282
|
+
* @param data - Current form data
|
|
283
|
+
* @param changedField - The name of the field that changed
|
|
284
|
+
*/
|
|
285
|
+
type OnChangeHandler = (data: FormData, changedField: string) => void;
|
|
286
|
+
/**
|
|
287
|
+
* Handler called when validation state changes.
|
|
288
|
+
*
|
|
289
|
+
* @param errors - Current validation errors
|
|
290
|
+
* @param isValid - Whether the form is currently valid
|
|
291
|
+
*/
|
|
292
|
+
type OnValidationChangeHandler = (errors: FieldErrors, isValid: boolean) => void;
|
|
293
|
+
/**
|
|
294
|
+
* Handler called when form is reset.
|
|
295
|
+
*/
|
|
296
|
+
type OnResetHandler = () => void;
|
|
297
|
+
/**
|
|
298
|
+
* Handler called on form submission errors.
|
|
299
|
+
*
|
|
300
|
+
* @param errors - Validation errors that prevented submission
|
|
301
|
+
*/
|
|
302
|
+
type OnErrorHandler = (errors: FieldErrors) => void;
|
|
303
|
+
//#endregion
|
|
304
|
+
//#region src/customComponents/types.d.ts
|
|
305
|
+
interface CustomComponentRenderProps<TProps extends Record<string, unknown> = Record<string, unknown>> {
|
|
306
|
+
field: ControllerRenderProps;
|
|
307
|
+
fieldState: ControllerFieldState;
|
|
308
|
+
config: CustomFieldElement;
|
|
309
|
+
componentProps: TProps;
|
|
310
|
+
formValues: FormData;
|
|
311
|
+
setValue: (name: string, value: unknown) => void;
|
|
312
|
+
}
|
|
313
|
+
interface CustomComponentDefinition<TProps extends Record<string, unknown> = Record<string, unknown>> {
|
|
314
|
+
component: React.ComponentType<CustomComponentRenderProps<TProps>>;
|
|
315
|
+
propsSchema?: ZodObject<ZodRawShape>;
|
|
316
|
+
defaultProps?: Partial<TProps>;
|
|
317
|
+
description?: string;
|
|
318
|
+
displayName?: string;
|
|
319
|
+
}
|
|
320
|
+
type CustomComponentRegistry = Record<string, CustomComponentDefinition<any> | React.ComponentType<any>>;
|
|
321
|
+
//#endregion
|
|
322
|
+
//#region src/customComponents/defineCustomComponent.d.ts
|
|
323
|
+
/**
|
|
324
|
+
* Type-safe helper for defining custom components.
|
|
325
|
+
* Provides TypeScript inference for component props based on propsSchema.
|
|
326
|
+
*
|
|
327
|
+
* @example
|
|
328
|
+
* ```ts
|
|
329
|
+
* const RatingField = defineCustomComponent({
|
|
330
|
+
* component: RatingFieldComponent,
|
|
331
|
+
* propsSchema: z.object({ maxStars: z.number() }),
|
|
332
|
+
* defaultProps: { maxStars: 5 },
|
|
333
|
+
* });
|
|
334
|
+
* ```
|
|
335
|
+
*/
|
|
336
|
+
declare function defineCustomComponent<TProps extends Record<string, unknown> = Record<string, unknown>>(definition: CustomComponentDefinition<TProps>): CustomComponentDefinition<TProps>;
|
|
337
|
+
//#endregion
|
|
338
|
+
//#region src/types/fields.d.ts
|
|
339
|
+
/**
|
|
340
|
+
* Base props passed to all field components.
|
|
341
|
+
* Field components receive react-hook-form controller props.
|
|
342
|
+
*
|
|
343
|
+
* @example
|
|
344
|
+
* ```tsx
|
|
345
|
+
* const MyTextField: TextFieldComponent = ({ field, fieldState, config, formValues }) => (
|
|
346
|
+
* <div>
|
|
347
|
+
* <label>{config.label}</label>
|
|
348
|
+
* <input {...field} />
|
|
349
|
+
* {fieldState.error && <span>{fieldState.error.message}</span>}
|
|
350
|
+
* </div>
|
|
351
|
+
* );
|
|
352
|
+
* ```
|
|
353
|
+
*/
|
|
354
|
+
interface BaseFieldProps<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TConfig extends BaseFieldElement = BaseFieldElement> {
|
|
355
|
+
/** react-hook-form field props (value, onChange, onBlur, name, ref) */
|
|
356
|
+
field: ControllerRenderProps<TFieldValues, TName>;
|
|
357
|
+
/** react-hook-form field state (invalid, isTouched, isDirty, error) */
|
|
358
|
+
fieldState: ControllerFieldState;
|
|
359
|
+
/** Field configuration from form config */
|
|
360
|
+
config: TConfig;
|
|
361
|
+
/** All current form values (for reading other fields, dependent logic) */
|
|
362
|
+
formValues: FormData;
|
|
363
|
+
/** Set any field value (for dependent field logic, cascading updates) */
|
|
364
|
+
setValue: (name: string, value: unknown) => void;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Props for text input field component.
|
|
368
|
+
*/
|
|
369
|
+
type TextFieldProps = BaseFieldProps<FieldValues, FieldPath<FieldValues>, TextFieldElement>;
|
|
370
|
+
/**
|
|
371
|
+
* Props for email input field component.
|
|
372
|
+
*/
|
|
373
|
+
type EmailFieldProps = BaseFieldProps<FieldValues, FieldPath<FieldValues>, EmailFieldElement>;
|
|
374
|
+
/**
|
|
375
|
+
* Props for boolean (checkbox/toggle) field component.
|
|
376
|
+
*/
|
|
377
|
+
type BooleanFieldProps = BaseFieldProps<FieldValues, FieldPath<FieldValues>, BooleanFieldElement>;
|
|
378
|
+
/**
|
|
379
|
+
* Props for phone input field component.
|
|
380
|
+
*/
|
|
381
|
+
type PhoneFieldProps = BaseFieldProps<FieldValues, FieldPath<FieldValues>, PhoneFieldElement>;
|
|
382
|
+
/**
|
|
383
|
+
* Props for date input field component.
|
|
384
|
+
*/
|
|
385
|
+
type DateFieldProps = BaseFieldProps<FieldValues, FieldPath<FieldValues>, DateFieldElement>;
|
|
386
|
+
/**
|
|
387
|
+
* Props for select field component.
|
|
388
|
+
*/
|
|
389
|
+
type SelectFieldProps = BaseFieldProps<FieldValues, FieldPath<FieldValues>, SelectFieldElement>;
|
|
390
|
+
/**
|
|
391
|
+
* Props for array field component.
|
|
392
|
+
*/
|
|
393
|
+
type ArrayFieldProps = BaseFieldProps<FieldValues, FieldPath<FieldValues>, ArrayFieldElement>;
|
|
394
|
+
/**
|
|
395
|
+
* Props for custom field components.
|
|
396
|
+
* Custom components receive additional componentProps from configuration.
|
|
397
|
+
*/
|
|
398
|
+
type CustomFieldProps = BaseFieldProps<FieldValues, FieldPath<FieldValues>, CustomFieldElement>;
|
|
399
|
+
/**
|
|
400
|
+
* Base component type that accepts any field configuration.
|
|
401
|
+
* Used internally for dynamic field rendering where the specific
|
|
402
|
+
* field type is determined at runtime.
|
|
403
|
+
*/
|
|
404
|
+
type BaseFieldComponent<TProps extends BaseFieldProps = BaseFieldProps> = React.ComponentType<TProps>;
|
|
405
|
+
/**
|
|
406
|
+
* Component type for text fields.
|
|
407
|
+
*/
|
|
408
|
+
type TextFieldComponent = BaseFieldComponent<TextFieldProps>;
|
|
409
|
+
/**
|
|
410
|
+
* Component type for email fields.
|
|
411
|
+
*/
|
|
412
|
+
type EmailFieldComponent = BaseFieldComponent<EmailFieldProps>;
|
|
413
|
+
/**
|
|
414
|
+
* Component type for boolean fields.
|
|
415
|
+
*/
|
|
416
|
+
type BooleanFieldComponent = BaseFieldComponent<BooleanFieldProps>;
|
|
417
|
+
/**
|
|
418
|
+
* Component type for phone fields.
|
|
419
|
+
*/
|
|
420
|
+
type PhoneFieldComponent = BaseFieldComponent<PhoneFieldProps>;
|
|
421
|
+
/**
|
|
422
|
+
* Component type for date fields.
|
|
423
|
+
*/
|
|
424
|
+
type DateFieldComponent = BaseFieldComponent<DateFieldProps>;
|
|
425
|
+
/**
|
|
426
|
+
* Component type for select fields.
|
|
427
|
+
*/
|
|
428
|
+
type SelectFieldComponent = BaseFieldComponent<SelectFieldProps>;
|
|
429
|
+
/**
|
|
430
|
+
* Component type for array fields.
|
|
431
|
+
*/
|
|
432
|
+
type ArrayFieldComponent = BaseFieldComponent<ArrayFieldProps>;
|
|
433
|
+
/**
|
|
434
|
+
* Component type for custom fields.
|
|
435
|
+
*/
|
|
436
|
+
type CustomFieldComponent = BaseFieldComponent<CustomFieldProps>;
|
|
437
|
+
type StandardFieldComponent = TextFieldComponent | EmailFieldComponent | BooleanFieldComponent | PhoneFieldComponent | DateFieldComponent | SelectFieldComponent | ArrayFieldComponent;
|
|
438
|
+
type StandardFieldComponentType = Exclude<ElementType, "custom">;
|
|
439
|
+
interface FieldComponentRegistry extends Partial<Record<StandardFieldComponentType, StandardFieldComponent>> {
|
|
440
|
+
text: TextFieldComponent;
|
|
441
|
+
email: EmailFieldComponent;
|
|
442
|
+
boolean: BooleanFieldComponent;
|
|
443
|
+
phone: PhoneFieldComponent;
|
|
444
|
+
date: DateFieldComponent;
|
|
445
|
+
select: SelectFieldComponent;
|
|
446
|
+
array: ArrayFieldComponent;
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Union type for all field props.
|
|
450
|
+
*/
|
|
451
|
+
type FieldProps = TextFieldProps | EmailFieldProps | BooleanFieldProps | PhoneFieldProps | DateFieldProps | SelectFieldProps | ArrayFieldProps | CustomFieldProps;
|
|
452
|
+
/**
|
|
453
|
+
* Props for container components.
|
|
454
|
+
* Containers wrap columns and provide layout structure.
|
|
455
|
+
*/
|
|
456
|
+
interface ContainerProps {
|
|
457
|
+
/** Container configuration from form config */
|
|
458
|
+
config: ContainerElement;
|
|
459
|
+
/** Column elements rendered as children */
|
|
460
|
+
children: React.ReactNode;
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Props for column components.
|
|
464
|
+
* Columns wrap form elements and apply width styling.
|
|
465
|
+
*/
|
|
466
|
+
interface ColumnProps {
|
|
467
|
+
/** Column configuration from form config */
|
|
468
|
+
config: ColumnElement;
|
|
469
|
+
/** Form elements rendered as children */
|
|
470
|
+
children: React.ReactNode;
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Component type for container layouts.
|
|
474
|
+
*/
|
|
475
|
+
type ContainerComponent = React.ComponentType<ContainerProps>;
|
|
476
|
+
/**
|
|
477
|
+
* Component type for column layouts.
|
|
478
|
+
*/
|
|
479
|
+
type ColumnComponent = React.ComponentType<ColumnProps>;
|
|
480
|
+
/**
|
|
481
|
+
* Registry for custom container components referenced by name.
|
|
482
|
+
* Allows users to provide custom container implementations.
|
|
483
|
+
*
|
|
484
|
+
* @example
|
|
485
|
+
* ```tsx
|
|
486
|
+
* const customContainers: CustomContainerRegistry = {
|
|
487
|
+
* card: CardContainer,
|
|
488
|
+
* section: SectionContainer,
|
|
489
|
+
* };
|
|
490
|
+
* ```
|
|
491
|
+
*/
|
|
492
|
+
type CustomContainerRegistry = Record<string, ContainerComponent>;
|
|
493
|
+
//#endregion
|
|
494
|
+
//#region src/types/config.d.ts
|
|
495
|
+
/**
|
|
496
|
+
* Props passed to the fieldWrapper function.
|
|
497
|
+
* Contains field metadata for custom wrapper implementations.
|
|
498
|
+
*/
|
|
499
|
+
interface FieldWrapperProps {
|
|
500
|
+
/** Field path (e.g., "contact.email") */
|
|
501
|
+
name: string;
|
|
502
|
+
/** Raw field configuration from form config */
|
|
503
|
+
config: FieldElement;
|
|
504
|
+
/** react-hook-form field state (error, isDirty, isTouched, invalid) */
|
|
505
|
+
fieldState: ControllerFieldState;
|
|
506
|
+
/** Current field value */
|
|
507
|
+
value: unknown;
|
|
508
|
+
/** All current form values (for reading other fields) */
|
|
509
|
+
formValues: FormData;
|
|
510
|
+
/** Set any field value (for dependent field logic) */
|
|
511
|
+
setValue: (name: string, value: unknown) => void;
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Function type for wrapping field components.
|
|
515
|
+
* Receives field metadata and the rendered field element.
|
|
516
|
+
*
|
|
517
|
+
* @example
|
|
518
|
+
* ```tsx
|
|
519
|
+
* const myFieldWrapper: FieldWrapperFunction = (props, children) => (
|
|
520
|
+
* <div className="field-wrapper">
|
|
521
|
+
* <Badge>{props.name}</Badge>
|
|
522
|
+
* {children}
|
|
523
|
+
* </div>
|
|
524
|
+
* );
|
|
525
|
+
* ```
|
|
526
|
+
*/
|
|
527
|
+
type FieldWrapperFunction = (props: FieldWrapperProps, children: ReactNode) => ReactNode;
|
|
528
|
+
/**
|
|
529
|
+
* Root form configuration object.
|
|
530
|
+
* This is the JSON structure that defines the entire form.
|
|
531
|
+
*
|
|
532
|
+
* @example
|
|
533
|
+
* ```json
|
|
534
|
+
* {
|
|
535
|
+
* "name": "Contact Form",
|
|
536
|
+
* "elements": [
|
|
537
|
+
* { "type": "text", "name": "source.name", "label": "Name" },
|
|
538
|
+
* { "type": "email", "name": "source.email", "label": "Email" }
|
|
539
|
+
* ]
|
|
540
|
+
* }
|
|
541
|
+
* ```
|
|
542
|
+
*/
|
|
543
|
+
interface FormConfiguration {
|
|
544
|
+
/** Optional name/identifier for the form */
|
|
545
|
+
name?: string;
|
|
546
|
+
/** Array of form elements (fields and layouts) */
|
|
547
|
+
elements: FormElement[];
|
|
548
|
+
/** Custom component definitions (for advanced use) */
|
|
549
|
+
customComponents?: Record<string, CustomComponentDefinition>;
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Props for the DynamicForm component.
|
|
553
|
+
*
|
|
554
|
+
* @example
|
|
555
|
+
* ```tsx
|
|
556
|
+
* <DynamicForm
|
|
557
|
+
* config={formConfig}
|
|
558
|
+
* fieldComponents={myFieldComponents}
|
|
559
|
+
* onSubmit={(data) => console.log(data)}
|
|
560
|
+
* onChange={(data, field) => console.log(`${field} changed`)}
|
|
561
|
+
* />
|
|
562
|
+
* ```
|
|
563
|
+
*/
|
|
564
|
+
interface DynamicFormProps {
|
|
565
|
+
/** Form configuration - defines structure, fields, and validation */
|
|
566
|
+
config: FormConfiguration;
|
|
567
|
+
/** Initial form data to populate fields */
|
|
568
|
+
initialData?: FormData;
|
|
569
|
+
/** Required: Field component implementations for each field type */
|
|
570
|
+
fieldComponents: FieldComponentRegistry;
|
|
571
|
+
/** Optional: Custom field components referenced by name in config */
|
|
572
|
+
customComponents?: CustomComponentRegistry;
|
|
573
|
+
/** Optional: Custom container components for layout customization (Phase 2) */
|
|
574
|
+
customContainers?: CustomContainerRegistry;
|
|
575
|
+
/** Called on successful form submission with valid data */
|
|
576
|
+
onSubmit: OnSubmitHandler;
|
|
577
|
+
/** Called when any field value changes */
|
|
578
|
+
onChange?: OnChangeHandler;
|
|
579
|
+
/** Called when validation state changes */
|
|
580
|
+
onValidationChange?: OnValidationChangeHandler;
|
|
581
|
+
/** Called when form is reset */
|
|
582
|
+
onReset?: OnResetHandler;
|
|
583
|
+
/** Called on submission errors (validation failures) */
|
|
584
|
+
onError?: OnErrorHandler;
|
|
585
|
+
/**
|
|
586
|
+
* Validation mode for react-hook-form.
|
|
587
|
+
* - 'onChange': Validate on every change (default)
|
|
588
|
+
* - 'onBlur': Validate on blur
|
|
589
|
+
* - 'onSubmit': Only validate on submit
|
|
590
|
+
* - 'onTouched': Validate on blur, then on every change
|
|
591
|
+
* - 'all': Validate on blur and change
|
|
592
|
+
*/
|
|
593
|
+
mode?: "onChange" | "onBlur" | "onSubmit" | "onTouched" | "all";
|
|
594
|
+
/**
|
|
595
|
+
* Controls validation behavior for invisible fields.
|
|
596
|
+
* Only applies when using `schema` prop (not custom `resolver`).
|
|
597
|
+
* - 'skip': Do not validate invisible fields (default)
|
|
598
|
+
* - 'validate': Validate all fields regardless of visibility
|
|
599
|
+
* - 'warn': Validate but treat errors as warnings (non-blocking)
|
|
600
|
+
*/
|
|
601
|
+
invisibleFieldValidation?: InvisibleFieldValidation;
|
|
602
|
+
/** CSS class name for the form element */
|
|
603
|
+
className?: string;
|
|
604
|
+
/** Inline styles for the form element */
|
|
605
|
+
style?: CSSProperties;
|
|
606
|
+
/** HTML id attribute for the form element */
|
|
607
|
+
id?: string;
|
|
608
|
+
/** Content to render after all form fields (e.g., submit button) */
|
|
609
|
+
children?: React.ReactNode;
|
|
610
|
+
/**
|
|
611
|
+
* Optional wrapper function for each field.
|
|
612
|
+
* Receives field metadata and children, returns wrapped element.
|
|
613
|
+
* Use this for adding confidence indicators, status badges, edit tracking, etc.
|
|
614
|
+
*
|
|
615
|
+
* @example
|
|
616
|
+
* ```tsx
|
|
617
|
+
* <DynamicForm
|
|
618
|
+
* fieldWrapper={(props, children) => (
|
|
619
|
+
* <div className="field-wrapper">
|
|
620
|
+
* <Badge>{props.config.label}</Badge>
|
|
621
|
+
* {children}
|
|
622
|
+
* </div>
|
|
623
|
+
* )}
|
|
624
|
+
* />
|
|
625
|
+
* ```
|
|
626
|
+
*/
|
|
627
|
+
fieldWrapper?: FieldWrapperFunction;
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Ref interface for external form control.
|
|
631
|
+
* Access form methods from outside the component.
|
|
632
|
+
*
|
|
633
|
+
* @example
|
|
634
|
+
* ```tsx
|
|
635
|
+
* const formRef = useRef<DynamicFormRef>(null);
|
|
636
|
+
*
|
|
637
|
+
* // Reset city when country changes externally
|
|
638
|
+
* const handleCountryChange = (country: string) => {
|
|
639
|
+
* formRef.current?.setValue('country', country);
|
|
640
|
+
* formRef.current?.setValue('city', null);
|
|
641
|
+
* };
|
|
642
|
+
*
|
|
643
|
+
* <DynamicForm ref={formRef} ... />
|
|
644
|
+
* ```
|
|
645
|
+
*/
|
|
646
|
+
interface DynamicFormRef {
|
|
647
|
+
/** Get all form values */
|
|
648
|
+
getValues: () => FormData;
|
|
649
|
+
/** Set a specific field value */
|
|
650
|
+
setValue: (name: string, value: unknown) => void;
|
|
651
|
+
/** Watch all form values reactively */
|
|
652
|
+
watchAll: () => FormData;
|
|
653
|
+
/** Watch a specific field value reactively */
|
|
654
|
+
watchField: (name: string) => unknown;
|
|
655
|
+
/** Reset form to initial values or provided values */
|
|
656
|
+
reset: (values?: FormData) => void;
|
|
657
|
+
/** Trigger validation for a specific field or all fields */
|
|
658
|
+
trigger: (name?: string) => Promise<boolean>;
|
|
659
|
+
}
|
|
660
|
+
//#endregion
|
|
661
|
+
//#region src/context/DynamicFormContext.d.ts
|
|
662
|
+
/**
|
|
663
|
+
* Value provided by the DynamicFormContext.
|
|
664
|
+
* Contains everything needed by child components to render and interact with the form.
|
|
665
|
+
*/
|
|
666
|
+
interface DynamicFormContextValue {
|
|
667
|
+
/**
|
|
668
|
+
* react-hook-form methods.
|
|
669
|
+
* Provides access to form state, validation, and control.
|
|
670
|
+
*/
|
|
671
|
+
form: UseFormReturn<FormData>;
|
|
672
|
+
/**
|
|
673
|
+
* Parsed and validated form configuration.
|
|
674
|
+
*/
|
|
675
|
+
config: FormConfiguration;
|
|
676
|
+
/**
|
|
677
|
+
* Registered field components for each field type.
|
|
678
|
+
* These are provided by the consuming application.
|
|
679
|
+
*/
|
|
680
|
+
fieldComponents: FieldComponentRegistry;
|
|
681
|
+
/**
|
|
682
|
+
* Registered custom components.
|
|
683
|
+
* These are referenced by name in 'custom' type elements.
|
|
684
|
+
*/
|
|
685
|
+
customComponents: CustomComponentRegistry;
|
|
686
|
+
/**
|
|
687
|
+
* Registered custom container components (Phase 2).
|
|
688
|
+
* These can be used to customize container layout rendering.
|
|
689
|
+
*/
|
|
690
|
+
customContainers: CustomContainerRegistry;
|
|
691
|
+
/**
|
|
692
|
+
* Current visibility state for all fields (Phase 4).
|
|
693
|
+
* Maps field names to their visibility (true = visible).
|
|
694
|
+
* For Phase 1, all fields are always visible.
|
|
695
|
+
*/
|
|
696
|
+
visibility: Record<string, boolean>;
|
|
697
|
+
/**
|
|
698
|
+
* Optional wrapper function for each field.
|
|
699
|
+
* When provided, every field is wrapped with this function.
|
|
700
|
+
*/
|
|
701
|
+
fieldWrapper?: FieldWrapperFunction;
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* Context for sharing form state and configuration with child components.
|
|
705
|
+
*
|
|
706
|
+
* This context is set up by the DynamicForm component and consumed by
|
|
707
|
+
* field renderers and other internal components.
|
|
708
|
+
*/
|
|
709
|
+
declare const DynamicFormContext: react0.Context<DynamicFormContextValue | null>;
|
|
710
|
+
//#endregion
|
|
711
|
+
//#region src/DynamicForm.d.ts
|
|
712
|
+
interface DynamicFormPropsWithRef extends DynamicFormProps {
|
|
713
|
+
ref?: React$1.Ref<DynamicFormRef>;
|
|
714
|
+
}
|
|
715
|
+
declare const DynamicForm: {
|
|
716
|
+
({
|
|
717
|
+
config,
|
|
718
|
+
initialData,
|
|
719
|
+
fieldComponents,
|
|
720
|
+
customComponents,
|
|
721
|
+
customContainers,
|
|
722
|
+
onSubmit,
|
|
723
|
+
onChange,
|
|
724
|
+
onValidationChange,
|
|
725
|
+
onReset,
|
|
726
|
+
onError,
|
|
727
|
+
mode,
|
|
728
|
+
invisibleFieldValidation,
|
|
729
|
+
className,
|
|
730
|
+
style,
|
|
731
|
+
id,
|
|
732
|
+
children,
|
|
733
|
+
fieldWrapper,
|
|
734
|
+
ref
|
|
735
|
+
}: DynamicFormPropsWithRef): React$1.ReactElement;
|
|
736
|
+
displayName: string;
|
|
737
|
+
};
|
|
738
|
+
//#endregion
|
|
739
|
+
//#region src/hooks/useDynamicFormContext.d.ts
|
|
740
|
+
/**
|
|
741
|
+
* Hook to access the DynamicForm context.
|
|
742
|
+
*
|
|
743
|
+
* Must be used within a DynamicForm component.
|
|
744
|
+
* Throws an error if used outside of the form context.
|
|
745
|
+
*
|
|
746
|
+
* @returns The DynamicFormContext value
|
|
747
|
+
* @throws Error if used outside of DynamicForm
|
|
748
|
+
*
|
|
749
|
+
* @example
|
|
750
|
+
* ```tsx
|
|
751
|
+
* function MyCustomField({ config }) {
|
|
752
|
+
* const { form, fieldComponents } = useDynamicFormContext();
|
|
753
|
+
*
|
|
754
|
+
* const value = form.watch(config.name);
|
|
755
|
+
* // ... render field
|
|
756
|
+
* }
|
|
757
|
+
* ```
|
|
758
|
+
*/
|
|
759
|
+
declare const useDynamicFormContext: () => DynamicFormContextValue;
|
|
760
|
+
/**
|
|
761
|
+
* Hook to safely access the DynamicForm context.
|
|
762
|
+
* Returns null if used outside of the form context instead of throwing.
|
|
763
|
+
*
|
|
764
|
+
* @returns The DynamicFormContext value or null
|
|
765
|
+
*
|
|
766
|
+
* @example
|
|
767
|
+
* ```tsx
|
|
768
|
+
* function MaybeInForm() {
|
|
769
|
+
* const context = useDynamicFormContextSafe();
|
|
770
|
+
*
|
|
771
|
+
* if (!context) {
|
|
772
|
+
* return <span>Not in a form</span>;
|
|
773
|
+
* }
|
|
774
|
+
*
|
|
775
|
+
* return <span>In a form!</span>;
|
|
776
|
+
* }
|
|
777
|
+
* ```
|
|
778
|
+
*/
|
|
779
|
+
declare const useDynamicFormContextSafe: () => DynamicFormContextValue | null;
|
|
780
|
+
//#endregion
|
|
781
|
+
//#region src/parser/configParser.d.ts
|
|
782
|
+
/**
|
|
783
|
+
* Error thrown when configuration parsing fails.
|
|
784
|
+
*/
|
|
785
|
+
declare class ConfigurationError extends Error {
|
|
786
|
+
/** The original validation errors */
|
|
787
|
+
readonly errors: unknown[];
|
|
788
|
+
constructor(message: string, errors: unknown[]);
|
|
789
|
+
}
|
|
790
|
+
/**
|
|
791
|
+
* Result of parsing a configuration.
|
|
792
|
+
*/
|
|
793
|
+
interface ParseResult {
|
|
794
|
+
success: boolean;
|
|
795
|
+
config?: FormConfiguration;
|
|
796
|
+
errors?: string[];
|
|
797
|
+
}
|
|
798
|
+
/**
|
|
799
|
+
* Parses and validates a form configuration.
|
|
800
|
+
*
|
|
801
|
+
* @param config - Raw configuration object (typically from JSON)
|
|
802
|
+
* @returns Validated FormConfiguration
|
|
803
|
+
* @throws ConfigurationError if validation fails
|
|
804
|
+
*
|
|
805
|
+
* @example
|
|
806
|
+
* ```typescript
|
|
807
|
+
* try {
|
|
808
|
+
* const config = parseConfiguration({
|
|
809
|
+
* elements: [
|
|
810
|
+
* { type: 'text', name: 'name', label: 'Name' }
|
|
811
|
+
* ]
|
|
812
|
+
* });
|
|
813
|
+
* // config is now typed as FormConfiguration
|
|
814
|
+
* } catch (error) {
|
|
815
|
+
* if (error instanceof ConfigurationError) {
|
|
816
|
+
* console.error('Invalid configuration:', error.errors);
|
|
817
|
+
* }
|
|
818
|
+
* }
|
|
819
|
+
* ```
|
|
820
|
+
*/
|
|
821
|
+
declare const parseConfiguration: (config: unknown) => FormConfiguration;
|
|
822
|
+
/**
|
|
823
|
+
* Safely parses and validates a form configuration without throwing.
|
|
824
|
+
*
|
|
825
|
+
* @param config - Raw configuration object
|
|
826
|
+
* @returns ParseResult with success status and config or errors
|
|
827
|
+
*
|
|
828
|
+
* @example
|
|
829
|
+
* ```typescript
|
|
830
|
+
* const result = safeParseConfiguration(rawConfig);
|
|
831
|
+
* if (result.success) {
|
|
832
|
+
* // result.config is available
|
|
833
|
+
* renderForm(result.config);
|
|
834
|
+
* } else {
|
|
835
|
+
* // result.errors contains validation messages
|
|
836
|
+
* showErrors(result.errors);
|
|
837
|
+
* }
|
|
838
|
+
* ```
|
|
839
|
+
*/
|
|
840
|
+
declare const safeParseConfiguration: (config: unknown) => ParseResult;
|
|
841
|
+
//#endregion
|
|
842
|
+
//#region src/resolver/visibilityAwareResolver.d.ts
|
|
843
|
+
/**
|
|
844
|
+
* Options for creating a visibility-aware resolver.
|
|
845
|
+
*/
|
|
846
|
+
interface VisibilityAwareResolverOptions<T extends ZodRawShape> {
|
|
847
|
+
/** Zod schema for validation */
|
|
848
|
+
schema: ZodObject<T>;
|
|
849
|
+
/** Function that returns current visibility state for all fields */
|
|
850
|
+
getVisibility: () => Record<string, boolean>;
|
|
851
|
+
/** How to handle validation for invisible fields */
|
|
852
|
+
invisibleFieldValidation: InvisibleFieldValidation;
|
|
853
|
+
}
|
|
854
|
+
/**
|
|
855
|
+
* Creates a resolver that respects field visibility.
|
|
856
|
+
*
|
|
857
|
+
* This resolver wraps the standard zodResolver and filters validation
|
|
858
|
+
* errors based on field visibility. This is useful when fields are
|
|
859
|
+
* conditionally shown/hidden and you want to skip validation for
|
|
860
|
+
* hidden fields.
|
|
861
|
+
*
|
|
862
|
+
* @param options - Configuration for the resolver
|
|
863
|
+
* @returns A react-hook-form resolver
|
|
864
|
+
*
|
|
865
|
+
* @example
|
|
866
|
+
* ```typescript
|
|
867
|
+
* const resolver = createVisibilityAwareResolver({
|
|
868
|
+
* schema: myZodSchema,
|
|
869
|
+
* getVisibility: () => ({ name: true, phone: false }),
|
|
870
|
+
* invisibleFieldValidation: "skip",
|
|
871
|
+
* });
|
|
872
|
+
*
|
|
873
|
+
* const form = useForm({ resolver });
|
|
874
|
+
* ```
|
|
875
|
+
*/
|
|
876
|
+
declare const createVisibilityAwareResolver: <T extends ZodRawShape>(options: VisibilityAwareResolverOptions<T>) => Resolver<FieldValues>;
|
|
877
|
+
//#endregion
|
|
878
|
+
//#region src/schema/fieldSchemas.d.ts
|
|
879
|
+
/**
|
|
880
|
+
* Build a complete Zod schema for a single field.
|
|
881
|
+
*
|
|
882
|
+
* @param field - Field element configuration
|
|
883
|
+
* @returns Zod schema for the field
|
|
884
|
+
*
|
|
885
|
+
* @example
|
|
886
|
+
* ```typescript
|
|
887
|
+
* const textField = {
|
|
888
|
+
* type: 'text',
|
|
889
|
+
* name: 'name',
|
|
890
|
+
* validation: { required: true, minLength: 3 }
|
|
891
|
+
* };
|
|
892
|
+
*
|
|
893
|
+
* const schema = buildFieldSchema(textField);
|
|
894
|
+
* // schema is z.string().min(1, 'required').min(3, '...')
|
|
895
|
+
* ```
|
|
896
|
+
*/
|
|
897
|
+
declare const buildFieldSchema: (field: FieldElement) => ZodTypeAny;
|
|
898
|
+
//#endregion
|
|
899
|
+
//#region src/schema/generateSchema.d.ts
|
|
900
|
+
/**
|
|
901
|
+
* Generated schema type - a Zod object schema.
|
|
902
|
+
*/
|
|
903
|
+
type GeneratedSchema = ZodObject<Record<string, ZodTypeAny>>;
|
|
904
|
+
/**
|
|
905
|
+
* Generate a Zod schema from form configuration.
|
|
906
|
+
* Supports nested field paths via dot notation.
|
|
907
|
+
*
|
|
908
|
+
* This function is called once when the form initializes and the schema
|
|
909
|
+
* is memoized. Visibility changes are handled at validation time, not
|
|
910
|
+
* by regenerating the schema.
|
|
911
|
+
*
|
|
912
|
+
* @param config - Form configuration object
|
|
913
|
+
* @returns Zod object schema for validating form data
|
|
914
|
+
*
|
|
915
|
+
* @example
|
|
916
|
+
* ```typescript
|
|
917
|
+
* const config = {
|
|
918
|
+
* elements: [
|
|
919
|
+
* { type: 'text', name: 'source.name', validation: { required: true } },
|
|
920
|
+
* { type: 'email', name: 'source.email' },
|
|
921
|
+
* { type: 'boolean', name: 'active' }
|
|
922
|
+
* ]
|
|
923
|
+
* };
|
|
924
|
+
*
|
|
925
|
+
* const schema = generateZodSchema(config);
|
|
926
|
+
*
|
|
927
|
+
* // The generated schema is equivalent to:
|
|
928
|
+
* // z.object({
|
|
929
|
+
* // source: z.object({
|
|
930
|
+
* // name: z.string().min(1, 'required'),
|
|
931
|
+
* // email: z.string().email()
|
|
932
|
+
* // }),
|
|
933
|
+
* // active: z.boolean()
|
|
934
|
+
* // })
|
|
935
|
+
*
|
|
936
|
+
* schema.parse({
|
|
937
|
+
* source: { name: 'John', email: 'john@example.com' },
|
|
938
|
+
* active: true
|
|
939
|
+
* }); // Valid
|
|
940
|
+
* ```
|
|
941
|
+
*/
|
|
942
|
+
declare const generateZodSchema: (config: FormConfiguration) => GeneratedSchema;
|
|
943
|
+
/**
|
|
944
|
+
* Infer the TypeScript type from a generated schema.
|
|
945
|
+
* Useful for typing form data in the consuming application.
|
|
946
|
+
*
|
|
947
|
+
* @example
|
|
948
|
+
* ```typescript
|
|
949
|
+
* const schema = generateZodSchema(config);
|
|
950
|
+
* type FormData = InferSchemaType<typeof schema>;
|
|
951
|
+
*
|
|
952
|
+
* const onSubmit = (data: FormData) => {
|
|
953
|
+
* // data is fully typed based on configuration
|
|
954
|
+
* };
|
|
955
|
+
* ```
|
|
956
|
+
*/
|
|
957
|
+
type InferSchemaType<T extends GeneratedSchema> = z.infer<T>;
|
|
958
|
+
/**
|
|
959
|
+
* Extract field paths from a generated schema.
|
|
960
|
+
* Returns all top-level and nested paths.
|
|
961
|
+
*
|
|
962
|
+
* @param schema - Generated Zod schema
|
|
963
|
+
* @param prefix - Current path prefix (used in recursion)
|
|
964
|
+
* @returns Array of all field paths
|
|
965
|
+
*/
|
|
966
|
+
declare const getSchemaFieldPaths: (schema: ZodObject<Record<string, ZodTypeAny>>, prefix?: string) => string[];
|
|
967
|
+
//#endregion
|
|
968
|
+
//#region src/utils/calculateVisibility.d.ts
|
|
969
|
+
/**
|
|
970
|
+
* Visibility state for all fields in the form.
|
|
971
|
+
* Maps field names to their visibility (true = visible).
|
|
972
|
+
*/
|
|
973
|
+
type VisibilityState = Record<string, boolean>;
|
|
974
|
+
/**
|
|
975
|
+
* Calculate visibility state for all fields based on their visibility rules.
|
|
976
|
+
* Evaluates JSON Logic rules against current form data.
|
|
977
|
+
*
|
|
978
|
+
* @param elements - Array of form elements
|
|
979
|
+
* @param formData - Current form values
|
|
980
|
+
* @returns Visibility state for all fields
|
|
981
|
+
*
|
|
982
|
+
* @example
|
|
983
|
+
* ```typescript
|
|
984
|
+
* const elements = [
|
|
985
|
+
* { type: 'text', name: 'reason', visible: { "==": [{ "var": "type" }, "other"] } },
|
|
986
|
+
* { type: 'text', name: 'name' }
|
|
987
|
+
* ];
|
|
988
|
+
*
|
|
989
|
+
* const visibility = calculateVisibility(elements, { type: 'other' });
|
|
990
|
+
* // Returns: { reason: true, name: true }
|
|
991
|
+
*
|
|
992
|
+
* const visibility2 = calculateVisibility(elements, { type: 'standard' });
|
|
993
|
+
* // Returns: { reason: false, name: true }
|
|
994
|
+
* ```
|
|
995
|
+
*/
|
|
996
|
+
declare const calculateVisibility: (elements: FormElement[], formData: Record<string, unknown>) => VisibilityState;
|
|
997
|
+
//#endregion
|
|
998
|
+
//#region src/utils/flattenFields.d.ts
|
|
999
|
+
/**
|
|
1000
|
+
* Recursively extracts all field elements from a form configuration.
|
|
1001
|
+
* Traverses containers and columns to find nested fields.
|
|
1002
|
+
*
|
|
1003
|
+
* @param elements - Array of form elements (may include containers/columns)
|
|
1004
|
+
* @returns Flat array of all field elements
|
|
1005
|
+
*
|
|
1006
|
+
* @example
|
|
1007
|
+
* ```typescript
|
|
1008
|
+
* const config = {
|
|
1009
|
+
* elements: [
|
|
1010
|
+
* { type: 'text', name: 'name' },
|
|
1011
|
+
* {
|
|
1012
|
+
* type: 'container',
|
|
1013
|
+
* columns: [{
|
|
1014
|
+
* type: 'column',
|
|
1015
|
+
* width: '50%',
|
|
1016
|
+
* elements: [{ type: 'email', name: 'email' }]
|
|
1017
|
+
* }]
|
|
1018
|
+
* }
|
|
1019
|
+
* ]
|
|
1020
|
+
* };
|
|
1021
|
+
*
|
|
1022
|
+
* const fields = flattenFields(config.elements);
|
|
1023
|
+
* // Returns: [{ type: 'text', name: 'name' }, { type: 'email', name: 'email' }]
|
|
1024
|
+
* ```
|
|
1025
|
+
*/
|
|
1026
|
+
declare const flattenFields: (elements: FormElement[]) => FieldElement[];
|
|
1027
|
+
/**
|
|
1028
|
+
* Gets all field names from a form configuration.
|
|
1029
|
+
* Useful for initializing form state or visibility tracking.
|
|
1030
|
+
*
|
|
1031
|
+
* @param elements - Array of form elements
|
|
1032
|
+
* @returns Array of field names (including nested paths like 'source.name')
|
|
1033
|
+
*/
|
|
1034
|
+
declare const getFieldNames: (elements: FormElement[]) => string[];
|
|
1035
|
+
//#endregion
|
|
1036
|
+
//#region src/utils/mergeDefaults.d.ts
|
|
1037
|
+
/**
|
|
1038
|
+
* Sets a value in a nested object using dot notation path.
|
|
1039
|
+
*
|
|
1040
|
+
* @param obj - Object to modify
|
|
1041
|
+
* @param path - Dot-notation path (e.g., 'source.name')
|
|
1042
|
+
* @param value - Value to set
|
|
1043
|
+
*
|
|
1044
|
+
* @example
|
|
1045
|
+
* ```typescript
|
|
1046
|
+
* const obj = {};
|
|
1047
|
+
* setNestedValue(obj, 'source.name', 'John');
|
|
1048
|
+
* // obj is now { source: { name: 'John' } }
|
|
1049
|
+
* ```
|
|
1050
|
+
*/
|
|
1051
|
+
declare const setNestedValue: (obj: Record<string, unknown>, path: string, value: unknown) => void;
|
|
1052
|
+
/**
|
|
1053
|
+
* Gets a value from a nested object using dot notation path.
|
|
1054
|
+
*
|
|
1055
|
+
* @param obj - Object to read from
|
|
1056
|
+
* @param path - Dot-notation path (e.g., 'source.name')
|
|
1057
|
+
* @returns The value at the path, or undefined if not found
|
|
1058
|
+
*
|
|
1059
|
+
* @example
|
|
1060
|
+
* ```typescript
|
|
1061
|
+
* const obj = { source: { name: 'John' } };
|
|
1062
|
+
* getNestedValue(obj, 'source.name'); // 'John'
|
|
1063
|
+
* getNestedValue(obj, 'source.email'); // undefined
|
|
1064
|
+
* ```
|
|
1065
|
+
*/
|
|
1066
|
+
declare const getNestedValue: (obj: Record<string, unknown>, path: string) => unknown;
|
|
1067
|
+
/**
|
|
1068
|
+
* Merges configuration default values with initial data.
|
|
1069
|
+
* Priority: initialData > config.defaultValue > type default
|
|
1070
|
+
*
|
|
1071
|
+
* @param config - Form configuration containing field definitions
|
|
1072
|
+
* @param initialData - Initial data provided by the user
|
|
1073
|
+
* @returns Merged default values for react-hook-form
|
|
1074
|
+
*
|
|
1075
|
+
* @example
|
|
1076
|
+
* ```typescript
|
|
1077
|
+
* const config = {
|
|
1078
|
+
* elements: [
|
|
1079
|
+
* { type: 'text', name: 'source.name', defaultValue: 'Default Name' },
|
|
1080
|
+
* { type: 'boolean', name: 'source.active' }
|
|
1081
|
+
* ]
|
|
1082
|
+
* };
|
|
1083
|
+
*
|
|
1084
|
+
* const initialData = { source: { name: 'Provided Name' } };
|
|
1085
|
+
* const defaults = mergeDefaults(config, initialData);
|
|
1086
|
+
* // Result: { source: { name: 'Provided Name', active: false } }
|
|
1087
|
+
* ```
|
|
1088
|
+
*/
|
|
1089
|
+
declare const mergeDefaults: (config: FormConfiguration, initialData?: FormData) => FormData;
|
|
1090
|
+
//#endregion
|
|
1091
|
+
//#region src/validation/jsonLogic.d.ts
|
|
1092
|
+
/**
|
|
1093
|
+
* Evaluate a JSON Logic rule against form data.
|
|
1094
|
+
*
|
|
1095
|
+
* @param rule - JSON Logic rule to evaluate
|
|
1096
|
+
* @param data - Form data to evaluate against
|
|
1097
|
+
* @returns Result of the evaluation
|
|
1098
|
+
*
|
|
1099
|
+
* @example
|
|
1100
|
+
* ```typescript
|
|
1101
|
+
* const rule = { "==": [{ var: "status" }, "active"] };
|
|
1102
|
+
* const data = { status: "active" };
|
|
1103
|
+
* applyJsonLogic(rule, data); // true
|
|
1104
|
+
* ```
|
|
1105
|
+
*/
|
|
1106
|
+
declare const applyJsonLogic: (rule: JsonLogicRule, data: Record<string, unknown>) => unknown;
|
|
1107
|
+
/**
|
|
1108
|
+
* Evaluate a JSON Logic rule and return boolean result.
|
|
1109
|
+
* Returns true if rule evaluates to a truthy value.
|
|
1110
|
+
*
|
|
1111
|
+
* @param rule - JSON Logic condition
|
|
1112
|
+
* @param data - Form data
|
|
1113
|
+
* @returns true if condition passes, false otherwise
|
|
1114
|
+
*
|
|
1115
|
+
* @example
|
|
1116
|
+
* ```typescript
|
|
1117
|
+
* const rule = { "and": [{ var: "active" }, { var: "confirmed" }] };
|
|
1118
|
+
* evaluateCondition(rule, { active: true, confirmed: true }); // true
|
|
1119
|
+
* evaluateCondition(rule, { active: true, confirmed: false }); // false
|
|
1120
|
+
* ```
|
|
1121
|
+
*/
|
|
1122
|
+
declare const evaluateCondition: (rule: JsonLogicRule, data: Record<string, unknown>) => boolean;
|
|
1123
|
+
//#endregion
|
|
1124
|
+
export { type ApiOptionsSource, type ArrayFieldComponent, type ArrayFieldElement, type ArrayFieldProps, type BaseFieldProps, type BooleanFieldComponent, type BooleanFieldElement, type BooleanFieldProps, type ColumnComponent, type ColumnElement, type ColumnProps, ConfigurationError, type ContainerComponent, type ContainerElement, type ContainerProps, type CustomComponentDefinition, type CustomComponentRegistry, type CustomComponentRenderProps, type CustomContainerRegistry, type CustomFieldComponent, type CustomFieldElement, type CustomFieldProps, type DateFieldComponent, type DateFieldElement, type DateFieldProps, DynamicForm, DynamicForm as default, DynamicFormContext, type DynamicFormContextValue, type DynamicFormProps, type DynamicFormRef, type ElementType, type EmailFieldComponent, type EmailFieldElement, type EmailFieldProps, type FieldComponentRegistry, type FieldElement, type FieldProps, type FieldType, type FieldWrapperFunction, type FieldWrapperProps, type FormConfiguration, type FormData, type FormElement, type GeneratedSchema, type InferSchemaType, type InvisibleFieldValidation, type JsonLogicRule, type LayoutElement, type MapOptionsSource, type OnChangeHandler, type OnErrorHandler, type OnResetHandler, type OnSubmitHandler, type OnValidationChangeHandler, type OptionsSource, type ParseResult, type PhoneFieldComponent, type PhoneFieldElement, type PhoneFieldProps, type ResolverOptionsSource, type SearchOptionsSource, type SelectFieldComponent, type SelectFieldElement, type SelectFieldProps, type SelectOption, type StaticOptionsSource, type TextFieldComponent, type TextFieldElement, type TextFieldProps, type ValidationConfig, type VisibilityAwareResolverOptions, type VisibilityState, applyJsonLogic, buildFieldSchema, calculateVisibility, createVisibilityAwareResolver, defineCustomComponent, evaluateCondition, flattenFields, generateZodSchema, getFieldNames, getNestedValue, getSchemaFieldPaths, isArrayFieldElement, isColumnElement, isContainerElement, isCustomFieldElement, isFieldElement, mergeDefaults, parseConfiguration, safeParseConfiguration, setNestedValue, useDynamicFormContext, useDynamicFormContextSafe };
|