@aws-amplify/ui-react-storage 3.12.2 → 3.13.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 (92) hide show
  1. package/dist/browser.js +1 -1
  2. package/dist/{createStorageBrowser-pzJe4BD8.js → createStorageBrowser-BazPNsU_.js} +1884 -1068
  3. package/dist/esm/browser.mjs +6 -2
  4. package/dist/esm/components/StorageBrowser/ErrorBoundary/ErrorBoundary.mjs +9 -0
  5. package/dist/esm/components/StorageBrowser/components/ComponentsProvider.mjs +9 -0
  6. package/dist/esm/components/StorageBrowser/components/base/Table.mjs +1 -1
  7. package/dist/esm/components/StorageBrowser/components/base/preview/DownloadButton.mjs +39 -0
  8. package/dist/esm/components/StorageBrowser/components/base/preview/FileMetadata.mjs +40 -0
  9. package/dist/esm/components/StorageBrowser/components/base/preview/FilePreviewLayout.mjs +19 -0
  10. package/dist/esm/components/StorageBrowser/components/base/preview/ImagePreview.mjs +37 -0
  11. package/dist/esm/components/StorageBrowser/components/base/preview/PreviewFallback.mjs +34 -0
  12. package/dist/esm/components/StorageBrowser/components/base/preview/PreviewPlaceholder.mjs +13 -0
  13. package/dist/esm/components/StorageBrowser/components/base/preview/TextPreview.mjs +64 -0
  14. package/dist/esm/components/StorageBrowser/components/base/preview/VideoPreview.mjs +61 -0
  15. package/dist/esm/components/StorageBrowser/components/composables/DataTable/DataTable.mjs +2 -1
  16. package/dist/esm/components/StorageBrowser/components/composables/FilePreview.mjs +85 -0
  17. package/dist/esm/components/StorageBrowser/components/composables/defaults.mjs +2 -0
  18. package/dist/esm/components/StorageBrowser/components/elements/definitions.mjs +2 -2
  19. package/dist/esm/components/StorageBrowser/controls/DataTableControl.mjs +9 -0
  20. package/dist/esm/components/StorageBrowser/controls/FilePreviewControl.mjs +24 -0
  21. package/dist/esm/components/StorageBrowser/createStorageBrowser/StorageBrowserDefault.mjs +1 -0
  22. package/dist/esm/components/StorageBrowser/createStorageBrowser/createProvider.mjs +4 -2
  23. package/dist/esm/components/StorageBrowser/createStorageBrowser/createStorageBrowser.mjs +1 -0
  24. package/dist/esm/components/StorageBrowser/displayText/context.mjs +4 -0
  25. package/dist/esm/components/StorageBrowser/displayText/libraries/en/locationDetailView.mjs +28 -0
  26. package/dist/esm/components/StorageBrowser/filePreview/context.mjs +12 -0
  27. package/dist/esm/components/StorageBrowser/views/LocationActionView/CopyView/CopyView.mjs +9 -0
  28. package/dist/esm/components/StorageBrowser/views/LocationActionView/CopyView/CopyViewProvider.mjs +8 -0
  29. package/dist/esm/components/StorageBrowser/views/LocationActionView/CopyView/FoldersMessageControl.mjs +8 -0
  30. package/dist/esm/components/StorageBrowser/views/LocationActionView/CreateFolderView/CreateFolderView.mjs +9 -0
  31. package/dist/esm/components/StorageBrowser/views/LocationActionView/DeleteView/DeleteView.mjs +9 -0
  32. package/dist/esm/components/StorageBrowser/views/LocationActionView/DownloadView/DownloadView.mjs +9 -0
  33. package/dist/esm/components/StorageBrowser/views/LocationActionView/UploadView/UploadView.mjs +9 -0
  34. package/dist/esm/components/StorageBrowser/views/LocationDetailView/LocationDetailView.mjs +17 -4
  35. package/dist/esm/components/StorageBrowser/views/LocationDetailView/LocationDetailViewProvider.mjs +9 -2
  36. package/dist/esm/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/constants.mjs +69 -1
  37. package/dist/esm/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/fileIcon.mjs +11 -0
  38. package/dist/esm/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getFileRowContent.mjs +8 -5
  39. package/dist/esm/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getLocationDetailViewTableData.mjs +8 -1
  40. package/dist/esm/components/StorageBrowser/views/LocationDetailView/useLocationDetailView.mjs +76 -3
  41. package/dist/esm/components/StorageBrowser/views/LocationsView/LocationsView.mjs +9 -0
  42. package/dist/esm/components/StorageBrowser/views/LocationsView/LocationsViewProvider.mjs +8 -0
  43. package/dist/esm/components/StorageBrowser/views/context/primaryViews.mjs +1 -0
  44. package/dist/esm/components/StorageBrowser/views/hooks/useFilePreview/useFilePreview.mjs +115 -0
  45. package/dist/esm/components/StorageBrowser/views/utils/files/const.mjs +62 -0
  46. package/dist/esm/components/StorageBrowser/views/utils/files/fileName.mjs +12 -0
  47. package/dist/esm/components/StorageBrowser/views/utils/files/fileSize.mjs +23 -0
  48. package/dist/esm/components/StorageBrowser/views/utils/files/fileType.mjs +87 -0
  49. package/dist/esm/components/StorageBrowser/views/utils/files/safeGetProperties.mjs +12 -0
  50. package/dist/esm/components/StorageBrowser/views/utils/files/url.mjs +16 -0
  51. package/dist/esm/version.mjs +1 -1
  52. package/dist/index.js +1 -1
  53. package/dist/styles.css +250 -0
  54. package/dist/types/components/StorageBrowser/actions/configs/defaults.d.ts +2 -2
  55. package/dist/types/components/StorageBrowser/actions/handlers/types.d.ts +4 -0
  56. package/dist/types/components/StorageBrowser/components/base/Table.d.ts +1 -0
  57. package/dist/types/components/StorageBrowser/components/base/preview/DownloadButton.d.ts +4 -0
  58. package/dist/types/components/StorageBrowser/components/base/preview/FileMetadata.d.ts +7 -0
  59. package/dist/types/components/StorageBrowser/components/base/preview/FilePreviewLayout.d.ts +8 -0
  60. package/dist/types/components/StorageBrowser/components/base/preview/ImagePreview.d.ts +3 -0
  61. package/dist/types/components/StorageBrowser/components/base/preview/PreviewFallback.d.ts +10 -0
  62. package/dist/types/components/StorageBrowser/components/base/preview/PreviewPlaceholder.d.ts +2 -0
  63. package/dist/types/components/StorageBrowser/components/base/preview/TextPreview.d.ts +3 -0
  64. package/dist/types/components/StorageBrowser/components/base/preview/VideoPreview.d.ts +3 -0
  65. package/dist/types/components/StorageBrowser/components/base/preview/type.d.ts +6 -0
  66. package/dist/types/components/StorageBrowser/components/composables/DataTable/DataTable.d.ts +1 -0
  67. package/dist/types/components/StorageBrowser/components/composables/FilePreview.d.ts +12 -0
  68. package/dist/types/components/StorageBrowser/components/composables/types.d.ts +2 -0
  69. package/dist/types/components/StorageBrowser/controls/FilePreviewControl.d.ts +2 -0
  70. package/dist/types/components/StorageBrowser/controls/types.d.ts +11 -2
  71. package/dist/types/components/StorageBrowser/createStorageBrowser/createProvider.d.ts +2 -1
  72. package/dist/types/components/StorageBrowser/createStorageBrowser/createStorageBrowser.d.ts +4 -1
  73. package/dist/types/components/StorageBrowser/createStorageBrowser/types.d.ts +78 -2
  74. package/dist/types/components/StorageBrowser/displayText/types.d.ts +30 -1
  75. package/dist/types/components/StorageBrowser/filePreview/context.d.ts +10 -0
  76. package/dist/types/components/StorageBrowser/filePreview/index.d.ts +1 -0
  77. package/dist/types/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/constants.d.ts +6 -0
  78. package/dist/types/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/fileIcon.d.ts +2 -0
  79. package/dist/types/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getFileRowContent.d.ts +3 -1
  80. package/dist/types/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getLocationDetailViewTableData.d.ts +5 -2
  81. package/dist/types/components/StorageBrowser/views/LocationDetailView/types.d.ts +10 -0
  82. package/dist/types/components/StorageBrowser/views/hooks/useFilePreview/index.d.ts +2 -0
  83. package/dist/types/components/StorageBrowser/views/hooks/useFilePreview/types.d.ts +28 -0
  84. package/dist/types/components/StorageBrowser/views/hooks/useFilePreview/useFilePreview.d.ts +5 -0
  85. package/dist/types/components/StorageBrowser/views/utils/files/const.d.ts +9 -0
  86. package/dist/types/components/StorageBrowser/views/utils/files/fileName.d.ts +6 -0
  87. package/dist/types/components/StorageBrowser/views/utils/files/fileSize.d.ts +2 -0
  88. package/dist/types/components/StorageBrowser/views/utils/files/fileType.d.ts +12 -0
  89. package/dist/types/components/StorageBrowser/views/utils/files/safeGetProperties.d.ts +2 -0
  90. package/dist/types/components/StorageBrowser/views/utils/files/url.d.ts +2 -0
  91. package/dist/types/version.d.ts +1 -1
  92. package/package.json +6 -6
@@ -12,8 +12,12 @@ import './components/StorageBrowser/components/elements/definitions.mjs';
12
12
  import './components/StorageBrowser/components/elements/IconElement.mjs';
13
13
  import './components/StorageBrowser/components/composables/context.mjs';
14
14
  import '@aws-amplify/ui-react-core';
15
+ import './components/StorageBrowser/useAction/context.mjs';
15
16
  import '@aws-amplify/ui-react-core/elements';
16
- export { componentsDefault } from './components/StorageBrowser/components/defaults.mjs';
17
- export { default as createStorageBrowser } from './components/StorageBrowser/createStorageBrowser/createStorageBrowser.mjs';
17
+ import './components/StorageBrowser/credentials/context.mjs';
18
+ import './components/StorageBrowser/configuration/context.mjs';
18
19
  import './components/StorageBrowser/displayText/context.mjs';
19
20
  export { DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT as DefaultStorageBrowserDisplayText } from './components/StorageBrowser/displayText/libraries/en/default.mjs';
21
+ import './components/StorageBrowser/filePreview/context.mjs';
22
+ export { componentsDefault } from './components/StorageBrowser/components/defaults.mjs';
23
+ export { default as createStorageBrowser } from './components/StorageBrowser/createStorageBrowser/createStorageBrowser.mjs';
@@ -6,7 +6,16 @@ import '../components/elements/IconElement.mjs';
6
6
  import { STORAGE_BROWSER_BLOCK_TO_BE_UPDATED } from '../components/base/constants.mjs';
7
7
  import '../components/composables/context.mjs';
8
8
  import '@aws-amplify/ui-react-core';
9
+ import '../useAction/context.mjs';
9
10
  import '@aws-amplify/ui-react-core/elements';
11
+ import '../credentials/context.mjs';
12
+ import '@aws-amplify/storage/internals';
13
+ import '../configuration/context.mjs';
14
+ import 'aws-amplify/storage';
15
+ import '../actions/configs/context.mjs';
16
+ import '../actions/configs/defaults.mjs';
17
+ import '../displayText/context.mjs';
18
+ import '../filePreview/context.mjs';
10
19
 
11
20
  const Fallback = () => (React__default.createElement("div", { className: STORAGE_BROWSER_BLOCK_TO_BE_UPDATED },
12
21
  React__default.createElement("div", { className: `${STORAGE_BROWSER_BLOCK_TO_BE_UPDATED}__error-boundary` }, "Something went wrong.")));
@@ -7,6 +7,15 @@ import './elements/definitions.mjs';
7
7
  import './elements/IconElement.mjs';
8
8
  import '@aws-amplify/ui-react';
9
9
  import '@aws-amplify/ui-react-core';
10
+ import '../useAction/context.mjs';
11
+ import '../credentials/context.mjs';
12
+ import '@aws-amplify/storage/internals';
13
+ import '../configuration/context.mjs';
14
+ import 'aws-amplify/storage';
15
+ import '../actions/configs/context.mjs';
16
+ import '../actions/configs/defaults.mjs';
17
+ import '../displayText/context.mjs';
18
+ import '../filePreview/context.mjs';
10
19
 
11
20
  function ComponentsProvider(props) {
12
21
  const { children, composables } = props;
@@ -7,7 +7,7 @@ import { STORAGE_BROWSER_BLOCK } from './constants.mjs';
7
7
  const Table = ({ headers, rows }) => {
8
8
  return (React__default.createElement(TableElement, { className: `${STORAGE_BROWSER_BLOCK}__table` },
9
9
  React__default.createElement(TableHeadElement, { className: `${STORAGE_BROWSER_BLOCK}__table-head` }, headers.length ? (React__default.createElement(TableRowElement, { className: `${STORAGE_BROWSER_BLOCK}__table-row` }, headers.map(({ key, content }) => (React__default.createElement(TableHeaderElement, { key: key, className: `${STORAGE_BROWSER_BLOCK}__table-header` }, content))))) : null),
10
- React__default.createElement(TableBodyElement, { className: `${STORAGE_BROWSER_BLOCK}__table-body` }, rows?.map(({ key, content }) => (React__default.createElement(TableRowElement, { key: key, className: `${STORAGE_BROWSER_BLOCK}__table-row` }, content.map(({ key, content, type }) => {
10
+ React__default.createElement(TableBodyElement, { className: `${STORAGE_BROWSER_BLOCK}__table-body` }, rows?.map(({ key, content, active }) => (React__default.createElement(TableRowElement, { key: key, className: `${STORAGE_BROWSER_BLOCK}__table-row${active ? ` ${STORAGE_BROWSER_BLOCK}__table-row_active` : ''}` }, content.map(({ key, content, type }) => {
11
11
  return type === 'header' ? (React__default.createElement(TableHeaderElement, { key: key, className: `${STORAGE_BROWSER_BLOCK}__table-header`, role: "rowheader" }, content)) : (React__default.createElement(TableDataCellElement, { key: key, className: `${STORAGE_BROWSER_BLOCK}__table-data-cell` }, content));
12
12
  })))))));
13
13
  };
@@ -0,0 +1,39 @@
1
+ import { STORAGE_BROWSER_BLOCK } from '../constants.mjs';
2
+ import React__default, { useMemo, useCallback } from 'react';
3
+ import '@aws-amplify/ui-react';
4
+ import { ButtonElement } from '../../elements/definitions.mjs';
5
+ import { IconElement } from '../../elements/IconElement.mjs';
6
+ import { getFileName } from '../../../views/utils/files/fileName.mjs';
7
+ import '../../../useAction/context.mjs';
8
+ import { useAction } from '../../../useAction/useAction.mjs';
9
+ import '@aws-amplify/ui-react-core';
10
+ import '@aws-amplify/ui-react-core/elements';
11
+ import '../../../credentials/context.mjs';
12
+ import '@aws-amplify/storage/internals';
13
+ import '../../../configuration/context.mjs';
14
+ import '@aws-amplify/ui';
15
+ import 'aws-amplify/storage';
16
+ import '../../../actions/configs/context.mjs';
17
+ import '../../../actions/configs/defaults.mjs';
18
+ import { useDisplayText } from '../../../displayText/context.mjs';
19
+
20
+ const DownloadButton = ({ fileKey }) => {
21
+ const [{ isProcessing: downloadPending }, handleDownload] = useAction('download');
22
+ const fileName = useMemo(() => getFileName(fileKey), [fileKey]);
23
+ const { LocationDetailView: displayText } = useDisplayText();
24
+ const { filePreview: { downloadButtonLabel }, } = displayText;
25
+ const handleDownloadClick = useCallback(() => {
26
+ handleDownload({
27
+ data: {
28
+ fileKey: fileName,
29
+ key: fileKey,
30
+ id: crypto.randomUUID(),
31
+ },
32
+ });
33
+ }, [fileName, fileKey, handleDownload]);
34
+ return (React__default.createElement(ButtonElement, { ['aria-label']: `Download ${fileName} file`, className: `${STORAGE_BROWSER_BLOCK}__download-button`, onClick: handleDownloadClick, disabled: downloadPending, variant: "primary" },
35
+ downloadPending ? (React__default.createElement(IconElement, { className: `${STORAGE_BROWSER_BLOCK}__download-button_icon`, variant: "action-progress" })) : null,
36
+ downloadButtonLabel));
37
+ };
38
+
39
+ export { DownloadButton };
@@ -0,0 +1,40 @@
1
+ import React__default from 'react';
2
+ import '@aws-amplify/ui-react';
3
+ import { ViewElement, HeadingElement, TextElement } from '../../elements/definitions.mjs';
4
+ import '../../elements/IconElement.mjs';
5
+ import { getFileExtension } from '../../../views/utils/files/fileType.mjs';
6
+ import { STORAGE_BROWSER_BLOCK } from '../constants.mjs';
7
+ import { useDisplayText } from '../../../displayText/context.mjs';
8
+ import { humanFileSize } from '@aws-amplify/ui';
9
+
10
+ const NONE = 'None';
11
+ function FileMetadata({ fileData, }) {
12
+ const { key, lastModified, versionId = NONE, size, eTag } = fileData;
13
+ const { LocationDetailView: displayText } = useDisplayText();
14
+ const { filePreview: { keyLabel, sizeLabel, versionIdLabel, lastModifiedLabel, entityTagLabel, typeLabel, fileInformationTitle, unknownValue, }, } = displayText;
15
+ return (React__default.createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__file-preview-section` },
16
+ React__default.createElement(HeadingElement, { className: `${STORAGE_BROWSER_BLOCK}__file-preview-title` }, fileInformationTitle),
17
+ React__default.createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__file-metadata` }, [
18
+ { label: keyLabel, value: key },
19
+ {
20
+ label: sizeLabel,
21
+ value: humanFileSize(size, true),
22
+ },
23
+ { label: versionIdLabel, value: versionId },
24
+ {
25
+ label: lastModifiedLabel,
26
+ value: lastModified?.toLocaleString() || unknownValue,
27
+ },
28
+ { label: entityTagLabel, value: eTag },
29
+ {
30
+ label: typeLabel,
31
+ value: getFileExtension(key) ?? NONE,
32
+ },
33
+ ].map(({ label, value }) => (React__default.createElement(ViewElement, { key: label, className: `${STORAGE_BROWSER_BLOCK}__file-metadata-item` },
34
+ React__default.createElement(TextElement, { className: `${STORAGE_BROWSER_BLOCK}__file-metadata-label` },
35
+ label,
36
+ ":"),
37
+ React__default.createElement(TextElement, { className: `${STORAGE_BROWSER_BLOCK}__file-metadata-value` }, value)))))));
38
+ }
39
+
40
+ export { FileMetadata };
@@ -0,0 +1,19 @@
1
+ import React__default from 'react';
2
+ import { useDisplayText } from '../../../displayText/context.mjs';
3
+ import { STORAGE_BROWSER_BLOCK } from '../constants.mjs';
4
+ import '@aws-amplify/ui-react';
5
+ import { ViewElement, HeadingElement } from '../../elements/definitions.mjs';
6
+ import '../../elements/IconElement.mjs';
7
+ import { FileMetadata } from './FileMetadata.mjs';
8
+
9
+ function FilePreviewLayout({ fileData, children, }) {
10
+ const { LocationDetailView: displayText } = useDisplayText();
11
+ const { filePreview: { filePreviewTitle }, } = displayText;
12
+ return (React__default.createElement(React__default.Fragment, null,
13
+ React__default.createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__file-preview-section` },
14
+ React__default.createElement(HeadingElement, { className: `${STORAGE_BROWSER_BLOCK}__file-preview-title` }, filePreviewTitle),
15
+ React__default.createElement("div", { className: `${STORAGE_BROWSER_BLOCK}__file-preview-content` }, children)),
16
+ React__default.createElement(FileMetadata, { fileData: fileData })));
17
+ }
18
+
19
+ export { FilePreviewLayout };
@@ -0,0 +1,37 @@
1
+ import React__default, { useState, useCallback } from 'react';
2
+ import { classNames, ComponentClassName } from '@aws-amplify/ui';
3
+ import { STORAGE_BROWSER_BLOCK } from '../constants.mjs';
4
+ import { PreviewPlaceholder } from './PreviewPlaceholder.mjs';
5
+ import { PreviewFallback } from './PreviewFallback.mjs';
6
+ import { getFileName } from '../../../views/utils/files/fileName.mjs';
7
+ import { useDisplayText } from '../../../displayText/context.mjs';
8
+
9
+ function ImagePreview({ url, fileKey, }) {
10
+ const [error, setError] = useState(null);
11
+ const [isLoading, setIsLoading] = useState(true);
12
+ const [imageKey, setImageKey] = useState(0);
13
+ const { LocationDetailView: displayText } = useDisplayText();
14
+ const { filePreview: { imageLoadErrorDescription }, } = displayText;
15
+ const handleError = useCallback(() => {
16
+ setError('Failed to load image');
17
+ setIsLoading(false);
18
+ }, []);
19
+ const handleLoad = useCallback(() => {
20
+ setIsLoading(false);
21
+ setError(null);
22
+ }, []);
23
+ const handleRetry = useCallback(() => {
24
+ setError(null);
25
+ setIsLoading(true);
26
+ setImageKey((prev) => prev + 1);
27
+ }, []);
28
+ if (error) {
29
+ return (React__default.createElement(PreviewFallback, { fileKey: fileKey, message: error, description: imageLoadErrorDescription, isError: true, onRetry: handleRetry, showRetry: true }));
30
+ }
31
+ return (React__default.createElement("div", { className: `${STORAGE_BROWSER_BLOCK}__image-container` },
32
+ isLoading && React__default.createElement(PreviewPlaceholder, null),
33
+ React__default.createElement("div", { className: `${STORAGE_BROWSER_BLOCK}__image-preview`, style: { display: isLoading ? 'none' : 'flex' } },
34
+ React__default.createElement("img", { key: imageKey, className: classNames(ComponentClassName.StorageImage), src: url, alt: `Image preview for ${getFileName(fileKey)}`, onError: handleError, onLoad: handleLoad }))));
35
+ }
36
+
37
+ export { ImagePreview };
@@ -0,0 +1,34 @@
1
+ import React__default from 'react';
2
+ import { DownloadButton } from './DownloadButton.mjs';
3
+ import { classNames } from '@aws-amplify/ui';
4
+ import '@aws-amplify/ui-react';
5
+ import { ViewElement, TextElement, ButtonElement } from '../../elements/definitions.mjs';
6
+ import { IconElement } from '../../elements/IconElement.mjs';
7
+ import { STORAGE_BROWSER_BLOCK } from '../constants.mjs';
8
+ import { useDisplayText } from '../../../displayText/context.mjs';
9
+ import { getFileName } from '../../../views/utils/files/fileName.mjs';
10
+ import { getFileThumbnail } from '../../../views/LocationDetailView/getLocationDetailViewTableData/fileIcon.mjs';
11
+
12
+ function PreviewFallback({ fileKey, message, description, isError = false, onRetry, showRetry = false, }) {
13
+ const { LocationDetailView: displayText } = useDisplayText();
14
+ const { filePreview: { errorDescription, unsupportedFileDescription, filePrefix, retryButtonLabel, }, } = displayText;
15
+ const fileName = getFileName(fileKey);
16
+ const fallbackClass = isError
17
+ ? `${STORAGE_BROWSER_BLOCK}__preview-fallback--error`
18
+ : `${STORAGE_BROWSER_BLOCK}__preview-fallback--default`;
19
+ return (React__default.createElement(ViewElement, { className: classNames(`${STORAGE_BROWSER_BLOCK}__preview-fallback`, fallbackClass) },
20
+ React__default.createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__preview-fallback-icon` },
21
+ React__default.createElement(IconElement, { className: "amplify-icon", variant: isError ? 'error' : getFileThumbnail(fileKey) })),
22
+ React__default.createElement(ViewElement, null,
23
+ React__default.createElement(TextElement, { className: `${STORAGE_BROWSER_BLOCK}__preview-fallback-title` }, message),
24
+ React__default.createElement(TextElement, { className: `${STORAGE_BROWSER_BLOCK}__preview-fallback-description` }, description ??
25
+ (isError ? errorDescription : unsupportedFileDescription)),
26
+ React__default.createElement(TextElement, { className: `${STORAGE_BROWSER_BLOCK}__preview-fallback-filename` },
27
+ filePrefix,
28
+ fileName)),
29
+ React__default.createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__preview-fallback-actions` },
30
+ showRetry && onRetry && (React__default.createElement(ButtonElement, { variant: "primary", onClick: onRetry, ['aria-label']: `Retry loading ${fileName} file` }, retryButtonLabel)),
31
+ React__default.createElement(DownloadButton, { fileKey: fileKey }))));
32
+ }
33
+
34
+ export { PreviewFallback };
@@ -0,0 +1,13 @@
1
+ import React__default from 'react';
2
+ import { Placeholder } from '@aws-amplify/ui-react';
3
+ import { ViewElement } from '../../elements/definitions.mjs';
4
+ import '../../elements/IconElement.mjs';
5
+ import { STORAGE_BROWSER_BLOCK } from '../constants.mjs';
6
+
7
+ function PreviewPlaceholder() {
8
+ return (React__default.createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__preview-placeholder` },
9
+ React__default.createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__preview-placeholder-content` },
10
+ React__default.createElement(Placeholder, { width: "100%", height: "400px" }))));
11
+ }
12
+
13
+ export { PreviewPlaceholder };
@@ -0,0 +1,64 @@
1
+ import React__default, { useState, useCallback, useEffect } from 'react';
2
+ import '@aws-amplify/ui-react';
3
+ import { ViewElement } from '../../elements/definitions.mjs';
4
+ import '../../elements/IconElement.mjs';
5
+ import { STORAGE_BROWSER_BLOCK } from '../constants.mjs';
6
+ import { useDisplayText } from '../../../displayText/context.mjs';
7
+ import { PreviewFallback } from './PreviewFallback.mjs';
8
+ import { PreviewPlaceholder } from './PreviewPlaceholder.mjs';
9
+
10
+ function TextPreview({ url, fileKey, }) {
11
+ const [content, setContent] = useState('');
12
+ const [isLoading, setIsLoading] = useState(true);
13
+ const [error, setError] = useState(null);
14
+ const [retryCount, setRetryCount] = useState(0);
15
+ const { LocationDetailView: displayText } = useDisplayText();
16
+ const { filePreview: { emptyFileMessage, textLoadErrorDescription }, } = displayText;
17
+ const handleRetry = useCallback(() => {
18
+ setRetryCount((prev) => prev + 1);
19
+ }, []);
20
+ useEffect(() => {
21
+ if (!url)
22
+ return;
23
+ const controller = new AbortController();
24
+ async function loadTextFileContent() {
25
+ try {
26
+ setIsLoading(true);
27
+ setError(null);
28
+ const response = await fetch(url, {
29
+ signal: controller.signal,
30
+ });
31
+ if (!response.ok) {
32
+ throw new Error(`Failed to fetch file: ${response.statusText}`);
33
+ }
34
+ const textContent = await response.text();
35
+ setContent(textContent);
36
+ }
37
+ catch (err) {
38
+ if (err instanceof Error && err.name !== 'AbortError') {
39
+ const errorMessage = err.message || 'Failed to load file';
40
+ setError(errorMessage);
41
+ }
42
+ }
43
+ finally {
44
+ if (!controller.signal.aborted) {
45
+ setIsLoading(false);
46
+ }
47
+ }
48
+ }
49
+ loadTextFileContent();
50
+ return () => {
51
+ controller.abort();
52
+ };
53
+ }, [url, fileKey, retryCount]);
54
+ if (isLoading) {
55
+ return React__default.createElement(PreviewPlaceholder, null);
56
+ }
57
+ if (error) {
58
+ return (React__default.createElement(PreviewFallback, { fileKey: fileKey, message: error, description: textLoadErrorDescription, isError: true, onRetry: handleRetry, showRetry: true }));
59
+ }
60
+ return (React__default.createElement("div", { className: `${STORAGE_BROWSER_BLOCK}__text-container` },
61
+ React__default.createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__text-preview` }, content || emptyFileMessage)));
62
+ }
63
+
64
+ export { TextPreview };
@@ -0,0 +1,61 @@
1
+ import React__default, { useState, useCallback } from 'react';
2
+ import { STORAGE_BROWSER_BLOCK } from '../constants.mjs';
3
+ import { PreviewPlaceholder } from './PreviewPlaceholder.mjs';
4
+ import { PreviewFallback } from './PreviewFallback.mjs';
5
+ import { getFileName } from '../../../views/utils/files/fileName.mjs';
6
+ import { useDisplayText } from '../../../displayText/context.mjs';
7
+
8
+ function VideoPreview({ url, fileKey, }) {
9
+ const [error, setError] = useState(null);
10
+ const [isLoading, setIsLoading] = useState(true);
11
+ const [videoKey, setVideoKey] = useState(0);
12
+ const { LocationDetailView: displayText } = useDisplayText();
13
+ const { filePreview: { videoLoadErrorDescription }, } = displayText;
14
+ const handleError = useCallback((event) => {
15
+ const videoElement = event.currentTarget;
16
+ const errorCode = videoElement.error?.code;
17
+ let errorMessage = 'Failed to load video';
18
+ switch (errorCode) {
19
+ case MediaError.MEDIA_ERR_ABORTED:
20
+ errorMessage = 'Video loading was aborted';
21
+ break;
22
+ case MediaError.MEDIA_ERR_NETWORK:
23
+ errorMessage = 'Network error occurred while loading video';
24
+ break;
25
+ case MediaError.MEDIA_ERR_DECODE:
26
+ errorMessage = 'Video format is not supported or corrupted';
27
+ break;
28
+ case MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED:
29
+ errorMessage = 'Video format is not supported';
30
+ break;
31
+ default:
32
+ errorMessage = 'An unknown error occurred while loading video';
33
+ }
34
+ setError(errorMessage);
35
+ setIsLoading(false);
36
+ }, []);
37
+ const handleLoadStart = useCallback(() => {
38
+ setIsLoading(true);
39
+ setError(null);
40
+ }, []);
41
+ const handleLoadedData = useCallback(() => {
42
+ setIsLoading(false);
43
+ setError(null);
44
+ }, []);
45
+ const handleRetry = useCallback(() => {
46
+ setError(null);
47
+ setIsLoading(true);
48
+ setVideoKey((prev) => prev + 1);
49
+ }, []);
50
+ if (error) {
51
+ return (React__default.createElement(PreviewFallback, { fileKey: fileKey, message: error, description: videoLoadErrorDescription, isError: true, onRetry: handleRetry, showRetry: true }));
52
+ }
53
+ return (React__default.createElement("div", { className: `${STORAGE_BROWSER_BLOCK}__video-container` },
54
+ isLoading && React__default.createElement(PreviewPlaceholder, null),
55
+ React__default.createElement("div", { className: `${STORAGE_BROWSER_BLOCK}__video-preview`, style: { display: isLoading ? 'none' : 'flex' } },
56
+ React__default.createElement("video", { key: videoKey, controls: true, preload: "metadata", onError: handleError, onLoadStart: handleLoadStart, onLoadedData: handleLoadedData, "aria-label": `Video preview for ${getFileName(fileKey)}` },
57
+ React__default.createElement("source", { src: url }),
58
+ "Your browser does not support the video tag."))));
59
+ }
60
+
61
+ export { VideoPreview };
@@ -39,8 +39,9 @@ const DataTable = ({ headers, isLoading, rows, }) => {
39
39
  });
40
40
  const mappedRows = isLoading
41
41
  ? []
42
- : rows.map(({ key, content }) => ({
42
+ : rows.map(({ key, content, active }) => ({
43
43
  key,
44
+ active,
44
45
  content: content.map(({ key, content, type }) => {
45
46
  switch (type) {
46
47
  case 'button': {
@@ -0,0 +1,85 @@
1
+ import React__default from 'react';
2
+ import { ImagePreview } from '../base/preview/ImagePreview.mjs';
3
+ import { useFilePreviewContext } from '../../filePreview/context.mjs';
4
+ import { VideoPreview } from '../base/preview/VideoPreview.mjs';
5
+ import { TextPreview } from '../base/preview/TextPreview.mjs';
6
+ import { PreviewFallback } from '../base/preview/PreviewFallback.mjs';
7
+ import '@aws-amplify/ui-react';
8
+ import { ViewElement, ButtonElement } from '../elements/definitions.mjs';
9
+ import { IconElement } from '../elements/IconElement.mjs';
10
+ import { PreviewPlaceholder } from '../base/preview/PreviewPlaceholder.mjs';
11
+ import '@aws-amplify/ui';
12
+ import { STORAGE_BROWSER_BLOCK } from '../base/constants.mjs';
13
+ import { useDisplayText } from '../../displayText/context.mjs';
14
+ import { FilePreviewLayout } from '../base/preview/FilePreviewLayout.mjs';
15
+ import { DownloadButton } from '../base/preview/DownloadButton.mjs';
16
+
17
+ const rendererMap = {
18
+ image: ImagePreview,
19
+ video: VideoPreview,
20
+ text: TextPreview,
21
+ };
22
+ const DefaultRenderer = ({ url, type, fileKey }) => {
23
+ const { LocationDetailView: displayText } = useDisplayText();
24
+ const { filePreview: { unsupportedFileDescription, unsupportedFileMessage }, } = displayText;
25
+ if (type && type in rendererMap) {
26
+ const PreviewComponent = rendererMap[type];
27
+ return React__default.createElement(PreviewComponent, { fileKey: fileKey, url: url });
28
+ }
29
+ return (React__default.createElement(PreviewFallback, { fileKey: fileKey, message: unsupportedFileMessage, description: unsupportedFileDescription }));
30
+ };
31
+ const ResolvedRenderer = ({ fileKey, url, fileData }) => {
32
+ const { rendererResolver } = (useFilePreviewContext() ?? {}) || {};
33
+ if (rendererResolver && fileData.fileType) {
34
+ const CustomRenderer = rendererResolver(fileData.fileType);
35
+ if (CustomRenderer) {
36
+ return React__default.createElement(CustomRenderer, { url: url, fileData: fileData });
37
+ }
38
+ }
39
+ return (React__default.createElement(DefaultRenderer, { fileKey: fileKey, url: url, type: fileData.fileType }));
40
+ };
41
+ const FilePreviewContent = ({ filePreview, activeFile, onRetryFilePreview, onSelectActiveFile, activeFileHasNext, activeFileHasPrev, }) => {
42
+ const { LocationDetailView: displayText } = useDisplayText();
43
+ const { filePreview: { errorMessage, sizeLimitMessage, generalPreviewErrorDescription, fileSizeLimitDescription, }, } = displayText;
44
+ const { key } = activeFile;
45
+ if (filePreview.isLoading) {
46
+ return (React__default.createElement(FilePreviewLayout, { fileData: activeFile },
47
+ React__default.createElement(PreviewPlaceholder, null)));
48
+ }
49
+ if (!filePreview.ok) {
50
+ if (filePreview.error === 'LIMIT_EXCEEDED') {
51
+ return (React__default.createElement(FilePreviewLayout, { fileData: activeFile },
52
+ React__default.createElement(PreviewFallback, { fileKey: key, message: sizeLimitMessage, description: fileSizeLimitDescription })));
53
+ }
54
+ return (React__default.createElement(FilePreviewLayout, { fileData: activeFile },
55
+ React__default.createElement(PreviewFallback, { fileKey: key, message: errorMessage, description: generalPreviewErrorDescription, isError: true, onRetry: onRetryFilePreview, showRetry: true })));
56
+ }
57
+ return (React__default.createElement(FilePreviewLayout, { fileData: filePreview.fileData },
58
+ React__default.createElement(ResolvedRenderer, { fileKey: key, url: filePreview.url, fileData: filePreview.fileData }),
59
+ React__default.createElement("div", { style: { display: 'flex', flexFlow: 'row nowrap' } },
60
+ React__default.createElement(ButtonElement, { disabled: !activeFileHasPrev, onClick: () => onSelectActiveFile('prev'), variant: 'paginate-previous' },
61
+ React__default.createElement(IconElement, { variant: 'paginate-previous' })),
62
+ React__default.createElement(DownloadButton, { fileKey: key }),
63
+ React__default.createElement(ButtonElement, { disabled: !activeFileHasNext, onClick: () => onSelectActiveFile('next'), variant: 'paginate-next' },
64
+ React__default.createElement(IconElement, { variant: 'paginate-next' })))));
65
+ };
66
+ function FilePreview(props) {
67
+ const { filePreview, activeFileHasNext, activeFileHasPrev, onRetryFilePreview = () => undefined, activeFile, onSelectActiveFile = () => undefined, } = props;
68
+ const { LocationDetailView: displayText } = useDisplayText();
69
+ const { filePreview: { closeButtonLabel }, } = displayText;
70
+ if (!activeFile || !filePreview) {
71
+ return null;
72
+ }
73
+ if (!filePreview.enabled) {
74
+ return null;
75
+ }
76
+ return (React__default.createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__file-preview` },
77
+ React__default.createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__file-preview-header` },
78
+ React__default.createElement(ButtonElement, { variant: "exit", onClick: () => onSelectActiveFile(undefined) },
79
+ React__default.createElement(IconElement, { variant: "dismiss" }),
80
+ closeButtonLabel)),
81
+ React__default.createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__file-preview-container` },
82
+ React__default.createElement(FilePreviewContent, { filePreview: filePreview, activeFile: activeFile, activeFileHasNext: activeFileHasNext, activeFileHasPrev: activeFileHasPrev, onRetryFilePreview: onRetryFilePreview, onSelectActiveFile: onSelectActiveFile }))));
83
+ }
84
+
85
+ export { FilePreview };
@@ -12,6 +12,7 @@ import { FolderNameField } from './FolderNameField.mjs';
12
12
  import { LoadingIndicator } from './LoadingIndicator.mjs';
13
13
  import { Message } from './Message.mjs';
14
14
  import { Navigation } from './Navigation.mjs';
15
+ import { FilePreview } from './FilePreview.mjs';
15
16
  import { OverwriteToggle } from './OverwriteToggle.mjs';
16
17
  import { Pagination } from './Pagination.mjs';
17
18
  import { SearchField } from './SearchField.mjs';
@@ -40,6 +41,7 @@ const DEFAULT_COMPOSABLES = {
40
41
  SearchField,
41
42
  StatusDisplay,
42
43
  Title,
44
+ FilePreview,
43
45
  };
44
46
 
45
47
  export { DEFAULT_COMPOSABLES };
@@ -21,7 +21,7 @@ const NavElement = defineBaseElement({
21
21
  type: 'nav',
22
22
  displayName: 'Nav',
23
23
  });
24
- defineBaseElement({
24
+ const TextElement = defineBaseElement({
25
25
  type: 'p',
26
26
  displayName: 'Text',
27
27
  });
@@ -83,4 +83,4 @@ const SpanElement = defineBaseElement({
83
83
  displayName: 'Span',
84
84
  });
85
85
 
86
- export { ButtonElement, DescriptionDetailsElement, DescriptionListElement, DescriptionTermElement, HeadingElement, InputElement, LabelElement, ListItemElement, NavElement, OrderedListElement, SpanElement, TableBodyElement, TableDataCellElement, TableElement, TableHeadElement, TableHeaderElement, TableRowElement, ViewElement };
86
+ export { ButtonElement, DescriptionDetailsElement, DescriptionListElement, DescriptionTermElement, HeadingElement, InputElement, LabelElement, ListItemElement, NavElement, OrderedListElement, SpanElement, TableBodyElement, TableDataCellElement, TableElement, TableHeadElement, TableHeaderElement, TableRowElement, TextElement, ViewElement };
@@ -6,7 +6,16 @@ import '../components/elements/IconElement.mjs';
6
6
  import '../components/composables/context.mjs';
7
7
  import { DataTable } from '../components/composables/DataTable/DataTable.mjs';
8
8
  import '@aws-amplify/ui-react-core';
9
+ import '../useAction/context.mjs';
9
10
  import '@aws-amplify/ui-react-core/elements';
11
+ import '../credentials/context.mjs';
12
+ import '@aws-amplify/storage/internals';
13
+ import '../configuration/context.mjs';
14
+ import 'aws-amplify/storage';
15
+ import '../actions/configs/context.mjs';
16
+ import '../actions/configs/defaults.mjs';
17
+ import '../displayText/context.mjs';
18
+ import '../filePreview/context.mjs';
10
19
  import { useDataTable } from './hooks/useDataTable.mjs';
11
20
  import { useResolvedComposable } from './hooks/useResolvedComposable.mjs';
12
21
 
@@ -0,0 +1,24 @@
1
+ import React__default from 'react';
2
+ import { useResolvedComposable } from './hooks/useResolvedComposable.mjs';
3
+ import { FilePreview } from '../components/composables/FilePreview.mjs';
4
+ import { useControlsContext } from './context.mjs';
5
+
6
+ function FilePreviewControl() {
7
+ const { data, onRetryFilePreview, onSelectActiveFile } = useControlsContext();
8
+ const { filePreviewState, activeFile, activeFileHasNext, activeFileHasPrev } = data;
9
+ const props = {
10
+ filePreview: filePreviewState,
11
+ activeFile,
12
+ activeFileHasNext,
13
+ activeFileHasPrev,
14
+ onRetryFilePreview,
15
+ onSelectActiveFile,
16
+ };
17
+ const Resolved = useResolvedComposable(FilePreview, 'FilePreview');
18
+ if (!activeFile) {
19
+ return null;
20
+ }
21
+ return React__default.createElement(Resolved, { ...props });
22
+ }
23
+
24
+ export { FilePreviewControl };
@@ -20,6 +20,7 @@ import '../views/context/actionViews.mjs';
20
20
  import '../views/LocationActionView/UploadView/UploadView.mjs';
21
21
  import '../fileItems/context.mjs';
22
22
  import '../views/LocationDetailView/LocationDetailView.mjs';
23
+ import '../filePreview/context.mjs';
23
24
  import '../views/LocationsView/LocationsView.mjs';
24
25
 
25
26
  /**
@@ -17,6 +17,7 @@ import '../configuration/context.mjs';
17
17
  import { DisplayTextProvider } from '../displayText/context.mjs';
18
18
  import { FileItemsProvider } from '../fileItems/context.mjs';
19
19
  import { defaultValidateFile } from '../fileItems/utils.mjs';
20
+ import { FilePreviewProvider } from '../filePreview/context.mjs';
20
21
  import { LocationItemsProvider } from '../locationItems/context.mjs';
21
22
  import { StoreProvider } from '../store/context.mjs';
22
23
  import { ActionHandlersProvider } from '../useAction/context.mjs';
@@ -32,7 +33,7 @@ import '../views/LocationActionView/UploadView/UploadView.mjs';
32
33
  import '../views/LocationDetailView/LocationDetailView.mjs';
33
34
  import '../views/LocationsView/LocationsView.mjs';
34
35
 
35
- function createProvider({ actions, components, config, options, }) {
36
+ function createProvider({ actions, components, config, options, filePreview = {}, }) {
36
37
  const { accountId, customEndpoint, registerAuthListener, getLocationCredentials, region, listLocations, } = config;
37
38
  const resolvedActions = {
38
39
  default: {
@@ -75,7 +76,8 @@ function createProvider({ actions, components, config, options, }) {
75
76
  React__default.createElement(ViewsProvider, { actions: resolvedActions, views: views },
76
77
  React__default.createElement(ComponentsProvider, { composables: composables },
77
78
  React__default.createElement(LocationItemsProvider, null,
78
- React__default.createElement(FileItemsProvider, { validateFile: validateFile }, children))))))))));
79
+ React__default.createElement(FileItemsProvider, { validateFile: validateFile },
80
+ React__default.createElement(FilePreviewProvider, { filePreview: filePreview }, children)))))))))));
79
81
  }
80
82
  return Provider;
81
83
  }
@@ -25,6 +25,7 @@ import { LocationActionView } from '../views/LocationActionView/LocationActionVi
25
25
  import { UploadView } from '../views/LocationActionView/UploadView/UploadView.mjs';
26
26
  import '../fileItems/context.mjs';
27
27
  import { LocationDetailView } from '../views/LocationDetailView/LocationDetailView.mjs';
28
+ import '../filePreview/context.mjs';
28
29
  import { LocationsView } from '../views/LocationsView/LocationsView.mjs';
29
30
  import { useView } from '../views/useView.mjs';
30
31
  import createProvider from './createProvider.mjs';
@@ -28,6 +28,10 @@ function resolveDisplayText(displayText) {
28
28
  LocationDetailView: {
29
29
  ...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.LocationDetailView,
30
30
  ...LocationDetailView,
31
+ filePreview: {
32
+ ...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.LocationDetailView.filePreview,
33
+ ...(LocationDetailView?.filePreview ?? {}),
34
+ },
31
35
  },
32
36
  LocationsView: {
33
37
  ...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.LocationsView,