@rjsf/core 6.3.1 → 6.4.1
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 +45 -14
- package/dist/index.cjs +45 -14
- package/dist/index.cjs.map +2 -2
- package/dist/index.esm.js +45 -14
- package/dist/index.esm.js.map +2 -2
- package/lib/components/Form.d.ts +10 -0
- package/lib/components/Form.d.ts.map +1 -1
- package/lib/components/Form.js +44 -13
- package/lib/components/fields/ArrayField.d.ts.map +1 -1
- package/lib/components/fields/ArrayField.js +2 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/src/components/Form.tsx +53 -13
- package/src/components/fields/ArrayField.tsx +2 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rjsf/core",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.4.1",
|
|
4
4
|
"description": "A simple React component capable of building HTML forms out of a JSON schema.",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"compileReplacer": "tsc -p tsconfig.replacer.json && move-file lodashReplacer.js lodashReplacer.cjs",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"node": ">=20"
|
|
67
67
|
},
|
|
68
68
|
"peerDependencies": {
|
|
69
|
-
"@rjsf/utils": "^6.
|
|
69
|
+
"@rjsf/utils": "^6.4.x",
|
|
70
70
|
"react": ">=18"
|
|
71
71
|
},
|
|
72
72
|
"dependencies": {
|
|
@@ -76,9 +76,9 @@
|
|
|
76
76
|
"prop-types": "^15.8.1"
|
|
77
77
|
},
|
|
78
78
|
"devDependencies": {
|
|
79
|
-
"@rjsf/snapshot-tests": "6.
|
|
80
|
-
"@rjsf/utils": "6.
|
|
81
|
-
"@rjsf/validator-ajv8": "6.
|
|
79
|
+
"@rjsf/snapshot-tests": "6.4.1",
|
|
80
|
+
"@rjsf/utils": "6.4.1",
|
|
81
|
+
"@rjsf/validator-ajv8": "6.4.1",
|
|
82
82
|
"@testing-library/jest-dom": "^6.9.1",
|
|
83
83
|
"@testing-library/react": "^16.3.2",
|
|
84
84
|
"@testing-library/user-event": "^14.6.1",
|
package/src/components/Form.tsx
CHANGED
|
@@ -308,6 +308,8 @@ export interface FormState<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
|
|
|
308
308
|
initialDefaultsGenerated: boolean;
|
|
309
309
|
/** The registry (re)computed only when props changed */
|
|
310
310
|
registry: Registry<T, S, F>;
|
|
311
|
+
/** Tracks the previous `extraErrors` prop reference so that `getDerivedStateFromProps` can detect changes */
|
|
312
|
+
_prevExtraErrors?: ErrorSchema<T>;
|
|
311
313
|
}
|
|
312
314
|
|
|
313
315
|
/** The event data passed when changes have been made to the form, includes everything from the `FormState` except
|
|
@@ -374,6 +376,38 @@ export default class Form<
|
|
|
374
376
|
*/
|
|
375
377
|
private _isProcessingUserChange = false;
|
|
376
378
|
|
|
379
|
+
/** When the `extraErrors` prop changes, re-merges `schemaValidationErrors` + `extraErrors` + `customErrors` into
|
|
380
|
+
* state before render, ensuring the updated errors are visible immediately in a single render cycle.
|
|
381
|
+
*
|
|
382
|
+
* @param props - The current props
|
|
383
|
+
* @param state - The current state
|
|
384
|
+
* @returns Partial state with re-merged errors if `extraErrors` changed, or `null` if no update is needed
|
|
385
|
+
*/
|
|
386
|
+
static getDerivedStateFromProps<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
|
|
387
|
+
props: FormProps<T, S, F>,
|
|
388
|
+
state: FormState<T, S, F>,
|
|
389
|
+
): Partial<FormState<T, S, F>> | null {
|
|
390
|
+
if (props.extraErrors !== state._prevExtraErrors) {
|
|
391
|
+
const baseErrors: ValidationData<T> = {
|
|
392
|
+
errors: state.schemaValidationErrors || [],
|
|
393
|
+
errorSchema: (state.schemaValidationErrorSchema || {}) as ErrorSchema<T>,
|
|
394
|
+
};
|
|
395
|
+
let { errors, errorSchema } = baseErrors;
|
|
396
|
+
if (props.extraErrors) {
|
|
397
|
+
({ errors, errorSchema } = validationDataMerge<T>(baseErrors, props.extraErrors));
|
|
398
|
+
}
|
|
399
|
+
if (state.customErrors) {
|
|
400
|
+
({ errors, errorSchema } = validationDataMerge<T>(
|
|
401
|
+
{ errors, errorSchema },
|
|
402
|
+
state.customErrors.ErrorSchema,
|
|
403
|
+
true,
|
|
404
|
+
));
|
|
405
|
+
}
|
|
406
|
+
return { _prevExtraErrors: props.extraErrors, errors, errorSchema };
|
|
407
|
+
}
|
|
408
|
+
return null;
|
|
409
|
+
}
|
|
410
|
+
|
|
377
411
|
/** Constructs the `Form` from the `props`. Will setup the initial state from the props. It will also call the
|
|
378
412
|
* `onChange` handler if the initially provided `formData` is modified to add missing default values as part of the
|
|
379
413
|
* state construction.
|
|
@@ -389,7 +423,10 @@ export default class Form<
|
|
|
389
423
|
|
|
390
424
|
const { formData: propsFormData, initialFormData, onChange } = props;
|
|
391
425
|
const formData = propsFormData ?? initialFormData;
|
|
392
|
-
this.state =
|
|
426
|
+
this.state = {
|
|
427
|
+
...this.getStateFromProps(props, formData, undefined, undefined, undefined, true),
|
|
428
|
+
_prevExtraErrors: props.extraErrors,
|
|
429
|
+
};
|
|
393
430
|
if (onChange && !deepEquals(this.state.formData, formData)) {
|
|
394
431
|
onChange(toIChangeEvent(this.state));
|
|
395
432
|
}
|
|
@@ -1219,17 +1256,12 @@ export default class Form<
|
|
|
1219
1256
|
const { extraErrors, extraErrorsBlockSubmit, focusOnFirstError, onError } = this.props;
|
|
1220
1257
|
const { errors: prevErrors } = this.state;
|
|
1221
1258
|
const schemaValidation = this.validate(formData);
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
const hasError = errors.length > 0 || (extraErrors && extraErrorsBlockSubmit);
|
|
1259
|
+
// Always merge extraErrors so they remain visible in state regardless of extraErrorsBlockSubmit.
|
|
1260
|
+
const { errors, errorSchema } = extraErrors ? this.mergeErrors(schemaValidation, extraErrors) : schemaValidation;
|
|
1261
|
+
// hasError gates submission: schema errors always block; extraErrors only block when
|
|
1262
|
+
// extraErrorsBlockSubmit is set (non-breaking default: extraErrors are informational only).
|
|
1263
|
+
const hasError = schemaValidation.errors.length > 0 || (extraErrors && extraErrorsBlockSubmit);
|
|
1227
1264
|
if (hasError) {
|
|
1228
|
-
if (extraErrors) {
|
|
1229
|
-
const merged = validationDataMerge(schemaValidation, extraErrors);
|
|
1230
|
-
errorSchema = merged.errorSchema;
|
|
1231
|
-
errors = merged.errors;
|
|
1232
|
-
}
|
|
1233
1265
|
if (focusOnFirstError) {
|
|
1234
1266
|
if (typeof focusOnFirstError === 'function') {
|
|
1235
1267
|
focusOnFirstError(errors[0]);
|
|
@@ -1241,8 +1273,8 @@ export default class Form<
|
|
|
1241
1273
|
{
|
|
1242
1274
|
errors,
|
|
1243
1275
|
errorSchema,
|
|
1244
|
-
schemaValidationErrors,
|
|
1245
|
-
schemaValidationErrorSchema,
|
|
1276
|
+
schemaValidationErrors: schemaValidation.errors,
|
|
1277
|
+
schemaValidationErrorSchema: schemaValidation.errorSchema,
|
|
1246
1278
|
},
|
|
1247
1279
|
() => {
|
|
1248
1280
|
if (onError) {
|
|
@@ -1252,6 +1284,14 @@ export default class Form<
|
|
|
1252
1284
|
}
|
|
1253
1285
|
},
|
|
1254
1286
|
);
|
|
1287
|
+
} else if (errors.length > 0) {
|
|
1288
|
+
// Non-blocking extraErrors are present — update display state without triggering onError.
|
|
1289
|
+
this.setState({
|
|
1290
|
+
errors,
|
|
1291
|
+
errorSchema,
|
|
1292
|
+
schemaValidationErrors: [],
|
|
1293
|
+
schemaValidationErrorSchema: {},
|
|
1294
|
+
});
|
|
1255
1295
|
} else if (prevErrors.length > 0) {
|
|
1256
1296
|
this.setState({
|
|
1257
1297
|
errors: [],
|
|
@@ -199,7 +199,8 @@ function ArrayAsMultiSelect<T = any, S extends StrictRJSFSchema = RJSFSchema, F
|
|
|
199
199
|
} = props;
|
|
200
200
|
const { widgets, schemaUtils, globalFormOptions, globalUiOptions } = registry;
|
|
201
201
|
const itemsSchema = schemaUtils.retrieveSchema(schema.items as S, items);
|
|
202
|
-
const
|
|
202
|
+
const itemsUiSchema = (uiSchema?.items ?? {}) as UiSchema<T[], S, F>;
|
|
203
|
+
const enumOptions = optionsList<T[], S, F>(itemsSchema, itemsUiSchema);
|
|
203
204
|
const { widget = 'select', title: uiTitle, ...options } = getUiOptions<T[], S, F>(uiSchema, globalUiOptions);
|
|
204
205
|
const Widget = getWidget<T[], S, F>(schema, widget, widgets);
|
|
205
206
|
const label = uiTitle ?? schema.title ?? name;
|