@bolttech/form-engine 3.0.0-beta.9 → 3.0.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 CHANGED
@@ -1,37 +1,189 @@
1
1
  # Form Engine React Adapter
2
2
 
3
- This is a react adapter to be used with form engine.
3
+ This is an adapter to be used with the bolttech form engine. Compatible with Next.js 13 and 14 and react 18.
4
4
 
5
- ## React `<FormProvider />`
5
+ 1. [Sample](#sample)
6
+ 2. [mappers](#mappers)
7
+ 3. [Form Group Context](#form-group-context)
6
8
 
7
- React context that lets you provide configuration information to your application forms
9
+ - 3.1 [FormGroupContextProvider](#formgroupcontextprovider)
10
+ - 3.2 [useFormGroupContext](#useformgroupcontext)
8
11
 
9
- ### Props
12
+ 4. [Form](#form)
10
13
 
11
- | Prop | Type | Description |
12
- | ------------ | ------------- | ------------------------------------------------------------- |
13
- | mapper | TMapper | Allow you to map your own components to be used with the form |
14
- | propsMapping | TPropsMapping | Map your component props names with the form functionalities |
14
+ - 4.1 [Submit Form](#submit-form)
15
15
 
16
- ### Example
16
+ 5. [schema](#schema)
17
+ 6. [schema components](#schema-components)
17
18
 
18
- The following example shows a provider that will provide forms with input and Dropdown component
19
+ - 6.1 [formatters](#formatters)
20
+ - 6.2 [masks](#masks)
21
+ - 6.3 [nameToSubmit](#nametosubmit)
22
+ - 6.4 [props](#props)
23
+ - 6.5 [validations](#validations)
24
+ - 6.6 [api](#api)
25
+ - 6.7 [resetValues](#resetvalues)
26
+ - 6.8 [visibilityConditions](#visibilityconditions)
27
+ - 6.9 [resetPropertyValues](#resetpropertyvalues)
28
+ - 6.10 [visibility](#visibility)
29
+ - 6.11 [persistValue](#persistValue)
19
30
 
20
- ```javascript
21
- import Input from 'Components/Input';
22
- import Dropdown from 'Components/Dropdown';
31
+ 7. [templating](#templating)
23
32
 
24
- const Mappings = {
25
- inputForm: { component: Input },
26
- dropdownForm: { component: Dropdown },
33
+ 8. [hooks](#hooks)
34
+
35
+ - 8.1 [useForm](#useform)
36
+ - 8.2 [useFormGroup](#useformgroup)
37
+
38
+ 9. [AsFormField](#asformfield)
39
+ 10. [AsFormFieldBuilder](#asformfieldbuilder)
40
+ 11. [AsFormFieldRepeater](#asformfieldrepeater)
41
+
42
+ <a id="sample"></a>
43
+
44
+ ## **Sample**
45
+
46
+ ```typescript
47
+ const mappers: TMapper<ElementType>[] = [
48
+ {
49
+ componentName: 'input',
50
+ component: Input,
51
+ events: {
52
+ getValue: 'onChange',
53
+ setValue: 'value',
54
+ setErrorMessage: 'errorMessage',
55
+ onBlur: 'onBlur',
56
+ onFocus: 'onFocus',
57
+ },
58
+ valueChangeEvent: (event: unknown) => {
59
+ return (event as ChangeEvent<HTMLInputElement>).target.value;
60
+ },
61
+ },
62
+ {
63
+ componentName: 'container',
64
+ asyncComponent: lazy(() =>
65
+ import('Components/Container').then((module) => ({
66
+ default: module.Container,
67
+ }))
68
+ ),
69
+ },
70
+ ];
71
+
72
+ const schema = {
73
+ index: 'form1',
74
+ components: [
75
+ {
76
+ component: 'container',
77
+ name: 'container1',
78
+ children: [
79
+ {
80
+ component: 'input',
81
+ name: 'input1',
82
+ props: {
83
+ label: 'input1 label',
84
+ },
85
+ },
86
+ ],
87
+ },
88
+ ],
27
89
  };
28
90
 
29
- const propsMapping = {
30
- inputForm: {
31
- getValue: 'onChange',
32
- setValue: 'value',
91
+ const ComponentProvider = ({ children }: PropsWithChildren) => {
92
+ return <FormGroupContextProvider mappers={mappers}>{children}</FormGroupContextProvider>;
93
+ };
94
+
95
+ const ComponentWithForm = ({ schema }: { schema: IFormSchema }) => {
96
+ const { printFormGroupInstance } = useFormGroupContext();
97
+
98
+ const handleData = (data: TFormData<unknown>) => {
99
+ console.log(data);
100
+ };
101
+
102
+ return (
103
+ <>
104
+ <button onClick={printFormGroupInstance}>print form instance</button>
105
+ <Form index={schema.index} schema={schema} onData={handleData} />
106
+ </>
107
+ );
108
+ };
109
+
110
+ const Sample = () => {
111
+ return (
112
+ <ComponentProvider>
113
+ <ComponentWithForm schema={schema} />
114
+ </ComponentProvider>
115
+ );
116
+ };
117
+ ```
118
+
119
+ <a id="mappers"></a>
120
+
121
+ ## **Mappers**
122
+
123
+ Mappers are the configuration that needs to be provided in order to use components onto schemas or a special component that render form fields
124
+
125
+ The mapper configuration goes as it follows:
126
+
127
+ | Prop | Type | Description |
128
+ | ---------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------ |
129
+ | componentName | string | name to be used onto schema to identify the component to be rendered on a field |
130
+ | events | TComponentPropsMapping | events mapping that will reference the component prop with the respective form-engine prop that will handle it's content |
131
+ | valueChangeEvent | TValueChangeEvent | component handle function to define how the value is extracted from the 'onChange' event of the component |
132
+ | component | T | component type that describes a normal imported component to be used on the field rendering |
133
+ | asynccomponent | T | component type that describes an async (lazy) imported component to be used on the field rendering |
134
+
135
+ `events` are optional and will reference component props that will provide it's dynamic behaviour:
136
+
137
+ | Prop | Type | Description |
138
+ | --------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
139
+ | getValue | string | component property that will contain the value |
140
+ | setValue | string | component property that handles onChange events triggered by the component |
141
+ | onBlur | string | component property that handles onBlur events triggered by the component |
142
+ | onClick | string | component property that handles onClick events triggered by the component |
143
+ | onSubmit | string | component property that handles form submission event triggered by the component (a way to submit a form using AsFormFieldBuilder, if used with AsFormField and Form will trigger submission twice) |
144
+ | onFocus | string | component property that handles onFocus events triggered by the component |
145
+ | onKeyUp | string | component property that handles onKeyUp events triggered by the component |
146
+ | onKeyDown | string | component property that handles onKeyDown events triggered by the component |
147
+ | setErrorMessage | string | component property that receives the errors of the field as string |
148
+ | setErrorState | string | component property that receives the error status of the field as boolean (not implemented) |
149
+
150
+ ### component and asynccomponent
151
+
152
+ You can choose the way your component is imported, you can directly import the component that will be bundled on your project when built,
153
+ or with React's `lazy` or any other method to be used with React's `Suspense` to load it asyncronously and allow code splitting.
154
+
155
+ Example:
156
+
157
+ ```typescript
158
+ import { Input } from '@bolttech/atoms-input';
159
+
160
+ const mappers = [
161
+ {
162
+ component: Input,
163
+ name: 'inputcomponent',
33
164
  },
34
- dropdownForm: {
165
+ {
166
+ component: lazy(() =>
167
+ import('@bolttech/atoms-input').then((module) => ({
168
+ default: module.Input,
169
+ }))
170
+ ),
171
+ name: 'inputasynccomponent',
172
+ },
173
+ ];
174
+ ```
175
+
176
+ ### from v2 to v3
177
+
178
+ Previously, mappers was two lists: `mappings` and `propsMappings`, now it's a single list, a simple example how to refactor a mapper:
179
+
180
+ ```typescript
181
+ //v2
182
+ const mappings = {
183
+ input: { component: Input },
184
+ };
185
+ const propsMappings = {
186
+ input: {
35
187
  getValue: 'onChangeCallback',
36
188
  setValue: 'data',
37
189
  setErrorMessage: 'errorMessageArray',
@@ -43,14 +195,111 @@ const propsMapping = {
43
195
  },
44
196
  };
45
197
 
46
- const App = () => {
47
- return <FormProvider mapper={Mappings} propsMapping={propsMapping} />;
198
+ //v3
199
+ const mappers = [
200
+ {
201
+ component: Input,
202
+ componentName: 'input',
203
+ events: {
204
+ getValue: 'onChangeCallback',
205
+ setValue: 'data',
206
+ setErrorMessage: 'errorMessageArray',
207
+ setErrorState: 'isErrored',
208
+ onBlur: 'onBlurCallback',
209
+ onFocus: 'onFocusCallback',
210
+ onKeyUp: 'onKeyUpCallback',
211
+ onKeyDown: 'onKeyDownCallback',
212
+ },
213
+ valueChangeEvent: (event: unknown) => {
214
+ return (event as SyntheticEvent<HTMLInputElement>).currentTarget.value;
215
+ },
216
+ },
217
+ ];
218
+ ```
219
+
220
+ for bolltech components, there are `valueChangeEvent` default functions provided by form-engine:
221
+
222
+ - defaultChangeEvent - `atoms/input` | `atoms/textarea`
223
+ - checkedChangeEvent - `atoms/checkbox`
224
+ - valueChangeEvent - `atoms/input` | `atoms/textarea`
225
+ - datepickerChangeEvent - `molecules/datepicker`
226
+ - dropdownChangeEvent - `molecules/dropdown`
227
+
228
+ Example:
229
+
230
+ ```typescript
231
+ import { Input } from '@bolttech/atoms-input';
232
+
233
+ import { defaultChangeEvent } from '@bolttech/form-engine';
234
+
235
+ const mapper = [
236
+ {
237
+ component: Input,
238
+ componentName: 'input',
239
+ events: {
240
+ getValue: 'onChange',
241
+ setValue: 'value',
242
+ setErrorMessage: 'errorMessage',
243
+ onBlur: 'onBlur',
244
+ onFocus: 'onFocus',
245
+ onKeyUp: 'onKeyUp',
246
+ onKeyDown: 'onKeyUpCapture',
247
+ },
248
+ valueChangeEvent: defaultChangeEvent,
249
+ },
250
+ ];
251
+ ```
252
+
253
+ <a id="form-group-context"></a>
254
+
255
+ ## **Form Group Context**
256
+
257
+ <a id="formgroupcontextprovider"></a>
258
+
259
+ ## **FormGroupContextProvider**
260
+
261
+ Provider of the context surrounding the child components, providing the state and functions to manage the group of forms.
262
+
263
+ ### Props
264
+
265
+ | Prop | Type | Description |
266
+ | --------- | ---------------------- | ------------------------------------------------------------------------------------------------------ |
267
+ | mappers | TMapper<ElementType>[] | Array of mappers for form element types. Allow you to map your own components to be used with the form |
268
+ | debugMode | boolean | Optional flag to enable debug mode (default: `false`). |
269
+ | config | TSchemaFormConfig | Optional configuration object to set api and events debounce time |
270
+
271
+ ### Implementation
272
+
273
+ - Creates a reference to the form group instance.
274
+ - Defines functions for adding, getting, and removing forms from the group.
275
+ - Defines a function to print the form group instance.
276
+ - Defines a function to submit multiple forms via the index.
277
+ - Defines the value of the context with the created functions and states.
278
+ - Returns the context provider involving the child components.
279
+
280
+ #### Calling provider
281
+
282
+ ```typescript
283
+ import React from 'react';
284
+ import { FormGroupContextProvider } from '@bolttech/form-engine'; // Import the previously created provider
285
+ import { mappers } from 'project/mappers'; // mappers defined on the previous topic
286
+
287
+ const App = ({ children }: React.PropsWithChildren): React.ReactElement => {
288
+ const debugMode = true; // Enable debug mode
289
+
290
+ return (
291
+ <FormGroupContextProvider mappers={mappers} debugMode={debugMode}>
292
+ {children}
293
+ </FormGroupContextProvider>
294
+ );
48
295
  };
296
+
297
+ export default App;
49
298
  ```
50
299
 
51
- You now can use in your [form](#react-form-) the mapped components with names `inputForm` and `dropdownForm`.
300
+ You now can use in your [form](#react-form-) the mapped components with names `input` and `dropdown`.
52
301
 
53
- Also note the data in `propsMapping`. There you can map up to five form functionalities per component
302
+ Also note the data in `TMapper.events`. There you can map up to five form functionalities per component
54
303
 
55
304
  | Key | Functionality |
56
305
  | --------------- | -------------------------------------------------------------------------------------------------------------------- |
@@ -63,7 +312,7 @@ Also note the data in `propsMapping`. There you can map up to five form function
63
312
  | onKeyUp | Prop name that is called when user releases a key on field |
64
313
  | onKeyDown | Prop name that is called when user presses a key on field |
65
314
 
66
- You can also use default prop names for functionalities like:
315
+ [DEPRECIATED] You can also use default prop names for functionalities like:
67
316
 
68
317
  ```javascript
69
318
  import Input from 'Components/Input';
@@ -85,47 +334,128 @@ const propsMapping = {
85
334
  onKeyDown: 'onKeyDownCallback',
86
335
  },
87
336
  };
337
+ ```
338
+
339
+ [DEPRECIATED] This will make form search for those names in all your components that do not have split mapping.
340
+
341
+ <a id="useformgroupcontext"></a>
342
+
343
+ ## **useFormGroupContext**
344
+
345
+ Hook that facilitates the use of the FormGroupContext context in functional components.
346
+
347
+ - Checks if the context is set or creates an isolated context that will only be accessible on the component that is defined.
348
+ - Returns the context.
349
+
350
+ ### What comes from
351
+
352
+ - `addForm`: Function to add a form to the group.
353
+ - `getForm`: Function to obtain a specific form from the group.
354
+ - `removeForm`: Function to remove a form from the group.
355
+ - `formGroupInstance`: Instance of the form group.
356
+ - `printFormGroupInstance`: Function to print the form group instance.
357
+ - `submitMultipleFormsByIndex`: Function to submit multiple forms by index.
358
+
359
+ ```typescript
360
+ type TFormContext = {
361
+ addForm: (payload: { key: string; formInstance: TFormCore }) => void;
362
+ getForm: (payload: { key: string }) => FormCore | undefined;
363
+ removeForm: (payload: { key: string }) => void;
364
+ formGroupInstance: TFormGroup;
365
+ printFormGroupInstance: () => void;
366
+ submitMultipleFormsByIndex: (indexes: string[]) => TFormValues;
367
+ };
368
+ ```
369
+
370
+ ### Example
371
+
372
+ ```typescript
373
+ import React from 'react';
374
+ import { useFormGroupContext } from '@bolttech/form-engine'; // Import the previously created hook
375
+
376
+ const FormComponent = (): React.ReactElement => {
377
+ const { addForm, removeForm, getForm, printFormGroupInstance, submitMultipleFormsByIndex, debugMode } = useFormGroupContext();
378
+
379
+ const handleAddForm = () => {
380
+ const key = 'form1';
381
+ const formInstance = new FormCore(); // Assuming FormCore is an existing class
382
+ addForm({ key, formInstance });
383
+ };
384
+
385
+ const handleRemoveForm = () => {
386
+ const key = 'form1';
387
+ removeForm({ key });
388
+ };
389
+
390
+ const handleGetForm = () => {
391
+ const key = 'form1';
392
+ const form = getForm({ key });
393
+ console.log(form);
394
+ };
395
+
396
+ const handleSubmitForms = () => {
397
+ const indexes = ['form1', 'form2'];
398
+ const formValues = submitMultipleFormsByIndex(indexes);
399
+ console.log(formValues);
400
+ };
88
401
 
89
- const App = () => {
90
- return <FormProvider mapper={Mappings} propsMapping={propsMapping} />;
402
+ return (
403
+ <div>
404
+ <button onClick={handleAddForm}>Add Form</button>
405
+ <button onClick={handleRemoveForm}>Remove Form</button>
406
+ <button onClick={handleGetForm}>Get Form</button>
407
+ <button onClick={handleSubmitForms}>Submit Forms</button>
408
+ <button onClick={printFormGroupInstance}>Print Form Group Instance</button>
409
+ {debugMode && <p>Debug mode is enabled</p>}
410
+ </div>
411
+ );
91
412
  };
413
+
414
+ export default FormComponent;
92
415
  ```
93
416
 
94
- This will make form search for those names in all your components that do not have split mapping.
417
+ <a id="form"></a>
95
418
 
96
- ## React `<Form />`
419
+ ## **Form**
97
420
 
98
421
  After configuring the provider, `<Form />` components lets you render a form
99
422
 
100
423
  ### Props
101
424
 
102
- | Prop | Type | Description |
103
- | --------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
104
- | disable | boolean | Disable all form inputs. It will use the default htm disable attribute |
105
- | group | string | Form group identifier. Used be able to group several forms and then get data with useGroupForm. One will be generated as default if omitted |
106
- | id | string | Form identified. One will be generated as default if omitted |
107
- | hooks | THooks | Provide functions to run on certain life-cycle events |
108
- | iVars | Object | One object with internal variables to be used in form with data binding |
109
- | initialValues | Object | Object with form initial values that will map to a field. |
110
- | Schema | TSchema | Form Schema |
111
- | autoComplete | string | HTML autocomplete |
112
- | className | string | Allow to style form |
113
- | onSubmit | callback(HTMLFormElement,TFormValues) | Will be called when there is a submit action in the form |
114
- | onData | callback(TFormValues,TComponent, TField) | Will be called when any field data change. The arguments will let you know which field changed and the field configuration |
115
- | onBlur | callback(TFormValues,TComponent, TField) | Will be called when any field blured. The arguments will let you know which field blured and the field configuration |
116
- | onFocus | callback(TFormValues,TComponent, TField) | Will be called when any field focused change. The arguments will let you know which field focused and the field configuration |
117
- | onFieldMount | callback(TFormValues,TComponent, TField) | Will be called when some field mounted. Its called with the field that information that mounted. |
118
- | onStep | callback(TFormValues) | Called when a form step changed |
119
- | onLog | callback(TLoggingEvent) | Called on each log, if the logging is enabled |
120
- | onScopeChange | onScopeChange?(scope: TScope, namespace: string, key: string): void; | Called everything scope change with the changing information (namespace and key) and the changed scope |
121
- | onClick | onClick(TFormValues, TField) | Callback function that runs on each component click |
122
- | afterApiCall | afterApiCall(values: TFormValues, component?: TComponent, field?: TField) | Callback function that runs on each component after api call. |
123
- | onFieldRehydrate | onFieldRehydrate?(values: TFormValues, component: TComponent, field: TField): void | This callback is called whenever some form field was rehydrated |
124
- | renderLoading | renderLoading?(): ReactElement; | Component to render while the schema has not rendered |
125
- | onFormMount | onFormMount?(values: TFormValues): void; | Called when the form finished mounted |
126
- | formattedDataDefaults | Object | Some default data to fields when they are undefined |
127
- | submitOnValidOnly | boolean | Boolean indicating if form can be submitted even if it is invalid |
128
- | renderFieldWrapper | renderFieldWrapper(component: TComponent, children: ReactElement[]) | Function that allows to insert a wrapper in place of a component or wrapping the component |
425
+ | Prop | Type | Description |
426
+ | ----------------------------------- | ---------------------------------------------------------------------------------- | ------------ |
427
+ | [DEPRECIATED] disable | boolean | Disable all form inputs. It will use the default htm disable attribute |
428
+ | [DEPRECIATED] group | string | Form group identifier. Used be able to group several forms and then get data with useGroupForm. One will be generated as default if omitted |
429
+ | index | string | Form identified. One will be generated as default if omitted |
430
+ | [DEPRECIATED] hooks | THooks | Provide functions to run on certain life-cycle events |
431
+ | iVars | Object | One object with internal variables to be used in form with data binding |
432
+ | initialValues | Object | Object with form initial values that will map to a field. |
433
+ | Schema | TSchema | Form Schema |
434
+ | [DEPRECIATED] autoComplete | string | HTML autocomplete |
435
+ | className | string | Allow to style form |
436
+ | onSubmit | callback(TFormValues) | Will be called when there is a submit action in the form |
437
+ | onData | callback(TFormData) | Will be called when any field data change. The arguments will let you know which field changed and the field configuration |
438
+ | onBlur | callback(TFieldEvent) | Will be called when any field blured. The arguments will let you know which field blured and the field configuration |
439
+ | onFocus | callback(TFieldEvent) | Will be called when any field focused change. The arguments will let you know which field focused and the field configuration |
440
+ | onMount | callback(TFormValues,TComponent, TField) | Will be called when some field mounted. Its called with the field that information that mounted. |
441
+ | [DEPRECIATED] onStep | callback(TFormValues) | Called when a form step changed |
442
+ | [DEPRECIATED] onLog | callback(TLoggingEvent) | Called on each log, if the logging is enabled |
443
+ | [DEPRECIATED] onScopeChange | onScopeChange?(scope: TScope, namespace: string, key: string): void; | Called everything scope change with the changing information (namespace and key) and the changed scope |
444
+ | onClick | onClick(TFieldEvent) | Callback function that runs on each component click |
445
+ | onApiResponse | onApiResponse(TFieldEvent) | Callback function that runs on each component after api call. |
446
+ | [DEPRECIATED] onFieldRehydrate | onFieldRehydrate?(values: TFormValues, component: TComponent, field: TField): void | This callback is called whenever some form field was rehydrated |
447
+ | [DEPRECIATED] renderLoading | renderLoading?(): ReactElement; | Component to render while the schema has not rendered |
448
+ | [DEPRECIATED] onFormMount | onFormMount?(values: TFormValues): void; | Called when the form finished mounted |
449
+ | [DEPRECIATED] formattedDataDefaults | Object | Some default data to fields when they are undefined |
450
+ | [DEPRECIATED] submitOnValidOnly | boolean | Boolean indicating if form can be submitted even if it is invalid |
451
+ | [DEPRECIATED] renderFieldWrapper | renderFieldWrapper(component: TComponent, children: ReactElement[]) | Function that allows to insert a wrapper in place of a component or wrapping the component |
452
+ | onApiRequest | onApiRequest(TFieldEvent) | Callback function that runs when an api call starts |
453
+ | onChange | onFieldChange(TFieldEvent) | Callback function that runs on each component value changes
454
+ | onKeyDown | onKeyDown(TFieldEvent) | Callback function that runs on each key down event |
455
+ | onKeyUp | onKeyUp(TFieldEvent) | Callback function that runs on each key up event |
456
+ | onCleared | onCleared(TFieldEvent) | Callback function that runs on a value that has been changed by resetValues event |
457
+ | onUnmount | onUnmount(TFieldEvent) | Callback function that runs when a field is unmounted or hidden by a visibility condition rule (use with caution) |
458
+
129
459
 
130
460
  ### Example
131
461
 
@@ -135,233 +465,872 @@ A simple example of rendering a basic form
135
465
  <Form schema={schema} />
136
466
  ```
137
467
 
138
- ## React `useForm()`
468
+ <a id="submit-form"></a>
139
469
 
140
- Exposed hook that allows you to connect to any form by the formId in any part of the application, as long as you are inside the form context.
470
+ ## **Submit Form**
141
471
 
142
- ### Props
472
+ In order to submit a form you need to have a button with the prop type `submit` and set a callback function on `onSubmit` Form prop
473
+
474
+ ### Example:
475
+
476
+ ```typescript
477
+ const schema = {
478
+ index: 'form1',
479
+ components: [
480
+ {
481
+ name: 'firstName',
482
+ component: 'input',
483
+ props: {
484
+ label: 'first name',
485
+ },
486
+ },
487
+ {
488
+ name: 'lastName',
489
+ component: 'input',
490
+ props: {
491
+ label: 'lase name',
492
+ },
493
+ },
494
+ {
495
+ name: 'submitButton',
496
+ component: 'button',
497
+ props: {
498
+ type: 'submit',
499
+ text: 'submit form',
500
+ },
501
+ },
502
+ ],
503
+ };
504
+
505
+ const Comp = () => {
506
+ const handleSubmit = (payload: TFormValues<unknown>) => {
507
+ const values = payload.values;
143
508
 
144
- You can use the following arguments to tho hook
509
+ userService
510
+ .addNewUser(values)
511
+ .then((res) => {
512
+ router.push(`/plans?hash=${res.hash}`);
513
+ })
514
+ .catch((e) => {
515
+ logService.push(e);
516
+ router.push(`/errorPage`);
517
+ });
518
+ };
145
519
 
146
- | Prop | Type | Description |
147
- | -------- | --------------- | ------------------------------------------------------ |
148
- | id | string | The id of the form you want to connect to |
149
- | ids | array of string | A range of ids of the each form you want to connect to |
150
- | onValid | callback | Called whenever form validation changes |
151
- | onClick | callback | Called whenever field has clicked |
152
- | onData | callback | Called whenever data changes |
153
- | onSubmit | callback | Called whenever form is submitted |
520
+ return <Form schema={schema} onSubmit={handleSubmit} />;
521
+ };
522
+ ```
523
+
524
+ This is a sample on how to handle a form submission, you can adapt to any use case, and also set the `onSubmit` callback function on the `useForm` hook, but when you
525
+ have a `Form` component, it's preferable to set the `onSubmit` callback function onto the `Form` prop, the hook is preferrable to `asFormFieldBuilder` fields that doesn't
526
+ have a `Form` component and event callback functions needs to be setted
527
+
528
+ <a id="schema"></a>
529
+
530
+ ## **schema**
531
+
532
+ Schema is the structure of the form, it will contain the logic to be rendered and configurations of the fields to apply dynamic logic
154
533
 
155
- And it will provide you the following
534
+ | Prop | Type | Description |
535
+ | ----------------------------------------------------------------------------------------------------------- | ----------------------- | ----------------------------------------------------------------------- |
536
+ | [index](../../docs/form-engine-core/src/interfaces/schema/interfaces/IFormSchema.md#index) | string | unique form id to handle multiple form on form group |
537
+ | [action](../../docs/form-engine-core/src/interfaces/schema/interfaces/IFormSchema.md#action)? | string | WIP: HTML form native action property to handle native form submissions |
538
+ | [method](../../docs/form-engine-core/src/interfaces/schema/interfaces/IFormSchema.md#method)? | string | WIP: HTML form native method property to handle native form submissions |
539
+ | [config](../../docs/form-engine-core/src/interfaces/schema/interfaces/IFormSchema.md#config)? | TSchemaFormConfig | Optional configuration object to set api and events debounce time |
540
+ | [initialValues](../../docs/form-engine-core/src/interfaces/schema/interfaces/IFormSchema.md#initialvalues)? | Record<string, unknown> | initial values to be loaded on the form |
541
+ | [iVars](../../docs/form-engine-core/src/interfaces/schema/interfaces/IFormSchema.md#ivars)? | Record<string, unknown> | dynamic values that can be changed externally to be used onto the form |
542
+ | [components](../../docs/form-engine-core/src/interfaces/schema/interfaces/IFormSchema.md#components)? | IComponentSchema[] | components to be rendered defined on the mappers |
156
543
 
157
- | Prop | Type | Description |
158
- | ---------- | -------- | ----------------------------------------------------------------------------------------------- |
159
- | submitForm | function | Function that lets you call the submit on the form. After, the onSubmit callback will be called |
160
- | formData | function | Lets you get the most up-to-date form date |
544
+ this root configuration can be defined onto the `Form` component except the `components`
161
545
 
162
546
  ### Example
163
547
 
164
- In the following example `useForm` hooks are used to connect to multiple forms that are inside other components.
548
+ ```typescript
549
+ const schema: IFormSchema = {
550
+ index: 'form1',
551
+ components: [
552
+ {
553
+ component: 'input',
554
+ name: 'input1',
555
+ props: {
556
+ label: 'input1',
557
+ },
558
+ },
559
+ {
560
+ component: 'input',
561
+ name: 'input2',
562
+ props: {
563
+ label: 'input2',
564
+ },
565
+ },
566
+ ],
567
+ };
568
+ ```
165
569
 
166
- ```javascript
167
- const Comp = () => {
168
- const { submitForm: submitOne } = useForm({
169
- id: 'id1',
170
- onData: (data) => {},
171
- onSubmit: () => {},
172
- });
173
- const { submitForm: submitTwo } = useForm({
174
- id: 'id2',
175
- onData: (data) => {},
176
- onSubmit: () => {},
177
- });
178
-
179
- return (
180
- <>
181
- <button onClick={(() => submitOne())}>
182
- <button onClick={(() => submitTwo())}>
183
- </>
184
- );
185
- }
570
+ <a id="schema-components"></a>
571
+
572
+ ## **schema components**
573
+
574
+ Schema components contains the information of the component that will be rendered and the configurations he will exectute
575
+
576
+ | Prop | Type | Description |
577
+ | ------------------------------------------------------------------------------------------------------------------------------ | -------------------- | ------------------------------------------------------------------------------------------- |
578
+ | [component](../../docs/form-engine-core/src/interfaces/schema/interfaces/IComponentSchema.md#component) | string | component name defined on schema to render the correspondent component |
579
+ | [props](../../docs/form-engine-core/src/interfaces/schema/interfaces/IComponentSchema.md#props)? | TProps | props of the component ex: label |
580
+ | [name](../../docs/form-engine-core/src/interfaces/schema/interfaces/IComponentSchema.md#name) | string | unique id to identify the field onto form-engine |
581
+ | [nameToSubmit](../../docs/form-engine-core/src/interfaces/schema/interfaces/IComponentSchema.md#nametosubmit)? | string | dot notation to submit a custom path to the component value ex: 'person.profile.firstName' |
582
+ | [validations](../../docs/form-engine-core/src/interfaces/schema/interfaces/IComponentSchema.md#validations)? | TValidations | validations configuration described below |
583
+ | [api](../../docs/form-engine-core/src/interfaces/schema/interfaces/IComponentSchema.md#api)? | TApiEvent | api configuration described below |
584
+ | [visibilityConditions](../../docs/form-engine-core/src/interfaces/schema/interfaces/IComponentSchema.md#visibilityconditions)? | TVisibility[] | visibilityConditions configuration described below |
585
+ | [resetValues](../../docs/form-engine-core/src/interfaces/schema/interfaces/IComponentSchema.md#resetvalues)? | TResetValueMethods[] | resetValues configuration described below |
586
+ | [formatters](../../docs/form-engine-core/src/interfaces/schema/interfaces/IComponentSchema.md#formatters)? | TFormatters | formatters configuration described below |
587
+ | [masks](../../docs/form-engine-core/src/interfaces/schema/interfaces/IComponentSchema.md#masks)? | TMasks | masks configuration described below |
588
+ | [children](../../docs/form-engine-core/src/interfaces/schema/interfaces/IComponentSchema.md#children)? | IComponentSchema[] | nested components to be rendered (if the current parent component accepts child components) |
589
+
590
+ ### Example
186
591
 
187
- const CompOne = () => {
188
- return (
189
- <Form id="id1" {...}/>
190
- );
592
+ ```typescript
593
+ {
594
+ component: 'input',
595
+ name: 'input1',
596
+ props: {
597
+ label: 'input1',
598
+ },
599
+ nameToSubmit: 'person.profile.firstName',
600
+ validations: {
601
+ methods: {
602
+ required: true,
603
+ },
604
+ eventMessages: {
605
+ ON_FIELD_CHANGE: ['required'],
606
+ },
607
+ messages: {
608
+ required: 'Value is required',
609
+ },
610
+ },
611
+ api: {
612
+ defaultConfig: {
613
+ config: {
614
+ method: 'GET',
615
+ url: 'https://api.chucknorris.io/jokes/random',
616
+ resultPath: 'value',
617
+ },
618
+ events: ['ON_FIELD_MOUNT'],
619
+ },
620
+ },
621
+ visibilityConditions: [
622
+ {
623
+ validations: {
624
+ isNumber: true,
625
+ },
626
+ events: ['ON_FIELD_CHANGE'],
627
+ fields: ['input2'],
628
+ },
629
+ ],
630
+ resetValues: [{
631
+ validations: {
632
+ isNumber: true,
633
+ },
634
+ events: ['ON_FIELD_CHANGE'],
635
+ fields: ['input2'],
636
+ resettledValue: ['resettledValue from input1'],
637
+ }]
638
+ }
639
+ ```
640
+
641
+ Check the [TSDocs](../../docs/form-engine-core/src/interfaces/schema/interfaces/IComponentSchema.md) from `IComponentSchema` on form-engine-core
642
+
643
+ <a id="formatters"></a>
644
+
645
+ ## **formatters**
646
+
647
+ formatters are methods that will format the input inserted on any field, they will format a value, regardless the event type.
648
+
649
+ | Prop | Type | Description |
650
+ | ------------------------------------------------------------------------------------------------------------ | ------------------------- | ---------------------------------------------------------------------------------------------------------------- |
651
+ | [callback](../../docs/form-engine-core/src/types/schema/type-aliases/TFormatters.md#callback)? | (value) => void | Custom formatter callback function |
652
+ | [capitalize](../../docs/form-engine-core/src/types/schema/type-aliases/TFormatters.md#capitalize)? | boolean | Capitalize the value |
653
+ | [dotEvery3chars](../../docs/form-engine-core/src/types/schema/type-aliases/TFormatters.md#dotevery3chars)? | boolean | Add a dot every 3 characters |
654
+ | [gapsCreditCard](../../docs/form-engine-core/src/types/schema/type-aliases/TFormatters.md#gapscreditcard) | string[] | Gaps to insert in credit card numbers |
655
+ | [maxLength](../../docs/form-engine-core/src/types/schema/type-aliases/TFormatters.md#maxlength)? | number | Truncates the input value to a specified maximum length if necessary |
656
+ | [onlyFloatNumber](../../docs/form-engine-core/src/types/schema/type-aliases/TFormatters.md#onlyfloatnumber)? | TCurrencyMask | Allow only float numbers with specific precision and decimal |
657
+ | [onlyLetters](../../docs/form-engine-core/src/types/schema/type-aliases/TFormatters.md#onlyletters)? | boolean | Allow only letters |
658
+ | [onlyNumbers](../../docs/form-engine-core/src/types/schema/type-aliases/TFormatters.md#onlynumbers)? | boolean | Allow only numbers |
659
+ | [regex](../../docs/form-engine-core/src/types/schema/type-aliases/TFormatters.md#regex)? | string | Regular expression for formatting |
660
+ | [splitter](../../docs/form-engine-core/src/types/schema/type-aliases/TFormatters.md#splitter)? | TSplitterFormatterValue[] | Splitter values for formatting |
661
+ | [trim](../../docs/form-engine-core/src/types/schema/type-aliases/TFormatters.md#trim)? | boolean | Removes whitespace from both ends of this string and returns a new string, without modifying the original string |
662
+ | [uppercase](../../docs/form-engine-core/src/types/schema/type-aliases/TFormatters.md#uppercase)? | boolean | Convert the value to uppercase |
663
+
664
+ ### Avaliable formatters
665
+
666
+ Check the [TSDocs](../../docs/form-engine-core/src/types/schema/type-aliases/TFormatters.md) from `TFormatters` on form-engine-core
667
+
668
+ <a id="masks"></a>
669
+
670
+ ## **masks**
671
+
672
+ masks are methods that will format the input inserted on any field, they will show to the user a formatted value, but the submission value will be the original input of the user.
673
+
674
+ | Prop | Type | Description |
675
+ | --------------------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------ |
676
+ | [card](../../docs/form-engine-core/src/types/schema/type-aliases/TMasks.md#card)? | boolean | Mask for card values |
677
+ | [cardDate](../../docs/form-engine-core/src/types/schema/type-aliases/TMasks.md#carddate)? | boolean | Mask for card date values |
678
+ | [currency](../../docs/form-engine-core/src/types/schema/type-aliases/TMasks.md#currency)? | TCurrencyMask | Mask for currency values |
679
+ | [custom](../../docs/form-engine-core/src/types/schema/type-aliases/TMasks.md#custom) | string | Custom mask pattern |
680
+ | [fein](../../docs/form-engine-core/src/types/schema/type-aliases/TMasks.md#fein)? | boolean | Mask for FEIN (Federal Employer Identification Number) |
681
+ | [generic](../../docs/form-engine-core/src/types/schema/type-aliases/TMasks.md#generic)? | TMaskGeneric[] | Array of generic masks |
682
+ | [replaceAll](../../docs/form-engine-core/src/types/schema/type-aliases/TMasks.md#replaceall)? | string | Value to replace all matches |
683
+ | [secureCreditCard](../../docs/form-engine-core/src/types/schema/type-aliases/TMasks.md#securecreditcard)? | boolean | Mask for securing credit card values |
684
+ | [callback](../../docs/form-engine-core/src/types/schema/type-aliases/TMasks.md#callback)? | (value, masks) => void | Custom mask callback function |
685
+
686
+ ### Avaliable masks
687
+
688
+ Check the [TSDocs](../../docs/form-engine-core/src/types/schema/type-aliases/TMasks.md) from `TMasks` on form-engine-core
689
+
690
+ ### From v2 to v3
691
+
692
+ ```typescript
693
+ //v2
694
+ const formatters = {
695
+ ON_FIELD_MOUNT: {
696
+ upperCase: true,
697
+ },
698
+ ON_FIELD_CHANGE: {
699
+ upperCase: true,
700
+ },
701
+ };
702
+
703
+ //v3
704
+ const formatters = {
705
+ upperCase: true,
706
+ };
707
+ ```
708
+
709
+ <a id="nametosubmit"></a>
710
+
711
+ ## **nameToSubmit**
712
+
713
+ nameToSubmit is a component property that will set the submit value to a custom dot notation path or key
714
+
715
+ ### Example
716
+
717
+ ```typescript
718
+ const component = {
719
+ component: 'input'
720
+ name: 'input1'
721
+ nameToSubmit: 'person.profile.firstName'
722
+ }
723
+ ```
724
+
725
+ when calling the `onSubmit` or `onData` the field section of this field will output:
726
+
727
+ ```json
728
+ {
729
+ "person": {
730
+ "profile": {
731
+ "firstName": "inserted value from input1"
732
+ }
191
733
  }
734
+ }
735
+ ```
736
+
737
+ <a id="props"></a>
738
+
739
+ ## **props**
192
740
 
193
- const CompTwo = () => {
194
- return (
195
- <Form id="id2" {...} />
196
- );
741
+ props let you add any prop the component you are using from the mappers that exists on the component
742
+
743
+ ### Example
744
+
745
+ ```typescript
746
+ const component = {
747
+ component: 'input'
748
+ name: 'input1'
749
+ props: {
750
+ label: 'input1 label'
197
751
  }
752
+ }
198
753
  ```
199
754
 
200
- ## React `useFormGroup()`
755
+ If the mapper of `input` has the `label` prop avaliable, it will be set with `input1 label` value
201
756
 
202
- Similar to `useForm`
757
+ <a id="validations"></a>
203
758
 
204
- ### Props
759
+ ## **validations**
205
760
 
206
- You can use the following arguments to tho hook
761
+ validations let you set rules in order to validate a field, then show errorMessages based on an event occured
207
762
 
208
- | Prop | Type | Description |
209
- | -------- | --------------- | --------------------------------------------------------- |
210
- | ids | array of string | The ids we want to listen to |
211
- | group | string | A string to identify the form group we want to connect to |
212
- | onValid | callback | Called whenever form validation changes |
213
- | onClick | callback | Called whenever field has clicked |
214
- | onData | callback | Called whenever data changes |
215
- | onSubmit | callback | Called whenever form is submitted |
763
+ | Prop | Type | Description |
764
+ | -------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------- |
765
+ | methods | TSchemaValidation | validations rules to be used to validate the field |
766
+ | eventMessages? | Partial<Record<TEvents, Partial<keyof TValidationMethods>[]>> | object with the event occured, and the messages to display on the occured event |
767
+ | messages? | TErrorMessages | object with the validations and the respective error message to display |
216
768
 
217
- And it will provide you the following
769
+ ### Avaliable validations
218
770
 
219
- | Prop | Type | Description |
220
- | ---------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
221
- | submitForm | function | Function that lets you call the submit on the form. After, the onSubmit callback will be called |
222
- | formData | function({aggregate}) | Lets you get the most up-to-date form date in two ways. Aggregate the forms data in a single object or split by the several forms in the group or identified by the id |
771
+ Check the [TSDocs](../../docs/form-engine-core/src/types/schema/type-aliases/TValidationMethods.md) from `TValidationMethods` on form-engine-core
223
772
 
224
- ### Example
773
+ ### From v2 to v3
225
774
 
226
- In the following example `useForm` hooks are used to connect to multiple forms that are inside other components.
775
+ ```typescript
776
+ //v2
777
+ const component: {
778
+ component: 'input';
779
+ name: 'input1';
780
+ validations: {
781
+ ON_FIELD_BLUR: {
782
+ required: true;
783
+ };
784
+ ON_FIELD_CHANGE: {
785
+ regex: '^[0-9]{2}/[0-9]{2}$';
786
+ };
787
+ errorMessages: {
788
+ required: 'field required';
789
+ regex: 'invalid format';
790
+ };
791
+ };
792
+ };
227
793
 
228
- ```javascript
229
- useForm({
230
- onSubmit: () => {
231
- dispatch(
232
- formData({
233
- aggregate: true,
234
- }),
235
- );
794
+ //v3
795
+ const validations: {
796
+ methods: {
797
+ required: true;
798
+ regex: '^[0-9]{2}/[0-9]{2}$';
799
+ };
800
+ eventMessages: {
801
+ ON_FIELD_BLUR: ['required'];
802
+ ON_FIELD_CHANGE: ['regex'];
803
+ };
804
+ messages: {
805
+ required: 'field required';
806
+ regex: 'invalid format';
807
+ };
808
+ };
809
+ ```
810
+
811
+ ### named validations
812
+
813
+ if you want to make a name validation, instead of using a `TValidationMethods`, you can write a custom name with `TValidationMethods` inside, ex:
814
+
815
+ ```typescript
816
+ const validations: {
817
+ methods: {
818
+ custom1: {
819
+ regex: '^[0-5]{4}/[0-3]{6}$';
820
+ };
821
+ custom2: {
822
+ regex: '^[0-9]{2}/[0-9]{2}$';
823
+ };
824
+ };
825
+ eventMessages: {
826
+ ON_FIELD_BLUR: ['custom1'];
827
+ ON_FIELD_CHANGE: ['custom2'];
828
+ };
829
+ messages: {
830
+ custom1: 'field required';
831
+ custom2: 'invalid format';
832
+ };
833
+ };
834
+ ```
835
+
836
+ This is useful if you want to make more than one rule of the same `TValidationMethods`,
837
+
838
+ ### default error message
839
+
840
+ If you don't want to specify each error message for each method, you can use `default`on `messages` property, this message will appear regardless the validation method
841
+ and only one method that will fail will display the message, you still need to set on `eventMessages` which events and methods will trigger an error message.
842
+
843
+ <a id="api"></a>
844
+
845
+ ## **api**
846
+
847
+ Api let's you make a request and use the response values onto fields
848
+
849
+ The configuration is as it follows:
850
+
851
+ | Prop | Type | Description |
852
+ | -------------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
853
+ | defaultConfig? | TEvent<TApiConfig> | this is the default config, preferred if you only have 1 API request on a field |
854
+ | configs? | Record<string, TEvent<TApiConfig>> | this is a named config, preferred if you have more than 1 API request on a field, you set a key and an API config |
855
+
856
+ Each config you opt to use, needs to be filled with an API configuration, the configuration is as it follows:
857
+
858
+ | Prop | Type | Description |
859
+ | --------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | ------------------------------------------------------------------------------------- |
860
+ | [method](../../docs/form-engine-core/src/types/schema/type-aliases/TApiConfig.md#method) | 'GET' or 'POST' | HTTP method (only GET or POST) |
861
+ | [url](../../docs/form-engine-core/src/types/schema/type-aliases/TApiConfig.md#url) | string | Request url ex: http://mockapi.org |
862
+ | [body](../../docs/form-engine-core/src/types/schema/type-aliases/TApiConfig.md#body)? | Record<string, unknown> | Request body (only POST requests) |
863
+ | [headers](../../docs/form-engine-core/src/types/schema/type-aliases/TApiConfig.md#headers)? | OutgoingHttpHeaders | Avaliable HTTP headers |
864
+ | [queryParams](../../docs/form-engine-core/src/types/schema/type-aliases/TApiConfig.md#queryparams)? | Record<string,string> | url query params (to be appended to the already existing ones) |
865
+ | [resultPath](../../docs/form-engine-core/src/types/schema/type-aliases/TApiConfig.md#resultpath)? | string | response dot notation path to the value needed from the response |
866
+ | [fallbackValue](../../docs/form-engine-core/src/types/schema/type-aliases/TApiConfig.md#fallbackvalue)? | unknown | default value to return if the API returns error |
867
+ | [preConditions](../../docs/form-engine-core/src/types/schema/type-aliases/TApiConfig.md#preconditions)? | TSchemaValidation | validations to occur before the request is made (check validations section) |
868
+ | [blockRequestWhenInvalid](../../docs/form-engine-core/src/types/schema/type-aliases/TApiConfig.md#blockrequestwheninvalid)? | boolean | flag to only request the api config if the field is valid |
869
+ | [transform](../../docs/form-engine-core/src/types/schema/type-aliases/TApiConfig.md#transform)? | { callback:(payload) => unknown } | custom function to be passed as callback to transform the request in any other format |
870
+
871
+ ### From v2 to v3
872
+
873
+ Instead of setting scope on the api config, you use a `config` with a key name that you want to use as scope, or you can just use `defaultConfig` and set the same
874
+ structure as you pass to the `config` without a key name
875
+
876
+ ```typescript
877
+ //v2
878
+ const api = {
879
+ ON_FIELD_BLUR: [
880
+ {
881
+ method: 'GET',
882
+ url: 'https://api.chucknorris.io/jokes/random',
883
+ scope: 'chuck',
236
884
  },
237
- id: 'main-form',
238
- });
239
- const { formData } = useFormGroup({
240
- onSubmit: (data) => {
241
- console.log('SUBMIT', data);
885
+ ],
886
+ ON_FIELD_CHANGE: [
887
+ {
888
+ method: 'GET',
889
+ url: 'https://api.chucknorris.io/jokes/random',
890
+ scope: 'chuck',
242
891
  },
243
- onData: (data) => {
244
- console.log('-> ', data);
892
+ ],
893
+ };
894
+
895
+ //v3
896
+ const api = {
897
+ config: {
898
+ chuck: {
899
+ config: {
900
+ method: 'GET',
901
+ url: 'https://api.chucknorris.io/jokes/random',
902
+ },
903
+ events: ['ON_FIELD_BLUR', 'ON_FIELD_CHANGE'],
245
904
  },
246
- group: 'logical',
247
- });
905
+ },
906
+ };
907
+ ```
248
908
 
249
- return (
250
- <Form
251
- id="1"
252
- group="logical"
253
- schema={...}
254
- />
255
- <Form
256
- id="2"
257
- group="logical"
258
- schema={...}
259
- />
260
- <Form
261
- id="main-form"
262
- schema={...}
263
- />
264
- )
909
+ the API result is commonly used with `templating`, check [templating](#templating) section
910
+
911
+ <a id="resetvalues"></a>
912
+
913
+ ## **resetValues**
914
+
915
+ resetValues lets you change input values with the same rules as validations
916
+
917
+ | Prop | Type | Description |
918
+ | --------------------------------------------------------------------------------------------- | -------------------- | ---------------------------------------------------------------------------------- |
919
+ | [validations](../../docs/form-engine-core/src/types/schema/type-aliases/TSchemaValidation.md) | TSchemaValidation | validations rules to be validated to reset the value to the configuration provided |
920
+ | fields | string[] or string | field or fields that will recieve the resettled value |
921
+ | events | Partial<TEvents>[] | events that will trigger the validation |
922
+ | resettledValue | unknown[] or unknown | value or values to be set on the specified fields |
923
+
924
+ if the event occurs and all the validations returns `true` the resettled value will trigger and the `fields` specified will be filled with the `resettledValue` values, also, the event ON_FIELD_CLEARED is triggered on the fields that gets the resettled value instead of ON_FIELD_CHANGE.
925
+
926
+ ### from v2 to v3
927
+
928
+ `clearFields` is changed to `resetValues`
929
+
930
+ ```typescript
931
+ //v2
932
+ const clearFields = {
933
+ ON_FIELD_CLICK: [
934
+ {
935
+ fields: ['input1', 'input2', 'dropdown'],
936
+ clearedValue: ['', 'Value has change', 'all'],
937
+ },
938
+ ],
939
+ ON_FIELD_BLUR: [
940
+ {
941
+ fields: ['input1', 'input2', 'dropdown'],
942
+ clearedValue: ['', 'Value has change', 'all'],
943
+ },
944
+ ],
945
+ };
946
+
947
+ //v3
948
+ const resetValues = [
949
+ {
950
+ fields: ['input1', 'input2', 'dropdown'],
951
+ resettledValue: ['', 'Value has change', 'all'],
952
+ events: ['ON_FIELD_CLICK', 'ON_FIELD_BLUR'],
953
+ },
954
+ ];
265
955
  ```
266
956
 
267
- The above example will connect to main-form with `useForm` and to a form group (logical) with `useFormGroup`
957
+ <a id="visibilityconditions"></a>
268
958
 
269
- ## React `asFormField()`
959
+ ## **visibilityConditions**
270
960
 
271
- Allows you to add separate components from a standard form engine form schema. Transforming it into a field on a standard form.
961
+ visibilityConditions will show or hide fields based on rules, the structure is similar as the resetValues, but instead, you will set the fields to be shown or hidden
272
962
 
273
- ### Props
963
+ | Prop | Type | Description |
964
+ | --------------- | ------------------ | ---------------------------------------------------------------------------------- |
965
+ | showOnlyIfTrue? | boolean | shows the fields specified is condition is true |
966
+ | validations | TSchemaValidation | validations rules to be validated to reset the value to the configuration provided |
967
+ | fields | string[] or string | field or fields that will be shown or hidden |
968
+ | events | Partial<TEvents>[] | events that will trigger the validation |
274
969
 
275
- You can use the following arguments declare a component as a form field
276
-
277
- | Prop | Type | Description |
278
- | ------------ | ------------------------ | -------------------------------------------------------------------------- |
279
- | Comp | React Function Component | The component to be used as form field. |
280
- | propsMapping | TComponentPropsMapping | Link for the TComponentPropsMapping likely props mapper from default form. |
281
-
282
- And this will give you the following properties in addition to the native ones of your component
283
-
284
- | Prop | Type | Description |
285
- | -------------------- | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
286
- | validations | TSchemaValidation | Setup validations to be used in the field. |
287
- | masks | TSchemaMasks | Allows you to display the value of the masked component by events |
288
- | clearFields | TSchemaClearFields | Will clear target fields in case they do not pass with the specified validations |
289
- | api | TSchemaApi | Allows you to make api calls using events emitted by the component. |
290
- | errorMessages | TErrorMessages | Field error messages in case any validation fails |
291
- | filter | TSchemaValidation | Filters the component value based on a validation. |
292
- | formatters | TSchemaFormatters | Allows you to format the value that the field will receive for each event issuance |
293
- | visibilityConditions | TSchemaVisibilityConditions | Allows you to specify the conditions a given field will be visible what will run when this field meets the specified life-cycle |
294
- | formId | string | Form id that you need to create and integrate the field. |
295
- | visibility | boolean | It's a prop that you can use to hide the component and control this state outside the component. |
296
- | name | string | Name of the component similar to name prop name on TComponent type. This name will be used later to correlate the field with the value, and you will be able to read it. |
297
- | value | any | The value of the field that you can control outside the component. |
298
- | disabled | boolean | The disabled of the field that you can control outside the component. |
299
- | optionList | any[] | The optionList of the field that you can control outside the component. This optionList will be used to manipulated a list of elements. For example, Dropdown optionList. |
300
- | onSelected | void | The onSelected of the field you can control outside the component by calling a custom function. onSelected makes the data available (TField) for manipulation. It is called when you mount and rehydrate the component at the first moment. Also, it is called every time the component changes (onChange). |
970
+ ### From v2 to v3
301
971
 
302
- ### Example
972
+ ```typescript
973
+ //v2
974
+ const visibilityConditions = {
975
+ ON_FIELD_MOUNT: [
976
+ {
977
+ validations: {
978
+ value: true,
979
+ },
980
+ fieldNames: ['roofUpdatedYear'],
981
+ },
982
+ ],
983
+ ON_FIELD_CHANGE: [
984
+ {
985
+ validations: {
986
+ value: true,
987
+ },
988
+ fieldNames: ['roofUpdatedYear'],
989
+ },
990
+ ],
991
+ };
992
+
993
+ //v3
994
+ const visibilityConditions = [
995
+ {
996
+ validations: {
997
+ value: true,
998
+ },
999
+ fields: 'roofUpdatedYear',
1000
+ events: ['ON_FIELD_MOUNT', 'ON_FIELD_CHANGE'],
1001
+ },
1002
+ ];
1003
+ ```
1004
+
1005
+ <a id="resetpropertyvalues"></a>
1006
+
1007
+ ## **resetPropertyValues**
1008
+
1009
+ resetPropertyValues will change a property value based on validation rules
1010
+
1011
+ > WARNING: do not rely on this to make mutations on your properties, templating already is a powerful tool and with this you can destroy some schema configurations accidentaly, this is a last resort schema manipulation tool to solve some edge cases with API requests callbacks handling
1012
+
1013
+ | Prop | Type | Description |
1014
+ | -------------- | -------------------------------------------- | -------------------------------------------------------------- |
1015
+ | property | typeof ALLOWED_RESET_PROPS_MUTATIONS[number] | property to be changed, ex: api, resetValues, etc.. |
1016
+ | path | string | path where the property to be changed is located |
1017
+ | field | string | field that will recieve the property change |
1018
+ | resettledValue | unknown | value to be replaced onto the property |
1019
+ | validations | TSchemaValidation | validations rules to be validated to change the property value |
1020
+ | events | Partial<TEvents>[] | events to listen to apply this change |
1021
+
1022
+ example:
1023
+
1024
+ this will change the `api.named.chuck` property onto field `postalCode` when the `ON_FIELD_CHANGE` event occurs,
1025
+ will change the content to: `{ status: null, response: ''}`
1026
+
1027
+ ```typescript
1028
+ resetPropertyValues: [
1029
+ {
1030
+ property: 'api',
1031
+ path: 'named.chuck',
1032
+ events: ['ON_FIELD_CHANGE'],
1033
+ field: 'postalCode',
1034
+ resettledValue: {
1035
+ status: null,
1036
+ response: '',
1037
+ },
1038
+ validations: {
1039
+ bool: false,
1040
+ },
1041
+ },
1042
+ ];
1043
+ ```
1044
+
1045
+ <a id="visibility"></a>
1046
+
1047
+ ## **visibility**
1048
+
1049
+ visibility prop is used to initiate the component with an initial visibility flag, before visibilityConditions take place, used on SSR
1050
+
1051
+ <a id="persistValue"></a>
1052
+
1053
+ ## **persistValue**
1054
+
1055
+ persistValue is a flag that deremines if the field gets hidden, the moment it comes back visible, it will hold the previous value or not
1056
+
1057
+ <a id="templating"></a>
1058
+
1059
+ ## **templating**
1060
+
1061
+ templating let's you use field properties or iVars as values of other properties
1062
+
1063
+ Templates separates on two scopes:
1064
+
1065
+ | Scope | Description |
1066
+ | ------ | --------------------------- |
1067
+ | fields | any property from a field |
1068
+ | iVars | any iVar passed to the form |
1069
+
1070
+ ### From v2 to v3
1071
+
1072
+ getting an iVar in v2:
1073
+ `${globals.ivarsample}`
1074
+
1075
+ getting an iVar in v3:
1076
+ `${iVars.ivarsample}`
1077
+
1078
+ **api scope now doesn't exist and the api response will be taken from the field**
1079
+
1080
+ getting api response from field `field1` in v2:
1081
+ `${api.chuck.value}`
303
1082
 
304
- In the following example `asFormField` hooks are used to create `Component` field into a stateful form `test`.
1083
+ getting api response from field `field1` in v3:
1084
+ `${fields.field1.api.chuck.response.value}`
1085
+
1086
+ ### Examples:
1087
+
1088
+ Templates start with the `scope` term, are defined with `${}` syntax and use dot notation to get the property you want,
1089
+
1090
+ Examples:
1091
+
1092
+ `${fields.field1.value}` this will get the current value of a field
1093
+
1094
+ `${fields.field1.api.default.response||[]}` this will get the response of a field api or an empty array
1095
+
1096
+ `${fields.field1.props.label}` this will get the label prop defined on the component schema prop
1097
+
1098
+ `${fields.field1.props.label||fields.field1.props.description}` this will get the `label` OR `description` defined on the component schema props
1099
+
1100
+ `${fields.field1.props.label} and ${fields.field1.props.description}` this will concatenate `label` AND `description` defined on the component schema props in a string
1101
+
1102
+ <a id="hooks"></a>
1103
+
1104
+ ## **hooks**
1105
+
1106
+ <a id="useform"></a>
1107
+
1108
+ ## **useForm**
1109
+
1110
+ `useForm` is used to register callback functions instead of passing them to the `Form` props,
305
1111
 
306
1112
  ```javascript
307
- {
308
- const FormComponent =
309
- asFormField <
310
- React.ComponentProps <
311
- typeof Component >>
312
- {
313
- Comp: Component,
314
- propsMapping: propsMapping.component,
315
- };
316
-
317
- <FormProvider mapper={Mappings} propsMapping={formBuilderPropsMapping}>
318
- <FormComponent
319
- formId="test"
320
- label="Field example"
321
- name="ss"
322
- filter={{ maxLength: 10 }}
323
- masks={{
324
- ON_FIELD_FOCUS: { cleanMask: true },
325
- ON_FIELD_BLUR: {
326
- generic: [
327
- {
328
- from: 1,
329
- to: 2,
330
- mask: 'X',
331
- },
332
- {
333
- from: 4,
334
- to: 5,
335
- mask: 'X',
336
- },
337
- ],
338
- },
339
- }}
340
- formatters={{
341
- ON_FIELD_CHANGE: {
342
- splitter: [
343
- {
344
- position: 2,
345
- value: '/',
346
- },
347
- {
348
- position: 5,
349
- value: '/',
350
- },
351
- ],
352
- },
353
- }}
354
- validations={{
355
- ON_FIELD_BLUR: {
356
- callback: (data) => {
357
- return {
358
- fail: data === '10/10/1000',
359
- };
360
- },
361
- },
1113
+ useForm({ id: 'form1', onData: (data) => console.log(data) });
1114
+
1115
+ return <Form index={'form1'} schema={schema}>
1116
+ ```
1117
+
1118
+ Each time a data event occurs, the callback function passed on `onData` executes, allowing to run additional code outside the form-engine lifecycle
1119
+
1120
+ Also, there's an additional property to be passed on this hook in order to event record occurs on certain scenarios
1121
+
1122
+ ```javascript
1123
+ useForm({ id: 'form1', onData: (data) => console.log(data) },[visible]);
1124
+
1125
+ return visible && <Form index={'form1'} schema={schema}>
1126
+ ```
1127
+
1128
+ If you happen to have a conditional form render inside the react jsx implementation, you need to add it to the dependency array, or, if you can pass
1129
+ the respective callback to the form props like this:
1130
+
1131
+ ```javascript
1132
+ <Form index={'form1'} schema={schema} onData={(data) => console.log(data)} />
1133
+ ```
1134
+
1135
+ The avalialbe callback methods are:
1136
+
1137
+ | method | payload | description |
1138
+ | ------------- | ---------------------- | -------------------------------------------------------------------- |
1139
+ | onChange | TFieldEvent | basic event returning this type if this event occurs, (check TSDocs) |
1140
+ | onBlur | TFieldEvent | same as above |
1141
+ | onFocus | TFieldEvent | same as above |
1142
+ | onKeyDown | TFieldEvent | same as above |
1143
+ | onKeyUp | TFieldEvent | same as above |
1144
+ | onClick | TFieldEvent | same as above |
1145
+ | onApiResponse | TFieldEvent | event occuring when a api response is ready |
1146
+ | onApiRequest | TFieldEvent | event occuring when a api resquest is started |
1147
+ | onMount | TFieldEvent | event occuring when a field is mounted or set visible |
1148
+ | onUnmount | TFieldEvent | event occuring when a field is unmounted or hidden |
1149
+ | onCleared | TFieldEvent | event occuring when the field value is set with resetValues |
1150
+ | onFormMount | TFormValues<T> | event occuring on form mount |
1151
+ | onData | TFormData<T> | event occuring when a value is changing via input or logic |
1152
+ | onSubmit | TFormValues<T> | event occuring when pressing the submit button defined on the form |
1153
+ | onValid | TFormValidationPayload | event occuring when validation status changes on the form |
1154
+
1155
+ <a id="useformgroup"></a>
1156
+
1157
+ ## **useFormGroup**
1158
+
1159
+ ```javascript
1160
+ useFormGroup({ ids: ['form1', 'form2'], onData: (payload) => console.log(payload) }, [deps]);
1161
+ ```
1162
+
1163
+ As `useForm`, `useFormGroup` serves the same purpose, but the difference is that it handles multiple forms and has limited callback functions to set:
1164
+
1165
+ | method | payload | description |
1166
+ | -------- | --------------------------------- | ----------------------------------------------------------- |
1167
+ | onData | TFormGroupOnDataEventPayload<T> | event occurring when a value is changing via input or logic |
1168
+ | onValid | TFormGroupOnValidEventPayload | event occurring when validation status changes on the form |
1169
+ | onSubmit | TFormGroupOnSubmitEventPayload<T> | event occurring when form submission is trigger |
1170
+
1171
+ <a id="asformfield"></a>
1172
+
1173
+ ## **asFormField**
1174
+
1175
+ Currently on development process, allows to build a schema with react components instead of a json schema
1176
+
1177
+ <a id="asformfieldbuilder"></a>
1178
+
1179
+ ## **AsFormFieldBuilder**
1180
+
1181
+ This component allows to create form fields with the functionality of form-engine without a form schema or a `Form` component,
1182
+ they will be identified by it's `id` on the formGroup context and they will interact with each other by the same id.
1183
+
1184
+ Also, they don't require component mapping, so the component mapping can be done on this component by passing the mapper by it's props:
1185
+
1186
+ Ex:
1187
+
1188
+ ```javascript
1189
+ <AsFormFieldBuilder
1190
+ mapper={{
1191
+ component: Input,
1192
+ events: {
1193
+ getValue: 'onChange',
1194
+ setValue: 'value',
1195
+ setErrorMessage: 'errorMessage',
1196
+ onBlur: 'onBlur',
1197
+ onFocus: 'onFocus',
1198
+ },
1199
+ valueChangeEvent: (event: unknown) => {
1200
+ return (event as ChangeEvent<HTMLInputElement>).target.value;
1201
+ }
1202
+ }}
1203
+ props={{
1204
+ label: 'Input label',
1205
+ }}
1206
+ formIndex={'form1'}
1207
+ name={'asFormField'}
1208
+ validations={{
1209
+ methods: {
1210
+ required: true,
1211
+ },
1212
+ eventMessages: {
1213
+ ON_FIELD_CHANGE: ['required'],
1214
+ },
1215
+ messages: {
1216
+ required: 'its required',
1217
+ },
1218
+ }}
1219
+ ></AsFormFieldBuilder>
1220
+ ```
1221
+
1222
+ Other than schema component properties like `validations`, `api`, etc.., it has additional properties to define the component, the associated form id and the name
1223
+
1224
+ | method | type | description |
1225
+ | --------- | ---------- | ------------------------------------------------------------------------------------------------------------------------ |
1226
+ | mapper | TMapper<T> | mapper configuration to define the component |
1227
+ | name | string | field name to be identified on the form |
1228
+ | formIndex | string | index of the form to be identified on the formGroup |
1229
+ | component | string | if mappers is provided from the formgroup context, you can assign the mapper by it's name instead of whole mapper config |
1230
+
1231
+ <a id="asformfieldrepeater"></a>
1232
+
1233
+ ## **AsFormFieldRepeater**
1234
+
1235
+ Component adapter to aid managing multiple forms that shares the same inputs
1236
+
1237
+ Props:
1238
+
1239
+ | Attr | Type | Description |
1240
+ | ----------------- | --------------------------------------------------------- | -------------------------------------------------------------------------- |
1241
+ | RepeaterComponent | ElementType<{ formIndex: string }> | Component with form schema or AsFormFieldBuilder elements |
1242
+ | addFieldName | string | name of the button in the RepeaterComponent to add forms |
1243
+ | removeFieldName | string | name of the button in the RepeaterComponent to remove forms |
1244
+ | existingElements | Record<string, unknown>[] | existing values emmitted from stateUpdater to restore previous used values |
1245
+ | initialElements | number | elements to be pre-rendered when the form is presented |
1246
+ | stateUpdater | (payload: TFormGroupOnDataEventPayload<unknown>) => void; | callback function that reacts to RepeaterComponet values changes |
1247
+ | formPrefix | string | prefix for form names ex, prefix: foo, forms: ["foo1","foo2","foo3"] |
1248
+ | RepeaterFooter | ElementType<{ formIndex: string }> | Component with a button to add forms on the last position |
1249
+
1250
+ Common use case for this Adapter is to manage multiple forms that collects the same data ex: multiple person personal data
1251
+
1252
+ # Example
1253
+
1254
+ ## RepeaterComponent
1255
+
1256
+ ```javascript
1257
+ const FormElement = ({ formIndex }: { formIndex: string }) => {
1258
+ return (
1259
+ <>
1260
+ <AsFormFieldBuilder formIndex={formIndex} name="foo" component="input" props={{ label: 'foo' }} />
1261
+ <AsFormFieldBuilder formIndex={formIndex} name="bar" component="input" props={{ label: 'bar' }} />
1262
+ <AsFormFieldBuilder
1263
+ formIndex={formIndex}
1264
+ name="addForm"
1265
+ component="button"
1266
+ props={{
1267
+ text: 'add element',
1268
+ }}
1269
+ />
1270
+ <AsFormFieldBuilder
1271
+ formIndex={formIndex}
1272
+ name="removeForm"
1273
+ component="button"
1274
+ props={{
1275
+ text: 'remove element',
1276
+ }}
1277
+ />
1278
+ </>
1279
+ );
1280
+ };
1281
+ ```
1282
+
1283
+ Important notes when developing this component is that it needs to receive an object with a key **formIndex**
1284
+
1285
+ Optionally, but to add form management functionality, add two buttons with **ON_FIELD_CLICK** event capture (can't be of type submit)
1286
+ both that Field button names will be needed on the next step
1287
+
1288
+ ## RepeaterFooter
1289
+
1290
+ Optionally, you can develop a footer component with a button that will be added the bottom of the repeated forms
1291
+ and when you press that button will add a form at the bottom of the list
1292
+
1293
+ It's props needs to be an objet with a **formIndex** key, the button needs to have **ON_FIELD_CLICK** event capture (can't be of type submit)
1294
+ Note: the button name needs to be different from the names you gave to the buttons you are passing on the RepeaterComponent
1295
+
1296
+ ```javascript
1297
+ const FormElementFooter = ({ formIndex }: { formIndex: string }) => {
1298
+ return (
1299
+ <AsFormFieldBuilder
1300
+ formIndex={formIndex}
1301
+ name="addFormBelow"
1302
+ component="button"
1303
+ props={{
1304
+ text: 'add element below',
362
1305
  }}
363
- errorMessages={{ default: 'ERRRO' }}
364
1306
  />
365
- </FormProvider>;
366
- }
1307
+ );
1308
+ };
367
1309
  ```
1310
+
1311
+ ## AsFormFieldRepeater
1312
+
1313
+ Set the AsFormFieldRepeater adapter with the element you created above and the names that you gave to the button fields
1314
+
1315
+ ```javascript
1316
+ <AsFormFieldRepeater
1317
+ RepeaterComponent={FormElement}
1318
+ RepeaterFooter={FormElementFooter}
1319
+ addFieldName="addForm"
1320
+ removeFieldName="removeForm"
1321
+ formPrefix="insured"
1322
+ stateUpdater={(payload) => {
1323
+ console.log(payload);
1324
+ }}
1325
+ />
1326
+ ```
1327
+
1328
+ **RepeaterComponent** and **RepeaterFooter** you set the elements created above
1329
+
1330
+ **addFieldName** you set the name to the button that will add a form on the position it's being clicked
1331
+
1332
+ **removeFieldName** you set the name to the button that will remove a form on the position it's being clicked
1333
+
1334
+ **formPrefix** the prefix for the forms emmited on **stateUpdater** enumerated
1335
+
1336
+ **stateUpdater** callback function that will receive the form values (similar to onData)