@rjsf/core 5.0.2 → 5.2.0

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.esm.js CHANGED
@@ -1,14 +1,16 @@
1
1
  import React, { Component, useState, useCallback, useEffect, useReducer, useMemo, forwardRef } from 'react';
2
- import { isFixedItems, allowAdditionalItems, getUiOptions, ITEMS_KEY, getTemplate, isCustomWidget, getWidget, optionsList, deepEquals, ERRORS_KEY, asNumber, REF_KEY, orderProperties, PROPERTIES_KEY, ADDITIONAL_PROPERTY_FLAG, ANY_OF_KEY, ONE_OF_KEY, mergeObjects, UI_OPTIONS_KEY, descriptionId, getSchemaType, ID_KEY, hasWidget, titleId, getInputProps, examplesId, ariaDescribedByIds, getSubmitButtonOptions, errorId, helpId, canExpand, parseDateString, toDateString, pad, schemaRequiresTrueValue, enumOptionsValueForIndex, enumOptionsIsSelected, optionId, enumOptionsSelectValue, enumOptionsDeselectValue, utcToLocal, localToUTC, dataURItoBlob, enumOptionsIndexForValue, createSchemaUtils, shouldRender, isObject as isObject$1, RJSF_ADDITONAL_PROPERTIES_FLAG, NAME_KEY } from '@rjsf/utils';
2
+ import { isFixedItems, allowAdditionalItems, getUiOptions, ITEMS_KEY, getTemplate, TranslatableString, isCustomWidget, getWidget, optionsList, deepEquals, ERRORS_KEY, asNumber, REF_KEY, orderProperties, PROPERTIES_KEY, ADDITIONAL_PROPERTY_FLAG, ANY_OF_KEY, ONE_OF_KEY, mergeObjects, UI_OPTIONS_KEY, descriptionId, getSchemaType, ID_KEY, hasWidget, titleId, getInputProps, examplesId, ariaDescribedByIds, getSubmitButtonOptions, errorId, helpId, canExpand, parseDateString, toDateString, pad, schemaRequiresTrueValue, enumOptionsValueForIndex, enumOptionsIsSelected, optionId, enumOptionsSelectValue, enumOptionsDeselectValue, utcToLocal, localToUTC, dataURItoBlob, enumOptionsIndexForValue, englishStringTranslator, createSchemaUtils, shouldRender, isObject as isObject$1, RJSF_ADDITONAL_PROPERTIES_FLAG, NAME_KEY } from '@rjsf/utils';
3
3
  import get from 'lodash-es/get';
4
4
  import isEmpty from 'lodash-es/isEmpty';
5
5
  import _pick from 'lodash-es/pick';
6
+ import _toPath from 'lodash-es/toPath';
6
7
  import isObject from 'lodash-es/isObject';
7
8
  import set from 'lodash-es/set';
8
9
  import { nanoid } from 'nanoid';
9
10
  import omit from 'lodash-es/omit';
10
11
  import has from 'lodash-es/has';
11
12
  import unset from 'lodash-es/unset';
13
+ import Markdown from 'markdown-to-jsx';
12
14
 
13
15
  function _defineProperties(target, props) {
14
16
  for (var i = 0; i < props.length; i++) {
@@ -188,7 +190,7 @@ var ArrayField = /*#__PURE__*/function (_Component) {
188
190
  onChange = _this$props3.onChange,
189
191
  errorSchema = _this$props3.errorSchema;
190
192
  var newErrorSchema;
191
- if (_this.props.errorSchema) {
193
+ if (errorSchema) {
192
194
  newErrorSchema = {};
193
195
  for (var idx in errorSchema) {
194
196
  var i = parseInt(idx);
@@ -365,14 +367,15 @@ var ArrayField = /*#__PURE__*/function (_Component) {
365
367
  uiSchema = _this$props7.uiSchema,
366
368
  idSchema = _this$props7.idSchema,
367
369
  registry = _this$props7.registry;
368
- var schemaUtils = registry.schemaUtils;
370
+ var schemaUtils = registry.schemaUtils,
371
+ translateString = registry.translateString;
369
372
  if (!(ITEMS_KEY in schema)) {
370
373
  var uiOptions = getUiOptions(uiSchema);
371
374
  var UnsupportedFieldTemplate = getTemplate("UnsupportedFieldTemplate", registry, uiOptions);
372
375
  return /*#__PURE__*/React.createElement(UnsupportedFieldTemplate, {
373
376
  schema: schema,
374
377
  idSchema: idSchema,
375
- reason: "Missing items definition",
378
+ reason: translateString(TranslatableString.MissingItems),
376
379
  registry: registry
377
380
  });
378
381
  }
@@ -829,8 +832,11 @@ var ArrayField = /*#__PURE__*/function (_Component) {
829
832
  _createClass(ArrayField, [{
830
833
  key: "itemTitle",
831
834
  get: function get$1() {
832
- var schema = this.props.schema;
833
- return get(schema, [ITEMS_KEY, "title"], get(schema, [ITEMS_KEY, "description"], "Item"));
835
+ var _this$props14 = this.props,
836
+ schema = _this$props14.schema,
837
+ registry = _this$props14.registry;
838
+ var translateString = registry.translateString;
839
+ return get(schema, [ITEMS_KEY, "title"], get(schema, [ITEMS_KEY, "description"], translateString(TranslatableString.ArrayItemTitle)));
834
840
  }
835
841
  }]);
836
842
  return ArrayField;
@@ -859,19 +865,22 @@ function BooleanField(props) {
859
865
  rawErrors = props.rawErrors;
860
866
  var title = schema.title;
861
867
  var widgets = registry.widgets,
862
- formContext = registry.formContext;
868
+ formContext = registry.formContext,
869
+ translateString = registry.translateString;
863
870
  var _getUiOptions = getUiOptions(uiSchema),
864
871
  _getUiOptions$widget = _getUiOptions.widget,
865
872
  widget = _getUiOptions$widget === void 0 ? "checkbox" : _getUiOptions$widget,
866
873
  options = _objectWithoutPropertiesLoose(_getUiOptions, _excluded$8);
867
874
  var Widget = getWidget(schema, widget, widgets);
875
+ var yes = translateString(TranslatableString.YesLabel);
876
+ var no = translateString(TranslatableString.NoLabel);
868
877
  var enumOptions;
869
878
  if (Array.isArray(schema.oneOf)) {
870
879
  enumOptions = optionsList({
871
880
  oneOf: schema.oneOf.map(function (option) {
872
881
  if (isObject(option)) {
873
882
  return _extends({}, option, {
874
- title: option.title || (option["const"] === true ? "Yes" : "No")
883
+ title: option.title || (option["const"] === true ? yes : no)
875
884
  });
876
885
  }
877
886
  return undefined;
@@ -889,10 +898,10 @@ function BooleanField(props) {
889
898
  })) {
890
899
  enumOptions = [{
891
900
  value: enums[0],
892
- label: enums[0] ? "Yes" : "No"
901
+ label: enums[0] ? yes : no
893
902
  }, {
894
903
  value: enums[1],
895
- label: enums[1] ? "Yes" : "No"
904
+ label: enums[1] ? yes : no
896
905
  }];
897
906
  } else {
898
907
  enumOptions = optionsList({
@@ -925,9 +934,6 @@ function BooleanField(props) {
925
934
  }
926
935
 
927
936
  var _excluded$7 = ["widget", "placeholder", "autofocus", "autocomplete", "title"];
928
- /** The prefix used when a oneOf option does not have a title
929
- */
930
- var UNKNOWN_OPTION_PREFIX = "Option";
931
937
  /** The `AnyOfField` component is used to render a field in the schema that is an `anyOf`, `allOf` or `oneOf`. It tracks
932
938
  * the currently selected option and cleans up any irrelevant data in `formData`.
933
939
  *
@@ -1066,7 +1072,8 @@ var AnyOfField = /*#__PURE__*/function (_Component) {
1066
1072
  schema = _this$props5.schema,
1067
1073
  uiSchema = _this$props5.uiSchema;
1068
1074
  var widgets = registry.widgets,
1069
- fields = registry.fields;
1075
+ fields = registry.fields,
1076
+ translateString = registry.translateString;
1070
1077
  var _SchemaField = fields.SchemaField;
1071
1078
  var _this$state2 = this.state,
1072
1079
  selectedOption = _this$state2.selectedOption,
@@ -1094,10 +1101,11 @@ var AnyOfField = /*#__PURE__*/function (_Component) {
1094
1101
  type: baseType
1095
1102
  });
1096
1103
  }
1097
- var optionLabel = title ? title + " " + UNKNOWN_OPTION_PREFIX.toLowerCase() : UNKNOWN_OPTION_PREFIX;
1104
+ var translateEnum = title ? TranslatableString.TitleOptionPrefix : TranslatableString.OptionPrefix;
1105
+ var translateParams = title ? [title] : [];
1098
1106
  var enumOptions = retrievedOptions.map(function (opt, index) {
1099
1107
  return {
1100
- label: opt.title || optionLabel + " " + (index + 1),
1108
+ label: opt.title || translateString(translateEnum, translateParams.concat(String(index + 1))),
1101
1109
  value: index
1102
1110
  };
1103
1111
  });
@@ -1352,9 +1360,8 @@ var ObjectField = /*#__PURE__*/function (_Component) {
1352
1360
  * @param type - The type of the new additional schema property
1353
1361
  */
1354
1362
  _proto.getDefaultValue = function getDefaultValue(type) {
1363
+ var translateString = this.props.registry.translateString;
1355
1364
  switch (type) {
1356
- case "string":
1357
- return "New Value";
1358
1365
  case "array":
1359
1366
  return [];
1360
1367
  case "boolean":
@@ -1365,9 +1372,10 @@ var ObjectField = /*#__PURE__*/function (_Component) {
1365
1372
  return 0;
1366
1373
  case "object":
1367
1374
  return {};
1375
+ case "string":
1368
1376
  default:
1369
1377
  // We don't have a datatype for some reason (perhaps additionalProperties was true)
1370
- return "New Value";
1378
+ return translateString(TranslatableString.NewStringDefault);
1371
1379
  }
1372
1380
  }
1373
1381
  /** Handles the adding of a new additional property on the given `schema`. Calls the `onChange` callback once the new
@@ -1501,7 +1509,8 @@ var COMPONENT_TYPES = {
1501
1509
  */
1502
1510
  function getFieldComponent(schema, uiOptions, idSchema, registry) {
1503
1511
  var field = uiOptions.field;
1504
- var fields = registry.fields;
1512
+ var fields = registry.fields,
1513
+ translateString = registry.translateString;
1505
1514
  if (typeof field === "function") {
1506
1515
  return field;
1507
1516
  }
@@ -1523,7 +1532,7 @@ function getFieldComponent(schema, uiOptions, idSchema, registry) {
1523
1532
  return /*#__PURE__*/React.createElement(UnsupportedFieldTemplate, {
1524
1533
  schema: schema,
1525
1534
  idSchema: idSchema,
1526
- reason: "Unknown field type " + schema.type,
1535
+ reason: translateString(TranslatableString.UnknownFieldType, [String(schema.type)]),
1527
1536
  registry: registry
1528
1537
  });
1529
1538
  };
@@ -2108,24 +2117,27 @@ function IconButton(props) {
2108
2117
  }));
2109
2118
  }
2110
2119
  function MoveDownButton(props) {
2120
+ var translateString = props.registry.translateString;
2111
2121
  return /*#__PURE__*/React.createElement(IconButton, _extends({
2112
- title: "Move down",
2122
+ title: translateString(TranslatableString.MoveDownButton),
2113
2123
  className: "array-item-move-down"
2114
2124
  }, props, {
2115
2125
  icon: "arrow-down"
2116
2126
  }));
2117
2127
  }
2118
2128
  function MoveUpButton(props) {
2129
+ var translateString = props.registry.translateString;
2119
2130
  return /*#__PURE__*/React.createElement(IconButton, _extends({
2120
- title: "Move up",
2131
+ title: translateString(TranslatableString.MoveUpButton),
2121
2132
  className: "array-item-move-up"
2122
2133
  }, props, {
2123
2134
  icon: "arrow-up"
2124
2135
  }));
2125
2136
  }
2126
2137
  function RemoveButton(props) {
2138
+ var translateString = props.registry.translateString;
2127
2139
  return /*#__PURE__*/React.createElement(IconButton, _extends({
2128
- title: "Remove",
2140
+ title: translateString(TranslatableString.RemoveButton),
2129
2141
  className: "array-item-remove"
2130
2142
  }, props, {
2131
2143
  iconType: "danger",
@@ -2140,6 +2152,7 @@ function AddButton(_ref) {
2140
2152
  onClick = _ref.onClick,
2141
2153
  disabled = _ref.disabled,
2142
2154
  registry = _ref.registry;
2155
+ var translateString = registry.translateString;
2143
2156
  return /*#__PURE__*/React.createElement("div", {
2144
2157
  className: "row"
2145
2158
  }, /*#__PURE__*/React.createElement("p", {
@@ -2148,7 +2161,7 @@ function AddButton(_ref) {
2148
2161
  iconType: "info",
2149
2162
  icon: "plus",
2150
2163
  className: "btn-add col-xs-12",
2151
- title: "Add",
2164
+ title: translateString(TranslatableString.AddButton),
2152
2165
  onClick: onClick,
2153
2166
  disabled: disabled,
2154
2167
  registry: registry
@@ -2193,14 +2206,16 @@ function DescriptionField(props) {
2193
2206
  * @param props - The `ErrorListProps` for this component
2194
2207
  */
2195
2208
  function ErrorList(_ref) {
2196
- var errors = _ref.errors;
2209
+ var errors = _ref.errors,
2210
+ registry = _ref.registry;
2211
+ var translateString = registry.translateString;
2197
2212
  return /*#__PURE__*/React.createElement("div", {
2198
2213
  className: "panel panel-danger errors"
2199
2214
  }, /*#__PURE__*/React.createElement("div", {
2200
2215
  className: "panel-heading"
2201
2216
  }, /*#__PURE__*/React.createElement("h3", {
2202
2217
  className: "panel-title"
2203
- }, "Errors")), /*#__PURE__*/React.createElement("ul", {
2218
+ }, translateString(TranslatableString.ErrorsLabel))), /*#__PURE__*/React.createElement("ul", {
2204
2219
  className: "list-group"
2205
2220
  }, errors.map(function (error, i) {
2206
2221
  return /*#__PURE__*/React.createElement("li", {
@@ -2383,10 +2398,22 @@ function TitleField(props) {
2383
2398
  function UnsupportedField(props) {
2384
2399
  var schema = props.schema,
2385
2400
  idSchema = props.idSchema,
2386
- reason = props.reason;
2401
+ reason = props.reason,
2402
+ registry = props.registry;
2403
+ var translateString = registry.translateString;
2404
+ var translateEnum = TranslatableString.UnsupportedField;
2405
+ var translateParams = [];
2406
+ if (idSchema && idSchema.$id) {
2407
+ translateEnum = TranslatableString.UnsupportedFieldWithId;
2408
+ translateParams.push(idSchema.$id);
2409
+ }
2410
+ if (reason) {
2411
+ translateEnum = translateEnum === TranslatableString.UnsupportedField ? TranslatableString.UnsupportedFieldWithReason : TranslatableString.UnsupportedFieldWithIdAndReason;
2412
+ translateParams.push(reason);
2413
+ }
2387
2414
  return /*#__PURE__*/React.createElement("div", {
2388
2415
  className: "unsupported-field"
2389
- }, /*#__PURE__*/React.createElement("p", null, "Unsupported field schema", idSchema && idSchema.$id && /*#__PURE__*/React.createElement("span", null, " for", " field ", /*#__PURE__*/React.createElement("code", null, idSchema.$id)), reason && /*#__PURE__*/React.createElement("em", null, ": ", reason), "."), schema && /*#__PURE__*/React.createElement("pre", null, JSON.stringify(schema, null, 2)));
2416
+ }, /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement(Markdown, null, translateString(translateEnum, translateParams))), schema && /*#__PURE__*/React.createElement("pre", null, JSON.stringify(schema, null, 2)));
2390
2417
  }
2391
2418
 
2392
2419
  /** The `WrapIfAdditional` component is used by the `FieldTemplate` to rename, or remove properties that are
@@ -2408,9 +2435,11 @@ function WrapIfAdditionalTemplate(props) {
2408
2435
  children = props.children,
2409
2436
  uiSchema = props.uiSchema,
2410
2437
  registry = props.registry;
2438
+ var templates = registry.templates,
2439
+ translateString = registry.translateString;
2411
2440
  // Button templates are not overridden in the uiSchema
2412
- var RemoveButton = registry.templates.ButtonTemplates.RemoveButton;
2413
- var keyLabel = label + " Key"; // i18n ?
2441
+ var RemoveButton = templates.ButtonTemplates.RemoveButton;
2442
+ var keyLabel = translateString(TranslatableString.KeyLabel, [label]);
2414
2443
  var additional = (ADDITIONAL_PROPERTY_FLAG in schema);
2415
2444
  if (!additional) {
2416
2445
  return /*#__PURE__*/React.createElement("div", {
@@ -2587,6 +2616,7 @@ function AltDateWidget(_ref2) {
2587
2616
  onFocus = _ref2.onFocus,
2588
2617
  onChange = _ref2.onChange,
2589
2618
  value = _ref2.value;
2619
+ var translateString = registry.translateString;
2590
2620
  var _useReducer = useReducer(function (state, action) {
2591
2621
  return _extends({}, state, action);
2592
2622
  }, parseDateString(value, time)),
@@ -2627,6 +2657,7 @@ function AltDateWidget(_ref2) {
2627
2657
  className: "list-inline"
2628
2658
  }, dateElementProps(state, time, options.yearsRange).map(function (elemProps, i) {
2629
2659
  return /*#__PURE__*/React.createElement("li", {
2660
+ className: "list-inline-item",
2630
2661
  key: i
2631
2662
  }, /*#__PURE__*/React.createElement(DateElement, _extends({
2632
2663
  rootId: id,
@@ -2639,15 +2670,19 @@ function AltDateWidget(_ref2) {
2639
2670
  onFocus: onFocus,
2640
2671
  autofocus: autofocus && i === 0
2641
2672
  })));
2642
- }), (options.hideNowButton !== "undefined" ? !options.hideNowButton : true) && /*#__PURE__*/React.createElement("li", null, /*#__PURE__*/React.createElement("a", {
2673
+ }), (options.hideNowButton !== "undefined" ? !options.hideNowButton : true) && /*#__PURE__*/React.createElement("li", {
2674
+ className: "list-inline-item"
2675
+ }, /*#__PURE__*/React.createElement("a", {
2643
2676
  href: "#",
2644
2677
  className: "btn btn-info btn-now",
2645
2678
  onClick: handleSetNow
2646
- }, "Now")), (options.hideClearButton !== "undefined" ? !options.hideClearButton : true) && /*#__PURE__*/React.createElement("li", null, /*#__PURE__*/React.createElement("a", {
2679
+ }, translateString(TranslatableString.NowLabel))), (options.hideClearButton !== "undefined" ? !options.hideClearButton : true) && /*#__PURE__*/React.createElement("li", {
2680
+ className: "list-inline-item"
2681
+ }, /*#__PURE__*/React.createElement("a", {
2647
2682
  href: "#",
2648
2683
  className: "btn btn-warning btn-clear",
2649
2684
  onClick: handleClear
2650
- }, "Clear")));
2685
+ }, translateString(TranslatableString.ClearLabel))));
2651
2686
  }
2652
2687
 
2653
2688
  var _excluded$1 = ["time"];
@@ -2900,10 +2935,12 @@ function processFiles(files) {
2900
2935
  return Promise.all(Array.from(files).map(processFile));
2901
2936
  }
2902
2937
  function FilesInfo(_ref) {
2903
- var filesInfo = _ref.filesInfo;
2938
+ var filesInfo = _ref.filesInfo,
2939
+ registry = _ref.registry;
2904
2940
  if (filesInfo.length === 0) {
2905
2941
  return null;
2906
2942
  }
2943
+ var translateString = registry.translateString;
2907
2944
  return /*#__PURE__*/React.createElement("ul", {
2908
2945
  className: "file-info"
2909
2946
  }, filesInfo.map(function (fileInfo, key) {
@@ -2912,7 +2949,7 @@ function FilesInfo(_ref) {
2912
2949
  type = fileInfo.type;
2913
2950
  return /*#__PURE__*/React.createElement("li", {
2914
2951
  key: key
2915
- }, /*#__PURE__*/React.createElement("strong", null, name), " (", type, ", ", size, " bytes)");
2952
+ }, /*#__PURE__*/React.createElement(Markdown, null, translateString(TranslatableString.FilesInfo, [name, type, String(size)])));
2916
2953
  }));
2917
2954
  }
2918
2955
  function extractFileInfo(dataURLs) {
@@ -2942,7 +2979,8 @@ function FileWidget(_ref2) {
2942
2979
  value = _ref2.value,
2943
2980
  _ref2$autofocus = _ref2.autofocus,
2944
2981
  autofocus = _ref2$autofocus === void 0 ? false : _ref2$autofocus,
2945
- options = _ref2.options;
2982
+ options = _ref2.options,
2983
+ registry = _ref2.registry;
2946
2984
  var extractedFilesInfo = useMemo(function () {
2947
2985
  return Array.isArray(value) ? extractFileInfo(value) : extractFileInfo([value]);
2948
2986
  }, [value]);
@@ -2977,7 +3015,8 @@ function FileWidget(_ref2) {
2977
3015
  accept: options.accept ? String(options.accept) : undefined,
2978
3016
  "aria-describedby": ariaDescribedByIds(id)
2979
3017
  })), /*#__PURE__*/React.createElement(FilesInfo, {
2980
- filesInfo: filesInfo
3018
+ filesInfo: filesInfo,
3019
+ registry: registry
2981
3020
  }));
2982
3021
  }
2983
3022
 
@@ -3289,7 +3328,8 @@ function getDefaultRegistry() {
3289
3328
  templates: templates(),
3290
3329
  widgets: widgets(),
3291
3330
  rootSchema: {},
3292
- formContext: {}
3331
+ formContext: {},
3332
+ translateString: englishStringTranslator
3293
3333
  };
3294
3334
  }
3295
3335
 
@@ -3516,7 +3556,7 @@ var Form = /*#__PURE__*/function (_Component) {
3516
3556
  if (!schemaUtils || schemaUtils.doesSchemaUtilsDiffer(props.validator, rootSchema)) {
3517
3557
  schemaUtils = createSchemaUtils(props.validator, rootSchema);
3518
3558
  }
3519
- var formData = schemaUtils.getDefaultFormState(schema, inputFormData, "excludeObjectChildren");
3559
+ var formData = schemaUtils.getDefaultFormState(schema, inputFormData);
3520
3560
  var retrievedSchema = schemaUtils.retrieveSchema(schema, formData);
3521
3561
  var getCurrentErrors = function getCurrentErrors() {
3522
3562
  if (props.noValidate) {
@@ -3617,7 +3657,8 @@ var Form = /*#__PURE__*/function (_Component) {
3617
3657
  errorSchema: errorSchema || {},
3618
3658
  schema: schema,
3619
3659
  uiSchema: uiSchema,
3620
- formContext: formContext
3660
+ formContext: formContext,
3661
+ registry: registry
3621
3662
  });
3622
3663
  }
3623
3664
  return null;
@@ -3630,12 +3671,14 @@ var Form = /*#__PURE__*/function (_Component) {
3630
3671
  /** Returns the registry for the form */
3631
3672
  _proto.getRegistry = function getRegistry() {
3632
3673
  var _this$props$templates;
3674
+ var customTranslateString = this.props.translateString;
3633
3675
  var schemaUtils = this.state.schemaUtils;
3634
3676
  var _getDefaultRegistry = getDefaultRegistry(),
3635
3677
  fields = _getDefaultRegistry.fields,
3636
3678
  templates = _getDefaultRegistry.templates,
3637
3679
  widgets = _getDefaultRegistry.widgets,
3638
- formContext = _getDefaultRegistry.formContext;
3680
+ formContext = _getDefaultRegistry.formContext,
3681
+ translateString = _getDefaultRegistry.translateString;
3639
3682
  return {
3640
3683
  fields: _extends({}, fields, this.props.fields),
3641
3684
  templates: _extends({}, templates, this.props.templates, {
@@ -3644,7 +3687,8 @@ var Form = /*#__PURE__*/function (_Component) {
3644
3687
  widgets: _extends({}, widgets, this.props.widgets),
3645
3688
  rootSchema: this.props.schema,
3646
3689
  formContext: this.props.formContext || formContext,
3647
- schemaUtils: schemaUtils
3690
+ schemaUtils: schemaUtils,
3691
+ translateString: customTranslateString || translateString
3648
3692
  };
3649
3693
  }
3650
3694
  /** Provides a function that can be used to programmatically submit the `Form` */;
@@ -3656,15 +3700,47 @@ var Form = /*#__PURE__*/function (_Component) {
3656
3700
  this.formElement.current.requestSubmit();
3657
3701
  }
3658
3702
  }
3703
+ /** Attempts to focus on the field associated with the `error`. Uses the `property` field to compute path of the error
3704
+ * field, then, using the `idPrefix` and `idSeparator` converts that path into an id. Then the input element with that
3705
+ * id is attempted to be found using the `formElement` ref. If it is located, then it is focused.
3706
+ *
3707
+ * @param error - The error on which to focus
3708
+ */;
3709
+ _proto.focusOnError = function focusOnError(error) {
3710
+ var _this$props4 = this.props,
3711
+ _this$props4$idPrefix = _this$props4.idPrefix,
3712
+ idPrefix = _this$props4$idPrefix === void 0 ? "root" : _this$props4$idPrefix,
3713
+ _this$props4$idSepara = _this$props4.idSeparator,
3714
+ idSeparator = _this$props4$idSepara === void 0 ? "_" : _this$props4$idSepara;
3715
+ var property = error.property;
3716
+ var path = _toPath(property);
3717
+ if (path[0] === "") {
3718
+ // Most of the time the `.foo` property results in the first element being empty, so replace it with the idPrefix
3719
+ path[0] = idPrefix;
3720
+ } else {
3721
+ // Otherwise insert the idPrefix into the first location using unshift
3722
+ path.unshift(idPrefix);
3723
+ }
3724
+ var elementId = path.join(idSeparator);
3725
+ var field = this.formElement.current.elements[elementId];
3726
+ if (!field) {
3727
+ // if not an exact match, try finding an input starting with the element id (like radio buttons or checkboxes)
3728
+ field = this.formElement.current.querySelector("input[id^=" + elementId);
3729
+ }
3730
+ if (field) {
3731
+ field.focus();
3732
+ }
3733
+ }
3659
3734
  /** Programmatically validate the form. If `onError` is provided, then it will be called with the list of errors the
3660
3735
  * same way as would happen on form submission.
3661
3736
  *
3662
3737
  * @returns - True if the form is valid, false otherwise.
3663
3738
  */;
3664
3739
  _proto.validateForm = function validateForm() {
3665
- var _this$props4 = this.props,
3666
- extraErrors = _this$props4.extraErrors,
3667
- onError = _this$props4.onError;
3740
+ var _this$props5 = this.props,
3741
+ extraErrors = _this$props5.extraErrors,
3742
+ focusOnFirstError = _this$props5.focusOnFirstError,
3743
+ onError = _this$props5.onError;
3668
3744
  var formData = this.state.formData;
3669
3745
  var schemaUtils = this.state.schemaUtils;
3670
3746
  var schemaValidation = this.validate(formData);
@@ -3678,6 +3754,9 @@ var Form = /*#__PURE__*/function (_Component) {
3678
3754
  errorSchema = merged.errorSchema;
3679
3755
  errors = merged.errors;
3680
3756
  }
3757
+ if (focusOnFirstError) {
3758
+ this.focusOnError(schemaValidation.errors[0]);
3759
+ }
3681
3760
  this.setState({
3682
3761
  errors: errors,
3683
3762
  errorSchema: errorSchema,
@@ -3698,31 +3777,31 @@ var Form = /*#__PURE__*/function (_Component) {
3698
3777
  * needed along with the submit button or any children of the form.
3699
3778
  */;
3700
3779
  _proto.render = function render() {
3701
- var _this$props5 = this.props,
3702
- children = _this$props5.children,
3703
- id = _this$props5.id,
3704
- idPrefix = _this$props5.idPrefix,
3705
- idSeparator = _this$props5.idSeparator,
3706
- _this$props5$classNam = _this$props5.className,
3707
- className = _this$props5$classNam === void 0 ? "" : _this$props5$classNam,
3708
- tagName = _this$props5.tagName,
3709
- name = _this$props5.name,
3710
- method = _this$props5.method,
3711
- target = _this$props5.target,
3712
- action = _this$props5.action,
3713
- autoComplete = _this$props5.autoComplete,
3714
- enctype = _this$props5.enctype,
3715
- acceptcharset = _this$props5.acceptcharset,
3716
- _this$props5$noHtml5V = _this$props5.noHtml5Validate,
3717
- noHtml5Validate = _this$props5$noHtml5V === void 0 ? false : _this$props5$noHtml5V,
3718
- _this$props5$disabled = _this$props5.disabled,
3719
- disabled = _this$props5$disabled === void 0 ? false : _this$props5$disabled,
3720
- _this$props5$readonly = _this$props5.readonly,
3721
- readonly = _this$props5$readonly === void 0 ? false : _this$props5$readonly,
3722
- formContext = _this$props5.formContext,
3723
- _this$props5$showErro = _this$props5.showErrorList,
3724
- showErrorList = _this$props5$showErro === void 0 ? "top" : _this$props5$showErro,
3725
- _internalFormWrapper = _this$props5._internalFormWrapper;
3780
+ var _this$props6 = this.props,
3781
+ children = _this$props6.children,
3782
+ id = _this$props6.id,
3783
+ idPrefix = _this$props6.idPrefix,
3784
+ idSeparator = _this$props6.idSeparator,
3785
+ _this$props6$classNam = _this$props6.className,
3786
+ className = _this$props6$classNam === void 0 ? "" : _this$props6$classNam,
3787
+ tagName = _this$props6.tagName,
3788
+ name = _this$props6.name,
3789
+ method = _this$props6.method,
3790
+ target = _this$props6.target,
3791
+ action = _this$props6.action,
3792
+ autoComplete = _this$props6.autoComplete,
3793
+ enctype = _this$props6.enctype,
3794
+ acceptcharset = _this$props6.acceptcharset,
3795
+ _this$props6$noHtml5V = _this$props6.noHtml5Validate,
3796
+ noHtml5Validate = _this$props6$noHtml5V === void 0 ? false : _this$props6$noHtml5V,
3797
+ _this$props6$disabled = _this$props6.disabled,
3798
+ disabled = _this$props6$disabled === void 0 ? false : _this$props6$disabled,
3799
+ _this$props6$readonly = _this$props6.readonly,
3800
+ readonly = _this$props6$readonly === void 0 ? false : _this$props6$readonly,
3801
+ formContext = _this$props6.formContext,
3802
+ _this$props6$showErro = _this$props6.showErrorList,
3803
+ showErrorList = _this$props6$showErro === void 0 ? "top" : _this$props6$showErro,
3804
+ _internalFormWrapper = _this$props6._internalFormWrapper;
3726
3805
  var _this$state4 = this.state,
3727
3806
  schema = _this$state4.schema,
3728
3807
  uiSchema = _this$state4.uiSchema,