@rjsf/mantine 6.0.0-beta.14
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/README.md +153 -0
- package/dist/index.js +1918 -0
- package/dist/index.js.map +7 -0
- package/dist/mantine.esm.js +1967 -0
- package/dist/mantine.esm.js.map +7 -0
- package/dist/mantine.umd.js +1714 -0
- package/lib/Form/index.d.ts +6 -0
- package/lib/Form/index.js +7 -0
- package/lib/Form/index.js.map +1 -0
- package/lib/Theme/index.d.ts +5 -0
- package/lib/Theme/index.js +10 -0
- package/lib/Theme/index.js.map +1 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.js +7 -0
- package/lib/index.js.map +1 -0
- package/lib/templates/ArrayFieldItemTemplate.d.ts +6 -0
- package/lib/templates/ArrayFieldItemTemplate.js +14 -0
- package/lib/templates/ArrayFieldItemTemplate.js.map +1 -0
- package/lib/templates/ArrayFieldTemplate.d.ts +6 -0
- package/lib/templates/ArrayFieldTemplate.js +20 -0
- package/lib/templates/ArrayFieldTemplate.js.map +1 -0
- package/lib/templates/ArrayFieldTitleTemplate.d.ts +7 -0
- package/lib/templates/ArrayFieldTitleTemplate.js +18 -0
- package/lib/templates/ArrayFieldTitleTemplate.js.map +1 -0
- package/lib/templates/BaseInputTemplate.d.ts +8 -0
- package/lib/templates/BaseInputTemplate.js +36 -0
- package/lib/templates/BaseInputTemplate.js.map +1 -0
- package/lib/templates/ButtonTemplates/AddButton.d.ts +4 -0
- package/lib/templates/ButtonTemplates/AddButton.js +11 -0
- package/lib/templates/ButtonTemplates/AddButton.js.map +1 -0
- package/lib/templates/ButtonTemplates/IconButton.d.ts +8 -0
- package/lib/templates/ButtonTemplates/IconButton.js +25 -0
- package/lib/templates/ButtonTemplates/IconButton.js.map +1 -0
- package/lib/templates/ButtonTemplates/SubmitButton.d.ts +4 -0
- package/lib/templates/ButtonTemplates/SubmitButton.js +13 -0
- package/lib/templates/ButtonTemplates/SubmitButton.js.map +1 -0
- package/lib/templates/ButtonTemplates/index.d.ts +3 -0
- package/lib/templates/ButtonTemplates/index.js +15 -0
- package/lib/templates/ButtonTemplates/index.js.map +1 -0
- package/lib/templates/DescriptionField.d.ts +6 -0
- package/lib/templates/DescriptionField.js +15 -0
- package/lib/templates/DescriptionField.js.map +1 -0
- package/lib/templates/ErrorList.d.ts +6 -0
- package/lib/templates/ErrorList.js +13 -0
- package/lib/templates/ErrorList.js.map +1 -0
- package/lib/templates/FieldErrorTemplate.d.ts +6 -0
- package/lib/templates/FieldErrorTemplate.js +16 -0
- package/lib/templates/FieldErrorTemplate.js.map +1 -0
- package/lib/templates/FieldHelpTemplate.d.ts +6 -0
- package/lib/templates/FieldHelpTemplate.js +13 -0
- package/lib/templates/FieldHelpTemplate.js.map +1 -0
- package/lib/templates/FieldTemplate.d.ts +7 -0
- package/lib/templates/FieldTemplate.js +18 -0
- package/lib/templates/FieldTemplate.js.map +1 -0
- package/lib/templates/GridTemplate.d.ts +7 -0
- package/lib/templates/GridTemplate.js +20 -0
- package/lib/templates/GridTemplate.js.map +1 -0
- package/lib/templates/MultiSchemaFieldTemplate.d.ts +2 -0
- package/lib/templates/MultiSchemaFieldTemplate.js +6 -0
- package/lib/templates/MultiSchemaFieldTemplate.js.map +1 -0
- package/lib/templates/ObjectFieldTemplate.d.ts +8 -0
- package/lib/templates/ObjectFieldTemplate.js +24 -0
- package/lib/templates/ObjectFieldTemplate.js.map +1 -0
- package/lib/templates/TitleField.d.ts +6 -0
- package/lib/templates/TitleField.js +11 -0
- package/lib/templates/TitleField.js.map +1 -0
- package/lib/templates/WrapIfAdditionalTemplate.d.ts +7 -0
- package/lib/templates/WrapIfAdditionalTemplate.js +29 -0
- package/lib/templates/WrapIfAdditionalTemplate.js.map +1 -0
- package/lib/templates/icons.d.ts +11 -0
- package/lib/templates/icons.js +20 -0
- package/lib/templates/icons.js.map +1 -0
- package/lib/templates/index.d.ts +4 -0
- package/lib/templates/index.js +36 -0
- package/lib/templates/index.js.map +1 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/lib/utils.d.ts +2 -0
- package/lib/utils.js +35 -0
- package/lib/utils.js.map +1 -0
- package/lib/widgets/CheckboxWidget.d.ts +8 -0
- package/lib/widgets/CheckboxWidget.js +33 -0
- package/lib/widgets/CheckboxWidget.js.map +1 -0
- package/lib/widgets/CheckboxesWidget.d.ts +7 -0
- package/lib/widgets/CheckboxesWidget.js +33 -0
- package/lib/widgets/CheckboxesWidget.js.map +1 -0
- package/lib/widgets/ColorWidget.d.ts +6 -0
- package/lib/widgets/ColorWidget.js +28 -0
- package/lib/widgets/ColorWidget.js.map +1 -0
- package/lib/widgets/DateTime/AltDateTimeWidget.d.ts +13 -0
- package/lib/widgets/DateTime/AltDateTimeWidget.js +16 -0
- package/lib/widgets/DateTime/AltDateTimeWidget.js.map +1 -0
- package/lib/widgets/DateTime/AltDateWidget.d.ts +11 -0
- package/lib/widgets/DateTime/AltDateWidget.js +51 -0
- package/lib/widgets/DateTime/AltDateWidget.js.map +1 -0
- package/lib/widgets/DateTime/DateTimeInput.d.ts +5 -0
- package/lib/widgets/DateTime/DateTimeInput.js +39 -0
- package/lib/widgets/DateTime/DateTimeInput.js.map +1 -0
- package/lib/widgets/DateTime/DateTimeWidget.d.ts +6 -0
- package/lib/widgets/DateTime/DateTimeWidget.js +11 -0
- package/lib/widgets/DateTime/DateTimeWidget.js.map +1 -0
- package/lib/widgets/DateTime/DateWidget.d.ts +6 -0
- package/lib/widgets/DateTime/DateWidget.js +11 -0
- package/lib/widgets/DateTime/DateWidget.js.map +1 -0
- package/lib/widgets/DateTime/TimeWidget.d.ts +6 -0
- package/lib/widgets/DateTime/TimeWidget.js +27 -0
- package/lib/widgets/DateTime/TimeWidget.js.map +1 -0
- package/lib/widgets/DateTime/index.d.ts +5 -0
- package/lib/widgets/DateTime/index.js +6 -0
- package/lib/widgets/DateTime/index.js.map +1 -0
- package/lib/widgets/FileWidget.d.ts +7 -0
- package/lib/widgets/FileWidget.js +106 -0
- package/lib/widgets/FileWidget.js.map +1 -0
- package/lib/widgets/PasswordWidget.d.ts +7 -0
- package/lib/widgets/PasswordWidget.js +30 -0
- package/lib/widgets/PasswordWidget.js.map +1 -0
- package/lib/widgets/RadioWidget.d.ts +7 -0
- package/lib/widgets/RadioWidget.js +33 -0
- package/lib/widgets/RadioWidget.js.map +1 -0
- package/lib/widgets/RangeWidget.d.ts +7 -0
- package/lib/widgets/RangeWidget.js +34 -0
- package/lib/widgets/RangeWidget.js.map +1 -0
- package/lib/widgets/SelectWidget.d.ts +7 -0
- package/lib/widgets/SelectWidget.js +45 -0
- package/lib/widgets/SelectWidget.js.map +1 -0
- package/lib/widgets/TextareaWidget.d.ts +7 -0
- package/lib/widgets/TextareaWidget.js +30 -0
- package/lib/widgets/TextareaWidget.js.map +1 -0
- package/lib/widgets/index.d.ts +4 -0
- package/lib/widgets/index.js +34 -0
- package/lib/widgets/index.js.map +1 -0
- package/package.json +110 -0
- package/src/Form/index.ts +15 -0
- package/src/Theme/index.ts +18 -0
- package/src/index.ts +8 -0
- package/src/templates/ArrayFieldItemTemplate.tsx +40 -0
- package/src/templates/ArrayFieldTemplate.tsx +103 -0
- package/src/templates/ArrayFieldTitleTemplate.tsx +33 -0
- package/src/templates/BaseInputTemplate.tsx +134 -0
- package/src/templates/ButtonTemplates/AddButton.tsx +17 -0
- package/src/templates/ButtonTemplates/IconButton.tsx +87 -0
- package/src/templates/ButtonTemplates/SubmitButton.tsx +20 -0
- package/src/templates/ButtonTemplates/index.ts +21 -0
- package/src/templates/DescriptionField.tsx +24 -0
- package/src/templates/ErrorList.tsx +36 -0
- package/src/templates/FieldErrorTemplate.tsx +27 -0
- package/src/templates/FieldHelpTemplate.tsx +22 -0
- package/src/templates/FieldTemplate.tsx +66 -0
- package/src/templates/GridTemplate.tsx +30 -0
- package/src/templates/MultiSchemaFieldTemplate.tsx +15 -0
- package/src/templates/ObjectFieldTemplate.tsx +104 -0
- package/src/templates/TitleField.tsx +17 -0
- package/src/templates/WrapIfAdditionalTemplate.tsx +99 -0
- package/src/templates/icons.tsx +141 -0
- package/src/templates/index.ts +43 -0
- package/src/tsconfig.json +23 -0
- package/src/utils.ts +37 -0
- package/src/widgets/CheckboxWidget.tsx +110 -0
- package/src/widgets/CheckboxesWidget.tsx +112 -0
- package/src/widgets/ColorWidget.tsx +85 -0
- package/src/widgets/DateTime/AltDateTimeWidget.tsx +22 -0
- package/src/widgets/DateTime/AltDateWidget.tsx +139 -0
- package/src/widgets/DateTime/DateTimeInput.tsx +97 -0
- package/src/widgets/DateTime/DateTimeWidget.tsx +24 -0
- package/src/widgets/DateTime/DateWidget.tsx +22 -0
- package/src/widgets/DateTime/TimeWidget.tsx +83 -0
- package/src/widgets/DateTime/index.ts +5 -0
- package/src/widgets/FileWidget.tsx +176 -0
- package/src/widgets/PasswordWidget.tsx +88 -0
- package/src/widgets/RadioWidget.tsx +103 -0
- package/src/widgets/RangeWidget.tsx +95 -0
- package/src/widgets/SelectWidget.tsx +109 -0
- package/src/widgets/TextareaWidget.tsx +87 -0
- package/src/widgets/index.ts +42 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
ariaDescribedByIds,
|
|
4
|
+
dateRangeOptions,
|
|
5
|
+
parseDateString,
|
|
6
|
+
toDateString,
|
|
7
|
+
getDateElementProps,
|
|
8
|
+
titleId,
|
|
9
|
+
DateObject,
|
|
10
|
+
type DateElementFormat,
|
|
11
|
+
FormContextType,
|
|
12
|
+
RJSFSchema,
|
|
13
|
+
StrictRJSFSchema,
|
|
14
|
+
TranslatableString,
|
|
15
|
+
WidgetProps,
|
|
16
|
+
} from '@rjsf/utils';
|
|
17
|
+
import { Flex, Box, Group, Button, Select, Input } from '@mantine/core';
|
|
18
|
+
|
|
19
|
+
function readyForChange(state: DateObject) {
|
|
20
|
+
return Object.values(state).every((value) => value !== -1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** The `AltDateWidget` is an alternative widget for rendering date properties.
|
|
24
|
+
* @param props - The `WidgetProps` for this component
|
|
25
|
+
*/
|
|
26
|
+
export default function AltDateWidget<
|
|
27
|
+
T = any,
|
|
28
|
+
S extends StrictRJSFSchema = RJSFSchema,
|
|
29
|
+
F extends FormContextType = any,
|
|
30
|
+
>(props: WidgetProps<T, S, F>) {
|
|
31
|
+
const {
|
|
32
|
+
id,
|
|
33
|
+
value,
|
|
34
|
+
required,
|
|
35
|
+
disabled,
|
|
36
|
+
readonly,
|
|
37
|
+
label,
|
|
38
|
+
hideLabel,
|
|
39
|
+
rawErrors,
|
|
40
|
+
options,
|
|
41
|
+
onChange,
|
|
42
|
+
showTime = false,
|
|
43
|
+
registry,
|
|
44
|
+
} = props;
|
|
45
|
+
|
|
46
|
+
const { translateString } = registry;
|
|
47
|
+
const [state, setState] = useState(parseDateString(value, showTime));
|
|
48
|
+
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
setState(parseDateString(value, showTime));
|
|
51
|
+
}, [showTime, value]);
|
|
52
|
+
|
|
53
|
+
const handleChange = useCallback(
|
|
54
|
+
(property: keyof DateObject, nextValue: any) => {
|
|
55
|
+
const nextState = {
|
|
56
|
+
...state,
|
|
57
|
+
[property]: typeof nextValue === 'undefined' ? -1 : nextValue,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
if (readyForChange(nextState)) {
|
|
61
|
+
onChange(toDateString(nextState, showTime));
|
|
62
|
+
} else {
|
|
63
|
+
setState(nextState);
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
[state, onChange, showTime],
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const handleSetNow = useCallback(() => {
|
|
70
|
+
if (!disabled && !readonly) {
|
|
71
|
+
const nextState = parseDateString(new Date().toJSON(), showTime);
|
|
72
|
+
onChange(toDateString(nextState, showTime));
|
|
73
|
+
}
|
|
74
|
+
}, [disabled, readonly, showTime, onChange]);
|
|
75
|
+
|
|
76
|
+
const handleClear = useCallback(() => {
|
|
77
|
+
if (!disabled && !readonly) {
|
|
78
|
+
onChange('');
|
|
79
|
+
}
|
|
80
|
+
}, [disabled, readonly, onChange]);
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<>
|
|
84
|
+
{!hideLabel && !!label && (
|
|
85
|
+
<Input.Label id={titleId<T>(id)} required={required}>
|
|
86
|
+
{label}
|
|
87
|
+
</Input.Label>
|
|
88
|
+
)}
|
|
89
|
+
<Flex gap='xs' align='center' wrap='nowrap'>
|
|
90
|
+
{getDateElementProps(
|
|
91
|
+
state,
|
|
92
|
+
showTime,
|
|
93
|
+
options.yearsRange as [number, number] | undefined,
|
|
94
|
+
options.format as DateElementFormat | undefined,
|
|
95
|
+
).map((elemProps, i) => {
|
|
96
|
+
const elemId = id + '_' + elemProps.type;
|
|
97
|
+
return (
|
|
98
|
+
<Box key={i}>
|
|
99
|
+
<Select
|
|
100
|
+
id={elemId}
|
|
101
|
+
name={elemId}
|
|
102
|
+
placeholder={elemProps.type}
|
|
103
|
+
disabled={disabled || readonly}
|
|
104
|
+
data={dateRangeOptions<S>(elemProps.range[0], elemProps.range[1]).map((item) => item.value.toString())}
|
|
105
|
+
value={!elemProps.value || elemProps.value < 0 ? null : elemProps.value.toString()}
|
|
106
|
+
onChange={(v) => handleChange(elemProps.type as keyof DateObject, v)}
|
|
107
|
+
searchable={false}
|
|
108
|
+
allowDeselect={false}
|
|
109
|
+
comboboxProps={{ withinPortal: false }}
|
|
110
|
+
aria-describedby={ariaDescribedByIds<T>(elemId)}
|
|
111
|
+
/>
|
|
112
|
+
</Box>
|
|
113
|
+
);
|
|
114
|
+
})}
|
|
115
|
+
<Group wrap='nowrap' gap={3}>
|
|
116
|
+
{(options.hideNowButton !== 'undefined' ? !options.hideNowButton : true) && (
|
|
117
|
+
<Button variant='subtle' size='xs' onClick={handleSetNow}>
|
|
118
|
+
{translateString(TranslatableString.NowLabel)}
|
|
119
|
+
</Button>
|
|
120
|
+
)}
|
|
121
|
+
{(options.hideClearButton !== 'undefined' ? !options.hideClearButton : true) && (
|
|
122
|
+
<Button variant='subtle' size='xs' onClick={handleClear}>
|
|
123
|
+
{translateString(TranslatableString.ClearLabel)}
|
|
124
|
+
</Button>
|
|
125
|
+
)}
|
|
126
|
+
</Group>
|
|
127
|
+
</Flex>
|
|
128
|
+
{rawErrors &&
|
|
129
|
+
rawErrors?.length > 0 &&
|
|
130
|
+
rawErrors.map((error: string, index: number) => (
|
|
131
|
+
<Input.Error key={`alt-date-widget-input-errors-${index}`}>{error}</Input.Error>
|
|
132
|
+
))}
|
|
133
|
+
</>
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
AltDateWidget.defaultProps = {
|
|
138
|
+
showTime: false,
|
|
139
|
+
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
ariaDescribedByIds,
|
|
4
|
+
FormContextType,
|
|
5
|
+
labelValue,
|
|
6
|
+
RJSFSchema,
|
|
7
|
+
StrictRJSFSchema,
|
|
8
|
+
WidgetProps,
|
|
9
|
+
} from '@rjsf/utils';
|
|
10
|
+
import dayjs from 'dayjs';
|
|
11
|
+
import { DateInput } from '@mantine/dates';
|
|
12
|
+
|
|
13
|
+
const dateParser = (input: string, format: string) => {
|
|
14
|
+
if (!input) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
const d = dayjs(input, format);
|
|
18
|
+
return d.isValid() ? d.toDate() : null;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const dateFormat = (date?: Date, format?: string) => {
|
|
22
|
+
if (!date) {
|
|
23
|
+
return '';
|
|
24
|
+
}
|
|
25
|
+
return dayjs(date).format(format || 'YYYY-MM-DD');
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/** The `DateTimeInput` is a base component that used by other Date-Time widget components.
|
|
29
|
+
* @param props - The `WidgetProps` for this component
|
|
30
|
+
*/
|
|
31
|
+
export default function DateTimeInput<
|
|
32
|
+
T = any,
|
|
33
|
+
S extends StrictRJSFSchema = RJSFSchema,
|
|
34
|
+
F extends FormContextType = any,
|
|
35
|
+
>(props: WidgetProps<T, S, F>) {
|
|
36
|
+
const {
|
|
37
|
+
id,
|
|
38
|
+
name,
|
|
39
|
+
value,
|
|
40
|
+
placeholder,
|
|
41
|
+
required,
|
|
42
|
+
disabled,
|
|
43
|
+
readonly,
|
|
44
|
+
autofocus,
|
|
45
|
+
label,
|
|
46
|
+
hideLabel,
|
|
47
|
+
rawErrors,
|
|
48
|
+
options,
|
|
49
|
+
onChange,
|
|
50
|
+
onBlur,
|
|
51
|
+
onFocus,
|
|
52
|
+
valueFormat,
|
|
53
|
+
displayFormat,
|
|
54
|
+
} = props;
|
|
55
|
+
|
|
56
|
+
const handleChange = useCallback(
|
|
57
|
+
(nextValue: any) => {
|
|
58
|
+
onChange(dateFormat(nextValue, valueFormat as string));
|
|
59
|
+
},
|
|
60
|
+
[onChange, valueFormat],
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const handleBlur = useCallback(() => {
|
|
64
|
+
if (onBlur) {
|
|
65
|
+
onBlur(id, value);
|
|
66
|
+
}
|
|
67
|
+
}, [onBlur, id, value]);
|
|
68
|
+
|
|
69
|
+
const handleFocus = useCallback(() => {
|
|
70
|
+
if (onFocus) {
|
|
71
|
+
onFocus(id, value);
|
|
72
|
+
}
|
|
73
|
+
}, [onFocus, id, value]);
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<DateInput
|
|
77
|
+
id={id}
|
|
78
|
+
name={name}
|
|
79
|
+
value={dateParser(value, valueFormat as string)}
|
|
80
|
+
dateParser={(v) => dateParser(v, displayFormat as string)}
|
|
81
|
+
placeholder={placeholder || undefined}
|
|
82
|
+
required={required}
|
|
83
|
+
disabled={disabled || readonly}
|
|
84
|
+
autoFocus={autofocus}
|
|
85
|
+
label={labelValue(label || undefined, hideLabel, false)}
|
|
86
|
+
onChange={handleChange}
|
|
87
|
+
onBlur={handleBlur}
|
|
88
|
+
onFocus={handleFocus}
|
|
89
|
+
error={rawErrors && rawErrors.length > 0 ? rawErrors.join('\n') : undefined}
|
|
90
|
+
{...options}
|
|
91
|
+
aria-describedby={ariaDescribedByIds<T>(id)}
|
|
92
|
+
popoverProps={{ withinPortal: false }}
|
|
93
|
+
classNames={typeof options?.classNames === 'object' ? options.classNames : undefined}
|
|
94
|
+
valueFormat={displayFormat}
|
|
95
|
+
/>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { FormContextType, RJSFSchema, StrictRJSFSchema, WidgetProps } from '@rjsf/utils';
|
|
2
|
+
|
|
3
|
+
import DateTimeInput from './DateTimeInput';
|
|
4
|
+
|
|
5
|
+
/** The `DateWidget` component uses the `DateTimeInput` changing the valueFormat to show `datetime`
|
|
6
|
+
*
|
|
7
|
+
* @param props - The `WidgetProps` for this component
|
|
8
|
+
*/
|
|
9
|
+
export default function DateTimeWidget<
|
|
10
|
+
T = any,
|
|
11
|
+
S extends StrictRJSFSchema = RJSFSchema,
|
|
12
|
+
F extends FormContextType = any,
|
|
13
|
+
>(props: WidgetProps<T, S, F>) {
|
|
14
|
+
const { valueFormat = 'YYYY-MM-DD HH:mm:ss', displayFormat, ...otherOptions } = props.options;
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<DateTimeInput
|
|
18
|
+
{...props}
|
|
19
|
+
options={otherOptions}
|
|
20
|
+
valueFormat={valueFormat}
|
|
21
|
+
displayFormat={displayFormat || valueFormat}
|
|
22
|
+
/>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { FormContextType, RJSFSchema, StrictRJSFSchema, WidgetProps } from '@rjsf/utils';
|
|
2
|
+
|
|
3
|
+
import DateTimeInput from './DateTimeInput';
|
|
4
|
+
|
|
5
|
+
/** The `DateWidget` component uses the `DateTimeInput` changing the valueFormat to show `date`
|
|
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 { valueFormat = 'YYYY-MM-DD', displayFormat, ...otherOptions } = props.options;
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<DateTimeInput
|
|
16
|
+
{...props}
|
|
17
|
+
options={otherOptions}
|
|
18
|
+
valueFormat={valueFormat}
|
|
19
|
+
displayFormat={displayFormat || valueFormat}
|
|
20
|
+
/>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { ChangeEvent, FocusEvent, useCallback } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
FormContextType,
|
|
4
|
+
RJSFSchema,
|
|
5
|
+
StrictRJSFSchema,
|
|
6
|
+
WidgetProps,
|
|
7
|
+
labelValue,
|
|
8
|
+
ariaDescribedByIds,
|
|
9
|
+
} from '@rjsf/utils';
|
|
10
|
+
import { TimeInput } from '@mantine/dates';
|
|
11
|
+
|
|
12
|
+
/** The `TimeWidget` component uses the `TimeInput` component from `@mantine/dates` for rendering.
|
|
13
|
+
*
|
|
14
|
+
* @param props - The `WidgetProps` for this component
|
|
15
|
+
*/
|
|
16
|
+
export default function TimeWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
|
|
17
|
+
props: WidgetProps<T, S, F>,
|
|
18
|
+
) {
|
|
19
|
+
const {
|
|
20
|
+
id,
|
|
21
|
+
name,
|
|
22
|
+
value,
|
|
23
|
+
placeholder,
|
|
24
|
+
required,
|
|
25
|
+
disabled,
|
|
26
|
+
readonly,
|
|
27
|
+
autofocus,
|
|
28
|
+
label,
|
|
29
|
+
hideLabel,
|
|
30
|
+
rawErrors,
|
|
31
|
+
options,
|
|
32
|
+
onChange,
|
|
33
|
+
onBlur,
|
|
34
|
+
onFocus,
|
|
35
|
+
} = props;
|
|
36
|
+
|
|
37
|
+
const emptyValue = options.emptyValue || '';
|
|
38
|
+
|
|
39
|
+
const handleChange = useCallback(
|
|
40
|
+
(e: ChangeEvent<HTMLInputElement>) => {
|
|
41
|
+
onChange(e.target.value === '' ? emptyValue : e.target.value);
|
|
42
|
+
},
|
|
43
|
+
[onChange, emptyValue],
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const handleBlur = useCallback(
|
|
47
|
+
({ target }: FocusEvent<HTMLInputElement>) => {
|
|
48
|
+
if (onBlur) {
|
|
49
|
+
onBlur(id, target && target.value);
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
[onBlur, id],
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
const handleFocus = useCallback(
|
|
56
|
+
({ target }: FocusEvent<HTMLInputElement>) => {
|
|
57
|
+
if (onFocus) {
|
|
58
|
+
onFocus(id, target && target.value);
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
[onFocus, id],
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<TimeInput
|
|
66
|
+
id={id}
|
|
67
|
+
name={name}
|
|
68
|
+
value={value || ''}
|
|
69
|
+
placeholder={placeholder || undefined}
|
|
70
|
+
required={required}
|
|
71
|
+
disabled={disabled || readonly}
|
|
72
|
+
autoFocus={autofocus}
|
|
73
|
+
label={labelValue(label || undefined, hideLabel, false)}
|
|
74
|
+
onChange={handleChange}
|
|
75
|
+
onBlur={handleBlur}
|
|
76
|
+
onFocus={handleFocus}
|
|
77
|
+
error={rawErrors && rawErrors.length > 0 ? rawErrors.join('\n') : undefined}
|
|
78
|
+
{...options}
|
|
79
|
+
aria-describedby={ariaDescribedByIds<T>(id)}
|
|
80
|
+
classNames={typeof options?.classNames === 'object' ? options.classNames : undefined}
|
|
81
|
+
/>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { default as AltDateTimeWidget } from './AltDateTimeWidget';
|
|
2
|
+
export { default as AltDateWidget } from './AltDateWidget';
|
|
3
|
+
export { default as DateWidget } from './DateWidget';
|
|
4
|
+
export { default as DateTimeWidget } from './DateTimeWidget';
|
|
5
|
+
export { default as TimeWidget } from './TimeWidget';
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
dataURItoBlob,
|
|
4
|
+
ariaDescribedByIds,
|
|
5
|
+
FormContextType,
|
|
6
|
+
labelValue,
|
|
7
|
+
RJSFSchema,
|
|
8
|
+
StrictRJSFSchema,
|
|
9
|
+
WidgetProps,
|
|
10
|
+
} from '@rjsf/utils';
|
|
11
|
+
import { FileInput, Pill } from '@mantine/core';
|
|
12
|
+
|
|
13
|
+
import { cleanupOptions } from '../utils';
|
|
14
|
+
|
|
15
|
+
function addNameToDataURL(dataURL: string, name: string) {
|
|
16
|
+
if (dataURL === null) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
return dataURL.replace(';base64', `;name=${encodeURIComponent(name)};base64`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
type FileInfoType = {
|
|
23
|
+
dataURL?: string | null;
|
|
24
|
+
name: string;
|
|
25
|
+
size: number;
|
|
26
|
+
type: string;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
function processFile(file: File): Promise<FileInfoType> {
|
|
30
|
+
const { name, size, type } = file;
|
|
31
|
+
return new Promise((resolve, reject) => {
|
|
32
|
+
const reader = new window.FileReader();
|
|
33
|
+
reader.onerror = reject;
|
|
34
|
+
reader.onload = (event) => {
|
|
35
|
+
if (typeof event.target?.result === 'string') {
|
|
36
|
+
resolve({
|
|
37
|
+
dataURL: addNameToDataURL(event.target.result, name),
|
|
38
|
+
name,
|
|
39
|
+
size,
|
|
40
|
+
type,
|
|
41
|
+
});
|
|
42
|
+
} else {
|
|
43
|
+
resolve({
|
|
44
|
+
dataURL: null,
|
|
45
|
+
name,
|
|
46
|
+
size,
|
|
47
|
+
type,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
reader.readAsDataURL(file);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function processFiles(files: FileList) {
|
|
56
|
+
return Promise.all(Array.from(files).map(processFile));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function extractFileInfo(dataURLs: string[]): FileInfoType[] {
|
|
60
|
+
return dataURLs.reduce((acc, dataURL) => {
|
|
61
|
+
if (!dataURL) {
|
|
62
|
+
return acc;
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
const { blob, name } = dataURItoBlob(dataURL);
|
|
66
|
+
return [
|
|
67
|
+
...acc,
|
|
68
|
+
{
|
|
69
|
+
dataURL,
|
|
70
|
+
name: name,
|
|
71
|
+
size: blob.size,
|
|
72
|
+
type: blob.type,
|
|
73
|
+
},
|
|
74
|
+
];
|
|
75
|
+
} catch (e) {
|
|
76
|
+
console.log(e);
|
|
77
|
+
// Invalid dataURI, so just ignore it.
|
|
78
|
+
return acc;
|
|
79
|
+
}
|
|
80
|
+
}, [] as FileInfoType[]);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* The `FileWidget` is a widget for rendering file upload fields.
|
|
85
|
+
*
|
|
86
|
+
* @param props - The `WidgetProps` for this component
|
|
87
|
+
*/
|
|
88
|
+
export default function FileWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
|
|
89
|
+
props: WidgetProps<T, S, F>,
|
|
90
|
+
) {
|
|
91
|
+
const {
|
|
92
|
+
id,
|
|
93
|
+
name,
|
|
94
|
+
value,
|
|
95
|
+
placeholder,
|
|
96
|
+
required,
|
|
97
|
+
disabled,
|
|
98
|
+
readonly,
|
|
99
|
+
autofocus,
|
|
100
|
+
label,
|
|
101
|
+
hideLabel,
|
|
102
|
+
rawErrors,
|
|
103
|
+
options,
|
|
104
|
+
multiple,
|
|
105
|
+
onChange,
|
|
106
|
+
} = props;
|
|
107
|
+
|
|
108
|
+
const themeProps = cleanupOptions(options);
|
|
109
|
+
|
|
110
|
+
const handleChange = useCallback(
|
|
111
|
+
(files: any) => {
|
|
112
|
+
if (typeof files === 'object') {
|
|
113
|
+
processFiles(multiple ? files : [files]).then((filesInfoEvent) => {
|
|
114
|
+
const newValue = filesInfoEvent.map((fileInfo) => fileInfo.dataURL);
|
|
115
|
+
if (multiple) {
|
|
116
|
+
onChange(value.concat(newValue));
|
|
117
|
+
} else {
|
|
118
|
+
onChange(newValue[0]);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return;
|
|
123
|
+
},
|
|
124
|
+
[multiple, value, onChange],
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
const handleRemoveFile = useCallback(
|
|
128
|
+
(index: number) => {
|
|
129
|
+
if (multiple) {
|
|
130
|
+
const newValue = value.filter((_: any, i: number) => i !== index);
|
|
131
|
+
onChange(newValue);
|
|
132
|
+
} else {
|
|
133
|
+
onChange(undefined);
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
[multiple, value, onChange],
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
const ValueComponent = useCallback(
|
|
140
|
+
(props: any) => {
|
|
141
|
+
const filesInfo = props.value ? extractFileInfo(Array.isArray(props.value) ? props.value : [props.value]) : null;
|
|
142
|
+
if (Array.isArray(filesInfo) && filesInfo.length > 0) {
|
|
143
|
+
return (
|
|
144
|
+
<Pill.Group>
|
|
145
|
+
{filesInfo.map((file, index) => (
|
|
146
|
+
<Pill key={index} withRemoveButton onRemove={() => handleRemoveFile(index)}>
|
|
147
|
+
{file.name}
|
|
148
|
+
</Pill>
|
|
149
|
+
))}
|
|
150
|
+
</Pill.Group>
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
return null;
|
|
154
|
+
},
|
|
155
|
+
[handleRemoveFile],
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
return (
|
|
159
|
+
<FileInput
|
|
160
|
+
id={id}
|
|
161
|
+
name={name}
|
|
162
|
+
value={value || ''}
|
|
163
|
+
placeholder={placeholder || undefined}
|
|
164
|
+
required={required}
|
|
165
|
+
disabled={disabled || readonly}
|
|
166
|
+
autoFocus={autofocus}
|
|
167
|
+
label={labelValue(label || undefined, hideLabel, false)}
|
|
168
|
+
multiple={!!multiple}
|
|
169
|
+
valueComponent={ValueComponent}
|
|
170
|
+
onChange={handleChange}
|
|
171
|
+
error={rawErrors && rawErrors.length > 0 ? rawErrors.join('\n') : undefined}
|
|
172
|
+
{...themeProps}
|
|
173
|
+
aria-describedby={ariaDescribedByIds<T>(id)}
|
|
174
|
+
/>
|
|
175
|
+
);
|
|
176
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { ChangeEvent, FocusEvent, useCallback } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
ariaDescribedByIds,
|
|
4
|
+
FormContextType,
|
|
5
|
+
labelValue,
|
|
6
|
+
RJSFSchema,
|
|
7
|
+
StrictRJSFSchema,
|
|
8
|
+
WidgetProps,
|
|
9
|
+
} from '@rjsf/utils';
|
|
10
|
+
import { PasswordInput } from '@mantine/core';
|
|
11
|
+
|
|
12
|
+
import { cleanupOptions } from '../utils';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The `PasswordWidget` component renders a password input element.
|
|
16
|
+
*
|
|
17
|
+
* @param props - The `WidgetProps` for this component
|
|
18
|
+
*/
|
|
19
|
+
export default function PasswordWidget<
|
|
20
|
+
T = any,
|
|
21
|
+
S extends StrictRJSFSchema = RJSFSchema,
|
|
22
|
+
F extends FormContextType = any,
|
|
23
|
+
>(props: WidgetProps<T, S, F>) {
|
|
24
|
+
const {
|
|
25
|
+
id,
|
|
26
|
+
name,
|
|
27
|
+
value,
|
|
28
|
+
placeholder,
|
|
29
|
+
required,
|
|
30
|
+
disabled,
|
|
31
|
+
readonly,
|
|
32
|
+
autofocus,
|
|
33
|
+
label,
|
|
34
|
+
hideLabel,
|
|
35
|
+
rawErrors,
|
|
36
|
+
options,
|
|
37
|
+
onChange,
|
|
38
|
+
onBlur,
|
|
39
|
+
onFocus,
|
|
40
|
+
} = props;
|
|
41
|
+
|
|
42
|
+
const emptyValue = options.emptyValue || '';
|
|
43
|
+
const themeProps = cleanupOptions(options);
|
|
44
|
+
|
|
45
|
+
const handleChange = useCallback(
|
|
46
|
+
(e: ChangeEvent<HTMLInputElement>) => {
|
|
47
|
+
onChange(e.target.value === '' ? emptyValue : e.target.value);
|
|
48
|
+
},
|
|
49
|
+
[onChange, emptyValue],
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const handleBlur = useCallback(
|
|
53
|
+
({ target }: FocusEvent<HTMLInputElement>) => {
|
|
54
|
+
if (onBlur) {
|
|
55
|
+
onBlur(id, target && target.value);
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
[onBlur, id],
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
const handleFocus = useCallback(
|
|
62
|
+
({ target }: FocusEvent<HTMLInputElement>) => {
|
|
63
|
+
if (onFocus) {
|
|
64
|
+
onFocus(id, target && target.value);
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
[onFocus, id],
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<PasswordInput
|
|
72
|
+
id={id}
|
|
73
|
+
name={name}
|
|
74
|
+
value={value || ''}
|
|
75
|
+
placeholder={placeholder || undefined}
|
|
76
|
+
required={required}
|
|
77
|
+
disabled={disabled || readonly}
|
|
78
|
+
autoFocus={autofocus}
|
|
79
|
+
label={labelValue(label || undefined, hideLabel, false)}
|
|
80
|
+
onChange={handleChange}
|
|
81
|
+
onBlur={handleBlur}
|
|
82
|
+
onFocus={handleFocus}
|
|
83
|
+
error={rawErrors && rawErrors.length > 0 ? rawErrors.join('\n') : undefined}
|
|
84
|
+
{...themeProps}
|
|
85
|
+
aria-describedby={ariaDescribedByIds<T>(id)}
|
|
86
|
+
/>
|
|
87
|
+
);
|
|
88
|
+
}
|