@nolwenture/formik-jsonschema-form 1.0.0-beta.57 → 1.0.0-beta.59
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/cjs/Form/fields/FilesUploadField/FilesUploadField.js +22 -14
- package/dist/cjs/Form/fields/FilesUploadField/FilesUploadFieldInput.js +37 -15
- package/dist/esm/Form/fields/FilesUploadField/FilesUploadField.js +22 -14
- package/dist/esm/Form/fields/FilesUploadField/FilesUploadFieldInput.js +38 -16
- package/package.json +1 -1
|
@@ -14,27 +14,35 @@ const FilesUploadField = (props) => {
|
|
|
14
14
|
const { name, uiSchema } = props;
|
|
15
15
|
const { props: inputProps } = (0, react_1.useMemo)(() => (0, utils_1.extractUiSchema)(uiSchema), [uiSchema]);
|
|
16
16
|
const { setFieldValue, values } = (0, formik_1.useFormikContext)();
|
|
17
|
-
const value = (0, formik_1.getIn)(values, name);
|
|
17
|
+
const value = (0, formik_1.getIn)(values, name) ?? [];
|
|
18
18
|
const { uploadFiles, removeFile } = (0, react_1.useContext)(FilesUploadContext_1.FilesUploadContext);
|
|
19
19
|
const [uploadedFiles, setUploadedFiles] = (0, react_1.useState)([]);
|
|
20
20
|
const [uploadProgress, setUploadProgress] = (0, react_1.useState)({});
|
|
21
21
|
(0, react_1.useEffect)(() => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
22
|
+
if (Array.isArray(value)) {
|
|
23
|
+
setUploadedFiles(() => value.map((f) => ({
|
|
24
|
+
name: f.name,
|
|
25
|
+
id: f.id,
|
|
26
|
+
progressId: f.id,
|
|
27
|
+
mimeType: f.mimeType,
|
|
28
|
+
size: f.size,
|
|
29
|
+
})));
|
|
30
|
+
value.forEach((f) => setUploadProgress((prev) => ({ ...prev, [f.id]: 100 })));
|
|
31
|
+
}
|
|
32
|
+
}, [value]);
|
|
31
33
|
const handleFileUpload = async (files, setFieldValue) => {
|
|
32
34
|
const filesWithIds = [];
|
|
33
35
|
const newFiles = [];
|
|
34
36
|
for (const file of files) {
|
|
35
37
|
const progressId = file.name + file.size + file.lastModified + Math.random();
|
|
36
38
|
filesWithIds.push({ data: file, progressId });
|
|
37
|
-
newFiles.push({
|
|
39
|
+
newFiles.push({
|
|
40
|
+
name: file.name,
|
|
41
|
+
size: file.size,
|
|
42
|
+
progressId,
|
|
43
|
+
mimeType: file.type,
|
|
44
|
+
id: null,
|
|
45
|
+
});
|
|
38
46
|
}
|
|
39
47
|
setUploadedFiles((f) => f.concat(newFiles));
|
|
40
48
|
try {
|
|
@@ -51,8 +59,8 @@ const FilesUploadField = (props) => {
|
|
|
51
59
|
// remove progressId values for adding to form data
|
|
52
60
|
const newFormValues = result.map(({ progressId, ...rest }) => rest);
|
|
53
61
|
// update ids for uploaded files
|
|
54
|
-
setUploadedFiles(prev => prev.map(item => {
|
|
55
|
-
const match = result.find(f => f.progressId === item.progressId);
|
|
62
|
+
setUploadedFiles((prev) => prev.map((item) => {
|
|
63
|
+
const match = result.find((f) => f.progressId === item.progressId);
|
|
56
64
|
return match ? { ...item, id: match.id } : item;
|
|
57
65
|
}));
|
|
58
66
|
const newValue = (Array.isArray(value) ? value : []).concat(newFormValues);
|
|
@@ -69,7 +77,7 @@ const FilesUploadField = (props) => {
|
|
|
69
77
|
const { [file.progressId]: _, ...rest } = prev;
|
|
70
78
|
return rest;
|
|
71
79
|
});
|
|
72
|
-
setUploadedFiles((prev) => prev.filter(f => f.id !== file.id));
|
|
80
|
+
setUploadedFiles((prev) => prev.filter((f) => f.id !== file.id));
|
|
73
81
|
setFieldValue(name, (value || []).filter((f) => f.id !== file.id));
|
|
74
82
|
}
|
|
75
83
|
};
|
|
@@ -6,19 +6,19 @@ const react_1 = require("react");
|
|
|
6
6
|
const fa_1 = require("react-icons/fa");
|
|
7
7
|
const FormRegistry_1 = require("../../FormRegistry");
|
|
8
8
|
const mimeTypeToIcon = {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
9
|
+
pdf: fa_1.FaFilePdf,
|
|
10
|
+
audio: fa_1.FaFileAudio,
|
|
11
|
+
image: fa_1.FaFileImage,
|
|
12
|
+
csv: fa_1.FaFileCsv,
|
|
13
|
+
"wordprocessingml.document": fa_1.FaFileWord,
|
|
14
|
+
msword: fa_1.FaFileWord,
|
|
15
|
+
"vnd.ms-excel": fa_1.FaFileExcel,
|
|
16
|
+
"vnd.openxmlformats-officedocument.spreadsheetml.sheet": fa_1.FaFileExcel,
|
|
17
|
+
"vnd.ms-powerpoint": fa_1.FaFilePowerpoint,
|
|
18
|
+
"vnd.openxmlformats-officedocument.presentationml.presentation": fa_1.FaFilePowerpoint,
|
|
19
|
+
javascript: fa_1.FaFileCode,
|
|
20
|
+
html: fa_1.FaFileCode,
|
|
21
|
+
css: fa_1.FaFileCode,
|
|
22
22
|
};
|
|
23
23
|
const getFileIcon = (mimeType) => {
|
|
24
24
|
for (const key in mimeTypeToIcon) {
|
|
@@ -59,14 +59,36 @@ const FilesUploadFieldInput = ({ acceptedFiletypes, className, deleteFileAriaLab
|
|
|
59
59
|
setIsDragging(false);
|
|
60
60
|
dragCounter.current = 0;
|
|
61
61
|
if (e.dataTransfer?.files && e.dataTransfer.files.length > 0) {
|
|
62
|
-
|
|
62
|
+
const files = Array.from(e.dataTransfer.files);
|
|
63
|
+
const acceptedTypes = acceptedFiletypes?.split(",").map((type) => type.trim()).filter(Boolean) ?? [];
|
|
64
|
+
const filteredFiles = files.filter((file) => {
|
|
65
|
+
console.log(acceptedTypes);
|
|
66
|
+
if (acceptedTypes.length === 0) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
return acceptedTypes.some((acceptedType) => {
|
|
70
|
+
if (acceptedType.endsWith("/*")) {
|
|
71
|
+
const mimeTypePrefix = acceptedType.slice(0, -2);
|
|
72
|
+
return file.type.startsWith(mimeTypePrefix);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
return acceptedType === file.type;
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
if (filteredFiles.length > 0) {
|
|
80
|
+
const filteredFileList = new DataTransfer();
|
|
81
|
+
filteredFiles.forEach((f) => filteredFileList.items.add(f));
|
|
82
|
+
handleFileUpload(filteredFileList.files, setFieldValue);
|
|
83
|
+
}
|
|
63
84
|
e.dataTransfer.clearData();
|
|
64
85
|
}
|
|
65
86
|
};
|
|
66
87
|
const defaultRenderFile = (file, progress, onDelete) => ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: progress === 100 ? ((0, jsx_runtime_1.jsxs)(UploadedFileItemContainer, { children: [(0, jsx_runtime_1.jsxs)(UploadedFileInfoContainer, { children: [!hideFileTypeIcon && ((0, jsx_runtime_1.jsx)(FileTypeIcon, { children: getFileIcon(file.mimeType ?? "") })), (0, jsx_runtime_1.jsxs)(UploadedFileName, { children: [file.name, !hideFileSize && ((0, jsx_runtime_1.jsx)(FileSize, { children: ` | ${file.size ? (file.size / (1024 * 1024)).toFixed(3) : "?"} MB` }))] })] }), !hideRemoveButton && file.id && ((0, jsx_runtime_1.jsx)(RemoveButton, { "aria-label": deleteFileAriaLabel ?? "Delete file", type: "button", onClick: () => onDelete(), ...removeButton?.props, children: removeButton?.content ?? (0, jsx_runtime_1.jsx)(RemoveButtonIcon, {}) }))] })) : ((0, jsx_runtime_1.jsxs)(FileItemContainer, { children: [(0, jsx_runtime_1.jsx)(UploadingFileName, { children: file.name }), (0, jsx_runtime_1.jsx)(ProgressBarContainer, { children: (0, jsx_runtime_1.jsx)(ProgressBar, { "$progress": progress }) })] })) }));
|
|
67
88
|
const uploadedFile = renderFile ?? defaultRenderFile;
|
|
68
89
|
const fileTypes = acceptedFiletypes ? { accept: acceptedFiletypes } : {};
|
|
69
|
-
return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsxs)(FileUploadFieldContainer, { className: className, onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragOver: handleDragOver, onDrop: handleDrop, children: [isDragging && (
|
|
90
|
+
return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsxs)(FileUploadFieldContainer, { className: className, onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragOver: handleDragOver, onDrop: handleDrop, children: [isDragging && (0, jsx_runtime_1.jsx)(DragOverlay, { children: infoText }), Array.isArray(uploadedFiles) &&
|
|
91
|
+
uploadedFiles.map((file) => ((0, jsx_runtime_1.jsx)(UploadedFileWrapper, { children: uploadedFile(file, uploadProgress[file.progressId], () => handleRemoveFile(file, setFieldValue)) }, file.progressId))), !uploadedFiles || uploadedFiles.length === 0 ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [!hideUploadIcon && (0, jsx_runtime_1.jsx)(UploadIcon, {}), infoText && (0, jsx_runtime_1.jsx)(InfoText, { children: infoText }), (0, jsx_runtime_1.jsx)(Divider, { children: (0, jsx_runtime_1.jsx)(DividerText, { children: orText ?? "or" }) }), (0, jsx_runtime_1.jsx)(FileUploadButton, { "aria-label": uploadButtonText ?? "Browse files", type: "button", onClick: () => document.getElementById(name)?.click(), children: uploadButtonText ?? "Browse files" }), fileInfoText && (0, jsx_runtime_1.jsx)(FileInfoText, { children: fileInfoText })] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [infoText && ((0, jsx_runtime_1.jsxs)(InfoText, { children: [`${infoText} ${orText ?? "or"} `, (0, jsx_runtime_1.jsx)(FileUploadText, { "aria-label": uploadButtonText ?? "Browse files", onClick: () => document.getElementById(name)?.click(), children: uploadButtonText ?? "Browse files" })] })), fileInfoText && ((0, jsx_runtime_1.jsx)(FileInfoTextMinimized, { children: fileInfoText }))] })), (0, jsx_runtime_1.jsx)(HiddenFileInput, { multiple: true, ...fileTypes, id: name, name: name, type: "file", onChange: (event) => {
|
|
70
92
|
const files = event.target.files;
|
|
71
93
|
if (files) {
|
|
72
94
|
handleFileUpload(files, setFieldValue);
|
|
@@ -11,27 +11,35 @@ export const FilesUploadField = (props) => {
|
|
|
11
11
|
const { name, uiSchema } = props;
|
|
12
12
|
const { props: inputProps } = useMemo(() => extractUiSchema(uiSchema), [uiSchema]);
|
|
13
13
|
const { setFieldValue, values } = useFormikContext();
|
|
14
|
-
const value = getIn(values, name);
|
|
14
|
+
const value = getIn(values, name) ?? [];
|
|
15
15
|
const { uploadFiles, removeFile } = useContext(FilesUploadContext);
|
|
16
16
|
const [uploadedFiles, setUploadedFiles] = useState([]);
|
|
17
17
|
const [uploadProgress, setUploadProgress] = useState({});
|
|
18
18
|
useEffect(() => {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
19
|
+
if (Array.isArray(value)) {
|
|
20
|
+
setUploadedFiles(() => value.map((f) => ({
|
|
21
|
+
name: f.name,
|
|
22
|
+
id: f.id,
|
|
23
|
+
progressId: f.id,
|
|
24
|
+
mimeType: f.mimeType,
|
|
25
|
+
size: f.size,
|
|
26
|
+
})));
|
|
27
|
+
value.forEach((f) => setUploadProgress((prev) => ({ ...prev, [f.id]: 100 })));
|
|
28
|
+
}
|
|
29
|
+
}, [value]);
|
|
28
30
|
const handleFileUpload = async (files, setFieldValue) => {
|
|
29
31
|
const filesWithIds = [];
|
|
30
32
|
const newFiles = [];
|
|
31
33
|
for (const file of files) {
|
|
32
34
|
const progressId = file.name + file.size + file.lastModified + Math.random();
|
|
33
35
|
filesWithIds.push({ data: file, progressId });
|
|
34
|
-
newFiles.push({
|
|
36
|
+
newFiles.push({
|
|
37
|
+
name: file.name,
|
|
38
|
+
size: file.size,
|
|
39
|
+
progressId,
|
|
40
|
+
mimeType: file.type,
|
|
41
|
+
id: null,
|
|
42
|
+
});
|
|
35
43
|
}
|
|
36
44
|
setUploadedFiles((f) => f.concat(newFiles));
|
|
37
45
|
try {
|
|
@@ -48,8 +56,8 @@ export const FilesUploadField = (props) => {
|
|
|
48
56
|
// remove progressId values for adding to form data
|
|
49
57
|
const newFormValues = result.map(({ progressId, ...rest }) => rest);
|
|
50
58
|
// update ids for uploaded files
|
|
51
|
-
setUploadedFiles(prev => prev.map(item => {
|
|
52
|
-
const match = result.find(f => f.progressId === item.progressId);
|
|
59
|
+
setUploadedFiles((prev) => prev.map((item) => {
|
|
60
|
+
const match = result.find((f) => f.progressId === item.progressId);
|
|
53
61
|
return match ? { ...item, id: match.id } : item;
|
|
54
62
|
}));
|
|
55
63
|
const newValue = (Array.isArray(value) ? value : []).concat(newFormValues);
|
|
@@ -66,7 +74,7 @@ export const FilesUploadField = (props) => {
|
|
|
66
74
|
const { [file.progressId]: _, ...rest } = prev;
|
|
67
75
|
return rest;
|
|
68
76
|
});
|
|
69
|
-
setUploadedFiles((prev) => prev.filter(f => f.id !== file.id));
|
|
77
|
+
setUploadedFiles((prev) => prev.filter((f) => f.id !== file.id));
|
|
70
78
|
setFieldValue(name, (value || []).filter((f) => f.id !== file.id));
|
|
71
79
|
}
|
|
72
80
|
};
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useContext, useState, useRef } from "react";
|
|
3
|
-
import { FaFile, FaFilePdf, FaFileAudio, FaFileCode, FaFileCsv, FaFileExcel, FaFileImage, FaFilePowerpoint, FaFileWord } from "react-icons/fa";
|
|
3
|
+
import { FaFile, FaFilePdf, FaFileAudio, FaFileCode, FaFileCsv, FaFileExcel, FaFileImage, FaFilePowerpoint, FaFileWord, } from "react-icons/fa";
|
|
4
4
|
import { FormRegistry } from "../../FormRegistry";
|
|
5
5
|
const mimeTypeToIcon = {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
6
|
+
pdf: FaFilePdf,
|
|
7
|
+
audio: FaFileAudio,
|
|
8
|
+
image: FaFileImage,
|
|
9
|
+
csv: FaFileCsv,
|
|
10
|
+
"wordprocessingml.document": FaFileWord,
|
|
11
|
+
msword: FaFileWord,
|
|
12
|
+
"vnd.ms-excel": FaFileExcel,
|
|
13
|
+
"vnd.openxmlformats-officedocument.spreadsheetml.sheet": FaFileExcel,
|
|
14
|
+
"vnd.ms-powerpoint": FaFilePowerpoint,
|
|
15
|
+
"vnd.openxmlformats-officedocument.presentationml.presentation": FaFilePowerpoint,
|
|
16
|
+
javascript: FaFileCode,
|
|
17
|
+
html: FaFileCode,
|
|
18
|
+
css: FaFileCode,
|
|
19
19
|
};
|
|
20
20
|
const getFileIcon = (mimeType) => {
|
|
21
21
|
for (const key in mimeTypeToIcon) {
|
|
@@ -56,14 +56,36 @@ export const FilesUploadFieldInput = ({ acceptedFiletypes, className, deleteFile
|
|
|
56
56
|
setIsDragging(false);
|
|
57
57
|
dragCounter.current = 0;
|
|
58
58
|
if (e.dataTransfer?.files && e.dataTransfer.files.length > 0) {
|
|
59
|
-
|
|
59
|
+
const files = Array.from(e.dataTransfer.files);
|
|
60
|
+
const acceptedTypes = acceptedFiletypes?.split(",").map((type) => type.trim()).filter(Boolean) ?? [];
|
|
61
|
+
const filteredFiles = files.filter((file) => {
|
|
62
|
+
console.log(acceptedTypes);
|
|
63
|
+
if (acceptedTypes.length === 0) {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
return acceptedTypes.some((acceptedType) => {
|
|
67
|
+
if (acceptedType.endsWith("/*")) {
|
|
68
|
+
const mimeTypePrefix = acceptedType.slice(0, -2);
|
|
69
|
+
return file.type.startsWith(mimeTypePrefix);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
return acceptedType === file.type;
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
if (filteredFiles.length > 0) {
|
|
77
|
+
const filteredFileList = new DataTransfer();
|
|
78
|
+
filteredFiles.forEach((f) => filteredFileList.items.add(f));
|
|
79
|
+
handleFileUpload(filteredFileList.files, setFieldValue);
|
|
80
|
+
}
|
|
60
81
|
e.dataTransfer.clearData();
|
|
61
82
|
}
|
|
62
83
|
};
|
|
63
84
|
const defaultRenderFile = (file, progress, onDelete) => (_jsx(_Fragment, { children: progress === 100 ? (_jsxs(UploadedFileItemContainer, { children: [_jsxs(UploadedFileInfoContainer, { children: [!hideFileTypeIcon && (_jsx(FileTypeIcon, { children: getFileIcon(file.mimeType ?? "") })), _jsxs(UploadedFileName, { children: [file.name, !hideFileSize && (_jsx(FileSize, { children: ` | ${file.size ? (file.size / (1024 * 1024)).toFixed(3) : "?"} MB` }))] })] }), !hideRemoveButton && file.id && (_jsx(RemoveButton, { "aria-label": deleteFileAriaLabel ?? "Delete file", type: "button", onClick: () => onDelete(), ...removeButton?.props, children: removeButton?.content ?? _jsx(RemoveButtonIcon, {}) }))] })) : (_jsxs(FileItemContainer, { children: [_jsx(UploadingFileName, { children: file.name }), _jsx(ProgressBarContainer, { children: _jsx(ProgressBar, { "$progress": progress }) })] })) }));
|
|
64
85
|
const uploadedFile = renderFile ?? defaultRenderFile;
|
|
65
86
|
const fileTypes = acceptedFiletypes ? { accept: acceptedFiletypes } : {};
|
|
66
|
-
return (_jsx(_Fragment, { children: _jsxs(FileUploadFieldContainer, { className: className, onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragOver: handleDragOver, onDrop: handleDrop, children: [isDragging &&
|
|
87
|
+
return (_jsx(_Fragment, { children: _jsxs(FileUploadFieldContainer, { className: className, onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragOver: handleDragOver, onDrop: handleDrop, children: [isDragging && _jsx(DragOverlay, { children: infoText }), Array.isArray(uploadedFiles) &&
|
|
88
|
+
uploadedFiles.map((file) => (_jsx(UploadedFileWrapper, { children: uploadedFile(file, uploadProgress[file.progressId], () => handleRemoveFile(file, setFieldValue)) }, file.progressId))), !uploadedFiles || uploadedFiles.length === 0 ? (_jsxs(_Fragment, { children: [!hideUploadIcon && _jsx(UploadIcon, {}), infoText && _jsx(InfoText, { children: infoText }), _jsx(Divider, { children: _jsx(DividerText, { children: orText ?? "or" }) }), _jsx(FileUploadButton, { "aria-label": uploadButtonText ?? "Browse files", type: "button", onClick: () => document.getElementById(name)?.click(), children: uploadButtonText ?? "Browse files" }), fileInfoText && _jsx(FileInfoText, { children: fileInfoText })] })) : (_jsxs(_Fragment, { children: [infoText && (_jsxs(InfoText, { children: [`${infoText} ${orText ?? "or"} `, _jsx(FileUploadText, { "aria-label": uploadButtonText ?? "Browse files", onClick: () => document.getElementById(name)?.click(), children: uploadButtonText ?? "Browse files" })] })), fileInfoText && (_jsx(FileInfoTextMinimized, { children: fileInfoText }))] })), _jsx(HiddenFileInput, { multiple: true, ...fileTypes, id: name, name: name, type: "file", onChange: (event) => {
|
|
67
89
|
const files = event.target.files;
|
|
68
90
|
if (files) {
|
|
69
91
|
handleFileUpload(files, setFieldValue);
|
package/package.json
CHANGED