@atlaskit/media-card 76.1.2 → 76.2.1

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 (77) hide show
  1. package/CHANGELOG.md +20 -1
  2. package/dist/cjs/card/actions.js +2 -2
  3. package/dist/cjs/card/card.js +3 -3
  4. package/dist/cjs/card/cardLoader.js +2 -5
  5. package/dist/cjs/card/cardSwitcher.js +12 -0
  6. package/dist/cjs/card/cardView.js +3 -4
  7. package/dist/cjs/card/getCardPreview/cache.js +3 -0
  8. package/dist/cjs/card/getCardPreview/index.js +2 -2
  9. package/dist/cjs/card/index.js +2 -2
  10. package/dist/cjs/card/media-card-analytics-error-boundary.js +3 -3
  11. package/dist/cjs/card/ui/progressBar/styledBar.js +1 -0
  12. package/dist/cjs/card/ui/titleBox/titleBoxComponents.js +1 -0
  13. package/dist/cjs/card/v2/cardV2.js +1054 -0
  14. package/dist/cjs/card/v2/cardV2Loader.js +95 -0
  15. package/dist/cjs/errors.js +89 -31
  16. package/dist/cjs/inline/loader.js +1 -1
  17. package/dist/cjs/inline/mediaInlineAnalyticsErrorBoundary.js +4 -4
  18. package/dist/cjs/inline/mediaInlineCardAnalytics.js +2 -2
  19. package/dist/cjs/utils/analytics.js +18 -8
  20. package/dist/cjs/utils/objectURLCache.js +5 -0
  21. package/dist/cjs/utils/ufoExperiences.js +3 -3
  22. package/dist/es2019/card/card.js +1 -1
  23. package/dist/es2019/card/cardLoader.js +2 -5
  24. package/dist/es2019/card/cardSwitcher.js +4 -0
  25. package/dist/es2019/card/cardView.js +1 -2
  26. package/dist/es2019/card/getCardPreview/cache.js +3 -0
  27. package/dist/es2019/card/index.js +1 -1
  28. package/dist/es2019/card/media-card-analytics-error-boundary.js +1 -1
  29. package/dist/es2019/card/ui/progressBar/styledBar.js +1 -0
  30. package/dist/es2019/card/ui/titleBox/titleBoxComponents.js +1 -0
  31. package/dist/es2019/card/v2/cardV2.js +1031 -0
  32. package/dist/es2019/card/v2/cardV2Loader.js +58 -0
  33. package/dist/es2019/errors.js +45 -0
  34. package/dist/es2019/inline/loader.js +1 -1
  35. package/dist/es2019/inline/mediaInlineAnalyticsErrorBoundary.js +2 -2
  36. package/dist/es2019/utils/analytics.js +17 -7
  37. package/dist/es2019/utils/objectURLCache.js +3 -0
  38. package/dist/es2019/utils/ufoExperiences.js +1 -1
  39. package/dist/esm/card/actions.js +2 -2
  40. package/dist/esm/card/card.js +3 -3
  41. package/dist/esm/card/cardLoader.js +2 -5
  42. package/dist/esm/card/cardSwitcher.js +4 -0
  43. package/dist/esm/card/cardView.js +3 -4
  44. package/dist/esm/card/getCardPreview/cache.js +3 -0
  45. package/dist/esm/card/getCardPreview/index.js +2 -2
  46. package/dist/esm/card/index.js +1 -1
  47. package/dist/esm/card/media-card-analytics-error-boundary.js +3 -3
  48. package/dist/esm/card/ui/progressBar/styledBar.js +1 -0
  49. package/dist/esm/card/ui/titleBox/titleBoxComponents.js +1 -0
  50. package/dist/esm/card/v2/cardV2.js +1043 -0
  51. package/dist/esm/card/v2/cardV2Loader.js +78 -0
  52. package/dist/esm/errors.js +83 -30
  53. package/dist/esm/inline/loader.js +1 -1
  54. package/dist/esm/inline/mediaInlineAnalyticsErrorBoundary.js +4 -4
  55. package/dist/esm/inline/mediaInlineCardAnalytics.js +2 -2
  56. package/dist/esm/utils/analytics.js +19 -9
  57. package/dist/esm/utils/objectURLCache.js +5 -0
  58. package/dist/esm/utils/ufoExperiences.js +3 -3
  59. package/dist/types/card/cardSwitcher.d.ts +3 -0
  60. package/dist/types/card/getCardPreview/cache.d.ts +2 -0
  61. package/dist/types/card/index.d.ts +1 -1
  62. package/dist/types/card/v2/cardV2.d.ts +62 -0
  63. package/dist/types/card/v2/cardV2Loader.d.ts +4 -0
  64. package/dist/types/errors.d.ts +12 -0
  65. package/dist/types/types.d.ts +1 -0
  66. package/dist/types/utils/objectURLCache.d.ts +1 -0
  67. package/dist/types-ts4.5/card/cardSwitcher.d.ts +3 -0
  68. package/dist/types-ts4.5/card/getCardPreview/cache.d.ts +2 -0
  69. package/dist/types-ts4.5/card/index.d.ts +1 -1
  70. package/dist/types-ts4.5/card/v2/cardV2.d.ts +62 -0
  71. package/dist/types-ts4.5/card/v2/cardV2Loader.d.ts +4 -0
  72. package/dist/types-ts4.5/errors.d.ts +12 -0
  73. package/dist/types-ts4.5/types.d.ts +1 -0
  74. package/dist/types-ts4.5/utils/objectURLCache.d.ts +1 -0
  75. package/package.json +16 -7
  76. package/report.api.md +4 -1
  77. package/tmp/api-report-tmp.d.ts +4 -1
@@ -0,0 +1,1031 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
3
+ import React, { Component, Suspense, useEffect } from 'react';
4
+ import ReactDOM from 'react-dom';
5
+ import { withAnalyticsEvents } from '@atlaskit/analytics-next';
6
+ import { withMediaAnalyticsContext } from '@atlaskit/media-common';
7
+ import DownloadIcon from '@atlaskit/icon/glyph/download';
8
+ import { getRandomHex } from '@atlaskit/media-common';
9
+ import { globalMediaEventEmitter, isDifferentIdentifier, isFileIdentifier, RECENTS_COLLECTION, isImageRepresentationReady, isExternalImageIdentifier, imageResizeModeToFileImageMode } from '@atlaskit/media-client';
10
+ import { MediaViewer } from '@atlaskit/media-viewer';
11
+ import { injectIntl, IntlProvider } from 'react-intl-next';
12
+ import { CardView } from '../cardView';
13
+ import { ViewportDetector } from '../../utils/viewportDetector';
14
+ import { videoIsPlayable } from '../../utils/videoIsPlayable';
15
+ import { getRequestedDimensions } from '../../utils/getDataURIDimension';
16
+ import { getCardPreview, getCardPreviewFromCache, removeCardPreviewFromCache, getFilePreviewFromFileState, shouldResolvePreview, getSSRCardPreview, isLocalPreview, isSSRPreview, isSSRClientPreview, isSSRDataPreview, fetchAndCacheRemotePreview } from '../getCardPreview';
17
+ import { getFileDetails } from '../../utils/metadata';
18
+ import { InlinePlayerLazy } from '../inlinePlayerLazy';
19
+ import { getFileAttributes, extractErrorInfo } from '../../utils/analytics';
20
+ import { isLocalPreviewError, MediaCardError, MediaFileStateError, ensureMediaCardError, ImageLoadError } from '../../errors';
21
+ import { fireOperationalEvent, fireCommencedEvent, fireCopiedEvent, fireScreenEvent, fireNonCriticalErrorEvent } from '../cardAnalytics';
22
+ import getDocument from '../../utils/document';
23
+ import { StoreSSRDataScript, getSSRData } from '../../utils/globalScope';
24
+ import { getCardStateFromFileState, createStateUpdater } from '../cardState';
25
+ import { isBigger } from '../../utils/dimensionComparer';
26
+ import { getMediaCardCursor } from '../../utils/getMediaCardCursor';
27
+ import { completeUfoExperience, startUfoExperience } from '../../utils/ufoExperiences';
28
+ import { generateUniqueId } from '../../utils/generateUniqueId';
29
+ import { useFileState } from '@atlaskit/media-client-react';
30
+ const packageName = "@atlaskit/media-card";
31
+ const packageVersion = "76.2.1";
32
+ export class CardV2Base extends Component {
33
+ constructor(props) {
34
+ super(props);
35
+ // An internalOccurrenceKey is a randomly generated value to differentiate various instances
36
+ // of Cards regardless of whether it shares the same file (either internal or external)
37
+ _defineProperty(this, "internalOccurrenceKey", generateUniqueId());
38
+ _defineProperty(this, "hasBeenMounted", false);
39
+ _defineProperty(this, "fileStateFlags", {
40
+ wasStatusUploading: false,
41
+ wasStatusProcessing: false
42
+ });
43
+ _defineProperty(this, "ssrReliability", {
44
+ server: {
45
+ status: 'unknown'
46
+ },
47
+ client: {
48
+ status: 'unknown'
49
+ }
50
+ });
51
+ // We initialise timeElapsedTillCommenced
52
+ // to avoid extra branching on a possibly undefined value.
53
+ _defineProperty(this, "timeElapsedTillCommenced", performance.now());
54
+ // Generate unique traceId for file
55
+ _defineProperty(this, "traceContext", {
56
+ traceId: getRandomHex(8)
57
+ });
58
+ _defineProperty(this, "getImageURLParams", ({
59
+ collectionName: collection
60
+ }) => ({
61
+ collection,
62
+ mode: imageResizeModeToFileImageMode(this.props.resizeMode),
63
+ ...this.requestedDimensions,
64
+ allowAnimated: true
65
+ }));
66
+ _defineProperty(this, "getMediaBlobUrlAttrs", (identifier, fileState) => {
67
+ const {
68
+ id,
69
+ collectionName: collection
70
+ } = identifier;
71
+ const {
72
+ originalDimensions,
73
+ contextId,
74
+ alt
75
+ } = this.props;
76
+ const {
77
+ mimeType,
78
+ name,
79
+ size
80
+ } = getFileDetails(identifier, fileState);
81
+ return contextId ? {
82
+ id,
83
+ collection,
84
+ contextId,
85
+ mimeType,
86
+ name,
87
+ size,
88
+ ...(originalDimensions || this.requestedDimensions),
89
+ alt
90
+ } : undefined;
91
+ });
92
+ _defineProperty(this, "getCardPreviewParams", (identifier, fileState) => {
93
+ const {
94
+ isBannedLocalPreview
95
+ } = this.state;
96
+ const {
97
+ id
98
+ } = identifier;
99
+ const {
100
+ dimensions = {},
101
+ mediaClient,
102
+ createAnalyticsEvent
103
+ } = this.props;
104
+ return {
105
+ mediaClient,
106
+ id,
107
+ dimensions,
108
+ onLocalPreviewError: this.fireNonCriticalErrorEvent,
109
+ filePreview: isBannedLocalPreview ? undefined : getFilePreviewFromFileState(fileState),
110
+ isRemotePreviewReady: isImageRepresentationReady(fileState),
111
+ imageUrlParams: this.getImageURLParams(identifier),
112
+ mediaBlobUrlAttrs: this.getMediaBlobUrlAttrs(identifier, fileState),
113
+ createAnalyticsEvent,
114
+ featureFlags: this.props.featureFlags,
115
+ traceContext: this.traceContext
116
+ };
117
+ });
118
+ _defineProperty(this, "setCacheSSRPreview", identifier => {
119
+ this.fetchAndCacheRemotePreview(identifier).catch(() => {
120
+ // No need to log this error.
121
+ // If preview fails, it will be refetched later
122
+ //TODO: test this catch
123
+ // https://product-fabric.atlassian.net/browse/MEX-1071
124
+ });
125
+ });
126
+ _defineProperty(this, "refetchSSRPreview", async identifier => {
127
+ try {
128
+ const cardPreview = await this.fetchAndCacheRemotePreview(identifier);
129
+ this.safeSetState({
130
+ cardPreview
131
+ });
132
+ } catch (e) {
133
+ const wrappedError = ensureMediaCardError('remote-preview-fetch-ssr', e, true);
134
+ this.fireNonCriticalErrorEvent(wrappedError);
135
+ }
136
+ });
137
+ _defineProperty(this, "resolveUpfrontPreview", async identifier => {
138
+ const requestedDimensions = {
139
+ ...this.props.dimensions
140
+ };
141
+ try {
142
+ const cardPreview = await this.fetchAndCacheRemotePreview(identifier);
143
+ const {
144
+ dimensions: currentDimensions
145
+ } = this.props;
146
+ const areValidRequestedDimensions = !isBigger(requestedDimensions, currentDimensions);
147
+
148
+ // If there are new and bigger dimensions in the props, and the upfront preview is still resolving,
149
+ // the fetched preview is no longer valid, and thus, we dismiss it and set the flag wasResolvedUpfrontPreview = true
150
+ // to trigger a normal preview fetch.
151
+ if (areValidRequestedDimensions) {
152
+ this.safeSetState({
153
+ cardPreview,
154
+ wasResolvedUpfrontPreview: true
155
+ });
156
+ } else {
157
+ this.safeSetState({
158
+ wasResolvedUpfrontPreview: true
159
+ });
160
+ }
161
+ } catch (e) {
162
+ this.safeSetState({
163
+ wasResolvedUpfrontPreview: true
164
+ });
165
+ // NO need to log error. If this call fails, a refetch will happen after
166
+ }
167
+ });
168
+ _defineProperty(this, "fetchAndCacheRemotePreview", identifier => {
169
+ const {
170
+ mediaClient,
171
+ dimensions = {}
172
+ } = this.props;
173
+ return fetchAndCacheRemotePreview(mediaClient, identifier.id, dimensions, this.getImageURLParams(identifier), this.getMediaBlobUrlAttrs(identifier));
174
+ });
175
+ _defineProperty(this, "resolvePreview", async (identifier, fileState) => {
176
+ try {
177
+ const params = this.getCardPreviewParams(identifier, fileState);
178
+ const cardPreview = await getCardPreview(params);
179
+ this.safeSetState({
180
+ cardPreview
181
+ });
182
+ } catch (e) {
183
+ const wrappedError = ensureMediaCardError('preview-fetch', e);
184
+ // If remote preview fails, we set status 'error'
185
+ // If local preview fails (i.e, no remote preview available),
186
+ // we can stay in the same status until there is a remote preview available
187
+ // If it's any other error we set status 'error'
188
+ if (isLocalPreviewError(wrappedError)) {
189
+ // This error should already been logged inside the getCardPreview. No need to log it here.
190
+ this.safeSetState({
191
+ isBannedLocalPreview: true
192
+ });
193
+ } else {
194
+ this.safeSetState({
195
+ status: 'error',
196
+ error: wrappedError
197
+ });
198
+ }
199
+ }
200
+ });
201
+ _defineProperty(this, "subscribeFileState", fileState => {
202
+ const {
203
+ isBannedLocalPreview
204
+ } = this.state;
205
+ if (fileState.status !== 'error') {
206
+ const {
207
+ featureFlags
208
+ } = this.props;
209
+ const newState = getCardStateFromFileState(fileState, isBannedLocalPreview, featureFlags);
210
+ this.safeSetState(newState);
211
+ } else {
212
+ const e = new MediaFileStateError(fileState.id, fileState.reason, fileState.message, fileState.details);
213
+ const errorReason = this.state.status === 'uploading' ? 'upload' : 'metadata-fetch';
214
+ const error = new MediaCardError(errorReason, e);
215
+ this.safeSetState({
216
+ error,
217
+ status: 'error'
218
+ });
219
+ }
220
+ });
221
+ _defineProperty(this, "getPerformanceAttributes", () => {
222
+ const {
223
+ timeElapsedTillCommenced
224
+ } = this;
225
+ const timeElapsedTillEvent = performance.now();
226
+ const durationSinceCommenced = timeElapsedTillCommenced && timeElapsedTillEvent - timeElapsedTillCommenced;
227
+ return {
228
+ overall: {
229
+ durationSincePageStart: timeElapsedTillEvent,
230
+ durationSinceCommenced
231
+ }
232
+ };
233
+ });
234
+ _defineProperty(this, "logSSRImageError", cardPreview => {
235
+ if (cardPreview) {
236
+ const failedSSRObject = {
237
+ status: 'fail',
238
+ ...extractErrorInfo(new ImageLoadError(cardPreview.source))
239
+ };
240
+ if (isSSRClientPreview(cardPreview)) {
241
+ this.ssrReliability.client = failedSSRObject;
242
+ }
243
+
244
+ /*
245
+ If the cardPreview failed and it comes from server (global scope / ssrData), it means that we have reused it in client and the error counts for both: server & client.
246
+ */
247
+
248
+ if (isSSRDataPreview(cardPreview)) {
249
+ this.ssrReliability.server = failedSSRObject;
250
+ this.ssrReliability.client = failedSSRObject;
251
+ }
252
+ }
253
+ });
254
+ _defineProperty(this, "onImageError", cardPreview => {
255
+ this.logSSRImageError(cardPreview);
256
+ const {
257
+ cardPreview: currentPreview
258
+ } = this.state;
259
+ // If the dataURI has been replaced, we can dismiss this error
260
+ if ((cardPreview === null || cardPreview === void 0 ? void 0 : cardPreview.dataURI) !== (currentPreview === null || currentPreview === void 0 ? void 0 : currentPreview.dataURI)) {
261
+ return;
262
+ }
263
+ const error = new ImageLoadError(cardPreview === null || cardPreview === void 0 ? void 0 : cardPreview.source);
264
+ const isLocal = cardPreview && isLocalPreview(cardPreview);
265
+ const isSSR = cardPreview && (isSSRClientPreview(cardPreview) || isSSRDataPreview(cardPreview));
266
+ if (isLocal || isSSR) {
267
+ const updateState = {
268
+ cardPreview: undefined
269
+ };
270
+ if (isLocal) {
271
+ updateState.isBannedLocalPreview = true;
272
+ this.fireNonCriticalErrorEvent(error);
273
+ }
274
+ const {
275
+ identifier,
276
+ resizeMode
277
+ } = this.props;
278
+ const fileImageMode = imageResizeModeToFileImageMode(resizeMode);
279
+ isFileIdentifier(identifier) && removeCardPreviewFromCache(identifier.id, fileImageMode);
280
+ this.safeSetState(updateState);
281
+ } else {
282
+ this.safeSetState({
283
+ status: 'error',
284
+ error
285
+ });
286
+ }
287
+ });
288
+ _defineProperty(this, "onImageLoad", cardPreview => {
289
+ if (cardPreview) {
290
+ if (isSSRClientPreview(cardPreview) && this.ssrReliability.client.status === 'unknown') {
291
+ this.ssrReliability.client = {
292
+ status: 'success'
293
+ };
294
+ }
295
+
296
+ /*
297
+ If the image loads successfully and it comes from server (global scope / ssrData), it means that we have reused it in client and the success counts for both: server & client.
298
+ */
299
+
300
+ if (isSSRDataPreview(cardPreview) && this.ssrReliability.server.status === 'unknown') {
301
+ this.ssrReliability.server = {
302
+ status: 'success'
303
+ };
304
+ this.ssrReliability.client = {
305
+ status: 'success'
306
+ };
307
+ }
308
+ }
309
+ const {
310
+ cardPreview: currentPreview
311
+ } = this.state;
312
+ // If the dataURI has been replaced, we can dismiss this callback
313
+ if ((cardPreview === null || cardPreview === void 0 ? void 0 : cardPreview.dataURI) !== (currentPreview === null || currentPreview === void 0 ? void 0 : currentPreview.dataURI)) {
314
+ return;
315
+ }
316
+ this.safeSetState({
317
+ previewDidRender: true
318
+ });
319
+ });
320
+ _defineProperty(this, "fireCopiedEvent", () => {
321
+ const {
322
+ createAnalyticsEvent
323
+ } = this.props;
324
+ const {
325
+ cardRef
326
+ } = this.state;
327
+ cardRef && createAnalyticsEvent && fireCopiedEvent(createAnalyticsEvent, this.metadata.id, cardRef);
328
+ });
329
+ _defineProperty(this, "fireScreenEvent", () => {
330
+ const {
331
+ createAnalyticsEvent
332
+ } = this.props;
333
+ createAnalyticsEvent && fireScreenEvent(createAnalyticsEvent, this.fileAttributes);
334
+ });
335
+ _defineProperty(this, "fireNonCriticalErrorEvent", error => {
336
+ const {
337
+ createAnalyticsEvent
338
+ } = this.props;
339
+ const {
340
+ fileState
341
+ } = this.state;
342
+ createAnalyticsEvent && fireNonCriticalErrorEvent(createAnalyticsEvent, this.state.status, this.fileAttributes, this.ssrReliability, error, this.traceContext, fileState === null || fileState === void 0 ? void 0 : fileState.metadataTraceContext);
343
+ });
344
+ _defineProperty(this, "safeSetState", newState => {
345
+ if (this.hasBeenMounted) {
346
+ /**
347
+ * createStateUpdater helper returns a callback to be passed to setState.
348
+ * It decides wether to update the 'status' depending on the current state vs the input state.
349
+ * From docs: "Both state and props received by the updater function are guaranteed to be up-to-date."
350
+ * If the input state brings an error and it won't be updating the state, the error will be logged as non-critical inside the helper.
351
+ * If the error persists int the state, it means it is a critical error and should be logged as a failed event for Card
352
+ */
353
+ this.setState(createStateUpdater(newState, this.fireNonCriticalErrorEvent));
354
+ }
355
+ });
356
+ _defineProperty(this, "onCardViewClick", (event, analyticsEvent) => {
357
+ const {
358
+ identifier,
359
+ useInlinePlayer,
360
+ shouldOpenMediaViewer
361
+ } = this.props;
362
+ const {
363
+ cardPreview
364
+ } = this.state;
365
+ const {
366
+ metadata
367
+ } = this;
368
+ this.onClick(event, analyticsEvent);
369
+ if (!metadata) {
370
+ return;
371
+ }
372
+ const isVideo = metadata && metadata.mediaType === 'video';
373
+ if (useInlinePlayer && isVideo && !!cardPreview) {
374
+ this.setState({
375
+ isPlayingFile: true,
376
+ shouldAutoplay: true
377
+ });
378
+ } else if (shouldOpenMediaViewer) {
379
+ let mediaViewerSelectedItem;
380
+ if (isFileIdentifier(identifier)) {
381
+ mediaViewerSelectedItem = {
382
+ id: identifier.id,
383
+ mediaItemType: 'file',
384
+ collectionName: identifier.collectionName,
385
+ occurrenceKey: identifier.occurrenceKey
386
+ };
387
+ } else {
388
+ mediaViewerSelectedItem = {
389
+ mediaItemType: 'external-image',
390
+ dataURI: identifier.dataURI,
391
+ name: identifier.name
392
+ };
393
+ }
394
+ this.setState({
395
+ mediaViewerSelectedItem
396
+ });
397
+ }
398
+ });
399
+ _defineProperty(this, "onInlinePlayerError", () => {
400
+ this.setState({
401
+ isPlayingFile: false
402
+ });
403
+ });
404
+ _defineProperty(this, "setRef", cardRef => {
405
+ !!cardRef && this.setState({
406
+ cardRef
407
+ });
408
+ });
409
+ _defineProperty(this, "renderInlinePlayer", () => {
410
+ const {
411
+ identifier,
412
+ mediaClient,
413
+ dimensions,
414
+ selected,
415
+ testId,
416
+ originalDimensions,
417
+ onFullscreenChange
418
+ } = this.props;
419
+ const {
420
+ shouldAutoplay,
421
+ cardPreview
422
+ } = this.state;
423
+ const card = this.renderCard(false, 'loading', false);
424
+ return /*#__PURE__*/React.createElement(Suspense, {
425
+ fallback: card
426
+ }, /*#__PURE__*/React.createElement(InlinePlayerLazy, {
427
+ mediaClient: mediaClient,
428
+ dimensions: dimensions,
429
+ originalDimensions: originalDimensions,
430
+ identifier: identifier,
431
+ autoplay: !!shouldAutoplay,
432
+ onFullscreenChange: onFullscreenChange,
433
+ onError: this.onInlinePlayerError,
434
+ onClick: this.onClick,
435
+ selected: selected,
436
+ ref: this.setRef,
437
+ testId: testId,
438
+ cardPreview: cardPreview
439
+ }));
440
+ });
441
+ _defineProperty(this, "onMediaViewerClose", () => {
442
+ this.setState({
443
+ mediaViewerSelectedItem: undefined
444
+ });
445
+ });
446
+ _defineProperty(this, "onDisplayImage", () => {
447
+ const {
448
+ identifier
449
+ } = this.props;
450
+ let payloadPart;
451
+ if (isFileIdentifier(identifier)) {
452
+ payloadPart = {
453
+ fileId: identifier.id,
454
+ isUserCollection: identifier.collectionName === RECENTS_COLLECTION
455
+ };
456
+ } else {
457
+ payloadPart = {
458
+ fileId: identifier.dataURI,
459
+ isUserCollection: false
460
+ };
461
+ }
462
+ globalMediaEventEmitter.emit('media-viewed', {
463
+ viewingLevel: 'minimal',
464
+ ...payloadPart
465
+ });
466
+ });
467
+ _defineProperty(this, "renderMediaViewer", () => {
468
+ const {
469
+ mediaViewerSelectedItem
470
+ } = this.state;
471
+ const {
472
+ mediaClient,
473
+ identifier,
474
+ mediaViewerItems,
475
+ contextId,
476
+ featureFlags
477
+ } = this.props;
478
+ if (!mediaViewerSelectedItem) {
479
+ return;
480
+ }
481
+ const collectionName = isFileIdentifier(identifier) ? identifier.collectionName || '' : '';
482
+ return /*#__PURE__*/ReactDOM.createPortal( /*#__PURE__*/React.createElement(MediaViewer, {
483
+ collectionName: collectionName,
484
+ items: mediaViewerItems || [],
485
+ mediaClientConfig: mediaClient.config,
486
+ selectedItem: mediaViewerSelectedItem,
487
+ onClose: this.onMediaViewerClose,
488
+ contextId: contextId,
489
+ featureFlags: featureFlags
490
+ }), document.body);
491
+ });
492
+ _defineProperty(this, "renderCard", (withCallbacks = true, cardStatusOverride, izLazyOverride) => {
493
+ const {
494
+ identifier,
495
+ isLazy,
496
+ appearance,
497
+ resizeMode,
498
+ dimensions,
499
+ selectable,
500
+ selected,
501
+ disableOverlay,
502
+ alt,
503
+ testId,
504
+ featureFlags,
505
+ titleBoxBgColor,
506
+ titleBoxIcon,
507
+ ssr,
508
+ useInlinePlayer,
509
+ shouldOpenMediaViewer,
510
+ shouldHideTooltip,
511
+ expandByPixel
512
+ } = this.props;
513
+ const {
514
+ mediaItemType
515
+ } = identifier;
516
+ const {
517
+ status,
518
+ progress,
519
+ cardPreview,
520
+ error,
521
+ cardRef,
522
+ isCardVisible
523
+ } = this.state;
524
+ const {
525
+ metadata
526
+ } = this;
527
+ const {
528
+ onCardViewClick,
529
+ onDisplayImage,
530
+ actions,
531
+ onMouseEnter
532
+ } = this;
533
+ const isLazyWithOverride = izLazyOverride === undefined ? isLazy : izLazyOverride;
534
+
535
+ // Card can be artificially turned visible before entering the viewport
536
+ // For example, when we have the image in cache
537
+ const nativeLazyLoad = isLazyWithOverride && !isCardVisible;
538
+ // Force Media Image to always display img for SSR
539
+ const forceSyncDisplay = !!ssr;
540
+ const mediaCardCursor = getMediaCardCursor(!!useInlinePlayer, !!shouldOpenMediaViewer, status === 'error' || status === 'failed-processing', !!this.state.cardPreview, metadata.mediaType);
541
+ const card = /*#__PURE__*/React.createElement(CardView, {
542
+ expandByPixel: expandByPixel,
543
+ status: cardStatusOverride || status,
544
+ error: error,
545
+ mediaItemType: mediaItemType,
546
+ metadata: metadata,
547
+ cardPreview: cardPreview,
548
+ alt: alt,
549
+ appearance: appearance,
550
+ resizeMode: resizeMode,
551
+ dimensions: dimensions,
552
+ actions: actions,
553
+ selectable: selectable,
554
+ selected: selected,
555
+ onClick: withCallbacks ? onCardViewClick : undefined,
556
+ onMouseEnter: withCallbacks ? onMouseEnter : undefined,
557
+ disableOverlay: disableOverlay,
558
+ progress: progress,
559
+ onDisplayImage: withCallbacks ? onDisplayImage : undefined,
560
+ innerRef: this.setRef,
561
+ testId: testId,
562
+ featureFlags: featureFlags,
563
+ titleBoxBgColor: titleBoxBgColor,
564
+ titleBoxIcon: titleBoxIcon,
565
+ onImageError: withCallbacks ? this.onImageError : undefined,
566
+ onImageLoad: withCallbacks ? this.onImageLoad : undefined,
567
+ nativeLazyLoad: nativeLazyLoad,
568
+ forceSyncDisplay: forceSyncDisplay,
569
+ mediaCardCursor: mediaCardCursor,
570
+ shouldHideTooltip: shouldHideTooltip
571
+ });
572
+ return isLazyWithOverride ? /*#__PURE__*/React.createElement(ViewportDetector, {
573
+ cardEl: cardRef,
574
+ onVisible: this.onCardInViewport
575
+ }, card) : card;
576
+ });
577
+ _defineProperty(this, "storeSSRData", () => {
578
+ var _this$ssrReliability$;
579
+ const {
580
+ ssr,
581
+ identifier
582
+ } = this.props;
583
+ const {
584
+ cardPreview: {
585
+ dataURI
586
+ } = {}
587
+ } = this.state;
588
+ return isFileIdentifier(identifier) && ssr === 'server' && /*#__PURE__*/React.createElement(StoreSSRDataScript, {
589
+ identifier: identifier,
590
+ dataURI: dataURI,
591
+ dimensions: this.requestedDimensions,
592
+ error: ((_this$ssrReliability$ = this.ssrReliability.server) === null || _this$ssrReliability$ === void 0 ? void 0 : _this$ssrReliability$.status) === 'fail' ? this.ssrReliability.server : undefined
593
+ });
594
+ });
595
+ _defineProperty(this, "onCardInViewport", () => {
596
+ this.setState({
597
+ isCardVisible: true
598
+ });
599
+ });
600
+ _defineProperty(this, "onClick", (event, analyticsEvent) => {
601
+ const {
602
+ onClick
603
+ } = this.props;
604
+ const {
605
+ metadata
606
+ } = this;
607
+ if (onClick) {
608
+ const cardEvent = {
609
+ event,
610
+ mediaItemDetails: metadata
611
+ };
612
+ onClick(cardEvent, analyticsEvent);
613
+ }
614
+ });
615
+ _defineProperty(this, "onMouseEnter", event => {
616
+ const {
617
+ onMouseEnter
618
+ } = this.props;
619
+ const {
620
+ metadata
621
+ } = this;
622
+ if (onMouseEnter) {
623
+ const cardEvent = {
624
+ event,
625
+ mediaItemDetails: metadata
626
+ };
627
+ onMouseEnter(cardEvent);
628
+ }
629
+ });
630
+ let _status = 'loading';
631
+ let _cardPreview;
632
+ let _error;
633
+ const {
634
+ identifier: _identifier,
635
+ resizeMode: _resizeMode,
636
+ ssr: _ssr,
637
+ mediaClient: _mediaClient
638
+ } = this.props;
639
+ if (isFileIdentifier(_identifier)) {
640
+ const {
641
+ id
642
+ } = _identifier;
643
+ const fileImageMode = imageResizeModeToFileImageMode(_resizeMode);
644
+ _cardPreview = getCardPreviewFromCache(id, fileImageMode);
645
+ if (!_cardPreview && _ssr) {
646
+ _cardPreview = this.getSSRPreview(_ssr, _identifier, _mediaClient);
647
+ }
648
+ } else if (isExternalImageIdentifier(_identifier)) {
649
+ this.fireCommencedEvent();
650
+ _status = 'loading-preview';
651
+ const {
652
+ dataURI
653
+ } = _identifier;
654
+ _cardPreview = {
655
+ dataURI,
656
+ orientation: 1,
657
+ source: 'external'
658
+ };
659
+ }
660
+
661
+ // If cardPreview is available from local cache or external, `isCardVisible`
662
+ // should be true to avoid flickers during re-mount of the component
663
+ // should not be visible for SSR preview, otherwise we'll fire the metadata fetch from
664
+ // outside the viewport
665
+ const _isCardVisible = !this.props.isLazy || !!_cardPreview && !isSSRPreview(_cardPreview);
666
+ this.state = {
667
+ status: _status,
668
+ isCardVisible: _isCardVisible,
669
+ isPlayingFile: false,
670
+ shouldAutoplay: false,
671
+ cardPreview: _cardPreview,
672
+ cardRef: null,
673
+ isBannedLocalPreview: false,
674
+ previewDidRender: false,
675
+ error: _error,
676
+ wasResolvedUpfrontPreview: false,
677
+ shouldUpdateStateForIdentifier: false
678
+ };
679
+ }
680
+ getSSRPreview(ssr, identifier, mediaClient) {
681
+ var _this$ssrData, _this$ssrData2;
682
+ this.ssrData = getSSRData(identifier);
683
+ if ((_this$ssrData = this.ssrData) !== null && _this$ssrData !== void 0 && _this$ssrData.error) {
684
+ this.ssrReliability.server = {
685
+ status: 'fail',
686
+ ...this.ssrData.error
687
+ };
688
+ }
689
+ if (!((_this$ssrData2 = this.ssrData) !== null && _this$ssrData2 !== void 0 && _this$ssrData2.dataURI)) {
690
+ try {
691
+ return getSSRCardPreview(ssr, mediaClient, identifier.id, this.getImageURLParams(identifier), this.getMediaBlobUrlAttrs(identifier));
692
+ } catch (e) {
693
+ this.ssrReliability[ssr] = {
694
+ status: 'fail',
695
+ ...extractErrorInfo(e)
696
+ };
697
+ }
698
+ } else {
699
+ return {
700
+ dataURI: this.ssrData.dataURI,
701
+ source: 'ssr-data'
702
+ };
703
+ }
704
+ }
705
+ componentDidMount() {
706
+ var _getDocument;
707
+ this.hasBeenMounted = true;
708
+ const {
709
+ isCardVisible,
710
+ cardPreview
711
+ } = this.state;
712
+ const {
713
+ identifier,
714
+ ssr,
715
+ dimensions
716
+ } = this.props;
717
+ if (isCardVisible && isFileIdentifier(identifier)) {
718
+ this.updateStateForIdentifier(identifier);
719
+ if (!cardPreview) {
720
+ this.resolveUpfrontPreview(identifier);
721
+ }
722
+ }
723
+ if (isCardVisible && !!ssr && !!cardPreview && isFileIdentifier(identifier)) {
724
+ var _this$ssrData3;
725
+ if (isSSRClientPreview(cardPreview)) {
726
+ // Since the SSR preview brings the token in the query params,
727
+ // We need to fetch the remote preview to be able to cache it,
728
+ this.setCacheSSRPreview(identifier);
729
+ }
730
+ if (isSSRDataPreview(cardPreview) && isBigger((_this$ssrData3 = this.ssrData) === null || _this$ssrData3 === void 0 ? void 0 : _this$ssrData3.dimensions, dimensions)) {
731
+ // If dimensions from Server have changed and are bigger,
732
+ // we need to refetch
733
+ this.refetchSSRPreview(identifier);
734
+ }
735
+ }
736
+ // we add a listener for each of the cards on the page
737
+ // and then check if the triggered listener is from the card
738
+ // that contains a div in current window.getSelection()
739
+ // won't work in IE11
740
+ (_getDocument = getDocument()) === null || _getDocument === void 0 ? void 0 : _getDocument.addEventListener('copy', this.fireCopiedEvent);
741
+ }
742
+ componentDidUpdate(prevProps, prevState) {
743
+ const {
744
+ mediaClient: prevMediaClient,
745
+ identifier: prevIdentifier,
746
+ dimensions: prevDimensions
747
+ } = prevProps;
748
+ const {
749
+ isCardVisible: prevIsCardVisible,
750
+ cardPreview: prevCardPreview
751
+ } = prevState;
752
+ const {
753
+ mediaClient,
754
+ identifier,
755
+ dimensions,
756
+ featureFlags,
757
+ useInlinePlayer,
758
+ disableOverlay,
759
+ resizeMode,
760
+ ssr
761
+ } = this.props;
762
+ const {
763
+ isCardVisible,
764
+ cardPreview,
765
+ status,
766
+ fileState,
767
+ isBannedLocalPreview,
768
+ previewDidRender,
769
+ isPlayingFile,
770
+ wasResolvedUpfrontPreview
771
+ } = this.state;
772
+ const isDiffIdentifier = isDifferentIdentifier(prevIdentifier, identifier);
773
+ /**
774
+ * Variable turnedVisible should only be true when media card
775
+ * was invisible in the previous state and is visible in the current one
776
+ *
777
+ * prevIsCardVisible | isCardVisible | turnedVisible
778
+ * ----------------------------------------------------
779
+ * false | false | false
780
+ * false | true | true
781
+ * true | true | false
782
+ * true | false | false (unreachable case)
783
+ * ----------------------------------------------------
784
+ */
785
+ const turnedVisible = !prevIsCardVisible && isCardVisible;
786
+ const hadSSRCardPreview = !!prevCardPreview && isSSRClientPreview(prevCardPreview) && !cardPreview;
787
+ const isNewMediaClient = prevMediaClient !== mediaClient;
788
+ const fileImageMode = imageResizeModeToFileImageMode(resizeMode);
789
+ this.updateFileStateFlag(fileState);
790
+ if (isExternalImageIdentifier(identifier) && isDiffIdentifier) {
791
+ this.fireCommencedEvent();
792
+ const {
793
+ dataURI
794
+ } = identifier;
795
+ this.setState({
796
+ status: 'loading-preview',
797
+ cardPreview: {
798
+ dataURI,
799
+ orientation: 1,
800
+ source: 'external'
801
+ },
802
+ isCardVisible: true
803
+ });
804
+ }
805
+ if (isFileIdentifier(identifier) && (turnedVisible || !!this.subscription && (isNewMediaClient || isDiffIdentifier))) {
806
+ this.updateStateForIdentifier(identifier);
807
+ }
808
+ if (this.state.status !== prevState.status) {
809
+ this.fireOperationalEvent();
810
+ if (this.state.status === 'complete' || this.fileAttributes.fileMediatype === 'video' && !!cardPreview && this.state.status === 'processing') {
811
+ this.fireScreenEvent();
812
+ }
813
+ }
814
+ if (isFileIdentifier(identifier) && (turnedVisible || ssr === 'client' && hadSSRCardPreview) && !cardPreview && !wasResolvedUpfrontPreview) {
815
+ // This is a one-off call, only meant to happen once in the component's lifecycle. Mainly when either:
816
+ // - turnedVisible = true
817
+ // - ssr = client and has no preview (the dataURI failed to load in the previous state, most likely because of an initial auth issue)
818
+ this.resolveUpfrontPreview(identifier);
819
+ } else if (isFileIdentifier(identifier) && fileState && shouldResolvePreview({
820
+ status,
821
+ fileState,
822
+ prevDimensions,
823
+ dimensions,
824
+ identifier,
825
+ fileImageMode,
826
+ featureFlags,
827
+ hasCardPreview: !!cardPreview,
828
+ isBannedLocalPreview,
829
+ wasResolvedUpfrontPreview
830
+ })) {
831
+ this.resolvePreview(identifier, fileState);
832
+ }
833
+ if (turnedVisible && this.props.ssr && !!cardPreview && isSSRClientPreview(cardPreview) && isFileIdentifier(identifier)) {
834
+ // Since the SSR preview brings the token in the query params,
835
+ // We need to fetch the remote preview to be able to cache it,
836
+ this.setCacheSSRPreview(identifier);
837
+ }
838
+ if (previewDidRender &&
839
+ // We should't complete if status is uploading
840
+ ['loading-preview', 'processing'].includes(status)) {
841
+ this.safeSetState({
842
+ status: 'complete',
843
+ shouldUpdateStateForIdentifier: false
844
+ });
845
+ if (this.hasBeenMounted) {
846
+ // TODO MEX-788: add test for "do not remove the card preview when unsubscribing".
847
+ this.setState({
848
+ isBannedLocalPreview: false
849
+ });
850
+ }
851
+ }
852
+ const isVideo = this.fileAttributes.fileMediatype === 'video';
853
+ const {
854
+ mimeType
855
+ } = getFileDetails(identifier, fileState);
856
+ const isVideoPlayable = videoIsPlayable(isBannedLocalPreview, fileState, mimeType);
857
+ if (isVideo && !isPlayingFile && disableOverlay && useInlinePlayer && isVideoPlayable) {
858
+ this.setState({
859
+ isPlayingFile: true
860
+ });
861
+ }
862
+ }
863
+ componentWillUnmount() {
864
+ var _getDocument2;
865
+ this.hasBeenMounted = false;
866
+ (_getDocument2 = getDocument()) === null || _getDocument2 === void 0 ? void 0 : _getDocument2.removeEventListener('copy', this.fireCopiedEvent);
867
+ }
868
+ updateStateForIdentifier(identifier) {
869
+ this.fireCommencedEvent();
870
+ this.setState({
871
+ shouldUpdateStateForIdentifier: true
872
+ });
873
+ }
874
+ updateFileStateFlag(fileState) {
875
+ if (!fileState) {
876
+ return;
877
+ }
878
+ const {
879
+ status
880
+ } = fileState;
881
+ if (status === 'processing') {
882
+ this.fileStateFlags.wasStatusProcessing = true;
883
+ } else if (status === 'uploading') {
884
+ this.fileStateFlags.wasStatusUploading = true;
885
+ }
886
+ }
887
+ get requestedDimensions() {
888
+ const {
889
+ dimensions
890
+ } = this.props;
891
+ const {
892
+ cardRef: element
893
+ } = this.state || {};
894
+ return getRequestedDimensions({
895
+ dimensions,
896
+ element
897
+ });
898
+ }
899
+ get metadata() {
900
+ var _this$state;
901
+ return getFileDetails(this.props.identifier, (_this$state = this.state) === null || _this$state === void 0 ? void 0 : _this$state.fileState);
902
+ }
903
+ get fileAttributes() {
904
+ var _this$state2, _this$state2$fileStat;
905
+ return getFileAttributes(this.metadata, (_this$state2 = this.state) === null || _this$state2 === void 0 ? void 0 : (_this$state2$fileStat = _this$state2.fileState) === null || _this$state2$fileStat === void 0 ? void 0 : _this$state2$fileStat.status);
906
+ }
907
+ fireOperationalEvent() {
908
+ const {
909
+ status,
910
+ error,
911
+ fileState
912
+ } = this.state;
913
+ const {
914
+ createAnalyticsEvent
915
+ } = this.props;
916
+ createAnalyticsEvent && fireOperationalEvent(createAnalyticsEvent, status, this.fileAttributes, this.getPerformanceAttributes(), this.ssrReliability, error, this.traceContext, fileState === null || fileState === void 0 ? void 0 : fileState.metadataTraceContext);
917
+ completeUfoExperience(this.internalOccurrenceKey, status, this.fileAttributes, this.fileStateFlags, this.ssrReliability, error);
918
+ }
919
+ fireCommencedEvent() {
920
+ this.timeElapsedTillCommenced = performance.now();
921
+ const {
922
+ createAnalyticsEvent
923
+ } = this.props;
924
+ createAnalyticsEvent && fireCommencedEvent(createAnalyticsEvent, this.fileAttributes, {
925
+ overall: {
926
+ durationSincePageStart: this.timeElapsedTillCommenced
927
+ }
928
+ }, this.traceContext);
929
+ startUfoExperience(this.internalOccurrenceKey);
930
+ }
931
+ get actions() {
932
+ const {
933
+ actions = [],
934
+ identifier,
935
+ shouldEnableDownloadButton
936
+ } = this.props;
937
+ const {
938
+ status
939
+ } = this.state;
940
+ const {
941
+ metadata
942
+ } = this;
943
+ if (isFileIdentifier(identifier) && (status === 'failed-processing' || shouldEnableDownloadButton)) {
944
+ const downloadAction = {
945
+ label: 'Download',
946
+ icon: /*#__PURE__*/React.createElement(DownloadIcon, {
947
+ label: "Download"
948
+ }),
949
+ handler: () => this.props.mediaClient.file.downloadBinary(identifier.id, metadata.name, identifier.collectionName)
950
+ };
951
+ return [downloadAction, ...actions];
952
+ } else {
953
+ return actions;
954
+ }
955
+ }
956
+ render() {
957
+ const {
958
+ isPlayingFile,
959
+ mediaViewerSelectedItem,
960
+ shouldUpdateStateForIdentifier
961
+ } = this.state;
962
+ const innerContent = /*#__PURE__*/React.createElement(React.Fragment, null, isPlayingFile ? this.renderInlinePlayer() : this.renderCard(), mediaViewerSelectedItem ? this.renderMediaViewer() : null, this.storeSSRData());
963
+ let wrappedContent = innerContent;
964
+ if (shouldUpdateStateForIdentifier) {
965
+ const {
966
+ id,
967
+ collectionName,
968
+ occurrenceKey
969
+ } = this.props.identifier;
970
+ wrappedContent = /*#__PURE__*/React.createElement(FileStateListener, {
971
+ id: id,
972
+ onChange: this.subscribeFileState,
973
+ collectionName: collectionName,
974
+ occurrenceKey: occurrenceKey
975
+ }, innerContent);
976
+ }
977
+ return this.props.intl ? wrappedContent : /*#__PURE__*/React.createElement(IntlProvider, {
978
+ locale: "en"
979
+ }, wrappedContent);
980
+ }
981
+ }
982
+ _defineProperty(CardV2Base, "defaultProps", {
983
+ appearance: 'auto',
984
+ resizeMode: 'crop',
985
+ isLazy: true,
986
+ disableOverlay: false,
987
+ // Media Feature Flag defaults are defined in @atlaskit/media-common
988
+ featureFlags: {}
989
+ });
990
+ const FileStateListener = ({
991
+ children,
992
+ onChange,
993
+ id,
994
+ collectionName,
995
+ occurrenceKey
996
+ }) => {
997
+ const {
998
+ fileState
999
+ } = useFileState(id, {
1000
+ collectionName,
1001
+ occurrenceKey
1002
+ });
1003
+ useEffect(() => {
1004
+ if (fileState) {
1005
+ onChange(fileState);
1006
+ }
1007
+ }, [fileState, onChange]);
1008
+ return children;
1009
+ };
1010
+
1011
+ /**
1012
+ * We require this wrapper in order to refresh media card state when the identifier is updated (via a key)
1013
+ * TODO: remove the key when the cardV2 is no longer required
1014
+ */
1015
+ const CardWithKey = props => {
1016
+ const {
1017
+ identifier
1018
+ } = props;
1019
+ const key = isFileIdentifier(identifier) ? identifier.id : identifier.dataURI;
1020
+ return /*#__PURE__*/React.createElement(CardV2Base, _extends({}, props, {
1021
+ key: key
1022
+ }));
1023
+ };
1024
+ export const CardV2 = withMediaAnalyticsContext({
1025
+ packageVersion,
1026
+ packageName,
1027
+ componentName: 'mediaCard',
1028
+ component: 'mediaCard'
1029
+ })(withAnalyticsEvents()(injectIntl(CardWithKey, {
1030
+ enforceContext: false
1031
+ })));