@atlaskit/editor-plugin-paste 11.0.2 → 11.0.4

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,25 @@
1
1
  # @atlaskit/editor-plugin-paste
2
2
 
3
+ ## 11.0.4
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+
9
+ ## 11.0.3
10
+
11
+ ### Patch Changes
12
+
13
+ - [`402738b592e0b`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/402738b592e0b) -
14
+ Fix invalid flexible list structures caused by delete, paste, and typing operations.
15
+
16
+ Under platform_editor_flexible_list_schema, operations that remove content spanning list or task
17
+ list items could leave nodes with a nested list as their first child instead of a required
18
+ paragraph/item. Normalisation now runs efficiently on all relevant transactions in
19
+ appendTransaction.
20
+
21
+ - Updated dependencies
22
+
3
23
  ## 11.0.2
4
24
 
5
25
  ### Patch Changes
@@ -45,30 +45,6 @@ var _tinyMCE = require("./util/tinyMCE");
45
45
  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; } } }; }
46
46
  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; } }
47
47
  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; } // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
48
- function isListIntoListPaste(tr, state) {
49
- var _state$schema$nodes = state.schema.nodes,
50
- listItem = _state$schema$nodes.listItem,
51
- bulletList = _state$schema$nodes.bulletList,
52
- orderedList = _state$schema$nodes.orderedList;
53
- var _state$selection = state.selection,
54
- $from = _state$selection.$from,
55
- $to = _state$selection.$to;
56
- var selectionInList = !!(0, _utils2.findParentNodeOfTypeClosestToPos)($from, [listItem]) || !!(0, _utils2.findParentNodeOfTypeClosestToPos)($to, [listItem]);
57
- if (!selectionInList) {
58
- return false;
59
- }
60
- return tr.steps.some(function (step) {
61
- var _slice$content;
62
- var slice = (0, _utils.extractSliceFromStep)(step);
63
- var listExists = false;
64
- slice === null || slice === void 0 || (_slice$content = slice.content) === null || _slice$content === void 0 || _slice$content.forEach(function (node) {
65
- if (node.type === bulletList || node.type === orderedList) {
66
- listExists = true;
67
- }
68
- });
69
- return listExists;
70
- });
71
- }
72
48
  var isInsideBlockQuote = exports.isInsideBlockQuote = function isInsideBlockQuote(state) {
73
49
  var blockquote = state.schema.nodes.blockquote;
74
50
  return (0, _utils2.hasParentNodeOfType)(blockquote)(state.selection);
@@ -307,10 +283,10 @@ function createPlugin(schema, dispatchAnalyticsEvent, dispatch, featureFlags, pl
307
283
  // to split those repairing transactions in prosemirror-history when they're being added to the
308
284
  // "done" stack
309
285
  var isPastingTable = tr.steps.some(function (step) {
310
- var _slice$content2;
286
+ var _slice$content;
311
287
  var slice = (0, _utils.extractSliceFromStep)(step);
312
288
  var tableExists = false;
313
- slice === null || slice === void 0 || (_slice$content2 = slice.content) === null || _slice$content2 === void 0 || _slice$content2.forEach(function (node) {
289
+ slice === null || slice === void 0 || (_slice$content = slice.content) === null || _slice$content === void 0 || _slice$content.forEach(function (node) {
314
290
  if (node.type === state.schema.nodes.table) {
315
291
  tableExists = true;
316
292
  }
@@ -318,14 +294,26 @@ function createPlugin(schema, dispatchAnalyticsEvent, dispatch, featureFlags, pl
318
294
  return tableExists;
319
295
  });
320
296
 
321
- // Don't add closeHistory if we're pasting a list into a list, as the list plugin will
322
- // appendTransaction to normalise the list structure and we want to keep the paste and
323
- // normalisation as one undo event. We also set a meta on the transaction so the list
324
- // plugin's appendTransaction can cheaply detect this case without re-checking flags.
325
- if ((0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_flexible_list_schema', 'isEnabled', true) && isListIntoListPaste(tr, state)) {
326
- tr = tr.setMeta('listPasteNormalisation', true);
297
+ // Don't flag as a paste event (add closeHistory) when the paste affects a list and
298
+ // the list plugin's appendTransaction will normalise the structure, and we want the
299
+ // paste + normalisation to be a single undo step.
300
+ // Pasting into an existing list selection is inside a list node.
301
+ var isPastingIntoList = false;
302
+ // Pasting list content from an external source — slice top-level contains a list node.
303
+ var isPastingListContent = false;
304
+ if ((0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_flexible_list_schema', 'isEnabled', true)) {
305
+ var listNodeTypes = [state.schema.nodes.bulletList, state.schema.nodes.orderedList, state.schema.nodes.taskList].filter(function (n) {
306
+ return Boolean(n);
307
+ });
308
+ isPastingIntoList = (0, _utils2.hasParentNodeOfType)(listNodeTypes)(state.selection);
309
+ for (var i = 0; i < slice.content.childCount; i++) {
310
+ if (listNodeTypes.includes(slice.content.child(i).type)) {
311
+ isPastingListContent = true;
312
+ break;
313
+ }
314
+ }
327
315
  }
328
- if (!isPastingTextInsidePlaceholderText && !isPastingTable && !isPastingOverLayoutColumns && !tr.getMeta('listPasteNormalisation') && pluginInjectionApi !== null && pluginInjectionApi !== void 0 && pluginInjectionApi.betterTypeHistory) {
316
+ if (!isPastingTextInsidePlaceholderText && !isPastingTable && !isPastingOverLayoutColumns && !isPastingIntoList && !isPastingListContent && pluginInjectionApi !== null && pluginInjectionApi !== void 0 && pluginInjectionApi.betterTypeHistory) {
329
317
  var _pluginInjectionApi$b;
330
318
  tr = pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$b = pluginInjectionApi.betterTypeHistory) === null || _pluginInjectionApi$b === void 0 ? void 0 : _pluginInjectionApi$b.actions.flagPasteEvent(tr);
331
319
  }
@@ -13,7 +13,7 @@ import { removeBreakoutFromRendererSyncBlockHTML, transformSingleColumnLayout, t
13
13
  import { containsAnyAnnotations, extractSliceFromStep, linkifyContent, mapChildren } from '@atlaskit/editor-common/utils';
14
14
  import { MarkdownTransformer } from '@atlaskit/editor-markdown-transformer';
15
15
  import { Fragment, Slice } from '@atlaskit/editor-prosemirror/model';
16
- import { contains, findParentNodeOfTypeClosestToPos, hasParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
16
+ import { contains, hasParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
17
17
  import { handlePaste as handlePasteTable } from '@atlaskit/editor-tables/utils';
18
18
  import { insm } from '@atlaskit/insm';
19
19
  import { extractClientIdsFromHtml } from '@atlaskit/media-common';
@@ -32,32 +32,6 @@ import { handleVSCodeBlock } from './util/edge-cases/handleVSCodeBlock';
32
32
  import { handleMacroAutoConvert, handleMention, handleParagraphBlockMarks, handlePasteExpand, handleTableContentPasteInBodiedExtension } from './util/handlers';
33
33
  import { handleSyncBlocksPaste } from './util/sync-block';
34
34
  import { htmlHasIncompleteTable, isPastedFromTinyMCEConfluence, tryRebuildCompleteTableHtml } from './util/tinyMCE';
35
- function isListIntoListPaste(tr, state) {
36
- const {
37
- listItem,
38
- bulletList,
39
- orderedList
40
- } = state.schema.nodes;
41
- const {
42
- $from,
43
- $to
44
- } = state.selection;
45
- const selectionInList = !!findParentNodeOfTypeClosestToPos($from, [listItem]) || !!findParentNodeOfTypeClosestToPos($to, [listItem]);
46
- if (!selectionInList) {
47
- return false;
48
- }
49
- return tr.steps.some(step => {
50
- var _slice$content;
51
- const slice = extractSliceFromStep(step);
52
- let listExists = false;
53
- slice === null || slice === void 0 ? void 0 : (_slice$content = slice.content) === null || _slice$content === void 0 ? void 0 : _slice$content.forEach(node => {
54
- if (node.type === bulletList || node.type === orderedList) {
55
- listExists = true;
56
- }
57
- });
58
- return listExists;
59
- });
60
- }
61
35
  export const isInsideBlockQuote = state => {
62
36
  const {
63
37
  blockquote
@@ -271,10 +245,10 @@ export function createPlugin(schema, dispatchAnalyticsEvent, dispatch, featureFl
271
245
  // to split those repairing transactions in prosemirror-history when they're being added to the
272
246
  // "done" stack
273
247
  const isPastingTable = tr.steps.some(step => {
274
- var _slice$content2;
248
+ var _slice$content;
275
249
  const slice = extractSliceFromStep(step);
276
250
  let tableExists = false;
277
- slice === null || slice === void 0 ? void 0 : (_slice$content2 = slice.content) === null || _slice$content2 === void 0 ? void 0 : _slice$content2.forEach(node => {
251
+ slice === null || slice === void 0 ? void 0 : (_slice$content = slice.content) === null || _slice$content === void 0 ? void 0 : _slice$content.forEach(node => {
278
252
  if (node.type === state.schema.nodes.table) {
279
253
  tableExists = true;
280
254
  }
@@ -282,14 +256,24 @@ export function createPlugin(schema, dispatchAnalyticsEvent, dispatch, featureFl
282
256
  return tableExists;
283
257
  });
284
258
 
285
- // Don't add closeHistory if we're pasting a list into a list, as the list plugin will
286
- // appendTransaction to normalise the list structure and we want to keep the paste and
287
- // normalisation as one undo event. We also set a meta on the transaction so the list
288
- // plugin's appendTransaction can cheaply detect this case without re-checking flags.
289
- if (expValEqualsNoExposure('platform_editor_flexible_list_schema', 'isEnabled', true) && isListIntoListPaste(tr, state)) {
290
- tr = tr.setMeta('listPasteNormalisation', true);
259
+ // Don't flag as a paste event (add closeHistory) when the paste affects a list and
260
+ // the list plugin's appendTransaction will normalise the structure, and we want the
261
+ // paste + normalisation to be a single undo step.
262
+ // Pasting into an existing list selection is inside a list node.
263
+ let isPastingIntoList = false;
264
+ // Pasting list content from an external source — slice top-level contains a list node.
265
+ let isPastingListContent = false;
266
+ if (expValEqualsNoExposure('platform_editor_flexible_list_schema', 'isEnabled', true)) {
267
+ const listNodeTypes = [state.schema.nodes.bulletList, state.schema.nodes.orderedList, state.schema.nodes.taskList].filter(n => Boolean(n));
268
+ isPastingIntoList = hasParentNodeOfType(listNodeTypes)(state.selection);
269
+ for (let i = 0; i < slice.content.childCount; i++) {
270
+ if (listNodeTypes.includes(slice.content.child(i).type)) {
271
+ isPastingListContent = true;
272
+ break;
273
+ }
274
+ }
291
275
  }
292
- if (!isPastingTextInsidePlaceholderText && !isPastingTable && !isPastingOverLayoutColumns && !tr.getMeta('listPasteNormalisation') && pluginInjectionApi !== null && pluginInjectionApi !== void 0 && pluginInjectionApi.betterTypeHistory) {
276
+ if (!isPastingTextInsidePlaceholderText && !isPastingTable && !isPastingOverLayoutColumns && !isPastingIntoList && !isPastingListContent && pluginInjectionApi !== null && pluginInjectionApi !== void 0 && pluginInjectionApi.betterTypeHistory) {
293
277
  var _pluginInjectionApi$b;
294
278
  tr = pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$b = pluginInjectionApi.betterTypeHistory) === null || _pluginInjectionApi$b === void 0 ? void 0 : _pluginInjectionApi$b.actions.flagPasteEvent(tr);
295
279
  }
@@ -18,7 +18,7 @@ import { removeBreakoutFromRendererSyncBlockHTML, transformSingleColumnLayout, t
18
18
  import { containsAnyAnnotations, extractSliceFromStep, linkifyContent, mapChildren } from '@atlaskit/editor-common/utils';
19
19
  import { MarkdownTransformer } from '@atlaskit/editor-markdown-transformer';
20
20
  import { Fragment, Slice } from '@atlaskit/editor-prosemirror/model';
21
- import { contains, findParentNodeOfTypeClosestToPos, hasParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
21
+ import { contains, hasParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
22
22
  import { handlePaste as handlePasteTable } from '@atlaskit/editor-tables/utils';
23
23
  import { insm } from '@atlaskit/insm';
24
24
  import { extractClientIdsFromHtml } from '@atlaskit/media-common';
@@ -37,30 +37,6 @@ import { handleVSCodeBlock } from './util/edge-cases/handleVSCodeBlock';
37
37
  import { handleMacroAutoConvert, handleMention, handleParagraphBlockMarks, handlePasteExpand, handleTableContentPasteInBodiedExtension } from './util/handlers';
38
38
  import { handleSyncBlocksPaste } from './util/sync-block';
39
39
  import { htmlHasIncompleteTable, isPastedFromTinyMCEConfluence, tryRebuildCompleteTableHtml } from './util/tinyMCE';
40
- function isListIntoListPaste(tr, state) {
41
- var _state$schema$nodes = state.schema.nodes,
42
- listItem = _state$schema$nodes.listItem,
43
- bulletList = _state$schema$nodes.bulletList,
44
- orderedList = _state$schema$nodes.orderedList;
45
- var _state$selection = state.selection,
46
- $from = _state$selection.$from,
47
- $to = _state$selection.$to;
48
- var selectionInList = !!findParentNodeOfTypeClosestToPos($from, [listItem]) || !!findParentNodeOfTypeClosestToPos($to, [listItem]);
49
- if (!selectionInList) {
50
- return false;
51
- }
52
- return tr.steps.some(function (step) {
53
- var _slice$content;
54
- var slice = extractSliceFromStep(step);
55
- var listExists = false;
56
- slice === null || slice === void 0 || (_slice$content = slice.content) === null || _slice$content === void 0 || _slice$content.forEach(function (node) {
57
- if (node.type === bulletList || node.type === orderedList) {
58
- listExists = true;
59
- }
60
- });
61
- return listExists;
62
- });
63
- }
64
40
  export var isInsideBlockQuote = function isInsideBlockQuote(state) {
65
41
  var blockquote = state.schema.nodes.blockquote;
66
42
  return hasParentNodeOfType(blockquote)(state.selection);
@@ -299,10 +275,10 @@ export function createPlugin(schema, dispatchAnalyticsEvent, dispatch, featureFl
299
275
  // to split those repairing transactions in prosemirror-history when they're being added to the
300
276
  // "done" stack
301
277
  var isPastingTable = tr.steps.some(function (step) {
302
- var _slice$content2;
278
+ var _slice$content;
303
279
  var slice = extractSliceFromStep(step);
304
280
  var tableExists = false;
305
- slice === null || slice === void 0 || (_slice$content2 = slice.content) === null || _slice$content2 === void 0 || _slice$content2.forEach(function (node) {
281
+ slice === null || slice === void 0 || (_slice$content = slice.content) === null || _slice$content === void 0 || _slice$content.forEach(function (node) {
306
282
  if (node.type === state.schema.nodes.table) {
307
283
  tableExists = true;
308
284
  }
@@ -310,14 +286,26 @@ export function createPlugin(schema, dispatchAnalyticsEvent, dispatch, featureFl
310
286
  return tableExists;
311
287
  });
312
288
 
313
- // Don't add closeHistory if we're pasting a list into a list, as the list plugin will
314
- // appendTransaction to normalise the list structure and we want to keep the paste and
315
- // normalisation as one undo event. We also set a meta on the transaction so the list
316
- // plugin's appendTransaction can cheaply detect this case without re-checking flags.
317
- if (expValEqualsNoExposure('platform_editor_flexible_list_schema', 'isEnabled', true) && isListIntoListPaste(tr, state)) {
318
- tr = tr.setMeta('listPasteNormalisation', true);
289
+ // Don't flag as a paste event (add closeHistory) when the paste affects a list and
290
+ // the list plugin's appendTransaction will normalise the structure, and we want the
291
+ // paste + normalisation to be a single undo step.
292
+ // Pasting into an existing list selection is inside a list node.
293
+ var isPastingIntoList = false;
294
+ // Pasting list content from an external source — slice top-level contains a list node.
295
+ var isPastingListContent = false;
296
+ if (expValEqualsNoExposure('platform_editor_flexible_list_schema', 'isEnabled', true)) {
297
+ var listNodeTypes = [state.schema.nodes.bulletList, state.schema.nodes.orderedList, state.schema.nodes.taskList].filter(function (n) {
298
+ return Boolean(n);
299
+ });
300
+ isPastingIntoList = hasParentNodeOfType(listNodeTypes)(state.selection);
301
+ for (var i = 0; i < slice.content.childCount; i++) {
302
+ if (listNodeTypes.includes(slice.content.child(i).type)) {
303
+ isPastingListContent = true;
304
+ break;
305
+ }
306
+ }
319
307
  }
320
- if (!isPastingTextInsidePlaceholderText && !isPastingTable && !isPastingOverLayoutColumns && !tr.getMeta('listPasteNormalisation') && pluginInjectionApi !== null && pluginInjectionApi !== void 0 && pluginInjectionApi.betterTypeHistory) {
308
+ if (!isPastingTextInsidePlaceholderText && !isPastingTable && !isPastingOverLayoutColumns && !isPastingIntoList && !isPastingListContent && pluginInjectionApi !== null && pluginInjectionApi !== void 0 && pluginInjectionApi.betterTypeHistory) {
321
309
  var _pluginInjectionApi$b;
322
310
  tr = pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$b = pluginInjectionApi.betterTypeHistory) === null || _pluginInjectionApi$b === void 0 ? void 0 : _pluginInjectionApi$b.actions.flagPasteEvent(tr);
323
311
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-paste",
3
- "version": "11.0.2",
3
+ "version": "11.0.4",
4
4
  "description": "Paste plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -48,14 +48,14 @@
48
48
  "@atlaskit/media-common": "^13.0.0",
49
49
  "@atlaskit/platform-feature-flags": "^1.1.0",
50
50
  "@atlaskit/prosemirror-history": "^0.2.0",
51
- "@atlaskit/tmp-editor-statsig": "^63.0.0",
51
+ "@atlaskit/tmp-editor-statsig": "^64.0.0",
52
52
  "@atlaskit/tokens": "^13.0.0",
53
53
  "@babel/runtime": "^7.0.0",
54
54
  "lodash": "^4.17.21",
55
55
  "uuid": "^3.1.0"
56
56
  },
57
57
  "peerDependencies": {
58
- "@atlaskit/editor-common": "^114.2.0",
58
+ "@atlaskit/editor-common": "^114.5.0",
59
59
  "react": "^18.2.0",
60
60
  "react-dom": "^18.2.0",
61
61
  "react-intl": "^5.25.1 || ^6.0.0 || ^7.0.0"