@atlaskit/smart-card 45.21.0 → 45.21.3

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 (44) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/cjs/extractors/action/extract-invoke-view-action.js +2 -8
  3. package/dist/cjs/extractors/flexible/actions/index.js +2 -3
  4. package/dist/cjs/extractors/flexible/extract-state.js +3 -4
  5. package/dist/cjs/extractors/flexible/index.js +3 -4
  6. package/dist/cjs/state/hooks/use-destination-url/index.js +6 -11
  7. package/dist/cjs/state/hooks/use-smart-link-cross-product-url-wrapper/index.js +49 -10
  8. package/dist/cjs/state/hooks-external/useSmartLinkActions.js +5 -6
  9. package/dist/cjs/utils/analytics/analytics.js +1 -1
  10. package/dist/cjs/view/CardWithUrl/component.js +62 -111
  11. package/dist/cjs/view/FlexibleCard/index.js +2 -3
  12. package/dist/cjs/view/HoverCard/components/HoverCardContent.js +16 -23
  13. package/dist/cjs/view/LinkUrl/index.js +1 -1
  14. package/dist/es2019/extractors/action/extract-invoke-view-action.js +3 -7
  15. package/dist/es2019/extractors/flexible/actions/index.js +1 -3
  16. package/dist/es2019/extractors/flexible/extract-state.js +2 -4
  17. package/dist/es2019/extractors/flexible/index.js +2 -4
  18. package/dist/es2019/state/hooks/use-destination-url/index.js +4 -7
  19. package/dist/es2019/state/hooks/use-smart-link-cross-product-url-wrapper/index.js +47 -5
  20. package/dist/es2019/state/hooks-external/useSmartLinkActions.js +5 -7
  21. package/dist/es2019/utils/analytics/analytics.js +1 -1
  22. package/dist/es2019/view/CardWithUrl/component.js +64 -113
  23. package/dist/es2019/view/FlexibleCard/index.js +3 -4
  24. package/dist/es2019/view/HoverCard/components/HoverCardContent.js +16 -20
  25. package/dist/es2019/view/LinkUrl/index.js +1 -1
  26. package/dist/esm/extractors/action/extract-invoke-view-action.js +2 -8
  27. package/dist/esm/extractors/flexible/actions/index.js +2 -3
  28. package/dist/esm/extractors/flexible/extract-state.js +3 -4
  29. package/dist/esm/extractors/flexible/index.js +3 -4
  30. package/dist/esm/state/hooks/use-destination-url/index.js +4 -9
  31. package/dist/esm/state/hooks/use-smart-link-cross-product-url-wrapper/index.js +47 -9
  32. package/dist/esm/state/hooks-external/useSmartLinkActions.js +6 -7
  33. package/dist/esm/utils/analytics/analytics.js +1 -1
  34. package/dist/esm/view/CardWithUrl/component.js +63 -112
  35. package/dist/esm/view/FlexibleCard/index.js +3 -4
  36. package/dist/esm/view/HoverCard/components/HoverCardContent.js +17 -24
  37. package/dist/esm/view/LinkUrl/index.js +1 -1
  38. package/dist/types/state/hooks/use-destination-url/index.d.ts +18 -1
  39. package/dist/types/state/hooks/use-smart-link-cross-product-url-wrapper/index.d.ts +5 -2
  40. package/package.json +3 -5
  41. package/dist/cjs/state/hooks/use-smart-link-cross-product-url-wrapper/useSmartLinkCrossProductUrlWrapper.js +0 -54
  42. package/dist/es2019/state/hooks/use-smart-link-cross-product-url-wrapper/useSmartLinkCrossProductUrlWrapper.js +0 -47
  43. package/dist/esm/state/hooks/use-smart-link-cross-product-url-wrapper/useSmartLinkCrossProductUrlWrapper.js +0 -47
  44. package/dist/types/state/hooks/use-smart-link-cross-product-url-wrapper/useSmartLinkCrossProductUrlWrapper.d.ts +0 -5
@@ -1,5 +1,4 @@
1
1
  import { extractLink } from '@atlaskit/link-extractors/extract-link';
2
- import { fg } from '@atlaskit/platform-feature-flags/fg';
3
2
  import { CardAction } from '../../constants';
4
3
  import { getDefinitionId } from '../../state/getDefinitionId';
5
4
  import { getExtensionKey } from '../../state/getExtensionKey';
@@ -26,12 +25,9 @@ export const extractInvokeViewAction = ({
26
25
  if (url && (viewActionExists || force)) {
27
26
  return {
28
27
  actionFn: async () => {
29
- if (fg('platform_smartlink_xpc_url_wrapping')) {
30
- var _transformUrl;
31
- const destinationUrl = (_transformUrl = transformUrl === null || transformUrl === void 0 ? void 0 : transformUrl(url)) !== null && _transformUrl !== void 0 ? _transformUrl : url;
32
- return openUrl(destinationUrl);
33
- }
34
- return openUrl(url);
28
+ var _transformUrl;
29
+ const destinationUrl = (_transformUrl = transformUrl === null || transformUrl === void 0 ? void 0 : transformUrl(url)) !== null && _transformUrl !== void 0 ? _transformUrl : url;
30
+ return openUrl(destinationUrl);
35
31
  },
36
32
  actionSubjectId: 'shortcutGoToLink',
37
33
  actionType: 'ViewAction',
@@ -50,9 +50,7 @@ export const extractFlexibleCardActions = ({
50
50
  isPreviewRestricted
51
51
  } : undefined),
52
52
  openPreviewPanel,
53
- ...(fg('platform_smartlink_xpc_url_wrapping') ? {
54
- transformUrl
55
- } : undefined)
53
+ transformUrl
56
54
  }),
57
55
  [ActionName.AutomationAction]: extractAutomationAction(response),
58
56
  [InternalActionName.AISummaryAction]: extractAISummaryAction(response, url, actionOptions, aiSummaryConfig),
@@ -49,9 +49,7 @@ const extractAction = (response, id, actionOptions, appearance, origin, fireEven
49
49
  isPreviewRestricted
50
50
  } : undefined),
51
51
  openPreviewPanel,
52
- ...(fg('platform_smartlink_xpc_url_wrapping') ? {
53
- transformUrl
54
- } : undefined)
52
+ transformUrl
55
53
  })) === null || _extractInvokePreview === void 0 ? void 0 : _extractInvokePreview.invokeAction : undefined;
56
54
  const details = {
57
55
  id,
@@ -75,7 +73,7 @@ const extractState = (response, actionOptions, id, appearance, origin, fireEvent
75
73
  if (!canShowAction(CardAction.ChangeStatusAction, actionOptions)) {
76
74
  return lozenge;
77
75
  }
78
- const action = extractAction(response, id, actionOptions, appearance, origin, fireEvent, resolve, isPreviewPanelAvailable, openPreviewPanel, fg('platform_smartlink_xpc_url_wrapping') ? transformUrl : undefined, fg('preview_panel_unit_check') ? isPreviewRestricted : undefined);
76
+ const action = extractAction(response, id, actionOptions, appearance, origin, fireEvent, resolve, isPreviewPanelAvailable, openPreviewPanel, transformUrl, fg('preview_panel_unit_check') ? isPreviewRestricted : undefined);
79
77
  return {
80
78
  ...lozenge,
81
79
  action
@@ -89,9 +89,7 @@ const extractFlexibleUiContext = ({
89
89
  isPreviewRestricted
90
90
  } : undefined),
91
91
  openPreviewPanel,
92
- ...(fg('platform_smartlink_xpc_url_wrapping') ? {
93
- transformUrl
94
- } : undefined)
92
+ transformUrl
95
93
  }),
96
94
  appliedToComponentsCount: extractAppliedToComponentsCount(data),
97
95
  assignedToGroup: extractPersonAssignedToAsArray(data),
@@ -124,7 +122,7 @@ const extractFlexibleUiContext = ({
124
122
  snippet: extractSmartLinkSummary(response) || undefined,
125
123
  // Explicitly set here to remove an empty string
126
124
  sourceBranch: extractSourceBranch(data),
127
- state: extractState(response, actionOptions, id, appearance, origin, fireEvent, resolve, isPreviewPanelAvailable, openPreviewPanel, fg('platform_smartlink_xpc_url_wrapping') ? transformUrl : undefined, fg('preview_panel_unit_check') ? isPreviewRestricted : undefined),
125
+ state: extractState(response, actionOptions, id, appearance, origin, fireEvent, resolve, isPreviewPanelAvailable, openPreviewPanel, transformUrl, fg('preview_panel_unit_check') ? isPreviewRestricted : undefined),
128
126
  subscriberCount: extractSubscriberCount(data),
129
127
  subTasksProgress: extractSubTasksProgress(data),
130
128
  storyPoints: extractStoryPoints(data),
@@ -1,11 +1,10 @@
1
- import { functionWithFG } from '@atlaskit/platform-feature-flags-react/function-with-fg';
2
- import { getClickUrl } from '../../getClickUrl';
1
+ import { getClickUrl } from '../../helpers';
3
2
  import { useSmartCardState } from '../../store';
4
- import { useSmartLinkCrossProductUrlWrapper } from '../use-smart-link-cross-product-url-wrapper/useSmartLinkCrossProductUrlWrapper';
3
+ import { useSmartLinkCrossProductUrlWrapper } from '../use-smart-link-cross-product-url-wrapper';
5
4
 
6
5
  /**
7
6
  * Returns the resolved destination URL for a Smart Link, with cross-product analytics
8
- * parameters appended when the `platform_smartlink_xpc_url_wrapping` feature gate is enabled.
7
+ * parameters appended when applicable.
9
8
  *
10
9
  * This is the same URL that SmartCard would navigate to when clicked. Use this as an `href`
11
10
  * wherever you render a link to a Smart Link URL outside of the SmartCard component itself
@@ -13,7 +12,6 @@ import { useSmartLinkCrossProductUrlWrapper } from '../use-smart-link-cross-prod
13
12
  *
14
13
  * Falls back to the raw `url` when:
15
14
  * - The link has not yet resolved
16
- * - The feature gate is disabled
17
15
  * - The link is not a first-party Atlassian link
18
16
  *
19
17
  * @example
@@ -21,7 +19,7 @@ import { useSmartLinkCrossProductUrlWrapper } from '../use-smart-link-cross-prod
21
19
  *
22
20
  * Use as <a href={href} target="_blank">Open link</a>
23
21
  */
24
- const useDestinationUrlImplementation = url => {
22
+ const useDestinationUrl = url => {
25
23
  const state = useSmartCardState(url);
26
24
  const appendCrossProductAnalyticsParams = useSmartLinkCrossProductUrlWrapper({
27
25
  details: state.details
@@ -29,7 +27,6 @@ const useDestinationUrlImplementation = url => {
29
27
  const resolvedUrl = getClickUrl(url, state.details);
30
28
  return appendCrossProductAnalyticsParams(resolvedUrl);
31
29
  };
32
- export const useDestinationUrl = functionWithFG('platform_smartlink_xpc_url_wrapping', useDestinationUrlImplementation, url => url);
33
30
 
34
31
  // Public API aliases preserved from an eliminated entry-point (volt-migrate-package).
35
32
  export { useDestinationUrl as useSmartLinkDestinationUrl };
@@ -1,5 +1,47 @@
1
- import { functionWithFG } from '@atlaskit/platform-feature-flags-react/function-with-fg';
2
- import { useSmartLinkCrossProductUrlWrapper } from './useSmartLinkCrossProductUrlWrapper';
3
- const identityUrlWrapper = url => url;
4
- const useSmartLinkCrossProductUrlWrapperFallback = _args => identityUrlWrapper;
5
- export const useSmartLinkCrossProductUrlWrapperGated = functionWithFG('platform_smartlink_xpc_url_wrapping', useSmartLinkCrossProductUrlWrapper, useSmartLinkCrossProductUrlWrapperFallback);
1
+ import { useCallback } from 'react';
2
+ import { useCrossProductUrlWrapper } from '@atlaskit/analytics-cross-product/useCrossProductUrlWrapper';
3
+ import { useSmartLinkContext } from '@atlaskit/link-provider';
4
+ import { XPC_CONSTANTS } from './constants';
5
+ import { getIsFirstPartyLink } from './getIsFirstPartyLink';
6
+ export const useSmartLinkCrossProductUrlWrapper = ({
7
+ details
8
+ }) => {
9
+ var _effectiveProduct$toL;
10
+ const {
11
+ product,
12
+ bridgeProduct,
13
+ xpcProduct,
14
+ xpcSubProduct
15
+ } = useSmartLinkContext();
16
+ // xpcProduct takes precedence over product — it identifies the host product for XPC analytics
17
+ // without affecting link resolution (which uses the `product` prop separately).
18
+ const effectiveProduct = xpcProduct !== null && xpcProduct !== void 0 ? xpcProduct : product;
19
+ const effectiveBridge = bridgeProduct !== null && bridgeProduct !== void 0 ? bridgeProduct : XPC_CONSTANTS.SMART_LINKS_XPC_BRIDGE;
20
+ const effectiveProductForWrapper = (_effectiveProduct$toL = effectiveProduct === null || effectiveProduct === void 0 ? void 0 : effectiveProduct.toLowerCase()) !== null && _effectiveProduct$toL !== void 0 ? _effectiveProduct$toL : 'unknown';
21
+ const wrapUrl = useCrossProductUrlWrapper({
22
+ bridge: effectiveBridge,
23
+ product: effectiveProductForWrapper,
24
+ ...(xpcSubProduct ? {
25
+ subProduct: xpcSubProduct
26
+ } : {})
27
+ });
28
+ return useCallback(url => {
29
+ if (typeof window === 'undefined' || !getIsFirstPartyLink(details) || !effectiveProduct) {
30
+ return url;
31
+ }
32
+ let parsedUrl;
33
+ try {
34
+ parsedUrl = new URL(url);
35
+ } catch {
36
+ return url;
37
+ }
38
+ if (parsedUrl.searchParams.has(XPC_CONSTANTS.QUERY_PARAM)) {
39
+ return url;
40
+ }
41
+ return wrapUrl(url);
42
+ },
43
+ // Keep bridge/subproduct in the dependency array so consumers that memoize this callback
44
+ // refresh when mini-modal context updates from smartLinks to rovo-chat.
45
+ // eslint-disable-next-line react-hooks/exhaustive-deps
46
+ [details, effectiveBridge, effectiveProduct, wrapUrl, xpcSubProduct]);
47
+ };
@@ -13,7 +13,7 @@ import { messages } from '../../messages';
13
13
  import { toAction } from '../../utils/actions/to-action';
14
14
  import useInvokeClientAction from '../hooks/use-invoke-client-action';
15
15
  import useResolve from '../hooks/use-resolve';
16
- import { useSmartLinkCrossProductUrlWrapperGated } from '../hooks/use-smart-link-cross-product-url-wrapper';
16
+ import { useSmartLinkCrossProductUrlWrapper } from '../hooks/use-smart-link-cross-product-url-wrapper';
17
17
  import { useSmartCardState as useLinkState } from '../store';
18
18
  export function useSmartLinkActions({
19
19
  url,
@@ -37,7 +37,7 @@ export function useSmartLinkActions({
37
37
  fireEvent
38
38
  });
39
39
  const resolve = useResolve();
40
- const appendCrossProductAnalyticsParams = useSmartLinkCrossProductUrlWrapperGated({
40
+ const appendCrossProductAnalyticsParams = useSmartLinkCrossProductUrlWrapper({
41
41
  details: linkState.details
42
42
  });
43
43
  if (expValEquals('platform_hover_card_preview_panel', 'cohort', 'test') && prefetch && !linkState.details) {
@@ -57,10 +57,10 @@ export function useSmartLinkActions({
57
57
  if (downloadActionProps) {
58
58
  actions.push(toAction(downloadActionProps, invokeClientAction, messages.download, 'download-content'));
59
59
  }
60
- const viewActionProps = fg('platform_smartlink_xpc_url_wrapping') ? extractInvokeViewAction({
60
+ const viewActionProps = extractInvokeViewAction({
61
61
  ...invokeParam,
62
62
  transformUrl: (destinationUrl = url) => appendCrossProductAnalyticsParams(destinationUrl)
63
- }) : extractInvokeViewAction(invokeParam);
63
+ });
64
64
  if (viewActionProps) {
65
65
  actions.push(toAction(viewActionProps, invokeClientAction, messages.view, 'view-content'));
66
66
  }
@@ -73,9 +73,7 @@ export function useSmartLinkActions({
73
73
  isPreviewRestricted
74
74
  } : undefined),
75
75
  openPreviewPanel,
76
- ...(fg('platform_smartlink_xpc_url_wrapping') ? {
77
- transformUrl: (destinationUrl = url) => appendCrossProductAnalyticsParams(destinationUrl)
78
- } : undefined)
76
+ transformUrl: (destinationUrl = url) => appendCrossProductAnalyticsParams(destinationUrl)
79
77
  });
80
78
  if (previewActionProps) {
81
79
  actions.push(toAction(previewActionProps.invokeAction, invokeClientAction, messages.preview_improved, 'preview-content'));
@@ -3,7 +3,7 @@ export const ANALYTICS_CHANNEL = 'media';
3
3
  export const context = {
4
4
  componentName: 'smart-cards',
5
5
  packageName: "@atlaskit/smart-card" || '',
6
- packageVersion: "45.20.7" || ''
6
+ packageVersion: "45.21.2" || ''
7
7
  };
8
8
  export let TrackQuickActionType = /*#__PURE__*/function (TrackQuickActionType) {
9
9
  TrackQuickActionType["StatusUpdate"] = "StatusUpdate";
@@ -16,7 +16,7 @@ import { getObjectName } from '../../state/getObjectName';
16
16
  import { getResourceType } from '../../state/getResourceType';
17
17
  import { getServices } from '../../state/getServices';
18
18
  import { getThirdPartyARI } from '../../state/getThirdPartyARI';
19
- import { useSmartLinkCrossProductUrlWrapperGated } from '../../state/hooks/use-smart-link-cross-product-url-wrapper';
19
+ import { useSmartLinkCrossProductUrlWrapper } from '../../state/hooks/use-smart-link-cross-product-url-wrapper';
20
20
  import { useSmartLink } from '../../state/hooks/useSmartLink';
21
21
  import { isFinalState } from '../../state/isFinalState';
22
22
  import { SmartLinkModalProvider } from '../../state/modal/SmartLinkModalProvider';
@@ -100,7 +100,7 @@ function Component({
100
100
  const services = getServices(state.details);
101
101
  const thirdPartyARI = getThirdPartyARI(state.details);
102
102
  const firstPartyIdentifier = getFirstPartyIdentifier();
103
- const appendCrossProductAnalyticsParams = useSmartLinkCrossProductUrlWrapperGated({
103
+ const appendCrossProductAnalyticsParams = useSmartLinkCrossProductUrlWrapper({
104
104
  details: state.details
105
105
  });
106
106
  const actionOptions = combineActionOptions({
@@ -137,127 +137,80 @@ function Component({
137
137
  // please reach out to the 3P Workflows Team via Slack in #help-3p-connector-workflow
138
138
  fire3PClickEvent === null || fire3PClickEvent === void 0 ? void 0 : fire3PClickEvent();
139
139
  }
140
- if (fg('platform_smartlink_xpc_url_wrapping')) {
141
- // FIXME: InlineCard, BlockCard and EmbedCard call event.preventDefault() internally
142
- // before the event bubbles up to this handler. This forces us to snapshot
143
- // event.defaultPrevented before calling onClick to detect whether the consumer
144
- // specifically prevented navigation. Ideally those components should not call
145
- // preventDefault so this workaround can be removed.
146
- const isEventDefaultPrevented = event.defaultPrevented;
147
- const canOpenPreviewPanel = !isModifierKeyPressed && ari && name && openPreviewPanel && (isPreviewPanelAvailable === null || isPreviewPanelAvailable === void 0 ? void 0 : isPreviewPanelAvailable({
148
- ari
149
- })) && !disablePreviewPanel;
150
140
 
151
- // Preview panel takes priority over link navigation when available.
152
- if (canOpenPreviewPanel) {
153
- var _extractSmartLinkEmbe;
154
- event.preventDefault();
155
- event.stopPropagation();
156
- openPreviewPanel({
157
- url,
158
- ari,
159
- name,
160
- iconUrl: getObjectIconUrl(state.details),
161
- panelData: {
162
- embedUrl: expValEquals('platform_hover_card_preview_panel', 'cohort', 'test') ? (_extractSmartLinkEmbe = extractSmartLinkEmbed(state.details)) === null || _extractSmartLinkEmbe === void 0 ? void 0 : _extractSmartLinkEmbe.src : undefined
163
- }
164
- });
165
- fireLinkClickedEvent(createAnalyticsEvent)(event, {
166
- attributes: {
167
- clickOutcome: 'previewPanel'
168
- }
169
- });
170
- return;
171
- }
172
- const destinationUrl = getDestinationUrl();
173
- updateAnchorHref(event, destinationUrl);
141
+ // FIXME: InlineCard, BlockCard and EmbedCard call event.preventDefault() internally
142
+ // before the event bubbles up to this handler. This forces us to snapshot
143
+ // event.defaultPrevented before calling onClick to detect whether the consumer
144
+ // specifically prevented navigation. Ideally those components should not call
145
+ // preventDefault so this workaround can be removed.
146
+ const isEventDefaultPrevented = event.defaultPrevented;
147
+ const canOpenPreviewPanel = !isModifierKeyPressed && ari && name && openPreviewPanel && (isPreviewPanelAvailable === null || isPreviewPanelAvailable === void 0 ? void 0 : isPreviewPanelAvailable({
148
+ ari
149
+ })) && !disablePreviewPanel;
174
150
 
175
- // For FlexibleCard, read target from the clicked anchor element (e.g. _blank for links
176
- // rendered with explicit target). For classic cards, default to _self
177
- const {
178
- target: anchorTarget
179
- } = getAnchorAttributesFromEvent(event);
180
- const target = isSpecialEvent(event) ? '_blank' : isFlexibleUi ? anchorTarget : '_self';
181
- onClick === null || onClick === void 0 ? void 0 : onClick(event, {
151
+ // Preview panel takes priority over link navigation when available.
152
+ if (canOpenPreviewPanel) {
153
+ var _extractSmartLinkEmbe;
154
+ event.preventDefault();
155
+ event.stopPropagation();
156
+ openPreviewPanel({
182
157
  url,
183
- destinationUrl
158
+ ari,
159
+ name,
160
+ iconUrl: getObjectIconUrl(state.details),
161
+ panelData: {
162
+ embedUrl: expValEquals('platform_hover_card_preview_panel', 'cohort', 'test') ? (_extractSmartLinkEmbe = extractSmartLinkEmbed(state.details)) === null || _extractSmartLinkEmbe === void 0 ? void 0 : _extractSmartLinkEmbe.src : undefined
163
+ }
164
+ });
165
+ fireLinkClickedEvent(createAnalyticsEvent)(event, {
166
+ attributes: {
167
+ clickOutcome: 'previewPanel'
168
+ }
184
169
  });
170
+ return;
171
+ }
172
+ const destinationUrl = getDestinationUrl();
173
+ updateAnchorHref(event, destinationUrl);
185
174
 
186
- // Check if the event is prevented via onClick callback
187
- const consumerPreventedNavigation = event.defaultPrevented && !isEventDefaultPrevented;
175
+ // For FlexibleCard, read target from the clicked anchor element (e.g. _blank for links
176
+ // rendered with explicit target). For classic cards, default to _self
177
+ const {
178
+ target: anchorTarget
179
+ } = getAnchorAttributesFromEvent(event);
180
+ const target = isSpecialEvent(event) ? '_blank' : isFlexibleUi ? anchorTarget : '_self';
181
+ onClick === null || onClick === void 0 ? void 0 : onClick(event, {
182
+ url,
183
+ destinationUrl
184
+ });
188
185
 
189
- // Classic cards (InlineCard, BlockCard, EmbedCard) rely on their own anchor navigation
190
- // when onClick is provided, so this handler should not open the link for them.
191
- // FlexibleCard's anchor is prevented from native navigation, so this handler always
192
- // opens the link for FlexibleCard unless the consumer's onClick called preventDefault.
193
- const shouldOpenLink = isFlexibleUi || !onClick;
194
- const doOpenLink = shouldOpenLink && !consumerPreventedNavigation;
195
- if (doOpenLink) {
196
- event.preventDefault();
197
- window.open(destinationUrl, target);
198
- }
186
+ // Check if the event is prevented via onClick callback
187
+ const consumerPreventedNavigation = event.defaultPrevented && !isEventDefaultPrevented;
199
188
 
200
- // Only set clickOutcome when this handler actually opened the link.
201
- // If a parent onClick handled navigation, fire a generic click event instead.
202
- fireLinkClickedEvent(createAnalyticsEvent)(event, doOpenLink ? {
203
- attributes: {
204
- clickOutcome: target === '_blank' ? 'clickThroughNewTabOrWindow' : 'clickThrough'
205
- }
206
- } : undefined);
207
- } else {
208
- // If preview panel is available and the user clicked on the link,
209
- // delegate the click to the preview panel handler
210
- if (!isModifierKeyPressed && ari && name && openPreviewPanel && isPreviewPanelAvailable !== null && isPreviewPanelAvailable !== void 0 && isPreviewPanelAvailable({
211
- ari
212
- }) && !disablePreviewPanel) {
213
- var _extractSmartLinkEmbe2;
214
- event.preventDefault();
215
- event.stopPropagation();
216
- openPreviewPanel({
217
- url,
218
- ari,
219
- name,
220
- iconUrl: getObjectIconUrl(state.details),
221
- panelData: {
222
- embedUrl: expValEquals('platform_hover_card_preview_panel', 'cohort', 'test') ? (_extractSmartLinkEmbe2 = extractSmartLinkEmbed(state.details)) === null || _extractSmartLinkEmbe2 === void 0 ? void 0 : _extractSmartLinkEmbe2.src : undefined
223
- }
224
- });
225
- fireLinkClickedEvent(createAnalyticsEvent)(event, {
226
- attributes: {
227
- clickOutcome: 'previewPanel'
228
- }
229
- });
230
- return;
231
- } else if (!onClick && !isFlexibleUi) {
232
- const clickUrl = getClickUrl(url, state.details);
189
+ // Classic cards (InlineCard, BlockCard, EmbedCard) rely on their own anchor navigation
190
+ // when onClick is provided, so this handler should not open the link for them.
191
+ // FlexibleCard's anchor is prevented from native navigation, so this handler always
192
+ // opens the link for FlexibleCard unless the consumer's onClick called preventDefault.
193
+ const shouldOpenLink = isFlexibleUi || !onClick;
194
+ const doOpenLink = shouldOpenLink && !consumerPreventedNavigation;
195
+ if (doOpenLink) {
196
+ event.preventDefault();
197
+ window.open(destinationUrl, target);
198
+ }
233
199
 
234
- // Ctrl+left click on mac typically doesn't trigger onClick
235
- // The event could have potentially had `e.preventDefault()` called on it by now
236
- // event by smart card internally
237
- // If it has been called then only then can `isSpecialEvent` be true.
238
- const target = isSpecialEvent(event) ? '_blank' : '_self';
239
- window.open(clickUrl, target);
240
- fireLinkClickedEvent(createAnalyticsEvent)(event, {
241
- attributes: {
242
- clickOutcome: target === '_blank' ? 'clickThroughNewTabOrWindow' : 'clickThrough'
243
- }
244
- });
245
- } else {
246
- if (onClick) {
247
- onClick(event);
248
- }
249
- fireLinkClickedEvent(createAnalyticsEvent)(event);
200
+ // Only set clickOutcome when this handler actually opened the link.
201
+ // If a parent onClick handled navigation, fire a generic click event instead.
202
+ fireLinkClickedEvent(createAnalyticsEvent)(event, doOpenLink ? {
203
+ attributes: {
204
+ clickOutcome: target === '_blank' ? 'clickThroughNewTabOrWindow' : 'clickThrough'
250
205
  }
251
- }
206
+ } : undefined);
252
207
  }, [fireEvent, id, isFlexibleUi, appearance, definitionId, getDestinationUrl, onClick, url, state.details, ari, name, fire3PClickEvent, shouldFire3PClickEvent, isPreviewPanelAvailable, openPreviewPanel, createAnalyticsEvent, disablePreviewPanel]);
253
208
 
254
209
  // Middle-click handler to trigger fire3PClickEvent on middle-clicks.
255
210
  // Scope is limited to 3P click analytics.
256
211
  const handleFrameAuxClick = useCallback(event => {
257
- if (fg('platform_smartlink_xpc_url_wrapping')) {
258
- const destinationUrl = getDestinationUrl();
259
- updateAnchorHref(event, destinationUrl);
260
- }
212
+ const destinationUrl = getDestinationUrl();
213
+ updateAnchorHref(event, destinationUrl);
261
214
 
262
215
  // isAuxClick filters Windows right-clicks (button === 2) that also fire onAuxClick.
263
216
  if (isAuxClick(event) && shouldFire3PClickEvent) {
@@ -270,10 +223,8 @@ function Component({
270
223
  // Right-click handler to trigger fire3PClickEvent on right-clicks.
271
224
  // Scope is limited to 3P click analytics.
272
225
  const handleFrameContextMenu = useCallback(event => {
273
- if (fg('platform_smartlink_xpc_url_wrapping')) {
274
- const destinationUrl = getDestinationUrl();
275
- updateAnchorHref(event, destinationUrl);
276
- }
226
+ const destinationUrl = getDestinationUrl();
227
+ updateAnchorHref(event, destinationUrl);
277
228
  if (shouldFire3PClickEvent) {
278
229
  fire3PClickEvent === null || fire3PClickEvent === void 0 ? void 0 : fire3PClickEvent({
279
230
  isContextMenu: true
@@ -10,7 +10,7 @@ import { FlexibleCardContext } from '../../state/flexible-ui-context';
10
10
  import { useAISummaryConfig } from '../../state/hooks/use-ai-summary-config';
11
11
  import useResolve from '../../state/hooks/use-resolve';
12
12
  import useRovoConfig from '../../state/hooks/use-rovo-config';
13
- import { useSmartLinkCrossProductUrlWrapperGated } from '../../state/hooks/use-smart-link-cross-product-url-wrapper';
13
+ import { useSmartLinkCrossProductUrlWrapper } from '../../state/hooks/use-smart-link-cross-product-url-wrapper';
14
14
  import Container from './components/container';
15
15
  import { getContextByStatus } from './getContextByStatus';
16
16
  const PENDING_LINK_STATUSES = [SmartLinkStatus.Pending, SmartLinkStatus.Resolving];
@@ -61,11 +61,10 @@ const FlexibleCard = ({
61
61
  details
62
62
  } = cardState;
63
63
  const status = cardType;
64
- const appendCrossProductAnalyticsParams = useSmartLinkCrossProductUrlWrapperGated({
64
+ const appendCrossProductAnalyticsParams = useSmartLinkCrossProductUrlWrapper({
65
65
  details
66
66
  });
67
- const transformUrlCallback = useCallback((destinationUrl = url) => appendCrossProductAnalyticsParams(destinationUrl), [appendCrossProductAnalyticsParams, url]);
68
- const transformUrl = fg('platform_smartlink_xpc_url_wrapping') ? transformUrlCallback : undefined;
67
+ const transformUrl = useCallback((destinationUrl = url) => appendCrossProductAnalyticsParams(destinationUrl), [appendCrossProductAnalyticsParams, url]);
69
68
 
70
69
  // if we have placeholder state it means we can internally use it
71
70
  // as temporary resolved data until the actual data comes back as one of the final statuses
@@ -13,7 +13,7 @@ import { getDefinitionId } from '../../../state/getDefinitionId';
13
13
  import { getExtensionKey } from '../../../state/getExtensionKey';
14
14
  import { getServices } from '../../../state/getServices';
15
15
  import useRovoConfig from '../../../state/hooks/use-rovo-config';
16
- import { useSmartLinkCrossProductUrlWrapperGated } from '../../../state/hooks/use-smart-link-cross-product-url-wrapper';
16
+ import { useSmartLinkCrossProductUrlWrapper } from '../../../state/hooks/use-smart-link-cross-product-url-wrapper';
17
17
  import { useSmartCardState } from '../../../state/store';
18
18
  import { isSpecialEvent } from '../../../utils/is-special-event';
19
19
  import { fireLinkClickedEvent } from '../../../utils/analytics/fireLinkClickedEvent';
@@ -90,7 +90,7 @@ const HoverCardContent = ({
90
90
  } = useSmartLinkContext();
91
91
  const isAISummaryEnabled = getIsAISummaryEnabled(isAdminHubAIEnabled, cardState.details);
92
92
  const services = getServices(linkState.details);
93
- const appendCrossProductAnalyticsParams = useSmartLinkCrossProductUrlWrapperGated({
93
+ const appendCrossProductAnalyticsParams = useSmartLinkCrossProductUrlWrapper({
94
94
  details: linkState.details
95
95
  });
96
96
  const statusRef = useRef(linkStatus);
@@ -154,20 +154,18 @@ const HoverCardContent = ({
154
154
  updateAnchorHref(event, destinationUrl);
155
155
  }, [getDestinationUrl]);
156
156
  const onClick = useCallback(event => {
157
- if (fg('platform_smartlink_xpc_url_wrapping')) {
158
- // Prevent the anchor's native navigation so we can open the destination URL
159
- // with cross-product analytics query parameters appended.
160
- // The cross-product params are client-only and cannot be rendered
161
- // server-side. Falls back to the original `url` prop if the event target is
162
- // not an anchor element.
163
- event.preventDefault();
164
- const {
165
- target
166
- } = getAnchorAttributesFromEvent(event);
167
- const destinationUrl = getDestinationUrl();
168
- updateAnchorHref(event, destinationUrl);
169
- window.open(destinationUrl, target);
170
- }
157
+ // Prevent the anchor's native navigation so we can open the destination URL
158
+ // with cross-product analytics query parameters appended.
159
+ // The cross-product params are client-only and cannot be rendered
160
+ // server-side. Falls back to the original `url` prop if the event target is
161
+ // not an anchor element.
162
+ event.preventDefault();
163
+ const {
164
+ target
165
+ } = getAnchorAttributesFromEvent(event);
166
+ const destinationUrl = getDestinationUrl();
167
+ updateAnchorHref(event, destinationUrl);
168
+ window.open(destinationUrl, target);
171
169
  const isModifierKeyPressed = isSpecialEvent(event);
172
170
  fireEvent('ui.smartLink.clicked.titleGoToLink', {
173
171
  id,
@@ -195,10 +193,8 @@ const HoverCardContent = ({
195
193
  appearance: CardDisplay.HoverCardPreview,
196
194
  cardState: cardState,
197
195
  onClick: onClick,
198
- ...(fg('platform_smartlink_xpc_url_wrapping') ? {
199
- onAuxClick,
200
- onContextMenu
201
- } : undefined),
196
+ onAuxClick,
197
+ onContextMenu,
202
198
  onResolve: onResolve,
203
199
  origin: 'smartLinkPreviewHoverCard',
204
200
  renderers: renderers,
@@ -9,7 +9,7 @@ import LinkWarningModal from './LinkWarningModal';
9
9
  import { useLinkWarningModal } from './LinkWarningModal/hooks/use-link-warning-modal';
10
10
  const PACKAGE_DATA = {
11
11
  packageName: "@atlaskit/smart-card",
12
- packageVersion: "45.20.7",
12
+ packageVersion: "45.21.2",
13
13
  componentName: 'linkUrl'
14
14
  };
15
15
  const LinkUrl = ({
@@ -1,7 +1,6 @@
1
1
  import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
2
  import _regeneratorRuntime from "@babel/runtime/regenerator";
3
3
  import { extractLink } from '@atlaskit/link-extractors/extract-link';
4
- import { fg } from '@atlaskit/platform-feature-flags/fg';
5
4
  import { CardAction } from '../../constants';
6
5
  import { getDefinitionId } from '../../state/getDefinitionId';
7
6
  import { getExtensionKey } from '../../state/getExtensionKey';
@@ -30,19 +29,14 @@ export var extractInvokeViewAction = function extractInvokeViewAction(_ref, forc
30
29
  return {
31
30
  actionFn: function () {
32
31
  var _actionFn = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
33
- var _transformUrl, destinationUrl;
32
+ var _transformUrl;
33
+ var destinationUrl;
34
34
  return _regeneratorRuntime.wrap(function (_context) {
35
35
  while (1) switch (_context.prev = _context.next) {
36
36
  case 0:
37
- if (!fg('platform_smartlink_xpc_url_wrapping')) {
38
- _context.next = 1;
39
- break;
40
- }
41
37
  destinationUrl = (_transformUrl = transformUrl === null || transformUrl === void 0 ? void 0 : transformUrl(url)) !== null && _transformUrl !== void 0 ? _transformUrl : url;
42
38
  return _context.abrupt("return", openUrl(destinationUrl));
43
39
  case 1:
44
- return _context.abrupt("return", openUrl(url));
45
- case 2:
46
40
  case "end":
47
41
  return _context.stop();
48
42
  }
@@ -47,10 +47,9 @@ export var extractFlexibleCardActions = function extractFlexibleCardActions(_ref
47
47
  }, fg('preview_panel_unit_check') ? {
48
48
  isPreviewRestricted: isPreviewRestricted
49
49
  } : undefined), {}, {
50
- openPreviewPanel: openPreviewPanel
51
- }, fg('platform_smartlink_xpc_url_wrapping') ? {
50
+ openPreviewPanel: openPreviewPanel,
52
51
  transformUrl: transformUrl
53
- } : undefined))), ActionName.AutomationAction, extractAutomationAction(response)), InternalActionName.AISummaryAction, extractAISummaryAction(response, url, actionOptions, aiSummaryConfig)), ActionName.RovoChatAction, extractRovoChatAction({
52
+ }))), ActionName.AutomationAction, extractAutomationAction(response)), InternalActionName.AISummaryAction, extractAISummaryAction(response, url, actionOptions, aiSummaryConfig)), ActionName.RovoChatAction, extractRovoChatAction({
54
53
  actionOptions: actionOptions,
55
54
  appearance: appearance,
56
55
  id: id,
@@ -55,10 +55,9 @@ var extractAction = function extractAction(response, id, actionOptions, appearan
55
55
  }, fg('preview_panel_unit_check') ? {
56
56
  isPreviewRestricted: isPreviewRestricted
57
57
  } : undefined), {}, {
58
- openPreviewPanel: openPreviewPanel
59
- }, fg('platform_smartlink_xpc_url_wrapping') ? {
58
+ openPreviewPanel: openPreviewPanel,
60
59
  transformUrl: transformUrl
61
- } : undefined))) === null || _extractInvokePreview === void 0 ? void 0 : _extractInvokePreview.invokeAction : undefined;
60
+ }))) === null || _extractInvokePreview === void 0 ? void 0 : _extractInvokePreview.invokeAction : undefined;
62
61
  var details = {
63
62
  id: id,
64
63
  url: url,
@@ -81,7 +80,7 @@ var extractState = function extractState(response, actionOptions, id, appearance
81
80
  if (!canShowAction(CardAction.ChangeStatusAction, actionOptions)) {
82
81
  return lozenge;
83
82
  }
84
- var action = extractAction(response, id, actionOptions, appearance, origin, fireEvent, resolve, isPreviewPanelAvailable, openPreviewPanel, fg('platform_smartlink_xpc_url_wrapping') ? transformUrl : undefined, fg('preview_panel_unit_check') ? isPreviewRestricted : undefined);
83
+ var action = extractAction(response, id, actionOptions, appearance, origin, fireEvent, resolve, isPreviewPanelAvailable, openPreviewPanel, transformUrl, fg('preview_panel_unit_check') ? isPreviewRestricted : undefined);
85
84
  return _objectSpread(_objectSpread({}, lozenge), {}, {
86
85
  action: action
87
86
  });
@@ -93,10 +93,9 @@ var extractFlexibleUiContext = function extractFlexibleUiContext() {
93
93
  }, fg('preview_panel_unit_check') ? {
94
94
  isPreviewRestricted: isPreviewRestricted
95
95
  } : undefined), {}, {
96
- openPreviewPanel: openPreviewPanel
97
- }, fg('platform_smartlink_xpc_url_wrapping') ? {
96
+ openPreviewPanel: openPreviewPanel,
98
97
  transformUrl: transformUrl
99
- } : undefined)),
98
+ })),
100
99
  appliedToComponentsCount: extractAppliedToComponentsCount(data),
101
100
  assignedToGroup: extractPersonAssignedToAsArray(data),
102
101
  attachmentCount: extractAttachmentCount(data),
@@ -128,7 +127,7 @@ var extractFlexibleUiContext = function extractFlexibleUiContext() {
128
127
  snippet: extractSmartLinkSummary(response) || undefined,
129
128
  // Explicitly set here to remove an empty string
130
129
  sourceBranch: extractSourceBranch(data),
131
- state: extractState(response, actionOptions, id, appearance, origin, fireEvent, resolve, isPreviewPanelAvailable, openPreviewPanel, fg('platform_smartlink_xpc_url_wrapping') ? transformUrl : undefined, fg('preview_panel_unit_check') ? isPreviewRestricted : undefined),
130
+ state: extractState(response, actionOptions, id, appearance, origin, fireEvent, resolve, isPreviewPanelAvailable, openPreviewPanel, transformUrl, fg('preview_panel_unit_check') ? isPreviewRestricted : undefined),
132
131
  subscriberCount: extractSubscriberCount(data),
133
132
  subTasksProgress: extractSubTasksProgress(data),
134
133
  storyPoints: extractStoryPoints(data),