@aws-amplify/ui-react-storage 3.2.1 → 3.3.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 (70) hide show
  1. package/dist/esm/components/FileUploader/FileUploader.mjs +185 -0
  2. package/dist/esm/components/FileUploader/hooks/useFileUploader/actions.mjs +39 -0
  3. package/dist/esm/components/FileUploader/hooks/useFileUploader/reducer.mjs +93 -0
  4. package/dist/esm/components/FileUploader/hooks/useFileUploader/types.mjs +13 -0
  5. package/dist/esm/components/FileUploader/hooks/useFileUploader/useFileUploader.mjs +62 -0
  6. package/dist/esm/components/FileUploader/hooks/useUploadFiles/useUploadFiles.mjs +79 -0
  7. package/dist/esm/components/FileUploader/types.mjs +11 -0
  8. package/dist/esm/components/FileUploader/ui/Container/Container.mjs +8 -0
  9. package/dist/esm/components/FileUploader/ui/DropZone/DropZone.mjs +16 -0
  10. package/dist/esm/components/FileUploader/ui/FileList/FileControl.mjs +23 -0
  11. package/dist/esm/components/FileUploader/ui/FileList/FileDetails.mjs +12 -0
  12. package/dist/esm/components/FileUploader/ui/FileList/FileList.mjs +44 -0
  13. package/dist/esm/components/FileUploader/ui/FileList/FileRemoveButton.mjs +12 -0
  14. package/dist/esm/components/FileUploader/ui/FileList/FileStatusMessage.mjs +28 -0
  15. package/dist/esm/components/FileUploader/ui/FileList/FileThumbnail.mjs +12 -0
  16. package/dist/esm/components/FileUploader/ui/FileListFooter/FileListFooter.mjs +13 -0
  17. package/dist/esm/components/FileUploader/ui/FileListHeader/FileListHeader.mjs +14 -0
  18. package/dist/esm/components/FileUploader/ui/FilePicker/FilePicker.mjs +9 -0
  19. package/dist/esm/components/FileUploader/utils/checkMaxFileSize.mjs +12 -0
  20. package/dist/esm/components/FileUploader/utils/displayText.mjs +39 -0
  21. package/dist/esm/components/FileUploader/utils/filterAllowedFiles.mjs +27 -0
  22. package/dist/esm/components/FileUploader/utils/getInput.mjs +39 -0
  23. package/dist/esm/components/FileUploader/utils/resolveFile.mjs +20 -0
  24. package/dist/esm/components/FileUploader/utils/uploadFile.mjs +26 -0
  25. package/dist/esm/components/StorageManager/StorageManager.mjs +4 -0
  26. package/dist/esm/index.mjs +1 -0
  27. package/dist/esm/version.mjs +1 -1
  28. package/dist/index.js +721 -7
  29. package/dist/types/components/FileUploader/FileUploader.d.ts +15 -0
  30. package/dist/types/components/FileUploader/hooks/index.d.ts +2 -0
  31. package/dist/types/components/FileUploader/hooks/useFileUploader/actions.d.ts +22 -0
  32. package/dist/types/components/FileUploader/hooks/useFileUploader/index.d.ts +1 -0
  33. package/dist/types/components/FileUploader/hooks/useFileUploader/reducer.d.ts +2 -0
  34. package/dist/types/components/FileUploader/hooks/useFileUploader/types.d.ts +50 -0
  35. package/dist/types/components/FileUploader/hooks/useFileUploader/useFileUploader.d.ts +35 -0
  36. package/dist/types/components/FileUploader/hooks/useUploadFiles/index.d.ts +1 -0
  37. package/dist/types/components/FileUploader/hooks/useUploadFiles/useUploadFiles.d.ts +12 -0
  38. package/dist/types/components/FileUploader/index.d.ts +3 -0
  39. package/dist/types/components/FileUploader/types.d.ts +129 -0
  40. package/dist/types/components/FileUploader/ui/Container/Container.d.ts +6 -0
  41. package/dist/types/components/FileUploader/ui/Container/index.d.ts +1 -0
  42. package/dist/types/components/FileUploader/ui/DropZone/DropZone.d.ts +3 -0
  43. package/dist/types/components/FileUploader/ui/DropZone/index.d.ts +2 -0
  44. package/dist/types/components/FileUploader/ui/DropZone/types.d.ts +13 -0
  45. package/dist/types/components/FileUploader/ui/FileList/FileControl.d.ts +3 -0
  46. package/dist/types/components/FileUploader/ui/FileList/FileDetails.d.ts +3 -0
  47. package/dist/types/components/FileUploader/ui/FileList/FileList.d.ts +3 -0
  48. package/dist/types/components/FileUploader/ui/FileList/FileRemoveButton.d.ts +3 -0
  49. package/dist/types/components/FileUploader/ui/FileList/FileStatusMessage.d.ts +3 -0
  50. package/dist/types/components/FileUploader/ui/FileList/FileThumbnail.d.ts +3 -0
  51. package/dist/types/components/FileUploader/ui/FileList/index.d.ts +2 -0
  52. package/dist/types/components/FileUploader/ui/FileList/types.d.ts +51 -0
  53. package/dist/types/components/FileUploader/ui/FileListFooter/FileListFooter.d.ts +9 -0
  54. package/dist/types/components/FileUploader/ui/FileListFooter/index.d.ts +1 -0
  55. package/dist/types/components/FileUploader/ui/FileListHeader/FileListHeader.d.ts +10 -0
  56. package/dist/types/components/FileUploader/ui/FileListHeader/index.d.ts +1 -0
  57. package/dist/types/components/FileUploader/ui/FilePicker/FilePicker.d.ts +4 -0
  58. package/dist/types/components/FileUploader/ui/FilePicker/index.d.ts +1 -0
  59. package/dist/types/components/FileUploader/ui/index.d.ts +6 -0
  60. package/dist/types/components/FileUploader/utils/checkMaxFileSize.d.ts +5 -0
  61. package/dist/types/components/FileUploader/utils/displayText.d.ts +22 -0
  62. package/dist/types/components/FileUploader/utils/filterAllowedFiles.d.ts +1 -0
  63. package/dist/types/components/FileUploader/utils/getInput.d.ts +17 -0
  64. package/dist/types/components/FileUploader/utils/index.d.ts +5 -0
  65. package/dist/types/components/FileUploader/utils/resolveFile.d.ts +9 -0
  66. package/dist/types/components/FileUploader/utils/uploadFile.d.ts +32 -0
  67. package/dist/types/components/index.d.ts +1 -0
  68. package/dist/types/index.d.ts +1 -1
  69. package/dist/types/version.d.ts +1 -1
  70. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -5,8 +5,8 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var React = require('react');
6
6
  var ui = require('@aws-amplify/ui');
7
7
  var uiReact = require('@aws-amplify/ui-react');
8
- var internal = require('@aws-amplify/ui-react/internal');
9
8
  var uiReactCore = require('@aws-amplify/ui-react-core');
9
+ var internal = require('@aws-amplify/ui-react/internal');
10
10
  var auth = require('aws-amplify/auth');
11
11
  var storage = require('aws-amplify/storage');
12
12
 
@@ -24,16 +24,725 @@ function _interopNamespace(e) {
24
24
  get: function () { return e[k]; }
25
25
  });
26
26
  }
27
- });
27
+ });
28
+ }
29
+ n["default"] = e;
30
+ return Object.freeze(n);
31
+ }
32
+
33
+ var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
34
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
35
+
36
+ var FileStatus$1;
37
+ (function (FileStatus) {
38
+ FileStatus["ADDED"] = "added";
39
+ FileStatus["QUEUED"] = "queued";
40
+ FileStatus["UPLOADING"] = "uploading";
41
+ FileStatus["PAUSED"] = "paused";
42
+ FileStatus["ERROR"] = "error";
43
+ FileStatus["UPLOADED"] = "uploaded";
44
+ })(FileStatus$1 || (FileStatus$1 = {}));
45
+
46
+ var FileUploaderActionTypes;
47
+ (function (FileUploaderActionTypes) {
48
+ FileUploaderActionTypes["ADD_FILES"] = "ADD_FILES";
49
+ FileUploaderActionTypes["CLEAR_FILES"] = "CLEAR_FILES";
50
+ FileUploaderActionTypes["QUEUE_FILES"] = "QUEUE_FILES";
51
+ FileUploaderActionTypes["SET_STATUS"] = "SET_STATUS";
52
+ FileUploaderActionTypes["SET_PROCESSED_FILE_KEY"] = "SET_PROCESSED_FILE_KEY";
53
+ FileUploaderActionTypes["SET_STATUS_UPLOADING"] = "SET_STATUS_UPLOADING";
54
+ FileUploaderActionTypes["SET_UPLOAD_PROGRESS"] = "SET_UPLOAD_PROGRESS";
55
+ FileUploaderActionTypes["REMOVE_UPLOAD"] = "REMOVE_UPLOAD";
56
+ })(FileUploaderActionTypes || (FileUploaderActionTypes = {}));
57
+
58
+ const updateFiles$1 = (files, nextFileData) => files.reduce((files, currentFile) => {
59
+ if (currentFile.id === nextFileData.id) {
60
+ return [...files, { ...currentFile, ...nextFileData }];
61
+ }
62
+ return [...files, currentFile];
63
+ }, []);
64
+ function fileUploaderStateReducer(state, action) {
65
+ switch (action.type) {
66
+ case FileUploaderActionTypes.ADD_FILES: {
67
+ const { files, status } = action;
68
+ const newUploads = files.map((file) => {
69
+ const errorText = action.getFileErrorMessage(file);
70
+ return {
71
+ // make sure id is unique,
72
+ // we only use it internally and don't send it to Storage
73
+ id: `${Date.now()}-${file.name}`,
74
+ file,
75
+ error: errorText,
76
+ key: file.name,
77
+ status: errorText ? FileStatus$1.ERROR : status,
78
+ isImage: file.type.startsWith('image/'),
79
+ progress: -1,
80
+ };
81
+ });
82
+ const newFiles = [...state.files, ...newUploads];
83
+ return { ...state, files: newFiles };
84
+ }
85
+ case FileUploaderActionTypes.CLEAR_FILES: {
86
+ return { ...state, files: [] };
87
+ }
88
+ case FileUploaderActionTypes.QUEUE_FILES: {
89
+ const { files } = state;
90
+ const newFiles = files.reduce((files, currentFile) => {
91
+ return [
92
+ ...files,
93
+ {
94
+ ...currentFile,
95
+ ...(currentFile.status === FileStatus$1.ADDED
96
+ ? { status: FileStatus$1.QUEUED }
97
+ : {}),
98
+ },
99
+ ];
100
+ }, []);
101
+ return {
102
+ ...state,
103
+ files: newFiles,
104
+ };
105
+ }
106
+ case FileUploaderActionTypes.SET_STATUS_UPLOADING: {
107
+ const { id, uploadTask } = action;
108
+ const status = FileStatus$1.UPLOADING;
109
+ const progress = 0;
110
+ const nextFileData = { status, progress, id, uploadTask };
111
+ const files = updateFiles$1(state.files, nextFileData);
112
+ return { ...state, files };
113
+ }
114
+ case FileUploaderActionTypes.SET_PROCESSED_FILE_KEY: {
115
+ const { processedKey, id } = action;
116
+ const files = updateFiles$1(state.files, { processedKey, id });
117
+ return { files };
118
+ }
119
+ case FileUploaderActionTypes.SET_UPLOAD_PROGRESS: {
120
+ const { id, progress } = action;
121
+ const files = updateFiles$1(state.files, { id, progress });
122
+ return { ...state, files };
123
+ }
124
+ case FileUploaderActionTypes.SET_STATUS: {
125
+ const { id, status } = action;
126
+ const files = updateFiles$1(state.files, { id, status });
127
+ return { ...state, files };
128
+ }
129
+ case FileUploaderActionTypes.REMOVE_UPLOAD: {
130
+ const { id } = action;
131
+ const { files } = state;
132
+ const newFiles = files.reduce((files, currentFile) => {
133
+ if (currentFile.id === id) {
134
+ // remove by not returning currentFile
135
+ return [...files];
136
+ }
137
+ return [...files, currentFile];
138
+ }, []);
139
+ return {
140
+ ...state,
141
+ files: newFiles,
142
+ };
143
+ }
144
+ }
145
+ }
146
+
147
+ const addFilesAction$1 = ({ files, status, getFileErrorMessage, }) => ({
148
+ type: FileUploaderActionTypes.ADD_FILES,
149
+ files,
150
+ status,
151
+ getFileErrorMessage,
152
+ });
153
+ const clearFilesAction$1 = () => ({
154
+ type: FileUploaderActionTypes.CLEAR_FILES,
155
+ });
156
+ const queueFilesAction$1 = () => ({
157
+ type: FileUploaderActionTypes.QUEUE_FILES,
158
+ });
159
+ const setProcessedKeyAction$1 = (input) => ({
160
+ ...input,
161
+ type: FileUploaderActionTypes.SET_PROCESSED_FILE_KEY,
162
+ });
163
+ const setUploadingFileAction$1 = ({ id, uploadTask, }) => ({
164
+ type: FileUploaderActionTypes.SET_STATUS_UPLOADING,
165
+ id,
166
+ uploadTask,
167
+ });
168
+ const setUploadProgressAction$1 = ({ id, progress, }) => ({
169
+ type: FileUploaderActionTypes.SET_UPLOAD_PROGRESS,
170
+ id,
171
+ progress,
172
+ });
173
+ const setUploadStatusAction$1 = ({ id, status, }) => ({
174
+ type: FileUploaderActionTypes.SET_STATUS,
175
+ id,
176
+ status,
177
+ });
178
+ const removeUploadAction$1 = ({ id }) => ({
179
+ type: FileUploaderActionTypes.REMOVE_UPLOAD,
180
+ id,
181
+ });
182
+
183
+ const isDefaultFile$1 = (file) => !!(ui.isObject(file) && file.key);
184
+ const createFileFromDefault$1 = (file) => isDefaultFile$1(file)
185
+ ? { ...file, id: file.key, status: FileStatus$1.UPLOADED }
186
+ : undefined;
187
+ function useFileUploader(defaultFiles = []) {
188
+ const [{ files }, dispatch] = React__default["default"].useReducer(fileUploaderStateReducer, {
189
+ files: (Array.isArray(defaultFiles)
190
+ ? defaultFiles.map(createFileFromDefault$1).filter((file) => !!file)
191
+ : []),
192
+ });
193
+ const addFiles = ({ files, status, getFileErrorMessage, }) => {
194
+ dispatch(addFilesAction$1({ files, status, getFileErrorMessage }));
195
+ };
196
+ const clearFiles = () => {
197
+ dispatch(clearFilesAction$1());
198
+ };
199
+ const queueFiles = () => {
200
+ dispatch(queueFilesAction$1());
201
+ };
202
+ const setUploadingFile = ({ uploadTask, id, }) => {
203
+ dispatch(setUploadingFileAction$1({ id, uploadTask }));
204
+ };
205
+ const setProcessedKey = (input) => {
206
+ dispatch(setProcessedKeyAction$1(input));
207
+ };
208
+ const setUploadProgress = ({ progress, id, }) => {
209
+ dispatch(setUploadProgressAction$1({ id, progress }));
210
+ };
211
+ const setUploadSuccess = ({ id }) => {
212
+ dispatch(setUploadStatusAction$1({ id, status: FileStatus$1.UPLOADED }));
213
+ };
214
+ const setUploadPaused = ({ id }) => {
215
+ dispatch(setUploadStatusAction$1({ id, status: FileStatus$1.PAUSED }));
216
+ };
217
+ const setUploadResumed = ({ id }) => {
218
+ dispatch(setUploadStatusAction$1({ id, status: FileStatus$1.UPLOADING }));
219
+ };
220
+ const removeUpload = ({ id }) => {
221
+ dispatch(removeUploadAction$1({ id }));
222
+ };
223
+ return {
224
+ removeUpload,
225
+ setProcessedKey,
226
+ setUploadPaused,
227
+ setUploadProgress,
228
+ setUploadResumed,
229
+ setUploadSuccess,
230
+ setUploadingFile,
231
+ queueFiles,
232
+ addFiles,
233
+ clearFiles,
234
+ files,
235
+ };
236
+ }
237
+
238
+ const checkMaxFileSize$1 = ({ file, getFileSizeErrorText, maxFileSize, }) => {
239
+ if (maxFileSize === undefined)
240
+ return '';
241
+ if (file.size > maxFileSize) {
242
+ return getFileSizeErrorText(ui.humanFileSize(maxFileSize, true));
243
+ }
244
+ return '';
245
+ };
246
+
247
+ const defaultFileUploaderDisplayText = {
248
+ getFilesUploadedText(count) {
249
+ return `${count} ${count === 1 ? 'file uploaded' : 'files uploaded'}`;
250
+ },
251
+ getFileSizeErrorText(sizeText) {
252
+ return `File size must be below ${sizeText}`;
253
+ },
254
+ getRemainingFilesText(count) {
255
+ return `${count} ${count === 1 ? 'file' : 'files'} uploading`;
256
+ },
257
+ getSelectedFilesText(count) {
258
+ return `${count} ${count === 1 ? 'file' : 'files'} selected`;
259
+ },
260
+ getUploadingText(percentage) {
261
+ return `Uploading${percentage > 0 ? `: ${percentage}%` : ''}`;
262
+ },
263
+ getUploadButtonText(count) {
264
+ return `Upload ${count} ${count === 1 ? 'file' : 'files'}`;
265
+ },
266
+ getMaxFilesErrorText(count) {
267
+ return `Cannot choose more than ${count} ${count === 1 ? 'file' : 'files'}. Remove files before updating`;
268
+ },
269
+ getErrorText(message) {
270
+ return message;
271
+ },
272
+ doneButtonText: 'Done',
273
+ clearAllButtonText: 'Clear all',
274
+ extensionNotAllowedText: 'Extension not allowed',
275
+ browseFilesText: 'Browse files',
276
+ dropFilesText: 'Drop files here or',
277
+ pauseButtonText: 'Pause',
278
+ resumeButtonText: 'Resume',
279
+ uploadSuccessfulText: 'Uploaded',
280
+ getPausedText(percentage) {
281
+ return `Paused: ${percentage}%`;
282
+ },
283
+ };
284
+
285
+ const filterAllowedFiles$1 = (files, acceptedFileTypes) => {
286
+ // Allow any files if acceptedFileTypes is undefined, empty array, or contains '*'
287
+ if (!acceptedFileTypes ||
288
+ acceptedFileTypes.length === 0 ||
289
+ acceptedFileTypes.includes('*')) {
290
+ return files;
291
+ }
292
+ // Remove any files that are not in the accepted file list
293
+ return files.filter((file) => {
294
+ const fileName = file.name || '';
295
+ const mimeType = (file.type || '').toLowerCase();
296
+ const baseMimeType = mimeType.replace(/\/.*$/, '');
297
+ return acceptedFileTypes.some((type) => {
298
+ const validType = type.trim().toLowerCase();
299
+ if (validType.charAt(0) === '.') {
300
+ return fileName.toLowerCase().endsWith(validType);
301
+ }
302
+ else if (validType.endsWith('/*')) {
303
+ // This is something like a image/* mime type
304
+ return baseMimeType === validType.replace(/\/.*$/, '');
305
+ }
306
+ return mimeType === validType;
307
+ });
308
+ });
309
+ };
310
+
311
+ /**
312
+ * Utility function that takes the processFile prop, along with a file a key
313
+ * and returns a Promise that resolves to { file, key, ..rest }
314
+ * regardless if processFile is defined and if it is sync or async
315
+ */
316
+ const resolveFile$1 = ({ processFile, ...input }) => {
317
+ return new Promise((resolve, reject) => {
318
+ const result = ui.isFunction(processFile) ? processFile(input) : input;
319
+ if (result instanceof Promise) {
320
+ result.then(resolve).catch(reject);
321
+ }
322
+ else {
323
+ resolve(result);
324
+ }
325
+ });
326
+ };
327
+
328
+ const getInput$1 = ({ accessLevel, file, key, onProcessFileSuccess, onProgress, path, processFile, useAccelerateEndpoint, }) => {
329
+ return async () => {
330
+ const hasCallbackPath = ui.isTypedFunction(path);
331
+ const hasStringPath = ui.isString(path);
332
+ const hasKeyInput = !!accessLevel && !hasCallbackPath;
333
+ const { file: data, key: processedKey, ...rest } = await resolveFile$1({ file, key, processFile });
334
+ const contentType = file.type || 'binary/octet-stream';
335
+ // IMPORTANT: always pass `...rest` here for backwards compatibility
336
+ const options = { contentType, onProgress, useAccelerateEndpoint, ...rest };
337
+ let inputResult;
338
+ if (hasKeyInput) {
339
+ // legacy handling of `path` is to prefix to `fileKey`
340
+ const resolvedKey = hasStringPath
341
+ ? `${path}${processedKey}`
342
+ : processedKey;
343
+ inputResult = {
344
+ data,
345
+ key: resolvedKey,
346
+ options: { ...options, accessLevel },
347
+ };
348
+ }
349
+ else {
350
+ const { identityId } = await auth.fetchAuthSession();
351
+ const resolvedPath = `${hasCallbackPath ? path({ identityId }) : path}${processedKey}`;
352
+ inputResult = { data: file, path: resolvedPath, options };
353
+ }
354
+ if (processFile) {
355
+ // provide post-processing value of target `key`
356
+ onProcessFileSuccess({ processedKey });
357
+ }
358
+ return inputResult;
359
+ };
360
+ };
361
+
362
+ async function uploadFile$1({ input, onError, onStart, onComplete, }) {
363
+ const resolvedInput = await input();
364
+ const uploadTask = storage.uploadData(resolvedInput);
365
+ const key = resolvedInput?.key ??
366
+ resolvedInput?.path;
367
+ if (ui.isFunction(onStart)) {
368
+ onStart({ key, uploadTask });
369
+ }
370
+ uploadTask.result
371
+ .then((result) => {
372
+ if (ui.isFunction(onComplete) && uploadTask.state === 'SUCCESS') {
373
+ onComplete(result);
374
+ }
375
+ })
376
+ .catch((error) => {
377
+ if (ui.isFunction(onError)) {
378
+ onError({ key, error });
379
+ }
380
+ });
381
+ return uploadTask;
382
+ }
383
+
384
+ function useUploadFiles$1({ accessLevel, files, isResumable, maxFileCount, onProcessFileSuccess, onUploadError, onUploadStart, onUploadSuccess, path, processFile, setUploadingFile, setUploadProgress, setUploadSuccess, useAccelerateEndpoint, }) {
385
+ React__namespace.useEffect(() => {
386
+ const filesReadyToUpload = files.filter((file) => file.status === FileStatus$1.QUEUED);
387
+ if (filesReadyToUpload.length > maxFileCount) {
388
+ return;
389
+ }
390
+ for (const { file, key, id } of filesReadyToUpload) {
391
+ const onProgress = (event) => {
392
+ /**
393
+ * When a file is zero bytes, the progress.total will equal zero.
394
+ * Therefore, this will prevent a divide by zero error.
395
+ */
396
+ const progress = event.totalBytes === undefined || event.totalBytes === 0
397
+ ? 100
398
+ : Math.floor((event.transferredBytes / event.totalBytes) * 100);
399
+ setUploadProgress({ id, progress });
400
+ };
401
+ if (file) {
402
+ const handleProcessFileSuccess = (input) => onProcessFileSuccess({ id, ...input });
403
+ const input = getInput$1({
404
+ accessLevel,
405
+ file,
406
+ key,
407
+ onProcessFileSuccess: handleProcessFileSuccess,
408
+ onProgress,
409
+ path,
410
+ processFile,
411
+ useAccelerateEndpoint,
412
+ });
413
+ uploadFile$1({
414
+ input,
415
+ onComplete: (event) => {
416
+ if (ui.isFunction(onUploadSuccess)) {
417
+ onUploadSuccess({
418
+ key: event.key ??
419
+ event.path,
420
+ });
421
+ }
422
+ setUploadSuccess({ id });
423
+ },
424
+ onError: ({ key, error }) => {
425
+ if (ui.isFunction(onUploadError)) {
426
+ onUploadError(error.message, { key });
427
+ }
428
+ },
429
+ onStart: ({ key, uploadTask }) => {
430
+ if (ui.isFunction(onUploadStart)) {
431
+ onUploadStart({ key });
432
+ }
433
+ setUploadingFile({ id, uploadTask });
434
+ },
435
+ });
436
+ }
437
+ }
438
+ }, [
439
+ files,
440
+ accessLevel,
441
+ isResumable,
442
+ setUploadProgress,
443
+ setUploadingFile,
444
+ onUploadError,
445
+ onProcessFileSuccess,
446
+ onUploadSuccess,
447
+ onUploadStart,
448
+ maxFileCount,
449
+ setUploadSuccess,
450
+ processFile,
451
+ path,
452
+ useAccelerateEndpoint,
453
+ ]);
454
+ }
455
+
456
+ function Container$1({ children, className, }) {
457
+ return React__default["default"].createElement(uiReact.View, { className: className }, children);
458
+ }
459
+
460
+ function DropZone$1({ children, displayText, inDropZone, onDragEnter, onDragLeave, onDragOver, onDragStart, onDrop, testId, }) {
461
+ const { dropFilesText } = displayText;
462
+ const icons = internal.useIcons('storageManager');
463
+ return (React__default["default"].createElement(uiReact.View, { className: ui.classNames(inDropZone &&
464
+ ui.classNameModifier(ui.ComponentClassName.FileUploaderDropZone, 'active'), ui.ComponentClassName.FileUploaderDropZone), "data-testid": testId, onDragStart: onDragStart, onDragEnter: onDragEnter, onDragLeave: onDragLeave, onDrop: onDrop, onDragOver: onDragOver },
465
+ React__default["default"].createElement(uiReact.View, { as: "span", "aria-hidden": true, className: ui.ComponentClassName.FileUploaderDropZoneIcon }, icons?.upload ?? React__default["default"].createElement(internal.IconUpload, null)),
466
+ React__default["default"].createElement(uiReact.Text, { className: ui.ComponentClassName.FileUploaderDropZoneText }, dropFilesText),
467
+ children));
468
+ }
469
+
470
+ const FileStatusMessage$1 = ({ errorMessage, getPausedText, getUploadingText, percentage, status, uploadSuccessfulText, }) => {
471
+ const icons = internal.useIcons('storageManager');
472
+ switch (status) {
473
+ case FileStatus$1.UPLOADING: {
474
+ return (React__default["default"].createElement(uiReact.Text, { className: ui.ComponentClassName.FileUploaderFileStatus }, getUploadingText(percentage)));
475
+ }
476
+ case FileStatus$1.PAUSED:
477
+ return (React__default["default"].createElement(uiReact.Text, { className: ui.ComponentClassName.FileUploaderFileStatus }, getPausedText(percentage)));
478
+ case FileStatus$1.UPLOADED:
479
+ return (React__default["default"].createElement(uiReact.Text, { className: ui.classNames(ui.ComponentClassName.FileUploaderFileStatus, ui.classNameModifier(ui.ComponentClassName.FileUploaderFileStatus, 'success')) },
480
+ React__default["default"].createElement(uiReact.View, { as: "span", fontSize: "xl" }, icons?.success ?? React__default["default"].createElement(internal.IconCheck, null)),
481
+ uploadSuccessfulText));
482
+ case FileStatus$1.ERROR:
483
+ return (React__default["default"].createElement(uiReact.Text, { className: ui.classNames(ui.ComponentClassName.FileUploaderFileStatus, ui.classNameModifier(ui.ComponentClassName.FileUploaderFileStatus, 'error')) },
484
+ React__default["default"].createElement(uiReact.View, { as: "span", fontSize: "xl" }, icons?.error ?? React__default["default"].createElement(internal.IconError, null)),
485
+ errorMessage));
486
+ default:
487
+ return null;
28
488
  }
29
- n["default"] = e;
30
- return Object.freeze(n);
489
+ };
490
+
491
+ const FileRemoveButton$1 = ({ altText, onClick, }) => {
492
+ const icons = internal.useIcons('storageManager');
493
+ return (React__default["default"].createElement(uiReact.Button, { size: "small", onClick: onClick, testId: "storage-manager-remove-button" },
494
+ React__default["default"].createElement(uiReact.VisuallyHidden, null, altText),
495
+ React__default["default"].createElement(uiReact.View, { as: "span", "aria-hidden": true, fontSize: "medium" }, icons?.remove ?? React__default["default"].createElement(internal.IconClose, null))));
496
+ };
497
+
498
+ const UploadDetails$1 = ({ displayName, fileSize, }) => {
499
+ return (React__default["default"].createElement(React__default["default"].Fragment, null,
500
+ React__default["default"].createElement(uiReact.View, { className: ui.ComponentClassName.FileUploaderFileMain },
501
+ React__default["default"].createElement(uiReact.Text, { className: ui.ComponentClassName.FileUploaderFileName }, displayName)),
502
+ React__default["default"].createElement(uiReact.Text, { as: "span", className: ui.ComponentClassName.FileUploaderFileSize }, fileSize ? ui.humanFileSize(fileSize, true) : '')));
503
+ };
504
+
505
+ const FileThumbnail$1 = ({ fileName, isImage, url, }) => {
506
+ const icons = internal.useIcons('storageManager');
507
+ const thumbnail = isImage ? (React__default["default"].createElement(uiReact.Image, { alt: fileName, src: url })) : (icons?.file ?? React__default["default"].createElement(internal.IconFile, null));
508
+ return (React__default["default"].createElement(uiReact.View, { className: ui.ComponentClassName.FileUploaderFileImage }, thumbnail));
509
+ };
510
+
511
+ function FileControl$1({ onPause, onResume, displayName, errorMessage, isImage, isResumable, loaderIsDeterminate, onRemove, progress, showThumbnails = true, size, status, displayText, thumbnailUrl, }) {
512
+ const { getPausedText, getUploadingText, uploadSuccessfulText, pauseButtonText, resumeButtonText, } = displayText;
513
+ return (React__default["default"].createElement(uiReact.View, { className: ui.ComponentClassName.FileUploaderFile },
514
+ React__default["default"].createElement(uiReact.View, { className: ui.ComponentClassName.FileUploaderFileWrapper },
515
+ showThumbnails ? (React__default["default"].createElement(FileThumbnail$1, { isImage: isImage, fileName: displayName, url: thumbnailUrl })) : null,
516
+ React__default["default"].createElement(UploadDetails$1, { displayName: displayName, fileSize: size }),
517
+ status === FileStatus$1.UPLOADING ? (React__default["default"].createElement(uiReact.Loader, { className: ui.ComponentClassName.FileUploaderLoader, variation: "linear", percentage: progress, isDeterminate: loaderIsDeterminate, isPercentageTextHidden: true })) : null,
518
+ isResumable &&
519
+ (status === FileStatus$1.UPLOADING || status === FileStatus$1.PAUSED) ? (status === FileStatus$1.PAUSED ? (React__default["default"].createElement(uiReact.Button, { onClick: onResume, size: "small", variation: "link" }, resumeButtonText)) : (React__default["default"].createElement(uiReact.Button, { onClick: onPause, size: "small", variation: "link" }, pauseButtonText))) : null,
520
+ React__default["default"].createElement(FileRemoveButton$1, { altText: `Remove file ${displayName}`, onClick: onRemove })),
521
+ React__default["default"].createElement(FileStatusMessage$1, { uploadSuccessfulText: uploadSuccessfulText, getUploadingText: getUploadingText, getPausedText: getPausedText, status: status, errorMessage: errorMessage, percentage: progress })));
31
522
  }
32
523
 
33
- var React__namespace = /*#__PURE__*/_interopNamespace(React);
34
- var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
524
+ function FileList$1({ displayText, files, hasMaxFilesError, isResumable, onCancelUpload, onDeleteUpload, onResume, onPause, showThumbnails, maxFileCount, }) {
525
+ if (files.length < 1) {
526
+ return null;
527
+ }
528
+ const { getMaxFilesErrorText } = displayText;
529
+ const headingMaxFiles = getMaxFilesErrorText(maxFileCount);
530
+ return (React__default["default"].createElement(uiReact.View, { className: ui.ComponentClassName.FileUploaderFileList },
531
+ files.map((storageFile) => {
532
+ const { file, status, progress, error, key, isImage, id, uploadTask } = storageFile;
533
+ const thumbnailUrl = file && isImage ? URL.createObjectURL(file) : '';
534
+ const loaderIsDeterminate = isResumable ? progress > 0 : true;
535
+ const isUploading = status === FileStatus$1.UPLOADING;
536
+ const onRemove = () => {
537
+ if (isResumable &&
538
+ (status === FileStatus$1.UPLOADING || status === FileStatus$1.PAUSED) &&
539
+ uploadTask) {
540
+ onCancelUpload({ id, uploadTask });
541
+ }
542
+ else {
543
+ onDeleteUpload({ id });
544
+ }
545
+ };
546
+ const handlePauseUpload = () => {
547
+ if (uploadTask) {
548
+ onPause({ id, uploadTask });
549
+ }
550
+ };
551
+ const handleResumeUpload = () => {
552
+ if (uploadTask) {
553
+ onResume({ id, uploadTask });
554
+ }
555
+ };
556
+ return (React__default["default"].createElement(FileControl$1, { displayName: key, errorMessage: error, displayText: displayText, isImage: isImage, isUploading: isUploading, isResumable: isResumable, key: id, loaderIsDeterminate: loaderIsDeterminate, onRemove: onRemove, onPause: handlePauseUpload, onResume: handleResumeUpload, progress: progress, showThumbnails: showThumbnails, size: file?.size, status: status, thumbnailUrl: thumbnailUrl }));
557
+ }),
558
+ hasMaxFilesError && (React__default["default"].createElement(uiReact.Alert, { variation: "error", heading: headingMaxFiles }))));
559
+ }
560
+
561
+ function FileListHeader$1({ allUploadsSuccessful, displayText, fileCount, remainingFilesCount, selectedFilesCount = 0, }) {
562
+ const { getFilesUploadedText, getRemainingFilesText, getSelectedFilesText } = displayText;
563
+ return (React__default["default"].createElement(uiReact.Text, { className: ui.ComponentClassName.FileUploaderPreviewerText }, selectedFilesCount
564
+ ? getSelectedFilesText(selectedFilesCount)
565
+ : allUploadsSuccessful
566
+ ? getFilesUploadedText(fileCount)
567
+ : getRemainingFilesText(remainingFilesCount)));
568
+ }
569
+
570
+ function FileListFooter$1({ displayText, remainingFilesCount, onClearAll, onUploadAll, }) {
571
+ const { clearAllButtonText, getUploadButtonText } = displayText;
572
+ return (React__default["default"].createElement(uiReact.View, { className: ui.ComponentClassName.FileUploaderPreviewerFooter },
573
+ React__default["default"].createElement(uiReact.View, { className: ui.ComponentClassName.FileUploaderPreviewerActions },
574
+ React__default["default"].createElement(uiReact.Button, { size: "small", variation: "link", onClick: onClearAll }, clearAllButtonText),
575
+ React__default["default"].createElement(uiReact.Button, { size: "small", variation: "primary", onClick: onUploadAll }, getUploadButtonText(remainingFilesCount)))));
576
+ }
577
+
578
+ function FilePicker$1({ children, className = ui.ComponentClassName.FileUploaderFilePicker, size = 'small', ...props }) {
579
+ return (React__default["default"].createElement(uiReact.Button, { ...props, className: className, size: size }, children));
580
+ }
581
+
582
+ const VERSION = '3.3.0';
35
583
 
36
- const VERSION = '3.2.1';
584
+ const logger$1 = ui.getLogger('Storage');
585
+ const MISSING_REQUIRED_PROPS_MESSAGE$1 = '`FileUploader` requires a `maxFileCount` prop to be provided.';
586
+ const ACCESS_LEVEL_WITH_PATH_CALLBACK_MESSAGE$1 = '`FileUploader` does not allow usage of a `path` callback prop with an `accessLevel` prop.';
587
+ const ACCESS_LEVEL_DEPRECATION_MESSAGE$1 = '`accessLevel` has been deprecated and will be removed in a future major version. See migration notes at https://ui.docs.amplify.aws/react/connected-components/storage/FileUploader';
588
+ const FileUploaderBase = React__namespace.forwardRef(function FileUploader({ acceptedFileTypes = [], accessLevel, autoUpload = true, components, defaultFiles, displayText: overrideDisplayText, isResumable = false, maxFileCount, maxFileSize, onFileRemove, onUploadError, onUploadStart, onUploadSuccess, path, processFile, showThumbnails = true, useAccelerateEndpoint, }, ref) {
589
+ if (!maxFileCount) {
590
+ // eslint-disable-next-line no-console
591
+ console.warn(MISSING_REQUIRED_PROPS_MESSAGE$1);
592
+ }
593
+ if (accessLevel && typeof path === 'function') {
594
+ throw new Error(ACCESS_LEVEL_WITH_PATH_CALLBACK_MESSAGE$1);
595
+ }
596
+ uiReactCore.useDeprecationWarning({
597
+ message: ACCESS_LEVEL_DEPRECATION_MESSAGE$1,
598
+ shouldWarn: !!accessLevel,
599
+ });
600
+ const Components = {
601
+ Container: Container$1,
602
+ DropZone: DropZone$1,
603
+ FileList: FileList$1,
604
+ FilePicker: FilePicker$1,
605
+ FileListHeader: FileListHeader$1,
606
+ FileListFooter: FileListFooter$1,
607
+ ...components,
608
+ };
609
+ const allowMultipleFiles = maxFileCount === undefined ||
610
+ (typeof maxFileCount === 'number' && maxFileCount > 1);
611
+ const displayText = {
612
+ ...defaultFileUploaderDisplayText,
613
+ ...overrideDisplayText,
614
+ };
615
+ const { getFileSizeErrorText } = displayText;
616
+ const getMaxFileSizeErrorMessage = (file) => {
617
+ return checkMaxFileSize$1({
618
+ file,
619
+ maxFileSize,
620
+ getFileSizeErrorText,
621
+ });
622
+ };
623
+ const { addFiles, clearFiles, files, removeUpload, queueFiles, setProcessedKey, setUploadingFile, setUploadPaused, setUploadProgress, setUploadSuccess, setUploadResumed, } = useFileUploader(defaultFiles);
624
+ React__namespace.useImperativeHandle(ref, () => ({ clearFiles }));
625
+ const { dragState, ...dropZoneProps } = internal.useDropZone({
626
+ acceptedFileTypes,
627
+ onDropComplete: ({ acceptedFiles, rejectedFiles }) => {
628
+ if (rejectedFiles && rejectedFiles.length > 0) {
629
+ logger$1.warn('Rejected files: ', rejectedFiles);
630
+ }
631
+ // We need to filter out files by extension here,
632
+ // we don't get filenames on the drag event, only on drop
633
+ const _acceptedFiles = filterAllowedFiles$1(acceptedFiles, acceptedFileTypes);
634
+ addFiles({
635
+ files: _acceptedFiles,
636
+ status: autoUpload ? FileStatus$1.QUEUED : FileStatus$1.ADDED,
637
+ getFileErrorMessage: getMaxFileSizeErrorMessage,
638
+ });
639
+ },
640
+ });
641
+ useUploadFiles$1({
642
+ accessLevel,
643
+ files,
644
+ isResumable,
645
+ maxFileCount,
646
+ onUploadError,
647
+ onUploadSuccess,
648
+ onUploadStart,
649
+ onProcessFileSuccess: setProcessedKey,
650
+ setUploadingFile,
651
+ setUploadProgress,
652
+ setUploadSuccess,
653
+ processFile,
654
+ path,
655
+ useAccelerateEndpoint,
656
+ });
657
+ const onFilePickerChange = (event) => {
658
+ const { files } = event.target;
659
+ if (!files || files.length === 0) {
660
+ return;
661
+ }
662
+ addFiles({
663
+ files: Array.from(files),
664
+ status: autoUpload ? FileStatus$1.QUEUED : FileStatus$1.ADDED,
665
+ getFileErrorMessage: getMaxFileSizeErrorMessage,
666
+ });
667
+ };
668
+ const onClearAll = () => {
669
+ clearFiles();
670
+ };
671
+ const onUploadAll = () => {
672
+ queueFiles();
673
+ };
674
+ const onPauseUpload = ({ id, uploadTask }) => {
675
+ uploadTask.pause();
676
+ setUploadPaused({ id });
677
+ };
678
+ const onResumeUpload = ({ id, uploadTask }) => {
679
+ uploadTask.resume();
680
+ setUploadResumed({ id });
681
+ };
682
+ const onCancelUpload = ({ id, uploadTask }) => {
683
+ // At this time we don't know if the delete
684
+ // permissions are enabled (required to cancel upload),
685
+ // so we do a pause instead and remove from files
686
+ uploadTask.pause();
687
+ removeUpload({ id });
688
+ };
689
+ const onDeleteUpload = ({ id }) => {
690
+ // At this time we don't know if the delete
691
+ // permissions are enabled, so we do a soft delete
692
+ // from file list, but don't remove from storage
693
+ removeUpload({ id });
694
+ if (typeof onFileRemove === 'function') {
695
+ const file = files.find((file) => file.id === id);
696
+ if (file) {
697
+ // return `processedKey` if available and `processFile` is provided
698
+ const key = (processFile && file?.processedKey) ?? file.key;
699
+ onFileRemove({ key });
700
+ }
701
+ }
702
+ };
703
+ // checks if all downloads completed to 100%
704
+ const allUploadsSuccessful = files.length === 0
705
+ ? false
706
+ : files.every((file) => file?.status === FileStatus$1.UPLOADED);
707
+ // Displays if over max files
708
+ const hasMaxFilesError = files.filter((file) => file.progress < 100).length > maxFileCount;
709
+ const uploadedFilesLength = files.filter((file) => file?.status === FileStatus$1.UPLOADED).length;
710
+ const remainingFilesCount = files.length - uploadedFilesLength;
711
+ // number of files selected for upload when autoUpload is turned off
712
+ const selectedFilesCount = autoUpload ? 0 : remainingFilesCount;
713
+ const hasFiles = files.length > 0;
714
+ const hasUploadActions = !autoUpload && remainingFilesCount > 0;
715
+ const hiddenInput = React__namespace.useRef(null);
716
+ function handleClick() {
717
+ if (hiddenInput.current) {
718
+ hiddenInput.current.click();
719
+ hiddenInput.current.value = '';
720
+ }
721
+ }
722
+ uiReactCore.useSetUserAgent({
723
+ componentName: 'FileUploader',
724
+ packageName: 'react-storage',
725
+ version: VERSION,
726
+ });
727
+ return (React__namespace.createElement(Components.Container, { className: `${ui.ComponentClassName.FileUploader} ${hasFiles ? ui.ComponentClassName.FileUploaderPreviewer : ''}` },
728
+ React__namespace.createElement(Components.DropZone, { inDropZone: dragState !== 'inactive', ...dropZoneProps, displayText: displayText },
729
+ React__namespace.createElement(React__namespace.Fragment, null,
730
+ React__namespace.createElement(Components.FilePicker, { onClick: handleClick }, displayText.browseFilesText),
731
+ React__namespace.createElement(uiReact.VisuallyHidden, null,
732
+ React__namespace.createElement("input", { type: "file", tabIndex: -1, ref: hiddenInput, onChange: onFilePickerChange, multiple: allowMultipleFiles, accept: acceptedFileTypes.join(',') })))),
733
+ hasFiles ? (React__namespace.createElement(Components.FileListHeader, { allUploadsSuccessful: allUploadsSuccessful, displayText: displayText, fileCount: files.length, remainingFilesCount: remainingFilesCount, selectedFilesCount: selectedFilesCount })) : null,
734
+ React__namespace.createElement(Components.FileList, { displayText: displayText, files: files, isResumable: isResumable, onCancelUpload: onCancelUpload, onDeleteUpload: onDeleteUpload, onResume: onResumeUpload, onPause: onPauseUpload, showThumbnails: showThumbnails, hasMaxFilesError: hasMaxFilesError, maxFileCount: maxFileCount }),
735
+ hasUploadActions ? (React__namespace.createElement(Components.FileListFooter, { displayText: displayText, remainingFilesCount: remainingFilesCount, onClearAll: onClearAll, onUploadAll: onUploadAll })) : null));
736
+ });
737
+ // pass an empty object as first param to avoid destructive action on `FileUploaderBase`
738
+ const FileUploader = Object.assign({}, FileUploaderBase, {
739
+ Container: Container$1,
740
+ DropZone: DropZone$1,
741
+ FileList: FileList$1,
742
+ FileListHeader: FileListHeader$1,
743
+ FileListFooter: FileListFooter$1,
744
+ FilePicker: FilePicker$1,
745
+ });
37
746
 
38
747
  const MISSING_REQUIRED_PROP_MESSAGE = '`StorageImage` requires either an `imgKey` or `path` prop.';
39
748
  const HAS_DEPRECATED_PROPS_MESSAGE = '`imgKey`, `accessLevel`, and `identityId` will be replaced with `path` in a future major version. See https://ui.docs.amplify.aws/react/connected-components/storage/storageimage#props';
@@ -635,6 +1344,10 @@ const MISSING_REQUIRED_PROPS_MESSAGE = '`StorageManager` requires a `maxFileCoun
635
1344
  const ACCESS_LEVEL_WITH_PATH_CALLBACK_MESSAGE = '`StorageManager` does not allow usage of a `path` callback prop with an `accessLevel` prop.';
636
1345
  const ACCESS_LEVEL_DEPRECATION_MESSAGE = '`accessLevel` has been deprecated and will be removed in a future major version. See migration notes at https://ui.docs.amplify.aws/react/connected-components/storage/storagemanager';
637
1346
  const StorageManagerBase = React__namespace.forwardRef(function StorageManager({ acceptedFileTypes = [], accessLevel, autoUpload = true, components, defaultFiles, displayText: overrideDisplayText, isResumable = false, maxFileCount, maxFileSize, onFileRemove, onUploadError, onUploadStart, onUploadSuccess, path, processFile, showThumbnails = true, useAccelerateEndpoint, }, ref) {
1347
+ uiReactCore.useDeprecationWarning({
1348
+ message: 'The `StorageManager` component has been renamed as the `FileUploader` component.',
1349
+ shouldWarn: false,
1350
+ });
638
1351
  if (!maxFileCount) {
639
1352
  // eslint-disable-next-line no-console
640
1353
  console.warn(MISSING_REQUIRED_PROPS_MESSAGE);
@@ -793,5 +1506,6 @@ const StorageManager = Object.assign({}, StorageManagerBase, {
793
1506
  FilePicker,
794
1507
  });
795
1508
 
1509
+ exports.FileUploader = FileUploader;
796
1510
  exports.StorageImage = StorageImage;
797
1511
  exports.StorageManager = StorageManager;