@bolttech/form-engine 3.0.0-beta.16 → 3.0.0-beta.17
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 +264 -212
- package/index.esm.js +131 -25
- package/package.json +2 -2
- package/src/components/AsFormField/AsFormField.d.ts +12 -3
- package/src/components/AsFormField/AsFormField.type.d.ts +9 -0
- package/src/components/AsFormFieldBuilder/AsFormFieldBuilder.d.ts +10 -6
- package/src/components/AsFormFieldBuilder/AsFormFieldBuilder.type.d.ts +16 -0
- package/src/components/FieldWrapper/FieldWrapper.d.ts +10 -8
- package/src/components/FieldWrapper/FieldWrapper.type.d.ts +28 -0
- package/src/components/Form/Form.d.ts +8 -4
- package/src/components/Form/Form.type.d.ts +11 -0
- package/src/context/FormGroupContext.d.ts +15 -26
- package/src/context/FormGroupContext.type.d.ts +46 -0
- package/src/generators/formBuilder.d.ts +15 -0
- package/src/helpers/helpers.d.ts +5 -2
- package/src/hooks/useForm.d.ts +5 -5
- package/src/hooks/useForm.type.d.ts +12 -0
- package/src/types/index.d.ts +12 -38
package/README.md
CHANGED
|
@@ -1,56 +1,128 @@
|
|
|
1
1
|
# Form Engine React Adapter
|
|
2
2
|
|
|
3
|
-
This is
|
|
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 `<
|
|
5
|
+
## React `<FormGroupContextProvider />`
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Provider of the context surrounding the child components, providing the state and functions to manage the group of forms.
|
|
8
8
|
|
|
9
9
|
### Props
|
|
10
10
|
|
|
11
|
-
| Prop
|
|
12
|
-
|
|
|
13
|
-
|
|
|
14
|
-
|
|
|
11
|
+
| Prop | Type | Description |
|
|
12
|
+
| --------- | ---------------------- | ------------------------------------------------------------------------------------------------------ |
|
|
13
|
+
| mappers | TMapper<ElementType>[] | Array of mappers for form element types. Allow you to map your own components to be used with the form |
|
|
14
|
+
| debugMode | boolean | Optional flag to enable debug mode (default: `false`). |
|
|
15
|
+
|
|
16
|
+
### Implementation
|
|
17
|
+
|
|
18
|
+
- Creates a reference to the form group instance.
|
|
19
|
+
- Defines functions for adding, getting, and removing forms from the group.
|
|
20
|
+
- Defines a function to print the form group instance.
|
|
21
|
+
- Defines a function to submit multiple forms via the index.
|
|
22
|
+
- Defines the value of the context with the created functions and states.
|
|
23
|
+
- Returns the context provider involving the child components.
|
|
15
24
|
|
|
16
25
|
### Example
|
|
17
26
|
|
|
18
27
|
The following example shows a provider that will provide forms with input and Dropdown component
|
|
19
28
|
|
|
20
|
-
|
|
21
|
-
import Input from 'Components/Input';
|
|
22
|
-
import Dropdown from 'Components/Dropdown';
|
|
29
|
+
#### With lazy import
|
|
23
30
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
31
|
+
```typescript
|
|
32
|
+
import { ElementType, SyntheticEvent } from 'react';
|
|
33
|
+
import { TValueChangeEvent, TMapper } from '@bolttech/form-engine-core';
|
|
34
|
+
|
|
35
|
+
const defaultChangeEvent: TValueChangeEvent = (event: unknown) => {
|
|
36
|
+
return (event as SyntheticEvent<HTMLInputElement>).currentTarget.value;
|
|
27
37
|
};
|
|
28
38
|
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
39
|
+
const pathImports = {
|
|
40
|
+
input: lazy(() =>
|
|
41
|
+
import('@bolttech/atoms-input').then((module) => ({
|
|
42
|
+
default: module.Input,
|
|
43
|
+
}))
|
|
44
|
+
),
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const mappers: TMapper<ElementType>[] = [
|
|
48
|
+
{
|
|
49
|
+
asynccomponent: pathImports.input,
|
|
50
|
+
componentName: 'input',
|
|
51
|
+
events: {
|
|
52
|
+
getValue: 'onChange',
|
|
53
|
+
setValue: 'value',
|
|
54
|
+
setErrorMessage: 'errorMessage',
|
|
55
|
+
onBlur: 'onBlur',
|
|
56
|
+
onFocus: 'onFocus',
|
|
57
|
+
onKeyUp: 'onKeyUp',
|
|
58
|
+
onKeyDown: 'onKeyUpCapture',
|
|
59
|
+
},
|
|
60
|
+
valueChangeEvent: defaultChangeEvent,
|
|
33
61
|
},
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
62
|
+
];
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
#### Without lazy import
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import { ElementType, SyntheticEvent } from 'react';
|
|
69
|
+
import { TValueChangeEvent, TMapper } from '@bolttech/form-engine-core';
|
|
70
|
+
import { OptionType } from '@bolttech/atoms-select';
|
|
71
|
+
import { Dropdown } from '@bolttech/molecules-dropdown';
|
|
72
|
+
|
|
73
|
+
const mappers: TMapper<ElementType>[] = [
|
|
74
|
+
{
|
|
75
|
+
component: Dropdown,
|
|
76
|
+
componentName: 'dropdown',
|
|
77
|
+
events: {
|
|
78
|
+
getValue: 'onChange',
|
|
79
|
+
setValue: 'value',
|
|
80
|
+
setErrorMessage: 'errorMessage',
|
|
81
|
+
},
|
|
82
|
+
valueChangeEvent: (event: unknown, opts) => {
|
|
83
|
+
if (typeof event === 'object' && event !== null && 'value' in event && 'id' in event) {
|
|
84
|
+
return {
|
|
85
|
+
_value: event?.id,
|
|
86
|
+
_metadata: event,
|
|
87
|
+
};
|
|
88
|
+
} else if (typeof event === 'string' && typeof opts === 'object' && 'props' in opts && typeof opts.props === 'object' && 'optionList' in opts.props && Array.isArray(opts.props.optionList)) {
|
|
89
|
+
const option = (opts.props.optionList as OptionType[]).find((el) => el?.value === event);
|
|
90
|
+
if (option) return { _value: option.id, _metadata: option };
|
|
91
|
+
} else return { _value: event, _metadata: event };
|
|
92
|
+
},
|
|
43
93
|
},
|
|
94
|
+
];
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The codes above are created using the `valueChangeEvent` method, which is a new way of controlling how the field value will be manipulated when setValue happens. In other words: Optional function to handle value changes.
|
|
98
|
+
|
|
99
|
+
#### Calling provider
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
import React from 'react';
|
|
103
|
+
import { FormGroupContextProvider } from '@bolttech/form-engine'; // Import the previously created provider
|
|
104
|
+
|
|
105
|
+
type Props = {
|
|
106
|
+
children: React.ReactNode;
|
|
44
107
|
};
|
|
45
108
|
|
|
46
|
-
const App = () => {
|
|
47
|
-
|
|
109
|
+
const App = ({ children }: Props): React.ReactElement => {
|
|
110
|
+
const mappers = []; // Define your type mappers here
|
|
111
|
+
const debugMode = true; // Enable debug mode
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
<FormGroupContextProvider mappers={mappers} debugMode={debugMode}>
|
|
115
|
+
{children}
|
|
116
|
+
</FormGroupContextProvider>
|
|
117
|
+
);
|
|
48
118
|
};
|
|
119
|
+
|
|
120
|
+
export default App;
|
|
49
121
|
```
|
|
50
122
|
|
|
51
|
-
You now can use in your [form](#react-form-) the mapped components with names `
|
|
123
|
+
You now can use in your [form](#react-form-) the mapped components with names `input` and `dropdown`.
|
|
52
124
|
|
|
53
|
-
Also note the data in `
|
|
125
|
+
Also note the data in `TMapper.events`. There you can map up to five form functionalities per component
|
|
54
126
|
|
|
55
127
|
| Key | Functionality |
|
|
56
128
|
| --------------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -63,7 +135,7 @@ Also note the data in `propsMapping`. There you can map up to five form function
|
|
|
63
135
|
| onKeyUp | Prop name that is called when user releases a key on field |
|
|
64
136
|
| onKeyDown | Prop name that is called when user presses a key on field |
|
|
65
137
|
|
|
66
|
-
You can also use default prop names for functionalities like:
|
|
138
|
+
[DEPRECIATED] You can also use default prop names for functionalities like:
|
|
67
139
|
|
|
68
140
|
```javascript
|
|
69
141
|
import Input from 'Components/Input';
|
|
@@ -91,180 +163,131 @@ const App = () => {
|
|
|
91
163
|
};
|
|
92
164
|
```
|
|
93
165
|
|
|
94
|
-
This will make form search for those names in all your components that do not have split mapping.
|
|
166
|
+
[DEPRECIATED] This will make form search for those names in all your components that do not have split mapping.
|
|
95
167
|
|
|
96
|
-
## React
|
|
168
|
+
## React `useFormGroupContext()` hook
|
|
97
169
|
|
|
98
|
-
|
|
170
|
+
Hook that facilitates the use of the FormGroupContext context in functional components.
|
|
99
171
|
|
|
100
|
-
|
|
172
|
+
- Checks if the context is set and throws an error if not.
|
|
173
|
+
- Returns the context.
|
|
101
174
|
|
|
102
|
-
|
|
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 |
|
|
175
|
+
### What comes from
|
|
129
176
|
|
|
130
|
-
|
|
177
|
+
- `addForm`: Function to add a form to the group.
|
|
178
|
+
- `getForm`: Function to obtain a specific form from the group.
|
|
179
|
+
- `removeForm`: Function to remove a form from the group.
|
|
180
|
+
- `formGroupInstance`: Instance of the form group.
|
|
181
|
+
- `printFormGroupInstance`: Function to print the form group instance.
|
|
182
|
+
- `submitMultipleFormsByIndex`: Function to submit multiple forms by index.
|
|
131
183
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
184
|
+
```typescript
|
|
185
|
+
type TFormContext = {
|
|
186
|
+
addForm: (payload: { key: string; formInstance: TFormCore }) => void;
|
|
187
|
+
getForm: (payload: { key: string }) => FormCore | undefined;
|
|
188
|
+
removeForm: (payload: { key: string }) => void;
|
|
189
|
+
formGroupInstance: TFormGroup;
|
|
190
|
+
printFormGroupInstance: () => void;
|
|
191
|
+
submitMultipleFormsByIndex: (indexes: string[]) => TFormValues;
|
|
192
|
+
};
|
|
136
193
|
```
|
|
137
194
|
|
|
138
|
-
|
|
139
|
-
|
|
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.
|
|
195
|
+
### Example
|
|
141
196
|
|
|
142
|
-
|
|
197
|
+
```typescript
|
|
198
|
+
import React from 'react';
|
|
199
|
+
import { useFormGroupContext } from '@bolttech/form-engine'; // Import the previously created hook
|
|
143
200
|
|
|
144
|
-
|
|
201
|
+
const FormComponent = (): React.ReactElement => {
|
|
202
|
+
const { addForm, removeForm, getForm, printFormGroupInstance, submitMultipleFormsByIndex, debugMode } = useFormGroupContext();
|
|
145
203
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
| onClick | callback | Called whenever field has clicked |
|
|
152
|
-
| onData | callback | Called whenever data changes |
|
|
153
|
-
| onSubmit | callback | Called whenever form is submitted |
|
|
204
|
+
const handleAddForm = () => {
|
|
205
|
+
const key = 'form1';
|
|
206
|
+
const formInstance = new FormCore(); // Assuming FormCore is an existing class
|
|
207
|
+
addForm({ key, formInstance });
|
|
208
|
+
};
|
|
154
209
|
|
|
155
|
-
|
|
210
|
+
const handleRemoveForm = () => {
|
|
211
|
+
const key = 'form1';
|
|
212
|
+
removeForm({ key });
|
|
213
|
+
};
|
|
156
214
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
215
|
+
const handleGetForm = () => {
|
|
216
|
+
const key = 'form1';
|
|
217
|
+
const form = getForm({ key });
|
|
218
|
+
console.log(form);
|
|
219
|
+
};
|
|
161
220
|
|
|
162
|
-
|
|
221
|
+
const handleSubmitForms = () => {
|
|
222
|
+
const indexes = ['form1', 'form2'];
|
|
223
|
+
const formValues = submitMultipleFormsByIndex(indexes);
|
|
224
|
+
console.log(formValues);
|
|
225
|
+
};
|
|
163
226
|
|
|
164
|
-
|
|
227
|
+
return (
|
|
228
|
+
<div>
|
|
229
|
+
<button onClick={handleAddForm}>Add Form</button>
|
|
230
|
+
<button onClick={handleRemoveForm}>Remove Form</button>
|
|
231
|
+
<button onClick={handleGetForm}>Get Form</button>
|
|
232
|
+
<button onClick={handleSubmitForms}>Submit Forms</button>
|
|
233
|
+
<button onClick={printFormGroupInstance}>Print Form Group Instance</button>
|
|
234
|
+
{debugMode && <p>Debug mode is enabled</p>}
|
|
235
|
+
</div>
|
|
236
|
+
);
|
|
237
|
+
};
|
|
165
238
|
|
|
166
|
-
|
|
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
|
-
}
|
|
186
|
-
|
|
187
|
-
const CompOne = () => {
|
|
188
|
-
return (
|
|
189
|
-
<Form id="id1" {...}/>
|
|
190
|
-
);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
const CompTwo = () => {
|
|
194
|
-
return (
|
|
195
|
-
<Form id="id2" {...} />
|
|
196
|
-
);
|
|
197
|
-
}
|
|
239
|
+
export default FormComponent;
|
|
198
240
|
```
|
|
199
241
|
|
|
200
|
-
## React
|
|
242
|
+
## React `<Form />`
|
|
201
243
|
|
|
202
|
-
|
|
244
|
+
After configuring the provider, `<Form />` components lets you render a form
|
|
203
245
|
|
|
204
246
|
### Props
|
|
205
247
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
|
209
|
-
|
|
|
210
|
-
|
|
|
211
|
-
|
|
|
212
|
-
|
|
|
213
|
-
|
|
|
214
|
-
|
|
|
215
|
-
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
|
220
|
-
|
|
|
221
|
-
|
|
|
222
|
-
|
|
|
248
|
+
| Prop | Type | Description |
|
|
249
|
+
| ----------------------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
250
|
+
| [DEPRECIATED] disable | boolean | Disable all form inputs. It will use the default htm disable attribute |
|
|
251
|
+
| [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 |
|
|
252
|
+
| index | string | Form identified. One will be generated as default if omitted |
|
|
253
|
+
| [DEPRECIATED] hooks | THooks | Provide functions to run on certain life-cycle events |
|
|
254
|
+
| iVars | Object | One object with internal variables to be used in form with data binding |
|
|
255
|
+
| initialValues | Object | Object with form initial values that will map to a field. |
|
|
256
|
+
| Schema | TSchema | Form Schema |
|
|
257
|
+
| [DEPRECIATED] autoComplete | string | HTML autocomplete |
|
|
258
|
+
| className | string | Allow to style form |
|
|
259
|
+
| onSubmit | callback(HTMLFormElement,TFormValues) | Will be called when there is a submit action in the form |
|
|
260
|
+
| 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 |
|
|
261
|
+
| 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 |
|
|
262
|
+
| 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 |
|
|
263
|
+
| onMount | callback(TFormValues,TComponent, TField) | Will be called when some field mounted. Its called with the field that information that mounted. |
|
|
264
|
+
| [DEPRECIATED] onStep | callback(TFormValues) | Called when a form step changed |
|
|
265
|
+
| [DEPRECIATED] onLog | callback(TLoggingEvent) | Called on each log, if the logging is enabled |
|
|
266
|
+
| [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 |
|
|
267
|
+
| onClick | onClick(TFormValues, TField) | Callback function that runs on each component click |
|
|
268
|
+
| onApiResponse | onApiResponse(values: TFormValues, component?: TComponent, field?: TField) | Callback function that runs on each component after api call. |
|
|
269
|
+
| [DEPRECIATED] onFieldRehydrate | onFieldRehydrate?(values: TFormValues, component: TComponent, field: TField): void | This callback is called whenever some form field was rehydrated |
|
|
270
|
+
| [DEPRECIATED] renderLoading | renderLoading?(): ReactElement; | Component to render while the schema has not rendered |
|
|
271
|
+
| [DEPRECIATED] onFormMount | onFormMount?(values: TFormValues): void; | Called when the form finished mounted |
|
|
272
|
+
| [DEPRECIATED] formattedDataDefaults | Object | Some default data to fields when they are undefined |
|
|
273
|
+
| [DEPRECIATED] submitOnValidOnly | boolean | Boolean indicating if form can be submitted even if it is invalid |
|
|
274
|
+
| [DEPRECIATED] renderFieldWrapper | renderFieldWrapper(component: TComponent, children: ReactElement[]) | Function that allows to insert a wrapper in place of a component or wrapping the component |
|
|
223
275
|
|
|
224
276
|
### Example
|
|
225
277
|
|
|
226
|
-
|
|
278
|
+
A simple example of rendering a basic form
|
|
227
279
|
|
|
228
280
|
```javascript
|
|
229
|
-
|
|
230
|
-
onSubmit: () => {
|
|
231
|
-
dispatch(
|
|
232
|
-
formData({
|
|
233
|
-
aggregate: true,
|
|
234
|
-
}),
|
|
235
|
-
);
|
|
236
|
-
},
|
|
237
|
-
id: 'main-form',
|
|
238
|
-
});
|
|
239
|
-
const { formData } = useFormGroup({
|
|
240
|
-
onSubmit: (data) => {
|
|
241
|
-
console.log('SUBMIT', data);
|
|
242
|
-
},
|
|
243
|
-
onData: (data) => {
|
|
244
|
-
console.log('-> ', data);
|
|
245
|
-
},
|
|
246
|
-
group: 'logical',
|
|
247
|
-
});
|
|
248
|
-
|
|
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
|
-
)
|
|
281
|
+
<Form schema={schema} />
|
|
265
282
|
```
|
|
266
283
|
|
|
267
|
-
|
|
284
|
+
## React `useForm()`
|
|
285
|
+
|
|
286
|
+
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.
|
|
287
|
+
|
|
288
|
+
## React `useFormGroup()` [DEPRECIATED]
|
|
289
|
+
|
|
290
|
+
Similar to `useForm`
|
|
268
291
|
|
|
269
292
|
## React `asFormField()`
|
|
270
293
|
|
|
@@ -314,54 +337,83 @@ In the following example `asFormField` hooks are used to create `Component` fiel
|
|
|
314
337
|
propsMapping: propsMapping.component,
|
|
315
338
|
};
|
|
316
339
|
|
|
317
|
-
<
|
|
340
|
+
<FormGroupContextProvider mapper={Mappings}>
|
|
318
341
|
<FormComponent
|
|
319
342
|
formId="test"
|
|
320
343
|
label="Field example"
|
|
321
344
|
name="ss"
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
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
|
-
}}
|
|
345
|
+
formatters={
|
|
346
|
+
splitter: [
|
|
347
|
+
{
|
|
348
|
+
position: 2,
|
|
349
|
+
value: '/',
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
position: 5,
|
|
353
|
+
value: '/',
|
|
354
|
+
},
|
|
355
|
+
]
|
|
356
|
+
}
|
|
354
357
|
validations={{
|
|
355
|
-
|
|
358
|
+
config: {
|
|
356
359
|
callback: (data) => {
|
|
357
360
|
return {
|
|
358
361
|
fail: data === '10/10/1000',
|
|
359
362
|
};
|
|
360
363
|
},
|
|
361
364
|
},
|
|
365
|
+
events: ['ON_FIELD_BLUR']
|
|
362
366
|
}}
|
|
363
|
-
errorMessages={{
|
|
367
|
+
errorMessages={{ callback: 'ERRRO' }}
|
|
364
368
|
/>
|
|
365
|
-
</
|
|
369
|
+
</FormGroupContextProvider>;
|
|
366
370
|
}
|
|
367
371
|
```
|
|
372
|
+
|
|
373
|
+
## React `AsFormFieldBuilder()`
|
|
374
|
+
|
|
375
|
+
Extends the asFormField implementation with the addition of the prop formId and mapper and doesn't required the Form component to render a form field
|
|
376
|
+
|
|
377
|
+
| Prop | Type | Description |
|
|
378
|
+
|formIndex | string | index of the form to identity the form |
|
|
379
|
+
|mapper | TMapper<ElementType> | same mapper used on the mapper context |
|
|
380
|
+
|
|
381
|
+
```javascript
|
|
382
|
+
<FormGroupContextProvider mapper={Mappings}>
|
|
383
|
+
<AsFormFieldBuilder
|
|
384
|
+
mapper={{
|
|
385
|
+
component: Input,
|
|
386
|
+
componentName: 'input',
|
|
387
|
+
events: {
|
|
388
|
+
getValue: 'onChange',
|
|
389
|
+
setValue: 'value',
|
|
390
|
+
setErrorMessage: 'errorMessage',
|
|
391
|
+
onBlur: 'onBlur',
|
|
392
|
+
onFocus: 'onFocus',
|
|
393
|
+
onKeyUp: 'onKeyUp',
|
|
394
|
+
onKeyDown: 'onKeyUpCapture',
|
|
395
|
+
},
|
|
396
|
+
valueChangeEvent: (event: unknown) => {
|
|
397
|
+
return (event as SyntheticEvent<HTMLInputElement>).currentTarget
|
|
398
|
+
.value;
|
|
399
|
+
},
|
|
400
|
+
}}
|
|
401
|
+
formIndex="form1"
|
|
402
|
+
name={`input1`}
|
|
403
|
+
props={{
|
|
404
|
+
label: '${"insert something"||${input1.value}}',
|
|
405
|
+
helperMessage: `\${input1.api.default.response}`,
|
|
406
|
+
}}
|
|
407
|
+
api={{
|
|
408
|
+
defaultConfig: {
|
|
409
|
+
config: {
|
|
410
|
+
method: 'GET',
|
|
411
|
+
url: 'https://api.chucknorris.io/jokes/random',
|
|
412
|
+
resultPath: 'value',
|
|
413
|
+
},
|
|
414
|
+
events: ['ON_FIELD_MOUNT'],
|
|
415
|
+
},
|
|
416
|
+
}}
|
|
417
|
+
/>
|
|
418
|
+
</FormGroupContextProvider>
|
|
419
|
+
```
|
package/index.esm.js
CHANGED
|
@@ -1616,8 +1616,13 @@ $$1({ target: 'Object', stat: true, arity: 2, forced: Object.assign !== assign }
|
|
|
1616
1616
|
assign: assign
|
|
1617
1617
|
});
|
|
1618
1618
|
|
|
1619
|
-
let context;
|
|
1620
1619
|
const FormGroupContext = /*#__PURE__*/createContext({});
|
|
1620
|
+
/**
|
|
1621
|
+
* context interface to be used isolated or with the context provider
|
|
1622
|
+
*
|
|
1623
|
+
* @param {TFormContextProvider} param context parameters
|
|
1624
|
+
* @returns {TFormContext}
|
|
1625
|
+
*/
|
|
1621
1626
|
const IsolatedContext = ({
|
|
1622
1627
|
debugMode: _debugMode = false,
|
|
1623
1628
|
mappers
|
|
@@ -1670,6 +1675,12 @@ const IsolatedContext = ({
|
|
|
1670
1675
|
};
|
|
1671
1676
|
return contextValue;
|
|
1672
1677
|
};
|
|
1678
|
+
/**
|
|
1679
|
+
* context provider to wrap form-engine adapter elements
|
|
1680
|
+
*
|
|
1681
|
+
* @param {PropsWithChildren<TFormContextProvider>} param context parameters
|
|
1682
|
+
* @returns {ReactElement}
|
|
1683
|
+
*/
|
|
1673
1684
|
const FormGroupContextProvider = ({
|
|
1674
1685
|
children,
|
|
1675
1686
|
mappers,
|
|
@@ -1691,9 +1702,15 @@ const FormGroupContextProvider = ({
|
|
|
1691
1702
|
}), children]
|
|
1692
1703
|
});
|
|
1693
1704
|
};
|
|
1705
|
+
/**
|
|
1706
|
+
* FormGroup context hook to handle context or isolated context implementations
|
|
1707
|
+
*
|
|
1708
|
+
* @param {TFormContextProvider} props form group context parameters
|
|
1709
|
+
* @returns {TFormContext}
|
|
1710
|
+
*/
|
|
1694
1711
|
const useFormGroupContext = props => {
|
|
1695
|
-
context = useContext(FormGroupContext);
|
|
1696
|
-
if (Object.keys(context).length === 0) {
|
|
1712
|
+
const context = useContext(FormGroupContext);
|
|
1713
|
+
if (Object.keys(context).length === 0 && props) {
|
|
1697
1714
|
return IsolatedContext({
|
|
1698
1715
|
debugMode: props.debugMode,
|
|
1699
1716
|
mappers: props.mappers
|
|
@@ -1702,6 +1719,12 @@ const useFormGroupContext = props => {
|
|
|
1702
1719
|
return context;
|
|
1703
1720
|
};
|
|
1704
1721
|
|
|
1722
|
+
/**
|
|
1723
|
+
* Renders the React element defined on the mappers configuration
|
|
1724
|
+
*
|
|
1725
|
+
* @param param component props, field instance and children to render
|
|
1726
|
+
* @returns
|
|
1727
|
+
*/
|
|
1705
1728
|
const FieldWrapperComponentRender = ({
|
|
1706
1729
|
props,
|
|
1707
1730
|
fieldInstance,
|
|
@@ -1722,6 +1745,13 @@ const FieldWrapperComponentRender = ({
|
|
|
1722
1745
|
children: `failed to render field ${fieldInstance === null || fieldInstance === void 0 ? void 0 : fieldInstance.name} with componentName:${(_c = fieldInstance === null || fieldInstance === void 0 ? void 0 : fieldInstance.mapper) === null || _c === void 0 ? void 0 : _c.componentName}, please check mappers`
|
|
1723
1746
|
});
|
|
1724
1747
|
};
|
|
1748
|
+
/**
|
|
1749
|
+
* Base field Wrapper to render the component with the necessary configurations from the schema
|
|
1750
|
+
* and mapper configuration
|
|
1751
|
+
*
|
|
1752
|
+
* @param {TFieldWrapperProps} param FieldWrapper params
|
|
1753
|
+
* @returns {ReactElement}
|
|
1754
|
+
*/
|
|
1725
1755
|
const FieldWrapper = ({
|
|
1726
1756
|
name,
|
|
1727
1757
|
formIndex,
|
|
@@ -1731,37 +1761,40 @@ const FieldWrapper = ({
|
|
|
1731
1761
|
}) => {
|
|
1732
1762
|
var _a;
|
|
1733
1763
|
const localContext = useFormGroupContext({});
|
|
1764
|
+
/**
|
|
1765
|
+
* picks the right context prioritizing the context passed as prop
|
|
1766
|
+
*/
|
|
1734
1767
|
const {
|
|
1735
1768
|
formGroupInstance,
|
|
1736
1769
|
debugMode
|
|
1737
1770
|
} = useMemo(() => context ? context : localContext, [context, localContext]);
|
|
1738
|
-
const fieldInstance = (_a = formGroupInstance.getForm({
|
|
1771
|
+
const fieldInstance = useRef((_a = formGroupInstance.getForm({
|
|
1739
1772
|
key: formIndex
|
|
1740
1773
|
})) === null || _a === void 0 ? void 0 : _a.getField({
|
|
1741
1774
|
key: name
|
|
1742
|
-
});
|
|
1743
|
-
const [valueState, setValueState] = useState(fieldInstance === null || fieldInstance === void 0 ? void 0 : fieldInstance.stateValue);
|
|
1775
|
+
})).current;
|
|
1776
|
+
const [valueState, setValueState] = useState((fieldInstance === null || fieldInstance === void 0 ? void 0 : fieldInstance.stateValue) || {});
|
|
1744
1777
|
const [state, setState] = useState({
|
|
1745
1778
|
visibility: (fieldInstance === null || fieldInstance === void 0 ? void 0 : fieldInstance.visibility) || true,
|
|
1746
|
-
props: (fieldInstance === null || fieldInstance === void 0 ? void 0 : fieldInstance.props) || props
|
|
1747
|
-
apiResponse: fieldInstance === null || fieldInstance === void 0 ? void 0 : fieldInstance.api
|
|
1779
|
+
props: (fieldInstance === null || fieldInstance === void 0 ? void 0 : fieldInstance.props) || props
|
|
1748
1780
|
});
|
|
1781
|
+
/**
|
|
1782
|
+
* handles the mounting and unmounting logic onto the field instance
|
|
1783
|
+
*/
|
|
1749
1784
|
useEffect(() => {
|
|
1750
1785
|
fieldInstance === null || fieldInstance === void 0 ? void 0 : fieldInstance.mountField({
|
|
1751
1786
|
valueSubscription: value => {
|
|
1752
1787
|
setValueState(value);
|
|
1753
1788
|
},
|
|
1754
1789
|
propsSubscription: ({
|
|
1755
|
-
errors,
|
|
1756
1790
|
visibility,
|
|
1757
|
-
|
|
1758
|
-
|
|
1791
|
+
props,
|
|
1792
|
+
errors
|
|
1759
1793
|
}) => {
|
|
1760
1794
|
setState(prev => Object.assign(Object.assign({}, prev), {
|
|
1761
|
-
errors,
|
|
1762
1795
|
visibility,
|
|
1763
|
-
|
|
1764
|
-
|
|
1796
|
+
props,
|
|
1797
|
+
errors
|
|
1765
1798
|
}));
|
|
1766
1799
|
}
|
|
1767
1800
|
});
|
|
@@ -1769,17 +1802,27 @@ const FieldWrapper = ({
|
|
|
1769
1802
|
fieldInstance === null || fieldInstance === void 0 ? void 0 : fieldInstance.destroyField();
|
|
1770
1803
|
};
|
|
1771
1804
|
}, []);
|
|
1805
|
+
/**
|
|
1806
|
+
* handles the value change onto the field instance
|
|
1807
|
+
*/
|
|
1772
1808
|
const handleChange = useCallback(event => {
|
|
1773
1809
|
fieldInstance === null || fieldInstance === void 0 ? void 0 : fieldInstance.emitValue({
|
|
1774
1810
|
value: event,
|
|
1775
1811
|
event: 'ON_FIELD_CHANGE'
|
|
1776
1812
|
});
|
|
1777
1813
|
}, []);
|
|
1814
|
+
/**
|
|
1815
|
+
* handles the event emission onto the field instance
|
|
1816
|
+
*/
|
|
1778
1817
|
const handleEvent = useCallback(event => {
|
|
1779
1818
|
fieldInstance === null || fieldInstance === void 0 ? void 0 : fieldInstance.emitEvents({
|
|
1780
1819
|
event
|
|
1781
1820
|
});
|
|
1782
1821
|
}, []);
|
|
1822
|
+
/**
|
|
1823
|
+
* handles the mappers configuration to bind the event submission callback
|
|
1824
|
+
* to the corresponding prop defined on the mappers
|
|
1825
|
+
*/
|
|
1783
1826
|
const mapProps = useMemo(() => {
|
|
1784
1827
|
var _a;
|
|
1785
1828
|
const events = (_a = fieldInstance === null || fieldInstance === void 0 ? void 0 : fieldInstance.mapper) === null || _a === void 0 ? void 0 : _a.events;
|
|
@@ -1792,13 +1835,6 @@ const FieldWrapper = ({
|
|
|
1792
1835
|
if (events === null || events === void 0 ? void 0 : events.onKeyDown) props[events.onKeyDown] = () => handleEvent('ON_FIELD_KEYDOWN');
|
|
1793
1836
|
return props;
|
|
1794
1837
|
}, []);
|
|
1795
|
-
const mapValue = useMemo(() => {
|
|
1796
|
-
var _a;
|
|
1797
|
-
const events = (_a = fieldInstance === null || fieldInstance === void 0 ? void 0 : fieldInstance.mapper) === null || _a === void 0 ? void 0 : _a.events;
|
|
1798
|
-
return (events === null || events === void 0 ? void 0 : events.setValue) ? {
|
|
1799
|
-
[events.setValue]: valueState
|
|
1800
|
-
} : {};
|
|
1801
|
-
}, [valueState]);
|
|
1802
1838
|
return (state === null || state === void 0 ? void 0 : state.visibility) ? jsxs(Fragment, {
|
|
1803
1839
|
children: [debugMode && jsxs(Fragment, {
|
|
1804
1840
|
children: [jsx("b", {
|
|
@@ -1809,13 +1845,22 @@ const FieldWrapper = ({
|
|
|
1809
1845
|
children: name
|
|
1810
1846
|
}), jsx("br", {}), jsx("hr", {})]
|
|
1811
1847
|
}), jsx(FieldWrapperComponentRender, {
|
|
1812
|
-
props: Object.assign(Object.assign(Object.assign({}, mapProps), state.props),
|
|
1848
|
+
props: Object.assign(Object.assign(Object.assign(Object.assign({}, mapProps), state.props), state.errors), valueState),
|
|
1813
1849
|
fieldInstance: fieldInstance,
|
|
1814
1850
|
children: children && children
|
|
1815
1851
|
})]
|
|
1816
1852
|
}) : jsx(Fragment, {});
|
|
1817
1853
|
};
|
|
1818
1854
|
|
|
1855
|
+
/**
|
|
1856
|
+
* recursive function to transform form fields from a form instance into
|
|
1857
|
+
* a react component tree
|
|
1858
|
+
*
|
|
1859
|
+
* @param {Map<string,IFormField>} param.fields form instance field Map
|
|
1860
|
+
* @param {string} param.prevPath previous field path to track the tree branch creation
|
|
1861
|
+
* @param {string} param.formIndex form index to aid field identification onto the FieldWrapper
|
|
1862
|
+
* @returns {ReactNode}
|
|
1863
|
+
*/
|
|
1819
1864
|
const BuildTree = ({
|
|
1820
1865
|
fields,
|
|
1821
1866
|
prevPath,
|
|
@@ -1838,6 +1883,12 @@ const BuildTree = ({
|
|
|
1838
1883
|
}, fieldName);
|
|
1839
1884
|
});
|
|
1840
1885
|
};
|
|
1886
|
+
/**
|
|
1887
|
+
* function to transform AsFormField elements onto a JSON schema
|
|
1888
|
+
*
|
|
1889
|
+
* @param param.children ReactNode children elements
|
|
1890
|
+
* @returns {IComponentSchema[] | null | undefined}
|
|
1891
|
+
*/
|
|
1841
1892
|
const BuildAsFormFieldTree = ({
|
|
1842
1893
|
children
|
|
1843
1894
|
}) => {
|
|
@@ -1890,6 +1941,9 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
1890
1941
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
1891
1942
|
};
|
|
1892
1943
|
|
|
1944
|
+
/**
|
|
1945
|
+
* events mapping to aid function callback binding
|
|
1946
|
+
*/
|
|
1893
1947
|
const eventsMapping = {
|
|
1894
1948
|
ON_FIELD_CHANGE: 'onChange',
|
|
1895
1949
|
ON_FIELD_BLUR: 'onBlur',
|
|
@@ -1901,6 +1955,9 @@ const eventsMapping = {
|
|
|
1901
1955
|
ON_FIELD_CLICK: 'onClick'
|
|
1902
1956
|
};
|
|
1903
1957
|
|
|
1958
|
+
/**
|
|
1959
|
+
* Hook to register events callback functions
|
|
1960
|
+
*/
|
|
1904
1961
|
const useForm = _a => {
|
|
1905
1962
|
var {
|
|
1906
1963
|
id
|
|
@@ -1909,10 +1966,18 @@ const useForm = _a => {
|
|
|
1909
1966
|
const {
|
|
1910
1967
|
formGroupInstance
|
|
1911
1968
|
} = useFormGroupContext({});
|
|
1969
|
+
/**
|
|
1970
|
+
* reference to store all updated callback functions rerendered by props change
|
|
1971
|
+
*/
|
|
1912
1972
|
const callbackRefs = useRef(rest);
|
|
1913
1973
|
useEffect(() => {
|
|
1914
1974
|
callbackRefs.current = rest;
|
|
1915
1975
|
}, [rest]);
|
|
1976
|
+
/**
|
|
1977
|
+
* handle function call after the debounce occurs on the form instance field event
|
|
1978
|
+
* subject in order to call the most updated function with the updated function
|
|
1979
|
+
* reference to avoid events get outdated values
|
|
1980
|
+
*/
|
|
1916
1981
|
useEffect(() => {
|
|
1917
1982
|
var _a;
|
|
1918
1983
|
const callback = payload => {
|
|
@@ -1932,6 +1997,11 @@ const useForm = _a => {
|
|
|
1932
1997
|
return;
|
|
1933
1998
|
};
|
|
1934
1999
|
|
|
2000
|
+
/**
|
|
2001
|
+
*
|
|
2002
|
+
* @param {TFormProps} param form properties initializor
|
|
2003
|
+
* @returns {ReactElement}
|
|
2004
|
+
*/
|
|
1935
2005
|
const Form = ({
|
|
1936
2006
|
schema,
|
|
1937
2007
|
index,
|
|
@@ -1960,6 +2030,9 @@ const Form = ({
|
|
|
1960
2030
|
} = useFormGroupContext({});
|
|
1961
2031
|
const [tree, setTree] = useState();
|
|
1962
2032
|
const schemaIndex = useMemo(() => index || (schema === null || schema === void 0 ? void 0 : schema.index) || 'defaultChange', [index, schema]);
|
|
2033
|
+
/**
|
|
2034
|
+
* logic to initialize the form instance and it's removal
|
|
2035
|
+
*/
|
|
1963
2036
|
useEffect(() => {
|
|
1964
2037
|
if (schemaIndex === 'defaultChange') {
|
|
1965
2038
|
console.warn('please, add an unique id to the form, otherwise multiple forms will break');
|
|
@@ -1988,6 +2061,11 @@ const Form = ({
|
|
|
1988
2061
|
});
|
|
1989
2062
|
};
|
|
1990
2063
|
}, []);
|
|
2064
|
+
/**
|
|
2065
|
+
* logic to transform AsFormFields onto JSON schema
|
|
2066
|
+
* and JSON schema onto FieldWrappers, refreshes when
|
|
2067
|
+
* the react tree changes it's children
|
|
2068
|
+
*/
|
|
1991
2069
|
useEffect(() => {
|
|
1992
2070
|
var _a;
|
|
1993
2071
|
const schema = BuildAsFormFieldTree({
|
|
@@ -2007,11 +2085,17 @@ const Form = ({
|
|
|
2007
2085
|
setTree(buildTree);
|
|
2008
2086
|
}
|
|
2009
2087
|
}, [children]);
|
|
2088
|
+
/**
|
|
2089
|
+
* iVars change tracker to update iVars onto form instance
|
|
2090
|
+
*/
|
|
2010
2091
|
useEffect(() => {
|
|
2011
2092
|
if (iVars) getForm({
|
|
2012
2093
|
key: index
|
|
2013
2094
|
}).iVars = iVars;
|
|
2014
2095
|
}, [iVars]);
|
|
2096
|
+
/**
|
|
2097
|
+
* hook usage to keep event bindings updated on callback functions passed as props
|
|
2098
|
+
*/
|
|
2015
2099
|
useForm({
|
|
2016
2100
|
id: schemaIndex,
|
|
2017
2101
|
onApiResponse,
|
|
@@ -2066,10 +2150,17 @@ const Form = ({
|
|
|
2066
2150
|
});
|
|
2067
2151
|
};
|
|
2068
2152
|
|
|
2153
|
+
/**
|
|
2154
|
+
* Component wrapper to aid building schemas with react without writting a JSON schema
|
|
2155
|
+
* along with BuildAsFormFieldTree inside a Form component, FieldWrapper gets this props
|
|
2156
|
+
* to build the component as it does with a JSON schema, this component only works inside
|
|
2157
|
+
* the Form component
|
|
2158
|
+
*
|
|
2159
|
+
* @param {TAsFormFieldProps} props JSON schema props
|
|
2160
|
+
* @returns {ReactNode}
|
|
2161
|
+
*/
|
|
2069
2162
|
const AsFormField = props => {
|
|
2070
|
-
return
|
|
2071
|
-
children: props.children
|
|
2072
|
-
});
|
|
2163
|
+
return props.children;
|
|
2073
2164
|
};
|
|
2074
2165
|
|
|
2075
2166
|
var wellKnownSymbol$1 = wellKnownSymbol$8;
|
|
@@ -2318,9 +2409,24 @@ $({ target: 'RegExp', proto: true, forced: /./.exec !== exec }, {
|
|
|
2318
2409
|
exec: exec
|
|
2319
2410
|
});
|
|
2320
2411
|
|
|
2412
|
+
/**
|
|
2413
|
+
* Component Wrapper to render form fields without the Form component, gets additional formId and mapper since
|
|
2414
|
+
* it won't rely on them and needs to be manually declared
|
|
2415
|
+
*
|
|
2416
|
+
* @param {TAsFormFieldBuilderProps} props JSON schema props along with FieldWrapper props and mapper props
|
|
2417
|
+
* @returns {ReactElement}
|
|
2418
|
+
*/
|
|
2321
2419
|
const AsFormFieldBuilder = props => {
|
|
2322
2420
|
const context = useFormGroupContext({});
|
|
2421
|
+
/**
|
|
2422
|
+
* state to track the field instance creation process
|
|
2423
|
+
*/
|
|
2323
2424
|
const [mounted, setMounted] = useState(false);
|
|
2425
|
+
/**
|
|
2426
|
+
* initializer to create or add a form instance to the formGroup by it's formId
|
|
2427
|
+
* and add the field to the form instance
|
|
2428
|
+
* Also has the logic to remove it once this element is removed
|
|
2429
|
+
*/
|
|
2324
2430
|
useEffect(() => {
|
|
2325
2431
|
var _a;
|
|
2326
2432
|
if (!((_a = context.formGroupInstance) === null || _a === void 0 ? void 0 : _a.forms.has(props.formIndex))) {
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bolttech/form-engine",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.17",
|
|
4
4
|
"description": "A react adapter for bolttech form engine",
|
|
5
5
|
"module": "./index.esm.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./index.esm.js",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@bolttech/form-engine-core": "0.0.1-beta.
|
|
9
|
+
"@bolttech/form-engine-core": "0.0.1-beta.8",
|
|
10
10
|
"react": "18.2.0"
|
|
11
11
|
},
|
|
12
12
|
"peerDependencies": {}
|
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { TAsFormFieldProps } from './AsFormField.type';
|
|
3
|
+
/**
|
|
4
|
+
* Component wrapper to aid building schemas with react without writting a JSON schema
|
|
5
|
+
* along with BuildAsFormFieldTree inside a Form component, FieldWrapper gets this props
|
|
6
|
+
* to build the component as it does with a JSON schema, this component only works inside
|
|
7
|
+
* the Form component
|
|
8
|
+
*
|
|
9
|
+
* @param {TAsFormFieldProps} props JSON schema props
|
|
10
|
+
* @returns {ReactNode}
|
|
11
|
+
*/
|
|
12
|
+
declare const AsFormField: (props: TAsFormFieldProps) => ReactNode;
|
|
4
13
|
export default AsFormField;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { IComponentSchema } from '@bolttech/form-engine-core';
|
|
2
|
+
import { PropsWithChildren } from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* AsFormField props, inherits all schema field implementation except the children
|
|
5
|
+
* property, that will be a ReactNode
|
|
6
|
+
* @see {@link IComponentSchema}
|
|
7
|
+
*/
|
|
8
|
+
type TAsFormFieldProps = PropsWithChildren<Omit<IComponentSchema, 'children'>>;
|
|
9
|
+
export type { TAsFormFieldProps };
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { ReactElement } from 'react';
|
|
2
|
+
import { TAsFormFieldBuilderProps } from './AsFormFieldBuilder.type';
|
|
3
|
+
/**
|
|
4
|
+
* Component Wrapper to render form fields without the Form component, gets additional formId and mapper since
|
|
5
|
+
* it won't rely on them and needs to be manually declared
|
|
6
|
+
*
|
|
7
|
+
* @param {TAsFormFieldBuilderProps} props JSON schema props along with FieldWrapper props and mapper props
|
|
8
|
+
* @returns {ReactElement}
|
|
9
|
+
*/
|
|
10
|
+
declare const AsFormFieldBuilder: (props: TAsFormFieldBuilderProps) => ReactElement;
|
|
7
11
|
export default AsFormFieldBuilder;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { IComponentSchema, TMapper } from '@bolttech/form-engine-core';
|
|
2
|
+
import { ElementType, PropsWithChildren } from 'react';
|
|
3
|
+
import { TFieldWrapper } from '../../types';
|
|
4
|
+
/**
|
|
5
|
+
* AsFormField props, inherits all schema field implementation except the children
|
|
6
|
+
* property, that will be a ReactNode
|
|
7
|
+
* also gets the formIndex for form identification and the mapper to build the component
|
|
8
|
+
* @property {TMapper} mapper element mapper to use
|
|
9
|
+
* @see {@link TMapper}
|
|
10
|
+
* @see {@link IComponentSchema}
|
|
11
|
+
* @see {@link TFieldWrapper}
|
|
12
|
+
*/
|
|
13
|
+
type TAsFormFieldBuilderProps = PropsWithChildren<Omit<IComponentSchema, 'children' | 'component' | 'name'> & Required<TFieldWrapper> & {
|
|
14
|
+
mapper: TMapper<ElementType>;
|
|
15
|
+
}>;
|
|
16
|
+
export type { TAsFormFieldBuilderProps };
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { ReactElement } from 'react';
|
|
2
|
+
import { TFieldWrapperProps } from './FieldWrapper.type';
|
|
3
|
+
/**
|
|
4
|
+
* Base field Wrapper to render the component with the necessary configurations from the schema
|
|
5
|
+
* and mapper configuration
|
|
6
|
+
*
|
|
7
|
+
* @param {TFieldWrapperProps} param FieldWrapper params
|
|
8
|
+
* @returns {ReactElement}
|
|
9
|
+
*/
|
|
10
|
+
declare const FieldWrapper: ({ name, formIndex, children, props, context, }: TFieldWrapperProps) => ReactElement;
|
|
9
11
|
export default FieldWrapper;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { PropsWithChildren } from 'react';
|
|
2
|
+
import { TFieldWrapper } from '../../types';
|
|
3
|
+
import { TFormContext } from '../../context/FormGroupContext';
|
|
4
|
+
import { FormField } from '@bolttech/form-engine-core';
|
|
5
|
+
/**
|
|
6
|
+
* Represents the props for a field wrapper component, including children.
|
|
7
|
+
*
|
|
8
|
+
* @property {Record<string, unknown>} [props] - Additional properties for the field.
|
|
9
|
+
* @property {TFormContext | null} [context] - The context of the form, which may be null.
|
|
10
|
+
* @property {React.ReactNode} children - The child elements of the component.
|
|
11
|
+
* @see {@link TFieldWrapper}
|
|
12
|
+
*/
|
|
13
|
+
type TFieldWrapperProps = PropsWithChildren<TFieldWrapper & {
|
|
14
|
+
props?: Record<string, unknown>;
|
|
15
|
+
context?: TFormContext | null;
|
|
16
|
+
}>;
|
|
17
|
+
/**
|
|
18
|
+
* Represents the props for rendering a field wrapper component, including children.
|
|
19
|
+
*
|
|
20
|
+
* @property {Record<string, unknown>} props - Additional properties for the field.
|
|
21
|
+
* @property {FormField} [fieldInstance] - The instance of the form field, which may be undefined.
|
|
22
|
+
* @property {React.ReactNode} children - The child elements of the component.
|
|
23
|
+
*/
|
|
24
|
+
type TFieldWrapperComponentRenderProps = PropsWithChildren<{
|
|
25
|
+
props: Record<string, unknown>;
|
|
26
|
+
fieldInstance?: FormField;
|
|
27
|
+
}>;
|
|
28
|
+
export type { TFieldWrapperProps, TFieldWrapperComponentRenderProps };
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { ReactElement } from 'react';
|
|
2
|
+
import { TFormProps } from './Form.type';
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @param {TFormProps} param form properties initializor
|
|
6
|
+
* @returns {ReactElement}
|
|
7
|
+
*/
|
|
8
|
+
declare const Form: ({ schema, index, initialValues, iVars, action, method, onSubmit, onData, onBlur, onChange, onApiResponse, onClick, onFocus, onKeyDown, onKeyUp, onMount, children, }: TFormProps) => ReactElement;
|
|
5
9
|
export default Form;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { TFormEntry } from '@bolttech/form-engine-core';
|
|
2
|
+
import { PropsWithChildren } from 'react';
|
|
3
|
+
import { TEventsCallbackProps } from '../../types';
|
|
4
|
+
/**
|
|
5
|
+
* Form props, inherits the form instance constructor implementation except the mapper
|
|
6
|
+
* along with all event callback register props shared with other implementations
|
|
7
|
+
* @see {@link TFormEntry}
|
|
8
|
+
* @see {@link TEventsCallbackProps}
|
|
9
|
+
*/
|
|
10
|
+
type TFormProps = PropsWithChildren<Omit<TFormEntry, 'mappers'> & TEventsCallbackProps>;
|
|
11
|
+
export type { TFormProps };
|
|
@@ -1,30 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
type TFormContext = {
|
|
4
|
-
addFormWithIndex: (index: string) => void;
|
|
5
|
-
addForm: (payload: {
|
|
6
|
-
key: string;
|
|
7
|
-
formInstance: TFormCore;
|
|
8
|
-
}) => void;
|
|
9
|
-
getForm: (payload: {
|
|
10
|
-
key: string;
|
|
11
|
-
}) => FormCore | undefined;
|
|
12
|
-
removeForm: (payload: {
|
|
13
|
-
key: string;
|
|
14
|
-
}) => void;
|
|
15
|
-
formGroupInstance: TFormGroup;
|
|
16
|
-
mappers?: TMapper<ElementType>[];
|
|
17
|
-
printFormGroupInstance: () => void;
|
|
18
|
-
submitMultipleFormsByIndex: (indexes: string[]) => TFormValues;
|
|
19
|
-
debugMode: boolean;
|
|
20
|
-
active: boolean;
|
|
21
|
-
};
|
|
22
|
-
type TFormContextProvider = {
|
|
23
|
-
mappers?: TMapper<ElementType>[];
|
|
24
|
-
debugMode?: boolean;
|
|
25
|
-
};
|
|
1
|
+
import { PropsWithChildren, ReactElement } from 'react';
|
|
2
|
+
import { TFormContext, TFormContextProvider } from './FormGroupContext.type';
|
|
26
3
|
declare const FormGroupContext: import("react").Context<TFormContext>;
|
|
4
|
+
/**
|
|
5
|
+
* context provider to wrap form-engine adapter elements
|
|
6
|
+
*
|
|
7
|
+
* @param {PropsWithChildren<TFormContextProvider>} param context parameters
|
|
8
|
+
* @returns {ReactElement}
|
|
9
|
+
*/
|
|
27
10
|
declare const FormGroupContextProvider: ({ children, mappers, debugMode, }: PropsWithChildren<TFormContextProvider>) => ReactElement;
|
|
28
|
-
|
|
11
|
+
/**
|
|
12
|
+
* FormGroup context hook to handle context or isolated context implementations
|
|
13
|
+
*
|
|
14
|
+
* @param {TFormContextProvider} props form group context parameters
|
|
15
|
+
* @returns {TFormContext}
|
|
16
|
+
*/
|
|
17
|
+
declare const useFormGroupContext: (props?: TFormContextProvider) => TFormContext;
|
|
29
18
|
export { FormGroupContext, FormGroupContextProvider, useFormGroupContext };
|
|
30
19
|
export type { TFormContext };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { FormCore, TFormCore, TFormGroup, TFormValues, TMapper } from '@bolttech/form-engine-core';
|
|
2
|
+
import { ElementType } from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* Represents the context for managing forms within a form group.
|
|
5
|
+
*
|
|
6
|
+
* @property {function(string): void} addFormWithIndex - Adds a form to the form group by its index.
|
|
7
|
+
* @property {function({ key: string, formInstance: TFormCore }): void} addForm - Adds a form to the form group using a payload containing the key and form instance.
|
|
8
|
+
* @property {function({ key: string }): (FormCore | undefined)} getForm - Retrieves a form from the form group using a payload containing the key.
|
|
9
|
+
* @property {function({ key: string }): void} removeForm - Removes a form from the form group using a payload containing the key.
|
|
10
|
+
* @property {TFormGroup} formGroupInstance - The instance of the form group.
|
|
11
|
+
* @property {TMapper<ElementType>[]} [mappers] - Optional array of mappers for elements.
|
|
12
|
+
* @property {function(): void} printFormGroupInstance - Prints the form group instance.
|
|
13
|
+
* @property {function(string[]): TFormValues} submitMultipleFormsByIndex - Submits multiple forms by their indexes and returns the form values.
|
|
14
|
+
* @property {boolean} debugMode - Indicates if debug mode is active.
|
|
15
|
+
* @property {boolean} active - Indicates if the form context is active.
|
|
16
|
+
*/
|
|
17
|
+
type TFormContext = {
|
|
18
|
+
addFormWithIndex: (index: string) => void;
|
|
19
|
+
addForm: (payload: {
|
|
20
|
+
key: string;
|
|
21
|
+
formInstance: TFormCore;
|
|
22
|
+
}) => void;
|
|
23
|
+
getForm: (payload: {
|
|
24
|
+
key: string;
|
|
25
|
+
}) => FormCore | undefined;
|
|
26
|
+
removeForm: (payload: {
|
|
27
|
+
key: string;
|
|
28
|
+
}) => void;
|
|
29
|
+
formGroupInstance: TFormGroup;
|
|
30
|
+
mappers?: TMapper<ElementType>[];
|
|
31
|
+
printFormGroupInstance: () => void;
|
|
32
|
+
submitMultipleFormsByIndex: <T>(indexes: string[]) => TFormValues<T>;
|
|
33
|
+
debugMode: boolean;
|
|
34
|
+
active: boolean;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Represents the props for a form context provider.
|
|
38
|
+
*
|
|
39
|
+
* @property {TMapper<ElementType>[]} [mappers] - Optional array of mappers for elements.
|
|
40
|
+
* @property {boolean} [debugMode] - Optional flag indicating if debug mode should be enabled.
|
|
41
|
+
*/
|
|
42
|
+
type TFormContextProvider = {
|
|
43
|
+
mappers?: TMapper<ElementType>[];
|
|
44
|
+
debugMode?: boolean;
|
|
45
|
+
};
|
|
46
|
+
export type { TFormContext, TFormContextProvider };
|
|
@@ -1,10 +1,25 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
import { IFormField, IComponentSchema } from '@bolttech/form-engine-core';
|
|
3
|
+
/**
|
|
4
|
+
* recursive function to transform form fields from a form instance into
|
|
5
|
+
* a react component tree
|
|
6
|
+
*
|
|
7
|
+
* @param {Map<string,IFormField>} param.fields form instance field Map
|
|
8
|
+
* @param {string} param.prevPath previous field path to track the tree branch creation
|
|
9
|
+
* @param {string} param.formIndex form index to aid field identification onto the FieldWrapper
|
|
10
|
+
* @returns {ReactNode}
|
|
11
|
+
*/
|
|
3
12
|
declare const BuildTree: ({ fields, prevPath, formIndex, }: {
|
|
4
13
|
fields: Map<string, IFormField>;
|
|
5
14
|
prevPath?: string | undefined;
|
|
6
15
|
formIndex: string;
|
|
7
16
|
}) => ReactNode;
|
|
17
|
+
/**
|
|
18
|
+
* function to transform AsFormField elements onto a JSON schema
|
|
19
|
+
*
|
|
20
|
+
* @param param.children ReactNode children elements
|
|
21
|
+
* @returns {IComponentSchema[] | null | undefined}
|
|
22
|
+
*/
|
|
8
23
|
declare const BuildAsFormFieldTree: ({ children, }: {
|
|
9
24
|
children?: ReactNode;
|
|
10
25
|
}) => IComponentSchema[] | null | undefined;
|
package/src/helpers/helpers.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { TEvents } from '@bolttech/form-engine-core';
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { TEventProps } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* events mapping to aid function callback binding
|
|
5
|
+
*/
|
|
6
|
+
declare const eventsMapping: Partial<Record<TEvents, TEventProps>>;
|
|
4
7
|
export { eventsMapping };
|
package/src/hooks/useForm.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { TUseFormProps } from './useForm.type';
|
|
2
|
+
/**
|
|
3
|
+
* Hook to register events callback functions
|
|
4
|
+
*/
|
|
5
|
+
declare const useForm: ({ id, ...rest }: TUseFormProps) => void;
|
|
6
6
|
export default useForm;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { TEventsCallbackProps } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Represents the properties for the useForm hook, including an ID and event callback properties.
|
|
4
|
+
*
|
|
5
|
+
* @property {string} id - The unique identifier for the form.
|
|
6
|
+
*
|
|
7
|
+
* @see {@link TEventsCallbackProps}
|
|
8
|
+
*/
|
|
9
|
+
type TUseFormProps = {
|
|
10
|
+
id: string;
|
|
11
|
+
} & TEventsCallbackProps;
|
|
12
|
+
export type { TUseFormProps };
|
package/src/types/index.d.ts
CHANGED
|
@@ -1,46 +1,20 @@
|
|
|
1
1
|
import { TFieldEvent } from '@bolttech/form-engine-core';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
* Represents the wrapper for a form field, including the component,
|
|
5
|
-
* event handlers, and other properties related to form management.
|
|
3
|
+
* Represents a field wrapper containing the name of the field and its index in the form.
|
|
6
4
|
*
|
|
7
|
-
* @property {string}
|
|
8
|
-
* @property {
|
|
9
|
-
* @property {(event: unknown) => unknown} [valueChangeEvent] - Function to handle value change events.
|
|
10
|
-
* @property {string} formKey - The key of the form.
|
|
11
|
-
* @property {string} [onBlur] - Function to handle the blur event.
|
|
12
|
-
* @property {string} [onChange] - Function to handle the change event.
|
|
13
|
-
* @property {string} [onFocus] - Function to handle the focus event.
|
|
14
|
-
* @property {string} [onClick] - Function to handle the click event.
|
|
15
|
-
* @property {string} [onKeyUp] - Function to handle the keyup event.
|
|
16
|
-
* @property {string} [onKeyDown] - Function to handle the keydown event.
|
|
17
|
-
* @property {unknown} [onValue] - The current value of the field.
|
|
18
|
-
* @property {string} [onErrorMessage] - error message prop name to set message string
|
|
19
|
-
*
|
|
20
|
-
* @example
|
|
21
|
-
* ```typescript
|
|
22
|
-
* const fieldWrapper: TFieldWrapper = {
|
|
23
|
-
* index: '1',
|
|
24
|
-
* Component: MyComponent,
|
|
25
|
-
* valueChangeEvent: (event) => {
|
|
26
|
-
* const newValue = (event as React.ChangeEvent<HTMLInputElement>).target.value;
|
|
27
|
-
* return newValue;
|
|
28
|
-
* },
|
|
29
|
-
* formKey: 'myForm',
|
|
30
|
-
* onBlur: 'handleBlur',
|
|
31
|
-
* onChange: 'handleChange',
|
|
32
|
-
* onFocus: 'handleFocus',
|
|
33
|
-
* onClick: 'handleClick',
|
|
34
|
-
* onKeyUp: 'handleKeyUp',
|
|
35
|
-
* onKeyDown: 'handleKeyDown',
|
|
36
|
-
* onValue: 'value'
|
|
37
|
-
* };
|
|
38
|
-
* ```
|
|
5
|
+
* @property {string} name - The name of the field.
|
|
6
|
+
* @property {string} formIndex - The index of the field within the form.
|
|
39
7
|
*/
|
|
40
8
|
type TFieldWrapper = {
|
|
41
9
|
name: string;
|
|
42
10
|
formIndex: string;
|
|
43
11
|
};
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Represents the possible event properties for form fields callbacks.
|
|
14
|
+
*/
|
|
15
|
+
type TEventProps = 'onChange' | 'onBlur' | 'onFocus' | 'onKeyDown' | 'onKeyUp' | 'onMount' | 'onApiResponse' | 'onClick' | 'onSubmit';
|
|
16
|
+
/**
|
|
17
|
+
* Represents a mapping of event properties to their corresponding callback functions.
|
|
18
|
+
*/
|
|
19
|
+
type TEventsCallbackProps = Partial<Record<TEventProps, ((payload: TFieldEvent) => void) | null | undefined>>;
|
|
20
|
+
export { TFieldWrapper, TEventProps, TEventsCallbackProps };
|