@atlaskit/media-viewer 48.1.7 → 48.2.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 (54) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/cjs/analytics/index.js +2 -3
  3. package/dist/cjs/analytics/ufoExperiences.js +1 -1
  4. package/dist/cjs/components/media-viewer.js +13 -1
  5. package/dist/cjs/errorMessage.js +5 -3
  6. package/dist/cjs/item-viewer.js +5 -4
  7. package/dist/cjs/media-viewer.js +21 -17
  8. package/dist/cjs/navigation.js +5 -4
  9. package/dist/cjs/styleWrappers.js +1 -0
  10. package/dist/cjs/v2/header-v2.js +159 -0
  11. package/dist/cjs/v2/item-viewer-v2.js +322 -0
  12. package/dist/cjs/v2/list-v2.js +71 -0
  13. package/dist/cjs/v2/media-viewer-v2.js +114 -0
  14. package/dist/cjs/viewers/archiveSidebar/archive.js +5 -3
  15. package/dist/cjs/zoomControls.js +6 -4
  16. package/dist/es2019/analytics/index.js +2 -5
  17. package/dist/es2019/analytics/ufoExperiences.js +1 -1
  18. package/dist/es2019/components/media-viewer.js +13 -1
  19. package/dist/es2019/errorMessage.js +5 -3
  20. package/dist/es2019/item-viewer.js +5 -4
  21. package/dist/es2019/media-viewer.js +8 -6
  22. package/dist/es2019/navigation.js +5 -4
  23. package/dist/es2019/styleWrappers.js +1 -0
  24. package/dist/es2019/v2/header-v2.js +138 -0
  25. package/dist/es2019/v2/item-viewer-v2.js +269 -0
  26. package/dist/es2019/v2/list-v2.js +52 -0
  27. package/dist/es2019/v2/media-viewer-v2.js +95 -0
  28. package/dist/es2019/viewers/archiveSidebar/archive.js +4 -3
  29. package/dist/es2019/zoomControls.js +6 -4
  30. package/dist/esm/analytics/index.js +2 -3
  31. package/dist/esm/analytics/ufoExperiences.js +1 -1
  32. package/dist/esm/components/media-viewer.js +13 -1
  33. package/dist/esm/errorMessage.js +5 -3
  34. package/dist/esm/item-viewer.js +5 -4
  35. package/dist/esm/media-viewer.js +21 -17
  36. package/dist/esm/navigation.js +5 -4
  37. package/dist/esm/styleWrappers.js +1 -0
  38. package/dist/esm/v2/header-v2.js +149 -0
  39. package/dist/esm/v2/item-viewer-v2.js +302 -0
  40. package/dist/esm/v2/list-v2.js +61 -0
  41. package/dist/esm/v2/media-viewer-v2.js +104 -0
  42. package/dist/esm/viewers/archiveSidebar/archive.js +5 -3
  43. package/dist/esm/zoomControls.js +6 -4
  44. package/dist/types/analytics/index.d.ts +2 -2
  45. package/dist/types/v2/header-v2.d.ts +18 -0
  46. package/dist/types/v2/item-viewer-v2.d.ts +21 -0
  47. package/dist/types/v2/list-v2.d.ts +22 -0
  48. package/dist/types/v2/media-viewer-v2.d.ts +14 -0
  49. package/dist/types-ts4.5/analytics/index.d.ts +2 -2
  50. package/dist/types-ts4.5/v2/header-v2.d.ts +18 -0
  51. package/dist/types-ts4.5/v2/item-viewer-v2.d.ts +21 -0
  52. package/dist/types-ts4.5/v2/list-v2.d.ts +22 -0
  53. package/dist/types-ts4.5/v2/media-viewer-v2.d.ts +14 -0
  54. package/package.json +11 -4
@@ -64,7 +64,7 @@ export class ItemViewerBase extends React.Component {
64
64
  item.whenSuccessful(fileItem => {
65
65
  if (isFileStateItem(fileItem)) {
66
66
  const fileAttributes = getFileAttributes(fileItem);
67
- fireAnalytics(createLoadSucceededEvent(fileAttributes, this.traceContext), this.props);
67
+ fireAnalytics(createLoadSucceededEvent(fileAttributes, this.traceContext), this.props.createAnalyticsEvent);
68
68
  succeedMediaFileUfoExperience({
69
69
  fileAttributes,
70
70
  fileStateFlags: this.fileStateFlags
@@ -80,7 +80,7 @@ export class ItemViewerBase extends React.Component {
80
80
  _defineProperty(this, "onExternalImgSuccess", () => {
81
81
  fireAnalytics(createLoadSucceededEvent({
82
82
  fileId: 'external-image'
83
- }), this.props);
83
+ }), this.props.createAnalyticsEvent);
84
84
  succeedMediaFileUfoExperience({
85
85
  fileAttributes: {
86
86
  fileId: 'external-image'
@@ -270,7 +270,8 @@ export class ItemViewerBase extends React.Component {
270
270
  init(props) {
271
271
  const {
272
272
  mediaClient,
273
- identifier
273
+ identifier,
274
+ createAnalyticsEvent
274
275
  } = props;
275
276
  if (isExternalImageIdentifier(identifier)) {
276
277
  // external images do not need to talk to our backend,
@@ -284,7 +285,7 @@ export class ItemViewerBase extends React.Component {
284
285
  const {
285
286
  id
286
287
  } = identifier;
287
- fireAnalytics(createCommencedEvent(id, this.traceContext), this.props);
288
+ fireAnalytics(createCommencedEvent(id, this.traceContext), createAnalyticsEvent);
288
289
  startMediaFileUfoExperience();
289
290
  this.subscription = mediaClient.file.getFileState(id, {
290
291
  collectionName: identifier.collectionName
@@ -22,20 +22,22 @@ export class MediaViewerComponent extends React.Component {
22
22
  isSidebarVisible: false
23
23
  });
24
24
  _defineProperty(this, "onShortcutClosed", () => {
25
- fireAnalytics(createClosedEvent('escKey'), this.props);
26
25
  const {
27
- onClose
26
+ onClose,
27
+ createAnalyticsEvent
28
28
  } = this.props;
29
+ fireAnalytics(createClosedEvent('escKey'), createAnalyticsEvent);
29
30
  if (onClose) {
30
31
  onClose();
31
32
  }
32
33
  });
33
34
  _defineProperty(this, "onContentClose", (_e, analyticsEvent) => {
34
35
  const {
35
- onClose
36
+ onClose,
37
+ createAnalyticsEvent
36
38
  } = this.props;
37
39
  if (analyticsEvent && analyticsEvent.payload && analyticsEvent.payload.actionSubject === 'button') {
38
- fireAnalytics(createClosedEvent('button'), this.props);
40
+ fireAnalytics(createClosedEvent('button'), createAnalyticsEvent);
39
41
  }
40
42
  if (onClose) {
41
43
  onClose();
@@ -70,7 +72,7 @@ export class MediaViewerComponent extends React.Component {
70
72
  });
71
73
  }
72
74
  UNSAFE_componentWillMount() {
73
- fireAnalytics(createModalEvent(), this.props);
75
+ fireAnalytics(createModalEvent(), this.props.createAnalyticsEvent);
74
76
  start('MediaViewer.SessionDuration');
75
77
  }
76
78
  get defaultSelectedItem() {
@@ -100,7 +102,7 @@ export class MediaViewerComponent extends React.Component {
100
102
  "data-testid": "media-viewer-popup",
101
103
  className: mediaViewerPopupClass
102
104
  }, /*#__PURE__*/React.createElement(Shortcut, {
103
- keyCode: 27,
105
+ code: 'Escape',
104
106
  handler: this.onShortcutClosed
105
107
  }), /*#__PURE__*/React.createElement(Content, {
106
108
  isSidebarVisible: isSidebarVisible,
@@ -18,14 +18,15 @@ export class NavigationBase extends Component {
18
18
  return () => {
19
19
  const {
20
20
  onChange,
21
- items
21
+ items,
22
+ createAnalyticsEvent
22
23
  } = this.props;
23
24
  const {
24
25
  selectedIndex
25
26
  } = this;
26
27
  const newItem = direction === 'next' ? items[selectedIndex + 1] : items[selectedIndex - 1];
27
28
  if (newItem) {
28
- fireAnalytics(createNavigatedEvent(direction, source, newItem), this.props);
29
+ fireAnalytics(createNavigatedEvent(direction, source, newItem), createAnalyticsEvent);
29
30
  onChange(newItem);
30
31
  }
31
32
  };
@@ -57,7 +58,7 @@ export class NavigationBase extends Component {
57
58
  }, isLeftVisible ? /*#__PURE__*/React.createElement(Arrow, {
58
59
  className: hideControlsClassName
59
60
  }, /*#__PURE__*/React.createElement(Shortcut, {
60
- keyCode: 37,
61
+ code: 'ArrowLeft',
61
62
  handler: prev('keyboard')
62
63
  }), /*#__PURE__*/React.createElement(Button, {
63
64
  testId: prevNavButtonId,
@@ -75,7 +76,7 @@ export class NavigationBase extends Component {
75
76
  })) : null), /*#__PURE__*/React.createElement(RightWrapper, null, isRightVisible ? /*#__PURE__*/React.createElement(Arrow, {
76
77
  className: hideControlsClassName
77
78
  }, /*#__PURE__*/React.createElement(Shortcut, {
78
- keyCode: 39,
79
+ code: 'ArrowRight',
79
80
  handler: next('keyboard')
80
81
  }), /*#__PURE__*/React.createElement(Button, {
81
82
  testId: nextNavButtonId,
@@ -5,6 +5,7 @@ import { forwardRef, useMemo } from 'react';
5
5
  import { arrowStyles, arrowsWrapperStyles, audioCoverStyles, audioPlayerStyles, audioStyles, baselineExtendStyles, blanketStyles, closeButtonWrapperStyles, contentWrapperStyles, customAudioPlayerWrapperStyles, customVideoPlayerWrapperStyles, defaultCoverWrapperStyles, downloadButtonWrapperStyles, errorImageStyles, errorMessageWrapperStyles, formattedMessageWrapperStyles, hdIconGroupWrapperStyles, hdIconWrapperStyles, headerStyles, headerWrapperStyles, imageWrapperStyles, imgStyles, leftHeaderStyles, leftWrapperStyles, listWrapperStyles, medatadataTextWrapperStyles, metadataFileNameStyles, metadataIconWrapperStyles, metadataSubTextStyles, metadataWrapperStyles, pdfWrapperStyles, rightHeaderStyles, rightWrapperStyles, sidebarWrapperStyles, spinnerWrapperStyles, videoStyles, zoomControlsWrapperStyles, zoomLevelIndicatorStyles, zoomWrapperStyles } from './styles';
6
6
  import { TouchScrollable } from 'react-scrolllock';
7
7
  import { useMergeRefs } from 'use-callback-ref';
8
+ // We are keeping this data-testid since JIRA is still using it in their codebase to perform checks. Before removing this, we need to ensure this 'media-viewer-popup' test id is not being used anywhere else in other codebases
8
9
  export const Blanket = ({
9
10
  'data-testid': datatestId,
10
11
  className,
@@ -0,0 +1,138 @@
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import { isExternalImageIdentifier, isErrorFileState } from '@atlaskit/media-client';
3
+ import { hideControlsClassName, messages, toHumanReadableMediaSize, MediaButton } from '@atlaskit/media-ui';
4
+ import { getLanguageType, getExtension, isCodeViewerItem } from '@atlaskit/media-ui/codeViewer';
5
+ import { FormattedMessage, injectIntl } from 'react-intl-next';
6
+ import { Outcome } from '../domain';
7
+ import { Header as HeaderWrapper, LeftHeader, RightHeader, MetadataWrapper, MetadataSubText, MedatadataTextWrapper, MetadataIconWrapper, MetadataFileName, FormattedMessageWrapper } from '../styleWrappers';
8
+ import { ToolbarDownloadButton, DisabledToolbarDownloadButton } from '../download';
9
+ import { MediaFileStateError, useFileState, useMediaClient } from '@atlaskit/media-client-react';
10
+ import { MimeTypeIcon } from '@atlaskit/media-ui/mime-type-icon';
11
+ import { getFormat } from '../viewers/codeViewer/util';
12
+ import { MediaViewerError } from '../errors';
13
+ export const HeaderV2 = ({
14
+ isArchiveSideBarVisible = false,
15
+ extensions,
16
+ isSidebarVisible,
17
+ onSidebarButtonClick,
18
+ identifier,
19
+ onSetArchiveSideBarVisible
20
+ }) => {
21
+ // States
22
+ const [item, setItem] = useState(Outcome.pending());
23
+
24
+ // Refs and Hooks
25
+ const mediaClient = useMediaClient();
26
+ const {
27
+ id,
28
+ collectionName,
29
+ occurrenceKey
30
+ } = identifier;
31
+ const {
32
+ fileState
33
+ } = useFileState(id, {
34
+ collectionName,
35
+ occurrenceKey
36
+ });
37
+ const onSetArchiveSideBarVisibleRef = useRef(onSetArchiveSideBarVisible);
38
+ onSetArchiveSideBarVisibleRef.current = onSetArchiveSideBarVisible;
39
+
40
+ // previous values
41
+ useEffect(() => {
42
+ if (isExternalImageIdentifier(identifier)) {
43
+ const {
44
+ name = identifier.dataURI
45
+ } = identifier;
46
+
47
+ // Simulate a processing file state to render right metadata
48
+ const fileState = {
49
+ status: 'processing',
50
+ id: name,
51
+ mediaType: 'image',
52
+ mimeType: 'image/',
53
+ name,
54
+ representations: {},
55
+ size: 0
56
+ };
57
+ setItem(Outcome.successful(fileState));
58
+ return;
59
+ }
60
+ if (!fileState) {
61
+ return;
62
+ }
63
+ if (fileState.status !== 'error') {
64
+ var _onSetArchiveSideBarV;
65
+ (_onSetArchiveSideBarV = onSetArchiveSideBarVisibleRef.current) === null || _onSetArchiveSideBarV === void 0 ? void 0 : _onSetArchiveSideBarV.call(onSetArchiveSideBarVisibleRef, !isErrorFileState(fileState) && fileState.mediaType === 'archive');
66
+ setItem(Outcome.successful(fileState));
67
+ } else {
68
+ const error = new MediaFileStateError(fileState.id, fileState.reason, fileState.message, fileState.details);
69
+ setItem(Outcome.failed(new MediaViewerError('header-fetch-metadata', error)));
70
+ }
71
+ }, [fileState, identifier]);
72
+ const renderFileTypeText = item => {
73
+ // render appropriate header if its a code/email item and the feature flag is enabled
74
+ if (isCodeViewerItem(item.name, item.mimeType)) {
75
+ // gather language and extension
76
+ // i.e test.py would have a language of 'python' and an extension of 'py'
77
+ const language = getLanguageType(item.name, item.mimeType);
78
+ const ext = getExtension(item.name);
79
+
80
+ // specific cases for if we want a certain word translated in other languages
81
+ switch (ext) {
82
+ case 'msg':
83
+ return /*#__PURE__*/React.createElement(FormattedMessage, messages.email);
84
+ case 'txt':
85
+ return /*#__PURE__*/React.createElement(FormattedMessage, messages.text);
86
+ }
87
+
88
+ // no need for translations in other languages
89
+ return /*#__PURE__*/React.createElement(React.Fragment, null, getFormat(language || 'unknown', ext));
90
+ }
91
+ const {
92
+ mediaType
93
+ } = item;
94
+ const mediaTypeTranslationMap = {
95
+ doc: messages.document,
96
+ audio: messages.audio,
97
+ video: messages.video,
98
+ image: messages.image,
99
+ archive: messages.archive,
100
+ unknown: messages.unknown
101
+ };
102
+ const message = mediaTypeTranslationMap[mediaType || 'unknown'];
103
+
104
+ // Defaulting to unknown again since backend has more mediaTypes than the current supported ones
105
+ return /*#__PURE__*/React.createElement(FormattedMessage, message || messages.unknown);
106
+ };
107
+ return /*#__PURE__*/React.createElement(HeaderWrapper, {
108
+ isArchiveSideBarVisible: isArchiveSideBarVisible,
109
+ className: hideControlsClassName
110
+ }, /*#__PURE__*/React.createElement(LeftHeader, null, item.match({
111
+ successful: item => !isErrorFileState(item) && /*#__PURE__*/React.createElement(MetadataWrapper, null, /*#__PURE__*/React.createElement(MetadataIconWrapper, null, /*#__PURE__*/React.createElement(MimeTypeIcon, {
112
+ testId: 'media-viewer-file-type-icon',
113
+ mediaType: item.mediaType,
114
+ mimeType: item.mimeType,
115
+ name: item.name
116
+ })), /*#__PURE__*/React.createElement(MedatadataTextWrapper, null, /*#__PURE__*/React.createElement(MetadataFileName, {
117
+ "data-testid": "media-viewer-file-name"
118
+ }, item.name || /*#__PURE__*/React.createElement(FormattedMessage, messages.unknown)), /*#__PURE__*/React.createElement(MetadataSubText, {
119
+ "data-testid": "media-viewer-file-metadata-text"
120
+ }, /*#__PURE__*/React.createElement(FormattedMessageWrapper, null, renderFileTypeText(item)), item.size ? ' · ' + toHumanReadableMediaSize(item.size) : ''))),
121
+ pending: () => null,
122
+ failed: () => null
123
+ })), /*#__PURE__*/React.createElement(RightHeader, null, (extensions === null || extensions === void 0 ? void 0 : extensions.sidebar) && /*#__PURE__*/React.createElement(MediaButton, {
124
+ isSelected: isSidebarVisible,
125
+ testId: "media-viewer-sidebar-button",
126
+ onClick: onSidebarButtonClick,
127
+ iconBefore: extensions.sidebar.icon
128
+ }), item.match({
129
+ pending: () => DisabledToolbarDownloadButton,
130
+ failed: () => DisabledToolbarDownloadButton,
131
+ successful: item => /*#__PURE__*/React.createElement(ToolbarDownloadButton, {
132
+ state: item,
133
+ identifier: identifier,
134
+ mediaClient: mediaClient
135
+ })
136
+ })));
137
+ };
138
+ export default injectIntl(HeaderV2);
@@ -0,0 +1,269 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ import React, { useCallback, useEffect, useState, useRef } from 'react';
3
+ import Loadable from 'react-loadable';
4
+ import { isExternalImageIdentifier, isFileIdentifier } from '@atlaskit/media-client';
5
+ import { FormattedMessage } from 'react-intl-next';
6
+ import { messages } from '@atlaskit/media-ui';
7
+ import { isCodeViewerItem } from '@atlaskit/media-ui/codeViewer';
8
+ import { useFileState, useMediaClient, MediaFileStateError } from '@atlaskit/media-client-react';
9
+ import { Outcome } from '../domain';
10
+ import { Spinner } from '../loading';
11
+ import ErrorMessage from '../errorMessage';
12
+ import { MediaViewerError } from '../errors';
13
+ import { ErrorViewDownloadButton } from '../download';
14
+ import { withAnalyticsEvents } from '@atlaskit/analytics-next';
15
+ import { createCommencedEvent } from '../analytics/events/operational/commenced';
16
+ import { createLoadSucceededEvent } from '../analytics/events/operational/loadSucceeded';
17
+ import { fireAnalytics, getFileAttributes } from '../analytics';
18
+ import { InteractiveImg } from '../viewers/image/interactive-img';
19
+ import ArchiveViewerLoader from '../viewers/archiveSidebar/archiveViewerLoader';
20
+ import { getRandomHex } from '@atlaskit/media-common';
21
+ import { startMediaFileUfoExperience, succeedMediaFileUfoExperience } from '../analytics/ufoExperiences';
22
+ const ImageViewer = Loadable({
23
+ loader: () => import( /* webpackChunkName: "@atlaskit-internal_imageViewer" */'../viewers/image').then(mod => mod.ImageViewer),
24
+ loading: () => /*#__PURE__*/React.createElement(Spinner, null)
25
+ });
26
+ const VideoViewer = Loadable({
27
+ loader: () => import( /* webpackChunkName: "@atlaskit-internal_videoViewer" */'../viewers/video').then(mod => mod.VideoViewer),
28
+ loading: () => /*#__PURE__*/React.createElement(Spinner, null)
29
+ });
30
+ const AudioViewer = Loadable({
31
+ loader: () => import( /* webpackChunkName: "@atlaskit-internal_audioViewer" */'../viewers/audio').then(mod => mod.AudioViewer),
32
+ loading: () => /*#__PURE__*/React.createElement(Spinner, null)
33
+ });
34
+ const DocViewer = Loadable({
35
+ loader: () => import( /* webpackChunkName: "@atlaskit-internal_docViewer" */'../viewers/doc').then(mod => mod.DocViewer),
36
+ loading: () => /*#__PURE__*/React.createElement(Spinner, null)
37
+ });
38
+ const CodeViewer = Loadable({
39
+ loader: () => import( /* webpackChunkName: "@atlaskit-internal_codeViewer" */'../viewers/codeViewer').then(mod => mod.CodeViewer),
40
+ loading: () => /*#__PURE__*/React.createElement(Spinner, null)
41
+ });
42
+ // Consts
43
+ export const isExternalImageItem = fileItem => fileItem === 'external-image';
44
+ export const isFileStateItem = fileItem => !isExternalImageItem(fileItem);
45
+ export const MAX_FILE_SIZE_SUPPORTED_BY_CODEVIEWER = 10 * 1024 * 1024;
46
+ export const ItemViewerV2Base = ({
47
+ identifier,
48
+ showControls,
49
+ onClose,
50
+ previewCount,
51
+ contextId,
52
+ createAnalyticsEvent
53
+ }) => {
54
+ // States and Refs
55
+ const [item, setItem] = useState(Outcome.pending());
56
+ const traceContext = useRef({
57
+ traceId: getRandomHex(8)
58
+ });
59
+ const fileStateFlagsRef = useRef({
60
+ wasStatusUploading: false,
61
+ wasStatusProcessing: false
62
+ });
63
+ const createAnalyticsEventRef = useRef(createAnalyticsEvent);
64
+ createAnalyticsEventRef.current = createAnalyticsEvent;
65
+
66
+ // Hooks
67
+ const mediaClient = useMediaClient();
68
+ const {
69
+ fileState
70
+ } = useFileState(isExternalImageIdentifier(identifier) ? '' : identifier.id, {
71
+ collectionName: isExternalImageIdentifier(identifier) ? '' : identifier.collectionName,
72
+ skipRemote: isExternalImageIdentifier(identifier)
73
+ });
74
+ const renderDownloadButton = useCallback((fileState, error) => {
75
+ const collectionName = isFileIdentifier(identifier) ? identifier.collectionName : undefined;
76
+ return /*#__PURE__*/React.createElement(ErrorViewDownloadButton, {
77
+ fileState: fileState,
78
+ mediaClient: mediaClient,
79
+ error: error,
80
+ collectionName: collectionName
81
+ });
82
+ }, [mediaClient, identifier]);
83
+
84
+ // Did mount
85
+
86
+ useEffect(() => {
87
+ if (isExternalImageIdentifier(identifier)) {
88
+ // external images do not need to talk to our backend,
89
+ // so therefore no need for media-client subscriptions.
90
+ // just set a successful outcome of type "external-image".
91
+ setItem(Outcome.successful('external-image'));
92
+ return;
93
+ }
94
+ fireAnalytics(createCommencedEvent(identifier === null || identifier === void 0 ? void 0 : identifier.id, traceContext.current), createAnalyticsEventRef.current);
95
+ startMediaFileUfoExperience();
96
+
97
+ // File Subscription
98
+
99
+ if (fileState) {
100
+ const {
101
+ status
102
+ } = fileState;
103
+ if (fileState.status !== 'error') {
104
+ // updateFileStateFlag
105
+
106
+ if (status === 'processing') {
107
+ fileStateFlagsRef.current.wasStatusProcessing = true;
108
+ } else if (status === 'uploading') {
109
+ fileStateFlagsRef.current.wasStatusUploading = true;
110
+ }
111
+ setItem(Outcome.successful(fileState));
112
+ } else {
113
+ const e = new MediaFileStateError(fileState.id, fileState.reason, fileState.message, fileState.details);
114
+ setItem(Outcome.failed(new MediaViewerError('itemviewer-fetch-metadata', e)));
115
+ }
116
+ }
117
+ }, [fileState, identifier]);
118
+ const onSuccess = useCallback(() => {
119
+ item.whenSuccessful(fileItem => {
120
+ if (isFileStateItem(fileItem)) {
121
+ const fileAttributes = getFileAttributes(fileItem);
122
+ fireAnalytics(createLoadSucceededEvent(fileAttributes, traceContext.current), createAnalyticsEventRef.current);
123
+ succeedMediaFileUfoExperience({
124
+ fileAttributes,
125
+ fileStateFlags: fileStateFlagsRef.current
126
+ });
127
+ }
128
+ });
129
+ }, [item]);
130
+ const onLoadFail = useCallback(mediaViewerError => {
131
+ setItem(Outcome.failed(mediaViewerError));
132
+ }, []);
133
+ const renderError = useCallback((error, fileItem) => {
134
+ if (fileItem) {
135
+ let fileState;
136
+ if (fileItem === 'external-image') {
137
+ // external image error outcome
138
+ fileState = {
139
+ id: 'external-image',
140
+ status: 'error'
141
+ };
142
+ } else {
143
+ // FileState error outcome
144
+ fileState = fileItem;
145
+ }
146
+ return /*#__PURE__*/React.createElement(ErrorMessage, {
147
+ fileId: isFileIdentifier(identifier) ? identifier.id : 'undefined',
148
+ error: error,
149
+ fileState: fileState,
150
+ fileStateFlags: fileStateFlagsRef.current,
151
+ traceContext: traceContext.current
152
+ }, /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement(FormattedMessage, messages.try_downloading_file)), renderDownloadButton(fileState, error));
153
+ } else {
154
+ return /*#__PURE__*/React.createElement(ErrorMessage, {
155
+ fileId: isFileIdentifier(identifier) ? identifier.id : 'undefined',
156
+ error: error,
157
+ fileStateFlags: fileStateFlagsRef.current
158
+ });
159
+ }
160
+ }, [identifier, renderDownloadButton, traceContext]);
161
+ return item.match({
162
+ successful: fileItem => {
163
+ if (fileItem === 'external-image') {
164
+ // render an external image
165
+ const {
166
+ dataURI
167
+ } = identifier;
168
+ return /*#__PURE__*/React.createElement(InteractiveImg, {
169
+ src: dataURI,
170
+ onLoad: () => {
171
+ fireAnalytics(createLoadSucceededEvent({
172
+ fileId: 'external-image'
173
+ }), createAnalyticsEventRef.current);
174
+ succeedMediaFileUfoExperience({
175
+ fileAttributes: {
176
+ fileId: 'external-image'
177
+ },
178
+ fileStateFlags: fileStateFlagsRef.current
179
+ });
180
+ },
181
+ onError: () => {
182
+ setItem(Outcome.failed(new MediaViewerError('imageviewer-external-onerror')));
183
+ }
184
+ });
185
+ } else {
186
+ // render a FileState fetched through media-client
187
+ switch (fileItem.status) {
188
+ case 'processed':
189
+ case 'uploading':
190
+ case 'processing':
191
+ // TODO: renderItem
192
+ const collectionName = isFileIdentifier(identifier) ? identifier.collectionName : undefined;
193
+ const viewerProps = {
194
+ mediaClient,
195
+ item: fileItem,
196
+ collectionName,
197
+ onClose,
198
+ previewCount
199
+ };
200
+
201
+ // TODO: fix all of the item errors
202
+
203
+ if (isCodeViewerItem(fileItem.name, fileItem.mimeType)) {
204
+ //Render error message if code file has size over 10MB.
205
+ //Required by https://product-fabric.atlassian.net/browse/MEX-1788
206
+ if (fileItem.size > MAX_FILE_SIZE_SUPPORTED_BY_CODEVIEWER) {
207
+ return renderError(new MediaViewerError('codeviewer-file-size-exceeds'), fileItem);
208
+ }
209
+ return /*#__PURE__*/React.createElement(CodeViewer, _extends({
210
+ onSuccess: onSuccess,
211
+ onError: onLoadFail
212
+ }, viewerProps));
213
+ }
214
+ const {
215
+ mediaType
216
+ } = fileItem;
217
+ switch (mediaType) {
218
+ case 'image':
219
+ return /*#__PURE__*/React.createElement(ImageViewer, _extends({
220
+ onLoad: onSuccess,
221
+ onError: onLoadFail,
222
+ contextId: contextId,
223
+ traceContext: traceContext.current
224
+ }, viewerProps));
225
+ case 'audio':
226
+ return /*#__PURE__*/React.createElement(AudioViewer, _extends({
227
+ showControls: showControls,
228
+ onCanPlay: onSuccess,
229
+ onError: onLoadFail
230
+ }, viewerProps));
231
+ case 'video':
232
+ return /*#__PURE__*/React.createElement(VideoViewer, _extends({
233
+ showControls: showControls,
234
+ onCanPlay: onSuccess,
235
+ onError: onLoadFail
236
+ }, viewerProps));
237
+ case 'doc':
238
+ return /*#__PURE__*/React.createElement(DocViewer, _extends({
239
+ onSuccess: onSuccess,
240
+ onError: onLoadFail
241
+ }, viewerProps));
242
+ case 'archive':
243
+ return /*#__PURE__*/React.createElement(ArchiveViewerLoader, _extends({
244
+ onSuccess: onSuccess,
245
+ onError: onLoadFail
246
+ }, viewerProps));
247
+ }
248
+ return renderError(new MediaViewerError('unsupported'), fileItem);
249
+ case 'failed-processing':
250
+ return renderError(new MediaViewerError('itemviewer-file-failed-processing-status'), fileItem);
251
+ case 'error':
252
+ return renderError(new MediaViewerError('itemviewer-file-error-status'), fileItem);
253
+ }
254
+ }
255
+ },
256
+ pending: () => /*#__PURE__*/React.createElement(Spinner, null),
257
+ failed: error => renderError(error, item.data)
258
+ });
259
+ };
260
+ const ViewerWithKey = props => {
261
+ const {
262
+ identifier
263
+ } = props;
264
+ const key = isFileIdentifier(identifier) ? identifier.id : identifier.dataURI;
265
+ return /*#__PURE__*/React.createElement(ItemViewerV2Base, _extends({}, props, {
266
+ key: key
267
+ }));
268
+ };
269
+ export const ItemViewerV2 = withAnalyticsEvents()(ViewerWithKey);
@@ -0,0 +1,52 @@
1
+ import React, { useState } from 'react';
2
+ import { hideControlsClassName } from '@atlaskit/media-ui';
3
+ import { ItemViewerV2 } from './item-viewer-v2';
4
+ import { HeaderWrapper, ListWrapper } from '../styleWrappers';
5
+ import { Navigation } from '../navigation';
6
+ import HeaderV2 from './header-v2';
7
+ export const ListV2 = ({
8
+ defaultSelectedItem,
9
+ onClose,
10
+ showControls,
11
+ extensions,
12
+ onSidebarButtonClick,
13
+ contextId,
14
+ featureFlags,
15
+ isSidebarVisible,
16
+ onNavigationChange,
17
+ items
18
+ }) => {
19
+ const [selectedItem, setSelectedItem] = useState(defaultSelectedItem);
20
+ const [previewCount, setPreviewCount] = useState(0);
21
+ const [isArchiveSideBarVisible, setIsArchiveSideBarVisible] = useState(false);
22
+ return /*#__PURE__*/React.createElement(ListWrapper, null, /*#__PURE__*/React.createElement(HeaderWrapper, {
23
+ className: hideControlsClassName,
24
+ isArchiveSideBarVisible: isArchiveSideBarVisible
25
+ }, /*#__PURE__*/React.createElement(HeaderV2, {
26
+ identifier: selectedItem,
27
+ onClose: onClose,
28
+ extensions: extensions,
29
+ onSidebarButtonClick: onSidebarButtonClick,
30
+ isSidebarVisible: isSidebarVisible,
31
+ isArchiveSideBarVisible: isArchiveSideBarVisible,
32
+ featureFlags: featureFlags,
33
+ onSetArchiveSideBarVisible: setIsArchiveSideBarVisible
34
+ })), /*#__PURE__*/React.createElement(ItemViewerV2, {
35
+ identifier: selectedItem,
36
+ showControls: showControls,
37
+ onClose: onClose,
38
+ previewCount: previewCount,
39
+ contextId: contextId,
40
+ featureFlags: featureFlags
41
+ }), /*#__PURE__*/React.createElement(Navigation, {
42
+ items: items,
43
+ selectedItem: selectedItem,
44
+ onChange: selectedItem => {
45
+ onNavigationChange === null || onNavigationChange === void 0 ? void 0 : onNavigationChange(selectedItem);
46
+ showControls === null || showControls === void 0 ? void 0 : showControls();
47
+ setSelectedItem(selectedItem);
48
+ setPreviewCount(previewCount + 1);
49
+ },
50
+ isArchiveSideBarVisible: isArchiveSideBarVisible
51
+ }));
52
+ };