@atlaskit/smart-card 18.0.18 → 18.0.21

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 (51) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/cjs/utils/flexible.js +1 -1
  3. package/dist/cjs/utils/token.js +1 -0
  4. package/dist/cjs/version.json +1 -1
  5. package/dist/cjs/view/FlexibleCard/components/blocks/action-group/index.js +3 -1
  6. package/dist/cjs/view/FlexibleCard/components/blocks/title-block/errored/index.js +4 -2
  7. package/dist/cjs/view/FlexibleCard/components/blocks/title-block/index.js +1 -1
  8. package/dist/cjs/view/FlexibleCard/components/blocks/utils.js +1 -1
  9. package/dist/cjs/view/FlexibleCard/components/container/index.js +66 -23
  10. package/dist/cjs/view/FlexibleCard/components/container/layered-link/index.js +37 -0
  11. package/dist/cjs/view/FlexibleCard/components/container/layered-link/types.js +5 -0
  12. package/dist/cjs/view/FlexibleCard/components/elements/avatar-group/index.js +1 -0
  13. package/dist/cjs/view/FlexibleCard/components/elements/link/index.js +13 -4
  14. package/dist/cjs/view/FlexibleCard/components/utils.js +10 -3
  15. package/dist/cjs/view/FlexibleCard/index.js +2 -2
  16. package/dist/es2019/utils/flexible.js +1 -1
  17. package/dist/es2019/utils/token.js +1 -0
  18. package/dist/es2019/version.json +1 -1
  19. package/dist/es2019/view/FlexibleCard/components/blocks/action-group/index.js +13 -0
  20. package/dist/es2019/view/FlexibleCard/components/blocks/title-block/errored/index.js +6 -1
  21. package/dist/es2019/view/FlexibleCard/components/blocks/title-block/index.js +4 -5
  22. package/dist/es2019/view/FlexibleCard/components/blocks/utils.js +0 -1
  23. package/dist/es2019/view/FlexibleCard/components/container/index.js +59 -10
  24. package/dist/es2019/view/FlexibleCard/components/container/layered-link/index.js +54 -0
  25. package/dist/es2019/view/FlexibleCard/components/container/layered-link/types.js +1 -0
  26. package/dist/es2019/view/FlexibleCard/components/elements/avatar-group/index.js +1 -0
  27. package/dist/es2019/view/FlexibleCard/components/elements/link/index.js +21 -18
  28. package/dist/es2019/view/FlexibleCard/components/utils.js +6 -3
  29. package/dist/es2019/view/FlexibleCard/index.js +2 -2
  30. package/dist/esm/utils/flexible.js +1 -1
  31. package/dist/esm/utils/token.js +1 -0
  32. package/dist/esm/version.json +1 -1
  33. package/dist/esm/view/FlexibleCard/components/blocks/action-group/index.js +2 -1
  34. package/dist/esm/view/FlexibleCard/components/blocks/title-block/errored/index.js +4 -2
  35. package/dist/esm/view/FlexibleCard/components/blocks/title-block/index.js +1 -1
  36. package/dist/esm/view/FlexibleCard/components/blocks/utils.js +1 -1
  37. package/dist/esm/view/FlexibleCard/components/container/index.js +57 -23
  38. package/dist/esm/view/FlexibleCard/components/container/layered-link/index.js +26 -0
  39. package/dist/esm/view/FlexibleCard/components/container/layered-link/types.js +1 -0
  40. package/dist/esm/view/FlexibleCard/components/elements/avatar-group/index.js +1 -0
  41. package/dist/esm/view/FlexibleCard/components/elements/link/index.js +8 -5
  42. package/dist/esm/view/FlexibleCard/components/utils.js +5 -1
  43. package/dist/esm/view/FlexibleCard/index.js +2 -2
  44. package/dist/types/utils/token.d.ts +1 -0
  45. package/dist/types/view/FlexibleCard/components/container/index.d.ts +1 -1
  46. package/dist/types/view/FlexibleCard/components/container/layered-link/index.d.ts +5 -0
  47. package/dist/types/view/FlexibleCard/components/container/layered-link/types.d.ts +6 -0
  48. package/dist/types/view/FlexibleCard/components/container/types.d.ts +1 -0
  49. package/dist/types/view/FlexibleCard/components/utils.d.ts +2 -1
  50. package/dist/types/view/FlexibleCard/types.d.ts +1 -0
  51. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @atlaskit/smart-card
2
2
 
3
+ ## 18.0.21
4
+
5
+ ### Patch Changes
6
+
7
+ - [`ffaf122189e`](https://bitbucket.org/atlassian/atlassian-frontend/commits/ffaf122189e) - Flexible UI: TitleBlock is now composory to display Flexible UI on Smart Links
8
+
9
+ ## 18.0.20
10
+
11
+ ### Patch Changes
12
+
13
+ - [`451f99db28a`](https://bitbucket.org/atlassian/atlassian-frontend/commits/451f99db28a) - Flexible UI: Improve link title truncate to support url string
14
+
15
+ ## 18.0.19
16
+
17
+ ### Patch Changes
18
+
19
+ - [`c09b670ffa1`](https://bitbucket.org/atlassian/atlassian-frontend/commits/c09b670ffa1) - Flexible UI: Add container clickable option and improve keyboard navigation
20
+
3
21
  ## 18.0.18
4
22
 
5
23
  ### Patch Changes
@@ -21,7 +21,7 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj &&
21
21
 
22
22
  var isFlexibleUiCard = function isFlexibleUiCard(children) {
23
23
  if (children && _react.default.Children.toArray(children).some(function (child) {
24
- return isFlexibleUiBlock(child);
24
+ return isFlexibleUiTitleBlock(child);
25
25
  })) {
26
26
  return true;
27
27
  }
@@ -19,6 +19,7 @@ var tokens = {
19
19
  elevation: (0, _tokens.token)('elevation.shadow.raised', '0px 1px 1px #091E4240, 0px 0px 1px #091E424F'),
20
20
  errorMessage: (0, _tokens.token)('color.text.disabled', '#6B778C'),
21
21
  errorMessageHover: (0, _tokens.token)('color.text.subtle', '#8993A4'),
22
+ focus: (0, _tokens.token)('color.border.focused', '#388BFF'),
22
23
  snippet: (0, _tokens.token)('color.text', '#172B4D'),
23
24
  text: (0, _tokens.token)('color.text.subtlest', '#626F86')
24
25
  };
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-card",
3
- "version": "18.0.18",
3
+ "version": "18.0.21",
4
4
  "sideEffects": false
5
5
  }
@@ -29,11 +29,13 @@ var _more = _interopRequireDefault(require("@atlaskit/icon/glyph/more"));
29
29
 
30
30
  var _action = require("../../actions/action");
31
31
 
32
+ var _token = require("../../../../../utils/token");
33
+
32
34
  var _excluded = ["triggerRef"];
33
35
 
34
36
  var _templateObject;
35
37
 
36
- var styles = (0, _core.css)(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2.default)(["\n display: inline-flex;\n line-height: 1rem;\n"])));
38
+ var styles = (0, _core.css)(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2.default)(["\n display: inline-flex;\n line-height: 1rem;\n > div {\n align-items: center;\n button:focus {\n // AK button removes the default browser outline on focus and apply\n // box-shadow styling to create the outline appearance.\n // Due to our container elements (Container/Block/ElementGroup) has\n // overflow hidden to prevent the metadata element from leaking outside\n // of its container, the box-shadow doesn't show properly.\n // Invert the AK box-shadow styling.\n box-shadow: inset 0 0 0 2px ", ";\n }\n }\n"])), _token.tokens.focus);
37
39
  /**
38
40
  * Creates a group of Action components. Accepts an array of Actions, in addition to some styling
39
41
  * preferences.
@@ -39,7 +39,7 @@ var actionStyles = (0, _core.css)(_templateObject || (_templateObject = (0, _tag
39
39
 
40
40
  var getMessageStyles = function getMessageStyles(size, hasAction) {
41
41
  var sizeStyles = (0, _utils.getLinkSizeStyles)(size);
42
- return (0, _core.css)(_templateObject2 || (_templateObject2 = (0, _taggedTemplateLiteral2.default)(["\n flex: 1 1 auto;\n justify-content: flex-end;\n ", "\n ", "\n ", "\n color: ", ";\n "])), hasAction ? actionStyles : '', sizeStyles, (0, _utils.getTruncateStyles)(1, (0, _utils.getLinkLineHeight)(size)), _token.tokens.errorMessage);
42
+ return (0, _core.css)(_templateObject2 || (_templateObject2 = (0, _taggedTemplateLiteral2.default)(["\n flex: 1 1 auto;\n justify-content: flex-end;\n ", "\n ", "\n ", "\n color: ", ";\n :focus {\n outline: ", " solid 2px;\n }\n "])), hasAction ? actionStyles : '', sizeStyles, (0, _utils.getTruncateStyles)(1, (0, _utils.getLinkLineHeight)(size)), _token.tokens.errorMessage, _token.tokens.focus);
43
43
  };
44
44
  /**
45
45
  * Represents an Errored TitleBlock view.
@@ -74,9 +74,11 @@ var TitleBlockErroredView = function TitleBlockErroredView(_ref) {
74
74
  direction: _constants.SmartLinkDirection.Horizontal,
75
75
  align: _constants.SmartLinkAlignment.Right
76
76
  }, (0, _core.jsx)("span", {
77
+ className: hasAction ? 'has-action' : '',
77
78
  css: getMessageStyles(size, hasAction),
78
79
  onClick: onClick,
79
- "data-testid": "".concat(testId, "-errored-view-message")
80
+ "data-testid": "".concat(testId, "-errored-view-message"),
81
+ tabIndex: hasAction ? 0 : -1
80
82
  }, (0, _core.jsx)(_reactIntlNext.FormattedMessage, (0, _extends2.default)({}, descriptor, {
81
83
  values: values
82
84
  })))), actionGroup);
@@ -43,7 +43,7 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj &&
43
43
 
44
44
  var getActionStyles = function getActionStyles(showOnHover, isOpen) {
45
45
  if (showOnHover && !isOpen) {
46
- return (0, _core.css)(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2.default)(["\n .actions-button-group {\n visibility: hidden;\n }\n\n &:hover {\n .actions-button-group {\n visibility: visible;\n }\n }\n "])));
46
+ return (0, _core.css)(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2.default)(["\n .actions-button-group {\n opacity: 0;\n }\n\n &:hover .actions-button-group,\n .actions-button-group:focus-within {\n opacity: 1;\n }\n "])));
47
47
  }
48
48
  };
49
49
 
@@ -82,7 +82,7 @@ var getGapSize = function getGapSize(size) {
82
82
  exports.getGapSize = getGapSize;
83
83
 
84
84
  var getBaseStyles = function getBaseStyles(direction, size) {
85
- return (0, _core.css)(_templateObject3 || (_templateObject3 = (0, _taggedTemplateLiteral2.default)(["\n display: flex;\n gap: ", "rem;\n line-height: 1rem;\n min-width: 0;\n overflow: hidden;\n overflow-y: hidden;\n ", ";\n &:empty {\n display: none;\n }\n & > * {\n min-width: 0;\n }\n & > [data-fit-to-content] {\n min-width: fit-content;\n }\n"])), getGapSize(size), getDirectionStyles(direction));
85
+ return (0, _core.css)(_templateObject3 || (_templateObject3 = (0, _taggedTemplateLiteral2.default)(["\n display: flex;\n gap: ", "rem;\n line-height: 1rem;\n min-width: 0;\n overflow: hidden;\n ", ";\n &:empty {\n display: none;\n }\n & > * {\n min-width: 0;\n }\n & > [data-fit-to-content] {\n min-width: fit-content;\n }\n"])), getGapSize(size), getDirectionStyles(direction));
86
86
  };
87
87
 
88
88
  exports.getBaseStyles = getBaseStyles;
@@ -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.getContainerStyles = exports.default = void 0;
9
11
 
10
12
  var _taggedTemplateLiteral2 = _interopRequireDefault(require("@babel/runtime/helpers/taggedTemplateLiteral"));
11
13
 
12
- var _react = _interopRequireDefault(require("react"));
14
+ var _react = _interopRequireWildcard(require("react"));
13
15
 
14
16
  var _core = require("@emotion/core");
15
17
 
@@ -19,7 +21,15 @@ var _flexible = require("../../../../utils/flexible");
19
21
 
20
22
  var _token = require("../../../../utils/token");
21
23
 
22
- var _templateObject, _templateObject2;
24
+ var _flexibleUiContext = require("../../../../state/flexible-ui-context");
25
+
26
+ var _layeredLink = _interopRequireDefault(require("./layered-link"));
27
+
28
+ var _templateObject, _templateObject2, _templateObject3;
29
+
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); }
31
+
32
+ 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; }
23
33
 
24
34
  var elevationStyles = (0, _core.css)(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2.default)(["\n border: 1px solid transparent;\n border-radius: 1.5px;\n box-shadow: ", ";\n margin: 2px;\n"])), _token.tokens.elevation);
25
35
 
@@ -57,8 +67,10 @@ var getPadding = function getPadding(size) {
57
67
  }
58
68
  };
59
69
 
60
- var getContainerStyles = function getContainerStyles(size, hideBackground, hideElevation, hidePadding) {
61
- return (0, _core.css)(_templateObject2 || (_templateObject2 = (0, _taggedTemplateLiteral2.default)(["\n display: flex;\n gap: ", " 0;\n flex-direction: column;\n min-width: 0;\n overflow: hidden;\n ", "\n ", "\n ", "\n"])), getGap(size), hideBackground ? '' : "background-color: ".concat(_token.tokens.background, ";"), hidePadding ? '' : "padding: ".concat(getPadding(size), ";"), hideElevation ? '' : elevationStyles);
70
+ var clickableContainerStyles = (0, _core.css)(_templateObject2 || (_templateObject2 = (0, _taggedTemplateLiteral2.default)(["\n // Position any interactive elements at the top of the z-index stack.\n a,\n button,\n .has-action {\n position: relative;\n z-index: 1;\n }\n"])));
71
+
72
+ var getContainerStyles = function getContainerStyles(size, hideBackground, hideElevation, hidePadding, clickableContainer) {
73
+ return (0, _core.css)(_templateObject3 || (_templateObject3 = (0, _taggedTemplateLiteral2.default)(["\n display: flex;\n gap: ", " 0;\n flex-direction: column;\n min-width: 0;\n overflow-x: hidden;\n position: relative;\n ", "\n ", "\n ", "\n ", "\n &:hover ~ .actions-button-group {\n opacity: 1;\n }\n a:focus,\n .has-action:focus {\n outline-offset: -2px;\n }\n"])), getGap(size), hideBackground ? '' : "background-color: ".concat(_token.tokens.background, ";"), hidePadding ? '' : "padding: ".concat(getPadding(size), ";"), hideElevation ? '' : elevationStyles, clickableContainer ? clickableContainerStyles : '');
62
74
  };
63
75
 
64
76
  exports.getContainerStyles = getContainerStyles;
@@ -77,34 +89,65 @@ var renderChildren = function renderChildren(children, containerSize, containerT
77
89
  }
78
90
  });
79
91
  };
92
+
93
+ var getTitleBlockProps = function getTitleBlockProps(children) {
94
+ var block = _react.default.Children.toArray(children).find(function (child) {
95
+ return (0, _flexible.isFlexibleUiTitleBlock)(child);
96
+ });
97
+
98
+ if ( /*#__PURE__*/_react.default.isValidElement(block)) {
99
+ return block.props;
100
+ }
101
+ };
102
+
103
+ var getLayeredLink = function getLayeredLink(testId, context, children) {
104
+ var _ref = context || {},
105
+ title = _ref.title,
106
+ _ref$url = _ref.url,
107
+ url = _ref$url === void 0 ? '' : _ref$url;
108
+
109
+ var _ref2 = getTitleBlockProps(children) || {},
110
+ target = _ref2.anchorTarget,
111
+ text = _ref2.text;
112
+
113
+ return (0, _core.jsx)(_layeredLink.default, {
114
+ target: target,
115
+ testId: testId,
116
+ text: text || title,
117
+ url: url
118
+ });
119
+ };
80
120
  /**
81
121
  * This represents the container in which all Flexible UI Smart Links are rendered.
82
122
  * @see Block
83
123
  */
84
124
 
85
125
 
86
- var Container = function Container(_ref) {
87
- var children = _ref.children,
88
- _ref$hideBackground = _ref.hideBackground,
89
- hideBackground = _ref$hideBackground === void 0 ? false : _ref$hideBackground,
90
- _ref$hideElevation = _ref.hideElevation,
91
- hideElevation = _ref$hideElevation === void 0 ? false : _ref$hideElevation,
92
- _ref$hidePadding = _ref.hidePadding,
93
- hidePadding = _ref$hidePadding === void 0 ? false : _ref$hidePadding,
94
- retry = _ref.retry,
95
- _ref$size = _ref.size,
96
- size = _ref$size === void 0 ? _constants.SmartLinkSize.Medium : _ref$size,
97
- status = _ref.status,
98
- _ref$testId = _ref.testId,
99
- testId = _ref$testId === void 0 ? 'smart-links-container' : _ref$testId,
100
- _ref$theme = _ref.theme,
101
- theme = _ref$theme === void 0 ? _constants.SmartLinkTheme.Link : _ref$theme,
102
- onClick = _ref.onClick;
126
+ var Container = function Container(_ref3) {
127
+ var children = _ref3.children,
128
+ _ref3$clickableContai = _ref3.clickableContainer,
129
+ clickableContainer = _ref3$clickableContai === void 0 ? false : _ref3$clickableContai,
130
+ _ref3$hideBackground = _ref3.hideBackground,
131
+ hideBackground = _ref3$hideBackground === void 0 ? false : _ref3$hideBackground,
132
+ _ref3$hideElevation = _ref3.hideElevation,
133
+ hideElevation = _ref3$hideElevation === void 0 ? false : _ref3$hideElevation,
134
+ _ref3$hidePadding = _ref3.hidePadding,
135
+ hidePadding = _ref3$hidePadding === void 0 ? false : _ref3$hidePadding,
136
+ onClick = _ref3.onClick,
137
+ retry = _ref3.retry,
138
+ _ref3$size = _ref3.size,
139
+ size = _ref3$size === void 0 ? _constants.SmartLinkSize.Medium : _ref3$size,
140
+ status = _ref3.status,
141
+ _ref3$testId = _ref3.testId,
142
+ testId = _ref3$testId === void 0 ? 'smart-links-container' : _ref3$testId,
143
+ _ref3$theme = _ref3.theme,
144
+ theme = _ref3$theme === void 0 ? _constants.SmartLinkTheme.Link : _ref3$theme;
145
+ var context = (0, _react.useContext)(_flexibleUiContext.FlexibleUiContext);
103
146
  return (0, _core.jsx)("div", {
104
- css: getContainerStyles(size, hideBackground, hideElevation, hidePadding),
147
+ css: getContainerStyles(size, hideBackground, hideElevation, hidePadding, clickableContainer),
105
148
  "data-smart-link-container": true,
106
149
  "data-testid": testId
107
- }, renderChildren(children, size, theme, status, retry, onClick));
150
+ }, clickableContainer ? getLayeredLink(testId, context, children) : null, renderChildren(children, size, theme, status, retry, onClick));
108
151
  };
109
152
 
110
153
  var _default = Container;
@@ -0,0 +1,37 @@
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 _taggedTemplateLiteral2 = _interopRequireDefault(require("@babel/runtime/helpers/taggedTemplateLiteral"));
11
+
12
+ var _react = _interopRequireDefault(require("react"));
13
+
14
+ var _core = require("@emotion/core");
15
+
16
+ var _templateObject;
17
+
18
+ var styles = (0, _core.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"])));
19
+
20
+ var LayeredLink = function LayeredLink(_ref) {
21
+ var target = _ref.target,
22
+ testId = _ref.testId,
23
+ text = _ref.text,
24
+ url = _ref.url;
25
+ return (0, _core.jsx)("a", {
26
+ className: "layered-link",
27
+ css: styles,
28
+ "data-testid": "".concat(testId, "-layered-link"),
29
+ href: url,
30
+ target: target,
31
+ tabIndex: -1 // Hide tab index and let the title link be the link.
32
+
33
+ }, text);
34
+ };
35
+
36
+ var _default = LayeredLink;
37
+ exports.default = _default;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
@@ -60,6 +60,7 @@ var AvatarGroup = function AvatarGroup(_ref) {
60
60
 
61
61
  return (0, _core.jsx)("span", {
62
62
  css: [getStyles(size), overrideCss],
63
+ "data-fit-to-content": true,
63
64
  "data-smart-element-avatar-group": true,
64
65
  "data-testid": testId
65
66
  }, (0, _core.jsx)(_avatarGroup.default, {
@@ -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 _taggedTemplateLiteral2 = _interopRequireDefault(require("@babel/runtime/helpers/taggedTemplateLiteral"));
11
13
 
12
- var _react = _interopRequireDefault(require("react"));
14
+ var _react = _interopRequireWildcard(require("react"));
13
15
 
14
16
  var _core = require("@emotion/core");
15
17
 
@@ -23,6 +25,10 @@ var _token = require("../../../../../utils/token");
23
25
 
24
26
  var _templateObject, _templateObject2, _templateObject3, _templateObject4;
25
27
 
28
+ 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
+
30
+ 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; }
31
+
26
32
  var DEFAULT_MAX_LINES = 2;
27
33
  var MAXIMUM_MAX_LINES = 2;
28
34
  var MINIMUM_MAX_LINES = 1;
@@ -40,9 +46,9 @@ var getThemeStyles = function getThemeStyles(theme) {
40
46
  }
41
47
  };
42
48
 
43
- var getAnchorStyles = function getAnchorStyles(size, theme, maxLines) {
49
+ var getAnchorStyles = function getAnchorStyles(size, theme, maxLines, hasSpace) {
44
50
  var sizeStyles = (0, _utils.getLinkSizeStyles)(size);
45
- return (0, _core.css)(_templateObject4 || (_templateObject4 = (0, _taggedTemplateLiteral2.default)(["\n flex: 1 1 auto;\n ", "\n ", "\n // Theme should be last to be spread because it contains override values\n ", "\n "])), sizeStyles, (0, _utils.getTruncateStyles)(maxLines, (0, _utils.getLinkLineHeight)(size)), getThemeStyles(theme));
51
+ return (0, _core.css)(_templateObject4 || (_templateObject4 = (0, _taggedTemplateLiteral2.default)(["\n flex: 1 1 auto;\n ", "\n ", "\n // Theme should be last to be spread because it contains override values\n ", "\n "])), sizeStyles, (0, _utils.getTruncateStyles)(maxLines, (0, _utils.getLinkLineHeight)(size), hasSpace ? 'break-word' : 'break-all'), getThemeStyles(theme));
46
52
  };
47
53
 
48
54
  var getMaxLines = function getMaxLines(maxLines) {
@@ -78,6 +84,9 @@ var Link = function Link(_ref) {
78
84
  url = _ref.url,
79
85
  onClick = _ref.onClick,
80
86
  target = _ref.target;
87
+ var hasSpace = (0, _react.useMemo)(function () {
88
+ return text ? (0, _utils.hasWhiteSpace)(text) : false;
89
+ }, [text]);
81
90
  return (0, _core.jsx)("span", {
82
91
  css: containerStyles
83
92
  }, (0, _core.jsx)(_tooltip.default, {
@@ -85,7 +94,7 @@ var Link = function Link(_ref) {
85
94
  testId: "".concat(testId, "-tooltip"),
86
95
  tag: "span"
87
96
  }, (0, _core.jsx)("a", {
88
- css: [getAnchorStyles(size, theme, getMaxLines(maxLines)), overrideCss],
97
+ css: [getAnchorStyles(size, theme, getMaxLines(maxLines), hasSpace), overrideCss],
89
98
  "data-smart-element-link": true,
90
99
  "data-testid": testId,
91
100
  onClick: onClick,
@@ -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.getTruncateStyles = exports.getMaxLines = exports.getLinkSizeStyles = exports.getLinkLineHeight = exports.getIconWidth = exports.getIconSizeStyles = exports.getFormattedMessage = void 0;
8
+ exports.hasWhiteSpace = exports.getTruncateStyles = exports.getMaxLines = exports.getLinkSizeStyles = exports.getLinkLineHeight = exports.getIconWidth = exports.getIconSizeStyles = exports.getFormattedMessage = void 0;
9
9
 
10
10
  var _taggedTemplateLiteral2 = _interopRequireDefault(require("@babel/runtime/helpers/taggedTemplateLiteral"));
11
11
 
@@ -111,7 +111,14 @@ exports.getMaxLines = getMaxLines;
111
111
 
112
112
  var getTruncateStyles = function getTruncateStyles(maxLines) {
113
113
  var lineHeight = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '1rem';
114
- return (0, _core.css)(_templateObject6 || (_templateObject6 = (0, _taggedTemplateLiteral2.default)(["\n display: -webkit-box;\n overflow: hidden;\n text-overflow: ellipsis;\n word-break: break-word;\n -webkit-line-clamp: ", ";\n -webkit-box-orient: vertical;\n // Fallback options\n max-height: calc(", " * ", ");\n "])), maxLines, maxLines, lineHeight);
114
+ var wordBreak = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'break-word';
115
+ return (0, _core.css)(_templateObject6 || (_templateObject6 = (0, _taggedTemplateLiteral2.default)(["\n display: -webkit-box;\n overflow: hidden;\n text-overflow: ellipsis;\n word-break: ", ";\n -webkit-line-clamp: ", ";\n -webkit-box-orient: vertical;\n // Fallback options\n max-height: calc(", " * ", ");\n "])), wordBreak, maxLines, maxLines, lineHeight);
115
116
  };
116
117
 
117
- exports.getTruncateStyles = getTruncateStyles;
118
+ exports.getTruncateStyles = getTruncateStyles;
119
+
120
+ var hasWhiteSpace = function hasWhiteSpace(str) {
121
+ return str.search(/\s/) >= 0;
122
+ };
123
+
124
+ exports.hasWhiteSpace = hasWhiteSpace;
@@ -42,9 +42,9 @@ var FlexibleCard = function FlexibleCard(_ref) {
42
42
  }, /*#__PURE__*/_react.default.createElement(_container.default, (0, _extends2.default)({
43
43
  testId: testId
44
44
  }, ui, {
45
+ onClick: onClick,
45
46
  retry: retry,
46
- status: status,
47
- onClick: onClick
47
+ status: status
48
48
  }), children));
49
49
  };
50
50
 
@@ -3,7 +3,7 @@ import * as Blocks from '../view/FlexibleCard/components/blocks';
3
3
  import { TitleBlock } from '../view/FlexibleCard/components/blocks';
4
4
  import * as Elements from '../view/FlexibleCard/components/elements';
5
5
  export const isFlexibleUiCard = children => {
6
- if (children && React.Children.toArray(children).some(child => isFlexibleUiBlock(child))) {
6
+ if (children && React.Children.toArray(children).some(child => isFlexibleUiTitleBlock(child))) {
7
7
  return true;
8
8
  }
9
9
 
@@ -11,6 +11,7 @@ export const tokens = {
11
11
  elevation: token('elevation.shadow.raised', '0px 1px 1px #091E4240, 0px 0px 1px #091E424F'),
12
12
  errorMessage: token('color.text.disabled', '#6B778C'),
13
13
  errorMessageHover: token('color.text.subtle', '#8993A4'),
14
+ focus: token('color.border.focused', '#388BFF'),
14
15
  snippet: token('color.text', '#172B4D'),
15
16
  text: token('color.text.subtlest', '#626F86')
16
17
  };
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-card",
3
- "version": "18.0.18",
3
+ "version": "18.0.21",
4
4
  "sideEffects": false
5
5
  }
@@ -9,9 +9,22 @@ import { SmartLinkSize } from '../../../../../constants';
9
9
  import Button from '@atlaskit/button/standard-button';
10
10
  import MoreIcon from '@atlaskit/icon/glyph/more';
11
11
  import { sizeToSpacing } from '../../actions/action';
12
+ import { tokens } from '../../../../../utils/token';
12
13
  const styles = css`
13
14
  display: inline-flex;
14
15
  line-height: 1rem;
16
+ > div {
17
+ align-items: center;
18
+ button:focus {
19
+ // AK button removes the default browser outline on focus and apply
20
+ // box-shadow styling to create the outline appearance.
21
+ // Due to our container elements (Container/Block/ElementGroup) has
22
+ // overflow hidden to prevent the metadata element from leaking outside
23
+ // of its container, the box-shadow doesn't show properly.
24
+ // Invert the AK box-shadow styling.
25
+ box-shadow: inset 0 0 0 2px ${tokens.focus};
26
+ }
27
+ }
15
28
  `;
16
29
  /**
17
30
  * Creates a group of Action components. Accepts an array of Actions, in addition to some styling
@@ -27,6 +27,9 @@ const getMessageStyles = (size, hasAction) => {
27
27
  ${sizeStyles}
28
28
  ${getTruncateStyles(1, getLinkLineHeight(size))}
29
29
  color: ${tokens.errorMessage};
30
+ :focus {
31
+ outline: ${tokens.focus} solid 2px;
32
+ }
30
33
  `;
31
34
  };
32
35
  /**
@@ -63,9 +66,11 @@ const TitleBlockErroredView = ({
63
66
  direction: SmartLinkDirection.Horizontal,
64
67
  align: SmartLinkAlignment.Right
65
68
  }, jsx("span", {
69
+ className: hasAction ? 'has-action' : '',
66
70
  css: getMessageStyles(size, hasAction),
67
71
  onClick: onClick,
68
- "data-testid": `${testId}-errored-view-message`
72
+ "data-testid": `${testId}-errored-view-message`,
73
+ tabIndex: hasAction ? 0 : -1
69
74
  }, jsx(FormattedMessage, _extends({}, descriptor, {
70
75
  values: values
71
76
  })))), actionGroup);
@@ -12,13 +12,12 @@ const getActionStyles = (showOnHover, isOpen) => {
12
12
  if (showOnHover && !isOpen) {
13
13
  return css`
14
14
  .actions-button-group {
15
- visibility: hidden;
15
+ opacity: 0;
16
16
  }
17
17
 
18
- &:hover {
19
- .actions-button-group {
20
- visibility: visible;
21
- }
18
+ &:hover .actions-button-group,
19
+ .actions-button-group:focus-within {
20
+ opacity: 1;
22
21
  }
23
22
  `;
24
23
  }
@@ -68,7 +68,6 @@ export const getBaseStyles = (direction, size) => css`
68
68
  line-height: 1rem;
69
69
  min-width: 0;
70
70
  overflow: hidden;
71
- overflow-y: hidden;
72
71
  ${getDirectionStyles(direction)};
73
72
  &:empty {
74
73
  display: none;
@@ -1,9 +1,11 @@
1
1
  /** @jsx jsx */
2
- import React from 'react';
2
+ import React, { useContext } from 'react';
3
3
  import { css, jsx } from '@emotion/core';
4
4
  import { SmartLinkSize, SmartLinkTheme } from '../../../../constants';
5
5
  import { isFlexibleUiBlock, isFlexibleUiTitleBlock } from '../../../../utils/flexible';
6
6
  import { tokens } from '../../../../utils/token';
7
+ import { FlexibleUiContext } from '../../../../state/flexible-ui-context';
8
+ import LayeredLink from './layered-link';
7
9
  const elevationStyles = css`
8
10
  border: 1px solid transparent;
9
11
  border-radius: 1.5px;
@@ -45,15 +47,33 @@ const getPadding = size => {
45
47
  }
46
48
  };
47
49
 
48
- export const getContainerStyles = (size, hideBackground, hideElevation, hidePadding) => css`
50
+ const clickableContainerStyles = css`
51
+ // Position any interactive elements at the top of the z-index stack.
52
+ a,
53
+ button,
54
+ .has-action {
55
+ position: relative;
56
+ z-index: 1;
57
+ }
58
+ `;
59
+ export const getContainerStyles = (size, hideBackground, hideElevation, hidePadding, clickableContainer) => css`
49
60
  display: flex;
50
61
  gap: ${getGap(size)} 0;
51
62
  flex-direction: column;
52
63
  min-width: 0;
53
- overflow: hidden;
64
+ overflow-x: hidden;
65
+ position: relative;
54
66
  ${hideBackground ? '' : `background-color: ${tokens.background};`}
55
67
  ${hidePadding ? '' : `padding: ${getPadding(size)};`}
56
68
  ${hideElevation ? '' : elevationStyles}
69
+ ${clickableContainer ? clickableContainerStyles : ''}
70
+ &:hover ~ .actions-button-group {
71
+ opacity: 1;
72
+ }
73
+ a:focus,
74
+ .has-action:focus {
75
+ outline-offset: -2px;
76
+ }
57
77
  `;
58
78
 
59
79
  const renderChildren = (children, containerSize, containerTheme, status, retry, onClick) => React.Children.map(children, child => {
@@ -70,6 +90,31 @@ const renderChildren = (children, containerSize, containerTheme, status, retry,
70
90
  });
71
91
  }
72
92
  });
93
+
94
+ const getTitleBlockProps = children => {
95
+ const block = React.Children.toArray(children).find(child => isFlexibleUiTitleBlock(child));
96
+
97
+ if ( /*#__PURE__*/React.isValidElement(block)) {
98
+ return block.props;
99
+ }
100
+ };
101
+
102
+ const getLayeredLink = (testId, context, children) => {
103
+ const {
104
+ title,
105
+ url = ''
106
+ } = context || {};
107
+ const {
108
+ anchorTarget: target,
109
+ text
110
+ } = getTitleBlockProps(children) || {};
111
+ return jsx(LayeredLink, {
112
+ target: target,
113
+ testId: testId,
114
+ text: text || title,
115
+ url: url
116
+ });
117
+ };
73
118
  /**
74
119
  * This represents the container in which all Flexible UI Smart Links are rendered.
75
120
  * @see Block
@@ -78,19 +123,23 @@ const renderChildren = (children, containerSize, containerTheme, status, retry,
78
123
 
79
124
  const Container = ({
80
125
  children,
126
+ clickableContainer = false,
81
127
  hideBackground = false,
82
128
  hideElevation = false,
83
129
  hidePadding = false,
130
+ onClick,
84
131
  retry,
85
132
  size = SmartLinkSize.Medium,
86
133
  status,
87
134
  testId = 'smart-links-container',
88
- theme = SmartLinkTheme.Link,
89
- onClick
90
- }) => jsx("div", {
91
- css: getContainerStyles(size, hideBackground, hideElevation, hidePadding),
92
- "data-smart-link-container": true,
93
- "data-testid": testId
94
- }, renderChildren(children, size, theme, status, retry, onClick));
135
+ theme = SmartLinkTheme.Link
136
+ }) => {
137
+ const context = useContext(FlexibleUiContext);
138
+ return jsx("div", {
139
+ css: getContainerStyles(size, hideBackground, hideElevation, hidePadding, clickableContainer),
140
+ "data-smart-link-container": true,
141
+ "data-testid": testId
142
+ }, clickableContainer ? getLayeredLink(testId, context, children) : null, renderChildren(children, size, theme, status, retry, onClick));
143
+ };
95
144
 
96
145
  export default Container;
@@ -0,0 +1,54 @@
1
+ /** @jsx jsx */
2
+ import React from 'react';
3
+ import { jsx, css } from '@emotion/core';
4
+ const styles = css`
5
+ // Stretch the invisible link over the whole of the post.
6
+ // Hide the link’s text.
7
+ top: 0;
8
+ right: 0;
9
+ bottom: 0;
10
+ left: 0;
11
+ overflow-x: hidden;
12
+ text-indent: 100%;
13
+ white-space: nowrap;
14
+
15
+ // Needs a heightened specificity to trump other anchor.
16
+ // Stack it under all other links in the post text.
17
+ a&.layered-link {
18
+ position: absolute;
19
+ z-index: 0;
20
+ }
21
+
22
+ // When hovering over the layered link, any hidden action buttons inside
23
+ // the Container should become visible.
24
+ // As actions resides inside blocks and layered link is expected to be
25
+ // on the same level of blocks. That makes the blocks, e.g. TitleBlock,
26
+ // its sibling. Using general sibling combinator here to apply styling to
27
+ // all the siblings of layered link.
28
+ // The general sibling combinator (~) separates two selectors and matches all
29
+ // iterations of the second element, that are following the first element
30
+ // (though not necessarily immediately), and are children of the same parent
31
+ // element.
32
+ &:hover ~ * {
33
+ .actions-button-group {
34
+ opacity: 1;
35
+ }
36
+ }
37
+ `;
38
+
39
+ const LayeredLink = ({
40
+ target,
41
+ testId,
42
+ text,
43
+ url
44
+ }) => jsx("a", {
45
+ className: "layered-link",
46
+ css: styles,
47
+ "data-testid": `${testId}-layered-link`,
48
+ href: url,
49
+ target: target,
50
+ tabIndex: -1 // Hide tab index and let the title link be the link.
51
+
52
+ }, text);
53
+
54
+ export default LayeredLink;
@@ -48,6 +48,7 @@ const AvatarGroup = ({
48
48
 
49
49
  return jsx("span", {
50
50
  css: [getStyles(size), overrideCss],
51
+ "data-fit-to-content": true,
51
52
  "data-smart-element-avatar-group": true,
52
53
  "data-testid": testId
53
54
  }, jsx(AtlaskitAvatarGroup, {
@@ -1,9 +1,9 @@
1
1
  /** @jsx jsx */
2
- import React from 'react';
2
+ import React, { useMemo } from 'react';
3
3
  import { css, jsx } from '@emotion/core';
4
4
  import Tooltip from '@atlaskit/tooltip';
5
5
  import { SmartLinkSize, SmartLinkTheme } from '../../../../../constants';
6
- import { getLinkLineHeight, getLinkSizeStyles, getTruncateStyles } from '../../utils';
6
+ import { getLinkLineHeight, getLinkSizeStyles, getTruncateStyles, hasWhiteSpace } from '../../utils';
7
7
  import { tokens } from '../../../../../utils/token';
8
8
  const DEFAULT_MAX_LINES = 2;
9
9
  const MAXIMUM_MAX_LINES = 2;
@@ -42,12 +42,12 @@ const getThemeStyles = theme => {
42
42
  }
43
43
  };
44
44
 
45
- const getAnchorStyles = (size, theme, maxLines) => {
45
+ const getAnchorStyles = (size, theme, maxLines, hasSpace) => {
46
46
  const sizeStyles = getLinkSizeStyles(size);
47
47
  return css`
48
48
  flex: 1 1 auto;
49
49
  ${sizeStyles}
50
- ${getTruncateStyles(maxLines, getLinkLineHeight(size))}
50
+ ${getTruncateStyles(maxLines, getLinkLineHeight(size), hasSpace ? 'break-word' : 'break-all')}
51
51
  // Theme should be last to be spread because it contains override values
52
52
  ${getThemeStyles(theme)}
53
53
  `;
@@ -82,19 +82,22 @@ const Link = ({
82
82
  url,
83
83
  onClick,
84
84
  target
85
- }) => jsx("span", {
86
- css: containerStyles
87
- }, jsx(Tooltip, {
88
- content: text,
89
- testId: `${testId}-tooltip`,
90
- tag: "span"
91
- }, jsx("a", {
92
- css: [getAnchorStyles(size, theme, getMaxLines(maxLines)), overrideCss],
93
- "data-smart-element-link": true,
94
- "data-testid": testId,
95
- onClick: onClick,
96
- href: url,
97
- target: target || '_blank'
98
- }, text)));
85
+ }) => {
86
+ const hasSpace = useMemo(() => text ? hasWhiteSpace(text) : false, [text]);
87
+ return jsx("span", {
88
+ css: containerStyles
89
+ }, jsx(Tooltip, {
90
+ content: text,
91
+ testId: `${testId}-tooltip`,
92
+ tag: "span"
93
+ }, jsx("a", {
94
+ css: [getAnchorStyles(size, theme, getMaxLines(maxLines), hasSpace), overrideCss],
95
+ "data-smart-element-link": true,
96
+ "data-testid": testId,
97
+ onClick: onClick,
98
+ href: url,
99
+ target: target || '_blank'
100
+ }, text)));
101
+ };
99
102
 
100
103
  export default Link;
@@ -107,13 +107,16 @@ export const getMaxLines = (value, defaultValue, max, min) => {
107
107
 
108
108
  return value;
109
109
  };
110
- export const getTruncateStyles = (maxLines, lineHeight = '1rem') => css`
110
+ export const getTruncateStyles = (maxLines, lineHeight = '1rem', wordBreak = 'break-word') => css`
111
111
  display: -webkit-box;
112
112
  overflow: hidden;
113
113
  text-overflow: ellipsis;
114
- word-break: break-word;
114
+ word-break: ${wordBreak};
115
115
  -webkit-line-clamp: ${maxLines};
116
116
  -webkit-box-orient: vertical;
117
117
  // Fallback options
118
118
  max-height: calc(${maxLines} * ${lineHeight});
119
- `;
119
+ `;
120
+ export const hasWhiteSpace = str => {
121
+ return str.search(/\s/) >= 0;
122
+ };
@@ -32,9 +32,9 @@ const FlexibleCard = ({
32
32
  }, /*#__PURE__*/React.createElement(Container, _extends({
33
33
  testId: testId
34
34
  }, ui, {
35
+ onClick: onClick,
35
36
  retry: retry,
36
- status: status,
37
- onClick: onClick
37
+ status: status
38
38
  }), children));
39
39
  };
40
40
 
@@ -4,7 +4,7 @@ import { TitleBlock } from '../view/FlexibleCard/components/blocks';
4
4
  import * as Elements from '../view/FlexibleCard/components/elements';
5
5
  export var isFlexibleUiCard = function isFlexibleUiCard(children) {
6
6
  if (children && React.Children.toArray(children).some(function (child) {
7
- return isFlexibleUiBlock(child);
7
+ return isFlexibleUiTitleBlock(child);
8
8
  })) {
9
9
  return true;
10
10
  }
@@ -11,6 +11,7 @@ export var tokens = {
11
11
  elevation: token('elevation.shadow.raised', '0px 1px 1px #091E4240, 0px 0px 1px #091E424F'),
12
12
  errorMessage: token('color.text.disabled', '#6B778C'),
13
13
  errorMessageHover: token('color.text.subtle', '#8993A4'),
14
+ focus: token('color.border.focused', '#388BFF'),
14
15
  snippet: token('color.text', '#172B4D'),
15
16
  text: token('color.text.subtlest', '#626F86')
16
17
  };
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-card",
3
- "version": "18.0.18",
3
+ "version": "18.0.21",
4
4
  "sideEffects": false
5
5
  }
@@ -14,7 +14,8 @@ import { SmartLinkSize } from '../../../../../constants';
14
14
  import Button from '@atlaskit/button/standard-button';
15
15
  import MoreIcon from '@atlaskit/icon/glyph/more';
16
16
  import { sizeToSpacing } from '../../actions/action';
17
- var styles = css(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n display: inline-flex;\n line-height: 1rem;\n"])));
17
+ import { tokens } from '../../../../../utils/token';
18
+ var styles = css(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n display: inline-flex;\n line-height: 1rem;\n > div {\n align-items: center;\n button:focus {\n // AK button removes the default browser outline on focus and apply\n // box-shadow styling to create the outline appearance.\n // Due to our container elements (Container/Block/ElementGroup) has\n // overflow hidden to prevent the metadata element from leaking outside\n // of its container, the box-shadow doesn't show properly.\n // Invert the AK box-shadow styling.\n box-shadow: inset 0 0 0 2px ", ";\n }\n }\n"])), tokens.focus);
18
19
  /**
19
20
  * Creates a group of Action components. Accepts an array of Actions, in addition to some styling
20
21
  * preferences.
@@ -19,7 +19,7 @@ var actionStyles = css(_templateObject || (_templateObject = _taggedTemplateLite
19
19
 
20
20
  var getMessageStyles = function getMessageStyles(size, hasAction) {
21
21
  var sizeStyles = getLinkSizeStyles(size);
22
- return css(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n flex: 1 1 auto;\n justify-content: flex-end;\n ", "\n ", "\n ", "\n color: ", ";\n "])), hasAction ? actionStyles : '', sizeStyles, getTruncateStyles(1, getLinkLineHeight(size)), tokens.errorMessage);
22
+ return css(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n flex: 1 1 auto;\n justify-content: flex-end;\n ", "\n ", "\n ", "\n color: ", ";\n :focus {\n outline: ", " solid 2px;\n }\n "])), hasAction ? actionStyles : '', sizeStyles, getTruncateStyles(1, getLinkLineHeight(size)), tokens.errorMessage, tokens.focus);
23
23
  };
24
24
  /**
25
25
  * Represents an Errored TitleBlock view.
@@ -54,9 +54,11 @@ var TitleBlockErroredView = function TitleBlockErroredView(_ref) {
54
54
  direction: SmartLinkDirection.Horizontal,
55
55
  align: SmartLinkAlignment.Right
56
56
  }, jsx("span", {
57
+ className: hasAction ? 'has-action' : '',
57
58
  css: getMessageStyles(size, hasAction),
58
59
  onClick: onClick,
59
- "data-testid": "".concat(testId, "-errored-view-message")
60
+ "data-testid": "".concat(testId, "-errored-view-message"),
61
+ tabIndex: hasAction ? 0 : -1
60
62
  }, jsx(FormattedMessage, _extends({}, descriptor, {
61
63
  values: values
62
64
  })))), actionGroup);
@@ -17,7 +17,7 @@ import { Title } from '../../elements';
17
17
 
18
18
  var getActionStyles = function getActionStyles(showOnHover, isOpen) {
19
19
  if (showOnHover && !isOpen) {
20
- return css(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n .actions-button-group {\n visibility: hidden;\n }\n\n &:hover {\n .actions-button-group {\n visibility: visible;\n }\n }\n "])));
20
+ return css(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n .actions-button-group {\n opacity: 0;\n }\n\n &:hover .actions-button-group,\n .actions-button-group:focus-within {\n opacity: 1;\n }\n "])));
21
21
  }
22
22
  };
23
23
 
@@ -50,7 +50,7 @@ export var getGapSize = function getGapSize(size) {
50
50
  }
51
51
  };
52
52
  export var getBaseStyles = function getBaseStyles(direction, size) {
53
- return css(_templateObject3 || (_templateObject3 = _taggedTemplateLiteral(["\n display: flex;\n gap: ", "rem;\n line-height: 1rem;\n min-width: 0;\n overflow: hidden;\n overflow-y: hidden;\n ", ";\n &:empty {\n display: none;\n }\n & > * {\n min-width: 0;\n }\n & > [data-fit-to-content] {\n min-width: fit-content;\n }\n"])), getGapSize(size), getDirectionStyles(direction));
53
+ return css(_templateObject3 || (_templateObject3 = _taggedTemplateLiteral(["\n display: flex;\n gap: ", "rem;\n line-height: 1rem;\n min-width: 0;\n overflow: hidden;\n ", ";\n &:empty {\n display: none;\n }\n & > * {\n min-width: 0;\n }\n & > [data-fit-to-content] {\n min-width: fit-content;\n }\n"])), getGapSize(size), getDirectionStyles(direction));
54
54
  };
55
55
 
56
56
  var isActionGroup = function isActionGroup(node) {
@@ -1,13 +1,15 @@
1
1
  import _taggedTemplateLiteral from "@babel/runtime/helpers/taggedTemplateLiteral";
2
2
 
3
- var _templateObject, _templateObject2;
3
+ var _templateObject, _templateObject2, _templateObject3;
4
4
 
5
5
  /** @jsx jsx */
6
- import React from 'react';
6
+ import React, { useContext } from 'react';
7
7
  import { css, jsx } from '@emotion/core';
8
8
  import { SmartLinkSize, SmartLinkTheme } from '../../../../constants';
9
9
  import { isFlexibleUiBlock, isFlexibleUiTitleBlock } from '../../../../utils/flexible';
10
10
  import { tokens } from '../../../../utils/token';
11
+ import { FlexibleUiContext } from '../../../../state/flexible-ui-context';
12
+ import LayeredLink from './layered-link';
11
13
  var elevationStyles = css(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n border: 1px solid transparent;\n border-radius: 1.5px;\n box-shadow: ", ";\n margin: 2px;\n"])), tokens.elevation);
12
14
 
13
15
  var getGap = function getGap(size) {
@@ -44,8 +46,9 @@ var getPadding = function getPadding(size) {
44
46
  }
45
47
  };
46
48
 
47
- export var getContainerStyles = function getContainerStyles(size, hideBackground, hideElevation, hidePadding) {
48
- return css(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n display: flex;\n gap: ", " 0;\n flex-direction: column;\n min-width: 0;\n overflow: hidden;\n ", "\n ", "\n ", "\n"])), getGap(size), hideBackground ? '' : "background-color: ".concat(tokens.background, ";"), hidePadding ? '' : "padding: ".concat(getPadding(size), ";"), hideElevation ? '' : elevationStyles);
49
+ var clickableContainerStyles = css(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n // Position any interactive elements at the top of the z-index stack.\n a,\n button,\n .has-action {\n position: relative;\n z-index: 1;\n }\n"])));
50
+ export var getContainerStyles = function getContainerStyles(size, hideBackground, hideElevation, hidePadding, clickableContainer) {
51
+ return css(_templateObject3 || (_templateObject3 = _taggedTemplateLiteral(["\n display: flex;\n gap: ", " 0;\n flex-direction: column;\n min-width: 0;\n overflow-x: hidden;\n position: relative;\n ", "\n ", "\n ", "\n ", "\n &:hover ~ .actions-button-group {\n opacity: 1;\n }\n a:focus,\n .has-action:focus {\n outline-offset: -2px;\n }\n"])), getGap(size), hideBackground ? '' : "background-color: ".concat(tokens.background, ";"), hidePadding ? '' : "padding: ".concat(getPadding(size), ";"), hideElevation ? '' : elevationStyles, clickableContainer ? clickableContainerStyles : '');
49
52
  };
50
53
 
51
54
  var renderChildren = function renderChildren(children, containerSize, containerTheme, status, retry, onClick) {
@@ -62,34 +65,65 @@ var renderChildren = function renderChildren(children, containerSize, containerT
62
65
  }
63
66
  });
64
67
  };
68
+
69
+ var getTitleBlockProps = function getTitleBlockProps(children) {
70
+ var block = React.Children.toArray(children).find(function (child) {
71
+ return isFlexibleUiTitleBlock(child);
72
+ });
73
+
74
+ if ( /*#__PURE__*/React.isValidElement(block)) {
75
+ return block.props;
76
+ }
77
+ };
78
+
79
+ var getLayeredLink = function getLayeredLink(testId, context, children) {
80
+ var _ref = context || {},
81
+ title = _ref.title,
82
+ _ref$url = _ref.url,
83
+ url = _ref$url === void 0 ? '' : _ref$url;
84
+
85
+ var _ref2 = getTitleBlockProps(children) || {},
86
+ target = _ref2.anchorTarget,
87
+ text = _ref2.text;
88
+
89
+ return jsx(LayeredLink, {
90
+ target: target,
91
+ testId: testId,
92
+ text: text || title,
93
+ url: url
94
+ });
95
+ };
65
96
  /**
66
97
  * This represents the container in which all Flexible UI Smart Links are rendered.
67
98
  * @see Block
68
99
  */
69
100
 
70
101
 
71
- var Container = function Container(_ref) {
72
- var children = _ref.children,
73
- _ref$hideBackground = _ref.hideBackground,
74
- hideBackground = _ref$hideBackground === void 0 ? false : _ref$hideBackground,
75
- _ref$hideElevation = _ref.hideElevation,
76
- hideElevation = _ref$hideElevation === void 0 ? false : _ref$hideElevation,
77
- _ref$hidePadding = _ref.hidePadding,
78
- hidePadding = _ref$hidePadding === void 0 ? false : _ref$hidePadding,
79
- retry = _ref.retry,
80
- _ref$size = _ref.size,
81
- size = _ref$size === void 0 ? SmartLinkSize.Medium : _ref$size,
82
- status = _ref.status,
83
- _ref$testId = _ref.testId,
84
- testId = _ref$testId === void 0 ? 'smart-links-container' : _ref$testId,
85
- _ref$theme = _ref.theme,
86
- theme = _ref$theme === void 0 ? SmartLinkTheme.Link : _ref$theme,
87
- onClick = _ref.onClick;
102
+ var Container = function Container(_ref3) {
103
+ var children = _ref3.children,
104
+ _ref3$clickableContai = _ref3.clickableContainer,
105
+ clickableContainer = _ref3$clickableContai === void 0 ? false : _ref3$clickableContai,
106
+ _ref3$hideBackground = _ref3.hideBackground,
107
+ hideBackground = _ref3$hideBackground === void 0 ? false : _ref3$hideBackground,
108
+ _ref3$hideElevation = _ref3.hideElevation,
109
+ hideElevation = _ref3$hideElevation === void 0 ? false : _ref3$hideElevation,
110
+ _ref3$hidePadding = _ref3.hidePadding,
111
+ hidePadding = _ref3$hidePadding === void 0 ? false : _ref3$hidePadding,
112
+ onClick = _ref3.onClick,
113
+ retry = _ref3.retry,
114
+ _ref3$size = _ref3.size,
115
+ size = _ref3$size === void 0 ? SmartLinkSize.Medium : _ref3$size,
116
+ status = _ref3.status,
117
+ _ref3$testId = _ref3.testId,
118
+ testId = _ref3$testId === void 0 ? 'smart-links-container' : _ref3$testId,
119
+ _ref3$theme = _ref3.theme,
120
+ theme = _ref3$theme === void 0 ? SmartLinkTheme.Link : _ref3$theme;
121
+ var context = useContext(FlexibleUiContext);
88
122
  return jsx("div", {
89
- css: getContainerStyles(size, hideBackground, hideElevation, hidePadding),
123
+ css: getContainerStyles(size, hideBackground, hideElevation, hidePadding, clickableContainer),
90
124
  "data-smart-link-container": true,
91
125
  "data-testid": testId
92
- }, renderChildren(children, size, theme, status, retry, onClick));
126
+ }, clickableContainer ? getLayeredLink(testId, context, children) : null, renderChildren(children, size, theme, status, retry, onClick));
93
127
  };
94
128
 
95
129
  export default Container;
@@ -0,0 +1,26 @@
1
+ import _taggedTemplateLiteral from "@babel/runtime/helpers/taggedTemplateLiteral";
2
+
3
+ var _templateObject;
4
+
5
+ /** @jsx jsx */
6
+ import React from 'react';
7
+ import { jsx, css } from '@emotion/core';
8
+ var styles = css(_templateObject || (_templateObject = _taggedTemplateLiteral(["\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"])));
9
+
10
+ var LayeredLink = function LayeredLink(_ref) {
11
+ var target = _ref.target,
12
+ testId = _ref.testId,
13
+ text = _ref.text,
14
+ url = _ref.url;
15
+ return jsx("a", {
16
+ className: "layered-link",
17
+ css: styles,
18
+ "data-testid": "".concat(testId, "-layered-link"),
19
+ href: url,
20
+ target: target,
21
+ tabIndex: -1 // Hide tab index and let the title link be the link.
22
+
23
+ }, text);
24
+ };
25
+
26
+ export default LayeredLink;
@@ -48,6 +48,7 @@ var AvatarGroup = function AvatarGroup(_ref) {
48
48
 
49
49
  return jsx("span", {
50
50
  css: [getStyles(size), overrideCss],
51
+ "data-fit-to-content": true,
51
52
  "data-smart-element-avatar-group": true,
52
53
  "data-testid": testId
53
54
  }, jsx(AtlaskitAvatarGroup, {
@@ -3,11 +3,11 @@ import _taggedTemplateLiteral from "@babel/runtime/helpers/taggedTemplateLiteral
3
3
  var _templateObject, _templateObject2, _templateObject3, _templateObject4;
4
4
 
5
5
  /** @jsx jsx */
6
- import React from 'react';
6
+ import React, { useMemo } from 'react';
7
7
  import { css, jsx } from '@emotion/core';
8
8
  import Tooltip from '@atlaskit/tooltip';
9
9
  import { SmartLinkSize, SmartLinkTheme } from '../../../../../constants';
10
- import { getLinkLineHeight, getLinkSizeStyles, getTruncateStyles } from '../../utils';
10
+ import { getLinkLineHeight, getLinkSizeStyles, getTruncateStyles, hasWhiteSpace } from '../../utils';
11
11
  import { tokens } from '../../../../../utils/token';
12
12
  var DEFAULT_MAX_LINES = 2;
13
13
  var MAXIMUM_MAX_LINES = 2;
@@ -26,9 +26,9 @@ var getThemeStyles = function getThemeStyles(theme) {
26
26
  }
27
27
  };
28
28
 
29
- var getAnchorStyles = function getAnchorStyles(size, theme, maxLines) {
29
+ var getAnchorStyles = function getAnchorStyles(size, theme, maxLines, hasSpace) {
30
30
  var sizeStyles = getLinkSizeStyles(size);
31
- return css(_templateObject4 || (_templateObject4 = _taggedTemplateLiteral(["\n flex: 1 1 auto;\n ", "\n ", "\n // Theme should be last to be spread because it contains override values\n ", "\n "])), sizeStyles, getTruncateStyles(maxLines, getLinkLineHeight(size)), getThemeStyles(theme));
31
+ return css(_templateObject4 || (_templateObject4 = _taggedTemplateLiteral(["\n flex: 1 1 auto;\n ", "\n ", "\n // Theme should be last to be spread because it contains override values\n ", "\n "])), sizeStyles, getTruncateStyles(maxLines, getLinkLineHeight(size), hasSpace ? 'break-word' : 'break-all'), getThemeStyles(theme));
32
32
  };
33
33
 
34
34
  var getMaxLines = function getMaxLines(maxLines) {
@@ -64,6 +64,9 @@ var Link = function Link(_ref) {
64
64
  url = _ref.url,
65
65
  onClick = _ref.onClick,
66
66
  target = _ref.target;
67
+ var hasSpace = useMemo(function () {
68
+ return text ? hasWhiteSpace(text) : false;
69
+ }, [text]);
67
70
  return jsx("span", {
68
71
  css: containerStyles
69
72
  }, jsx(Tooltip, {
@@ -71,7 +74,7 @@ var Link = function Link(_ref) {
71
74
  testId: "".concat(testId, "-tooltip"),
72
75
  tag: "span"
73
76
  }, jsx("a", {
74
- css: [getAnchorStyles(size, theme, getMaxLines(maxLines)), overrideCss],
77
+ css: [getAnchorStyles(size, theme, getMaxLines(maxLines), hasSpace), overrideCss],
75
78
  "data-smart-element-link": true,
76
79
  "data-testid": testId,
77
80
  onClick: onClick,
@@ -80,5 +80,9 @@ export var getMaxLines = function getMaxLines(value, defaultValue, max, min) {
80
80
  };
81
81
  export var getTruncateStyles = function getTruncateStyles(maxLines) {
82
82
  var lineHeight = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '1rem';
83
- return css(_templateObject6 || (_templateObject6 = _taggedTemplateLiteral(["\n display: -webkit-box;\n overflow: hidden;\n text-overflow: ellipsis;\n word-break: break-word;\n -webkit-line-clamp: ", ";\n -webkit-box-orient: vertical;\n // Fallback options\n max-height: calc(", " * ", ");\n "])), maxLines, maxLines, lineHeight);
83
+ var wordBreak = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'break-word';
84
+ return css(_templateObject6 || (_templateObject6 = _taggedTemplateLiteral(["\n display: -webkit-box;\n overflow: hidden;\n text-overflow: ellipsis;\n word-break: ", ";\n -webkit-line-clamp: ", ";\n -webkit-box-orient: vertical;\n // Fallback options\n max-height: calc(", " * ", ");\n "])), wordBreak, maxLines, maxLines, lineHeight);
85
+ };
86
+ export var hasWhiteSpace = function hasWhiteSpace(str) {
87
+ return str.search(/\s/) >= 0;
84
88
  };
@@ -29,9 +29,9 @@ var FlexibleCard = function FlexibleCard(_ref) {
29
29
  }, /*#__PURE__*/React.createElement(Container, _extends({
30
30
  testId: testId
31
31
  }, ui, {
32
+ onClick: onClick,
32
33
  retry: retry,
33
- status: status,
34
- onClick: onClick
34
+ status: status
35
35
  }), children));
36
36
  };
37
37
 
@@ -10,6 +10,7 @@ export declare const tokens: {
10
10
  elevation: "var(--ds-shadow-raised)";
11
11
  errorMessage: "var(--ds-text-disabled)";
12
12
  errorMessageHover: "var(--ds-text-subtle)";
13
+ focus: "var(--ds-border-focused)";
13
14
  snippet: "var(--ds-text)";
14
15
  text: "var(--ds-text-subtlest)";
15
16
  };
@@ -3,7 +3,7 @@ import React from 'react';
3
3
  import { SerializedStyles } from '@emotion/core';
4
4
  import { SmartLinkSize } from '../../../../constants';
5
5
  import { ContainerProps } from './types';
6
- export declare const getContainerStyles: (size: SmartLinkSize, hideBackground: boolean, hideElevation: boolean, hidePadding: boolean) => SerializedStyles;
6
+ export declare const getContainerStyles: (size: SmartLinkSize, hideBackground: boolean, hideElevation: boolean, hidePadding: boolean, clickableContainer: boolean) => SerializedStyles;
7
7
  /**
8
8
  * This represents the container in which all Flexible UI Smart Links are rendered.
9
9
  * @see Block
@@ -0,0 +1,5 @@
1
+ /** @jsx jsx */
2
+ import React from 'react';
3
+ import { LayeredLinkProps } from './types';
4
+ declare const LayeredLink: React.FC<LayeredLinkProps>;
5
+ export default LayeredLink;
@@ -0,0 +1,6 @@
1
+ export declare type LayeredLinkProps = {
2
+ target?: '_blank' | '_self' | '_top' | '_parent';
3
+ testId?: string;
4
+ text?: string;
5
+ url: string;
6
+ };
@@ -2,6 +2,7 @@
2
2
  import { SmartLinkSize, SmartLinkStatus, SmartLinkTheme } from '../../../../constants';
3
3
  import { RetryOptions } from '../../types';
4
4
  export declare type ContainerProps = {
5
+ clickableContainer?: boolean;
5
6
  hideElevation?: boolean;
6
7
  hidePadding?: boolean;
7
8
  hideBackground?: boolean;
@@ -8,4 +8,5 @@ export declare const getIconWidth: (size?: SmartLinkSize | undefined) => string;
8
8
  export declare const getLinkLineHeight: (size: SmartLinkSize) => string;
9
9
  export declare const getLinkSizeStyles: (size: SmartLinkSize) => SerializedStyles;
10
10
  export declare const getMaxLines: (value: number, defaultValue: number, max: number, min: number) => number;
11
- export declare const getTruncateStyles: (maxLines: number, lineHeight?: string) => SerializedStyles;
11
+ export declare const getTruncateStyles: (maxLines: number, lineHeight?: string, wordBreak?: 'break-word' | 'break-all') => SerializedStyles;
12
+ export declare const hasWhiteSpace: (str: string) => boolean;
@@ -15,6 +15,7 @@ export declare type FlexibleCardProps = {
15
15
  onClick?: React.EventHandler<React.MouseEvent | React.KeyboardEvent>;
16
16
  };
17
17
  export declare type FlexibleUiOptions = {
18
+ clickableContainer?: boolean;
18
19
  hideElevation?: boolean;
19
20
  hidePadding?: boolean;
20
21
  hideBackground?: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-card",
3
- "version": "18.0.18",
3
+ "version": "18.0.21",
4
4
  "description": "Smart card component",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"