@atlaskit/media-card 77.4.10 → 77.5.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 (131) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/cjs/card/card.js +1 -1
  3. package/dist/cjs/card/cardLoader.js +3 -47
  4. package/dist/cjs/card/cardWithMediaClient.js +26 -0
  5. package/dist/cjs/card/media-card-analytics-error-boundary.js +1 -1
  6. package/dist/cjs/card/v2/cardV2.js +1 -1
  7. package/dist/cjs/card/v2/cardV2Loader.js +3 -54
  8. package/dist/cjs/card/v2/cardViewV2.js +7 -6
  9. package/dist/cjs/card/v2/cardWithMediaClientV2.js +34 -0
  10. package/dist/cjs/card/v2/useFilePreview/errors.js +132 -0
  11. package/dist/cjs/card/v2/useFilePreview/getPreview/cache.js +39 -0
  12. package/dist/cjs/card/v2/useFilePreview/getPreview/filePreviewStatus.js +45 -0
  13. package/dist/cjs/card/v2/useFilePreview/getPreview/getPreview.js +119 -0
  14. package/dist/cjs/card/v2/useFilePreview/getPreview/helpers.js +167 -0
  15. package/dist/cjs/card/v2/useFilePreview/getPreview/index.js +62 -0
  16. package/dist/cjs/card/v2/useFilePreview/getPreview/objectURLCache.js +85 -0
  17. package/dist/cjs/card/v2/useFilePreview/getPreview/videoSnapshot.js +58 -0
  18. package/dist/cjs/card/v2/useFilePreview/globalScope/getSSRData.js +14 -0
  19. package/dist/cjs/card/v2/useFilePreview/globalScope/globalScope.js +66 -0
  20. package/dist/cjs/card/v2/useFilePreview/globalScope/index.js +37 -0
  21. package/dist/cjs/card/v2/useFilePreview/globalScope/printScript.js +32 -0
  22. package/dist/cjs/card/v2/useFilePreview/globalScope/types.js +5 -0
  23. package/dist/cjs/card/v2/useFilePreview/helpers.js +64 -0
  24. package/dist/cjs/card/v2/useFilePreview/index.js +12 -0
  25. package/dist/cjs/card/v2/useFilePreview/types.js +5 -0
  26. package/dist/cjs/card/v2/{useFilePreview.js → useFilePreview/useFilePreview.js} +58 -194
  27. package/dist/cjs/inline/loader.js +1 -1
  28. package/dist/cjs/utils/ufoExperiences.js +1 -1
  29. package/dist/es2019/card/card.js +1 -1
  30. package/dist/es2019/card/cardLoader.js +2 -32
  31. package/dist/es2019/card/cardWithMediaClient.js +21 -0
  32. package/dist/es2019/card/media-card-analytics-error-boundary.js +1 -1
  33. package/dist/es2019/card/v2/cardV2.js +1 -1
  34. package/dist/es2019/card/v2/cardV2Loader.js +2 -35
  35. package/dist/es2019/card/v2/cardViewV2.js +7 -6
  36. package/dist/es2019/card/v2/cardWithMediaClientV2.js +25 -0
  37. package/dist/es2019/card/v2/useFilePreview/errors.js +81 -0
  38. package/dist/es2019/card/v2/useFilePreview/getPreview/cache.js +30 -0
  39. package/dist/es2019/card/v2/useFilePreview/getPreview/filePreviewStatus.js +43 -0
  40. package/dist/es2019/card/v2/useFilePreview/getPreview/getPreview.js +75 -0
  41. package/dist/es2019/card/v2/useFilePreview/getPreview/helpers.js +76 -0
  42. package/dist/es2019/card/v2/useFilePreview/getPreview/index.js +3 -0
  43. package/dist/es2019/card/v2/useFilePreview/getPreview/objectURLCache.js +44 -0
  44. package/dist/es2019/card/v2/useFilePreview/getPreview/videoSnapshot.js +36 -0
  45. package/dist/es2019/card/v2/useFilePreview/globalScope/getSSRData.js +8 -0
  46. package/dist/es2019/card/v2/useFilePreview/globalScope/globalScope.js +48 -0
  47. package/dist/es2019/card/v2/useFilePreview/globalScope/index.js +2 -0
  48. package/dist/es2019/card/v2/useFilePreview/globalScope/printScript.js +16 -0
  49. package/dist/es2019/card/v2/useFilePreview/globalScope/types.js +1 -0
  50. package/dist/es2019/card/v2/useFilePreview/helpers.js +61 -0
  51. package/dist/es2019/card/v2/useFilePreview/index.js +1 -0
  52. package/dist/es2019/card/v2/useFilePreview/types.js +1 -0
  53. package/dist/es2019/card/v2/{useFilePreview.js → useFilePreview/useFilePreview.js} +18 -132
  54. package/dist/es2019/inline/loader.js +1 -1
  55. package/dist/es2019/utils/ufoExperiences.js +1 -1
  56. package/dist/esm/card/card.js +1 -1
  57. package/dist/esm/card/cardLoader.js +3 -43
  58. package/dist/esm/card/cardWithMediaClient.js +19 -0
  59. package/dist/esm/card/media-card-analytics-error-boundary.js +1 -1
  60. package/dist/esm/card/v2/cardV2.js +1 -1
  61. package/dist/esm/card/v2/cardV2Loader.js +3 -50
  62. package/dist/esm/card/v2/cardViewV2.js +7 -6
  63. package/dist/esm/card/v2/cardWithMediaClientV2.js +27 -0
  64. package/dist/esm/card/v2/useFilePreview/errors.js +124 -0
  65. package/dist/esm/card/v2/useFilePreview/getPreview/cache.js +32 -0
  66. package/dist/esm/card/v2/useFilePreview/getPreview/filePreviewStatus.js +40 -0
  67. package/dist/esm/card/v2/useFilePreview/getPreview/getPreview.js +112 -0
  68. package/dist/esm/card/v2/useFilePreview/getPreview/helpers.js +160 -0
  69. package/dist/esm/card/v2/useFilePreview/getPreview/index.js +3 -0
  70. package/dist/esm/card/v2/useFilePreview/getPreview/objectURLCache.js +78 -0
  71. package/dist/esm/card/v2/useFilePreview/getPreview/videoSnapshot.js +51 -0
  72. package/dist/esm/card/v2/useFilePreview/globalScope/getSSRData.js +8 -0
  73. package/dist/esm/card/v2/useFilePreview/globalScope/globalScope.js +56 -0
  74. package/dist/esm/card/v2/useFilePreview/globalScope/index.js +2 -0
  75. package/dist/esm/card/v2/useFilePreview/globalScope/printScript.js +25 -0
  76. package/dist/esm/card/v2/useFilePreview/globalScope/types.js +1 -0
  77. package/dist/esm/card/v2/useFilePreview/helpers.js +57 -0
  78. package/dist/esm/card/v2/useFilePreview/index.js +1 -0
  79. package/dist/esm/card/v2/useFilePreview/types.js +1 -0
  80. package/dist/esm/card/v2/{useFilePreview.js → useFilePreview/useFilePreview.js} +41 -177
  81. package/dist/esm/inline/loader.js +1 -1
  82. package/dist/esm/utils/ufoExperiences.js +1 -1
  83. package/dist/types/card/cardLoader.d.ts +1 -3
  84. package/dist/types/card/cardSwitcher.d.ts +1 -1
  85. package/dist/types/card/cardWithMediaClient.d.ts +3 -0
  86. package/dist/types/card/types.d.ts +3 -0
  87. package/dist/types/card/v2/cardV2Loader.d.ts +1 -1
  88. package/dist/types/card/v2/cardViewV2.d.ts +5 -4
  89. package/dist/types/card/v2/cardWithMediaClientV2.d.ts +3 -0
  90. package/dist/types/card/v2/useFilePreview/errors.d.ts +38 -0
  91. package/dist/types/card/v2/useFilePreview/getPreview/cache.d.ts +21 -0
  92. package/dist/types/card/v2/useFilePreview/getPreview/filePreviewStatus.d.ts +4 -0
  93. package/dist/types/card/v2/useFilePreview/getPreview/getPreview.d.ts +9 -0
  94. package/dist/types/card/v2/useFilePreview/getPreview/helpers.d.ts +10 -0
  95. package/dist/types/card/v2/useFilePreview/getPreview/index.d.ts +3 -0
  96. package/dist/types/card/v2/useFilePreview/getPreview/objectURLCache.d.ts +12 -0
  97. package/dist/types/card/v2/useFilePreview/getPreview/videoSnapshot.d.ts +1 -0
  98. package/dist/types/card/v2/useFilePreview/globalScope/getSSRData.d.ts +3 -0
  99. package/dist/types/card/v2/useFilePreview/globalScope/globalScope.d.ts +15 -0
  100. package/dist/types/card/v2/useFilePreview/globalScope/index.d.ts +4 -0
  101. package/dist/types/card/v2/useFilePreview/globalScope/printScript.d.ts +2 -0
  102. package/dist/types/card/v2/useFilePreview/globalScope/types.d.ts +8 -0
  103. package/dist/types/card/v2/useFilePreview/helpers.d.ts +11 -0
  104. package/dist/types/card/v2/useFilePreview/index.d.ts +2 -0
  105. package/dist/types/card/v2/useFilePreview/types.d.ts +18 -0
  106. package/dist/{types-ts4.5/card/v2 → types/card/v2/useFilePreview}/useFilePreview.d.ts +8 -8
  107. package/dist/types-ts4.5/card/cardLoader.d.ts +1 -3
  108. package/dist/types-ts4.5/card/cardSwitcher.d.ts +1 -1
  109. package/dist/types-ts4.5/card/cardWithMediaClient.d.ts +3 -0
  110. package/dist/types-ts4.5/card/types.d.ts +3 -0
  111. package/dist/types-ts4.5/card/v2/cardV2Loader.d.ts +1 -1
  112. package/dist/types-ts4.5/card/v2/cardViewV2.d.ts +5 -4
  113. package/dist/types-ts4.5/card/v2/cardWithMediaClientV2.d.ts +3 -0
  114. package/dist/types-ts4.5/card/v2/useFilePreview/errors.d.ts +38 -0
  115. package/dist/types-ts4.5/card/v2/useFilePreview/getPreview/cache.d.ts +21 -0
  116. package/dist/types-ts4.5/card/v2/useFilePreview/getPreview/filePreviewStatus.d.ts +4 -0
  117. package/dist/types-ts4.5/card/v2/useFilePreview/getPreview/getPreview.d.ts +9 -0
  118. package/dist/types-ts4.5/card/v2/useFilePreview/getPreview/helpers.d.ts +10 -0
  119. package/dist/types-ts4.5/card/v2/useFilePreview/getPreview/index.d.ts +3 -0
  120. package/dist/types-ts4.5/card/v2/useFilePreview/getPreview/objectURLCache.d.ts +12 -0
  121. package/dist/types-ts4.5/card/v2/useFilePreview/getPreview/videoSnapshot.d.ts +1 -0
  122. package/dist/types-ts4.5/card/v2/useFilePreview/globalScope/getSSRData.d.ts +3 -0
  123. package/dist/types-ts4.5/card/v2/useFilePreview/globalScope/globalScope.d.ts +15 -0
  124. package/dist/types-ts4.5/card/v2/useFilePreview/globalScope/index.d.ts +4 -0
  125. package/dist/types-ts4.5/card/v2/useFilePreview/globalScope/printScript.d.ts +2 -0
  126. package/dist/types-ts4.5/card/v2/useFilePreview/globalScope/types.d.ts +8 -0
  127. package/dist/types-ts4.5/card/v2/useFilePreview/helpers.d.ts +11 -0
  128. package/dist/types-ts4.5/card/v2/useFilePreview/index.d.ts +2 -0
  129. package/dist/types-ts4.5/card/v2/useFilePreview/types.d.ts +18 -0
  130. package/dist/{types/card/v2 → types-ts4.5/card/v2/useFilePreview}/useFilePreview.d.ts +8 -8
  131. package/package.json +1 -1
@@ -0,0 +1,25 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ import React from 'react';
3
+ import { withMediaClient } from '@atlaskit/media-client-react';
4
+ import MediaCardAnalyticsErrorBoundary from '../media-card-analytics-error-boundary';
5
+ import { CardV2 } from './cardV2';
6
+ export const CardWithMediaClientV2 = props => {
7
+ const {
8
+ dimensions,
9
+ onClick,
10
+ featureFlags
11
+ } = props;
12
+ const Card = React.useMemo(() => {
13
+ return withMediaClient(CardV2);
14
+ }, []);
15
+ const featureFlagsWithMediaCardV2 = React.useMemo(() => ({
16
+ ...featureFlags,
17
+ mediaCardV2: true //used for analytics - internal use only
18
+ }), [featureFlags]);
19
+ return /*#__PURE__*/React.createElement(MediaCardAnalyticsErrorBoundary, {
20
+ dimensions: dimensions,
21
+ onClick: onClick
22
+ }, /*#__PURE__*/React.createElement(Card, _extends({}, props, {
23
+ featureFlags: featureFlagsWithMediaCardV2
24
+ })));
25
+ };
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Primary reason is logged through Data Portal.
3
+ * Make sure all the values are whitelisted in Measure -> Event Regitry -> "mediaCardRender failed" event
4
+ */
5
+
6
+ export class MediaFilePreviewError extends Error {
7
+ constructor(primaryReason, secondaryError) {
8
+ super(primaryReason);
9
+ // https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#support-for-newtarget
10
+ this.primaryReason = primaryReason;
11
+ this.secondaryError = secondaryError;
12
+ Object.setPrototypeOf(this, new.target.prototype);
13
+
14
+ // https://v8.dev/docs/stack-trace-api
15
+ if ('captureStackTrace' in Error) {
16
+ Error.captureStackTrace(this, new.target);
17
+ }
18
+ }
19
+ }
20
+ export class LocalPreviewError extends MediaFilePreviewError {
21
+ constructor(primaryReason, secondaryError) {
22
+ super(primaryReason, secondaryError);
23
+ this.primaryReason = primaryReason;
24
+ this.secondaryError = secondaryError;
25
+ }
26
+ }
27
+ export class RemotePreviewError extends MediaFilePreviewError {
28
+ constructor(primaryReason, secondaryError) {
29
+ super(primaryReason, secondaryError);
30
+ this.primaryReason = primaryReason;
31
+ this.secondaryError = secondaryError;
32
+ }
33
+ }
34
+ export class SsrPreviewError extends MediaFilePreviewError {
35
+ constructor(primaryReason, secondaryError) {
36
+ super(primaryReason, secondaryError);
37
+ this.primaryReason = primaryReason;
38
+ this.secondaryError = secondaryError;
39
+ }
40
+ }
41
+ const getImageLoadPrimaryReason = source => {
42
+ switch (source) {
43
+ case 'cache-remote':
44
+ return 'cache-remote-uri';
45
+ case 'cache-local':
46
+ return 'cache-local-uri';
47
+ case 'external':
48
+ return 'external-uri';
49
+ case 'local':
50
+ return 'local-uri';
51
+ case 'remote':
52
+ return 'remote-uri';
53
+ // This fail reason will come from a bug, most likely.
54
+ default:
55
+ return `unknown-uri`;
56
+ }
57
+ };
58
+ export class ImageLoadError extends MediaFilePreviewError {
59
+ constructor(source) {
60
+ super(getImageLoadPrimaryReason(source));
61
+ }
62
+ }
63
+ export function isMediaFilePreviewError(err) {
64
+ return err instanceof MediaFilePreviewError;
65
+ }
66
+ export const isLocalPreviewError = err => err instanceof LocalPreviewError;
67
+ export const isRemotePreviewError = err => err instanceof RemotePreviewError;
68
+ export const isUnsupportedLocalPreviewError = err => isMediaFilePreviewError(err) && err.primaryReason === 'local-preview-unsupported';
69
+
70
+ // In a try/catch statement, the error caught is the type of unknown.
71
+ // We can use this helper to ensure that the error handled is the type of MediaFilePreviewError if unsure
72
+ // If updatePrimaryReason is true, if it's a MediaFilePreviewError already, it will update it's primary reason
73
+ export const ensureMediaFilePreviewError = (primaryReason, error, updatePrimaryReason) => {
74
+ if (isMediaFilePreviewError(error)) {
75
+ if (updatePrimaryReason && error.primaryReason !== primaryReason) {
76
+ return new MediaFilePreviewError(primaryReason, error.secondaryError);
77
+ }
78
+ return error;
79
+ }
80
+ return new MediaFilePreviewError(primaryReason, error);
81
+ };
@@ -0,0 +1,30 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ import { createObjectURLCache } from './objectURLCache';
3
+
4
+ // Dimensions are used to create a key.
5
+ // Cache is invalidated when different dimensions are provided.
6
+ export const getCacheKey = (id, mode) => {
7
+ const resizeMode = mode || 'crop';
8
+ return [id, resizeMode].join('-');
9
+ };
10
+ export class CardPreviewCacheImpl {
11
+ constructor(previewCache) {
12
+ _defineProperty(this, "get", (id, mode) => {
13
+ const cacheKey = getCacheKey(id, mode);
14
+ return this.previewCache.get(cacheKey);
15
+ });
16
+ _defineProperty(this, "set", (id, mode, cardPreview) => {
17
+ const cacheKey = getCacheKey(id, mode);
18
+ this.previewCache.set(cacheKey, cardPreview);
19
+ });
20
+ _defineProperty(this, "remove", (id, mode) => {
21
+ const cacheKey = getCacheKey(id, mode);
22
+ this.previewCache.remove(cacheKey);
23
+ });
24
+ _defineProperty(this, "clear", () => {
25
+ this.previewCache.clear();
26
+ });
27
+ this.previewCache = previewCache;
28
+ }
29
+ }
30
+ export const mediaFilePreviewCache = new CardPreviewCacheImpl(createObjectURLCache());
@@ -0,0 +1,43 @@
1
+ import { isMimeTypeSupportedByBrowser } from '@atlaskit/media-common';
2
+ import { isPreviewableFileState, isPreviewableType, isImageRepresentationReady } from '@atlaskit/media-client';
3
+ import { isSupportedLocalPreview } from './helpers';
4
+
5
+ // TODO: align these checks with helpers from Media Client
6
+ // https://product-fabric.atlassian.net/browse/BMPT-1300
7
+ export const extractFilePreviewStatus = (fileState, isBannedLocalPreview) => {
8
+ const hasFilesize = 'size' in fileState && !!fileState.size;
9
+ const {
10
+ mediaType
11
+ } = 'mediaType' in fileState && fileState || {};
12
+ const {
13
+ mimeType
14
+ } = 'mimeType' in fileState && fileState || {};
15
+ const isPreviewable = !!mediaType && isPreviewableType(mediaType);
16
+
17
+ // Local preview is available only if it's supported by browser and supported by Media Card (isSupportedLocalPreview)
18
+ // For example, SVGs are mime type NOT supported by browser but media type supported by Media Card (image)
19
+ // Then, local Preview NOT available
20
+ const hasLocalPreview = !isBannedLocalPreview && isPreviewableFileState(fileState) && isSupportedLocalPreview(mediaType) && !!mimeType && isMimeTypeSupportedByBrowser(mimeType);
21
+ const hasRemotePreview = isImageRepresentationReady(fileState);
22
+ const hasPreview = hasLocalPreview || hasRemotePreview;
23
+ const isSupportedByBrowser = !!mimeType && isMimeTypeSupportedByBrowser(mimeType);
24
+ return {
25
+ hasFilesize,
26
+ isPreviewable,
27
+ hasPreview,
28
+ isSupportedByBrowser
29
+ };
30
+ };
31
+
32
+ // CXP-2723 TODO: Review this in relation to removing status from the hook
33
+ export const isPreviewableStatus = (cardStatus, {
34
+ isPreviewable,
35
+ hasPreview,
36
+ isSupportedByBrowser
37
+ }) => {
38
+ return hasPreview && isPreviewable && (cardStatus === 'complete' || cardStatus === 'loading-preview' || cardStatus === 'uploading' ||
39
+ // For Video, we can have local or remote preview while processing.
40
+ // Then, we only want to show the thumbnail if the file is supported by the browser,
41
+ // this way we prevent playing unsupported videos that are not procesed
42
+ cardStatus === 'processing' && isSupportedByBrowser);
43
+ };
@@ -0,0 +1,75 @@
1
+ import { addFileAttrsToUrl } from '@atlaskit/media-client';
2
+ import { mediaFilePreviewCache } from './cache';
3
+ import { getLocalPreview, getRemotePreview } from './helpers';
4
+ import { SsrPreviewError } from '../errors';
5
+ const extendAndCachePreview = (id, mode, preview, mediaBlobUrlAttrs) => {
6
+ let source;
7
+ switch (preview.source) {
8
+ case 'local':
9
+ source = 'cache-local';
10
+ break;
11
+ case 'remote':
12
+ source = 'cache-remote';
13
+ break;
14
+ case 'ssr-server':
15
+ source = 'cache-ssr-server';
16
+ break;
17
+ case 'ssr-client':
18
+ source = 'cache-ssr-client';
19
+ break;
20
+ default:
21
+ source = preview.source;
22
+ }
23
+ // We want to embed some meta context into dataURI for Copy/Paste to work.
24
+ const dataURI = mediaBlobUrlAttrs ? addFileAttrsToUrl(preview.dataURI, mediaBlobUrlAttrs) : preview.dataURI;
25
+ // We store new cardPreview into cache
26
+ mediaFilePreviewCache.set(id, mode, {
27
+ ...preview,
28
+ source,
29
+ dataURI
30
+ });
31
+ return {
32
+ ...preview,
33
+ dataURI
34
+ };
35
+ };
36
+ export const getSSRCardPreview = (ssr, mediaClient, id, params, mediaBlobUrlAttrs) => {
37
+ let dataURI;
38
+ try {
39
+ const rawDataURI = mediaClient.getImageUrlSync(id, params);
40
+ // We want to embed some meta context into dataURI for Copy/Paste to work.
41
+ dataURI = mediaBlobUrlAttrs ? addFileAttrsToUrl(rawDataURI, mediaBlobUrlAttrs) : rawDataURI;
42
+ const source = ssr === 'client' ? 'ssr-client' : 'ssr-server';
43
+ return {
44
+ dataURI,
45
+ source,
46
+ orientation: 1
47
+ };
48
+ } catch (e) {
49
+ const reason = ssr === 'server' ? 'ssr-server-uri' : 'ssr-client-uri';
50
+ throw new SsrPreviewError(reason, e instanceof Error ? e : undefined);
51
+ }
52
+ };
53
+ export const isLocalPreview = preview => {
54
+ const localSources = ['local', 'cache-local'];
55
+ return localSources.includes(preview.source);
56
+ };
57
+ export const isSSRClientPreview = preview => {
58
+ const ssrClientSources = ['ssr-client', 'cache-ssr-client'];
59
+ return ssrClientSources.includes(preview.source);
60
+ };
61
+ export const isSSRDataPreview = preview => preview.source === 'ssr-data';
62
+ export const getAndCacheRemotePreview = async (mediaClient, id, dimensions, params, mediaBlobUrlAttrs, traceContext) => {
63
+ const remotePreview = await getRemotePreview(mediaClient, id, params, traceContext);
64
+ return extendAndCachePreview(id, params.mode, {
65
+ ...remotePreview,
66
+ dimensions
67
+ }, mediaBlobUrlAttrs);
68
+ };
69
+ export const getAndCacheLocalPreview = async (id, filePreview, dimensions, mode, mediaBlobUrlAttrs) => {
70
+ const localPreview = await getLocalPreview(filePreview);
71
+ return extendAndCachePreview(id, mode, {
72
+ ...localPreview,
73
+ dimensions
74
+ }, mediaBlobUrlAttrs);
75
+ };
@@ -0,0 +1,76 @@
1
+ import { takeSnapshot } from './videoSnapshot';
2
+ import { getMediaTypeFromMimeType } from '@atlaskit/media-common';
3
+ import { getOrientation } from '@atlaskit/media-ui';
4
+ import { LocalPreviewError, RemotePreviewError } from '../errors';
5
+ /**
6
+ * This method tells the support for the media
7
+ * types covered in getCardPreviewFromFilePreview
8
+ */
9
+ export const isSupportedLocalPreview = mediaType => mediaType === 'image' || mediaType === 'video';
10
+ const getImageLocalPreview = async value => {
11
+ try {
12
+ const orientation = await getOrientation(value);
13
+ const dataURI = URL.createObjectURL(value);
14
+ return {
15
+ dataURI,
16
+ orientation,
17
+ source: 'local'
18
+ };
19
+ } catch (e) {
20
+ throw new LocalPreviewError('local-preview-image', e instanceof Error ? e : undefined);
21
+ }
22
+ };
23
+ const getVideoLocalPreview = async value => {
24
+ try {
25
+ const dataURI = await takeSnapshot(value);
26
+ return {
27
+ dataURI,
28
+ orientation: 1,
29
+ source: 'local'
30
+ };
31
+ } catch (e) {
32
+ throw new LocalPreviewError('local-preview-video', e instanceof Error ? e : undefined);
33
+ }
34
+ };
35
+ export const getLocalPreview = async filePreview => {
36
+ let value;
37
+ try {
38
+ const resolvedFilePreview = await filePreview;
39
+ value = resolvedFilePreview.value;
40
+ } catch (e) {
41
+ throw new LocalPreviewError('local-preview-rejected', e instanceof Error ? e : undefined);
42
+ }
43
+ if (typeof value === 'string') {
44
+ return {
45
+ dataURI: value,
46
+ orientation: 1,
47
+ source: 'local'
48
+ };
49
+ } else if (value instanceof Blob) {
50
+ const {
51
+ type
52
+ } = value;
53
+ const mediaType = getMediaTypeFromMimeType(type);
54
+ switch (mediaType) {
55
+ case 'image':
56
+ return getImageLocalPreview(value);
57
+ case 'video':
58
+ return getVideoLocalPreview(value);
59
+ default:
60
+ throw new LocalPreviewError('local-preview-unsupported');
61
+ }
62
+ }
63
+ throw new LocalPreviewError('local-preview-unsupported');
64
+ };
65
+ export const getRemotePreview = async (mediaClient, id, params, traceContext) => {
66
+ try {
67
+ const blob = await mediaClient.getImage(id, params, undefined, undefined, traceContext);
68
+ return {
69
+ dataURI: URL.createObjectURL(blob),
70
+ orientation: 1,
71
+ source: 'remote'
72
+ };
73
+ } catch (e) {
74
+ throw new RemotePreviewError('remote-preview-fetch', e instanceof Error ? e : undefined);
75
+ }
76
+ };
@@ -0,0 +1,3 @@
1
+ export { mediaFilePreviewCache } from './cache';
2
+ export { isPreviewableStatus, extractFilePreviewStatus } from './filePreviewStatus';
3
+ export { getSSRCardPreview, isLocalPreview, isSSRClientPreview, isSSRDataPreview, getAndCacheRemotePreview, getAndCacheLocalPreview } from './getPreview';
@@ -0,0 +1,44 @@
1
+ import { LRUMap } from 'lru_map';
2
+ import { EventEmitter2 } from 'eventemitter2';
3
+ export const PREVIEW_CACHE_LRU_SIZE = 50;
4
+ class ExtendedLRUCache extends LRUMap {
5
+ constructor(limit) {
6
+ super(limit);
7
+ this.eventEmitter = new EventEmitter2();
8
+ }
9
+ shift() {
10
+ const entry = super.shift();
11
+ this.eventEmitter.emit('shift', entry);
12
+ return entry;
13
+ }
14
+ on(event, callback) {
15
+ this.eventEmitter.on(event, callback);
16
+ }
17
+ }
18
+ export class ObjectURLCache {
19
+ constructor(size) {
20
+ this.cache = new ExtendedLRUCache(size);
21
+ this.cache.on('shift', entry => {
22
+ if (entry && entry[1].dataURI) {
23
+ URL.revokeObjectURL(entry[1].dataURI);
24
+ }
25
+ });
26
+ }
27
+ has(key) {
28
+ return !!this.cache.find(key);
29
+ }
30
+ get(key) {
31
+ return this.cache.get(key);
32
+ }
33
+ set(key, value) {
34
+ this.cache.set(key, value);
35
+ }
36
+ remove(key) {
37
+ const removed = this.cache.delete(key);
38
+ removed && URL.revokeObjectURL(removed.dataURI);
39
+ }
40
+ clear() {
41
+ this.cache.clear();
42
+ }
43
+ }
44
+ export const createObjectURLCache = () => new ObjectURLCache(PREVIEW_CACHE_LRU_SIZE);
@@ -0,0 +1,36 @@
1
+ export const takeSnapshot = async blob => {
2
+ return new Promise((resolve, reject) => {
3
+ const url = URL.createObjectURL(blob);
4
+ const video = document.createElement('video');
5
+ video.preload = 'metadata';
6
+ video.src = url;
7
+ video.muted = true;
8
+ video.play().catch(() => {
9
+ return reject(new Error('failed to play video'));
10
+ });
11
+ video.addEventListener('timeupdate', function timeUpdateHandler() {
12
+ video.removeEventListener('timeupdate', timeUpdateHandler);
13
+ video.pause();
14
+ URL.revokeObjectURL(url);
15
+ //create canvas to draw our first frame on.
16
+
17
+ if (!video.videoWidth && !video.videoHeight) {
18
+ return reject(new Error('error retrieving video dimensions'));
19
+ }
20
+ const canvas = document.createElement('canvas');
21
+ canvas.width = video.videoWidth;
22
+ canvas.height = video.videoHeight;
23
+ const context = canvas.getContext('2d');
24
+ if (!context) {
25
+ return reject(new Error('error creating canvas context'));
26
+ }
27
+ context.drawImage(video, 0, 0, canvas.width, canvas.height);
28
+ const dataURL = canvas.toDataURL('image/jpeg', 0.85);
29
+ resolve(dataURL);
30
+ });
31
+ video.addEventListener('error', () => {
32
+ reject(new Error('failed to load video'));
33
+ URL.revokeObjectURL(url);
34
+ });
35
+ });
36
+ };
@@ -0,0 +1,8 @@
1
+ import { getMediaCardSSR, getKey } from './globalScope';
2
+ export const getSSRData = identifier => {
3
+ const mediaCardSsr = getMediaCardSSR();
4
+ if (!mediaCardSsr) {
5
+ return;
6
+ }
7
+ return mediaCardSsr[getKey(identifier)];
8
+ };
@@ -0,0 +1,48 @@
1
+ import { printFunctionCall, printScript } from './printScript';
2
+ // ----- WARNING -----
3
+ // This is a very sensitive fraction of code.
4
+ // Any changes to this file must be tested directly in product before merging.
5
+ // The scripts printed here might differ from what we observe in our internal tests
6
+ // due to minimification, for example.
7
+ export const GLOBAL_MEDIA_CARD_SSR = 'mediaCardSsr';
8
+ export const GLOBAL_MEDIA_NAMESPACE = '__MEDIA_INTERNAL';
9
+ export function getMediaGlobalScope(globalScope = window) {
10
+ // Must match GLOBAL_MEDIA_NAMESPACE. Can't reference the constant from here.
11
+ const namespace = '__MEDIA_INTERNAL';
12
+ if (!globalScope[namespace]) {
13
+ globalScope[namespace] = {};
14
+ }
15
+ return globalScope[namespace];
16
+ }
17
+ export function getMediaCardSSR(globalScope = window) {
18
+ const globalMedia = getMediaGlobalScope(globalScope);
19
+ // Must match GLOBAL_MEDIA_CARD_SSR. Can't reference the constant from here.
20
+ const key = 'mediaCardSsr';
21
+ if (!globalMedia[key]) {
22
+ globalMedia[key] = {};
23
+ }
24
+ return globalMedia[key];
25
+ }
26
+ const dashed = param => param ? `-${param}` : '';
27
+ export const getKey = ({
28
+ id,
29
+ collectionName,
30
+ occurrenceKey
31
+ }) => `${id}${dashed(collectionName)}${dashed(occurrenceKey)}`;
32
+ export const storeDataURI = (key, dataURI, dimensions, error, globalScope = window) => {
33
+ const mediaCardSsr = getMediaCardSSR(globalScope);
34
+ mediaCardSsr[key] = {
35
+ dataURI,
36
+ dimensions,
37
+ error
38
+ };
39
+ };
40
+ const generateScript = (identifier, dataURI, dimensions, error) => {
41
+ const functionCall = printFunctionCall(storeDataURI, getKey(identifier), dataURI, dimensions, error);
42
+ return printScript([getMediaCardSSR.toString(), getMediaGlobalScope.toString(), functionCall]);
43
+ };
44
+ export const generateScriptProps = (identifier, dataURI, dimensions, error) => ({
45
+ dangerouslySetInnerHTML: {
46
+ __html: generateScript(identifier, dataURI, dimensions, error)
47
+ }
48
+ });
@@ -0,0 +1,2 @@
1
+ export { GLOBAL_MEDIA_NAMESPACE, GLOBAL_MEDIA_CARD_SSR, generateScriptProps, getKey } from './globalScope';
2
+ export { getSSRData } from './getSSRData';
@@ -0,0 +1,16 @@
1
+ const printParam = param => {
2
+ if (typeof param === 'string') {
3
+ return `'${param}'`;
4
+ } else if (typeof param === 'object') {
5
+ return JSON.stringify(param);
6
+ } else if (param === undefined) {
7
+ return 'undefined';
8
+ }
9
+ return param;
10
+ };
11
+ const printParams = args => args.map(arg => printParam(arg)).join(',');
12
+ export const printFunctionCall = (fn, ...args) => `(${fn.toString()})(${printParams(args)});`;
13
+ export const printScript = statements => `(function(){
14
+ ${statements.join(';')}
15
+ })();
16
+ `;
@@ -0,0 +1,61 @@
1
+ import { useRef, useEffect } from 'react';
2
+
3
+ /**
4
+ * Checks if at least one of next dimensions is bigger than current
5
+ * If a single dimension is undefined, returns false
6
+ */
7
+ export const isBigger = (current, next) => {
8
+ const {
9
+ width: currentWidth,
10
+ height: currentHeight
11
+ } = current || {};
12
+ const {
13
+ width: nextWidth,
14
+ height: nextHeight
15
+ } = next || {};
16
+ if (!!currentWidth && !!currentHeight && !!nextWidth && !!nextHeight) {
17
+ const nextIsWider = currentWidth < nextWidth;
18
+ const nextIsHigher = currentHeight < nextHeight;
19
+ return nextIsHigher || nextIsWider;
20
+ } else {
21
+ return false;
22
+ }
23
+ };
24
+
25
+ /** Verifies if the current screen is retina display */
26
+ function isRetina() {
27
+ const mediaQuery = '(-webkit-min-device-pixel-ratio: 1.5), (min--moz-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3/2), (min-resolution: 1.5dppx)';
28
+ return window.devicePixelRatio > 1 || window.matchMedia && window.matchMedia(mediaQuery).matches;
29
+ }
30
+ export const createRequestDimensions = dimensions => {
31
+ if (!dimensions) {
32
+ return;
33
+ }
34
+ const retinaFactor = isRetina() ? 2 : 1;
35
+ const {
36
+ width,
37
+ height
38
+ } = dimensions;
39
+ const result = {};
40
+ if (width) {
41
+ result.width = width * retinaFactor;
42
+ }
43
+ if (height) {
44
+ result.height = height * retinaFactor;
45
+ }
46
+ return result;
47
+ };
48
+
49
+ /** Stores the provided value in a */
50
+ export function useCurrentValueRef(value) {
51
+ const ref = useRef(value);
52
+ ref.current = value;
53
+ return ref;
54
+ }
55
+ export function usePrevious(value) {
56
+ const ref = useRef();
57
+ useEffect(() => {
58
+ ref.current = value;
59
+ }, [value]);
60
+ return ref.current;
61
+ }
@@ -0,0 +1 @@
1
+ export { useFilePreview } from './useFilePreview';
@@ -0,0 +1 @@
1
+ export {};