@springmicro/forms 0.6.4 → 0.7.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.
Files changed (78) hide show
  1. package/.eslintrc.cjs +22 -22
  2. package/README.md +11 -11
  3. package/dist/index.d.ts +0 -0
  4. package/dist/index.js +0 -0
  5. package/dist/index.umd.cjs +0 -0
  6. package/package.json +3 -3
  7. package/src/builder/bottom-drawer.tsx +429 -429
  8. package/src/builder/form-builder.tsx +256 -256
  9. package/src/builder/modal.tsx +39 -39
  10. package/src/builder/nodes/node-base.tsx +94 -94
  11. package/src/builder/nodes/node-child-helpers.tsx +273 -273
  12. package/src/builder/nodes/node-parent.tsx +187 -187
  13. package/src/builder/nodes/node-types/array-node.tsx +134 -134
  14. package/src/builder/nodes/node-types/date-node.tsx +60 -60
  15. package/src/builder/nodes/node-types/file-node.tsx +67 -67
  16. package/src/builder/nodes/node-types/integer-node.tsx +60 -60
  17. package/src/builder/nodes/node-types/object-node.tsx +67 -67
  18. package/src/builder/nodes/node-types/text-node.tsx +66 -66
  19. package/src/fields/ArrayField.tsx +875 -875
  20. package/src/fields/BooleanField.tsx +110 -110
  21. package/src/fields/MultiSchemaField.tsx +236 -236
  22. package/src/fields/NullField.tsx +22 -22
  23. package/src/fields/NumberField.tsx +87 -87
  24. package/src/fields/ObjectField.tsx +338 -338
  25. package/src/fields/SchemaField.tsx +402 -402
  26. package/src/fields/StringField.tsx +67 -67
  27. package/src/fields/index.ts +24 -24
  28. package/src/index.tsx +26 -26
  29. package/src/interfaces/MessagesProps.interface.ts +5 -5
  30. package/src/interfaces/Option.interface.ts +4 -4
  31. package/src/styles/select.styles.ts +28 -28
  32. package/src/templates/ArrayFieldDescriptionTemplate.tsx +42 -42
  33. package/src/templates/ArrayFieldItemTemplate.tsx +78 -78
  34. package/src/templates/ArrayFieldTemplate.tsx +90 -90
  35. package/src/templates/ArrayFieldTitleTemplate.tsx +44 -44
  36. package/src/templates/BaseInputTemplate.tsx +94 -94
  37. package/src/templates/ButtonTemplates/AddButton.tsx +29 -29
  38. package/src/templates/ButtonTemplates/IconButton.tsx +49 -49
  39. package/src/templates/ButtonTemplates/SubmitButton.tsx +29 -29
  40. package/src/templates/ButtonTemplates/index.ts +16 -16
  41. package/src/templates/DescriptionField.tsx +29 -29
  42. package/src/templates/ErrorList.tsx +25 -25
  43. package/src/templates/FieldTemplate/FieldTemplate.tsx +39 -39
  44. package/src/templates/FieldTemplate/Label.tsx +29 -29
  45. package/src/templates/FieldTemplate/WrapIfAdditional.tsx +85 -85
  46. package/src/templates/FieldTemplate/index.ts +3 -3
  47. package/src/templates/ObjectFieldTemplate.tsx +79 -79
  48. package/src/templates/TitleField.tsx +20 -20
  49. package/src/templates/UnsupportedField.tsx +29 -29
  50. package/src/templates/index.ts +32 -32
  51. package/src/types/Message.type.ts +6 -6
  52. package/src/types/RawMessage.type.ts +15 -15
  53. package/src/types/form-builder.ts +135 -135
  54. package/src/types/utils.type.ts +1 -1
  55. package/src/utils/form-builder.ts +424 -424
  56. package/src/utils/processSelectValue.ts +50 -50
  57. package/src/widgets/AltDateTimeWidget.tsx +17 -17
  58. package/src/widgets/AltDateWidget.tsx +216 -216
  59. package/src/widgets/CheckboxWidget.tsx +80 -80
  60. package/src/widgets/CheckboxesWidget.tsx +74 -74
  61. package/src/widgets/ColorWidget.tsx +26 -26
  62. package/src/widgets/DateTimeWidget.tsx +28 -28
  63. package/src/widgets/DateWidget.tsx +36 -36
  64. package/src/widgets/EmailWidget.tsx +19 -19
  65. package/src/widgets/FileWidget.tsx +144 -144
  66. package/src/widgets/HiddenWidget.tsx +22 -22
  67. package/src/widgets/PasswordWidget.tsx +20 -20
  68. package/src/widgets/RadioWidget.tsx +87 -87
  69. package/src/widgets/RangeWidget.tsx +24 -24
  70. package/src/widgets/SelectWidget.tsx +99 -99
  71. package/src/widgets/TextWidget.tsx +19 -19
  72. package/src/widgets/TextareaWidget.tsx +64 -64
  73. package/src/widgets/URLWidget.tsx +19 -19
  74. package/src/widgets/UpDownWidget.tsx +20 -20
  75. package/src/widgets/index.ts +43 -43
  76. package/tsconfig.json +24 -24
  77. package/tsconfig.node.json +10 -10
  78. package/vite.config.ts +25 -25
@@ -1,402 +1,402 @@
1
- import React from "react";
2
- import type {
3
- FieldProps,
4
- FieldTemplateProps,
5
- IdSchema,
6
- Registry,
7
- RJSFSchema,
8
- UIOptionsType,
9
- GenericObjectType,
10
- } from "@rjsf/utils";
11
- import {
12
- mergeObjects,
13
- deepEquals,
14
- getUiOptions,
15
- getSchemaType,
16
- getTemplate,
17
- ID_KEY,
18
- } from "@rjsf/utils";
19
- import isObject from "lodash/isObject";
20
- import omit from "lodash/omit";
21
-
22
- /** The map of component type to FieldName */
23
- const COMPONENT_TYPES: { [key: string]: string } = {
24
- array: "ArrayField",
25
- boolean: "BooleanField",
26
- integer: "NumberField",
27
- number: "NumberField",
28
- object: "ObjectField",
29
- string: "StringField",
30
- null: "NullField",
31
- };
32
-
33
- /** Computes and returns which `Field` implementation to return in order to render the field represented by the
34
- * `schema`. The `uiOptions` are used to alter what potential `Field` implementation is actually returned. If no
35
- * appropriate `Field` implementation can be found then a wrapper around `UnsupportedFieldTemplate` is used.
36
- *
37
- * @param schema - The schema from which to obtain the type
38
- * @param uiOptions - The UI Options that may affect the component decision
39
- * @param idSchema - The id that is passed to the `UnsupportedFieldTemplate`
40
- * @param registry - The registry from which fields and templates are obtained
41
- * @returns - The `Field` component that is used to render the actual field data
42
- */
43
- function getFieldComponent<T, F extends GenericObjectType = any>(
44
- schema: F,
45
- uiOptions: UIOptionsType<T, F>,
46
- idSchema: IdSchema<T>,
47
- registry: Registry<T, F>
48
- ) {
49
- const field = uiOptions.field;
50
- const { fields } = registry;
51
- if (typeof field === "function") {
52
- return field;
53
- }
54
- if (typeof field === "string" && field in fields) {
55
- return fields[field];
56
- }
57
-
58
- const schemaType = getSchemaType(schema);
59
- const type: string = Array.isArray(schemaType)
60
- ? schemaType[0]
61
- : schemaType || "";
62
- const componentName = COMPONENT_TYPES[type];
63
-
64
- // If the type is not defined and the schema uses 'anyOf' or 'oneOf', don't
65
- // render a field and let the MultiSchemaField component handle the form display
66
- if (!componentName && (schema.anyOf || schema.oneOf)) {
67
- return () => null;
68
- }
69
-
70
- return componentName in fields
71
- ? fields[componentName]
72
- : () => {
73
- const UnsupportedFieldTemplate = getTemplate<
74
- "UnsupportedFieldTemplate",
75
- T,
76
- F
77
- >("UnsupportedFieldTemplate", registry, uiOptions);
78
-
79
- return (
80
- <UnsupportedFieldTemplate
81
- schema={schema}
82
- idSchema={idSchema}
83
- reason={`Unknown field type ${schema.type}`}
84
- registry={registry}
85
- />
86
- );
87
- };
88
- }
89
-
90
- /** The `Help` component renders any help desired for a field
91
- *
92
- * @param props - The id and help information to be rendered
93
- */
94
- function Help(props: { id: string; help?: string | React.ReactElement }) {
95
- const { id, help } = props;
96
- if (!help) {
97
- return null;
98
- }
99
- if (typeof help === "string") {
100
- return (
101
- <p id={id} className="help-block">
102
- {help}
103
- </p>
104
- );
105
- }
106
- return (
107
- <div id={id} className="help-block">
108
- {help}
109
- </div>
110
- );
111
- }
112
-
113
- /** The `ErrorList` component renders the errors local to the particular field
114
- *
115
- * @param props - The list of errors to show
116
- */
117
- function ErrorList(props: { errors?: string[] }) {
118
- const { errors = [] } = props;
119
- if (errors.length === 0) {
120
- return null;
121
- }
122
-
123
- return (
124
- <div>
125
- <ul className="error-detail bs-callout bs-callout-info">
126
- {errors
127
- .filter((elem) => !!elem)
128
- .map((error, index) => {
129
- return (
130
- <li className="text-danger" key={index}>
131
- {error}
132
- </li>
133
- );
134
- })}
135
- </ul>
136
- </div>
137
- );
138
- }
139
-
140
- /** The `SchemaFieldRender` component is the work-horse of react-jsonschema-form, determining what kind of real field to
141
- * render based on the `schema`, `uiSchema` and all the other props. It also deals with rendering the `anyOf` and
142
- * `oneOf` fields.
143
- *
144
- * @param props - The `FieldProps` for this component
145
- */
146
- function SchemaFieldRender<T, F extends GenericObjectType = any>(
147
- props: FieldProps<T, F>
148
- ) {
149
- const {
150
- schema: _schema,
151
- idSchema: _idSchema,
152
- uiSchema,
153
- formData,
154
- errorSchema,
155
- idPrefix,
156
- idSeparator,
157
- name,
158
- onChange,
159
- onKeyChange,
160
- onDropPropertyClick,
161
- required,
162
- registry,
163
- wasPropertyKeyModified = false,
164
- } = props;
165
- const { formContext, schemaUtils } = registry;
166
- const uiOptions = getUiOptions<T, F>(uiSchema);
167
- const FieldTemplate = getTemplate<"FieldTemplate", T, F>(
168
- "FieldTemplate",
169
- registry,
170
- uiOptions
171
- );
172
- const DescriptionFieldTemplate = getTemplate<
173
- "DescriptionFieldTemplate",
174
- T,
175
- F
176
- >("DescriptionFieldTemplate", registry, uiOptions);
177
- const schema = schemaUtils.retrieveSchema(_schema, formData);
178
- const idSchema = mergeObjects(
179
- schemaUtils.toIdSchema(
180
- schema,
181
- _idSchema.$id,
182
- formData,
183
- idPrefix,
184
- idSeparator
185
- ),
186
- _idSchema
187
- ) as IdSchema<T>;
188
- // @ts-ignore
189
- const FieldComponent = getFieldComponent(
190
- schema,
191
- uiOptions,
192
- idSchema,
193
- registry
194
- );
195
- const disabled = Boolean(props.disabled || uiOptions.disabled);
196
- const readonly = Boolean(
197
- props.readonly ||
198
- uiOptions.readonly ||
199
- props.schema.readOnly ||
200
- schema.readOnly
201
- );
202
- const uiSchemaHideError = uiOptions.hideError;
203
- // Set hideError to the value provided in the uiSchema, otherwise stick with the prop to propagate to children
204
- const hideError =
205
- uiSchemaHideError === undefined
206
- ? props.hideError
207
- : Boolean(uiSchemaHideError);
208
- const autofocus = Boolean(props.autofocus || uiOptions.autofocus);
209
- if (Object.keys(schema).length === 0) {
210
- return null;
211
- }
212
-
213
- const displayLabel = schemaUtils.getDisplayLabel(schema, uiSchema);
214
-
215
- const { __errors, ...fieldErrorSchema } = errorSchema || {};
216
- // See #439: uiSchema: Don't pass consumed class names to child components
217
- const fieldUiSchema = omit(uiSchema, ["ui:classNames", "classNames"]);
218
- if ("ui:options" in fieldUiSchema) {
219
- fieldUiSchema["ui:options"] = omit(fieldUiSchema["ui:options"], [
220
- "classNames",
221
- ]);
222
- }
223
-
224
- const field = (
225
- // @ts-ignore
226
- <FieldComponent
227
- {...props}
228
- idSchema={idSchema}
229
- schema={schema}
230
- uiSchema={fieldUiSchema}
231
- disabled={disabled}
232
- readonly={readonly}
233
- hideError={hideError}
234
- autofocus={autofocus}
235
- errorSchema={fieldErrorSchema}
236
- formContext={formContext}
237
- rawErrors={__errors}
238
- />
239
- );
240
-
241
- const id = idSchema[ID_KEY];
242
-
243
- // If this schema has a title defined, but the user has set a new key/label, retain their input.
244
- let label;
245
- if (wasPropertyKeyModified) {
246
- label = name;
247
- } else {
248
- label = uiOptions.title || props.schema.title || schema.title || name;
249
- }
250
-
251
- const description =
252
- uiOptions.description ||
253
- props.schema.description ||
254
- schema.description ||
255
- "";
256
- const errors = __errors;
257
- const help = uiOptions.help;
258
- const hidden = uiOptions.widget === "hidden";
259
-
260
- const classNames = ["form-control", "mb-2", "field", `field-${schema.type}`];
261
- if (!hideError && errors && errors.length > 0) {
262
- classNames.push("field-error has-error has-danger");
263
- }
264
- if (uiSchema?.classNames) {
265
- if (import.meta.env.NODE_ENV !== "production") {
266
- console.warn(
267
- "'uiSchema.classNames' is deprecated and may be removed in a major release; Use 'ui:classNames' instead."
268
- );
269
- }
270
- classNames.push(uiSchema.classNames);
271
- }
272
- if (uiOptions.classNames) {
273
- classNames.push(uiOptions.classNames);
274
- }
275
-
276
- const fieldProps: Omit<FieldTemplateProps<T, F>, "children"> = {
277
- description: (
278
- <DescriptionFieldTemplate
279
- schema={schema}
280
- id={`${id}__description`}
281
- description={description}
282
- registry={registry}
283
- />
284
- ),
285
- rawDescription: description,
286
- help: <Help id={`${id}__help`} help={help} />,
287
- rawHelp: typeof help === "string" ? help : undefined,
288
- errors: hideError ? undefined : <ErrorList errors={errors} />,
289
- rawErrors: hideError ? undefined : errors,
290
- id,
291
- label,
292
- hidden,
293
- onChange,
294
- onKeyChange,
295
- onDropPropertyClick,
296
- required,
297
- disabled,
298
- readonly,
299
- hideError,
300
- displayLabel,
301
- classNames: classNames.join(" ").trim(),
302
- formContext,
303
- formData,
304
- schema,
305
- uiSchema,
306
- registry,
307
- };
308
-
309
- const _AnyOfField = registry.fields.AnyOfField;
310
- const _OneOfField = registry.fields.OneOfField;
311
-
312
- return (
313
- <FieldTemplate {...fieldProps}>
314
- <>
315
- {field}
316
- {/*
317
- If the schema `anyOf` or 'oneOf' can be rendered as a select control, don't
318
- render the selection and let `StringField` component handle
319
- rendering
320
- */}
321
- {schema.anyOf &&
322
- !uiSchema?.["ui:field"] &&
323
- !schemaUtils.isSelect(schema) && (
324
- <_AnyOfField
325
- name={name}
326
- disabled={disabled}
327
- readonly={readonly}
328
- hideError={hideError}
329
- errorSchema={errorSchema}
330
- formData={formData}
331
- formContext={formContext}
332
- idPrefix={idPrefix}
333
- idSchema={idSchema}
334
- idSeparator={idSeparator}
335
- onBlur={props.onBlur}
336
- onChange={props.onChange}
337
- onFocus={props.onFocus}
338
- options={schema.anyOf.map((_schema: any) =>
339
- schemaUtils.retrieveSchema(
340
- // @ts-ignore
341
- isObject(_schema) ? _schema : {},
342
- formData
343
- )
344
- )}
345
- baseType={schema.type}
346
- registry={registry}
347
- schema={schema}
348
- uiSchema={uiSchema}
349
- />
350
- )}
351
- {schema.oneOf &&
352
- !uiSchema?.["ui:field"] &&
353
- !schemaUtils.isSelect(schema) && (
354
- <_OneOfField
355
- name={name}
356
- disabled={disabled}
357
- readonly={readonly}
358
- hideError={hideError}
359
- errorSchema={errorSchema}
360
- formData={formData}
361
- formContext={formContext}
362
- idPrefix={idPrefix}
363
- idSchema={idSchema}
364
- idSeparator={idSeparator}
365
- onBlur={props.onBlur}
366
- onChange={props.onChange}
367
- onFocus={props.onFocus}
368
- options={schema.oneOf.map((_schema: any) =>
369
- schemaUtils.retrieveSchema(
370
- // @ts-ignore
371
- isObject(_schema) ? _schema : {},
372
- formData
373
- )
374
- )}
375
- baseType={schema.type}
376
- registry={registry}
377
- schema={schema}
378
- uiSchema={uiSchema}
379
- />
380
- )}
381
- </>
382
- </FieldTemplate>
383
- );
384
- }
385
-
386
- /** The `SchemaField` component determines whether it is necessary to rerender the component based on any props changes
387
- * and if so, calls the `SchemaFieldRender` component with the props.
388
- */
389
- class SchemaField<
390
- T = any,
391
- F extends GenericObjectType = any,
392
- > extends React.Component<FieldProps<T, F>> {
393
- shouldComponentUpdate(nextProps: Readonly<FieldProps<T, F>>) {
394
- return !deepEquals(this.props, nextProps);
395
- }
396
-
397
- render() {
398
- return <SchemaFieldRender<T, F> {...this.props} />;
399
- }
400
- }
401
-
402
- export default SchemaField;
1
+ import React from "react";
2
+ import type {
3
+ FieldProps,
4
+ FieldTemplateProps,
5
+ IdSchema,
6
+ Registry,
7
+ RJSFSchema,
8
+ UIOptionsType,
9
+ GenericObjectType,
10
+ } from "@rjsf/utils";
11
+ import {
12
+ mergeObjects,
13
+ deepEquals,
14
+ getUiOptions,
15
+ getSchemaType,
16
+ getTemplate,
17
+ ID_KEY,
18
+ } from "@rjsf/utils";
19
+ import isObject from "lodash/isObject";
20
+ import omit from "lodash/omit";
21
+
22
+ /** The map of component type to FieldName */
23
+ const COMPONENT_TYPES: { [key: string]: string } = {
24
+ array: "ArrayField",
25
+ boolean: "BooleanField",
26
+ integer: "NumberField",
27
+ number: "NumberField",
28
+ object: "ObjectField",
29
+ string: "StringField",
30
+ null: "NullField",
31
+ };
32
+
33
+ /** Computes and returns which `Field` implementation to return in order to render the field represented by the
34
+ * `schema`. The `uiOptions` are used to alter what potential `Field` implementation is actually returned. If no
35
+ * appropriate `Field` implementation can be found then a wrapper around `UnsupportedFieldTemplate` is used.
36
+ *
37
+ * @param schema - The schema from which to obtain the type
38
+ * @param uiOptions - The UI Options that may affect the component decision
39
+ * @param idSchema - The id that is passed to the `UnsupportedFieldTemplate`
40
+ * @param registry - The registry from which fields and templates are obtained
41
+ * @returns - The `Field` component that is used to render the actual field data
42
+ */
43
+ function getFieldComponent<T, F extends GenericObjectType = any>(
44
+ schema: F,
45
+ uiOptions: UIOptionsType<T, F>,
46
+ idSchema: IdSchema<T>,
47
+ registry: Registry<T, F>
48
+ ) {
49
+ const field = uiOptions.field;
50
+ const { fields } = registry;
51
+ if (typeof field === "function") {
52
+ return field;
53
+ }
54
+ if (typeof field === "string" && field in fields) {
55
+ return fields[field];
56
+ }
57
+
58
+ const schemaType = getSchemaType(schema);
59
+ const type: string = Array.isArray(schemaType)
60
+ ? schemaType[0]
61
+ : schemaType || "";
62
+ const componentName = COMPONENT_TYPES[type];
63
+
64
+ // If the type is not defined and the schema uses 'anyOf' or 'oneOf', don't
65
+ // render a field and let the MultiSchemaField component handle the form display
66
+ if (!componentName && (schema.anyOf || schema.oneOf)) {
67
+ return () => null;
68
+ }
69
+
70
+ return componentName in fields
71
+ ? fields[componentName]
72
+ : () => {
73
+ const UnsupportedFieldTemplate = getTemplate<
74
+ "UnsupportedFieldTemplate",
75
+ T,
76
+ F
77
+ >("UnsupportedFieldTemplate", registry, uiOptions);
78
+
79
+ return (
80
+ <UnsupportedFieldTemplate
81
+ schema={schema}
82
+ idSchema={idSchema}
83
+ reason={`Unknown field type ${schema.type}`}
84
+ registry={registry}
85
+ />
86
+ );
87
+ };
88
+ }
89
+
90
+ /** The `Help` component renders any help desired for a field
91
+ *
92
+ * @param props - The id and help information to be rendered
93
+ */
94
+ function Help(props: { id: string; help?: string | React.ReactElement }) {
95
+ const { id, help } = props;
96
+ if (!help) {
97
+ return null;
98
+ }
99
+ if (typeof help === "string") {
100
+ return (
101
+ <p id={id} className="help-block">
102
+ {help}
103
+ </p>
104
+ );
105
+ }
106
+ return (
107
+ <div id={id} className="help-block">
108
+ {help}
109
+ </div>
110
+ );
111
+ }
112
+
113
+ /** The `ErrorList` component renders the errors local to the particular field
114
+ *
115
+ * @param props - The list of errors to show
116
+ */
117
+ function ErrorList(props: { errors?: string[] }) {
118
+ const { errors = [] } = props;
119
+ if (errors.length === 0) {
120
+ return null;
121
+ }
122
+
123
+ return (
124
+ <div>
125
+ <ul className="error-detail bs-callout bs-callout-info">
126
+ {errors
127
+ .filter((elem) => !!elem)
128
+ .map((error, index) => {
129
+ return (
130
+ <li className="text-danger" key={index}>
131
+ {error}
132
+ </li>
133
+ );
134
+ })}
135
+ </ul>
136
+ </div>
137
+ );
138
+ }
139
+
140
+ /** The `SchemaFieldRender` component is the work-horse of react-jsonschema-form, determining what kind of real field to
141
+ * render based on the `schema`, `uiSchema` and all the other props. It also deals with rendering the `anyOf` and
142
+ * `oneOf` fields.
143
+ *
144
+ * @param props - The `FieldProps` for this component
145
+ */
146
+ function SchemaFieldRender<T, F extends GenericObjectType = any>(
147
+ props: FieldProps<T, F>
148
+ ) {
149
+ const {
150
+ schema: _schema,
151
+ idSchema: _idSchema,
152
+ uiSchema,
153
+ formData,
154
+ errorSchema,
155
+ idPrefix,
156
+ idSeparator,
157
+ name,
158
+ onChange,
159
+ onKeyChange,
160
+ onDropPropertyClick,
161
+ required,
162
+ registry,
163
+ wasPropertyKeyModified = false,
164
+ } = props;
165
+ const { formContext, schemaUtils } = registry;
166
+ const uiOptions = getUiOptions<T, F>(uiSchema);
167
+ const FieldTemplate = getTemplate<"FieldTemplate", T, F>(
168
+ "FieldTemplate",
169
+ registry,
170
+ uiOptions
171
+ );
172
+ const DescriptionFieldTemplate = getTemplate<
173
+ "DescriptionFieldTemplate",
174
+ T,
175
+ F
176
+ >("DescriptionFieldTemplate", registry, uiOptions);
177
+ const schema = schemaUtils.retrieveSchema(_schema, formData);
178
+ const idSchema = mergeObjects(
179
+ schemaUtils.toIdSchema(
180
+ schema,
181
+ _idSchema.$id,
182
+ formData,
183
+ idPrefix,
184
+ idSeparator
185
+ ),
186
+ _idSchema
187
+ ) as IdSchema<T>;
188
+ // @ts-ignore
189
+ const FieldComponent = getFieldComponent(
190
+ schema,
191
+ uiOptions,
192
+ idSchema,
193
+ registry
194
+ );
195
+ const disabled = Boolean(props.disabled || uiOptions.disabled);
196
+ const readonly = Boolean(
197
+ props.readonly ||
198
+ uiOptions.readonly ||
199
+ props.schema.readOnly ||
200
+ schema.readOnly
201
+ );
202
+ const uiSchemaHideError = uiOptions.hideError;
203
+ // Set hideError to the value provided in the uiSchema, otherwise stick with the prop to propagate to children
204
+ const hideError =
205
+ uiSchemaHideError === undefined
206
+ ? props.hideError
207
+ : Boolean(uiSchemaHideError);
208
+ const autofocus = Boolean(props.autofocus || uiOptions.autofocus);
209
+ if (Object.keys(schema).length === 0) {
210
+ return null;
211
+ }
212
+
213
+ const displayLabel = schemaUtils.getDisplayLabel(schema, uiSchema);
214
+
215
+ const { __errors, ...fieldErrorSchema } = errorSchema || {};
216
+ // See #439: uiSchema: Don't pass consumed class names to child components
217
+ const fieldUiSchema = omit(uiSchema, ["ui:classNames", "classNames"]);
218
+ if ("ui:options" in fieldUiSchema) {
219
+ fieldUiSchema["ui:options"] = omit(fieldUiSchema["ui:options"], [
220
+ "classNames",
221
+ ]);
222
+ }
223
+
224
+ const field = (
225
+ // @ts-ignore
226
+ <FieldComponent
227
+ {...props}
228
+ idSchema={idSchema}
229
+ schema={schema}
230
+ uiSchema={fieldUiSchema}
231
+ disabled={disabled}
232
+ readonly={readonly}
233
+ hideError={hideError}
234
+ autofocus={autofocus}
235
+ errorSchema={fieldErrorSchema}
236
+ formContext={formContext}
237
+ rawErrors={__errors}
238
+ />
239
+ );
240
+
241
+ const id = idSchema[ID_KEY];
242
+
243
+ // If this schema has a title defined, but the user has set a new key/label, retain their input.
244
+ let label;
245
+ if (wasPropertyKeyModified) {
246
+ label = name;
247
+ } else {
248
+ label = uiOptions.title || props.schema.title || schema.title || name;
249
+ }
250
+
251
+ const description =
252
+ uiOptions.description ||
253
+ props.schema.description ||
254
+ schema.description ||
255
+ "";
256
+ const errors = __errors;
257
+ const help = uiOptions.help;
258
+ const hidden = uiOptions.widget === "hidden";
259
+
260
+ const classNames = ["form-control", "mb-2", "field", `field-${schema.type}`];
261
+ if (!hideError && errors && errors.length > 0) {
262
+ classNames.push("field-error has-error has-danger");
263
+ }
264
+ if (uiSchema?.classNames) {
265
+ if (import.meta.env.NODE_ENV !== "production") {
266
+ console.warn(
267
+ "'uiSchema.classNames' is deprecated and may be removed in a major release; Use 'ui:classNames' instead."
268
+ );
269
+ }
270
+ classNames.push(uiSchema.classNames);
271
+ }
272
+ if (uiOptions.classNames) {
273
+ classNames.push(uiOptions.classNames);
274
+ }
275
+
276
+ const fieldProps: Omit<FieldTemplateProps<T, F>, "children"> = {
277
+ description: (
278
+ <DescriptionFieldTemplate
279
+ schema={schema}
280
+ id={`${id}__description`}
281
+ description={description}
282
+ registry={registry}
283
+ />
284
+ ),
285
+ rawDescription: description,
286
+ help: <Help id={`${id}__help`} help={help} />,
287
+ rawHelp: typeof help === "string" ? help : undefined,
288
+ errors: hideError ? undefined : <ErrorList errors={errors} />,
289
+ rawErrors: hideError ? undefined : errors,
290
+ id,
291
+ label,
292
+ hidden,
293
+ onChange,
294
+ onKeyChange,
295
+ onDropPropertyClick,
296
+ required,
297
+ disabled,
298
+ readonly,
299
+ hideError,
300
+ displayLabel,
301
+ classNames: classNames.join(" ").trim(),
302
+ formContext,
303
+ formData,
304
+ schema,
305
+ uiSchema,
306
+ registry,
307
+ };
308
+
309
+ const _AnyOfField = registry.fields.AnyOfField;
310
+ const _OneOfField = registry.fields.OneOfField;
311
+
312
+ return (
313
+ <FieldTemplate {...fieldProps}>
314
+ <>
315
+ {field}
316
+ {/*
317
+ If the schema `anyOf` or 'oneOf' can be rendered as a select control, don't
318
+ render the selection and let `StringField` component handle
319
+ rendering
320
+ */}
321
+ {schema.anyOf &&
322
+ !uiSchema?.["ui:field"] &&
323
+ !schemaUtils.isSelect(schema) && (
324
+ <_AnyOfField
325
+ name={name}
326
+ disabled={disabled}
327
+ readonly={readonly}
328
+ hideError={hideError}
329
+ errorSchema={errorSchema}
330
+ formData={formData}
331
+ formContext={formContext}
332
+ idPrefix={idPrefix}
333
+ idSchema={idSchema}
334
+ idSeparator={idSeparator}
335
+ onBlur={props.onBlur}
336
+ onChange={props.onChange}
337
+ onFocus={props.onFocus}
338
+ options={schema.anyOf.map((_schema: any) =>
339
+ schemaUtils.retrieveSchema(
340
+ // @ts-ignore
341
+ isObject(_schema) ? _schema : {},
342
+ formData
343
+ )
344
+ )}
345
+ baseType={schema.type}
346
+ registry={registry}
347
+ schema={schema}
348
+ uiSchema={uiSchema}
349
+ />
350
+ )}
351
+ {schema.oneOf &&
352
+ !uiSchema?.["ui:field"] &&
353
+ !schemaUtils.isSelect(schema) && (
354
+ <_OneOfField
355
+ name={name}
356
+ disabled={disabled}
357
+ readonly={readonly}
358
+ hideError={hideError}
359
+ errorSchema={errorSchema}
360
+ formData={formData}
361
+ formContext={formContext}
362
+ idPrefix={idPrefix}
363
+ idSchema={idSchema}
364
+ idSeparator={idSeparator}
365
+ onBlur={props.onBlur}
366
+ onChange={props.onChange}
367
+ onFocus={props.onFocus}
368
+ options={schema.oneOf.map((_schema: any) =>
369
+ schemaUtils.retrieveSchema(
370
+ // @ts-ignore
371
+ isObject(_schema) ? _schema : {},
372
+ formData
373
+ )
374
+ )}
375
+ baseType={schema.type}
376
+ registry={registry}
377
+ schema={schema}
378
+ uiSchema={uiSchema}
379
+ />
380
+ )}
381
+ </>
382
+ </FieldTemplate>
383
+ );
384
+ }
385
+
386
+ /** The `SchemaField` component determines whether it is necessary to rerender the component based on any props changes
387
+ * and if so, calls the `SchemaFieldRender` component with the props.
388
+ */
389
+ class SchemaField<
390
+ T = any,
391
+ F extends GenericObjectType = any,
392
+ > extends React.Component<FieldProps<T, F>> {
393
+ shouldComponentUpdate(nextProps: Readonly<FieldProps<T, F>>) {
394
+ return !deepEquals(this.props, nextProps);
395
+ }
396
+
397
+ render() {
398
+ return <SchemaFieldRender<T, F> {...this.props} />;
399
+ }
400
+ }
401
+
402
+ export default SchemaField;