@rjsf/core 5.11.2 → 5.12.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 +3464 -0
- package/dist/index.esm.js +3814 -0
- package/dist/index.esm.js.map +7 -0
- package/dist/index.js +3714 -5
- package/dist/index.js.map +7 -0
- package/{dist/index.d.ts → lib/components/Form.d.ts} +321 -337
- package/lib/components/Form.js +474 -0
- package/lib/components/Form.js.map +1 -0
- package/lib/components/fields/ArrayField.d.ts +179 -0
- package/lib/components/fields/ArrayField.js +568 -0
- package/lib/components/fields/ArrayField.js.map +1 -0
- package/lib/components/fields/BooleanField.d.ts +9 -0
- package/lib/components/fields/BooleanField.js +62 -0
- package/lib/components/fields/BooleanField.js.map +1 -0
- package/lib/components/fields/MultiSchemaField.d.ts +47 -0
- package/lib/components/fields/MultiSchemaField.js +129 -0
- package/lib/components/fields/MultiSchemaField.js.map +1 -0
- package/lib/components/fields/NullField.d.ts +8 -0
- package/lib/components/fields/NullField.js +17 -0
- package/lib/components/fields/NullField.js.map +1 -0
- package/lib/components/fields/NumberField.d.ts +21 -0
- package/lib/components/fields/NumberField.js +70 -0
- package/lib/components/fields/NumberField.js.map +1 -0
- package/lib/components/fields/ObjectField.d.ts +73 -0
- package/lib/components/fields/ObjectField.js +222 -0
- package/lib/components/fields/ObjectField.js.map +1 -0
- package/lib/components/fields/SchemaField.d.ts +10 -0
- package/lib/components/fields/SchemaField.js +172 -0
- package/lib/components/fields/SchemaField.js.map +1 -0
- package/lib/components/fields/StringField.d.ts +8 -0
- package/lib/components/fields/StringField.js +25 -0
- package/lib/components/fields/StringField.js.map +1 -0
- package/lib/components/fields/index.d.ts +3 -0
- package/lib/components/fields/index.js +24 -0
- package/lib/components/fields/index.js.map +1 -0
- package/lib/components/templates/ArrayFieldDescriptionTemplate.d.ts +8 -0
- package/lib/components/templates/ArrayFieldDescriptionTemplate.js +18 -0
- package/lib/components/templates/ArrayFieldDescriptionTemplate.js.map +1 -0
- package/lib/components/templates/ArrayFieldItemTemplate.d.ts +7 -0
- package/lib/components/templates/ArrayFieldItemTemplate.js +20 -0
- package/lib/components/templates/ArrayFieldItemTemplate.js.map +1 -0
- package/lib/components/templates/ArrayFieldTemplate.d.ts +7 -0
- package/lib/components/templates/ArrayFieldTemplate.js +22 -0
- package/lib/components/templates/ArrayFieldTemplate.js.map +1 -0
- package/lib/components/templates/ArrayFieldTitleTemplate.d.ts +8 -0
- package/lib/components/templates/ArrayFieldTitleTemplate.js +18 -0
- package/lib/components/templates/ArrayFieldTitleTemplate.js.map +1 -0
- package/lib/components/templates/BaseInputTemplate.d.ts +9 -0
- package/lib/components/templates/BaseInputTemplate.js +39 -0
- package/lib/components/templates/BaseInputTemplate.js.map +1 -0
- package/lib/components/templates/ButtonTemplates/AddButton.d.ts +5 -0
- package/lib/components/templates/ButtonTemplates/AddButton.js +10 -0
- package/lib/components/templates/ButtonTemplates/AddButton.js.map +1 -0
- package/lib/components/templates/ButtonTemplates/IconButton.d.ts +7 -0
- package/lib/components/templates/ButtonTemplates/IconButton.js +24 -0
- package/lib/components/templates/ButtonTemplates/IconButton.js.map +1 -0
- package/lib/components/templates/ButtonTemplates/SubmitButton.d.ts +5 -0
- package/lib/components/templates/ButtonTemplates/SubmitButton.js +12 -0
- package/lib/components/templates/ButtonTemplates/SubmitButton.js.map +1 -0
- package/lib/components/templates/ButtonTemplates/index.d.ts +3 -0
- package/lib/components/templates/ButtonTemplates/index.js +15 -0
- package/lib/components/templates/ButtonTemplates/index.js.map +1 -0
- package/lib/components/templates/DescriptionField.d.ts +7 -0
- package/lib/components/templates/DescriptionField.js +18 -0
- package/lib/components/templates/DescriptionField.js.map +1 -0
- package/lib/components/templates/ErrorList.d.ts +7 -0
- package/lib/components/templates/ErrorList.js +13 -0
- package/lib/components/templates/ErrorList.js.map +1 -0
- package/lib/components/templates/FieldErrorTemplate.d.ts +7 -0
- package/lib/components/templates/FieldErrorTemplate.js +19 -0
- package/lib/components/templates/FieldErrorTemplate.js.map +1 -0
- package/lib/components/templates/FieldHelpTemplate.d.ts +7 -0
- package/lib/components/templates/FieldHelpTemplate.js +18 -0
- package/lib/components/templates/FieldHelpTemplate.js.map +1 -0
- package/lib/components/templates/FieldTemplate/FieldTemplate.d.ts +8 -0
- package/lib/components/templates/FieldTemplate/FieldTemplate.js +18 -0
- package/lib/components/templates/FieldTemplate/FieldTemplate.js.map +1 -0
- package/lib/components/templates/FieldTemplate/Label.d.ts +14 -0
- package/lib/components/templates/FieldTemplate/Label.js +14 -0
- package/lib/components/templates/FieldTemplate/Label.js.map +1 -0
- package/lib/components/templates/FieldTemplate/index.d.ts +2 -0
- package/lib/components/templates/FieldTemplate/index.js +3 -0
- package/lib/components/templates/FieldTemplate/index.js.map +1 -0
- package/lib/components/templates/ObjectFieldTemplate.d.ts +9 -0
- package/lib/components/templates/ObjectFieldTemplate.js +18 -0
- package/lib/components/templates/ObjectFieldTemplate.js.map +1 -0
- package/lib/components/templates/TitleField.d.ts +7 -0
- package/lib/components/templates/TitleField.js +11 -0
- package/lib/components/templates/TitleField.js.map +1 -0
- package/lib/components/templates/UnsupportedField.d.ts +9 -0
- package/lib/components/templates/UnsupportedField.js +28 -0
- package/lib/components/templates/UnsupportedField.js.map +1 -0
- package/lib/components/templates/WrapIfAdditionalTemplate.d.ts +8 -0
- package/lib/components/templates/WrapIfAdditionalTemplate.js +21 -0
- package/lib/components/templates/WrapIfAdditionalTemplate.js.map +1 -0
- package/lib/components/templates/index.d.ts +3 -0
- package/lib/components/templates/index.js +36 -0
- package/lib/components/templates/index.js.map +1 -0
- package/lib/components/widgets/AltDateTimeWidget.d.ts +9 -0
- package/lib/components/widgets/AltDateTimeWidget.js +14 -0
- package/lib/components/widgets/AltDateTimeWidget.js.map +1 -0
- package/lib/components/widgets/AltDateWidget.d.ts +7 -0
- package/lib/components/widgets/AltDateWidget.js +77 -0
- package/lib/components/widgets/AltDateWidget.js.map +1 -0
- package/lib/components/widgets/CheckboxWidget.d.ts +9 -0
- package/lib/components/widgets/CheckboxWidget.js +23 -0
- package/lib/components/widgets/CheckboxWidget.js.map +1 -0
- package/lib/components/widgets/CheckboxesWidget.d.ts +9 -0
- package/lib/components/widgets/CheckboxesWidget.js +31 -0
- package/lib/components/widgets/CheckboxesWidget.js.map +1 -0
- package/lib/components/widgets/ColorWidget.d.ts +8 -0
- package/lib/components/widgets/ColorWidget.js +13 -0
- package/lib/components/widgets/ColorWidget.js.map +1 -0
- package/lib/components/widgets/DateTimeWidget.d.ts +8 -0
- package/lib/components/widgets/DateTimeWidget.js +13 -0
- package/lib/components/widgets/DateTimeWidget.js.map +1 -0
- package/lib/components/widgets/DateWidget.d.ts +8 -0
- package/lib/components/widgets/DateWidget.js +15 -0
- package/lib/components/widgets/DateWidget.js.map +1 -0
- package/lib/components/widgets/EmailWidget.d.ts +7 -0
- package/lib/components/widgets/EmailWidget.js +12 -0
- package/lib/components/widgets/EmailWidget.js.map +1 -0
- package/lib/components/widgets/FileWidget.d.ts +8 -0
- package/lib/components/widgets/FileWidget.js +105 -0
- package/lib/components/widgets/FileWidget.js.map +1 -0
- package/lib/components/widgets/HiddenWidget.d.ts +9 -0
- package/lib/components/widgets/HiddenWidget.js +11 -0
- package/lib/components/widgets/HiddenWidget.js.map +1 -0
- package/lib/components/widgets/PasswordWidget.d.ts +7 -0
- package/lib/components/widgets/PasswordWidget.js +12 -0
- package/lib/components/widgets/PasswordWidget.js.map +1 -0
- package/lib/components/widgets/RadioWidget.d.ts +9 -0
- package/lib/components/widgets/RadioWidget.js +24 -0
- package/lib/components/widgets/RadioWidget.js.map +1 -0
- package/lib/components/widgets/RangeWidget.d.ts +8 -0
- package/lib/components/widgets/RangeWidget.js +11 -0
- package/lib/components/widgets/RangeWidget.js.map +1 -0
- package/lib/components/widgets/SelectWidget.d.ts +9 -0
- package/lib/components/widgets/SelectWidget.js +41 -0
- package/lib/components/widgets/SelectWidget.js.map +1 -0
- package/lib/components/widgets/TextWidget.d.ts +7 -0
- package/lib/components/widgets/TextWidget.js +12 -0
- package/lib/components/widgets/TextWidget.js.map +1 -0
- package/lib/components/widgets/TextareaWidget.d.ts +14 -0
- package/lib/components/widgets/TextareaWidget.js +19 -0
- package/lib/components/widgets/TextareaWidget.js.map +1 -0
- package/lib/components/widgets/TimeWidget.d.ts +8 -0
- package/lib/components/widgets/TimeWidget.js +15 -0
- package/lib/components/widgets/TimeWidget.js.map +1 -0
- package/lib/components/widgets/URLWidget.d.ts +7 -0
- package/lib/components/widgets/URLWidget.js +12 -0
- package/lib/components/widgets/URLWidget.js.map +1 -0
- package/lib/components/widgets/UpDownWidget.d.ts +7 -0
- package/lib/components/widgets/UpDownWidget.js +12 -0
- package/lib/components/widgets/UpDownWidget.js.map +1 -0
- package/lib/components/widgets/index.d.ts +3 -0
- package/lib/components/widgets/index.js +44 -0
- package/lib/components/widgets/index.js.map +1 -0
- package/lib/getDefaultRegistry.d.ts +6 -0
- package/lib/getDefaultRegistry.js +19 -0
- package/lib/getDefaultRegistry.js.map +1 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.js +6 -0
- package/lib/index.js.map +1 -0
- package/lib/withTheme.d.ts +9 -0
- package/lib/withTheme.js +16 -0
- package/lib/withTheme.js.map +1 -0
- package/package.json +23 -16
- package/src/components/Form.tsx +853 -0
- package/src/components/fields/ArrayField.tsx +875 -0
- package/src/components/fields/BooleanField.tsx +114 -0
- package/src/components/fields/MultiSchemaField.tsx +221 -0
- package/src/components/fields/NullField.tsx +22 -0
- package/src/components/fields/NumberField.tsx +86 -0
- package/src/components/fields/ObjectField.tsx +331 -0
- package/src/components/fields/SchemaField.tsx +360 -0
- package/src/components/fields/StringField.tsx +71 -0
- package/src/components/fields/index.ts +31 -0
- package/src/components/templates/ArrayFieldDescriptionTemplate.tsx +41 -0
- package/src/components/templates/ArrayFieldItemTemplate.tsx +90 -0
- package/src/components/templates/ArrayFieldTemplate.tsx +88 -0
- package/src/components/templates/ArrayFieldTitleTemplate.tsx +43 -0
- package/src/components/templates/BaseInputTemplate.tsx +102 -0
- package/src/components/templates/ButtonTemplates/AddButton.tsx +29 -0
- package/src/components/templates/ButtonTemplates/IconButton.tsx +77 -0
- package/src/components/templates/ButtonTemplates/SubmitButton.tsx +21 -0
- package/src/components/templates/ButtonTemplates/index.ts +22 -0
- package/src/components/templates/DescriptionField.tsx +29 -0
- package/src/components/templates/ErrorList.tsx +35 -0
- package/src/components/templates/FieldErrorTemplate.tsx +33 -0
- package/src/components/templates/FieldHelpTemplate.tsx +29 -0
- package/src/components/templates/FieldTemplate/FieldTemplate.tsx +41 -0
- package/src/components/templates/FieldTemplate/Label.tsx +27 -0
- package/src/components/templates/FieldTemplate/index.ts +3 -0
- package/src/components/templates/ObjectFieldTemplate.tsx +83 -0
- package/src/components/templates/TitleField.tsx +19 -0
- package/src/components/templates/UnsupportedField.tsx +37 -0
- package/src/components/templates/WrapIfAdditionalTemplate.tsx +80 -0
- package/src/components/templates/index.ts +43 -0
- package/src/components/widgets/AltDateTimeWidget.tsx +16 -0
- package/src/components/widgets/AltDateWidget.tsx +198 -0
- package/src/components/widgets/CheckboxWidget.tsx +92 -0
- package/src/components/widgets/CheckboxesWidget.tsx +92 -0
- package/src/components/widgets/ColorWidget.tsx +14 -0
- package/src/components/widgets/DateTimeWidget.tsx +31 -0
- package/src/components/widgets/DateWidget.tsx +17 -0
- package/src/components/widgets/EmailWidget.tsx +13 -0
- package/src/components/widgets/FileWidget.tsx +178 -0
- package/src/components/widgets/HiddenWidget.tsx +15 -0
- package/src/components/widgets/PasswordWidget.tsx +15 -0
- package/src/components/widgets/RadioWidget.tsx +88 -0
- package/src/components/widgets/RangeWidget.tsx +23 -0
- package/src/components/widgets/SelectWidget.tsx +100 -0
- package/src/components/widgets/TextWidget.tsx +13 -0
- package/src/components/widgets/TextareaWidget.tsx +61 -0
- package/src/components/widgets/TimeWidget.tsx +17 -0
- package/src/components/widgets/URLWidget.tsx +13 -0
- package/src/components/widgets/UpDownWidget.tsx +13 -0
- package/src/components/widgets/index.ts +51 -0
- package/src/getDefaultRegistry.ts +24 -0
- package/src/index.ts +8 -0
- package/src/withTheme.tsx +42 -0
- package/dist/core.cjs.development.js +0 -4403
- package/dist/core.cjs.development.js.map +0 -1
- package/dist/core.cjs.production.min.js +0 -2
- package/dist/core.cjs.production.min.js.map +0 -1
- package/dist/core.esm.js +0 -4383
- package/dist/core.esm.js.map +0 -1
- package/dist/core.umd.development.js +0 -4393
- package/dist/core.umd.development.js.map +0 -1
- package/dist/core.umd.production.min.js +0 -2
- package/dist/core.umd.production.min.js.map +0 -1
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { ChangeEvent, FocusEvent, useCallback } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
ariaDescribedByIds,
|
|
4
|
+
descriptionId,
|
|
5
|
+
getTemplate,
|
|
6
|
+
labelValue,
|
|
7
|
+
schemaRequiresTrueValue,
|
|
8
|
+
FormContextType,
|
|
9
|
+
RJSFSchema,
|
|
10
|
+
StrictRJSFSchema,
|
|
11
|
+
WidgetProps,
|
|
12
|
+
} from '@rjsf/utils';
|
|
13
|
+
|
|
14
|
+
/** The `CheckBoxWidget` is a widget for rendering boolean properties.
|
|
15
|
+
* It is typically used to represent a boolean.
|
|
16
|
+
*
|
|
17
|
+
* @param props - The `WidgetProps` for this component
|
|
18
|
+
*/
|
|
19
|
+
function CheckboxWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>({
|
|
20
|
+
schema,
|
|
21
|
+
uiSchema,
|
|
22
|
+
options,
|
|
23
|
+
id,
|
|
24
|
+
value,
|
|
25
|
+
disabled,
|
|
26
|
+
readonly,
|
|
27
|
+
label,
|
|
28
|
+
hideLabel,
|
|
29
|
+
autofocus = false,
|
|
30
|
+
onBlur,
|
|
31
|
+
onFocus,
|
|
32
|
+
onChange,
|
|
33
|
+
registry,
|
|
34
|
+
}: WidgetProps<T, S, F>) {
|
|
35
|
+
const DescriptionFieldTemplate = getTemplate<'DescriptionFieldTemplate', T, S, F>(
|
|
36
|
+
'DescriptionFieldTemplate',
|
|
37
|
+
registry,
|
|
38
|
+
options
|
|
39
|
+
);
|
|
40
|
+
// Because an unchecked checkbox will cause html5 validation to fail, only add
|
|
41
|
+
// the "required" attribute if the field value must be "true", due to the
|
|
42
|
+
// "const" or "enum" keywords
|
|
43
|
+
const required = schemaRequiresTrueValue<S>(schema);
|
|
44
|
+
|
|
45
|
+
const handleChange = useCallback(
|
|
46
|
+
(event: ChangeEvent<HTMLInputElement>) => onChange(event.target.checked),
|
|
47
|
+
[onChange]
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const handleBlur = useCallback(
|
|
51
|
+
(event: FocusEvent<HTMLInputElement>) => onBlur(id, event.target.checked),
|
|
52
|
+
[onBlur, id]
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
const handleFocus = useCallback(
|
|
56
|
+
(event: FocusEvent<HTMLInputElement>) => onFocus(id, event.target.checked),
|
|
57
|
+
[onFocus, id]
|
|
58
|
+
);
|
|
59
|
+
const description = options.description ?? schema.description;
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<div className={`checkbox ${disabled || readonly ? 'disabled' : ''}`}>
|
|
63
|
+
{!hideLabel && !!description && (
|
|
64
|
+
<DescriptionFieldTemplate
|
|
65
|
+
id={descriptionId<T>(id)}
|
|
66
|
+
description={description}
|
|
67
|
+
schema={schema}
|
|
68
|
+
uiSchema={uiSchema}
|
|
69
|
+
registry={registry}
|
|
70
|
+
/>
|
|
71
|
+
)}
|
|
72
|
+
<label>
|
|
73
|
+
<input
|
|
74
|
+
type='checkbox'
|
|
75
|
+
id={id}
|
|
76
|
+
name={id}
|
|
77
|
+
checked={typeof value === 'undefined' ? false : value}
|
|
78
|
+
required={required}
|
|
79
|
+
disabled={disabled || readonly}
|
|
80
|
+
autoFocus={autofocus}
|
|
81
|
+
onChange={handleChange}
|
|
82
|
+
onBlur={handleBlur}
|
|
83
|
+
onFocus={handleFocus}
|
|
84
|
+
aria-describedby={ariaDescribedByIds<T>(id)}
|
|
85
|
+
/>
|
|
86
|
+
{labelValue(<span>{label}</span>, hideLabel)}
|
|
87
|
+
</label>
|
|
88
|
+
</div>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export default CheckboxWidget;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { ChangeEvent, FocusEvent, useCallback } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
ariaDescribedByIds,
|
|
4
|
+
enumOptionsDeselectValue,
|
|
5
|
+
enumOptionsIsSelected,
|
|
6
|
+
enumOptionsSelectValue,
|
|
7
|
+
enumOptionsValueForIndex,
|
|
8
|
+
optionId,
|
|
9
|
+
FormContextType,
|
|
10
|
+
WidgetProps,
|
|
11
|
+
RJSFSchema,
|
|
12
|
+
StrictRJSFSchema,
|
|
13
|
+
} from '@rjsf/utils';
|
|
14
|
+
|
|
15
|
+
/** The `CheckboxesWidget` is a widget for rendering checkbox groups.
|
|
16
|
+
* It is typically used to represent an array of enums.
|
|
17
|
+
*
|
|
18
|
+
* @param props - The `WidgetProps` for this component
|
|
19
|
+
*/
|
|
20
|
+
function CheckboxesWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>({
|
|
21
|
+
id,
|
|
22
|
+
disabled,
|
|
23
|
+
options: { inline = false, enumOptions, enumDisabled, emptyValue },
|
|
24
|
+
value,
|
|
25
|
+
autofocus = false,
|
|
26
|
+
readonly,
|
|
27
|
+
onChange,
|
|
28
|
+
onBlur,
|
|
29
|
+
onFocus,
|
|
30
|
+
}: WidgetProps<T, S, F>) {
|
|
31
|
+
const checkboxesValues = Array.isArray(value) ? value : [value];
|
|
32
|
+
|
|
33
|
+
const handleBlur = useCallback(
|
|
34
|
+
({ target: { value } }: FocusEvent<HTMLInputElement>) =>
|
|
35
|
+
onBlur(id, enumOptionsValueForIndex<S>(value, enumOptions, emptyValue)),
|
|
36
|
+
[onBlur, id]
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const handleFocus = useCallback(
|
|
40
|
+
({ target: { value } }: FocusEvent<HTMLInputElement>) =>
|
|
41
|
+
onFocus(id, enumOptionsValueForIndex<S>(value, enumOptions, emptyValue)),
|
|
42
|
+
[onFocus, id]
|
|
43
|
+
);
|
|
44
|
+
return (
|
|
45
|
+
<div className='checkboxes' id={id}>
|
|
46
|
+
{Array.isArray(enumOptions) &&
|
|
47
|
+
enumOptions.map((option, index) => {
|
|
48
|
+
const checked = enumOptionsIsSelected<S>(option.value, checkboxesValues);
|
|
49
|
+
const itemDisabled = Array.isArray(enumDisabled) && enumDisabled.indexOf(option.value) !== -1;
|
|
50
|
+
const disabledCls = disabled || itemDisabled || readonly ? 'disabled' : '';
|
|
51
|
+
|
|
52
|
+
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
|
|
53
|
+
if (event.target.checked) {
|
|
54
|
+
onChange(enumOptionsSelectValue<S>(index, checkboxesValues, enumOptions));
|
|
55
|
+
} else {
|
|
56
|
+
onChange(enumOptionsDeselectValue<S>(index, checkboxesValues, enumOptions));
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const checkbox = (
|
|
61
|
+
<span>
|
|
62
|
+
<input
|
|
63
|
+
type='checkbox'
|
|
64
|
+
id={optionId(id, index)}
|
|
65
|
+
name={id}
|
|
66
|
+
checked={checked}
|
|
67
|
+
value={String(index)}
|
|
68
|
+
disabled={disabled || itemDisabled || readonly}
|
|
69
|
+
autoFocus={autofocus && index === 0}
|
|
70
|
+
onChange={handleChange}
|
|
71
|
+
onBlur={handleBlur}
|
|
72
|
+
onFocus={handleFocus}
|
|
73
|
+
aria-describedby={ariaDescribedByIds<T>(id)}
|
|
74
|
+
/>
|
|
75
|
+
<span>{option.label}</span>
|
|
76
|
+
</span>
|
|
77
|
+
);
|
|
78
|
+
return inline ? (
|
|
79
|
+
<label key={index} className={`checkbox-inline ${disabledCls}`}>
|
|
80
|
+
{checkbox}
|
|
81
|
+
</label>
|
|
82
|
+
) : (
|
|
83
|
+
<div key={index} className={`checkbox ${disabledCls}`}>
|
|
84
|
+
<label>{checkbox}</label>
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
})}
|
|
88
|
+
</div>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export default CheckboxesWidget;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { getTemplate, FormContextType, RJSFSchema, StrictRJSFSchema, WidgetProps } from '@rjsf/utils';
|
|
2
|
+
|
|
3
|
+
/** The `ColorWidget` component uses the `BaseInputTemplate` changing the type to `color` and disables it when it is
|
|
4
|
+
* either disabled or readonly.
|
|
5
|
+
*
|
|
6
|
+
* @param props - The `WidgetProps` for this component
|
|
7
|
+
*/
|
|
8
|
+
export default function ColorWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
|
|
9
|
+
props: WidgetProps<T, S, F>
|
|
10
|
+
) {
|
|
11
|
+
const { disabled, readonly, options, registry } = props;
|
|
12
|
+
const BaseInputTemplate = getTemplate<'BaseInputTemplate', T, S, F>('BaseInputTemplate', registry, options);
|
|
13
|
+
return <BaseInputTemplate type='color' {...props} disabled={disabled || readonly} />;
|
|
14
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getTemplate,
|
|
3
|
+
localToUTC,
|
|
4
|
+
utcToLocal,
|
|
5
|
+
FormContextType,
|
|
6
|
+
RJSFSchema,
|
|
7
|
+
StrictRJSFSchema,
|
|
8
|
+
WidgetProps,
|
|
9
|
+
} from '@rjsf/utils';
|
|
10
|
+
|
|
11
|
+
/** The `DateTimeWidget` component uses the `BaseInputTemplate` changing the type to `datetime-local` and transforms
|
|
12
|
+
* the value to/from utc using the appropriate utility functions.
|
|
13
|
+
*
|
|
14
|
+
* @param props - The `WidgetProps` for this component
|
|
15
|
+
*/
|
|
16
|
+
export default function DateTimeWidget<
|
|
17
|
+
T = any,
|
|
18
|
+
S extends StrictRJSFSchema = RJSFSchema,
|
|
19
|
+
F extends FormContextType = any
|
|
20
|
+
>(props: WidgetProps<T, S, F>) {
|
|
21
|
+
const { onChange, value, options, registry } = props;
|
|
22
|
+
const BaseInputTemplate = getTemplate<'BaseInputTemplate', T, S, F>('BaseInputTemplate', registry, options);
|
|
23
|
+
return (
|
|
24
|
+
<BaseInputTemplate
|
|
25
|
+
type='datetime-local'
|
|
26
|
+
{...props}
|
|
27
|
+
value={utcToLocal(value)}
|
|
28
|
+
onChange={(value) => onChange(localToUTC(value))}
|
|
29
|
+
/>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import { getTemplate, FormContextType, RJSFSchema, StrictRJSFSchema, WidgetProps } from '@rjsf/utils';
|
|
3
|
+
|
|
4
|
+
/** The `DateWidget` component uses the `BaseInputTemplate` changing the type to `date` and transforms
|
|
5
|
+
* the value to undefined when it is falsy during the `onChange` handling.
|
|
6
|
+
*
|
|
7
|
+
* @param props - The `WidgetProps` for this component
|
|
8
|
+
*/
|
|
9
|
+
export default function DateWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
|
|
10
|
+
props: WidgetProps<T, S, F>
|
|
11
|
+
) {
|
|
12
|
+
const { onChange, options, registry } = props;
|
|
13
|
+
const BaseInputTemplate = getTemplate<'BaseInputTemplate', T, S, F>('BaseInputTemplate', registry, options);
|
|
14
|
+
const handleChange = useCallback((value: any) => onChange(value || undefined), [onChange]);
|
|
15
|
+
|
|
16
|
+
return <BaseInputTemplate type='date' {...props} onChange={handleChange} />;
|
|
17
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { getTemplate, FormContextType, RJSFSchema, StrictRJSFSchema, WidgetProps } from '@rjsf/utils';
|
|
2
|
+
|
|
3
|
+
/** The `EmailWidget` component uses the `BaseInputTemplate` changing the type to `email`.
|
|
4
|
+
*
|
|
5
|
+
* @param props - The `WidgetProps` for this component
|
|
6
|
+
*/
|
|
7
|
+
export default function EmailWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
|
|
8
|
+
props: WidgetProps<T, S, F>
|
|
9
|
+
) {
|
|
10
|
+
const { options, registry } = props;
|
|
11
|
+
const BaseInputTemplate = getTemplate<'BaseInputTemplate', T, S, F>('BaseInputTemplate', registry, options);
|
|
12
|
+
return <BaseInputTemplate type='email' {...props} />;
|
|
13
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { ChangeEvent, useCallback, useState } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
dataURItoBlob,
|
|
4
|
+
FormContextType,
|
|
5
|
+
getTemplate,
|
|
6
|
+
Registry,
|
|
7
|
+
RJSFSchema,
|
|
8
|
+
StrictRJSFSchema,
|
|
9
|
+
TranslatableString,
|
|
10
|
+
WidgetProps,
|
|
11
|
+
} from '@rjsf/utils';
|
|
12
|
+
import Markdown from 'markdown-to-jsx';
|
|
13
|
+
|
|
14
|
+
function addNameToDataURL(dataURL: string, name: string) {
|
|
15
|
+
if (dataURL === null) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
return dataURL.replace(';base64', `;name=${encodeURIComponent(name)};base64`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type FileInfoType = {
|
|
22
|
+
dataURL?: string | null;
|
|
23
|
+
name: string;
|
|
24
|
+
size: number;
|
|
25
|
+
type: string;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
function processFile(file: File): Promise<FileInfoType> {
|
|
29
|
+
const { name, size, type } = file;
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
const reader = new window.FileReader();
|
|
32
|
+
reader.onerror = reject;
|
|
33
|
+
reader.onload = (event) => {
|
|
34
|
+
if (typeof event.target?.result === 'string') {
|
|
35
|
+
resolve({
|
|
36
|
+
dataURL: addNameToDataURL(event.target.result, name),
|
|
37
|
+
name,
|
|
38
|
+
size,
|
|
39
|
+
type,
|
|
40
|
+
});
|
|
41
|
+
} else {
|
|
42
|
+
resolve({
|
|
43
|
+
dataURL: null,
|
|
44
|
+
name,
|
|
45
|
+
size,
|
|
46
|
+
type,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
reader.readAsDataURL(file);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function processFiles(files: FileList) {
|
|
55
|
+
return Promise.all(Array.from(files).map(processFile));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function FileInfoPreview<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>({
|
|
59
|
+
fileInfo,
|
|
60
|
+
registry,
|
|
61
|
+
}: {
|
|
62
|
+
fileInfo: FileInfoType;
|
|
63
|
+
registry: Registry<T, S, F>;
|
|
64
|
+
}) {
|
|
65
|
+
const { translateString } = registry;
|
|
66
|
+
const { dataURL, type, name } = fileInfo;
|
|
67
|
+
if (!dataURL) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (type.indexOf('image') !== -1) {
|
|
72
|
+
return <img src={dataURL} style={{ maxWidth: '100%' }} className='file-preview' />;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<>
|
|
77
|
+
{' '}
|
|
78
|
+
<a download={`preview-${name}`} href={dataURL} className='file-download'>
|
|
79
|
+
{translateString(TranslatableString.PreviewLabel)}
|
|
80
|
+
</a>
|
|
81
|
+
</>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function FilesInfo<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>({
|
|
86
|
+
filesInfo,
|
|
87
|
+
registry,
|
|
88
|
+
preview,
|
|
89
|
+
}: {
|
|
90
|
+
filesInfo: FileInfoType[];
|
|
91
|
+
registry: Registry<T, S, F>;
|
|
92
|
+
preview?: boolean;
|
|
93
|
+
}) {
|
|
94
|
+
if (filesInfo.length === 0) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
const { translateString } = registry;
|
|
98
|
+
return (
|
|
99
|
+
<ul className='file-info'>
|
|
100
|
+
{filesInfo.map((fileInfo, key) => {
|
|
101
|
+
const { name, size, type } = fileInfo;
|
|
102
|
+
return (
|
|
103
|
+
<li key={key}>
|
|
104
|
+
<Markdown>{translateString(TranslatableString.FilesInfo, [name, type, String(size)])}</Markdown>
|
|
105
|
+
{preview && <FileInfoPreview<T, S, F> fileInfo={fileInfo} registry={registry} />}
|
|
106
|
+
</li>
|
|
107
|
+
);
|
|
108
|
+
})}
|
|
109
|
+
</ul>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function extractFileInfo(dataURLs: string[]): FileInfoType[] {
|
|
114
|
+
return dataURLs
|
|
115
|
+
.filter((dataURL) => dataURL)
|
|
116
|
+
.map((dataURL) => {
|
|
117
|
+
const { blob, name } = dataURItoBlob(dataURL);
|
|
118
|
+
return {
|
|
119
|
+
dataURL,
|
|
120
|
+
name: name,
|
|
121
|
+
size: blob.size,
|
|
122
|
+
type: blob.type,
|
|
123
|
+
};
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* The `FileWidget` is a widget for rendering file upload fields.
|
|
129
|
+
* It is typically used with a string property with data-url format.
|
|
130
|
+
*/
|
|
131
|
+
function FileWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
|
|
132
|
+
props: WidgetProps<T, S, F>
|
|
133
|
+
) {
|
|
134
|
+
const { disabled, readonly, required, multiple, onChange, value, options, registry } = props;
|
|
135
|
+
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
|
+
|
|
140
|
+
const handleChange = useCallback(
|
|
141
|
+
(event: ChangeEvent<HTMLInputElement>) => {
|
|
142
|
+
if (!event.target.files) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
// Due to variances in themes, dealing with multiple files for the array case now happens one file at a time.
|
|
146
|
+
// This is because we don't pass `multiple` into the `BaseInputTemplate` anymore. Instead, we deal with the single
|
|
147
|
+
// file in each event and concatenate them together ourselves
|
|
148
|
+
processFiles(event.target.files).then((filesInfoEvent) => {
|
|
149
|
+
const newValue = filesInfoEvent.map((fileInfo) => fileInfo.dataURL);
|
|
150
|
+
if (multiple) {
|
|
151
|
+
setFilesInfo(filesInfo.concat(filesInfoEvent[0]));
|
|
152
|
+
onChange(value.concat(newValue[0]));
|
|
153
|
+
} else {
|
|
154
|
+
setFilesInfo(filesInfoEvent);
|
|
155
|
+
onChange(newValue[0]);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
},
|
|
159
|
+
[multiple, value, filesInfo, onChange]
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
return (
|
|
163
|
+
<div>
|
|
164
|
+
<BaseInputTemplate
|
|
165
|
+
{...props}
|
|
166
|
+
disabled={disabled || readonly}
|
|
167
|
+
type='file'
|
|
168
|
+
required={value ? false : required} // this turns off HTML required validation when a value exists
|
|
169
|
+
onChangeOverride={handleChange}
|
|
170
|
+
value=''
|
|
171
|
+
accept={options.accept ? String(options.accept) : undefined}
|
|
172
|
+
/>
|
|
173
|
+
<FilesInfo<T, S, F> filesInfo={filesInfo} registry={registry} preview={options.filePreview} />
|
|
174
|
+
</div>
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export default FileWidget;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { FormContextType, RJSFSchema, StrictRJSFSchema, WidgetProps } from '@rjsf/utils';
|
|
2
|
+
|
|
3
|
+
/** The `HiddenWidget` is a widget for rendering a hidden input field.
|
|
4
|
+
* It is typically used by setting type to "hidden".
|
|
5
|
+
*
|
|
6
|
+
* @param props - The `WidgetProps` for this component
|
|
7
|
+
*/
|
|
8
|
+
function HiddenWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>({
|
|
9
|
+
id,
|
|
10
|
+
value,
|
|
11
|
+
}: WidgetProps<T, S, F>) {
|
|
12
|
+
return <input type='hidden' id={id} name={id} value={typeof value === 'undefined' ? '' : value} />;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default HiddenWidget;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { getTemplate, FormContextType, RJSFSchema, StrictRJSFSchema, WidgetProps } from '@rjsf/utils';
|
|
2
|
+
|
|
3
|
+
/** The `PasswordWidget` component uses the `BaseInputTemplate` changing the type to `password`.
|
|
4
|
+
*
|
|
5
|
+
* @param props - The `WidgetProps` for this component
|
|
6
|
+
*/
|
|
7
|
+
export default function PasswordWidget<
|
|
8
|
+
T = any,
|
|
9
|
+
S extends StrictRJSFSchema = RJSFSchema,
|
|
10
|
+
F extends FormContextType = any
|
|
11
|
+
>(props: WidgetProps<T, S, F>) {
|
|
12
|
+
const { options, registry } = props;
|
|
13
|
+
const BaseInputTemplate = getTemplate<'BaseInputTemplate', T, S, F>('BaseInputTemplate', registry, options);
|
|
14
|
+
return <BaseInputTemplate type='password' {...props} />;
|
|
15
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { FocusEvent, useCallback } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
ariaDescribedByIds,
|
|
4
|
+
enumOptionsIsSelected,
|
|
5
|
+
enumOptionsValueForIndex,
|
|
6
|
+
optionId,
|
|
7
|
+
FormContextType,
|
|
8
|
+
RJSFSchema,
|
|
9
|
+
StrictRJSFSchema,
|
|
10
|
+
WidgetProps,
|
|
11
|
+
} from '@rjsf/utils';
|
|
12
|
+
|
|
13
|
+
/** The `RadioWidget` is a widget for rendering a radio group.
|
|
14
|
+
* It is typically used with a string property constrained with enum options.
|
|
15
|
+
*
|
|
16
|
+
* @param props - The `WidgetProps` for this component
|
|
17
|
+
*/
|
|
18
|
+
function RadioWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>({
|
|
19
|
+
options,
|
|
20
|
+
value,
|
|
21
|
+
required,
|
|
22
|
+
disabled,
|
|
23
|
+
readonly,
|
|
24
|
+
autofocus = false,
|
|
25
|
+
onBlur,
|
|
26
|
+
onFocus,
|
|
27
|
+
onChange,
|
|
28
|
+
id,
|
|
29
|
+
}: WidgetProps<T, S, F>) {
|
|
30
|
+
const { enumOptions, enumDisabled, inline, emptyValue } = options;
|
|
31
|
+
|
|
32
|
+
const handleBlur = useCallback(
|
|
33
|
+
({ target: { value } }: FocusEvent<HTMLInputElement>) =>
|
|
34
|
+
onBlur(id, enumOptionsValueForIndex<S>(value, enumOptions, emptyValue)),
|
|
35
|
+
[onBlur, id]
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
const handleFocus = useCallback(
|
|
39
|
+
({ target: { value } }: FocusEvent<HTMLInputElement>) =>
|
|
40
|
+
onFocus(id, enumOptionsValueForIndex<S>(value, enumOptions, emptyValue)),
|
|
41
|
+
[onFocus, id]
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div className='field-radio-group' id={id}>
|
|
46
|
+
{Array.isArray(enumOptions) &&
|
|
47
|
+
enumOptions.map((option, i) => {
|
|
48
|
+
const checked = enumOptionsIsSelected<S>(option.value, value);
|
|
49
|
+
const itemDisabled = Array.isArray(enumDisabled) && enumDisabled.indexOf(option.value) !== -1;
|
|
50
|
+
const disabledCls = disabled || itemDisabled || readonly ? 'disabled' : '';
|
|
51
|
+
|
|
52
|
+
const handleChange = () => onChange(option.value);
|
|
53
|
+
|
|
54
|
+
const radio = (
|
|
55
|
+
<span>
|
|
56
|
+
<input
|
|
57
|
+
type='radio'
|
|
58
|
+
id={optionId(id, i)}
|
|
59
|
+
checked={checked}
|
|
60
|
+
name={id}
|
|
61
|
+
required={required}
|
|
62
|
+
value={String(i)}
|
|
63
|
+
disabled={disabled || itemDisabled || readonly}
|
|
64
|
+
autoFocus={autofocus && i === 0}
|
|
65
|
+
onChange={handleChange}
|
|
66
|
+
onBlur={handleBlur}
|
|
67
|
+
onFocus={handleFocus}
|
|
68
|
+
aria-describedby={ariaDescribedByIds<T>(id)}
|
|
69
|
+
/>
|
|
70
|
+
<span>{option.label}</span>
|
|
71
|
+
</span>
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
return inline ? (
|
|
75
|
+
<label key={i} className={`radio-inline ${disabledCls}`}>
|
|
76
|
+
{radio}
|
|
77
|
+
</label>
|
|
78
|
+
) : (
|
|
79
|
+
<div key={i} className={`radio ${disabledCls}`}>
|
|
80
|
+
<label>{radio}</label>
|
|
81
|
+
</div>
|
|
82
|
+
);
|
|
83
|
+
})}
|
|
84
|
+
</div>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export default RadioWidget;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { FormContextType, RJSFSchema, StrictRJSFSchema, WidgetProps } from '@rjsf/utils';
|
|
2
|
+
|
|
3
|
+
/** The `RangeWidget` component uses the `BaseInputTemplate` changing the type to `range` and wrapping the result
|
|
4
|
+
* in a div, with the value along side it.
|
|
5
|
+
*
|
|
6
|
+
* @param props - The `WidgetProps` for this component
|
|
7
|
+
*/
|
|
8
|
+
export default function RangeWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
|
|
9
|
+
props: WidgetProps<T, S, F>
|
|
10
|
+
) {
|
|
11
|
+
const {
|
|
12
|
+
value,
|
|
13
|
+
registry: {
|
|
14
|
+
templates: { BaseInputTemplate },
|
|
15
|
+
},
|
|
16
|
+
} = props;
|
|
17
|
+
return (
|
|
18
|
+
<div className='field-range-wrapper'>
|
|
19
|
+
<BaseInputTemplate type='range' {...props} />
|
|
20
|
+
<span className='range-view'>{value}</span>
|
|
21
|
+
</div>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { ChangeEvent, FocusEvent, SyntheticEvent, useCallback } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
ariaDescribedByIds,
|
|
4
|
+
enumOptionsIndexForValue,
|
|
5
|
+
enumOptionsValueForIndex,
|
|
6
|
+
FormContextType,
|
|
7
|
+
RJSFSchema,
|
|
8
|
+
StrictRJSFSchema,
|
|
9
|
+
WidgetProps,
|
|
10
|
+
} from '@rjsf/utils';
|
|
11
|
+
|
|
12
|
+
function getValue(event: SyntheticEvent<HTMLSelectElement>, multiple: boolean) {
|
|
13
|
+
if (multiple) {
|
|
14
|
+
return Array.from((event.target as HTMLSelectElement).options)
|
|
15
|
+
.slice()
|
|
16
|
+
.filter((o) => o.selected)
|
|
17
|
+
.map((o) => o.value);
|
|
18
|
+
}
|
|
19
|
+
return (event.target as HTMLSelectElement).value;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** The `SelectWidget` is a widget for rendering dropdowns.
|
|
23
|
+
* It is typically used with string properties constrained with enum options.
|
|
24
|
+
*
|
|
25
|
+
* @param props - The `WidgetProps` for this component
|
|
26
|
+
*/
|
|
27
|
+
function SelectWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>({
|
|
28
|
+
schema,
|
|
29
|
+
id,
|
|
30
|
+
options,
|
|
31
|
+
value,
|
|
32
|
+
required,
|
|
33
|
+
disabled,
|
|
34
|
+
readonly,
|
|
35
|
+
multiple = false,
|
|
36
|
+
autofocus = false,
|
|
37
|
+
onChange,
|
|
38
|
+
onBlur,
|
|
39
|
+
onFocus,
|
|
40
|
+
placeholder,
|
|
41
|
+
}: WidgetProps<T, S, F>) {
|
|
42
|
+
const { enumOptions, enumDisabled, emptyValue: optEmptyVal } = options;
|
|
43
|
+
const emptyValue = multiple ? [] : '';
|
|
44
|
+
|
|
45
|
+
const handleFocus = useCallback(
|
|
46
|
+
(event: FocusEvent<HTMLSelectElement>) => {
|
|
47
|
+
const newValue = getValue(event, multiple);
|
|
48
|
+
return onFocus(id, enumOptionsValueForIndex<S>(newValue, enumOptions, optEmptyVal));
|
|
49
|
+
},
|
|
50
|
+
[onFocus, id, schema, multiple, options]
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const handleBlur = useCallback(
|
|
54
|
+
(event: FocusEvent<HTMLSelectElement>) => {
|
|
55
|
+
const newValue = getValue(event, multiple);
|
|
56
|
+
return onBlur(id, enumOptionsValueForIndex<S>(newValue, enumOptions, optEmptyVal));
|
|
57
|
+
},
|
|
58
|
+
[onBlur, id, schema, multiple, options]
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
const handleChange = useCallback(
|
|
62
|
+
(event: ChangeEvent<HTMLSelectElement>) => {
|
|
63
|
+
const newValue = getValue(event, multiple);
|
|
64
|
+
return onChange(enumOptionsValueForIndex<S>(newValue, enumOptions, optEmptyVal));
|
|
65
|
+
},
|
|
66
|
+
[onChange, schema, multiple, options]
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const selectedIndexes = enumOptionsIndexForValue<S>(value, enumOptions, multiple);
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<select
|
|
73
|
+
id={id}
|
|
74
|
+
name={id}
|
|
75
|
+
multiple={multiple}
|
|
76
|
+
className='form-control'
|
|
77
|
+
value={typeof selectedIndexes === 'undefined' ? emptyValue : selectedIndexes}
|
|
78
|
+
required={required}
|
|
79
|
+
disabled={disabled || readonly}
|
|
80
|
+
autoFocus={autofocus}
|
|
81
|
+
onBlur={handleBlur}
|
|
82
|
+
onFocus={handleFocus}
|
|
83
|
+
onChange={handleChange}
|
|
84
|
+
aria-describedby={ariaDescribedByIds<T>(id)}
|
|
85
|
+
>
|
|
86
|
+
{!multiple && schema.default === undefined && <option value=''>{placeholder}</option>}
|
|
87
|
+
{Array.isArray(enumOptions) &&
|
|
88
|
+
enumOptions.map(({ value, label }, i) => {
|
|
89
|
+
const disabled = enumDisabled && enumDisabled.indexOf(value) !== -1;
|
|
90
|
+
return (
|
|
91
|
+
<option key={i} value={String(i)} disabled={disabled}>
|
|
92
|
+
{label}
|
|
93
|
+
</option>
|
|
94
|
+
);
|
|
95
|
+
})}
|
|
96
|
+
</select>
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export default SelectWidget;
|