@transferwise/components 0.0.0-experimental-4b8556a → 0.0.0-experimental-3064bdb
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/build/alert/Alert.js +52 -49
- package/build/alert/Alert.js.map +1 -1
- package/build/alert/Alert.mjs +53 -50
- package/build/alert/Alert.mjs.map +1 -1
- package/build/i18n/en.json +2 -0
- package/build/i18n/en.json.js +2 -0
- package/build/i18n/en.json.js.map +1 -1
- package/build/i18n/en.json.mjs +2 -0
- package/build/i18n/en.json.mjs.map +1 -1
- package/build/main.css +214 -0
- package/build/styles/main.css +214 -0
- package/build/styles/table/Table.css +214 -0
- package/build/types/alert/Alert.d.ts +3 -1
- package/build/types/alert/Alert.d.ts.map +1 -1
- package/build/types/table/Table.d.ts +23 -0
- package/build/types/table/Table.d.ts.map +1 -0
- package/build/types/table/Table.messages.d.ts +12 -0
- package/build/types/table/Table.messages.d.ts.map +1 -0
- package/build/types/table/TableCell.d.ts +37 -0
- package/build/types/table/TableCell.d.ts.map +1 -0
- package/build/types/table/TableHeader.d.ts +12 -0
- package/build/types/table/TableHeader.d.ts.map +1 -0
- package/build/types/table/TableRow.d.ts +17 -0
- package/build/types/table/TableRow.d.ts.map +1 -0
- package/build/types/table/TableStatusText.d.ts +9 -0
- package/build/types/table/TableStatusText.d.ts.map +1 -0
- package/build/types/table/index.d.ts +6 -0
- package/build/types/table/index.d.ts.map +1 -0
- package/build/types/uploadInput/UploadInput.d.ts +0 -9
- package/build/types/uploadInput/UploadInput.d.ts.map +1 -1
- package/build/types/uploadInput/uploadItem/UploadItem.d.ts +1 -3
- package/build/types/uploadInput/uploadItem/UploadItem.d.ts.map +1 -1
- package/build/types/uploadInput/uploadItem/UploadItemLink.d.ts.map +1 -1
- package/build/uploadInput/UploadInput.js +51 -57
- package/build/uploadInput/UploadInput.js.map +1 -1
- package/build/uploadInput/UploadInput.mjs +51 -57
- package/build/uploadInput/UploadInput.mjs.map +1 -1
- package/build/uploadInput/uploadItem/UploadItem.js +3 -8
- package/build/uploadInput/uploadItem/UploadItem.js.map +1 -1
- package/build/uploadInput/uploadItem/UploadItem.mjs +3 -8
- package/build/uploadInput/uploadItem/UploadItem.mjs.map +1 -1
- package/build/uploadInput/uploadItem/UploadItemLink.js +0 -1
- package/build/uploadInput/uploadItem/UploadItemLink.js.map +1 -1
- package/build/uploadInput/uploadItem/UploadItemLink.mjs +0 -1
- package/build/uploadInput/uploadItem/UploadItemLink.mjs.map +1 -1
- package/package.json +3 -3
- package/src/alert/Alert.spec.tsx +20 -0
- package/src/alert/Alert.story.tsx +50 -2
- package/src/alert/Alert.tsx +57 -50
- package/src/i18n/en.json +2 -0
- package/src/main.css +214 -0
- package/src/main.less +1 -0
- package/src/table/Table.css +214 -0
- package/src/table/Table.less +253 -0
- package/src/table/Table.messages.ts +12 -0
- package/src/table/Table.spec.tsx +87 -0
- package/src/table/Table.story.tsx +352 -0
- package/src/table/Table.tsx +121 -0
- package/src/table/TableCell.spec.tsx +298 -0
- package/src/table/TableCell.tsx +153 -0
- package/src/table/TableHeader.spec.tsx +58 -0
- package/src/table/TableHeader.tsx +50 -0
- package/src/table/TableRow.spec.tsx +104 -0
- package/src/table/TableRow.tsx +62 -0
- package/src/table/TableStatusText.spec.tsx +53 -0
- package/src/table/TableStatusText.tsx +35 -0
- package/src/table/index.ts +11 -0
- package/src/uploadInput/UploadInput.spec.tsx +6 -150
- package/src/uploadInput/UploadInput.tsx +60 -83
- package/src/uploadInput/uploadItem/UploadItem.tsx +6 -12
- package/src/uploadInput/uploadItem/UploadItemLink.tsx +1 -9
|
@@ -24,15 +24,6 @@ function generateFileId(file) {
|
|
|
24
24
|
const uploadTimeStamp = new Date().getTime();
|
|
25
25
|
return `${name}_${size}_${uploadTimeStamp}`;
|
|
26
26
|
}
|
|
27
|
-
/**
|
|
28
|
-
* The component allows users to upload files, manage the list of uploaded files,
|
|
29
|
-
* and handle file validation and deletion.
|
|
30
|
-
*
|
|
31
|
-
* @param {UploadInputProps} props - The properties for the UploadInput component.
|
|
32
|
-
*
|
|
33
|
-
* @see {@link UploadInput} for further information.
|
|
34
|
-
* @see {@link https://storybook.wise.design/?path=/docs/forms-uploadinput--docs|Storybook Wise Design}
|
|
35
|
-
*/
|
|
36
27
|
const UploadInput = ({
|
|
37
28
|
files = [],
|
|
38
29
|
fileInputName = 'file',
|
|
@@ -58,7 +49,7 @@ const UploadInput = ({
|
|
|
58
49
|
nonLabelable: true
|
|
59
50
|
});
|
|
60
51
|
const [markedFileForDelete, setMarkedFileForDelete] = React.useState(null);
|
|
61
|
-
const [
|
|
52
|
+
const [fileToRemoveIndex, setFileToRemoveIndex] = React.useState(null);
|
|
62
53
|
const [mounted, setMounted] = React.useState(false);
|
|
63
54
|
const {
|
|
64
55
|
formatMessage
|
|
@@ -66,59 +57,44 @@ const UploadInput = ({
|
|
|
66
57
|
const itemRefs = React.useRef([]);
|
|
67
58
|
const uploadInputRef = React.useRef(null);
|
|
68
59
|
const PROGRESS_STATUSES = new Set([status.Status.PENDING, status.Status.PROCESSING]);
|
|
69
|
-
const FOCUS_TIMEOUT = 400; // Set to 400ms to allow animations and Modal to unmount
|
|
70
60
|
const [uploadedFiles, setUploadedFiles] = React.useState(multiple || files.length === 0 ? files : [files[0]]);
|
|
71
61
|
const uploadedFilesListReference = React.useRef(multiple || files.length === 0 ? files : [files[0]]);
|
|
72
|
-
function updateFileList(updateFn) {
|
|
73
|
-
setUploadedFiles(updateFn);
|
|
74
|
-
uploadedFilesListReference.current = updateFn(uploadedFilesListReference.current);
|
|
75
|
-
}
|
|
76
62
|
function addFileToList(recentUploadedFile) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
function modifyFileInList(file, updates) {
|
|
83
|
-
updateFileList(list => list.map(fileInList => fileInList === file || fileInList.id === file.id ? {
|
|
84
|
-
...file,
|
|
85
|
-
...updates
|
|
86
|
-
} : fileInList));
|
|
63
|
+
function addToList(listToAddTo) {
|
|
64
|
+
return [...listToAddTo, recentUploadedFile];
|
|
65
|
+
}
|
|
66
|
+
setUploadedFiles(addToList);
|
|
67
|
+
uploadedFilesListReference.current = addToList(uploadedFilesListReference.current);
|
|
87
68
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
69
|
+
const removeFileFromList = file => {
|
|
70
|
+
function filterOutFrom(listToFilterFrom) {
|
|
71
|
+
return listToFilterFrom.filter(fileInList => file !== fileInList && file.id !== fileInList.id);
|
|
72
|
+
}
|
|
73
|
+
setUploadedFiles(filterOutFrom);
|
|
74
|
+
uploadedFilesListReference.current = filterOutFrom(uploadedFilesListReference.current);
|
|
75
|
+
};
|
|
76
|
+
const modifyFileInList = (file, updates) => {
|
|
77
|
+
const updateListItem = listToUpdate => listToUpdate.map(fileInList => {
|
|
78
|
+
return fileInList === file || fileInList.id === file.id ? {
|
|
79
|
+
...file,
|
|
80
|
+
...updates
|
|
81
|
+
} : fileInList;
|
|
100
82
|
});
|
|
101
|
-
|
|
83
|
+
setUploadedFiles(updateListItem);
|
|
84
|
+
uploadedFilesListReference.current = updateListItem(uploadedFilesListReference.current);
|
|
85
|
+
};
|
|
86
|
+
const [fileToRemove, setFileToRemove] = React.useState(null);
|
|
102
87
|
const removeFile = file => {
|
|
103
88
|
const {
|
|
104
89
|
id,
|
|
105
90
|
status: status$1
|
|
106
91
|
} = file;
|
|
107
92
|
const index = uploadedFiles.findIndex(f => f.id === file.id);
|
|
108
|
-
|
|
109
|
-
const nextIndexId = uploadedFiles[index + 1]?.id;
|
|
110
|
-
const focusId = nextIndexId ?? null;
|
|
93
|
+
setFileToRemoveIndex(index);
|
|
111
94
|
if (status$1 === status.Status.FAILED) {
|
|
112
|
-
setNextFocusItem({
|
|
113
|
-
focusId: focusId ?? null,
|
|
114
|
-
isLastItem
|
|
115
|
-
});
|
|
116
95
|
removeFileFromList(file);
|
|
96
|
+
setFileToRemove(file);
|
|
117
97
|
} else if (onDeleteFile && id) {
|
|
118
|
-
setNextFocusItem({
|
|
119
|
-
focusId,
|
|
120
|
-
isLastItem
|
|
121
|
-
});
|
|
122
98
|
modifyFileInList(file, {
|
|
123
99
|
status: status.Status.PROCESSING,
|
|
124
100
|
error: undefined
|
|
@@ -126,13 +102,11 @@ const UploadInput = ({
|
|
|
126
102
|
onDeleteFile(id).then(() => {
|
|
127
103
|
removeFileFromList(file);
|
|
128
104
|
}).catch(error => {
|
|
129
|
-
setNextFocusItem({
|
|
130
|
-
focusId,
|
|
131
|
-
isLastItem
|
|
132
|
-
});
|
|
133
105
|
modifyFileInList(file, {
|
|
134
106
|
error: error
|
|
135
107
|
});
|
|
108
|
+
}).finally(() => {
|
|
109
|
+
setFileToRemove(file);
|
|
136
110
|
});
|
|
137
111
|
}
|
|
138
112
|
};
|
|
@@ -164,17 +138,22 @@ const UploadInput = ({
|
|
|
164
138
|
const numberOfValidFiles = getNumberOfFilesUploaded();
|
|
165
139
|
return numberOfValidFiles >= maxFiles;
|
|
166
140
|
}
|
|
141
|
+
// One or more files selected, create entries for them
|
|
167
142
|
const addFiles = selectedFiles => {
|
|
168
143
|
for (let i = 0; i < selectedFiles.length; i += 1) {
|
|
169
144
|
const file = selectedFiles.item(i);
|
|
145
|
+
// Returning a FormData[] array instead of FileList so we can filter out incorrect files
|
|
170
146
|
const formData = new FormData();
|
|
171
147
|
if (file) {
|
|
172
148
|
generateFileId(file);
|
|
173
149
|
const allowedFileTypes = typeof fileTypes === 'string' ? fileTypes : fileTypes.join(',');
|
|
150
|
+
// Check if file type is valid
|
|
174
151
|
if (!isTypeValid.isTypeValid(file, allowedFileTypes)) {
|
|
175
152
|
handleFileUploadFailure(file, formatMessage(UploadInput_messages.fileTypeNotSupported));
|
|
176
153
|
continue;
|
|
177
154
|
}
|
|
155
|
+
// Check if the filesize is valid
|
|
156
|
+
// Convert to rough bytes
|
|
178
157
|
if (!isSizeValid.isSizeValid(file, sizeLimit * 1000)) {
|
|
179
158
|
const failureMessage = sizeLimitErrorMessage || formatMessage(UploadInput_messages.fileIsTooLarge);
|
|
180
159
|
handleFileUploadFailure(file, failureMessage);
|
|
@@ -187,10 +166,13 @@ const UploadInput = ({
|
|
|
187
166
|
handleFileUploadFailure(file, failureMessage);
|
|
188
167
|
continue;
|
|
189
168
|
}
|
|
169
|
+
// Check if the file is already in the list
|
|
190
170
|
const existingFile = uploadedFiles.find(f => f.filename === file.name);
|
|
191
171
|
if (existingFile) {
|
|
172
|
+
// Remove the file from the list before adding it again
|
|
192
173
|
removeFileFromList(existingFile);
|
|
193
174
|
}
|
|
175
|
+
// Add the file to the list
|
|
194
176
|
formData.append(fileInputName, file);
|
|
195
177
|
const pendingFile = {
|
|
196
178
|
id: generateFileId(file),
|
|
@@ -198,11 +180,13 @@ const UploadInput = ({
|
|
|
198
180
|
status: status.Status.PENDING
|
|
199
181
|
};
|
|
200
182
|
addFileToList(pendingFile);
|
|
183
|
+
// Start uploading the file
|
|
201
184
|
onUploadFile(formData).then(({
|
|
202
185
|
id,
|
|
203
186
|
url,
|
|
204
187
|
error
|
|
205
188
|
}) => {
|
|
189
|
+
// Replace the temporary id with the final one received from the API, and also set any errors
|
|
206
190
|
modifyFileInList(pendingFile, {
|
|
207
191
|
id,
|
|
208
192
|
url,
|
|
@@ -216,17 +200,27 @@ const UploadInput = ({
|
|
|
216
200
|
});
|
|
217
201
|
});
|
|
218
202
|
if (!multiple) {
|
|
203
|
+
// Only upload a single file
|
|
219
204
|
break;
|
|
220
205
|
}
|
|
221
206
|
}
|
|
222
207
|
}
|
|
223
208
|
};
|
|
224
209
|
React.useLayoutEffect(() => {
|
|
225
|
-
if (
|
|
226
|
-
|
|
210
|
+
if (fileToRemove && fileToRemoveIndex !== null) {
|
|
211
|
+
requestAnimationFrame(() => {
|
|
212
|
+
const nextFocusIndex = Math.min(fileToRemoveIndex, uploadedFiles.length - 1);
|
|
213
|
+
if (itemRefs.current[nextFocusIndex]) {
|
|
214
|
+
itemRefs.current[nextFocusIndex].focus(); // Focus the next UploadItem
|
|
215
|
+
} else {
|
|
216
|
+
// If there's only one item left, focus the UploadButton
|
|
217
|
+
uploadInputRef.current?.focus();
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
setFileToRemove(null); // Reset the state
|
|
221
|
+
setFileToRemoveIndex(null); // Reset the index
|
|
227
222
|
}
|
|
228
|
-
|
|
229
|
-
}, [nextFocusItem]);
|
|
223
|
+
}, [uploadedFiles, fileToRemove, fileToRemoveIndex, itemRefs, uploadInputRef]);
|
|
230
224
|
React.useEffect(() => {
|
|
231
225
|
setMounted(true);
|
|
232
226
|
}, []);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UploadInput.js","sources":["../../src/uploadInput/UploadInput.tsx"],"sourcesContent":["import { clsx } from 'clsx';\nimport { useEffect, useLayoutEffect, useRef, useState } from 'react';\nimport { useIntl } from 'react-intl';\n\nimport Button from '../button';\nimport { CommonProps, ControlType, Priority, Status } from '../common';\nimport { useInputAttributes } from '../inputs/contexts';\nimport Modal from '../modal';\nimport { isSizeValid } from '../upload/utils/isSizeValid';\nimport { isTypeValid } from '../upload/utils/isTypeValid';\n\nimport MESSAGES from './UploadInput.messages';\nimport { UploadedFile, UploadError, UploadResponse } from './types';\nimport UploadButton, { UploadButtonProps } from './uploadButton/UploadButton';\nimport { DEFAULT_SIZE_LIMIT, imageFileTypes } from './uploadButton/defaults';\nimport UploadItem, { UploadItemProps } from './uploadItem/UploadItem';\n\nexport type UploadInputProps = {\n /**\n * List of already existing, failed or in progress files\n */\n files?: readonly UploadedFile[];\n\n /**\n * The key of the file in the returned FormData object (default: file)\n */\n fileInputName?: string;\n\n /**\n * Callback that handles form submission\n *\n * @param formData\n */\n onUploadFile: (formData: FormData) => Promise<UploadResponse>;\n\n /**\n * Provide a callback if the file can be removed/deleted from the server\n * Your app is responsible for reloading the uploaded files list and updating the component to ensure that the file has in fact been deleted successfully\n *\n * @param id\n */\n onDeleteFile?: (id: string | number) => Promise<any>;\n\n /**\n * Provide a callback to trigger on validation error\n *\n * @param file\n */\n onValidationError?: (file: UploadedFile) => void;\n\n /**\n * Provide a callback to trigger on change whenever the files are updated\n *\n * @param files\n */\n onFilesChange?: (files: UploadedFile[]) => void;\n\n /**\n * Confirmation modal displayed on delete\n */\n deleteConfirm?: {\n /**\n * The title of the confirmation modal on delete\n */\n title?: string;\n\n /**\n * The body of the confirmation modal on delete\n */\n body?: React.ReactNode;\n\n /**\n * The confirm button text of the confirmation modal on delete\n */\n confirmText?: string;\n\n /**\n * The cancel button text of the confirmation modal on delete\n */\n cancelText?: string;\n };\n\n /**\n * Maximum number of files allowed, if provided, shows error below file item\n */\n maxFiles?: number;\n\n /**\n * Error message to show when the maximum number of files are uploaded already\n */\n maxFilesErrorMessage?: string;\n\n /**\n * Error message to show when files over a allowed size limit are uploaded\n */\n sizeLimitErrorMessage?: string;\n} & Pick<\n UploadButtonProps,\n 'disabled' | 'multiple' | 'fileTypes' | 'sizeLimit' | 'description' | 'id' | 'uploadButtonTitle'\n> & { onDownload?: UploadItemProps['onDownload'] } & CommonProps;\n\n/**\n * Interface representing a reference to an UploadItem component.\n * Provides a method to focus the UploadItem.\n */\ninterface UploadItemRef {\n /**\n * Focuses the UploadItem component.\n */\n focus: () => void;\n}\n\n/**\n * Represents the next item to focus on after an action is performed.\n */\ntype NextFocusItem = {\n /** The ID of the next item to focus on. If null, no specific item is targeted. */\n focusId: number | null;\n /** Indicates if the next item to focus on is the last item in the list. */\n isLastItem: boolean;\n};\n\n/**\n * Generates a unique ID for a file based on its name, size, and the current timestamp\n */\nfunction generateFileId(file: File) {\n const { name, size } = file;\n const uploadTimeStamp = new Date().getTime();\n return `${name}_${size}_${uploadTimeStamp}`;\n}\n\n/**\n * The component allows users to upload files, manage the list of uploaded files,\n * and handle file validation and deletion.\n *\n * @param {UploadInputProps} props - The properties for the UploadInput component.\n *\n * @see {@link UploadInput} for further information.\n * @see {@link https://storybook.wise.design/?path=/docs/forms-uploadinput--docs|Storybook Wise Design}\n */\nconst UploadInput = ({\n files = [],\n fileInputName = 'file',\n className,\n deleteConfirm,\n disabled,\n multiple = false,\n fileTypes = imageFileTypes,\n sizeLimit = DEFAULT_SIZE_LIMIT,\n description,\n onUploadFile,\n onDeleteFile,\n onValidationError,\n onFilesChange,\n onDownload,\n maxFiles,\n maxFilesErrorMessage,\n id,\n sizeLimitErrorMessage,\n uploadButtonTitle,\n}: UploadInputProps) => {\n const inputAttributes = useInputAttributes({ nonLabelable: true });\n const [markedFileForDelete, setMarkedFileForDelete] = useState<UploadedFile | null>(null);\n const [nextFocusItem, setNextFocusItem] = useState<NextFocusItem | null>(null);\n const [mounted, setMounted] = useState(false);\n const { formatMessage } = useIntl();\n const itemRefs = useRef<(HTMLDivElement | UploadItemRef | null)[]>([]);\n const uploadInputRef = useRef<HTMLInputElement | null>(null);\n\n const PROGRESS_STATUSES = new Set([Status.PENDING, Status.PROCESSING]);\n const FOCUS_TIMEOUT = 400; // Set to 400ms to allow animations and Modal to unmount\n\n const [uploadedFiles, setUploadedFiles] = useState<readonly UploadedFile[]>(\n multiple || files.length === 0 ? files : [files[0]],\n );\n\n const uploadedFilesListReference = useRef(multiple || files.length === 0 ? files : [files[0]]);\n\n function updateFileList(updateFn: (list: readonly UploadedFile[]) => readonly UploadedFile[]) {\n setUploadedFiles(updateFn);\n uploadedFilesListReference.current = updateFn(uploadedFilesListReference.current);\n }\n\n function addFileToList(recentUploadedFile: UploadedFile) {\n updateFileList((list) => [...list, recentUploadedFile]);\n }\n\n function removeFileFromList(file: UploadedFile) {\n updateFileList((list) =>\n list.filter((fileInList) => file !== fileInList && file.id !== fileInList.id),\n );\n }\n\n function modifyFileInList(file: UploadedFile, updates: Partial<UploadedFile>) {\n updateFileList((list) =>\n list.map((fileInList) =>\n fileInList === file || fileInList.id === file.id ? { ...file, ...updates } : fileInList,\n ),\n );\n }\n\n function focusNextItem(\n focusId: number | null = null,\n isLastItem = false,\n timeout: number = FOCUS_TIMEOUT,\n ) {\n requestAnimationFrame(() => {\n setTimeout(() => {\n const nextFocusIdIndex = focusId\n ? uploadedFilesListReference.current.findIndex(\n (item: UploadedFile) => item.id === focusId,\n )\n : -1;\n\n if (isLastItem || nextFocusIdIndex === -1) {\n // If it's the last item or no next item, focus on the upload input reference\n uploadInputRef.current?.focus();\n } else {\n const nextFocusElement = itemRefs.current[nextFocusIdIndex];\n nextFocusElement?.focus();\n }\n }, timeout);\n });\n }\n\n const removeFile = (file: UploadedFile) => {\n const { id, status } = file;\n const index = uploadedFiles.findIndex((f) => f.id === file.id);\n const isLastItem = index === uploadedFiles.length - 1;\n const nextIndexId = uploadedFiles[index + 1]?.id as number;\n const focusId = nextIndexId ?? null;\n\n if (status === Status.FAILED) {\n setNextFocusItem({ focusId: focusId ?? null, isLastItem });\n removeFileFromList(file);\n } else if (onDeleteFile && id) {\n setNextFocusItem({ focusId, isLastItem });\n modifyFileInList(file, { status: Status.PROCESSING, error: undefined });\n\n onDeleteFile(id)\n .then(() => {\n removeFileFromList(file);\n })\n .catch((error) => {\n setNextFocusItem({ focusId, isLastItem });\n modifyFileInList(file, { error: error as UploadError });\n });\n }\n };\n\n function handleFileUploadFailure(file: File, failureMessage: string) {\n const { name } = file;\n const id = generateFileId(file);\n const failedUpload = {\n id,\n filename: name,\n status: Status.FAILED,\n error: failureMessage,\n };\n\n addFileToList(failedUpload);\n\n if (onValidationError) {\n onValidationError(failedUpload);\n }\n }\n\n function getNumberOfFilesUploaded() {\n const uploadInitiatedStatus = new Set([Status.SUCCEEDED, Status.PENDING]);\n const validFiles = uploadedFilesListReference.current.filter(\n (file) => file.status && uploadInitiatedStatus.has(file.status),\n );\n return validFiles.length;\n }\n\n function areMaximumFilesUploadedAlready() {\n if (!maxFiles) {\n return false;\n }\n\n const numberOfValidFiles = getNumberOfFilesUploaded();\n return numberOfValidFiles >= maxFiles;\n }\n\n const addFiles = (selectedFiles: FileList) => {\n for (let i = 0; i < selectedFiles.length; i += 1) {\n const file = selectedFiles.item(i);\n\n const formData = new FormData();\n\n if (file) {\n const { name } = file;\n const id = generateFileId(file);\n\n const allowedFileTypes = typeof fileTypes === 'string' ? fileTypes : fileTypes.join(',');\n\n if (!isTypeValid(file, allowedFileTypes)) {\n handleFileUploadFailure(file, formatMessage(MESSAGES.fileTypeNotSupported));\n continue;\n }\n\n if (!isSizeValid(file, sizeLimit * 1000)) {\n const failureMessage = sizeLimitErrorMessage || formatMessage(MESSAGES.fileIsTooLarge);\n handleFileUploadFailure(file, failureMessage);\n continue;\n }\n\n if (areMaximumFilesUploadedAlready()) {\n const failureMessage =\n maxFilesErrorMessage ||\n formatMessage(MESSAGES.maximumFilesAlreadyUploaded, { maxFilesAllowed: maxFiles });\n handleFileUploadFailure(file, failureMessage);\n continue;\n }\n\n const existingFile = uploadedFiles.find((f) => f.filename === file.name);\n if (existingFile) {\n removeFileFromList(existingFile);\n }\n\n formData.append(fileInputName, file);\n const pendingFile = {\n id: generateFileId(file),\n filename: file.name,\n status: Status.PENDING,\n };\n\n addFileToList(pendingFile);\n\n onUploadFile(formData)\n .then(({ id, url, error }: UploadResponse) => {\n modifyFileInList(pendingFile, { id, url, error, status: Status.SUCCEEDED });\n })\n .catch((error) => {\n modifyFileInList(pendingFile, { error: error as UploadError, status: Status.FAILED });\n });\n\n if (!multiple) {\n break;\n }\n }\n }\n };\n\n useLayoutEffect(() => {\n if (nextFocusItem) {\n focusNextItem(nextFocusItem.focusId, nextFocusItem.isLastItem);\n }\n setNextFocusItem(null);\n }, [nextFocusItem]);\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n if (onFilesChange && mounted) {\n onFilesChange([...uploadedFiles]);\n }\n }, [onFilesChange, uploadedFiles]); // eslint-disable-line react-hooks/exhaustive-deps\n\n return (\n <>\n <div\n role=\"group\"\n className={clsx('np-upload-input', className, { disabled })}\n {...inputAttributes}\n >\n <div\n className=\"np-upload-input__section\"\n aria-live=\"polite\"\n aria-relevant=\"all\"\n role=\"region\"\n >\n {uploadedFiles.map((file, index) => (\n <UploadItem\n key={file.id}\n ref={(el: UploadItemRef | null) => {\n itemRefs.current[index] = el;\n }}\n file={file}\n singleFileUpload={!multiple}\n canDelete={\n (!!onDeleteFile || file.status === Status.FAILED) &&\n (!file.status || !PROGRESS_STATUSES.has(file.status))\n }\n onDelete={\n file.status === Status.FAILED\n ? () => removeFile(file)\n : () => setMarkedFileForDelete(file)\n }\n onDownload={onDownload}\n />\n ))}\n </div>\n {(multiple || (!multiple && !uploadedFiles.length)) && (\n <div className=\"np-upload-input__section np-upload-input__section--uploader\">\n <UploadButton\n ref={uploadInputRef}\n id={id}\n uploadButtonTitle={uploadButtonTitle}\n disabled={areMaximumFilesUploadedAlready() || disabled}\n multiple={multiple}\n fileTypes={fileTypes}\n sizeLimit={sizeLimit}\n description={description}\n maxFiles={maxFiles}\n withEntries={Boolean(uploadedFiles.length)}\n onChange={addFiles}\n />\n </div>\n )}\n </div>\n <Modal\n title={\n deleteConfirm?.title !== undefined\n ? deleteConfirm.title\n : formatMessage(MESSAGES.deleteModalTitle)\n }\n body={\n deleteConfirm?.body !== undefined\n ? deleteConfirm.body\n : formatMessage(MESSAGES.deleteModalBody)\n }\n open={!!markedFileForDelete}\n footer={\n <>\n <Button\n block\n onClick={() => {\n setMarkedFileForDelete(null);\n }}\n >\n {deleteConfirm?.cancelText || formatMessage(MESSAGES.deleteModalCancelButtonText)}\n </Button>\n <Button\n block\n priority={Priority.SECONDARY}\n type={ControlType.NEGATIVE}\n onClick={() => {\n if (markedFileForDelete) {\n removeFile(markedFileForDelete);\n }\n setMarkedFileForDelete(null);\n }}\n >\n {deleteConfirm?.confirmText || formatMessage(MESSAGES.deleteModalConfirmButtonText)}\n </Button>\n </>\n }\n onClose={() => {\n setMarkedFileForDelete(null);\n }}\n />\n </>\n );\n};\n\nexport default UploadInput;\n"],"names":["generateFileId","file","name","size","uploadTimeStamp","Date","getTime","UploadInput","files","fileInputName","className","deleteConfirm","disabled","multiple","fileTypes","imageFileTypes","sizeLimit","DEFAULT_SIZE_LIMIT","description","onUploadFile","onDeleteFile","onValidationError","onFilesChange","onDownload","maxFiles","maxFilesErrorMessage","id","sizeLimitErrorMessage","uploadButtonTitle","inputAttributes","useInputAttributes","nonLabelable","markedFileForDelete","setMarkedFileForDelete","useState","nextFocusItem","setNextFocusItem","mounted","setMounted","formatMessage","useIntl","itemRefs","useRef","uploadInputRef","PROGRESS_STATUSES","Set","Status","PENDING","PROCESSING","FOCUS_TIMEOUT","uploadedFiles","setUploadedFiles","length","uploadedFilesListReference","updateFileList","updateFn","current","addFileToList","recentUploadedFile","list","removeFileFromList","filter","fileInList","modifyFileInList","updates","map","focusNextItem","focusId","isLastItem","timeout","requestAnimationFrame","setTimeout","nextFocusIdIndex","findIndex","item","focus","nextFocusElement","removeFile","status","index","f","nextIndexId","FAILED","error","undefined","then","catch","handleFileUploadFailure","failureMessage","failedUpload","filename","getNumberOfFilesUploaded","uploadInitiatedStatus","SUCCEEDED","validFiles","has","areMaximumFilesUploadedAlready","numberOfValidFiles","addFiles","selectedFiles","i","formData","FormData","allowedFileTypes","join","isTypeValid","MESSAGES","fileTypeNotSupported","isSizeValid","fileIsTooLarge","maximumFilesAlreadyUploaded","maxFilesAllowed","existingFile","find","append","pendingFile","url","useLayoutEffect","useEffect","_jsxs","_Fragment","children","role","clsx","_jsx","UploadItem","ref","el","singleFileUpload","canDelete","onDelete","UploadButton","withEntries","Boolean","onChange","Modal","title","deleteModalTitle","body","deleteModalBody","open","footer","Button","block","onClick","cancelText","deleteModalCancelButtonText","priority","Priority","SECONDARY","type","ControlType","NEGATIVE","confirmText","deleteModalConfirmButtonText","onClose"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"UploadInput.js","sources":["../../src/uploadInput/UploadInput.tsx"],"sourcesContent":["import { clsx } from 'clsx';\nimport { useEffect, useRef, useState, useLayoutEffect } from 'react';\nimport { useIntl } from 'react-intl';\n\nimport Button from '../button';\nimport { CommonProps, ControlType, Priority, Status } from '../common';\nimport { useInputAttributes } from '../inputs/contexts';\nimport Modal from '../modal';\nimport { isSizeValid } from '../upload/utils/isSizeValid';\nimport { isTypeValid } from '../upload/utils/isTypeValid';\n\nimport MESSAGES from './UploadInput.messages';\nimport { UploadedFile, UploadError, UploadResponse } from './types';\nimport UploadButton, { UploadButtonProps } from './uploadButton/UploadButton';\nimport { DEFAULT_SIZE_LIMIT, imageFileTypes } from './uploadButton/defaults';\nimport UploadItem, { UploadItemProps } from './uploadItem/UploadItem';\n\nexport type UploadInputProps = {\n /**\n * List of already existing, failed or in progress files\n */\n files?: readonly UploadedFile[];\n\n /**\n * The key of the file in the returned FormData object (default: file)\n */\n fileInputName?: string;\n\n /**\n * Callback that handles form submission\n *\n * @param formData\n */\n onUploadFile: (formData: FormData) => Promise<UploadResponse>;\n\n /**\n * Provide a callback if the file can be removed/deleted from the server\n * Your app is responsible for reloading the uploaded files list and updating the component to ensure that the file has in fact been deleted successfully\n *\n * @param id\n */\n onDeleteFile?: (id: string | number) => Promise<any>;\n\n /**\n * Provide a callback to trigger on validation error\n *\n * @param file\n */\n onValidationError?: (file: UploadedFile) => void;\n\n /**\n * Provide a callback to trigger on change whenever the files are updated\n *\n * @param files\n */\n onFilesChange?: (files: UploadedFile[]) => void;\n\n /**\n * Confirmation modal displayed on delete\n */\n deleteConfirm?: {\n /**\n * The title of the confirmation modal on delete\n */\n title?: string;\n\n /**\n * The body of the confirmation modal on delete\n */\n body?: React.ReactNode;\n\n /**\n * The confirm button text of the confirmation modal on delete\n */\n confirmText?: string;\n\n /**\n * The cancel button text of the confirmation modal on delete\n */\n cancelText?: string;\n };\n\n /**\n * Maximum number of files allowed, if provided, shows error below file item\n */\n maxFiles?: number;\n\n /**\n * Error message to show when the maximum number of files are uploaded already\n */\n maxFilesErrorMessage?: string;\n\n /**\n * Error message to show when files over a allowed size limit are uploaded\n */\n sizeLimitErrorMessage?: string;\n} & Pick<\n UploadButtonProps,\n 'disabled' | 'multiple' | 'fileTypes' | 'sizeLimit' | 'description' | 'id' | 'uploadButtonTitle'\n> & { onDownload?: UploadItemProps['onDownload'] } & CommonProps;\n\ninterface UploadItemRef {\n focus: () => void;\n}\n\nfunction generateFileId(file: File) {\n const { name, size } = file;\n const uploadTimeStamp = new Date().getTime();\n return `${name}_${size}_${uploadTimeStamp}`;\n}\n\nconst UploadInput = ({\n files = [],\n fileInputName = 'file',\n className,\n deleteConfirm,\n disabled,\n multiple = false,\n fileTypes = imageFileTypes,\n sizeLimit = DEFAULT_SIZE_LIMIT,\n description,\n onUploadFile,\n onDeleteFile,\n onValidationError,\n onFilesChange,\n onDownload,\n maxFiles,\n maxFilesErrorMessage,\n id,\n sizeLimitErrorMessage,\n uploadButtonTitle,\n}: UploadInputProps) => {\n const inputAttributes = useInputAttributes({ nonLabelable: true });\n\n const [markedFileForDelete, setMarkedFileForDelete] = useState<UploadedFile | null>(null);\n const [fileToRemoveIndex, setFileToRemoveIndex] = useState<number | null>(null);\n const [mounted, setMounted] = useState(false);\n const { formatMessage } = useIntl();\n const itemRefs = useRef<(HTMLDivElement | UploadItemRef | null)[]>([]);\n const uploadInputRef = useRef<HTMLInputElement | null>(null);\n\n const PROGRESS_STATUSES = new Set([Status.PENDING, Status.PROCESSING]);\n\n const [uploadedFiles, setUploadedFiles] = useState<readonly UploadedFile[]>(\n multiple || files.length === 0 ? files : [files[0]],\n );\n\n const uploadedFilesListReference = useRef(multiple || files.length === 0 ? files : [files[0]]);\n\n function addFileToList(recentUploadedFile: UploadedFile) {\n function addToList(listToAddTo: readonly UploadedFile[]) {\n return [...listToAddTo, recentUploadedFile];\n }\n\n setUploadedFiles(addToList);\n uploadedFilesListReference.current = addToList(uploadedFilesListReference.current);\n }\n\n const removeFileFromList = (file: UploadedFile) => {\n function filterOutFrom(listToFilterFrom: readonly UploadedFile[]) {\n return listToFilterFrom.filter(\n (fileInList) => file !== fileInList && file.id !== fileInList.id,\n );\n }\n\n setUploadedFiles(filterOutFrom);\n uploadedFilesListReference.current = filterOutFrom(uploadedFilesListReference.current);\n };\n\n const modifyFileInList = (file: UploadedFile, updates: Partial<UploadedFile>) => {\n const updateListItem = (listToUpdate: readonly UploadedFile[]) =>\n listToUpdate.map((fileInList) => {\n return fileInList === file || fileInList.id === file.id\n ? { ...file, ...updates }\n : fileInList;\n });\n\n setUploadedFiles(updateListItem);\n uploadedFilesListReference.current = updateListItem(uploadedFilesListReference.current);\n };\n\n const [fileToRemove, setFileToRemove] = useState<UploadedFile | null>(null);\n\n const removeFile = (file: UploadedFile) => {\n const { id, status } = file;\n const index = uploadedFiles.findIndex((f) => f.id === file.id);\n setFileToRemoveIndex(index);\n\n if (status === Status.FAILED) {\n removeFileFromList(file);\n setFileToRemove(file);\n } else if (onDeleteFile && id) {\n modifyFileInList(file, { status: Status.PROCESSING, error: undefined });\n\n onDeleteFile(id)\n .then(() => {\n removeFileFromList(file);\n })\n .catch((error) => {\n modifyFileInList(file, { error: error as UploadError });\n })\n .finally(() => {\n setFileToRemove(file);\n });\n }\n };\n\n function handleFileUploadFailure(file: File, failureMessage: string) {\n const { name } = file;\n const id = generateFileId(file);\n const failedUpload = {\n id,\n filename: name,\n status: Status.FAILED,\n error: failureMessage,\n };\n\n addFileToList(failedUpload);\n\n if (onValidationError) {\n onValidationError(failedUpload);\n }\n }\n\n function getNumberOfFilesUploaded() {\n const uploadInitiatedStatus = new Set([Status.SUCCEEDED, Status.PENDING]);\n const validFiles = uploadedFilesListReference.current.filter(\n (file) => file.status && uploadInitiatedStatus.has(file.status),\n );\n return validFiles.length;\n }\n\n function areMaximumFilesUploadedAlready() {\n if (!maxFiles) {\n return false;\n }\n\n const numberOfValidFiles = getNumberOfFilesUploaded();\n return numberOfValidFiles >= maxFiles;\n }\n\n // One or more files selected, create entries for them\n const addFiles = (selectedFiles: FileList) => {\n for (let i = 0; i < selectedFiles.length; i += 1) {\n const file = selectedFiles.item(i);\n\n // Returning a FormData[] array instead of FileList so we can filter out incorrect files\n const formData = new FormData();\n\n if (file) {\n const { name } = file;\n const id = generateFileId(file);\n\n const allowedFileTypes = typeof fileTypes === 'string' ? fileTypes : fileTypes.join(',');\n\n // Check if file type is valid\n if (!isTypeValid(file, allowedFileTypes)) {\n handleFileUploadFailure(file, formatMessage(MESSAGES.fileTypeNotSupported));\n continue;\n }\n\n // Check if the filesize is valid\n // Convert to rough bytes\n if (!isSizeValid(file, sizeLimit * 1000)) {\n const failureMessage = sizeLimitErrorMessage || formatMessage(MESSAGES.fileIsTooLarge);\n handleFileUploadFailure(file, failureMessage);\n continue;\n }\n\n if (areMaximumFilesUploadedAlready()) {\n const failureMessage =\n maxFilesErrorMessage ||\n formatMessage(MESSAGES.maximumFilesAlreadyUploaded, { maxFilesAllowed: maxFiles });\n handleFileUploadFailure(file, failureMessage);\n continue;\n }\n\n // Check if the file is already in the list\n const existingFile = uploadedFiles.find((f) => f.filename === file.name);\n if (existingFile) {\n // Remove the file from the list before adding it again\n removeFileFromList(existingFile);\n }\n\n // Add the file to the list\n formData.append(fileInputName, file);\n const pendingFile = {\n id: generateFileId(file),\n filename: file.name,\n status: Status.PENDING,\n };\n\n addFileToList(pendingFile);\n\n // Start uploading the file\n onUploadFile(formData)\n .then(({ id, url, error }: UploadResponse) => {\n // Replace the temporary id with the final one received from the API, and also set any errors\n modifyFileInList(pendingFile, { id, url, error, status: Status.SUCCEEDED });\n })\n .catch((error) => {\n modifyFileInList(pendingFile, { error: error as UploadError, status: Status.FAILED });\n });\n\n if (!multiple) {\n // Only upload a single file\n break;\n }\n }\n }\n };\n\n useLayoutEffect(() => {\n if (fileToRemove && fileToRemoveIndex !== null) {\n requestAnimationFrame(() => {\n const nextFocusIndex = Math.min(fileToRemoveIndex, uploadedFiles.length - 1);\n if (itemRefs.current[nextFocusIndex]) {\n itemRefs.current[nextFocusIndex].focus(); // Focus the next UploadItem\n } else {\n // If there's only one item left, focus the UploadButton\n uploadInputRef.current?.focus();\n }\n });\n setFileToRemove(null); // Reset the state\n setFileToRemoveIndex(null); // Reset the index\n }\n }, [uploadedFiles, fileToRemove, fileToRemoveIndex, itemRefs, uploadInputRef]);\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n if (onFilesChange && mounted) {\n onFilesChange([...uploadedFiles]);\n }\n }, [onFilesChange, uploadedFiles]); // eslint-disable-line react-hooks/exhaustive-deps\n\n return (\n <>\n <div\n role=\"group\"\n className={clsx('np-upload-input', className, { disabled })}\n {...inputAttributes}\n >\n <div\n className=\"np-upload-input__section\"\n aria-live=\"polite\"\n aria-relevant=\"all\"\n role=\"region\"\n >\n {uploadedFiles.map((file, index) => (\n <UploadItem\n key={file.id}\n ref={(el: UploadItemRef | null) => {\n itemRefs.current[index] = el;\n }}\n file={file}\n singleFileUpload={!multiple}\n canDelete={\n (!!onDeleteFile || file.status === Status.FAILED) &&\n (!file.status || !PROGRESS_STATUSES.has(file.status))\n }\n onDelete={\n file.status === Status.FAILED\n ? () => removeFile(file)\n : () => setMarkedFileForDelete(file)\n }\n onDownload={onDownload}\n />\n ))}\n </div>\n {(multiple || (!multiple && !uploadedFiles.length)) && (\n <div className=\"np-upload-input__section np-upload-input__section--uploader\">\n <UploadButton\n ref={uploadInputRef}\n id={id}\n uploadButtonTitle={uploadButtonTitle}\n disabled={areMaximumFilesUploadedAlready() || disabled}\n multiple={multiple}\n fileTypes={fileTypes}\n sizeLimit={sizeLimit}\n description={description}\n maxFiles={maxFiles}\n withEntries={Boolean(uploadedFiles.length)}\n onChange={addFiles}\n />\n </div>\n )}\n </div>\n <Modal\n title={\n deleteConfirm?.title !== undefined\n ? deleteConfirm.title\n : formatMessage(MESSAGES.deleteModalTitle)\n }\n body={\n deleteConfirm?.body !== undefined\n ? deleteConfirm.body\n : formatMessage(MESSAGES.deleteModalBody)\n }\n open={!!markedFileForDelete}\n footer={\n <>\n <Button\n block\n onClick={() => {\n setMarkedFileForDelete(null);\n }}\n >\n {deleteConfirm?.cancelText || formatMessage(MESSAGES.deleteModalCancelButtonText)}\n </Button>\n <Button\n block\n priority={Priority.SECONDARY}\n type={ControlType.NEGATIVE}\n onClick={() => {\n if (markedFileForDelete) {\n removeFile(markedFileForDelete);\n }\n setMarkedFileForDelete(null);\n }}\n >\n {deleteConfirm?.confirmText || formatMessage(MESSAGES.deleteModalConfirmButtonText)}\n </Button>\n </>\n }\n onClose={() => {\n setMarkedFileForDelete(null);\n }}\n />\n </>\n );\n};\n\nexport default UploadInput;\n"],"names":["generateFileId","file","name","size","uploadTimeStamp","Date","getTime","UploadInput","files","fileInputName","className","deleteConfirm","disabled","multiple","fileTypes","imageFileTypes","sizeLimit","DEFAULT_SIZE_LIMIT","description","onUploadFile","onDeleteFile","onValidationError","onFilesChange","onDownload","maxFiles","maxFilesErrorMessage","id","sizeLimitErrorMessage","uploadButtonTitle","inputAttributes","useInputAttributes","nonLabelable","markedFileForDelete","setMarkedFileForDelete","useState","fileToRemoveIndex","setFileToRemoveIndex","mounted","setMounted","formatMessage","useIntl","itemRefs","useRef","uploadInputRef","PROGRESS_STATUSES","Set","Status","PENDING","PROCESSING","uploadedFiles","setUploadedFiles","length","uploadedFilesListReference","addFileToList","recentUploadedFile","addToList","listToAddTo","current","removeFileFromList","filterOutFrom","listToFilterFrom","filter","fileInList","modifyFileInList","updates","updateListItem","listToUpdate","map","fileToRemove","setFileToRemove","removeFile","status","index","findIndex","f","FAILED","error","undefined","then","catch","finally","handleFileUploadFailure","failureMessage","failedUpload","filename","getNumberOfFilesUploaded","uploadInitiatedStatus","SUCCEEDED","validFiles","has","areMaximumFilesUploadedAlready","numberOfValidFiles","addFiles","selectedFiles","i","item","formData","FormData","allowedFileTypes","join","isTypeValid","MESSAGES","fileTypeNotSupported","isSizeValid","fileIsTooLarge","maximumFilesAlreadyUploaded","maxFilesAllowed","existingFile","find","append","pendingFile","url","useLayoutEffect","requestAnimationFrame","nextFocusIndex","Math","min","focus","useEffect","_jsxs","_Fragment","children","role","clsx","_jsx","UploadItem","ref","el","singleFileUpload","canDelete","onDelete","UploadButton","withEntries","Boolean","onChange","Modal","title","deleteModalTitle","body","deleteModalBody","open","footer","Button","block","onClick","cancelText","deleteModalCancelButtonText","priority","Priority","SECONDARY","type","ControlType","NEGATIVE","confirmText","deleteModalConfirmButtonText","onClose"],"mappings":"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"}
|
|
@@ -22,15 +22,6 @@ function generateFileId(file) {
|
|
|
22
22
|
const uploadTimeStamp = new Date().getTime();
|
|
23
23
|
return `${name}_${size}_${uploadTimeStamp}`;
|
|
24
24
|
}
|
|
25
|
-
/**
|
|
26
|
-
* The component allows users to upload files, manage the list of uploaded files,
|
|
27
|
-
* and handle file validation and deletion.
|
|
28
|
-
*
|
|
29
|
-
* @param {UploadInputProps} props - The properties for the UploadInput component.
|
|
30
|
-
*
|
|
31
|
-
* @see {@link UploadInput} for further information.
|
|
32
|
-
* @see {@link https://storybook.wise.design/?path=/docs/forms-uploadinput--docs|Storybook Wise Design}
|
|
33
|
-
*/
|
|
34
25
|
const UploadInput = ({
|
|
35
26
|
files = [],
|
|
36
27
|
fileInputName = 'file',
|
|
@@ -56,7 +47,7 @@ const UploadInput = ({
|
|
|
56
47
|
nonLabelable: true
|
|
57
48
|
});
|
|
58
49
|
const [markedFileForDelete, setMarkedFileForDelete] = useState(null);
|
|
59
|
-
const [
|
|
50
|
+
const [fileToRemoveIndex, setFileToRemoveIndex] = useState(null);
|
|
60
51
|
const [mounted, setMounted] = useState(false);
|
|
61
52
|
const {
|
|
62
53
|
formatMessage
|
|
@@ -64,59 +55,44 @@ const UploadInput = ({
|
|
|
64
55
|
const itemRefs = useRef([]);
|
|
65
56
|
const uploadInputRef = useRef(null);
|
|
66
57
|
const PROGRESS_STATUSES = new Set([Status.PENDING, Status.PROCESSING]);
|
|
67
|
-
const FOCUS_TIMEOUT = 400; // Set to 400ms to allow animations and Modal to unmount
|
|
68
58
|
const [uploadedFiles, setUploadedFiles] = useState(multiple || files.length === 0 ? files : [files[0]]);
|
|
69
59
|
const uploadedFilesListReference = useRef(multiple || files.length === 0 ? files : [files[0]]);
|
|
70
|
-
function updateFileList(updateFn) {
|
|
71
|
-
setUploadedFiles(updateFn);
|
|
72
|
-
uploadedFilesListReference.current = updateFn(uploadedFilesListReference.current);
|
|
73
|
-
}
|
|
74
60
|
function addFileToList(recentUploadedFile) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
function modifyFileInList(file, updates) {
|
|
81
|
-
updateFileList(list => list.map(fileInList => fileInList === file || fileInList.id === file.id ? {
|
|
82
|
-
...file,
|
|
83
|
-
...updates
|
|
84
|
-
} : fileInList));
|
|
61
|
+
function addToList(listToAddTo) {
|
|
62
|
+
return [...listToAddTo, recentUploadedFile];
|
|
63
|
+
}
|
|
64
|
+
setUploadedFiles(addToList);
|
|
65
|
+
uploadedFilesListReference.current = addToList(uploadedFilesListReference.current);
|
|
85
66
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
67
|
+
const removeFileFromList = file => {
|
|
68
|
+
function filterOutFrom(listToFilterFrom) {
|
|
69
|
+
return listToFilterFrom.filter(fileInList => file !== fileInList && file.id !== fileInList.id);
|
|
70
|
+
}
|
|
71
|
+
setUploadedFiles(filterOutFrom);
|
|
72
|
+
uploadedFilesListReference.current = filterOutFrom(uploadedFilesListReference.current);
|
|
73
|
+
};
|
|
74
|
+
const modifyFileInList = (file, updates) => {
|
|
75
|
+
const updateListItem = listToUpdate => listToUpdate.map(fileInList => {
|
|
76
|
+
return fileInList === file || fileInList.id === file.id ? {
|
|
77
|
+
...file,
|
|
78
|
+
...updates
|
|
79
|
+
} : fileInList;
|
|
98
80
|
});
|
|
99
|
-
|
|
81
|
+
setUploadedFiles(updateListItem);
|
|
82
|
+
uploadedFilesListReference.current = updateListItem(uploadedFilesListReference.current);
|
|
83
|
+
};
|
|
84
|
+
const [fileToRemove, setFileToRemove] = useState(null);
|
|
100
85
|
const removeFile = file => {
|
|
101
86
|
const {
|
|
102
87
|
id,
|
|
103
88
|
status
|
|
104
89
|
} = file;
|
|
105
90
|
const index = uploadedFiles.findIndex(f => f.id === file.id);
|
|
106
|
-
|
|
107
|
-
const nextIndexId = uploadedFiles[index + 1]?.id;
|
|
108
|
-
const focusId = nextIndexId ?? null;
|
|
91
|
+
setFileToRemoveIndex(index);
|
|
109
92
|
if (status === Status.FAILED) {
|
|
110
|
-
setNextFocusItem({
|
|
111
|
-
focusId: focusId ?? null,
|
|
112
|
-
isLastItem
|
|
113
|
-
});
|
|
114
93
|
removeFileFromList(file);
|
|
94
|
+
setFileToRemove(file);
|
|
115
95
|
} else if (onDeleteFile && id) {
|
|
116
|
-
setNextFocusItem({
|
|
117
|
-
focusId,
|
|
118
|
-
isLastItem
|
|
119
|
-
});
|
|
120
96
|
modifyFileInList(file, {
|
|
121
97
|
status: Status.PROCESSING,
|
|
122
98
|
error: undefined
|
|
@@ -124,13 +100,11 @@ const UploadInput = ({
|
|
|
124
100
|
onDeleteFile(id).then(() => {
|
|
125
101
|
removeFileFromList(file);
|
|
126
102
|
}).catch(error => {
|
|
127
|
-
setNextFocusItem({
|
|
128
|
-
focusId,
|
|
129
|
-
isLastItem
|
|
130
|
-
});
|
|
131
103
|
modifyFileInList(file, {
|
|
132
104
|
error: error
|
|
133
105
|
});
|
|
106
|
+
}).finally(() => {
|
|
107
|
+
setFileToRemove(file);
|
|
134
108
|
});
|
|
135
109
|
}
|
|
136
110
|
};
|
|
@@ -162,17 +136,22 @@ const UploadInput = ({
|
|
|
162
136
|
const numberOfValidFiles = getNumberOfFilesUploaded();
|
|
163
137
|
return numberOfValidFiles >= maxFiles;
|
|
164
138
|
}
|
|
139
|
+
// One or more files selected, create entries for them
|
|
165
140
|
const addFiles = selectedFiles => {
|
|
166
141
|
for (let i = 0; i < selectedFiles.length; i += 1) {
|
|
167
142
|
const file = selectedFiles.item(i);
|
|
143
|
+
// Returning a FormData[] array instead of FileList so we can filter out incorrect files
|
|
168
144
|
const formData = new FormData();
|
|
169
145
|
if (file) {
|
|
170
146
|
generateFileId(file);
|
|
171
147
|
const allowedFileTypes = typeof fileTypes === 'string' ? fileTypes : fileTypes.join(',');
|
|
148
|
+
// Check if file type is valid
|
|
172
149
|
if (!isTypeValid(file, allowedFileTypes)) {
|
|
173
150
|
handleFileUploadFailure(file, formatMessage(MESSAGES.fileTypeNotSupported));
|
|
174
151
|
continue;
|
|
175
152
|
}
|
|
153
|
+
// Check if the filesize is valid
|
|
154
|
+
// Convert to rough bytes
|
|
176
155
|
if (!isSizeValid(file, sizeLimit * 1000)) {
|
|
177
156
|
const failureMessage = sizeLimitErrorMessage || formatMessage(MESSAGES.fileIsTooLarge);
|
|
178
157
|
handleFileUploadFailure(file, failureMessage);
|
|
@@ -185,10 +164,13 @@ const UploadInput = ({
|
|
|
185
164
|
handleFileUploadFailure(file, failureMessage);
|
|
186
165
|
continue;
|
|
187
166
|
}
|
|
167
|
+
// Check if the file is already in the list
|
|
188
168
|
const existingFile = uploadedFiles.find(f => f.filename === file.name);
|
|
189
169
|
if (existingFile) {
|
|
170
|
+
// Remove the file from the list before adding it again
|
|
190
171
|
removeFileFromList(existingFile);
|
|
191
172
|
}
|
|
173
|
+
// Add the file to the list
|
|
192
174
|
formData.append(fileInputName, file);
|
|
193
175
|
const pendingFile = {
|
|
194
176
|
id: generateFileId(file),
|
|
@@ -196,11 +178,13 @@ const UploadInput = ({
|
|
|
196
178
|
status: Status.PENDING
|
|
197
179
|
};
|
|
198
180
|
addFileToList(pendingFile);
|
|
181
|
+
// Start uploading the file
|
|
199
182
|
onUploadFile(formData).then(({
|
|
200
183
|
id,
|
|
201
184
|
url,
|
|
202
185
|
error
|
|
203
186
|
}) => {
|
|
187
|
+
// Replace the temporary id with the final one received from the API, and also set any errors
|
|
204
188
|
modifyFileInList(pendingFile, {
|
|
205
189
|
id,
|
|
206
190
|
url,
|
|
@@ -214,17 +198,27 @@ const UploadInput = ({
|
|
|
214
198
|
});
|
|
215
199
|
});
|
|
216
200
|
if (!multiple) {
|
|
201
|
+
// Only upload a single file
|
|
217
202
|
break;
|
|
218
203
|
}
|
|
219
204
|
}
|
|
220
205
|
}
|
|
221
206
|
};
|
|
222
207
|
useLayoutEffect(() => {
|
|
223
|
-
if (
|
|
224
|
-
|
|
208
|
+
if (fileToRemove && fileToRemoveIndex !== null) {
|
|
209
|
+
requestAnimationFrame(() => {
|
|
210
|
+
const nextFocusIndex = Math.min(fileToRemoveIndex, uploadedFiles.length - 1);
|
|
211
|
+
if (itemRefs.current[nextFocusIndex]) {
|
|
212
|
+
itemRefs.current[nextFocusIndex].focus(); // Focus the next UploadItem
|
|
213
|
+
} else {
|
|
214
|
+
// If there's only one item left, focus the UploadButton
|
|
215
|
+
uploadInputRef.current?.focus();
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
setFileToRemove(null); // Reset the state
|
|
219
|
+
setFileToRemoveIndex(null); // Reset the index
|
|
225
220
|
}
|
|
226
|
-
|
|
227
|
-
}, [nextFocusItem]);
|
|
221
|
+
}, [uploadedFiles, fileToRemove, fileToRemoveIndex, itemRefs, uploadInputRef]);
|
|
228
222
|
useEffect(() => {
|
|
229
223
|
setMounted(true);
|
|
230
224
|
}, []);
|