@atlaskit/editor-plugin-card 17.4.1 → 17.4.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # @atlaskit/editor-plugin-card
2
2
 
3
+ ## 17.4.3
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+
9
+ ## 17.4.2
10
+
11
+ ### Patch Changes
12
+
13
+ - [`92da883bae00d`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/92da883bae00d) -
14
+ Use XPC-wrapped destination URL for link navigation behind `platform_smartlink_xpc_url_wrapping`.
15
+
16
+ When the feature gate is enabled, the following link-opening locations now use the cross-product
17
+ analytics parameter-enriched URL provided by SmartCard instead of the raw node URL:
18
+ - **Toolbar "Open Link" button** (both smart card and datasource paths) — uses the new
19
+ `useSmartLinkDestinationUrl` hook from
20
+ `@atlaskit/smart-card/hook/use-smart-link-destination-url` via a new `OpenLinkToolbarButton`
21
+ custom toolbar component.
22
+ - **Inline card overlay anchor** (`InlineCardOverlay`) — `href` updated to use
23
+ `useSmartLinkDestinationUrl`.
24
+ - **Hover link overlay** (`HoverLinkOverlay`) — accepts a new optional `destinationUrl` prop; when
25
+ provided and the gate is on, uses it for both the anchor `href` and double-click `window.open`.
26
+ The `destinationUrl` is computed by `inlineCardWithAwareness` using `useSmartLinkDestinationUrl`
27
+ and passed down — keeping `editor-common` free of any SmartCard provider dependency.
28
+ - **Inline card Cmd/Ctrl+click** — reads `data.destinationUrl` from SmartCard's `onClick` callback
29
+ (typed as `OnClickCallback` from `@atlaskit/smart-card/card/types`).
30
+
31
+ All changes gracefully fall back to the raw URL when the gate is off or the link has not yet
32
+ resolved.
33
+
34
+ - Updated dependencies
35
+
3
36
  ## 17.4.1
4
37
 
5
38
  ### Patch Changes
@@ -112,13 +112,13 @@ var InlineCard = exports.InlineCard = /*#__PURE__*/(0, _react.memo)(function (_r
112
112
  url: url
113
113
  });
114
114
  }, [onResolve]);
115
- var handleOnClick = (0, _react.useCallback)(function (event) {
115
+ var handleOnClick = (0, _react.useCallback)(function (event, data) {
116
116
  if (event.metaKey || event.ctrlKey) {
117
- var _pluginInjectionApi$a;
117
+ var _pluginInjectionApi$a, _data$destinationUrl;
118
118
  var _ref3 = (_pluginInjectionApi$a = pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : pluginInjectionApi.analytics) !== null && _pluginInjectionApi$a !== void 0 ? _pluginInjectionApi$a : {},
119
119
  editorAnalyticsApi = _ref3.actions;
120
120
  (0, _toolbar.visitCardLinkAnalytics)(editorAnalyticsApi, _analytics.INPUT_METHOD.META_CLICK)(view.state, view.dispatch);
121
- window.open(url, '_blank');
121
+ window.open((0, _platformFeatureFlags.fg)('platform_smartlink_xpc_url_wrapping') ? (_data$destinationUrl = data === null || data === void 0 ? void 0 : data.destinationUrl) !== null && _data$destinationUrl !== void 0 ? _data$destinationUrl : url : url, '_blank');
122
122
  } else {
123
123
  // only trigger the provided onClick callback if the meta key or ctrl key is not pressed
124
124
  propsOnClick === null || propsOnClick === void 0 || propsOnClick(event);
@@ -15,6 +15,7 @@ var _state = require("@atlaskit/editor-prosemirror/state");
15
15
  var _linkExtractors = require("@atlaskit/link-extractors");
16
16
  var _utils = require("@atlaskit/linking-common/utils");
17
17
  var _smartCard = require("@atlaskit/smart-card");
18
+ var _useSmartLinkDestinationUrl = require("@atlaskit/smart-card/hook/use-smart-link-destination-url");
18
19
  var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
19
20
  var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
20
21
  var _actions = require("../pm-plugins/actions");
@@ -59,6 +60,7 @@ var InlineCardWithAwareness = exports.InlineCardWithAwareness = /*#__PURE__*/(0,
59
60
  isResolvedViewRendered = _useState6[0],
60
61
  setIsResolvedViewRendered = _useState6[1];
61
62
  var editorAppearance = pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$c = pluginInjectionApi.card.sharedState.currentState()) === null || _pluginInjectionApi$c === void 0 ? void 0 : _pluginInjectionApi$c.editorAppearance;
63
+ var destinationUrl = (0, _useSmartLinkDestinationUrl.useSmartLinkDestinationUrl)(node.attrs.url);
62
64
  var onResolve = (0, _react.useCallback)(function (tr, title) {
63
65
  var metadata = tr.getMeta(_pluginKey.pluginKey);
64
66
  if (metadata && metadata.type === 'REGISTER') {
@@ -97,6 +99,7 @@ var InlineCardWithAwareness = exports.InlineCardWithAwareness = /*#__PURE__*/(0,
97
99
  return /*#__PURE__*/_react.default.createElement(_ui.HoverLinkOverlay, {
98
100
  isVisible: isResolvedViewRendered,
99
101
  url: node.attrs.url,
102
+ destinationUrl: destinationUrl,
100
103
  compactPadding: editorAppearance === 'comment' || editorAppearance === 'chromeless',
101
104
  editorAnalyticsApi: pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$a = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a === void 0 ? void 0 : _pluginInjectionApi$a.actions,
102
105
  view: view
@@ -115,7 +118,7 @@ var InlineCardWithAwareness = exports.InlineCardWithAwareness = /*#__PURE__*/(0,
115
118
  pluginInjectionApi: pluginInjectionApi,
116
119
  disablePreviewPanel: true
117
120
  }));
118
- }, [isResolvedViewRendered, node, editorAppearance, view, getPos, useAlternativePreloader, actionOptions, onResolve, onClick, cardContext, isHovered, isPageSSRed, provider, pluginInjectionApi]);
121
+ }, [isResolvedViewRendered, node, editorAppearance, view, getPos, useAlternativePreloader, actionOptions, onResolve, onClick, cardContext, isHovered, isPageSSRed, provider, pluginInjectionApi, destinationUrl]);
119
122
  var innerCardOriginal = (0, _react.useMemo)(function () {
120
123
  return /*#__PURE__*/_react.default.createElement(_inlineCard.InlineCard, {
121
124
  node: node,
@@ -194,6 +197,7 @@ var InlineCardWithAwareness = exports.InlineCardWithAwareness = /*#__PURE__*/(0,
194
197
  return /*#__PURE__*/_react.default.createElement(_ui.HoverLinkOverlay, {
195
198
  isVisible: isResolvedViewRendered,
196
199
  url: url,
200
+ destinationUrl: destinationUrl,
197
201
  compactPadding: editorAppearance === 'comment' || editorAppearance === 'chromeless',
198
202
  editorAnalyticsApi: pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$a4 = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a4 === void 0 ? void 0 : _pluginInjectionApi$a4.actions,
199
203
  view: view,
@@ -17,6 +17,8 @@ var _reactIntl = require("react-intl");
17
17
  var _messages = require("@atlaskit/editor-common/messages");
18
18
  var _whitespace = require("@atlaskit/editor-common/whitespace");
19
19
  var _customize = _interopRequireDefault(require("@atlaskit/icon/core/customize"));
20
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
21
+ var _useSmartLinkDestinationUrl = require("@atlaskit/smart-card/hook/use-smart-link-destination-url");
20
22
  var _utils = require("./utils");
21
23
  var _excluded = ["children", "isSelected", "isVisible", "testId", "url"];
22
24
  /* eslint-disable @atlaskit/design-system/no-nested-styles */
@@ -111,6 +113,7 @@ var gradientStyles = (0, _react2.css)({
111
113
  background: getGradientWithColor(SMART_LINK_BACKGROUND_COLOR)
112
114
  });
113
115
  var InlineCardOverlay = function InlineCardOverlay(_ref) {
116
+ var _useSmartLinkDestinat;
114
117
  var children = _ref.children,
115
118
  _ref$isSelected = _ref.isSelected,
116
119
  isSelected = _ref$isSelected === void 0 ? false : _ref$isSelected,
@@ -221,6 +224,7 @@ var InlineCardOverlay = function InlineCardOverlay(_ref) {
221
224
  observer.disconnect();
222
225
  };
223
226
  }, [isVisible, setVisibility]);
227
+ var destinationUrl = (_useSmartLinkDestinat = (0, _useSmartLinkDestinationUrl.useSmartLinkDestinationUrl)(url)) !== null && _useSmartLinkDestinat !== void 0 ? _useSmartLinkDestinat : url;
224
228
  var intl = (0, _reactIntl.useIntl)();
225
229
  var label = intl.formatMessage(_messages.cardMessages.inlineOverlay);
226
230
  return (
@@ -240,7 +244,7 @@ var InlineCardOverlay = function InlineCardOverlay(_ref) {
240
244
  width: availableWidth
241
245
  },
242
246
  "data-testid": testId,
243
- href: url,
247
+ href: (0, _platformFeatureFlags.fg)('platform_smartlink_xpc_url_wrapping') ? destinationUrl : url,
244
248
  onClick: function onClick(e) {
245
249
  return e.preventDefault();
246
250
  },
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ var _typeof = require("@babel/runtime/helpers/typeof");
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.OpenLinkToolbarButton = void 0;
9
+ var _react = _interopRequireWildcard(require("react"));
10
+ var _ui = require("@atlaskit/editor-common/ui");
11
+ var _linkExternal = _interopRequireDefault(require("@atlaskit/icon/core/link-external"));
12
+ var _useSmartLinkDestinationUrl = require("@atlaskit/smart-card/hook/use-smart-link-destination-url");
13
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
14
+ /**
15
+ * Toolbar button that opens a Smart Link URL in a new tab, with the XPC-wrapped destination URL.
16
+ *
17
+ * This component is only rendered when `fg('platform_smartlink_xpc_url_wrapping')` is ON.
18
+ * It wraps `FloatingToolbarButton` and replaces `href` with the resolved destination URL
19
+ * (cross-product analytics parameters appended), falling back to the raw `url` when the
20
+ * link is unresolved or not a first-party Atlassian link.
21
+ */
22
+ var OpenLinkToolbarButton = exports.OpenLinkToolbarButton = function OpenLinkToolbarButton(_ref) {
23
+ var url = _ref.url,
24
+ areAnyNewToolbarFlagsEnabled = _ref.areAnyNewToolbarFlagsEnabled,
25
+ editorView = _ref.editorView,
26
+ onClick = _ref.onClick,
27
+ title = _ref.title;
28
+ var destinationUrl = (0, _useSmartLinkDestinationUrl.useSmartLinkDestinationUrl)(url);
29
+ var handleClick = (0, _react.useCallback)(function () {
30
+ onClick(editorView.state, editorView.dispatch);
31
+ }, [editorView, onClick]);
32
+ return /*#__PURE__*/_react.default.createElement(_ui.FloatingToolbarButton
33
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
34
+ , {
35
+ className: "hyperlink-open-link",
36
+ title: title,
37
+ icon: /*#__PURE__*/_react.default.createElement(_linkExternal.default, {
38
+ label: ""
39
+ }),
40
+ href: destinationUrl,
41
+ target: "_blank",
42
+ onClick: handleClick,
43
+ areAnyNewToolbarFlagsEnabled: areAnyNewToolbarFlagsEnabled
44
+ });
45
+ };
@@ -28,6 +28,7 @@ var _edit = _interopRequireDefault(require("@atlaskit/icon/core/edit"));
28
28
  var _linkBroken = _interopRequireDefault(require("@atlaskit/icon/core/link-broken"));
29
29
  var _linkExternal = _interopRequireDefault(require("@atlaskit/icon/core/link-external"));
30
30
  var _settings = _interopRequireDefault(require("@atlaskit/icon/core/settings"));
31
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
31
32
  var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
32
33
  var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
33
34
  var _doc = require("../pm-plugins/doc");
@@ -40,6 +41,7 @@ var _HyperlinkToolbarAppearance = require("./HyperlinkToolbarAppearance");
40
41
  var _HyperlinkToolbarAppearanceDropdown = require("./HyperlinkToolbarAppearanceDropdown");
41
42
  var _LinkToolbarAppearance = require("./LinkToolbarAppearance");
42
43
  var _LinkToolbarAppearanceDropdown = require("./LinkToolbarAppearanceDropdown");
44
+ var _OpenLinkToolbarButton = require("./OpenLinkToolbarButton");
43
45
  var _OpenPreviewButton = require("./OpenPreviewButton");
44
46
  var _ToolbarViewedEvent = require("./ToolbarViewedEvent");
45
47
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
@@ -370,7 +372,7 @@ var generateToolbarItems = function generateToolbarItems(state, intl, providerFa
370
372
  }
371
373
  }] : [];
372
374
  var resolvedToolbarAttributes = url ? (_pluginState$resolved = pluginState === null || pluginState === void 0 ? void 0 : pluginState.resolvedToolbarAttributesByUrl[url]) !== null && _pluginState$resolved !== void 0 ? _pluginState$resolved : {} : {};
373
- var openLinkToolbarItem = {
375
+ var openLinkToolbarItemFallback = {
374
376
  id: 'editor.link.openLink',
375
377
  type: 'button',
376
378
  icon: _linkExternal.default,
@@ -382,6 +384,19 @@ var generateToolbarItems = function generateToolbarItems(state, intl, providerFa
382
384
  href: url,
383
385
  target: '_blank'
384
386
  };
387
+ var openLinkToolbarItem = (0, _platformFeatureFlags.fg)('platform_smartlink_xpc_url_wrapping') ? {
388
+ type: 'custom',
389
+ fallback: [openLinkToolbarItemFallback],
390
+ render: function render(editorView) {
391
+ return editorView && url ? /*#__PURE__*/_react.default.createElement(_OpenLinkToolbarButton.OpenLinkToolbarButton, {
392
+ url: url,
393
+ title: intl.formatMessage(_messages.linkMessages.openLink),
394
+ editorView: editorView,
395
+ onClick: fireOpenLinkToolbarAnalytics(editorAnalyticsApi, openLinkInputMethod, resolvedToolbarAttributes),
396
+ areAnyNewToolbarFlagsEnabled: !areAllNewToolbarFlagsDisabled
397
+ }) : null;
398
+ }
399
+ } : openLinkToolbarItemFallback;
385
400
  var toolbarItems = areAllNewToolbarFlagsDisabled ? [].concat(editItems, commentItems, openPreviewPanelItems, [openLinkToolbarItem, {
386
401
  type: 'separator'
387
402
  }], (0, _toConsumableArray2.default)(getUnlinkButtonGroup(state, intl, node, inlineCard, editorAnalyticsApi, !areAllNewToolbarFlagsDisabled)), [{
@@ -646,7 +661,7 @@ var getDatasourceButtonGroup = function getDatasourceButtonGroup(metadata, intl,
646
661
  });
647
662
  if (node !== null && node !== void 0 && (_node$attrs3 = node.attrs) !== null && _node$attrs3 !== void 0 && _node$attrs3.url) {
648
663
  var _pluginState$resolved2;
649
- toolbarItems.push({
664
+ var openLinkToolbarItemFallback = {
650
665
  id: 'editor.link.openLink',
651
666
  type: 'button',
652
667
  icon: _linkExternal.default,
@@ -657,7 +672,21 @@ var getDatasourceButtonGroup = function getDatasourceButtonGroup(metadata, intl,
657
672
  onClick: fireOpenLinkToolbarAnalytics(editorAnalyticsApi, openLinkInputMethod, (_pluginState$resolved2 = pluginState === null || pluginState === void 0 ? void 0 : pluginState.resolvedToolbarAttributesByUrl[node.attrs.url]) !== null && _pluginState$resolved2 !== void 0 ? _pluginState$resolved2 : {}),
658
673
  href: node.attrs.url,
659
674
  target: '_blank'
660
- });
675
+ };
676
+ toolbarItems.push((0, _platformFeatureFlags.fg)('platform_smartlink_xpc_url_wrapping') ? {
677
+ type: 'custom',
678
+ fallback: [openLinkToolbarItemFallback],
679
+ render: function render(editorView) {
680
+ var _pluginState$resolved3;
681
+ return editorView ? /*#__PURE__*/_react.default.createElement(_OpenLinkToolbarButton.OpenLinkToolbarButton, {
682
+ url: node.attrs.url,
683
+ title: intl.formatMessage(_messages.linkMessages.openLink),
684
+ editorView: editorView,
685
+ onClick: fireOpenLinkToolbarAnalytics(editorAnalyticsApi, openLinkInputMethod, (_pluginState$resolved3 = pluginState === null || pluginState === void 0 ? void 0 : pluginState.resolvedToolbarAttributesByUrl[node.attrs.url]) !== null && _pluginState$resolved3 !== void 0 ? _pluginState$resolved3 : {}),
686
+ areAnyNewToolbarFlagsEnabled: !areAllNewToolbarFlagsDisabled
687
+ }) : null;
688
+ }
689
+ } : openLinkToolbarItemFallback);
661
690
  if (areAllNewToolbarFlagsDisabled) {
662
691
  toolbarItems.push({
663
692
  type: 'separator'
@@ -107,14 +107,14 @@ export const InlineCard = /*#__PURE__*/memo(({
107
107
  url
108
108
  });
109
109
  }, [onResolve]);
110
- const handleOnClick = useCallback(event => {
110
+ const handleOnClick = useCallback((event, data) => {
111
111
  if (event.metaKey || event.ctrlKey) {
112
- var _pluginInjectionApi$a;
112
+ var _pluginInjectionApi$a, _data$destinationUrl;
113
113
  const {
114
114
  actions: editorAnalyticsApi
115
115
  } = (_pluginInjectionApi$a = pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : pluginInjectionApi.analytics) !== null && _pluginInjectionApi$a !== void 0 ? _pluginInjectionApi$a : {};
116
116
  visitCardLinkAnalytics(editorAnalyticsApi, INPUT_METHOD.META_CLICK)(view.state, view.dispatch);
117
- window.open(url, '_blank');
117
+ window.open(fg('platform_smartlink_xpc_url_wrapping') ? (_data$destinationUrl = data === null || data === void 0 ? void 0 : data.destinationUrl) !== null && _data$destinationUrl !== void 0 ? _data$destinationUrl : url : url, '_blank');
118
118
  } else {
119
119
  // only trigger the provided onClick callback if the meta key or ctrl key is not pressed
120
120
  propsOnClick === null || propsOnClick === void 0 ? void 0 : propsOnClick(event);
@@ -6,6 +6,7 @@ import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
6
6
  import { extractSmartLinkEmbed } from '@atlaskit/link-extractors';
7
7
  import { isWithinPreviewPanelIFrame } from '@atlaskit/linking-common/utils';
8
8
  import { getObjectAri, getObjectName, getObjectIconUrl } from '@atlaskit/smart-card';
9
+ import { useSmartLinkDestinationUrl } from '@atlaskit/smart-card/hook/use-smart-link-destination-url';
9
10
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
10
11
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
11
12
  import { registerRemoveOverlay } from '../pm-plugins/actions';
@@ -41,6 +42,7 @@ export const InlineCardWithAwareness = /*#__PURE__*/memo(({
41
42
  const [isInserted, setIsInserted] = useState(false);
42
43
  const [isResolvedViewRendered, setIsResolvedViewRendered] = useState(false);
43
44
  const editorAppearance = pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$c = pluginInjectionApi.card.sharedState.currentState()) === null || _pluginInjectionApi$c === void 0 ? void 0 : _pluginInjectionApi$c.editorAppearance;
45
+ const destinationUrl = useSmartLinkDestinationUrl(node.attrs.url);
44
46
  const onResolve = useCallback((tr, title) => {
45
47
  const metadata = tr.getMeta(pluginKey);
46
48
  if (metadata && metadata.type === 'REGISTER') {
@@ -76,6 +78,7 @@ export const InlineCardWithAwareness = /*#__PURE__*/memo(({
76
78
  return /*#__PURE__*/React.createElement(HoverLinkOverlay, {
77
79
  isVisible: isResolvedViewRendered,
78
80
  url: node.attrs.url,
81
+ destinationUrl: destinationUrl,
79
82
  compactPadding: editorAppearance === 'comment' || editorAppearance === 'chromeless',
80
83
  editorAnalyticsApi: pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$a = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a === void 0 ? void 0 : _pluginInjectionApi$a.actions,
81
84
  view: view
@@ -94,7 +97,7 @@ export const InlineCardWithAwareness = /*#__PURE__*/memo(({
94
97
  pluginInjectionApi: pluginInjectionApi,
95
98
  disablePreviewPanel: true
96
99
  }));
97
- }, [isResolvedViewRendered, node, editorAppearance, view, getPos, useAlternativePreloader, actionOptions, onResolve, onClick, cardContext, isHovered, isPageSSRed, provider, pluginInjectionApi]);
100
+ }, [isResolvedViewRendered, node, editorAppearance, view, getPos, useAlternativePreloader, actionOptions, onResolve, onClick, cardContext, isHovered, isPageSSRed, provider, pluginInjectionApi, destinationUrl]);
98
101
  const innerCardOriginal = useMemo(() => /*#__PURE__*/React.createElement(InlineCard, {
99
102
  node: node,
100
103
  view: view,
@@ -173,6 +176,7 @@ export const InlineCardWithAwareness = /*#__PURE__*/memo(({
173
176
  return /*#__PURE__*/React.createElement(HoverLinkOverlay, {
174
177
  isVisible: isResolvedViewRendered,
175
178
  url: url,
179
+ destinationUrl: destinationUrl,
176
180
  compactPadding: editorAppearance === 'comment' || editorAppearance === 'chromeless',
177
181
  editorAnalyticsApi: pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$a5 = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a5 === void 0 ? void 0 : _pluginInjectionApi$a5.actions,
178
182
  view: view,
@@ -14,6 +14,8 @@ import { useIntl } from 'react-intl';
14
14
  import { cardMessages as messages } from '@atlaskit/editor-common/messages';
15
15
  import { ZERO_WIDTH_JOINER } from '@atlaskit/editor-common/whitespace';
16
16
  import CustomizeIcon from '@atlaskit/icon/core/customize';
17
+ import { fg } from '@atlaskit/platform-feature-flags';
18
+ import { useSmartLinkDestinationUrl } from '@atlaskit/smart-card/hook/use-smart-link-destination-url';
17
19
  import { getChildElement, getInlineCardAvailableWidth, getOverlayWidths, isOneLine } from './utils';
18
20
  const DEBOUNCE_IN_MS = 5;
19
21
  const ESTIMATED_MIN_WIDTH_IN_PX = 16;
@@ -111,6 +113,7 @@ const InlineCardOverlay = ({
111
113
  url,
112
114
  ...props
113
115
  }) => {
116
+ var _useSmartLinkDestinat;
114
117
  const [showOverlay, setShowOverlay] = useState(false);
115
118
  const [showLabel, setShowLabel] = useState(true);
116
119
  const [availableWidth, setAvailableWidth] = useState(undefined);
@@ -204,6 +207,7 @@ const InlineCardOverlay = ({
204
207
  observer.disconnect();
205
208
  };
206
209
  }, [isVisible, setVisibility]);
210
+ const destinationUrl = (_useSmartLinkDestinat = useSmartLinkDestinationUrl(url)) !== null && _useSmartLinkDestinat !== void 0 ? _useSmartLinkDestinat : url;
207
211
  const intl = useIntl();
208
212
  const label = intl.formatMessage(messages.inlineOverlay);
209
213
  return (
@@ -223,7 +227,7 @@ const InlineCardOverlay = ({
223
227
  width: availableWidth
224
228
  },
225
229
  "data-testid": testId,
226
- href: url,
230
+ href: fg('platform_smartlink_xpc_url_wrapping') ? destinationUrl : url,
227
231
  onClick: e => e.preventDefault(),
228
232
  tabIndex: -1
229
233
  }, jsx("span", {
@@ -0,0 +1,37 @@
1
+ import React, { useCallback } from 'react';
2
+ import { FloatingToolbarButton as Button } from '@atlaskit/editor-common/ui';
3
+ import LinkExternalIcon from '@atlaskit/icon/core/link-external';
4
+ import { useSmartLinkDestinationUrl } from '@atlaskit/smart-card/hook/use-smart-link-destination-url';
5
+ /**
6
+ * Toolbar button that opens a Smart Link URL in a new tab, with the XPC-wrapped destination URL.
7
+ *
8
+ * This component is only rendered when `fg('platform_smartlink_xpc_url_wrapping')` is ON.
9
+ * It wraps `FloatingToolbarButton` and replaces `href` with the resolved destination URL
10
+ * (cross-product analytics parameters appended), falling back to the raw `url` when the
11
+ * link is unresolved or not a first-party Atlassian link.
12
+ */
13
+ export const OpenLinkToolbarButton = ({
14
+ url,
15
+ areAnyNewToolbarFlagsEnabled,
16
+ editorView,
17
+ onClick,
18
+ title
19
+ }) => {
20
+ const destinationUrl = useSmartLinkDestinationUrl(url);
21
+ const handleClick = useCallback(() => {
22
+ onClick(editorView.state, editorView.dispatch);
23
+ }, [editorView, onClick]);
24
+ return /*#__PURE__*/React.createElement(Button
25
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
26
+ , {
27
+ className: "hyperlink-open-link",
28
+ title: title,
29
+ icon: /*#__PURE__*/React.createElement(LinkExternalIcon, {
30
+ label: ""
31
+ }),
32
+ href: destinationUrl,
33
+ target: "_blank",
34
+ onClick: handleClick,
35
+ areAnyNewToolbarFlagsEnabled: areAnyNewToolbarFlagsEnabled
36
+ });
37
+ };
@@ -18,6 +18,7 @@ import EditIcon from '@atlaskit/icon/core/edit';
18
18
  import LinkBrokenIcon from '@atlaskit/icon/core/link-broken';
19
19
  import LinkExternalIcon from '@atlaskit/icon/core/link-external';
20
20
  import CogIcon from '@atlaskit/icon/core/settings';
21
+ import { fg } from '@atlaskit/platform-feature-flags';
21
22
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
22
23
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
23
24
  import { changeSelectedCardToText } from '../pm-plugins/doc';
@@ -30,6 +31,7 @@ import { HyperlinkToolbarAppearance } from './HyperlinkToolbarAppearance';
30
31
  import { getCustomHyperlinkAppearanceDropdown } from './HyperlinkToolbarAppearanceDropdown';
31
32
  import { LinkToolbarAppearance } from './LinkToolbarAppearance';
32
33
  import { getLinkAppearanceDropdown } from './LinkToolbarAppearanceDropdown';
34
+ import { OpenLinkToolbarButton } from './OpenLinkToolbarButton';
33
35
  import { OpenPreviewPanelToolbarButton } from './OpenPreviewButton';
34
36
  import { ToolbarViewedEvent } from './ToolbarViewedEvent';
35
37
  export const removeCard = editorAnalyticsApi => commandWithMetadata((state, dispatch) => {
@@ -355,7 +357,7 @@ const generateToolbarItems = (state, intl, providerFactory, cardOptions, lpLinkP
355
357
  })
356
358
  }] : [];
357
359
  const resolvedToolbarAttributes = url ? (_pluginState$resolved = pluginState === null || pluginState === void 0 ? void 0 : pluginState.resolvedToolbarAttributesByUrl[url]) !== null && _pluginState$resolved !== void 0 ? _pluginState$resolved : {} : {};
358
- const openLinkToolbarItem = {
360
+ const openLinkToolbarItemFallback = {
359
361
  id: 'editor.link.openLink',
360
362
  type: 'button',
361
363
  icon: LinkExternalIcon,
@@ -367,6 +369,17 @@ const generateToolbarItems = (state, intl, providerFactory, cardOptions, lpLinkP
367
369
  href: url,
368
370
  target: '_blank'
369
371
  };
372
+ const openLinkToolbarItem = fg('platform_smartlink_xpc_url_wrapping') ? {
373
+ type: 'custom',
374
+ fallback: [openLinkToolbarItemFallback],
375
+ render: editorView => editorView && url ? /*#__PURE__*/React.createElement(OpenLinkToolbarButton, {
376
+ url: url,
377
+ title: intl.formatMessage(linkMessages.openLink),
378
+ editorView: editorView,
379
+ onClick: fireOpenLinkToolbarAnalytics(editorAnalyticsApi, openLinkInputMethod, resolvedToolbarAttributes),
380
+ areAnyNewToolbarFlagsEnabled: !areAllNewToolbarFlagsDisabled
381
+ }) : null
382
+ } : openLinkToolbarItemFallback;
370
383
  const toolbarItems = areAllNewToolbarFlagsDisabled ? [...editItems, ...commentItems, ...openPreviewPanelItems, openLinkToolbarItem, {
371
384
  type: 'separator'
372
385
  }, ...getUnlinkButtonGroup(state, intl, node, inlineCard, editorAnalyticsApi, !areAllNewToolbarFlagsDisabled), {
@@ -628,7 +641,7 @@ const getDatasourceButtonGroup = (metadata, intl, editorAnalyticsApi, node, hove
628
641
  });
629
642
  if (node !== null && node !== void 0 && (_node$attrs3 = node.attrs) !== null && _node$attrs3 !== void 0 && _node$attrs3.url) {
630
643
  var _pluginState$resolved2;
631
- toolbarItems.push({
644
+ const openLinkToolbarItemFallback = {
632
645
  id: 'editor.link.openLink',
633
646
  type: 'button',
634
647
  icon: LinkExternalIcon,
@@ -639,7 +652,21 @@ const getDatasourceButtonGroup = (metadata, intl, editorAnalyticsApi, node, hove
639
652
  onClick: fireOpenLinkToolbarAnalytics(editorAnalyticsApi, openLinkInputMethod, (_pluginState$resolved2 = pluginState === null || pluginState === void 0 ? void 0 : pluginState.resolvedToolbarAttributesByUrl[node.attrs.url]) !== null && _pluginState$resolved2 !== void 0 ? _pluginState$resolved2 : {}),
640
653
  href: node.attrs.url,
641
654
  target: '_blank'
642
- });
655
+ };
656
+ toolbarItems.push(fg('platform_smartlink_xpc_url_wrapping') ? {
657
+ type: 'custom',
658
+ fallback: [openLinkToolbarItemFallback],
659
+ render: editorView => {
660
+ var _pluginState$resolved3;
661
+ return editorView ? /*#__PURE__*/React.createElement(OpenLinkToolbarButton, {
662
+ url: node.attrs.url,
663
+ title: intl.formatMessage(linkMessages.openLink),
664
+ editorView: editorView,
665
+ onClick: fireOpenLinkToolbarAnalytics(editorAnalyticsApi, openLinkInputMethod, (_pluginState$resolved3 = pluginState === null || pluginState === void 0 ? void 0 : pluginState.resolvedToolbarAttributesByUrl[node.attrs.url]) !== null && _pluginState$resolved3 !== void 0 ? _pluginState$resolved3 : {}),
666
+ areAnyNewToolbarFlagsEnabled: !areAllNewToolbarFlagsDisabled
667
+ }) : null;
668
+ }
669
+ } : openLinkToolbarItemFallback);
643
670
  if (areAllNewToolbarFlagsDisabled) {
644
671
  toolbarItems.push({
645
672
  type: 'separator'
@@ -100,13 +100,13 @@ export var InlineCard = /*#__PURE__*/memo(function (_ref) {
100
100
  url: url
101
101
  });
102
102
  }, [onResolve]);
103
- var handleOnClick = useCallback(function (event) {
103
+ var handleOnClick = useCallback(function (event, data) {
104
104
  if (event.metaKey || event.ctrlKey) {
105
- var _pluginInjectionApi$a;
105
+ var _pluginInjectionApi$a, _data$destinationUrl;
106
106
  var _ref3 = (_pluginInjectionApi$a = pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : pluginInjectionApi.analytics) !== null && _pluginInjectionApi$a !== void 0 ? _pluginInjectionApi$a : {},
107
107
  editorAnalyticsApi = _ref3.actions;
108
108
  visitCardLinkAnalytics(editorAnalyticsApi, INPUT_METHOD.META_CLICK)(view.state, view.dispatch);
109
- window.open(url, '_blank');
109
+ window.open(fg('platform_smartlink_xpc_url_wrapping') ? (_data$destinationUrl = data === null || data === void 0 ? void 0 : data.destinationUrl) !== null && _data$destinationUrl !== void 0 ? _data$destinationUrl : url : url, '_blank');
110
110
  } else {
111
111
  // only trigger the provided onClick callback if the meta key or ctrl key is not pressed
112
112
  propsOnClick === null || propsOnClick === void 0 || propsOnClick(event);
@@ -7,6 +7,7 @@ import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
7
7
  import { extractSmartLinkEmbed } from '@atlaskit/link-extractors';
8
8
  import { isWithinPreviewPanelIFrame } from '@atlaskit/linking-common/utils';
9
9
  import { getObjectAri, getObjectName, getObjectIconUrl } from '@atlaskit/smart-card';
10
+ import { useSmartLinkDestinationUrl } from '@atlaskit/smart-card/hook/use-smart-link-destination-url';
10
11
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
11
12
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
12
13
  import { registerRemoveOverlay } from '../pm-plugins/actions';
@@ -50,6 +51,7 @@ export var InlineCardWithAwareness = /*#__PURE__*/memo(function (_ref) {
50
51
  isResolvedViewRendered = _useState6[0],
51
52
  setIsResolvedViewRendered = _useState6[1];
52
53
  var editorAppearance = pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$c = pluginInjectionApi.card.sharedState.currentState()) === null || _pluginInjectionApi$c === void 0 ? void 0 : _pluginInjectionApi$c.editorAppearance;
54
+ var destinationUrl = useSmartLinkDestinationUrl(node.attrs.url);
53
55
  var onResolve = useCallback(function (tr, title) {
54
56
  var metadata = tr.getMeta(pluginKey);
55
57
  if (metadata && metadata.type === 'REGISTER') {
@@ -88,6 +90,7 @@ export var InlineCardWithAwareness = /*#__PURE__*/memo(function (_ref) {
88
90
  return /*#__PURE__*/React.createElement(HoverLinkOverlay, {
89
91
  isVisible: isResolvedViewRendered,
90
92
  url: node.attrs.url,
93
+ destinationUrl: destinationUrl,
91
94
  compactPadding: editorAppearance === 'comment' || editorAppearance === 'chromeless',
92
95
  editorAnalyticsApi: pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$a = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a === void 0 ? void 0 : _pluginInjectionApi$a.actions,
93
96
  view: view
@@ -106,7 +109,7 @@ export var InlineCardWithAwareness = /*#__PURE__*/memo(function (_ref) {
106
109
  pluginInjectionApi: pluginInjectionApi,
107
110
  disablePreviewPanel: true
108
111
  }));
109
- }, [isResolvedViewRendered, node, editorAppearance, view, getPos, useAlternativePreloader, actionOptions, onResolve, onClick, cardContext, isHovered, isPageSSRed, provider, pluginInjectionApi]);
112
+ }, [isResolvedViewRendered, node, editorAppearance, view, getPos, useAlternativePreloader, actionOptions, onResolve, onClick, cardContext, isHovered, isPageSSRed, provider, pluginInjectionApi, destinationUrl]);
110
113
  var innerCardOriginal = useMemo(function () {
111
114
  return /*#__PURE__*/React.createElement(InlineCard, {
112
115
  node: node,
@@ -185,6 +188,7 @@ export var InlineCardWithAwareness = /*#__PURE__*/memo(function (_ref) {
185
188
  return /*#__PURE__*/React.createElement(HoverLinkOverlay, {
186
189
  isVisible: isResolvedViewRendered,
187
190
  url: url,
191
+ destinationUrl: destinationUrl,
188
192
  compactPadding: editorAppearance === 'comment' || editorAppearance === 'chromeless',
189
193
  editorAnalyticsApi: pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$a4 = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a4 === void 0 ? void 0 : _pluginInjectionApi$a4.actions,
190
194
  view: view,
@@ -18,6 +18,8 @@ import { useIntl } from 'react-intl';
18
18
  import { cardMessages as messages } from '@atlaskit/editor-common/messages';
19
19
  import { ZERO_WIDTH_JOINER } from '@atlaskit/editor-common/whitespace';
20
20
  import CustomizeIcon from '@atlaskit/icon/core/customize';
21
+ import { fg } from '@atlaskit/platform-feature-flags';
22
+ import { useSmartLinkDestinationUrl } from '@atlaskit/smart-card/hook/use-smart-link-destination-url';
21
23
  import { getChildElement, getInlineCardAvailableWidth, getOverlayWidths, isOneLine } from './utils';
22
24
  var DEBOUNCE_IN_MS = 5;
23
25
  var ESTIMATED_MIN_WIDTH_IN_PX = 16;
@@ -103,6 +105,7 @@ var gradientStyles = css({
103
105
  background: getGradientWithColor(SMART_LINK_BACKGROUND_COLOR)
104
106
  });
105
107
  var InlineCardOverlay = function InlineCardOverlay(_ref) {
108
+ var _useSmartLinkDestinat;
106
109
  var children = _ref.children,
107
110
  _ref$isSelected = _ref.isSelected,
108
111
  isSelected = _ref$isSelected === void 0 ? false : _ref$isSelected,
@@ -213,6 +216,7 @@ var InlineCardOverlay = function InlineCardOverlay(_ref) {
213
216
  observer.disconnect();
214
217
  };
215
218
  }, [isVisible, setVisibility]);
219
+ var destinationUrl = (_useSmartLinkDestinat = useSmartLinkDestinationUrl(url)) !== null && _useSmartLinkDestinat !== void 0 ? _useSmartLinkDestinat : url;
216
220
  var intl = useIntl();
217
221
  var label = intl.formatMessage(messages.inlineOverlay);
218
222
  return (
@@ -232,7 +236,7 @@ var InlineCardOverlay = function InlineCardOverlay(_ref) {
232
236
  width: availableWidth
233
237
  },
234
238
  "data-testid": testId,
235
- href: url,
239
+ href: fg('platform_smartlink_xpc_url_wrapping') ? destinationUrl : url,
236
240
  onClick: function onClick(e) {
237
241
  return e.preventDefault();
238
242
  },
@@ -0,0 +1,36 @@
1
+ import React, { useCallback } from 'react';
2
+ import { FloatingToolbarButton as Button } from '@atlaskit/editor-common/ui';
3
+ import LinkExternalIcon from '@atlaskit/icon/core/link-external';
4
+ import { useSmartLinkDestinationUrl } from '@atlaskit/smart-card/hook/use-smart-link-destination-url';
5
+ /**
6
+ * Toolbar button that opens a Smart Link URL in a new tab, with the XPC-wrapped destination URL.
7
+ *
8
+ * This component is only rendered when `fg('platform_smartlink_xpc_url_wrapping')` is ON.
9
+ * It wraps `FloatingToolbarButton` and replaces `href` with the resolved destination URL
10
+ * (cross-product analytics parameters appended), falling back to the raw `url` when the
11
+ * link is unresolved or not a first-party Atlassian link.
12
+ */
13
+ export var OpenLinkToolbarButton = function OpenLinkToolbarButton(_ref) {
14
+ var url = _ref.url,
15
+ areAnyNewToolbarFlagsEnabled = _ref.areAnyNewToolbarFlagsEnabled,
16
+ editorView = _ref.editorView,
17
+ onClick = _ref.onClick,
18
+ title = _ref.title;
19
+ var destinationUrl = useSmartLinkDestinationUrl(url);
20
+ var handleClick = useCallback(function () {
21
+ onClick(editorView.state, editorView.dispatch);
22
+ }, [editorView, onClick]);
23
+ return /*#__PURE__*/React.createElement(Button
24
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
25
+ , {
26
+ className: "hyperlink-open-link",
27
+ title: title,
28
+ icon: /*#__PURE__*/React.createElement(LinkExternalIcon, {
29
+ label: ""
30
+ }),
31
+ href: destinationUrl,
32
+ target: "_blank",
33
+ onClick: handleClick,
34
+ areAnyNewToolbarFlagsEnabled: areAnyNewToolbarFlagsEnabled
35
+ });
36
+ };
@@ -22,6 +22,7 @@ import EditIcon from '@atlaskit/icon/core/edit';
22
22
  import LinkBrokenIcon from '@atlaskit/icon/core/link-broken';
23
23
  import LinkExternalIcon from '@atlaskit/icon/core/link-external';
24
24
  import CogIcon from '@atlaskit/icon/core/settings';
25
+ import { fg } from '@atlaskit/platform-feature-flags';
25
26
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
26
27
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
27
28
  import { changeSelectedCardToText } from '../pm-plugins/doc';
@@ -34,6 +35,7 @@ import { HyperlinkToolbarAppearance } from './HyperlinkToolbarAppearance';
34
35
  import { getCustomHyperlinkAppearanceDropdown } from './HyperlinkToolbarAppearanceDropdown';
35
36
  import { LinkToolbarAppearance } from './LinkToolbarAppearance';
36
37
  import { getLinkAppearanceDropdown } from './LinkToolbarAppearanceDropdown';
38
+ import { OpenLinkToolbarButton } from './OpenLinkToolbarButton';
37
39
  import { OpenPreviewPanelToolbarButton } from './OpenPreviewButton';
38
40
  import { ToolbarViewedEvent } from './ToolbarViewedEvent';
39
41
  export var removeCard = function removeCard(editorAnalyticsApi) {
@@ -361,7 +363,7 @@ var generateToolbarItems = function generateToolbarItems(state, intl, providerFa
361
363
  }
362
364
  }] : [];
363
365
  var resolvedToolbarAttributes = url ? (_pluginState$resolved = pluginState === null || pluginState === void 0 ? void 0 : pluginState.resolvedToolbarAttributesByUrl[url]) !== null && _pluginState$resolved !== void 0 ? _pluginState$resolved : {} : {};
364
- var openLinkToolbarItem = {
366
+ var openLinkToolbarItemFallback = {
365
367
  id: 'editor.link.openLink',
366
368
  type: 'button',
367
369
  icon: LinkExternalIcon,
@@ -373,6 +375,19 @@ var generateToolbarItems = function generateToolbarItems(state, intl, providerFa
373
375
  href: url,
374
376
  target: '_blank'
375
377
  };
378
+ var openLinkToolbarItem = fg('platform_smartlink_xpc_url_wrapping') ? {
379
+ type: 'custom',
380
+ fallback: [openLinkToolbarItemFallback],
381
+ render: function render(editorView) {
382
+ return editorView && url ? /*#__PURE__*/React.createElement(OpenLinkToolbarButton, {
383
+ url: url,
384
+ title: intl.formatMessage(linkMessages.openLink),
385
+ editorView: editorView,
386
+ onClick: fireOpenLinkToolbarAnalytics(editorAnalyticsApi, openLinkInputMethod, resolvedToolbarAttributes),
387
+ areAnyNewToolbarFlagsEnabled: !areAllNewToolbarFlagsDisabled
388
+ }) : null;
389
+ }
390
+ } : openLinkToolbarItemFallback;
376
391
  var toolbarItems = areAllNewToolbarFlagsDisabled ? [].concat(editItems, commentItems, openPreviewPanelItems, [openLinkToolbarItem, {
377
392
  type: 'separator'
378
393
  }], _toConsumableArray(getUnlinkButtonGroup(state, intl, node, inlineCard, editorAnalyticsApi, !areAllNewToolbarFlagsDisabled)), [{
@@ -637,7 +652,7 @@ var getDatasourceButtonGroup = function getDatasourceButtonGroup(metadata, intl,
637
652
  });
638
653
  if (node !== null && node !== void 0 && (_node$attrs3 = node.attrs) !== null && _node$attrs3 !== void 0 && _node$attrs3.url) {
639
654
  var _pluginState$resolved2;
640
- toolbarItems.push({
655
+ var openLinkToolbarItemFallback = {
641
656
  id: 'editor.link.openLink',
642
657
  type: 'button',
643
658
  icon: LinkExternalIcon,
@@ -648,7 +663,21 @@ var getDatasourceButtonGroup = function getDatasourceButtonGroup(metadata, intl,
648
663
  onClick: fireOpenLinkToolbarAnalytics(editorAnalyticsApi, openLinkInputMethod, (_pluginState$resolved2 = pluginState === null || pluginState === void 0 ? void 0 : pluginState.resolvedToolbarAttributesByUrl[node.attrs.url]) !== null && _pluginState$resolved2 !== void 0 ? _pluginState$resolved2 : {}),
649
664
  href: node.attrs.url,
650
665
  target: '_blank'
651
- });
666
+ };
667
+ toolbarItems.push(fg('platform_smartlink_xpc_url_wrapping') ? {
668
+ type: 'custom',
669
+ fallback: [openLinkToolbarItemFallback],
670
+ render: function render(editorView) {
671
+ var _pluginState$resolved3;
672
+ return editorView ? /*#__PURE__*/React.createElement(OpenLinkToolbarButton, {
673
+ url: node.attrs.url,
674
+ title: intl.formatMessage(linkMessages.openLink),
675
+ editorView: editorView,
676
+ onClick: fireOpenLinkToolbarAnalytics(editorAnalyticsApi, openLinkInputMethod, (_pluginState$resolved3 = pluginState === null || pluginState === void 0 ? void 0 : pluginState.resolvedToolbarAttributesByUrl[node.attrs.url]) !== null && _pluginState$resolved3 !== void 0 ? _pluginState$resolved3 : {}),
677
+ areAnyNewToolbarFlagsEnabled: !areAllNewToolbarFlagsDisabled
678
+ }) : null;
679
+ }
680
+ } : openLinkToolbarItemFallback);
652
681
  if (areAllNewToolbarFlagsDisabled) {
653
682
  toolbarItems.push({
654
683
  type: 'separator'
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ import type { Command } from '@atlaskit/editor-common/types';
3
+ import type { EditorView } from '@atlaskit/editor-prosemirror/view';
4
+ type OpenLinkToolbarButtonProps = {
5
+ areAnyNewToolbarFlagsEnabled: boolean;
6
+ editorView: EditorView;
7
+ onClick: Command;
8
+ title: string;
9
+ url: string;
10
+ };
11
+ /**
12
+ * Toolbar button that opens a Smart Link URL in a new tab, with the XPC-wrapped destination URL.
13
+ *
14
+ * This component is only rendered when `fg('platform_smartlink_xpc_url_wrapping')` is ON.
15
+ * It wraps `FloatingToolbarButton` and replaces `href` with the resolved destination URL
16
+ * (cross-product analytics parameters appended), falling back to the raw `url` when the
17
+ * link is unresolved or not a first-party Atlassian link.
18
+ */
19
+ export declare const OpenLinkToolbarButton: ({ url, areAnyNewToolbarFlagsEnabled, editorView, onClick, title, }: OpenLinkToolbarButtonProps) => React.JSX.Element;
20
+ export {};
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ import type { Command } from '@atlaskit/editor-common/types';
3
+ import type { EditorView } from '@atlaskit/editor-prosemirror/view';
4
+ type OpenLinkToolbarButtonProps = {
5
+ areAnyNewToolbarFlagsEnabled: boolean;
6
+ editorView: EditorView;
7
+ onClick: Command;
8
+ title: string;
9
+ url: string;
10
+ };
11
+ /**
12
+ * Toolbar button that opens a Smart Link URL in a new tab, with the XPC-wrapped destination URL.
13
+ *
14
+ * This component is only rendered when `fg('platform_smartlink_xpc_url_wrapping')` is ON.
15
+ * It wraps `FloatingToolbarButton` and replaces `href` with the resolved destination URL
16
+ * (cross-product analytics parameters appended), falling back to the raw `url` when the
17
+ * link is unresolved or not a first-party Atlassian link.
18
+ */
19
+ export declare const OpenLinkToolbarButton: ({ url, areAnyNewToolbarFlagsEnabled, editorView, onClick, title, }: OpenLinkToolbarButtonProps) => React.JSX.Element;
20
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-card",
3
- "version": "17.4.1",
3
+ "version": "17.4.3",
4
4
  "description": "Card plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -29,7 +29,7 @@
29
29
  ],
30
30
  "atlaskit:src": "src/index.ts",
31
31
  "dependencies": {
32
- "@atlaskit/adf-schema": "^52.16.0",
32
+ "@atlaskit/adf-schema": "^53.0.0",
33
33
  "@atlaskit/analytics-next": "^11.3.0",
34
34
  "@atlaskit/button": "^23.11.0",
35
35
  "@atlaskit/css": "^0.19.0",
@@ -65,7 +65,7 @@
65
65
  "@atlaskit/platform-feature-flags-react": "^0.5.0",
66
66
  "@atlaskit/primitives": "^19.0.0",
67
67
  "@atlaskit/prosemirror-history": "^0.2.0",
68
- "@atlaskit/smart-card": "^44.25.0",
68
+ "@atlaskit/smart-card": "^44.26.0",
69
69
  "@atlaskit/tmp-editor-statsig": "^94.0.0",
70
70
  "@atlaskit/tokens": "^13.3.0",
71
71
  "@babel/runtime": "^7.0.0",
@@ -76,7 +76,7 @@
76
76
  "uuid": "^3.1.0"
77
77
  },
78
78
  "peerDependencies": {
79
- "@atlaskit/editor-common": "^115.8.0",
79
+ "@atlaskit/editor-common": "^115.10.0",
80
80
  "@atlaskit/link-provider": "^4.7.0",
81
81
  "react": "^18.2.0",
82
82
  "react-intl": "^5.25.1 || ^6.0.0 || ^7.0.0"
@@ -130,6 +130,10 @@
130
130
  "platform_editor_adf_with_localid": {
131
131
  "type": "boolean"
132
132
  },
133
+ "platform_smartlink_xpc_url_wrapping": {
134
+ "type": "boolean",
135
+ "referenceOnly": true
136
+ },
133
137
  "jim-lower-ranking-in-jira-macro-search": {
134
138
  "type": "boolean"
135
139
  }