@rjsf/core 5.24.4 → 5.24.7
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/dist/core.umd.js +602 -601
- package/dist/index.esm.js +602 -601
- package/dist/index.esm.js.map +2 -2
- package/dist/index.js +602 -601
- package/dist/index.js.map +2 -2
- package/lib/components/Form.d.ts +1 -0
- package/lib/components/Form.d.ts.map +1 -0
- package/lib/components/Form.js +293 -293
- package/lib/components/fields/ArrayField.d.ts +1 -0
- package/lib/components/fields/ArrayField.d.ts.map +1 -0
- package/lib/components/fields/ArrayField.js +190 -194
- package/lib/components/fields/BooleanField.d.ts +1 -0
- package/lib/components/fields/BooleanField.d.ts.map +1 -0
- package/lib/components/fields/BooleanField.js +3 -5
- package/lib/components/fields/MultiSchemaField.d.ts +1 -0
- package/lib/components/fields/MultiSchemaField.d.ts.map +1 -0
- package/lib/components/fields/MultiSchemaField.js +30 -31
- package/lib/components/fields/NullField.d.ts +1 -0
- package/lib/components/fields/NullField.d.ts.map +1 -0
- package/lib/components/fields/NullField.js +0 -1
- package/lib/components/fields/NumberField.d.ts +1 -0
- package/lib/components/fields/NumberField.d.ts.map +1 -0
- package/lib/components/fields/NumberField.js +0 -1
- package/lib/components/fields/ObjectField.d.ts +1 -0
- package/lib/components/fields/ObjectField.d.ts.map +1 -0
- package/lib/components/fields/ObjectField.js +139 -145
- package/lib/components/fields/SchemaField.d.ts +1 -0
- package/lib/components/fields/SchemaField.d.ts.map +1 -0
- package/lib/components/fields/SchemaField.js +7 -9
- package/lib/components/fields/StringField.d.ts +1 -0
- package/lib/components/fields/StringField.d.ts.map +1 -0
- package/lib/components/fields/StringField.js +1 -3
- package/lib/components/fields/index.d.ts +1 -0
- package/lib/components/fields/index.d.ts.map +1 -0
- package/lib/components/fields/index.js +8 -9
- package/lib/components/templates/ArrayFieldDescriptionTemplate.d.ts +1 -0
- package/lib/components/templates/ArrayFieldDescriptionTemplate.d.ts.map +1 -0
- package/lib/components/templates/ArrayFieldDescriptionTemplate.js +0 -1
- package/lib/components/templates/ArrayFieldItemTemplate.d.ts +1 -0
- package/lib/components/templates/ArrayFieldItemTemplate.d.ts.map +1 -0
- package/lib/components/templates/ArrayFieldItemTemplate.js +0 -1
- package/lib/components/templates/ArrayFieldTemplate.d.ts +1 -0
- package/lib/components/templates/ArrayFieldTemplate.d.ts.map +1 -0
- package/lib/components/templates/ArrayFieldTemplate.js +0 -1
- package/lib/components/templates/ArrayFieldTitleTemplate.d.ts +1 -0
- package/lib/components/templates/ArrayFieldTitleTemplate.d.ts.map +1 -0
- package/lib/components/templates/ArrayFieldTitleTemplate.js +0 -1
- package/lib/components/templates/BaseInputTemplate.d.ts +1 -0
- package/lib/components/templates/BaseInputTemplate.d.ts.map +1 -0
- package/lib/components/templates/BaseInputTemplate.js +0 -1
- package/lib/components/templates/ButtonTemplates/AddButton.d.ts +1 -0
- package/lib/components/templates/ButtonTemplates/AddButton.d.ts.map +1 -0
- package/lib/components/templates/ButtonTemplates/AddButton.js +1 -2
- package/lib/components/templates/ButtonTemplates/IconButton.d.ts +1 -0
- package/lib/components/templates/ButtonTemplates/IconButton.d.ts.map +1 -0
- package/lib/components/templates/ButtonTemplates/IconButton.js +0 -1
- package/lib/components/templates/ButtonTemplates/SubmitButton.d.ts +1 -0
- package/lib/components/templates/ButtonTemplates/SubmitButton.d.ts.map +1 -0
- package/lib/components/templates/ButtonTemplates/SubmitButton.js +0 -1
- package/lib/components/templates/ButtonTemplates/index.d.ts +1 -0
- package/lib/components/templates/ButtonTemplates/index.d.ts.map +1 -0
- package/lib/components/templates/ButtonTemplates/index.js +3 -4
- package/lib/components/templates/DescriptionField.d.ts +1 -0
- package/lib/components/templates/DescriptionField.d.ts.map +1 -0
- package/lib/components/templates/DescriptionField.js +0 -1
- package/lib/components/templates/ErrorList.d.ts +1 -0
- package/lib/components/templates/ErrorList.d.ts.map +1 -0
- package/lib/components/templates/ErrorList.js +0 -1
- package/lib/components/templates/FieldErrorTemplate.d.ts +1 -0
- package/lib/components/templates/FieldErrorTemplate.d.ts.map +1 -0
- package/lib/components/templates/FieldErrorTemplate.js +0 -1
- package/lib/components/templates/FieldHelpTemplate.d.ts +1 -0
- package/lib/components/templates/FieldHelpTemplate.d.ts.map +1 -0
- package/lib/components/templates/FieldHelpTemplate.js +0 -1
- package/lib/components/templates/FieldTemplate/FieldTemplate.d.ts +1 -0
- package/lib/components/templates/FieldTemplate/FieldTemplate.d.ts.map +1 -0
- package/lib/components/templates/FieldTemplate/FieldTemplate.js +1 -2
- package/lib/components/templates/FieldTemplate/Label.d.ts +1 -0
- package/lib/components/templates/FieldTemplate/Label.d.ts.map +1 -0
- package/lib/components/templates/FieldTemplate/Label.js +0 -1
- package/lib/components/templates/FieldTemplate/index.d.ts +2 -1
- package/lib/components/templates/FieldTemplate/index.d.ts.map +1 -0
- package/lib/components/templates/FieldTemplate/index.js +1 -2
- package/lib/components/templates/ObjectFieldTemplate.d.ts +1 -0
- package/lib/components/templates/ObjectFieldTemplate.d.ts.map +1 -0
- package/lib/components/templates/ObjectFieldTemplate.js +0 -1
- package/lib/components/templates/TitleField.d.ts +1 -0
- package/lib/components/templates/TitleField.d.ts.map +1 -0
- package/lib/components/templates/TitleField.js +0 -1
- package/lib/components/templates/UnsupportedField.d.ts +1 -0
- package/lib/components/templates/UnsupportedField.d.ts.map +1 -0
- package/lib/components/templates/UnsupportedField.js +0 -1
- package/lib/components/templates/WrapIfAdditionalTemplate.d.ts +1 -0
- package/lib/components/templates/WrapIfAdditionalTemplate.d.ts.map +1 -0
- package/lib/components/templates/WrapIfAdditionalTemplate.js +1 -2
- package/lib/components/templates/index.d.ts +1 -0
- package/lib/components/templates/index.d.ts.map +1 -0
- package/lib/components/templates/index.js +15 -16
- package/lib/components/widgets/AltDateTimeWidget.d.ts +1 -0
- package/lib/components/widgets/AltDateTimeWidget.d.ts.map +1 -0
- package/lib/components/widgets/AltDateTimeWidget.js +0 -1
- package/lib/components/widgets/AltDateWidget.d.ts +1 -0
- package/lib/components/widgets/AltDateWidget.d.ts.map +1 -0
- package/lib/components/widgets/AltDateWidget.js +0 -1
- package/lib/components/widgets/CheckboxWidget.d.ts +1 -0
- package/lib/components/widgets/CheckboxWidget.d.ts.map +1 -0
- package/lib/components/widgets/CheckboxWidget.js +1 -3
- package/lib/components/widgets/CheckboxesWidget.d.ts +1 -0
- package/lib/components/widgets/CheckboxesWidget.d.ts.map +1 -0
- package/lib/components/widgets/CheckboxesWidget.js +0 -1
- package/lib/components/widgets/ColorWidget.d.ts +1 -0
- package/lib/components/widgets/ColorWidget.d.ts.map +1 -0
- package/lib/components/widgets/ColorWidget.js +0 -1
- package/lib/components/widgets/DateTimeWidget.d.ts +1 -0
- package/lib/components/widgets/DateTimeWidget.d.ts.map +1 -0
- package/lib/components/widgets/DateTimeWidget.js +0 -1
- package/lib/components/widgets/DateWidget.d.ts +1 -0
- package/lib/components/widgets/DateWidget.d.ts.map +1 -0
- package/lib/components/widgets/DateWidget.js +0 -1
- package/lib/components/widgets/EmailWidget.d.ts +1 -0
- package/lib/components/widgets/EmailWidget.d.ts.map +1 -0
- package/lib/components/widgets/EmailWidget.js +0 -1
- package/lib/components/widgets/FileWidget.d.ts +1 -0
- package/lib/components/widgets/FileWidget.d.ts.map +1 -0
- package/lib/components/widgets/FileWidget.js +1 -3
- package/lib/components/widgets/HiddenWidget.d.ts +1 -0
- package/lib/components/widgets/HiddenWidget.d.ts.map +1 -0
- package/lib/components/widgets/HiddenWidget.js +0 -1
- package/lib/components/widgets/PasswordWidget.d.ts +1 -0
- package/lib/components/widgets/PasswordWidget.d.ts.map +1 -0
- package/lib/components/widgets/PasswordWidget.js +0 -1
- package/lib/components/widgets/RadioWidget.d.ts +1 -0
- package/lib/components/widgets/RadioWidget.d.ts.map +1 -0
- package/lib/components/widgets/RadioWidget.js +0 -1
- package/lib/components/widgets/RangeWidget.d.ts +1 -0
- package/lib/components/widgets/RangeWidget.d.ts.map +1 -0
- package/lib/components/widgets/RangeWidget.js +0 -1
- package/lib/components/widgets/SelectWidget.d.ts +1 -0
- package/lib/components/widgets/SelectWidget.d.ts.map +1 -0
- package/lib/components/widgets/SelectWidget.js +0 -1
- package/lib/components/widgets/TextWidget.d.ts +1 -0
- package/lib/components/widgets/TextWidget.d.ts.map +1 -0
- package/lib/components/widgets/TextWidget.js +0 -1
- package/lib/components/widgets/TextareaWidget.d.ts +1 -0
- package/lib/components/widgets/TextareaWidget.d.ts.map +1 -0
- package/lib/components/widgets/TextareaWidget.js +0 -1
- package/lib/components/widgets/TimeWidget.d.ts +1 -0
- package/lib/components/widgets/TimeWidget.d.ts.map +1 -0
- package/lib/components/widgets/TimeWidget.js +0 -1
- package/lib/components/widgets/URLWidget.d.ts +1 -0
- package/lib/components/widgets/URLWidget.d.ts.map +1 -0
- package/lib/components/widgets/URLWidget.js +0 -1
- package/lib/components/widgets/UpDownWidget.d.ts +1 -0
- package/lib/components/widgets/UpDownWidget.d.ts.map +1 -0
- package/lib/components/widgets/UpDownWidget.js +0 -1
- package/lib/components/widgets/index.d.ts +1 -0
- package/lib/components/widgets/index.d.ts.map +1 -0
- package/lib/components/widgets/index.js +19 -20
- package/lib/getDefaultRegistry.d.ts +1 -0
- package/lib/getDefaultRegistry.d.ts.map +1 -0
- package/lib/getDefaultRegistry.js +3 -4
- package/lib/index.d.ts +4 -3
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +3 -4
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/withTheme.d.ts +2 -1
- package/lib/withTheme.d.ts.map +1 -0
- package/lib/withTheme.js +6 -8
- package/package.json +31 -9
- package/src/tsconfig.json +14 -3
- package/lib/components/Form.js.map +0 -1
- package/lib/components/fields/ArrayField.js.map +0 -1
- package/lib/components/fields/BooleanField.js.map +0 -1
- package/lib/components/fields/MultiSchemaField.js.map +0 -1
- package/lib/components/fields/NullField.js.map +0 -1
- package/lib/components/fields/NumberField.js.map +0 -1
- package/lib/components/fields/ObjectField.js.map +0 -1
- package/lib/components/fields/SchemaField.js.map +0 -1
- package/lib/components/fields/StringField.js.map +0 -1
- package/lib/components/fields/index.js.map +0 -1
- package/lib/components/templates/ArrayFieldDescriptionTemplate.js.map +0 -1
- package/lib/components/templates/ArrayFieldItemTemplate.js.map +0 -1
- package/lib/components/templates/ArrayFieldTemplate.js.map +0 -1
- package/lib/components/templates/ArrayFieldTitleTemplate.js.map +0 -1
- package/lib/components/templates/BaseInputTemplate.js.map +0 -1
- package/lib/components/templates/ButtonTemplates/AddButton.js.map +0 -1
- package/lib/components/templates/ButtonTemplates/IconButton.js.map +0 -1
- package/lib/components/templates/ButtonTemplates/SubmitButton.js.map +0 -1
- package/lib/components/templates/ButtonTemplates/index.js.map +0 -1
- package/lib/components/templates/DescriptionField.js.map +0 -1
- package/lib/components/templates/ErrorList.js.map +0 -1
- package/lib/components/templates/FieldErrorTemplate.js.map +0 -1
- package/lib/components/templates/FieldHelpTemplate.js.map +0 -1
- package/lib/components/templates/FieldTemplate/FieldTemplate.js.map +0 -1
- package/lib/components/templates/FieldTemplate/Label.js.map +0 -1
- package/lib/components/templates/FieldTemplate/index.js.map +0 -1
- package/lib/components/templates/ObjectFieldTemplate.js.map +0 -1
- package/lib/components/templates/TitleField.js.map +0 -1
- package/lib/components/templates/UnsupportedField.js.map +0 -1
- package/lib/components/templates/WrapIfAdditionalTemplate.js.map +0 -1
- package/lib/components/templates/index.js.map +0 -1
- package/lib/components/widgets/AltDateTimeWidget.js.map +0 -1
- package/lib/components/widgets/AltDateWidget.js.map +0 -1
- package/lib/components/widgets/CheckboxWidget.js.map +0 -1
- package/lib/components/widgets/CheckboxesWidget.js.map +0 -1
- package/lib/components/widgets/ColorWidget.js.map +0 -1
- package/lib/components/widgets/DateTimeWidget.js.map +0 -1
- package/lib/components/widgets/DateWidget.js.map +0 -1
- package/lib/components/widgets/EmailWidget.js.map +0 -1
- package/lib/components/widgets/FileWidget.js.map +0 -1
- package/lib/components/widgets/HiddenWidget.js.map +0 -1
- package/lib/components/widgets/PasswordWidget.js.map +0 -1
- package/lib/components/widgets/RadioWidget.js.map +0 -1
- package/lib/components/widgets/RangeWidget.js.map +0 -1
- package/lib/components/widgets/SelectWidget.js.map +0 -1
- package/lib/components/widgets/TextWidget.js.map +0 -1
- package/lib/components/widgets/TextareaWidget.js.map +0 -1
- package/lib/components/widgets/TimeWidget.js.map +0 -1
- package/lib/components/widgets/URLWidget.js.map +0 -1
- package/lib/components/widgets/UpDownWidget.js.map +0 -1
- package/lib/components/widgets/index.js.map +0 -1
- package/lib/getDefaultRegistry.js.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/withTheme.js.map +0 -1
package/lib/components/Form.js
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Component, createRef } from 'react';
|
|
3
3
|
import { createSchemaUtils, deepEquals, getChangedFields, getTemplate, getUiOptions, isObject, mergeObjects, NAME_KEY, RJSF_ADDITIONAL_PROPERTIES_FLAG, shouldRender, SUBMIT_BTN_OPTIONS_KEY, toErrorList, UI_GLOBAL_OPTIONS_KEY, UI_OPTIONS_KEY, validationDataMerge, createErrorHandler, unwrapErrorHandler, } from '@rjsf/utils';
|
|
4
|
-
import _forEach from 'lodash/forEach';
|
|
5
|
-
import _get from 'lodash/get';
|
|
6
|
-
import _isEmpty from 'lodash/isEmpty';
|
|
7
|
-
import _isNil from 'lodash/isNil';
|
|
8
|
-
import _pick from 'lodash/pick';
|
|
9
|
-
import _toPath from 'lodash/toPath';
|
|
10
|
-
import getDefaultRegistry from '../getDefaultRegistry';
|
|
4
|
+
import _forEach from 'lodash-es/forEach.js';
|
|
5
|
+
import _get from 'lodash-es/get.js';
|
|
6
|
+
import _isEmpty from 'lodash-es/isEmpty.js';
|
|
7
|
+
import _isNil from 'lodash-es/isNil.js';
|
|
8
|
+
import _pick from 'lodash-es/pick.js';
|
|
9
|
+
import _toPath from 'lodash-es/toPath.js';
|
|
10
|
+
import getDefaultRegistry from '../getDefaultRegistry.js';
|
|
11
11
|
/** The `Form` component renders the outer form and all the fields defined in the `schema` */
|
|
12
12
|
export default class Form extends Component {
|
|
13
|
+
/** The ref used to hold the `form` element, this needs to be `any` because `tagName` or `_internalFormWrapper` can
|
|
14
|
+
* provide any possible type here
|
|
15
|
+
*/
|
|
16
|
+
formElement;
|
|
13
17
|
/** Constructs the `Form` from the `props`. Will setup the initial state from the props. It will also call the
|
|
14
18
|
* `onChange` handler if the initially provided `formData` is modified to add missing default values as part of the
|
|
15
19
|
* state construction.
|
|
@@ -18,280 +22,6 @@ export default class Form extends Component {
|
|
|
18
22
|
*/
|
|
19
23
|
constructor(props) {
|
|
20
24
|
super(props);
|
|
21
|
-
/** Returns the `formData` with only the elements specified in the `fields` list
|
|
22
|
-
*
|
|
23
|
-
* @param formData - The data for the `Form`
|
|
24
|
-
* @param fields - The fields to keep while filtering
|
|
25
|
-
*/
|
|
26
|
-
this.getUsedFormData = (formData, fields) => {
|
|
27
|
-
// For the case of a single input form
|
|
28
|
-
if (fields.length === 0 && typeof formData !== 'object') {
|
|
29
|
-
return formData;
|
|
30
|
-
}
|
|
31
|
-
// _pick has incorrect type definition, it works with string[][], because lodash/hasIn supports it
|
|
32
|
-
const data = _pick(formData, fields);
|
|
33
|
-
if (Array.isArray(formData)) {
|
|
34
|
-
return Object.keys(data).map((key) => data[key]);
|
|
35
|
-
}
|
|
36
|
-
return data;
|
|
37
|
-
};
|
|
38
|
-
/** Returns the list of field names from inspecting the `pathSchema` as well as using the `formData`
|
|
39
|
-
*
|
|
40
|
-
* @param pathSchema - The `PathSchema` object for the form
|
|
41
|
-
* @param [formData] - The form data to use while checking for empty objects/arrays
|
|
42
|
-
*/
|
|
43
|
-
this.getFieldNames = (pathSchema, formData) => {
|
|
44
|
-
const getAllPaths = (_obj, acc = [], paths = [[]]) => {
|
|
45
|
-
Object.keys(_obj).forEach((key) => {
|
|
46
|
-
if (typeof _obj[key] === 'object') {
|
|
47
|
-
const newPaths = paths.map((path) => [...path, key]);
|
|
48
|
-
// If an object is marked with additionalProperties, all its keys are valid
|
|
49
|
-
if (_obj[key][RJSF_ADDITIONAL_PROPERTIES_FLAG] && _obj[key][NAME_KEY] !== '') {
|
|
50
|
-
acc.push(_obj[key][NAME_KEY]);
|
|
51
|
-
}
|
|
52
|
-
else {
|
|
53
|
-
getAllPaths(_obj[key], acc, newPaths);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
else if (key === NAME_KEY && _obj[key] !== '') {
|
|
57
|
-
paths.forEach((path) => {
|
|
58
|
-
const formValue = _get(formData, path);
|
|
59
|
-
// adds path to fieldNames if it points to a value
|
|
60
|
-
// or an empty object/array
|
|
61
|
-
if (typeof formValue !== 'object' ||
|
|
62
|
-
_isEmpty(formValue) ||
|
|
63
|
-
(Array.isArray(formValue) && formValue.every((val) => typeof val !== 'object'))) {
|
|
64
|
-
acc.push(path);
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
return acc;
|
|
70
|
-
};
|
|
71
|
-
return getAllPaths(pathSchema);
|
|
72
|
-
};
|
|
73
|
-
/** Returns the `formData` after filtering to remove any extra data not in a form field
|
|
74
|
-
*
|
|
75
|
-
* @param formData - The data for the `Form`
|
|
76
|
-
* @returns The `formData` after omitting extra data
|
|
77
|
-
*/
|
|
78
|
-
this.omitExtraData = (formData) => {
|
|
79
|
-
const { schema, schemaUtils } = this.state;
|
|
80
|
-
const retrievedSchema = schemaUtils.retrieveSchema(schema, formData);
|
|
81
|
-
const pathSchema = schemaUtils.toPathSchema(retrievedSchema, '', formData);
|
|
82
|
-
const fieldNames = this.getFieldNames(pathSchema, formData);
|
|
83
|
-
const newFormData = this.getUsedFormData(formData, fieldNames);
|
|
84
|
-
return newFormData;
|
|
85
|
-
};
|
|
86
|
-
/** Function to handle changes made to a field in the `Form`. This handler receives an entirely new copy of the
|
|
87
|
-
* `formData` along with a new `ErrorSchema`. It will first update the `formData` with any missing default fields and
|
|
88
|
-
* then, if `omitExtraData` and `liveOmit` are turned on, the `formData` will be filtered to remove any extra data not
|
|
89
|
-
* in a form field. Then, the resulting formData will be validated if required. The state will be updated with the new
|
|
90
|
-
* updated (potentially filtered) `formData`, any errors that resulted from validation. Finally the `onChange`
|
|
91
|
-
* callback will be called if specified with the updated state.
|
|
92
|
-
*
|
|
93
|
-
* @param formData - The new form data from a change to a field
|
|
94
|
-
* @param newErrorSchema - The new `ErrorSchema` based on the field change
|
|
95
|
-
* @param id - The id of the field that caused the change
|
|
96
|
-
*/
|
|
97
|
-
this.onChange = (formData, newErrorSchema, id) => {
|
|
98
|
-
const { extraErrors, omitExtraData, liveOmit, noValidate, liveValidate, onChange } = this.props;
|
|
99
|
-
const { schemaUtils, schema } = this.state;
|
|
100
|
-
let retrievedSchema = this.state.retrievedSchema;
|
|
101
|
-
if (isObject(formData) || Array.isArray(formData)) {
|
|
102
|
-
const newState = this.getStateFromProps(this.props, formData);
|
|
103
|
-
formData = newState.formData;
|
|
104
|
-
retrievedSchema = newState.retrievedSchema;
|
|
105
|
-
}
|
|
106
|
-
const mustValidate = !noValidate && liveValidate;
|
|
107
|
-
let state = { formData, schema };
|
|
108
|
-
let newFormData = formData;
|
|
109
|
-
if (omitExtraData === true && liveOmit === true) {
|
|
110
|
-
newFormData = this.omitExtraData(formData);
|
|
111
|
-
state = {
|
|
112
|
-
formData: newFormData,
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
if (mustValidate) {
|
|
116
|
-
const schemaValidation = this.validate(newFormData, schema, schemaUtils, retrievedSchema);
|
|
117
|
-
let errors = schemaValidation.errors;
|
|
118
|
-
let errorSchema = schemaValidation.errorSchema;
|
|
119
|
-
const schemaValidationErrors = errors;
|
|
120
|
-
const schemaValidationErrorSchema = errorSchema;
|
|
121
|
-
if (extraErrors) {
|
|
122
|
-
const merged = validationDataMerge(schemaValidation, extraErrors);
|
|
123
|
-
errorSchema = merged.errorSchema;
|
|
124
|
-
errors = merged.errors;
|
|
125
|
-
}
|
|
126
|
-
// Merging 'newErrorSchema' into 'errorSchema' to display the custom raised errors.
|
|
127
|
-
if (newErrorSchema) {
|
|
128
|
-
const filteredErrors = this.filterErrorsBasedOnSchema(newErrorSchema, retrievedSchema, newFormData);
|
|
129
|
-
errorSchema = mergeObjects(errorSchema, filteredErrors, 'preventDuplicates');
|
|
130
|
-
}
|
|
131
|
-
state = {
|
|
132
|
-
formData: newFormData,
|
|
133
|
-
errors,
|
|
134
|
-
errorSchema,
|
|
135
|
-
schemaValidationErrors,
|
|
136
|
-
schemaValidationErrorSchema,
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
else if (!noValidate && newErrorSchema) {
|
|
140
|
-
const errorSchema = extraErrors
|
|
141
|
-
? mergeObjects(newErrorSchema, extraErrors, 'preventDuplicates')
|
|
142
|
-
: newErrorSchema;
|
|
143
|
-
state = {
|
|
144
|
-
formData: newFormData,
|
|
145
|
-
errorSchema: errorSchema,
|
|
146
|
-
errors: toErrorList(errorSchema),
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
this.setState(state, () => onChange && onChange({ ...this.state, ...state }, id));
|
|
150
|
-
};
|
|
151
|
-
/**
|
|
152
|
-
* Callback function to handle reset form data.
|
|
153
|
-
* - Reset all fields with default values.
|
|
154
|
-
* - Reset validations and errors
|
|
155
|
-
*
|
|
156
|
-
*/
|
|
157
|
-
this.reset = () => {
|
|
158
|
-
const { onChange } = this.props;
|
|
159
|
-
const newState = this.getStateFromProps(this.props, undefined);
|
|
160
|
-
const newFormData = newState.formData;
|
|
161
|
-
const state = {
|
|
162
|
-
formData: newFormData,
|
|
163
|
-
errorSchema: {},
|
|
164
|
-
errors: [],
|
|
165
|
-
schemaValidationErrors: [],
|
|
166
|
-
schemaValidationErrorSchema: {},
|
|
167
|
-
};
|
|
168
|
-
this.setState(state, () => onChange && onChange({ ...this.state, ...state }));
|
|
169
|
-
};
|
|
170
|
-
/** Callback function to handle when a field on the form is blurred. Calls the `onBlur` callback for the `Form` if it
|
|
171
|
-
* was provided.
|
|
172
|
-
*
|
|
173
|
-
* @param id - The unique `id` of the field that was blurred
|
|
174
|
-
* @param data - The data associated with the field that was blurred
|
|
175
|
-
*/
|
|
176
|
-
this.onBlur = (id, data) => {
|
|
177
|
-
const { onBlur } = this.props;
|
|
178
|
-
if (onBlur) {
|
|
179
|
-
onBlur(id, data);
|
|
180
|
-
}
|
|
181
|
-
};
|
|
182
|
-
/** Callback function to handle when a field on the form is focused. Calls the `onFocus` callback for the `Form` if it
|
|
183
|
-
* was provided.
|
|
184
|
-
*
|
|
185
|
-
* @param id - The unique `id` of the field that was focused
|
|
186
|
-
* @param data - The data associated with the field that was focused
|
|
187
|
-
*/
|
|
188
|
-
this.onFocus = (id, data) => {
|
|
189
|
-
const { onFocus } = this.props;
|
|
190
|
-
if (onFocus) {
|
|
191
|
-
onFocus(id, data);
|
|
192
|
-
}
|
|
193
|
-
};
|
|
194
|
-
/** Callback function to handle when the form is submitted. First, it prevents the default event behavior. Nothing
|
|
195
|
-
* happens if the target and currentTarget of the event are not the same. It will omit any extra data in the
|
|
196
|
-
* `formData` in the state if `omitExtraData` is true. It will validate the resulting `formData`, reporting errors
|
|
197
|
-
* via the `onError()` callback unless validation is disabled. Finally, it will add in any `extraErrors` and then call
|
|
198
|
-
* back the `onSubmit` callback if it was provided.
|
|
199
|
-
*
|
|
200
|
-
* @param event - The submit HTML form event
|
|
201
|
-
*/
|
|
202
|
-
this.onSubmit = (event) => {
|
|
203
|
-
event.preventDefault();
|
|
204
|
-
if (event.target !== event.currentTarget) {
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
event.persist();
|
|
208
|
-
const { omitExtraData, extraErrors, noValidate, onSubmit } = this.props;
|
|
209
|
-
let { formData: newFormData } = this.state;
|
|
210
|
-
if (omitExtraData === true) {
|
|
211
|
-
newFormData = this.omitExtraData(newFormData);
|
|
212
|
-
}
|
|
213
|
-
if (noValidate || this.validateFormWithFormData(newFormData)) {
|
|
214
|
-
// There are no errors generated through schema validation.
|
|
215
|
-
// Check for user provided errors and update state accordingly.
|
|
216
|
-
const errorSchema = extraErrors || {};
|
|
217
|
-
const errors = extraErrors ? toErrorList(extraErrors) : [];
|
|
218
|
-
this.setState({
|
|
219
|
-
formData: newFormData,
|
|
220
|
-
errors,
|
|
221
|
-
errorSchema,
|
|
222
|
-
schemaValidationErrors: [],
|
|
223
|
-
schemaValidationErrorSchema: {},
|
|
224
|
-
}, () => {
|
|
225
|
-
if (onSubmit) {
|
|
226
|
-
onSubmit({ ...this.state, formData: newFormData, status: 'submitted' }, event);
|
|
227
|
-
}
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
};
|
|
231
|
-
/** Provides a function that can be used to programmatically submit the `Form` */
|
|
232
|
-
this.submit = () => {
|
|
233
|
-
if (this.formElement.current) {
|
|
234
|
-
const submitCustomEvent = new CustomEvent('submit', {
|
|
235
|
-
cancelable: true,
|
|
236
|
-
});
|
|
237
|
-
submitCustomEvent.preventDefault();
|
|
238
|
-
this.formElement.current.dispatchEvent(submitCustomEvent);
|
|
239
|
-
this.formElement.current.requestSubmit();
|
|
240
|
-
}
|
|
241
|
-
};
|
|
242
|
-
/** Validates the form using the given `formData`. For use on form submission or on programmatic validation.
|
|
243
|
-
* If `onError` is provided, then it will be called with the list of errors.
|
|
244
|
-
*
|
|
245
|
-
* @param formData - The form data to validate
|
|
246
|
-
* @returns - True if the form is valid, false otherwise.
|
|
247
|
-
*/
|
|
248
|
-
this.validateFormWithFormData = (formData) => {
|
|
249
|
-
const { extraErrors, extraErrorsBlockSubmit, focusOnFirstError, onError } = this.props;
|
|
250
|
-
const { errors: prevErrors } = this.state;
|
|
251
|
-
const schemaValidation = this.validate(formData);
|
|
252
|
-
let errors = schemaValidation.errors;
|
|
253
|
-
let errorSchema = schemaValidation.errorSchema;
|
|
254
|
-
const schemaValidationErrors = errors;
|
|
255
|
-
const schemaValidationErrorSchema = errorSchema;
|
|
256
|
-
const hasError = errors.length > 0 || (extraErrors && extraErrorsBlockSubmit);
|
|
257
|
-
if (hasError) {
|
|
258
|
-
if (extraErrors) {
|
|
259
|
-
const merged = validationDataMerge(schemaValidation, extraErrors);
|
|
260
|
-
errorSchema = merged.errorSchema;
|
|
261
|
-
errors = merged.errors;
|
|
262
|
-
}
|
|
263
|
-
if (focusOnFirstError) {
|
|
264
|
-
if (typeof focusOnFirstError === 'function') {
|
|
265
|
-
focusOnFirstError(errors[0]);
|
|
266
|
-
}
|
|
267
|
-
else {
|
|
268
|
-
this.focusOnError(errors[0]);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
this.setState({
|
|
272
|
-
errors,
|
|
273
|
-
errorSchema,
|
|
274
|
-
schemaValidationErrors,
|
|
275
|
-
schemaValidationErrorSchema,
|
|
276
|
-
}, () => {
|
|
277
|
-
if (onError) {
|
|
278
|
-
onError(errors);
|
|
279
|
-
}
|
|
280
|
-
else {
|
|
281
|
-
console.error('Form validation failed', errors);
|
|
282
|
-
}
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
else if (prevErrors.length > 0) {
|
|
286
|
-
this.setState({
|
|
287
|
-
errors: [],
|
|
288
|
-
errorSchema: {},
|
|
289
|
-
schemaValidationErrors: [],
|
|
290
|
-
schemaValidationErrorSchema: {},
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
|
-
return !hasError;
|
|
294
|
-
};
|
|
295
25
|
if (!props.validator) {
|
|
296
26
|
throw new Error('A validator is required for Form functionality to work');
|
|
297
27
|
}
|
|
@@ -374,7 +104,6 @@ export default class Form extends Component {
|
|
|
374
104
|
* @returns - The new state for the `Form`
|
|
375
105
|
*/
|
|
376
106
|
getStateFromProps(props, inputFormData, retrievedSchema, isSchemaChanged = false, formDataChangedFields = []) {
|
|
377
|
-
var _a;
|
|
378
107
|
const state = this.state || {};
|
|
379
108
|
const schema = 'schema' in props ? props.schema : this.props.schema;
|
|
380
109
|
const uiSchema = ('uiSchema' in props ? props.uiSchema : this.props.uiSchema) || {};
|
|
@@ -394,7 +123,7 @@ export default class Form extends Component {
|
|
|
394
123
|
schemaUtils = createSchemaUtils(props.validator, rootSchema, experimental_defaultFormStateBehavior, experimental_customMergeAllOf);
|
|
395
124
|
}
|
|
396
125
|
const formData = schemaUtils.getDefaultFormState(schema, inputFormData);
|
|
397
|
-
const _retrievedSchema = this.updateRetrievedSchema(retrievedSchema
|
|
126
|
+
const _retrievedSchema = this.updateRetrievedSchema(retrievedSchema ?? schemaUtils.retrieveSchema(schema, formData));
|
|
398
127
|
const getCurrentErrors = () => {
|
|
399
128
|
// If the `props.noValidate` option is set or the schema has changed, we reset the error state.
|
|
400
129
|
if (props.noValidate || isSchemaChanged) {
|
|
@@ -424,7 +153,7 @@ export default class Form extends Component {
|
|
|
424
153
|
errorSchema = schemaValidation.errorSchema;
|
|
425
154
|
}
|
|
426
155
|
else {
|
|
427
|
-
errorSchema = mergeObjects(
|
|
156
|
+
errorSchema = mergeObjects(this.state?.errorSchema, schemaValidation.errorSchema, 'preventDuplicates');
|
|
428
157
|
}
|
|
429
158
|
schemaValidationErrors = errors;
|
|
430
159
|
schemaValidationErrorSchema = errorSchema;
|
|
@@ -496,7 +225,7 @@ export default class Form extends Component {
|
|
|
496
225
|
validate(formData, schema = this.props.schema, altSchemaUtils, retrievedSchema) {
|
|
497
226
|
const schemaUtils = altSchemaUtils ? altSchemaUtils : this.state.schemaUtils;
|
|
498
227
|
const { customValidate, transformErrors, uiSchema } = this.props;
|
|
499
|
-
const resolvedSchema = retrievedSchema
|
|
228
|
+
const resolvedSchema = retrievedSchema ?? schemaUtils.retrieveSchema(schema, formData);
|
|
500
229
|
return schemaUtils
|
|
501
230
|
.getValidator()
|
|
502
231
|
.validateFormData(formData, resolvedSchema, customValidate, transformErrors, uiSchema);
|
|
@@ -512,15 +241,80 @@ export default class Form extends Component {
|
|
|
512
241
|
}
|
|
513
242
|
return null;
|
|
514
243
|
}
|
|
244
|
+
/** Returns the `formData` with only the elements specified in the `fields` list
|
|
245
|
+
*
|
|
246
|
+
* @param formData - The data for the `Form`
|
|
247
|
+
* @param fields - The fields to keep while filtering
|
|
248
|
+
*/
|
|
249
|
+
getUsedFormData = (formData, fields) => {
|
|
250
|
+
// For the case of a single input form
|
|
251
|
+
if (fields.length === 0 && typeof formData !== 'object') {
|
|
252
|
+
return formData;
|
|
253
|
+
}
|
|
254
|
+
// _pick has incorrect type definition, it works with string[][], because lodash/hasIn supports it
|
|
255
|
+
const data = _pick(formData, fields);
|
|
256
|
+
if (Array.isArray(formData)) {
|
|
257
|
+
return Object.keys(data).map((key) => data[key]);
|
|
258
|
+
}
|
|
259
|
+
return data;
|
|
260
|
+
};
|
|
261
|
+
/** Returns the list of field names from inspecting the `pathSchema` as well as using the `formData`
|
|
262
|
+
*
|
|
263
|
+
* @param pathSchema - The `PathSchema` object for the form
|
|
264
|
+
* @param [formData] - The form data to use while checking for empty objects/arrays
|
|
265
|
+
*/
|
|
266
|
+
getFieldNames = (pathSchema, formData) => {
|
|
267
|
+
const getAllPaths = (_obj, acc = [], paths = [[]]) => {
|
|
268
|
+
Object.keys(_obj).forEach((key) => {
|
|
269
|
+
if (typeof _obj[key] === 'object') {
|
|
270
|
+
const newPaths = paths.map((path) => [...path, key]);
|
|
271
|
+
// If an object is marked with additionalProperties, all its keys are valid
|
|
272
|
+
if (_obj[key][RJSF_ADDITIONAL_PROPERTIES_FLAG] && _obj[key][NAME_KEY] !== '') {
|
|
273
|
+
acc.push(_obj[key][NAME_KEY]);
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
getAllPaths(_obj[key], acc, newPaths);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
else if (key === NAME_KEY && _obj[key] !== '') {
|
|
280
|
+
paths.forEach((path) => {
|
|
281
|
+
const formValue = _get(formData, path);
|
|
282
|
+
// adds path to fieldNames if it points to a value
|
|
283
|
+
// or an empty object/array
|
|
284
|
+
if (typeof formValue !== 'object' ||
|
|
285
|
+
_isEmpty(formValue) ||
|
|
286
|
+
(Array.isArray(formValue) && formValue.every((val) => typeof val !== 'object'))) {
|
|
287
|
+
acc.push(path);
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
return acc;
|
|
293
|
+
};
|
|
294
|
+
return getAllPaths(pathSchema);
|
|
295
|
+
};
|
|
296
|
+
/** Returns the `formData` after filtering to remove any extra data not in a form field
|
|
297
|
+
*
|
|
298
|
+
* @param formData - The data for the `Form`
|
|
299
|
+
* @returns The `formData` after omitting extra data
|
|
300
|
+
*/
|
|
301
|
+
omitExtraData = (formData) => {
|
|
302
|
+
const { schema, schemaUtils } = this.state;
|
|
303
|
+
const retrievedSchema = schemaUtils.retrieveSchema(schema, formData);
|
|
304
|
+
const pathSchema = schemaUtils.toPathSchema(retrievedSchema, '', formData);
|
|
305
|
+
const fieldNames = this.getFieldNames(pathSchema, formData);
|
|
306
|
+
const newFormData = this.getUsedFormData(formData, fieldNames);
|
|
307
|
+
return newFormData;
|
|
308
|
+
};
|
|
515
309
|
// Filtering errors based on your retrieved schema to only show errors for properties in the selected branch.
|
|
516
310
|
filterErrorsBasedOnSchema(schemaErrors, resolvedSchema, formData) {
|
|
517
311
|
const { retrievedSchema, schemaUtils } = this.state;
|
|
518
|
-
const _retrievedSchema = resolvedSchema
|
|
312
|
+
const _retrievedSchema = resolvedSchema ?? retrievedSchema;
|
|
519
313
|
const pathSchema = schemaUtils.toPathSchema(_retrievedSchema, '', formData);
|
|
520
314
|
const fieldNames = this.getFieldNames(pathSchema, formData);
|
|
521
315
|
const filteredErrors = _pick(schemaErrors, fieldNames);
|
|
522
316
|
// If the root schema is of a primitive type, do not filter out the __errors
|
|
523
|
-
if (
|
|
317
|
+
if (resolvedSchema?.type !== 'object' && resolvedSchema?.type !== 'array') {
|
|
524
318
|
filteredErrors.__errors = schemaErrors.__errors;
|
|
525
319
|
}
|
|
526
320
|
const prevCustomValidateErrors = this.getPreviousCustomValidateErrors();
|
|
@@ -542,7 +336,7 @@ export default class Form extends Component {
|
|
|
542
336
|
}
|
|
543
337
|
else if (isObject(errorAtKey) &&
|
|
544
338
|
isObject(prevCustomValidateErrorAtKey) &&
|
|
545
|
-
Array.isArray(prevCustomValidateErrorAtKey
|
|
339
|
+
Array.isArray(prevCustomValidateErrorAtKey?.__errors)) {
|
|
546
340
|
// if previous customValidate error is an object and has __errors array, filter out the errors previous customValidate errors.
|
|
547
341
|
errors[errorKey] = filterPreviousCustomErrors(errorAtKey.__errors, prevCustomValidateErrorAtKey.__errors);
|
|
548
342
|
}
|
|
@@ -554,6 +348,71 @@ export default class Form extends Component {
|
|
|
554
348
|
};
|
|
555
349
|
return filterNilOrEmptyErrors(filteredErrors, prevCustomValidateErrors);
|
|
556
350
|
}
|
|
351
|
+
/** Function to handle changes made to a field in the `Form`. This handler receives an entirely new copy of the
|
|
352
|
+
* `formData` along with a new `ErrorSchema`. It will first update the `formData` with any missing default fields and
|
|
353
|
+
* then, if `omitExtraData` and `liveOmit` are turned on, the `formData` will be filtered to remove any extra data not
|
|
354
|
+
* in a form field. Then, the resulting formData will be validated if required. The state will be updated with the new
|
|
355
|
+
* updated (potentially filtered) `formData`, any errors that resulted from validation. Finally the `onChange`
|
|
356
|
+
* callback will be called if specified with the updated state.
|
|
357
|
+
*
|
|
358
|
+
* @param formData - The new form data from a change to a field
|
|
359
|
+
* @param newErrorSchema - The new `ErrorSchema` based on the field change
|
|
360
|
+
* @param id - The id of the field that caused the change
|
|
361
|
+
*/
|
|
362
|
+
onChange = (formData, newErrorSchema, id) => {
|
|
363
|
+
const { extraErrors, omitExtraData, liveOmit, noValidate, liveValidate, onChange } = this.props;
|
|
364
|
+
const { schemaUtils, schema } = this.state;
|
|
365
|
+
let retrievedSchema = this.state.retrievedSchema;
|
|
366
|
+
if (isObject(formData) || Array.isArray(formData)) {
|
|
367
|
+
const newState = this.getStateFromProps(this.props, formData);
|
|
368
|
+
formData = newState.formData;
|
|
369
|
+
retrievedSchema = newState.retrievedSchema;
|
|
370
|
+
}
|
|
371
|
+
const mustValidate = !noValidate && liveValidate;
|
|
372
|
+
let state = { formData, schema };
|
|
373
|
+
let newFormData = formData;
|
|
374
|
+
if (omitExtraData === true && liveOmit === true) {
|
|
375
|
+
newFormData = this.omitExtraData(formData);
|
|
376
|
+
state = {
|
|
377
|
+
formData: newFormData,
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
if (mustValidate) {
|
|
381
|
+
const schemaValidation = this.validate(newFormData, schema, schemaUtils, retrievedSchema);
|
|
382
|
+
let errors = schemaValidation.errors;
|
|
383
|
+
let errorSchema = schemaValidation.errorSchema;
|
|
384
|
+
const schemaValidationErrors = errors;
|
|
385
|
+
const schemaValidationErrorSchema = errorSchema;
|
|
386
|
+
if (extraErrors) {
|
|
387
|
+
const merged = validationDataMerge(schemaValidation, extraErrors);
|
|
388
|
+
errorSchema = merged.errorSchema;
|
|
389
|
+
errors = merged.errors;
|
|
390
|
+
}
|
|
391
|
+
// Merging 'newErrorSchema' into 'errorSchema' to display the custom raised errors.
|
|
392
|
+
if (newErrorSchema) {
|
|
393
|
+
const filteredErrors = this.filterErrorsBasedOnSchema(newErrorSchema, retrievedSchema, newFormData);
|
|
394
|
+
errorSchema = mergeObjects(errorSchema, filteredErrors, 'preventDuplicates');
|
|
395
|
+
}
|
|
396
|
+
state = {
|
|
397
|
+
formData: newFormData,
|
|
398
|
+
errors,
|
|
399
|
+
errorSchema,
|
|
400
|
+
schemaValidationErrors,
|
|
401
|
+
schemaValidationErrorSchema,
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
else if (!noValidate && newErrorSchema) {
|
|
405
|
+
const errorSchema = extraErrors
|
|
406
|
+
? mergeObjects(newErrorSchema, extraErrors, 'preventDuplicates')
|
|
407
|
+
: newErrorSchema;
|
|
408
|
+
state = {
|
|
409
|
+
formData: newFormData,
|
|
410
|
+
errorSchema: errorSchema,
|
|
411
|
+
errors: toErrorList(errorSchema),
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
this.setState(state, () => onChange && onChange({ ...this.state, ...state }, id));
|
|
415
|
+
};
|
|
557
416
|
/**
|
|
558
417
|
* If the retrievedSchema has changed the new retrievedSchema is returned.
|
|
559
418
|
* Otherwise, the old retrievedSchema is returned to persist reference.
|
|
@@ -564,13 +423,91 @@ export default class Form extends Component {
|
|
|
564
423
|
* @returns The new retrieved schema if it has changed, else the old retrieved schema.
|
|
565
424
|
*/
|
|
566
425
|
updateRetrievedSchema(retrievedSchema) {
|
|
567
|
-
|
|
568
|
-
const isTheSame = deepEquals(retrievedSchema, (_a = this.state) === null || _a === void 0 ? void 0 : _a.retrievedSchema);
|
|
426
|
+
const isTheSame = deepEquals(retrievedSchema, this.state?.retrievedSchema);
|
|
569
427
|
return isTheSame ? this.state.retrievedSchema : retrievedSchema;
|
|
570
428
|
}
|
|
429
|
+
/**
|
|
430
|
+
* Callback function to handle reset form data.
|
|
431
|
+
* - Reset all fields with default values.
|
|
432
|
+
* - Reset validations and errors
|
|
433
|
+
*
|
|
434
|
+
*/
|
|
435
|
+
reset = () => {
|
|
436
|
+
const { onChange } = this.props;
|
|
437
|
+
const newState = this.getStateFromProps(this.props, undefined);
|
|
438
|
+
const newFormData = newState.formData;
|
|
439
|
+
const state = {
|
|
440
|
+
formData: newFormData,
|
|
441
|
+
errorSchema: {},
|
|
442
|
+
errors: [],
|
|
443
|
+
schemaValidationErrors: [],
|
|
444
|
+
schemaValidationErrorSchema: {},
|
|
445
|
+
};
|
|
446
|
+
this.setState(state, () => onChange && onChange({ ...this.state, ...state }));
|
|
447
|
+
};
|
|
448
|
+
/** Callback function to handle when a field on the form is blurred. Calls the `onBlur` callback for the `Form` if it
|
|
449
|
+
* was provided.
|
|
450
|
+
*
|
|
451
|
+
* @param id - The unique `id` of the field that was blurred
|
|
452
|
+
* @param data - The data associated with the field that was blurred
|
|
453
|
+
*/
|
|
454
|
+
onBlur = (id, data) => {
|
|
455
|
+
const { onBlur } = this.props;
|
|
456
|
+
if (onBlur) {
|
|
457
|
+
onBlur(id, data);
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
/** Callback function to handle when a field on the form is focused. Calls the `onFocus` callback for the `Form` if it
|
|
461
|
+
* was provided.
|
|
462
|
+
*
|
|
463
|
+
* @param id - The unique `id` of the field that was focused
|
|
464
|
+
* @param data - The data associated with the field that was focused
|
|
465
|
+
*/
|
|
466
|
+
onFocus = (id, data) => {
|
|
467
|
+
const { onFocus } = this.props;
|
|
468
|
+
if (onFocus) {
|
|
469
|
+
onFocus(id, data);
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
/** Callback function to handle when the form is submitted. First, it prevents the default event behavior. Nothing
|
|
473
|
+
* happens if the target and currentTarget of the event are not the same. It will omit any extra data in the
|
|
474
|
+
* `formData` in the state if `omitExtraData` is true. It will validate the resulting `formData`, reporting errors
|
|
475
|
+
* via the `onError()` callback unless validation is disabled. Finally, it will add in any `extraErrors` and then call
|
|
476
|
+
* back the `onSubmit` callback if it was provided.
|
|
477
|
+
*
|
|
478
|
+
* @param event - The submit HTML form event
|
|
479
|
+
*/
|
|
480
|
+
onSubmit = (event) => {
|
|
481
|
+
event.preventDefault();
|
|
482
|
+
if (event.target !== event.currentTarget) {
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
event.persist();
|
|
486
|
+
const { omitExtraData, extraErrors, noValidate, onSubmit } = this.props;
|
|
487
|
+
let { formData: newFormData } = this.state;
|
|
488
|
+
if (omitExtraData === true) {
|
|
489
|
+
newFormData = this.omitExtraData(newFormData);
|
|
490
|
+
}
|
|
491
|
+
if (noValidate || this.validateFormWithFormData(newFormData)) {
|
|
492
|
+
// There are no errors generated through schema validation.
|
|
493
|
+
// Check for user provided errors and update state accordingly.
|
|
494
|
+
const errorSchema = extraErrors || {};
|
|
495
|
+
const errors = extraErrors ? toErrorList(extraErrors) : [];
|
|
496
|
+
this.setState({
|
|
497
|
+
formData: newFormData,
|
|
498
|
+
errors,
|
|
499
|
+
errorSchema,
|
|
500
|
+
schemaValidationErrors: [],
|
|
501
|
+
schemaValidationErrorSchema: {},
|
|
502
|
+
}, () => {
|
|
503
|
+
if (onSubmit) {
|
|
504
|
+
onSubmit({ ...this.state, formData: newFormData, status: 'submitted' }, event);
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
};
|
|
571
509
|
/** Returns the registry for the form */
|
|
572
510
|
getRegistry() {
|
|
573
|
-
var _a;
|
|
574
511
|
const { translateString: customTranslateString, uiSchema = {} } = this.props;
|
|
575
512
|
const { schemaUtils } = this.state;
|
|
576
513
|
const { fields, templates, widgets, formContext, translateString } = getDefaultRegistry();
|
|
@@ -581,7 +518,7 @@ export default class Form extends Component {
|
|
|
581
518
|
...this.props.templates,
|
|
582
519
|
ButtonTemplates: {
|
|
583
520
|
...templates.ButtonTemplates,
|
|
584
|
-
...
|
|
521
|
+
...this.props.templates?.ButtonTemplates,
|
|
585
522
|
},
|
|
586
523
|
},
|
|
587
524
|
widgets: { ...widgets, ...this.props.widgets },
|
|
@@ -592,6 +529,17 @@ export default class Form extends Component {
|
|
|
592
529
|
globalUiOptions: uiSchema[UI_GLOBAL_OPTIONS_KEY],
|
|
593
530
|
};
|
|
594
531
|
}
|
|
532
|
+
/** Provides a function that can be used to programmatically submit the `Form` */
|
|
533
|
+
submit = () => {
|
|
534
|
+
if (this.formElement.current) {
|
|
535
|
+
const submitCustomEvent = new CustomEvent('submit', {
|
|
536
|
+
cancelable: true,
|
|
537
|
+
});
|
|
538
|
+
submitCustomEvent.preventDefault();
|
|
539
|
+
this.formElement.current.dispatchEvent(submitCustomEvent);
|
|
540
|
+
this.formElement.current.requestSubmit();
|
|
541
|
+
}
|
|
542
|
+
};
|
|
595
543
|
/** Attempts to focus on the field associated with the `error`. Uses the `property` field to compute path of the error
|
|
596
544
|
* field, then, using the `idPrefix` and `idSeparator` converts that path into an id. Then the input element with that
|
|
597
545
|
* id is attempted to be found using the `formElement` ref. If it is located, then it is focused.
|
|
@@ -624,6 +572,59 @@ export default class Form extends Component {
|
|
|
624
572
|
field.focus();
|
|
625
573
|
}
|
|
626
574
|
}
|
|
575
|
+
/** Validates the form using the given `formData`. For use on form submission or on programmatic validation.
|
|
576
|
+
* If `onError` is provided, then it will be called with the list of errors.
|
|
577
|
+
*
|
|
578
|
+
* @param formData - The form data to validate
|
|
579
|
+
* @returns - True if the form is valid, false otherwise.
|
|
580
|
+
*/
|
|
581
|
+
validateFormWithFormData = (formData) => {
|
|
582
|
+
const { extraErrors, extraErrorsBlockSubmit, focusOnFirstError, onError } = this.props;
|
|
583
|
+
const { errors: prevErrors } = this.state;
|
|
584
|
+
const schemaValidation = this.validate(formData);
|
|
585
|
+
let errors = schemaValidation.errors;
|
|
586
|
+
let errorSchema = schemaValidation.errorSchema;
|
|
587
|
+
const schemaValidationErrors = errors;
|
|
588
|
+
const schemaValidationErrorSchema = errorSchema;
|
|
589
|
+
const hasError = errors.length > 0 || (extraErrors && extraErrorsBlockSubmit);
|
|
590
|
+
if (hasError) {
|
|
591
|
+
if (extraErrors) {
|
|
592
|
+
const merged = validationDataMerge(schemaValidation, extraErrors);
|
|
593
|
+
errorSchema = merged.errorSchema;
|
|
594
|
+
errors = merged.errors;
|
|
595
|
+
}
|
|
596
|
+
if (focusOnFirstError) {
|
|
597
|
+
if (typeof focusOnFirstError === 'function') {
|
|
598
|
+
focusOnFirstError(errors[0]);
|
|
599
|
+
}
|
|
600
|
+
else {
|
|
601
|
+
this.focusOnError(errors[0]);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
this.setState({
|
|
605
|
+
errors,
|
|
606
|
+
errorSchema,
|
|
607
|
+
schemaValidationErrors,
|
|
608
|
+
schemaValidationErrorSchema,
|
|
609
|
+
}, () => {
|
|
610
|
+
if (onError) {
|
|
611
|
+
onError(errors);
|
|
612
|
+
}
|
|
613
|
+
else {
|
|
614
|
+
console.error('Form validation failed', errors);
|
|
615
|
+
}
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
else if (prevErrors.length > 0) {
|
|
619
|
+
this.setState({
|
|
620
|
+
errors: [],
|
|
621
|
+
errorSchema: {},
|
|
622
|
+
schemaValidationErrors: [],
|
|
623
|
+
schemaValidationErrorSchema: {},
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
return !hasError;
|
|
627
|
+
};
|
|
627
628
|
/** Programmatically validate the form. If `omitExtraData` is true, the `formData` will first be filtered to remove
|
|
628
629
|
* any extra data not in a form field. If `onError` is provided, then it will be called with the list of errors the
|
|
629
630
|
* same way as would happen on form submission.
|
|
@@ -660,4 +661,3 @@ export default class Form extends Component {
|
|
|
660
661
|
return (_jsxs(FormTag, { className: className ? className : 'rjsf', id: id, name: name, method: method, target: target, action: action, autoComplete: autoComplete, encType: enctype, acceptCharset: acceptCharset || acceptcharset, noValidate: noHtml5Validate, onSubmit: this.onSubmit, as: as, ref: this.formElement, children: [showErrorList === 'top' && this.renderErrors(registry), _jsx(_SchemaField, { name: '', schema: schema, uiSchema: uiSchema, errorSchema: errorSchema, idSchema: idSchema, idPrefix: idPrefix, idSeparator: idSeparator, formContext: formContext, formData: formData, onChange: this.onChange, onBlur: this.onBlur, onFocus: this.onFocus, registry: registry, disabled: disabled, readonly: readonly }), children ? children : _jsx(SubmitButton, { uiSchema: submitUiSchema, registry: registry }), showErrorList === 'bottom' && this.renderErrors(registry)] }));
|
|
661
662
|
}
|
|
662
663
|
}
|
|
663
|
-
//# sourceMappingURL=Form.js.map
|