@atlaskit/smart-card 45.21.0 → 45.21.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 (44) hide show
  1. package/CHANGELOG.md +24 -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,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
- var useDestinationUrlImplementation = function useDestinationUrlImplementation(url) {
22
+ var useDestinationUrl = function useDestinationUrl(url) {
25
23
  var state = useSmartCardState(url);
26
24
  var appendCrossProductAnalyticsParams = useSmartLinkCrossProductUrlWrapper({
27
25
  details: state.details
@@ -29,9 +27,6 @@ var useDestinationUrlImplementation = function useDestinationUrlImplementation(u
29
27
  var resolvedUrl = getClickUrl(url, state.details);
30
28
  return appendCrossProductAnalyticsParams(resolvedUrl);
31
29
  };
32
- export var useDestinationUrl = functionWithFG('platform_smartlink_xpc_url_wrapping', useDestinationUrlImplementation, function (url) {
33
- return url;
34
- });
35
30
 
36
31
  // Public API aliases preserved from an eliminated entry-point (volt-migrate-package).
37
32
  export { useDestinationUrl as useSmartLinkDestinationUrl };
@@ -1,9 +1,47 @@
1
- import { functionWithFG } from '@atlaskit/platform-feature-flags-react/function-with-fg';
2
- import { useSmartLinkCrossProductUrlWrapper } from './useSmartLinkCrossProductUrlWrapper';
3
- var identityUrlWrapper = function identityUrlWrapper(url) {
4
- return url;
5
- };
6
- var useSmartLinkCrossProductUrlWrapperFallback = function useSmartLinkCrossProductUrlWrapperFallback(_args) {
7
- return identityUrlWrapper;
8
- };
9
- export var useSmartLinkCrossProductUrlWrapperGated = functionWithFG('platform_smartlink_xpc_url_wrapping', useSmartLinkCrossProductUrlWrapper, useSmartLinkCrossProductUrlWrapperFallback);
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
+ import { useCallback } from 'react';
5
+ import { useCrossProductUrlWrapper } from '@atlaskit/analytics-cross-product/useCrossProductUrlWrapper';
6
+ import { useSmartLinkContext } from '@atlaskit/link-provider';
7
+ import { XPC_CONSTANTS } from './constants';
8
+ import { getIsFirstPartyLink } from './getIsFirstPartyLink';
9
+ export var useSmartLinkCrossProductUrlWrapper = function useSmartLinkCrossProductUrlWrapper(_ref) {
10
+ var _effectiveProduct$toL;
11
+ var details = _ref.details;
12
+ var _useSmartLinkContext = useSmartLinkContext(),
13
+ product = _useSmartLinkContext.product,
14
+ bridgeProduct = _useSmartLinkContext.bridgeProduct,
15
+ xpcProduct = _useSmartLinkContext.xpcProduct,
16
+ xpcSubProduct = _useSmartLinkContext.xpcSubProduct;
17
+ // xpcProduct takes precedence over product — it identifies the host product for XPC analytics
18
+ // without affecting link resolution (which uses the `product` prop separately).
19
+ var effectiveProduct = xpcProduct !== null && xpcProduct !== void 0 ? xpcProduct : product;
20
+ var effectiveBridge = bridgeProduct !== null && bridgeProduct !== void 0 ? bridgeProduct : XPC_CONSTANTS.SMART_LINKS_XPC_BRIDGE;
21
+ var effectiveProductForWrapper = (_effectiveProduct$toL = effectiveProduct === null || effectiveProduct === void 0 ? void 0 : effectiveProduct.toLowerCase()) !== null && _effectiveProduct$toL !== void 0 ? _effectiveProduct$toL : 'unknown';
22
+ var wrapUrl = useCrossProductUrlWrapper(_objectSpread({
23
+ bridge: effectiveBridge,
24
+ product: effectiveProductForWrapper
25
+ }, xpcSubProduct ? {
26
+ subProduct: xpcSubProduct
27
+ } : {}));
28
+ return useCallback(function (url) {
29
+ if (typeof window === 'undefined' || !getIsFirstPartyLink(details) || !effectiveProduct) {
30
+ return url;
31
+ }
32
+ var parsedUrl;
33
+ try {
34
+ parsedUrl = new URL(url);
35
+ } catch (_unused) {
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
+ };
@@ -16,7 +16,7 @@ import { messages } from '../../messages';
16
16
  import { toAction } from '../../utils/actions/to-action';
17
17
  import useInvokeClientAction from '../hooks/use-invoke-client-action';
18
18
  import useResolve from '../hooks/use-resolve';
19
- import { useSmartLinkCrossProductUrlWrapperGated } from '../hooks/use-smart-link-cross-product-url-wrapper';
19
+ import { useSmartLinkCrossProductUrlWrapper } from '../hooks/use-smart-link-cross-product-url-wrapper';
20
20
  import { useSmartCardState as useLinkState } from '../store';
21
21
  export function useSmartLinkActions(_ref) {
22
22
  var url = _ref.url,
@@ -39,7 +39,7 @@ export function useSmartLinkActions(_ref) {
39
39
  fireEvent: fireEvent
40
40
  });
41
41
  var resolve = useResolve();
42
- var appendCrossProductAnalyticsParams = useSmartLinkCrossProductUrlWrapperGated({
42
+ var appendCrossProductAnalyticsParams = useSmartLinkCrossProductUrlWrapper({
43
43
  details: linkState.details
44
44
  });
45
45
  if (expValEquals('platform_hover_card_preview_panel', 'cohort', 'test') && prefetch && !linkState.details) {
@@ -59,12 +59,12 @@ export function useSmartLinkActions(_ref) {
59
59
  if (downloadActionProps) {
60
60
  actions.push(toAction(downloadActionProps, invokeClientAction, messages.download, 'download-content'));
61
61
  }
62
- var viewActionProps = fg('platform_smartlink_xpc_url_wrapping') ? extractInvokeViewAction(_objectSpread(_objectSpread({}, invokeParam), {}, {
62
+ var viewActionProps = extractInvokeViewAction(_objectSpread(_objectSpread({}, invokeParam), {}, {
63
63
  transformUrl: function transformUrl() {
64
64
  var destinationUrl = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : url;
65
65
  return appendCrossProductAnalyticsParams(destinationUrl);
66
66
  }
67
- })) : extractInvokeViewAction(invokeParam);
67
+ }));
68
68
  if (viewActionProps) {
69
69
  actions.push(toAction(viewActionProps, invokeClientAction, messages.view, 'view-content'));
70
70
  }
@@ -75,13 +75,12 @@ export function useSmartLinkActions(_ref) {
75
75
  }, fg('preview_panel_unit_check') ? {
76
76
  isPreviewRestricted: isPreviewRestricted
77
77
  } : undefined), {}, {
78
- openPreviewPanel: openPreviewPanel
79
- }, fg('platform_smartlink_xpc_url_wrapping') ? {
78
+ openPreviewPanel: openPreviewPanel,
80
79
  transformUrl: function transformUrl() {
81
80
  var destinationUrl = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : url;
82
81
  return appendCrossProductAnalyticsParams(destinationUrl);
83
82
  }
84
- } : undefined));
83
+ }));
85
84
  if (previewActionProps) {
86
85
  actions.push(toAction(previewActionProps.invokeAction, invokeClientAction, messages.preview_improved, 'preview-content'));
87
86
  }
@@ -3,7 +3,7 @@ export var ANALYTICS_CHANNEL = 'media';
3
3
  export var context = {
4
4
  componentName: 'smart-cards',
5
5
  packageName: "@atlaskit/smart-card" || '',
6
- packageVersion: "45.20.7" || ''
6
+ packageVersion: "45.21.0" || ''
7
7
  };
8
8
  export var TrackQuickActionType = /*#__PURE__*/function (TrackQuickActionType) {
9
9
  TrackQuickActionType["StatusUpdate"] = "StatusUpdate";
@@ -19,7 +19,7 @@ import { getObjectName } from '../../state/getObjectName';
19
19
  import { getResourceType } from '../../state/getResourceType';
20
20
  import { getServices } from '../../state/getServices';
21
21
  import { getThirdPartyARI } from '../../state/getThirdPartyARI';
22
- import { useSmartLinkCrossProductUrlWrapperGated } from '../../state/hooks/use-smart-link-cross-product-url-wrapper';
22
+ import { useSmartLinkCrossProductUrlWrapper } from '../../state/hooks/use-smart-link-cross-product-url-wrapper';
23
23
  import { useSmartLink } from '../../state/hooks/useSmartLink';
24
24
  import { isFinalState } from '../../state/isFinalState';
25
25
  import { SmartLinkModalProvider } from '../../state/modal/SmartLinkModalProvider';
@@ -101,7 +101,7 @@ function Component(_ref) {
101
101
  var services = getServices(state.details);
102
102
  var thirdPartyARI = getThirdPartyARI(state.details);
103
103
  var firstPartyIdentifier = getFirstPartyIdentifier();
104
- var appendCrossProductAnalyticsParams = useSmartLinkCrossProductUrlWrapperGated({
104
+ var appendCrossProductAnalyticsParams = useSmartLinkCrossProductUrlWrapper({
105
105
  details: state.details
106
106
  });
107
107
  var actionOptions = combineActionOptions({
@@ -138,126 +138,79 @@ function Component(_ref) {
138
138
  // please reach out to the 3P Workflows Team via Slack in #help-3p-connector-workflow
139
139
  fire3PClickEvent === null || fire3PClickEvent === void 0 || fire3PClickEvent();
140
140
  }
141
- if (fg('platform_smartlink_xpc_url_wrapping')) {
142
- // FIXME: InlineCard, BlockCard and EmbedCard call event.preventDefault() internally
143
- // before the event bubbles up to this handler. This forces us to snapshot
144
- // event.defaultPrevented before calling onClick to detect whether the consumer
145
- // specifically prevented navigation. Ideally those components should not call
146
- // preventDefault so this workaround can be removed.
147
- var isEventDefaultPrevented = event.defaultPrevented;
148
- var canOpenPreviewPanel = !isModifierKeyPressed && ari && name && openPreviewPanel && (isPreviewPanelAvailable === null || isPreviewPanelAvailable === void 0 ? void 0 : isPreviewPanelAvailable({
149
- ari: ari
150
- })) && !disablePreviewPanel;
151
141
 
152
- // Preview panel takes priority over link navigation when available.
153
- if (canOpenPreviewPanel) {
154
- var _extractSmartLinkEmbe;
155
- event.preventDefault();
156
- event.stopPropagation();
157
- openPreviewPanel({
158
- url: url,
159
- ari: ari,
160
- name: name,
161
- iconUrl: getObjectIconUrl(state.details),
162
- panelData: {
163
- embedUrl: expValEquals('platform_hover_card_preview_panel', 'cohort', 'test') ? (_extractSmartLinkEmbe = extractSmartLinkEmbed(state.details)) === null || _extractSmartLinkEmbe === void 0 ? void 0 : _extractSmartLinkEmbe.src : undefined
164
- }
165
- });
166
- fireLinkClickedEvent(createAnalyticsEvent)(event, {
167
- attributes: {
168
- clickOutcome: 'previewPanel'
169
- }
170
- });
171
- return;
172
- }
173
- var destinationUrl = getDestinationUrl();
174
- updateAnchorHref(event, destinationUrl);
142
+ // FIXME: InlineCard, BlockCard and EmbedCard call event.preventDefault() internally
143
+ // before the event bubbles up to this handler. This forces us to snapshot
144
+ // event.defaultPrevented before calling onClick to detect whether the consumer
145
+ // specifically prevented navigation. Ideally those components should not call
146
+ // preventDefault so this workaround can be removed.
147
+ var isEventDefaultPrevented = event.defaultPrevented;
148
+ var canOpenPreviewPanel = !isModifierKeyPressed && ari && name && openPreviewPanel && (isPreviewPanelAvailable === null || isPreviewPanelAvailable === void 0 ? void 0 : isPreviewPanelAvailable({
149
+ ari: ari
150
+ })) && !disablePreviewPanel;
175
151
 
176
- // For FlexibleCard, read target from the clicked anchor element (e.g. _blank for links
177
- // rendered with explicit target). For classic cards, default to _self
178
- var _getAnchorAttributesF = getAnchorAttributesFromEvent(event),
179
- anchorTarget = _getAnchorAttributesF.target;
180
- var target = isSpecialEvent(event) ? '_blank' : isFlexibleUi ? anchorTarget : '_self';
181
- onClick === null || onClick === void 0 || onClick(event, {
152
+ // Preview panel takes priority over link navigation when available.
153
+ if (canOpenPreviewPanel) {
154
+ var _extractSmartLinkEmbe;
155
+ event.preventDefault();
156
+ event.stopPropagation();
157
+ openPreviewPanel({
182
158
  url: url,
183
- destinationUrl: destinationUrl
159
+ ari: ari,
160
+ name: name,
161
+ iconUrl: getObjectIconUrl(state.details),
162
+ panelData: {
163
+ embedUrl: expValEquals('platform_hover_card_preview_panel', 'cohort', 'test') ? (_extractSmartLinkEmbe = extractSmartLinkEmbed(state.details)) === null || _extractSmartLinkEmbe === void 0 ? void 0 : _extractSmartLinkEmbe.src : undefined
164
+ }
165
+ });
166
+ fireLinkClickedEvent(createAnalyticsEvent)(event, {
167
+ attributes: {
168
+ clickOutcome: 'previewPanel'
169
+ }
184
170
  });
171
+ return;
172
+ }
173
+ var destinationUrl = getDestinationUrl();
174
+ updateAnchorHref(event, destinationUrl);
185
175
 
186
- // Check if the event is prevented via onClick callback
187
- var consumerPreventedNavigation = event.defaultPrevented && !isEventDefaultPrevented;
176
+ // For FlexibleCard, read target from the clicked anchor element (e.g. _blank for links
177
+ // rendered with explicit target). For classic cards, default to _self
178
+ var _getAnchorAttributesF = getAnchorAttributesFromEvent(event),
179
+ anchorTarget = _getAnchorAttributesF.target;
180
+ var target = isSpecialEvent(event) ? '_blank' : isFlexibleUi ? anchorTarget : '_self';
181
+ onClick === null || onClick === void 0 || onClick(event, {
182
+ url: url,
183
+ destinationUrl: 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
- var shouldOpenLink = isFlexibleUi || !onClick;
194
- var 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
+ var 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: ari
212
- }) && !disablePreviewPanel) {
213
- var _extractSmartLinkEmbe2;
214
- event.preventDefault();
215
- event.stopPropagation();
216
- openPreviewPanel({
217
- url: url,
218
- ari: ari,
219
- name: 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
- var 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
+ var shouldOpenLink = isFlexibleUi || !onClick;
194
+ var 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
- var _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
  var handleFrameAuxClick = useCallback(function (event) {
257
- if (fg('platform_smartlink_xpc_url_wrapping')) {
258
- var destinationUrl = getDestinationUrl();
259
- updateAnchorHref(event, destinationUrl);
260
- }
212
+ var 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(_ref) {
270
223
  // Right-click handler to trigger fire3PClickEvent on right-clicks.
271
224
  // Scope is limited to 3P click analytics.
272
225
  var handleFrameContextMenu = useCallback(function (event) {
273
- if (fg('platform_smartlink_xpc_url_wrapping')) {
274
- var destinationUrl = getDestinationUrl();
275
- updateAnchorHref(event, destinationUrl);
276
- }
226
+ var destinationUrl = getDestinationUrl();
227
+ updateAnchorHref(event, destinationUrl);
277
228
  if (shouldFire3PClickEvent) {
278
229
  fire3PClickEvent === null || fire3PClickEvent === void 0 || fire3PClickEvent({
279
230
  isContextMenu: true
@@ -13,7 +13,7 @@ import { FlexibleCardContext } from '../../state/flexible-ui-context';
13
13
  import { useAISummaryConfig } from '../../state/hooks/use-ai-summary-config';
14
14
  import useResolve from '../../state/hooks/use-resolve';
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 Container from './components/container';
18
18
  import { getContextByStatus } from './getContextByStatus';
19
19
  var PENDING_LINK_STATUSES = [SmartLinkStatus.Pending, SmartLinkStatus.Resolving];
@@ -60,14 +60,13 @@ var FlexibleCard = function FlexibleCard(_ref) {
60
60
  var cardType = cardState.status,
61
61
  details = cardState.details;
62
62
  var status = cardType;
63
- var appendCrossProductAnalyticsParams = useSmartLinkCrossProductUrlWrapperGated({
63
+ var appendCrossProductAnalyticsParams = useSmartLinkCrossProductUrlWrapper({
64
64
  details: details
65
65
  });
66
- var transformUrlCallback = useCallback(function () {
66
+ var transformUrl = useCallback(function () {
67
67
  var destinationUrl = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : url;
68
68
  return appendCrossProductAnalyticsParams(destinationUrl);
69
69
  }, [appendCrossProductAnalyticsParams, url]);
70
- var transformUrl = fg('platform_smartlink_xpc_url_wrapping') ? transformUrlCallback : undefined;
71
70
 
72
71
  // if we have placeholder state it means we can internally use it
73
72
  // as temporary resolved data until the actual data comes back as one of the final statuses
@@ -1,6 +1,3 @@
1
- import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
- function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
- function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
1
  import React, { useCallback, useEffect, useMemo, useRef } from 'react';
5
2
  import AnalyticsContext from '@atlaskit/analytics-next/AnalyticsContext';
6
3
  import { useAnalyticsEvents as useAnalyticsEventsNext } from '@atlaskit/analytics-next/useAnalyticsEvents';
@@ -16,7 +13,7 @@ import { getDefinitionId } from '../../../state/getDefinitionId';
16
13
  import { getExtensionKey } from '../../../state/getExtensionKey';
17
14
  import { getServices } from '../../../state/getServices';
18
15
  import useRovoConfig from '../../../state/hooks/use-rovo-config';
19
- 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';
20
17
  import { useSmartCardState } from '../../../state/store';
21
18
  import { isSpecialEvent } from '../../../utils/is-special-event';
22
19
  import { fireLinkClickedEvent } from '../../../utils/analytics/fireLinkClickedEvent';
@@ -90,7 +87,7 @@ var HoverCardContent = function HoverCardContent(_ref4) {
90
87
  product = _useSmartLinkContext.product;
91
88
  var isAISummaryEnabled = getIsAISummaryEnabled(isAdminHubAIEnabled, cardState.details);
92
89
  var services = getServices(linkState.details);
93
- var appendCrossProductAnalyticsParams = useSmartLinkCrossProductUrlWrapperGated({
90
+ var appendCrossProductAnalyticsParams = useSmartLinkCrossProductUrlWrapper({
94
91
  details: linkState.details
95
92
  });
96
93
  var statusRef = useRef(linkStatus);
@@ -154,19 +151,17 @@ var HoverCardContent = function HoverCardContent(_ref4) {
154
151
  updateAnchorHref(event, destinationUrl);
155
152
  }, [getDestinationUrl]);
156
153
  var onClick = useCallback(function (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
- var _getAnchorAttributesF = getAnchorAttributesFromEvent(event),
165
- target = _getAnchorAttributesF.target;
166
- var destinationUrl = getDestinationUrl();
167
- updateAnchorHref(event, destinationUrl);
168
- window.open(destinationUrl, target);
169
- }
154
+ // Prevent the anchor's native navigation so we can open the destination URL
155
+ // with cross-product analytics query parameters appended.
156
+ // The cross-product params are client-only and cannot be rendered
157
+ // server-side. Falls back to the original `url` prop if the event target is
158
+ // not an anchor element.
159
+ event.preventDefault();
160
+ var _getAnchorAttributesF = getAnchorAttributesFromEvent(event),
161
+ target = _getAnchorAttributesF.target;
162
+ var destinationUrl = getDestinationUrl();
163
+ updateAnchorHref(event, destinationUrl);
164
+ window.open(destinationUrl, target);
170
165
  var isModifierKeyPressed = isSpecialEvent(event);
171
166
  fireEvent('ui.smartLink.clicked.titleGoToLink', {
172
167
  id: id,
@@ -189,14 +184,12 @@ var HoverCardContent = function HoverCardContent(_ref4) {
189
184
  };
190
185
  var uiOptions = flexibleUiOptions;
191
186
  uiOptions.enableSnippetRenderer = true;
192
- var flexibleCardProps = _objectSpread(_objectSpread({
187
+ var flexibleCardProps = {
193
188
  appearance: CardDisplay.HoverCardPreview,
194
189
  cardState: cardState,
195
- onClick: onClick
196
- }, fg('platform_smartlink_xpc_url_wrapping') ? {
190
+ onClick: onClick,
197
191
  onAuxClick: onAuxClick,
198
- onContextMenu: onContextMenu
199
- } : undefined), {}, {
192
+ onContextMenu: onContextMenu,
200
193
  onResolve: onResolve,
201
194
  origin: 'smartLinkPreviewHoverCard',
202
195
  renderers: renderers,
@@ -204,7 +197,7 @@ var HoverCardContent = function HoverCardContent(_ref4) {
204
197
  ui: uiOptions,
205
198
  url: url,
206
199
  children: null
207
- });
200
+ };
208
201
  var onClickStopPropagation = useCallback(function (e) {
209
202
  return e.stopPropagation();
210
203
  }, []);
@@ -12,7 +12,7 @@ import LinkWarningModal from './LinkWarningModal';
12
12
  import { useLinkWarningModal } from './LinkWarningModal/hooks/use-link-warning-modal';
13
13
  var PACKAGE_DATA = {
14
14
  packageName: "@atlaskit/smart-card",
15
- packageVersion: "45.20.7",
15
+ packageVersion: "45.21.0",
16
16
  componentName: 'linkUrl'
17
17
  };
18
18
  var LinkUrl = function LinkUrl(_ref) {
@@ -1,2 +1,19 @@
1
- export declare const useDestinationUrl: (url: string) => string;
1
+ /**
2
+ * Returns the resolved destination URL for a Smart Link, with cross-product analytics
3
+ * parameters appended when applicable.
4
+ *
5
+ * This is the same URL that SmartCard would navigate to when clicked. Use this as an `href`
6
+ * wherever you render a link to a Smart Link URL outside of the SmartCard component itself
7
+ * (e.g. toolbar buttons, overlays).
8
+ *
9
+ * Falls back to the raw `url` when:
10
+ * - The link has not yet resolved
11
+ * - The link is not a first-party Atlassian link
12
+ *
13
+ * @example
14
+ * const href = useSmartLinkDestinationUrl(url);
15
+ *
16
+ * Use as <a href={href} target="_blank">Open link</a>
17
+ */
18
+ declare const useDestinationUrl: (url: string) => string;
2
19
  export { useDestinationUrl as useSmartLinkDestinationUrl };
@@ -1,2 +1,5 @@
1
- import { useSmartLinkCrossProductUrlWrapper } from './useSmartLinkCrossProductUrlWrapper';
2
- export declare const useSmartLinkCrossProductUrlWrapperGated: typeof useSmartLinkCrossProductUrlWrapper;
1
+ import type { SmartLinkResponse } from '@atlaskit/linking-types/smart-link';
2
+ export type UseSmartLinkCrossProductUrlWrapperArgs = {
3
+ details?: SmartLinkResponse;
4
+ };
5
+ export declare const useSmartLinkCrossProductUrlWrapper: ({ details, }: UseSmartLinkCrossProductUrlWrapperArgs) => ((url: string) => string);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-card",
3
- "version": "45.21.0",
3
+ "version": "45.21.1",
4
4
  "description": "Smart card component",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -90,7 +90,7 @@
90
90
  "@atlaskit/textfield": "^10.2.0",
91
91
  "@atlaskit/theme": "^28.2.0",
92
92
  "@atlaskit/tile": "^4.1.0",
93
- "@atlaskit/tmp-editor-statsig": "^179.0.0",
93
+ "@atlaskit/tmp-editor-statsig": "^180.0.0",
94
94
  "@atlaskit/tokens": "^16.11.0",
95
95
  "@atlaskit/tooltip": "^24.3.0",
96
96
  "@atlaskit/ufo": "^1.2.0",
@@ -142,6 +142,7 @@
142
142
  "@types/lorem-ipsum": "^1.0.2",
143
143
  "@types/react": "^18.2.0",
144
144
  "@types/react-loadable": "^5.4.1",
145
+ "@types/react-test-renderer": "^18.0.6",
145
146
  "@types/use-sync-external-store": "^1",
146
147
  "abortcontroller-polyfill": "^1.1.9",
147
148
  "brace": "^0.11.1",
@@ -181,9 +182,6 @@
181
182
  "platform_smartlink_3pclick_analytics": {
182
183
  "type": "boolean"
183
184
  },
184
- "platform_smartlink_xpc_url_wrapping": {
185
- "type": "boolean"
186
- },
187
185
  "rovogrowth-635-pre-auth-cta-preview-fg": {
188
186
  "type": "boolean"
189
187
  },
@@ -1,54 +0,0 @@
1
- "use strict";
2
-
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
- Object.defineProperty(exports, "__esModule", {
5
- value: true
6
- });
7
- exports.useSmartLinkCrossProductUrlWrapper = void 0;
8
- var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
- var _react = require("react");
10
- var _useCrossProductUrlWrapper = require("@atlaskit/analytics-cross-product/useCrossProductUrlWrapper");
11
- var _linkProvider = require("@atlaskit/link-provider");
12
- var _constants = require("./constants");
13
- var _getIsFirstPartyLink = require("./getIsFirstPartyLink");
14
- function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
15
- function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
16
- var useSmartLinkCrossProductUrlWrapper = exports.useSmartLinkCrossProductUrlWrapper = function useSmartLinkCrossProductUrlWrapper(_ref) {
17
- var _effectiveProduct$toL;
18
- var details = _ref.details;
19
- var _useSmartLinkContext = (0, _linkProvider.useSmartLinkContext)(),
20
- product = _useSmartLinkContext.product,
21
- bridgeProduct = _useSmartLinkContext.bridgeProduct,
22
- xpcProduct = _useSmartLinkContext.xpcProduct,
23
- xpcSubProduct = _useSmartLinkContext.xpcSubProduct;
24
- // xpcProduct takes precedence over product — it identifies the host product for XPC analytics
25
- // without affecting link resolution (which uses the `product` prop separately).
26
- var effectiveProduct = xpcProduct !== null && xpcProduct !== void 0 ? xpcProduct : product;
27
- var effectiveBridge = bridgeProduct !== null && bridgeProduct !== void 0 ? bridgeProduct : _constants.XPC_CONSTANTS.SMART_LINKS_XPC_BRIDGE;
28
- var effectiveProductForWrapper = (_effectiveProduct$toL = effectiveProduct === null || effectiveProduct === void 0 ? void 0 : effectiveProduct.toLowerCase()) !== null && _effectiveProduct$toL !== void 0 ? _effectiveProduct$toL : 'unknown';
29
- var wrapUrl = (0, _useCrossProductUrlWrapper.useCrossProductUrlWrapper)(_objectSpread({
30
- bridge: effectiveBridge,
31
- product: effectiveProductForWrapper
32
- }, xpcSubProduct ? {
33
- subProduct: xpcSubProduct
34
- } : {}));
35
- return (0, _react.useCallback)(function (url) {
36
- if (typeof window === 'undefined' || !(0, _getIsFirstPartyLink.getIsFirstPartyLink)(details) || !effectiveProduct) {
37
- return url;
38
- }
39
- var parsedUrl;
40
- try {
41
- parsedUrl = new URL(url);
42
- } catch (_unused) {
43
- return url;
44
- }
45
- if (parsedUrl.searchParams.has(_constants.XPC_CONSTANTS.QUERY_PARAM)) {
46
- return url;
47
- }
48
- return wrapUrl(url);
49
- },
50
- // Keep bridge/subproduct in the dependency array so consumers that memoize this callback
51
- // refresh when mini-modal context updates from smartLinks to rovo-chat.
52
- // eslint-disable-next-line react-hooks/exhaustive-deps
53
- [details, effectiveBridge, effectiveProduct, wrapUrl, xpcSubProduct]);
54
- };