@bolttech/form-engine
Version:
A react adapter for bolttech form engine
1,012 lines (825 loc) • 67.7 kB
Markdown
# Form Engine React Adapter
This is an adapter to be used with the bolttech form engine. Compatible with Next.js 13, 14 and 15 (App Router SSR supported), React 18 and 19.
1. [Sample](#sample)
2. [mappers](#mappers)
3. [Form Group Context](#form-group-context)
- 3.1 [FormGroupContextProvider](#formgroupcontextprovider)
- 3.2 [useFormGroupContext](#useformgroupcontext)
4. [Form](#form)
- 4.1 [Submit Form](#submit-form)
5. [schema](#schema)
6. [schema components](#schema-components)
- 6.1 [formatters](#formatters)
- 6.2 [masks](#masks)
- 6.3 [nameToSubmit](#nametosubmit)
- 6.4 [props](#props)
- 6.5 [validations](#validations)
- 6.6 [api](#api)
- 6.7 [resetValues](#resetvalues)
- 6.8 [visibilityConditions](#visibilityconditions)
- 6.9 [resetPropertyValues](#resetpropertyvalues)
- 6.10 [visibility](#visibility)
- 6.11 [persistValue](#persistValue)
7. [templating](#templating)
8. [hooks](#hooks)
- 8.1 [useForm](#useform)
- 8.2 [useFormGroup](#useformgroup)
9. [AsFormField](#asformfield)
10. [AsFormFieldBuilder](#asformfieldbuilder)
11. [AsFormFieldRepeater](#asformfieldrepeater)
12. [Server-Side Rendering (SSR)](#ssr)
<a id="sample"></a>
## **Sample**
```typescript
const mappers: TMapper<ElementType>[] = [
{
componentName: 'input',
component: Input,
events: {
getValue: 'onChange',
setValue: 'value',
setErrorMessage: 'errorMessage',
onBlur: 'onBlur',
onFocus: 'onFocus',
},
valueChangeEvent: (event: unknown) => {
return (event as ChangeEvent<HTMLInputElement>).target.value;
},
},
{
componentName: 'container',
asyncComponent: lazy(() =>
import('Components/Container').then((module) => ({
default: module.Container,
}))
),
},
];
const schema = {
index: 'form1',
components: [
{
component: 'container',
name: 'container1',
children: [
{
component: 'input',
name: 'input1',
props: {
label: 'input1 label',
},
},
],
},
],
};
const ComponentProvider = ({ children }: PropsWithChildren) => {
return <FormGroupContextProvider mappers={mappers}>{children}</FormGroupContextProvider>;
};
const ComponentWithForm = ({ schema }: { schema: IFormSchema }) => {
const { printFormGroupInstance } = useFormGroupContext();
const handleData = (data: TFormData<unknown>) => {
console.log(data);
};
return (
<>
<button onClick={printFormGroupInstance}>print form instance</button>
<Form index={schema.index} schema={schema} onData={handleData} />
</>
);
};
const Sample = () => {
return (
<ComponentProvider>
<ComponentWithForm schema={schema} />
</ComponentProvider>
);
};
```
<a id="mappers"></a>
## **Mappers**
Mappers are the configuration that needs to be provided in order to use components onto schemas or a special component that render form fields
The mapper configuration goes as it follows:
| Prop | Type | Description |
| ---------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| componentName | string | name to be used onto schema to identify the component to be rendered on a field |
| events | TComponentPropsMapping | events mapping that will reference the component prop with the respective form-engine prop that will handle it's content |
| valueChangeEvent | TValueChangeEvent | component handle function to define how the value is extracted from the 'onChange' event of the component |
| component | T | component type that describes a normal imported component to be used on the field rendering |
| asynccomponent | T | component type that describes an async (lazy) imported component to be used on the field rendering |
`events` are optional and will reference component props that will provide it's dynamic behaviour:
| Prop | Type | Description |
| --------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| getValue | string | component property that will contain the value |
| setValue | string | component property that handles onChange events triggered by the component |
| onBlur | string | component property that handles onBlur events triggered by the component |
| onClick | string | component property that handles onClick events triggered by the component |
| 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) |
| onFocus | string | component property that handles onFocus events triggered by the component |
| onKeyUp | string | component property that handles onKeyUp events triggered by the component |
| onKeyDown | string | component property that handles onKeyDown events triggered by the component |
| setErrorMessage | string | component property that receives the errors of the field as string |
| setErrorState | string | component property that receives the error status of the field as boolean (not implemented) |
### component and asynccomponent
You can choose the way your component is imported, you can directly import the component that will be bundled on your project when built,
or with React's `lazy` or any other method to be used with React's `Suspense` to load it asyncronously and allow code splitting.
Example:
```typescript
import { Input } from '@bolttech/atoms-input';
const mappers = [
{
component: Input,
name: 'inputcomponent',
},
{
component: lazy(() =>
import('@bolttech/atoms-input').then((module) => ({
default: module.Input,
}))
),
name: 'inputasynccomponent',
},
];
```
### from v2 to v3
Previously, mappers was two lists: `mappings` and `propsMappings`, now it's a single list, a simple example how to refactor a mapper:
```typescript
//v2
const mappings = {
input: { component: Input },
};
const propsMappings = {
input: {
getValue: 'onChangeCallback',
setValue: 'data',
setErrorMessage: 'errorMessageArray',
setErrorState: 'isErrored',
onBlur: 'onBlurCallback',
onFocus: 'onFocusCallback',
onKeyUp: 'onKeyUpCallback',
onKeyDown: 'onKeyDownCallback',
},
};
//v3
const mappers = [
{
component: Input,
componentName: 'input',
events: {
getValue: 'onChangeCallback',
setValue: 'data',
setErrorMessage: 'errorMessageArray',
setErrorState: 'isErrored',
onBlur: 'onBlurCallback',
onFocus: 'onFocusCallback',
onKeyUp: 'onKeyUpCallback',
onKeyDown: 'onKeyDownCallback',
},
valueChangeEvent: (event: unknown) => {
return (event as SyntheticEvent<HTMLInputElement>).currentTarget.value;
},
},
];
```
for bolltech components, there are `valueChangeEvent` default functions provided by form-engine:
- defaultChangeEvent - `atoms/input` | `atoms/textarea`
- checkedChangeEvent - `atoms/checkbox`
- valueChangeEvent - `atoms/input` | `atoms/textarea`
- datepickerChangeEvent - `molecules/datepicker`
- dropdownChangeEvent - `molecules/dropdown`
Example:
```typescript
import { Input } from '@bolttech/atoms-input';
import { defaultChangeEvent } from '@bolttech/form-engine';
const mapper = [
{
component: Input,
componentName: 'input',
events: {
getValue: 'onChange',
setValue: 'value',
setErrorMessage: 'errorMessage',
onBlur: 'onBlur',
onFocus: 'onFocus',
onKeyUp: 'onKeyUp',
onKeyDown: 'onKeyUpCapture',
},
valueChangeEvent: defaultChangeEvent,
},
];
```
<a id="form-group-context"></a>
## **Form Group Context**
<a id="formgroupcontextprovider"></a>
## **FormGroupContextProvider**
Provider of the context surrounding the child components, providing the state and functions to manage the group of forms.
### Props
| Prop | Type | Description |
| --------- | ---------------------- | ------------------------------------------------------------------------------------------------------ |
| mappers | TMapper<ElementType>[] | Array of mappers for form element types. Allow you to map your own components to be used with the form |
| debugMode | boolean | Optional flag to enable debug mode (default: `false`). |
| config | TSchemaFormConfig | Optional configuration object to set api and events debounce time |
### Implementation
- Creates a reference to the form group instance.
- Defines functions for adding, getting, and removing forms from the group.
- Defines a function to print the form group instance.
- Defines a function to submit multiple forms via the index.
- Defines the value of the context with the created functions and states.
- Returns the context provider involving the child components.
#### Calling provider
```typescript
import React from 'react';
import { FormGroupContextProvider } from '@bolttech/form-engine'; // Import the previously created provider
import { mappers } from 'project/mappers'; // mappers defined on the previous topic
const App = ({ children }: React.PropsWithChildren): React.ReactElement => {
const debugMode = true; // Enable debug mode
return (
<FormGroupContextProvider mappers={mappers} debugMode={debugMode}>
{children}
</FormGroupContextProvider>
);
};
export default App;
```
You now can use in your [form](#react-form-) the mapped components with names `input` and `dropdown`.
Also note the data in `TMapper.events`. There you can map up to five form functionalities per component
| Key | Functionality |
| --------------- | -------------------------------------------------------------------------------------------------------------------- |
| getValue | The name of your component prop that will give back the selected value. |
| setValue | Prop name that receives the value |
| setErrorMessage | Component prop name to receive an error message in case this field will have error and error message is configured |
| setErrorState | Component prop name to receive a boolean indicating if the field has an error or not according to the configurations |
| onBlur | Prop name that is called when field is blured |
| onFocus | Prop name that is called when field is focused |
| onKeyUp | Prop name that is called when user releases a key on field |
| onKeyDown | Prop name that is called when user presses a key on field |
[DEPRECIATED] You can also use default prop names for functionalities like:
```javascript
import Input from 'Components/Input';
import Dropdown from 'Components/Dropdown';
const Mappings = {
inputForm: { component: Input },
dropdownForm: { component: Dropdown },
};
const propsMapping = {
__default__: {
getValue: 'onChangeCallback',
setValue: 'data',
setErrorMessage: 'errorMessageArray',
onBlur: 'onBlurCallback',
onFocus: 'onFocusCallback',
onKeyUp: 'onKeyUpCallback',
onKeyDown: 'onKeyDownCallback',
},
};
```
[DEPRECIATED] This will make form search for those names in all your components that do not have split mapping.
<a id="useformgroupcontext"></a>
## **useFormGroupContext**
Hook that facilitates the use of the FormGroupContext context in functional components.
- Checks if the context is set or creates an isolated context that will only be accessible on the component that is defined.
- Returns the context.
### What comes from
- `addForm`: Function to add a form to the group.
- `getForm`: Function to obtain a specific form from the group.
- `removeForm`: Function to remove a form from the group.
- `formGroupInstance`: Instance of the form group.
- `printFormGroupInstance`: Function to print the form group instance.
- `submitMultipleFormsByIndex`: Function to submit multiple forms by index.
```typescript
type TFormContext = {
addForm: (payload: { key: string; formInstance: TFormCore }) => void;
getForm: (payload: { key: string }) => FormCore | undefined;
removeForm: (payload: { key: string }) => void;
formGroupInstance: TFormGroup;
printFormGroupInstance: () => void;
submitMultipleFormsByIndex: (indexes: string[]) => TFormValues;
};
```
### Example
```typescript
import React from 'react';
import { useFormGroupContext } from '@bolttech/form-engine'; // Import the previously created hook
const FormComponent = (): React.ReactElement => {
const { addForm, removeForm, getForm, printFormGroupInstance, submitMultipleFormsByIndex, debugMode } = useFormGroupContext();
const handleAddForm = () => {
const key = 'form1';
const formInstance = new FormCore(); // Assuming FormCore is an existing class
addForm({ key, formInstance });
};
const handleRemoveForm = () => {
const key = 'form1';
removeForm({ key });
};
const handleGetForm = () => {
const key = 'form1';
const form = getForm({ key });
console.log(form);
};
const handleSubmitForms = () => {
const indexes = ['form1', 'form2'];
const formValues = submitMultipleFormsByIndex(indexes);
console.log(formValues);
};
return (
<div>
<button onClick={handleAddForm}>Add Form</button>
<button onClick={handleRemoveForm}>Remove Form</button>
<button onClick={handleGetForm}>Get Form</button>
<button onClick={handleSubmitForms}>Submit Forms</button>
<button onClick={printFormGroupInstance}>Print Form Group Instance</button>
{debugMode && <p>Debug mode is enabled</p>}
</div>
);
};
export default FormComponent;
```
<a id="form"></a>
## **Form**
After configuring the provider, `<Form />` components lets you render a form
### Props
| Prop | Type | Description |
| ----------------------------------- | ---------------------------------------------------------------------------------- | ------------ |
| [DEPRECIATED] disable | boolean | Disable all form inputs. It will use the default htm disable attribute |
| [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 |
| index | string | Form identified. One will be generated as default if omitted |
| [DEPRECIATED] hooks | THooks | Provide functions to run on certain life-cycle events |
| iVars | Object | One object with internal variables to be used in form with data binding |
| initialValues | Object | Object with form initial values that will map to a field. |
| Schema | TSchema | Form Schema |
| [DEPRECIATED] autoComplete | string | HTML autocomplete |
| className | string | Allow to style form |
| onSubmit | callback(TFormValues) | Will be called when there is a submit action in the form |
| onData | callback(TFormData) | Will be called when any field data change. The arguments will let you know which field changed and the field configuration |
| onBlur | callback(TFieldEvent) | Will be called when any field blured. The arguments will let you know which field blured and the field configuration |
| onFocus | callback(TFieldEvent) | Will be called when any field focused change. The arguments will let you know which field focused and the field configuration |
| onMount | callback(TFormValues,TComponent, TField) | Will be called when some field mounted. Its called with the field that information that mounted. |
| [DEPRECIATED] onStep | callback(TFormValues) | Called when a form step changed |
| [DEPRECIATED] onLog | callback(TLoggingEvent) | Called on each log, if the logging is enabled |
| [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 |
| onClick | onClick(TFieldEvent) | Callback function that runs on each component click |
| onApiResponse | onApiResponse(TFieldEvent) | Callback function that runs on each component after api call. |
| [DEPRECIATED] onFieldRehydrate | onFieldRehydrate?(values: TFormValues, component: TComponent, field: TField): void | This callback is called whenever some form field was rehydrated |
| [DEPRECIATED] renderLoading | renderLoading?(): ReactElement; | Component to render while the schema has not rendered |
| [DEPRECIATED] onFormMount | onFormMount?(values: TFormValues): void; | Called when the form finished mounted |
| [DEPRECIATED] formattedDataDefaults | Object | Some default data to fields when they are undefined |
| [DEPRECIATED] submitOnValidOnly | boolean | Boolean indicating if form can be submitted even if it is invalid |
| [DEPRECIATED] renderFieldWrapper | renderFieldWrapper(component: TComponent, children: ReactElement[]) | Function that allows to insert a wrapper in place of a component or wrapping the component |
| onApiRequest | onApiRequest(TFieldEvent) | Callback function that runs when an api call starts |
| onChange | onFieldChange(TFieldEvent) | Callback function that runs on each component value changes
| onKeyDown | onKeyDown(TFieldEvent) | Callback function that runs on each key down event |
| onKeyUp | onKeyUp(TFieldEvent) | Callback function that runs on each key up event |
| onCleared | onCleared(TFieldEvent) | Callback function that runs on a value that has been changed by resetValues event |
| onUnmount | onUnmount(TFieldEvent) | Callback function that runs when a field is unmounted or hidden by a visibility condition rule (use with caution) |
### Example
A simple example of rendering a basic form
```javascript
<Form schema={schema} />
```
<a id="submit-form"></a>
## **Submit Form**
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
### Example:
```typescript
const schema = {
index: 'form1',
components: [
{
name: 'firstName',
component: 'input',
props: {
label: 'first name',
},
},
{
name: 'lastName',
component: 'input',
props: {
label: 'lase name',
},
},
{
name: 'submitButton',
component: 'button',
props: {
type: 'submit',
text: 'submit form',
},
},
],
};
const Comp = () => {
const handleSubmit = (payload: TFormValues<unknown>) => {
const values = payload.values;
userService
.addNewUser(values)
.then((res) => {
router.push(`/plans?hash=${res.hash}`);
})
.catch((e) => {
logService.push(e);
router.push(`/errorPage`);
});
};
return <Form schema={schema} onSubmit={handleSubmit} />;
};
```
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
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
have a `Form` component and event callback functions needs to be setted
<a id="schema"></a>
## **schema**
Schema is the structure of the form, it will contain the logic to be rendered and configurations of the fields to apply dynamic logic
| Prop | Type | Description |
| ----------------------------------------------------------------------------------------------------------- | ----------------------- | ----------------------------------------------------------------------- |
| [index](../../docs/form-engine-core/src/interfaces/schema/interfaces/IFormSchema.md#index) | string | unique form id to handle multiple form on form group |
| [action](../../docs/form-engine-core/src/interfaces/schema/interfaces/IFormSchema.md#action)? | string | WIP: HTML form native action property to handle native form submissions |
| [method](../../docs/form-engine-core/src/interfaces/schema/interfaces/IFormSchema.md#method)? | string | WIP: HTML form native method property to handle native form submissions |
| [config](../../docs/form-engine-core/src/interfaces/schema/interfaces/IFormSchema.md#config)? | TSchemaFormConfig | Optional configuration object to set api and events debounce time |
| [initialValues](../../docs/form-engine-core/src/interfaces/schema/interfaces/IFormSchema.md#initialvalues)? | Record<string, unknown> | initial values to be loaded on the form |
| [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 |
| [components](../../docs/form-engine-core/src/interfaces/schema/interfaces/IFormSchema.md#components)? | IComponentSchema[] | components to be rendered defined on the mappers |
this root configuration can be defined onto the `Form` component except the `components`
### Example
```typescript
const schema: IFormSchema = {
index: 'form1',
components: [
{
component: 'input',
name: 'input1',
props: {
label: 'input1',
},
},
{
component: 'input',
name: 'input2',
props: {
label: 'input2',
},
},
],
};
```
<a id="schema-components"></a>
## **schema components**
Schema components contains the information of the component that will be rendered and the configurations he will exectute
| Prop | Type | Description |
| ------------------------------------------------------------------------------------------------------------------------------ | -------------------- | ------------------------------------------------------------------------------------------- |
| [component](../../docs/form-engine-core/src/interfaces/schema/interfaces/IComponentSchema.md#component) | string | component name defined on schema to render the correspondent component |
| [props](../../docs/form-engine-core/src/interfaces/schema/interfaces/IComponentSchema.md#props)? | TProps | props of the component ex: label |
| [name](../../docs/form-engine-core/src/interfaces/schema/interfaces/IComponentSchema.md#name) | string | unique id to identify the field onto form-engine |
| [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' |
| [validations](../../docs/form-engine-core/src/interfaces/schema/interfaces/IComponentSchema.md#validations)? | TValidations | validations configuration described below |
| [api](../../docs/form-engine-core/src/interfaces/schema/interfaces/IComponentSchema.md#api)? | TApiEvent | api configuration described below |
| [visibilityConditions](../../docs/form-engine-core/src/interfaces/schema/interfaces/IComponentSchema.md#visibilityconditions)? | TVisibility[] | visibilityConditions configuration described below |
| [resetValues](../../docs/form-engine-core/src/interfaces/schema/interfaces/IComponentSchema.md#resetvalues)? | TResetValueMethods[] | resetValues configuration described below |
| [formatters](../../docs/form-engine-core/src/interfaces/schema/interfaces/IComponentSchema.md#formatters)? | TFormatters | formatters configuration described below |
| [masks](../../docs/form-engine-core/src/interfaces/schema/interfaces/IComponentSchema.md#masks)? | TMasks | masks configuration described below |
| [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) |
### Example
```typescript
{
component: 'input',
name: 'input1',
props: {
label: 'input1',
},
nameToSubmit: 'person.profile.firstName',
validations: {
methods: {
required: true,
},
eventMessages: {
ON_FIELD_CHANGE: ['required'],
},
messages: {
required: 'Value is required',
},
},
api: {
defaultConfig: {
config: {
method: 'GET',
url: 'https://api.chucknorris.io/jokes/random',
resultPath: 'value',
},
events: ['ON_FIELD_MOUNT'],
},
},
visibilityConditions: [
{
validations: {
isNumber: true,
},
events: ['ON_FIELD_CHANGE'],
fields: ['input2'],
},
],
resetValues: [{
validations: {
isNumber: true,
},
events: ['ON_FIELD_CHANGE'],
fields: ['input2'],
resettledValue: ['resettledValue from input1'],
}]
}
```
Check the [TSDocs](../../docs/form-engine-core/src/interfaces/schema/interfaces/IComponentSchema.md) from `IComponentSchema` on form-engine-core
<a id="formatters"></a>
## **formatters**
formatters are methods that will format the input inserted on any field, they will format a value, regardless the event type.
| Prop | Type | Description |
| ------------------------------------------------------------------------------------------------------------ | ------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| [callback](../../docs/form-engine-core/src/types/schema/type-aliases/TFormatters.md#callback)? | (value) => void | Custom formatter callback function |
| [capitalize](../../docs/form-engine-core/src/types/schema/type-aliases/TFormatters.md#capitalize)? | boolean | Capitalize the value |
| [dotEvery3chars](../../docs/form-engine-core/src/types/schema/type-aliases/TFormatters.md#dotevery3chars)? | boolean | Add a dot every 3 characters |
| [gapsCreditCard](../../docs/form-engine-core/src/types/schema/type-aliases/TFormatters.md#gapscreditcard) | string[] | Gaps to insert in credit card numbers |
| [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 |
| [onlyFloatNumber](../../docs/form-engine-core/src/types/schema/type-aliases/TFormatters.md#onlyfloatnumber)? | TCurrencyMask | Allow only float numbers with specific precision and decimal |
| [onlyLetters](../../docs/form-engine-core/src/types/schema/type-aliases/TFormatters.md#onlyletters)? | boolean | Allow only letters |
| [onlyNumbers](../../docs/form-engine-core/src/types/schema/type-aliases/TFormatters.md#onlynumbers)? | boolean | Allow only numbers |
| [regex](../../docs/form-engine-core/src/types/schema/type-aliases/TFormatters.md#regex)? | string | Regular expression for formatting |
| [splitter](../../docs/form-engine-core/src/types/schema/type-aliases/TFormatters.md#splitter)? | TSplitterFormatterValue[] | Splitter values for formatting |
| [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 |
| [uppercase](../../docs/form-engine-core/src/types/schema/type-aliases/TFormatters.md#uppercase)? | boolean | Convert the value to uppercase |
### Avaliable formatters
Check the [TSDocs](../../docs/form-engine-core/src/types/schema/type-aliases/TFormatters.md) from `TFormatters` on form-engine-core
<a id="masks"></a>
## **masks**
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.
| Prop | Type | Description |
| --------------------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------ |
| [card](../../docs/form-engine-core/src/types/schema/type-aliases/TMasks.md#card)? | boolean | Mask for card values |
| [cardDate](../../docs/form-engine-core/src/types/schema/type-aliases/TMasks.md#carddate)? | boolean | Mask for card date values |
| [currency](../../docs/form-engine-core/src/types/schema/type-aliases/TMasks.md#currency)? | TCurrencyMask | Mask for currency values |
| [custom](../../docs/form-engine-core/src/types/schema/type-aliases/TMasks.md#custom) | string | Custom mask pattern |
| [fein](../../docs/form-engine-core/src/types/schema/type-aliases/TMasks.md#fein)? | boolean | Mask for FEIN (Federal Employer Identification Number) |
| [generic](../../docs/form-engine-core/src/types/schema/type-aliases/TMasks.md#generic)? | TMaskGeneric[] | Array of generic masks |
| [replaceAll](../../docs/form-engine-core/src/types/schema/type-aliases/TMasks.md#replaceall)? | string | Value to replace all matches |
| [secureCreditCard](../../docs/form-engine-core/src/types/schema/type-aliases/TMasks.md#securecreditcard)? | boolean | Mask for securing credit card values |
| [callback](../../docs/form-engine-core/src/types/schema/type-aliases/TMasks.md#callback)? | (value, masks) => void | Custom mask callback function |
### Avaliable masks
Check the [TSDocs](../../docs/form-engine-core/src/types/schema/type-aliases/TMasks.md) from `TMasks` on form-engine-core
### From v2 to v3
```typescript
//v2
const formatters = {
ON_FIELD_MOUNT: {
upperCase: true,
},
ON_FIELD_CHANGE: {
upperCase: true,
},
};
//v3
const formatters = {
upperCase: true,
};
```
<a id="nametosubmit"></a>
## **nameToSubmit**
nameToSubmit is a component property that will set the submit value to a custom dot notation path or key
### Example
```typescript
const component = {
component: 'input'
name: 'input1'
nameToSubmit: 'person.profile.firstName'
}
```
when calling the `onSubmit` or `onData` the field section of this field will output:
```json
{
"person": {
"profile": {
"firstName": "inserted value from input1"
}
}
}
```
<a id="props"></a>
## **props**
props let you add any prop the component you are using from the mappers that exists on the component
### Example
```typescript
const component = {
component: 'input'
name: 'input1'
props: {
label: 'input1 label'
}
}
```
If the mapper of `input` has the `label` prop avaliable, it will be set with `input1 label` value
<a id="validations"></a>
## **validations**
validations let you set rules in order to validate a field, then show errorMessages based on an event occured
| Prop | Type | Description |
| -------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| methods | TSchemaValidation | validations rules to be used to validate the field |
| eventMessages? | Partial<Record<TEvents, Partial<keyof TValidationMethods>[]>> | object with the event occured, and the messages to display on the occured event |
| messages? | TErrorMessages | object with the validations and the respective error message to display |
### Avaliable validations
Check the [TSDocs](../../docs/form-engine-core/src/types/schema/type-aliases/TValidationMethods.md) from `TValidationMethods` on form-engine-core
### From v2 to v3
```typescript
//v2
const component: {
component: 'input';
name: 'input1';
validations: {
ON_FIELD_BLUR: {
required: true;
};
ON_FIELD_CHANGE: {
regex: '^[0-9]{2}/[0-9]{2}$';
};
errorMessages: {
required: 'field required';
regex: 'invalid format';
};
};
};
//v3
const validations: {
methods: {
required: true;
regex: '^[0-9]{2}/[0-9]{2}$';
};
eventMessages: {
ON_FIELD_BLUR: ['required'];
ON_FIELD_CHANGE: ['regex'];
};
messages: {
required: 'field required';
regex: 'invalid format';
};
};
```
### named validations
if you want to make a name validation, instead of using a `TValidationMethods`, you can write a custom name with `TValidationMethods` inside, ex:
```typescript
const validations: {
methods: {
custom1: {
regex: '^[0-5]{4}/[0-3]{6}$';
};
custom2: {
regex: '^[0-9]{2}/[0-9]{2}$';
};
};
eventMessages: {
ON_FIELD_BLUR: ['custom1'];
ON_FIELD_CHANGE: ['custom2'];
};
messages: {
custom1: 'field required';
custom2: 'invalid format';
};
};
```
This is useful if you want to make more than one rule of the same `TValidationMethods`,
### default error message
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
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.
<a id="api"></a>
## **api**
Api let's you make a request and use the response values onto fields
The configuration is as it follows:
| Prop | Type | Description |
| -------------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| defaultConfig? | TEvent<TApiConfig> | this is the default config, preferred if you only have 1 API request on a field |
| 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 |
Each config you opt to use, needs to be filled with an API configuration, the configuration is as it follows:
| Prop | Type | Description |
| --------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | ------------------------------------------------------------------------------------- |
| [method](../../docs/form-engine-core/src/types/schema/type-aliases/TApiConfig.md#method) | 'GET' or 'POST' | HTTP method (only GET or POST) |
| [url](../../docs/form-engine-core/src/types/schema/type-aliases/TApiConfig.md#url) | string | Request url ex: http://mockapi.org |
| [body](../../docs/form-engine-core/src/types/schema/type-aliases/TApiConfig.md#body)? | Record<string, unknown> | Request body (only POST requests) |
| [headers](../../docs/form-engine-core/src/types/schema/type-aliases/TApiConfig.md#headers)? | OutgoingHttpHeaders | Avaliable HTTP headers |
| [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) |
| [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 |
| [fallbackValue](../../docs/form-engine-core/src/types/schema/type-aliases/TApiConfig.md#fallbackvalue)? | unknown | default value to return if the API returns error |
| [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) |
| [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 |
| [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 |
### From v2 to v3
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
structure as you pass to the `config` without a key name
```typescript
//v2
const api = {
ON_FIELD_BLUR: [
{
method: 'GET',
url: 'https://api.chucknorris.io/jokes/random',
scope: 'chuck',
},
],
ON_FIELD_CHANGE: [
{
method: 'GET',
url: 'https://api.chucknorris.io/jokes/random',
scope: 'chuck',
},
],
};
//v3
const api = {
config: {
chuck: {
config: {
method: 'GET',
url: 'https://api.chucknorris.io/jokes/random',
},
events: ['ON_FIELD_BLUR', 'ON_FIELD_CHANGE'],
},
},
};
```
the API result is commonly used with `templating`, check [templating](#templating) section
<a id="resetvalues"></a>
## **resetValues**
resetValues lets you change input values with the same rules as validations
| Prop | Type | Description |
| --------------------------------------------------------------------------------------------- | -------------------- | ---------------------------------------------------------------------------------- |
| [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 |
| fields | string[] or string | field or fields that will recieve the resettled value |
| events | Partial<TEvents>[] | events that will trigger the validation |
| resettledValue | unknown[] or unknown | value or values to be set on the specified fields |
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.
### from v2 to v3
`clearFields` is changed to `resetValues`
```typescript
//v2
const clearFields = {
ON_FIELD_CLICK: [
{
fields: ['input1', 'input2', 'dropdown'],
clearedValue: ['', 'Value has change', 'all'],
},
],
ON_FIELD_BLUR: [
{
fields: ['input1', 'input2', 'dropdown'],
clearedValue: ['', 'Value has change', 'all'],
},
],
};
//v3
const resetValues = [
{
fields: ['input1', 'input2', 'dropdown'],
resettledValue: ['', 'Value has change', 'all'],
events: ['ON_FIELD_CLICK', 'ON_FIELD_BLUR'],
},
];
```
<a id="visibilityconditions"></a>
## **visibilityConditions**
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
| Prop | Type | Description |
| --------------- | ------------------ | ---------------------------------------------------------------------------------- |
| showOnlyIfTrue? | boolean | shows the fields specified is condition is true |
| validations | TSchemaValidation | validations rules to be validated to reset the value to the configuration provided |
| fields | string[] or string | field or fields that will be shown or hidden |
| events | Partial<TEvents>[] | events that will trigger the validation |
### From v2 to v3
```typescript
//v2
const visibilityConditions = {
ON_FIELD_MOUNT: [
{
validations: {
value: true,
},
fieldNames: ['roofUpdatedYear'],
},
],
ON_FIELD_CHANGE: [
{
validations: {
value: true,
},
fieldNames: ['roofUpdatedYear'],
},
],
};
//v3
const visibilityConditions = [
{
validations: {
value: true,
},
fields: 'roofUpdatedYear',
events: ['ON_FIELD_MOUNT', 'ON_FIELD_CHANGE'],
},
];
```
<a id="resetpropertyvalues"></a>
## **resetPropertyValues**
resetPropertyValues will change a property value based on validation rules
> WARNING: do not rely on this to make mutations on your properties, templating already is a powerful tool and wit