@atlaskit/smart-card 20.0.6 → 20.1.2

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 (66) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/cjs/state/actions/constants.js +4 -2
  3. package/dist/cjs/state/actions/index.js +51 -19
  4. package/dist/cjs/version.json +1 -1
  5. package/dist/cjs/view/BlockCard/index.js +29 -0
  6. package/dist/cjs/view/CardWithUrl/component.js +7 -2
  7. package/dist/cjs/view/CardWithUrl/loader.js +2 -0
  8. package/dist/cjs/view/EmbedCard/index.js +29 -0
  9. package/dist/cjs/view/FlexibleCard/components/common/loading-skeleton/index.js +6 -4
  10. package/dist/cjs/view/FlexibleCard/index.js +34 -7
  11. package/dist/cjs/view/HoverCard/components/HoverCardComponent.js +27 -4
  12. package/dist/cjs/view/HoverCard/components/HoverCardContent.js +32 -10
  13. package/dist/cjs/view/HoverCard/components/HoverCardLoadingView.js +46 -0
  14. package/dist/cjs/view/HoverCard/styled.js +10 -4
  15. package/dist/cjs/view/InlineCard/index.js +29 -0
  16. package/dist/es2019/state/actions/constants.js +2 -1
  17. package/dist/es2019/state/actions/index.js +46 -18
  18. package/dist/es2019/version.json +1 -1
  19. package/dist/es2019/view/BlockCard/index.js +29 -0
  20. package/dist/es2019/view/CardWithUrl/component.js +7 -2
  21. package/dist/es2019/view/CardWithUrl/loader.js +2 -0
  22. package/dist/es2019/view/EmbedCard/index.js +29 -0
  23. package/dist/es2019/view/FlexibleCard/components/common/loading-skeleton/index.js +38 -31
  24. package/dist/es2019/view/FlexibleCard/index.js +32 -7
  25. package/dist/es2019/view/HoverCard/components/HoverCardComponent.js +27 -4
  26. package/dist/es2019/view/HoverCard/components/HoverCardContent.js +28 -9
  27. package/dist/es2019/view/HoverCard/components/HoverCardLoadingView.js +32 -0
  28. package/dist/es2019/view/HoverCard/styled.js +12 -1
  29. package/dist/es2019/view/InlineCard/index.js +29 -0
  30. package/dist/esm/state/actions/constants.js +2 -1
  31. package/dist/esm/state/actions/index.js +51 -20
  32. package/dist/esm/version.json +1 -1
  33. package/dist/esm/view/BlockCard/index.js +29 -0
  34. package/dist/esm/view/CardWithUrl/component.js +7 -2
  35. package/dist/esm/view/CardWithUrl/loader.js +2 -0
  36. package/dist/esm/view/EmbedCard/index.js +29 -0
  37. package/dist/esm/view/FlexibleCard/components/common/loading-skeleton/index.js +6 -3
  38. package/dist/esm/view/FlexibleCard/index.js +33 -7
  39. package/dist/esm/view/HoverCard/components/HoverCardComponent.js +27 -4
  40. package/dist/esm/view/HoverCard/components/HoverCardContent.js +30 -10
  41. package/dist/esm/view/HoverCard/components/HoverCardLoadingView.js +31 -0
  42. package/dist/esm/view/HoverCard/styled.js +6 -3
  43. package/dist/esm/view/InlineCard/index.js +29 -0
  44. package/dist/types/state/actions/constants.d.ts +1 -0
  45. package/dist/types/state/actions/index.d.ts +1 -0
  46. package/dist/types/state/hooks/useSmartLink.d.ts +1 -0
  47. package/dist/types/view/BlockCard/types.d.ts +2 -0
  48. package/dist/types/view/Card/index.d.ts +1 -1
  49. package/dist/types/view/Card/types.d.ts +2 -1
  50. package/dist/types/view/CardWithUrl/component.d.ts +1 -1
  51. package/dist/types/view/CardWithUrl/types.d.ts +2 -1
  52. package/dist/types/view/EmbedCard/components/styled.d.ts +16 -16
  53. package/dist/types/view/EmbedCard/types.d.ts +2 -0
  54. package/dist/types/view/FlexibleCard/components/common/loading-skeleton/types.d.ts +8 -0
  55. package/dist/types/view/FlexibleCard/types.d.ts +9 -4
  56. package/dist/types/view/HoverCard/components/HoverCardLoadingView.d.ts +4 -0
  57. package/dist/types/view/HoverCard/styled.d.ts +3 -0
  58. package/dist/types/view/HoverCard/types.d.ts +7 -0
  59. package/dist/types/view/InlineCard/Frame/styled.d.ts +1 -1
  60. package/dist/types/view/InlineCard/Icon.d.ts +3 -3
  61. package/dist/types/view/InlineCard/IconAndTitleLayout/styled.d.ts +9 -9
  62. package/dist/types/view/InlineCard/ResolvingView/styled.d.ts +13 -5
  63. package/dist/types/view/InlineCard/styled.d.ts +8 -4
  64. package/dist/types/view/InlineCard/types.d.ts +2 -1
  65. package/dist/types/view/types.d.ts +6 -0
  66. package/package.json +4 -4
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.default = void 0;
9
+
10
+ var _core = require("@emotion/core");
11
+
12
+ var _react = _interopRequireDefault(require("react"));
13
+
14
+ var _loadingSkeleton = _interopRequireDefault(require("../../FlexibleCard/components/common/loading-skeleton"));
15
+
16
+ var _FlexibleCard = _interopRequireDefault(require("../../FlexibleCard"));
17
+
18
+ var _blocks = require("../../FlexibleCard/components/blocks");
19
+
20
+ var _styled = require("../styled");
21
+
22
+ /** @jsx jsx */
23
+ var HoverCardLoadingView = function HoverCardLoadingView(_ref) {
24
+ var flexibleCardProps = _ref.flexibleCardProps,
25
+ titleBlockProps = _ref.titleBlockProps;
26
+ var lineHeightRem = 1.25;
27
+ var skeletonWidth = _styled.CARD_WIDTH_REM - 2;
28
+ return (0, _core.jsx)("div", {
29
+ css: _styled.loadingViewContainer,
30
+ "data-testid": "hover-card-loading-view"
31
+ }, (0, _core.jsx)(_FlexibleCard.default, flexibleCardProps, (0, _core.jsx)(_blocks.TitleBlock, titleBlockProps)), (0, _core.jsx)("div", {
32
+ css: _styled.skeletonContainer
33
+ }, (0, _core.jsx)("span", null), (0, _core.jsx)(_loadingSkeleton.default, {
34
+ width: skeletonWidth,
35
+ height: lineHeightRem
36
+ }), (0, _core.jsx)(_loadingSkeleton.default, {
37
+ width: skeletonWidth,
38
+ height: lineHeightRem * 3
39
+ }), (0, _core.jsx)(_loadingSkeleton.default, {
40
+ width: skeletonWidth,
41
+ height: lineHeightRem
42
+ })));
43
+ };
44
+
45
+ var _default = HoverCardLoadingView;
46
+ exports.default = _default;
@@ -5,7 +5,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
5
5
  Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
- exports.titleBlockCss = exports.metadataBlockCss = exports.footerBlockCss = exports.flexibleUiOptions = exports.HoverCardContainer = void 0;
8
+ exports.titleBlockCss = exports.skeletonContainer = exports.metadataBlockCss = exports.loadingViewContainer = exports.footerBlockCss = exports.flexibleUiOptions = exports.HoverCardContainer = exports.CARD_WIDTH_REM = void 0;
9
9
 
10
10
  var _taggedTemplateLiteral2 = _interopRequireDefault(require("@babel/runtime/helpers/taggedTemplateLiteral"));
11
11
 
@@ -15,7 +15,7 @@ var _index = require("../../index");
15
15
 
16
16
  var _constants = require("../../constants");
17
17
 
18
- var _templateObject, _templateObject2, _templateObject3, _templateObject4, _templateObject5;
18
+ var _templateObject, _templateObject2, _templateObject3, _templateObject4, _templateObject5, _templateObject6, _templateObject7;
19
19
 
20
20
  var flexibleUiOptions = {
21
21
  hideElevation: true,
@@ -25,14 +25,20 @@ var flexibleUiOptions = {
25
25
  hidePadding: true
26
26
  };
27
27
  exports.flexibleUiOptions = flexibleUiOptions;
28
+ var CARD_WIDTH_REM = 24;
29
+ exports.CARD_WIDTH_REM = CARD_WIDTH_REM;
28
30
  var blockGap = '0.5rem';
29
31
  var elementGap = '0.5rem';
30
32
  var separatorCss = (0, _core.css)(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2.default)(["\n [data-separator] + [data-separator]:before {\n margin-right: ", ";\n }\n"])), elementGap);
31
- var HoverCardContainer = (0, _core.css)(_templateObject2 || (_templateObject2 = (0, _taggedTemplateLiteral2.default)(["\n background: none;\n border-width: 0;\n box-sizing: border-box;\n width: 24rem;\n padding: 1rem;\n\n .", " {\n display: none;\n }\n"])), _index.loadingPlaceholderClassName);
33
+ var HoverCardContainer = (0, _core.css)(_templateObject2 || (_templateObject2 = (0, _taggedTemplateLiteral2.default)(["\n background: none;\n border-width: 0;\n box-sizing: border-box;\n width: ", "rem;\n padding: 1rem;\n\n .", " {\n display: none;\n }\n"])), CARD_WIDTH_REM, _index.loadingPlaceholderClassName);
32
34
  exports.HoverCardContainer = HoverCardContainer;
33
35
  var titleBlockCss = (0, _core.css)(_templateObject3 || (_templateObject3 = (0, _taggedTemplateLiteral2.default)(["\n gap: ", ";\n\n ", "\n\n // title and subtitle element group\n [data-smart-element-group] {\n // gap between title and subtitle\n gap: 0.06rem;\n\n /* subtitle element group */\n > [data-smart-element-group] {\n > span {\n margin-right: ", ";\n }\n }\n }\n"])), blockGap, separatorCss, elementGap);
34
36
  exports.titleBlockCss = titleBlockCss;
35
37
  var metadataBlockCss = (0, _core.css)(_templateObject4 || (_templateObject4 = (0, _taggedTemplateLiteral2.default)(["\n gap: 0px;\n\n /* primary element group */\n [data-smart-element-group]:nth-of-type(1) {\n flex-grow: 7;\n\n // a separator between text-based element\n ", "\n\n /* horizontal spacing between elements in group */\n > span {\n margin-right: ", ";\n }\n }\n /* secondary element group */\n [data-smart-element-group]:nth-of-type(2) {\n flex-grow: 3;\n /* horizontal spacing between elements in group */\n > span {\n margin-left: ", ";\n }\n }\n"])), separatorCss, elementGap, elementGap);
36
38
  exports.metadataBlockCss = metadataBlockCss;
37
39
  var footerBlockCss = (0, _core.css)(_templateObject5 || (_templateObject5 = (0, _taggedTemplateLiteral2.default)(["\n padding-top: 0.25rem;\n"])));
38
- exports.footerBlockCss = footerBlockCss;
40
+ exports.footerBlockCss = footerBlockCss;
41
+ var loadingViewContainer = (0, _core.css)(_templateObject6 || (_templateObject6 = (0, _taggedTemplateLiteral2.default)(["\n display: flex;\n flex-direction: column;\n"])));
42
+ exports.loadingViewContainer = loadingViewContainer;
43
+ var skeletonContainer = (0, _core.css)(_templateObject7 || (_templateObject7 = (0, _taggedTemplateLiteral2.default)(["\n display: flex;\n flex-direction: column;\n gap: 0.625rem;\n align-items: center;\n"])));
44
+ exports.skeletonContainer = skeletonContainer;
@@ -72,6 +72,7 @@ var InlineCard = function InlineCard(_ref) {
72
72
  isSelected = _ref.isSelected,
73
73
  renderers = _ref.renderers,
74
74
  onResolve = _ref.onResolve,
75
+ onError = _ref.onError,
75
76
  testId = _ref.testId,
76
77
  inlinePreloaderStyle = _ref.inlinePreloaderStyle,
77
78
  showHoverPreview = _ref.showHoverPreview;
@@ -111,6 +112,13 @@ var InlineCard = function InlineCard(_ref) {
111
112
  }));
112
113
 
113
114
  case 'unauthorized':
115
+ if (onError) {
116
+ onError({
117
+ url: url,
118
+ status: status
119
+ });
120
+ }
121
+
114
122
  var provider = (0, _extractors.extractProvider)(cardDetails);
115
123
  return /*#__PURE__*/_react.default.createElement(_UnauthorisedView.InlineCardUnauthorizedView, {
116
124
  icon: provider && provider.icon,
@@ -122,6 +130,13 @@ var InlineCard = function InlineCard(_ref) {
122
130
  });
123
131
 
124
132
  case 'forbidden':
133
+ if (onError) {
134
+ onError({
135
+ url: url,
136
+ status: status
137
+ });
138
+ }
139
+
125
140
  var providerForbidden = (0, _extractors.extractProvider)(cardDetails);
126
141
  var cardMetadata = (_details$meta = details === null || details === void 0 ? void 0 : details.meta) !== null && _details$meta !== void 0 ? _details$meta : (0, _jsonld.getUnauthorizedJsonLd)().meta;
127
142
  var requestAccessContext = (0, _context.extractRequestAccessContext)({
@@ -141,6 +156,13 @@ var InlineCard = function InlineCard(_ref) {
141
156
  });
142
157
 
143
158
  case 'not_found':
159
+ if (onError) {
160
+ onError({
161
+ url: url,
162
+ status: status
163
+ });
164
+ }
165
+
144
166
  var providerNotFound = (0, _extractors.extractProvider)(cardDetails);
145
167
  return /*#__PURE__*/_react.default.createElement(_ErroredView.InlineCardErroredView, {
146
168
  url: url,
@@ -153,6 +175,13 @@ var InlineCard = function InlineCard(_ref) {
153
175
 
154
176
  case 'fallback':
155
177
  case 'errored':
178
+ if (onError) {
179
+ onError({
180
+ url: url,
181
+ status: status
182
+ });
183
+ }
184
+
156
185
  return /*#__PURE__*/_react.default.createElement(_LinkView.CardLinkView, {
157
186
  link: url,
158
187
  isSelected: isSelected,
@@ -2,4 +2,5 @@ export const ANALYTICS_RESOLVING = 'resolving';
2
2
  export const ANALYTICS_ERROR = 'errored';
3
3
  export const ANALYTICS_FALLBACK = 'fallback';
4
4
  export const ERROR_MESSAGE_OAUTH = 'Provider.authFlow is not set to OAuth2.';
5
- export const ERROR_MESSAGE_FATAL = 'Fatal error resolving URL';
5
+ export const ERROR_MESSAGE_FATAL = 'Fatal error resolving URL';
6
+ export const ERROR_MESSAGE_METADATA = 'Error resolving metadata.';
@@ -1,10 +1,9 @@
1
1
  import { useMemo, useCallback } from 'react';
2
2
  import { auth } from '@atlaskit/outbound-auth-flow-client';
3
- import { APIError } from '@atlaskit/linking-common';
4
3
  import { useSmartLinkContext } from '@atlaskit/link-provider';
5
- import { ACTION_PENDING, ACTION_RESOLVED, ACTION_ERROR, ACTION_ERROR_FALLBACK, ACTION_RELOADING, cardAction } from '@atlaskit/linking-common';
4
+ import { ACTION_PENDING, ACTION_RESOLVED, ACTION_ERROR, ACTION_ERROR_FALLBACK, ACTION_RELOADING, ACTION_UPDATE_METADATA_STATUS, cardAction, APIError } from '@atlaskit/linking-common';
6
5
  import { getDefinitionId, getByDefinitionId, getServices, getStatus, getExtensionKey } from '../helpers';
7
- import { ERROR_MESSAGE_OAUTH, ERROR_MESSAGE_FATAL } from './constants';
6
+ import { ERROR_MESSAGE_OAUTH, ERROR_MESSAGE_FATAL, ERROR_MESSAGE_METADATA } from './constants';
8
7
  import * as measure from '../../utils/performance';
9
8
  import { getUnauthorizedJsonLd } from '../../utils/jsonld';
10
9
  import { addMetadataToExperience } from '../analytics';
@@ -20,14 +19,26 @@ export const useSmartCardActions = (id, url, analytics) => {
20
19
  } = store;
21
20
  const {
22
21
  details,
23
- status
22
+ status,
23
+ metadataStatus
24
24
  } = getState()[url] || {
25
25
  status: 'pending',
26
26
  details: undefined
27
27
  };
28
28
  const hasAuthFlowSupported = config.authFlow !== 'disabled';
29
29
  const hasData = !!(details && details.data);
30
- const handleResolvedLinkError = useCallback((url, error, response) => {
30
+ const setMetadataStatus = useCallback(metadataStatus => {
31
+ dispatch(cardAction(ACTION_UPDATE_METADATA_STATUS, {
32
+ url
33
+ }, undefined, undefined, metadataStatus));
34
+ }, [dispatch, url]);
35
+ const handleResolvedLinkError = useCallback((url, error, response, isMetadataRequest) => {
36
+ // If metadata request then set metadata status, return and do not alter link status
37
+ if (isMetadataRequest) {
38
+ setMetadataStatus('errored');
39
+ return;
40
+ }
41
+
31
42
  if (error.kind === 'fatal') {
32
43
  // If there's no previous data in the store for this URL, then bail
33
44
  // out and let the editor handle fallbacks (returns to a blue link).
@@ -64,24 +75,32 @@ export const useSmartCardActions = (id, url, analytics) => {
64
75
  }, undefined, error));
65
76
  }
66
77
  }
67
- }, [hasData, status, dispatch, details]);
68
- const handleResolvedLinkResponse = useCallback((resourceUrl, response, isReloading = false) => {
78
+ }, [setMetadataStatus, hasData, status, dispatch, details]);
79
+ const handleResolvedLinkResponse = useCallback((resourceUrl, response, isReloading = false, isMetadataRequest) => {
69
80
  const hostname = new URL(resourceUrl).hostname;
70
81
  const nextStatus = response ? getStatus(response) : 'fatal'; // If we require authorization & do not have an authFlow available,
71
82
  // throw an error and render as a normal blue link.
72
83
 
73
84
  if ((nextStatus === 'unauthorized' || nextStatus === 'forbidden') && !hasAuthFlowSupported) {
74
- handleResolvedLinkError(resourceUrl, new APIError('fallback', hostname, ERROR_MESSAGE_OAUTH), response);
85
+ handleResolvedLinkError(resourceUrl, new APIError('fallback', hostname, ERROR_MESSAGE_OAUTH), response, isMetadataRequest);
75
86
  return;
76
87
  } // Handle any other errors
77
88
 
78
89
 
79
90
  if (nextStatus === 'fatal') {
80
- handleResolvedLinkError(resourceUrl, new APIError('fatal', hostname, ERROR_MESSAGE_FATAL));
91
+ handleResolvedLinkError(resourceUrl, new APIError('fatal', hostname, ERROR_MESSAGE_FATAL), undefined, isMetadataRequest);
81
92
  return;
82
- } // Dispatch Analytics and resolved card action - including unauthorized states.
93
+ } // Handle errors of any other kind in the metadata request response
83
94
 
84
95
 
96
+ if (isMetadataRequest && nextStatus !== 'resolved') {
97
+ handleResolvedLinkError(resourceUrl, new APIError('error', hostname, ERROR_MESSAGE_METADATA), response, isMetadataRequest);
98
+ return;
99
+ } //if a link resolves normally, metadata will also always be resolved
100
+
101
+
102
+ setMetadataStatus('resolved'); // Dispatch Analytics and resolved card action - including unauthorized states.
103
+
85
104
  if (isReloading) {
86
105
  dispatch(cardAction(ACTION_RELOADING, {
87
106
  url: resourceUrl
@@ -89,15 +108,15 @@ export const useSmartCardActions = (id, url, analytics) => {
89
108
  } else {
90
109
  dispatch(cardAction(ACTION_RESOLVED, {
91
110
  url: resourceUrl
92
- }, response));
111
+ }, response, undefined, undefined, isMetadataRequest));
93
112
  }
94
- }, [dispatch, handleResolvedLinkError, hasAuthFlowSupported]);
95
- const resolve = useCallback(async (resourceUrl = url, isReloading = false) => {
113
+ }, [dispatch, handleResolvedLinkError, hasAuthFlowSupported, setMetadataStatus]);
114
+ const resolve = useCallback(async (resourceUrl = url, isReloading = false, isMetadataRequest = false) => {
96
115
  // Request JSON-LD data for the card from ORS, iff it has extended
97
116
  // its cache lifespan OR there is no data for it currently. Once the data
98
117
  // has come back asynchronously, dispatch the resolved action for the card.
99
- if (isReloading || !hasData) {
100
- return connections.client.fetchData(resourceUrl).then(response => handleResolvedLinkResponse(resourceUrl, response, isReloading)).catch(error => handleResolvedLinkError(resourceUrl, error));
118
+ if (isReloading || !hasData || isMetadataRequest) {
119
+ return connections.client.fetchData(resourceUrl).then(response => handleResolvedLinkResponse(resourceUrl, response, isReloading, isMetadataRequest)).catch(error => handleResolvedLinkError(resourceUrl, error, undefined, isMetadataRequest));
101
120
  } else {
102
121
  addMetadataToExperience('smart-link-rendered', id, {
103
122
  cached: true
@@ -109,10 +128,11 @@ export const useSmartCardActions = (id, url, analytics) => {
109
128
  dispatch(cardAction(ACTION_PENDING, {
110
129
  url
111
130
  }));
131
+ setMetadataStatus('pending');
112
132
  }
113
133
 
114
134
  return resolve();
115
- }, [url, resolve, details, dispatch]);
135
+ }, [details, resolve, dispatch, url, setMetadataStatus]);
116
136
  const reload = useCallback(() => {
117
137
  const definitionId = getDefinitionId(details);
118
138
 
@@ -122,6 +142,13 @@ export const useSmartCardActions = (id, url, analytics) => {
122
142
  resolve(url, true);
123
143
  }
124
144
  }, [url, details, getState, resolve]);
145
+ const loadMetadata = useCallback(() => {
146
+ //metadataStatus will be undefined for SSR links only
147
+ if (metadataStatus === undefined) {
148
+ setMetadataStatus('pending');
149
+ return resolve(url, false, true);
150
+ }
151
+ }, [metadataStatus, resolve, setMetadataStatus, url]);
125
152
  const authorize = useCallback(appearance => {
126
153
  const definitionId = getDefinitionId(details);
127
154
  const extensionKey = getExtensionKey(details);
@@ -187,6 +214,7 @@ export const useSmartCardActions = (id, url, analytics) => {
187
214
  register,
188
215
  reload,
189
216
  authorize,
190
- invoke
191
- }), [register, reload, authorize, invoke]);
217
+ invoke,
218
+ loadMetadata
219
+ }), [register, reload, authorize, invoke, loadMetadata]);
192
220
  };
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-card",
3
- "version": "20.0.6",
3
+ "version": "20.1.2",
4
4
  "sideEffects": false
5
5
  }
@@ -30,6 +30,7 @@ export const BlockCard = ({
30
30
  renderers,
31
31
  isSelected,
32
32
  onResolve,
33
+ onError,
33
34
  testId,
34
35
  showActions,
35
36
  platform
@@ -70,6 +71,13 @@ export const BlockCard = ({
70
71
  }));
71
72
 
72
73
  case 'unauthorized':
74
+ if (onError) {
75
+ onError({
76
+ url,
77
+ status
78
+ });
79
+ }
80
+
73
81
  const unauthorizedViewProps = extractBlockProps(data, meta, extractorOpts);
74
82
  return /*#__PURE__*/React.createElement(BlockCardUnauthorisedView, _extends({}, unauthorizedViewProps, {
75
83
  isSelected: isSelected,
@@ -80,6 +88,13 @@ export const BlockCard = ({
80
88
  }));
81
89
 
82
90
  case 'forbidden':
91
+ if (onError) {
92
+ onError({
93
+ url,
94
+ status
95
+ });
96
+ }
97
+
83
98
  const forbiddenViewProps = extractBlockProps(data, meta, extractorOpts);
84
99
  const cardMetadata = (_details$meta = details === null || details === void 0 ? void 0 : details.meta) !== null && _details$meta !== void 0 ? _details$meta : getUnauthorizedJsonLd().meta;
85
100
  const requestAccessContext = extractRequestAccessContext({
@@ -96,6 +111,13 @@ export const BlockCard = ({
96
111
  }));
97
112
 
98
113
  case 'not_found':
114
+ if (onError) {
115
+ onError({
116
+ url,
117
+ status
118
+ });
119
+ }
120
+
99
121
  const notFoundViewProps = extractBlockProps(data, meta, extractorOpts);
100
122
  return /*#__PURE__*/React.createElement(BlockCardNotFoundView, _extends({}, notFoundViewProps, {
101
123
  isSelected: isSelected,
@@ -105,6 +127,13 @@ export const BlockCard = ({
105
127
 
106
128
  case 'fallback':
107
129
  case 'errored':
130
+ if (onError) {
131
+ onError({
132
+ url,
133
+ status
134
+ });
135
+ }
136
+
108
137
  if (authFlow && authFlow === 'disabled') {
109
138
  return /*#__PURE__*/React.createElement(CardLinkView, {
110
139
  link: url,
@@ -20,6 +20,7 @@ export function CardWithUrlContent({
20
20
  appearance,
21
21
  dispatchAnalytics,
22
22
  onResolve,
23
+ onError,
23
24
  testId,
24
25
  showActions,
25
26
  inheritDimensions,
@@ -91,7 +92,7 @@ export function CardWithUrlContent({
91
92
  if (isFinalState(state.status)) {
92
93
  analytics.ui.renderSuccessEvent(appearance, state.status, id, definitionId, extensionKey);
93
94
  }
94
- }, [appearance, state.details, state.status, url, definitionId, extensionKey, analytics.ui, id]);
95
+ }, [appearance, state.status, url, definitionId, extensionKey, analytics.ui, id]);
95
96
 
96
97
  if (isFlexibleUi) {
97
98
  let cardState = state;
@@ -115,7 +116,8 @@ export function CardWithUrlContent({
115
116
  ui: ui,
116
117
  url: url,
117
118
  testId: testId,
118
- onResolve: onResolve
119
+ onResolve: onResolve,
120
+ onError: onError
119
121
  }, children);
120
122
  } // We have to keep this last to prevent hook order from being violated
121
123
 
@@ -135,6 +137,7 @@ export function CardWithUrlContent({
135
137
  handleFrameClick: handleClickWrapper,
136
138
  isSelected: isSelected,
137
139
  onResolve: onResolve,
140
+ onError: onError,
138
141
  testId: testId,
139
142
  inlinePreloaderStyle: inlinePreloaderStyle,
140
143
  showHoverPreview: showHoverPreview
@@ -154,6 +157,7 @@ export function CardWithUrlContent({
154
157
  handleAnalytics: dispatchAnalytics,
155
158
  isSelected: isSelected,
156
159
  onResolve: onResolve,
160
+ onError: onError,
157
161
  testId: testId,
158
162
  showActions: showActions,
159
163
  platform: platform
@@ -173,6 +177,7 @@ export function CardWithUrlContent({
173
177
  isFrameVisible: isFrameVisible,
174
178
  platform: platform,
175
179
  onResolve: onResolve,
180
+ onError: onError,
176
181
  testId: testId,
177
182
  inheritDimensions: inheritDimensions,
178
183
  showActions: showActions,
@@ -25,6 +25,7 @@ export function CardWithURLRenderer(props) {
25
25
  onClick,
26
26
  container,
27
27
  onResolve,
28
+ onError,
28
29
  testId,
29
30
  showActions,
30
31
  inheritDimensions,
@@ -85,6 +86,7 @@ export function CardWithURLRenderer(props) {
85
86
  dispatchAnalytics,
86
87
  container,
87
88
  onResolve,
89
+ onError,
88
90
  testId,
89
91
  showActions,
90
92
  inheritDimensions,
@@ -29,6 +29,7 @@ export const EmbedCard = /*#__PURE__*/React.forwardRef(({
29
29
  isFrameVisible,
30
30
  platform,
31
31
  onResolve,
32
+ onError,
32
33
  testId,
33
34
  inheritDimensions
34
35
  }, iframeRef) => {
@@ -91,6 +92,13 @@ export const EmbedCard = /*#__PURE__*/React.forwardRef(({
91
92
  }
92
93
 
93
94
  case 'unauthorized':
95
+ if (onError) {
96
+ onError({
97
+ url,
98
+ status
99
+ });
100
+ }
101
+
94
102
  const unauthorisedViewProps = extractEmbedProps(data, meta, platform);
95
103
  return /*#__PURE__*/React.createElement(EmbedCardUnauthorisedView, _extends({}, unauthorisedViewProps, {
96
104
  isSelected: isSelected,
@@ -100,6 +108,13 @@ export const EmbedCard = /*#__PURE__*/React.forwardRef(({
100
108
  }));
101
109
 
102
110
  case 'forbidden':
111
+ if (onError) {
112
+ onError({
113
+ url,
114
+ status
115
+ });
116
+ }
117
+
103
118
  const forbiddenViewProps = extractEmbedProps(data, meta, platform);
104
119
  const cardMetadata = (_details$meta = details === null || details === void 0 ? void 0 : details.meta) !== null && _details$meta !== void 0 ? _details$meta : getUnauthorizedJsonLd().meta;
105
120
  const requestAccessContext = extractRequestAccessContext({
@@ -116,6 +131,13 @@ export const EmbedCard = /*#__PURE__*/React.forwardRef(({
116
131
  }));
117
132
 
118
133
  case 'not_found':
134
+ if (onError) {
135
+ onError({
136
+ url,
137
+ status
138
+ });
139
+ }
140
+
119
141
  const notFoundViewProps = extractEmbedProps(data, meta, platform);
120
142
  return /*#__PURE__*/React.createElement(EmbedCardNotFoundView, _extends({}, notFoundViewProps, {
121
143
  isSelected: isSelected,
@@ -125,6 +147,13 @@ export const EmbedCard = /*#__PURE__*/React.forwardRef(({
125
147
 
126
148
  case 'fallback':
127
149
  case 'errored':
150
+ if (onError) {
151
+ onError({
152
+ url,
153
+ status
154
+ });
155
+ }
156
+
128
157
  return /*#__PURE__*/React.createElement(EmbedCardErroredView, {
129
158
  onRetry: handleErrorRetry,
130
159
  inheritDimensions: inheritDimensions,
@@ -2,38 +2,45 @@
2
2
  import React from 'react';
3
3
  import { css, jsx, keyframes } from '@emotion/core';
4
4
  import { token } from '@atlaskit/tokens';
5
- const animationNameStyles = keyframes`
6
- 0% { background-position: -20px 0; }
7
- 100% { background-position: 20px 0; }
8
- `;
9
- const styles = css`
10
- border-radius: 2px;
11
- user-select: none;
12
- background: ${token('color.skeleton.subtle', '#f6f7f8')};
13
- // TODO: https://product-fabric.atlassian.net/browse/DSP-4236
14
- background-image: linear-gradient(
15
- to right,
16
- ${token('color.skeleton.subtle', '#f6f7f8')} 0%,
17
- ${token('color.skeleton', '#edeef1')} 20%,
18
- ${token('color.skeleton.subtle', '#f6f7f8')} 40%,
19
- ${token('color.skeleton.subtle', '#f6f7f8')}100%
20
- );
21
- background-repeat: no-repeat;
22
- background-size: 280% 100%;
23
- display: inline-block;
24
-
25
- animation-duration: 1s;
26
- animation-fill-mode: forwards;
27
- animation-iteration-count: infinite;
28
- animation-name: ${animationNameStyles};
29
- animation-timing-function: linear;
30
- `;
31
5
 
32
6
  const LoadingSkeleton = ({
33
- testId
34
- }) => jsx("span", {
35
- css: styles,
36
- "data-testid": testId
37
- });
7
+ testId,
8
+ width,
9
+ height
10
+ }) => {
11
+ const animationWidth = width ? `${width}rem` : '20px';
12
+ const animationNameStyles = keyframes`
13
+ 0% { background-position: -${animationWidth} 0; }
14
+ 100% { background-position: ${animationWidth} 0; }
15
+ `;
16
+ const styles = css`
17
+ width: ${width}rem;
18
+ height: ${height}rem;
19
+ border-radius: 2px;
20
+ user-select: none;
21
+ background: ${token('color.skeleton.subtle', '#f6f7f8')};
22
+ // TODO: https://product-fabric.atlassian.net/browse/DSP-4236
23
+ background-image: linear-gradient(
24
+ to right,
25
+ ${token('color.skeleton.subtle', '#f6f7f8')} 0%,
26
+ ${token('color.skeleton', '#edeef1')} 20%,
27
+ ${token('color.skeleton.subtle', '#f6f7f8')} 40%,
28
+ ${token('color.skeleton.subtle', '#f6f7f8')}100%
29
+ );
30
+ background-repeat: no-repeat;
31
+ background-size: 280% 100%;
32
+ display: inline-block;
33
+
34
+ animation-duration: 1s;
35
+ animation-fill-mode: forwards;
36
+ animation-iteration-count: infinite;
37
+ animation-name: ${animationNameStyles};
38
+ animation-timing-function: linear;
39
+ `;
40
+ return jsx("span", {
41
+ css: styles,
42
+ "data-testid": testId
43
+ });
44
+ };
38
45
 
39
46
  export default LoadingSkeleton;
@@ -1,5 +1,6 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
2
  import React, { useEffect } from 'react';
3
+ import { SmartLinkStatus } from '../../constants';
3
4
  import Container from './components/container';
4
5
  import { FlexibleUiContext } from '../../state/flexible-ui-context';
5
6
  import { getContextByStatus, getRetryOptions } from './utils';
@@ -14,12 +15,13 @@ const FlexibleCard = ({
14
15
  cardState,
15
16
  children,
16
17
  onAuthorize,
18
+ onError,
19
+ onResolve,
17
20
  renderers,
18
21
  ui,
19
22
  url,
20
23
  onClick,
21
- testId,
22
- onResolve
24
+ testId
23
25
  }) => {
24
26
  const {
25
27
  status: cardType,
@@ -28,13 +30,36 @@ const FlexibleCard = ({
28
30
  const status = cardType;
29
31
  const context = getContextByStatus(url, status, details, renderers);
30
32
  const retry = getRetryOptions(url, status, details, onAuthorize);
33
+ const {
34
+ title
35
+ } = context || {};
31
36
  useEffect(() => {
32
- if (status === 'resolved' && onResolve) {
33
- onResolve({
34
- url
35
- });
37
+ switch (status) {
38
+ case SmartLinkStatus.Resolved:
39
+ if (onResolve) {
40
+ onResolve({
41
+ title,
42
+ url
43
+ });
44
+ }
45
+
46
+ break;
47
+
48
+ case SmartLinkStatus.Errored:
49
+ case SmartLinkStatus.Fallback:
50
+ case SmartLinkStatus.Forbidden:
51
+ case SmartLinkStatus.NotFound:
52
+ case SmartLinkStatus.Unauthorized:
53
+ if (onError) {
54
+ onError({
55
+ status,
56
+ url
57
+ });
58
+ }
59
+
60
+ break;
36
61
  }
37
- }, [onResolve, status, url]);
62
+ }, [onError, onResolve, status, title, url]);
38
63
  return /*#__PURE__*/React.createElement(FlexibleUiContext.Provider, {
39
64
  value: context
40
65
  }, /*#__PURE__*/React.createElement(Container, _extends({