@atlaskit/media-card 70.10.0 → 72.1.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 (150) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/dist/cjs/errors.js +76 -5
  3. package/dist/cjs/files/cardImageView/index.js +58 -89
  4. package/dist/cjs/files/index.js +0 -6
  5. package/dist/cjs/index.js +16 -6
  6. package/dist/cjs/root/card/cardAnalytics.js +33 -19
  7. package/dist/cjs/root/card/cardConstants.js +8 -0
  8. package/dist/cjs/root/card/cardLoader.js +66 -124
  9. package/dist/cjs/root/card/cardState.js +50 -0
  10. package/dist/cjs/root/card/getCardPreview/cache.js +5 -0
  11. package/dist/cjs/root/card/getCardPreview/filePreviewStatus.js +50 -0
  12. package/dist/cjs/root/card/getCardPreview/helpers.js +13 -21
  13. package/dist/cjs/root/card/getCardPreview/index.js +171 -100
  14. package/dist/cjs/root/card/getCardStatus.js +7 -1
  15. package/dist/cjs/root/card/index.js +407 -322
  16. package/dist/cjs/root/cardView.js +115 -76
  17. package/dist/cjs/root/index.js +9 -1
  18. package/dist/cjs/root/inline/loader.js +22 -21
  19. package/dist/cjs/root/inline/{inlineMediaCard.js → mediaInlineCard.js} +72 -25
  20. package/dist/cjs/root/inlinePlayer.js +5 -15
  21. package/dist/cjs/root/ui/iconMessage/index.js +17 -9
  22. package/dist/cjs/root/ui/imageRenderer/imageRenderer.js +36 -115
  23. package/dist/cjs/root/ui/styled.js +1 -1
  24. package/dist/cjs/root/ui/titleBox/failedTitleBox.js +7 -3
  25. package/dist/cjs/utils/analytics.js +26 -43
  26. package/dist/cjs/utils/cardActions/cardActionsDropdownMenu.js +16 -9
  27. package/dist/cjs/utils/dimensionComparer.js +1 -1
  28. package/dist/cjs/utils/document.js +12 -0
  29. package/dist/cjs/utils/getDataURIDimension.js +13 -2
  30. package/dist/cjs/utils/metadata.js +11 -3
  31. package/dist/cjs/utils/objectURLCache.js +6 -0
  32. package/dist/cjs/utils/resizeModeToMediaImageProps.js +13 -0
  33. package/dist/cjs/utils/shouldDisplayImageThumbnail.js +1 -1
  34. package/dist/cjs/version.json +1 -1
  35. package/dist/es2019/errors.js +42 -2
  36. package/dist/es2019/files/cardImageView/index.js +12 -46
  37. package/dist/es2019/files/index.js +1 -1
  38. package/dist/es2019/index.js +3 -3
  39. package/dist/es2019/root/card/cardAnalytics.js +23 -17
  40. package/dist/es2019/root/card/cardConstants.js +1 -0
  41. package/dist/es2019/root/card/cardLoader.js +47 -53
  42. package/dist/es2019/root/card/cardState.js +26 -0
  43. package/dist/es2019/root/card/getCardPreview/cache.js +5 -0
  44. package/dist/es2019/root/card/getCardPreview/filePreviewStatus.js +35 -0
  45. package/dist/es2019/root/card/getCardPreview/helpers.js +2 -12
  46. package/dist/es2019/root/card/getCardPreview/index.js +112 -79
  47. package/dist/es2019/root/card/getCardStatus.js +1 -0
  48. package/dist/es2019/root/card/index.js +356 -254
  49. package/dist/es2019/root/cardView.js +98 -58
  50. package/dist/es2019/root/index.js +2 -1
  51. package/dist/es2019/root/inline/loader.js +16 -15
  52. package/dist/es2019/root/inline/mediaInlineCard.js +132 -0
  53. package/dist/es2019/root/inlinePlayer.js +5 -13
  54. package/dist/es2019/root/ui/iconMessage/index.js +10 -6
  55. package/dist/es2019/root/ui/imageRenderer/imageRenderer.js +26 -74
  56. package/dist/es2019/root/ui/styled.js +1 -0
  57. package/dist/es2019/root/ui/titleBox/failedTitleBox.js +5 -3
  58. package/dist/es2019/utils/analytics.js +29 -40
  59. package/dist/es2019/utils/cardActions/cardActionsDropdownMenu.js +8 -4
  60. package/dist/es2019/utils/dimensionComparer.js +1 -1
  61. package/dist/es2019/utils/document.js +1 -0
  62. package/dist/es2019/utils/getDataURIDimension.js +8 -0
  63. package/dist/es2019/utils/metadata.js +12 -4
  64. package/dist/es2019/utils/objectURLCache.js +5 -0
  65. package/dist/es2019/utils/resizeModeToMediaImageProps.js +6 -0
  66. package/dist/es2019/utils/shouldDisplayImageThumbnail.js +1 -1
  67. package/dist/es2019/version.json +1 -1
  68. package/dist/esm/errors.js +60 -1
  69. package/dist/esm/files/cardImageView/index.js +55 -87
  70. package/dist/esm/files/index.js +1 -1
  71. package/dist/esm/index.js +3 -3
  72. package/dist/esm/root/card/cardAnalytics.js +23 -18
  73. package/dist/esm/root/card/cardConstants.js +1 -0
  74. package/dist/esm/root/card/cardLoader.js +66 -126
  75. package/dist/esm/root/card/cardState.js +32 -0
  76. package/dist/esm/root/card/getCardPreview/cache.js +6 -0
  77. package/dist/esm/root/card/getCardPreview/filePreviewStatus.js +35 -0
  78. package/dist/esm/root/card/getCardPreview/helpers.js +13 -21
  79. package/dist/esm/root/card/getCardPreview/index.js +142 -95
  80. package/dist/esm/root/card/getCardStatus.js +3 -0
  81. package/dist/esm/root/card/index.js +416 -325
  82. package/dist/esm/root/cardView.js +114 -73
  83. package/dist/esm/root/index.js +2 -1
  84. package/dist/esm/root/inline/loader.js +23 -22
  85. package/dist/esm/root/inline/mediaInlineCard.js +145 -0
  86. package/dist/esm/root/inlinePlayer.js +5 -13
  87. package/dist/esm/root/ui/iconMessage/index.js +12 -7
  88. package/dist/esm/root/ui/imageRenderer/imageRenderer.js +28 -106
  89. package/dist/esm/root/ui/styled.js +1 -1
  90. package/dist/esm/root/ui/titleBox/failedTitleBox.js +6 -3
  91. package/dist/esm/utils/analytics.js +22 -35
  92. package/dist/esm/utils/cardActions/cardActionsDropdownMenu.js +16 -9
  93. package/dist/esm/utils/dimensionComparer.js +1 -1
  94. package/dist/esm/utils/document.js +3 -0
  95. package/dist/esm/utils/getDataURIDimension.js +8 -0
  96. package/dist/esm/utils/metadata.js +12 -4
  97. package/dist/esm/utils/objectURLCache.js +6 -0
  98. package/dist/esm/utils/resizeModeToMediaImageProps.js +6 -0
  99. package/dist/esm/utils/shouldDisplayImageThumbnail.js +1 -1
  100. package/dist/esm/version.json +1 -1
  101. package/dist/types/errors.d.ts +15 -1
  102. package/dist/types/files/cardImageView/index.d.ts +5 -12
  103. package/dist/types/files/cardImageView/styled.d.ts +1 -1
  104. package/dist/types/files/index.d.ts +1 -1
  105. package/dist/types/index.d.ts +11 -13
  106. package/dist/types/root/card/cardAnalytics.d.ts +5 -7
  107. package/dist/types/root/card/cardConstants.d.ts +1 -0
  108. package/dist/types/root/card/cardLoader.d.ts +4 -18
  109. package/dist/types/root/card/cardState.d.ts +5 -0
  110. package/dist/types/root/card/getCardPreview/cache.d.ts +4 -2
  111. package/dist/types/root/card/getCardPreview/filePreviewStatus.d.ts +5 -0
  112. package/dist/types/root/card/getCardPreview/helpers.d.ts +4 -5
  113. package/dist/types/root/card/getCardPreview/index.d.ts +25 -14
  114. package/dist/types/root/card/getCardStatus.d.ts +1 -0
  115. package/dist/types/root/card/index.d.ts +18 -15
  116. package/dist/types/root/cardView.d.ts +14 -8
  117. package/dist/types/root/index.d.ts +1 -0
  118. package/dist/types/root/inline/loader.d.ts +8 -8
  119. package/dist/types/root/inline/{inlineMediaCard.d.ts → mediaInlineCard.d.ts} +4 -4
  120. package/dist/types/root/inlinePlayer.d.ts +1 -1
  121. package/dist/types/root/ui/iconMessage/index.d.ts +7 -2
  122. package/dist/types/root/ui/imageRenderer/imageRenderer.d.ts +5 -18
  123. package/dist/types/root/ui/titleBox/failedTitleBox.d.ts +2 -0
  124. package/dist/types/types.d.ts +9 -1
  125. package/dist/types/utils/analytics.d.ts +20 -21
  126. package/dist/types/utils/cardDimensions.d.ts +5 -1
  127. package/dist/types/utils/dimensionComparer.d.ts +1 -1
  128. package/dist/types/utils/document.d.ts +2 -0
  129. package/dist/types/utils/getDataURIDimension.d.ts +3 -1
  130. package/dist/types/utils/index.d.ts +1 -0
  131. package/dist/types/utils/lazyContent/styled.d.ts +1 -1
  132. package/dist/types/utils/lightCards/types.d.ts +1 -1
  133. package/dist/types/utils/metadata.d.ts +2 -2
  134. package/dist/types/utils/objectURLCache.d.ts +2 -1
  135. package/dist/types/utils/resizeModeToMediaImageProps.d.ts +5 -0
  136. package/dist/types/utils/shouldDisplayImageThumbnail.d.ts +1 -1
  137. package/example-helpers/developmentUseMessage.tsx +14 -0
  138. package/example-helpers/index.tsx +55 -4
  139. package/example-helpers/selectableCard.tsx +2 -1
  140. package/package.json +18 -14
  141. package/dist/cjs/root/card/getCardPreview/types.js +0 -5
  142. package/dist/cjs/utils/fileAttributesContext.js +0 -40
  143. package/dist/es2019/root/card/getCardPreview/types.js +0 -1
  144. package/dist/es2019/root/inline/inlineMediaCard.js +0 -92
  145. package/dist/es2019/utils/fileAttributesContext.js +0 -19
  146. package/dist/esm/root/card/getCardPreview/types.js +0 -1
  147. package/dist/esm/root/inline/inlineMediaCard.js +0 -100
  148. package/dist/esm/utils/fileAttributesContext.js +0 -18
  149. package/dist/types/root/card/getCardPreview/types.d.ts +0 -5
  150. package/dist/types/utils/fileAttributesContext.d.ts +0 -10
@@ -5,116 +5,223 @@ import { version as packageVersion, name as packageName } from '../../version.js
5
5
  import { withAnalyticsEvents } from '@atlaskit/analytics-next';
6
6
  import { withMediaAnalyticsContext } from '@atlaskit/media-common';
7
7
  import DownloadIcon from '@atlaskit/icon/glyph/download';
8
- import { addFileAttrsToUrl, globalMediaEventEmitter, isDifferentIdentifier, isFileIdentifier, isErrorFileState, RECENTS_COLLECTION, isImageRepresentationReady } from '@atlaskit/media-client';
8
+ import { globalMediaEventEmitter, isDifferentIdentifier, isFileIdentifier, RECENTS_COLLECTION, isImageRepresentationReady, isExternalImageIdentifier, imageResizeModeToFileImageMode } from '@atlaskit/media-client';
9
9
  import { MediaViewer } from '@atlaskit/media-viewer';
10
10
  import { IntlProvider, intlShape } from 'react-intl';
11
11
  import { CardView } from '../cardView';
12
12
  import { ViewportDetector } from '../../utils/viewportDetector';
13
- import { getDataURIDimension } from '../../utils/getDataURIDimension';
14
- import { shouldGetCardPreview, extractFilePreviewStatus, getCardPreview, getCardPreviewFromCache, getFilePreviewFromFileState } from './getCardPreview';
13
+ import { getRequestedDimensions } from '../../utils/getDataURIDimension';
14
+ import { getCardPreview, getCardPreviewFromCache, removeCardPreviewFromCache, getFilePreviewFromFileState, shouldResolvePreview, getSSRCardPreview, isLocalPreview, isSSRPreview, isSSRClientPreview, fetchAndCacheRemotePreview } from './getCardPreview';
15
15
  import { getFileDetails } from '../../utils/metadata';
16
- import { isBigger } from '../../utils/dimensionComparer';
17
- import { getCardStatus } from './getCardStatus';
18
16
  import { InlinePlayer } from '../inlinePlayer';
19
- import { fireMediaCardEvent, getFileAttributes, getRenderCommencedEventPayload, getCopiedFilePayload } from '../../utils/analytics';
20
- import { FileAttributesProvider } from '../../utils/fileAttributesContext';
21
- import { isRemotePreviewError, MediaCardError, ensureMediaCardError } from '../../errors';
22
- import { fireOperationalEvent, relevantFeatureFlagNames } from './cardAnalytics';
17
+ import { getFileAttributes } from '../../utils/analytics';
18
+ import { isLocalPreviewError, MediaCardError, ensureMediaCardError, ImageLoadError } from '../../errors';
19
+ import { fireOperationalEvent, fireCommencedEvent, relevantFeatureFlagNames, fireCopiedEvent, fireScreenEvent } from './cardAnalytics';
20
+ import getDocument from '../../utils/document';
21
+ import { getCardStateFromFileState, createStateUpdater } from './cardState';
23
22
  export class CardBase extends Component {
23
+ // We initialise timeElapsedTillCommenced
24
+ // to avoid extra branching on a possibly undefined value.
24
25
  constructor(props) {
25
26
  super(props);
26
27
 
27
28
  _defineProperty(this, "hasBeenMounted", false);
28
29
 
29
- _defineProperty(this, "onCopyListener", () => {
30
- if (typeof window.getSelection === 'function') {
31
- const selection = window.getSelection();
32
- const {
33
- cardRef
34
- } = this.state;
35
-
36
- if (cardRef && selection && selection.containsNode && selection.containsNode(cardRef, true)) {
37
- this.fireFileCopiedEvent();
38
- }
39
- }
40
- });
41
-
42
- _defineProperty(this, "shouldRefetchImage", (current, next) => {
43
- if (!current || !next) {
44
- return false;
45
- }
30
+ _defineProperty(this, "timeElapsedTillCommenced", performance.now());
46
31
 
47
- return isBigger(current, next);
48
- });
49
-
50
- _defineProperty(this, "isLatestCardStatusUpdate", cardStatusUpdateTimestamp => !this.lastCardStatusUpdateTimestamp || this.lastCardStatusUpdateTimestamp <= cardStatusUpdateTimestamp);
32
+ _defineProperty(this, "getImageURLParams", ({
33
+ collectionName: collection
34
+ }) => ({
35
+ collection,
36
+ mode: imageResizeModeToFileImageMode(this.props.resizeMode),
37
+ ...this.requestedDimensions,
38
+ allowAnimated: true
39
+ }));
51
40
 
52
- _defineProperty(this, "onLocalPreviewError", error => {// TODO: track local preview success rate
53
- // https://product-fabric.atlassian.net/browse/MEX-774
54
- });
55
-
56
- _defineProperty(this, "createAddContextToDataURI", (fileId, fileState, {
57
- width,
58
- height
59
- }, collectionName) => dataURI => {
41
+ _defineProperty(this, "getMediaBlobUrlAttrs", (identifier, fileState) => {
42
+ const {
43
+ id,
44
+ collectionName: collection
45
+ } = identifier;
60
46
  const {
47
+ originalDimensions,
61
48
  contextId,
62
49
  alt
63
50
  } = this.props;
64
-
65
- if (!contextId) {
66
- return dataURI;
67
- }
68
-
69
- const metadata = getFileDetails(fileState);
70
- return addFileAttrsToUrl(dataURI, {
71
- id: fileId,
72
- collection: collectionName,
51
+ const {
52
+ mimeType,
53
+ name,
54
+ size
55
+ } = getFileDetails(identifier, fileState);
56
+ return contextId ? {
57
+ id,
58
+ collection,
73
59
  contextId,
74
- mimeType: metadata.mimeType,
75
- name: metadata.name,
76
- size: metadata.size,
77
- width,
78
- height,
60
+ mimeType,
61
+ name,
62
+ size,
63
+ ...(originalDimensions || this.requestedDimensions),
79
64
  alt
80
- });
65
+ } : undefined;
81
66
  });
82
67
 
83
- _defineProperty(this, "getCardPreviewParams", (id, collectionName, fileState) => {
68
+ _defineProperty(this, "getCardPreviewParams", (identifier, fileState) => {
84
69
  const {
85
- requestedDimensions,
86
- onLocalPreviewError
87
- } = this;
70
+ isBannedLocalPreview
71
+ } = this.state;
72
+ const {
73
+ id
74
+ } = identifier;
88
75
  const {
89
76
  dimensions = {},
90
- originalDimensions,
91
- resizeMode,
92
77
  mediaClient
93
78
  } = this.props;
94
79
  return {
95
80
  mediaClient,
96
81
  id,
97
- collectionName,
98
82
  dimensions,
99
- resizeMode,
100
- requestedDimensions,
101
- onLocalPreviewError,
102
- filePreview: getFilePreviewFromFileState(fileState),
83
+ onLocalPreviewError: this.fireLocalPreviewErrorEvent,
84
+ filePreview: isBannedLocalPreview ? undefined : getFilePreviewFromFileState(fileState),
103
85
  isRemotePreviewReady: isImageRepresentationReady(fileState),
104
- addContextToDataURI: this.createAddContextToDataURI(id, fileState, originalDimensions || this.requestedDimensions, collectionName)
86
+ imageUrlParams: this.getImageURLParams(identifier),
87
+ mediaBlobUrlAttrs: this.getMediaBlobUrlAttrs(identifier, fileState)
105
88
  };
106
89
  });
107
90
 
108
- _defineProperty(this, "fireFileCopiedEvent", () => {
91
+ _defineProperty(this, "setCacheSSRPreview", identifier => {
92
+ const {
93
+ mediaClient,
94
+ dimensions = {}
95
+ } = this.props;
96
+ fetchAndCacheRemotePreview(mediaClient, identifier.id, dimensions, this.getImageURLParams(identifier), this.getMediaBlobUrlAttrs(identifier)).catch(() => {// No need to log this error.
97
+ // If preview fails, it will be refetched later
98
+ //TODO: test this catch
99
+ // https://product-fabric.atlassian.net/browse/MEX-1071
100
+ });
101
+ });
102
+
103
+ _defineProperty(this, "resolveSSRPreview", (identifier, ssr) => {
104
+ const {
105
+ mediaClient
106
+ } = this.props;
107
+
108
+ try {
109
+ return getSSRCardPreview(ssr, mediaClient, identifier.id, this.getImageURLParams(identifier), this.getMediaBlobUrlAttrs(identifier));
110
+ } catch (e) {// TODO: log SSR reliability 'failed'
111
+ // https://product-fabric.atlassian.net/browse/MEX-770
112
+ }
113
+ });
114
+
115
+ _defineProperty(this, "resolvePreview", async (identifier, fileState) => {
116
+ try {
117
+ const params = this.getCardPreviewParams(identifier, fileState);
118
+ const cardPreview = await getCardPreview(params);
119
+ this.safeSetState({
120
+ cardPreview
121
+ });
122
+ } catch (e) {
123
+ const wrappedError = ensureMediaCardError('preview-fetch', e); // If remote preview fails, we set status 'error'
124
+ // If local preview fails (i.e, no remote preview available),
125
+ // we can stay in the same status until there is a remote preview available
126
+ // If it's any other error we set status 'error'
127
+
128
+ if (isLocalPreviewError(wrappedError)) {
129
+ this.safeSetState({
130
+ isBannedLocalPreview: true
131
+ });
132
+ } else {
133
+ this.safeSetState({
134
+ status: 'error',
135
+ error: wrappedError
136
+ });
137
+ }
138
+ }
139
+ });
140
+
141
+ _defineProperty(this, "getPerformanceAttributes", () => {
142
+ const {
143
+ timeElapsedTillCommenced
144
+ } = this;
145
+ const timeElapsedTillEvent = performance.now();
146
+ const durationSinceCommenced = timeElapsedTillCommenced && timeElapsedTillEvent - timeElapsedTillCommenced;
147
+ return {
148
+ overall: {
149
+ durationSincePageStart: timeElapsedTillEvent,
150
+ durationSinceCommenced
151
+ }
152
+ };
153
+ });
154
+
155
+ _defineProperty(this, "onImageError", () => {
156
+ const {
157
+ cardPreview
158
+ } = this.state;
159
+ const error = new ImageLoadError(cardPreview === null || cardPreview === void 0 ? void 0 : cardPreview.source);
160
+ const isLocal = cardPreview && isLocalPreview(cardPreview);
161
+ const isSSR = cardPreview && isSSRClientPreview(cardPreview);
162
+
163
+ if (isLocal || isSSR) {
164
+ const updateState = {
165
+ cardPreview: undefined
166
+ };
167
+
168
+ if (isLocal) {
169
+ updateState.isBannedLocalPreview = true;
170
+ this.fireLocalPreviewErrorEvent(error);
171
+ }
172
+
173
+ if (isSSR) {// TODO: set SSR-client reliability 'failed'.
174
+ // https://product-fabric.atlassian.net/browse/MEX-770
175
+ }
176
+
177
+ const {
178
+ identifier,
179
+ dimensions = {}
180
+ } = this.props;
181
+ isFileIdentifier(identifier) && removeCardPreviewFromCache(identifier.id, dimensions);
182
+ this.safeSetState(updateState);
183
+ } else {
184
+ this.safeSetState({
185
+ status: 'error',
186
+ error
187
+ });
188
+ }
189
+ });
190
+
191
+ _defineProperty(this, "onImageLoad", () => {
192
+ this.safeSetState({
193
+ previewDidRender: true
194
+ });
195
+ });
196
+
197
+ _defineProperty(this, "fireCopiedEvent", () => {
198
+ const {
199
+ createAnalyticsEvent
200
+ } = this.props;
201
+ const {
202
+ cardRef
203
+ } = this.state;
204
+ cardRef && createAnalyticsEvent && fireCopiedEvent(createAnalyticsEvent, this.metadata.id, cardRef);
205
+ });
206
+
207
+ _defineProperty(this, "fireScreenEvent", () => {
109
208
  const {
110
209
  createAnalyticsEvent
111
210
  } = this.props;
112
- fireMediaCardEvent(getCopiedFilePayload(this.metadata.id), createAnalyticsEvent);
211
+ createAnalyticsEvent && fireScreenEvent(createAnalyticsEvent, this.fileAttributes);
212
+ });
213
+
214
+ _defineProperty(this, "fireLocalPreviewErrorEvent", error => {// TODO: track local preview success rate
215
+ // https://product-fabric.atlassian.net/browse/MEX-774
113
216
  });
114
217
 
115
218
  _defineProperty(this, "safeSetState", state => {
116
219
  if (this.hasBeenMounted) {
117
- this.setState(state);
220
+ // If it's setting the status, we need to use a state updater function,
221
+ // which ensures that no non-final status overrides a final status.
222
+ // If no status is set, we don't need a sate updater
223
+ const updater = !!state.status ? createStateUpdater(state) : state;
224
+ this.setState(updater);
118
225
  }
119
226
  });
120
227
 
@@ -124,8 +231,9 @@ export class CardBase extends Component {
124
231
  }
125
232
 
126
233
  if (this.hasBeenMounted) {
234
+ // TODO MEX-788: add test for "do not remove the card preview when unsubscribing".
127
235
  this.setState({
128
- cardPreview: undefined
236
+ isBannedLocalPreview: false
129
237
  });
130
238
  }
131
239
  });
@@ -287,7 +395,8 @@ export class CardBase extends Component {
287
395
  testId,
288
396
  featureFlags,
289
397
  titleBoxBgColor,
290
- titleBoxIcon
398
+ titleBoxIcon,
399
+ ssr
291
400
  } = this.props;
292
401
  const {
293
402
  mediaItemType
@@ -303,7 +412,8 @@ export class CardBase extends Component {
303
412
  orientation: 1
304
413
  },
305
414
  error,
306
- cardRef
415
+ cardRef,
416
+ isCardVisible
307
417
  } = this.state;
308
418
  const {
309
419
  metadata
@@ -313,10 +423,15 @@ export class CardBase extends Component {
313
423
  onDisplayImage,
314
424
  actions,
315
425
  onMouseEnter
316
- } = this;
426
+ } = this; // Card can be artificially turned visible before entering the viewport
427
+ // For example, when we have the image in cache
428
+
429
+ const nativeLazyLoad = isLazy && !isCardVisible; // Force Media Image to always display img for SSR
430
+
431
+ const forceSyncDisplay = !!ssr;
317
432
  const card = /*#__PURE__*/React.createElement(CardView, {
318
433
  status: status,
319
- error: error && error.secondaryError,
434
+ error: error,
320
435
  mediaItemType: mediaItemType,
321
436
  metadata: metadata,
322
437
  dataURI: dataURI,
@@ -337,7 +452,11 @@ export class CardBase extends Component {
337
452
  testId: testId,
338
453
  featureFlags: featureFlags,
339
454
  titleBoxBgColor: titleBoxBgColor,
340
- titleBoxIcon: titleBoxIcon
455
+ titleBoxIcon: titleBoxIcon,
456
+ onImageError: this.onImageError,
457
+ onImageLoad: this.onImageLoad,
458
+ nativeLazyLoad: nativeLazyLoad,
459
+ forceSyncDisplay: forceSyncDisplay
341
460
  });
342
461
  return isLazy ? /*#__PURE__*/React.createElement(ViewportDetector, {
343
462
  targetRef: cardRef,
@@ -385,11 +504,14 @@ export class CardBase extends Component {
385
504
  }
386
505
  });
387
506
 
507
+ let _status = 'loading';
508
+
388
509
  let _cardPreview;
389
510
 
390
511
  const {
391
512
  identifier: _identifier,
392
- dimensions: _dimensions = {}
513
+ dimensions: _dimensions = {},
514
+ ssr: _ssr
393
515
  } = this.props;
394
516
 
395
517
  if (isFileIdentifier(_identifier)) {
@@ -397,31 +519,67 @@ export class CardBase extends Component {
397
519
  id
398
520
  } = _identifier;
399
521
  _cardPreview = getCardPreviewFromCache(id, _dimensions);
400
- }
401
- /**
402
- * If cardPreview is available from local cache, `isCardVisible`
403
- * should be true to avoid flickers during re-mount of the component
404
- */
405
522
 
523
+ if (!_cardPreview && _ssr) {
524
+ this.fireCommencedEvent();
525
+ _cardPreview = this.resolveSSRPreview(_identifier, _ssr);
526
+ }
527
+ } else if (isExternalImageIdentifier(_identifier)) {
528
+ this.fireCommencedEvent();
529
+ _status = 'loading-preview';
530
+ const {
531
+ dataURI
532
+ } = _identifier;
533
+ _cardPreview = {
534
+ dataURI,
535
+ orientation: 1,
536
+ source: 'external'
537
+ };
538
+ } // If cardPreview is available from local cache or external, `isCardVisible`
539
+ // should be true to avoid flickers during re-mount of the component
540
+ // should not be visible for SSR preview, otherwise we'll fire the metadata fetch from
541
+ // outside the viewport
542
+
543
+
544
+ const _isCardVisible = !this.props.isLazy || !!_cardPreview && !isSSRPreview(_cardPreview);
406
545
 
407
546
  this.state = {
408
- status: 'loading',
409
- isCardVisible: _cardPreview ? true : !this.props.isLazy,
547
+ status: _status,
548
+ isCardVisible: _isCardVisible,
410
549
  isPlayingFile: false,
411
550
  cardPreview: _cardPreview,
412
- cardRef: null
551
+ cardRef: null,
552
+ isBannedLocalPreview: false,
553
+ previewDidRender: false
413
554
  };
414
- } // we add a listener for each of the cards on the page
415
- // and then check if the triggered listener is from the card
416
- // that contains a div in current window.getSelection()
417
- // won't work in IE11
418
-
555
+ }
419
556
 
420
557
  componentDidMount() {
421
558
  this.hasBeenMounted = true;
422
- this.fireCommencedEvent();
423
- this.updateStateForIdentifier();
424
- document.addEventListener('copy', this.onCopyListener);
559
+ const {
560
+ isCardVisible,
561
+ cardPreview
562
+ } = this.state;
563
+ const {
564
+ identifier,
565
+ ssr
566
+ } = this.props;
567
+
568
+ if (isCardVisible && isFileIdentifier(identifier)) {
569
+ this.updateStateForIdentifier(identifier);
570
+ }
571
+
572
+ if (isCardVisible && !!ssr && !!cardPreview && isSSRClientPreview(cardPreview) && isFileIdentifier(identifier)) {
573
+ // Since the SSR preview brings the token in the query params,
574
+ // We need to fetch the remote preview to be able to cache it,
575
+ this.setCacheSSRPreview(identifier);
576
+ } // we add a listener for each of the cards on the page
577
+ // and then check if the triggered listener is from the card
578
+ // that contains a div in current window.getSelection()
579
+ // won't work in IE11
580
+
581
+
582
+ getDocument().addEventListener('copy', this.fireCopiedEvent);
425
583
  }
426
584
 
427
585
  componentDidUpdate(prevProps, prevState) {
@@ -436,197 +594,168 @@ export class CardBase extends Component {
436
594
  const {
437
595
  mediaClient,
438
596
  identifier,
439
- dimensions
597
+ dimensions,
598
+ featureFlags
440
599
  } = this.props;
441
600
  const {
442
- isCardVisible
601
+ isCardVisible,
602
+ cardPreview,
603
+ status,
604
+ fileState,
605
+ isBannedLocalPreview,
606
+ previewDidRender
443
607
  } = this.state;
444
608
  const isDifferent = isDifferentIdentifier(prevIdentifier, identifier);
609
+ const turnedVisible = !prevIsCardVisible && isCardVisible;
610
+ const isNewMediaClient = prevMediaClient !== mediaClient;
445
611
 
446
- if (prevIsCardVisible !== isCardVisible && isCardVisible || prevMediaClient !== mediaClient || isDifferent || this.shouldRefetchImage(prevDimensions, dimensions)) {
612
+ if (isExternalImageIdentifier(identifier) && isDifferent) {
447
613
  this.fireCommencedEvent();
448
- this.updateStateForIdentifier();
614
+ const {
615
+ dataURI
616
+ } = identifier;
617
+ this.setState({
618
+ status: 'loading-preview',
619
+ cardPreview: {
620
+ dataURI,
621
+ orientation: 1,
622
+ source: 'external'
623
+ },
624
+ isCardVisible: true
625
+ });
626
+ }
627
+
628
+ if (isFileIdentifier(identifier) && (turnedVisible || !!this.subscription && (isNewMediaClient || isDifferent))) {
629
+ this.updateStateForIdentifier(identifier);
449
630
  }
450
631
 
451
632
  if (this.state.status !== prevState.status) {
452
- const {
453
- status,
454
- cardPreview,
455
- error
456
- } = this.state;
457
- const {
458
- createAnalyticsEvent
459
- } = this.props;
460
- createAnalyticsEvent && fireOperationalEvent(createAnalyticsEvent, status, this.fileAttributes, {
461
- cardPreview,
462
- error
633
+ this.fireOperationalEvent();
634
+
635
+ if (this.state.status === 'complete' || this.fileAttributes.fileMediatype === 'video' && !!cardPreview && this.state.status === 'processing') {
636
+ this.fireScreenEvent();
637
+ }
638
+ }
639
+
640
+ if (isFileIdentifier(identifier) && fileState && shouldResolvePreview({
641
+ status,
642
+ fileState,
643
+ dimensions,
644
+ prevDimensions,
645
+ featureFlags,
646
+ hasCardPreview: !!cardPreview,
647
+ isBannedLocalPreview
648
+ })) {
649
+ this.resolvePreview(identifier, fileState);
650
+ }
651
+
652
+ if (turnedVisible && this.props.ssr && !!cardPreview && isSSRClientPreview(cardPreview) && isFileIdentifier(identifier)) {
653
+ // Since the SSR preview brings the token in the query params,
654
+ // We need to fetch the remote preview to be able to cache it,
655
+ this.setCacheSSRPreview(identifier);
656
+ }
657
+
658
+ if (previewDidRender && // We should't complete if status is uploading
659
+ ['loading-preview', 'processing'].includes(status)) {
660
+ this.safeSetState({
661
+ status: 'complete'
463
662
  });
663
+ this.unsubscribe();
464
664
  }
465
665
  }
466
666
 
467
667
  componentWillUnmount() {
468
668
  this.hasBeenMounted = false;
469
669
  this.unsubscribe();
470
- document.removeEventListener('copy', this.onCopyListener);
670
+ getDocument().removeEventListener('copy', this.fireCopiedEvent);
471
671
  }
472
672
 
473
- updateStateForIdentifier() {
474
- const {
475
- mediaClient,
476
- identifier
477
- } = this.props;
478
- const {
479
- isCardVisible
480
- } = this.state;
481
-
482
- if (!isCardVisible) {
483
- return;
484
- }
485
-
486
- if (identifier.mediaItemType === 'file') {
487
- this.unsubscribe();
488
- this.subscribeInternalFile(identifier, mediaClient);
489
- }
673
+ updateStateForIdentifier(identifier) {
674
+ this.fireCommencedEvent();
675
+ this.subscribeInternalFile(identifier);
490
676
  }
491
677
 
492
- get requestedDimensions() {
678
+ subscribeInternalFile(identifier) {
493
679
  const {
494
- dimensions
680
+ mediaClient
495
681
  } = this.props;
496
682
  const {
497
- cardRef
683
+ isBannedLocalPreview
498
684
  } = this.state;
499
- const options = {
500
- dimensions,
501
- element: cardRef
502
- };
503
- const width = getDataURIDimension('width', options);
504
- const height = getDataURIDimension('height', options);
505
- return {
506
- width,
507
- height
508
- };
509
- }
510
-
511
- subscribeInternalFile(identifier, mediaClient) {
512
685
  const {
513
686
  id,
514
687
  collectionName,
515
688
  occurrenceKey
516
689
  } = identifier;
690
+ this.unsubscribe();
517
691
  this.subscription = mediaClient.file.getFileState(id, {
518
692
  collectionName,
519
693
  occurrenceKey
520
694
  }).subscribe({
521
- next: async fileState => {
522
- this.lastFileState = fileState;
523
- const thisCardStatusUpdateTimestamp = (performance || Date).now();
524
- const filePreviewStatus = extractFilePreviewStatus(fileState, this.props.featureFlags);
525
- let status = getCardStatus(fileState.status, filePreviewStatus);
526
- this.safeSetState({
527
- fileState
528
- });
529
- let cardPreview;
530
- let error;
531
-
532
- if (shouldGetCardPreview(status, filePreviewStatus)) {
533
- try {
534
- cardPreview = await getCardPreview(this.getCardPreviewParams(id, collectionName, fileState));
535
-
536
- if (['loading-preview', 'processing'].includes(status)) {
537
- status = 'complete';
538
- }
539
- } catch (e) {
540
- const wrappedError = ensureMediaCardError('preview-fetch', e);
541
- /**
542
- * If remote preview fails, we set status 'error'
543
- * If the local preview fails (i.e, no remote preview available),
544
- * we can stay in the same status until there is a remote preview available
545
- * */
546
-
547
- if (isRemotePreviewError(wrappedError)) {
548
- status = 'error';
549
- error = wrappedError;
550
- }
551
- }
552
- }
553
-
554
- if (this.isLatestCardStatusUpdate(thisCardStatusUpdateTimestamp)) {
555
- // These status and progress must not override values representing more recent FileState
556
-
557
- /* next() start some await() delay in next() status & progress update
558
- * ------- ------------------ ------------------------
559
- * |----[1]FileState:uploading------>| |
560
- * | | |
561
- * |----[2]FileState:uploading------>| |
562
- * | | |
563
- * | |----[2]FileState:uploading------>| Update status to `uploading`
564
- * |----[3]FileState:processing----->| |
565
- * | |----[3]FileState:processing----->| Update status to `complete`
566
- * | | |
567
- * | |----[1]FileState:uploading------>| We do not want to update status to `uploading` again!
568
- *
569
- */
570
- if (status === 'error' && isErrorFileState(fileState) && !error) {
571
- error = new MediaCardError('error-file-state', new Error(fileState.message));
572
- }
573
-
574
- this.safeSetState({
575
- status,
576
- cardPreview,
577
- progress: status === 'uploading' && fileState.status === 'uploading' ? fileState.progress : 1,
578
- error: status === 'error' && error ? error : undefined
579
- });
580
- this.lastCardStatusUpdateTimestamp = thisCardStatusUpdateTimestamp;
581
- }
695
+ next: fileState => {
696
+ const {
697
+ featureFlags
698
+ } = this.props;
699
+ const newState = getCardStateFromFileState(fileState, isBannedLocalPreview, featureFlags);
700
+ this.safeSetState(newState);
582
701
  },
583
702
  error: e => {
584
- // If file state subscription decides that the card is complete
585
- // and later there is an error, we won't change the card's status.
586
- if (this.state.status === 'complete') {
587
- return;
588
- }
589
-
590
- const errorReason = this.fileAttributes.fileStatus === 'uploading' ? 'upload' : 'metadata-fetch';
703
+ const errorReason = this.state.status === 'uploading' ? 'upload' : 'metadata-fetch';
591
704
  const error = new MediaCardError(errorReason, e);
592
705
  this.safeSetState({
593
706
  error,
594
707
  status: 'error'
595
708
  });
596
- this.lastCardStatusUpdateTimestamp = (performance || Date).now();
597
709
  }
598
710
  });
599
711
  }
600
712
 
601
- get metadata() {
713
+ get requestedDimensions() {
602
714
  const {
603
- identifier
715
+ dimensions
604
716
  } = this.props;
605
- return isFileIdentifier(identifier) ? this.state.fileState ? getFileDetails(this.state.fileState) : {
606
- id: identifier.id
607
- } : {
608
- id: identifier.mediaItemType,
609
- name: identifier.name || identifier.dataURI,
610
- mediaType: 'image'
611
- };
717
+ const {
718
+ cardRef: element
719
+ } = this.state || {};
720
+ return getRequestedDimensions({
721
+ dimensions,
722
+ element
723
+ });
724
+ }
725
+
726
+ get metadata() {
727
+ var _this$state;
728
+
729
+ return getFileDetails(this.props.identifier, (_this$state = this.state) === null || _this$state === void 0 ? void 0 : _this$state.fileState);
612
730
  }
613
731
 
614
732
  get fileAttributes() {
615
- var _this$lastFileState;
733
+ var _this$state2, _this$state2$fileStat;
616
734
 
617
- return getFileAttributes(this.metadata, (_this$lastFileState = this.lastFileState) === null || _this$lastFileState === void 0 ? void 0 : _this$lastFileState.status);
735
+ 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);
618
736
  }
619
737
 
620
- fireCommencedEvent() {
621
- if (!this.state.isCardVisible) {
622
- return;
623
- }
738
+ fireOperationalEvent() {
739
+ const {
740
+ status,
741
+ error
742
+ } = this.state;
743
+ const {
744
+ createAnalyticsEvent
745
+ } = this.props;
746
+ createAnalyticsEvent && fireOperationalEvent(createAnalyticsEvent, status, this.fileAttributes, this.getPerformanceAttributes(), error);
747
+ }
624
748
 
749
+ fireCommencedEvent() {
750
+ this.timeElapsedTillCommenced = performance.now();
625
751
  const {
626
752
  createAnalyticsEvent
627
753
  } = this.props;
628
- const payload = getRenderCommencedEventPayload(this.fileAttributes);
629
- fireMediaCardEvent(payload, createAnalyticsEvent);
754
+ createAnalyticsEvent && fireCommencedEvent(createAnalyticsEvent, this.fileAttributes, {
755
+ overall: {
756
+ durationSincePageStart: this.timeElapsedTillCommenced
757
+ }
758
+ });
630
759
  }
631
760
 
632
761
  get actions() {
@@ -657,19 +786,14 @@ export class CardBase extends Component {
657
786
  }
658
787
 
659
788
  render() {
660
- var _this$lastFileState2;
661
-
662
789
  const {
663
790
  isPlayingFile,
664
791
  mediaViewerSelectedItem
665
792
  } = this.state;
666
793
  const innerContent = /*#__PURE__*/React.createElement(React.Fragment, null, isPlayingFile ? this.renderInlinePlayer() : this.renderCard(), mediaViewerSelectedItem ? this.renderMediaViewer() : null);
667
- const content = this.context.intl ? innerContent : /*#__PURE__*/React.createElement(IntlProvider, {
794
+ return this.context.intl ? innerContent : /*#__PURE__*/React.createElement(IntlProvider, {
668
795
  locale: "en"
669
796
  }, innerContent);
670
- return /*#__PURE__*/React.createElement(FileAttributesProvider, {
671
- data: getFileAttributes(this.metadata, (_this$lastFileState2 = this.lastFileState) === null || _this$lastFileState2 === void 0 ? void 0 : _this$lastFileState2.status)
672
- }, content);
673
797
  }
674
798
 
675
799
  }
@@ -688,28 +812,6 @@ _defineProperty(CardBase, "contextTypes", {
688
812
  intl: intlShape
689
813
  });
690
814
 
691
- _defineProperty(CardBase, "getDerivedStateFromProps", props => {
692
- const {
693
- identifier
694
- } = props;
695
-
696
- if (identifier.mediaItemType === 'external-image') {
697
- const {
698
- dataURI
699
- } = identifier;
700
- return {
701
- status: 'complete',
702
- cardPreview: {
703
- dataURI,
704
- orientation: 1,
705
- source: 'external'
706
- }
707
- };
708
- }
709
-
710
- return null;
711
- });
712
-
713
815
  export const Card = withMediaAnalyticsContext({
714
816
  packageVersion,
715
817
  packageName,