@rjsf/core 6.0.0-beta.2 → 6.0.0-beta.20
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 +469 -360
- package/dist/{index.js → index.cjs} +640 -519
- package/dist/index.cjs.map +7 -0
- package/dist/index.esm.js +706 -566
- package/dist/index.esm.js.map +4 -4
- package/lib/components/Form.d.ts +66 -16
- package/lib/components/Form.d.ts.map +1 -1
- package/lib/components/Form.js +138 -59
- package/lib/components/fields/ArrayField.d.ts +17 -7
- package/lib/components/fields/ArrayField.d.ts.map +1 -1
- package/lib/components/fields/ArrayField.js +92 -59
- package/lib/components/fields/BooleanField.d.ts.map +1 -1
- package/lib/components/fields/BooleanField.js +7 -2
- package/lib/components/fields/LayoutGridField.d.ts +27 -25
- package/lib/components/fields/LayoutGridField.d.ts.map +1 -1
- package/lib/components/fields/LayoutGridField.js +83 -53
- package/lib/components/fields/LayoutHeaderField.d.ts +1 -1
- package/lib/components/fields/LayoutHeaderField.js +3 -3
- package/lib/components/fields/LayoutMultiSchemaField.js +6 -5
- package/lib/components/fields/MultiSchemaField.d.ts.map +1 -1
- package/lib/components/fields/MultiSchemaField.js +13 -9
- package/lib/components/fields/NullField.js +3 -3
- package/lib/components/fields/NumberField.d.ts.map +1 -1
- package/lib/components/fields/NumberField.js +3 -3
- package/lib/components/fields/ObjectField.d.ts +3 -3
- package/lib/components/fields/ObjectField.d.ts.map +1 -1
- package/lib/components/fields/ObjectField.js +18 -25
- package/lib/components/fields/SchemaField.d.ts.map +1 -1
- package/lib/components/fields/SchemaField.js +17 -17
- package/lib/components/fields/StringField.d.ts.map +1 -1
- package/lib/components/fields/StringField.js +7 -2
- package/lib/components/templates/ArrayFieldDescriptionTemplate.d.ts +1 -1
- package/lib/components/templates/ArrayFieldDescriptionTemplate.js +3 -3
- package/lib/components/templates/ArrayFieldItemButtonsTemplate.js +2 -2
- package/lib/components/templates/ArrayFieldTemplate.js +3 -3
- package/lib/components/templates/ArrayFieldTitleTemplate.d.ts +1 -1
- package/lib/components/templates/ArrayFieldTitleTemplate.js +3 -3
- package/lib/components/templates/FieldErrorTemplate.js +2 -2
- package/lib/components/templates/FieldHelpTemplate.js +2 -2
- package/lib/components/templates/MultiSchemaFieldTemplate.d.ts +8 -0
- package/lib/components/templates/MultiSchemaFieldTemplate.d.ts.map +1 -0
- package/lib/components/templates/MultiSchemaFieldTemplate.js +10 -0
- package/lib/components/templates/ObjectFieldTemplate.js +2 -2
- package/lib/components/templates/UnsupportedField.js +3 -3
- package/lib/components/templates/index.d.ts.map +1 -1
- package/lib/components/templates/index.js +2 -0
- package/lib/components/widgets/AltDateWidget.d.ts.map +1 -1
- package/lib/components/widgets/AltDateWidget.js +15 -18
- package/lib/components/widgets/CheckboxesWidget.js +2 -2
- package/lib/getDefaultRegistry.d.ts.map +1 -1
- package/lib/getDefaultRegistry.js +2 -1
- package/lib/getTestRegistry.d.ts +5 -0
- package/lib/getTestRegistry.d.ts.map +1 -0
- package/lib/getTestRegistry.js +19 -0
- package/lib/index.d.ts +2 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +18 -19
- package/src/components/Form.tsx +183 -73
- package/src/components/fields/ArrayField.tsx +99 -67
- package/src/components/fields/BooleanField.tsx +12 -3
- package/src/components/fields/LayoutGridField.tsx +95 -82
- package/src/components/fields/LayoutHeaderField.tsx +3 -3
- package/src/components/fields/LayoutMultiSchemaField.tsx +5 -5
- package/src/components/fields/MultiSchemaField.tsx +51 -35
- package/src/components/fields/NullField.tsx +3 -3
- package/src/components/fields/NumberField.tsx +11 -3
- package/src/components/fields/ObjectField.tsx +19 -36
- package/src/components/fields/SchemaField.tsx +24 -30
- package/src/components/fields/StringField.tsx +12 -3
- package/src/components/templates/ArrayFieldDescriptionTemplate.tsx +3 -3
- package/src/components/templates/ArrayFieldItemButtonsTemplate.tsx +5 -5
- package/src/components/templates/ArrayFieldTemplate.tsx +5 -5
- package/src/components/templates/ArrayFieldTitleTemplate.tsx +3 -3
- package/src/components/templates/BaseInputTemplate.tsx +3 -3
- package/src/components/templates/FieldErrorTemplate.tsx +2 -2
- package/src/components/templates/FieldHelpTemplate.tsx +2 -2
- package/src/components/templates/MultiSchemaFieldTemplate.tsx +20 -0
- package/src/components/templates/ObjectFieldTemplate.tsx +5 -5
- package/src/components/templates/UnsupportedField.tsx +3 -3
- package/src/components/templates/WrapIfAdditionalTemplate.tsx +1 -1
- package/src/components/templates/index.ts +2 -0
- package/src/components/widgets/AltDateWidget.tsx +21 -23
- package/src/components/widgets/CheckboxWidget.tsx +2 -2
- package/src/components/widgets/CheckboxesWidget.tsx +3 -3
- package/src/components/widgets/RadioWidget.tsx +1 -1
- package/src/components/widgets/SelectWidget.tsx +1 -1
- package/src/components/widgets/TextareaWidget.tsx +1 -1
- package/src/getDefaultRegistry.ts +10 -1
- package/src/getTestRegistry.tsx +34 -0
- package/src/index.ts +2 -1
- package/dist/index.js.map +0 -7
package/lib/components/Form.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Component, ElementType, FormEvent, ReactNode, Ref, RefObject } from 'react';
|
|
2
|
-
import { CustomValidator, ErrorSchema, ErrorTransformer,
|
|
2
|
+
import { CustomValidator, ErrorSchema, ErrorTransformer, FieldPathId, FieldPathList, FormContextType, PathSchema, StrictRJSFSchema, Registry, RegistryFieldsType, RegistryWidgetsType, RJSFSchema, RJSFValidationError, SchemaUtilsType, TemplatesType, UiSchema, ValidationData, ValidatorType, Experimental_DefaultFormStateBehavior, Experimental_CustomMergeAllOf } from '@rjsf/utils';
|
|
3
3
|
/** The properties that are passed to the `Form` */
|
|
4
4
|
export interface FormProps<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> {
|
|
5
5
|
/** The JSON schema object for the form */
|
|
@@ -144,6 +144,17 @@ export interface FormProps<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
|
|
|
144
144
|
* `emptyObjectFields`
|
|
145
145
|
*/
|
|
146
146
|
experimental_defaultFormStateBehavior?: Experimental_DefaultFormStateBehavior;
|
|
147
|
+
/**
|
|
148
|
+
* Controls the component update strategy used by the Form's `shouldComponentUpdate` lifecycle method.
|
|
149
|
+
*
|
|
150
|
+
* - `'customDeep'`: Uses RJSF's custom deep equality checks via the `deepEquals` utility function,
|
|
151
|
+
* which treats all functions as equivalent and provides optimized performance for form data comparisons.
|
|
152
|
+
* - `'shallow'`: Uses shallow comparison of props and state (only compares direct properties). This matches React's PureComponent behavior.
|
|
153
|
+
* - `'always'`: Always rerenders when called. This matches React's Component behavior.
|
|
154
|
+
*
|
|
155
|
+
* @default 'customDeep'
|
|
156
|
+
*/
|
|
157
|
+
experimental_componentUpdateStrategy?: 'customDeep' | 'shallow' | 'always';
|
|
147
158
|
/** Optional function that allows for custom merging of `allOf` schemas
|
|
148
159
|
*/
|
|
149
160
|
experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>;
|
|
@@ -173,10 +184,10 @@ export interface FormState<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
|
|
|
173
184
|
schema: S;
|
|
174
185
|
/** The uiSchema for the form */
|
|
175
186
|
uiSchema: UiSchema<T, S, F>;
|
|
176
|
-
/** The `
|
|
187
|
+
/** The `FieldPathId` for the form, computed from the `schema`, the `rootFieldId`, the `idPrefix` and
|
|
177
188
|
* `idSeparator` props.
|
|
178
189
|
*/
|
|
179
|
-
|
|
190
|
+
fieldPathId: FieldPathId;
|
|
180
191
|
/** The schemaUtils implementation used by the `Form`, created from the `validator` and the `schema` */
|
|
181
192
|
schemaUtils: SchemaUtilsType<T, S, F>;
|
|
182
193
|
/** The current data for the form, computed from the `formData` prop and the changes made by the user */
|
|
@@ -203,12 +214,27 @@ export interface IChangeEvent<T = any, S extends StrictRJSFSchema = RJSFSchema,
|
|
|
203
214
|
/** The status of the form when submitted */
|
|
204
215
|
status?: 'submitted';
|
|
205
216
|
}
|
|
217
|
+
/** The definition of a pending change that will be processed in the `onChange` handler
|
|
218
|
+
*/
|
|
219
|
+
interface PendingChange<T> {
|
|
220
|
+
/** The path into the formData/errorSchema at which the `newValue`/`newErrorSchema` will be set */
|
|
221
|
+
path: FieldPathList;
|
|
222
|
+
/** The new value to set into the formData */
|
|
223
|
+
newValue?: T;
|
|
224
|
+
/** The new errors to be set into the errorSchema, if any */
|
|
225
|
+
newErrorSchema?: ErrorSchema<T>;
|
|
226
|
+
/** The optional id of the field for which the change is being made */
|
|
227
|
+
id?: string;
|
|
228
|
+
}
|
|
206
229
|
/** The `Form` component renders the outer form and all the fields defined in the `schema` */
|
|
207
230
|
export default class Form<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> extends Component<FormProps<T, S, F>, FormState<T, S, F>> {
|
|
208
231
|
/** The ref used to hold the `form` element, this needs to be `any` because `tagName` or `_internalFormWrapper` can
|
|
209
232
|
* provide any possible type here
|
|
210
233
|
*/
|
|
211
234
|
formElement: RefObject<any>;
|
|
235
|
+
/** The list of pending changes
|
|
236
|
+
*/
|
|
237
|
+
pendingChanges: PendingChange<T>[];
|
|
212
238
|
/** Constructs the `Form` from the `props`. Will setup the initial state from the props. It will also call the
|
|
213
239
|
* `onChange` handler if the initially provided `formData` is modified to add missing default values as part of the
|
|
214
240
|
* state construction.
|
|
@@ -267,9 +293,10 @@ export default class Form<T = any, S extends StrictRJSFSchema = RJSFSchema, F ex
|
|
|
267
293
|
* @param retrievedSchema - An expanded schema, if not provided, it will be retrieved from the `schema` and `formData`.
|
|
268
294
|
* @param isSchemaChanged - A flag indicating whether the schema has changed.
|
|
269
295
|
* @param formDataChangedFields - The changed fields of `formData`
|
|
296
|
+
* @param skipLiveValidate - Optional flag, if true, means that we are not running live validation
|
|
270
297
|
* @returns - The new state for the `Form`
|
|
271
298
|
*/
|
|
272
|
-
getStateFromProps(props: FormProps<T, S, F>, inputFormData?: T, retrievedSchema?: S, isSchemaChanged?: boolean, formDataChangedFields?: string[]): FormState<T, S, F>;
|
|
299
|
+
getStateFromProps(props: FormProps<T, S, F>, inputFormData?: T, retrievedSchema?: S, isSchemaChanged?: boolean, formDataChangedFields?: string[], skipLiveValidate?: boolean): FormState<T, S, F>;
|
|
273
300
|
/** React lifecycle method that is used to determine whether component should be updated.
|
|
274
301
|
*
|
|
275
302
|
* @param nextProps - The next version of the props
|
|
@@ -287,7 +314,8 @@ export default class Form<T = any, S extends StrictRJSFSchema = RJSFSchema, F ex
|
|
|
287
314
|
*
|
|
288
315
|
* @param formData - The new form data to validate
|
|
289
316
|
* @param schema - The schema used to validate against
|
|
290
|
-
* @param altSchemaUtils - The alternate schemaUtils to use for validation
|
|
317
|
+
* @param [altSchemaUtils] - The alternate schemaUtils to use for validation
|
|
318
|
+
* @param [retrievedSchema] - An optionally retrieved schema for per
|
|
291
319
|
*/
|
|
292
320
|
validate(formData: T | undefined, schema?: S, altSchemaUtils?: SchemaUtilsType<T, S, F>, retrievedSchema?: S): ValidationData<T>;
|
|
293
321
|
/** Renders any errors contained in the `state` in using the `ErrorList`, if not disabled by `showErrorList`. */
|
|
@@ -310,19 +338,33 @@ export default class Form<T = any, S extends StrictRJSFSchema = RJSFSchema, F ex
|
|
|
310
338
|
* @returns The `formData` after omitting extra data
|
|
311
339
|
*/
|
|
312
340
|
omitExtraData: (formData?: T) => T | undefined;
|
|
313
|
-
|
|
314
|
-
/** Function to handle changes made to a field in the `Form`. This handler receives an entirely new copy of the
|
|
315
|
-
* `formData` along with a new `ErrorSchema`. It will first update the `formData` with any missing default fields and
|
|
316
|
-
* then, if `omitExtraData` and `liveOmit` are turned on, the `formData` will be filtered to remove any extra data not
|
|
317
|
-
* in a form field. Then, the resulting formData will be validated if required. The state will be updated with the new
|
|
318
|
-
* updated (potentially filtered) `formData`, any errors that resulted from validation. Finally the `onChange`
|
|
319
|
-
* callback will be called if specified with the updated state.
|
|
341
|
+
/** Filtering errors based on your retrieved schema to only show errors for properties in the selected branch.
|
|
320
342
|
*
|
|
321
|
-
* @param
|
|
322
|
-
* @param
|
|
323
|
-
* @param
|
|
343
|
+
* @param schemaErrors - The schema errors to filter
|
|
344
|
+
* @param [resolvedSchema] - An optionally resolved schema to use for performance reasons
|
|
345
|
+
* @param [formData] - The formData to help filter errors
|
|
346
|
+
* @private
|
|
324
347
|
*/
|
|
325
|
-
|
|
348
|
+
private filterErrorsBasedOnSchema;
|
|
349
|
+
/** Pushes the given change information into the `pendingChanges` array and then calls `processPendingChanges()` if
|
|
350
|
+
* the array only contains a single pending change.
|
|
351
|
+
*
|
|
352
|
+
* @param newValue - The new form data from a change to a field
|
|
353
|
+
* @param path - The path to the change into which to set the formData
|
|
354
|
+
* @param [newErrorSchema] - The new `ErrorSchema` based on the field change
|
|
355
|
+
* @param [id] - The id of the field that caused the change
|
|
356
|
+
*/
|
|
357
|
+
onChange: (newValue: T | undefined, path: FieldPathList, newErrorSchema?: ErrorSchema<T>, id?: string) => void;
|
|
358
|
+
/** Function to handle changes made to a field in the `Form`. This handler gets the first change from the
|
|
359
|
+
* `pendingChanges` list, containing the `newValue` for the `formData` and the `path` at which the `newValue` is to be
|
|
360
|
+
* updated, along with a new, optional `ErrorSchema` for that same `path` and potentially the `id` of the field being
|
|
361
|
+
* changed. It will first update the `formData` with any missing default fields and then, if `omitExtraData` and
|
|
362
|
+
* `liveOmit` are turned on, the `formData` will be filtered to remove any extra data not in a form field. Then, the
|
|
363
|
+
* resulting `formData` will be validated if required. The state will be updated with the new updated (potentially
|
|
364
|
+
* filtered) `formData`, any errors that resulted from validation. Finally the `onChange` callback will be called, if
|
|
365
|
+
* specified, with the updated state and the `processPendingChange()` function is called again.
|
|
366
|
+
*/
|
|
367
|
+
processPendingChange(): void;
|
|
326
368
|
/**
|
|
327
369
|
* If the retrievedSchema has changed the new retrievedSchema is returned.
|
|
328
370
|
* Otherwise, the old retrievedSchema is returned to persist reference.
|
|
@@ -363,6 +405,13 @@ export default class Form<T = any, S extends StrictRJSFSchema = RJSFSchema, F ex
|
|
|
363
405
|
* @param event - The submit HTML form event
|
|
364
406
|
*/
|
|
365
407
|
onSubmit: (event: FormEvent<any>) => void;
|
|
408
|
+
/** Extracts the `GlobalFormOptions` from the given Form `props`
|
|
409
|
+
*
|
|
410
|
+
* @param props - The form props to extract the global form options from
|
|
411
|
+
* @returns - The `GlobalFormOptions` from the props
|
|
412
|
+
* @private
|
|
413
|
+
*/
|
|
414
|
+
private getGlobalFormOptions;
|
|
366
415
|
/** Returns the registry for the form */
|
|
367
416
|
getRegistry(): Registry<T, S, F>;
|
|
368
417
|
/** Provides a function that can be used to programmatically submit the `Form` */
|
|
@@ -393,4 +442,5 @@ export default class Form<T = any, S extends StrictRJSFSchema = RJSFSchema, F ex
|
|
|
393
442
|
*/
|
|
394
443
|
render(): import("react/jsx-runtime").JSX.Element;
|
|
395
444
|
}
|
|
445
|
+
export {};
|
|
396
446
|
//# sourceMappingURL=Form.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Form.d.ts","sourceRoot":"","sources":["../../src/components/Form.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAa,MAAM,OAAO,CAAC;AAChG,OAAO,EAEL,eAAe,
|
|
1
|
+
{"version":3,"file":"Form.d.ts","sourceRoot":"","sources":["../../src/components/Form.tsx"],"names":[],"mappings":"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"}
|
package/lib/components/Form.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Component, createRef } from 'react';
|
|
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';
|
|
3
|
+
import { createSchemaUtils, deepEquals, ERRORS_KEY, getChangedFields, getTemplate, getUiOptions, isObject, mergeObjects, NAME_KEY, RJSF_ADDITIONAL_PROPERTIES_FLAG, shouldRender, SUBMIT_BTN_OPTIONS_KEY, toErrorList, toFieldPathId, UI_GLOBAL_OPTIONS_KEY, UI_OPTIONS_KEY, validationDataMerge, createErrorHandler, unwrapErrorHandler, DEFAULT_ID_SEPARATOR, DEFAULT_ID_PREFIX, } from '@rjsf/utils';
|
|
4
|
+
import _cloneDeep from 'lodash-es/cloneDeep.js';
|
|
4
5
|
import _forEach from 'lodash-es/forEach.js';
|
|
5
6
|
import _get from 'lodash-es/get.js';
|
|
6
7
|
import _isEmpty from 'lodash-es/isEmpty.js';
|
|
7
8
|
import _isNil from 'lodash-es/isNil.js';
|
|
8
9
|
import _pick from 'lodash-es/pick.js';
|
|
10
|
+
import _set from 'lodash-es/set.js';
|
|
9
11
|
import _toPath from 'lodash-es/toPath.js';
|
|
10
12
|
import getDefaultRegistry from '../getDefaultRegistry.js';
|
|
11
13
|
/** The `Form` component renders the outer form and all the fields defined in the `schema` */
|
|
@@ -14,6 +16,9 @@ export default class Form extends Component {
|
|
|
14
16
|
* provide any possible type here
|
|
15
17
|
*/
|
|
16
18
|
formElement;
|
|
19
|
+
/** The list of pending changes
|
|
20
|
+
*/
|
|
21
|
+
pendingChanges = [];
|
|
17
22
|
/** Constructs the `Form` from the `props`. Will setup the initial state from the props. It will also call the
|
|
18
23
|
* `onChange` handler if the initially provided `formData` is modified to add missing default values as part of the
|
|
19
24
|
* state construction.
|
|
@@ -51,16 +56,23 @@ export default class Form extends Component {
|
|
|
51
56
|
*/
|
|
52
57
|
getSnapshotBeforeUpdate(prevProps, prevState) {
|
|
53
58
|
if (!deepEquals(this.props, prevProps)) {
|
|
59
|
+
// Compare the previous props formData against the current props formData
|
|
54
60
|
const formDataChangedFields = getChangedFields(this.props.formData, prevProps.formData);
|
|
61
|
+
// Compare the current props formData against the current state's formData to determine if the new props were the
|
|
62
|
+
// result of the onChange from the existing state formData
|
|
63
|
+
const stateDataChangedFields = getChangedFields(this.props.formData, this.state.formData);
|
|
55
64
|
const isSchemaChanged = !deepEquals(prevProps.schema, this.props.schema);
|
|
56
65
|
// When formData is not an object, getChangedFields returns an empty array.
|
|
57
66
|
// In this case, deepEquals is most needed to check again.
|
|
58
67
|
const isFormDataChanged = formDataChangedFields.length > 0 || !deepEquals(prevProps.formData, this.props.formData);
|
|
68
|
+
const isStateDataChanged = stateDataChangedFields.length > 0 || !deepEquals(this.state.formData, this.props.formData);
|
|
59
69
|
const nextState = this.getStateFromProps(this.props, this.props.formData,
|
|
60
70
|
// If the `schema` has changed, we need to update the retrieved schema.
|
|
61
71
|
// Or if the `formData` changes, for example in the case of a schema with dependencies that need to
|
|
62
72
|
// match one of the subSchemas, the retrieved schema must be updated.
|
|
63
|
-
isSchemaChanged || isFormDataChanged ? undefined : this.state.retrievedSchema, isSchemaChanged, formDataChangedFields
|
|
73
|
+
isSchemaChanged || isFormDataChanged ? undefined : this.state.retrievedSchema, isSchemaChanged, formDataChangedFields,
|
|
74
|
+
// Skip live validation for this request if no form data has changed from the last state
|
|
75
|
+
!isStateDataChanged);
|
|
64
76
|
const shouldUpdate = !deepEquals(nextState, prevState);
|
|
65
77
|
return { nextState, shouldUpdate };
|
|
66
78
|
}
|
|
@@ -98,16 +110,17 @@ export default class Form extends Component {
|
|
|
98
110
|
* @param retrievedSchema - An expanded schema, if not provided, it will be retrieved from the `schema` and `formData`.
|
|
99
111
|
* @param isSchemaChanged - A flag indicating whether the schema has changed.
|
|
100
112
|
* @param formDataChangedFields - The changed fields of `formData`
|
|
113
|
+
* @param skipLiveValidate - Optional flag, if true, means that we are not running live validation
|
|
101
114
|
* @returns - The new state for the `Form`
|
|
102
115
|
*/
|
|
103
|
-
getStateFromProps(props, inputFormData, retrievedSchema, isSchemaChanged = false, formDataChangedFields = []) {
|
|
116
|
+
getStateFromProps(props, inputFormData, retrievedSchema, isSchemaChanged = false, formDataChangedFields = [], skipLiveValidate = false) {
|
|
104
117
|
const state = this.state || {};
|
|
105
118
|
const schema = 'schema' in props ? props.schema : this.props.schema;
|
|
119
|
+
const validator = 'validator' in props ? props.validator : this.props.validator;
|
|
106
120
|
const uiSchema = ('uiSchema' in props ? props.uiSchema : this.props.uiSchema) || {};
|
|
107
121
|
const edit = typeof inputFormData !== 'undefined';
|
|
108
122
|
const liveValidate = 'liveValidate' in props ? props.liveValidate : this.props.liveValidate;
|
|
109
123
|
const mustValidate = edit && !props.noValidate && liveValidate;
|
|
110
|
-
const rootSchema = schema;
|
|
111
124
|
const experimental_defaultFormStateBehavior = 'experimental_defaultFormStateBehavior' in props
|
|
112
125
|
? props.experimental_defaultFormStateBehavior
|
|
113
126
|
: this.props.experimental_defaultFormStateBehavior;
|
|
@@ -116,11 +129,12 @@ export default class Form extends Component {
|
|
|
116
129
|
: this.props.experimental_customMergeAllOf;
|
|
117
130
|
let schemaUtils = state.schemaUtils;
|
|
118
131
|
if (!schemaUtils ||
|
|
119
|
-
schemaUtils.doesSchemaUtilsDiffer(
|
|
120
|
-
schemaUtils = createSchemaUtils(
|
|
132
|
+
schemaUtils.doesSchemaUtilsDiffer(validator, schema, experimental_defaultFormStateBehavior, experimental_customMergeAllOf)) {
|
|
133
|
+
schemaUtils = createSchemaUtils(validator, schema, experimental_defaultFormStateBehavior, experimental_customMergeAllOf);
|
|
121
134
|
}
|
|
122
|
-
const
|
|
123
|
-
const
|
|
135
|
+
const rootSchema = schemaUtils.getRootSchema();
|
|
136
|
+
const formData = schemaUtils.getDefaultFormState(rootSchema, inputFormData);
|
|
137
|
+
const _retrievedSchema = this.updateRetrievedSchema(retrievedSchema ?? schemaUtils.retrieveSchema(rootSchema, formData));
|
|
124
138
|
const getCurrentErrors = () => {
|
|
125
139
|
// If the `props.noValidate` option is set or the schema has changed, we reset the error state.
|
|
126
140
|
if (props.noValidate || isSchemaChanged) {
|
|
@@ -141,8 +155,9 @@ export default class Form extends Component {
|
|
|
141
155
|
let errorSchema;
|
|
142
156
|
let schemaValidationErrors = state.schemaValidationErrors;
|
|
143
157
|
let schemaValidationErrorSchema = state.schemaValidationErrorSchema;
|
|
144
|
-
|
|
145
|
-
|
|
158
|
+
// If we are skipping live validate, it means that the state has already been updated with live validation errors
|
|
159
|
+
if (mustValidate && !skipLiveValidate) {
|
|
160
|
+
const schemaValidation = this.validate(formData, rootSchema, schemaUtils, _retrievedSchema);
|
|
146
161
|
errors = schemaValidation.errors;
|
|
147
162
|
// If retrievedSchema is undefined which means the schema or formData has changed, we do not merge state.
|
|
148
163
|
// Else in the case where it hasn't changed, we merge 'state.errorSchema' with 'schemaValidation.errorSchema.' This done to display the raised field error.
|
|
@@ -159,7 +174,8 @@ export default class Form extends Component {
|
|
|
159
174
|
const currentErrors = getCurrentErrors();
|
|
160
175
|
errors = currentErrors.errors;
|
|
161
176
|
errorSchema = currentErrors.errorSchema;
|
|
162
|
-
if
|
|
177
|
+
// We only update the error schema for changed fields if mustValidate is false
|
|
178
|
+
if (formDataChangedFields.length > 0 && !mustValidate) {
|
|
163
179
|
const newErrorSchema = formDataChangedFields.reduce((acc, key) => {
|
|
164
180
|
acc[key] = undefined;
|
|
165
181
|
return acc;
|
|
@@ -172,12 +188,12 @@ export default class Form extends Component {
|
|
|
172
188
|
errorSchema = merged.errorSchema;
|
|
173
189
|
errors = merged.errors;
|
|
174
190
|
}
|
|
175
|
-
const
|
|
191
|
+
const fieldPathId = toFieldPathId('', this.getGlobalFormOptions(this.props));
|
|
176
192
|
const nextState = {
|
|
177
193
|
schemaUtils,
|
|
178
|
-
schema,
|
|
194
|
+
schema: rootSchema,
|
|
179
195
|
uiSchema,
|
|
180
|
-
|
|
196
|
+
fieldPathId,
|
|
181
197
|
formData,
|
|
182
198
|
edit,
|
|
183
199
|
errors,
|
|
@@ -195,7 +211,8 @@ export default class Form extends Component {
|
|
|
195
211
|
* @returns - True if the component should be updated, false otherwise
|
|
196
212
|
*/
|
|
197
213
|
shouldComponentUpdate(nextProps, nextState) {
|
|
198
|
-
|
|
214
|
+
const { experimental_componentUpdateStrategy = 'customDeep' } = this.props;
|
|
215
|
+
return shouldRender(this, nextProps, nextState, experimental_componentUpdateStrategy);
|
|
199
216
|
}
|
|
200
217
|
/** Gets the previously raised customValidate errors.
|
|
201
218
|
*
|
|
@@ -207,8 +224,7 @@ export default class Form extends Component {
|
|
|
207
224
|
let customValidateErrors = {};
|
|
208
225
|
if (typeof customValidate === 'function') {
|
|
209
226
|
const errorHandler = customValidate(prevFormData, createErrorHandler(prevFormData), uiSchema);
|
|
210
|
-
|
|
211
|
-
customValidateErrors = userErrorSchema;
|
|
227
|
+
customValidateErrors = unwrapErrorHandler(errorHandler);
|
|
212
228
|
}
|
|
213
229
|
return customValidateErrors;
|
|
214
230
|
}
|
|
@@ -217,9 +233,10 @@ export default class Form extends Component {
|
|
|
217
233
|
*
|
|
218
234
|
* @param formData - The new form data to validate
|
|
219
235
|
* @param schema - The schema used to validate against
|
|
220
|
-
* @param altSchemaUtils - The alternate schemaUtils to use for validation
|
|
236
|
+
* @param [altSchemaUtils] - The alternate schemaUtils to use for validation
|
|
237
|
+
* @param [retrievedSchema] - An optionally retrieved schema for per
|
|
221
238
|
*/
|
|
222
|
-
validate(formData, schema = this.
|
|
239
|
+
validate(formData, schema = this.state.schema, altSchemaUtils, retrievedSchema) {
|
|
223
240
|
const schemaUtils = altSchemaUtils ? altSchemaUtils : this.state.schemaUtils;
|
|
224
241
|
const { customValidate, transformErrors, uiSchema } = this.props;
|
|
225
242
|
const resolvedSchema = retrievedSchema ?? schemaUtils.retrieveSchema(schema, formData);
|
|
@@ -230,11 +247,10 @@ export default class Form extends Component {
|
|
|
230
247
|
/** Renders any errors contained in the `state` in using the `ErrorList`, if not disabled by `showErrorList`. */
|
|
231
248
|
renderErrors(registry) {
|
|
232
249
|
const { errors, errorSchema, schema, uiSchema } = this.state;
|
|
233
|
-
const { formContext } = this.props;
|
|
234
250
|
const options = getUiOptions(uiSchema);
|
|
235
251
|
const ErrorListTemplate = getTemplate('ErrorListTemplate', registry, options);
|
|
236
252
|
if (errors && errors.length) {
|
|
237
|
-
return (_jsx(ErrorListTemplate, { errors: errors, errorSchema: errorSchema || {}, schema: schema, uiSchema: uiSchema,
|
|
253
|
+
return (_jsx(ErrorListTemplate, { errors: errors, errorSchema: errorSchema || {}, schema: schema, uiSchema: uiSchema, registry: registry }));
|
|
238
254
|
}
|
|
239
255
|
return null;
|
|
240
256
|
}
|
|
@@ -261,26 +277,28 @@ export default class Form extends Component {
|
|
|
261
277
|
* @param [formData] - The form data to use while checking for empty objects/arrays
|
|
262
278
|
*/
|
|
263
279
|
getFieldNames = (pathSchema, formData) => {
|
|
280
|
+
const formValueHasData = (value, isLeaf) => typeof value !== 'object' || _isEmpty(value) || (isLeaf && !_isEmpty(value));
|
|
264
281
|
const getAllPaths = (_obj, acc = [], paths = [[]]) => {
|
|
265
|
-
Object.keys(_obj)
|
|
266
|
-
|
|
282
|
+
const objKeys = Object.keys(_obj);
|
|
283
|
+
objKeys.forEach((key) => {
|
|
284
|
+
const data = _obj[key];
|
|
285
|
+
if (typeof data === 'object') {
|
|
267
286
|
const newPaths = paths.map((path) => [...path, key]);
|
|
268
287
|
// If an object is marked with additionalProperties, all its keys are valid
|
|
269
|
-
if (
|
|
270
|
-
acc.push(
|
|
288
|
+
if (data[RJSF_ADDITIONAL_PROPERTIES_FLAG] && data[NAME_KEY] !== '') {
|
|
289
|
+
acc.push(data[NAME_KEY]);
|
|
271
290
|
}
|
|
272
291
|
else {
|
|
273
|
-
getAllPaths(
|
|
292
|
+
getAllPaths(data, acc, newPaths);
|
|
274
293
|
}
|
|
275
294
|
}
|
|
276
|
-
else if (key === NAME_KEY &&
|
|
295
|
+
else if (key === NAME_KEY && data !== '') {
|
|
277
296
|
paths.forEach((path) => {
|
|
278
297
|
const formValue = _get(formData, path);
|
|
279
|
-
|
|
280
|
-
// or an empty object/array
|
|
281
|
-
if (
|
|
282
|
-
|
|
283
|
-
(Array.isArray(formValue) && formValue.every((val) => typeof val !== 'object'))) {
|
|
298
|
+
const isLeaf = objKeys.length === 1;
|
|
299
|
+
// adds path to fieldNames if it points to a value or an empty object/array which is not a leaf
|
|
300
|
+
if (formValueHasData(formValue, isLeaf) ||
|
|
301
|
+
(Array.isArray(formValue) && formValue.every((val) => formValueHasData(val, isLeaf)))) {
|
|
284
302
|
acc.push(path);
|
|
285
303
|
}
|
|
286
304
|
});
|
|
@@ -300,10 +318,15 @@ export default class Form extends Component {
|
|
|
300
318
|
const retrievedSchema = schemaUtils.retrieveSchema(schema, formData);
|
|
301
319
|
const pathSchema = schemaUtils.toPathSchema(retrievedSchema, '', formData);
|
|
302
320
|
const fieldNames = this.getFieldNames(pathSchema, formData);
|
|
303
|
-
|
|
304
|
-
return newFormData;
|
|
321
|
+
return this.getUsedFormData(formData, fieldNames);
|
|
305
322
|
};
|
|
306
|
-
|
|
323
|
+
/** Filtering errors based on your retrieved schema to only show errors for properties in the selected branch.
|
|
324
|
+
*
|
|
325
|
+
* @param schemaErrors - The schema errors to filter
|
|
326
|
+
* @param [resolvedSchema] - An optionally resolved schema to use for performance reasons
|
|
327
|
+
* @param [formData] - The formData to help filter errors
|
|
328
|
+
* @private
|
|
329
|
+
*/
|
|
307
330
|
filterErrorsBasedOnSchema(schemaErrors, resolvedSchema, formData) {
|
|
308
331
|
const { retrievedSchema, schemaUtils } = this.state;
|
|
309
332
|
const _retrievedSchema = resolvedSchema ?? retrievedSchema;
|
|
@@ -312,7 +335,7 @@ export default class Form extends Component {
|
|
|
312
335
|
const filteredErrors = _pick(schemaErrors, fieldNames);
|
|
313
336
|
// If the root schema is of a primitive type, do not filter out the __errors
|
|
314
337
|
if (resolvedSchema?.type !== 'object' && resolvedSchema?.type !== 'array') {
|
|
315
|
-
filteredErrors
|
|
338
|
+
filteredErrors[ERRORS_KEY] = schemaErrors[ERRORS_KEY];
|
|
316
339
|
}
|
|
317
340
|
const prevCustomValidateErrors = this.getPreviousCustomValidateErrors();
|
|
318
341
|
// Filtering out the previous raised customValidate errors so that they are cleared when no longer valid.
|
|
@@ -333,11 +356,13 @@ export default class Form extends Component {
|
|
|
333
356
|
}
|
|
334
357
|
else if (isObject(errorAtKey) &&
|
|
335
358
|
isObject(prevCustomValidateErrorAtKey) &&
|
|
336
|
-
Array.isArray(prevCustomValidateErrorAtKey?.
|
|
359
|
+
Array.isArray(prevCustomValidateErrorAtKey?.[ERRORS_KEY])) {
|
|
337
360
|
// if previous customValidate error is an object and has __errors array, filter out the errors previous customValidate errors.
|
|
338
|
-
errors[errorKey] =
|
|
361
|
+
errors[errorKey] = {
|
|
362
|
+
[ERRORS_KEY]: filterPreviousCustomErrors(errorAtKey[ERRORS_KEY], prevCustomValidateErrorAtKey?.[ERRORS_KEY]),
|
|
363
|
+
};
|
|
339
364
|
}
|
|
340
|
-
else if (typeof errorAtKey === 'object' && !Array.isArray(errorAtKey
|
|
365
|
+
else if (typeof errorAtKey === 'object' && !Array.isArray(errorAtKey[ERRORS_KEY])) {
|
|
341
366
|
filterNilOrEmptyErrors(errorAtKey, previousCustomValidateErrors[errorKey]);
|
|
342
367
|
}
|
|
343
368
|
});
|
|
@@ -345,23 +370,48 @@ export default class Form extends Component {
|
|
|
345
370
|
};
|
|
346
371
|
return filterNilOrEmptyErrors(filteredErrors, prevCustomValidateErrors);
|
|
347
372
|
}
|
|
348
|
-
/**
|
|
349
|
-
*
|
|
350
|
-
* then, if `omitExtraData` and `liveOmit` are turned on, the `formData` will be filtered to remove any extra data not
|
|
351
|
-
* in a form field. Then, the resulting formData will be validated if required. The state will be updated with the new
|
|
352
|
-
* updated (potentially filtered) `formData`, any errors that resulted from validation. Finally the `onChange`
|
|
353
|
-
* callback will be called if specified with the updated state.
|
|
373
|
+
/** Pushes the given change information into the `pendingChanges` array and then calls `processPendingChanges()` if
|
|
374
|
+
* the array only contains a single pending change.
|
|
354
375
|
*
|
|
355
|
-
* @param
|
|
356
|
-
* @param
|
|
357
|
-
* @param
|
|
376
|
+
* @param newValue - The new form data from a change to a field
|
|
377
|
+
* @param path - The path to the change into which to set the formData
|
|
378
|
+
* @param [newErrorSchema] - The new `ErrorSchema` based on the field change
|
|
379
|
+
* @param [id] - The id of the field that caused the change
|
|
358
380
|
*/
|
|
359
|
-
onChange = (
|
|
381
|
+
onChange = (newValue, path, newErrorSchema, id) => {
|
|
382
|
+
this.pendingChanges.push({ newValue, path, newErrorSchema, id });
|
|
383
|
+
if (this.pendingChanges.length === 1) {
|
|
384
|
+
this.processPendingChange();
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
/** Function to handle changes made to a field in the `Form`. This handler gets the first change from the
|
|
388
|
+
* `pendingChanges` list, containing the `newValue` for the `formData` and the `path` at which the `newValue` is to be
|
|
389
|
+
* updated, along with a new, optional `ErrorSchema` for that same `path` and potentially the `id` of the field being
|
|
390
|
+
* changed. It will first update the `formData` with any missing default fields and then, if `omitExtraData` and
|
|
391
|
+
* `liveOmit` are turned on, the `formData` will be filtered to remove any extra data not in a form field. Then, the
|
|
392
|
+
* resulting `formData` will be validated if required. The state will be updated with the new updated (potentially
|
|
393
|
+
* filtered) `formData`, any errors that resulted from validation. Finally the `onChange` callback will be called, if
|
|
394
|
+
* specified, with the updated state and the `processPendingChange()` function is called again.
|
|
395
|
+
*/
|
|
396
|
+
processPendingChange() {
|
|
397
|
+
if (this.pendingChanges.length === 0) {
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
const { newValue, path, id } = this.pendingChanges[0];
|
|
401
|
+
let { newErrorSchema } = this.pendingChanges[0];
|
|
360
402
|
const { extraErrors, omitExtraData, liveOmit, noValidate, liveValidate, onChange } = this.props;
|
|
361
|
-
const { schemaUtils, schema } = this.state;
|
|
403
|
+
const { formData: oldFormData, schemaUtils, schema, errorSchema, fieldPathId } = this.state;
|
|
404
|
+
const rootPathId = fieldPathId.path[0] || '';
|
|
405
|
+
const isRootPath = !path || path.length === 0 || (path.length === 1 && path[0] === rootPathId);
|
|
362
406
|
let retrievedSchema = this.state.retrievedSchema;
|
|
407
|
+
let formData = isRootPath ? newValue : _cloneDeep(oldFormData);
|
|
363
408
|
if (isObject(formData) || Array.isArray(formData)) {
|
|
364
|
-
|
|
409
|
+
if (!isRootPath) {
|
|
410
|
+
// If the newValue is not on the root path, then set it into the form data
|
|
411
|
+
_set(formData, path, newValue);
|
|
412
|
+
}
|
|
413
|
+
// Pass true to skip live validation in `getStateFromProps()` since we will do it a bit later
|
|
414
|
+
const newState = this.getStateFromProps(this.props, formData, undefined, undefined, undefined, true);
|
|
365
415
|
formData = newState.formData;
|
|
366
416
|
retrievedSchema = newState.retrievedSchema;
|
|
367
417
|
}
|
|
@@ -374,7 +424,15 @@ export default class Form extends Component {
|
|
|
374
424
|
formData: newFormData,
|
|
375
425
|
};
|
|
376
426
|
}
|
|
377
|
-
if
|
|
427
|
+
// First update the value in the newErrorSchema in a copy of the old error schema if it was specified and the path
|
|
428
|
+
// is not the root
|
|
429
|
+
if (newErrorSchema && !isRootPath) {
|
|
430
|
+
const errorSchemaCopy = _cloneDeep(errorSchema);
|
|
431
|
+
_set(errorSchemaCopy, path, newErrorSchema);
|
|
432
|
+
newErrorSchema = errorSchemaCopy;
|
|
433
|
+
}
|
|
434
|
+
// If there are pending changes in the queue, skip live validation since it will happen with the last change
|
|
435
|
+
if (mustValidate && this.pendingChanges.length === 1) {
|
|
378
436
|
const schemaValidation = this.validate(newFormData, schema, schemaUtils, retrievedSchema);
|
|
379
437
|
let errors = schemaValidation.errors;
|
|
380
438
|
let errorSchema = schemaValidation.errorSchema;
|
|
@@ -399,6 +457,7 @@ export default class Form extends Component {
|
|
|
399
457
|
};
|
|
400
458
|
}
|
|
401
459
|
else if (!noValidate && newErrorSchema) {
|
|
460
|
+
// Merging 'newErrorSchema' into 'errorSchema' to display the custom raised errors.
|
|
402
461
|
const errorSchema = extraErrors
|
|
403
462
|
? mergeObjects(newErrorSchema, extraErrors, 'preventDuplicates')
|
|
404
463
|
: newErrorSchema;
|
|
@@ -408,8 +467,15 @@ export default class Form extends Component {
|
|
|
408
467
|
errors: toErrorList(errorSchema),
|
|
409
468
|
};
|
|
410
469
|
}
|
|
411
|
-
this.setState(state, () =>
|
|
412
|
-
|
|
470
|
+
this.setState(state, () => {
|
|
471
|
+
if (onChange) {
|
|
472
|
+
onChange({ ...this.state, ...state }, id);
|
|
473
|
+
}
|
|
474
|
+
// Now remove the change we just completed and call this again
|
|
475
|
+
this.pendingChanges.shift();
|
|
476
|
+
this.processPendingChange();
|
|
477
|
+
});
|
|
478
|
+
}
|
|
413
479
|
/**
|
|
414
480
|
* If the retrievedSchema has changed the new retrievedSchema is returned.
|
|
415
481
|
* Otherwise, the old retrievedSchema is returned to persist reference.
|
|
@@ -503,10 +569,22 @@ export default class Form extends Component {
|
|
|
503
569
|
});
|
|
504
570
|
}
|
|
505
571
|
};
|
|
572
|
+
/** Extracts the `GlobalFormOptions` from the given Form `props`
|
|
573
|
+
*
|
|
574
|
+
* @param props - The form props to extract the global form options from
|
|
575
|
+
* @returns - The `GlobalFormOptions` from the props
|
|
576
|
+
* @private
|
|
577
|
+
*/
|
|
578
|
+
getGlobalFormOptions(props) {
|
|
579
|
+
const { uiSchema = {}, experimental_componentUpdateStrategy, idSeparator = DEFAULT_ID_SEPARATOR, idPrefix = DEFAULT_ID_PREFIX, } = props;
|
|
580
|
+
const rootFieldId = uiSchema['ui:rootFieldId'];
|
|
581
|
+
// Omit any options that are undefined or null
|
|
582
|
+
return { idPrefix: rootFieldId || idPrefix, idSeparator, experimental_componentUpdateStrategy };
|
|
583
|
+
}
|
|
506
584
|
/** Returns the registry for the form */
|
|
507
585
|
getRegistry() {
|
|
508
586
|
const { translateString: customTranslateString, uiSchema = {} } = this.props;
|
|
509
|
-
const { schemaUtils } = this.state;
|
|
587
|
+
const { schema, schemaUtils } = this.state;
|
|
510
588
|
const { fields, templates, widgets, formContext, translateString } = getDefaultRegistry();
|
|
511
589
|
return {
|
|
512
590
|
fields: { ...fields, ...this.props.fields },
|
|
@@ -519,11 +597,12 @@ export default class Form extends Component {
|
|
|
519
597
|
},
|
|
520
598
|
},
|
|
521
599
|
widgets: { ...widgets, ...this.props.widgets },
|
|
522
|
-
rootSchema:
|
|
600
|
+
rootSchema: schema,
|
|
523
601
|
formContext: this.props.formContext || formContext,
|
|
524
602
|
schemaUtils,
|
|
525
603
|
translateString: customTranslateString || translateString,
|
|
526
604
|
globalUiOptions: uiSchema[UI_GLOBAL_OPTIONS_KEY],
|
|
605
|
+
globalFormOptions: this.getGlobalFormOptions(this.props),
|
|
527
606
|
};
|
|
528
607
|
}
|
|
529
608
|
/** Provides a function that can be used to programmatically submit the `Form` */
|
|
@@ -640,8 +719,8 @@ export default class Form extends Component {
|
|
|
640
719
|
* needed along with the submit button or any children of the form.
|
|
641
720
|
*/
|
|
642
721
|
render() {
|
|
643
|
-
const { children, id,
|
|
644
|
-
const { schema, uiSchema, formData, errorSchema,
|
|
722
|
+
const { children, id, className = '', tagName, name, method, target, action, autoComplete, enctype, acceptCharset, noHtml5Validate = false, disabled, readonly, showErrorList = 'top', _internalFormWrapper, } = this.props;
|
|
723
|
+
const { schema, uiSchema, formData, errorSchema, fieldPathId } = this.state;
|
|
645
724
|
const registry = this.getRegistry();
|
|
646
725
|
const { SchemaField: _SchemaField } = registry.fields;
|
|
647
726
|
const { SubmitButton } = registry.templates.ButtonTemplates;
|
|
@@ -655,6 +734,6 @@ export default class Form extends Component {
|
|
|
655
734
|
submitOptions = { ...submitOptions, props: { ...submitOptions.props, disabled: true } };
|
|
656
735
|
}
|
|
657
736
|
const submitUiSchema = { [UI_OPTIONS_KEY]: { [SUBMIT_BTN_OPTIONS_KEY]: submitOptions } };
|
|
658
|
-
return (_jsxs(FormTag, { className: className ? className : 'rjsf', id: id, name: name, method: method, target: target, action: action, autoComplete: autoComplete, encType: enctype, 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,
|
|
737
|
+
return (_jsxs(FormTag, { className: className ? className : 'rjsf', id: id, name: name, method: method, target: target, action: action, autoComplete: autoComplete, encType: enctype, 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, fieldPathId: fieldPathId, 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)] }));
|
|
659
738
|
}
|
|
660
739
|
}
|