@rjsf/core 6.0.1 → 6.1.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 (52) hide show
  1. package/dist/core.umd.js +139 -91
  2. package/dist/index.cjs +369 -312
  3. package/dist/index.cjs.map +4 -4
  4. package/dist/index.esm.js +248 -188
  5. package/dist/index.esm.js.map +4 -4
  6. package/lib/components/Form.d.ts.map +1 -1
  7. package/lib/components/Form.js +7 -3
  8. package/lib/components/RichHelp.d.ts +20 -0
  9. package/lib/components/RichHelp.d.ts.map +1 -0
  10. package/lib/components/RichHelp.js +17 -0
  11. package/lib/components/constants.d.ts +5 -0
  12. package/lib/components/constants.d.ts.map +1 -0
  13. package/lib/components/constants.js +4 -0
  14. package/lib/components/fields/ArrayField.d.ts.map +1 -1
  15. package/lib/components/fields/ArrayField.js +39 -17
  16. package/lib/components/fields/FallbackField.d.ts.map +1 -1
  17. package/lib/components/fields/FallbackField.js +11 -3
  18. package/lib/components/fields/ObjectField.d.ts.map +1 -1
  19. package/lib/components/fields/ObjectField.js +7 -9
  20. package/lib/components/fields/StringField.d.ts.map +1 -1
  21. package/lib/components/fields/StringField.js +3 -3
  22. package/lib/components/templates/ArrayFieldItemTemplate.d.ts.map +1 -1
  23. package/lib/components/templates/ArrayFieldItemTemplate.js +5 -5
  24. package/lib/components/templates/ButtonTemplates/AddButton.d.ts.map +1 -1
  25. package/lib/components/templates/ButtonTemplates/AddButton.js +1 -1
  26. package/lib/components/templates/FieldHelpTemplate.d.ts.map +1 -1
  27. package/lib/components/templates/FieldHelpTemplate.js +3 -6
  28. package/lib/components/templates/FieldTemplate/FieldTemplate.d.ts.map +1 -1
  29. package/lib/components/templates/FieldTemplate/FieldTemplate.js +2 -1
  30. package/lib/components/templates/WrapIfAdditionalTemplate.d.ts.map +1 -1
  31. package/lib/components/templates/WrapIfAdditionalTemplate.js +4 -2
  32. package/lib/components/widgets/CheckboxWidget.d.ts.map +1 -1
  33. package/lib/components/widgets/CheckboxWidget.js +4 -2
  34. package/lib/index.d.ts +3 -2
  35. package/lib/index.d.ts.map +1 -1
  36. package/lib/index.js +2 -1
  37. package/lib/tsconfig.tsbuildinfo +1 -1
  38. package/package.json +2 -2
  39. package/src/components/Form.tsx +6 -4
  40. package/src/components/RichHelp.tsx +46 -0
  41. package/src/components/constants.ts +5 -0
  42. package/src/components/fields/ArrayField.tsx +52 -29
  43. package/src/components/fields/FallbackField.tsx +18 -10
  44. package/src/components/fields/ObjectField.tsx +7 -12
  45. package/src/components/fields/StringField.tsx +3 -2
  46. package/src/components/templates/ArrayFieldItemTemplate.tsx +8 -11
  47. package/src/components/templates/ButtonTemplates/AddButton.tsx +3 -1
  48. package/src/components/templates/FieldHelpTemplate.tsx +5 -11
  49. package/src/components/templates/FieldTemplate/FieldTemplate.tsx +2 -1
  50. package/src/components/templates/WrapIfAdditionalTemplate.tsx +7 -3
  51. package/src/components/widgets/CheckboxWidget.tsx +4 -1
  52. package/src/index.ts +3 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rjsf/core",
3
- "version": "6.0.1",
3
+ "version": "6.1.0",
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",
@@ -88,7 +88,7 @@
88
88
  "eslint": "^8.57.1",
89
89
  "html": "^1.0.0",
90
90
  "jsdom": "^27.0.1",
91
- "mocha": "^10.8.2",
91
+ "mocha": "^11.7.4",
92
92
  "react-portal": "^4.3.0",
93
93
  "sinon": "^9.2.4"
94
94
  },
@@ -51,11 +51,10 @@ import _isEmpty from 'lodash/isEmpty';
51
51
  import _pick from 'lodash/pick';
52
52
  import _set from 'lodash/set';
53
53
  import _toPath from 'lodash/toPath';
54
+ import _unset from 'lodash/unset';
54
55
 
55
56
  import getDefaultRegistry from '../getDefaultRegistry';
56
-
57
- /** Internal only symbol used by the `reset()` function to indicate that a reset operation is happening */
58
- const IS_RESET = Symbol('reset');
57
+ import { ADDITIONAL_PROPERTY_KEY_REMOVE, IS_RESET } from './constants';
59
58
 
60
59
  /** The properties that are passed to the `Form` */
61
60
  export interface FormProps<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> {
@@ -875,7 +874,10 @@ export default class Form<
875
874
  let retrievedSchema = this.state.retrievedSchema;
876
875
  let formData = isRootPath ? newValue : _cloneDeep(oldFormData);
877
876
  if (isObject(formData) || Array.isArray(formData)) {
878
- if (!isRootPath) {
877
+ if (newValue === ADDITIONAL_PROPERTY_KEY_REMOVE) {
878
+ // For additional properties, we were given the special remove this key value, so unset it
879
+ _unset(formData, path);
880
+ } else if (!isRootPath) {
879
881
  // If the newValue is not on the root path, then set it into the form data
880
882
  _set(formData, path, newValue);
881
883
  }
@@ -0,0 +1,46 @@
1
+ import { ReactElement } from 'react';
2
+ import {
3
+ FormContextType,
4
+ Registry,
5
+ RJSFSchema,
6
+ StrictRJSFSchema,
7
+ UiSchema,
8
+ getTestIds,
9
+ getUiOptions,
10
+ } from '@rjsf/utils';
11
+ import Markdown from 'markdown-to-jsx';
12
+
13
+ const TEST_IDS = getTestIds();
14
+
15
+ export interface RichHelpProps<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> {
16
+ /** The description text for a field, potentially containing markdown */
17
+ help: string | ReactElement;
18
+ /** The uiSchema object for this base component */
19
+ uiSchema?: UiSchema<T, S, F>;
20
+ /** The `registry` object */
21
+ registry: Registry<T, S, F>;
22
+ }
23
+
24
+ /** Renders the given `description` in the props as
25
+ *
26
+ * @param props - The `RichHelpProps` for this component
27
+ */
28
+ export default function RichHelp<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>({
29
+ help,
30
+ registry,
31
+ uiSchema = {},
32
+ }: RichHelpProps<T, S, F>) {
33
+ const { globalUiOptions } = registry;
34
+ const uiOptions = getUiOptions<T, S, F>(uiSchema, globalUiOptions);
35
+
36
+ if (uiOptions.enableMarkdownInHelp && typeof help === 'string') {
37
+ return (
38
+ <Markdown options={{ disableParsingRawHTML: true }} data-testid={TEST_IDS.markdown}>
39
+ {help}
40
+ </Markdown>
41
+ );
42
+ }
43
+ return help;
44
+ }
45
+
46
+ RichHelp.TEST_IDS = TEST_IDS;
@@ -0,0 +1,5 @@
1
+ /** Internal only symbol used by `Form` & `ObjectField` to mark an additional property element to be removed */
2
+ export const ADDITIONAL_PROPERTY_KEY_REMOVE = Symbol('remove-this-key');
3
+
4
+ /** Internal only symbol used by the `reset()` function to indicate that a reset operation is happening */
5
+ export const IS_RESET = Symbol('reset');
@@ -153,9 +153,12 @@ function getNewFormDataRow<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
153
153
  registry: Registry<T[], S, F>,
154
154
  schema: S,
155
155
  ): T {
156
- const { schemaUtils } = registry;
156
+ const { schemaUtils, globalFormOptions } = registry;
157
157
  let itemSchema = schema.items as S;
158
- if (isFixedItems(schema) && allowAdditionalItems(schema)) {
158
+ if (globalFormOptions.useFallbackUiForUnsupportedType && !itemSchema) {
159
+ // If we don't have itemSchema and useFallbackUiForUnsupportedType is on, use an empty schema
160
+ itemSchema = {} as S;
161
+ } else if (isFixedItems(schema) && allowAdditionalItems(schema)) {
159
162
  itemSchema = schema.additionalItems as S;
160
163
  }
161
164
  // Cast this as a T to work around schema utils being for T[] caused by the FieldProps<T[], S, F> call on the class
@@ -403,7 +406,9 @@ function ArrayFieldItem<T = any, S extends StrictRJSFSchema = RJSFSchema, F exte
403
406
  handleReorderItems,
404
407
  } = props;
405
408
  const {
409
+ schemaUtils,
406
410
  fields: { ArraySchemaField, SchemaField },
411
+ globalUiOptions,
407
412
  } = registry;
408
413
  const fieldPathId = useDeepCompareMemo<FieldPathId>(itemFieldPathId);
409
414
  const ItemSchemaField = ArraySchemaField || SchemaField;
@@ -412,6 +417,9 @@ function ArrayFieldItem<T = any, S extends StrictRJSFSchema = RJSFSchema, F exte
412
417
  registry,
413
418
  uiOptions,
414
419
  );
420
+ const displayLabel = schemaUtils.getDisplayLabel(itemSchema, itemUiSchema, globalUiOptions);
421
+ const { description } = getUiOptions(itemUiSchema);
422
+ const hasDescription = !!description || !!itemSchema.description;
415
423
  const { orderable = true, removable = true, copyable = false } = uiOptions;
416
424
  const has: { [key: string]: boolean } = {
417
425
  moveUp: orderable && canMoveUp,
@@ -507,6 +515,8 @@ function ArrayFieldItem<T = any, S extends StrictRJSFSchema = RJSFSchema, F exte
507
515
  schema: itemSchema,
508
516
  uiSchema: itemUiSchema,
509
517
  parentUiSchema,
518
+ displayLabel,
519
+ hasDescription,
510
520
  };
511
521
  return <ArrayFieldItemTemplate {...templateProps} />;
512
522
  }
@@ -840,7 +850,7 @@ export default function ArrayField<T = any, S extends StrictRJSFSchema = RJSFSch
840
850
  props: FieldProps<T[], S, F>,
841
851
  ) {
842
852
  const { schema, uiSchema, errorSchema, fieldPathId, registry, formData, onChange } = props;
843
- const { schemaUtils, translateString } = registry;
853
+ const { globalFormOptions, schemaUtils, translateString } = registry;
844
854
  const { keyedFormData, updateKeyedFormData } = useKeyedFormData<T>(formData);
845
855
  // All the children will use childFieldPathId if present in the props, falling back to the fieldPathId
846
856
  const childFieldPathId = props.childFieldPathId ?? fieldPathId;
@@ -1027,24 +1037,14 @@ export default function ArrayField<T = any, S extends StrictRJSFSchema = RJSFSch
1027
1037
  [onChange, childFieldPathId],
1028
1038
  );
1029
1039
 
1030
- if (!(ITEMS_KEY in schema)) {
1031
- const uiOptions = getUiOptions<T[], S, F>(uiSchema);
1032
- const UnsupportedFieldTemplate = getTemplate<'UnsupportedFieldTemplate', T[], S, F>(
1033
- 'UnsupportedFieldTemplate',
1034
- registry,
1035
- uiOptions,
1036
- );
1037
-
1038
- return (
1039
- <UnsupportedFieldTemplate
1040
- schema={schema}
1041
- fieldPathId={fieldPathId}
1042
- reason={translateString(TranslatableString.MissingItems)}
1043
- registry={registry}
1044
- />
1045
- );
1046
- }
1047
- const arrayProps = {
1040
+ const arrayAsMultiProps: ArrayAsFieldProps<T[], S, F> = {
1041
+ ...props,
1042
+ formData,
1043
+ fieldPathId: childFieldPathId,
1044
+ onSelectChange: onSelectChange,
1045
+ };
1046
+ const arrayProps: InternalArrayFieldProps<T, S, F> = {
1047
+ ...props,
1048
1048
  handleAddItem,
1049
1049
  handleCopyItem,
1050
1050
  handleRemoveItem,
@@ -1052,18 +1052,41 @@ export default function ArrayField<T = any, S extends StrictRJSFSchema = RJSFSch
1052
1052
  keyedFormData,
1053
1053
  onChange: handleChange,
1054
1054
  };
1055
- if (schemaUtils.isMultiSelect(schema)) {
1055
+ if (!(ITEMS_KEY in schema)) {
1056
+ if (!globalFormOptions.useFallbackUiForUnsupportedType) {
1057
+ const uiOptions = getUiOptions<T[], S, F>(uiSchema);
1058
+ const UnsupportedFieldTemplate = getTemplate<'UnsupportedFieldTemplate', T[], S, F>(
1059
+ 'UnsupportedFieldTemplate',
1060
+ registry,
1061
+ uiOptions,
1062
+ );
1063
+
1064
+ return (
1065
+ <UnsupportedFieldTemplate
1066
+ schema={schema}
1067
+ fieldPathId={fieldPathId}
1068
+ reason={translateString(TranslatableString.MissingItems)}
1069
+ registry={registry}
1070
+ />
1071
+ );
1072
+ }
1073
+ // Add an items schema with type as undefined so it triggers FallbackField later on
1074
+ const fallbackSchema = { ...schema, [ITEMS_KEY]: { type: undefined } };
1075
+ arrayAsMultiProps.schema = fallbackSchema;
1076
+ arrayProps.schema = fallbackSchema;
1077
+ }
1078
+ if (schemaUtils.isMultiSelect(arrayAsMultiProps.schema)) {
1056
1079
  // If array has enum or uniqueItems set to true, call renderMultiSelect() to render the default multiselect widget or a custom widget, if specified.
1057
- return <ArrayAsMultiSelect<T, S, F> {...props} fieldPathId={childFieldPathId} onSelectChange={onSelectChange} />;
1080
+ return <ArrayAsMultiSelect<T, S, F> {...arrayAsMultiProps} />;
1058
1081
  }
1059
1082
  if (isCustomWidget<T[], S, F>(uiSchema)) {
1060
- return <ArrayAsCustomWidget<T, S, F> {...props} fieldPathId={childFieldPathId} onSelectChange={onSelectChange} />;
1083
+ return <ArrayAsCustomWidget<T, S, F> {...arrayAsMultiProps} />;
1061
1084
  }
1062
- if (isFixedItems(schema)) {
1063
- return <FixedArray<T, S, F> {...props} {...arrayProps} />;
1085
+ if (isFixedItems(arrayAsMultiProps.schema)) {
1086
+ return <FixedArray<T, S, F> {...arrayProps} />;
1064
1087
  }
1065
- if (schemaUtils.isFilesArray(schema, uiSchema)) {
1066
- return <ArrayAsFiles {...props} fieldPathId={childFieldPathId} onSelectChange={onSelectChange} />;
1088
+ if (schemaUtils.isFilesArray(arrayAsMultiProps.schema, uiSchema)) {
1089
+ return <ArrayAsFiles<T, S, F> {...arrayAsMultiProps} />;
1067
1090
  }
1068
- return <NormalArray<T, S, F> {...props} {...arrayProps} />;
1091
+ return <NormalArray<T, S, F> {...arrayProps} />;
1069
1092
  }
@@ -21,7 +21,7 @@ import { JSONSchema7TypeName } from 'json-schema';
21
21
  function getFallbackTypeSelectionSchema(title: string): RJSFSchema {
22
22
  return {
23
23
  type: 'string',
24
- enum: ['string', 'number', 'boolean'],
24
+ enum: ['string', 'number', 'boolean', 'object', 'array'],
25
25
  default: 'string',
26
26
  title: title,
27
27
  };
@@ -36,6 +36,9 @@ function getTypeOfFormData(formData: any): JSONSchema7TypeName {
36
36
  if (dataType === 'string' || dataType === 'number' || dataType === 'boolean') {
37
37
  return dataType;
38
38
  }
39
+ if (dataType === 'object') {
40
+ return Array.isArray(formData) ? 'array' : 'object';
41
+ }
39
42
  // Treat everything else as a string
40
43
  return 'string';
41
44
  }
@@ -106,20 +109,14 @@ export default function FallbackField<
106
109
  };
107
110
 
108
111
  if (!globalFormOptions.useFallbackUiForUnsupportedType) {
112
+ const { reason = translateString(TranslatableString.UnknownFieldType, [String(schema.type)]) } = props;
109
113
  const UnsupportedFieldTemplate = getTemplate<'UnsupportedFieldTemplate', T, S, F>(
110
114
  'UnsupportedFieldTemplate',
111
115
  registry,
112
116
  uiOptions,
113
117
  );
114
118
 
115
- return (
116
- <UnsupportedFieldTemplate
117
- schema={schema}
118
- fieldPathId={fieldPathId}
119
- reason={translateString(TranslatableString.UnknownFieldType, [String(schema.type)])}
120
- registry={registry}
121
- />
122
- );
119
+ return <UnsupportedFieldTemplate schema={schema} fieldPathId={fieldPathId} reason={reason} registry={registry} />;
123
120
  }
124
121
 
125
122
  const FallbackFieldTemplate = getTemplate<'FallbackFieldTemplate', T, S, F>(
@@ -151,7 +148,18 @@ export default function FallbackField<
151
148
  required={required}
152
149
  />
153
150
  }
154
- schemaField={<SchemaField {...props} schema={{ type, title: translateString(TranslatableString.Value) } as S} />}
151
+ schemaField={
152
+ <SchemaField
153
+ {...props}
154
+ schema={
155
+ {
156
+ type,
157
+ title: translateString(TranslatableString.Value),
158
+ ...(type === 'object' && { additionalProperties: true }),
159
+ } as S
160
+ }
161
+ />
162
+ }
155
163
  />
156
164
  );
157
165
  }
@@ -4,7 +4,6 @@ import {
4
4
  ANY_OF_KEY,
5
5
  getTemplate,
6
6
  getUiOptions,
7
- hashObject,
8
7
  isFormDataAvailable,
9
8
  orderProperties,
10
9
  shouldRenderOptionalField,
@@ -29,7 +28,8 @@ import get from 'lodash/get';
29
28
  import has from 'lodash/has';
30
29
  import isObject from 'lodash/isObject';
31
30
  import set from 'lodash/set';
32
- import unset from 'lodash/unset';
31
+
32
+ import { ADDITIONAL_PROPERTY_KEY_REMOVE } from '../constants';
33
33
 
34
34
  /** Returns a flag indicating whether the `name` field is required in the object schema
35
35
  *
@@ -220,7 +220,6 @@ export default function ObjectField<T = any, S extends StrictRJSFSchema = RJSFSc
220
220
  const schema: S = schemaUtils.retrieveSchema(rawSchema, formData, true);
221
221
  const uiOptions = getUiOptions<T, S, F>(uiSchema, globalUiOptions);
222
222
  const { properties: schemaProperties = {} } = schema;
223
- const formDataHash = hashObject(formData || {});
224
223
  // All the children will use childFieldPathId if present in the props, falling back to the fieldPathId
225
224
  const childFieldPathId = props.childFieldPathId ?? fieldPathId;
226
225
 
@@ -320,15 +319,14 @@ export default function ObjectField<T = any, S extends StrictRJSFSchema = RJSFSc
320
319
  [formData, onChange, childFieldPathId, getAvailableKey],
321
320
  );
322
321
 
323
- /** Handles the remove click which removes the old `key` data and calls the `onChange` callback with it
322
+ /** Handles the remove click which calls the `onChange` callback with the special ADDITIONAL_PROPERTY_FIELD_REMOVE
323
+ * value for the path plus the key to be removed
324
324
  */
325
325
  const handleRemoveProperty = useCallback(
326
326
  (key: string) => {
327
- const copiedFormData = { ...formData } as T;
328
- unset(copiedFormData, key);
329
- onChange(copiedFormData, childFieldPathId.path);
327
+ onChange(ADDITIONAL_PROPERTY_KEY_REMOVE as T, [...childFieldPathId.path, key]);
330
328
  },
331
- [onChange, childFieldPathId, formData],
329
+ [onChange, childFieldPathId],
332
330
  );
333
331
 
334
332
  if (!renderOptionalField || hasFormData) {
@@ -364,10 +362,7 @@ export default function ObjectField<T = any, S extends StrictRJSFSchema = RJSFSc
364
362
  const hidden = getUiOptions<T, S, F>(fieldUiSchema).widget === 'hidden';
365
363
  const content = (
366
364
  <ObjectFieldProperty<T, S, F>
367
- // For regular properties, the key is just the name. For additionalProperties, the key is a combination of the
368
- // name and the hash of the formData so that react rerenders the components with the updated additional
369
- // property related callback which will change due to formData changes
370
- key={addedByAdditionalProperties ? `${name}-${formDataHash}` : name}
365
+ key={name}
371
366
  propertyName={name}
372
367
  required={isRequired<S>(schema, name)}
373
368
  schema={get(schema, [PROPERTIES_KEY, name], {}) as S}
@@ -34,8 +34,9 @@ function StringField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends
34
34
  registry,
35
35
  rawErrors,
36
36
  hideError,
37
+ title,
37
38
  } = props;
38
- const { title, format } = schema;
39
+ const { title: schemaTitle, format } = schema;
39
40
  const { widgets, schemaUtils, globalUiOptions } = registry;
40
41
  const enumOptions = schemaUtils.isSelect(schema) ? optionsList<T, S, F>(schema, uiSchema) : undefined;
41
42
  let defaultWidget = enumOptions ? 'select' : 'text';
@@ -44,7 +45,7 @@ function StringField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends
44
45
  }
45
46
  const { widget = defaultWidget, placeholder = '', title: uiTitle, ...options } = getUiOptions<T, S, F>(uiSchema);
46
47
  const displayLabel = schemaUtils.getDisplayLabel(schema, uiSchema, globalUiOptions);
47
- const label = uiTitle ?? title ?? name;
48
+ const label = uiTitle ?? title ?? schemaTitle ?? name;
48
49
  const Widget = getWidget<T, S, F>(schema, widget, widgets);
49
50
  const onWidgetChange = useCallback(
50
51
  (value: T | undefined, errorSchema?: ErrorSchema, id?: string) => {
@@ -17,7 +17,7 @@ export default function ArrayFieldItemTemplate<
17
17
  S extends StrictRJSFSchema = RJSFSchema,
18
18
  F extends FormContextType = any,
19
19
  >(props: ArrayFieldItemTemplateProps<T, S, F>) {
20
- const { children, className, buttonsProps, hasToolbar, registry, uiSchema } = props;
20
+ const { children, className, buttonsProps, displayLabel, hasDescription, hasToolbar, registry, uiSchema } = props;
21
21
  const uiOptions = getUiOptions<T, S, F>(uiSchema);
22
22
  const ArrayFieldItemButtonsTemplate = getTemplate<'ArrayFieldItemButtonsTemplate', T, S, F>(
23
23
  'ArrayFieldItemButtonsTemplate',
@@ -30,18 +30,15 @@ export default function ArrayFieldItemTemplate<
30
30
  paddingRight: 6,
31
31
  fontWeight: 'bold',
32
32
  };
33
+ const margin = hasDescription ? 31 : 9;
34
+ const containerStyle = { display: 'flex', alignItems: displayLabel ? 'center' : 'baseline' };
35
+ const toolbarStyle = { display: 'flex', justifyContent: 'flex-end', marginTop: displayLabel ? `${margin}px` : 0 };
33
36
  return (
34
- <div className={className}>
35
- <div className={hasToolbar ? 'col-xs-9' : 'col-xs-12'}>{children}</div>
37
+ <div className={className} style={containerStyle}>
38
+ <div className={hasToolbar ? 'col-xs-9 col-md-10 col-xl-11' : 'col-xs-12'}>{children}</div>
36
39
  {hasToolbar && (
37
- <div className='col-xs-3 array-item-toolbox'>
38
- <div
39
- className='btn-group'
40
- style={{
41
- display: 'flex',
42
- justifyContent: 'space-around',
43
- }}
44
- >
40
+ <div className='col-xs-3 col-md-2 col-xl-1 array-item-toolbox'>
41
+ <div className='btn-group' style={toolbarStyle}>
45
42
  <ArrayFieldItemButtonsTemplate {...buttonsProps} style={btnStyle} />
46
43
  </div>
47
44
  </div>
@@ -14,7 +14,9 @@ export default function AddButton<T = any, S extends StrictRJSFSchema = RJSFSche
14
14
  const { translateString } = registry;
15
15
  return (
16
16
  <div className='row'>
17
- <p className={`col-xs-3 col-xs-offset-9 text-right ${className}`}>
17
+ <p
18
+ className={`col-xs-4 col-sm-2 col-lg-1 col-xs-offset-8 col-sm-offset-10 col-lg-offset-11 text-right ${className}`}
19
+ >
18
20
  <IconButton
19
21
  id={id}
20
22
  iconType='info'
@@ -1,4 +1,5 @@
1
1
  import { helpId, FieldHelpProps, FormContextType, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils';
2
+ import RichHelp from '../RichHelp';
2
3
 
3
4
  /** The `FieldHelpTemplate` component renders any help desired for a field
4
5
  *
@@ -9,21 +10,14 @@ export default function FieldHelpTemplate<
9
10
  S extends StrictRJSFSchema = RJSFSchema,
10
11
  F extends FormContextType = any,
11
12
  >(props: FieldHelpProps<T, S, F>) {
12
- const { fieldPathId, help } = props;
13
+ const { fieldPathId, help, uiSchema, registry } = props;
13
14
  if (!help) {
14
15
  return null;
15
16
  }
16
- const id = helpId(fieldPathId);
17
- if (typeof help === 'string') {
18
- return (
19
- <p id={id} className='help-block'>
20
- {help}
21
- </p>
22
- );
23
- }
17
+
24
18
  return (
25
- <div id={id} className='help-block'>
26
- {help}
19
+ <div id={helpId(fieldPathId)} className='help-block'>
20
+ <RichHelp help={help as string} registry={registry} uiSchema={uiSchema} />
27
21
  </div>
28
22
  );
29
23
  }
@@ -29,9 +29,10 @@ export default function FieldTemplate<
29
29
  if (hidden) {
30
30
  return <div className='hidden'>{children}</div>;
31
31
  }
32
+ const isCheckbox = uiOptions.widget === 'checkbox';
32
33
  return (
33
34
  <WrapIfAdditionalTemplate {...props}>
34
- {displayLabel && <Label label={label} required={required} id={id} />}
35
+ {displayLabel && !isCheckbox && <Label label={label} required={required} id={id} />}
35
36
  {displayLabel && description ? description : null}
36
37
  {children}
37
38
  {errors}
@@ -25,9 +25,11 @@ export default function WrapIfAdditionalTemplate<
25
25
  classNames,
26
26
  style,
27
27
  disabled,
28
+ displayLabel,
28
29
  label,
29
30
  onKeyRenameBlur,
30
31
  onRemoveProperty,
32
+ rawDescription,
31
33
  readonly,
32
34
  required,
33
35
  schema,
@@ -42,6 +44,7 @@ export default function WrapIfAdditionalTemplate<
42
44
  const { RemoveButton } = templates.ButtonTemplates;
43
45
  const keyLabel = translateString(TranslatableString.KeyLabel, [label]);
44
46
  const additional = ADDITIONAL_PROPERTY_FLAG in schema;
47
+ const hasDescription = !!rawDescription;
45
48
 
46
49
  const classNamesList = ['form-group', classNames];
47
50
  if (!hideError && rawErrors && rawErrors.length > 0) {
@@ -56,13 +59,14 @@ export default function WrapIfAdditionalTemplate<
56
59
  </div>
57
60
  );
58
61
  }
59
-
62
+ const margin = hasDescription ? 46 : 26;
60
63
  return (
61
64
  <div className={uiClassNames} style={style}>
62
65
  <div className='row'>
63
66
  <div className='col-xs-5 form-additional'>
64
67
  <div className='form-group'>
65
- <Label label={keyLabel} required={required} id={`${id}-key`} />
68
+ {displayLabel && <Label label={keyLabel} required={required} id={`${id}-key`} />}
69
+ {displayLabel && rawDescription && <div>&nbsp;</div>}
66
70
  <input
67
71
  className='form-control'
68
72
  type='text'
@@ -73,7 +77,7 @@ export default function WrapIfAdditionalTemplate<
73
77
  </div>
74
78
  </div>
75
79
  <div className='form-additional form-group col-xs-5'>{children}</div>
76
- <div className='col-xs-2'>
80
+ <div className='col-xs-2' style={{ marginTop: displayLabel ? `${margin}px` : undefined }}>
77
81
  <RemoveButton
78
82
  id={buttonId(id, 'remove')}
79
83
  className='rjsf-object-property-remove btn-block'
@@ -9,6 +9,7 @@ import {
9
9
  RJSFSchema,
10
10
  StrictRJSFSchema,
11
11
  WidgetProps,
12
+ getUiOptions,
12
13
  } from '@rjsf/utils';
13
14
 
14
15
  /** The `CheckBoxWidget` is a widget for rendering boolean properties.
@@ -57,8 +58,10 @@ function CheckboxWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F exte
57
58
  (event: FocusEvent<HTMLInputElement>) => onFocus(id, event.target.checked),
58
59
  [onFocus, id],
59
60
  );
60
- const description = options.description ?? schema.description;
61
61
 
62
+ const uiOptions = getUiOptions(uiSchema);
63
+ const isCheckboxWidget = uiOptions.widget === 'checkbox';
64
+ const description = isCheckboxWidget ? undefined : (options.description ?? schema.description);
62
65
  return (
63
66
  <div className={`checkbox ${disabled || readonly ? 'disabled' : ''}`}>
64
67
  {!hideLabel && description && (
package/src/index.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  import Form, { FormProps, FormState, IChangeEvent } from './components/Form';
2
2
  import RichDescription, { RichDescriptionProps } from './components/RichDescription';
3
+ import RichHelp, { RichHelpProps } from './components/RichHelp';
3
4
  import withTheme, { ThemeProps } from './withTheme';
4
5
  import getDefaultRegistry from './getDefaultRegistry';
5
6
  import getTestRegistry from './getTestRegistry';
6
7
 
7
- export type { FormProps, FormState, IChangeEvent, ThemeProps, RichDescriptionProps };
8
+ export type { FormProps, FormState, IChangeEvent, ThemeProps, RichDescriptionProps, RichHelpProps };
8
9
 
9
- export { withTheme, getDefaultRegistry, getTestRegistry, RichDescription };
10
+ export { withTheme, getDefaultRegistry, getTestRegistry, RichDescription, RichHelp };
10
11
  export default Form;