@springmicro/forms 0.1.3
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/.eslintrc.cjs +18 -0
- package/README.md +11 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +24760 -0
- package/dist/index.umd.cjs +105 -0
- package/package.json +46 -0
- package/src/fields/ArrayField.tsx +875 -0
- package/src/fields/BooleanField.tsx +110 -0
- package/src/fields/MultiSchemaField.tsx +236 -0
- package/src/fields/NullField.tsx +22 -0
- package/src/fields/NumberField.tsx +87 -0
- package/src/fields/ObjectField.tsx +338 -0
- package/src/fields/SchemaField.tsx +402 -0
- package/src/fields/StringField.tsx +67 -0
- package/src/fields/index.ts +24 -0
- package/src/index.tsx +17 -0
- package/src/interfaces/MessagesProps.interface.ts +5 -0
- package/src/interfaces/Option.interface.ts +4 -0
- package/src/styles/select.styles.ts +28 -0
- package/src/templates/ArrayFieldDescriptionTemplate.tsx +42 -0
- package/src/templates/ArrayFieldItemTemplate.tsx +78 -0
- package/src/templates/ArrayFieldTemplate.tsx +90 -0
- package/src/templates/ArrayFieldTitleTemplate.tsx +44 -0
- package/src/templates/BaseInputTemplate.tsx +94 -0
- package/src/templates/ButtonTemplates/AddButton.tsx +29 -0
- package/src/templates/ButtonTemplates/IconButton.tsx +49 -0
- package/src/templates/ButtonTemplates/SubmitButton.tsx +29 -0
- package/src/templates/ButtonTemplates/index.ts +16 -0
- package/src/templates/DescriptionField.tsx +29 -0
- package/src/templates/ErrorList.tsx +25 -0
- package/src/templates/FieldTemplate/FieldTemplate.tsx +39 -0
- package/src/templates/FieldTemplate/Label.tsx +29 -0
- package/src/templates/FieldTemplate/WrapIfAdditional.tsx +85 -0
- package/src/templates/FieldTemplate/index.ts +3 -0
- package/src/templates/ObjectFieldTemplate.tsx +79 -0
- package/src/templates/TitleField.tsx +20 -0
- package/src/templates/UnsupportedField.tsx +29 -0
- package/src/templates/index.ts +32 -0
- package/src/types/Message.type.ts +6 -0
- package/src/types/RawMessage.type.ts +15 -0
- package/src/utils/processSelectValue.ts +50 -0
- package/src/widgets/AltDateTimeWidget.tsx +17 -0
- package/src/widgets/AltDateWidget.tsx +216 -0
- package/src/widgets/CheckboxWidget.tsx +80 -0
- package/src/widgets/CheckboxesWidget.tsx +74 -0
- package/src/widgets/ColorWidget.tsx +26 -0
- package/src/widgets/DateTimeWidget.tsx +28 -0
- package/src/widgets/DateWidget.tsx +36 -0
- package/src/widgets/EmailWidget.tsx +19 -0
- package/src/widgets/FileWidget.tsx +144 -0
- package/src/widgets/HiddenWidget.tsx +22 -0
- package/src/widgets/PasswordWidget.tsx +20 -0
- package/src/widgets/RadioWidget.tsx +87 -0
- package/src/widgets/RangeWidget.tsx +24 -0
- package/src/widgets/SelectWidget.tsx +99 -0
- package/src/widgets/TextWidget.tsx +19 -0
- package/src/widgets/TextareaWidget.tsx +64 -0
- package/src/widgets/URLWidget.tsx +19 -0
- package/src/widgets/UpDownWidget.tsx +20 -0
- package/src/widgets/index.ts +43 -0
- package/tsconfig.json +24 -0
- package/tsconfig.node.json +10 -0
- package/vite.config.ts +25 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type {
|
|
3
|
+
ArrayFieldTemplateProps,
|
|
4
|
+
ArrayFieldTemplateItemType,
|
|
5
|
+
GenericObjectType,
|
|
6
|
+
} from "@rjsf/utils";
|
|
7
|
+
import { getTemplate, getUiOptions } from "@rjsf/utils";
|
|
8
|
+
|
|
9
|
+
/** The `ArrayFieldTemplate` component is the template used to render all items in an array.
|
|
10
|
+
*
|
|
11
|
+
* @param props - The `ArrayFieldTemplateItemType` props for the component
|
|
12
|
+
*/
|
|
13
|
+
export default function ArrayFieldTemplate<
|
|
14
|
+
T = any,
|
|
15
|
+
F extends GenericObjectType = any
|
|
16
|
+
>(props: ArrayFieldTemplateProps<T, F>) {
|
|
17
|
+
const {
|
|
18
|
+
canAdd,
|
|
19
|
+
className,
|
|
20
|
+
disabled,
|
|
21
|
+
idSchema,
|
|
22
|
+
uiSchema,
|
|
23
|
+
items,
|
|
24
|
+
onAddClick,
|
|
25
|
+
readonly,
|
|
26
|
+
registry,
|
|
27
|
+
required,
|
|
28
|
+
schema,
|
|
29
|
+
title,
|
|
30
|
+
} = props;
|
|
31
|
+
const uiOptions = getUiOptions<T, F>(uiSchema);
|
|
32
|
+
const ArrayFieldDescriptionTemplate = getTemplate<
|
|
33
|
+
"ArrayFieldDescriptionTemplate",
|
|
34
|
+
T,
|
|
35
|
+
F
|
|
36
|
+
>("ArrayFieldDescriptionTemplate", registry, uiOptions);
|
|
37
|
+
const ArrayFieldItemTemplate = getTemplate<"ArrayFieldItemTemplate", T, F>(
|
|
38
|
+
"ArrayFieldItemTemplate",
|
|
39
|
+
registry,
|
|
40
|
+
uiOptions
|
|
41
|
+
);
|
|
42
|
+
const ArrayFieldTitleTemplate = getTemplate<"ArrayFieldTitleTemplate", T, F>(
|
|
43
|
+
"ArrayFieldTitleTemplate",
|
|
44
|
+
registry,
|
|
45
|
+
uiOptions
|
|
46
|
+
);
|
|
47
|
+
// Button templates are not overridden in the uiSchema
|
|
48
|
+
const {
|
|
49
|
+
ButtonTemplates: { AddButton },
|
|
50
|
+
} = registry.templates;
|
|
51
|
+
return (
|
|
52
|
+
<fieldset className={className} id={idSchema.$id}>
|
|
53
|
+
<ArrayFieldTitleTemplate
|
|
54
|
+
schema={schema}
|
|
55
|
+
idSchema={idSchema}
|
|
56
|
+
title={uiOptions.title || title}
|
|
57
|
+
required={required}
|
|
58
|
+
uiSchema={uiSchema}
|
|
59
|
+
registry={registry}
|
|
60
|
+
/>
|
|
61
|
+
{(uiOptions.description || schema.description) && (
|
|
62
|
+
<ArrayFieldDescriptionTemplate
|
|
63
|
+
schema={schema}
|
|
64
|
+
idSchema={idSchema}
|
|
65
|
+
description={(uiOptions.description || schema.description)!}
|
|
66
|
+
uiSchema={uiSchema}
|
|
67
|
+
registry={registry}
|
|
68
|
+
/>
|
|
69
|
+
)}
|
|
70
|
+
<div className="row array-item-list">
|
|
71
|
+
{items &&
|
|
72
|
+
items.map(
|
|
73
|
+
// @ts-ignore
|
|
74
|
+
({ key, ...itemProps }: ArrayFieldTemplateItemType) => (
|
|
75
|
+
// @ts-ignore
|
|
76
|
+
<ArrayFieldItemTemplate key={key} {...itemProps} />
|
|
77
|
+
)
|
|
78
|
+
)}
|
|
79
|
+
</div>
|
|
80
|
+
{canAdd && (
|
|
81
|
+
<AddButton
|
|
82
|
+
registry={registry}
|
|
83
|
+
className="array-item-add"
|
|
84
|
+
onClick={onAddClick}
|
|
85
|
+
disabled={disabled || readonly}
|
|
86
|
+
/>
|
|
87
|
+
)}
|
|
88
|
+
</fieldset>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type {
|
|
3
|
+
ArrayFieldTitleProps,
|
|
4
|
+
TemplatesType,
|
|
5
|
+
GenericObjectType,
|
|
6
|
+
Registry,
|
|
7
|
+
UiSchema,
|
|
8
|
+
} from "@rjsf/utils";
|
|
9
|
+
import { getTemplate, getUiOptions } from "@rjsf/utils";
|
|
10
|
+
|
|
11
|
+
/** The `ArrayFieldTitleTemplate` component renders a `TitleFieldTemplate` with an `id` derived from
|
|
12
|
+
* the `idSchema`.
|
|
13
|
+
*
|
|
14
|
+
* @param props - The `ArrayFieldTitleProps` for the component
|
|
15
|
+
*/
|
|
16
|
+
export default function ArrayFieldTitleTemplate<
|
|
17
|
+
T = any,
|
|
18
|
+
F extends GenericObjectType = any
|
|
19
|
+
>(props: ArrayFieldTitleProps) {
|
|
20
|
+
const { schema, idSchema, title, uiSchema, required, registry } = props;
|
|
21
|
+
if (!title) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const options = getUiOptions<T, F>(
|
|
25
|
+
uiSchema as unknown as UiSchema<T, F, any>
|
|
26
|
+
);
|
|
27
|
+
const TitleFieldTemplate: TemplatesType<T, F>["TitleFieldTemplate"] =
|
|
28
|
+
getTemplate<"TitleFieldTemplate", T, F>(
|
|
29
|
+
"TitleFieldTemplate",
|
|
30
|
+
registry as unknown as Registry<T, F, any>,
|
|
31
|
+
options
|
|
32
|
+
);
|
|
33
|
+
const id = `${idSchema.$id}__title`;
|
|
34
|
+
return (
|
|
35
|
+
<TitleFieldTemplate
|
|
36
|
+
schema={schema as unknown as F}
|
|
37
|
+
id={id}
|
|
38
|
+
title={title}
|
|
39
|
+
required={required}
|
|
40
|
+
uiSchema={uiSchema as unknown as UiSchema<T, F, any>}
|
|
41
|
+
registry={registry as unknown as Registry<T, F, any>}
|
|
42
|
+
/>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import React, { useCallback } from "react";
|
|
2
|
+
import type { WidgetProps, GenericObjectType } from "@rjsf/utils";
|
|
3
|
+
import { getInputProps } from "@rjsf/utils";
|
|
4
|
+
|
|
5
|
+
/** The `BaseInputTemplate` is the template to use to render the basic `<input>` component for the `core` theme.
|
|
6
|
+
* It is used as the template for rendering many of the <input> based widgets that differ by `type` and callbacks only.
|
|
7
|
+
* It can be customized/overridden for other themes or individual implementations as needed.
|
|
8
|
+
*
|
|
9
|
+
* @param props - The `WidgetProps` for this template
|
|
10
|
+
*/
|
|
11
|
+
export default function BaseInputTemplate<
|
|
12
|
+
T = any,
|
|
13
|
+
F extends GenericObjectType = any
|
|
14
|
+
>(props: WidgetProps<T, F>) {
|
|
15
|
+
const {
|
|
16
|
+
id,
|
|
17
|
+
value,
|
|
18
|
+
readonly,
|
|
19
|
+
disabled,
|
|
20
|
+
autofocus,
|
|
21
|
+
onBlur,
|
|
22
|
+
onFocus,
|
|
23
|
+
onChange,
|
|
24
|
+
options,
|
|
25
|
+
schema,
|
|
26
|
+
uiSchema,
|
|
27
|
+
formContext,
|
|
28
|
+
registry,
|
|
29
|
+
rawErrors,
|
|
30
|
+
type,
|
|
31
|
+
...rest
|
|
32
|
+
} = props;
|
|
33
|
+
|
|
34
|
+
// Note: since React 15.2.0 we can't forward unknown element attributes, so we
|
|
35
|
+
// exclude the "options" and "schema" ones here.
|
|
36
|
+
if (!id) {
|
|
37
|
+
console.log("No id for", props);
|
|
38
|
+
throw new Error(`no id for props ${JSON.stringify(props)}`);
|
|
39
|
+
}
|
|
40
|
+
const inputProps = { ...rest, ...getInputProps<T, F>(schema, type, options) };
|
|
41
|
+
|
|
42
|
+
let inputValue;
|
|
43
|
+
if (inputProps.type === "number" || inputProps.type === "integer") {
|
|
44
|
+
inputValue = value || value === 0 ? value : "";
|
|
45
|
+
} else {
|
|
46
|
+
inputValue = value == null ? "" : value;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const _onChange = useCallback(
|
|
50
|
+
({ target: { value } }: React.ChangeEvent<HTMLInputElement>) =>
|
|
51
|
+
onChange(value === "" ? options.emptyValue : value),
|
|
52
|
+
[onChange, options]
|
|
53
|
+
);
|
|
54
|
+
const _onBlur = useCallback(
|
|
55
|
+
({ target: { value } }: React.FocusEvent<HTMLInputElement>) =>
|
|
56
|
+
onBlur(id, value),
|
|
57
|
+
[onBlur, id]
|
|
58
|
+
);
|
|
59
|
+
const _onFocus = useCallback(
|
|
60
|
+
({ target: { value } }: React.FocusEvent<HTMLInputElement>) =>
|
|
61
|
+
onFocus(id, value),
|
|
62
|
+
[onFocus, id]
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<>
|
|
67
|
+
<input
|
|
68
|
+
key={id}
|
|
69
|
+
id={id}
|
|
70
|
+
className="input input-bordered"
|
|
71
|
+
readOnly={readonly}
|
|
72
|
+
disabled={disabled}
|
|
73
|
+
autoFocus={autofocus}
|
|
74
|
+
value={inputValue}
|
|
75
|
+
{...inputProps}
|
|
76
|
+
list={schema.examples ? `examples_${id}` : undefined}
|
|
77
|
+
onChange={_onChange}
|
|
78
|
+
onBlur={_onBlur}
|
|
79
|
+
onFocus={_onFocus}
|
|
80
|
+
/>
|
|
81
|
+
{Array.isArray(schema.examples) && (
|
|
82
|
+
<datalist key={`datalist_${id}`} id={`examples_${id}`}>
|
|
83
|
+
{[
|
|
84
|
+
...new Set(
|
|
85
|
+
schema.examples.concat(schema.default ? [schema.default] : [])
|
|
86
|
+
),
|
|
87
|
+
].map((example: any) => (
|
|
88
|
+
<option key={example} value={example} />
|
|
89
|
+
))}
|
|
90
|
+
</datalist>
|
|
91
|
+
)}
|
|
92
|
+
</>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { IconButtonProps } from "@rjsf/utils";
|
|
3
|
+
|
|
4
|
+
import IconButton from "./IconButton";
|
|
5
|
+
|
|
6
|
+
/** The `AddButton` renders a button that represent the `Add` action on a form
|
|
7
|
+
*/
|
|
8
|
+
export default function AddButton({
|
|
9
|
+
registry,
|
|
10
|
+
className,
|
|
11
|
+
onClick,
|
|
12
|
+
disabled,
|
|
13
|
+
}: IconButtonProps) {
|
|
14
|
+
return (
|
|
15
|
+
<div className="row">
|
|
16
|
+
<p className={`col-xs-3 col-xs-offset-9 text-right ${className}`}>
|
|
17
|
+
<IconButton
|
|
18
|
+
registry={registry}
|
|
19
|
+
iconType="info"
|
|
20
|
+
icon="plus"
|
|
21
|
+
className="btn-add col-xs-12"
|
|
22
|
+
title="Add"
|
|
23
|
+
onClick={onClick}
|
|
24
|
+
disabled={disabled}
|
|
25
|
+
/>
|
|
26
|
+
</p>
|
|
27
|
+
</div>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { IconButtonProps } from "@rjsf/utils";
|
|
3
|
+
|
|
4
|
+
export default function IconButton(props: IconButtonProps) {
|
|
5
|
+
const { iconType = "default", icon, className, ...otherProps } = props;
|
|
6
|
+
return (
|
|
7
|
+
<button
|
|
8
|
+
type="button"
|
|
9
|
+
className={`btn btn-${iconType} ${className}`}
|
|
10
|
+
{...otherProps}
|
|
11
|
+
>
|
|
12
|
+
<i className={`glyphicon glyphicon-${icon}`} />
|
|
13
|
+
</button>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function MoveDownButton(props: IconButtonProps) {
|
|
18
|
+
return (
|
|
19
|
+
<IconButton
|
|
20
|
+
title="Move down"
|
|
21
|
+
className="array-item-move-down"
|
|
22
|
+
{...props}
|
|
23
|
+
icon="arrow-down"
|
|
24
|
+
/>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function MoveUpButton(props: IconButtonProps) {
|
|
29
|
+
return (
|
|
30
|
+
<IconButton
|
|
31
|
+
title="Move up"
|
|
32
|
+
className="array-item-move-up"
|
|
33
|
+
{...props}
|
|
34
|
+
icon="arrow-up"
|
|
35
|
+
/>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function RemoveButton(props: IconButtonProps) {
|
|
40
|
+
return (
|
|
41
|
+
<IconButton
|
|
42
|
+
title="Remove"
|
|
43
|
+
className="array-item-remove"
|
|
44
|
+
{...props}
|
|
45
|
+
iconType="danger"
|
|
46
|
+
icon="remove"
|
|
47
|
+
/>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { SubmitButtonProps, GenericObjectType } from "@rjsf/utils";
|
|
3
|
+
import { getSubmitButtonOptions } from "@rjsf/utils";
|
|
4
|
+
|
|
5
|
+
/** The `SubmitButton` renders a button that represent the `Submit` action on a form
|
|
6
|
+
*/
|
|
7
|
+
export default function SubmitButton<T, F extends GenericObjectType = any>({
|
|
8
|
+
uiSchema,
|
|
9
|
+
}: SubmitButtonProps<T, F>) {
|
|
10
|
+
const {
|
|
11
|
+
submitText,
|
|
12
|
+
norender,
|
|
13
|
+
props: submitButtonProps = {},
|
|
14
|
+
} = getSubmitButtonOptions(uiSchema);
|
|
15
|
+
if (norender) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
return (
|
|
19
|
+
<div>
|
|
20
|
+
<button
|
|
21
|
+
type="submit"
|
|
22
|
+
{...submitButtonProps}
|
|
23
|
+
className={`btn btn-primary ${submitButtonProps.className}`}
|
|
24
|
+
>
|
|
25
|
+
{submitText}
|
|
26
|
+
</button>
|
|
27
|
+
</div>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { TemplatesType } from "@rjsf/utils";
|
|
2
|
+
|
|
3
|
+
import SubmitButton from "./SubmitButton";
|
|
4
|
+
import AddButton from "./AddButton";
|
|
5
|
+
import { RemoveButton, MoveDownButton, MoveUpButton } from "./IconButton";
|
|
6
|
+
|
|
7
|
+
// @ts-ignore
|
|
8
|
+
const buttonTemplates: TemplatesType["ButtonTemplates"] = {
|
|
9
|
+
SubmitButton,
|
|
10
|
+
AddButton,
|
|
11
|
+
MoveDownButton,
|
|
12
|
+
MoveUpButton,
|
|
13
|
+
RemoveButton,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default buttonTemplates;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { DescriptionFieldProps, GenericObjectType } from "@rjsf/utils";
|
|
3
|
+
|
|
4
|
+
/** The `DescriptionField` is the template to use to render the description of a field
|
|
5
|
+
*
|
|
6
|
+
* @param props - The `DescriptionFieldProps` for this component
|
|
7
|
+
*/
|
|
8
|
+
export default function DescriptionField<
|
|
9
|
+
T = any,
|
|
10
|
+
F extends GenericObjectType = any
|
|
11
|
+
>(props: DescriptionFieldProps<T, F>) {
|
|
12
|
+
const { id, description } = props;
|
|
13
|
+
if (!description) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
if (typeof description === "string") {
|
|
17
|
+
return (
|
|
18
|
+
<p id={id} className="field-description">
|
|
19
|
+
{description}
|
|
20
|
+
</p>
|
|
21
|
+
);
|
|
22
|
+
} else {
|
|
23
|
+
return (
|
|
24
|
+
<div id={id} className="field-description">
|
|
25
|
+
{description}
|
|
26
|
+
</div>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { ErrorListProps, RJSFValidationError } from "@rjsf/utils";
|
|
3
|
+
|
|
4
|
+
/** The `ErrorList` component is the template that renders the all the errors associated with the fields in the `Form`
|
|
5
|
+
*
|
|
6
|
+
* @param props - The `ErrorListProps` for this component
|
|
7
|
+
*/
|
|
8
|
+
export default function ErrorList<T = any>({ errors }: ErrorListProps<T>) {
|
|
9
|
+
return (
|
|
10
|
+
<div className="panel panel-danger errors">
|
|
11
|
+
<div className="panel-heading">
|
|
12
|
+
<h3 className="panel-title">Errors</h3>
|
|
13
|
+
</div>
|
|
14
|
+
<ul className="list-group">
|
|
15
|
+
{errors.map((error: RJSFValidationError, i: number) => {
|
|
16
|
+
return (
|
|
17
|
+
<li key={i} className="list-group-item text-danger">
|
|
18
|
+
{error.stack}
|
|
19
|
+
</li>
|
|
20
|
+
);
|
|
21
|
+
})}
|
|
22
|
+
</ul>
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { FieldTemplateProps, GenericObjectType } from "@rjsf/utils";
|
|
3
|
+
|
|
4
|
+
import Label from "./Label";
|
|
5
|
+
import WrapIfAdditional from "./WrapIfAdditional";
|
|
6
|
+
|
|
7
|
+
/** The `FieldTemplate` component is the template used by `SchemaField` to render any field. It renders the field
|
|
8
|
+
* content, (label, description, children, errors and help) inside of a `WrapIfAdditional` component.
|
|
9
|
+
*
|
|
10
|
+
* @param props - The `FieldTemplateProps` for this component
|
|
11
|
+
*/
|
|
12
|
+
export default function FieldTemplate<
|
|
13
|
+
T = any,
|
|
14
|
+
F extends GenericObjectType = any
|
|
15
|
+
>(props: FieldTemplateProps<T, F>) {
|
|
16
|
+
const {
|
|
17
|
+
id,
|
|
18
|
+
label,
|
|
19
|
+
children,
|
|
20
|
+
errors,
|
|
21
|
+
help,
|
|
22
|
+
description,
|
|
23
|
+
hidden,
|
|
24
|
+
required,
|
|
25
|
+
displayLabel,
|
|
26
|
+
} = props;
|
|
27
|
+
if (hidden) {
|
|
28
|
+
return <div className="hidden">{children}</div>;
|
|
29
|
+
}
|
|
30
|
+
return (
|
|
31
|
+
<WrapIfAdditional<T, F> {...props}>
|
|
32
|
+
{displayLabel && <Label label={label} required={required} id={id} />}
|
|
33
|
+
{displayLabel && description ? description : null}
|
|
34
|
+
{children}
|
|
35
|
+
{errors}
|
|
36
|
+
{help}
|
|
37
|
+
</WrapIfAdditional>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
const REQUIRED_FIELD_SYMBOL = "*";
|
|
4
|
+
|
|
5
|
+
export type LabelProps = {
|
|
6
|
+
/** The label for the field */
|
|
7
|
+
label?: string;
|
|
8
|
+
/** A boolean value stating if the field is required */
|
|
9
|
+
required?: boolean;
|
|
10
|
+
/** The id of the input field being labeled */
|
|
11
|
+
id?: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/** Renders a label for a field
|
|
15
|
+
*
|
|
16
|
+
* @param props - The `LabelProps` for this component
|
|
17
|
+
*/
|
|
18
|
+
export default function Label(props: LabelProps) {
|
|
19
|
+
const { label, required, id } = props;
|
|
20
|
+
if (!label) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
return (
|
|
24
|
+
<label className="justify-start gap-1 label" htmlFor={id}>
|
|
25
|
+
<span className="label-text">{label}</span>
|
|
26
|
+
{required && <span className="required">{REQUIRED_FIELD_SYMBOL}</span>}
|
|
27
|
+
</label>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { FieldTemplateProps, GenericObjectType } from "@rjsf/utils";
|
|
3
|
+
import { ADDITIONAL_PROPERTY_FLAG } from "@rjsf/utils";
|
|
4
|
+
|
|
5
|
+
import Label from "./Label";
|
|
6
|
+
|
|
7
|
+
/** The properties that are passed to a WrapIfAdditionalTemplate implementation */
|
|
8
|
+
export type WrapIfAdditionalProps<
|
|
9
|
+
T = any,
|
|
10
|
+
F extends GenericObjectType = any
|
|
11
|
+
> = {
|
|
12
|
+
children: React.ReactNode;
|
|
13
|
+
} & Pick<
|
|
14
|
+
FieldTemplateProps<T, F>,
|
|
15
|
+
| "classNames"
|
|
16
|
+
| "disabled"
|
|
17
|
+
| "id"
|
|
18
|
+
| "label"
|
|
19
|
+
| "onDropPropertyClick"
|
|
20
|
+
| "onKeyChange"
|
|
21
|
+
| "readonly"
|
|
22
|
+
| "required"
|
|
23
|
+
| "schema"
|
|
24
|
+
| "registry"
|
|
25
|
+
>;
|
|
26
|
+
|
|
27
|
+
/** The `WrapIfAdditional` component is used by the `FieldTemplate` to rename, or remove properties that are
|
|
28
|
+
* part of an `additionalProperties` part of a schema.
|
|
29
|
+
*
|
|
30
|
+
* @param props - The `WrapIfAdditionalProps` for this component
|
|
31
|
+
*/
|
|
32
|
+
export default function WrapIfAdditional<
|
|
33
|
+
T = any,
|
|
34
|
+
F extends GenericObjectType = any
|
|
35
|
+
>(props: WrapIfAdditionalProps<T, F>) {
|
|
36
|
+
const {
|
|
37
|
+
id,
|
|
38
|
+
classNames,
|
|
39
|
+
disabled,
|
|
40
|
+
label,
|
|
41
|
+
onKeyChange,
|
|
42
|
+
onDropPropertyClick,
|
|
43
|
+
readonly,
|
|
44
|
+
required,
|
|
45
|
+
schema,
|
|
46
|
+
children,
|
|
47
|
+
registry,
|
|
48
|
+
} = props;
|
|
49
|
+
const { RemoveButton } = registry.templates.ButtonTemplates;
|
|
50
|
+
const keyLabel = `${label} Key`; // i18n ?
|
|
51
|
+
const additional = ADDITIONAL_PROPERTY_FLAG in schema;
|
|
52
|
+
|
|
53
|
+
if (!additional) {
|
|
54
|
+
return <div className={classNames}>{children}</div>;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<div className={classNames}>
|
|
59
|
+
<div className="row">
|
|
60
|
+
<div className="form-additional">
|
|
61
|
+
<div className="form-control">
|
|
62
|
+
<Label label={keyLabel} required={required} id={`${id}-key`} />
|
|
63
|
+
<input
|
|
64
|
+
className="form-control"
|
|
65
|
+
type="text"
|
|
66
|
+
id={`${id}-key`}
|
|
67
|
+
onBlur={(event) => onKeyChange(event.target.value)}
|
|
68
|
+
defaultValue={label}
|
|
69
|
+
/>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
<div className="form-additional form-control">{children}</div>
|
|
73
|
+
<div className="col-xs-2">
|
|
74
|
+
<RemoveButton
|
|
75
|
+
registry={registry}
|
|
76
|
+
className="array-item-remove btn-block"
|
|
77
|
+
style={{ border: "0" }}
|
|
78
|
+
disabled={disabled || readonly}
|
|
79
|
+
onClick={onDropPropertyClick(label)}
|
|
80
|
+
/>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {
|
|
3
|
+
GenericObjectType,
|
|
4
|
+
ObjectFieldTemplatePropertyType,
|
|
5
|
+
ObjectFieldTemplateProps,
|
|
6
|
+
} from "@rjsf/utils";
|
|
7
|
+
import { canExpand, getTemplate, getUiOptions } from "@rjsf/utils";
|
|
8
|
+
|
|
9
|
+
/** The `ObjectFieldTemplate` is the template to use to render all the inner properties of an object along with the
|
|
10
|
+
* title and description if available. If the object is expandable, then an `AddButton` is also rendered after all
|
|
11
|
+
* the properties.
|
|
12
|
+
*
|
|
13
|
+
* @param props - The `ObjectFieldTemplateProps` for this component
|
|
14
|
+
*/
|
|
15
|
+
export default function ObjectFieldTemplate<
|
|
16
|
+
T = any,
|
|
17
|
+
F extends GenericObjectType = any
|
|
18
|
+
>(props: ObjectFieldTemplateProps<T, F>) {
|
|
19
|
+
const {
|
|
20
|
+
description,
|
|
21
|
+
disabled,
|
|
22
|
+
formData,
|
|
23
|
+
idSchema,
|
|
24
|
+
onAddClick,
|
|
25
|
+
properties,
|
|
26
|
+
readonly,
|
|
27
|
+
registry,
|
|
28
|
+
required,
|
|
29
|
+
schema,
|
|
30
|
+
title,
|
|
31
|
+
uiSchema,
|
|
32
|
+
} = props;
|
|
33
|
+
const options = getUiOptions<T, F>(uiSchema);
|
|
34
|
+
const TitleFieldTemplate = getTemplate<"TitleFieldTemplate", T, F>(
|
|
35
|
+
"TitleFieldTemplate",
|
|
36
|
+
registry,
|
|
37
|
+
options
|
|
38
|
+
);
|
|
39
|
+
const DescriptionFieldTemplate = getTemplate<
|
|
40
|
+
"DescriptionFieldTemplate",
|
|
41
|
+
T,
|
|
42
|
+
F
|
|
43
|
+
>("DescriptionFieldTemplate", registry, options);
|
|
44
|
+
// Button templates are not overridden in the uiSchema
|
|
45
|
+
const {
|
|
46
|
+
ButtonTemplates: { AddButton },
|
|
47
|
+
} = registry.templates;
|
|
48
|
+
return (
|
|
49
|
+
<fieldset id={idSchema.$id}>
|
|
50
|
+
{(options.title || title) && (
|
|
51
|
+
<TitleFieldTemplate
|
|
52
|
+
schema={schema}
|
|
53
|
+
id={`${idSchema.$id}__title`}
|
|
54
|
+
title={options.title || title}
|
|
55
|
+
required={required}
|
|
56
|
+
uiSchema={uiSchema}
|
|
57
|
+
registry={registry}
|
|
58
|
+
/>
|
|
59
|
+
)}
|
|
60
|
+
{(options.description || description) && (
|
|
61
|
+
<DescriptionFieldTemplate
|
|
62
|
+
schema={schema}
|
|
63
|
+
id={`${idSchema.$id}__description`}
|
|
64
|
+
description={options.description || description!}
|
|
65
|
+
registry={registry}
|
|
66
|
+
/>
|
|
67
|
+
)}
|
|
68
|
+
{properties.map((prop: ObjectFieldTemplatePropertyType) => prop.content)}
|
|
69
|
+
{canExpand(schema, uiSchema, formData) && (
|
|
70
|
+
<AddButton
|
|
71
|
+
registry={registry}
|
|
72
|
+
className="object-property-expand"
|
|
73
|
+
onClick={onAddClick(schema)}
|
|
74
|
+
disabled={disabled || readonly}
|
|
75
|
+
/>
|
|
76
|
+
)}
|
|
77
|
+
</fieldset>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { GenericObjectType, TitleFieldProps } from "@rjsf/utils";
|
|
3
|
+
|
|
4
|
+
const REQUIRED_FIELD_SYMBOL = "*";
|
|
5
|
+
|
|
6
|
+
/** The `TitleField` is the template to use to render the title of a field
|
|
7
|
+
*
|
|
8
|
+
* @param props - The `TitleFieldProps` for this component
|
|
9
|
+
*/
|
|
10
|
+
export default function TitleField<T = any, F extends GenericObjectType = any>(
|
|
11
|
+
props: TitleFieldProps<T, F>
|
|
12
|
+
) {
|
|
13
|
+
const { id, title, required } = props;
|
|
14
|
+
return (
|
|
15
|
+
<legend id={id}>
|
|
16
|
+
{title}
|
|
17
|
+
{required && <span className="required">{REQUIRED_FIELD_SYMBOL}</span>}
|
|
18
|
+
</legend>
|
|
19
|
+
);
|
|
20
|
+
}
|