@rjsf/core 5.15.0 → 5.16.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.umd.js +67 -53
- package/dist/index.esm.js +70 -55
- package/dist/index.esm.js.map +3 -3
- package/dist/index.js +67 -53
- package/dist/index.js.map +3 -3
- package/lib/components/Form.d.ts +1 -1
- package/lib/components/Form.js +12 -10
- package/lib/components/Form.js.map +1 -1
- package/lib/components/fields/ArrayField.d.ts +1 -0
- package/lib/components/fields/ArrayField.js +10 -8
- package/lib/components/fields/ArrayField.js.map +1 -1
- package/lib/components/fields/BooleanField.js +5 -5
- package/lib/components/fields/BooleanField.js.map +1 -1
- package/lib/components/fields/ObjectField.js +5 -5
- package/lib/components/fields/ObjectField.js.map +1 -1
- package/lib/components/fields/SchemaField.js +4 -1
- package/lib/components/fields/SchemaField.js.map +1 -1
- package/lib/components/widgets/AltDateWidget.js +2 -18
- package/lib/components/widgets/AltDateWidget.js.map +1 -1
- package/lib/components/widgets/FileWidget.js +17 -8
- package/lib/components/widgets/FileWidget.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +23 -23
- package/src/components/Form.tsx +7 -3
- package/src/components/fields/ArrayField.tsx +11 -4
- package/src/components/fields/BooleanField.tsx +3 -2
- package/src/components/fields/ObjectField.tsx +3 -2
- package/src/components/fields/SchemaField.tsx +4 -1
- package/src/components/widgets/AltDateWidget.tsx +8 -26
- package/src/components/widgets/FileWidget.tsx +31 -8
package/src/components/Form.tsx
CHANGED
|
@@ -533,7 +533,11 @@ export default class Form<
|
|
|
533
533
|
const formValue = _get(formData, path);
|
|
534
534
|
// adds path to fieldNames if it points to a value
|
|
535
535
|
// or an empty object/array
|
|
536
|
-
if (
|
|
536
|
+
if (
|
|
537
|
+
typeof formValue !== 'object' ||
|
|
538
|
+
_isEmpty(formValue) ||
|
|
539
|
+
(Array.isArray(formValue) && formValue.every((val) => typeof val !== 'object'))
|
|
540
|
+
) {
|
|
537
541
|
acc.push(path);
|
|
538
542
|
}
|
|
539
543
|
});
|
|
@@ -738,7 +742,7 @@ export default class Form<
|
|
|
738
742
|
}
|
|
739
743
|
|
|
740
744
|
/** Provides a function that can be used to programmatically submit the `Form` */
|
|
741
|
-
submit() {
|
|
745
|
+
submit = () => {
|
|
742
746
|
if (this.formElement.current) {
|
|
743
747
|
this.formElement.current.dispatchEvent(
|
|
744
748
|
new CustomEvent('submit', {
|
|
@@ -747,7 +751,7 @@ export default class Form<
|
|
|
747
751
|
);
|
|
748
752
|
this.formElement.current.requestSubmit();
|
|
749
753
|
}
|
|
750
|
-
}
|
|
754
|
+
};
|
|
751
755
|
|
|
752
756
|
/** Attempts to focus on the field associated with the `error`. Uses the `property` field to compute path of the error
|
|
753
757
|
* field, then, using the `idPrefix` and `idSeparator` converts that path into an id. Then the input element with that
|
|
@@ -470,6 +470,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
470
470
|
errorSchema,
|
|
471
471
|
idSchema,
|
|
472
472
|
name,
|
|
473
|
+
title,
|
|
473
474
|
disabled = false,
|
|
474
475
|
readonly = false,
|
|
475
476
|
autofocus = false,
|
|
@@ -482,7 +483,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
482
483
|
rawErrors,
|
|
483
484
|
} = this.props;
|
|
484
485
|
const { keyedFormData } = this.state;
|
|
485
|
-
const
|
|
486
|
+
const fieldTitle = schema.title || title || name;
|
|
486
487
|
const { schemaUtils, formContext } = registry;
|
|
487
488
|
const uiOptions = getUiOptions<T[], S, F>(uiSchema);
|
|
488
489
|
const _schemaItems: S = isObject(schema.items) ? (schema.items as S) : ({} as S);
|
|
@@ -503,6 +504,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
503
504
|
key,
|
|
504
505
|
index,
|
|
505
506
|
name: name && `${name}-${index}`,
|
|
507
|
+
title: fieldTitle ? `${fieldTitle}-${index + 1}` : undefined,
|
|
506
508
|
canAdd,
|
|
507
509
|
canMoveUp: index > 0,
|
|
508
510
|
canMoveDown: index < formData.length - 1,
|
|
@@ -526,7 +528,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
526
528
|
readonly,
|
|
527
529
|
required,
|
|
528
530
|
schema,
|
|
529
|
-
title,
|
|
531
|
+
title: fieldTitle,
|
|
530
532
|
formContext,
|
|
531
533
|
formData,
|
|
532
534
|
rawErrors,
|
|
@@ -701,6 +703,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
701
703
|
idSeparator = '_',
|
|
702
704
|
idSchema,
|
|
703
705
|
name,
|
|
706
|
+
title,
|
|
704
707
|
disabled = false,
|
|
705
708
|
readonly = false,
|
|
706
709
|
autofocus = false,
|
|
@@ -712,7 +715,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
712
715
|
} = this.props;
|
|
713
716
|
const { keyedFormData } = this.state;
|
|
714
717
|
let { formData: items = [] } = this.props;
|
|
715
|
-
const
|
|
718
|
+
const fieldTitle = schema.title || title || name;
|
|
716
719
|
const uiOptions = getUiOptions<T[], S, F>(uiSchema);
|
|
717
720
|
const { schemaUtils, formContext } = registry;
|
|
718
721
|
const _schemaItems: S[] = isObject(schema.items) ? (schema.items as S[]) : ([] as S[]);
|
|
@@ -759,6 +762,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
759
762
|
key,
|
|
760
763
|
index,
|
|
761
764
|
name: name && `${name}-${index}`,
|
|
765
|
+
title: fieldTitle ? `${fieldTitle}-${index + 1}` : undefined,
|
|
762
766
|
canAdd,
|
|
763
767
|
canRemove: additional,
|
|
764
768
|
canMoveUp: index >= itemSchemas.length + 1,
|
|
@@ -781,7 +785,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
781
785
|
registry,
|
|
782
786
|
schema,
|
|
783
787
|
uiSchema,
|
|
784
|
-
title,
|
|
788
|
+
title: fieldTitle,
|
|
785
789
|
formContext,
|
|
786
790
|
rawErrors,
|
|
787
791
|
};
|
|
@@ -799,6 +803,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
799
803
|
key: string;
|
|
800
804
|
index: number;
|
|
801
805
|
name: string;
|
|
806
|
+
title: string | undefined;
|
|
802
807
|
canAdd: boolean;
|
|
803
808
|
canRemove?: boolean;
|
|
804
809
|
canMoveUp: boolean;
|
|
@@ -832,6 +837,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
832
837
|
onFocus,
|
|
833
838
|
rawErrors,
|
|
834
839
|
totalItems,
|
|
840
|
+
title,
|
|
835
841
|
} = props;
|
|
836
842
|
const { disabled, hideError, idPrefix, idSeparator, readonly, uiSchema, registry, formContext } = this.props;
|
|
837
843
|
const {
|
|
@@ -853,6 +859,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
853
859
|
children: (
|
|
854
860
|
<ItemSchemaField
|
|
855
861
|
name={name}
|
|
862
|
+
title={title}
|
|
856
863
|
index={index}
|
|
857
864
|
schema={itemSchema}
|
|
858
865
|
uiSchema={itemUiSchema}
|
|
@@ -31,12 +31,13 @@ function BooleanField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extend
|
|
|
31
31
|
readonly,
|
|
32
32
|
hideError,
|
|
33
33
|
autofocus,
|
|
34
|
+
title,
|
|
34
35
|
onChange,
|
|
35
36
|
onFocus,
|
|
36
37
|
onBlur,
|
|
37
38
|
rawErrors,
|
|
38
39
|
} = props;
|
|
39
|
-
const { title } = schema;
|
|
40
|
+
const { title: schemaTitle } = schema;
|
|
40
41
|
const { widgets, formContext, translateString, globalUiOptions } = registry;
|
|
41
42
|
const {
|
|
42
43
|
widget = 'checkbox',
|
|
@@ -49,7 +50,7 @@ function BooleanField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extend
|
|
|
49
50
|
const yes = translateString(TranslatableString.YesLabel);
|
|
50
51
|
const no = translateString(TranslatableString.NoLabel);
|
|
51
52
|
let enumOptions: EnumOptionsType<S>[] | undefined;
|
|
52
|
-
const label = uiTitle ?? title ?? name;
|
|
53
|
+
const label = uiTitle ?? schemaTitle ?? title ?? name;
|
|
53
54
|
if (Array.isArray(schema.oneOf)) {
|
|
54
55
|
enumOptions = optionsList<S>({
|
|
55
56
|
oneOf: schema.oneOf
|
|
@@ -241,6 +241,7 @@ class ObjectField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
|
|
|
241
241
|
onBlur,
|
|
242
242
|
onFocus,
|
|
243
243
|
registry,
|
|
244
|
+
title,
|
|
244
245
|
} = this.props;
|
|
245
246
|
|
|
246
247
|
const { fields, formContext, schemaUtils, translateString, globalUiOptions } = registry;
|
|
@@ -249,7 +250,7 @@ class ObjectField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
|
|
|
249
250
|
const uiOptions = getUiOptions<T, S, F>(uiSchema, globalUiOptions);
|
|
250
251
|
const { properties: schemaProperties = {} } = schema;
|
|
251
252
|
|
|
252
|
-
const
|
|
253
|
+
const templateTitle = uiOptions.title ?? schema.title ?? title ?? name;
|
|
253
254
|
const description = uiOptions.description ?? schema.description;
|
|
254
255
|
let orderedProperties: string[];
|
|
255
256
|
try {
|
|
@@ -272,7 +273,7 @@ class ObjectField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
|
|
|
272
273
|
|
|
273
274
|
const templateProps = {
|
|
274
275
|
// getDisplayLabel() always returns false for object types, so just check the `uiOptions.label`
|
|
275
|
-
title: uiOptions.label === false ? '' :
|
|
276
|
+
title: uiOptions.label === false ? '' : templateTitle,
|
|
276
277
|
description: uiOptions.label === false ? undefined : description,
|
|
277
278
|
properties: orderedProperties.map((name) => {
|
|
278
279
|
const addedByAdditionalProperties = has(schema, [PROPERTIES_KEY, name, ADDITIONAL_PROPERTY_FLAG]);
|
|
@@ -193,7 +193,10 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
|
|
|
193
193
|
if (wasPropertyKeyModified) {
|
|
194
194
|
label = name;
|
|
195
195
|
} else {
|
|
196
|
-
label =
|
|
196
|
+
label =
|
|
197
|
+
ADDITIONAL_PROPERTY_FLAG in schema
|
|
198
|
+
? name
|
|
199
|
+
: uiOptions.title || props.schema.title || schema.title || props.title || name;
|
|
197
200
|
}
|
|
198
201
|
|
|
199
202
|
const description = uiOptions.description || props.schema.description || schema.description || '';
|
|
@@ -5,11 +5,13 @@ import {
|
|
|
5
5
|
toDateString,
|
|
6
6
|
pad,
|
|
7
7
|
DateObject,
|
|
8
|
+
type DateElementFormat,
|
|
8
9
|
FormContextType,
|
|
9
10
|
RJSFSchema,
|
|
10
11
|
StrictRJSFSchema,
|
|
11
12
|
TranslatableString,
|
|
12
13
|
WidgetProps,
|
|
14
|
+
getDateElementProps,
|
|
13
15
|
} from '@rjsf/utils';
|
|
14
16
|
|
|
15
17
|
function rangeOptions(start: number, stop: number) {
|
|
@@ -24,31 +26,6 @@ function readyForChange(state: DateObject) {
|
|
|
24
26
|
return Object.values(state).every((value) => value !== -1);
|
|
25
27
|
}
|
|
26
28
|
|
|
27
|
-
function dateElementProps(
|
|
28
|
-
state: DateObject,
|
|
29
|
-
time: boolean,
|
|
30
|
-
yearsRange: [number, number] = [1900, new Date().getFullYear() + 2]
|
|
31
|
-
) {
|
|
32
|
-
const { year, month, day, hour, minute, second } = state;
|
|
33
|
-
const data = [
|
|
34
|
-
{
|
|
35
|
-
type: 'year',
|
|
36
|
-
range: yearsRange,
|
|
37
|
-
value: year,
|
|
38
|
-
},
|
|
39
|
-
{ type: 'month', range: [1, 12], value: month },
|
|
40
|
-
{ type: 'day', range: [1, 31], value: day },
|
|
41
|
-
] as { type: string; range: [number, number]; value: number | undefined }[];
|
|
42
|
-
if (time) {
|
|
43
|
-
data.push(
|
|
44
|
-
{ type: 'hour', range: [0, 23], value: hour },
|
|
45
|
-
{ type: 'minute', range: [0, 59], value: minute },
|
|
46
|
-
{ type: 'second', range: [0, 59], value: second }
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
return data;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
29
|
type DateElementProps<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> = Pick<
|
|
53
30
|
WidgetProps<T, S, F>,
|
|
54
31
|
'value' | 'name' | 'disabled' | 'readonly' | 'autofocus' | 'registry' | 'onBlur' | 'onFocus'
|
|
@@ -161,7 +138,12 @@ function AltDateWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F exten
|
|
|
161
138
|
|
|
162
139
|
return (
|
|
163
140
|
<ul className='list-inline'>
|
|
164
|
-
{
|
|
141
|
+
{getDateElementProps(
|
|
142
|
+
state,
|
|
143
|
+
time,
|
|
144
|
+
options.yearsRange as [number, number] | undefined,
|
|
145
|
+
options.format as DateElementFormat | undefined
|
|
146
|
+
).map((elemProps, i) => (
|
|
165
147
|
<li className='list-inline-item' key={i}>
|
|
166
148
|
<DateElement
|
|
167
149
|
rootId={id}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ChangeEvent, useCallback,
|
|
1
|
+
import { ChangeEvent, useCallback, useMemo } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
dataURItoBlob,
|
|
4
4
|
FormContextType,
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
RJSFSchema,
|
|
8
8
|
StrictRJSFSchema,
|
|
9
9
|
TranslatableString,
|
|
10
|
+
UIOptionsType,
|
|
10
11
|
WidgetProps,
|
|
11
12
|
} from '@rjsf/utils';
|
|
12
13
|
import Markdown from 'markdown-to-jsx';
|
|
@@ -86,23 +87,32 @@ function FilesInfo<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends F
|
|
|
86
87
|
filesInfo,
|
|
87
88
|
registry,
|
|
88
89
|
preview,
|
|
90
|
+
onRemove,
|
|
91
|
+
options,
|
|
89
92
|
}: {
|
|
90
93
|
filesInfo: FileInfoType[];
|
|
91
94
|
registry: Registry<T, S, F>;
|
|
92
95
|
preview?: boolean;
|
|
96
|
+
onRemove: (index: number) => void;
|
|
97
|
+
options: UIOptionsType<T, S, F>;
|
|
93
98
|
}) {
|
|
94
99
|
if (filesInfo.length === 0) {
|
|
95
100
|
return null;
|
|
96
101
|
}
|
|
97
102
|
const { translateString } = registry;
|
|
103
|
+
|
|
104
|
+
const { RemoveButton } = getTemplate<'ButtonTemplates', T, S, F>('ButtonTemplates', registry, options);
|
|
105
|
+
|
|
98
106
|
return (
|
|
99
107
|
<ul className='file-info'>
|
|
100
108
|
{filesInfo.map((fileInfo, key) => {
|
|
101
109
|
const { name, size, type } = fileInfo;
|
|
110
|
+
const handleRemove = () => onRemove(key);
|
|
102
111
|
return (
|
|
103
112
|
<li key={key}>
|
|
104
113
|
<Markdown>{translateString(TranslatableString.FilesInfo, [name, type, String(size)])}</Markdown>
|
|
105
114
|
{preview && <FileInfoPreview<T, S, F> fileInfo={fileInfo} registry={registry} />}
|
|
115
|
+
<RemoveButton onClick={handleRemove} registry={registry} />
|
|
106
116
|
</li>
|
|
107
117
|
);
|
|
108
118
|
})}
|
|
@@ -133,9 +143,6 @@ function FileWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends
|
|
|
133
143
|
) {
|
|
134
144
|
const { disabled, readonly, required, multiple, onChange, value, options, registry } = props;
|
|
135
145
|
const BaseInputTemplate = getTemplate<'BaseInputTemplate', T, S, F>('BaseInputTemplate', registry, options);
|
|
136
|
-
const [filesInfo, setFilesInfo] = useState<FileInfoType[]>(
|
|
137
|
-
Array.isArray(value) ? extractFileInfo(value) : extractFileInfo([value])
|
|
138
|
-
);
|
|
139
146
|
|
|
140
147
|
const handleChange = useCallback(
|
|
141
148
|
(event: ChangeEvent<HTMLInputElement>) => {
|
|
@@ -148,17 +155,27 @@ function FileWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends
|
|
|
148
155
|
processFiles(event.target.files).then((filesInfoEvent) => {
|
|
149
156
|
const newValue = filesInfoEvent.map((fileInfo) => fileInfo.dataURL);
|
|
150
157
|
if (multiple) {
|
|
151
|
-
setFilesInfo(filesInfo.concat(filesInfoEvent[0]));
|
|
152
158
|
onChange(value.concat(newValue[0]));
|
|
153
159
|
} else {
|
|
154
|
-
setFilesInfo(filesInfoEvent);
|
|
155
160
|
onChange(newValue[0]);
|
|
156
161
|
}
|
|
157
162
|
});
|
|
158
163
|
},
|
|
159
|
-
[multiple, value,
|
|
164
|
+
[multiple, value, onChange]
|
|
160
165
|
);
|
|
161
166
|
|
|
167
|
+
const filesInfo = useMemo(() => extractFileInfo(Array.isArray(value) ? value : [value]), [value]);
|
|
168
|
+
const rmFile = useCallback(
|
|
169
|
+
(index: number) => {
|
|
170
|
+
if (multiple) {
|
|
171
|
+
const newValue = value.filter((_: any, i: number) => i !== index);
|
|
172
|
+
onChange(newValue);
|
|
173
|
+
} else {
|
|
174
|
+
onChange(undefined);
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
[multiple, value, onChange]
|
|
178
|
+
);
|
|
162
179
|
return (
|
|
163
180
|
<div>
|
|
164
181
|
<BaseInputTemplate
|
|
@@ -170,7 +187,13 @@ function FileWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends
|
|
|
170
187
|
value=''
|
|
171
188
|
accept={options.accept ? String(options.accept) : undefined}
|
|
172
189
|
/>
|
|
173
|
-
<FilesInfo<T, S, F>
|
|
190
|
+
<FilesInfo<T, S, F>
|
|
191
|
+
filesInfo={filesInfo}
|
|
192
|
+
onRemove={rmFile}
|
|
193
|
+
registry={registry}
|
|
194
|
+
preview={options.filePreview}
|
|
195
|
+
options={options}
|
|
196
|
+
/>
|
|
174
197
|
</div>
|
|
175
198
|
);
|
|
176
199
|
}
|