@atlaskit/smart-card 19.0.1 → 19.0.4

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 (32) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/cjs/messages.js +16 -6
  3. package/dist/cjs/version.json +1 -1
  4. package/dist/cjs/view/CardWithUrl/component-lazy/LazyIntersectionObserverCard.js +6 -2
  5. package/dist/cjs/view/CardWithUrl/component-lazy/LazyLazilyRenderCard.js +15 -2
  6. package/dist/cjs/view/CardWithUrl/component.js +2 -1
  7. package/dist/cjs/view/CardWithUrl/loader.js +5 -7
  8. package/dist/cjs/view/FlexibleCard/components/elements/date-time/index.js +32 -10
  9. package/dist/cjs/view/FlexibleCard/index.js +16 -2
  10. package/dist/cjs/view/HoverCard/index.js +10 -3
  11. package/dist/es2019/messages.js +16 -6
  12. package/dist/es2019/version.json +1 -1
  13. package/dist/es2019/view/CardWithUrl/component-lazy/LazyIntersectionObserverCard.js +6 -3
  14. package/dist/es2019/view/CardWithUrl/component-lazy/LazyLazilyRenderCard.js +8 -2
  15. package/dist/es2019/view/CardWithUrl/component.js +2 -1
  16. package/dist/es2019/view/CardWithUrl/loader.js +5 -7
  17. package/dist/es2019/view/FlexibleCard/components/elements/date-time/index.js +33 -11
  18. package/dist/es2019/view/FlexibleCard/index.js +10 -2
  19. package/dist/es2019/view/HoverCard/index.js +12 -3
  20. package/dist/esm/messages.js +16 -6
  21. package/dist/esm/version.json +1 -1
  22. package/dist/esm/view/CardWithUrl/component-lazy/LazyIntersectionObserverCard.js +6 -3
  23. package/dist/esm/view/CardWithUrl/component-lazy/LazyLazilyRenderCard.js +8 -2
  24. package/dist/esm/view/CardWithUrl/component.js +2 -1
  25. package/dist/esm/view/CardWithUrl/loader.js +5 -7
  26. package/dist/esm/view/FlexibleCard/components/elements/date-time/index.js +32 -10
  27. package/dist/esm/view/FlexibleCard/index.js +10 -2
  28. package/dist/esm/view/HoverCard/index.js +10 -3
  29. package/dist/types/messages.d.ts +1 -1
  30. package/dist/types/view/FlexibleCard/types.d.ts +5 -0
  31. package/dist/types/view/__mocks__/intersection-observer.d.ts +3 -0
  32. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @atlaskit/smart-card
2
2
 
3
+ ## 19.0.4
4
+
5
+ ### Patch Changes
6
+
7
+ - [`3eea7c153d6`](https://bitbucket.org/atlassian/atlassian-frontend/commits/3eea7c153d6) - Handle onResolve prop from smart-card in flexible-card and use the prop inside hover-card to dynamically update popup positioning
8
+
9
+ ## 19.0.3
10
+
11
+ ### Patch Changes
12
+
13
+ - [`cae40e59c49`](https://bitbucket.org/atlassian/atlassian-frontend/commits/cae40e59c49) - Show relative date for dates less then 7 days away (flexible ui)
14
+
15
+ ## 19.0.2
16
+
17
+ ### Patch Changes
18
+
19
+ - [`f3026520fc6`](https://bitbucket.org/atlassian/atlassian-frontend/commits/f3026520fc6) - Fix long tti times for UFO smart-link-rendered experience
20
+
3
21
  ## 19.0.1
4
22
 
5
23
  ### Patch Changes
@@ -33,10 +33,15 @@ var messages = (0, _reactIntlNext.defineMessages)({
33
33
  defaultMessage: 'Created by {context}',
34
34
  description: 'Indicates the person or entity that created the resource.'
35
35
  },
36
- created_on: {
37
- id: 'fabric.linking.create_on',
36
+ created_on_relative: {
37
+ id: 'fabric.linking.create_on_relative',
38
38
  defaultMessage: 'Created {context}',
39
- description: 'Indicated when entity was created'
39
+ description: 'Indicated when entity was created (relative form)'
40
+ },
41
+ created_on_absolute: {
42
+ id: 'fabric.linking.create_on_absolute',
43
+ defaultMessage: 'Created on {context}',
44
+ description: 'Indicated when entity was created (absolute form)'
40
45
  },
41
46
  delete: {
42
47
  id: 'fabric.linking.delete',
@@ -53,10 +58,15 @@ var messages = (0, _reactIntlNext.defineMessages)({
53
58
  defaultMessage: 'Modified by {context}',
54
59
  description: 'Indicates the person or entity that modified the resource.'
55
60
  },
56
- modified_on: {
57
- id: 'fabric.linking.modified_on',
61
+ modified_on_relative: {
62
+ id: 'fabric.linking.modified_on_relative',
58
63
  defaultMessage: 'Updated {context}',
59
- description: 'Indicated when entity was modified'
64
+ description: 'Indicated when entity was modified (relative form)'
65
+ },
66
+ modified_on_absolute: {
67
+ id: 'fabric.linking.modified_on_absolute',
68
+ defaultMessage: 'Updated on {context}',
69
+ description: 'Indicated when entity was modified (absolute form)'
60
70
  },
61
71
  priority_blocker: {
62
72
  id: 'fabric.linking.priority_blocker',
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-card",
3
- "version": "19.0.1",
3
+ "version": "19.0.4",
4
4
  "sideEffects": false
5
5
  }
@@ -21,6 +21,8 @@ var _component = require("../component");
21
21
 
22
22
  var _LazyFallback = require("./LazyFallback");
23
23
 
24
+ var _ufoExperiences = require("../../../state/analytics/ufoExperiences");
25
+
24
26
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
25
27
 
26
28
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
@@ -39,7 +41,8 @@ function LazyIntersectionObserverCard(props) {
39
41
 
40
42
  var showActions = props.showActions,
41
43
  appearance = props.appearance,
42
- url = props.url;
44
+ url = props.url,
45
+ id = props.id;
43
46
  var prefetch = (0, _state.usePrefetch)(url);
44
47
  var Component = appearance === 'inline' ? 'span' : 'div';
45
48
  var ComponentObserver = Component;
@@ -49,12 +52,13 @@ function LazyIntersectionObserverCard(props) {
49
52
  });
50
53
 
51
54
  if (isVisible) {
55
+ (0, _ufoExperiences.startUfoExperience)('smart-link-rendered', id);
52
56
  setIsIntersecting(true);
53
57
  observer.disconnect();
54
58
  } else {
55
59
  prefetch();
56
60
  }
57
- }, [prefetch]);
61
+ }, [prefetch, id]);
58
62
  var onRef = (0, _react.useCallback)(function (element) {
59
63
  if (!element) {
60
64
  return;
@@ -2,6 +2,8 @@
2
2
 
3
3
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
4
 
5
+ var _typeof = require("@babel/runtime/helpers/typeof");
6
+
5
7
  Object.defineProperty(exports, "__esModule", {
6
8
  value: true
7
9
  });
@@ -9,7 +11,7 @@ exports.LazyLazilyRenderCard = LazyLazilyRenderCard;
9
11
 
10
12
  var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
11
13
 
12
- var _react = _interopRequireDefault(require("react"));
14
+ var _react = _interopRequireWildcard(require("react"));
13
15
 
14
16
  var _reactLazilyRender = _interopRequireDefault(require("react-lazily-render"));
15
17
 
@@ -17,11 +19,22 @@ var _component = require("../component");
17
19
 
18
20
  var _LazyFallback = require("./LazyFallback");
19
21
 
22
+ var _ufoExperiences = require("../../../state/analytics/ufoExperiences");
23
+
24
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
25
+
26
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
27
+
20
28
  function LazyLazilyRenderCard(props) {
21
29
  var appearance = props.appearance,
22
30
  container = props.container,
23
- showActions = props.showActions;
31
+ showActions = props.showActions,
32
+ id = props.id;
24
33
  var offset = Math.ceil(window.innerHeight / 4);
34
+ (0, _react.useState)(function () {
35
+ // Start of experience when intersectionObserver is not supported.
36
+ (0, _ufoExperiences.startUfoExperience)('smart-link-rendered', id);
37
+ });
25
38
  return /*#__PURE__*/_react.default.createElement(_reactLazilyRender.default, {
26
39
  offset: offset,
27
40
  component: appearance === 'inline' ? 'span' : 'div',
@@ -136,7 +136,8 @@ function CardWithUrlContent(_ref) {
136
136
  renderers: renderers,
137
137
  ui: ui,
138
138
  url: url,
139
- testId: testId
139
+ testId: testId,
140
+ onResolve: onResolve
140
141
  }, children);
141
142
  } // We have to keep this last to prevent hook order from being violated
142
143
 
@@ -40,13 +40,8 @@ function CardWithURLRenderer(props) {
40
40
  return (0, _uuid.default)();
41
41
  }),
42
42
  _useState2 = (0, _slicedToArray2.default)(_useState, 1),
43
- id = _useState2[0]; // Equivalent to ComponentWillMount
43
+ id = _useState2[0];
44
44
 
45
-
46
- (0, _react.useState)(function () {
47
- // We want to start timing of render event only once and right at the start
48
- (0, _ufoExperiences.startUfoExperience)('smart-link-rendered', id);
49
- });
50
45
  (0, _react.useEffect)(function () {
51
46
  // ComponentWillUnmount
52
47
  return function () {
@@ -96,7 +91,10 @@ function CardWithURLRenderer(props) {
96
91
  else {
97
92
  var errorInfo = {
98
93
  componentStack: componentStack
99
- };
94
+ }; // Start and fail the smart-link-rendered experience. If it has already
95
+ // been started nothing happens.
96
+
97
+ (0, _ufoExperiences.startUfoExperience)('smart-link-rendered', id);
100
98
  (0, _ufoExperiences.failUfoExperience)('smart-link-rendered', id);
101
99
  (0, _ufoExperiences.failUfoExperience)('smart-link-authenticated', id);
102
100
  dispatchAnalytics((0, _analytics.uiRenderFailedEvent)(appearance, error, errorInfo));
@@ -29,8 +29,14 @@ var _templateObject;
29
29
 
30
30
  var styles = (0, _core.css)(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2.default)(["\n color: ", ";\n font-size: 0.75rem;\n line-height: 1rem;\n ", "\n"])), _token.tokens.text, (0, _utils.getTruncateStyles)(1));
31
31
  var typeToDescriptorMap = {
32
- created: _messages.messages.created_on,
33
- modified: _messages.messages.modified_on
32
+ created: {
33
+ relative: _messages.messages.created_on_relative,
34
+ absolute: _messages.messages.created_on_absolute
35
+ },
36
+ modified: {
37
+ relative: _messages.messages.modified_on_relative,
38
+ absolute: _messages.messages.modified_on_absolute
39
+ }
34
40
  };
35
41
  /**
36
42
  * A base element that displays an ISO Timestamp in text.
@@ -48,25 +54,41 @@ var DateTime = function DateTime(_ref) {
48
54
  testId = _ref$testId === void 0 ? 'smart-element-date-time' : _ref$testId;
49
55
 
50
56
  var _useIntl = (0, _reactIntlNext.useIntl)(),
51
- formatRelativeTime = _useIntl.formatRelativeTime;
57
+ formatRelativeTime = _useIntl.formatRelativeTime,
58
+ formatDate = _useIntl.formatDate;
52
59
 
53
60
  if (!type || !date) {
54
61
  return null;
55
62
  }
56
63
 
57
- var _selectUnit = (0, _intlUtils.selectUnit)(date, Date.now()),
58
- value = _selectUnit.value,
59
- unit = _selectUnit.unit;
64
+ var isLongerThenWeek = Math.abs(date.getTime() - Date.now()) > 1000 * 60 * 60 * 24 * 7;
65
+ var context;
66
+ var typeVariant;
67
+
68
+ if (isLongerThenWeek) {
69
+ typeVariant = 'absolute';
70
+ context = formatDate(date, {
71
+ month: 'long',
72
+ day: 'numeric',
73
+ year: 'numeric'
74
+ });
75
+ } else {
76
+ var _selectUnit = (0, _intlUtils.selectUnit)(date, Date.now()),
77
+ value = _selectUnit.value,
78
+ unit = _selectUnit.unit;
79
+
80
+ typeVariant = 'relative';
81
+ context = formatRelativeTime(value, unit, {
82
+ numeric: 'auto'
83
+ });
84
+ }
60
85
 
61
- var context = formatRelativeTime(value, unit, {
62
- numeric: 'auto'
63
- });
64
86
  return (0, _core.jsx)("span", {
65
87
  css: [styles, overrideCss],
66
88
  "data-separator": true,
67
89
  "data-smart-element-date-time": true,
68
90
  "data-testid": testId
69
- }, (0, _core.jsx)(_reactIntlNext.FormattedMessage, (0, _extends2.default)({}, typeToDescriptorMap[type], {
91
+ }, (0, _core.jsx)(_reactIntlNext.FormattedMessage, (0, _extends2.default)({}, typeToDescriptorMap[type][typeVariant], {
70
92
  values: {
71
93
  context: context
72
94
  }
@@ -2,6 +2,8 @@
2
2
 
3
3
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
4
 
5
+ var _typeof = require("@babel/runtime/helpers/typeof");
6
+
5
7
  Object.defineProperty(exports, "__esModule", {
6
8
  value: true
7
9
  });
@@ -9,7 +11,7 @@ exports.default = void 0;
9
11
 
10
12
  var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
11
13
 
12
- var _react = _interopRequireDefault(require("react"));
14
+ var _react = _interopRequireWildcard(require("react"));
13
15
 
14
16
  var _container = _interopRequireDefault(require("./components/container"));
15
17
 
@@ -17,6 +19,10 @@ var _flexibleUiContext = require("../../state/flexible-ui-context");
17
19
 
18
20
  var _utils = require("./utils");
19
21
 
22
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
23
+
24
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
25
+
20
26
  /**
21
27
  * This represents a Flexible Card: a link represented by a card with metadata.
22
28
  * This is the container in which all Flexible UI Blocks and Elements exist.
@@ -31,12 +37,20 @@ var FlexibleCard = function FlexibleCard(_ref) {
31
37
  ui = _ref.ui,
32
38
  url = _ref.url,
33
39
  onClick = _ref.onClick,
34
- testId = _ref.testId;
40
+ testId = _ref.testId,
41
+ onResolve = _ref.onResolve;
35
42
  var cardType = cardState.status,
36
43
  details = cardState.details;
37
44
  var status = cardType;
38
45
  var context = (0, _utils.getContextByStatus)(url, status, details, renderers);
39
46
  var retry = (0, _utils.getRetryOptions)(url, status, details, onAuthorize);
47
+ (0, _react.useEffect)(function () {
48
+ if (status === 'resolved' && onResolve) {
49
+ onResolve({
50
+ url: url
51
+ });
52
+ }
53
+ }, [onResolve, status, url]);
40
54
  return /*#__PURE__*/_react.default.createElement(_flexibleUiContext.FlexibleUiContext.Provider, {
41
55
  value: context
42
56
  }, /*#__PURE__*/_react.default.createElement(_container.default, (0, _extends2.default)({
@@ -138,7 +138,8 @@ var HoverCardComponent = function HoverCardComponent(_ref) {
138
138
  };
139
139
  }, [url, definitionId, extensionKey, analytics]);
140
140
 
141
- var CardComponent = function CardComponent() {
141
+ var CardComponent = function CardComponent(_ref2) {
142
+ var update = _ref2.update;
142
143
  //TODO: EDM-3224 deleted simulated and use real JsonLd
143
144
  var metadataElements = (0, _extractMetadata.extractMetadata)((0, _utils.getSimulatedMetadata)(extensionKey));
144
145
  return (0, _core.jsx)("div", {
@@ -151,7 +152,8 @@ var HoverCardComponent = function HoverCardComponent(_ref) {
151
152
  ui: {
152
153
  hideElevation: true,
153
154
  size: _constants.SmartLinkSize.Large
154
- }
155
+ },
156
+ onResolve: update
155
157
  }, (0, _core.jsx)(_blocks.TitleBlock, {
156
158
  actions: [openAction]
157
159
  }), (0, _core.jsx)(_blocks.MetadataBlock, {
@@ -170,7 +172,12 @@ var HoverCardComponent = function HoverCardComponent(_ref) {
170
172
  isOpen: isOpen,
171
173
  onClose: onClose,
172
174
  placement: "bottom-start",
173
- content: CardComponent,
175
+ content: function content(_ref3) {
176
+ var update = _ref3.update;
177
+ return (0, _core.jsx)(CardComponent, {
178
+ update: update
179
+ });
180
+ },
174
181
  trigger: function trigger(triggerProps) {
175
182
  return (0, _core.jsx)("span", (0, _extends2.default)({}, triggerProps, {
176
183
  onMouseEnter: initShowCard,
@@ -25,10 +25,15 @@ export const messages = defineMessages({
25
25
  defaultMessage: 'Created by {context}',
26
26
  description: 'Indicates the person or entity that created the resource.'
27
27
  },
28
- created_on: {
29
- id: 'fabric.linking.create_on',
28
+ created_on_relative: {
29
+ id: 'fabric.linking.create_on_relative',
30
30
  defaultMessage: 'Created {context}',
31
- description: 'Indicated when entity was created'
31
+ description: 'Indicated when entity was created (relative form)'
32
+ },
33
+ created_on_absolute: {
34
+ id: 'fabric.linking.create_on_absolute',
35
+ defaultMessage: 'Created on {context}',
36
+ description: 'Indicated when entity was created (absolute form)'
32
37
  },
33
38
  delete: {
34
39
  id: 'fabric.linking.delete',
@@ -45,10 +50,15 @@ export const messages = defineMessages({
45
50
  defaultMessage: 'Modified by {context}',
46
51
  description: 'Indicates the person or entity that modified the resource.'
47
52
  },
48
- modified_on: {
49
- id: 'fabric.linking.modified_on',
53
+ modified_on_relative: {
54
+ id: 'fabric.linking.modified_on_relative',
50
55
  defaultMessage: 'Updated {context}',
51
- description: 'Indicated when entity was modified'
56
+ description: 'Indicated when entity was modified (relative form)'
57
+ },
58
+ modified_on_absolute: {
59
+ id: 'fabric.linking.modified_on_absolute',
60
+ defaultMessage: 'Updated on {context}',
61
+ description: 'Indicated when entity was modified (absolute form)'
52
62
  },
53
63
  priority_blocker: {
54
64
  id: 'fabric.linking.priority_blocker',
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-card",
3
- "version": "19.0.1",
3
+ "version": "19.0.4",
4
4
  "sideEffects": false
5
5
  }
@@ -2,7 +2,8 @@ import _extends from "@babel/runtime/helpers/extends";
2
2
  import React, { useCallback, useState } from 'react';
3
3
  import { usePrefetch } from '../../../state';
4
4
  import { CardWithUrlContent } from '../component';
5
- import { LoadingCardLink } from './LazyFallback'; // This property enables the intersection observer to be run once the
5
+ import { LoadingCardLink } from './LazyFallback';
6
+ import { startUfoExperience } from '../../../state/analytics/ufoExperiences'; // This property enables the intersection observer to be run once the
6
7
  // HTML element being observed is within `X` px of the target container it is
7
8
  // being compared to. Since the default container is the `document`, we set this
8
9
  // up to check once a Smart Link is within `X` px from the bottom of the viewport.
@@ -13,7 +14,8 @@ export function LazyIntersectionObserverCard(props) {
13
14
  const {
14
15
  showActions,
15
16
  appearance,
16
- url
17
+ url,
18
+ id
17
19
  } = props;
18
20
  const prefetch = usePrefetch(url);
19
21
  const Component = appearance === 'inline' ? 'span' : 'div';
@@ -22,12 +24,13 @@ export function LazyIntersectionObserverCard(props) {
22
24
  const isVisible = entries.some(entry => entry.isIntersecting);
23
25
 
24
26
  if (isVisible) {
27
+ startUfoExperience('smart-link-rendered', id);
25
28
  setIsIntersecting(true);
26
29
  observer.disconnect();
27
30
  } else {
28
31
  prefetch();
29
32
  }
30
- }, [prefetch]);
33
+ }, [prefetch, id]);
31
34
  const onRef = useCallback(element => {
32
35
  if (!element) {
33
36
  return;
@@ -1,15 +1,21 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
- import React from 'react';
2
+ import React, { useState } from 'react';
3
3
  import LazilyRender from 'react-lazily-render';
4
4
  import { CardWithUrlContent } from '../component';
5
5
  import { LoadingCardLink } from './LazyFallback';
6
+ import { startUfoExperience } from '../../../state/analytics/ufoExperiences';
6
7
  export function LazyLazilyRenderCard(props) {
7
8
  const {
8
9
  appearance,
9
10
  container,
10
- showActions
11
+ showActions,
12
+ id
11
13
  } = props;
12
14
  const offset = Math.ceil(window.innerHeight / 4);
15
+ useState(() => {
16
+ // Start of experience when intersectionObserver is not supported.
17
+ startUfoExperience('smart-link-rendered', id);
18
+ });
13
19
  return /*#__PURE__*/React.createElement(LazilyRender, {
14
20
  offset: offset,
15
21
  component: appearance === 'inline' ? 'span' : 'div',
@@ -104,7 +104,8 @@ export function CardWithUrlContent({
104
104
  renderers: renderers,
105
105
  ui: ui,
106
106
  url: url,
107
- testId: testId
107
+ testId: testId,
108
+ onResolve: onResolve
108
109
  }, children);
109
110
  } // We have to keep this last to prevent hook order from being violated
110
111
 
@@ -9,12 +9,7 @@ const LazyCardWithUrlContent = /*#__PURE__*/lazy(() => import(
9
9
  /* webpackChunkName: "@atlaskit-internal_smartcard-urlcardcontent" */
10
10
  './component-lazy/index'));
11
11
  export function CardWithURLRenderer(props) {
12
- const [id] = useState(() => uuid()); // Equivalent to ComponentWillMount
13
-
14
- useState(() => {
15
- // We want to start timing of render event only once and right at the start
16
- startUfoExperience('smart-link-rendered', id);
17
- });
12
+ const [id] = useState(() => uuid());
18
13
  useEffect(() => {
19
14
  // ComponentWillUnmount
20
15
  return () => {
@@ -68,7 +63,10 @@ export function CardWithURLRenderer(props) {
68
63
  else {
69
64
  const errorInfo = {
70
65
  componentStack
71
- };
66
+ }; // Start and fail the smart-link-rendered experience. If it has already
67
+ // been started nothing happens.
68
+
69
+ startUfoExperience('smart-link-rendered', id);
72
70
  failUfoExperience('smart-link-rendered', id);
73
71
  failUfoExperience('smart-link-authenticated', id);
74
72
  dispatchAnalytics(uiRenderFailedEvent(appearance, error, errorInfo));
@@ -15,8 +15,14 @@ const styles = css`
15
15
  ${getTruncateStyles(1)}
16
16
  `;
17
17
  const typeToDescriptorMap = {
18
- created: messages.created_on,
19
- modified: messages.modified_on
18
+ created: {
19
+ relative: messages.created_on_relative,
20
+ absolute: messages.created_on_absolute
21
+ },
22
+ modified: {
23
+ relative: messages.modified_on_relative,
24
+ absolute: messages.modified_on_absolute
25
+ }
20
26
  };
21
27
  /**
22
28
  * A base element that displays an ISO Timestamp in text.
@@ -33,26 +39,42 @@ const DateTime = ({
33
39
  testId = 'smart-element-date-time'
34
40
  }) => {
35
41
  const {
36
- formatRelativeTime
42
+ formatRelativeTime,
43
+ formatDate
37
44
  } = useIntl();
38
45
 
39
46
  if (!type || !date) {
40
47
  return null;
41
48
  }
42
49
 
43
- const {
44
- value,
45
- unit
46
- } = selectUnit(date, Date.now());
47
- const context = formatRelativeTime(value, unit, {
48
- numeric: 'auto'
49
- });
50
+ const isLongerThenWeek = Math.abs(date.getTime() - Date.now()) > 1000 * 60 * 60 * 24 * 7;
51
+ let context;
52
+ let typeVariant;
53
+
54
+ if (isLongerThenWeek) {
55
+ typeVariant = 'absolute';
56
+ context = formatDate(date, {
57
+ month: 'long',
58
+ day: 'numeric',
59
+ year: 'numeric'
60
+ });
61
+ } else {
62
+ const {
63
+ value,
64
+ unit
65
+ } = selectUnit(date, Date.now());
66
+ typeVariant = 'relative';
67
+ context = formatRelativeTime(value, unit, {
68
+ numeric: 'auto'
69
+ });
70
+ }
71
+
50
72
  return jsx("span", {
51
73
  css: [styles, overrideCss],
52
74
  "data-separator": true,
53
75
  "data-smart-element-date-time": true,
54
76
  "data-testid": testId
55
- }, jsx(FormattedMessage, _extends({}, typeToDescriptorMap[type], {
77
+ }, jsx(FormattedMessage, _extends({}, typeToDescriptorMap[type][typeVariant], {
56
78
  values: {
57
79
  context
58
80
  }
@@ -1,5 +1,5 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
- import React from 'react';
2
+ import React, { useEffect } from 'react';
3
3
  import Container from './components/container';
4
4
  import { FlexibleUiContext } from '../../state/flexible-ui-context';
5
5
  import { getContextByStatus, getRetryOptions } from './utils';
@@ -18,7 +18,8 @@ const FlexibleCard = ({
18
18
  ui,
19
19
  url,
20
20
  onClick,
21
- testId
21
+ testId,
22
+ onResolve
22
23
  }) => {
23
24
  const {
24
25
  status: cardType,
@@ -27,6 +28,13 @@ const FlexibleCard = ({
27
28
  const status = cardType;
28
29
  const context = getContextByStatus(url, status, details, renderers);
29
30
  const retry = getRetryOptions(url, status, details, onAuthorize);
31
+ useEffect(() => {
32
+ if (status === 'resolved' && onResolve) {
33
+ onResolve({
34
+ url
35
+ });
36
+ }
37
+ }, [onResolve, status, url]);
30
38
  return /*#__PURE__*/React.createElement(FlexibleUiContext.Provider, {
31
39
  value: context
32
40
  }, /*#__PURE__*/React.createElement(Container, _extends({
@@ -91,7 +91,9 @@ export const HoverCardComponent = ({
91
91
  };
92
92
  }, [url, definitionId, extensionKey, analytics]);
93
93
 
94
- const CardComponent = () => {
94
+ const CardComponent = ({
95
+ update
96
+ }) => {
95
97
  //TODO: EDM-3224 deleted simulated and use real JsonLd
96
98
  const metadataElements = extractMetadata(getSimulatedMetadata(extensionKey));
97
99
  return jsx("div", {
@@ -104,7 +106,8 @@ export const HoverCardComponent = ({
104
106
  ui: {
105
107
  hideElevation: true,
106
108
  size: SmartLinkSize.Large
107
- }
109
+ },
110
+ onResolve: update
108
111
  }, jsx(TitleBlock, {
109
112
  actions: [openAction]
110
113
  }), jsx(MetadataBlock, {
@@ -121,7 +124,13 @@ export const HoverCardComponent = ({
121
124
  isOpen: isOpen,
122
125
  onClose: onClose,
123
126
  placement: "bottom-start",
124
- content: CardComponent,
127
+ content: ({
128
+ update
129
+ }) => {
130
+ return jsx(CardComponent, {
131
+ update: update
132
+ });
133
+ },
125
134
  trigger: triggerProps => jsx("span", _extends({}, triggerProps, {
126
135
  onMouseEnter: initShowCard,
127
136
  onMouseLeave: initHideCard
@@ -25,10 +25,15 @@ export var messages = defineMessages({
25
25
  defaultMessage: 'Created by {context}',
26
26
  description: 'Indicates the person or entity that created the resource.'
27
27
  },
28
- created_on: {
29
- id: 'fabric.linking.create_on',
28
+ created_on_relative: {
29
+ id: 'fabric.linking.create_on_relative',
30
30
  defaultMessage: 'Created {context}',
31
- description: 'Indicated when entity was created'
31
+ description: 'Indicated when entity was created (relative form)'
32
+ },
33
+ created_on_absolute: {
34
+ id: 'fabric.linking.create_on_absolute',
35
+ defaultMessage: 'Created on {context}',
36
+ description: 'Indicated when entity was created (absolute form)'
32
37
  },
33
38
  delete: {
34
39
  id: 'fabric.linking.delete',
@@ -45,10 +50,15 @@ export var messages = defineMessages({
45
50
  defaultMessage: 'Modified by {context}',
46
51
  description: 'Indicates the person or entity that modified the resource.'
47
52
  },
48
- modified_on: {
49
- id: 'fabric.linking.modified_on',
53
+ modified_on_relative: {
54
+ id: 'fabric.linking.modified_on_relative',
50
55
  defaultMessage: 'Updated {context}',
51
- description: 'Indicated when entity was modified'
56
+ description: 'Indicated when entity was modified (relative form)'
57
+ },
58
+ modified_on_absolute: {
59
+ id: 'fabric.linking.modified_on_absolute',
60
+ defaultMessage: 'Updated on {context}',
61
+ description: 'Indicated when entity was modified (absolute form)'
52
62
  },
53
63
  priority_blocker: {
54
64
  id: 'fabric.linking.priority_blocker',
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-card",
3
- "version": "19.0.1",
3
+ "version": "19.0.4",
4
4
  "sideEffects": false
5
5
  }
@@ -3,7 +3,8 @@ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
3
3
  import React, { useCallback, useState } from 'react';
4
4
  import { usePrefetch } from '../../../state';
5
5
  import { CardWithUrlContent } from '../component';
6
- import { LoadingCardLink } from './LazyFallback'; // This property enables the intersection observer to be run once the
6
+ import { LoadingCardLink } from './LazyFallback';
7
+ import { startUfoExperience } from '../../../state/analytics/ufoExperiences'; // This property enables the intersection observer to be run once the
7
8
  // HTML element being observed is within `X` px of the target container it is
8
9
  // being compared to. Since the default container is the `document`, we set this
9
10
  // up to check once a Smart Link is within `X` px from the bottom of the viewport.
@@ -17,7 +18,8 @@ export function LazyIntersectionObserverCard(props) {
17
18
 
18
19
  var showActions = props.showActions,
19
20
  appearance = props.appearance,
20
- url = props.url;
21
+ url = props.url,
22
+ id = props.id;
21
23
  var prefetch = usePrefetch(url);
22
24
  var Component = appearance === 'inline' ? 'span' : 'div';
23
25
  var ComponentObserver = Component;
@@ -27,12 +29,13 @@ export function LazyIntersectionObserverCard(props) {
27
29
  });
28
30
 
29
31
  if (isVisible) {
32
+ startUfoExperience('smart-link-rendered', id);
30
33
  setIsIntersecting(true);
31
34
  observer.disconnect();
32
35
  } else {
33
36
  prefetch();
34
37
  }
35
- }, [prefetch]);
38
+ }, [prefetch, id]);
36
39
  var onRef = useCallback(function (element) {
37
40
  if (!element) {
38
41
  return;
@@ -1,13 +1,19 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
- import React from 'react';
2
+ import React, { useState } from 'react';
3
3
  import LazilyRender from 'react-lazily-render';
4
4
  import { CardWithUrlContent } from '../component';
5
5
  import { LoadingCardLink } from './LazyFallback';
6
+ import { startUfoExperience } from '../../../state/analytics/ufoExperiences';
6
7
  export function LazyLazilyRenderCard(props) {
7
8
  var appearance = props.appearance,
8
9
  container = props.container,
9
- showActions = props.showActions;
10
+ showActions = props.showActions,
11
+ id = props.id;
10
12
  var offset = Math.ceil(window.innerHeight / 4);
13
+ useState(function () {
14
+ // Start of experience when intersectionObserver is not supported.
15
+ startUfoExperience('smart-link-rendered', id);
16
+ });
11
17
  return /*#__PURE__*/React.createElement(LazilyRender, {
12
18
  offset: offset,
13
19
  component: appearance === 'inline' ? 'span' : 'div',
@@ -110,7 +110,8 @@ export function CardWithUrlContent(_ref) {
110
110
  renderers: renderers,
111
111
  ui: ui,
112
112
  url: url,
113
- testId: testId
113
+ testId: testId,
114
+ onResolve: onResolve
114
115
  }, children);
115
116
  } // We have to keep this last to prevent hook order from being violated
116
117
 
@@ -16,13 +16,8 @@ export function CardWithURLRenderer(props) {
16
16
  return uuid();
17
17
  }),
18
18
  _useState2 = _slicedToArray(_useState, 1),
19
- id = _useState2[0]; // Equivalent to ComponentWillMount
19
+ id = _useState2[0];
20
20
 
21
-
22
- useState(function () {
23
- // We want to start timing of render event only once and right at the start
24
- startUfoExperience('smart-link-rendered', id);
25
- });
26
21
  useEffect(function () {
27
22
  // ComponentWillUnmount
28
23
  return function () {
@@ -72,7 +67,10 @@ export function CardWithURLRenderer(props) {
72
67
  else {
73
68
  var errorInfo = {
74
69
  componentStack: componentStack
75
- };
70
+ }; // Start and fail the smart-link-rendered experience. If it has already
71
+ // been started nothing happens.
72
+
73
+ startUfoExperience('smart-link-rendered', id);
76
74
  failUfoExperience('smart-link-rendered', id);
77
75
  failUfoExperience('smart-link-authenticated', id);
78
76
  dispatchAnalytics(uiRenderFailedEvent(appearance, error, errorInfo));
@@ -13,8 +13,14 @@ import { selectUnit } from '@formatjs/intl-utils';
13
13
  import { messages } from '../../../../../messages';
14
14
  var styles = css(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n color: ", ";\n font-size: 0.75rem;\n line-height: 1rem;\n ", "\n"])), tokens.text, getTruncateStyles(1));
15
15
  var typeToDescriptorMap = {
16
- created: messages.created_on,
17
- modified: messages.modified_on
16
+ created: {
17
+ relative: messages.created_on_relative,
18
+ absolute: messages.created_on_absolute
19
+ },
20
+ modified: {
21
+ relative: messages.modified_on_relative,
22
+ absolute: messages.modified_on_absolute
23
+ }
18
24
  };
19
25
  /**
20
26
  * A base element that displays an ISO Timestamp in text.
@@ -32,25 +38,41 @@ var DateTime = function DateTime(_ref) {
32
38
  testId = _ref$testId === void 0 ? 'smart-element-date-time' : _ref$testId;
33
39
 
34
40
  var _useIntl = useIntl(),
35
- formatRelativeTime = _useIntl.formatRelativeTime;
41
+ formatRelativeTime = _useIntl.formatRelativeTime,
42
+ formatDate = _useIntl.formatDate;
36
43
 
37
44
  if (!type || !date) {
38
45
  return null;
39
46
  }
40
47
 
41
- var _selectUnit = selectUnit(date, Date.now()),
42
- value = _selectUnit.value,
43
- unit = _selectUnit.unit;
48
+ var isLongerThenWeek = Math.abs(date.getTime() - Date.now()) > 1000 * 60 * 60 * 24 * 7;
49
+ var context;
50
+ var typeVariant;
51
+
52
+ if (isLongerThenWeek) {
53
+ typeVariant = 'absolute';
54
+ context = formatDate(date, {
55
+ month: 'long',
56
+ day: 'numeric',
57
+ year: 'numeric'
58
+ });
59
+ } else {
60
+ var _selectUnit = selectUnit(date, Date.now()),
61
+ value = _selectUnit.value,
62
+ unit = _selectUnit.unit;
63
+
64
+ typeVariant = 'relative';
65
+ context = formatRelativeTime(value, unit, {
66
+ numeric: 'auto'
67
+ });
68
+ }
44
69
 
45
- var context = formatRelativeTime(value, unit, {
46
- numeric: 'auto'
47
- });
48
70
  return jsx("span", {
49
71
  css: [styles, overrideCss],
50
72
  "data-separator": true,
51
73
  "data-smart-element-date-time": true,
52
74
  "data-testid": testId
53
- }, jsx(FormattedMessage, _extends({}, typeToDescriptorMap[type], {
75
+ }, jsx(FormattedMessage, _extends({}, typeToDescriptorMap[type][typeVariant], {
54
76
  values: {
55
77
  context: context
56
78
  }
@@ -1,5 +1,5 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
- import React from 'react';
2
+ import React, { useEffect } from 'react';
3
3
  import Container from './components/container';
4
4
  import { FlexibleUiContext } from '../../state/flexible-ui-context';
5
5
  import { getContextByStatus, getRetryOptions } from './utils';
@@ -18,12 +18,20 @@ var FlexibleCard = function FlexibleCard(_ref) {
18
18
  ui = _ref.ui,
19
19
  url = _ref.url,
20
20
  onClick = _ref.onClick,
21
- testId = _ref.testId;
21
+ testId = _ref.testId,
22
+ onResolve = _ref.onResolve;
22
23
  var cardType = cardState.status,
23
24
  details = cardState.details;
24
25
  var status = cardType;
25
26
  var context = getContextByStatus(url, status, details, renderers);
26
27
  var retry = getRetryOptions(url, status, details, onAuthorize);
28
+ useEffect(function () {
29
+ if (status === 'resolved' && onResolve) {
30
+ onResolve({
31
+ url: url
32
+ });
33
+ }
34
+ }, [onResolve, status, url]);
27
35
  return /*#__PURE__*/React.createElement(FlexibleUiContext.Provider, {
28
36
  value: context
29
37
  }, /*#__PURE__*/React.createElement(Container, _extends({
@@ -106,7 +106,8 @@ export var HoverCardComponent = function HoverCardComponent(_ref) {
106
106
  };
107
107
  }, [url, definitionId, extensionKey, analytics]);
108
108
 
109
- var CardComponent = function CardComponent() {
109
+ var CardComponent = function CardComponent(_ref2) {
110
+ var update = _ref2.update;
110
111
  //TODO: EDM-3224 deleted simulated and use real JsonLd
111
112
  var metadataElements = extractMetadata(getSimulatedMetadata(extensionKey));
112
113
  return jsx("div", {
@@ -119,7 +120,8 @@ export var HoverCardComponent = function HoverCardComponent(_ref) {
119
120
  ui: {
120
121
  hideElevation: true,
121
122
  size: SmartLinkSize.Large
122
- }
123
+ },
124
+ onResolve: update
123
125
  }, jsx(TitleBlock, {
124
126
  actions: [openAction]
125
127
  }), jsx(MetadataBlock, {
@@ -138,7 +140,12 @@ export var HoverCardComponent = function HoverCardComponent(_ref) {
138
140
  isOpen: isOpen,
139
141
  onClose: onClose,
140
142
  placement: "bottom-start",
141
- content: CardComponent,
143
+ content: function content(_ref3) {
144
+ var update = _ref3.update;
145
+ return jsx(CardComponent, {
146
+ update: update
147
+ });
148
+ },
142
149
  trigger: function trigger(triggerProps) {
143
150
  return jsx("span", _extends({}, triggerProps, {
144
151
  onMouseEnter: initShowCard,
@@ -1,5 +1,5 @@
1
1
  import { MessageDescriptor } from 'react-intl-next';
2
- export declare type MessageKey = 'cannot_find_link' | 'click_to_join' | 'connect_link_account' | 'created_by' | 'created_on' | 'delete' | 'edit' | 'modified_by' | 'modified_on' | 'priority_blocker' | 'priority_critical' | 'priority_high' | 'priority_highest' | 'priority_low' | 'priority_lowest' | 'priority_major' | 'priority_medium' | 'priority_minor' | 'priority_trivial' | 'priority_undefined' | 'forbidden_access' | 'pending_request' | 'restricted_link' | 'request_access' | 'request_denied';
2
+ export declare type MessageKey = 'cannot_find_link' | 'click_to_join' | 'connect_link_account' | 'created_by' | 'created_on_relative' | 'created_on_absolute' | 'delete' | 'edit' | 'modified_by' | 'modified_on_relative' | 'modified_on_absolute' | 'priority_blocker' | 'priority_critical' | 'priority_high' | 'priority_highest' | 'priority_low' | 'priority_lowest' | 'priority_major' | 'priority_medium' | 'priority_minor' | 'priority_trivial' | 'priority_undefined' | 'forbidden_access' | 'pending_request' | 'restricted_link' | 'request_access' | 'request_denied';
3
3
  declare type Messages = {
4
4
  [K in MessageKey]: MessageDescriptor;
5
5
  };
@@ -4,6 +4,7 @@ import { CardState } from '@atlaskit/linking-common';
4
4
  import { CardProviderRenderers } from '@atlaskit/link-provider';
5
5
  import { SmartLinkSize, SmartLinkTheme } from '../../constants';
6
6
  import { CardAppearance } from '../../view/Card';
7
+ import { OnResolveCallback } from '../Card/types';
7
8
  export declare type FlexibleCardProps = {
8
9
  /**
9
10
  * Determines the appearance of the Smart Link.
@@ -51,6 +52,10 @@ export declare type FlexibleCardProps = {
51
52
  * Determines the URL of the Smart Link.
52
53
  */
53
54
  url: string;
55
+ /**
56
+ * function to be called after a flexible card has rendered its resolved state
57
+ */
58
+ onResolve?: OnResolveCallback;
54
59
  };
55
60
  export declare type FlexibleUiOptions = {
56
61
  /**
@@ -13,8 +13,11 @@ export declare const MockIntersectionObserverFactory: (mockIntersectionObserverO
13
13
  readonly root: Element | null;
14
14
  readonly rootMargin: string;
15
15
  readonly thresholds: ReadonlyArray<number>;
16
+ previousMockEntries: MockEntry[];
16
17
  callback: IntersectionObserverCallback;
17
18
  observe(_element: HTMLElement): void;
19
+ callIntersectionObserverCallback: () => void;
20
+ checkIntersection: () => void;
18
21
  disconnect: jest.Mock<any, any>;
19
22
  takeRecords: jest.Mock<any, any>;
20
23
  unobserve: jest.Mock<any, any>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-card",
3
- "version": "19.0.1",
3
+ "version": "19.0.4",
4
4
  "description": "Smart card component",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"