@atlaskit/editor-plugin-extension 10.1.5 → 10.1.7

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,21 @@
1
1
  # @atlaskit/editor-plugin-extension
2
2
 
3
+ ## 10.1.7
4
+
5
+ ### Patch Changes
6
+
7
+ - [`d2f1426fe5b85`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/d2f1426fe5b85) -
8
+ [ux] ENGHEALTH-46817 Add feature gated a11y eslint fixes across editor packages
9
+ - Updated dependencies
10
+
11
+ ## 10.1.6
12
+
13
+ ### Patch Changes
14
+
15
+ - [`abdf6c5320b01`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/abdf6c5320b01) -
16
+ [EDITOR-5370] Support Unsupported Content: handle copy content from nodes like mention
17
+ - Updated dependencies
18
+
3
19
  ## 10.1.5
4
20
 
5
21
  ### Patch Changes
@@ -268,10 +268,12 @@ var calculateToolbarPosition = function calculateToolbarPosition(editorView, nex
268
268
  * if the current selected extension is an unsupported content extension.
269
269
  */
270
270
  var createOnClickCopyButton = exports.createOnClickCopyButton = function createOnClickCopyButton(_ref) {
271
- var extensionApi = _ref.extensionApi,
271
+ var formatMessage = _ref.formatMessage,
272
+ extensionApi = _ref.extensionApi,
272
273
  extensionProvider = _ref.extensionProvider,
273
274
  getUnsupportedContent = _ref.getUnsupportedContent,
274
- state = _ref.state;
275
+ state = _ref.state,
276
+ locale = _ref.locale;
275
277
  if (!extensionProvider) {
276
278
  return;
277
279
  }
@@ -298,18 +300,21 @@ var createOnClickCopyButton = exports.createOnClickCopyButton = function createO
298
300
 
299
301
  // this command copies the text content of the unsupported content extension to the clipboard
300
302
  return function (editorState) {
301
- var error = (0, _utils3.copyUnsupportedContentToClipboard)({
303
+ (0, _utils3.copyUnsupportedContentToClipboard)({
304
+ locale: locale,
302
305
  unsupportedContent: adf,
303
- schema: state.schema
304
- });
305
- if (error) {
306
+ schema: state.schema,
307
+ api: extensionApi
308
+ }).then(function () {
309
+ var _extensionApi$copyBut;
310
+ extensionApi === null || extensionApi === void 0 || (_extensionApi$copyBut = extensionApi.copyButton) === null || _extensionApi$copyBut === void 0 || _extensionApi$copyBut.actions.afterCopy(formatMessage(_messages.default.copiedToClipboard));
311
+ }).catch(function (error) {
306
312
  (0, _utils3.onCopyFailed)({
307
313
  error: error,
308
314
  extensionApi: extensionApi,
309
315
  state: editorState
310
316
  });
311
- return false;
312
- }
317
+ });
313
318
  return true;
314
319
  };
315
320
  };
@@ -320,7 +325,8 @@ var getToolbarConfig = exports.getToolbarConfig = function getToolbarConfig(_ref
320
325
  getUnsupportedContent = _ref2.getUnsupportedContent;
321
326
  return function (state, intl) {
322
327
  var _extensionApi$decorat, _extensionApi$context, _extensionApi$analyti, _extensionApi$connect;
323
- var formatMessage = intl.formatMessage;
328
+ var formatMessage = intl.formatMessage,
329
+ locale = intl.locale;
324
330
  var extensionState = (0, _pluginFactory.getPluginState)(state);
325
331
  var extensionProvider = extensionState.extensionProvider;
326
332
  var hoverDecoration = extensionApi === null || extensionApi === void 0 || (_extensionApi$decorat = extensionApi.decorations) === null || _extensionApi$decorat === void 0 ? void 0 : _extensionApi$decorat.actions.hoverDecoration;
@@ -391,10 +397,12 @@ var getToolbarConfig = exports.getToolbarConfig = function getToolbarConfig(_ref
391
397
  formatMessage: intl.formatMessage,
392
398
  nodeType: nodeType,
393
399
  onClick: (0, _expValEquals.expValEquals)('platform_editor_ai_edit_unsupported_content', 'isEnabled', true) ? createOnClickCopyButton({
400
+ formatMessage: formatMessage,
394
401
  extensionApi: extensionApi,
395
402
  extensionProvider: extensionProvider,
396
403
  getUnsupportedContent: getUnsupportedContent,
397
- state: state
404
+ state: state,
405
+ locale: locale
398
406
  }) : undefined
399
407
  }]
400
408
  }, shouldHideCopyButton && {
@@ -1,14 +1,21 @@
1
1
  "use strict";
2
2
 
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
3
4
  Object.defineProperty(exports, "__esModule", {
4
5
  value: true
5
6
  });
6
7
  exports.onCopyFailed = exports.getSelectedExtension = exports.getSelectedDomElement = exports.getNodeTypesReferenced = exports.getDataConsumerMark = exports.findNodePosWithLocalId = exports.findExtensionWithLocalId = exports.copyUnsupportedContentToClipboard = void 0;
8
+ var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
9
+ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
7
10
  var _analytics = require("@atlaskit/editor-common/analytics");
8
11
  var _clipboard = require("@atlaskit/editor-common/clipboard");
9
12
  var _utils = require("@atlaskit/editor-common/utils");
10
13
  var _editorJsonTransformer = require("@atlaskit/editor-json-transformer");
11
14
  var _utils2 = require("@atlaskit/editor-prosemirror/utils");
15
+ var _resource = require("@atlaskit/mention/resource");
16
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
17
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
18
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
12
19
  var getSelectedExtension = exports.getSelectedExtension = function getSelectedExtension(state) {
13
20
  var searchParent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
14
21
  var _state$schema$nodes = state.schema.nodes,
@@ -75,35 +82,189 @@ var findNodePosWithLocalId = exports.findNodePosWithLocalId = function findNodeP
75
82
  return nodes.length >= 1 ? nodes[0] : undefined;
76
83
  };
77
84
  /**
78
- * copying ADF from the unsupported content extension as text to clipboard
85
+ * Converts a ProseMirror node to its text representation.
86
+ * Handles text nodes with marks (links) and inline nodes (status, mention, emoji).
87
+ * Returns the content for this node, with a trailing separator for text blocks.
79
88
  */
80
- var copyUnsupportedContentToClipboard = exports.copyUnsupportedContentToClipboard = function copyUnsupportedContentToClipboard(_ref2) {
81
- var schema = _ref2.schema,
82
- unsupportedContent = _ref2.unsupportedContent;
83
- try {
84
- if (!unsupportedContent) {
85
- return new Error('No nested content found');
89
+ var convertNodeToText = function convertNodeToText(node, mentionSet, parent, locale) {
90
+ if (node.isInline) {
91
+ var schema = node.type.schema;
92
+ var finalText = '';
93
+ if (node.isText) {
94
+ finalText = node.text || '';
95
+ if (node.marks.length > 0) {
96
+ var _iterator = _createForOfIteratorHelper(node.marks),
97
+ _step;
98
+ try {
99
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
100
+ var mark = _step.value;
101
+ // if it's link, include the href in the text
102
+ if (mark.type === schema.marks.link) {
103
+ var href = mark.attrs.href;
104
+ var text = node.text || '';
105
+ // If the text differs from the href, include both
106
+ if (text && text !== href) {
107
+ finalText = "".concat(text, " ").concat(href);
108
+ } else {
109
+ finalText = href;
110
+ }
111
+ }
112
+ }
113
+ } catch (err) {
114
+ _iterator.e(err);
115
+ } finally {
116
+ _iterator.f();
117
+ }
118
+ }
119
+ } else {
120
+ switch (node.type) {
121
+ case schema.nodes.status:
122
+ finalText = node.attrs.text || '';
123
+ break;
124
+ case schema.nodes.mention:
125
+ mentionSet.add(node.attrs.id);
126
+ finalText = "@".concat(node.attrs.id);
127
+ break;
128
+ case schema.nodes.emoji:
129
+ finalText = node.attrs.shortName || '';
130
+ break;
131
+ case schema.nodes.date:
132
+ var timestamp = new Date(Number(node.attrs.timestamp));
133
+ finalText = !isNaN(timestamp.getTime()) ? timestamp.toLocaleDateString(locale !== null && locale !== void 0 ? locale : 'en-US') : String(node.attrs.timestamp);
134
+ break;
135
+ default:
136
+ finalText = node.textContent;
137
+ break;
138
+ }
86
139
  }
87
- if (unsupportedContent.type !== 'doc') {
88
- unsupportedContent = {
89
- version: 1,
90
- type: 'doc',
91
- content: [unsupportedContent]
92
- };
140
+ if (parent && parent.isTextblock && node === parent.lastChild && parent.childCount > 0) {
141
+ finalText += '\n\n';
93
142
  }
94
- var transformer = new _editorJsonTransformer.JSONTransformer(schema);
95
- var pmNode = transformer.parse(unsupportedContent);
96
- var text = pmNode.textBetween(0, pmNode.content.size, '\n\n');
97
- (0, _clipboard.copyToClipboard)(text);
98
- } catch (error) {
99
- return error instanceof Error ? error : new Error('Failed to copy content');
143
+ return finalText;
100
144
  }
145
+ return '';
101
146
  };
102
- var onCopyFailed = exports.onCopyFailed = function onCopyFailed(_ref3) {
147
+
148
+ /**
149
+ * Resolves mention IDs to their display names and replaces them in the text.
150
+ * Returns the text with resolved mentions, or the original text if the provider is unavailable.
151
+ */
152
+ var resolveMentionsInText = /*#__PURE__*/function () {
153
+ var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(text, mentionSet, api) {
154
+ var _api$mention;
155
+ var mentionProvider, resolvedText, _iterator2, _step2, id, mention;
156
+ return _regenerator.default.wrap(function _callee$(_context) {
157
+ while (1) switch (_context.prev = _context.next) {
158
+ case 0:
159
+ mentionProvider = api === null || api === void 0 || (_api$mention = api.mention) === null || _api$mention === void 0 || (_api$mention = _api$mention.sharedState) === null || _api$mention === void 0 || (_api$mention = _api$mention.currentState()) === null || _api$mention === void 0 ? void 0 : _api$mention.mentionProvider;
160
+ if (!(!mentionProvider || !(0, _resource.isResolvingMentionProvider)(mentionProvider))) {
161
+ _context.next = 3;
162
+ break;
163
+ }
164
+ return _context.abrupt("return", text);
165
+ case 3:
166
+ resolvedText = text;
167
+ _iterator2 = _createForOfIteratorHelper(mentionSet);
168
+ _context.prev = 5;
169
+ _iterator2.s();
170
+ case 7:
171
+ if ((_step2 = _iterator2.n()).done) {
172
+ _context.next = 15;
173
+ break;
174
+ }
175
+ id = _step2.value;
176
+ _context.next = 11;
177
+ return mentionProvider.resolveMentionName(id);
178
+ case 11:
179
+ mention = _context.sent;
180
+ resolvedText = resolvedText.replace("@".concat(id), "@".concat(mention.name) || '@…');
181
+ case 13:
182
+ _context.next = 7;
183
+ break;
184
+ case 15:
185
+ _context.next = 20;
186
+ break;
187
+ case 17:
188
+ _context.prev = 17;
189
+ _context.t0 = _context["catch"](5);
190
+ _iterator2.e(_context.t0);
191
+ case 20:
192
+ _context.prev = 20;
193
+ _iterator2.f();
194
+ return _context.finish(20);
195
+ case 23:
196
+ return _context.abrupt("return", resolvedText);
197
+ case 24:
198
+ case "end":
199
+ return _context.stop();
200
+ }
201
+ }, _callee, null, [[5, 17, 20, 23]]);
202
+ }));
203
+ return function resolveMentionsInText(_x, _x2, _x3) {
204
+ return _ref2.apply(this, arguments);
205
+ };
206
+ }();
207
+
208
+ /**
209
+ * copying ADF from the unsupported content extension as text to clipboard
210
+ */
211
+ var copyUnsupportedContentToClipboard = exports.copyUnsupportedContentToClipboard = /*#__PURE__*/function () {
212
+ var _ref4 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(_ref3) {
213
+ var locale, schema, unsupportedContent, api, transformer, pmNode, text, mentionSet;
214
+ return _regenerator.default.wrap(function _callee2$(_context2) {
215
+ while (1) switch (_context2.prev = _context2.next) {
216
+ case 0:
217
+ locale = _ref3.locale, schema = _ref3.schema, unsupportedContent = _ref3.unsupportedContent, api = _ref3.api;
218
+ _context2.prev = 1;
219
+ if (unsupportedContent) {
220
+ _context2.next = 4;
221
+ break;
222
+ }
223
+ throw new Error('No nested content found');
224
+ case 4:
225
+ if (unsupportedContent.type !== 'doc') {
226
+ unsupportedContent = {
227
+ version: 1,
228
+ type: 'doc',
229
+ content: [unsupportedContent]
230
+ };
231
+ }
232
+ transformer = new _editorJsonTransformer.JSONTransformer(schema);
233
+ pmNode = transformer.parse(unsupportedContent);
234
+ text = '';
235
+ mentionSet = new Set();
236
+ pmNode.nodesBetween(0, pmNode.content.size, function (node, _pos, parent) {
237
+ text += convertNodeToText(node, mentionSet, parent, locale);
238
+ });
239
+
240
+ // Trim leading/trailing whitespace from the collected text
241
+ text = text.trim();
242
+ _context2.next = 13;
243
+ return resolveMentionsInText(text, mentionSet, api);
244
+ case 13:
245
+ text = _context2.sent;
246
+ (0, _clipboard.copyToClipboard)(text);
247
+ _context2.next = 20;
248
+ break;
249
+ case 17:
250
+ _context2.prev = 17;
251
+ _context2.t0 = _context2["catch"](1);
252
+ throw _context2.t0 instanceof Error ? _context2.t0 : new Error('Failed to copy content');
253
+ case 20:
254
+ case "end":
255
+ return _context2.stop();
256
+ }
257
+ }, _callee2, null, [[1, 17]]);
258
+ }));
259
+ return function copyUnsupportedContentToClipboard(_x4) {
260
+ return _ref4.apply(this, arguments);
261
+ };
262
+ }();
263
+ var onCopyFailed = exports.onCopyFailed = function onCopyFailed(_ref5) {
103
264
  var _extensionApi$analyti;
104
- var error = _ref3.error,
105
- extensionApi = _ref3.extensionApi,
106
- state = _ref3.state;
265
+ var error = _ref5.error,
266
+ extensionApi = _ref5.extensionApi,
267
+ state = _ref5.state;
107
268
  var nodeWithPos = getSelectedExtension(state, true);
108
269
  if (!nodeWithPos) {
109
270
  return;
@@ -16,11 +16,13 @@ var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/ge
16
16
  var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
17
17
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
18
18
  var _react = _interopRequireWildcard(require("react"));
19
+ var _bindEventListener = require("bind-event-listener");
19
20
  var _isEqual2 = _interopRequireDefault(require("lodash/isEqual"));
20
21
  var _merge = _interopRequireDefault(require("lodash/merge"));
21
22
  var _memoizeOne = _interopRequireDefault(require("memoize-one"));
22
23
  var _reactIntlNext = require("react-intl-next");
23
24
  var _analyticsNext = require("@atlaskit/analytics-next");
25
+ var _browserApis = require("@atlaskit/browser-apis");
24
26
  var _buttonGroup = _interopRequireDefault(require("@atlaskit/button/button-group"));
25
27
  var _new = _interopRequireDefault(require("@atlaskit/button/new"));
26
28
  var _analytics = require("@atlaskit/editor-common/analytics");
@@ -28,6 +30,7 @@ var _extensions = require("@atlaskit/editor-common/extensions");
28
30
  var _hooks = require("@atlaskit/editor-common/hooks");
29
31
  var _form = _interopRequireWildcard(require("@atlaskit/form"));
30
32
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
33
+ var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
31
34
  var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
32
35
  var _constants = require("./constants");
33
36
  var _DescriptionSummary = require("./DescriptionSummary");
@@ -354,6 +357,7 @@ var ConfigPanel = /*#__PURE__*/function (_React$Component) {
354
357
  firstVisibleFieldName: props.fields ? _this.getFirstVisibleFieldName(props.fields) : undefined
355
358
  };
356
359
  _this.onFieldChange = null;
360
+ _this.unbindKeyDownHandler = null;
357
361
  return _this;
358
362
  }
359
363
  (0, _inherits2.default)(ConfigPanel, _React$Component);
@@ -364,15 +368,26 @@ var ConfigPanel = /*#__PURE__*/function (_React$Component) {
364
368
  fields = _this$props3.fields,
365
369
  parameters = _this$props3.parameters;
366
370
  this.parseParameters(fields, parameters);
371
+ if ((0, _expValEquals.expValEquals)('platform_editor_a11y_eslint_fix', 'isEnabled', true)) {
372
+ var doc = (0, _browserApis.getDocument)();
373
+ if (doc) {
374
+ this.unbindKeyDownHandler = (0, _bindEventListener.bind)(doc, {
375
+ type: 'keydown',
376
+ listener: this.handleKeyDown
377
+ });
378
+ }
379
+ }
367
380
  }
368
381
  }, {
369
382
  key: "componentWillUnmount",
370
383
  value: function componentWillUnmount() {
384
+ var _this$unbindKeyDownHa;
371
385
  var _this$props4 = this.props,
372
386
  createAnalyticsEvent = _this$props4.createAnalyticsEvent,
373
387
  extensionManifest = _this$props4.extensionManifest,
374
388
  fields = _this$props4.fields;
375
389
  var currentParameters = this.state.currentParameters;
390
+ (_this$unbindKeyDownHa = this.unbindKeyDownHandler) === null || _this$unbindKeyDownHa === void 0 || _this$unbindKeyDownHa.call(this);
376
391
  (0, _analytics.fireAnalyticsEvent)(createAnalyticsEvent)({
377
392
  payload: {
378
393
  action: _analytics.ACTION.CLOSED,
@@ -456,32 +471,28 @@ var ConfigPanel = /*#__PURE__*/function (_React$Component) {
456
471
  handleSubmit: handleSubmit
457
472
  }, function (onFieldChange) {
458
473
  _this2.onFieldChange = onFieldChange;
459
- return (
460
- /*#__PURE__*/
461
- // eslint-disable-next-line @atlassian/a11y/no-noninteractive-element-interactions
462
- _react.default.createElement("form", (0, _extends2.default)({}, formProps, {
463
- noValidate: true,
464
- onKeyDown: handleKeyDown,
465
- "data-testid": "extension-config-panel"
466
- }), _this2.renderHeader(extensionManifest), (0, _platformFeatureFlags.fg)('platform_editor_ai_object_sidebar_injection') && /*#__PURE__*/_react.default.createElement(_DescriptionSummary.DescriptionSummary, {
467
- extensionManifest: extensionManifest
468
- }), /*#__PURE__*/_react.default.createElement(ConfigFormIntlWithBoundary, {
469
- api: api,
470
- canSave: false,
471
- errorMessage: errorMessage,
472
- extensionManifest: extensionManifest,
473
- fields: fields !== null && fields !== void 0 ? fields : [],
474
- firstVisibleFieldName: firstVisibleFieldName,
475
- hasParsedParameters: hasParsedParameters,
476
- isLoading: isLoading || false,
477
- onCancel: onCancel,
478
- onFieldChange: onFieldChange,
479
- parameters: currentParameters,
480
- submitting: submitting,
481
- featureFlags: featureFlags,
482
- disableFields: _this2.props.disableFields
483
- }))
484
- );
474
+ return /*#__PURE__*/_react.default.createElement("form", (0, _extends2.default)({}, formProps, {
475
+ noValidate: true,
476
+ onKeyDown: (0, _expValEquals.expValEquals)('platform_editor_a11y_eslint_fix', 'isEnabled', true) ? undefined : handleKeyDown,
477
+ "data-testid": "extension-config-panel"
478
+ }), _this2.renderHeader(extensionManifest), (0, _platformFeatureFlags.fg)('platform_editor_ai_object_sidebar_injection') && /*#__PURE__*/_react.default.createElement(_DescriptionSummary.DescriptionSummary, {
479
+ extensionManifest: extensionManifest
480
+ }), /*#__PURE__*/_react.default.createElement(ConfigFormIntlWithBoundary, {
481
+ api: api,
482
+ canSave: false,
483
+ errorMessage: errorMessage,
484
+ extensionManifest: extensionManifest,
485
+ fields: fields !== null && fields !== void 0 ? fields : [],
486
+ firstVisibleFieldName: firstVisibleFieldName,
487
+ hasParsedParameters: hasParsedParameters,
488
+ isLoading: isLoading || false,
489
+ onCancel: onCancel,
490
+ onFieldChange: onFieldChange,
491
+ parameters: currentParameters,
492
+ submitting: submitting,
493
+ featureFlags: featureFlags,
494
+ disableFields: _this2.props.disableFields
495
+ }));
485
496
  });
486
497
  });
487
498
  }
@@ -11,6 +11,7 @@ var _reactIntlNext = require("react-intl-next");
11
11
  var _extensions = require("@atlaskit/editor-common/extensions");
12
12
  var _crossCircle = _interopRequireDefault(require("@atlaskit/icon/core/cross-circle"));
13
13
  var _colors = require("@atlaskit/theme/colors");
14
+ var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
14
15
  var _tooltip = _interopRequireDefault(require("@atlaskit/tooltip"));
15
16
  /**
16
17
  * @jsxRuntime classic
@@ -53,12 +54,14 @@ var RemovableField = function RemovableField(_ref) {
53
54
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
54
55
  ,
55
56
  className: className
56
- }, children, canRemoveField &&
57
- // eslint-disable-next-line @atlassian/a11y/click-events-have-key-events, @atlassian/a11y/interactive-element-not-keyboard-focusable, @atlassian/a11y/no-static-element-interactions
58
- (0, _react2.jsx)("div", {
57
+ }, children, canRemoveField && (0, _react2.jsx)("div", {
58
+ role: (0, _expValEquals.expValEquals)('platform_editor_a11y_eslint_fix', 'isEnabled', true) ? 'button' : undefined,
59
59
  css: removeButtonWrapperStyles,
60
60
  "data-testid": "remove-field-".concat(name),
61
- onClick: onClickCallback
61
+ onClick: onClickCallback,
62
+ onKeyDown: (0, _expValEquals.expValEquals)('platform_editor_a11y_eslint_fix', 'isEnabled', true) ? onClickCallback : undefined,
63
+ onFocus: (0, _expValEquals.expValEquals)('platform_editor_a11y_eslint_fix', 'isEnabled', true) ? onClickCallback : undefined,
64
+ tabIndex: (0, _expValEquals.expValEquals)('platform_editor_a11y_eslint_fix', 'isEnabled', true) ? 0 : undefined
62
65
  }, (0, _react2.jsx)(_tooltip.default, {
63
66
  content: intl.formatMessage(_extensions.configPanelMessages.removeField),
64
67
  position: "left"
@@ -266,10 +266,12 @@ const calculateToolbarPosition = (editorView, nextPos, state, extensionNode) =>
266
266
  * if the current selected extension is an unsupported content extension.
267
267
  */
268
268
  export const createOnClickCopyButton = ({
269
+ formatMessage,
269
270
  extensionApi,
270
271
  extensionProvider,
271
272
  getUnsupportedContent,
272
- state
273
+ state,
274
+ locale
273
275
  }) => {
274
276
  if (!extensionProvider) {
275
277
  return;
@@ -300,18 +302,21 @@ export const createOnClickCopyButton = ({
300
302
 
301
303
  // this command copies the text content of the unsupported content extension to the clipboard
302
304
  return editorState => {
303
- const error = copyUnsupportedContentToClipboard({
305
+ copyUnsupportedContentToClipboard({
306
+ locale,
304
307
  unsupportedContent: adf,
305
- schema: state.schema
306
- });
307
- if (error) {
308
+ schema: state.schema,
309
+ api: extensionApi
310
+ }).then(() => {
311
+ var _extensionApi$copyBut;
312
+ extensionApi === null || extensionApi === void 0 ? void 0 : (_extensionApi$copyBut = extensionApi.copyButton) === null || _extensionApi$copyBut === void 0 ? void 0 : _extensionApi$copyBut.actions.afterCopy(formatMessage(commonMessages.copiedToClipboard));
313
+ }).catch(error => {
308
314
  onCopyFailed({
309
315
  error,
310
316
  extensionApi,
311
317
  state: editorState
312
318
  });
313
- return false;
314
- }
319
+ });
315
320
  return true;
316
321
  };
317
322
  };
@@ -322,7 +327,8 @@ export const getToolbarConfig = ({
322
327
  }) => (state, intl) => {
323
328
  var _extensionApi$decorat, _extensionApi$context, _extensionApi$analyti, _extensionApi$connect, _extensionApi$connect2, _extensionApi$connect3;
324
329
  const {
325
- formatMessage
330
+ formatMessage,
331
+ locale
326
332
  } = intl;
327
333
  const extensionState = getPluginState(state);
328
334
  const {
@@ -387,10 +393,12 @@ export const getToolbarConfig = ({
387
393
  formatMessage: intl.formatMessage,
388
394
  nodeType,
389
395
  onClick: expValEquals('platform_editor_ai_edit_unsupported_content', 'isEnabled', true) ? createOnClickCopyButton({
396
+ formatMessage,
390
397
  extensionApi,
391
398
  extensionProvider,
392
399
  getUnsupportedContent,
393
- state
400
+ state,
401
+ locale
394
402
  }) : undefined
395
403
  }],
396
404
  ...(shouldHideCopyButton && {
@@ -3,6 +3,7 @@ import { copyToClipboard } from '@atlaskit/editor-common/clipboard';
3
3
  import { closestElement, findNodePosByLocalIds } from '@atlaskit/editor-common/utils';
4
4
  import { JSONTransformer } from '@atlaskit/editor-json-transformer';
5
5
  import { findDomRefAtPos, findParentNodeOfType, findSelectedNodeOfType } from '@atlaskit/editor-prosemirror/utils';
6
+ import { isResolvingMentionProvider } from '@atlaskit/mention/resource';
6
7
  export const getSelectedExtension = (state, searchParent = false) => {
7
8
  const {
8
9
  inlineExtension,
@@ -66,16 +67,91 @@ export const findNodePosWithLocalId = (state, localId) => {
66
67
  const nodes = findNodePosByLocalIds(state, [localId]);
67
68
  return nodes.length >= 1 ? nodes[0] : undefined;
68
69
  };
70
+ /**
71
+ * Converts a ProseMirror node to its text representation.
72
+ * Handles text nodes with marks (links) and inline nodes (status, mention, emoji).
73
+ * Returns the content for this node, with a trailing separator for text blocks.
74
+ */
75
+ const convertNodeToText = (node, mentionSet, parent, locale) => {
76
+ if (node.isInline) {
77
+ const schema = node.type.schema;
78
+ let finalText = '';
79
+ if (node.isText) {
80
+ finalText = node.text || '';
81
+ if (node.marks.length > 0) {
82
+ for (const mark of node.marks) {
83
+ // if it's link, include the href in the text
84
+ if (mark.type === schema.marks.link) {
85
+ const href = mark.attrs.href;
86
+ const text = node.text || '';
87
+ // If the text differs from the href, include both
88
+ if (text && text !== href) {
89
+ finalText = `${text} ${href}`;
90
+ } else {
91
+ finalText = href;
92
+ }
93
+ }
94
+ }
95
+ }
96
+ } else {
97
+ switch (node.type) {
98
+ case schema.nodes.status:
99
+ finalText = node.attrs.text || '';
100
+ break;
101
+ case schema.nodes.mention:
102
+ mentionSet.add(node.attrs.id);
103
+ finalText = `@${node.attrs.id}`;
104
+ break;
105
+ case schema.nodes.emoji:
106
+ finalText = node.attrs.shortName || '';
107
+ break;
108
+ case schema.nodes.date:
109
+ const timestamp = new Date(Number(node.attrs.timestamp));
110
+ finalText = !isNaN(timestamp.getTime()) ? timestamp.toLocaleDateString(locale !== null && locale !== void 0 ? locale : 'en-US') : String(node.attrs.timestamp);
111
+ break;
112
+ default:
113
+ finalText = node.textContent;
114
+ break;
115
+ }
116
+ }
117
+ if (parent && parent.isTextblock && node === parent.lastChild && parent.childCount > 0) {
118
+ finalText += '\n\n';
119
+ }
120
+ return finalText;
121
+ }
122
+ return '';
123
+ };
124
+
125
+ /**
126
+ * Resolves mention IDs to their display names and replaces them in the text.
127
+ * Returns the text with resolved mentions, or the original text if the provider is unavailable.
128
+ */
129
+ const resolveMentionsInText = async (text, mentionSet, api) => {
130
+ var _api$mention, _api$mention$sharedSt, _api$mention$sharedSt2;
131
+ const mentionProvider = api === null || api === void 0 ? void 0 : (_api$mention = api.mention) === null || _api$mention === void 0 ? void 0 : (_api$mention$sharedSt = _api$mention.sharedState) === null || _api$mention$sharedSt === void 0 ? void 0 : (_api$mention$sharedSt2 = _api$mention$sharedSt.currentState()) === null || _api$mention$sharedSt2 === void 0 ? void 0 : _api$mention$sharedSt2.mentionProvider;
132
+ if (!mentionProvider || !isResolvingMentionProvider(mentionProvider)) {
133
+ return text;
134
+ }
135
+ let resolvedText = text;
136
+ for (const id of mentionSet) {
137
+ const mention = await mentionProvider.resolveMentionName(id);
138
+ resolvedText = resolvedText.replace(`@${id}`, `@${mention.name}` || '@…');
139
+ }
140
+ return resolvedText;
141
+ };
142
+
69
143
  /**
70
144
  * copying ADF from the unsupported content extension as text to clipboard
71
145
  */
72
- export const copyUnsupportedContentToClipboard = ({
146
+ export const copyUnsupportedContentToClipboard = async ({
147
+ locale,
73
148
  schema,
74
- unsupportedContent
149
+ unsupportedContent,
150
+ api
75
151
  }) => {
76
152
  try {
77
153
  if (!unsupportedContent) {
78
- return new Error('No nested content found');
154
+ throw new Error('No nested content found');
79
155
  }
80
156
  if (unsupportedContent.type !== 'doc') {
81
157
  unsupportedContent = {
@@ -86,10 +162,18 @@ export const copyUnsupportedContentToClipboard = ({
86
162
  }
87
163
  const transformer = new JSONTransformer(schema);
88
164
  const pmNode = transformer.parse(unsupportedContent);
89
- const text = pmNode.textBetween(0, pmNode.content.size, '\n\n');
165
+ let text = '';
166
+ const mentionSet = new Set();
167
+ pmNode.nodesBetween(0, pmNode.content.size, (node, _pos, parent) => {
168
+ text += convertNodeToText(node, mentionSet, parent, locale);
169
+ });
170
+
171
+ // Trim leading/trailing whitespace from the collected text
172
+ text = text.trim();
173
+ text = await resolveMentionsInText(text, mentionSet, api);
90
174
  copyToClipboard(text);
91
175
  } catch (error) {
92
- return error instanceof Error ? error : new Error('Failed to copy content');
176
+ throw error instanceof Error ? error : new Error('Failed to copy content');
93
177
  }
94
178
  };
95
179
  export const onCopyFailed = ({