@atlaskit/media-card 77.2.3 → 77.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 (42) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/cjs/card/card.js +1 -1
  3. package/dist/cjs/card/media-card-analytics-error-boundary.js +1 -1
  4. package/dist/cjs/card/ui/imageRenderer/imageRenderer.js +6 -3
  5. package/dist/cjs/card/v2/cardV2.js +18 -1037
  6. package/dist/cjs/card/v2/externalImageCard.js +299 -0
  7. package/dist/cjs/card/v2/fileCard.js +1001 -0
  8. package/dist/cjs/inline/loader.js +1 -1
  9. package/dist/cjs/utils/ufoExperiences.js +1 -1
  10. package/dist/cjs/utils/useCurrentValueRef.js +12 -0
  11. package/dist/cjs/utils/usePrevious.js +14 -0
  12. package/dist/es2019/card/card.js +1 -1
  13. package/dist/es2019/card/media-card-analytics-error-boundary.js +1 -1
  14. package/dist/es2019/card/ui/imageRenderer/imageRenderer.js +6 -3
  15. package/dist/es2019/card/v2/cardV2.js +17 -1021
  16. package/dist/es2019/card/v2/externalImageCard.js +261 -0
  17. package/dist/es2019/card/v2/fileCard.js +881 -0
  18. package/dist/es2019/inline/loader.js +1 -1
  19. package/dist/es2019/utils/ufoExperiences.js +1 -1
  20. package/dist/es2019/utils/useCurrentValueRef.js +6 -0
  21. package/dist/es2019/utils/usePrevious.js +8 -0
  22. package/dist/esm/card/card.js +1 -1
  23. package/dist/esm/card/media-card-analytics-error-boundary.js +1 -1
  24. package/dist/esm/card/ui/imageRenderer/imageRenderer.js +6 -3
  25. package/dist/esm/card/v2/cardV2.js +19 -1036
  26. package/dist/esm/card/v2/externalImageCard.js +289 -0
  27. package/dist/esm/card/v2/fileCard.js +991 -0
  28. package/dist/esm/inline/loader.js +1 -1
  29. package/dist/esm/utils/ufoExperiences.js +1 -1
  30. package/dist/esm/utils/useCurrentValueRef.js +6 -0
  31. package/dist/esm/utils/usePrevious.js +8 -0
  32. package/dist/types/card/v2/cardV2.d.ts +4 -60
  33. package/dist/types/card/v2/externalImageCard.d.ts +14 -0
  34. package/dist/types/card/v2/fileCard.d.ts +19 -0
  35. package/dist/types/utils/useCurrentValueRef.d.ts +2 -0
  36. package/dist/types/utils/usePrevious.d.ts +1 -0
  37. package/dist/types-ts4.5/card/v2/cardV2.d.ts +4 -60
  38. package/dist/types-ts4.5/card/v2/externalImageCard.d.ts +14 -0
  39. package/dist/types-ts4.5/card/v2/fileCard.d.ts +19 -0
  40. package/dist/types-ts4.5/utils/useCurrentValueRef.d.ts +2 -0
  41. package/dist/types-ts4.5/utils/usePrevious.d.ts +1 -0
  42. package/package.json +2 -2
@@ -0,0 +1,261 @@
1
+ import { globalMediaEventEmitter } from '@atlaskit/media-client';
2
+ import { getRandomHex } from '@atlaskit/media-common';
3
+ import { MediaViewer } from '@atlaskit/media-viewer';
4
+ import React, { useEffect, useMemo, useRef, useState } from 'react';
5
+ import ReactDOM from 'react-dom';
6
+ import { ImageLoadError } from '../../errors';
7
+ import getDocument from '../../utils/document';
8
+ import { generateUniqueId } from '../../utils/generateUniqueId';
9
+ import { getMediaCardCursor } from '../../utils/getMediaCardCursor';
10
+ import { abortUfoExperience, completeUfoExperience, startUfoExperience } from '../../utils/ufoExperiences';
11
+ import { useCurrentValueRef } from '../../utils/useCurrentValueRef';
12
+ import { usePrevious } from '../../utils/usePrevious';
13
+ import { fireCommencedEvent, fireCopiedEvent, fireOperationalEvent, fireScreenEvent } from '../cardAnalytics';
14
+ import { CardViewV2 } from './cardViewV2';
15
+ export const ExternalImageCard = ({
16
+ mediaClient,
17
+ appearance = 'auto',
18
+ resizeMode = 'crop',
19
+ disableOverlay = false,
20
+ // Media Feature Flag defaults are defined in @atlaskit/media-common
21
+ featureFlags = {},
22
+ identifier,
23
+ dimensions,
24
+ contextId,
25
+ alt,
26
+ actions,
27
+ shouldOpenMediaViewer,
28
+ selectable,
29
+ selected,
30
+ testId,
31
+ titleBoxBgColor,
32
+ titleBoxIcon,
33
+ shouldHideTooltip,
34
+ mediaViewerItems,
35
+ onClick,
36
+ onMouseEnter,
37
+ createAnalyticsEvent
38
+ }) => {
39
+ const internalOccurrenceKey = useMemo(() => generateUniqueId(), []);
40
+ const timeElapsedTillCommenced = useMemo(() => performance.now(), []);
41
+
42
+ // Generate unique traceId for file
43
+ const traceContext = useMemo(() => ({
44
+ traceId: getRandomHex(8)
45
+ }), []);
46
+ const [cardElement, setCardElement] = useState(null);
47
+ const fileStateFlagsRef = useRef({
48
+ wasStatusUploading: false,
49
+ wasStatusProcessing: false
50
+ });
51
+ const fireCommencedEventRef = useCurrentValueRef(() => {
52
+ createAnalyticsEvent && fireCommencedEvent(createAnalyticsEvent, fileAttributes, {
53
+ overall: {
54
+ durationSincePageStart: timeElapsedTillCommenced
55
+ }
56
+ }, traceContext);
57
+ startUfoExperience(internalOccurrenceKey);
58
+ });
59
+ const [status, setStatus] = useState('loading-preview');
60
+ useEffect(() => {
61
+ fireCommencedEventRef.current();
62
+ setStatus('loading-preview');
63
+ }, [fireCommencedEventRef, identifier]);
64
+ const cardPreview = useMemo(() => ({
65
+ dataURI: identifier.dataURI,
66
+ orientation: 1,
67
+ source: 'external'
68
+ }), [identifier.dataURI]);
69
+ const metadata = {
70
+ id: identifier.mediaItemType,
71
+ name: identifier.name || identifier.dataURI,
72
+ mediaType: 'image'
73
+ };
74
+ const fileAttributes = {
75
+ fileMediatype: 'image',
76
+ fileId: metadata.id
77
+ };
78
+
79
+ // for analytics
80
+ const ssrReliability = {
81
+ server: {
82
+ status: 'unknown'
83
+ },
84
+ client: {
85
+ status: 'unknown'
86
+ }
87
+ };
88
+ const [previewDidRender, setPreviewDidRender] = useState(false);
89
+ const [error, setError] = useState();
90
+ const [mediaViewerSelectedItem, setMediaViewerSelectedItem] = useState(null);
91
+
92
+ //----------------------------------------------------------------//
93
+ //---------------------- Analytics ------------------------------//
94
+ //----------------------------------------------------------------//
95
+
96
+ const fireOperationalEventRef = useCurrentValueRef(() => {
97
+ const timeElapsedTillEvent = performance.now();
98
+ const durationSinceCommenced = timeElapsedTillEvent - timeElapsedTillCommenced;
99
+ const performanceAttributes = {
100
+ overall: {
101
+ durationSincePageStart: timeElapsedTillEvent,
102
+ durationSinceCommenced
103
+ }
104
+ };
105
+ createAnalyticsEvent && fireOperationalEvent(createAnalyticsEvent, status, fileAttributes, performanceAttributes, ssrReliability, error, traceContext, undefined);
106
+ completeUfoExperience(internalOccurrenceKey, status, fileAttributes, fileStateFlagsRef.current, ssrReliability, error);
107
+ });
108
+ const fireScreenEventRef = useCurrentValueRef(() => {
109
+ createAnalyticsEvent && fireScreenEvent(createAnalyticsEvent, fileAttributes);
110
+ });
111
+ const fireAbortedEventRef = useCurrentValueRef(() => {
112
+ // UFO won't abort if it's already in a final state (succeeded, failed, aborted, etc)
113
+ abortUfoExperience(internalOccurrenceKey, {
114
+ fileAttributes,
115
+ fileStateFlags: fileStateFlagsRef === null || fileStateFlagsRef === void 0 ? void 0 : fileStateFlagsRef.current,
116
+ ssrReliability: ssrReliability
117
+ });
118
+ });
119
+
120
+ //----------------------------------------------------------------//
121
+ //------------------------ useEffects ----------------------------//
122
+ //----------------------------------------------------------------//
123
+
124
+ useEffect(() => {
125
+ var _getDocument;
126
+ const fireCopiedCardEvent = () => {
127
+ cardElement && createAnalyticsEvent && fireCopiedEvent(createAnalyticsEvent, metadata.id, cardElement);
128
+ };
129
+
130
+ // we add a listener for each of the cards on the page
131
+ // and then check if the triggered listener is from the card
132
+ // that contains a div in current window.getSelection()
133
+ // won't work in IE11
134
+ (_getDocument = getDocument()) === null || _getDocument === void 0 ? void 0 : _getDocument.addEventListener('copy', fireCopiedCardEvent);
135
+ return () => {
136
+ var _getDocument2;
137
+ (_getDocument2 = getDocument()) === null || _getDocument2 === void 0 ? void 0 : _getDocument2.removeEventListener('copy', fireCopiedCardEvent);
138
+ };
139
+ }, [cardElement, createAnalyticsEvent, metadata.id]);
140
+ const prevStatus = usePrevious(status);
141
+ useEffect(() => {
142
+ if (prevStatus !== undefined && status !== prevStatus) {
143
+ fireOperationalEventRef.current();
144
+ }
145
+ }, [fireOperationalEventRef, prevStatus, status]);
146
+ useEffect(() => {
147
+ if (previewDidRender && status === 'loading-preview') {
148
+ setStatus('complete');
149
+ }
150
+ }, [previewDidRender, status]);
151
+ useEffect(() => {
152
+ if (prevStatus !== undefined && status !== prevStatus) {
153
+ if (status === 'complete') {
154
+ fireScreenEventRef.current();
155
+ }
156
+ }
157
+ }, [fireScreenEventRef, prevStatus, status]);
158
+ useEffect(() => {
159
+ return () => {
160
+ // eslint-disable-next-line react-hooks/exhaustive-deps
161
+ fireAbortedEventRef.current();
162
+ };
163
+ }, [fireAbortedEventRef]);
164
+
165
+ //----------------------------------------------------------------//
166
+ //---------------------- Render Functions ------------------------//
167
+ //----------------------------------------------------------------//
168
+
169
+ const renderMediaViewer = () => {
170
+ if (!mediaViewerSelectedItem) {
171
+ return;
172
+ }
173
+ return /*#__PURE__*/ReactDOM.createPortal( /*#__PURE__*/React.createElement(MediaViewer, {
174
+ collectionName: '',
175
+ items: mediaViewerItems || [],
176
+ mediaClientConfig: mediaClient.config,
177
+ selectedItem: mediaViewerSelectedItem,
178
+ onClose: () => {
179
+ setMediaViewerSelectedItem(null);
180
+ },
181
+ contextId: contextId,
182
+ featureFlags: featureFlags
183
+ }), document.body);
184
+ };
185
+
186
+ //----------------------------------------------------------------//
187
+ //-------------------------- RENDER ------------------------------//
188
+ //----------------------------------------------------------------//
189
+
190
+ const mediaCardCursor = getMediaCardCursor(false, !!shouldOpenMediaViewer, status === 'error', !!cardPreview, metadata.mediaType);
191
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(CardViewV2, {
192
+ status: status,
193
+ error: error,
194
+ mediaItemType: identifier.mediaItemType,
195
+ metadata: metadata,
196
+ cardPreview: cardPreview,
197
+ alt: alt,
198
+ appearance: appearance,
199
+ resizeMode: resizeMode,
200
+ dimensions: dimensions,
201
+ actions: actions,
202
+ selectable: selectable,
203
+ selected: selected,
204
+ onClick: (event, analyticsEvent) => {
205
+ if (onClick) {
206
+ const cardEvent = {
207
+ event,
208
+ mediaItemDetails: metadata
209
+ };
210
+ onClick(cardEvent, analyticsEvent);
211
+ }
212
+ if (shouldOpenMediaViewer) {
213
+ setMediaViewerSelectedItem({
214
+ mediaItemType: 'external-image',
215
+ dataURI: identifier.dataURI,
216
+ name: identifier.name
217
+ });
218
+ }
219
+ },
220
+ onMouseEnter: event => {
221
+ onMouseEnter === null || onMouseEnter === void 0 ? void 0 : onMouseEnter({
222
+ event,
223
+ mediaItemDetails: metadata
224
+ });
225
+ },
226
+ disableOverlay: disableOverlay,
227
+ onDisplayImage: () => {
228
+ const payloadPart = {
229
+ fileId: identifier.dataURI,
230
+ isUserCollection: false
231
+ };
232
+ globalMediaEventEmitter.emit('media-viewed', {
233
+ viewingLevel: 'minimal',
234
+ ...payloadPart
235
+ });
236
+ },
237
+ innerRef: setCardElement,
238
+ testId: testId,
239
+ featureFlags: featureFlags,
240
+ titleBoxBgColor: titleBoxBgColor,
241
+ titleBoxIcon: titleBoxIcon,
242
+ onImageError: newCardPreview => {
243
+ // If the dataURI has been replaced, we can dismiss this error
244
+ if ((newCardPreview === null || newCardPreview === void 0 ? void 0 : newCardPreview.dataURI) !== (cardPreview === null || cardPreview === void 0 ? void 0 : cardPreview.dataURI)) {
245
+ return;
246
+ }
247
+ const error = new ImageLoadError(newCardPreview === null || newCardPreview === void 0 ? void 0 : newCardPreview.source);
248
+ setStatus('error');
249
+ setError(error);
250
+ },
251
+ onImageLoad: newCardPreview => {
252
+ // If the dataURI has been replaced, we can dismiss this callback
253
+ if ((newCardPreview === null || newCardPreview === void 0 ? void 0 : newCardPreview.dataURI) !== (cardPreview === null || cardPreview === void 0 ? void 0 : cardPreview.dataURI)) {
254
+ return;
255
+ }
256
+ setPreviewDidRender(true);
257
+ },
258
+ mediaCardCursor: mediaCardCursor,
259
+ shouldHideTooltip: shouldHideTooltip
260
+ }), mediaViewerSelectedItem ? renderMediaViewer() : null);
261
+ };