@aws-amplify/ui-react-storage 3.10.3 → 3.11.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 (55) hide show
  1. package/dist/browser.js +1 -1
  2. package/dist/{createStorageBrowser-B75dAYRb.js → createStorageBrowser-CVfazB4S.js} +167 -169
  3. package/dist/esm/components/StorageBrowser/actions/handlers/listLocations.mjs +1 -1
  4. package/dist/esm/components/StorageBrowser/createStorageBrowser/StorageBrowserDefault.mjs +1 -1
  5. package/dist/esm/components/StorageBrowser/createStorageBrowser/createProvider.mjs +5 -3
  6. package/dist/esm/components/StorageBrowser/createStorageBrowser/createStorageBrowser.mjs +1 -1
  7. package/dist/esm/components/StorageBrowser/displayText/libraries/en/uploadView.mjs +3 -6
  8. package/dist/esm/components/StorageBrowser/fileItems/constants.mjs +11 -0
  9. package/dist/esm/components/StorageBrowser/fileItems/context.mjs +42 -0
  10. package/dist/esm/components/StorageBrowser/fileItems/fileItemsReducer.mjs +33 -0
  11. package/dist/esm/components/StorageBrowser/fileItems/utils.mjs +55 -0
  12. package/dist/esm/components/StorageBrowser/views/LocationActionView/CopyView/CopyViewProvider.mjs +3 -2
  13. package/dist/esm/components/StorageBrowser/views/LocationActionView/CreateFolderView/CreateFolderViewProvider.mjs +0 -1
  14. package/dist/esm/components/StorageBrowser/views/LocationActionView/DeleteView/DeleteViewProvider.mjs +4 -3
  15. package/dist/esm/components/StorageBrowser/views/LocationActionView/UploadView/useUploadView.mjs +13 -34
  16. package/dist/esm/components/StorageBrowser/views/LocationDetailView/LocationDetailViewProvider.mjs +0 -1
  17. package/dist/esm/components/StorageBrowser/views/LocationDetailView/useLocationDetailView.mjs +3 -3
  18. package/dist/esm/components/StorageBrowser/views/context/actionViews.mjs +1 -1
  19. package/dist/esm/components/StorageBrowser/views/context/primaryViews.mjs +1 -1
  20. package/dist/esm/components/StorageBrowser/views/utils/tableResolvers/constants.mjs +9 -1
  21. package/dist/esm/components/StorageBrowser/views/utils/tableResolvers/copyResolvers.mjs +4 -42
  22. package/dist/esm/components/StorageBrowser/views/utils/tableResolvers/deleteResolvers.mjs +4 -42
  23. package/dist/esm/components/StorageBrowser/views/utils/tableResolvers/utils.mjs +45 -5
  24. package/dist/esm/version.mjs +1 -1
  25. package/dist/index.js +1 -1
  26. package/dist/types/components/StorageBrowser/actions/index.d.ts +1 -1
  27. package/dist/types/components/StorageBrowser/createStorageBrowser/createProvider.d.ts +1 -1
  28. package/dist/types/components/StorageBrowser/createStorageBrowser/types.d.ts +21 -3
  29. package/dist/types/components/StorageBrowser/displayText/types.d.ts +1 -1
  30. package/dist/types/components/StorageBrowser/fileItems/constants.d.ts +4 -0
  31. package/dist/types/components/StorageBrowser/fileItems/context.d.ts +6 -0
  32. package/dist/types/components/StorageBrowser/fileItems/fileItemsReducer.d.ts +6 -0
  33. package/dist/types/components/StorageBrowser/fileItems/index.d.ts +3 -0
  34. package/dist/types/components/StorageBrowser/fileItems/types.d.ts +44 -0
  35. package/dist/types/components/StorageBrowser/fileItems/utils.d.ts +5 -0
  36. package/dist/types/components/StorageBrowser/validators/index.d.ts +1 -2
  37. package/dist/types/components/StorageBrowser/views/LocationActionView/UploadView/types.d.ts +1 -1
  38. package/dist/types/components/StorageBrowser/views/utils/index.d.ts +1 -1
  39. package/dist/types/components/StorageBrowser/views/utils/tableResolvers/__testUtils__/tasks.d.ts +6 -11
  40. package/dist/types/components/StorageBrowser/views/utils/tableResolvers/constants.d.ts +1 -0
  41. package/dist/types/components/StorageBrowser/views/utils/tableResolvers/copyResolvers.d.ts +2 -3
  42. package/dist/types/components/StorageBrowser/views/utils/tableResolvers/deleteResolvers.d.ts +2 -3
  43. package/dist/types/components/StorageBrowser/views/utils/tableResolvers/index.d.ts +3 -2
  44. package/dist/types/components/StorageBrowser/views/utils/tableResolvers/types.d.ts +10 -10
  45. package/dist/types/components/StorageBrowser/views/utils/tableResolvers/utils.d.ts +15 -7
  46. package/dist/types/version.d.ts +1 -1
  47. package/package.json +1 -1
  48. package/dist/esm/components/StorageBrowser/files/context.mjs +0 -31
  49. package/dist/esm/components/StorageBrowser/files/utils.mjs +0 -52
  50. package/dist/esm/components/StorageBrowser/validators/isFileTooBig.mjs +0 -4
  51. package/dist/types/components/StorageBrowser/files/context.d.ts +0 -6
  52. package/dist/types/components/StorageBrowser/files/index.d.ts +0 -2
  53. package/dist/types/components/StorageBrowser/files/types.d.ts +0 -28
  54. package/dist/types/components/StorageBrowser/files/utils.d.ts +0 -7
  55. package/dist/types/components/StorageBrowser/validators/isFileTooBig.d.ts +0 -2
package/dist/browser.js CHANGED
@@ -4,7 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var internals = require('@aws-amplify/storage/internals');
6
6
  require('@aws-amplify/ui');
7
- var createStorageBrowser = require('./createStorageBrowser-B75dAYRb.js');
7
+ var createStorageBrowser = require('./createStorageBrowser-CVfazB4S.js');
8
8
  require('aws-amplify/storage');
9
9
  require('react');
10
10
  require('@aws-amplify/ui-react');
@@ -32,7 +32,7 @@ function _interopNamespace(e) {
32
32
 
33
33
  var React__namespace = /*#__PURE__*/_interopNamespace(React);
34
34
 
35
- const VERSION = '3.10.3';
35
+ const VERSION = '3.11.0';
36
36
 
37
37
  const toAccessGrantPermission = (permission) => {
38
38
  let result = '';
@@ -541,9 +541,6 @@ function assertRegisterAuthListener(value) {
541
541
  }
542
542
  }
543
543
 
544
- const UPLOAD_FILE_SIZE_LIMIT = 160 * 1000 * 1000 * 1000;
545
- const isFileTooBig = (file) => file.size > UPLOAD_FILE_SIZE_LIMIT;
546
-
547
544
  const defaultValue$7 = {
548
545
  actionConfigs: undefined,
549
546
  };
@@ -1664,7 +1661,7 @@ function CredentialsProvider({ children, ...props }) {
1664
1661
  return (React__namespace["default"].createElement(CredentialsContext.Provider, { value: value }, children));
1665
1662
  }
1666
1663
 
1667
- const DEFAULT_STATE$1 = {
1664
+ const DEFAULT_STATE$2 = {
1668
1665
  actionType: undefined,
1669
1666
  location: { current: undefined, path: '', key: '' },
1670
1667
  };
@@ -1683,7 +1680,7 @@ function storeReducer(state, action) {
1683
1680
  case 'RESET_LOCATION': {
1684
1681
  if (state.location.current === undefined)
1685
1682
  return state;
1686
- return { ...state, location: DEFAULT_STATE$1.location };
1683
+ return { ...state, location: DEFAULT_STATE$2.location };
1687
1684
  }
1688
1685
  case 'CHANGE_ACTION_TYPE': {
1689
1686
  const { actionType } = action;
@@ -1695,7 +1692,7 @@ function storeReducer(state, action) {
1695
1692
  case 'RESET_ACTION_TYPE': {
1696
1693
  if (state.actionType === undefined)
1697
1694
  return state;
1698
- return { ...state, actionType: DEFAULT_STATE$1.actionType };
1695
+ return { ...state, actionType: DEFAULT_STATE$2.actionType };
1699
1696
  }
1700
1697
  }
1701
1698
  }
@@ -1711,10 +1708,10 @@ function getLocationData(location) {
1711
1708
  }
1712
1709
  function getState(value) {
1713
1710
  if (value === undefined || value === null)
1714
- return DEFAULT_STATE$1;
1711
+ return DEFAULT_STATE$2;
1715
1712
  const current = getLocationData(value.location);
1716
1713
  if (!current)
1717
- return DEFAULT_STATE$1;
1714
+ return DEFAULT_STATE$2;
1718
1715
  const actionType = value?.actionType;
1719
1716
  const path = value?.location?.path ?? '';
1720
1717
  const key = `${current.prefix}${path}`;
@@ -1816,7 +1813,7 @@ function useStoreReducer(props) {
1816
1813
  });
1817
1814
  }
1818
1815
 
1819
- const DEFAULT_VALUE = [DEFAULT_STATE$1, ui.noop];
1816
+ const DEFAULT_VALUE = [DEFAULT_STATE$2, ui.noop];
1820
1817
  const { StoreContext, useStore } = uiReactCore.createContextUtilities({
1821
1818
  contextName: 'Store',
1822
1819
  defaultValue: DEFAULT_VALUE,
@@ -3035,13 +3032,12 @@ const DEFAULT_UPLOAD_VIEW_DISPLAY_TEXT = {
3035
3032
  if (!data?.invalidFiles) {
3036
3033
  return undefined;
3037
3034
  }
3038
- const tooBigFileNames = data.invalidFiles
3039
- .filter(({ file }) => isFileTooBig(file))
3035
+ const invalidFileNames = data.invalidFiles
3040
3036
  .map(({ file }) => file.name)
3041
3037
  .join(', ');
3042
- if (tooBigFileNames) {
3038
+ if (invalidFileNames) {
3043
3039
  return {
3044
- content: `Files larger than 160GB cannot be added to the upload queue: ${tooBigFileNames}`,
3040
+ content: `Files larger than 160GB cannot be added to the upload queue: ${invalidFileNames}`,
3045
3041
  type: 'warning',
3046
3042
  };
3047
3043
  }
@@ -3132,19 +3128,33 @@ const STATUS_ICONS = {
3132
3128
  CANCELED: 'action-canceled',
3133
3129
  QUEUED: 'action-queued',
3134
3130
  };
3131
+ const FILE_DATA_ITEM_TABLE_KEYS = [
3132
+ 'name',
3133
+ 'folder',
3134
+ 'type',
3135
+ 'size',
3136
+ 'status',
3137
+ 'cancel',
3138
+ ];
3135
3139
 
3136
3140
  const getFileType = (value, fallback = '') => value.lastIndexOf('.') !== -1
3137
3141
  ? value.slice(value.lastIndexOf('.') + 1)
3138
3142
  : fallback;
3139
3143
  const getCellName = (value) =>
3140
3144
  // `value.split` always returns an array with at least one entry
3141
- // ensruing `.pop()` will always return a string
3145
+ // ensuring `.pop()` will always return a string
3142
3146
  value.split('/').pop();
3143
3147
  const getUploadCellFolder = ({ data: { file: { webkitRelativePath }, }, }, fallback = '-') => webkitRelativePath
3144
3148
  ? webkitRelativePath.slice(0, webkitRelativePath.lastIndexOf('/') + 1)
3145
3149
  : fallback;
3146
- const getCopyCellFolder = ({ data: { fileKey, sourceKey }, }) => sourceKey.slice(0, -fileKey.length);
3147
- const getDeleteCellFolder = ({ data: { fileKey, key }, }) => key.slice(0, -fileKey.length);
3150
+ const isCopyActionTask = (task) => 'sourceKey' in task.data;
3151
+ const getFileDataCellFolder = (task) => {
3152
+ const targetKey = isCopyActionTask(task)
3153
+ ? task.data.sourceKey
3154
+ : task.data.key;
3155
+ const { fileKey } = task.data;
3156
+ return targetKey.slice(0, -fileKey.length);
3157
+ };
3148
3158
  const getUploadCellProgress = ({ progress, status, }) => {
3149
3159
  // prefer `progress` if available, 1 if status is complete, default 0
3150
3160
  const value = progress ?? (status === 'COMPLETE' ? 1 : 0);
@@ -3152,7 +3162,7 @@ const getUploadCellProgress = ({ progress, status, }) => {
3152
3162
  return { displayValue, value };
3153
3163
  };
3154
3164
  const getFileSize = (value, fallback = '-') => (!value ? fallback : ui.humanFileSize(value, true));
3155
- const getCopyOrDeleteCancelCellContent = (data) => {
3165
+ const getFileDataCancelCellContent = (data) => {
3156
3166
  const { item, props } = data;
3157
3167
  const { cancel, status } = item;
3158
3168
  const { isProcessing, onTaskRemove } = props;
@@ -3178,42 +3188,42 @@ const getCopyOrDeleteCancelCellContent = (data) => {
3178
3188
  };
3179
3189
  return { ariaLabel, isDisabled, onClick, icon: 'cancel' };
3180
3190
  };
3181
-
3182
- const COPY_TABLE_KEYS = [
3183
- 'name',
3184
- 'folder',
3185
- 'type',
3186
- 'size',
3187
- 'status',
3188
- 'cancel',
3189
- ];
3190
- const getCopyCellKey = ({ key, item, }) => `${key}-${item.data.id}`;
3191
- const name$2 = (data) => {
3192
- const key = getCopyCellKey(data);
3191
+ /**
3192
+ * Generates a unique key for a table cell based on the key and item id
3193
+ */
3194
+ const getFileDataCellKey = ({ key, item, }) => `${key}-${item.data.id}`;
3195
+ const name$1 = (data) => {
3196
+ const key = getFileDataCellKey(data);
3193
3197
  const { item } = data;
3194
3198
  const text = item.data.fileKey;
3195
3199
  const icon = STATUS_ICONS[item.status];
3196
3200
  return { key, type: 'text', content: { icon, text } };
3197
3201
  };
3198
- const folder$2 = (data) => {
3199
- const key = getCopyCellKey(data);
3200
- const text = getCopyCellFolder(data.item);
3202
+ const folder$1 = (data) => {
3203
+ const key = getFileDataCellKey(data);
3204
+ const text = getFileDataCellFolder(data.item);
3201
3205
  return { key, type: 'text', content: { text } };
3202
3206
  };
3203
- const type$2 = (data) => {
3204
- const key = getCopyCellKey(data);
3207
+ const type$1 = (data) => {
3208
+ const key = getFileDataCellKey(data);
3205
3209
  const { fileKey } = data.item.data;
3206
3210
  const text = getFileType(fileKey);
3207
3211
  return { key, type: 'text', content: { text } };
3208
3212
  };
3209
- const size$2 = (data) => {
3210
- const key = getCopyCellKey(data);
3213
+ const size$1 = (data) => {
3214
+ const key = getFileDataCellKey(data);
3211
3215
  const { size: value } = data.item.data;
3212
3216
  const displayValue = getFileSize(value);
3213
3217
  return { key, type: 'number', content: { value, displayValue } };
3214
3218
  };
3219
+ const cancel$1 = (data) => {
3220
+ const key = getFileDataCellKey(data);
3221
+ const content = getFileDataCancelCellContent(data);
3222
+ return { key, type: 'button', content };
3223
+ };
3224
+
3215
3225
  const status$2 = (data) => {
3216
- const key = getCopyCellKey(data);
3226
+ const key = getFileDataCellKey(data);
3217
3227
  const { item: { status }, props: { displayText }, } = data;
3218
3228
  const statusLabelKey = STATUS_LABELS[status];
3219
3229
  const text = isCopyViewDisplayTextKey(statusLabelKey)
@@ -3221,18 +3231,13 @@ const status$2 = (data) => {
3221
3231
  : '';
3222
3232
  return { key, type: 'text', content: { text } };
3223
3233
  };
3224
- const cancel$2 = (data) => {
3225
- const key = getCopyCellKey(data);
3226
- const content = getCopyOrDeleteCancelCellContent(data);
3227
- return { key, type: 'button', content };
3228
- };
3229
3234
  const COPY_CELL_RESOLVERS = {
3230
- name: name$2,
3231
- folder: folder$2,
3232
- type: type$2,
3233
- size: size$2,
3235
+ name: name$1,
3236
+ folder: folder$1,
3237
+ type: type$1,
3238
+ size: size$1,
3234
3239
  status: status$2,
3235
- cancel: cancel$2,
3240
+ cancel: cancel$1,
3236
3241
  /**
3237
3242
  * @deprecated
3238
3243
  *
@@ -3264,25 +3269,25 @@ const UPLOAD_TABLE_KEYS = [
3264
3269
  'cancel',
3265
3270
  ];
3266
3271
  const getUploadCellKey = ({ key, item, }) => `${key}-${item.data.id}`;
3267
- const name$1 = (data) => {
3272
+ const name = (data) => {
3268
3273
  const key = getUploadCellKey(data);
3269
3274
  const { item } = data;
3270
3275
  const icon = STATUS_ICONS[item.status];
3271
3276
  const text = getCellName(item.data.key);
3272
3277
  return { key, type: 'text', content: { icon, text } };
3273
3278
  };
3274
- const folder$1 = (data) => {
3279
+ const folder = (data) => {
3275
3280
  const key = getUploadCellKey(data);
3276
3281
  const text = getUploadCellFolder(data.item);
3277
3282
  return { key, type: 'text', content: { text } };
3278
3283
  };
3279
- const type$1 = (data) => {
3284
+ const type = (data) => {
3280
3285
  const key = getUploadCellKey(data);
3281
3286
  const { item } = data;
3282
3287
  const text = getFileType(getCellName(item.data.key));
3283
3288
  return { key, type: 'text', content: { text } };
3284
3289
  };
3285
- const size$1 = (data) => {
3290
+ const size = (data) => {
3286
3291
  const key = getUploadCellKey(data);
3287
3292
  const { size: value } = data.item.data.file;
3288
3293
  const displayValue = getFileSize(value);
@@ -3299,7 +3304,7 @@ const progress = (data) => {
3299
3304
  const content = getUploadCellProgress(data.item);
3300
3305
  return { key, type: 'number', content };
3301
3306
  };
3302
- const cancel$1 = (data) => {
3307
+ const cancel = (data) => {
3303
3308
  const key = getUploadCellKey(data);
3304
3309
  const { item, props } = data;
3305
3310
  const { cancel, data: taskData, status, progress } = item;
@@ -3341,13 +3346,13 @@ const cancel$1 = (data) => {
3341
3346
  return { key, type: 'button', content };
3342
3347
  };
3343
3348
  const UPLOAD_CELL_RESOLVERS = {
3344
- cancel: cancel$1,
3345
- folder: folder$1,
3346
- name: name$1,
3349
+ cancel,
3350
+ folder,
3351
+ name,
3347
3352
  progress,
3348
- size: size$1,
3353
+ size,
3349
3354
  status: status$1,
3350
- type: type$1,
3355
+ type,
3351
3356
  };
3352
3357
  const UPLOAD_TABLE_RESOLVERS = {
3353
3358
  getCell: (data) => UPLOAD_CELL_RESOLVERS[data.key](data),
@@ -3361,41 +3366,8 @@ const UPLOAD_TABLE_RESOLVERS = {
3361
3366
  getRowKey: ({ item }) => item.data.id,
3362
3367
  };
3363
3368
 
3364
- const DELETE_TABLE_KEYS = [
3365
- 'name',
3366
- 'folder',
3367
- 'type',
3368
- 'size',
3369
- 'status',
3370
- 'cancel',
3371
- ];
3372
- const getDeleteCellKey = ({ key, item, }) => `${key}-${item.data.id}`;
3373
- const name = (data) => {
3374
- const key = getDeleteCellKey(data);
3375
- const { item } = data;
3376
- const text = item.data.fileKey;
3377
- const icon = STATUS_ICONS[item.status];
3378
- return { key, type: 'text', content: { icon, text } };
3379
- };
3380
- const folder = (data) => {
3381
- const key = getDeleteCellKey(data);
3382
- const text = getDeleteCellFolder(data.item);
3383
- return { key, type: 'text', content: { text } };
3384
- };
3385
- const type = (data) => {
3386
- const key = getDeleteCellKey(data);
3387
- const { fileKey } = data.item.data;
3388
- const text = getFileType(fileKey);
3389
- return { key, type: 'text', content: { text } };
3390
- };
3391
- const size = (data) => {
3392
- const key = getDeleteCellKey(data);
3393
- const { size: value } = data.item.data;
3394
- const displayValue = getFileSize(value);
3395
- return { key, type: 'number', content: { value, displayValue } };
3396
- };
3397
3369
  const status = (data) => {
3398
- const key = getDeleteCellKey(data);
3370
+ const key = getFileDataCellKey(data);
3399
3371
  const { item: { status }, props: { displayText }, } = data;
3400
3372
  const statusLabelKey = STATUS_LABELS[status];
3401
3373
  const text = isDeleteViewDisplayTextKey(statusLabelKey)
@@ -3403,18 +3375,13 @@ const status = (data) => {
3403
3375
  : '';
3404
3376
  return { key, type: 'text', content: { text } };
3405
3377
  };
3406
- const cancel = (data) => {
3407
- const key = getDeleteCellKey(data);
3408
- const content = getCopyOrDeleteCancelCellContent(data);
3409
- return { key, type: 'button', content };
3410
- };
3411
3378
  const DELETE_CELL_RESOLVERS = {
3412
- name,
3413
- folder,
3414
- type,
3415
- size,
3379
+ name: name$1,
3380
+ folder: folder$1,
3381
+ type: type$1,
3382
+ size: size$1,
3416
3383
  status,
3417
- cancel,
3384
+ cancel: cancel$1,
3418
3385
  /**
3419
3386
  * @deprecated
3420
3387
  *
@@ -3489,14 +3456,43 @@ function UploadViewProvider({ children, ...props }) {
3489
3456
  }, onDropFiles: onDropFiles, onToggleOverwrite: onToggleOverwrite }, children));
3490
3457
  }
3491
3458
 
3459
+ const DEFAULT_STATE$1 = {
3460
+ validItems: undefined,
3461
+ invalidItems: undefined,
3462
+ };
3463
+ const DEFAULT_RESOLVED_FILES = {
3464
+ validFiles: undefined,
3465
+ invalidFiles: undefined,
3466
+ };
3467
+ const UPLOAD_FILE_SIZE_LIMIT = 160 * 1000 * 1000 * 1000;
3468
+
3492
3469
  const compareFileItems = (prev, next) => prev.key.localeCompare(next.key);
3493
- const resolveFiles = (prevItems, files) => {
3470
+ const constructFiles = (files, file) => ui.isUndefined(files) ? [file] : files.concat(file);
3471
+ const defaultValidateFile = (file) => file.size <= UPLOAD_FILE_SIZE_LIMIT;
3472
+ const resolveFiles = (files, validateFile) => {
3473
+ if (!files?.length)
3474
+ return DEFAULT_RESOLVED_FILES;
3475
+ if (!validateFile)
3476
+ return { validFiles: files, invalidFiles: undefined };
3477
+ return files.reduce((acc, file) => {
3478
+ if (validateFile(file)) {
3479
+ acc.validFiles = constructFiles(acc.validFiles, file);
3480
+ }
3481
+ else {
3482
+ acc.invalidFiles = constructFiles(acc.invalidFiles, file);
3483
+ }
3484
+ return acc;
3485
+ },
3486
+ // create new copy of default to be modified
3487
+ { ...DEFAULT_RESOLVED_FILES });
3488
+ };
3489
+ const processFileItems = (prevItems, files) => {
3494
3490
  if (!files?.length)
3495
3491
  return prevItems;
3496
3492
  // construct `nextItems` and filter out existing `file` entries
3497
3493
  const nextItems = files.reduce((items, file) => {
3498
3494
  const { name, webkitRelativePath } = file;
3499
- return prevItems.some(({ file: existing }) => existing.name === name &&
3495
+ return prevItems?.some(({ file: existing }) => existing.name === name &&
3500
3496
  existing.webkitRelativePath === webkitRelativePath)
3501
3497
  ? items
3502
3498
  : items.concat({
@@ -3507,27 +3503,10 @@ const resolveFiles = (prevItems, files) => {
3507
3503
  }, []);
3508
3504
  if (!nextItems.length)
3509
3505
  return prevItems;
3510
- if (!prevItems.length) {
3506
+ if (!prevItems?.length) {
3511
3507
  return nextItems.sort(compareFileItems);
3512
3508
  }
3513
- return prevItems.concat(nextItems).sort(compareFileItems);
3514
- };
3515
- const filesReducer = (prevItems, input) => {
3516
- switch (input.type) {
3517
- case 'ADD_FILE_ITEMS': {
3518
- return resolveFiles(prevItems, input.files);
3519
- }
3520
- case 'REMOVE_FILE_ITEM': {
3521
- const filteredItems = prevItems.filter(({ id }) => id !== input.id);
3522
- return filteredItems.length === prevItems.length
3523
- ? prevItems
3524
- : filteredItems;
3525
- }
3526
- case 'RESET_FILE_ITEMS': {
3527
- return [];
3528
- }
3529
- // TODO: clear message
3530
- }
3509
+ return prevItems?.concat(nextItems).sort(compareFileItems);
3531
3510
  };
3532
3511
  const parseFileSelectParams = (value) => {
3533
3512
  if (ui.isUndefined(value))
@@ -3538,26 +3517,64 @@ const parseFileSelectParams = (value) => {
3538
3517
  return [selectType, !rest?.length ? undefined : { accept: rest.join() }];
3539
3518
  };
3540
3519
 
3541
- const defaultValue$4 = [undefined, ui.noop];
3542
- const { FilesContext, useFiles } = uiReactCore.createContextUtilities({
3543
- contextName: 'Files',
3520
+ const fileItemsReducer = (state, action) => {
3521
+ switch (action.type) {
3522
+ case 'ADD_FILE_ITEMS': {
3523
+ if (!action.validFiles?.length && !action.invalidFiles?.length) {
3524
+ return state;
3525
+ }
3526
+ const validItems = processFileItems(state.validItems, action.validFiles);
3527
+ // `invalidItems` should only track invalid items from latest action taken
3528
+ const invalidItems = processFileItems(undefined, action.invalidFiles);
3529
+ return { validItems, invalidItems };
3530
+ }
3531
+ case 'REMOVE_FILE_ITEM': {
3532
+ const { validItems: prevItems } = state;
3533
+ if (!prevItems?.length)
3534
+ return state;
3535
+ const nextItems = prevItems.filter(({ id }) => id !== action.id);
3536
+ if (nextItems.length === prevItems.length)
3537
+ return state;
3538
+ // `validItems` is strictly undefined if it has 0 file items
3539
+ // otherwise, `validItems` is guaranteed to have at least 1+ file items
3540
+ const validItems = nextItems.length ? nextItems : undefined;
3541
+ return { ...state, validItems };
3542
+ }
3543
+ case 'RESET_FILE_ITEMS': {
3544
+ return DEFAULT_STATE$1;
3545
+ }
3546
+ }
3547
+ };
3548
+
3549
+ const defaultValue$4 = [DEFAULT_STATE$1, ui.noop];
3550
+ const { FileItemsContext, useFileItems } = uiReactCore.createContextUtilities({
3551
+ contextName: 'FileItems',
3544
3552
  defaultValue: defaultValue$4,
3545
3553
  });
3546
- function FilesProvider({ children, }) {
3547
- const [items, dispatch] = React__namespace["default"].useReducer(filesReducer, []);
3554
+ function FileItemsProvider({ children, validateFile, }) {
3555
+ const [state, dispatch] = React__namespace["default"].useReducer(fileItemsReducer, DEFAULT_STATE$1);
3548
3556
  const [fileInput, handleFileSelect] = internal.useFileSelect((nextFiles) => {
3549
- dispatch({ type: 'ADD_FILE_ITEMS', files: nextFiles });
3557
+ dispatch({
3558
+ type: 'ADD_FILE_ITEMS',
3559
+ ...resolveFiles(nextFiles, validateFile),
3560
+ });
3550
3561
  });
3551
3562
  const handleFilesAction = React__namespace["default"].useCallback((action) => {
3552
3563
  if (action.type === 'SELECT_FILES') {
3553
3564
  handleFileSelect(...parseFileSelectParams(action.selectionType));
3554
3565
  }
3566
+ else if (action.type === 'ADD_FILES') {
3567
+ dispatch({
3568
+ type: 'ADD_FILE_ITEMS',
3569
+ ...resolveFiles(action.files, validateFile),
3570
+ });
3571
+ }
3555
3572
  else {
3556
3573
  dispatch(action);
3557
3574
  }
3558
- }, [handleFileSelect]);
3559
- const value = React__namespace["default"].useMemo(() => [items, handleFilesAction], [items, handleFilesAction]);
3560
- return (React__namespace["default"].createElement(FilesContext.Provider, { value: value },
3575
+ }, [handleFileSelect, validateFile]);
3576
+ const value = React__namespace["default"].useMemo(() => [state, handleFilesAction], [state, handleFilesAction]);
3577
+ return (React__namespace["default"].createElement(FileItemsContext.Provider, { value: value },
3561
3578
  fileInput,
3562
3579
  children));
3563
3580
  }
@@ -3567,44 +3584,24 @@ const DEFAULT_OVERWRITE_ENABLED = false;
3567
3584
  const useUploadView = (options) => {
3568
3585
  const { onExit: _onExit } = options ?? {};
3569
3586
  const [{ location }, storeDispatch] = useStore();
3570
- const [files, filesDispatch] = useFiles();
3587
+ const [{ validItems, invalidItems: invalidFiles }, fileItemsDispatch] = useFileItems();
3571
3588
  const { current } = location;
3572
3589
  const [isOverwritingEnabled, setIsOverwritingEnabled] = React__namespace["default"].useState(DEFAULT_OVERWRITE_ENABLED);
3573
- const filesData = React__namespace["default"].useMemo(() => (files ?? [])?.reduce((curr, item) => {
3574
- if (isFileTooBig(item.file)) {
3575
- curr.invalidFiles = ui.isUndefined(curr.invalidFiles)
3576
- ? [item]
3577
- : curr.invalidFiles.concat(item);
3578
- }
3579
- else {
3580
- curr.validFiles = ui.isUndefined(curr.validFiles)
3581
- ? [item]
3582
- : curr.validFiles.concat(item);
3583
- const parsedFileItem = {
3584
- ...item,
3585
- key: `${location.key}${item.key}`,
3586
- };
3587
- curr.data = curr.data.concat({
3588
- ...parsedFileItem,
3589
- preventOverwrite: !isOverwritingEnabled,
3590
- });
3591
- }
3592
- return curr;
3593
- }, { invalidFiles: undefined, validFiles: undefined, data: [] }), [files, isOverwritingEnabled, location.key]);
3594
- const { data, invalidFiles } = filesData;
3595
- const [{ isProcessing, isProcessingComplete, statusCounts, tasks }, handleUploads,] = useAction('upload', { items: data });
3590
+ const items = React__namespace["default"].useMemo(() => (validItems ?? []).map((item) => ({
3591
+ ...item,
3592
+ key: `${location.key}${item.key}`,
3593
+ preventOverwrite: !isOverwritingEnabled,
3594
+ })), [validItems, isOverwritingEnabled, location.key]);
3595
+ const [{ isProcessing, isProcessingComplete, statusCounts, tasks }, handleUploads,] = useAction('upload', { items });
3596
3596
  const onDropFiles = (files) => {
3597
3597
  if (files) {
3598
- filesDispatch({ type: 'ADD_FILE_ITEMS', files });
3598
+ fileItemsDispatch({ type: 'ADD_FILES', files });
3599
3599
  }
3600
3600
  };
3601
3601
  const onSelectFiles = (type) => {
3602
- filesDispatch({ type: 'SELECT_FILES', selectionType: type });
3602
+ fileItemsDispatch({ type: 'SELECT_FILES', selectionType: type });
3603
3603
  };
3604
3604
  const onActionStart = () => {
3605
- invalidFiles?.forEach((file) => {
3606
- filesDispatch({ type: 'REMOVE_FILE_ITEM', id: file.id });
3607
- });
3608
3605
  handleUploads();
3609
3606
  };
3610
3607
  const onActionCancel = () => {
@@ -3612,7 +3609,7 @@ const useUploadView = (options) => {
3612
3609
  };
3613
3610
  const onActionExit = () => {
3614
3611
  // clear files state
3615
- filesDispatch({ type: 'RESET_FILE_ITEMS' });
3612
+ fileItemsDispatch({ type: 'RESET_FILE_ITEMS' });
3616
3613
  // clear selected action
3617
3614
  storeDispatch({ type: 'RESET_ACTION_TYPE' });
3618
3615
  _onExit?.(current);
@@ -3621,7 +3618,7 @@ const useUploadView = (options) => {
3621
3618
  setIsOverwritingEnabled((prev) => !prev);
3622
3619
  };
3623
3620
  const onTaskRemove = ({ data }) => {
3624
- filesDispatch({ type: 'REMOVE_FILE_ITEM', id: data.id });
3621
+ fileItemsDispatch({ type: 'REMOVE_FILE_ITEM', id: data.id });
3625
3622
  };
3626
3623
  return {
3627
3624
  isProcessing,
@@ -3854,7 +3851,7 @@ function CopyViewProvider({ children, ...props }) {
3854
3851
  const { actionCancelLabel, actionDestinationLabel, actionExitLabel, actionStartLabel, getActionCompleteMessage, overwriteWarningMessage, searchPlaceholder, searchSubmitLabel, searchClearLabel, statusDisplayCanceledLabel, statusDisplayCompletedLabel, statusDisplayFailedLabel, statusDisplayQueuedLabel, title, } = displayText;
3855
3852
  const { destination, folders, isProcessing, isProcessingComplete, statusCounts, tasks: items, onActionCancel, onActionExit, onActionStart, onSelectDestination, onTaskRemove, } = props;
3856
3853
  const { hasNextPage, highestPageVisited, hasError: hasFoldersError, message: foldersErrorMessage, query, hasExhaustedSearch, isLoading, page, pageItems, onPaginate, onQuery, onSearchClear, onSearch, onSelectFolder, } = folders;
3857
- const tableData = useResolveTableData(COPY_TABLE_KEYS, COPY_TABLE_RESOLVERS, {
3854
+ const tableData = useResolveTableData(FILE_DATA_ITEM_TABLE_KEYS, COPY_TABLE_RESOLVERS, {
3858
3855
  items,
3859
3856
  props: { displayText, isProcessing, onTaskRemove },
3860
3857
  });
@@ -4198,7 +4195,7 @@ function DeleteViewProvider({ children, ...props }) {
4198
4195
  const message = isProcessingComplete
4199
4196
  ? getActionCompleteMessage({ counts: statusCounts })
4200
4197
  : undefined;
4201
- const tableData = useResolveTableData(DELETE_TABLE_KEYS, DELETE_TABLE_RESOLVERS, {
4198
+ const tableData = useResolveTableData(FILE_DATA_ITEM_TABLE_KEYS, DELETE_TABLE_RESOLVERS, {
4202
4199
  items,
4203
4200
  props: { displayText, isProcessing, onTaskRemove },
4204
4201
  });
@@ -4637,7 +4634,7 @@ const useLocationDetailView = (options) => {
4637
4634
  const listOptions = listOptionsRef.current;
4638
4635
  const [{ location, actionType }, storeDispatch] = useStore();
4639
4636
  const [locationItems, locationItemsDispatch] = useLocationItems();
4640
- const filesDispatch = useFiles()[1];
4637
+ const fileItemsDispatch = useFileItems()[1];
4641
4638
  const { current, key } = location;
4642
4639
  const { permissions, prefix } = current ?? {};
4643
4640
  const { fileDataItems } = locationItems;
@@ -4753,7 +4750,7 @@ const useLocationDetailView = (options) => {
4753
4750
  locationItemsDispatch({ type: 'RESET_LOCATION_ITEMS' });
4754
4751
  },
4755
4752
  onDropFiles: (files) => {
4756
- filesDispatch({ type: 'ADD_FILE_ITEMS', files });
4753
+ fileItemsDispatch({ type: 'ADD_FILES', files });
4757
4754
  const actionType = 'upload';
4758
4755
  storeDispatch({ type: 'CHANGE_ACTION_TYPE', actionType });
4759
4756
  options?.onActionSelect?.(actionType);
@@ -5157,7 +5154,7 @@ const useView = (type) => {
5157
5154
  return USE_VIEW_HOOKS[type]();
5158
5155
  };
5159
5156
 
5160
- function createProvider({ actions, components, config, }) {
5157
+ function createProvider({ actions, components, config, options, }) {
5161
5158
  const { accountId, customEndpoint, registerAuthListener, getLocationCredentials, region, listLocations, } = config;
5162
5159
  const resolvedActions = {
5163
5160
  default: {
@@ -5186,6 +5183,7 @@ function createProvider({ actions, components, config, }) {
5186
5183
  // override components
5187
5184
  ...components,
5188
5185
  };
5186
+ const { validateFile = defaultValidateFile } = options ?? {};
5189
5187
  /**
5190
5188
  * Provides state, configuration and action values that are shared between
5191
5189
  * the primary View components
@@ -5199,7 +5197,7 @@ function createProvider({ actions, components, config, }) {
5199
5197
  React__namespace["default"].createElement(ViewsProvider, { actions: resolvedActions, views: views },
5200
5198
  React__namespace["default"].createElement(ComponentsProvider, { composables: composables },
5201
5199
  React__namespace["default"].createElement(LocationItemsProvider, null,
5202
- React__namespace["default"].createElement(FilesProvider, null, children))))))))));
5200
+ React__namespace["default"].createElement(FileItemsProvider, { validateFile: validateFile }, children))))))))));
5203
5201
  }
5204
5202
  return Provider;
5205
5203
  }
@@ -1,6 +1,6 @@
1
1
  import { listCallerAccessGrants } from '@aws-amplify/storage/internals';
2
- import '@aws-amplify/ui';
3
2
  import { assertAccountId } from '../../validators/assertAccountId.mjs';
3
+ import '@aws-amplify/ui';
4
4
  import { getFilteredLocations } from './utils.mjs';
5
5
 
6
6
  const DEFAULT_PAGE_SIZE = 1000;
@@ -17,7 +17,7 @@ import '../views/LocationActionView/CreateFolderView/CreateFolderView.mjs';
17
17
  import '../views/LocationActionView/DeleteView/DeleteView.mjs';
18
18
  import '../views/context/actionViews.mjs';
19
19
  import '../views/LocationActionView/UploadView/UploadView.mjs';
20
- import '../files/context.mjs';
20
+ import '../fileItems/context.mjs';
21
21
  import '../views/LocationDetailView/LocationDetailView.mjs';
22
22
  import '../views/LocationsView/LocationsView.mjs';
23
23