@atlaskit/editor-plugin-show-diff 3.0.2 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @atlaskit/editor-plugin-show-diff
2
2
 
3
+ ## 3.1.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`174d939cfd1ba`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/174d939cfd1ba) -
8
+ Use valid positioning for deleted diff content to avoid invalid nesting diffs
9
+
10
+ ## 3.1.0
11
+
12
+ ### Minor Changes
13
+
14
+ - [`5167552fe1a93`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/5167552fe1a93) -
15
+ [EDITOR-2339] Bump @atlaskit/adf-schema to 51.3.0
16
+
17
+ ### Patch Changes
18
+
19
+ - [`38fb1054b8b7a`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/38fb1054b8b7a) -
20
+ Recover from invalid deletion decorations
21
+ - Updated dependencies
22
+
3
23
  ## 3.0.2
4
24
 
5
25
  ### Patch Changes
@@ -74,6 +74,21 @@ var NodeViewSerializer = exports.NodeViewSerializer = /*#__PURE__*/function () {
74
74
  this.nodeViews = (_ref = nodeViews !== null && nodeViews !== void 0 ? nodeViews : (_this$editorView = this.editorView) === null || _this$editorView === void 0 ? void 0 : _this$editorView.nodeViews) !== null && _ref !== void 0 ? _ref : {};
75
75
  }
76
76
 
77
+ /**
78
+ * Appends serialized child nodes to the given contentDOM element.
79
+ */
80
+ }, {
81
+ key: "appendChildNodes",
82
+ value: function appendChildNodes(children, contentDOM) {
83
+ var _this = this;
84
+ children.forEach(function (child) {
85
+ var childNode = _this.tryCreateNodeView(child) || _this.serializeNode(child);
86
+ if (childNode) {
87
+ contentDOM === null || contentDOM === void 0 || contentDOM.append(childNode);
88
+ }
89
+ });
90
+ }
91
+
77
92
  /**
78
93
  * Attempts to create a node view for the given node.
79
94
  *
@@ -83,8 +98,7 @@ var NodeViewSerializer = exports.NodeViewSerializer = /*#__PURE__*/function () {
83
98
  }, {
84
99
  key: "tryCreateNodeView",
85
100
  value: function tryCreateNodeView(targetNode) {
86
- var _this$nodeViews,
87
- _this = this;
101
+ var _this$nodeViews;
88
102
  if (!this.editorView) {
89
103
  return null;
90
104
  }
@@ -92,40 +106,40 @@ var NodeViewSerializer = exports.NodeViewSerializer = /*#__PURE__*/function () {
92
106
  if (this.nodeViewBlocklist.has(targetNode.type.name)) {
93
107
  return null;
94
108
  }
95
- if (!constructor) {
96
- var _targetNode$type$spec, _targetNode$type$spec2;
97
- if (targetNode.isInline) {
98
- return null;
99
- }
100
- var toDOMResult = (_targetNode$type$spec = (_targetNode$type$spec2 = targetNode.type.spec).toDOM) === null || _targetNode$type$spec === void 0 ? void 0 : _targetNode$type$spec.call(_targetNode$type$spec2, targetNode);
101
- if (!toDOMResult) {
102
- return null;
103
- }
104
- var _DOMSerializer$render = _model.DOMSerializer.renderSpec(document, toDOMResult),
105
- _dom = _DOMSerializer$render.dom,
106
- _contentDOM = _DOMSerializer$render.contentDOM;
107
- if (_dom instanceof HTMLElement) {
108
- if (targetNode.type.name === 'paragraph' && targetNode.children.length === 1) {
109
- return this.serializeFragment(targetNode.content);
109
+ try {
110
+ if (!constructor) {
111
+ var _targetNode$type$spec, _targetNode$type$spec2;
112
+ if (targetNode.isInline) {
113
+ return null;
110
114
  }
115
+ var toDOMResult = (_targetNode$type$spec = (_targetNode$type$spec2 = targetNode.type.spec).toDOM) === null || _targetNode$type$spec === void 0 ? void 0 : _targetNode$type$spec.call(_targetNode$type$spec2, targetNode);
116
+ if (!toDOMResult) {
117
+ return null;
118
+ }
119
+ var _DOMSerializer$render = _model.DOMSerializer.renderSpec(document, toDOMResult),
120
+ _dom = _DOMSerializer$render.dom,
121
+ _contentDOM = _DOMSerializer$render.contentDOM;
122
+ if (_dom instanceof HTMLElement) {
123
+ if (targetNode.type.name === 'paragraph' && targetNode.children.length === 1) {
124
+ return this.serializeFragment(targetNode.content);
125
+ }
111
126
 
112
- // Iteratively populate children
113
- targetNode.children.forEach(function (child) {
114
- _contentDOM === null || _contentDOM === void 0 || _contentDOM.append(_this.tryCreateNodeView(child) || _this.serializeNode(child));
115
- });
127
+ // Iteratively populate children
128
+ this.appendChildNodes(targetNode.children, _contentDOM);
129
+ }
130
+ return _dom;
116
131
  }
117
- return _dom;
132
+ var _constructor = constructor(targetNode, this.editorView, function () {
133
+ return 0;
134
+ }, [], {}),
135
+ dom = _constructor.dom,
136
+ contentDOM = _constructor.contentDOM;
137
+ // Iteratively populate children
138
+ this.appendChildNodes(targetNode.children, contentDOM);
139
+ return dom;
140
+ } catch (e) {
141
+ return null;
118
142
  }
119
- var _constructor = constructor(targetNode, this.editorView, function () {
120
- return 0;
121
- }, [], {}),
122
- dom = _constructor.dom,
123
- contentDOM = _constructor.contentDOM;
124
- // Iteratively populate children
125
- targetNode.children.forEach(function (child) {
126
- contentDOM === null || contentDOM === void 0 || contentDOM.append(_this.tryCreateNodeView(child) || _this.serializeNode(child));
127
- });
128
- return dom;
129
143
  }
130
144
 
131
145
  /**
@@ -137,7 +151,11 @@ var NodeViewSerializer = exports.NodeViewSerializer = /*#__PURE__*/function () {
137
151
  if (!this.serializer) {
138
152
  throw new Error('NodeViewSerializer must be initialized with init() before use');
139
153
  }
140
- return this.serializer.serializeNode(node);
154
+ try {
155
+ return this.serializer.serializeNode(node);
156
+ } catch (e) {
157
+ return null;
158
+ }
141
159
  }
142
160
 
143
161
  /**
@@ -149,7 +167,11 @@ var NodeViewSerializer = exports.NodeViewSerializer = /*#__PURE__*/function () {
149
167
  if (!this.serializer) {
150
168
  throw new Error('NodeViewSerializer must be initialized with init() before use');
151
169
  }
152
- return this.serializer.serializeFragment(fragment);
170
+ try {
171
+ return this.serializer.serializeFragment(fragment);
172
+ } catch (e) {
173
+ return null;
174
+ }
153
175
  }
154
176
 
155
177
  /**
@@ -140,7 +140,8 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref)
140
140
  change: change,
141
141
  doc: originalDoc,
142
142
  nodeViewSerializer: nodeViewSerializer,
143
- colourScheme: colourScheme
143
+ colourScheme: colourScheme,
144
+ newDoc: tr.doc
144
145
  });
145
146
  if (decoration) {
146
147
  decorations.push(decoration);
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.createInlineChangedDecoration = exports.createDeletedContentDecoration = exports.createBlockChangedDecoration = void 0;
7
7
  var _lazyNodeView = require("@atlaskit/editor-common/lazy-node-view");
8
8
  var _view = require("@atlaskit/editor-prosemirror/view");
9
+ var _findSafeInsertPos = require("./findSafeInsertPos");
9
10
  var editingStyle = (0, _lazyNodeView.convertToInlineCss)({
10
11
  background: "var(--ds-background-accent-purple-subtlest, #F3F0FF)",
11
12
  textDecoration: 'underline',
@@ -151,7 +152,8 @@ var createDeletedContentDecoration = exports.createDeletedContentDecoration = fu
151
152
  var change = _ref.change,
152
153
  doc = _ref.doc,
153
154
  nodeViewSerializer = _ref.nodeViewSerializer,
154
- colourScheme = _ref.colourScheme;
155
+ colourScheme = _ref.colourScheme,
156
+ newDoc = _ref.newDoc;
155
157
  var slice = doc.slice(change.fromA, change.toA);
156
158
  if (slice.content.content.length === 0) {
157
159
  return;
@@ -203,7 +205,9 @@ var createDeletedContentDecoration = exports.createDeletedContentDecoration = fu
203
205
  } else {
204
206
  // Fallback to serializing the individual child node
205
207
  var serializedChild = serializer.serializeNode(childNode);
206
- dom.append(serializedChild);
208
+ if (serializedChild) {
209
+ dom.append(serializedChild);
210
+ }
207
211
  }
208
212
  });
209
213
  return true; // Indicates we handled multiple children
@@ -265,12 +269,16 @@ var createDeletedContentDecoration = exports.createDeletedContentDecoration = fu
265
269
  // Skip the case where the node is a paragraph or table row that way it can still be rendered and delete the entire table
266
270
  return;
267
271
  } else {
268
- dom.append(fallbackSerialization());
272
+ var fallbackNode = fallbackSerialization();
273
+ if (fallbackNode) {
274
+ dom.append(fallbackNode);
275
+ }
269
276
  }
270
277
  });
271
278
  dom.setAttribute('data-testid', 'show-diff-deleted-decoration');
272
279
 
273
280
  // Widget decoration used for deletions as the content is not in the document
274
281
  // and we want to display the deleted content with a style.
275
- return _view.Decoration.widget(change.fromB, dom, {});
282
+ var safeInsertPos = (0, _findSafeInsertPos.findSafeInsertPos)(newDoc, change.fromB, slice);
283
+ return _view.Decoration.widget(safeInsertPos, dom, {});
276
284
  };
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.findSafeInsertPos = findSafeInsertPos;
7
+ var _utils = require("@atlaskit/editor-prosemirror/utils");
8
+ /**
9
+ * Find a safe position to insert a deletion slice at the given position.
10
+ * @param doc
11
+ * @param pos
12
+ * @param slice
13
+ * @returns
14
+ */
15
+ function findSafeInsertPos(doc, pos, slice) {
16
+ if (pos > doc.content.size) {
17
+ return doc.content.size;
18
+ }
19
+ var $pos = doc.resolve(pos);
20
+ while (!(0, _utils.canInsert)($pos, slice.content) && ((_slice$content$firstC = slice.content.firstChild) === null || _slice$content$firstC === void 0 ? void 0 : _slice$content$firstC.type.name) !== 'paragraph') {
21
+ var _slice$content$firstC;
22
+ if ($pos.pos + 1 > doc.content.size) {
23
+ break;
24
+ }
25
+ $pos = doc.resolve($pos.pos + 1);
26
+ }
27
+ return $pos.pos;
28
+ }
@@ -62,6 +62,18 @@ export class NodeViewSerializer {
62
62
  this.nodeViews = (_ref = nodeViews !== null && nodeViews !== void 0 ? nodeViews : (_this$editorView = this.editorView) === null || _this$editorView === void 0 ? void 0 : _this$editorView.nodeViews) !== null && _ref !== void 0 ? _ref : {};
63
63
  }
64
64
 
65
+ /**
66
+ * Appends serialized child nodes to the given contentDOM element.
67
+ */
68
+ appendChildNodes(children, contentDOM) {
69
+ children.forEach(child => {
70
+ const childNode = this.tryCreateNodeView(child) || this.serializeNode(child);
71
+ if (childNode) {
72
+ contentDOM === null || contentDOM === void 0 ? void 0 : contentDOM.append(childNode);
73
+ }
74
+ });
75
+ }
76
+
65
77
  /**
66
78
  * Attempts to create a node view for the given node.
67
79
  *
@@ -77,40 +89,40 @@ export class NodeViewSerializer {
77
89
  if (this.nodeViewBlocklist.has(targetNode.type.name)) {
78
90
  return null;
79
91
  }
80
- if (!constructor) {
81
- var _targetNode$type$spec, _targetNode$type$spec2;
82
- if (targetNode.isInline) {
83
- return null;
84
- }
85
- const toDOMResult = (_targetNode$type$spec = (_targetNode$type$spec2 = targetNode.type.spec).toDOM) === null || _targetNode$type$spec === void 0 ? void 0 : _targetNode$type$spec.call(_targetNode$type$spec2, targetNode);
86
- if (!toDOMResult) {
87
- return null;
92
+ try {
93
+ if (!constructor) {
94
+ var _targetNode$type$spec, _targetNode$type$spec2;
95
+ if (targetNode.isInline) {
96
+ return null;
97
+ }
98
+ const toDOMResult = (_targetNode$type$spec = (_targetNode$type$spec2 = targetNode.type.spec).toDOM) === null || _targetNode$type$spec === void 0 ? void 0 : _targetNode$type$spec.call(_targetNode$type$spec2, targetNode);
99
+ if (!toDOMResult) {
100
+ return null;
101
+ }
102
+ const {
103
+ dom,
104
+ contentDOM
105
+ } = DOMSerializer.renderSpec(document, toDOMResult);
106
+ if (dom instanceof HTMLElement) {
107
+ if (targetNode.type.name === 'paragraph' && targetNode.children.length === 1) {
108
+ return this.serializeFragment(targetNode.content);
109
+ }
110
+
111
+ // Iteratively populate children
112
+ this.appendChildNodes(targetNode.children, contentDOM);
113
+ }
114
+ return dom;
88
115
  }
89
116
  const {
90
117
  dom,
91
118
  contentDOM
92
- } = DOMSerializer.renderSpec(document, toDOMResult);
93
- if (dom instanceof HTMLElement) {
94
- if (targetNode.type.name === 'paragraph' && targetNode.children.length === 1) {
95
- return this.serializeFragment(targetNode.content);
96
- }
97
-
98
- // Iteratively populate children
99
- targetNode.children.forEach(child => {
100
- contentDOM === null || contentDOM === void 0 ? void 0 : contentDOM.append(this.tryCreateNodeView(child) || this.serializeNode(child));
101
- });
102
- }
119
+ } = constructor(targetNode, this.editorView, () => 0, [], {});
120
+ // Iteratively populate children
121
+ this.appendChildNodes(targetNode.children, contentDOM);
103
122
  return dom;
123
+ } catch (e) {
124
+ return null;
104
125
  }
105
- const {
106
- dom,
107
- contentDOM
108
- } = constructor(targetNode, this.editorView, () => 0, [], {});
109
- // Iteratively populate children
110
- targetNode.children.forEach(child => {
111
- contentDOM === null || contentDOM === void 0 ? void 0 : contentDOM.append(this.tryCreateNodeView(child) || this.serializeNode(child));
112
- });
113
- return dom;
114
126
  }
115
127
 
116
128
  /**
@@ -120,7 +132,11 @@ export class NodeViewSerializer {
120
132
  if (!this.serializer) {
121
133
  throw new Error('NodeViewSerializer must be initialized with init() before use');
122
134
  }
123
- return this.serializer.serializeNode(node);
135
+ try {
136
+ return this.serializer.serializeNode(node);
137
+ } catch (e) {
138
+ return null;
139
+ }
124
140
  }
125
141
 
126
142
  /**
@@ -130,7 +146,11 @@ export class NodeViewSerializer {
130
146
  if (!this.serializer) {
131
147
  throw new Error('NodeViewSerializer must be initialized with init() before use');
132
148
  }
133
- return this.serializer.serializeFragment(fragment);
149
+ try {
150
+ return this.serializer.serializeFragment(fragment);
151
+ } catch (e) {
152
+ return null;
153
+ }
134
154
  }
135
155
 
136
156
  /**
@@ -124,7 +124,8 @@ const calculateDiffDecorationsInner = ({
124
124
  change,
125
125
  doc: originalDoc,
126
126
  nodeViewSerializer,
127
- colourScheme
127
+ colourScheme,
128
+ newDoc: tr.doc
128
129
  });
129
130
  if (decoration) {
130
131
  decorations.push(decoration);
@@ -1,5 +1,6 @@
1
1
  import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
2
2
  import { Decoration } from '@atlaskit/editor-prosemirror/view';
3
+ import { findSafeInsertPos } from './findSafeInsertPos';
3
4
  const editingStyle = convertToInlineCss({
4
5
  background: "var(--ds-background-accent-purple-subtlest, #F3F0FF)",
5
6
  textDecoration: 'underline',
@@ -137,7 +138,8 @@ export const createDeletedContentDecoration = ({
137
138
  change,
138
139
  doc,
139
140
  nodeViewSerializer,
140
- colourScheme
141
+ colourScheme,
142
+ newDoc
141
143
  }) => {
142
144
  const slice = doc.slice(change.fromA, change.toA);
143
145
  if (slice.content.content.length === 0) {
@@ -186,7 +188,9 @@ export const createDeletedContentDecoration = ({
186
188
  } else {
187
189
  // Fallback to serializing the individual child node
188
190
  const serializedChild = serializer.serializeNode(childNode);
189
- dom.append(serializedChild);
191
+ if (serializedChild) {
192
+ dom.append(serializedChild);
193
+ }
190
194
  }
191
195
  });
192
196
  return true; // Indicates we handled multiple children
@@ -244,12 +248,16 @@ export const createDeletedContentDecoration = ({
244
248
  // Skip the case where the node is a paragraph or table row that way it can still be rendered and delete the entire table
245
249
  return;
246
250
  } else {
247
- dom.append(fallbackSerialization());
251
+ const fallbackNode = fallbackSerialization();
252
+ if (fallbackNode) {
253
+ dom.append(fallbackNode);
254
+ }
248
255
  }
249
256
  });
250
257
  dom.setAttribute('data-testid', 'show-diff-deleted-decoration');
251
258
 
252
259
  // Widget decoration used for deletions as the content is not in the document
253
260
  // and we want to display the deleted content with a style.
254
- return Decoration.widget(change.fromB, dom, {});
261
+ const safeInsertPos = findSafeInsertPos(newDoc, change.fromB, slice);
262
+ return Decoration.widget(safeInsertPos, dom, {});
255
263
  };
@@ -0,0 +1,23 @@
1
+ import { canInsert } from '@atlaskit/editor-prosemirror/utils';
2
+
3
+ /**
4
+ * Find a safe position to insert a deletion slice at the given position.
5
+ * @param doc
6
+ * @param pos
7
+ * @param slice
8
+ * @returns
9
+ */
10
+ export function findSafeInsertPos(doc, pos, slice) {
11
+ if (pos > doc.content.size) {
12
+ return doc.content.size;
13
+ }
14
+ let $pos = doc.resolve(pos);
15
+ while (!canInsert($pos, slice.content) && ((_slice$content$firstC = slice.content.firstChild) === null || _slice$content$firstC === void 0 ? void 0 : _slice$content$firstC.type.name) !== 'paragraph') {
16
+ var _slice$content$firstC;
17
+ if ($pos.pos + 1 > doc.content.size) {
18
+ break;
19
+ }
20
+ $pos = doc.resolve($pos.pos + 1);
21
+ }
22
+ return $pos.pos;
23
+ }
@@ -67,6 +67,21 @@ export var NodeViewSerializer = /*#__PURE__*/function () {
67
67
  this.nodeViews = (_ref = nodeViews !== null && nodeViews !== void 0 ? nodeViews : (_this$editorView = this.editorView) === null || _this$editorView === void 0 ? void 0 : _this$editorView.nodeViews) !== null && _ref !== void 0 ? _ref : {};
68
68
  }
69
69
 
70
+ /**
71
+ * Appends serialized child nodes to the given contentDOM element.
72
+ */
73
+ }, {
74
+ key: "appendChildNodes",
75
+ value: function appendChildNodes(children, contentDOM) {
76
+ var _this = this;
77
+ children.forEach(function (child) {
78
+ var childNode = _this.tryCreateNodeView(child) || _this.serializeNode(child);
79
+ if (childNode) {
80
+ contentDOM === null || contentDOM === void 0 || contentDOM.append(childNode);
81
+ }
82
+ });
83
+ }
84
+
70
85
  /**
71
86
  * Attempts to create a node view for the given node.
72
87
  *
@@ -76,8 +91,7 @@ export var NodeViewSerializer = /*#__PURE__*/function () {
76
91
  }, {
77
92
  key: "tryCreateNodeView",
78
93
  value: function tryCreateNodeView(targetNode) {
79
- var _this$nodeViews,
80
- _this = this;
94
+ var _this$nodeViews;
81
95
  if (!this.editorView) {
82
96
  return null;
83
97
  }
@@ -85,40 +99,40 @@ export var NodeViewSerializer = /*#__PURE__*/function () {
85
99
  if (this.nodeViewBlocklist.has(targetNode.type.name)) {
86
100
  return null;
87
101
  }
88
- if (!constructor) {
89
- var _targetNode$type$spec, _targetNode$type$spec2;
90
- if (targetNode.isInline) {
91
- return null;
92
- }
93
- var toDOMResult = (_targetNode$type$spec = (_targetNode$type$spec2 = targetNode.type.spec).toDOM) === null || _targetNode$type$spec === void 0 ? void 0 : _targetNode$type$spec.call(_targetNode$type$spec2, targetNode);
94
- if (!toDOMResult) {
95
- return null;
96
- }
97
- var _DOMSerializer$render = DOMSerializer.renderSpec(document, toDOMResult),
98
- _dom = _DOMSerializer$render.dom,
99
- _contentDOM = _DOMSerializer$render.contentDOM;
100
- if (_dom instanceof HTMLElement) {
101
- if (targetNode.type.name === 'paragraph' && targetNode.children.length === 1) {
102
- return this.serializeFragment(targetNode.content);
102
+ try {
103
+ if (!constructor) {
104
+ var _targetNode$type$spec, _targetNode$type$spec2;
105
+ if (targetNode.isInline) {
106
+ return null;
103
107
  }
108
+ var toDOMResult = (_targetNode$type$spec = (_targetNode$type$spec2 = targetNode.type.spec).toDOM) === null || _targetNode$type$spec === void 0 ? void 0 : _targetNode$type$spec.call(_targetNode$type$spec2, targetNode);
109
+ if (!toDOMResult) {
110
+ return null;
111
+ }
112
+ var _DOMSerializer$render = DOMSerializer.renderSpec(document, toDOMResult),
113
+ _dom = _DOMSerializer$render.dom,
114
+ _contentDOM = _DOMSerializer$render.contentDOM;
115
+ if (_dom instanceof HTMLElement) {
116
+ if (targetNode.type.name === 'paragraph' && targetNode.children.length === 1) {
117
+ return this.serializeFragment(targetNode.content);
118
+ }
104
119
 
105
- // Iteratively populate children
106
- targetNode.children.forEach(function (child) {
107
- _contentDOM === null || _contentDOM === void 0 || _contentDOM.append(_this.tryCreateNodeView(child) || _this.serializeNode(child));
108
- });
120
+ // Iteratively populate children
121
+ this.appendChildNodes(targetNode.children, _contentDOM);
122
+ }
123
+ return _dom;
109
124
  }
110
- return _dom;
125
+ var _constructor = constructor(targetNode, this.editorView, function () {
126
+ return 0;
127
+ }, [], {}),
128
+ dom = _constructor.dom,
129
+ contentDOM = _constructor.contentDOM;
130
+ // Iteratively populate children
131
+ this.appendChildNodes(targetNode.children, contentDOM);
132
+ return dom;
133
+ } catch (e) {
134
+ return null;
111
135
  }
112
- var _constructor = constructor(targetNode, this.editorView, function () {
113
- return 0;
114
- }, [], {}),
115
- dom = _constructor.dom,
116
- contentDOM = _constructor.contentDOM;
117
- // Iteratively populate children
118
- targetNode.children.forEach(function (child) {
119
- contentDOM === null || contentDOM === void 0 || contentDOM.append(_this.tryCreateNodeView(child) || _this.serializeNode(child));
120
- });
121
- return dom;
122
136
  }
123
137
 
124
138
  /**
@@ -130,7 +144,11 @@ export var NodeViewSerializer = /*#__PURE__*/function () {
130
144
  if (!this.serializer) {
131
145
  throw new Error('NodeViewSerializer must be initialized with init() before use');
132
146
  }
133
- return this.serializer.serializeNode(node);
147
+ try {
148
+ return this.serializer.serializeNode(node);
149
+ } catch (e) {
150
+ return null;
151
+ }
134
152
  }
135
153
 
136
154
  /**
@@ -142,7 +160,11 @@ export var NodeViewSerializer = /*#__PURE__*/function () {
142
160
  if (!this.serializer) {
143
161
  throw new Error('NodeViewSerializer must be initialized with init() before use');
144
162
  }
145
- return this.serializer.serializeFragment(fragment);
163
+ try {
164
+ return this.serializer.serializeFragment(fragment);
165
+ } catch (e) {
166
+ return null;
167
+ }
146
168
  }
147
169
 
148
170
  /**
@@ -134,7 +134,8 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref)
134
134
  change: change,
135
135
  doc: originalDoc,
136
136
  nodeViewSerializer: nodeViewSerializer,
137
- colourScheme: colourScheme
137
+ colourScheme: colourScheme,
138
+ newDoc: tr.doc
138
139
  });
139
140
  if (decoration) {
140
141
  decorations.push(decoration);
@@ -1,5 +1,6 @@
1
1
  import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
2
2
  import { Decoration } from '@atlaskit/editor-prosemirror/view';
3
+ import { findSafeInsertPos } from './findSafeInsertPos';
3
4
  var editingStyle = convertToInlineCss({
4
5
  background: "var(--ds-background-accent-purple-subtlest, #F3F0FF)",
5
6
  textDecoration: 'underline',
@@ -145,7 +146,8 @@ export var createDeletedContentDecoration = function createDeletedContentDecorat
145
146
  var change = _ref.change,
146
147
  doc = _ref.doc,
147
148
  nodeViewSerializer = _ref.nodeViewSerializer,
148
- colourScheme = _ref.colourScheme;
149
+ colourScheme = _ref.colourScheme,
150
+ newDoc = _ref.newDoc;
149
151
  var slice = doc.slice(change.fromA, change.toA);
150
152
  if (slice.content.content.length === 0) {
151
153
  return;
@@ -197,7 +199,9 @@ export var createDeletedContentDecoration = function createDeletedContentDecorat
197
199
  } else {
198
200
  // Fallback to serializing the individual child node
199
201
  var serializedChild = serializer.serializeNode(childNode);
200
- dom.append(serializedChild);
202
+ if (serializedChild) {
203
+ dom.append(serializedChild);
204
+ }
201
205
  }
202
206
  });
203
207
  return true; // Indicates we handled multiple children
@@ -259,12 +263,16 @@ export var createDeletedContentDecoration = function createDeletedContentDecorat
259
263
  // Skip the case where the node is a paragraph or table row that way it can still be rendered and delete the entire table
260
264
  return;
261
265
  } else {
262
- dom.append(fallbackSerialization());
266
+ var fallbackNode = fallbackSerialization();
267
+ if (fallbackNode) {
268
+ dom.append(fallbackNode);
269
+ }
263
270
  }
264
271
  });
265
272
  dom.setAttribute('data-testid', 'show-diff-deleted-decoration');
266
273
 
267
274
  // Widget decoration used for deletions as the content is not in the document
268
275
  // and we want to display the deleted content with a style.
269
- return Decoration.widget(change.fromB, dom, {});
276
+ var safeInsertPos = findSafeInsertPos(newDoc, change.fromB, slice);
277
+ return Decoration.widget(safeInsertPos, dom, {});
270
278
  };
@@ -0,0 +1,23 @@
1
+ import { canInsert } from '@atlaskit/editor-prosemirror/utils';
2
+
3
+ /**
4
+ * Find a safe position to insert a deletion slice at the given position.
5
+ * @param doc
6
+ * @param pos
7
+ * @param slice
8
+ * @returns
9
+ */
10
+ export function findSafeInsertPos(doc, pos, slice) {
11
+ if (pos > doc.content.size) {
12
+ return doc.content.size;
13
+ }
14
+ var $pos = doc.resolve(pos);
15
+ while (!canInsert($pos, slice.content) && ((_slice$content$firstC = slice.content.firstChild) === null || _slice$content$firstC === void 0 ? void 0 : _slice$content$firstC.type.name) !== 'paragraph') {
16
+ var _slice$content$firstC;
17
+ if ($pos.pos + 1 > doc.content.size) {
18
+ break;
19
+ }
20
+ $pos = doc.resolve($pos.pos + 1);
21
+ }
22
+ return $pos.pos;
23
+ }
@@ -49,6 +49,10 @@ export declare class NodeViewSerializer {
49
49
  init(params: {
50
50
  editorView: EditorView;
51
51
  }): void;
52
+ /**
53
+ * Appends serialized child nodes to the given contentDOM element.
54
+ */
55
+ private appendChildNodes;
52
56
  /**
53
57
  * Attempts to create a node view for the given node.
54
58
  *
@@ -59,11 +63,11 @@ export declare class NodeViewSerializer {
59
63
  /**
60
64
  * Serializes a node to a DOM `Node` using the schema's `DOMSerializer`.
61
65
  */
62
- serializeNode(node: PMNode): Node;
66
+ serializeNode(node: PMNode): Node | null;
63
67
  /**
64
68
  * Serializes a fragment to a `DocumentFragment` using the schema's `DOMSerializer`.
65
69
  */
66
- serializeFragment(fragment: Fragment): DocumentFragment | HTMLElement;
70
+ serializeFragment(fragment: Fragment): DocumentFragment | HTMLElement | null;
67
71
  /**
68
72
  * Returns a copy of the current node view blocklist.
69
73
  */
@@ -27,7 +27,8 @@ interface DeletedContentDecorationProps {
27
27
  change: Change;
28
28
  colourScheme?: 'standard' | 'traditional';
29
29
  doc: PMNode;
30
+ newDoc: PMNode;
30
31
  nodeViewSerializer: NodeViewSerializer;
31
32
  }
32
- export declare const createDeletedContentDecoration: ({ change, doc, nodeViewSerializer, colourScheme, }: DeletedContentDecorationProps) => Decoration | undefined;
33
+ export declare const createDeletedContentDecoration: ({ change, doc, nodeViewSerializer, colourScheme, newDoc, }: DeletedContentDecorationProps) => Decoration | undefined;
33
34
  export {};
@@ -0,0 +1,9 @@
1
+ import type { Node as PMNode, Slice } from '@atlaskit/editor-prosemirror/model';
2
+ /**
3
+ * Find a safe position to insert a deletion slice at the given position.
4
+ * @param doc
5
+ * @param pos
6
+ * @param slice
7
+ * @returns
8
+ */
9
+ export declare function findSafeInsertPos(doc: PMNode, pos: number, slice: Slice): number;
@@ -49,6 +49,10 @@ export declare class NodeViewSerializer {
49
49
  init(params: {
50
50
  editorView: EditorView;
51
51
  }): void;
52
+ /**
53
+ * Appends serialized child nodes to the given contentDOM element.
54
+ */
55
+ private appendChildNodes;
52
56
  /**
53
57
  * Attempts to create a node view for the given node.
54
58
  *
@@ -59,11 +63,11 @@ export declare class NodeViewSerializer {
59
63
  /**
60
64
  * Serializes a node to a DOM `Node` using the schema's `DOMSerializer`.
61
65
  */
62
- serializeNode(node: PMNode): Node;
66
+ serializeNode(node: PMNode): Node | null;
63
67
  /**
64
68
  * Serializes a fragment to a `DocumentFragment` using the schema's `DOMSerializer`.
65
69
  */
66
- serializeFragment(fragment: Fragment): DocumentFragment | HTMLElement;
70
+ serializeFragment(fragment: Fragment): DocumentFragment | HTMLElement | null;
67
71
  /**
68
72
  * Returns a copy of the current node view blocklist.
69
73
  */
@@ -27,7 +27,8 @@ interface DeletedContentDecorationProps {
27
27
  change: Change;
28
28
  colourScheme?: 'standard' | 'traditional';
29
29
  doc: PMNode;
30
+ newDoc: PMNode;
30
31
  nodeViewSerializer: NodeViewSerializer;
31
32
  }
32
- export declare const createDeletedContentDecoration: ({ change, doc, nodeViewSerializer, colourScheme, }: DeletedContentDecorationProps) => Decoration | undefined;
33
+ export declare const createDeletedContentDecoration: ({ change, doc, nodeViewSerializer, colourScheme, newDoc, }: DeletedContentDecorationProps) => Decoration | undefined;
33
34
  export {};
@@ -0,0 +1,9 @@
1
+ import type { Node as PMNode, Slice } from '@atlaskit/editor-prosemirror/model';
2
+ /**
3
+ * Find a safe position to insert a deletion slice at the given position.
4
+ * @param doc
5
+ * @param pos
6
+ * @param slice
7
+ * @returns
8
+ */
9
+ export declare function findSafeInsertPos(doc: PMNode, pos: number, slice: Slice): number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-show-diff",
3
- "version": "3.0.2",
3
+ "version": "3.1.1",
4
4
  "description": "ShowDiff plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -28,7 +28,7 @@
28
28
  "sideEffects": false,
29
29
  "atlaskit:src": "src/index.ts",
30
30
  "dependencies": {
31
- "@atlaskit/adf-schema": "^51.2.0",
31
+ "@atlaskit/adf-schema": "^51.3.0",
32
32
  "@atlaskit/editor-prosemirror": "7.0.0",
33
33
  "@atlaskit/tokens": "^7.0.0",
34
34
  "@babel/runtime": "^7.0.0",
@@ -37,7 +37,7 @@
37
37
  "prosemirror-changeset": "^2.2.1"
38
38
  },
39
39
  "peerDependencies": {
40
- "@atlaskit/editor-common": "^110.13.0",
40
+ "@atlaskit/editor-common": "^110.15.0",
41
41
  "react": "^18.2.0"
42
42
  },
43
43
  "techstack": {