@atlaskit/media-viewer 49.2.6 → 49.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/cjs/analytics/index.js +1 -1
  3. package/dist/cjs/analytics/ufoExperiences.js +1 -1
  4. package/dist/cjs/components/media-viewer.js +4 -2
  5. package/dist/cjs/item-viewer.js +20 -3
  6. package/dist/cjs/list.js +4 -2
  7. package/dist/cjs/media-viewer.js +4 -2
  8. package/dist/cjs/viewerOptions.js +5 -0
  9. package/dist/cjs/viewers/archiveSidebar/archive.js +52 -8
  10. package/dist/cjs/viewers/customViewer/customViewer.js +55 -0
  11. package/dist/cjs/viewers/video.js +25 -19
  12. package/dist/es2019/analytics/index.js +1 -1
  13. package/dist/es2019/analytics/ufoExperiences.js +1 -1
  14. package/dist/es2019/components/media-viewer.js +4 -2
  15. package/dist/es2019/item-viewer.js +18 -3
  16. package/dist/es2019/list.js +4 -2
  17. package/dist/es2019/media-viewer.js +4 -2
  18. package/dist/es2019/viewerOptions.js +1 -0
  19. package/dist/es2019/viewers/archiveSidebar/archive.js +27 -5
  20. package/dist/es2019/viewers/customViewer/customViewer.js +37 -0
  21. package/dist/es2019/viewers/video.js +7 -3
  22. package/dist/esm/analytics/index.js +1 -1
  23. package/dist/esm/analytics/ufoExperiences.js +1 -1
  24. package/dist/esm/components/media-viewer.js +4 -2
  25. package/dist/esm/item-viewer.js +20 -3
  26. package/dist/esm/list.js +4 -2
  27. package/dist/esm/media-viewer.js +4 -2
  28. package/dist/esm/viewerOptions.js +1 -0
  29. package/dist/esm/viewers/archiveSidebar/archive.js +52 -8
  30. package/dist/esm/viewers/customViewer/customViewer.js +46 -0
  31. package/dist/esm/viewers/video.js +25 -19
  32. package/dist/types/components/media-viewer.d.ts +1 -1
  33. package/dist/types/components/types.d.ts +2 -0
  34. package/dist/types/errors.d.ts +2 -2
  35. package/dist/types/index.d.ts +1 -0
  36. package/dist/types/item-viewer.d.ts +4 -1
  37. package/dist/types/list.d.ts +3 -1
  38. package/dist/types/media-viewer.d.ts +2 -0
  39. package/dist/types/viewerOptions.d.ts +21 -0
  40. package/dist/types/viewers/archiveSidebar/types.d.ts +2 -0
  41. package/dist/types/viewers/customViewer/customViewer.d.ts +12 -0
  42. package/dist/types-ts4.5/components/media-viewer.d.ts +1 -1
  43. package/dist/types-ts4.5/components/types.d.ts +2 -0
  44. package/dist/types-ts4.5/errors.d.ts +2 -2
  45. package/dist/types-ts4.5/index.d.ts +1 -0
  46. package/dist/types-ts4.5/item-viewer.d.ts +4 -1
  47. package/dist/types-ts4.5/list.d.ts +3 -1
  48. package/dist/types-ts4.5/media-viewer.d.ts +2 -0
  49. package/dist/types-ts4.5/viewerOptions.d.ts +21 -0
  50. package/dist/types-ts4.5/viewers/archiveSidebar/types.d.ts +2 -0
  51. package/dist/types-ts4.5/viewers/customViewer/customViewer.d.ts +12 -0
  52. package/package.json +7 -7
@@ -5,6 +5,7 @@ import { unzip, HTTPRangeReader } from 'unzipit';
5
5
  import { FormattedMessage } from 'react-intl-next';
6
6
  import { CustomMediaPlayer, messages } from '@atlaskit/media-ui';
7
7
  import { getLanguageType, isCodeViewerItem } from '@atlaskit/media-ui/codeViewer';
8
+ import { Text } from '@atlaskit/primitives';
8
9
  import { Outcome } from '../../domain';
9
10
  import { CustomVideoPlayerWrapper, AudioPlayer, CustomAudioPlayerWrapper, DefaultCoverWrapper, ListWrapper } from '../../styleWrappers';
10
11
  import AudioIcon from '@atlaskit/icon/core/migration/audio--media-services-audio';
@@ -48,7 +49,8 @@ export class ArchiveViewerBase extends BaseViewer {
48
49
  this.setState({
49
50
  content: Outcome.successful({
50
51
  ...this.state.content.data,
51
- selectedArchiveEntry: undefined
52
+ selectedArchiveEntry: undefined,
53
+ hasLoadedEntries: false // displays a nice loading spinner for the content viewer
52
54
  })
53
55
  });
54
56
  let src = '';
@@ -56,7 +58,7 @@ export class ArchiveViewerBase extends BaseViewer {
56
58
  const isCodeMimeType = isCodeViewerItem(selectedArchiveEntry.name, getMimeTypeFromFilename(selectedArchiveEntry.name));
57
59
  if (!selectedArchiveEntry.isDirectory) {
58
60
  try {
59
- const blob = await rejectAfter(() => selectedArchiveEntry.blob());
61
+ const blob = await rejectAfter(() => selectedArchiveEntry.blob(), 10000);
60
62
  src = URL.createObjectURL(blob);
61
63
  if (isCodeMimeType) {
62
64
  codeViewerSrc = await rejectAfter(() => blob.text());
@@ -74,7 +76,8 @@ export class ArchiveViewerBase extends BaseViewer {
74
76
  isDirectory: selectedArchiveEntry.isDirectory,
75
77
  error: undefined,
76
78
  codeViewerSrc,
77
- isCodeMimeType
79
+ isCodeMimeType,
80
+ hasLoadedEntries: true
78
81
  })
79
82
  });
80
83
  });
@@ -145,7 +148,8 @@ export class ArchiveViewerBase extends BaseViewer {
145
148
  }
146
149
  renderArchiveItemViewer(content) {
147
150
  const {
148
- item
151
+ item,
152
+ viewerOptions
149
153
  } = this.props;
150
154
  const {
151
155
  src,
@@ -160,9 +164,27 @@ export class ArchiveViewerBase extends BaseViewer {
160
164
  return this.renderPreviewError(error, selectedArchiveEntry);
161
165
  }
162
166
  if (!isDirectory && selectedArchiveEntry) {
167
+ var _viewerOptions$custom;
163
168
  if (!name || !src) {
164
169
  return this.renderPreviewError(new ArchiveViewerError('archiveviewer-missing-name-src'), selectedArchiveEntry);
165
170
  }
171
+ const customRenderer = viewerOptions === null || viewerOptions === void 0 ? void 0 : (_viewerOptions$custom = viewerOptions.customRenderers) === null || _viewerOptions$custom === void 0 ? void 0 : _viewerOptions$custom.find(renderer => renderer.shouldUseCustomRenderer({
172
+ fileItem: item,
173
+ archiveFileItem: {
174
+ name
175
+ }
176
+ }));
177
+ if (customRenderer) {
178
+ return /*#__PURE__*/React.createElement(ArchiveItemViewerWrapper, null, customRenderer.renderContent({
179
+ fileItem: item,
180
+ archiveFileItem: {
181
+ name
182
+ },
183
+ getBinaryContent: async () => (await fetch(src)).blob(),
184
+ onLoad: this.onViewerLoad(selectedArchiveEntry),
185
+ onError: this.onViewerError('archiveviewer-customrenderer-onerror', selectedArchiveEntry)
186
+ }));
187
+ }
166
188
  const mediaType = getMediaTypeFromFilename(name);
167
189
  if (isCodeMimeType) {
168
190
  // Same code viewer logic as in Item-Viewer.tsx
@@ -242,7 +264,7 @@ export class ArchiveViewerBase extends BaseViewer {
242
264
  fileState: item,
243
265
  error: error,
244
266
  supressAnalytics: true
245
- }, /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement(FormattedMessage, messages.try_downloading_file))));
267
+ }, /*#__PURE__*/React.createElement(Text, null, /*#__PURE__*/React.createElement(FormattedMessage, messages.try_downloading_file))));
246
268
  }
247
269
  }
248
270
  export const ArchiveViewer = withAnalyticsEvents()(ArchiveViewerBase);
@@ -0,0 +1,37 @@
1
+ import { MediaViewerError } from '../../errors';
2
+ import { useCallback, useEffect, useState } from 'react';
3
+ import React from 'react';
4
+ import { Spinner } from '../../loading';
5
+ export const CustomViewer = ({
6
+ mediaClient,
7
+ item,
8
+ customRendererConfig,
9
+ onSuccess,
10
+ onError
11
+ }) => {
12
+ const [getBinaryContent, setGetBinaryContent] = useState();
13
+ useEffect(() => {
14
+ setGetBinaryContent(undefined);
15
+ const abortController = new AbortController();
16
+ // This sets the 'getBinaryContent' to an async function that fetches the binary content of the file
17
+ // The 'getBinaryContent' function has to be updated when the item changes
18
+ // This approach handles aborting in-progress request outside of the custom-renderer concern
19
+ if (item.status === 'processed' || item.status === 'failed-processing') {
20
+ setGetBinaryContent(() => () => mediaClient.mediaStore.getFileBinary(item.id, undefined, abortController));
21
+ }
22
+ return () => abortController.abort();
23
+ }, [item, mediaClient]);
24
+ const onLoadFailed = useCallback(error => {
25
+ const mediaError = new MediaViewerError('custom-viewer-error', error);
26
+ onError(mediaError, item);
27
+ }, [item, onError]);
28
+ if (!getBinaryContent) {
29
+ return /*#__PURE__*/React.createElement(Spinner, null);
30
+ }
31
+ return /*#__PURE__*/React.createElement(React.Fragment, null, customRendererConfig.renderContent({
32
+ fileItem: item,
33
+ getBinaryContent,
34
+ onLoad: onSuccess,
35
+ onError: onLoadFailed
36
+ }));
37
+ };
@@ -63,6 +63,8 @@ export class VideoViewer extends BaseViewer {
63
63
  } = this.props;
64
64
  const useCustomVideoPlayer = !isIE();
65
65
  const isAutoPlay = previewCount === 0;
66
+ const hdAvailable = isHDAvailable(item);
67
+ const hdActiveOverride = fg('platform_media_disable_video_640p_artifact_usage') ? hdAvailable : isHDActive;
66
68
  return useCustomVideoPlayer ? /*#__PURE__*/React.createElement(CustomVideoPlayerWrapper, {
67
69
  "data-testid": "media-viewer-video-content"
68
70
  }, /*#__PURE__*/React.createElement(CustomMediaPlayer, {
@@ -72,8 +74,8 @@ export class VideoViewer extends BaseViewer {
72
74
  showControls: showControls,
73
75
  src: content,
74
76
  fileId: item.id,
75
- isHDActive: isHDActive,
76
- isHDAvailable: isHDAvailable(item),
77
+ isHDActive: hdActiveOverride,
78
+ isHDAvailable: hdAvailable,
77
79
  isShortcutEnabled: true,
78
80
  onFirstPlay: this.onFirstPlay,
79
81
  onError: this.onError,
@@ -95,7 +97,9 @@ export class VideoViewer extends BaseViewer {
95
97
  try {
96
98
  let contentUrl;
97
99
  if (item.status === 'processed') {
98
- const preferHd = isHDActive && isHDAvailable(item);
100
+ const hdAvailable = isHDAvailable(item);
101
+ const hdActiveOverride = fg('platform_media_disable_video_640p_artifact_usage') ? hdAvailable : isHDActive;
102
+ const preferHd = hdActiveOverride && hdAvailable;
99
103
  contentUrl = await mediaClient.file.getArtifactURL(item.artifacts, preferHd ? hdArtifact : sdArtifact, collectionName);
100
104
  if (!contentUrl) {
101
105
  throw new MediaViewerError(`videoviewer-missing-artefact`);
@@ -1,7 +1,7 @@
1
1
  import { ANALYTICS_MEDIA_CHANNEL, sanitiseAnalyticsPayload } from '@atlaskit/media-common/analytics';
2
2
  var componentName = 'mediaViewer';
3
3
  var packageName = "@atlaskit/media-viewer";
4
- var packageVersion = "49.2.6";
4
+ var packageVersion = "49.3.0";
5
5
  export { packageName, packageVersion, componentName, componentName as component };
6
6
  export function getFileAttributes(fileState) {
7
7
  if (!fileState) {
@@ -5,7 +5,7 @@ import { UFOExperience, ExperiencePerformanceTypes, ExperienceTypes } from '@atl
5
5
  import { getMediaEnvironment, getMediaRegion } from '@atlaskit/media-client';
6
6
  import { getFeatureFlagKeysAllProducts } from '@atlaskit/media-common';
7
7
  var packageName = "@atlaskit/media-viewer";
8
- var packageVersion = "49.2.6";
8
+ var packageVersion = "49.3.0";
9
9
  var ufoExperience;
10
10
  var getExperience = function getExperience() {
11
11
  if (!ufoExperience) {
@@ -37,7 +37,8 @@ export var MediaViewerBase = function MediaViewerBase(_ref) {
37
37
  collectionName = _ref.collectionName,
38
38
  items = _ref.items,
39
39
  extensions = _ref.extensions,
40
- contextId = _ref.contextId;
40
+ contextId = _ref.contextId,
41
+ viewerOptions = _ref.viewerOptions;
41
42
  var _useMemo = useMemo(function () {
42
43
  return normaliseItems(items, selectedItem, collectionName);
43
44
  }, [items, selectedItem, collectionName]),
@@ -70,7 +71,8 @@ export var MediaViewerBase = function MediaViewerBase(_ref) {
70
71
  items: normalisedItems,
71
72
  featureFlags: featureFlags,
72
73
  extensions: extensions,
73
- contextId: contextId
74
+ contextId: contextId,
75
+ viewerOptions: viewerOptions
74
76
  });
75
77
  };
76
78
 
@@ -3,6 +3,7 @@ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
3
3
  import React, { useCallback, useEffect, useState, useRef } from 'react';
4
4
  import Loadable from 'react-loadable';
5
5
  import { isExternalImageIdentifier, isFileIdentifier } from '@atlaskit/media-client';
6
+ import { Text } from '@atlaskit/primitives';
6
7
  import { FormattedMessage } from 'react-intl-next';
7
8
  import { messages } from '@atlaskit/media-ui';
8
9
  import { isCodeViewerItem } from '@atlaskit/media-ui/codeViewer';
@@ -20,6 +21,7 @@ import { InteractiveImg } from './viewers/image/interactive-img';
20
21
  import ArchiveViewerLoader from './viewers/archiveSidebar/archiveViewerLoader';
21
22
  import { getRandomHex } from '@atlaskit/media-common';
22
23
  import { startMediaFileUfoExperience, succeedMediaFileUfoExperience } from './analytics/ufoExperiences';
24
+ import { CustomViewer } from './viewers/customViewer/customViewer';
23
25
  var ImageViewer = Loadable({
24
26
  loader: function loader() {
25
27
  return import( /* webpackChunkName: "@atlaskit-internal_imageViewer" */'./viewers/image').then(function (mod) {
@@ -97,7 +99,8 @@ export var ItemViewerBase = function ItemViewerBase(_ref) {
97
99
  onClose = _ref.onClose,
98
100
  previewCount = _ref.previewCount,
99
101
  contextId = _ref.contextId,
100
- createAnalyticsEvent = _ref.createAnalyticsEvent;
102
+ createAnalyticsEvent = _ref.createAnalyticsEvent,
103
+ viewerOptions = _ref.viewerOptions;
101
104
  // States and Refs
102
105
  var _useState = useState(Outcome.pending()),
103
106
  _useState2 = _slicedToArray(_useState, 2),
@@ -182,14 +185,28 @@ export var ItemViewerBase = function ItemViewerBase(_ref) {
182
185
  setItem(Outcome.failed(mediaViewerError, fileState));
183
186
  }, [fileState]);
184
187
  var renderItem = function renderItem(fileItem) {
188
+ var _viewerOptions$custom;
185
189
  var collectionName = isFileIdentifier(identifier) ? identifier.collectionName : undefined;
186
190
  var viewerProps = {
187
191
  mediaClient: mediaClient,
188
192
  item: fileItem,
189
193
  collectionName: collectionName,
190
194
  onClose: onClose,
191
- previewCount: previewCount
195
+ previewCount: previewCount,
196
+ viewerOptions: viewerOptions
192
197
  };
198
+ var customRenderer = viewerOptions === null || viewerOptions === void 0 || (_viewerOptions$custom = viewerOptions.customRenderers) === null || _viewerOptions$custom === void 0 ? void 0 : _viewerOptions$custom.find(function (renderer) {
199
+ return renderer.shouldUseCustomRenderer({
200
+ fileItem: fileItem
201
+ });
202
+ });
203
+ if (customRenderer) {
204
+ return /*#__PURE__*/React.createElement(CustomViewer, _extends({
205
+ customRendererConfig: customRenderer,
206
+ onError: onLoadFail,
207
+ onSuccess: onSuccess
208
+ }, viewerProps));
209
+ }
193
210
 
194
211
  // TODO: fix all of the item errors
195
212
 
@@ -266,7 +283,7 @@ export var ItemViewerBase = function ItemViewerBase(_ref) {
266
283
  fileState: _fileState,
267
284
  fileStateFlags: fileStateFlagsRef.current,
268
285
  traceContext: traceContext.current
269
- }, /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement(FormattedMessage, messages.try_downloading_file)), renderDownloadButton(_fileState, error));
286
+ }, /*#__PURE__*/React.createElement(Text, null, /*#__PURE__*/React.createElement(FormattedMessage, messages.try_downloading_file)), renderDownloadButton(_fileState, error));
270
287
  } else {
271
288
  return /*#__PURE__*/React.createElement(ErrorMessage, {
272
289
  fileId: isFileIdentifier(identifier) ? identifier.id : 'undefined',
package/dist/esm/list.js CHANGED
@@ -15,7 +15,8 @@ export var List = function List(_ref) {
15
15
  featureFlags = _ref.featureFlags,
16
16
  isSidebarVisible = _ref.isSidebarVisible,
17
17
  onNavigationChange = _ref.onNavigationChange,
18
- items = _ref.items;
18
+ items = _ref.items,
19
+ viewerOptions = _ref.viewerOptions;
19
20
  var _useState = useState(defaultSelectedItem),
20
21
  _useState2 = _slicedToArray(_useState, 2),
21
22
  selectedItem = _useState2[0],
@@ -48,7 +49,8 @@ export var List = function List(_ref) {
48
49
  onClose: onClose,
49
50
  previewCount: previewCount,
50
51
  contextId: contextId,
51
- featureFlags: featureFlags
52
+ featureFlags: featureFlags,
53
+ viewerOptions: viewerOptions
52
54
  }), /*#__PURE__*/React.createElement(Navigation, {
53
55
  items: items,
54
56
  selectedItem: selectedItem,
@@ -22,7 +22,8 @@ var MediaViewerComponent = function MediaViewerComponent(_ref) {
22
22
  innerRef = _ref.innerRef,
23
23
  _onClose = _ref.onClose,
24
24
  selectedItem = _ref.selectedItem,
25
- intl = _ref.intl;
25
+ intl = _ref.intl,
26
+ viewerOptions = _ref.viewerOptions;
26
27
  var _useState = useState(false),
27
28
  _useState2 = _slicedToArray(_useState, 2),
28
29
  isSidebarVisible = _useState2[0],
@@ -85,7 +86,8 @@ var MediaViewerComponent = function MediaViewerComponent(_ref) {
85
86
  },
86
87
  isSidebarVisible: isSidebarVisible,
87
88
  contextId: contextId,
88
- featureFlags: featureFlags
89
+ featureFlags: featureFlags,
90
+ viewerOptions: viewerOptions
89
91
  })), renderSidebar()));
90
92
  return intl ? content : /*#__PURE__*/React.createElement(IntlProvider, {
91
93
  locale: "en"
@@ -0,0 +1 @@
1
+ export {};
@@ -17,6 +17,7 @@ import { unzip, HTTPRangeReader } from 'unzipit';
17
17
  import { FormattedMessage } from 'react-intl-next';
18
18
  import { CustomMediaPlayer, messages } from '@atlaskit/media-ui';
19
19
  import { getLanguageType, isCodeViewerItem } from '@atlaskit/media-ui/codeViewer';
20
+ import { Text } from '@atlaskit/primitives';
20
21
  import { Outcome } from '../../domain';
21
22
  import { CustomVideoPlayerWrapper, AudioPlayer, CustomAudioPlayerWrapper, DefaultCoverWrapper, ListWrapper } from '../../styleWrappers';
22
23
  import AudioIcon from '@atlaskit/icon/core/migration/audio--media-services-audio';
@@ -92,7 +93,8 @@ export var ArchiveViewerBase = /*#__PURE__*/function (_BaseViewer) {
92
93
  case 0:
93
94
  _this.setState({
94
95
  content: Outcome.successful(_objectSpread(_objectSpread({}, _this.state.content.data), {}, {
95
- selectedArchiveEntry: undefined
96
+ selectedArchiveEntry: undefined,
97
+ hasLoadedEntries: false // displays a nice loading spinner for the content viewer
96
98
  }))
97
99
  });
98
100
  src = '';
@@ -106,7 +108,7 @@ export var ArchiveViewerBase = /*#__PURE__*/function (_BaseViewer) {
106
108
  _context2.next = 8;
107
109
  return rejectAfter(function () {
108
110
  return selectedArchiveEntry.blob();
109
- });
111
+ }, 10000);
110
112
  case 8:
111
113
  blob = _context2.sent;
112
114
  src = URL.createObjectURL(blob);
@@ -136,7 +138,8 @@ export var ArchiveViewerBase = /*#__PURE__*/function (_BaseViewer) {
136
138
  isDirectory: selectedArchiveEntry.isDirectory,
137
139
  error: undefined,
138
140
  codeViewerSrc: codeViewerSrc,
139
- isCodeMimeType: isCodeMimeType
141
+ isCodeMimeType: isCodeMimeType,
142
+ hasLoadedEntries: true
140
143
  }))
141
144
  });
142
145
  case 20:
@@ -238,7 +241,9 @@ export var ArchiveViewerBase = /*#__PURE__*/function (_BaseViewer) {
238
241
  }, {
239
242
  key: "renderArchiveItemViewer",
240
243
  value: function renderArchiveItemViewer(content) {
241
- var item = this.props.item;
244
+ var _this$props2 = this.props,
245
+ item = _this$props2.item,
246
+ viewerOptions = _this$props2.viewerOptions;
242
247
  var src = content.src,
243
248
  name = content.name,
244
249
  isDirectory = content.isDirectory,
@@ -250,9 +255,48 @@ export var ArchiveViewerBase = /*#__PURE__*/function (_BaseViewer) {
250
255
  return this.renderPreviewError(error, selectedArchiveEntry);
251
256
  }
252
257
  if (!isDirectory && selectedArchiveEntry) {
258
+ var _viewerOptions$custom;
253
259
  if (!name || !src) {
254
260
  return this.renderPreviewError(new ArchiveViewerError('archiveviewer-missing-name-src'), selectedArchiveEntry);
255
261
  }
262
+ var customRenderer = viewerOptions === null || viewerOptions === void 0 || (_viewerOptions$custom = viewerOptions.customRenderers) === null || _viewerOptions$custom === void 0 ? void 0 : _viewerOptions$custom.find(function (renderer) {
263
+ return renderer.shouldUseCustomRenderer({
264
+ fileItem: item,
265
+ archiveFileItem: {
266
+ name: name
267
+ }
268
+ });
269
+ });
270
+ if (customRenderer) {
271
+ return /*#__PURE__*/React.createElement(ArchiveItemViewerWrapper, null, customRenderer.renderContent({
272
+ fileItem: item,
273
+ archiveFileItem: {
274
+ name: name
275
+ },
276
+ getBinaryContent: function () {
277
+ var _getBinaryContent = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
278
+ return _regeneratorRuntime.wrap(function _callee4$(_context4) {
279
+ while (1) switch (_context4.prev = _context4.next) {
280
+ case 0:
281
+ _context4.next = 2;
282
+ return fetch(src);
283
+ case 2:
284
+ return _context4.abrupt("return", _context4.sent.blob());
285
+ case 3:
286
+ case "end":
287
+ return _context4.stop();
288
+ }
289
+ }, _callee4);
290
+ }));
291
+ function getBinaryContent() {
292
+ return _getBinaryContent.apply(this, arguments);
293
+ }
294
+ return getBinaryContent;
295
+ }(),
296
+ onLoad: this.onViewerLoad(selectedArchiveEntry),
297
+ onError: this.onViewerError('archiveviewer-customrenderer-onerror', selectedArchiveEntry)
298
+ }));
299
+ }
256
300
  var mediaType = getMediaTypeFromFilename(name);
257
301
  if (isCodeMimeType) {
258
302
  // Same code viewer logic as in Item-Viewer.tsx
@@ -324,16 +368,16 @@ export var ArchiveViewerBase = /*#__PURE__*/function (_BaseViewer) {
324
368
  }, {
325
369
  key: "renderPreviewError",
326
370
  value: function renderPreviewError(error, entry) {
327
- var _this$props2 = this.props,
328
- item = _this$props2.item,
329
- createAnalyticsEvent = _this$props2.createAnalyticsEvent;
371
+ var _this$props3 = this.props,
372
+ item = _this$props3.item,
373
+ createAnalyticsEvent = _this$props3.createAnalyticsEvent;
330
374
  fireAnalytics(createZipEntryLoadFailedEvent(item, error, entry), createAnalyticsEvent);
331
375
  return /*#__PURE__*/React.createElement(ListWrapper, null, /*#__PURE__*/React.createElement(ErrorMessage, {
332
376
  fileId: item.id,
333
377
  fileState: item,
334
378
  error: error,
335
379
  supressAnalytics: true
336
- }, /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement(FormattedMessage, messages.try_downloading_file))));
380
+ }, /*#__PURE__*/React.createElement(Text, null, /*#__PURE__*/React.createElement(FormattedMessage, messages.try_downloading_file))));
337
381
  }
338
382
  }]);
339
383
  return ArchiveViewerBase;
@@ -0,0 +1,46 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
+ import { MediaViewerError } from '../../errors';
3
+ import { useCallback, useEffect, useState } from 'react';
4
+ import React from 'react';
5
+ import { Spinner } from '../../loading';
6
+ export var CustomViewer = function CustomViewer(_ref) {
7
+ var mediaClient = _ref.mediaClient,
8
+ item = _ref.item,
9
+ customRendererConfig = _ref.customRendererConfig,
10
+ onSuccess = _ref.onSuccess,
11
+ onError = _ref.onError;
12
+ var _useState = useState(),
13
+ _useState2 = _slicedToArray(_useState, 2),
14
+ getBinaryContent = _useState2[0],
15
+ setGetBinaryContent = _useState2[1];
16
+ useEffect(function () {
17
+ setGetBinaryContent(undefined);
18
+ var abortController = new AbortController();
19
+ // This sets the 'getBinaryContent' to an async function that fetches the binary content of the file
20
+ // The 'getBinaryContent' function has to be updated when the item changes
21
+ // This approach handles aborting in-progress request outside of the custom-renderer concern
22
+ if (item.status === 'processed' || item.status === 'failed-processing') {
23
+ setGetBinaryContent(function () {
24
+ return function () {
25
+ return mediaClient.mediaStore.getFileBinary(item.id, undefined, abortController);
26
+ };
27
+ });
28
+ }
29
+ return function () {
30
+ return abortController.abort();
31
+ };
32
+ }, [item, mediaClient]);
33
+ var onLoadFailed = useCallback(function (error) {
34
+ var mediaError = new MediaViewerError('custom-viewer-error', error);
35
+ onError(mediaError, item);
36
+ }, [item, onError]);
37
+ if (!getBinaryContent) {
38
+ return /*#__PURE__*/React.createElement(Spinner, null);
39
+ }
40
+ return /*#__PURE__*/React.createElement(React.Fragment, null, customRendererConfig.renderContent({
41
+ fileItem: item,
42
+ getBinaryContent: getBinaryContent,
43
+ onLoad: onSuccess,
44
+ onError: onLoadFailed
45
+ }));
46
+ };
@@ -77,6 +77,8 @@ export var VideoViewer = /*#__PURE__*/function (_BaseViewer) {
77
77
  previewCount = _this$props2.previewCount;
78
78
  var useCustomVideoPlayer = !isIE();
79
79
  var isAutoPlay = previewCount === 0;
80
+ var hdAvailable = isHDAvailable(item);
81
+ var hdActiveOverride = fg('platform_media_disable_video_640p_artifact_usage') ? hdAvailable : isHDActive;
80
82
  return useCustomVideoPlayer ? /*#__PURE__*/React.createElement(CustomVideoPlayerWrapper, {
81
83
  "data-testid": "media-viewer-video-content"
82
84
  }, /*#__PURE__*/React.createElement(CustomMediaPlayer, {
@@ -86,8 +88,8 @@ export var VideoViewer = /*#__PURE__*/function (_BaseViewer) {
86
88
  showControls: showControls,
87
89
  src: content,
88
90
  fileId: item.id,
89
- isHDActive: isHDActive,
90
- isHDAvailable: isHDAvailable(item),
91
+ isHDActive: hdActiveOverride,
92
+ isHDAvailable: hdAvailable,
91
93
  isShortcutEnabled: true,
92
94
  onFirstPlay: this.onFirstPlay,
93
95
  onError: this.onError,
@@ -110,6 +112,8 @@ export var VideoViewer = /*#__PURE__*/function (_BaseViewer) {
110
112
  item,
111
113
  collectionName,
112
114
  contentUrl,
115
+ hdAvailable,
116
+ hdActiveOverride,
113
117
  preferHd,
114
118
  _args = arguments;
115
119
  return _regeneratorRuntime.wrap(function _callee$(_context) {
@@ -119,52 +123,54 @@ export var VideoViewer = /*#__PURE__*/function (_BaseViewer) {
119
123
  _this$props3 = this.props, mediaClient = _this$props3.mediaClient, item = _this$props3.item, collectionName = _this$props3.collectionName;
120
124
  _context.prev = 2;
121
125
  if (!(item.status === 'processed')) {
122
- _context.next = 12;
126
+ _context.next = 14;
123
127
  break;
124
128
  }
125
- preferHd = isHDActive && isHDAvailable(item);
126
- _context.next = 7;
129
+ hdAvailable = isHDAvailable(item);
130
+ hdActiveOverride = fg('platform_media_disable_video_640p_artifact_usage') ? hdAvailable : isHDActive;
131
+ preferHd = hdActiveOverride && hdAvailable;
132
+ _context.next = 9;
127
133
  return mediaClient.file.getArtifactURL(item.artifacts, preferHd ? hdArtifact : sdArtifact, collectionName);
128
- case 7:
134
+ case 9:
129
135
  contentUrl = _context.sent;
130
136
  if (contentUrl) {
131
- _context.next = 10;
137
+ _context.next = 12;
132
138
  break;
133
139
  }
134
140
  throw new MediaViewerError("videoviewer-missing-artefact");
135
- case 10:
136
- _context.next = 18;
137
- break;
138
141
  case 12:
139
- _context.next = 14;
140
- return getObjectUrlFromFileState(item);
142
+ _context.next = 20;
143
+ break;
141
144
  case 14:
145
+ _context.next = 16;
146
+ return getObjectUrlFromFileState(item);
147
+ case 16:
142
148
  contentUrl = _context.sent;
143
149
  if (contentUrl) {
144
- _context.next = 18;
150
+ _context.next = 20;
145
151
  break;
146
152
  }
147
153
  this.setState({
148
154
  content: Outcome.pending()
149
155
  });
150
156
  return _context.abrupt("return");
151
- case 18:
157
+ case 20:
152
158
  this.setState({
153
159
  content: Outcome.successful(contentUrl)
154
160
  });
155
- _context.next = 24;
161
+ _context.next = 26;
156
162
  break;
157
- case 21:
158
- _context.prev = 21;
163
+ case 23:
164
+ _context.prev = 23;
159
165
  _context.t0 = _context["catch"](2);
160
166
  this.setState({
161
167
  content: Outcome.failed(new MediaViewerError('videoviewer-fetch-url', _context.t0 instanceof Error ? _context.t0 : undefined))
162
168
  });
163
- case 24:
169
+ case 26:
164
170
  case "end":
165
171
  return _context.stop();
166
172
  }
167
- }, _callee, this, [[2, 21]]);
173
+ }, _callee, this, [[2, 23]]);
168
174
  }));
169
175
  function init() {
170
176
  return _init.apply(this, arguments);
@@ -1,5 +1,5 @@
1
1
  /// <reference types="react" />
2
2
  import { type MediaViewerProps } from './types';
3
3
  import type { MediaViewerWithMediaClientConfigProps } from './types';
4
- export declare const MediaViewerBase: ({ featureFlags, onClose, selectedItem, collectionName, items, extensions, contextId, }: MediaViewerProps) => JSX.Element;
4
+ export declare const MediaViewerBase: ({ featureFlags, onClose, selectedItem, collectionName, items, extensions, contextId, viewerOptions, }: MediaViewerProps) => JSX.Element;
5
5
  export declare const MediaViewerWithMediaClient: (props: MediaViewerWithMediaClientConfigProps) => JSX.Element;
@@ -2,6 +2,7 @@ import { type Identifier, type MediaClient } from '@atlaskit/media-client';
2
2
  import type { WithMediaClientConfigProps } from '@atlaskit/media-client-react';
3
3
  import { type MediaFeatureFlags } from '@atlaskit/media-common';
4
4
  import { type ReactNode } from 'react';
5
+ import { type ViewerOptionsProps } from '../viewerOptions';
5
6
  export type FileStateFlags = {
6
7
  wasStatusProcessing: boolean;
7
8
  wasStatusUploading: boolean;
@@ -24,6 +25,7 @@ export interface MediaViewerProps {
24
25
  readonly featureFlags?: MediaFeatureFlags;
25
26
  readonly extensions?: MediaViewerExtensions;
26
27
  readonly contextId?: string;
28
+ readonly viewerOptions?: ViewerOptionsProps;
27
29
  }
28
30
  export type MediaMessage = {
29
31
  source: 'media';
@@ -13,8 +13,8 @@ export declare class ArchiveViewerError extends MediaViewerError {
13
13
  constructor(primaryReason: ArchiveViewerErrorReason, secondaryError?: Error | undefined, zipEntry?: ZipEntry | undefined);
14
14
  }
15
15
  export declare function isArchiveViewerError(err: Error): err is ArchiveViewerError;
16
- export type MediaViewerErrorReason = 'collection-fetch-metadata' | 'header-fetch-metadata' | 'itemviewer-onerror' | 'itemviewer-fetch-metadata' | 'itemviewer-file-error-status' | 'itemviewer-file-failed-processing-status' | 'imageviewer-external-onerror' | 'imageviewer-fetch-url' | 'imageviewer-src-onerror' | 'audioviewer-fetch-url' | 'audioviewer-missing-artefact' | 'audioviewer-playback' | 'videoviewer-fetch-url' | 'videoviewer-missing-artefact' | 'videoviewer-playback' | 'docviewer-fetch-url' | 'docviewer-fetch-pdf' | 'codeviewer-fetch-src' | 'codeviewer-load-src' | 'codeviewer-file-size-exceeds' | 'codeviewer-parse-email' | 'svg-img-error' | 'svg-binary-fetch' | 'svg-unknown-error' | 'unsupported';
17
- export type ArchiveViewerErrorReason = 'archiveviewer-bundle-loader' | 'archiveviewer-read-binary' | 'archiveviewer-create-url' | 'archiveviewer-imageviewer-onerror' | 'archiveviewer-videoviewer-onerror' | 'archiveviewer-audioviewer-onerror' | 'archiveviewer-docviewer-onerror' | 'archiveviewer-codeviewer-onerror' | 'archiveviewer-codeviewer-file-size-exceeds' | 'archiveviewer-missing-name-src' | 'archiveviewer-unsupported' | 'archiveviewer-encrypted-entry';
16
+ export type MediaViewerErrorReason = 'collection-fetch-metadata' | 'header-fetch-metadata' | 'itemviewer-onerror' | 'itemviewer-fetch-metadata' | 'itemviewer-file-error-status' | 'itemviewer-file-failed-processing-status' | 'imageviewer-external-onerror' | 'imageviewer-fetch-url' | 'imageviewer-src-onerror' | 'audioviewer-fetch-url' | 'audioviewer-missing-artefact' | 'audioviewer-playback' | 'videoviewer-fetch-url' | 'videoviewer-missing-artefact' | 'videoviewer-playback' | 'docviewer-fetch-url' | 'docviewer-fetch-pdf' | 'codeviewer-fetch-src' | 'codeviewer-load-src' | 'codeviewer-file-size-exceeds' | 'codeviewer-parse-email' | 'svg-img-error' | 'svg-binary-fetch' | 'svg-unknown-error' | 'unsupported' | 'custom-viewer-error';
17
+ export type ArchiveViewerErrorReason = 'archiveviewer-bundle-loader' | 'archiveviewer-read-binary' | 'archiveviewer-create-url' | 'archiveviewer-imageviewer-onerror' | 'archiveviewer-videoviewer-onerror' | 'archiveviewer-audioviewer-onerror' | 'archiveviewer-docviewer-onerror' | 'archiveviewer-codeviewer-onerror' | 'archiveviewer-codeviewer-file-size-exceeds' | 'archiveviewer-missing-name-src' | 'archiveviewer-unsupported' | 'archiveviewer-encrypted-entry' | 'archiveviewer-customrenderer-onerror';
18
18
  export type PrimaryErrorReason = MediaViewerErrorReason | ArchiveViewerErrorReason;
19
19
  export type SecondaryErrorReason = MediaClientErrorReason | 'unknown' | 'nativeError' | undefined;
20
20
  export declare function getPrimaryErrorReason(error: MediaViewerError): PrimaryErrorReason;
@@ -1,2 +1,3 @@
1
1
  export { default as MediaViewer } from './components/media-viewer-loader';
2
2
  export type { MediaViewerExtensions, MediaViewerExtensionsActions, MediaViewerProps, MediaMessage, } from './components/types';
3
+ export type { ViewerOptionsProps, CustomRendererConfig, CustomRendererStateProps, CustomRendererProps, ArchiveFileItem, } from './viewerOptions';
@@ -5,23 +5,26 @@ import { Outcome } from './domain';
5
5
  import { MediaViewerError } from './errors';
6
6
  import { type WithAnalyticsEventsProps } from '@atlaskit/analytics-next';
7
7
  import { type MediaFeatureFlags } from '@atlaskit/media-common';
8
+ import { type ViewerOptionsProps } from './viewerOptions';
8
9
  export type Props = Readonly<{
9
10
  identifier: Identifier;
10
11
  onClose?: () => void;
11
12
  previewCount: number;
12
13
  contextId?: string;
13
14
  featureFlags?: MediaFeatureFlags;
15
+ viewerOptions?: ViewerOptionsProps;
14
16
  }> & WithAnalyticsEventsProps & WithShowControlMethodProp;
15
17
  export type FileItem = FileState | 'external-image';
16
18
  export type State = Outcome<FileItem, MediaViewerError>;
17
19
  export declare const isExternalImageItem: (fileItem: FileItem) => fileItem is "external-image";
18
20
  export declare const isFileStateItem: (fileItem: FileItem) => fileItem is FileState;
19
21
  export declare const MAX_FILE_SIZE_SUPPORTED_BY_CODEVIEWER: number;
20
- export declare const ItemViewerBase: ({ identifier, showControls, onClose, previewCount, contextId, createAnalyticsEvent, }: Props) => React.ReactElement | null;
22
+ export declare const ItemViewerBase: ({ identifier, showControls, onClose, previewCount, contextId, createAnalyticsEvent, viewerOptions, }: Props) => React.ReactElement | null;
21
23
  export declare const ItemViewer: React.ForwardRefExoticComponent<Omit<Readonly<{
22
24
  identifier: Identifier;
23
25
  onClose?: (() => void) | undefined;
24
26
  previewCount: number;
25
27
  contextId?: string | undefined;
26
28
  featureFlags?: MediaFeatureFlags | undefined;
29
+ viewerOptions?: ViewerOptionsProps | undefined;
27
30
  }> & WithShowControlMethodProp, keyof WithAnalyticsEventsProps> & React.RefAttributes<any>>;