@aws-amplify/ui-react-storage 3.0.17 → 3.1.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 (27) hide show
  1. package/dist/esm/components/StorageImage/StorageImage.mjs +46 -20
  2. package/dist/esm/components/StorageManager/StorageManager.mjs +23 -10
  3. package/dist/esm/components/StorageManager/hooks/useStorageManager/actions.mjs +31 -45
  4. package/dist/esm/components/StorageManager/hooks/useStorageManager/reducer.mjs +1 -1
  5. package/dist/esm/components/StorageManager/hooks/useUploadFiles/useUploadFiles.mjs +34 -31
  6. package/dist/esm/components/StorageManager/ui/FileList/FileDetails.mjs +1 -0
  7. package/dist/esm/components/StorageManager/utils/getInput.mjs +25 -0
  8. package/dist/esm/components/StorageManager/{hooks/useUploadFiles → utils}/resolveFile.mjs +2 -4
  9. package/dist/esm/components/StorageManager/utils/uploadFile.mjs +18 -21
  10. package/dist/esm/version.mjs +1 -1
  11. package/dist/index.js +264 -222
  12. package/dist/types/components/StorageImage/StorageImage.d.ts +6 -2
  13. package/dist/types/components/StorageImage/types.d.ts +30 -0
  14. package/dist/types/components/StorageManager/StorageManager.d.ts +5 -2
  15. package/dist/types/components/StorageManager/hooks/useStorageManager/actions.d.ts +2 -5
  16. package/dist/types/components/StorageManager/hooks/useStorageManager/types.d.ts +2 -2
  17. package/dist/types/components/StorageManager/hooks/useStorageManager/useStorageManager.d.ts +2 -5
  18. package/dist/types/components/StorageManager/hooks/useUploadFiles/useUploadFiles.d.ts +4 -1
  19. package/dist/types/components/StorageManager/types.d.ts +17 -7
  20. package/dist/types/components/StorageManager/ui/FileList/types.d.ts +4 -14
  21. package/dist/types/components/StorageManager/utils/getInput.d.ts +13 -0
  22. package/dist/types/components/StorageManager/utils/index.d.ts +2 -1
  23. package/dist/types/components/StorageManager/utils/resolveFile.d.ts +9 -0
  24. package/dist/types/components/StorageManager/utils/uploadFile.d.ts +31 -12
  25. package/dist/types/version.d.ts +1 -1
  26. package/package.json +6 -6
  27. package/dist/types/components/StorageManager/hooks/useUploadFiles/resolveFile.d.ts +0 -10
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@ var ui = require('@aws-amplify/ui');
7
7
  var uiReact = require('@aws-amplify/ui-react');
8
8
  var internal = require('@aws-amplify/ui-react/internal');
9
9
  var uiReactCore = require('@aws-amplify/ui-react-core');
10
+ var auth = require('aws-amplify/auth');
10
11
  var storage = require('aws-amplify/storage');
11
12
 
12
13
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
@@ -32,29 +33,55 @@ function _interopNamespace(e) {
32
33
  var React__namespace = /*#__PURE__*/_interopNamespace(React);
33
34
  var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
34
35
 
35
- const VERSION = '3.0.17';
36
+ const VERSION = '3.1.0';
36
37
 
37
- const StorageImage = ({ accessLevel, className, fallbackSrc, identityId, imgKey, onStorageGetError, validateObjectExistence, ...rest }) => {
38
- const resolvedValidateObjectExistence = ui.isUndefined(validateObjectExistence)
39
- ? true
40
- : validateObjectExistence;
41
- const options = React__namespace.useMemo(() => ({
42
- accessLevel,
43
- targetIdentityId: identityId,
44
- validateObjectExistence: resolvedValidateObjectExistence,
45
- }), [accessLevel, identityId, resolvedValidateObjectExistence]);
38
+ const MISSING_REQUIRED_PROP_MESSAGE = '`StorageImage` requires either an `imgKey` or `path` prop.';
39
+ 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';
40
+ const HAS_PATH_AND_KEY_MESSAGE = '`imgKey` is ignored when both `imgKey` and `path` props are provided.';
41
+ const HAS_PATH_AND_UNSUPPORTED_OPTIONS_MESSAGE = '`accessLevel` and `identityId` are ignored when the `path` prop is provided.';
42
+ const getDeprecationMessage = ({ hasImgkey, hasPath, hasDeprecatedOptions, }) => {
43
+ let message = '';
44
+ if (hasPath && hasImgkey) {
45
+ message = HAS_PATH_AND_KEY_MESSAGE;
46
+ }
47
+ else if (hasPath && hasDeprecatedOptions) {
48
+ message = HAS_PATH_AND_UNSUPPORTED_OPTIONS_MESSAGE;
49
+ }
50
+ else if (hasImgkey) {
51
+ message = HAS_DEPRECATED_PROPS_MESSAGE;
52
+ }
53
+ return message;
54
+ };
55
+ const StorageImage = ({ accessLevel, className, fallbackSrc, identityId, imgKey, path, onStorageGetError, onGetUrlError, validateObjectExistence = true, ...rest }) => {
56
+ const hasImgkey = !!imgKey;
57
+ const hasPath = !!path;
58
+ const hasDeprecatedOptions = !!accessLevel || !!identityId;
59
+ const message = getDeprecationMessage({
60
+ hasDeprecatedOptions,
61
+ hasImgkey,
62
+ hasPath,
63
+ });
64
+ internal.useDeprecationWarning({ message, shouldWarn: !!message });
65
+ if (!hasImgkey && !hasPath) {
66
+ throw new Error(MISSING_REQUIRED_PROP_MESSAGE);
67
+ }
46
68
  uiReactCore.useSetUserAgent({
47
69
  componentName: 'StorageImage',
48
70
  packageName: 'react-storage',
49
71
  version: VERSION,
50
72
  });
51
- const url = internal.useStorageURL({
52
- key: imgKey,
53
- options,
54
- fallbackURL: fallbackSrc,
55
- onStorageGetError,
56
- });
57
- return (React__namespace.createElement(uiReact.Image, { ...rest, className: ui.classNames(ui.ComponentClassName.StorageImage, className), src: url }));
73
+ const onError = onGetUrlError ?? onStorageGetError;
74
+ const input = React__namespace.useMemo(() => ({
75
+ ...(path ? { path } : { key: imgKey }),
76
+ onError,
77
+ options: {
78
+ accessLevel,
79
+ targetIdentityId: identityId,
80
+ validateObjectExistence,
81
+ },
82
+ }), [accessLevel, imgKey, identityId, onError, path, validateObjectExistence]);
83
+ const { url } = uiReactCore.useGetUrl(input);
84
+ return (React__namespace.createElement(uiReact.Image, { ...rest, className: ui.classNames(ui.ComponentClassName.StorageImage, className), src: url?.toString() ?? fallbackSrc }));
58
85
  };
59
86
 
60
87
  var FileStatus;
@@ -137,7 +164,7 @@ function storageManagerStateReducer(state, action) {
137
164
  ...currentFile,
138
165
  status: FileStatus.UPLOADING,
139
166
  progress: 0,
140
- uploadTask: uploadTask ? uploadTask : undefined,
167
+ uploadTask,
141
168
  },
142
169
  ];
143
170
  }
@@ -206,51 +233,37 @@ function storageManagerStateReducer(state, action) {
206
233
  }
207
234
  }
208
235
 
209
- const addFilesAction = ({ files, status, getFileErrorMessage, }) => {
210
- return {
211
- type: StorageManagerActionTypes.ADD_FILES,
212
- files,
213
- status,
214
- getFileErrorMessage,
215
- };
216
- };
217
- const clearFilesAction = () => {
218
- return {
219
- type: StorageManagerActionTypes.CLEAR_FILES,
220
- };
221
- };
222
- const queueFilesAction = () => {
223
- return {
224
- type: StorageManagerActionTypes.QUEUE_FILES,
225
- };
226
- };
227
- const setUploadingFileAction = ({ id, uploadTask, }) => {
228
- return {
229
- type: StorageManagerActionTypes.SET_STATUS_UPLOADING,
230
- id,
231
- uploadTask,
232
- };
233
- };
234
- const setUploadProgressAction = ({ id, progress, }) => {
235
- return {
236
- type: StorageManagerActionTypes.SET_UPLOAD_PROGRESS,
237
- id,
238
- progress,
239
- };
240
- };
241
- const setUploadStatusAction = ({ id, status, }) => {
242
- return {
243
- type: StorageManagerActionTypes.SET_STATUS,
244
- id,
245
- status,
246
- };
247
- };
248
- const removeUploadAction = ({ id }) => {
249
- return {
250
- type: StorageManagerActionTypes.REMOVE_UPLOAD,
251
- id,
252
- };
253
- };
236
+ const addFilesAction = ({ files, status, getFileErrorMessage, }) => ({
237
+ type: StorageManagerActionTypes.ADD_FILES,
238
+ files,
239
+ status,
240
+ getFileErrorMessage,
241
+ });
242
+ const clearFilesAction = () => ({
243
+ type: StorageManagerActionTypes.CLEAR_FILES,
244
+ });
245
+ const queueFilesAction = () => ({
246
+ type: StorageManagerActionTypes.QUEUE_FILES,
247
+ });
248
+ const setUploadingFileAction = ({ id, uploadTask, }) => ({
249
+ type: StorageManagerActionTypes.SET_STATUS_UPLOADING,
250
+ id,
251
+ uploadTask,
252
+ });
253
+ const setUploadProgressAction = ({ id, progress, }) => ({
254
+ type: StorageManagerActionTypes.SET_UPLOAD_PROGRESS,
255
+ id,
256
+ progress,
257
+ });
258
+ const setUploadStatusAction = ({ id, status, }) => ({
259
+ type: StorageManagerActionTypes.SET_STATUS,
260
+ id,
261
+ status,
262
+ });
263
+ const removeUploadAction = ({ id }) => ({
264
+ type: StorageManagerActionTypes.REMOVE_UPLOAD,
265
+ id,
266
+ });
254
267
 
255
268
  const isDefaultFile = (file) => !!(ui.isObject(file) && file.key);
256
269
  const createFileFromDefault = (file) => isDefaultFile(file)
@@ -303,157 +316,6 @@ function useStorageManager(defaultFiles = []) {
303
316
  };
304
317
  }
305
318
 
306
- function uploadFile({ file, key, level = 'private', progressCallback: onProgress, errorCallback, completeCallback, ...rest }) {
307
- const contentType = file.type || 'binary/octet-stream';
308
- const input = {
309
- key,
310
- data: file,
311
- options: {
312
- accessLevel: level,
313
- contentType,
314
- onProgress,
315
- ...rest,
316
- },
317
- };
318
- const output = storage.uploadData(input);
319
- output.result
320
- .then(() => {
321
- if (output.state === 'SUCCESS') {
322
- completeCallback?.({ key });
323
- }
324
- })
325
- .catch((e) => {
326
- const error = e;
327
- errorCallback?.(error.message);
328
- });
329
- return output;
330
- }
331
-
332
- /**
333
- * Utility function that takes the processFile prop, along with a file a key
334
- * and returns a Promise that resolves to { file, key, ..rest }
335
- * regardless if processFile is defined and if it is sync or async
336
- */
337
- const resolveFile = ({ processFile, file, key, }) => {
338
- return new Promise((resolve, reject) => {
339
- const result = ui.isFunction(processFile)
340
- ? processFile({ file, key })
341
- : { file, key };
342
- if (result instanceof Promise) {
343
- result.then(resolve).catch(reject);
344
- }
345
- else {
346
- resolve(result);
347
- }
348
- });
349
- };
350
-
351
- function useUploadFiles({ files, accessLevel, isResumable, setUploadProgress, setUploadingFile, setUploadSuccess, onUploadError, onUploadSuccess, onUploadStart, maxFileCount, processFile, path, }) {
352
- React__namespace.useEffect(() => {
353
- const filesReadyToUpload = files.filter((file) => file.status === FileStatus.QUEUED);
354
- if (filesReadyToUpload.length > maxFileCount) {
355
- return;
356
- }
357
- for (const { file, key, id } of filesReadyToUpload) {
358
- const onComplete = (event) => {
359
- if (ui.isFunction(onUploadSuccess)) {
360
- onUploadSuccess(event);
361
- }
362
- setUploadSuccess({ id });
363
- };
364
- const onProgress = (event) => {
365
- /**
366
- * When a file is zero bytes, the progress.total will equal zero.
367
- * Therefore, this will prevent a divide by zero error.
368
- */
369
- const progressPercentage = event.totalBytes === undefined || event.totalBytes === 0
370
- ? 100
371
- : Math.floor((event.transferredBytes / event.totalBytes) * 100);
372
- setUploadProgress({ id, progress: progressPercentage });
373
- };
374
- if (file) {
375
- resolveFile({ processFile, file, key }).then(({ key: processedKey, ...rest }) => {
376
- // prepend `path` to `processedKey`
377
- const resolvedKey = ui.isString(path)
378
- ? `${path}${processedKey}`
379
- : processedKey;
380
- if (ui.isFunction(onUploadStart)) {
381
- onUploadStart({ key: resolvedKey });
382
- }
383
- const uploadTask = uploadFile({
384
- ...rest,
385
- key: resolvedKey,
386
- level: accessLevel,
387
- progressCallback: onProgress,
388
- errorCallback: (error) => {
389
- if (ui.isFunction(onUploadError)) {
390
- onUploadError(error, { key: resolvedKey });
391
- }
392
- },
393
- completeCallback: onComplete,
394
- });
395
- setUploadingFile({ id, uploadTask });
396
- });
397
- }
398
- }
399
- }, [
400
- files,
401
- accessLevel,
402
- isResumable,
403
- setUploadProgress,
404
- setUploadingFile,
405
- onUploadError,
406
- onUploadSuccess,
407
- onUploadStart,
408
- maxFileCount,
409
- setUploadSuccess,
410
- processFile,
411
- path,
412
- ]);
413
- }
414
-
415
- function Container({ children, className, }) {
416
- return React__default["default"].createElement(uiReact.View, { className: className }, children);
417
- }
418
-
419
- function DropZone({ children, displayText, inDropZone, onDragEnter, onDragLeave, onDragOver, onDragStart, onDrop, testId, }) {
420
- const { dropFilesText } = displayText;
421
- const icons = internal.useIcons('storageManager');
422
- return (React__default["default"].createElement(uiReact.View, { className: ui.classNames(inDropZone &&
423
- ui.classNameModifier(ui.ComponentClassName.StorageManagerDropZone, 'active'), ui.ComponentClassName.StorageManagerDropZone), "data-testid": testId, onDragStart: onDragStart, onDragEnter: onDragEnter, onDragLeave: onDragLeave, onDrop: onDrop, onDragOver: onDragOver },
424
- React__default["default"].createElement(uiReact.View, { as: "span", "aria-hidden": true, className: ui.ComponentClassName.StorageManagerDropZoneIcon }, icons?.upload ?? React__default["default"].createElement(internal.IconUpload, null)),
425
- React__default["default"].createElement(uiReact.Text, { className: ui.ComponentClassName.StorageManagerDropZoneText }, dropFilesText),
426
- children));
427
- }
428
-
429
- const FileStatusMessage = ({ errorMessage, getPausedText, getUploadingText, percentage, status, uploadSuccessfulText, }) => {
430
- const icons = internal.useIcons('storageManager');
431
- switch (status) {
432
- case FileStatus.UPLOADING: {
433
- return (React__default["default"].createElement(uiReact.Text, { className: ui.ComponentClassName.StorageManagerFileStatus }, getUploadingText(percentage)));
434
- }
435
- case FileStatus.PAUSED:
436
- return (React__default["default"].createElement(uiReact.Text, { className: ui.ComponentClassName.StorageManagerFileStatus }, getPausedText(percentage)));
437
- case FileStatus.UPLOADED:
438
- return (React__default["default"].createElement(uiReact.Text, { className: ui.classNames(ui.ComponentClassName.StorageManagerFileStatus, ui.classNameModifier(ui.ComponentClassName.StorageManagerFileStatus, 'success')) },
439
- React__default["default"].createElement(uiReact.View, { as: "span", fontSize: "xl" }, icons?.success ?? React__default["default"].createElement(internal.IconCheck, null)),
440
- uploadSuccessfulText));
441
- case FileStatus.ERROR:
442
- return (React__default["default"].createElement(uiReact.Text, { className: ui.classNames(ui.ComponentClassName.StorageManagerFileStatus, ui.classNameModifier(ui.ComponentClassName.StorageManagerFileStatus, 'error')) },
443
- React__default["default"].createElement(uiReact.View, { as: "span", fontSize: "xl" }, icons?.error ?? React__default["default"].createElement(internal.IconError, null)),
444
- errorMessage));
445
- default:
446
- return null;
447
- }
448
- };
449
-
450
- const FileRemoveButton = ({ altText, onClick, }) => {
451
- const icons = internal.useIcons('storageManager');
452
- return (React__default["default"].createElement(uiReact.Button, { size: "small", onClick: onClick },
453
- React__default["default"].createElement(uiReact.VisuallyHidden, null, altText),
454
- React__default["default"].createElement(uiReact.View, { as: "span", "aria-hidden": true, fontSize: "medium" }, icons?.remove ?? React__default["default"].createElement(internal.IconClose, null))));
455
- };
456
-
457
319
  /**
458
320
  * Format bytes as human-readable text.
459
321
  *
@@ -555,6 +417,174 @@ const filterAllowedFiles = (files, acceptedFileTypes) => {
555
417
  });
556
418
  };
557
419
 
420
+ /**
421
+ * Utility function that takes the processFile prop, along with a file a key
422
+ * and returns a Promise that resolves to { file, key, ..rest }
423
+ * regardless if processFile is defined and if it is sync or async
424
+ */
425
+ const resolveFile = ({ processFile, ...input }) => {
426
+ return new Promise((resolve, reject) => {
427
+ const result = ui.isFunction(processFile) ? processFile(input) : input;
428
+ if (result instanceof Promise) {
429
+ result.then(resolve).catch(reject);
430
+ }
431
+ else {
432
+ resolve(result);
433
+ }
434
+ });
435
+ };
436
+
437
+ const getInput = ({ accessLevel, file, key, onProgress, path, processFile, }) => {
438
+ return async () => {
439
+ const hasCallbackPath = ui.isTypedFunction(path);
440
+ const hasStringPath = ui.isString(path);
441
+ const hasKeyInput = !!accessLevel && !hasCallbackPath;
442
+ const { file: data, key: fileKey, ...rest } = await resolveFile({ file, key, processFile });
443
+ const contentType = file.type || 'binary/octet-stream';
444
+ // IMPORTANT: always pass `...rest` here for backwards compatibility
445
+ const options = { contentType, onProgress, ...rest };
446
+ if (hasKeyInput) {
447
+ // legacy handling of `path` is to prefix to `fileKey`
448
+ const resolvedKey = hasStringPath ? `${path}${fileKey}` : fileKey;
449
+ return { data, key: resolvedKey, options: { ...options, accessLevel } };
450
+ }
451
+ const { identityId } = await auth.fetchAuthSession();
452
+ const resolvedPath = `${hasCallbackPath ? path({ identityId }) : path}${fileKey}`;
453
+ return { data: file, path: resolvedPath, options };
454
+ };
455
+ };
456
+
457
+ async function uploadFile({ input, onError, onStart, onComplete, }) {
458
+ const resolvedInput = await input();
459
+ const uploadTask = storage.uploadData(resolvedInput);
460
+ const key = resolvedInput?.key ??
461
+ resolvedInput?.path;
462
+ if (ui.isFunction(onStart)) {
463
+ onStart({ key, uploadTask });
464
+ }
465
+ uploadTask.result
466
+ .then((result) => {
467
+ if (ui.isFunction(onComplete) && uploadTask.state === 'SUCCESS') {
468
+ onComplete(result);
469
+ }
470
+ })
471
+ .catch((error) => {
472
+ if (ui.isFunction(onError)) {
473
+ onError({ key, error });
474
+ }
475
+ });
476
+ return uploadTask;
477
+ }
478
+
479
+ function useUploadFiles({ files, accessLevel, isResumable, setUploadProgress, setUploadingFile, setUploadSuccess, onUploadError, onUploadSuccess, onUploadStart, maxFileCount, processFile, path, }) {
480
+ React__namespace.useEffect(() => {
481
+ const filesReadyToUpload = files.filter((file) => file.status === FileStatus.QUEUED);
482
+ if (filesReadyToUpload.length > maxFileCount) {
483
+ return;
484
+ }
485
+ for (const { file, key, id } of filesReadyToUpload) {
486
+ const onProgress = (event) => {
487
+ /**
488
+ * When a file is zero bytes, the progress.total will equal zero.
489
+ * Therefore, this will prevent a divide by zero error.
490
+ */
491
+ const progress = event.totalBytes === undefined || event.totalBytes === 0
492
+ ? 100
493
+ : Math.floor((event.transferredBytes / event.totalBytes) * 100);
494
+ setUploadProgress({ id, progress });
495
+ };
496
+ if (file) {
497
+ const input = getInput({
498
+ accessLevel,
499
+ file,
500
+ key,
501
+ onProgress,
502
+ path,
503
+ processFile,
504
+ });
505
+ uploadFile({
506
+ input,
507
+ onComplete: (event) => {
508
+ if (ui.isFunction(onUploadSuccess)) {
509
+ onUploadSuccess({
510
+ key: event.key ??
511
+ event.path,
512
+ });
513
+ }
514
+ setUploadSuccess({ id });
515
+ },
516
+ onError: ({ key, error }) => {
517
+ if (ui.isFunction(onUploadError)) {
518
+ onUploadError(error.message, { key });
519
+ }
520
+ },
521
+ onStart: ({ key, uploadTask }) => {
522
+ if (ui.isFunction(onUploadStart)) {
523
+ onUploadStart({ key });
524
+ }
525
+ setUploadingFile({ id, uploadTask });
526
+ },
527
+ });
528
+ }
529
+ }
530
+ }, [
531
+ files,
532
+ accessLevel,
533
+ isResumable,
534
+ setUploadProgress,
535
+ setUploadingFile,
536
+ onUploadError,
537
+ onUploadSuccess,
538
+ onUploadStart,
539
+ maxFileCount,
540
+ setUploadSuccess,
541
+ processFile,
542
+ path,
543
+ ]);
544
+ }
545
+
546
+ function Container({ children, className, }) {
547
+ return React__default["default"].createElement(uiReact.View, { className: className }, children);
548
+ }
549
+
550
+ function DropZone({ children, displayText, inDropZone, onDragEnter, onDragLeave, onDragOver, onDragStart, onDrop, testId, }) {
551
+ const { dropFilesText } = displayText;
552
+ const icons = internal.useIcons('storageManager');
553
+ return (React__default["default"].createElement(uiReact.View, { className: ui.classNames(inDropZone &&
554
+ ui.classNameModifier(ui.ComponentClassName.StorageManagerDropZone, 'active'), ui.ComponentClassName.StorageManagerDropZone), "data-testid": testId, onDragStart: onDragStart, onDragEnter: onDragEnter, onDragLeave: onDragLeave, onDrop: onDrop, onDragOver: onDragOver },
555
+ React__default["default"].createElement(uiReact.View, { as: "span", "aria-hidden": true, className: ui.ComponentClassName.StorageManagerDropZoneIcon }, icons?.upload ?? React__default["default"].createElement(internal.IconUpload, null)),
556
+ React__default["default"].createElement(uiReact.Text, { className: ui.ComponentClassName.StorageManagerDropZoneText }, dropFilesText),
557
+ children));
558
+ }
559
+
560
+ const FileStatusMessage = ({ errorMessage, getPausedText, getUploadingText, percentage, status, uploadSuccessfulText, }) => {
561
+ const icons = internal.useIcons('storageManager');
562
+ switch (status) {
563
+ case FileStatus.UPLOADING: {
564
+ return (React__default["default"].createElement(uiReact.Text, { className: ui.ComponentClassName.StorageManagerFileStatus }, getUploadingText(percentage)));
565
+ }
566
+ case FileStatus.PAUSED:
567
+ return (React__default["default"].createElement(uiReact.Text, { className: ui.ComponentClassName.StorageManagerFileStatus }, getPausedText(percentage)));
568
+ case FileStatus.UPLOADED:
569
+ return (React__default["default"].createElement(uiReact.Text, { className: ui.classNames(ui.ComponentClassName.StorageManagerFileStatus, ui.classNameModifier(ui.ComponentClassName.StorageManagerFileStatus, 'success')) },
570
+ React__default["default"].createElement(uiReact.View, { as: "span", fontSize: "xl" }, icons?.success ?? React__default["default"].createElement(internal.IconCheck, null)),
571
+ uploadSuccessfulText));
572
+ case FileStatus.ERROR:
573
+ return (React__default["default"].createElement(uiReact.Text, { className: ui.classNames(ui.ComponentClassName.StorageManagerFileStatus, ui.classNameModifier(ui.ComponentClassName.StorageManagerFileStatus, 'error')) },
574
+ React__default["default"].createElement(uiReact.View, { as: "span", fontSize: "xl" }, icons?.error ?? React__default["default"].createElement(internal.IconError, null)),
575
+ errorMessage));
576
+ default:
577
+ return null;
578
+ }
579
+ };
580
+
581
+ const FileRemoveButton = ({ altText, onClick, }) => {
582
+ const icons = internal.useIcons('storageManager');
583
+ return (React__default["default"].createElement(uiReact.Button, { size: "small", onClick: onClick },
584
+ React__default["default"].createElement(uiReact.VisuallyHidden, null, altText),
585
+ React__default["default"].createElement(uiReact.View, { as: "span", "aria-hidden": true, fontSize: "medium" }, icons?.remove ?? React__default["default"].createElement(internal.IconClose, null))));
586
+ };
587
+
558
588
  const UploadDetails = ({ displayName, fileSize, }) => {
559
589
  return (React__default["default"].createElement(React__default["default"].Fragment, null,
560
590
  React__default["default"].createElement(uiReact.View, { className: ui.ComponentClassName.StorageManagerFileMain },
@@ -640,10 +670,21 @@ function FilePicker({ children, className = ui.ComponentClassName.StorageManager
640
670
  }
641
671
 
642
672
  const logger = ui.getLogger('Storage');
643
- function StorageManagerBase({ acceptedFileTypes = [], accessLevel, autoUpload = true, defaultFiles, displayText: overrideDisplayText, isResumable = false, maxFileCount, maxFileSize, onUploadError, onUploadSuccess, onFileRemove, onUploadStart, showThumbnails = true, processFile, components, path, }, ref) {
644
- if (!accessLevel || !maxFileCount) {
645
- logger.warn('StorageManager requires accessLevel and maxFileCount props');
673
+ const MISSING_REQUIRED_PROPS_MESSAGE = '`StorageManager` requires a `maxFileCount` prop to be provided.';
674
+ const ACCESS_LEVEL_WITH_PATH_CALLBACK_MESSAGE = '`StorageManager` does not allow usage of a `path` callback prop with an `accessLevel` prop.';
675
+ 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';
676
+ 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, }, ref) {
677
+ if (!maxFileCount) {
678
+ // eslint-disable-next-line no-console
679
+ console.warn(MISSING_REQUIRED_PROPS_MESSAGE);
680
+ }
681
+ if (accessLevel && typeof path === 'function') {
682
+ throw new Error(ACCESS_LEVEL_WITH_PATH_CALLBACK_MESSAGE);
646
683
  }
684
+ uiReactCore.useDeprecationWarning({
685
+ message: ACCESS_LEVEL_DEPRECATION_MESSAGE,
686
+ shouldWarn: !!accessLevel,
687
+ });
647
688
  const Components = {
648
689
  Container,
649
690
  DropZone,
@@ -716,15 +757,15 @@ function StorageManagerBase({ acceptedFileTypes = [], accessLevel, autoUpload =
716
757
  const onUploadAll = () => {
717
758
  queueFiles();
718
759
  };
719
- const onPauseUpload = ({ id, uploadTask, }) => {
760
+ const onPauseUpload = ({ id, uploadTask }) => {
720
761
  uploadTask.pause();
721
762
  setUploadPaused({ id });
722
763
  };
723
- const onResumeUpload = ({ id, uploadTask, }) => {
764
+ const onResumeUpload = ({ id, uploadTask }) => {
724
765
  uploadTask.resume();
725
766
  setUploadResumed({ id });
726
767
  };
727
- const onCancelUpload = ({ id, uploadTask, }) => {
768
+ const onCancelUpload = ({ id, uploadTask }) => {
728
769
  // At this time we don't know if the delete
729
770
  // permissions are enabled (required to cancel upload),
730
771
  // so we do a pause instead and remove from files
@@ -776,8 +817,9 @@ function StorageManagerBase({ acceptedFileTypes = [], accessLevel, autoUpload =
776
817
  hasFiles ? (React__namespace.createElement(Components.FileListHeader, { allUploadsSuccessful: allUploadsSuccessful, displayText: displayText, fileCount: files.length, remainingFilesCount: remainingFilesCount, selectedFilesCount: selectedFilesCount })) : null,
777
818
  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 }),
778
819
  hasUploadActions ? (React__namespace.createElement(Components.FileListFooter, { displayText: displayText, remainingFilesCount: remainingFilesCount, onClearAll: onClearAll, onUploadAll: onUploadAll })) : null));
779
- }
780
- const StorageManager = Object.assign(React__namespace.forwardRef(StorageManagerBase), {
820
+ });
821
+ // pass an empty object as first param to avoid destructive action on `StorageManagerBase`
822
+ const StorageManager = Object.assign({}, StorageManagerBase, {
781
823
  Container,
782
824
  DropZone,
783
825
  FileList,
@@ -1,3 +1,7 @@
1
1
  /// <reference types="react" />
2
- import type { StorageImageProps } from './types';
3
- export declare const StorageImage: ({ accessLevel, className, fallbackSrc, identityId, imgKey, onStorageGetError, validateObjectExistence, ...rest }: StorageImageProps) => JSX.Element;
2
+ import type { StorageImageProps, StorageImagePathProps } from './types';
3
+ export declare const MISSING_REQUIRED_PROP_MESSAGE = "`StorageImage` requires either an `imgKey` or `path` prop.";
4
+ export declare 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";
5
+ export declare const HAS_PATH_AND_KEY_MESSAGE = "`imgKey` is ignored when both `imgKey` and `path` props are provided.";
6
+ export declare const HAS_PATH_AND_UNSUPPORTED_OPTIONS_MESSAGE = "`accessLevel` and `identityId` are ignored when the `path` prop is provided.";
7
+ export declare const StorageImage: ({ accessLevel, className, fallbackSrc, identityId, imgKey, path, onStorageGetError, onGetUrlError, validateObjectExistence, ...rest }: StorageImageProps | StorageImagePathProps) => JSX.Element;
@@ -1,10 +1,40 @@
1
1
  import { StorageAccessLevel } from '@aws-amplify/core';
2
2
  import { ImageProps } from '@aws-amplify/ui-react';
3
3
  export interface StorageImageProps extends Omit<ImageProps, 'src'> {
4
+ /**
5
+ * @deprecated
6
+ * `imgKey` will be replaced with `path` in a future major version of Amplify UI. See https://ui.docs.amplify.aws/react/connected-components/storage/storageimage#props
7
+ */
4
8
  imgKey: string;
9
+ /**
10
+ * @deprecated
11
+ * `accessLevel` will be replaced with `path` in a future major version of Amplify UI. See https://ui.docs.amplify.aws/react/connected-components/storage/storageimage#props
12
+ */
5
13
  accessLevel: StorageAccessLevel;
14
+ /**
15
+ * @deprecated
16
+ * `identityId` will be replaced with `path` in a future major version of Amplify UI. See https://ui.docs.amplify.aws/react/connected-components/storage/storageimage#props
17
+ */
6
18
  identityId?: string;
7
19
  fallbackSrc?: string;
8
20
  validateObjectExistence?: boolean;
21
+ /**
22
+ * @deprecated use `onGetUrlError`
23
+ *
24
+ * `onStorageGetError` will be replaced with `onGetUrlError` in a future major version of Amplify UI. See https://ui.docs.amplify.aws/react/connected-components/storage/storageimage#props
25
+ */
9
26
  onStorageGetError?: (error: Error) => void;
27
+ onGetUrlError?: (error: Error) => void;
28
+ path?: never;
10
29
  }
30
+ type OmittedPropKey = 'accessLevel' | 'imgKey' | 'identityId' | 'onStorageGetError' | 'path';
31
+ export interface StorageImagePathProps extends Omit<StorageImageProps, OmittedPropKey> {
32
+ path: string | ((input: {
33
+ identityId?: string;
34
+ }) => string);
35
+ imgKey?: never;
36
+ accessLevel?: never;
37
+ identityId?: never;
38
+ onStorageGetError?: never;
39
+ }
40
+ export {};
@@ -1,7 +1,10 @@
1
1
  import * as React from 'react';
2
- import { StorageManagerProps, StorageManagerHandle } from './types';
2
+ import { StorageManagerProps, StorageManagerPathProps, StorageManagerHandle } from './types';
3
3
  import { Container, DropZone, FileList, FileListHeader, FileListFooter, FilePicker } from './ui';
4
- declare const StorageManager: React.ForwardRefExoticComponent<StorageManagerProps & React.RefAttributes<StorageManagerHandle>> & {
4
+ export declare const MISSING_REQUIRED_PROPS_MESSAGE = "`StorageManager` requires a `maxFileCount` prop to be provided.";
5
+ export declare const ACCESS_LEVEL_WITH_PATH_CALLBACK_MESSAGE = "`StorageManager` does not allow usage of a `path` callback prop with an `accessLevel` prop.";
6
+ export declare 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";
7
+ declare const StorageManager: React.ForwardRefExoticComponent<(StorageManagerProps | StorageManagerPathProps) & React.RefAttributes<StorageManagerHandle>> & {
5
8
  Container: typeof Container;
6
9
  DropZone: typeof DropZone;
7
10
  FileList: typeof FileList;
@@ -1,13 +1,10 @@
1
- import { UploadDataOutput } from 'aws-amplify/storage';
2
1
  import { FileStatus } from '../../types';
3
2
  import { Action, AddFilesActionParams } from './types';
3
+ import { TaskEvent } from '../../utils';
4
4
  export declare const addFilesAction: ({ files, status, getFileErrorMessage, }: AddFilesActionParams) => Action;
5
5
  export declare const clearFilesAction: () => Action;
6
6
  export declare const queueFilesAction: () => Action;
7
- export declare const setUploadingFileAction: ({ id, uploadTask, }: {
8
- id: string;
9
- uploadTask: UploadDataOutput | undefined;
10
- }) => Action;
7
+ export declare const setUploadingFileAction: ({ id, uploadTask, }: TaskEvent) => Action;
11
8
  export declare const setUploadProgressAction: ({ id, progress, }: {
12
9
  id: string;
13
10
  progress: number;
@@ -1,5 +1,5 @@
1
- import { UploadDataOutput } from 'aws-amplify/storage';
2
1
  import { FileStatus, StorageFiles } from '../../types';
2
+ import { UploadTask } from '../../utils';
3
3
  export interface UseStorageManagerState {
4
4
  files: StorageFiles;
5
5
  }
@@ -29,7 +29,7 @@ export type Action = {
29
29
  } | {
30
30
  type: StorageManagerActionTypes.SET_STATUS_UPLOADING;
31
31
  id: string;
32
- uploadTask?: UploadDataOutput;
32
+ uploadTask?: UploadTask;
33
33
  } | {
34
34
  type: StorageManagerActionTypes.SET_UPLOAD_PROGRESS;
35
35
  id: string;