@atlaskit/smart-card 23.8.2 → 23.9.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 (62) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/cjs/utils/flexible.js +8 -2
  3. package/dist/cjs/utils/mocks.js +38 -0
  4. package/dist/cjs/version.json +1 -1
  5. package/dist/cjs/view/BlockCard/actions/flexible/AuthorizeAction.js +2 -1
  6. package/dist/cjs/view/BlockCard/actions/flexible/ForbiddenAction.js +2 -1
  7. package/dist/cjs/view/BlockCard/actions/flexible/RetryAction.js +2 -1
  8. package/dist/cjs/view/BlockCard/index.js +24 -0
  9. package/dist/cjs/view/BlockCard/views/flexible/FlexibleResolvedView.js +3 -1
  10. package/dist/cjs/view/CardWithUrl/component.js +1 -6
  11. package/dist/cjs/view/FlexibleCard/components/actions/action/action-button/index.js +1 -6
  12. package/dist/cjs/view/FlexibleCard/components/blocks/action-group/index.js +2 -7
  13. package/dist/cjs/view/FlexibleCard/components/blocks/footer-block/index.js +17 -2
  14. package/dist/cjs/view/FlexibleCard/components/container/index.js +34 -3
  15. package/dist/cjs/view/FlexibleCard/index.js +3 -1
  16. package/dist/cjs/view/HoverCard/components/HoverCardComponent.js +15 -3
  17. package/dist/cjs/view/InlineCard/index.js +7 -0
  18. package/dist/es2019/utils/flexible.js +3 -2
  19. package/dist/es2019/utils/mocks.js +38 -0
  20. package/dist/es2019/version.json +1 -1
  21. package/dist/es2019/view/BlockCard/actions/flexible/AuthorizeAction.js +2 -1
  22. package/dist/es2019/view/BlockCard/actions/flexible/ForbiddenAction.js +2 -1
  23. package/dist/es2019/view/BlockCard/actions/flexible/RetryAction.js +2 -1
  24. package/dist/es2019/view/BlockCard/index.js +24 -0
  25. package/dist/es2019/view/BlockCard/views/flexible/FlexibleResolvedView.js +3 -1
  26. package/dist/es2019/view/CardWithUrl/component.js +1 -6
  27. package/dist/es2019/view/FlexibleCard/components/actions/action/action-button/index.js +1 -6
  28. package/dist/es2019/view/FlexibleCard/components/blocks/action-group/index.js +2 -5
  29. package/dist/es2019/view/FlexibleCard/components/blocks/footer-block/index.js +11 -2
  30. package/dist/es2019/view/FlexibleCard/components/container/index.js +25 -5
  31. package/dist/es2019/view/FlexibleCard/index.js +3 -1
  32. package/dist/es2019/view/HoverCard/components/HoverCardComponent.js +13 -3
  33. package/dist/es2019/view/InlineCard/index.js +6 -0
  34. package/dist/esm/utils/flexible.js +4 -1
  35. package/dist/esm/utils/mocks.js +38 -0
  36. package/dist/esm/version.json +1 -1
  37. package/dist/esm/view/BlockCard/actions/flexible/AuthorizeAction.js +2 -1
  38. package/dist/esm/view/BlockCard/actions/flexible/ForbiddenAction.js +2 -1
  39. package/dist/esm/view/BlockCard/actions/flexible/RetryAction.js +2 -1
  40. package/dist/esm/view/BlockCard/index.js +24 -0
  41. package/dist/esm/view/BlockCard/views/flexible/FlexibleResolvedView.js +3 -1
  42. package/dist/esm/view/CardWithUrl/component.js +1 -6
  43. package/dist/esm/view/FlexibleCard/components/actions/action/action-button/index.js +1 -6
  44. package/dist/esm/view/FlexibleCard/components/blocks/action-group/index.js +2 -7
  45. package/dist/esm/view/FlexibleCard/components/blocks/footer-block/index.js +11 -2
  46. package/dist/esm/view/FlexibleCard/components/container/index.js +34 -5
  47. package/dist/esm/view/FlexibleCard/index.js +3 -1
  48. package/dist/esm/view/HoverCard/components/HoverCardComponent.js +15 -3
  49. package/dist/esm/view/InlineCard/index.js +6 -0
  50. package/dist/types/utils/flexible.d.ts +1 -0
  51. package/dist/types/utils/mocks.d.ts +2 -0
  52. package/dist/types/view/BlockCard/views/flexible/FlexibleResolvedView.d.ts +1 -1
  53. package/dist/types/view/Card/index.d.ts +1 -1
  54. package/dist/types/view/FlexibleCard/components/blocks/action-group/types.d.ts +1 -1
  55. package/dist/types/view/FlexibleCard/components/blocks/footer-block/types.d.ts +5 -0
  56. package/dist/types/view/FlexibleCard/components/container/types.d.ts +5 -0
  57. package/dist/types/view/FlexibleCard/types.d.ts +5 -0
  58. package/dist/types/view/HoverCard/index.d.ts +1 -1
  59. package/dist/types/view/HoverCard/types.d.ts +24 -0
  60. package/package.json +1 -1
  61. package/report.api.md +1 -0
  62. package/tmp/api-report-tmp.d.ts +1 -0
@@ -49,12 +49,6 @@ export function CardWithUrlContent({
49
49
  const subproduct = getSubproduct(state.details);
50
50
  const services = getServices(state.details);
51
51
  let isFlexibleUi = useMemo(() => isFlexibleUiCard(children), [children]);
52
- const showHoverPreviewFlag = useFeatureFlag('showHoverPreview');
53
-
54
- if (showHoverPreview === undefined && showHoverPreviewFlag !== undefined) {
55
- showHoverPreview = Boolean(showHoverPreviewFlag);
56
- }
57
-
58
52
  const showAuthTooltipValue = useFeatureFlag('showAuthTooltip');
59
53
  const showAuthTooltip = !!showAuthTooltipValue && showAuthTooltipValue === 'experiment';
60
54
  const enableFlexibleBlockCardFlag = Boolean(useFeatureFlag('enableFlexibleBlockCard')); // Setup UI handlers.
@@ -140,6 +134,7 @@ export function CardWithUrlContent({
140
134
  onClick: handleClickWrapper,
141
135
  renderers: renderers,
142
136
  ui: ui,
137
+ showHoverPreview: showHoverPreview,
143
138
  url: url,
144
139
  testId: testId,
145
140
  onResolve: onResolve,
@@ -63,14 +63,9 @@ const ActionButton = ({
63
63
  e.preventDefault();
64
64
  handler();
65
65
  }, []);
66
- const onContainerClick = useCallback(e => {
67
- // Stop button on click event from propagate into parent container.
68
- e.stopPropagation();
69
- }, []);
70
66
  return jsx("div", {
71
67
  css: [getButtonStyle(size, iconOnly), overrideCss],
72
- "data-testid": `${testId}-button-wrapper`,
73
- onClick: onContainerClick
68
+ "data-testid": `${testId}-button-wrapper`
74
69
  }, jsx(Tooltip, {
75
70
  content: tooltipMessage,
76
71
  hideTooltipOnClick: true,
@@ -46,9 +46,7 @@ const ActionGroup = ({
46
46
  onDropdownOpenChange,
47
47
  testId
48
48
  }) => {
49
- const [isOpen, setIsOpen] = useState(false); // Stop AK dropdown menu to propagate event on click.
50
-
51
- const onClick = useCallback(e => e.stopPropagation(), []);
49
+ const [isOpen, setIsOpen] = useState(false);
52
50
  const onOpenChange = useCallback(attrs => {
53
51
  setIsOpen(attrs.isOpen);
54
52
 
@@ -74,8 +72,7 @@ const ActionGroup = ({
74
72
  const buttonGroupElement = renderActionItems(buttonActions, size, appearance, false, onActionClick);
75
73
  return jsx("div", {
76
74
  css: styles,
77
- className: "actions-button-group",
78
- onClick: onClick
75
+ className: "actions-button-group"
79
76
  }, jsx(ButtonGroup, null, buttonGroupElement, dropdownItemActions.length > 0 && dropdownMenuElement && dropdownMenuElement.length > 0 ? jsx(DropdownMenu, {
80
77
  isOpen: isOpen,
81
78
  onOpenChange: onOpenChange,
@@ -1,5 +1,5 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
- import React from 'react';
2
+ import React, { useCallback } from 'react';
3
3
  import { css } from '@emotion/react';
4
4
  import { SmartLinkAlignment, SmartLinkDirection, SmartLinkSize, SmartLinkStatus, SmartLinkWidth } from '../../../../../constants';
5
5
  import Block from '../block';
@@ -31,8 +31,16 @@ const FooterBlock = props => {
31
31
  status,
32
32
  actions,
33
33
  size = SmartLinkSize.Medium,
34
- testId = 'smart-footer-block'
34
+ testId = 'smart-footer-block',
35
+ onActionMenuOpenChange
35
36
  } = props;
37
+ const onDropdownOpenChange = useCallback(isOpen => {
38
+ if (onActionMenuOpenChange) {
39
+ onActionMenuOpenChange({
40
+ isOpen
41
+ });
42
+ }
43
+ }, [onActionMenuOpenChange]);
36
44
 
37
45
  if (status !== SmartLinkStatus.Resolved) {
38
46
  return null;
@@ -49,6 +57,7 @@ const FooterBlock = props => {
49
57
  overrideCss: getActionGroupStyles(size),
50
58
  width: SmartLinkWidth.Flexible
51
59
  }, /*#__PURE__*/React.createElement(ActionGroup, {
60
+ onDropdownOpenChange: onDropdownOpenChange,
52
61
  items: actions,
53
62
  appearance: "default"
54
63
  })) : null);
@@ -1,11 +1,12 @@
1
1
  /** @jsx jsx */
2
- import React, { useContext } from 'react';
2
+ import React, { useContext, useState, useCallback } from 'react';
3
3
  import { css, jsx } from '@emotion/react';
4
4
  import { MediaPlacement, SmartLinkSize, SmartLinkTheme } from '../../../../constants';
5
- import { isFlexibleUiBlock, isFlexibleUiPreviewBlock, isFlexibleUiTitleBlock } from '../../../../utils/flexible';
5
+ import { isFlexibleUiBlock, isFlexibleUiPreviewBlock, isFlexibleUiTitleBlock, isFlexibleUiFooterBlock } from '../../../../utils/flexible';
6
6
  import { tokens } from '../../../../utils/token';
7
7
  import { FlexibleUiContext } from '../../../../state/flexible-ui-context';
8
8
  import LayeredLink from './layered-link';
9
+ import { HoverCard } from '../../../HoverCard';
9
10
  import { isFlexUiPreviewPresent } from '../../../../state/flexible-ui-context/utils';
10
11
  const elevationStyles = css`
11
12
  border: 1px solid transparent;
@@ -127,7 +128,7 @@ export const getContainerStyles = (size, hideBackground, hideElevation, hidePadd
127
128
  `;
128
129
  };
129
130
 
130
- const renderChildren = (children, containerSize, containerTheme, status, retry, onClick) => React.Children.map(children, child => {
131
+ const renderChildren = (children, containerSize, containerTheme, status, retry, onClick, onActionMenuOpenChange) => React.Children.map(children, child => {
131
132
  if ( /*#__PURE__*/React.isValidElement(child) && isFlexibleUiBlock(child)) {
132
133
  const {
133
134
  size: blockSize
@@ -142,6 +143,12 @@ const renderChildren = (children, containerSize, containerTheme, status, retry,
142
143
  status,
143
144
  theme: containerTheme
144
145
  });
146
+ } else if (onActionMenuOpenChange && isFlexibleUiFooterBlock(child)) {
147
+ return /*#__PURE__*/React.cloneElement(child, {
148
+ size,
149
+ status,
150
+ onActionMenuOpenChange
151
+ });
145
152
  }
146
153
 
147
154
  return /*#__PURE__*/React.cloneElement(child, {
@@ -192,6 +199,7 @@ const Container = ({
192
199
  hideBackground = false,
193
200
  hideElevation = false,
194
201
  hidePadding = false,
202
+ showHoverPreview = false,
195
203
  onClick,
196
204
  retry,
197
205
  size = SmartLinkSize.Medium,
@@ -201,11 +209,23 @@ const Container = ({
201
209
  }) => {
202
210
  const context = useContext(FlexibleUiContext);
203
211
  const childrenOptions = getChildrenOptions(children, context);
204
- return jsx("div", {
212
+ const [hoverCardCanOpen, setHoverCardCanOpen] = useState(true);
213
+ const onActionMenuOpenChange = useCallback(options => setHoverCardCanOpen(!options.isOpen), []);
214
+ const containerContent = jsx("div", {
205
215
  css: getContainerStyles(size, hideBackground, hideElevation, hidePadding, clickableContainer, childrenOptions),
206
216
  "data-smart-link-container": true,
207
217
  "data-testid": testId
208
- }, clickableContainer ? getLayeredLink(testId, context, children, onClick) : null, renderChildren(children, size, theme, status, retry, onClick));
218
+ }, clickableContainer ? getLayeredLink(testId, context, children, onClick) : null, renderChildren(children, size, theme, status, retry, onClick, showHoverPreview ? onActionMenuOpenChange : undefined));
219
+
220
+ if (showHoverPreview && context !== null && context !== void 0 && context.url) {
221
+ return jsx(HoverCard, {
222
+ url: context === null || context === void 0 ? void 0 : context.url,
223
+ canOpen: hoverCardCanOpen,
224
+ closeOnChildClick: true
225
+ }, containerContent);
226
+ }
227
+
228
+ return containerContent;
209
229
  };
210
230
 
211
231
  export default Container;
@@ -22,7 +22,8 @@ const FlexibleCard = ({
22
22
  url,
23
23
  onClick,
24
24
  testId,
25
- analytics
25
+ analytics,
26
+ showHoverPreview
26
27
  }) => {
27
28
  const {
28
29
  status: cardType,
@@ -68,6 +69,7 @@ const FlexibleCard = ({
68
69
  }, /*#__PURE__*/React.createElement(Container, _extends({
69
70
  testId: testId
70
71
  }, ui, {
72
+ showHoverPreview: showHoverPreview,
71
73
  onClick: onClick,
72
74
  retry: retry,
73
75
  status: status
@@ -14,7 +14,9 @@ export const HoverCardComponent = ({
14
14
  children,
15
15
  url,
16
16
  analyticsHandler,
17
- analytics
17
+ analytics,
18
+ canOpen = true,
19
+ closeOnChildClick = false
18
20
  }) => {
19
21
  const delay = 300;
20
22
  const [isOpen, setIsOpen] = React.useState(false);
@@ -102,9 +104,16 @@ export const HoverCardComponent = ({
102
104
  }
103
105
  }, [hideCard]); // Stop hover preview content to propagate event to parent.
104
106
 
107
+ const onChildClick = useCallback(e => {
108
+ e.stopPropagation();
109
+
110
+ if (closeOnChildClick) {
111
+ hideCard();
112
+ }
113
+ }, [closeOnChildClick, hideCard]);
105
114
  return jsx(Popup, {
106
115
  testId: "hover-card",
107
- isOpen: isOpen,
116
+ isOpen: isOpen && canOpen,
108
117
  onClose: hideCard,
109
118
  placement: "bottom-start",
110
119
  offset: popupOffset.current,
@@ -127,7 +136,8 @@ export const HoverCardComponent = ({
127
136
  }, jsx("span", _extends({}, triggerProps, {
128
137
  onMouseEnter: initShowCard,
129
138
  onMouseLeave: initHideCard,
130
- onMouseMove: setMousePosition
139
+ onMouseMove: setMousePosition,
140
+ onClick: onChildClick
131
141
  }), children)),
132
142
  zIndex: 511 // Temporary fix for Confluence inline comment on editor mod has z-index of 500, Jira issue view has z-index of 510
133
143
 
@@ -10,6 +10,7 @@ import { InlineCardResolvedView } from './ResolvedView';
10
10
  import { InlineCardResolvingView } from './ResolvingView';
11
11
  import { InlineCardUnauthorizedView } from './UnauthorisedView';
12
12
  import { extractProvider } from '@atlaskit/linking-common/extractors';
13
+ import { useFeatureFlag } from '@atlaskit/link-provider';
13
14
  export { InlineCardResolvedView, InlineCardResolvingView, InlineCardErroredView, InlineCardForbiddenView, InlineCardUnauthorizedView };
14
15
  export const InlineCard = ({
15
16
  id,
@@ -34,6 +35,11 @@ export const InlineCard = ({
34
35
  } = cardState;
35
36
  const cardDetails = details && details.data || getEmptyJsonLd();
36
37
  const testIdWithStatus = testId ? `${testId}-${status}-view` : undefined;
38
+ const showHoverPreviewFlag = useFeatureFlag('showHoverPreview');
39
+
40
+ if (showHoverPreview === undefined && showHoverPreviewFlag !== undefined) {
41
+ showHoverPreview = Boolean(showHoverPreviewFlag);
42
+ }
37
43
 
38
44
  switch (status) {
39
45
  case 'pending':
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import * as Blocks from '../view/FlexibleCard/components/blocks';
3
- import { PreviewBlock, TitleBlock } from '../view/FlexibleCard/components/blocks';
3
+ import { PreviewBlock, TitleBlock, FooterBlock } 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) {
@@ -26,4 +26,7 @@ export var isFlexibleUiTitleBlock = function isFlexibleUiTitleBlock(node) {
26
26
  };
27
27
  export var isFlexibleUiPreviewBlock = function isFlexibleUiPreviewBlock(node) {
28
28
  return /*#__PURE__*/React.isValidElement(node) && node.type === PreviewBlock;
29
+ };
30
+ export var isFlexibleUiFooterBlock = function isFlexibleUiFooterBlock(node) {
31
+ return /*#__PURE__*/React.isValidElement(node) && node.type === FooterBlock;
29
32
  };
@@ -119,6 +119,25 @@ export var mocks = {
119
119
  url: 'https://some.url'
120
120
  }
121
121
  },
122
+ forbiddenWithNoAuth: {
123
+ meta: {
124
+ visibility: 'restricted',
125
+ access: 'forbidden',
126
+ auth: [],
127
+ definitionId: 'd1',
128
+ key: 'object-provider'
129
+ },
130
+ data: {
131
+ '@context': {
132
+ '@vocab': 'https://www.w3.org/ns/activitystreams#',
133
+ atlassian: 'https://schema.atlassian.com/ns/vocabulary#',
134
+ schema: 'http://schema.org/'
135
+ },
136
+ '@type': 'Object',
137
+ name: 'I love cheese',
138
+ url: 'https://some.url'
139
+ }
140
+ },
122
141
  unauthorized: {
123
142
  meta: {
124
143
  visibility: 'restricted',
@@ -142,6 +161,25 @@ export var mocks = {
142
161
  url: 'https://some.url'
143
162
  }
144
163
  },
164
+ unauthorizedWithNoAuth: {
165
+ meta: {
166
+ visibility: 'restricted',
167
+ access: 'unauthorized',
168
+ auth: [],
169
+ definitionId: 'd1',
170
+ key: 'object-provider'
171
+ },
172
+ data: {
173
+ '@context': {
174
+ '@vocab': 'https://www.w3.org/ns/activitystreams#',
175
+ atlassian: 'https://schema.atlassian.com/ns/vocabulary#',
176
+ schema: 'http://schema.org/'
177
+ },
178
+ '@type': 'Object',
179
+ name: 'I love cheese',
180
+ url: 'https://some.url'
181
+ }
182
+ },
145
183
  actionSuccess: {
146
184
  meta: {
147
185
  visibility: 'public',
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-card",
3
- "version": "23.8.2",
3
+ "version": "23.9.1",
4
4
  "sideEffects": false
5
5
  }
@@ -19,6 +19,7 @@ export var AuthorizeAction = function AuthorizeAction(onAuthorize, providerName)
19
19
  context: providerName
20
20
  }
21
21
  })) : /*#__PURE__*/React.createElement(FormattedMessage, messages.connect_link_account_card),
22
- onClick: onAuthorize
22
+ onClick: onAuthorize,
23
+ testId: 'smart-action-connect-account'
23
24
  };
24
25
  };
@@ -20,6 +20,7 @@ export var ForbiddenAction = function ForbiddenAction(onClick, content, context)
20
20
  context: context
21
21
  }
22
22
  })),
23
- onClick: onClick
23
+ onClick: onClick,
24
+ testId: 'smart-action-connect-other-account'
24
25
  };
25
26
  };
@@ -13,6 +13,7 @@ export var RetryAction = function RetryAction(onRetry) {
13
13
  return {
14
14
  name: ActionName.CustomAction,
15
15
  onClick: onRetry,
16
- content: /*#__PURE__*/React.createElement(FormattedMessage, messages.try_again)
16
+ content: /*#__PURE__*/React.createElement(FormattedMessage, messages.try_again),
17
+ testId: 'smart-action-try-again'
17
18
  };
18
19
  };
@@ -69,6 +69,7 @@ export var BlockCard = function BlockCard(_ref) {
69
69
  url: url,
70
70
  testId: testId,
71
71
  onError: onError,
72
+ onResolve: onResolve,
72
73
  renderers: renderers,
73
74
  ui: ui,
74
75
  analytics: analytics,
@@ -78,6 +79,12 @@ export var BlockCard = function BlockCard(_ref) {
78
79
  switch (status) {
79
80
  case 'pending':
80
81
  case 'resolving':
82
+ return jsx("div", {
83
+ css: flexibleBlockCardElevationStyle
84
+ }, jsx(FlexibleResolvedView, _extends({}, flexibleProps, {
85
+ testId: 'smart-block-resolving-view'
86
+ })));
87
+
81
88
  case 'resolved':
82
89
  return jsx("div", {
83
90
  css: flexibleBlockCardElevationStyle
@@ -106,6 +113,23 @@ export var BlockCard = function BlockCard(_ref) {
106
113
 
107
114
  case 'fallback':
108
115
  case 'errored':
116
+ default:
117
+ if (onError) {
118
+ onError({
119
+ url: url,
120
+ status: status
121
+ });
122
+ }
123
+
124
+ if (authFlow && authFlow === 'disabled') {
125
+ return jsx(CardLinkView, {
126
+ link: url,
127
+ isSelected: isSelected,
128
+ onClick: handleFrameClick,
129
+ testId: "".concat(testId, "-").concat(status)
130
+ });
131
+ }
132
+
109
133
  return jsx("div", {
110
134
  css: flexibleBlockCardElevationStyle
111
135
  }, jsx(FlexibleErroredView, _extends({}, flexibleProps, {
@@ -16,6 +16,7 @@ var FlexibleResolvedView = function FlexibleResolvedView(_ref) {
16
16
  cardState = _ref.cardState,
17
17
  onClick = _ref.onClick,
18
18
  onError = _ref.onError,
19
+ onResolve = _ref.onResolve,
19
20
  _ref$testId = _ref.testId,
20
21
  testId = _ref$testId === void 0 ? 'smart-block-resolved-view' : _ref$testId,
21
22
  ui = _ref.ui,
@@ -42,6 +43,7 @@ var FlexibleResolvedView = function FlexibleResolvedView(_ref) {
42
43
  cardState: cardState,
43
44
  onClick: onClick,
44
45
  onError: onError,
46
+ onResolve: onResolve,
45
47
  testId: testId,
46
48
  ui: ui,
47
49
  url: url
@@ -77,7 +79,7 @@ var FlexibleResolvedView = function FlexibleResolvedView(_ref) {
77
79
  name: ElementName.DueOn
78
80
  }],
79
81
  maxLines: 1
80
- }), /*#__PURE__*/React.createElement(MetadataBlock, null), /*#__PURE__*/React.createElement(SnippetBlock, null), !isPreviewBlockErrored ? /*#__PURE__*/React.createElement(PreviewBlock, {
82
+ }), /*#__PURE__*/React.createElement(SnippetBlock, null), !isPreviewBlockErrored ? /*#__PURE__*/React.createElement(PreviewBlock, {
81
83
  placement: MediaPlacement.Right,
82
84
  ignoreContainerPadding: true,
83
85
  onError: function onError() {
@@ -51,12 +51,6 @@ export function CardWithUrlContent(_ref) {
51
51
  var isFlexibleUi = useMemo(function () {
52
52
  return isFlexibleUiCard(children);
53
53
  }, [children]);
54
- var showHoverPreviewFlag = useFeatureFlag('showHoverPreview');
55
-
56
- if (showHoverPreview === undefined && showHoverPreviewFlag !== undefined) {
57
- showHoverPreview = Boolean(showHoverPreviewFlag);
58
- }
59
-
60
54
  var showAuthTooltipValue = useFeatureFlag('showAuthTooltip');
61
55
  var showAuthTooltip = !!showAuthTooltipValue && showAuthTooltipValue === 'experiment';
62
56
  var enableFlexibleBlockCardFlag = Boolean(useFeatureFlag('enableFlexibleBlockCard')); // Setup UI handlers.
@@ -146,6 +140,7 @@ export function CardWithUrlContent(_ref) {
146
140
  onClick: handleClickWrapper,
147
141
  renderers: renderers,
148
142
  ui: ui,
143
+ showHoverPreview: showHoverPreview,
149
144
  url: url,
150
145
  testId: testId,
151
146
  onResolve: onResolve,
@@ -42,14 +42,9 @@ var ActionButton = function ActionButton(_ref) {
42
42
  handler();
43
43
  };
44
44
  }, []);
45
- var onContainerClick = useCallback(function (e) {
46
- // Stop button on click event from propagate into parent container.
47
- e.stopPropagation();
48
- }, []);
49
45
  return jsx("div", {
50
46
  css: [getButtonStyle(size, iconOnly), overrideCss],
51
- "data-testid": "".concat(testId, "-button-wrapper"),
52
- onClick: onContainerClick
47
+ "data-testid": "".concat(testId, "-button-wrapper")
53
48
  }, jsx(Tooltip, {
54
49
  content: tooltipMessage,
55
50
  hideTooltipOnClick: true,
@@ -43,12 +43,8 @@ var ActionGroup = function ActionGroup(_ref) {
43
43
  var _useState = useState(false),
44
44
  _useState2 = _slicedToArray(_useState, 2),
45
45
  isOpen = _useState2[0],
46
- setIsOpen = _useState2[1]; // Stop AK dropdown menu to propagate event on click.
46
+ setIsOpen = _useState2[1];
47
47
 
48
-
49
- var onClick = useCallback(function (e) {
50
- return e.stopPropagation();
51
- }, []);
52
48
  var onOpenChange = useCallback(function (attrs) {
53
49
  setIsOpen(attrs.isOpen);
54
50
 
@@ -81,8 +77,7 @@ var ActionGroup = function ActionGroup(_ref) {
81
77
  var buttonGroupElement = renderActionItems(buttonActions, size, appearance, false, onActionClick);
82
78
  return jsx("div", {
83
79
  css: styles,
84
- className: "actions-button-group",
85
- onClick: onClick
80
+ className: "actions-button-group"
86
81
  }, jsx(ButtonGroup, null, buttonGroupElement, dropdownItemActions.length > 0 && dropdownMenuElement && dropdownMenuElement.length > 0 ? jsx(DropdownMenu, {
87
82
  isOpen: isOpen,
88
83
  onOpenChange: onOpenChange,
@@ -3,7 +3,7 @@ import _taggedTemplateLiteral from "@babel/runtime/helpers/taggedTemplateLiteral
3
3
 
4
4
  var _templateObject;
5
5
 
6
- import React from 'react';
6
+ import React, { useCallback } from 'react';
7
7
  import { css } from '@emotion/react';
8
8
  import { SmartLinkAlignment, SmartLinkDirection, SmartLinkSize, SmartLinkStatus, SmartLinkWidth } from '../../../../../constants';
9
9
  import Block from '../block';
@@ -34,7 +34,15 @@ var FooterBlock = function FooterBlock(props) {
34
34
  _props$size = props.size,
35
35
  size = _props$size === void 0 ? SmartLinkSize.Medium : _props$size,
36
36
  _props$testId = props.testId,
37
- testId = _props$testId === void 0 ? 'smart-footer-block' : _props$testId;
37
+ testId = _props$testId === void 0 ? 'smart-footer-block' : _props$testId,
38
+ onActionMenuOpenChange = props.onActionMenuOpenChange;
39
+ var onDropdownOpenChange = useCallback(function (isOpen) {
40
+ if (onActionMenuOpenChange) {
41
+ onActionMenuOpenChange({
42
+ isOpen: isOpen
43
+ });
44
+ }
45
+ }, [onActionMenuOpenChange]);
38
46
 
39
47
  if (status !== SmartLinkStatus.Resolved) {
40
48
  return null;
@@ -51,6 +59,7 @@ var FooterBlock = function FooterBlock(props) {
51
59
  overrideCss: getActionGroupStyles(size),
52
60
  width: SmartLinkWidth.Flexible
53
61
  }, /*#__PURE__*/React.createElement(ActionGroup, {
62
+ onDropdownOpenChange: onDropdownOpenChange,
54
63
  items: actions,
55
64
  appearance: "default"
56
65
  })) : null);
@@ -1,15 +1,17 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
1
2
  import _taggedTemplateLiteral from "@babel/runtime/helpers/taggedTemplateLiteral";
2
3
 
3
4
  var _templateObject, _templateObject2, _templateObject3, _templateObject4;
4
5
 
5
6
  /** @jsx jsx */
6
- import React, { useContext } from 'react';
7
+ import React, { useContext, useState, useCallback } from 'react';
7
8
  import { css, jsx } from '@emotion/react';
8
9
  import { MediaPlacement, SmartLinkSize, SmartLinkTheme } from '../../../../constants';
9
- import { isFlexibleUiBlock, isFlexibleUiPreviewBlock, isFlexibleUiTitleBlock } from '../../../../utils/flexible';
10
+ import { isFlexibleUiBlock, isFlexibleUiPreviewBlock, isFlexibleUiTitleBlock, isFlexibleUiFooterBlock } from '../../../../utils/flexible';
10
11
  import { tokens } from '../../../../utils/token';
11
12
  import { FlexibleUiContext } from '../../../../state/flexible-ui-context';
12
13
  import LayeredLink from './layered-link';
14
+ import { HoverCard } from '../../../HoverCard';
13
15
  import { isFlexUiPreviewPresent } from '../../../../state/flexible-ui-context/utils';
14
16
  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);
15
17
 
@@ -86,7 +88,7 @@ export var getContainerStyles = function getContainerStyles(size, hideBackground
86
88
  return css(_templateObject4 || (_templateObject4 = _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, ";"), paddingCss, hideElevation ? '' : elevationStyles, clickableContainer ? clickableContainerStyles : '');
87
89
  };
88
90
 
89
- var renderChildren = function renderChildren(children, containerSize, containerTheme, status, retry, onClick) {
91
+ var renderChildren = function renderChildren(children, containerSize, containerTheme, status, retry, onClick, onActionMenuOpenChange) {
90
92
  return React.Children.map(children, function (child) {
91
93
  if ( /*#__PURE__*/React.isValidElement(child) && isFlexibleUiBlock(child)) {
92
94
  var blockSize = child.props.size;
@@ -100,6 +102,12 @@ var renderChildren = function renderChildren(children, containerSize, containerT
100
102
  status: status,
101
103
  theme: containerTheme
102
104
  });
105
+ } else if (onActionMenuOpenChange && isFlexibleUiFooterBlock(child)) {
106
+ return /*#__PURE__*/React.cloneElement(child, {
107
+ size: size,
108
+ status: status,
109
+ onActionMenuOpenChange: onActionMenuOpenChange
110
+ });
103
111
  }
104
112
 
105
113
  return /*#__PURE__*/React.cloneElement(child, {
@@ -158,6 +166,8 @@ var Container = function Container(_ref3) {
158
166
  hideElevation = _ref3$hideElevation === void 0 ? false : _ref3$hideElevation,
159
167
  _ref3$hidePadding = _ref3.hidePadding,
160
168
  hidePadding = _ref3$hidePadding === void 0 ? false : _ref3$hidePadding,
169
+ _ref3$showHoverPrevie = _ref3.showHoverPreview,
170
+ showHoverPreview = _ref3$showHoverPrevie === void 0 ? false : _ref3$showHoverPrevie,
161
171
  onClick = _ref3.onClick,
162
172
  retry = _ref3.retry,
163
173
  _ref3$size = _ref3.size,
@@ -169,11 +179,30 @@ var Container = function Container(_ref3) {
169
179
  theme = _ref3$theme === void 0 ? SmartLinkTheme.Link : _ref3$theme;
170
180
  var context = useContext(FlexibleUiContext);
171
181
  var childrenOptions = getChildrenOptions(children, context);
172
- return jsx("div", {
182
+
183
+ var _useState = useState(true),
184
+ _useState2 = _slicedToArray(_useState, 2),
185
+ hoverCardCanOpen = _useState2[0],
186
+ setHoverCardCanOpen = _useState2[1];
187
+
188
+ var onActionMenuOpenChange = useCallback(function (options) {
189
+ return setHoverCardCanOpen(!options.isOpen);
190
+ }, []);
191
+ var containerContent = jsx("div", {
173
192
  css: getContainerStyles(size, hideBackground, hideElevation, hidePadding, clickableContainer, childrenOptions),
174
193
  "data-smart-link-container": true,
175
194
  "data-testid": testId
176
- }, clickableContainer ? getLayeredLink(testId, context, children, onClick) : null, renderChildren(children, size, theme, status, retry, onClick));
195
+ }, clickableContainer ? getLayeredLink(testId, context, children, onClick) : null, renderChildren(children, size, theme, status, retry, onClick, showHoverPreview ? onActionMenuOpenChange : undefined));
196
+
197
+ if (showHoverPreview && context !== null && context !== void 0 && context.url) {
198
+ return jsx(HoverCard, {
199
+ url: context === null || context === void 0 ? void 0 : context.url,
200
+ canOpen: hoverCardCanOpen,
201
+ closeOnChildClick: true
202
+ }, containerContent);
203
+ }
204
+
205
+ return containerContent;
177
206
  };
178
207
 
179
208
  export default Container;
@@ -22,7 +22,8 @@ var FlexibleCard = function FlexibleCard(_ref) {
22
22
  url = _ref.url,
23
23
  onClick = _ref.onClick,
24
24
  testId = _ref.testId,
25
- analytics = _ref.analytics;
25
+ analytics = _ref.analytics,
26
+ showHoverPreview = _ref.showHoverPreview;
26
27
  var cardType = cardState.status,
27
28
  details = cardState.details;
28
29
  var status = cardType;
@@ -66,6 +67,7 @@ var FlexibleCard = function FlexibleCard(_ref) {
66
67
  }, /*#__PURE__*/React.createElement(Container, _extends({
67
68
  testId: testId
68
69
  }, ui, {
70
+ showHoverPreview: showHoverPreview,
69
71
  onClick: onClick,
70
72
  retry: retry,
71
73
  status: status
@@ -15,7 +15,11 @@ export var HoverCardComponent = function HoverCardComponent(_ref) {
15
15
  var children = _ref.children,
16
16
  url = _ref.url,
17
17
  analyticsHandler = _ref.analyticsHandler,
18
- analytics = _ref.analytics;
18
+ analytics = _ref.analytics,
19
+ _ref$canOpen = _ref.canOpen,
20
+ canOpen = _ref$canOpen === void 0 ? true : _ref$canOpen,
21
+ _ref$closeOnChildClic = _ref.closeOnChildClick,
22
+ closeOnChildClick = _ref$closeOnChildClic === void 0 ? false : _ref$closeOnChildClic;
19
23
  var delay = 300;
20
24
 
21
25
  var _React$useState = React.useState(false),
@@ -109,9 +113,16 @@ export var HoverCardComponent = function HoverCardComponent(_ref) {
109
113
  }
110
114
  }, [hideCard]); // Stop hover preview content to propagate event to parent.
111
115
 
116
+ var onChildClick = useCallback(function (e) {
117
+ e.stopPropagation();
118
+
119
+ if (closeOnChildClick) {
120
+ hideCard();
121
+ }
122
+ }, [closeOnChildClick, hideCard]);
112
123
  return jsx(Popup, {
113
124
  testId: "hover-card",
114
- isOpen: isOpen,
125
+ isOpen: isOpen && canOpen,
115
126
  onClose: hideCard,
116
127
  placement: "bottom-start",
117
128
  offset: popupOffset.current,
@@ -136,7 +147,8 @@ export var HoverCardComponent = function HoverCardComponent(_ref) {
136
147
  }, jsx("span", _extends({}, triggerProps, {
137
148
  onMouseEnter: initShowCard,
138
149
  onMouseLeave: initHideCard,
139
- onMouseMove: setMousePosition
150
+ onMouseMove: setMousePosition,
151
+ onClick: onChildClick
140
152
  }), children));
141
153
  },
142
154
  zIndex: 511 // Temporary fix for Confluence inline comment on editor mod has z-index of 500, Jira issue view has z-index of 510