@rilaykit/forms 0.1.1-alpha.1 → 0.1.2
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/LICENSE +21 -0
- package/README.md +239 -0
- package/dist/index.d.mts +982 -152
- package/dist/index.d.ts +982 -152
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +29 -12
package/dist/index.d.ts
CHANGED
|
@@ -1,210 +1,1040 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { FormConfiguration, ValidationError,
|
|
3
|
-
export * from '@rilaykit/core';
|
|
4
|
-
export { createZodValidator, ril } from '@rilaykit/core';
|
|
2
|
+
import { ril, FieldValidationConfig, RepeatableFieldConfig, ConditionalBehavior, FormFieldConfig, FormRowEntry, FormValidationConfig, FormConfiguration, ComponentRendererBaseProps, FormBodyRendererProps, FieldConditions, FormState, ValidationError, ValidationState, FieldState, ValidationResult, RepeatableFieldItem, MonitoringConfig, FormPerformanceMetrics, FormRowRendererProps, FormFieldRow, FormSubmitButtonRendererProps } from '@rilaykit/core';
|
|
5
3
|
import * as React$1 from 'react';
|
|
6
4
|
import React__default from 'react';
|
|
5
|
+
import * as zustand from 'zustand';
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
declare function FormProvider({ children, formConfig, defaultValues, onSubmit, onFieldChange, className, }: FormProviderProps): react_jsx_runtime.JSX.Element;
|
|
65
|
-
declare function useFormContext(): FormContextValue;
|
|
66
|
-
|
|
67
|
-
interface FormRowProps {
|
|
68
|
-
row: FormFieldRow;
|
|
69
|
-
className?: string;
|
|
70
|
-
}
|
|
71
|
-
declare function FormRow({ row, className }: FormRowProps): React$1.ReactElement<any, string | React$1.JSXElementConstructor<any>>;
|
|
72
|
-
|
|
73
|
-
interface FormSubmitButtonProps {
|
|
74
|
-
className?: string;
|
|
75
|
-
children?: React__default.ReactNode;
|
|
7
|
+
/**
|
|
8
|
+
* Fluent builder for configuring repeatable field groups
|
|
9
|
+
*
|
|
10
|
+
* Used via callback in `form.addRepeatable()`:
|
|
11
|
+
* ```typescript
|
|
12
|
+
* form.create(ril, "order")
|
|
13
|
+
* .addRepeatable("items", r => r
|
|
14
|
+
* .add(
|
|
15
|
+
* { id: "name", type: "text", props: { label: "Item" } },
|
|
16
|
+
* { id: "qty", type: "number", props: { label: "Qty" } }
|
|
17
|
+
* )
|
|
18
|
+
* .min(1)
|
|
19
|
+
* .max(10)
|
|
20
|
+
* .defaultValue({ name: "", qty: 1 })
|
|
21
|
+
* )
|
|
22
|
+
* .build()
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
declare class RepeatableBuilder<C extends Record<string, any>> {
|
|
26
|
+
private innerForm;
|
|
27
|
+
private _min?;
|
|
28
|
+
private _max?;
|
|
29
|
+
private _defaultValue?;
|
|
30
|
+
private _validation?;
|
|
31
|
+
constructor(config: ril<C>);
|
|
32
|
+
/**
|
|
33
|
+
* Add fields to the repeatable template
|
|
34
|
+
* Same API as form.add() — variadic ≤3 puts them on the same row
|
|
35
|
+
*/
|
|
36
|
+
add<T extends keyof C & string>(...fields: FieldConfig<C, T>[]): this;
|
|
37
|
+
add<T extends keyof C & string>(fields: FieldConfig<C, T>[]): this;
|
|
38
|
+
/**
|
|
39
|
+
* Add fields each on their own row
|
|
40
|
+
*/
|
|
41
|
+
addSeparateRows<T extends keyof C & string>(fields: FieldConfig<C, T>[]): this;
|
|
42
|
+
/**
|
|
43
|
+
* Set minimum number of items (defaults to 0)
|
|
44
|
+
*/
|
|
45
|
+
min(value: number): this;
|
|
46
|
+
/**
|
|
47
|
+
* Set maximum number of items (unlimited if not set)
|
|
48
|
+
*/
|
|
49
|
+
max(value: number): this;
|
|
50
|
+
/**
|
|
51
|
+
* Set default values for new items
|
|
52
|
+
*/
|
|
53
|
+
defaultValue(value: Record<string, unknown>): this;
|
|
54
|
+
/**
|
|
55
|
+
* Set group-level validation (applied to the entire array)
|
|
56
|
+
*/
|
|
57
|
+
validation(config: FieldValidationConfig): this;
|
|
58
|
+
/** @internal — called by form.addRepeatable */
|
|
59
|
+
_build(id: string): RepeatableFieldConfig;
|
|
60
|
+
/** @internal — check if the inner builder has repeatables (nesting forbidden) */
|
|
61
|
+
_hasRepeatables(): boolean;
|
|
76
62
|
}
|
|
77
|
-
declare function FormSubmitButton({ className, children }: FormSubmitButtonProps): React__default.ReactElement<any, string | React__default.JSXElementConstructor<any>>;
|
|
78
63
|
|
|
79
64
|
/**
|
|
80
|
-
*
|
|
81
|
-
*
|
|
65
|
+
* Configuration for a form field with type safety
|
|
66
|
+
*
|
|
67
|
+
* @template C - The component configuration map
|
|
68
|
+
* @template T - The specific component type key
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* const fieldConfig: FieldConfig<MyComponents, 'text'> = {
|
|
73
|
+
* type: 'text',
|
|
74
|
+
* props: { placeholder: 'Enter your name' },
|
|
75
|
+
* validation: {
|
|
76
|
+
* validators: [required(), minLength(2)],
|
|
77
|
+
* validateOnChange: true,
|
|
78
|
+
* validateOnBlur: true
|
|
79
|
+
* }
|
|
80
|
+
* };
|
|
81
|
+
* ```
|
|
82
82
|
*/
|
|
83
|
-
|
|
83
|
+
type FieldConfig<C extends Record<string, any>, T extends keyof C> = {
|
|
84
|
+
/** Unique identifier for the field. Auto-generated if not provided */
|
|
85
|
+
id?: string;
|
|
86
|
+
/** Component type from the registered components */
|
|
87
|
+
type: T;
|
|
88
|
+
/** Component-specific properties */
|
|
89
|
+
props?: Partial<C[T]>;
|
|
90
|
+
/** Validation configuration for this field */
|
|
91
|
+
validation?: FieldValidationConfig;
|
|
92
|
+
/** Conditional behavior configuration for this field */
|
|
93
|
+
conditions?: ConditionalBehavior;
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Form builder for creating type-safe form configurations
|
|
97
|
+
*
|
|
98
|
+
* DX Notes (How to create a form):
|
|
99
|
+
* - Recommended: use the static factory
|
|
100
|
+
*
|
|
101
|
+
* const rilConfig = ril
|
|
102
|
+
* .create()
|
|
103
|
+
* .addComponent('text', { name: 'Text', renderer: TextInput })
|
|
104
|
+
* .addComponent('email', { name: 'Email', renderer: EmailInput });
|
|
105
|
+
*
|
|
106
|
+
* const myForm = form
|
|
107
|
+
* .create(rilConfig, 'contact-form')
|
|
108
|
+
* .add({ id: 'firstName', type: 'text', props: { label: 'First name' } })
|
|
109
|
+
* .add(
|
|
110
|
+
* { id: 'email', type: 'email', props: { label: 'Email' } },
|
|
111
|
+
* { id: 'role', type: 'text', props: { label: 'Role' } }
|
|
112
|
+
* )
|
|
113
|
+
* .build();
|
|
114
|
+
*
|
|
115
|
+
* - Or instantiate directly:
|
|
116
|
+
*
|
|
117
|
+
* const myForm = new form(rilConfig, 'contact-form')
|
|
118
|
+
* .add({ id: 'firstName', type: 'text' })
|
|
119
|
+
* .build();
|
|
120
|
+
*
|
|
121
|
+
* Why we do not augment ril with .form():
|
|
122
|
+
* - Keep the API explicit and bundler-friendly (no prototype/module augmentation)
|
|
123
|
+
* - Better discoverability and IntelliSense via the builder class
|
|
124
|
+
*
|
|
125
|
+
* Typing & autocomplete:
|
|
126
|
+
* - Types flow from your ril configuration: once components are registered,
|
|
127
|
+
* the `type` and `props` of `.add({ ... })` are fully typed.
|
|
128
|
+
*
|
|
129
|
+
* Adding fields:
|
|
130
|
+
* - Variadic: .add(fieldA, fieldB) => same row (max 3 per row)
|
|
131
|
+
* - Array: .add([fieldA, fieldB]) => explicit single row
|
|
132
|
+
* - >3 fields (variadic) => split across multiple rows automatically
|
|
133
|
+
*
|
|
134
|
+
* Output of .build(): FormConfiguration<C>
|
|
135
|
+
* - id, rows, allFields, renderConfig (from ril), optional validation
|
|
136
|
+
*/
|
|
137
|
+
declare class form<C extends Record<string, any> = Record<string, never>> {
|
|
138
|
+
/** The ril configuration instance containing component definitions */
|
|
84
139
|
private config;
|
|
140
|
+
/** Array of form rows containing field configurations */
|
|
85
141
|
private rows;
|
|
142
|
+
/** Unique identifier for this form */
|
|
86
143
|
private formId;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
* @param
|
|
95
|
-
* @param
|
|
96
|
-
*
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
144
|
+
/** Generator for creating unique IDs */
|
|
145
|
+
private idGenerator;
|
|
146
|
+
/** Form-level validation configuration */
|
|
147
|
+
private formValidation?;
|
|
148
|
+
/**
|
|
149
|
+
* Creates a new form builder instance
|
|
150
|
+
*
|
|
151
|
+
* @param config - The ril configuration containing component definitions
|
|
152
|
+
* @param formId - Optional unique identifier for the form. Auto-generated if not provided
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```typescript
|
|
156
|
+
* const builder = new form(rilConfig, 'my-form');
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
constructor(config: ril<C>, formId?: string);
|
|
160
|
+
/**
|
|
161
|
+
* Static factory to create a new form builder
|
|
162
|
+
*
|
|
163
|
+
* Usage (recommended):
|
|
164
|
+
*
|
|
165
|
+
* const myForm = form
|
|
166
|
+
* .create(rilConfig, 'my-form')
|
|
167
|
+
* .add({ id: 'email', type: 'email', props: { label: 'Email' } })
|
|
168
|
+
* .build();
|
|
169
|
+
*
|
|
170
|
+
* Why prefer this over `new form(...)`?
|
|
171
|
+
* - Clearer intent and better discoverability
|
|
172
|
+
* - Consistent with other builder APIs
|
|
173
|
+
*/
|
|
174
|
+
static create<Cm extends Record<string, any> = Record<string, never>>(config: ril<Cm>, formId?: string): form<Cm>;
|
|
175
|
+
/**
|
|
176
|
+
* Converts a FieldConfig to a FormFieldConfig
|
|
177
|
+
*
|
|
178
|
+
* This internal method handles the transformation from the builder's field
|
|
179
|
+
* configuration format to the final form field configuration, including
|
|
180
|
+
* component lookup, prop merging, ID generation, and validation setup.
|
|
181
|
+
*
|
|
182
|
+
* The validation system combines component-level validation (defined in the component config)
|
|
183
|
+
* with field-level validation (defined in the field config). Component validators are
|
|
184
|
+
* applied first, followed by field validators.
|
|
185
|
+
*
|
|
186
|
+
* @template T - The component type
|
|
187
|
+
* @param fieldConfig - The field configuration to convert
|
|
188
|
+
* @returns A complete FormFieldConfig ready for use
|
|
189
|
+
* @throws Error if the specified component type is not registered
|
|
190
|
+
*
|
|
191
|
+
* @internal
|
|
192
|
+
*/
|
|
193
|
+
private createFormField;
|
|
194
|
+
/**
|
|
195
|
+
* Creates a form row with the specified fields and options
|
|
196
|
+
*
|
|
197
|
+
* This internal method handles row creation,
|
|
198
|
+
* proper spacing, and alignment configuration.
|
|
199
|
+
*
|
|
200
|
+
* @template T - The component type
|
|
104
201
|
* @param fieldConfigs - Array of field configurations for the row
|
|
105
|
-
* @
|
|
106
|
-
* @
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
*
|
|
202
|
+
* @returns A complete FormFieldRow configuration
|
|
203
|
+
* @throws Error if no fields provided or more than 3 fields specified
|
|
204
|
+
*
|
|
205
|
+
* @internal
|
|
206
|
+
*/
|
|
207
|
+
private createRow;
|
|
208
|
+
/**
|
|
209
|
+
* Universal method for adding fields to the form
|
|
210
|
+
*
|
|
211
|
+
* This is the primary method for adding fields to your form. It supports multiple
|
|
212
|
+
* usage patterns for maximum flexibility:
|
|
213
|
+
*
|
|
214
|
+
* - Single field: Creates a new row with one field
|
|
215
|
+
* - Multiple fields (≤3): Creates one row with all fields
|
|
216
|
+
* - Multiple fields (>3): Creates separate rows for each field
|
|
217
|
+
* - Array with options: Explicit control over row configuration
|
|
218
|
+
*
|
|
219
|
+
* @template T - The component type
|
|
220
|
+
* @param fields - Field configurations (variadic or array)
|
|
221
|
+
* @returns The form builder instance for method chaining
|
|
222
|
+
* @throws Error if no fields provided or invalid configuration
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* ```typescript
|
|
226
|
+
* // Single field on its own row
|
|
227
|
+
* builder.add({ type: 'text', props: { label: 'Name' } });
|
|
228
|
+
*
|
|
229
|
+
* // Multiple fields on same row (max 3)
|
|
230
|
+
* builder.add(
|
|
231
|
+
* { type: 'text', props: { label: 'First Name' } },
|
|
232
|
+
* { type: 'text', props: { label: 'Last Name' } }
|
|
233
|
+
* );
|
|
234
|
+
*
|
|
235
|
+
* // Array syntax with row options
|
|
236
|
+
* builder.add([
|
|
237
|
+
* { type: 'email', props: { label: 'Email' } },
|
|
238
|
+
* { type: 'phone', props: { label: 'Phone' } }
|
|
239
|
+
* ], { spacing: 'loose', alignment: 'center' });
|
|
240
|
+
* ```
|
|
241
|
+
*/
|
|
242
|
+
add<T extends keyof C & string>(...fields: FieldConfig<C, T>[]): this;
|
|
243
|
+
add<T extends keyof C & string>(fields: FieldConfig<C, T>[]): this;
|
|
244
|
+
/**
|
|
245
|
+
* Adds multiple fields on separate rows
|
|
246
|
+
*
|
|
247
|
+
* This method is useful when you want to ensure each field gets its own row,
|
|
248
|
+
* regardless of the number of fields. It's an alternative to the add() method
|
|
249
|
+
* when you need explicit control over row separation.
|
|
250
|
+
*
|
|
251
|
+
* @template T - The component type
|
|
120
252
|
* @param fieldConfigs - Array of field configurations
|
|
121
|
-
* @returns form instance for chaining
|
|
253
|
+
* @returns The form builder instance for method chaining
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* ```typescript
|
|
257
|
+
* // Each field will be on its own row
|
|
258
|
+
* builder.addSeparateRows([
|
|
259
|
+
* { type: 'text', props: { label: 'Field 1' } },
|
|
260
|
+
* { type: 'text', props: { label: 'Field 2' } },
|
|
261
|
+
* { type: 'text', props: { label: 'Field 3' } }
|
|
262
|
+
* ]);
|
|
263
|
+
* ```
|
|
122
264
|
*/
|
|
123
|
-
|
|
124
|
-
fieldId: string;
|
|
125
|
-
componentSubType: InputType | LayoutType;
|
|
126
|
-
props?: Record<string, any>;
|
|
127
|
-
validation?: ValidationConfig;
|
|
128
|
-
conditional?: ConditionalConfig;
|
|
129
|
-
}>): this;
|
|
265
|
+
addSeparateRows<T extends keyof C & string>(fieldConfigs: FieldConfig<C, T>[]): this;
|
|
130
266
|
/**
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
267
|
+
* Adds a repeatable field group to the form
|
|
268
|
+
*
|
|
269
|
+
* Repeatable fields allow users to add/remove instances of a group of fields
|
|
270
|
+
* at runtime (e.g., "Add another item", "Add another contact").
|
|
271
|
+
*
|
|
272
|
+
* @param id - Unique identifier for the repeatable group (cannot contain [ or ])
|
|
273
|
+
* @param configure - Callback receiving a RepeatableBuilder for fluent configuration
|
|
274
|
+
* @returns The form builder instance for method chaining
|
|
275
|
+
*
|
|
276
|
+
* @example
|
|
277
|
+
* ```typescript
|
|
278
|
+
* builder.addRepeatable("items", r => r
|
|
279
|
+
* .add(
|
|
280
|
+
* { id: "name", type: "text", props: { label: "Item" } },
|
|
281
|
+
* { id: "qty", type: "number", props: { label: "Qty" } }
|
|
282
|
+
* )
|
|
283
|
+
* .min(1)
|
|
284
|
+
* .max(10)
|
|
285
|
+
* .defaultValue({ name: "", qty: 1 })
|
|
286
|
+
* );
|
|
287
|
+
* ```
|
|
288
|
+
*/
|
|
289
|
+
addRepeatable(id: string, configure: (builder: RepeatableBuilder<C>) => RepeatableBuilder<C>): this;
|
|
290
|
+
/**
|
|
291
|
+
* Sets the form identifier
|
|
292
|
+
*
|
|
293
|
+
* @param id - The new form identifier
|
|
294
|
+
* @returns The form builder instance for method chaining
|
|
295
|
+
*
|
|
296
|
+
* @example
|
|
297
|
+
* ```typescript
|
|
298
|
+
* builder.setId('user-profile-form');
|
|
299
|
+
* ```
|
|
134
300
|
*/
|
|
135
301
|
setId(id: string): this;
|
|
136
302
|
/**
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
303
|
+
* Updates an existing field's configuration
|
|
304
|
+
*
|
|
305
|
+
* This method allows you to modify field properties after the field has been added to the form.
|
|
306
|
+
*
|
|
307
|
+
* @param fieldId - The unique identifier of the field to update
|
|
308
|
+
* @param updates - Partial field configuration with updates to apply
|
|
309
|
+
* @returns The form builder instance for method chaining
|
|
310
|
+
* @throws Error if the field with the specified ID is not found
|
|
311
|
+
*
|
|
312
|
+
* @example
|
|
313
|
+
* ```typescript
|
|
314
|
+
* builder.updateField('email-field', {
|
|
315
|
+
* props: { placeholder: 'Enter your email address' },
|
|
316
|
+
* });
|
|
317
|
+
* ```
|
|
141
318
|
*/
|
|
142
319
|
updateField(fieldId: string, updates: Partial<Omit<FormFieldConfig, 'id'>>): this;
|
|
143
320
|
/**
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
321
|
+
* Finds a field by its unique identifier
|
|
322
|
+
*
|
|
323
|
+
* This internal method searches through all rows to locate a field
|
|
324
|
+
* with the specified ID.
|
|
325
|
+
*
|
|
326
|
+
* @param fieldId - The field identifier to search for
|
|
327
|
+
* @returns The field configuration if found, null otherwise
|
|
328
|
+
*
|
|
329
|
+
* @internal
|
|
330
|
+
*/
|
|
331
|
+
private findField;
|
|
332
|
+
/**
|
|
333
|
+
* Removes a field from the form
|
|
334
|
+
*
|
|
335
|
+
* This method removes the specified field and cleans up any empty rows
|
|
336
|
+
* that result from the removal. The form structure is automatically
|
|
337
|
+
* reorganized to maintain consistency.
|
|
338
|
+
*
|
|
339
|
+
* @param fieldId - The unique identifier of the field to remove
|
|
340
|
+
* @returns The form builder instance for method chaining
|
|
341
|
+
*
|
|
342
|
+
* @example
|
|
343
|
+
* ```typescript
|
|
344
|
+
* builder.removeField('unwanted-field-id');
|
|
345
|
+
* ```
|
|
147
346
|
*/
|
|
148
347
|
removeField(fieldId: string): this;
|
|
149
348
|
/**
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
* @
|
|
349
|
+
* Retrieves a field configuration by its ID
|
|
350
|
+
*
|
|
351
|
+
* @param fieldId - The unique identifier of the field
|
|
352
|
+
* @returns The field configuration if found, undefined otherwise
|
|
353
|
+
*
|
|
354
|
+
* @example
|
|
355
|
+
* ```typescript
|
|
356
|
+
* const emailField = builder.getField('email-field');
|
|
357
|
+
* if (emailField) {
|
|
358
|
+
* console.log('Email field props:', emailField.props);
|
|
359
|
+
* }
|
|
360
|
+
* ```
|
|
153
361
|
*/
|
|
154
362
|
getField(fieldId: string): FormFieldConfig | undefined;
|
|
155
363
|
/**
|
|
156
|
-
*
|
|
157
|
-
*
|
|
364
|
+
* Gets all fields as a flat array
|
|
365
|
+
*
|
|
366
|
+
* This method flattens the row structure to provide a simple array
|
|
367
|
+
* of all field configurations in the form, maintaining their order.
|
|
368
|
+
*
|
|
369
|
+
* @returns Array of all field configurations in the form
|
|
370
|
+
*
|
|
371
|
+
* @example
|
|
372
|
+
* ```typescript
|
|
373
|
+
* const allFields = builder.getFields();
|
|
374
|
+
* console.log(`Form has ${allFields.length} fields`);
|
|
375
|
+
* ```
|
|
158
376
|
*/
|
|
159
377
|
getFields(): FormFieldConfig[];
|
|
160
378
|
/**
|
|
161
|
-
*
|
|
162
|
-
*
|
|
379
|
+
* Gets all rows in the form
|
|
380
|
+
*
|
|
381
|
+
* Returns a copy of the internal rows array to prevent external
|
|
382
|
+
* modification while allowing inspection of the form structure.
|
|
383
|
+
*
|
|
384
|
+
* @returns Array of all form rows
|
|
385
|
+
*
|
|
386
|
+
* @example
|
|
387
|
+
* ```typescript
|
|
388
|
+
* const rows = builder.getRows();
|
|
389
|
+
* console.log(`Form has ${rows.length} rows`);
|
|
390
|
+
* ```
|
|
163
391
|
*/
|
|
164
|
-
getRows():
|
|
392
|
+
getRows(): FormRowEntry[];
|
|
165
393
|
/**
|
|
166
|
-
*
|
|
167
|
-
*
|
|
394
|
+
* Clears all fields and rows from the form
|
|
395
|
+
*
|
|
396
|
+
* This method resets the form to an empty state and resets the ID generator
|
|
397
|
+
* to ensure clean ID generation for subsequent fields.
|
|
398
|
+
*
|
|
399
|
+
* @returns The form builder instance for method chaining
|
|
400
|
+
*
|
|
401
|
+
* @example
|
|
402
|
+
* ```typescript
|
|
403
|
+
* builder.clear().add({ type: 'text', props: { label: 'New start' } });
|
|
404
|
+
* ```
|
|
168
405
|
*/
|
|
169
406
|
clear(): this;
|
|
170
407
|
/**
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
408
|
+
* Configures validation for the entire form
|
|
409
|
+
*
|
|
410
|
+
* This method sets up form-level validation that will be applied when the
|
|
411
|
+
* form is submitted or when validation is explicitly triggered. Form validators
|
|
412
|
+
* receive all form data and can perform cross-field validation.
|
|
413
|
+
*
|
|
414
|
+
* @param validationConfig - Form validation configuration
|
|
415
|
+
* @returns The form builder instance for method chaining
|
|
416
|
+
*
|
|
417
|
+
* @example
|
|
418
|
+
* ```typescript
|
|
419
|
+
* builder.setValidation({
|
|
420
|
+
* validators: [
|
|
421
|
+
* (formData, context) => {
|
|
422
|
+
* if (!formData.email && !formData.phone) {
|
|
423
|
+
* return createErrorResult('Either email or phone is required');
|
|
424
|
+
* }
|
|
425
|
+
* return createSuccessResult();
|
|
426
|
+
* }
|
|
427
|
+
* ],
|
|
428
|
+
* validateOnSubmit: true
|
|
429
|
+
* });
|
|
430
|
+
* ```
|
|
431
|
+
*/
|
|
432
|
+
setValidation(validationConfig: FormValidationConfig): this;
|
|
433
|
+
/**
|
|
434
|
+
* Adds validators to the form-level validation
|
|
435
|
+
*
|
|
436
|
+
* This method allows adding validators to an existing validation configuration
|
|
437
|
+
* without replacing the entire configuration.
|
|
438
|
+
*
|
|
439
|
+
* @param validators - Array of form validators to add
|
|
440
|
+
* @returns The form builder instance for method chaining
|
|
441
|
+
*
|
|
442
|
+
* @example
|
|
443
|
+
* ```typescript
|
|
444
|
+
* builder.addValidators([
|
|
445
|
+
* customFormValidator,
|
|
446
|
+
* anotherFormValidator
|
|
447
|
+
* ]);
|
|
448
|
+
* ```
|
|
449
|
+
*/
|
|
450
|
+
/**
|
|
451
|
+
* Adds validation to a specific field by ID
|
|
452
|
+
*
|
|
453
|
+
* This method allows adding validation to a field after it has been created,
|
|
454
|
+
* useful for dynamic validation requirements.
|
|
455
|
+
*
|
|
456
|
+
* @param fieldId - The ID of the field to add validation to
|
|
457
|
+
* @param validationConfig - Field validation configuration
|
|
458
|
+
* @returns The form builder instance for method chaining
|
|
459
|
+
* @throws Error if the field with the specified ID is not found
|
|
460
|
+
*
|
|
461
|
+
* @example
|
|
462
|
+
* ```typescript
|
|
463
|
+
* builder.addFieldValidation('email', {
|
|
464
|
+
* validators: [required(), email()],
|
|
465
|
+
* validateOnBlur: true
|
|
466
|
+
* });
|
|
467
|
+
* ```
|
|
468
|
+
*/
|
|
469
|
+
/** @deprecated Use updateField with new validation.validate property instead */
|
|
470
|
+
addFieldValidation(fieldId: string, validationConfig: any): this;
|
|
471
|
+
/**
|
|
472
|
+
* Adds conditions to a specific field by ID
|
|
473
|
+
*
|
|
474
|
+
* This method allows adding conditional behavior to a field after it has been created,
|
|
475
|
+
* useful for dynamic conditional requirements.
|
|
476
|
+
*
|
|
477
|
+
* @param fieldId - The ID of the field to add conditions to
|
|
478
|
+
* @param conditions - Conditional behavior configuration
|
|
479
|
+
* @returns The form builder instance for method chaining
|
|
480
|
+
* @throws Error if the field with the specified ID is not found
|
|
481
|
+
*
|
|
482
|
+
* @example
|
|
483
|
+
* ```typescript
|
|
484
|
+
* builder.addFieldConditions('phone', {
|
|
485
|
+
* visible: when('contactMethod').equals('phone').build(),
|
|
486
|
+
* required: when('contactMethod').equals('phone').build()
|
|
487
|
+
* });
|
|
488
|
+
* ```
|
|
489
|
+
*/
|
|
490
|
+
addFieldConditions(fieldId: string, conditions: ConditionalBehavior): this;
|
|
491
|
+
/**
|
|
492
|
+
* Creates a deep copy of the current form builder
|
|
493
|
+
*
|
|
494
|
+
* This method creates a completely independent copy of the form builder,
|
|
495
|
+
* including all field configurations and internal state. The cloned
|
|
496
|
+
* builder can be modified without affecting the original.
|
|
497
|
+
*
|
|
498
|
+
* @param newFormId - Optional new form ID for the clone
|
|
499
|
+
* @returns A new form builder instance with copied configuration
|
|
500
|
+
*
|
|
501
|
+
* @example
|
|
502
|
+
* ```typescript
|
|
503
|
+
* const originalForm = builder.clone();
|
|
504
|
+
* const modifiedForm = builder.clone('modified-form')
|
|
505
|
+
* .add({ type: 'text', props: { label: 'Additional field' } });
|
|
506
|
+
* ```
|
|
174
507
|
*/
|
|
175
|
-
clone(newFormId?: string): form
|
|
508
|
+
clone(newFormId?: string): form<C>;
|
|
176
509
|
/**
|
|
177
|
-
*
|
|
178
|
-
*
|
|
510
|
+
* Checks the current form configuration for basic structural issues.
|
|
511
|
+
*
|
|
512
|
+
* @returns Array of error messages (empty if valid)
|
|
179
513
|
*/
|
|
180
514
|
validate(): string[];
|
|
181
515
|
/**
|
|
182
|
-
*
|
|
183
|
-
*
|
|
516
|
+
* Builds the final form configuration
|
|
517
|
+
*
|
|
518
|
+
* This method creates the complete form
|
|
519
|
+
* configuration object ready for rendering. It includes all field
|
|
520
|
+
* configurations, render settings, validation configuration, and metadata.
|
|
521
|
+
*
|
|
522
|
+
* @returns Complete form configuration ready for use
|
|
523
|
+
*
|
|
524
|
+
* @example
|
|
525
|
+
* ```typescript
|
|
526
|
+
* const formConfig = builder.build();
|
|
527
|
+
* // Use formConfig with your form renderer
|
|
528
|
+
* ```
|
|
529
|
+
*
|
|
530
|
+
* @remarks
|
|
531
|
+
* The returned configuration includes:
|
|
532
|
+
* - Form ID and metadata
|
|
533
|
+
* - All rows with their field configurations
|
|
534
|
+
* - Flattened array of all fields for easy access
|
|
535
|
+
* - Component configuration reference
|
|
536
|
+
* - Render configuration for customization
|
|
537
|
+
* - Form-level validation configuration
|
|
184
538
|
*/
|
|
185
|
-
build(): FormConfiguration
|
|
539
|
+
build(): FormConfiguration<C>;
|
|
186
540
|
/**
|
|
187
|
-
*
|
|
188
|
-
*
|
|
541
|
+
* Exports the form configuration as JSON
|
|
542
|
+
*
|
|
543
|
+
* This method serializes the form configuration to a plain JavaScript
|
|
544
|
+
* object suitable for storage, transmission, or debugging.
|
|
545
|
+
*
|
|
546
|
+
* @returns Plain object representation of the form
|
|
547
|
+
*
|
|
548
|
+
* @example
|
|
549
|
+
* ```typescript
|
|
550
|
+
* const formJson = builder.toJSON();
|
|
551
|
+
* localStorage.setItem('savedForm', JSON.stringify(formJson));
|
|
552
|
+
* ```
|
|
189
553
|
*/
|
|
190
554
|
toJSON(): any;
|
|
191
555
|
/**
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
*
|
|
556
|
+
* Imports form configuration from JSON
|
|
557
|
+
*
|
|
558
|
+
* This method restores form state from a previously exported JSON
|
|
559
|
+
* configuration. It's useful for loading saved forms or restoring
|
|
560
|
+
* form state from external sources.
|
|
561
|
+
*
|
|
562
|
+
* @param json - The JSON object containing form configuration
|
|
563
|
+
* @returns The form builder instance for method chaining
|
|
564
|
+
*
|
|
565
|
+
* @example
|
|
566
|
+
* ```typescript
|
|
567
|
+
* const savedForm = JSON.parse(localStorage.getItem('savedForm'));
|
|
568
|
+
* builder.fromJSON(savedForm);
|
|
569
|
+
* ```
|
|
570
|
+
*
|
|
571
|
+
* @remarks
|
|
572
|
+
* - Only imports basic form structure (ID and rows)
|
|
573
|
+
* - Does not validate imported configuration
|
|
574
|
+
* - Existing form content is replaced
|
|
195
575
|
*/
|
|
196
576
|
fromJSON(json: any): this;
|
|
197
577
|
/**
|
|
198
|
-
*
|
|
199
|
-
*
|
|
578
|
+
* Gets comprehensive statistics about the form
|
|
579
|
+
*
|
|
580
|
+
* This method provides useful metrics about the form structure,
|
|
581
|
+
* helpful for analytics, debugging, or UI display purposes.
|
|
582
|
+
*
|
|
583
|
+
* @returns Object containing form statistics
|
|
584
|
+
*
|
|
585
|
+
* @example
|
|
586
|
+
* ```typescript
|
|
587
|
+
* const stats = builder.getStats();
|
|
588
|
+
* console.log(`Form has ${stats.totalFields} fields in ${stats.totalRows} rows`);
|
|
589
|
+
* console.log(`Average fields per row: ${stats.averageFieldsPerRow.toFixed(1)}`);
|
|
590
|
+
* ```
|
|
591
|
+
*
|
|
592
|
+
* @remarks
|
|
593
|
+
* Statistics include:
|
|
594
|
+
* - Total number of fields and rows
|
|
595
|
+
* - Average fields per row
|
|
596
|
+
* - Maximum and minimum fields in any row
|
|
597
|
+
* - Useful for form complexity analysis
|
|
200
598
|
*/
|
|
201
599
|
getStats(): {
|
|
600
|
+
/** Total number of static fields across all rows */
|
|
202
601
|
totalFields: number;
|
|
602
|
+
/** Total number of rows in the form */
|
|
203
603
|
totalRows: number;
|
|
604
|
+
/** Average number of fields per row (field rows only) */
|
|
204
605
|
averageFieldsPerRow: number;
|
|
606
|
+
/** Maximum number of fields in any single row */
|
|
205
607
|
maxFieldsInRow: number;
|
|
608
|
+
/** Minimum number of fields in any single row */
|
|
206
609
|
minFieldsInRow: number;
|
|
610
|
+
/** Total number of repeatable groups */
|
|
611
|
+
totalRepeatables: number;
|
|
612
|
+
/** Total number of fields across all repeatable templates */
|
|
613
|
+
totalRepeatableFields: number;
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
interface FormProps {
|
|
618
|
+
formConfig: FormConfiguration<any> | form<any>;
|
|
619
|
+
defaultValues?: Record<string, any>;
|
|
620
|
+
onSubmit?: (data: Record<string, any>) => void | Promise<void>;
|
|
621
|
+
onFieldChange?: (fieldId: string, value: any, formData: Record<string, any>) => void;
|
|
622
|
+
className?: string;
|
|
623
|
+
children: React.ReactNode;
|
|
624
|
+
}
|
|
625
|
+
declare function Form({ formConfig, defaultValues, onSubmit, onFieldChange, className, children, }: FormProps): react_jsx_runtime.JSX.Element;
|
|
626
|
+
|
|
627
|
+
declare const FormBody: React__default.NamedExoticComponent<ComponentRendererBaseProps<FormBodyRendererProps>>;
|
|
628
|
+
|
|
629
|
+
interface FormFieldProps {
|
|
630
|
+
fieldId: string;
|
|
631
|
+
/** Pre-resolved field config (used by RepeatableItem to skip allFields lookup) */
|
|
632
|
+
fieldConfig?: FormFieldConfig;
|
|
633
|
+
disabled?: boolean;
|
|
634
|
+
customProps?: Record<string, unknown>;
|
|
635
|
+
className?: string;
|
|
636
|
+
forceVisible?: boolean;
|
|
637
|
+
}
|
|
638
|
+
declare const FormField: React__default.NamedExoticComponent<FormFieldProps>;
|
|
639
|
+
|
|
640
|
+
interface ConditionEvaluationResult {
|
|
641
|
+
visible: boolean;
|
|
642
|
+
disabled: boolean;
|
|
643
|
+
required: boolean;
|
|
644
|
+
readonly: boolean;
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* Hook to evaluate conditional behaviors based on form data
|
|
648
|
+
*
|
|
649
|
+
* @param conditions - The conditional behavior configuration
|
|
650
|
+
* @param formData - Current form data to evaluate against
|
|
651
|
+
* @param defaultState - Default state when no conditions are provided
|
|
652
|
+
* @returns Evaluated condition results
|
|
653
|
+
*/
|
|
654
|
+
declare function useConditionEvaluation(conditions?: ConditionalBehavior, formData?: Record<string, any>, defaultState?: Partial<ConditionEvaluationResult>): ConditionEvaluationResult;
|
|
655
|
+
/**
|
|
656
|
+
* Hook to evaluate conditions for multiple fields at once
|
|
657
|
+
*
|
|
658
|
+
* @param fieldsWithConditions - Map of field IDs to their conditional behaviors
|
|
659
|
+
* @param formData - Current form data
|
|
660
|
+
* @returns Map of field IDs to their evaluated conditions
|
|
661
|
+
*/
|
|
662
|
+
declare function useMultipleConditionEvaluation(fieldsWithConditions: Record<string, ConditionalBehavior | undefined>, formData?: Record<string, any>): Record<string, ConditionEvaluationResult>;
|
|
663
|
+
|
|
664
|
+
interface UseFieldConditionsLazyOptions {
|
|
665
|
+
/**
|
|
666
|
+
* The field's conditional behavior configuration
|
|
667
|
+
*/
|
|
668
|
+
conditions?: ConditionalBehavior;
|
|
669
|
+
/**
|
|
670
|
+
* Whether to skip evaluation (e.g., if field has no conditions)
|
|
671
|
+
*/
|
|
672
|
+
skip?: boolean;
|
|
673
|
+
}
|
|
674
|
+
/**
|
|
675
|
+
* Lazy condition evaluation hook with caching
|
|
676
|
+
*
|
|
677
|
+
* This hook:
|
|
678
|
+
* 1. Only evaluates conditions when called
|
|
679
|
+
* 2. Caches the result based on form values hash
|
|
680
|
+
* 3. Returns cached result if values haven't changed
|
|
681
|
+
*
|
|
682
|
+
* @param fieldId - The field ID
|
|
683
|
+
* @param options - Configuration options
|
|
684
|
+
* @returns The evaluated field conditions
|
|
685
|
+
*
|
|
686
|
+
* @example
|
|
687
|
+
* ```tsx
|
|
688
|
+
* const conditions = useFieldConditionsLazy('myField', {
|
|
689
|
+
* conditions: fieldConfig.conditions
|
|
690
|
+
* });
|
|
691
|
+
*
|
|
692
|
+
* if (!conditions.visible) return null;
|
|
693
|
+
* ```
|
|
694
|
+
*/
|
|
695
|
+
declare function useFieldConditionsLazy(fieldId: string, options?: UseFieldConditionsLazyOptions): FieldConditions;
|
|
696
|
+
/**
|
|
697
|
+
* Hook to create a lazy condition evaluator function
|
|
698
|
+
*
|
|
699
|
+
* This is useful when you need to evaluate conditions for multiple fields
|
|
700
|
+
* on-demand, without triggering re-renders.
|
|
701
|
+
*
|
|
702
|
+
* @returns A function that evaluates conditions for a given field
|
|
703
|
+
*/
|
|
704
|
+
declare function useConditionEvaluator(): (fieldId: string, conditions?: ConditionalBehavior) => FieldConditions;
|
|
705
|
+
/**
|
|
706
|
+
* Hook that provides both current conditions and a way to force re-evaluation
|
|
707
|
+
*/
|
|
708
|
+
declare function useFieldConditionsWithRefresh(fieldId: string, conditions?: ConditionalBehavior): {
|
|
709
|
+
conditions: FieldConditions;
|
|
710
|
+
refresh: () => FieldConditions;
|
|
711
|
+
};
|
|
712
|
+
|
|
713
|
+
interface UseFormConditionsProps {
|
|
714
|
+
formConfig: FormConfiguration;
|
|
715
|
+
formValues: Record<string, any>;
|
|
716
|
+
/** Active repeatable item keys, keyed by repeatable ID */
|
|
717
|
+
repeatableOrder?: Record<string, string[]>;
|
|
718
|
+
}
|
|
719
|
+
interface UseFormConditionsReturn {
|
|
720
|
+
fieldConditions: Record<string, ConditionEvaluationResult>;
|
|
721
|
+
hasConditionalFields: boolean;
|
|
722
|
+
getFieldCondition: (fieldId: string) => ConditionEvaluationResult | undefined;
|
|
723
|
+
isFieldVisible: (fieldId: string) => boolean;
|
|
724
|
+
isFieldDisabled: (fieldId: string) => boolean;
|
|
725
|
+
isFieldRequired: (fieldId: string) => boolean;
|
|
726
|
+
isFieldReadonly: (fieldId: string) => boolean;
|
|
727
|
+
}
|
|
728
|
+
/**
|
|
729
|
+
* Hook to manage conditional behaviors for form fields
|
|
730
|
+
*
|
|
731
|
+
* This hook evaluates conditions for all form fields and provides
|
|
732
|
+
* convenient methods to check field states.
|
|
733
|
+
*
|
|
734
|
+
* @param props - Configuration for form conditions
|
|
735
|
+
* @returns Object containing field conditions and helper methods
|
|
736
|
+
*
|
|
737
|
+
* @example
|
|
738
|
+
* ```tsx
|
|
739
|
+
* const {
|
|
740
|
+
* fieldConditions,
|
|
741
|
+
* isFieldVisible,
|
|
742
|
+
* isFieldDisabled
|
|
743
|
+
* } = useFormConditions({
|
|
744
|
+
* formConfig,
|
|
745
|
+
* formValues
|
|
746
|
+
* });
|
|
747
|
+
*
|
|
748
|
+
* // Check if a field should be visible
|
|
749
|
+
* if (!isFieldVisible('phoneField')) {
|
|
750
|
+
* return null;
|
|
751
|
+
* }
|
|
752
|
+
* ```
|
|
753
|
+
*/
|
|
754
|
+
declare function useFormConditions({ formConfig, formValues, repeatableOrder, }: UseFormConditionsProps): UseFormConditionsReturn;
|
|
755
|
+
|
|
756
|
+
interface FormStoreState extends FormState {
|
|
757
|
+
_defaultValues: Record<string, unknown>;
|
|
758
|
+
_fieldConditions: Record<string, FieldConditions>;
|
|
759
|
+
_repeatableConfigs: Record<string, RepeatableFieldConfig>;
|
|
760
|
+
_repeatableOrder: Record<string, string[]>;
|
|
761
|
+
_repeatableNextKey: Record<string, number>;
|
|
762
|
+
_setValue: (fieldId: string, value: unknown) => void;
|
|
763
|
+
_setTouched: (fieldId: string) => void;
|
|
764
|
+
_setErrors: (fieldId: string, errors: ValidationError[]) => void;
|
|
765
|
+
_clearErrors: (fieldId: string) => void;
|
|
766
|
+
_setValidationState: (fieldId: string, state: ValidationState) => void;
|
|
767
|
+
_setSubmitting: (isSubmitting: boolean) => void;
|
|
768
|
+
_reset: (values?: Record<string, unknown>) => void;
|
|
769
|
+
_setFieldConditions: (fieldId: string, conditions: FieldConditions) => void;
|
|
770
|
+
_updateIsValid: () => void;
|
|
771
|
+
_setRepeatableConfig: (id: string, config: RepeatableFieldConfig) => void;
|
|
772
|
+
_appendRepeatableItem: (repeatableId: string, defaultValue?: Record<string, unknown>) => string | null;
|
|
773
|
+
_removeRepeatableItem: (repeatableId: string, key: string) => boolean;
|
|
774
|
+
_moveRepeatableItem: (repeatableId: string, fromIndex: number, toIndex: number) => void;
|
|
775
|
+
_insertRepeatableItem: (repeatableId: string, index: number, defaultValue?: Record<string, unknown>) => string | null;
|
|
776
|
+
}
|
|
777
|
+
type FormStore = ReturnType<typeof createFormStore>;
|
|
778
|
+
declare function createFormStore(initialValues?: Record<string, unknown>): Omit<zustand.StoreApi<FormStoreState>, "subscribe"> & {
|
|
779
|
+
subscribe: {
|
|
780
|
+
(listener: (selectedState: FormStoreState, previousSelectedState: FormStoreState) => void): () => void;
|
|
781
|
+
<U>(selector: (state: FormStoreState) => U, listener: (selectedState: U, previousSelectedState: U) => void, options?: {
|
|
782
|
+
equalityFn?: ((a: U, b: U) => boolean) | undefined;
|
|
783
|
+
fireImmediately?: boolean;
|
|
784
|
+
} | undefined): () => void;
|
|
785
|
+
};
|
|
786
|
+
};
|
|
787
|
+
declare const FormStoreContext: React$1.Context<(Omit<zustand.StoreApi<FormStoreState>, "subscribe"> & {
|
|
788
|
+
subscribe: {
|
|
789
|
+
(listener: (selectedState: FormStoreState, previousSelectedState: FormStoreState) => void): () => void;
|
|
790
|
+
<U>(selector: (state: FormStoreState) => U, listener: (selectedState: U, previousSelectedState: U) => void, options?: {
|
|
791
|
+
equalityFn?: ((a: U, b: U) => boolean) | undefined;
|
|
792
|
+
fireImmediately?: boolean;
|
|
793
|
+
} | undefined): () => void;
|
|
207
794
|
};
|
|
795
|
+
}) | null>;
|
|
796
|
+
/**
|
|
797
|
+
* Get the form store from context
|
|
798
|
+
* @throws Error if used outside of FormProvider
|
|
799
|
+
*/
|
|
800
|
+
declare function useFormStore(): FormStore;
|
|
801
|
+
/**
|
|
802
|
+
* Select a single field value - re-renders only when this field's value changes
|
|
803
|
+
*/
|
|
804
|
+
declare function useFieldValue<T = unknown>(fieldId: string): T;
|
|
805
|
+
/**
|
|
806
|
+
* Select field errors - re-renders only when this field's errors change
|
|
807
|
+
*/
|
|
808
|
+
declare function useFieldErrors(fieldId: string): ValidationError[];
|
|
809
|
+
/**
|
|
810
|
+
* Select field touched state - re-renders only when this field's touched state changes
|
|
811
|
+
*/
|
|
812
|
+
declare function useFieldTouched(fieldId: string): boolean;
|
|
813
|
+
/**
|
|
814
|
+
* Select field validation state - re-renders only when this field's validation state changes
|
|
815
|
+
*/
|
|
816
|
+
declare function useFieldValidationState(fieldId: string): ValidationState;
|
|
817
|
+
/**
|
|
818
|
+
* Select field conditions - re-renders only when this field's conditions change
|
|
819
|
+
*/
|
|
820
|
+
declare function useFieldConditions(fieldId: string): FieldConditions;
|
|
821
|
+
/**
|
|
822
|
+
* Select complete field state - uses individual selectors to avoid object recreation
|
|
823
|
+
*/
|
|
824
|
+
declare function useFieldState(fieldId: string): FieldState;
|
|
825
|
+
/**
|
|
826
|
+
* Select form submitting state
|
|
827
|
+
*/
|
|
828
|
+
declare function useFormSubmitting(): boolean;
|
|
829
|
+
/**
|
|
830
|
+
* Select form valid state
|
|
831
|
+
*/
|
|
832
|
+
declare function useFormValid(): boolean;
|
|
833
|
+
/**
|
|
834
|
+
* Select form dirty state
|
|
835
|
+
*/
|
|
836
|
+
declare function useFormDirty(): boolean;
|
|
837
|
+
/**
|
|
838
|
+
* Select all form values - uses shallow comparison
|
|
839
|
+
*/
|
|
840
|
+
declare function useFormValues(): Record<string, unknown>;
|
|
841
|
+
/**
|
|
842
|
+
* Select form state for submit button - minimal re-renders
|
|
843
|
+
*/
|
|
844
|
+
declare function useFormSubmitState(): {
|
|
845
|
+
isSubmitting: boolean;
|
|
846
|
+
isValid: boolean;
|
|
847
|
+
isDirty: boolean;
|
|
848
|
+
};
|
|
849
|
+
/**
|
|
850
|
+
* Select ordered keys for a repeatable field — re-renders when the order changes
|
|
851
|
+
*/
|
|
852
|
+
declare function useRepeatableKeys(repeatableId: string): string[];
|
|
853
|
+
interface UseFieldActionsResult {
|
|
854
|
+
setValue: (value: unknown) => void;
|
|
855
|
+
setTouched: () => void;
|
|
856
|
+
setErrors: (errors: ValidationError[]) => void;
|
|
857
|
+
clearErrors: () => void;
|
|
858
|
+
setValidationState: (state: ValidationState) => void;
|
|
208
859
|
}
|
|
860
|
+
/**
|
|
861
|
+
* Get stable action references for a field
|
|
862
|
+
* Actions don't cause re-renders
|
|
863
|
+
*/
|
|
864
|
+
declare function useFieldActions(fieldId: string): UseFieldActionsResult;
|
|
865
|
+
interface UseFormActionsResult {
|
|
866
|
+
setValue: (fieldId: string, value: unknown) => void;
|
|
867
|
+
setTouched: (fieldId: string) => void;
|
|
868
|
+
setErrors: (fieldId: string, errors: ValidationError[]) => void;
|
|
869
|
+
setSubmitting: (isSubmitting: boolean) => void;
|
|
870
|
+
reset: (values?: Record<string, unknown>) => void;
|
|
871
|
+
setFieldConditions: (fieldId: string, conditions: FieldConditions) => void;
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* Get stable form-level action references
|
|
875
|
+
* Actions don't cause re-renders
|
|
876
|
+
*/
|
|
877
|
+
declare function useFormActions(): UseFormActionsResult;
|
|
878
|
+
/**
|
|
879
|
+
* Get the raw store for advanced use cases (like validation hooks)
|
|
880
|
+
*/
|
|
881
|
+
declare function useFormStoreApi(): FormStore;
|
|
882
|
+
|
|
883
|
+
interface UseFormSubmissionWithStoreProps {
|
|
884
|
+
store: FormStore;
|
|
885
|
+
onSubmit?: (data: Record<string, unknown>) => void | Promise<void>;
|
|
886
|
+
validateForm: () => Promise<ValidationResult>;
|
|
887
|
+
}
|
|
888
|
+
declare function useFormSubmissionWithStore({ store, onSubmit, validateForm, }: UseFormSubmissionWithStoreProps): {
|
|
889
|
+
submit: (event?: React__default.FormEvent) => Promise<boolean>;
|
|
890
|
+
};
|
|
891
|
+
|
|
892
|
+
interface UseFormValidationWithStoreProps {
|
|
893
|
+
formConfig: FormConfiguration;
|
|
894
|
+
store: FormStore;
|
|
895
|
+
conditionsHelpers: Omit<UseFormConditionsReturn, 'fieldConditions'>;
|
|
896
|
+
}
|
|
897
|
+
declare function useFormValidationWithStore({ formConfig, store, conditionsHelpers, }: UseFormValidationWithStoreProps): {
|
|
898
|
+
validateField: (fieldId: string, value?: unknown) => Promise<ValidationResult>;
|
|
899
|
+
validateForm: () => Promise<ValidationResult>;
|
|
900
|
+
};
|
|
901
|
+
|
|
902
|
+
interface UseRepeatableFieldReturn {
|
|
903
|
+
items: RepeatableFieldItem[];
|
|
904
|
+
append: (defaultValue?: Record<string, unknown>) => void;
|
|
905
|
+
remove: (key: string) => void;
|
|
906
|
+
move: (fromIndex: number, toIndex: number) => void;
|
|
907
|
+
canAdd: boolean;
|
|
908
|
+
canRemove: boolean;
|
|
909
|
+
count: number;
|
|
910
|
+
}
|
|
911
|
+
/**
|
|
912
|
+
* Hook to manage a repeatable field group
|
|
913
|
+
*
|
|
914
|
+
* Provides the list of items and actions to add, remove, and reorder them.
|
|
915
|
+
* Each item contains scoped field configs ready for rendering.
|
|
916
|
+
*
|
|
917
|
+
* @param repeatableId - The ID of the repeatable group (as defined in addRepeatable)
|
|
918
|
+
* @returns Items, actions, and constraints
|
|
919
|
+
*
|
|
920
|
+
* @example
|
|
921
|
+
* ```tsx
|
|
922
|
+
* const { items, append, remove, canAdd, canRemove } = useRepeatableField("items");
|
|
923
|
+
*
|
|
924
|
+
* return (
|
|
925
|
+
* <div>
|
|
926
|
+
* {items.map(item => (
|
|
927
|
+
* <div key={item.key}>
|
|
928
|
+
* {item.allFields.map(field => (
|
|
929
|
+
* <FormField key={field.id} fieldId={field.id} fieldConfig={field} />
|
|
930
|
+
* ))}
|
|
931
|
+
* {canRemove && <button onClick={() => remove(item.key)}>Remove</button>}
|
|
932
|
+
* </div>
|
|
933
|
+
* ))}
|
|
934
|
+
* {canAdd && <button onClick={append}>Add</button>}
|
|
935
|
+
* </div>
|
|
936
|
+
* );
|
|
937
|
+
* ```
|
|
938
|
+
*/
|
|
939
|
+
declare function useRepeatableField(repeatableId: string): UseRepeatableFieldReturn;
|
|
940
|
+
|
|
941
|
+
interface UseFormMonitoringProps {
|
|
942
|
+
formConfig: FormConfiguration;
|
|
943
|
+
monitoring?: MonitoringConfig;
|
|
944
|
+
enabled?: boolean;
|
|
945
|
+
}
|
|
946
|
+
interface UseFormMonitoringReturn {
|
|
947
|
+
trackFormRender: (renderCount?: number) => void;
|
|
948
|
+
trackFormValidation: (validationErrors: number, fieldCount?: number) => void;
|
|
949
|
+
trackFormSubmission: (success: boolean, fieldCount?: number) => void;
|
|
950
|
+
trackFieldChange: (fieldId: string, componentType: string) => void;
|
|
951
|
+
startPerformanceTracking: (label: string) => void;
|
|
952
|
+
endPerformanceTracking: (label: string) => FormPerformanceMetrics | null;
|
|
953
|
+
}
|
|
954
|
+
declare function useFormMonitoring({ formConfig, enabled, }: UseFormMonitoringProps): UseFormMonitoringReturn;
|
|
955
|
+
|
|
956
|
+
interface FormConfigContextValue {
|
|
957
|
+
formConfig: FormConfiguration;
|
|
958
|
+
conditionsHelpers: Omit<UseFormConditionsReturn, 'fieldConditions'>;
|
|
959
|
+
validateField: (fieldId: string, value?: unknown) => Promise<ValidationResult>;
|
|
960
|
+
validateForm: () => Promise<ValidationResult>;
|
|
961
|
+
submit: (event?: React__default.FormEvent) => Promise<boolean>;
|
|
962
|
+
}
|
|
963
|
+
/**
|
|
964
|
+
* Access form configuration and validation methods
|
|
965
|
+
*/
|
|
966
|
+
declare function useFormConfigContext(): FormConfigContextValue;
|
|
967
|
+
interface FormProviderProps {
|
|
968
|
+
children: React__default.ReactNode;
|
|
969
|
+
formConfig: FormConfiguration;
|
|
970
|
+
defaultValues?: Record<string, unknown>;
|
|
971
|
+
onSubmit?: (data: Record<string, unknown>) => void | Promise<void>;
|
|
972
|
+
onFieldChange?: (fieldId: string, value: unknown, formData: Record<string, unknown>) => void;
|
|
973
|
+
className?: string;
|
|
974
|
+
}
|
|
975
|
+
declare function FormProvider({ children, formConfig, defaultValues, onSubmit, onFieldChange, className, }: FormProviderProps): react_jsx_runtime.JSX.Element;
|
|
976
|
+
|
|
977
|
+
interface FormRowProps extends ComponentRendererBaseProps<FormRowRendererProps> {
|
|
978
|
+
row: FormFieldRow;
|
|
979
|
+
}
|
|
980
|
+
declare const FormRow: React__default.NamedExoticComponent<FormRowProps>;
|
|
981
|
+
|
|
982
|
+
interface FormSubmitButtonProps extends ComponentRendererBaseProps<FormSubmitButtonRendererProps> {
|
|
983
|
+
/**
|
|
984
|
+
* Override the isSubmitting state from form context
|
|
985
|
+
* If provided, this value will be used instead of the form's isSubmitting state
|
|
986
|
+
*/
|
|
987
|
+
isSubmitting?: boolean;
|
|
988
|
+
}
|
|
989
|
+
declare const FormSubmitButton: React__default.NamedExoticComponent<FormSubmitButtonProps>;
|
|
990
|
+
|
|
991
|
+
interface RepeatableFieldProps {
|
|
992
|
+
repeatableId: string;
|
|
993
|
+
repeatableConfig: RepeatableFieldConfig;
|
|
994
|
+
className?: string;
|
|
995
|
+
}
|
|
996
|
+
declare const RepeatableField: React__default.NamedExoticComponent<RepeatableFieldProps>;
|
|
997
|
+
|
|
998
|
+
interface RepeatableItemProps {
|
|
999
|
+
item: RepeatableFieldItem;
|
|
1000
|
+
index: number;
|
|
1001
|
+
total: number;
|
|
1002
|
+
canRemove: boolean;
|
|
1003
|
+
canMoveUp: boolean;
|
|
1004
|
+
canMoveDown: boolean;
|
|
1005
|
+
onRemove: () => void;
|
|
1006
|
+
onMoveUp: () => void;
|
|
1007
|
+
onMoveDown: () => void;
|
|
1008
|
+
}
|
|
1009
|
+
declare const RepeatableItem: React__default.NamedExoticComponent<RepeatableItemProps>;
|
|
1010
|
+
|
|
1011
|
+
/**
|
|
1012
|
+
* Converts flat store values with composite keys into structured nested data.
|
|
1013
|
+
*
|
|
1014
|
+
* Input (store values):
|
|
1015
|
+
* { customerName: "John", "items[k0].name": "Widget", "items[k0].qty": 2, "items[k1].name": "Gadget", "items[k1].qty": 1 }
|
|
1016
|
+
*
|
|
1017
|
+
* Output (structured):
|
|
1018
|
+
* { customerName: "John", items: [{ name: "Widget", qty: 2 }, { name: "Gadget", qty: 1 }] }
|
|
1019
|
+
*/
|
|
1020
|
+
declare function structureFormValues(values: Record<string, unknown>, repeatableConfigs: Record<string, RepeatableFieldConfig>, repeatableOrder: Record<string, string[]>): Record<string, unknown>;
|
|
1021
|
+
/**
|
|
1022
|
+
* Converts structured nested data into flat store values with composite keys.
|
|
1023
|
+
*
|
|
1024
|
+
* Input (structured):
|
|
1025
|
+
* { customerName: "John", items: [{ name: "Widget", qty: 2 }, { name: "Gadget", qty: 1 }] }
|
|
1026
|
+
*
|
|
1027
|
+
* Output:
|
|
1028
|
+
* {
|
|
1029
|
+
* values: { customerName: "John", "items[k0].name": "Widget", "items[k0].qty": 2, "items[k1].name": "Gadget", "items[k1].qty": 1 },
|
|
1030
|
+
* order: { items: ["k0", "k1"] },
|
|
1031
|
+
* nextKeys: { items: 2 }
|
|
1032
|
+
* }
|
|
1033
|
+
*/
|
|
1034
|
+
declare function flattenRepeatableValues(data: Record<string, unknown>, repeatableConfigs: Record<string, RepeatableFieldConfig>): {
|
|
1035
|
+
values: Record<string, unknown>;
|
|
1036
|
+
order: Record<string, string[]>;
|
|
1037
|
+
nextKeys: Record<string, number>;
|
|
1038
|
+
};
|
|
209
1039
|
|
|
210
|
-
export {
|
|
1040
|
+
export { type ConditionEvaluationResult, type FieldConfig, Form, FormBody, form as FormBuilder, type FormConfigContextValue, FormField, FormProvider, type FormProviderProps, FormRow, type FormStore, FormStoreContext, type FormStoreState, FormSubmitButton, RepeatableBuilder, RepeatableField, RepeatableItem, type UseFieldActionsResult, type UseFieldConditionsLazyOptions, type UseFormActionsResult, type UseFormConditionsProps, type UseFormConditionsReturn, type UseFormMonitoringProps, type UseFormMonitoringReturn, type UseFormSubmissionWithStoreProps, type UseFormValidationWithStoreProps, type UseRepeatableFieldReturn, createFormStore, flattenRepeatableValues, form, structureFormValues, useConditionEvaluation, useConditionEvaluator, useFieldActions, useFieldConditions, useFieldConditionsLazy, useFieldConditionsWithRefresh, useFieldErrors, useFieldState, useFieldTouched, useFieldValidationState, useFieldValue, useFormActions, useFormConditions, useFormConfigContext, useFormDirty, useFormMonitoring, useFormStore, useFormStoreApi, useFormSubmissionWithStore, useFormSubmitState, useFormSubmitting, useFormValid, useFormValidationWithStore, useFormValues, useMultipleConditionEvaluation, useRepeatableField, useRepeatableKeys };
|