@springmicro/forms 0.6.4 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/.eslintrc.cjs +22 -22
  2. package/README.md +11 -11
  3. package/dist/index.d.ts +0 -0
  4. package/dist/index.js +0 -0
  5. package/dist/index.umd.cjs +0 -0
  6. package/package.json +3 -3
  7. package/src/builder/bottom-drawer.tsx +429 -429
  8. package/src/builder/form-builder.tsx +256 -256
  9. package/src/builder/modal.tsx +39 -39
  10. package/src/builder/nodes/node-base.tsx +94 -94
  11. package/src/builder/nodes/node-child-helpers.tsx +273 -273
  12. package/src/builder/nodes/node-parent.tsx +187 -187
  13. package/src/builder/nodes/node-types/array-node.tsx +134 -134
  14. package/src/builder/nodes/node-types/date-node.tsx +60 -60
  15. package/src/builder/nodes/node-types/file-node.tsx +67 -67
  16. package/src/builder/nodes/node-types/integer-node.tsx +60 -60
  17. package/src/builder/nodes/node-types/object-node.tsx +67 -67
  18. package/src/builder/nodes/node-types/text-node.tsx +66 -66
  19. package/src/fields/ArrayField.tsx +875 -875
  20. package/src/fields/BooleanField.tsx +110 -110
  21. package/src/fields/MultiSchemaField.tsx +236 -236
  22. package/src/fields/NullField.tsx +22 -22
  23. package/src/fields/NumberField.tsx +87 -87
  24. package/src/fields/ObjectField.tsx +338 -338
  25. package/src/fields/SchemaField.tsx +402 -402
  26. package/src/fields/StringField.tsx +67 -67
  27. package/src/fields/index.ts +24 -24
  28. package/src/index.tsx +26 -26
  29. package/src/interfaces/MessagesProps.interface.ts +5 -5
  30. package/src/interfaces/Option.interface.ts +4 -4
  31. package/src/styles/select.styles.ts +28 -28
  32. package/src/templates/ArrayFieldDescriptionTemplate.tsx +42 -42
  33. package/src/templates/ArrayFieldItemTemplate.tsx +78 -78
  34. package/src/templates/ArrayFieldTemplate.tsx +90 -90
  35. package/src/templates/ArrayFieldTitleTemplate.tsx +44 -44
  36. package/src/templates/BaseInputTemplate.tsx +94 -94
  37. package/src/templates/ButtonTemplates/AddButton.tsx +29 -29
  38. package/src/templates/ButtonTemplates/IconButton.tsx +49 -49
  39. package/src/templates/ButtonTemplates/SubmitButton.tsx +29 -29
  40. package/src/templates/ButtonTemplates/index.ts +16 -16
  41. package/src/templates/DescriptionField.tsx +29 -29
  42. package/src/templates/ErrorList.tsx +25 -25
  43. package/src/templates/FieldTemplate/FieldTemplate.tsx +39 -39
  44. package/src/templates/FieldTemplate/Label.tsx +29 -29
  45. package/src/templates/FieldTemplate/WrapIfAdditional.tsx +85 -85
  46. package/src/templates/FieldTemplate/index.ts +3 -3
  47. package/src/templates/ObjectFieldTemplate.tsx +79 -79
  48. package/src/templates/TitleField.tsx +20 -20
  49. package/src/templates/UnsupportedField.tsx +29 -29
  50. package/src/templates/index.ts +32 -32
  51. package/src/types/Message.type.ts +6 -6
  52. package/src/types/RawMessage.type.ts +15 -15
  53. package/src/types/form-builder.ts +135 -135
  54. package/src/types/utils.type.ts +1 -1
  55. package/src/utils/form-builder.ts +424 -424
  56. package/src/utils/processSelectValue.ts +50 -50
  57. package/src/widgets/AltDateTimeWidget.tsx +17 -17
  58. package/src/widgets/AltDateWidget.tsx +216 -216
  59. package/src/widgets/CheckboxWidget.tsx +80 -80
  60. package/src/widgets/CheckboxesWidget.tsx +74 -74
  61. package/src/widgets/ColorWidget.tsx +26 -26
  62. package/src/widgets/DateTimeWidget.tsx +28 -28
  63. package/src/widgets/DateWidget.tsx +36 -36
  64. package/src/widgets/EmailWidget.tsx +19 -19
  65. package/src/widgets/FileWidget.tsx +144 -144
  66. package/src/widgets/HiddenWidget.tsx +22 -22
  67. package/src/widgets/PasswordWidget.tsx +20 -20
  68. package/src/widgets/RadioWidget.tsx +87 -87
  69. package/src/widgets/RangeWidget.tsx +24 -24
  70. package/src/widgets/SelectWidget.tsx +99 -99
  71. package/src/widgets/TextWidget.tsx +19 -19
  72. package/src/widgets/TextareaWidget.tsx +64 -64
  73. package/src/widgets/URLWidget.tsx +19 -19
  74. package/src/widgets/UpDownWidget.tsx +20 -20
  75. package/src/widgets/index.ts +43 -43
  76. package/tsconfig.json +24 -24
  77. package/tsconfig.node.json +10 -10
  78. package/vite.config.ts +25 -25
@@ -1,144 +1,144 @@
1
- import React, { ChangeEvent, useCallback, useMemo, useState } from "react";
2
-
3
- import type { WidgetProps, GenericObjectType } from "@rjsf/utils";
4
- import { dataURItoBlob } from "@rjsf/utils";
5
-
6
- function addNameToDataURL(dataURL: string, name: string) {
7
- if (dataURL === null) {
8
- return null;
9
- }
10
- return dataURL.replace(";base64", `;name=${encodeURIComponent(name)};base64`);
11
- }
12
-
13
- type FileInfoType = {
14
- dataURL?: string | null;
15
- name: string;
16
- size: number;
17
- type: string;
18
- };
19
-
20
- function processFile(file: File): Promise<FileInfoType> {
21
- const { name, size, type } = file;
22
- return new Promise((resolve, reject) => {
23
- const reader = new window.FileReader();
24
- reader.onerror = reject;
25
- reader.onload = (event) => {
26
- if (typeof event.target?.result === "string") {
27
- resolve({
28
- dataURL: addNameToDataURL(event.target.result, name),
29
- name,
30
- size,
31
- type,
32
- });
33
- } else {
34
- resolve({
35
- dataURL: null,
36
- name,
37
- size,
38
- type,
39
- });
40
- }
41
- };
42
- reader.readAsDataURL(file);
43
- });
44
- }
45
-
46
- function processFiles(files: FileList) {
47
- return Promise.all(Array.from(files).map(processFile));
48
- }
49
-
50
- function FilesInfo({
51
- filesInfo,
52
- }: {
53
- filesInfo: { name: string; size: number; type: string }[];
54
- }) {
55
- if (filesInfo.length === 0) {
56
- return null;
57
- }
58
- return (
59
- <ul className="file-info">
60
- {filesInfo.map((fileInfo, key) => {
61
- const { name, size, type } = fileInfo;
62
- return (
63
- <li key={key}>
64
- <strong>{name}</strong> ({type}, {size} bytes)
65
- </li>
66
- );
67
- })}
68
- </ul>
69
- );
70
- }
71
-
72
- function extractFileInfo(dataURLs: string[]) {
73
- return dataURLs
74
- .filter((dataURL) => typeof dataURL !== "undefined")
75
- .map((dataURL) => {
76
- const { blob, name } = dataURItoBlob(dataURL);
77
- return {
78
- name: name,
79
- size: blob.size,
80
- type: blob.type,
81
- };
82
- });
83
- }
84
-
85
- /**
86
- * The `FileWidget` is a widget for rendering file upload fields.
87
- * It is typically used with a string property with data-url format.
88
- */
89
- function FileWidget<T, F extends GenericObjectType = any>({
90
- multiple,
91
- id,
92
- readonly,
93
- disabled,
94
- onChange,
95
- value,
96
- autofocus = false,
97
- options,
98
- }: WidgetProps<T, F>) {
99
- const extractedFilesInfo = useMemo(
100
- () =>
101
- Array.isArray(value) ? extractFileInfo(value) : extractFileInfo([value]),
102
- [value]
103
- );
104
- const [filesInfo, setFilesInfo] =
105
- useState<FileInfoType[]>(extractedFilesInfo);
106
-
107
- const handleChange = useCallback(
108
- (event: ChangeEvent<HTMLInputElement>) => {
109
- if (!event.target.files) {
110
- return;
111
- }
112
- processFiles(event.target.files).then((filesInfoEvent) => {
113
- setFilesInfo(filesInfoEvent);
114
- const newValue = filesInfoEvent.map((fileInfo) => fileInfo.dataURL);
115
- if (multiple) {
116
- onChange(newValue);
117
- } else {
118
- onChange(newValue[0]);
119
- }
120
- });
121
- },
122
- [multiple, onChange]
123
- );
124
-
125
- return (
126
- <div>
127
- <p>
128
- <input
129
- id={id}
130
- type="file"
131
- disabled={readonly || disabled}
132
- onChange={handleChange}
133
- defaultValue=""
134
- autoFocus={autofocus}
135
- multiple={multiple}
136
- accept={options.accept ? String(options.accept) : undefined}
137
- />
138
- </p>
139
- <FilesInfo filesInfo={filesInfo} />
140
- </div>
141
- );
142
- }
143
-
144
- export default FileWidget;
1
+ import React, { ChangeEvent, useCallback, useMemo, useState } from "react";
2
+
3
+ import type { WidgetProps, GenericObjectType } from "@rjsf/utils";
4
+ import { dataURItoBlob } from "@rjsf/utils";
5
+
6
+ function addNameToDataURL(dataURL: string, name: string) {
7
+ if (dataURL === null) {
8
+ return null;
9
+ }
10
+ return dataURL.replace(";base64", `;name=${encodeURIComponent(name)};base64`);
11
+ }
12
+
13
+ type FileInfoType = {
14
+ dataURL?: string | null;
15
+ name: string;
16
+ size: number;
17
+ type: string;
18
+ };
19
+
20
+ function processFile(file: File): Promise<FileInfoType> {
21
+ const { name, size, type } = file;
22
+ return new Promise((resolve, reject) => {
23
+ const reader = new window.FileReader();
24
+ reader.onerror = reject;
25
+ reader.onload = (event) => {
26
+ if (typeof event.target?.result === "string") {
27
+ resolve({
28
+ dataURL: addNameToDataURL(event.target.result, name),
29
+ name,
30
+ size,
31
+ type,
32
+ });
33
+ } else {
34
+ resolve({
35
+ dataURL: null,
36
+ name,
37
+ size,
38
+ type,
39
+ });
40
+ }
41
+ };
42
+ reader.readAsDataURL(file);
43
+ });
44
+ }
45
+
46
+ function processFiles(files: FileList) {
47
+ return Promise.all(Array.from(files).map(processFile));
48
+ }
49
+
50
+ function FilesInfo({
51
+ filesInfo,
52
+ }: {
53
+ filesInfo: { name: string; size: number; type: string }[];
54
+ }) {
55
+ if (filesInfo.length === 0) {
56
+ return null;
57
+ }
58
+ return (
59
+ <ul className="file-info">
60
+ {filesInfo.map((fileInfo, key) => {
61
+ const { name, size, type } = fileInfo;
62
+ return (
63
+ <li key={key}>
64
+ <strong>{name}</strong> ({type}, {size} bytes)
65
+ </li>
66
+ );
67
+ })}
68
+ </ul>
69
+ );
70
+ }
71
+
72
+ function extractFileInfo(dataURLs: string[]) {
73
+ return dataURLs
74
+ .filter((dataURL) => typeof dataURL !== "undefined")
75
+ .map((dataURL) => {
76
+ const { blob, name } = dataURItoBlob(dataURL);
77
+ return {
78
+ name: name,
79
+ size: blob.size,
80
+ type: blob.type,
81
+ };
82
+ });
83
+ }
84
+
85
+ /**
86
+ * The `FileWidget` is a widget for rendering file upload fields.
87
+ * It is typically used with a string property with data-url format.
88
+ */
89
+ function FileWidget<T, F extends GenericObjectType = any>({
90
+ multiple,
91
+ id,
92
+ readonly,
93
+ disabled,
94
+ onChange,
95
+ value,
96
+ autofocus = false,
97
+ options,
98
+ }: WidgetProps<T, F>) {
99
+ const extractedFilesInfo = useMemo(
100
+ () =>
101
+ Array.isArray(value) ? extractFileInfo(value) : extractFileInfo([value]),
102
+ [value]
103
+ );
104
+ const [filesInfo, setFilesInfo] =
105
+ useState<FileInfoType[]>(extractedFilesInfo);
106
+
107
+ const handleChange = useCallback(
108
+ (event: ChangeEvent<HTMLInputElement>) => {
109
+ if (!event.target.files) {
110
+ return;
111
+ }
112
+ processFiles(event.target.files).then((filesInfoEvent) => {
113
+ setFilesInfo(filesInfoEvent);
114
+ const newValue = filesInfoEvent.map((fileInfo) => fileInfo.dataURL);
115
+ if (multiple) {
116
+ onChange(newValue);
117
+ } else {
118
+ onChange(newValue[0]);
119
+ }
120
+ });
121
+ },
122
+ [multiple, onChange]
123
+ );
124
+
125
+ return (
126
+ <div>
127
+ <p>
128
+ <input
129
+ id={id}
130
+ type="file"
131
+ disabled={readonly || disabled}
132
+ onChange={handleChange}
133
+ defaultValue=""
134
+ autoFocus={autofocus}
135
+ multiple={multiple}
136
+ accept={options.accept ? String(options.accept) : undefined}
137
+ />
138
+ </p>
139
+ <FilesInfo filesInfo={filesInfo} />
140
+ </div>
141
+ );
142
+ }
143
+
144
+ export default FileWidget;
@@ -1,22 +1,22 @@
1
- import React from "react";
2
- import type { WidgetProps, GenericObjectType } from "@rjsf/utils";
3
-
4
- /** The `HiddenWidget` is a widget for rendering a hidden input field.
5
- * It is typically used by setting type to "hidden".
6
- *
7
- * @param props - The `WidgetProps` for this component
8
- */
9
- function HiddenWidget<T = any, F extends GenericObjectType = any>({
10
- id,
11
- value,
12
- }: WidgetProps<T, F>) {
13
- return (
14
- <input
15
- type="hidden"
16
- id={id}
17
- value={typeof value === "undefined" ? "" : value}
18
- />
19
- );
20
- }
21
-
22
- export default HiddenWidget;
1
+ import React from "react";
2
+ import type { WidgetProps, GenericObjectType } from "@rjsf/utils";
3
+
4
+ /** The `HiddenWidget` is a widget for rendering a hidden input field.
5
+ * It is typically used by setting type to "hidden".
6
+ *
7
+ * @param props - The `WidgetProps` for this component
8
+ */
9
+ function HiddenWidget<T = any, F extends GenericObjectType = any>({
10
+ id,
11
+ value,
12
+ }: WidgetProps<T, F>) {
13
+ return (
14
+ <input
15
+ type="hidden"
16
+ id={id}
17
+ value={typeof value === "undefined" ? "" : value}
18
+ />
19
+ );
20
+ }
21
+
22
+ export default HiddenWidget;
@@ -1,20 +1,20 @@
1
- import React from "react";
2
- import type { WidgetProps, GenericObjectType } from "@rjsf/utils";
3
- import { getTemplate } from "@rjsf/utils";
4
-
5
- /** The `PasswordWidget` component uses the `BaseInputTemplate` changing the type to `password`.
6
- *
7
- * @param props - The `WidgetProps` for this component
8
- */
9
- export default function PasswordWidget<
10
- T = any,
11
- F extends GenericObjectType = any
12
- >(props: WidgetProps<T, F>) {
13
- const { options, registry } = props;
14
- const BaseInputTemplate = getTemplate<"BaseInputTemplate", T, F>(
15
- "BaseInputTemplate",
16
- registry,
17
- options
18
- );
19
- return <BaseInputTemplate type="password" {...props} />;
20
- }
1
+ import React from "react";
2
+ import type { WidgetProps, GenericObjectType } from "@rjsf/utils";
3
+ import { getTemplate } from "@rjsf/utils";
4
+
5
+ /** The `PasswordWidget` component uses the `BaseInputTemplate` changing the type to `password`.
6
+ *
7
+ * @param props - The `WidgetProps` for this component
8
+ */
9
+ export default function PasswordWidget<
10
+ T = any,
11
+ F extends GenericObjectType = any
12
+ >(props: WidgetProps<T, F>) {
13
+ const { options, registry } = props;
14
+ const BaseInputTemplate = getTemplate<"BaseInputTemplate", T, F>(
15
+ "BaseInputTemplate",
16
+ registry,
17
+ options
18
+ );
19
+ return <BaseInputTemplate type="password" {...props} />;
20
+ }
@@ -1,87 +1,87 @@
1
- import React, { FocusEvent, useCallback } from "react";
2
- import type { WidgetProps, GenericObjectType } from "@rjsf/utils";
3
-
4
- /** The `RadioWidget` is a widget for rendering a radio group.
5
- * It is typically used with a string property constrained with enum options.
6
- *
7
- * @param props - The `WidgetProps` for this component
8
- */
9
- function RadioWidget<T = any, F extends GenericObjectType = any>({
10
- options,
11
- value,
12
- required,
13
- disabled,
14
- readonly,
15
- autofocus = false,
16
- onBlur,
17
- onFocus,
18
- onChange,
19
- id,
20
- }: WidgetProps<T, F>) {
21
- // Generating a unique field name to identify this set of radio buttons
22
- const name = Math.random().toString();
23
- const { enumOptions, enumDisabled, inline } = options;
24
- // checked={checked} has been moved above name={name}, As mentioned in #349;
25
- // this is a temporary fix for radio button rendering bug in React, facebook/react#7630.
26
-
27
- const handleBlur = useCallback(
28
- (event: FocusEvent<HTMLInputElement>) => onBlur(id, event.target.value),
29
- [onBlur, id]
30
- );
31
-
32
- const handleFocus = useCallback(
33
- (event: FocusEvent<HTMLInputElement>) => onFocus(id, event.target.value),
34
- [onFocus, id]
35
- );
36
-
37
- return (
38
- <div
39
- className={`flex field-radio-group ${
40
- inline ? "flex-row gap-2" : "flex-col"
41
- }`}
42
- id={id}
43
- >
44
- {Array.isArray(enumOptions) &&
45
- enumOptions.map((option, i) => {
46
- const checked = option.value === value;
47
- const itemDisabled =
48
- enumDisabled && enumDisabled.indexOf(option.value) != -1;
49
- const disabledCls =
50
- disabled || itemDisabled || readonly ? "disabled" : "";
51
-
52
- const handleChange = () => onChange(option.value);
53
-
54
- const radio = (
55
- <>
56
- <input
57
- type="radio"
58
- className="radio radio-secondary"
59
- id={`${id}_${i}`}
60
- checked={checked}
61
- name={id}
62
- required={required}
63
- value={option.value}
64
- disabled={disabled || itemDisabled || readonly}
65
- autoFocus={autofocus && i === 0}
66
- onChange={handleChange}
67
- onBlur={handleBlur}
68
- onFocus={handleFocus}
69
- />
70
- <span className="label-text">{option.label}</span>
71
- </>
72
- );
73
-
74
- return (
75
- <label
76
- key={i}
77
- className={`label justify-start gap-2 ${disabledCls}`}
78
- >
79
- {radio}
80
- </label>
81
- );
82
- })}
83
- </div>
84
- );
85
- }
86
-
87
- export default RadioWidget;
1
+ import React, { FocusEvent, useCallback } from "react";
2
+ import type { WidgetProps, GenericObjectType } from "@rjsf/utils";
3
+
4
+ /** The `RadioWidget` is a widget for rendering a radio group.
5
+ * It is typically used with a string property constrained with enum options.
6
+ *
7
+ * @param props - The `WidgetProps` for this component
8
+ */
9
+ function RadioWidget<T = any, F extends GenericObjectType = any>({
10
+ options,
11
+ value,
12
+ required,
13
+ disabled,
14
+ readonly,
15
+ autofocus = false,
16
+ onBlur,
17
+ onFocus,
18
+ onChange,
19
+ id,
20
+ }: WidgetProps<T, F>) {
21
+ // Generating a unique field name to identify this set of radio buttons
22
+ const name = Math.random().toString();
23
+ const { enumOptions, enumDisabled, inline } = options;
24
+ // checked={checked} has been moved above name={name}, As mentioned in #349;
25
+ // this is a temporary fix for radio button rendering bug in React, facebook/react#7630.
26
+
27
+ const handleBlur = useCallback(
28
+ (event: FocusEvent<HTMLInputElement>) => onBlur(id, event.target.value),
29
+ [onBlur, id]
30
+ );
31
+
32
+ const handleFocus = useCallback(
33
+ (event: FocusEvent<HTMLInputElement>) => onFocus(id, event.target.value),
34
+ [onFocus, id]
35
+ );
36
+
37
+ return (
38
+ <div
39
+ className={`flex field-radio-group ${
40
+ inline ? "flex-row gap-2" : "flex-col"
41
+ }`}
42
+ id={id}
43
+ >
44
+ {Array.isArray(enumOptions) &&
45
+ enumOptions.map((option, i) => {
46
+ const checked = option.value === value;
47
+ const itemDisabled =
48
+ enumDisabled && enumDisabled.indexOf(option.value) != -1;
49
+ const disabledCls =
50
+ disabled || itemDisabled || readonly ? "disabled" : "";
51
+
52
+ const handleChange = () => onChange(option.value);
53
+
54
+ const radio = (
55
+ <>
56
+ <input
57
+ type="radio"
58
+ className="radio radio-secondary"
59
+ id={`${id}_${i}`}
60
+ checked={checked}
61
+ name={id}
62
+ required={required}
63
+ value={option.value}
64
+ disabled={disabled || itemDisabled || readonly}
65
+ autoFocus={autofocus && i === 0}
66
+ onChange={handleChange}
67
+ onBlur={handleBlur}
68
+ onFocus={handleFocus}
69
+ />
70
+ <span className="label-text">{option.label}</span>
71
+ </>
72
+ );
73
+
74
+ return (
75
+ <label
76
+ key={i}
77
+ className={`label justify-start gap-2 ${disabledCls}`}
78
+ >
79
+ {radio}
80
+ </label>
81
+ );
82
+ })}
83
+ </div>
84
+ );
85
+ }
86
+
87
+ export default RadioWidget;
@@ -1,24 +1,24 @@
1
- import React from "react";
2
- import type { WidgetProps, GenericObjectType } from "@rjsf/utils";
3
-
4
- /** The `RangeWidget` component uses the `BaseInputTemplate` changing the type to `range` and wrapping the result
5
- * in a div, with the value along side it.
6
- *
7
- * @param props - The `WidgetProps` for this component
8
- */
9
- export default function RangeWidget<T = any, F extends GenericObjectType = any>(
10
- props: WidgetProps<T, F>
11
- ) {
12
- const {
13
- value,
14
- registry: {
15
- templates: { BaseInputTemplate },
16
- },
17
- } = props;
18
- return (
19
- <div className="field-range-wrapper">
20
- <BaseInputTemplate type="range" {...props} />
21
- <span className="range-view">{value}</span>
22
- </div>
23
- );
24
- }
1
+ import React from "react";
2
+ import type { WidgetProps, GenericObjectType } from "@rjsf/utils";
3
+
4
+ /** The `RangeWidget` component uses the `BaseInputTemplate` changing the type to `range` and wrapping the result
5
+ * in a div, with the value along side it.
6
+ *
7
+ * @param props - The `WidgetProps` for this component
8
+ */
9
+ export default function RangeWidget<T = any, F extends GenericObjectType = any>(
10
+ props: WidgetProps<T, F>
11
+ ) {
12
+ const {
13
+ value,
14
+ registry: {
15
+ templates: { BaseInputTemplate },
16
+ },
17
+ } = props;
18
+ return (
19
+ <div className="field-range-wrapper">
20
+ <BaseInputTemplate type="range" {...props} />
21
+ <span className="range-view">{value}</span>
22
+ </div>
23
+ );
24
+ }