@atlaskit/smart-card 23.14.2 → 24.0.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 (50) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/cjs/state/analytics/useMouseDownEvent.js +24 -0
  3. package/dist/cjs/utils/analytics/click.js +121 -0
  4. package/dist/cjs/utils/index.js +10 -0
  5. package/dist/cjs/version.json +1 -1
  6. package/dist/cjs/view/BlockCard/components/ContentHeader.js +4 -0
  7. package/dist/cjs/view/BlockCard/index.js +1 -0
  8. package/dist/cjs/view/CardWithUrl/component.js +24 -9
  9. package/dist/cjs/view/EmbedCard/components/ExpandedFrame.js +4 -1
  10. package/dist/cjs/view/EmbedModal/components/link-info/link-info-button/index.js +3 -0
  11. package/dist/cjs/view/FlexibleCard/components/blocks/title-block/index.js +3 -0
  12. package/dist/cjs/view/FlexibleCard/components/container/layered-link/index.js +3 -0
  13. package/dist/cjs/view/FlexibleCard/components/elements/link/index.js +3 -0
  14. package/dist/cjs/view/HoverCard/components/HoverCardContent.js +6 -1
  15. package/dist/cjs/view/InlineCard/Frame/index.js +4 -0
  16. package/dist/es2019/state/analytics/useMouseDownEvent.js +18 -0
  17. package/dist/es2019/utils/analytics/click.js +106 -0
  18. package/dist/es2019/utils/index.js +10 -0
  19. package/dist/es2019/version.json +1 -1
  20. package/dist/es2019/view/BlockCard/components/ContentHeader.js +19 -14
  21. package/dist/es2019/view/BlockCard/index.js +1 -0
  22. package/dist/es2019/view/CardWithUrl/component.js +25 -9
  23. package/dist/es2019/view/EmbedCard/components/ExpandedFrame.js +4 -1
  24. package/dist/es2019/view/EmbedModal/components/link-info/link-info-button/index.js +3 -0
  25. package/dist/es2019/view/FlexibleCard/components/blocks/title-block/index.js +3 -0
  26. package/dist/es2019/view/FlexibleCard/components/container/layered-link/index.js +14 -9
  27. package/dist/es2019/view/FlexibleCard/components/elements/link/index.js +3 -0
  28. package/dist/es2019/view/HoverCard/components/HoverCardContent.js +7 -1
  29. package/dist/es2019/view/InlineCard/Frame/index.js +3 -0
  30. package/dist/esm/state/analytics/useMouseDownEvent.js +17 -0
  31. package/dist/esm/utils/analytics/click.js +109 -0
  32. package/dist/esm/utils/index.js +10 -0
  33. package/dist/esm/version.json +1 -1
  34. package/dist/esm/view/BlockCard/components/ContentHeader.js +3 -0
  35. package/dist/esm/view/BlockCard/index.js +1 -0
  36. package/dist/esm/view/CardWithUrl/component.js +24 -9
  37. package/dist/esm/view/EmbedCard/components/ExpandedFrame.js +4 -1
  38. package/dist/esm/view/EmbedModal/components/link-info/link-info-button/index.js +3 -0
  39. package/dist/esm/view/FlexibleCard/components/blocks/title-block/index.js +3 -0
  40. package/dist/esm/view/FlexibleCard/components/container/layered-link/index.js +3 -0
  41. package/dist/esm/view/FlexibleCard/components/elements/link/index.js +3 -0
  42. package/dist/esm/view/HoverCard/components/HoverCardContent.js +6 -1
  43. package/dist/esm/view/InlineCard/Frame/index.js +3 -0
  44. package/dist/types/state/analytics/useMouseDownEvent.d.ts +3 -0
  45. package/dist/types/utils/analytics/click.d.ts +21 -0
  46. package/dist/types/utils/analytics/types.d.ts +16 -0
  47. package/dist/types/utils/index.d.ts +9 -0
  48. package/dist/types/view/FlexibleCard/components/elements/link/types.d.ts +4 -0
  49. package/package.json +6 -4
  50. package/report.api.md +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @atlaskit/smart-card
2
2
 
3
+ ## 24.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`4661d4f7f7b`](https://bitbucket.org/atlassian/atlassian-frontend/commits/4661d4f7f7b) - Add `link clicked` UI event to Smart Card.
8
+ - Updated dependencies
9
+
10
+ ## 24.0.0
11
+
12
+ ### Patch Changes
13
+
14
+ - Updated dependencies
15
+
3
16
  ## 23.14.2
4
17
 
5
18
  ### Patch Changes
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _react = require("react");
8
+ var _analyticsNext = require("@atlaskit/analytics-next");
9
+ var _click = require("../../utils/analytics/click");
10
+ var useMouseDownEvent = function useMouseDownEvent(onMouseDown) {
11
+ var _useAnalyticsEvents = (0, _analyticsNext.useAnalyticsEvents)(),
12
+ createAnalyticsEvent = _useAnalyticsEvents.createAnalyticsEvent;
13
+ return (0, _react.useCallback)(function (event) {
14
+ onMouseDown === null || onMouseDown === void 0 ? void 0 : onMouseDown(event);
15
+
16
+ // ignore left clicks
17
+ // these would be handled by `onClick` handler instead
18
+ if (event.button !== 0) {
19
+ (0, _click.fireLinkClickedEvent)(createAnalyticsEvent)(event);
20
+ }
21
+ }, [onMouseDown, createAnalyticsEvent]);
22
+ };
23
+ var _default = useMouseDownEvent;
24
+ exports.default = _default;
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.getKeys = exports.fireLinkClickedEvent = exports.createLinkClickedPayload = exports.buttonMap = void 0;
8
+ exports.getLinkClickOutcome = getLinkClickOutcome;
9
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
10
+ var _userAgent = require("@atlaskit/linking-common/user-agent");
11
+ var _analytics = require("./analytics");
12
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
13
+ 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) { (0, _defineProperty2.default)(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; }
14
+ var buttonMap = new Map([[undefined, 'none'], [0, 'left'], [1, 'middle'], [2, 'right']]);
15
+ exports.buttonMap = buttonMap;
16
+ var getKeys = function getKeys(e) {
17
+ return ['alt', 'ctrl', 'meta', 'shift'].filter(function (key) {
18
+ return e["".concat(key, "Key")] === true;
19
+ });
20
+ };
21
+ exports.getKeys = getKeys;
22
+ var isContentEditable = function isContentEditable(el) {
23
+ return el instanceof HTMLElement && el.isContentEditable;
24
+ };
25
+ function getLinkClickOutcome(e, clickType) {
26
+ var _browser = (0, _userAgent.browser)(),
27
+ mac = _browser.mac,
28
+ safari = _browser.safari;
29
+ if (e.defaultPrevented) {
30
+ return 'prevented';
31
+ }
32
+ /**
33
+ * If the link/parent is content editable then left click won't have typical effect
34
+ */
35
+ if (isContentEditable(e.currentTarget) && ['left', 'middle'].includes(clickType)) {
36
+ return 'contentEditable';
37
+ }
38
+ switch (clickType) {
39
+ case 'left':
40
+ {
41
+ // Meta key = Cmd for macOS, Windows key sometimes for Windows (otherwise false)
42
+ // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/metaKey
43
+ if (e.metaKey) {
44
+ return mac ? 'clickThroughNewTabOrWindow' : 'clickThrough';
45
+ }
46
+ if (e.shiftKey) {
47
+ // Alt/option click in safari typically adds the link to bookmarks
48
+ if (safari) {
49
+ return 'alt';
50
+ }
51
+ return 'clickThroughNewTabOrWindow';
52
+ }
53
+ if (e.ctrlKey) {
54
+ // Ctrl+Left on macOS defaults to triggering a right click instead (so won't trigger onClick)
55
+ // but if this behaviour is disabled, likely outcome is clickThrough
56
+ if (mac) {
57
+ return 'clickThrough';
58
+ }
59
+ return 'clickThroughNewTabOrWindow';
60
+ }
61
+ if (e.altKey) {
62
+ return 'alt';
63
+ }
64
+ var target = e.currentTarget.getAttribute('target');
65
+ if (target === '_blank') {
66
+ return 'clickThroughNewTabOrWindow';
67
+ }
68
+ return 'clickThrough';
69
+ }
70
+ case 'middle':
71
+ {
72
+ return 'clickThroughNewTabOrWindow';
73
+ }
74
+ case 'right':
75
+ {
76
+ return 'contextMenu';
77
+ }
78
+ }
79
+ return '_unknown';
80
+ }
81
+ var linkClickedEvent = function linkClickedEvent(_ref) {
82
+ var clickType = _ref.clickType,
83
+ clickOutcome = _ref.clickOutcome,
84
+ keysHeld = _ref.keysHeld;
85
+ return {
86
+ action: 'clicked',
87
+ actionSubject: 'link',
88
+ eventType: 'ui',
89
+ attributes: {
90
+ clickType: clickType,
91
+ clickOutcome: clickOutcome,
92
+ keysHeld: keysHeld
93
+ }
94
+ };
95
+ };
96
+ var createLinkClickedPayload = function createLinkClickedPayload(event) {
97
+ var clickType = buttonMap.get(event.button);
98
+ if (!clickType) {
99
+ return;
100
+ }
101
+ var clickOutcome = getLinkClickOutcome(event, clickType);
102
+ var keysHeld = getKeys(event);
103
+ return linkClickedEvent({
104
+ clickType: clickType,
105
+ clickOutcome: clickOutcome,
106
+ keysHeld: keysHeld
107
+ });
108
+ };
109
+ exports.createLinkClickedPayload = createLinkClickedPayload;
110
+ var fireLinkClickedEvent = function fireLinkClickedEvent(createAnalyticsEvent) {
111
+ return function (event) {
112
+ var overrides = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
113
+ var payload = createLinkClickedPayload(event);
114
+ if (payload) {
115
+ createAnalyticsEvent(_objectSpread(_objectSpread(_objectSpread({}, payload), overrides), {}, {
116
+ attributes: _objectSpread(_objectSpread({}, payload.attributes), overrides === null || overrides === void 0 ? void 0 : overrides.attributes)
117
+ })).fire(_analytics.ANALYTICS_CHANNEL);
118
+ }
119
+ };
120
+ };
121
+ exports.fireLinkClickedEvent = fireLinkClickedEvent;
@@ -24,6 +24,16 @@ exports.isSpecialEvent = isSpecialEvent;
24
24
  var isIframe = function isIframe() {
25
25
  return window.parent !== parent;
26
26
  };
27
+
28
+ /**
29
+ * Meta key = cmd on mac, windows key on windows
30
+ * Ctrl key on mac by default triggers a right click instead of left click
31
+ * Ctrl key on Windows has the same behaviour of cmd key of mac (open in new tab)
32
+ *
33
+ * `isSpecialKey` on a mouse event on mac with default behaviour should be equivalent to opening in new tab
34
+ * On Windows it will be equivalent to opening a new tab, unless its the Window key that is held
35
+ * in which case typically only a standard clickthrough will occur, this is likely a small portion of events
36
+ */
27
37
  exports.isIframe = isIframe;
28
38
  var isSpecialKey = function isSpecialKey(event) {
29
39
  return event.metaKey || event.ctrlKey;
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-card",
3
- "version": "23.14.2",
3
+ "version": "24.0.1",
4
4
  "sideEffects": false
5
5
  }
@@ -1,10 +1,12 @@
1
1
  "use strict";
2
2
 
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
3
4
  Object.defineProperty(exports, "__esModule", {
4
5
  value: true
5
6
  });
6
7
  exports.blockCardContentHeaderClassName = exports.ContentHeader = void 0;
7
8
  var _react = require("@emotion/react");
9
+ var _useMouseDownEvent = _interopRequireDefault(require("../../../state/analytics/useMouseDownEvent"));
8
10
  /** @jsx jsx */
9
11
 
10
12
  var blockCardContentHeaderClassName = 'block-card-content-header';
@@ -13,8 +15,10 @@ var ContentHeader = function ContentHeader(_ref) {
13
15
  var onClick = _ref.onClick,
14
16
  link = _ref.link,
15
17
  children = _ref.children;
18
+ var onMouseDown = (0, _useMouseDownEvent.default)();
16
19
  return (0, _react.jsx)("a", {
17
20
  onClick: onClick,
21
+ onMouseDown: onMouseDown,
18
22
  href: link,
19
23
  target: "_blank",
20
24
  css: {
@@ -123,6 +123,7 @@ var BlockCard = function BlockCard(_ref) {
123
123
  cardState: cardState,
124
124
  url: url,
125
125
  testId: testId,
126
+ onClick: handleFrameClick,
126
127
  onError: onError,
127
128
  onResolve: onResolve,
128
129
  renderers: renderers,
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", {
7
7
  });
8
8
  exports.CardWithUrlContent = CardWithUrlContent;
9
9
  var _react = _interopRequireWildcard(require("react"));
10
+ var _analyticsNext = require("@atlaskit/analytics-next");
10
11
  var _linkProvider = require("@atlaskit/link-provider");
11
12
  var _utils = require("../../utils");
12
13
  var measure = _interopRequireWildcard(require("../../utils/performance"));
@@ -19,6 +20,7 @@ var _flexible = require("../../utils/flexible");
19
20
  var _FlexibleCard = _interopRequireDefault(require("../FlexibleCard"));
20
21
  var _ = require("../..");
21
22
  var _constants = require("../../constants");
23
+ var _click = require("../../utils/analytics/click");
22
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); }
23
25
  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; }
24
26
  function CardWithUrlContent(_ref) {
@@ -42,6 +44,9 @@ function CardWithUrlContent(_ref) {
42
44
  showHoverPreview = _ref.showHoverPreview,
43
45
  showAuthTooltipProp = _ref.showAuthTooltip,
44
46
  analyticsEvents = _ref.analyticsEvents;
47
+ var _useAnalyticsEvents = (0, _analyticsNext.useAnalyticsEvents)(),
48
+ createAnalyticsEvent = _useAnalyticsEvents.createAnalyticsEvent;
49
+
45
50
  // Get state, actions for this card.
46
51
  var _useSmartLink = (0, _state.useSmartLink)(id, url, dispatchAnalytics),
47
52
  state = _useSmartLink.state,
@@ -65,10 +70,6 @@ function CardWithUrlContent(_ref) {
65
70
  var enableFlexibleBlockCardFlag = Boolean((0, _linkProvider.useFeatureFlag)('enableFlexibleBlockCard'));
66
71
 
67
72
  // Setup UI handlers.
68
- var handleClick = (0, _react.useCallback)(function (event) {
69
- var clickUrl = (0, _helpers.getClickUrl)(url, state.details);
70
- (0, _utils.isSpecialEvent)(event) ? window.open(clickUrl, '_blank') : window.open(clickUrl, '_self');
71
- }, [state.details, url]);
72
73
  var handleClickWrapper = (0, _react.useCallback)(function (event) {
73
74
  var isModifierKeyPressed = (0, _utils.isSpecialEvent)(event);
74
75
  analytics.ui.cardClickedEvent({
@@ -81,12 +82,26 @@ function CardWithUrlContent(_ref) {
81
82
  destinationProduct: product,
82
83
  destinationSubproduct: subproduct
83
84
  });
84
- if (onClick) {
85
- onClick(event);
86
- } else if (!isFlexibleUi) {
87
- handleClick(event);
85
+ if (!onClick && !isFlexibleUi) {
86
+ var clickUrl = (0, _helpers.getClickUrl)(url, state.details);
87
+ // Ctrl+left click on mac typically doesn't trigger onClick
88
+ // The event could have potentially had `e.preventDefault()` called on it by now
89
+ // event by smart card internally
90
+ // If it has been called then only then can `isModifierKeyPressed` be true.
91
+ var target = isModifierKeyPressed ? '_blank' : '_self';
92
+ window.open(clickUrl, target);
93
+ (0, _click.fireLinkClickedEvent)(createAnalyticsEvent)(event, {
94
+ attributes: {
95
+ clickOutcome: target === '_blank' ? 'clickThroughNewTabOrWindow' : 'clickThrough'
96
+ }
97
+ });
98
+ } else {
99
+ if (onClick) {
100
+ onClick(event);
101
+ }
102
+ (0, _click.fireLinkClickedEvent)(createAnalyticsEvent)(event);
88
103
  }
89
- }, [id, state.status, analytics.ui, appearance, definitionId, extensionKey, onClick, handleClick, isFlexibleUi, product, subproduct]);
104
+ }, [id, url, state.details, state.status, analytics.ui, appearance, definitionId, extensionKey, onClick, isFlexibleUi, product, subproduct, createAnalyticsEvent]);
90
105
  var handleAuthorize = (0, _react.useCallback)(function () {
91
106
  return actions.authorize(appearance);
92
107
  }, [actions, appearance]);
@@ -8,6 +8,7 @@ exports.ExpandedFrame = void 0;
8
8
  var _react = _interopRequireDefault(require("react"));
9
9
  var _styled = require("./styled");
10
10
  var _handlers = require("../../BlockCard/utils/handlers");
11
+ var _useMouseDownEvent = _interopRequireDefault(require("../../../state/analytics/useMouseDownEvent"));
11
12
  var ExpandedFrame = function ExpandedFrame(_ref) {
12
13
  var _ref$isPlaceholder = _ref.isPlaceholder,
13
14
  isPlaceholder = _ref$isPlaceholder === void 0 ? false : _ref$isPlaceholder,
@@ -32,6 +33,7 @@ var ExpandedFrame = function ExpandedFrame(_ref) {
32
33
  var handleClick = function handleClick(event) {
33
34
  return (0, _handlers.handleClickCommon)(event, onClick);
34
35
  };
36
+ var handleMouseDown = (0, _useMouseDownEvent.default)();
35
37
  var renderHeader = function renderHeader() {
36
38
  return /*#__PURE__*/_react.default.createElement(_styled.Header, {
37
39
  className: "embed-header"
@@ -41,7 +43,8 @@ var ExpandedFrame = function ExpandedFrame(_ref) {
41
43
  isPlaceholder: isPlaceholder
42
44
  }, !isPlaceholder && /*#__PURE__*/_react.default.createElement("a", {
43
45
  href: href,
44
- onClick: handleClick
46
+ onClick: handleClick,
47
+ onMouseDown: handleMouseDown
45
48
  }, text)));
46
49
  };
47
50
  var renderContent = function renderContent() {
@@ -8,6 +8,7 @@ exports.default = void 0;
8
8
  var _react = _interopRequireDefault(require("react"));
9
9
  var _tooltip = _interopRequireDefault(require("@atlaskit/tooltip"));
10
10
  var _customThemeButton = _interopRequireDefault(require("@atlaskit/button/custom-theme-button"));
11
+ var _useMouseDownEvent = _interopRequireDefault(require("../../../../../state/analytics/useMouseDownEvent"));
11
12
  var LinkInfoButton = function LinkInfoButton(_ref) {
12
13
  var content = _ref.content,
13
14
  href = _ref.href,
@@ -15,6 +16,7 @@ var LinkInfoButton = function LinkInfoButton(_ref) {
15
16
  onClick = _ref.onClick,
16
17
  target = _ref.target,
17
18
  testId = _ref.testId;
19
+ var onMouseDown = (0, _useMouseDownEvent.default)();
18
20
  return /*#__PURE__*/_react.default.createElement(_tooltip.default, {
19
21
  content: content,
20
22
  hideTooltipOnClick: true,
@@ -26,6 +28,7 @@ var LinkInfoButton = function LinkInfoButton(_ref) {
26
28
  href: href,
27
29
  iconBefore: icon,
28
30
  onClick: onClick,
31
+ onMouseDown: onMouseDown,
29
32
  spacing: "none",
30
33
  target: target,
31
34
  testId: "".concat(testId, "-button")
@@ -12,6 +12,7 @@ var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/h
12
12
  var _taggedTemplateLiteral2 = _interopRequireDefault(require("@babel/runtime/helpers/taggedTemplateLiteral"));
13
13
  var _react = _interopRequireWildcard(require("react"));
14
14
  var _react2 = require("@emotion/react");
15
+ var _useMouseDownEvent = _interopRequireDefault(require("../../../../../state/analytics/useMouseDownEvent"));
15
16
  var _constants = require("../../../../../constants");
16
17
  var _resolved = _interopRequireDefault(require("./resolved"));
17
18
  var _errored = _interopRequireDefault(require("./errored"));
@@ -99,10 +100,12 @@ var TitleBlock = function TitleBlock(_ref) {
99
100
  var overrideText = !!text ? {
100
101
  text: text
101
102
  } : {};
103
+ var onMouseDown = (0, _useMouseDownEvent.default)();
102
104
  var title = /*#__PURE__*/_react.default.createElement(_elements.Title, (0, _extends2.default)({
103
105
  hideTooltip: hideTitleTooltip,
104
106
  maxLines: maxLines,
105
107
  onClick: onClick,
108
+ onMouseDown: onMouseDown,
106
109
  target: anchorTarget,
107
110
  theme: theme
108
111
  }, overrideText));
@@ -8,6 +8,7 @@ exports.default = void 0;
8
8
  var _taggedTemplateLiteral2 = _interopRequireDefault(require("@babel/runtime/helpers/taggedTemplateLiteral"));
9
9
  var _react = _interopRequireDefault(require("react"));
10
10
  var _react2 = require("@emotion/react");
11
+ var _useMouseDownEvent = _interopRequireDefault(require("../../../../../state/analytics/useMouseDownEvent"));
11
12
  var _templateObject;
12
13
  var styles = (0, _react2.css)(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2.default)(["\n // Stretch the invisible link over the whole of the post.\n // Hide the link\u2019s text.\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n overflow-x: hidden;\n text-indent: 100%;\n white-space: nowrap;\n\n // Needs a heightened specificity to trump other anchor.\n // Stack it under all other links in the post text.\n a&.layered-link {\n position: absolute;\n z-index: 0;\n }\n\n // When hovering over the layered link, any hidden action buttons inside\n // the Container should become visible.\n // As actions resides inside blocks and layered link is expected to be\n // on the same level of blocks. That makes the blocks, e.g. TitleBlock,\n // its sibling. Using general sibling combinator here to apply styling to\n // all the siblings of layered link.\n // The general sibling combinator (~) separates two selectors and matches all\n // iterations of the second element, that are following the first element\n // (though not necessarily immediately), and are children of the same parent\n // element.\n &:hover ~ * {\n .actions-button-group {\n opacity: 1;\n }\n }\n"])));
13
14
 
@@ -22,12 +23,14 @@ var LayeredLink = function LayeredLink(_ref) {
22
23
  testId = _ref.testId,
23
24
  text = _ref.text,
24
25
  url = _ref.url;
26
+ var onMouseDown = (0, _useMouseDownEvent.default)();
25
27
  return (0, _react2.jsx)("a", {
26
28
  className: "layered-link",
27
29
  css: styles,
28
30
  "data-testid": "".concat(testId, "-layered-link"),
29
31
  href: url,
30
32
  onClick: onClick,
33
+ onMouseDown: onMouseDown,
31
34
  target: target,
32
35
  tabIndex: -1 // Hide tab index and let the title link be the link.
33
36
  }, text);
@@ -13,6 +13,7 @@ var _tooltip = _interopRequireDefault(require("@atlaskit/tooltip"));
13
13
  var _constants = require("../../../../../constants");
14
14
  var _utils = require("../../utils");
15
15
  var _token = require("../../../../../utils/token");
16
+ var _useMouseDownEvent = _interopRequireDefault(require("../../../../../state/analytics/useMouseDownEvent"));
16
17
  var _templateObject, _templateObject2, _templateObject3, _templateObject4;
17
18
  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); }
18
19
  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; }
@@ -73,6 +74,7 @@ var Link = function Link(_ref) {
73
74
  url = _ref.url,
74
75
  onClick = _ref.onClick,
75
76
  target = _ref.target;
77
+ var onMouseDown = (0, _useMouseDownEvent.default)();
76
78
  var hasSpace = (0, _react.useMemo)(function () {
77
79
  return text ? (0, _utils.hasWhiteSpace)(text) : false;
78
80
  }, [text]);
@@ -82,6 +84,7 @@ var Link = function Link(_ref) {
82
84
  "data-smart-element-link": true,
83
85
  "data-testid": testId,
84
86
  onClick: onClick,
87
+ onMouseDown: onMouseDown,
85
88
  href: url,
86
89
  target: target || '_blank'
87
90
  }, text);
@@ -12,6 +12,7 @@ var _react = require("@emotion/react");
12
12
  var _shortcut = _interopRequireDefault(require("@atlaskit/icon/glyph/shortcut"));
13
13
  var _copy = _interopRequireDefault(require("@atlaskit/icon/glyph/copy"));
14
14
  var _extractors = require("@atlaskit/linking-common/extractors");
15
+ var _analyticsNext = require("@atlaskit/analytics-next");
15
16
  var _react2 = _interopRequireWildcard(require("react"));
16
17
  var _constants = require("../../../constants");
17
18
  var _extractMetadata2 = require("../../../extractors/hover/extractMetadata");
@@ -25,6 +26,7 @@ var _resolved = _interopRequireDefault(require("./views/resolved"));
25
26
  var _reactIntlNext = require("react-intl-next");
26
27
  var _messages = require("../../../messages");
27
28
  var _actions = require("../../../state/actions");
29
+ var _click = require("../../../utils/analytics/click");
28
30
  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); }
29
31
  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; }
30
32
  /** @jsx jsx */
@@ -102,6 +104,8 @@ var HoverCardContent = function HoverCardContent(_ref) {
102
104
  url = _ref.url,
103
105
  onMouseEnter = _ref.onMouseEnter,
104
106
  onMouseLeave = _ref.onMouseLeave;
107
+ var _useAnalyticsEvents = (0, _analyticsNext.useAnalyticsEvents)(),
108
+ createAnalyticsEvent = _useAnalyticsEvents.createAnalyticsEvent;
105
109
  var extensionKey = (0, _react2.useMemo)(function () {
106
110
  return (0, _helpers.getExtensionKey)(cardState.details);
107
111
  }, [cardState.details]);
@@ -118,7 +122,8 @@ var HoverCardContent = function HoverCardContent(_ref) {
118
122
  isModifierKeyPressed: isModifierKeyPressed,
119
123
  actionSubjectId: 'titleGoToLink'
120
124
  });
121
- }, [cardState.status, analytics.ui, id]);
125
+ (0, _click.fireLinkClickedEvent)(createAnalyticsEvent)(event);
126
+ }, [createAnalyticsEvent, cardState.status, analytics.ui, id]);
122
127
  var titleActions = (0, _react2.useMemo)(function () {
123
128
  return [getCopyAction(url), getOpenAction(url, analytics, onActionClick)];
124
129
  }, [url, analytics, onActionClick]);
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
 
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
3
4
  var _typeof = require("@babel/runtime/helpers/typeof");
4
5
  Object.defineProperty(exports, "__esModule", {
5
6
  value: true
@@ -8,6 +9,7 @@ exports.Frame = void 0;
8
9
  var _react = _interopRequireWildcard(require("react"));
9
10
  var _components = require("@atlaskit/theme/components");
10
11
  var _styled = require("./styled");
12
+ var _useMouseDownEvent = _interopRequireDefault(require("../../../state/analytics/useMouseDownEvent"));
11
13
  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); }
12
14
  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; }
13
15
  var Frame = function Frame(props) {
@@ -35,6 +37,7 @@ var Frame = function Frame(props) {
35
37
  onClick(event);
36
38
  }
37
39
  }, [onClick]);
40
+ var handleMouseDown = (0, _useMouseDownEvent.default)();
38
41
  var isInteractive = Boolean(onClick);
39
42
 
40
43
  // Depending on whenever Frame was given onClick or link itself we display span or anchor elements
@@ -51,6 +54,7 @@ var Frame = function Frame(props) {
51
54
  tabIndex: isInteractive ? 0 : undefined,
52
55
  role: isInteractive ? 'button' : undefined,
53
56
  onClick: handleClick,
57
+ onMouseDown: handleMouseDown,
54
58
  onKeyPress: handleKeyPress,
55
59
  "data-testid": testId,
56
60
  className: className
@@ -0,0 +1,18 @@
1
+ import { useCallback } from 'react';
2
+ import { useAnalyticsEvents } from '@atlaskit/analytics-next';
3
+ import { fireLinkClickedEvent } from '../../utils/analytics/click';
4
+ const useMouseDownEvent = onMouseDown => {
5
+ const {
6
+ createAnalyticsEvent
7
+ } = useAnalyticsEvents();
8
+ return useCallback(event => {
9
+ onMouseDown === null || onMouseDown === void 0 ? void 0 : onMouseDown(event);
10
+
11
+ // ignore left clicks
12
+ // these would be handled by `onClick` handler instead
13
+ if (event.button !== 0) {
14
+ fireLinkClickedEvent(createAnalyticsEvent)(event);
15
+ }
16
+ }, [onMouseDown, createAnalyticsEvent]);
17
+ };
18
+ export default useMouseDownEvent;
@@ -0,0 +1,106 @@
1
+ import { browser } from '@atlaskit/linking-common/user-agent';
2
+ import { ANALYTICS_CHANNEL } from './analytics';
3
+ export const buttonMap = new Map([[undefined, 'none'], [0, 'left'], [1, 'middle'], [2, 'right']]);
4
+ export const getKeys = e => {
5
+ return ['alt', 'ctrl', 'meta', 'shift'].filter(key => e[`${key}Key`] === true);
6
+ };
7
+ const isContentEditable = el => {
8
+ return el instanceof HTMLElement && el.isContentEditable;
9
+ };
10
+ export function getLinkClickOutcome(e, clickType) {
11
+ const {
12
+ mac,
13
+ safari
14
+ } = browser();
15
+ if (e.defaultPrevented) {
16
+ return 'prevented';
17
+ }
18
+ /**
19
+ * If the link/parent is content editable then left click won't have typical effect
20
+ */
21
+ if (isContentEditable(e.currentTarget) && ['left', 'middle'].includes(clickType)) {
22
+ return 'contentEditable';
23
+ }
24
+ switch (clickType) {
25
+ case 'left':
26
+ {
27
+ // Meta key = Cmd for macOS, Windows key sometimes for Windows (otherwise false)
28
+ // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/metaKey
29
+ if (e.metaKey) {
30
+ return mac ? 'clickThroughNewTabOrWindow' : 'clickThrough';
31
+ }
32
+ if (e.shiftKey) {
33
+ // Alt/option click in safari typically adds the link to bookmarks
34
+ if (safari) {
35
+ return 'alt';
36
+ }
37
+ return 'clickThroughNewTabOrWindow';
38
+ }
39
+ if (e.ctrlKey) {
40
+ // Ctrl+Left on macOS defaults to triggering a right click instead (so won't trigger onClick)
41
+ // but if this behaviour is disabled, likely outcome is clickThrough
42
+ if (mac) {
43
+ return 'clickThrough';
44
+ }
45
+ return 'clickThroughNewTabOrWindow';
46
+ }
47
+ if (e.altKey) {
48
+ return 'alt';
49
+ }
50
+ const target = e.currentTarget.getAttribute('target');
51
+ if (target === '_blank') {
52
+ return 'clickThroughNewTabOrWindow';
53
+ }
54
+ return 'clickThrough';
55
+ }
56
+ case 'middle':
57
+ {
58
+ return 'clickThroughNewTabOrWindow';
59
+ }
60
+ case 'right':
61
+ {
62
+ return 'contextMenu';
63
+ }
64
+ }
65
+ return '_unknown';
66
+ }
67
+ const linkClickedEvent = ({
68
+ clickType,
69
+ clickOutcome,
70
+ keysHeld
71
+ }) => ({
72
+ action: 'clicked',
73
+ actionSubject: 'link',
74
+ eventType: 'ui',
75
+ attributes: {
76
+ clickType,
77
+ clickOutcome,
78
+ keysHeld
79
+ }
80
+ });
81
+ export const createLinkClickedPayload = event => {
82
+ const clickType = buttonMap.get(event.button);
83
+ if (!clickType) {
84
+ return;
85
+ }
86
+ const clickOutcome = getLinkClickOutcome(event, clickType);
87
+ const keysHeld = getKeys(event);
88
+ return linkClickedEvent({
89
+ clickType,
90
+ clickOutcome,
91
+ keysHeld
92
+ });
93
+ };
94
+ export const fireLinkClickedEvent = createAnalyticsEvent => (event, overrides = {}) => {
95
+ const payload = createLinkClickedPayload(event);
96
+ if (payload) {
97
+ createAnalyticsEvent({
98
+ ...payload,
99
+ ...overrides,
100
+ attributes: {
101
+ ...payload.attributes,
102
+ ...(overrides === null || overrides === void 0 ? void 0 : overrides.attributes)
103
+ }
104
+ }).fire(ANALYTICS_CHANNEL);
105
+ }
106
+ };
@@ -3,6 +3,16 @@ import Loadable from 'react-loadable';
3
3
  export const isCardWithData = props => !!props.data;
4
4
  export const isSpecialEvent = evt => evt.isDefaultPrevented() && (isIframe() || isSpecialKey(evt) || isSpecialClick(evt));
5
5
  export const isIframe = () => window.parent !== parent;
6
+
7
+ /**
8
+ * Meta key = cmd on mac, windows key on windows
9
+ * Ctrl key on mac by default triggers a right click instead of left click
10
+ * Ctrl key on Windows has the same behaviour of cmd key of mac (open in new tab)
11
+ *
12
+ * `isSpecialKey` on a mouse event on mac with default behaviour should be equivalent to opening in new tab
13
+ * On Windows it will be equivalent to opening a new tab, unless its the Window key that is held
14
+ * in which case typically only a standard clickthrough will occur, this is likely a small portion of events
15
+ */
6
16
  export const isSpecialKey = event => event.metaKey || event.ctrlKey;
7
17
  export const isSpecialClick = event => event.button === 1;
8
18
  export const getIconForFileType = fileMimeType => {
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-card",
3
- "version": "23.14.2",
3
+ "version": "24.0.1",
4
4
  "sideEffects": false
5
5
  }