@atlaskit/smart-card 21.3.0 → 22.1.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 (103) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/dist/cjs/extractors/block/index.js +6 -7
  3. package/dist/cjs/extractors/common/actions/extractPreviewAction.js +16 -19
  4. package/dist/cjs/state/actions/index.js +54 -10
  5. package/dist/cjs/state/analytics/types.js +5 -0
  6. package/dist/cjs/state/analytics/useSmartLinkAnalytics.js +429 -109
  7. package/dist/cjs/state/hooks-external/useSmartLinkActions.js +5 -3
  8. package/dist/cjs/utils/analytics/analytics.js +241 -74
  9. package/dist/cjs/utils/analytics/index.js +32 -5
  10. package/dist/cjs/utils/mocks.js +28 -2
  11. package/dist/cjs/version.json +1 -1
  12. package/dist/cjs/view/BlockCard/actions/PreviewAction.js +2 -2
  13. package/dist/cjs/view/BlockCard/index.js +6 -5
  14. package/dist/cjs/view/CardWithUrl/component.js +27 -5
  15. package/dist/cjs/view/CardWithUrl/loader.js +6 -1
  16. package/dist/cjs/view/EmbedCard/index.js +3 -2
  17. package/dist/cjs/view/EmbedModal/components/analytics/index.js +100 -0
  18. package/dist/cjs/view/EmbedModal/components/analytics/types.js +5 -0
  19. package/dist/cjs/view/EmbedModal/components/size-experiment/index.js +5 -10
  20. package/dist/cjs/view/EmbedModal/index.js +54 -15
  21. package/dist/cjs/view/EmbedModal/types.js +9 -1
  22. package/dist/cjs/view/HoverCard/components/HoverCardComponent.js +11 -3
  23. package/dist/cjs/view/HoverCard/components/HoverCardContent.js +15 -4
  24. package/dist/cjs/view/HoverCard/index.js +6 -1
  25. package/dist/cjs/view/InlineCard/IconAndTitleLayout/styled.js +2 -2
  26. package/dist/cjs/view/common/Modal.js +29 -4
  27. package/dist/cjs/view/common/ModalHeader.js +3 -2
  28. package/dist/es2019/extractors/block/index.js +6 -7
  29. package/dist/es2019/extractors/common/actions/extractPreviewAction.js +16 -10
  30. package/dist/es2019/state/actions/index.js +54 -10
  31. package/dist/es2019/state/analytics/types.js +1 -0
  32. package/dist/es2019/state/analytics/useSmartLinkAnalytics.js +424 -41
  33. package/dist/es2019/state/hooks-external/useSmartLinkActions.js +5 -3
  34. package/dist/es2019/utils/analytics/analytics.js +254 -79
  35. package/dist/es2019/utils/analytics/index.js +32 -4
  36. package/dist/es2019/utils/mocks.js +26 -1
  37. package/dist/es2019/version.json +1 -1
  38. package/dist/es2019/view/BlockCard/actions/PreviewAction.js +3 -3
  39. package/dist/es2019/view/BlockCard/index.js +5 -4
  40. package/dist/es2019/view/CardWithUrl/component.js +27 -5
  41. package/dist/es2019/view/CardWithUrl/loader.js +6 -1
  42. package/dist/es2019/view/EmbedCard/index.js +3 -2
  43. package/dist/es2019/view/EmbedModal/components/analytics/index.js +80 -0
  44. package/dist/es2019/view/EmbedModal/components/analytics/types.js +1 -0
  45. package/dist/es2019/view/EmbedModal/components/size-experiment/index.js +5 -9
  46. package/dist/es2019/view/EmbedModal/index.js +46 -13
  47. package/dist/es2019/view/EmbedModal/types.js +6 -1
  48. package/dist/es2019/view/HoverCard/components/HoverCardComponent.js +11 -3
  49. package/dist/es2019/view/HoverCard/components/HoverCardContent.js +15 -4
  50. package/dist/es2019/view/HoverCard/index.js +6 -1
  51. package/dist/es2019/view/InlineCard/IconAndTitleLayout/styled.js +0 -2
  52. package/dist/es2019/view/common/Modal.js +27 -6
  53. package/dist/es2019/view/common/ModalHeader.js +3 -2
  54. package/dist/esm/extractors/block/index.js +6 -7
  55. package/dist/esm/extractors/common/actions/extractPreviewAction.js +17 -19
  56. package/dist/esm/state/actions/index.js +54 -10
  57. package/dist/esm/state/analytics/types.js +1 -0
  58. package/dist/esm/state/analytics/useSmartLinkAnalytics.js +428 -111
  59. package/dist/esm/state/hooks-external/useSmartLinkActions.js +5 -3
  60. package/dist/esm/utils/analytics/analytics.js +241 -74
  61. package/dist/esm/utils/analytics/index.js +31 -4
  62. package/dist/esm/utils/mocks.js +25 -0
  63. package/dist/esm/version.json +1 -1
  64. package/dist/esm/view/BlockCard/actions/PreviewAction.js +3 -3
  65. package/dist/esm/view/BlockCard/index.js +5 -4
  66. package/dist/esm/view/CardWithUrl/component.js +27 -5
  67. package/dist/esm/view/CardWithUrl/loader.js +6 -1
  68. package/dist/esm/view/EmbedCard/index.js +3 -2
  69. package/dist/esm/view/EmbedModal/components/analytics/index.js +82 -0
  70. package/dist/esm/view/EmbedModal/components/analytics/types.js +1 -0
  71. package/dist/esm/view/EmbedModal/components/size-experiment/index.js +5 -10
  72. package/dist/esm/view/EmbedModal/index.js +52 -15
  73. package/dist/esm/view/EmbedModal/types.js +6 -1
  74. package/dist/esm/view/HoverCard/components/HoverCardComponent.js +11 -3
  75. package/dist/esm/view/HoverCard/components/HoverCardContent.js +15 -4
  76. package/dist/esm/view/HoverCard/index.js +6 -1
  77. package/dist/esm/view/InlineCard/IconAndTitleLayout/styled.js +2 -2
  78. package/dist/esm/view/common/Modal.js +28 -6
  79. package/dist/esm/view/common/ModalHeader.js +3 -2
  80. package/dist/types/extractors/block/types.d.ts +4 -2
  81. package/dist/types/extractors/common/actions/extractPreviewAction.d.ts +7 -5
  82. package/dist/types/state/analytics/types.d.ts +9 -0
  83. package/dist/types/state/analytics/useSmartLinkAnalytics.d.ts +41 -24
  84. package/dist/types/state/hooks/useSmartLink.d.ts +26 -18
  85. package/dist/types/state/hooks-external/useSmartLinkActions.d.ts +6 -2
  86. package/dist/types/utils/analytics/analytics.d.ts +19 -21
  87. package/dist/types/utils/analytics/index.d.ts +2 -2
  88. package/dist/types/utils/analytics/types.d.ts +91 -0
  89. package/dist/types/utils/mocks.d.ts +48 -0
  90. package/dist/types/utils/types.d.ts +3 -1
  91. package/dist/types/view/BlockCard/actions/PreviewAction.d.ts +4 -0
  92. package/dist/types/view/BlockCard/index.d.ts +2 -2
  93. package/dist/types/view/BlockCard/types.d.ts +4 -4
  94. package/dist/types/view/Card/index.d.ts +1 -1
  95. package/dist/types/view/EmbedCard/types.d.ts +2 -2
  96. package/dist/types/view/EmbedModal/components/analytics/index.d.ts +5 -0
  97. package/dist/types/view/EmbedModal/components/analytics/types.d.ts +6 -0
  98. package/dist/types/view/EmbedModal/components/size-experiment/index.d.ts +4 -3
  99. package/dist/types/view/EmbedModal/index.d.ts +3 -1
  100. package/dist/types/view/EmbedModal/types.d.ts +14 -4
  101. package/dist/types/view/common/Modal.d.ts +6 -8
  102. package/package.json +17 -17
  103. package/report.api.md +302 -107
@@ -61,7 +61,16 @@ export function CardWithUrlContent({
61
61
  }, [state.details, url]);
62
62
  const handleClickWrapper = useCallback(event => {
63
63
  const isModifierKeyPressed = isSpecialEvent(event);
64
- analytics.ui.cardClickedEvent(id, isFlexibleUi ? 'flexible' : appearance, state.status, definitionId, extensionKey, isModifierKeyPressed, undefined, product, subproduct);
64
+ analytics.ui.cardClickedEvent({
65
+ id,
66
+ display: isFlexibleUi ? 'flexible' : appearance,
67
+ status: state.status,
68
+ definitionId,
69
+ extensionKey,
70
+ isModifierKeyPressed,
71
+ destinationProduct: product,
72
+ destinationSubproduct: subproduct
73
+ });
65
74
 
66
75
  if (onClick) {
67
76
  onClick(event);
@@ -81,7 +90,14 @@ export function CardWithUrlContent({
81
90
 
82
91
  if (state.status !== 'pending') {
83
92
  measure.create(id, state.status);
84
- analytics.operational.instrument(id, state.status, definitionId, extensionKey, resourceType, state.error);
93
+ analytics.operational.instrument({
94
+ id,
95
+ status: state.status,
96
+ definitionId,
97
+ extensionKey,
98
+ resourceType,
99
+ error: state.error
100
+ });
85
101
  }
86
102
  }, [id, appearance, state.status, state.error, definitionId, extensionKey, resourceType, analytics.operational]); // NB: once the smart-card has rendered into an end state, we capture
87
103
  // this as a successful render. These can be one of:
@@ -90,7 +106,13 @@ export function CardWithUrlContent({
90
106
 
91
107
  useEffect(() => {
92
108
  if (isFinalState(state.status)) {
93
- analytics.ui.renderSuccessEvent(appearance, state.status, id, definitionId, extensionKey);
109
+ analytics.ui.renderSuccessEvent({
110
+ display: appearance,
111
+ status: state.status,
112
+ id,
113
+ definitionId,
114
+ extensionKey
115
+ });
94
116
  }
95
117
  }, [appearance, state.status, url, definitionId, extensionKey, analytics.ui, id]);
96
118
 
@@ -154,7 +176,7 @@ export function CardWithUrlContent({
154
176
  handleErrorRetry: handleRetry,
155
177
  handleInvoke: handleInvoke,
156
178
  handleFrameClick: handleClickWrapper,
157
- handleAnalytics: dispatchAnalytics,
179
+ analytics: analytics,
158
180
  isSelected: isSelected,
159
181
  onResolve: onResolve,
160
182
  onError: onError,
@@ -172,7 +194,7 @@ export function CardWithUrlContent({
172
194
  handleErrorRetry: handleRetry,
173
195
  handleFrameClick: handleClickWrapper,
174
196
  handleInvoke: handleInvoke,
175
- handleAnalytics: dispatchAnalytics,
197
+ analytics: analytics,
176
198
  isSelected: isSelected,
177
199
  isFrameVisible: isFrameVisible,
178
200
  platform: platform,
@@ -68,7 +68,12 @@ export function CardWithURLRenderer(props) {
68
68
  const errorInfo = {
69
69
  componentStack
70
70
  };
71
- analytics.ui.renderFailedEvent(appearance, id, error, errorInfo);
71
+ analytics.ui.renderFailedEvent({
72
+ display: appearance,
73
+ id,
74
+ error,
75
+ errorInfo
76
+ });
72
77
  }
73
78
  }, [analytics.ui, appearance, id]);
74
79
 
@@ -22,7 +22,7 @@ export const EmbedCard = /*#__PURE__*/React.forwardRef(({
22
22
  handleAuthorize,
23
23
  handleErrorRetry,
24
24
  handleFrameClick,
25
- handleAnalytics,
25
+ analytics,
26
26
  handleInvoke,
27
27
  showActions,
28
28
  isSelected,
@@ -79,7 +79,8 @@ export const EmbedCard = /*#__PURE__*/React.forwardRef(({
79
79
  }
80
80
 
81
81
  const resolvedBlockViewProps = extractBlockProps(data, meta, {
82
- handleAnalytics,
82
+ analytics,
83
+ origin: 'smartLinkEmbed',
83
84
  handleInvoke,
84
85
  extensionKey: getExtensionKey(details)
85
86
  });
@@ -0,0 +1,80 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ import React, { useCallback } from 'react';
3
+ import { EmbedModalSize } from '../../types';
4
+
5
+ const getResizeFrom = size => size === EmbedModalSize.Small ? EmbedModalSize.Large : EmbedModalSize.Small;
6
+
7
+ const withAnalytics = Component => props => {
8
+ const {
9
+ analytics,
10
+ onClose,
11
+ onOpen,
12
+ onOpenFailed,
13
+ onResize,
14
+ origin
15
+ } = props;
16
+ const handleOnOpen = useCallback(context => {
17
+ analytics.screen.modalViewedEvent({
18
+ name: 'embedPreviewModal',
19
+ attributes: {
20
+ origin,
21
+ size: context.size
22
+ }
23
+ });
24
+ analytics.ui.renderSuccessEvent({
25
+ status: 'resolved',
26
+ display: 'preview'
27
+ });
28
+
29
+ if (onOpen) {
30
+ onOpen(context);
31
+ }
32
+ }, [analytics.screen, analytics.ui, onOpen, origin]);
33
+ const handleOnOpenFailed = useCallback((error, errorInfo) => {
34
+ analytics.ui.renderFailedEvent({
35
+ display: 'preview',
36
+ error,
37
+ errorInfo
38
+ });
39
+
40
+ if (onOpenFailed) {
41
+ onOpenFailed(error, errorInfo);
42
+ }
43
+ }, [analytics.ui, onOpenFailed]);
44
+ const handleOnClose = useCallback(context => {
45
+ analytics.ui.modalClosedEvent({
46
+ actionSubjectId: 'embedPreview',
47
+ attributes: {
48
+ origin,
49
+ previewTime: context.duration,
50
+ size: context.size
51
+ }
52
+ });
53
+
54
+ if (onClose) {
55
+ onClose(context);
56
+ }
57
+ }, [analytics.ui, onClose, origin]);
58
+ const handleOnResize = useCallback(context => {
59
+ analytics.ui.buttonClickedEvent({
60
+ actionSubjectId: 'embedPreviewResize',
61
+ attributes: {
62
+ newSize: context.size,
63
+ origin,
64
+ previousSize: getResizeFrom(context.size)
65
+ }
66
+ });
67
+
68
+ if (onResize) {
69
+ onResize(context);
70
+ }
71
+ }, [analytics.ui, onResize, origin]);
72
+ return /*#__PURE__*/React.createElement(Component, _extends({}, props, {
73
+ onClose: handleOnClose,
74
+ onOpen: handleOnOpen,
75
+ onOpenFailed: handleOnOpenFailed,
76
+ onResize: handleOnResize
77
+ }));
78
+ };
79
+
80
+ export default withAnalytics;
@@ -1,28 +1,24 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
2
  import React from 'react';
3
3
  import Modal from '../../../common/Modal';
4
- import { MAX_MODAL_SIZE, MIN_MODAL_SIZE } from '../../constants';
4
+ import { EmbedModalSize } from '../../types';
5
5
 
6
6
  const withSizeExperiment = Component => props => {
7
7
  const {
8
- featureFlags = {},
9
- closeLabel = 'Close Preview'
8
+ featureFlags = {}
10
9
  } = props;
11
10
  const {
12
- embedModalSize
11
+ embedModalSize: size
13
12
  } = featureFlags; // Experiment
14
13
 
15
- if (embedModalSize === 'large' || embedModalSize === 'small') {
16
- const size = embedModalSize === 'large' ? MAX_MODAL_SIZE : MIN_MODAL_SIZE;
14
+ if (size === EmbedModalSize.Large || size === EmbedModalSize.Small) {
17
15
  return /*#__PURE__*/React.createElement(Component, _extends({}, props, {
18
16
  size: size
19
17
  }));
20
18
  } // Control
21
19
 
22
20
 
23
- return /*#__PURE__*/React.createElement(Modal, _extends({}, props, {
24
- closeLabel: closeLabel
25
- }));
21
+ return /*#__PURE__*/React.createElement(Modal, props);
26
22
  };
27
23
 
28
24
  export default withSizeExperiment;
@@ -1,10 +1,16 @@
1
- import React, { useCallback, useState } from 'react';
1
+ import React, { useCallback, useRef, useState } from 'react';
2
2
  import ModalDialog, { ModalBody, ModalTransition } from '@atlaskit/modal-dialog';
3
3
  import LinkInfo from './components/link-info';
4
4
  import { MAX_MODAL_SIZE, MIN_MODAL_SIZE } from './constants';
5
5
  import EmbedContent from './components/embed-content';
6
+ import { EmbedModalSize } from './types';
6
7
  import withErrorBoundary from './components/error-boundary';
7
8
  import withSizeExperiment from './components/size-experiment';
9
+ import withAnalytics from './components/analytics';
10
+
11
+ const toSize = width => width === MAX_MODAL_SIZE ? EmbedModalSize.Large : EmbedModalSize.Small;
12
+
13
+ const toWidth = size => size === EmbedModalSize.Large ? MAX_MODAL_SIZE : MIN_MODAL_SIZE;
8
14
 
9
15
  const EmbedModal = ({
10
16
  download: downloadUrl,
@@ -14,37 +20,64 @@ const EmbedModal = ({
14
20
  onClose,
15
21
  onDownloadActionClick,
16
22
  onOpen,
23
+ onResize,
17
24
  onViewActionClick,
18
25
  providerName,
19
26
  showModal,
20
- size: defaultSize = MIN_MODAL_SIZE,
27
+ size = EmbedModalSize.Small,
21
28
  src,
22
29
  testId = 'smart-embed-preview-modal',
23
30
  title,
24
31
  url
25
32
  }) => {
33
+ const defaultWidth = toWidth(size);
26
34
  const [isOpen, setIsOpen] = useState(showModal);
27
- const [size, setSize] = useState(defaultSize);
35
+ const [width, setWidth] = useState(defaultWidth);
36
+ const openAt = useRef();
37
+ const handleOnOpenComplete = useCallback(() => {
38
+ openAt.current = Date.now();
39
+
40
+ if (onOpen) {
41
+ onOpen({
42
+ size
43
+ });
44
+ }
45
+ }, [onOpen, size]);
28
46
  const handleOnClose = useCallback(() => setIsOpen(false), []);
29
- const handleOnSizeClick = useCallback(() => {
30
- const newSize = size === MIN_MODAL_SIZE ? MAX_MODAL_SIZE : MIN_MODAL_SIZE;
31
- setSize(newSize);
32
- }, [size]);
47
+ const handleOnCloseComplete = useCallback(() => {
48
+ if (onClose) {
49
+ const duration = openAt.current ? Date.now() - openAt.current : undefined;
50
+ onClose({
51
+ duration,
52
+ size: toSize(width)
53
+ });
54
+ }
55
+ }, [onClose, width]);
56
+ const handleOnResizeClick = useCallback(() => {
57
+ const newWidth = width === MIN_MODAL_SIZE ? MAX_MODAL_SIZE : MIN_MODAL_SIZE;
58
+ setWidth(newWidth);
59
+
60
+ if (onResize) {
61
+ onResize({
62
+ size: toSize(newWidth)
63
+ });
64
+ }
65
+ }, [onResize, width]);
33
66
  return /*#__PURE__*/React.createElement(ModalTransition, null, isOpen && /*#__PURE__*/React.createElement(ModalDialog, {
34
67
  height: "100%",
35
68
  onClose: handleOnClose,
36
- onCloseComplete: onClose,
37
- onOpenComplete: onOpen,
69
+ onCloseComplete: handleOnCloseComplete,
70
+ onOpenComplete: handleOnOpenComplete,
38
71
  testId: testId,
39
- width: size
72
+ width: width
40
73
  }, /*#__PURE__*/React.createElement(LinkInfo, {
41
74
  downloadUrl: downloadUrl,
42
75
  icon: icon,
43
76
  providerName: providerName,
44
77
  onViewButtonClick: onViewActionClick,
45
78
  onDownloadButtonClick: onDownloadActionClick,
46
- onResizeButtonClick: handleOnSizeClick,
47
- size: size,
79
+ onResizeButtonClick: handleOnResizeClick,
80
+ size: width,
48
81
  title: title,
49
82
  testId: testId,
50
83
  url: url
@@ -56,4 +89,4 @@ const EmbedModal = ({
56
89
  }))));
57
90
  };
58
91
 
59
- export default withSizeExperiment(withErrorBoundary(EmbedModal));
92
+ export default withSizeExperiment(withAnalytics(withErrorBoundary(EmbedModal)));
@@ -1 +1,6 @@
1
- export {};
1
+ export let EmbedModalSize;
2
+
3
+ (function (EmbedModalSize) {
4
+ EmbedModalSize["Large"] = "large";
5
+ EmbedModalSize["Small"] = "small";
6
+ })(EmbedModalSize || (EmbedModalSize = {}));
@@ -43,7 +43,11 @@ export const HoverCardComponent = ({
43
43
  //Check its previously open to avoid firing events when moving between the child and hover card components
44
44
  if (isOpen === true && cardOpenTime.current) {
45
45
  const hoverTime = Date.now() - cardOpenTime.current;
46
- analytics.ui.hoverCardDismissedEvent('card', hoverTime, 'mouse_hover');
46
+ analytics.ui.hoverCardDismissedEvent({
47
+ previewDisplay: 'card',
48
+ hoverTime,
49
+ previewInvokeMethod: 'mouse_hover'
50
+ });
47
51
  }
48
52
 
49
53
  setIsOpen(false);
@@ -66,7 +70,10 @@ export const HoverCardComponent = ({
66
70
  //Check if its previously closed to avoid firing events when moving between the child and hover card components
67
71
  if (isOpen === false) {
68
72
  cardOpenTime.current = Date.now();
69
- analytics.ui.hoverCardViewedEvent(hoverDisplay, invokeMethod);
73
+ analytics.ui.hoverCardViewedEvent({
74
+ previewDisplay: hoverDisplay,
75
+ previewInvokeMethod: invokeMethod
76
+ });
70
77
  } //If these are undefined then popupOffset is undefined and we fallback to default bottom-start placement
71
78
 
72
79
 
@@ -84,7 +91,8 @@ export const HoverCardComponent = ({
84
91
  const linkActions = useSmartLinkActions({
85
92
  url,
86
93
  appearance: SMART_CARD_ANALYTICS_DISPLAY,
87
- analyticsHandler
94
+ analyticsHandler,
95
+ origin: 'smartLinkPreviewHoverCard'
88
96
  });
89
97
  const onActionClick = useCallback(actionId => {
90
98
  if (actionId === 'preview-content') {
@@ -25,7 +25,9 @@ export const getOpenAction = (url, analytics, onActionClick) => ({
25
25
  }
26
26
 
27
27
  window.open(url, '_blank');
28
- analytics.ui.hoverCardOpenLinkClickedEvent('card');
28
+ analytics.ui.hoverCardOpenLinkClickedEvent({
29
+ previewDisplay: 'card'
30
+ });
29
31
  },
30
32
  testId: 'hover-card-open-button'
31
33
  });
@@ -61,13 +63,22 @@ const HoverCardContent = ({
61
63
  useEffect(() => {
62
64
  // Since hover preview only render on resolved status,
63
65
  // there is no need to check for statuses.
64
- analytics.ui.renderSuccessEvent(SMART_CARD_ANALYTICS_DISPLAY, cardState.status);
66
+ analytics.ui.renderSuccessEvent({
67
+ display: SMART_CARD_ANALYTICS_DISPLAY,
68
+ status: cardState.status
69
+ });
65
70
  }, [analytics.ui, cardState.status]);
66
71
  const extensionKey = useMemo(() => getExtensionKey(cardState.details), [cardState.details]);
67
72
  const onClick = useCallback(event => {
68
73
  const isModifierKeyPressed = isSpecialEvent(event);
69
- analytics.ui.cardClickedEvent(undefined, SMART_CARD_ANALYTICS_DISPLAY, cardState.status, undefined, undefined, isModifierKeyPressed, undefined, undefined, undefined, 'titleGoToLink');
70
- }, [cardState.status, analytics.ui]);
74
+ analytics.ui.cardClickedEvent({
75
+ id,
76
+ display: SMART_CARD_ANALYTICS_DISPLAY,
77
+ status: cardState.status,
78
+ isModifierKeyPressed,
79
+ actionSubjectId: 'titleGoToLink'
80
+ });
81
+ }, [cardState.status, analytics.ui, id]);
71
82
  const titleActions = useMemo(() => [getOpenAction(url, analytics, onActionClick)], [url, analytics, onActionClick]);
72
83
  const footerActions = useMemo(() => toFooterActions(cardActions, onActionClick), [cardActions, onActionClick]);
73
84
  const data = (_cardState$details = cardState.details) === null || _cardState$details === void 0 ? void 0 : _cardState$details.data;
@@ -22,7 +22,12 @@ const HoverCardWithErrorBoundary = props => {
22
22
  }, [createAnalyticsEvent]);
23
23
  const analytics = useSmartLinkAnalytics(url, analyticsHandler, id);
24
24
  const onError = useCallback((error, info) => {
25
- analytics.ui.renderFailedEvent(SMART_CARD_ANALYTICS_DISPLAY, id, error, info);
25
+ analytics.ui.renderFailedEvent({
26
+ display: SMART_CARD_ANALYTICS_DISPLAY,
27
+ id,
28
+ error,
29
+ errorInfo: info
30
+ });
26
31
  }, [analytics.ui, id]);
27
32
  return jsx(ErrorBoundary, {
28
33
  fallback: children,
@@ -64,14 +64,12 @@ export const LozengeWrapper = styled.span`
64
64
  vertical-align: 1px;
65
65
  & > span {
66
66
  margin-left: 4px;
67
- padding: 2px 0 2px 0;
68
67
  }
69
68
  `; // TODO: Replace overrides with proper AtlasKit solution.
70
69
 
71
70
  export const LozengeBlockWrapper = styled.span`
72
71
  & > span {
73
72
  margin-left: 4px;
74
- padding: 2px 0 2px 0;
75
73
  }
76
74
  `;
77
75
  export const RightIconPositionWrapper = styled.span`
@@ -14,10 +14,12 @@ manually passed to your custom components.
14
14
 
15
15
  For a complete guide on customization using the new compositional API, refer to the docs at
16
16
  https://atlassian.design/components/modal-dialog/examples#customizing-modal-dialog. */
17
- import React, { useState } from 'react';
18
- import ModalDialog, { ModalTransition, ModalBody } from '@atlaskit/modal-dialog';
17
+ import React, { useCallback, useRef, useState } from 'react';
18
+ import ModalDialog, { ModalBody, ModalTransition } from '@atlaskit/modal-dialog';
19
19
  import { Header } from './ModalHeader';
20
20
  import { getIframeSandboxAttribute } from '../../utils';
21
+ import withAnalytics from '../EmbedModal/components/analytics';
22
+ import { EmbedModalSize } from '../EmbedModal/types';
21
23
  const iframeStyles = {
22
24
  width: `100%`,
23
25
  height: 'calc(100vh - 248px)'
@@ -45,7 +47,7 @@ const Modal = ({
45
47
  providerName,
46
48
  metadata,
47
49
  icon,
48
- closeLabel,
50
+ closeLabel = 'Close Preview',
49
51
  iframeName,
50
52
  title,
51
53
  url,
@@ -56,16 +58,35 @@ const Modal = ({
56
58
  onDownloadActionClick
57
59
  }) => {
58
60
  let [isOpen, setIsOpen] = useState(showModal);
61
+ const openAt = useRef();
62
+ const handleOnOpenComplete = useCallback(() => {
63
+ openAt.current = Date.now();
64
+
65
+ if (onOpen) {
66
+ onOpen({
67
+ size: EmbedModalSize.Small
68
+ });
69
+ }
70
+ }, [onOpen]);
71
+ const handleOnCloseComplete = useCallback(() => {
72
+ if (onClose) {
73
+ const duration = openAt.current ? Date.now() - openAt.current : undefined;
74
+ onClose({
75
+ duration,
76
+ size: EmbedModalSize.Small
77
+ });
78
+ }
79
+ }, [onClose]);
59
80
  const sandbox = getIframeSandboxAttribute(isTrusted);
60
81
  return /*#__PURE__*/React.createElement(ModalTransition, null, isOpen && /*#__PURE__*/React.createElement(ModalDialog, {
61
82
  height: "100%",
62
83
  width: "large",
63
84
  testId: testId,
64
- onOpenComplete: onOpen,
85
+ onOpenComplete: handleOnOpenComplete,
65
86
  onClose: () => {
66
87
  setIsOpen(false);
67
88
  },
68
- onCloseComplete: onClose
89
+ onCloseComplete: handleOnCloseComplete
69
90
  }, /*#__PURE__*/React.createElement(Header, {
70
91
  providerName: providerName,
71
92
  icon: icon,
@@ -91,4 +112,4 @@ const Modal = ({
91
112
  }))));
92
113
  };
93
114
 
94
- export default ModalWithErrorBoundary;
115
+ export default withAnalytics(ModalWithErrorBoundary);
@@ -74,7 +74,7 @@ export const Header = ({
74
74
  testId: "preview-view-action",
75
75
  iconAfter: jsx(ShortcutIcon, {
76
76
  size: "small",
77
- label: "go to source"
77
+ label: ""
78
78
  }),
79
79
  onClick: onViewActionClick
80
80
  }, providerName ? jsx(F, null, jsx(FormattedMessage, messages.viewIn), " ", providerName) : jsx(FormattedMessage, messages.viewOriginal)), jsx(Button, {
@@ -82,6 +82,7 @@ export const Header = ({
82
82
  iconBefore: jsx(EditorCloseIcon, {
83
83
  label: label
84
84
  }),
85
- onClick: onClose
85
+ onClick: onClose,
86
+ testId: "preview-close-button"
86
87
  }))));
87
88
  };
@@ -37,14 +37,13 @@ var extractBlockDetails = function extractBlockDetails(jsonLd) {
37
37
 
38
38
  export var extractBlockActions = function extractBlockActions(props, jsonLd, opts, platform) {
39
39
  if (opts) {
40
- var featureFlags = opts.featureFlags,
41
- handleInvoke = opts.handleInvoke,
42
- handleAnalytics = opts.handleAnalytics,
43
- extensionKey = opts.extensionKey,
44
- source = opts.source,
45
- testId = opts.testId;
40
+ var handleInvoke = opts.handleInvoke;
46
41
  var actions = extractActions(jsonLd, handleInvoke);
47
- var previewAction = extractPreviewAction(extensionKey, props, jsonLd, handleInvoke, handleAnalytics, testId, platform, source, featureFlags); // The previewAction should always be the last action
42
+ var previewAction = extractPreviewAction(_objectSpread(_objectSpread({}, opts), {}, {
43
+ viewProps: props,
44
+ jsonLd: jsonLd,
45
+ platform: platform
46
+ })); // The previewAction should always be the last action
48
47
 
49
48
  if (previewAction) {
50
49
  actions.push(previewAction);
@@ -4,9 +4,8 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (O
4
4
 
5
5
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
6
6
 
7
- import { uiRenderSuccessEvent, uiRenderFailedEvent } from '../../../utils/analytics';
8
7
  import { extractDownloadUrl } from '../detail';
9
- import { extractProvider, extractPreview } from '@atlaskit/linking-common/extractors';
8
+ import { extractPreview, extractProvider } from '@atlaskit/linking-common/extractors';
10
9
  import { PreviewAction } from '../../../view/BlockCard';
11
10
 
12
11
  var getMetadataFromJsonLd = function getMetadataFromJsonLd(jsonLd, platform) {
@@ -51,16 +50,19 @@ var getInvokeOpts = function getInvokeOpts(key, action, source) {
51
50
  };
52
51
  };
53
52
 
54
- export var extractPreviewAction = function extractPreviewAction() {
55
- var extensionKey = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'empty-object-provider';
56
- var viewProps = arguments.length > 1 ? arguments[1] : undefined;
57
- var jsonLd = arguments.length > 2 ? arguments[2] : undefined;
58
- var handleInvoke = arguments.length > 3 ? arguments[3] : undefined;
59
- var handleAnalytics = arguments.length > 4 ? arguments[4] : undefined;
60
- var testId = arguments.length > 5 ? arguments[5] : undefined;
61
- var platform = arguments.length > 6 ? arguments[6] : undefined;
62
- var source = arguments.length > 7 ? arguments[7] : undefined;
63
- var featureFlags = arguments.length > 8 ? arguments[8] : undefined;
53
+ export var extractPreviewAction = function extractPreviewAction(_ref) {
54
+ var _ref$extensionKey = _ref.extensionKey,
55
+ extensionKey = _ref$extensionKey === void 0 ? 'empty-object-provider' : _ref$extensionKey,
56
+ viewProps = _ref.viewProps,
57
+ jsonLd = _ref.jsonLd,
58
+ handleInvoke = _ref.handleInvoke,
59
+ testId = _ref.testId,
60
+ platform = _ref.platform,
61
+ origin = _ref.origin,
62
+ _ref$source = _ref.source,
63
+ source = _ref$source === void 0 ? 'block' : _ref$source,
64
+ featureFlags = _ref.featureFlags,
65
+ analytics = _ref.analytics;
64
66
  // Extract metadata from view props & raw JSON-LD.
65
67
  var metadataFromJsonLd = getMetadataFromJsonLd(jsonLd, platform);
66
68
  var metadataFromViewProps = getMetadataFromResolvedProps(viewProps);
@@ -72,14 +74,10 @@ export var extractPreviewAction = function extractPreviewAction() {
72
74
  // Build action using instrumentation hooks.
73
75
  var key = extensionKey;
74
76
  var previewAction = PreviewAction(_objectSpread(_objectSpread({}, metadata), {}, {
77
+ analytics: analytics,
78
+ origin: origin,
75
79
  featureFlags: featureFlags,
76
80
  testId: testId,
77
- onOpen: function onOpen() {
78
- handleAnalytics(uiRenderSuccessEvent('preview', 'resolved', key));
79
- },
80
- onOpenFailed: function onOpenFailed(error, errorInfo) {
81
- handleAnalytics(uiRenderFailedEvent('preview', error, errorInfo));
82
- },
83
81
  onDownloadActionClick: function onDownloadActionClick() {
84
82
  handleInvoke(getInvokeOpts(key, 'DownloadAction'));
85
83
  },
@@ -89,7 +87,7 @@ export var extractPreviewAction = function extractPreviewAction() {
89
87
  })); // Setup props to go through proper Redux 'invocation' flow
90
88
  // for analytics, further state management if required in future.
91
89
 
92
- var previewActionProps = getInvokeOpts(key, 'PreviewAction', source !== null && source !== void 0 ? source : 'block'); // - Promise invoked by the action invocation handler; open preview.
90
+ var previewActionProps = getInvokeOpts(key, 'PreviewAction', source); // - Promise invoked by the action invocation handler; open preview.
93
91
 
94
92
  previewActionProps.action.promise = previewAction.promise; // - Promise invoked on click of `Preview` on block card; trigger above promise.
95
93