@atlaskit/editor-plugin-show-diff 6.1.2 → 6.1.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.
Files changed (31) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/cjs/pm-plugins/areDocsEqualByBlockStructureAndText.js +29 -0
  3. package/dist/cjs/pm-plugins/calculateDiffDecorations.js +29 -10
  4. package/dist/cjs/pm-plugins/decorations/colorSchemes/standard.js +1 -1
  5. package/dist/cjs/pm-plugins/decorations/colorSchemes/traditional.js +39 -2
  6. package/dist/cjs/pm-plugins/decorations/createBlockChangedDecoration.js +37 -27
  7. package/dist/cjs/pm-plugins/decorations/createNodeChangedDecorationWidget.js +10 -4
  8. package/dist/cjs/pm-plugins/main.js +19 -3
  9. package/dist/es2019/pm-plugins/areDocsEqualByBlockStructureAndText.js +23 -0
  10. package/dist/es2019/pm-plugins/calculateDiffDecorations.js +28 -10
  11. package/dist/es2019/pm-plugins/decorations/colorSchemes/standard.js +1 -1
  12. package/dist/es2019/pm-plugins/decorations/colorSchemes/traditional.js +38 -1
  13. package/dist/es2019/pm-plugins/decorations/createBlockChangedDecoration.js +36 -28
  14. package/dist/es2019/pm-plugins/decorations/createNodeChangedDecorationWidget.js +13 -6
  15. package/dist/es2019/pm-plugins/main.js +17 -1
  16. package/dist/esm/pm-plugins/areDocsEqualByBlockStructureAndText.js +23 -0
  17. package/dist/esm/pm-plugins/calculateDiffDecorations.js +29 -10
  18. package/dist/esm/pm-plugins/decorations/colorSchemes/standard.js +1 -1
  19. package/dist/esm/pm-plugins/decorations/colorSchemes/traditional.js +38 -1
  20. package/dist/esm/pm-plugins/decorations/createBlockChangedDecoration.js +38 -28
  21. package/dist/esm/pm-plugins/decorations/createNodeChangedDecorationWidget.js +11 -5
  22. package/dist/esm/pm-plugins/main.js +19 -3
  23. package/dist/types/pm-plugins/areDocsEqualByBlockStructureAndText.d.ts +7 -0
  24. package/dist/types/pm-plugins/decorations/colorSchemes/traditional.d.ts +9 -0
  25. package/dist/types/pm-plugins/decorations/createBlockChangedDecoration.d.ts +8 -5
  26. package/dist/types/pm-plugins/decorations/createNodeChangedDecorationWidget.d.ts +1 -1
  27. package/dist/types-ts4.5/pm-plugins/areDocsEqualByBlockStructureAndText.d.ts +7 -0
  28. package/dist/types-ts4.5/pm-plugins/decorations/colorSchemes/traditional.d.ts +9 -0
  29. package/dist/types-ts4.5/pm-plugins/decorations/createBlockChangedDecoration.d.ts +8 -5
  30. package/dist/types-ts4.5/pm-plugins/decorations/createNodeChangedDecorationWidget.d.ts +1 -1
  31. package/package.json +5 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # @atlaskit/editor-plugin-show-diff
2
2
 
3
+ ## 6.1.4
4
+
5
+ ### Patch Changes
6
+
7
+ - [`9df4b10b5f0f8`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/9df4b10b5f0f8) -
8
+ Improve edge cases when showing diff by using a looser equality structure for steps.
9
+ - Updated dependencies
10
+
11
+ ## 6.1.3
12
+
13
+ ### Patch Changes
14
+
15
+ - [`8c860e8e9e774`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/8c860e8e9e774) -
16
+ Make active decorations more distinct
17
+
3
18
  ## 6.1.2
4
19
 
5
20
  ### Patch Changes
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.areDocsEqualByBlockStructureAndText = areDocsEqualByBlockStructureAndText;
7
+ /**
8
+ * Returns true if both nodes have the same tree structure (type and child count at every level).
9
+ */
10
+ function isBlockStructureEqual(node1, node2) {
11
+ if (node1.type !== node2.type || node1.childCount !== node2.childCount) {
12
+ return false;
13
+ }
14
+ for (var i = 0; i < node1.childCount; i++) {
15
+ if (!isBlockStructureEqual(node1.child(i), node2.child(i))) {
16
+ return false;
17
+ }
18
+ }
19
+ return true;
20
+ }
21
+
22
+ /**
23
+ * Looser equality for "safe diff" cases: same full text content and same block structure
24
+ * (e.g. text moved across text-node boundaries). Used when strict areNodesEqualIgnoreAttrs fails.
25
+ * This is safe because we ensure decorations get applied to valid positions.
26
+ */
27
+ function areDocsEqualByBlockStructureAndText(doc1, doc2) {
28
+ return doc1.textContent === doc2.textContent && doc1.nodeSize === doc2.nodeSize && isBlockStructureEqual(doc1, doc2);
29
+ }
@@ -13,7 +13,9 @@ var _memoizeOne = _interopRequireDefault(require("memoize-one"));
13
13
  var _prosemirrorChangeset = require("prosemirror-changeset");
14
14
  var _document = require("@atlaskit/editor-common/utils/document");
15
15
  var _view = require("@atlaskit/editor-prosemirror/view");
16
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
16
17
  var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
18
+ var _areDocsEqualByBlockStructureAndText = require("./areDocsEqualByBlockStructureAndText");
17
19
  var _createBlockChangedDecoration = require("./decorations/createBlockChangedDecoration");
18
20
  var _createInlineChangedDecoration = require("./decorations/createInlineChangedDecoration");
19
21
  var _createNodeChangedDecorationWidget = require("./decorations/createNodeChangedDecorationWidget");
@@ -31,19 +33,23 @@ var calculateNodesForBlockDecoration = function calculateNodesForBlockDecoration
31
33
  to = _ref.to,
32
34
  colorScheme = _ref.colorScheme,
33
35
  _ref$isInserted = _ref.isInserted,
34
- isInserted = _ref$isInserted === void 0 ? true : _ref$isInserted;
36
+ isInserted = _ref$isInserted === void 0 ? true : _ref$isInserted,
37
+ activeIndexPos = _ref.activeIndexPos;
35
38
  var decorations = [];
36
39
  // Iterate over the document nodes within the range
37
40
  doc.nodesBetween(from, to, function (node, pos) {
38
41
  if (node.isBlock && (!(0, _expValEquals.expValEquals)('platform_editor_diff_plugin_extended', 'isEnabled', true) || pos + node.nodeSize <= to)) {
42
+ var nodeEnd = pos + node.nodeSize;
43
+ var isActive = activeIndexPos && pos === activeIndexPos.from && nodeEnd === activeIndexPos.to;
39
44
  var decoration = (0, _createBlockChangedDecoration.createBlockChangedDecoration)({
40
45
  change: {
41
46
  from: pos,
42
- to: pos + node.nodeSize,
47
+ to: nodeEnd,
43
48
  name: node.type.name
44
49
  },
45
50
  colorScheme: colorScheme,
46
- isInserted: isInserted
51
+ isInserted: isInserted,
52
+ isActive: isActive
47
53
  });
48
54
  if (decoration) {
49
55
  decorations.push(decoration);
@@ -128,6 +134,7 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref2
128
134
  _iterator.f();
129
135
  }
130
136
  if (!(0, _document.areNodesEqualIgnoreAttrs)(steppedDoc, tr.doc)) {
137
+ var recoveredViaContentEquality = (0, _platformFeatureFlags.fg)('platform_editor_show_diff_equality_fallback') ? (0, _areDocsEqualByBlockStructureAndText.areDocsEqualByBlockStructureAndText)(steppedDoc, tr.doc) : undefined;
131
138
  if ((0, _expValEquals.expValEquals)('platform_editor_are_nodes_equal_ignore_mark_order', 'isEnabled', true)) {
132
139
  var _api$analytics;
133
140
  api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || _api$analytics.actions.fireAnalyticsEvent({
@@ -136,18 +143,25 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref2
136
143
  actionSubject: 'showDiff',
137
144
  attributes: {
138
145
  docSizeEqual: steppedDoc.nodeSize === tr.doc.nodeSize,
139
- colorScheme: colorScheme
146
+ colorScheme: colorScheme,
147
+ recoveredViaContentEquality: recoveredViaContentEquality
140
148
  }
141
149
  });
142
150
  }
143
- return _view.DecorationSet.empty;
151
+ if ((0, _platformFeatureFlags.fg)('platform_editor_show_diff_equality_fallback')) {
152
+ if (!recoveredViaContentEquality) {
153
+ return _view.DecorationSet.empty;
154
+ }
155
+ } else {
156
+ return _view.DecorationSet.empty;
157
+ }
144
158
  }
145
159
  var changeset = _prosemirrorChangeset.ChangeSet.create(originalDoc).addSteps(steppedDoc, stepMaps, tr.doc);
146
160
  var changes = (0, _prosemirrorChangeset.simplifyChanges)(changeset.changes, tr.doc);
147
161
  var optimizedChanges = optimizeChanges(changes);
148
162
  var decorations = [];
149
163
  optimizedChanges.forEach(function (change) {
150
- var isActive = activeIndexPos && change.fromB >= activeIndexPos.from && change.toB <= activeIndexPos.to;
164
+ var isActive = activeIndexPos && change.fromB === activeIndexPos.from && change.toB === activeIndexPos.to;
151
165
  // Our default operations are insertions, so it should match the opposite of isInverted.
152
166
  var isInserted = !isInverted;
153
167
  if (change.inserted.length > 0) {
@@ -158,17 +172,20 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref2
158
172
  }, (0, _expValEquals.expValEquals)('platform_editor_diff_plugin_extended', 'isEnabled', true) && {
159
173
  isInserted: isInserted
160
174
  })));
161
- decorations.push.apply(decorations, (0, _toConsumableArray2.default)(calculateNodesForBlockDecoration(_objectSpread({
175
+ decorations.push.apply(decorations, (0, _toConsumableArray2.default)(calculateNodesForBlockDecoration(_objectSpread(_objectSpread({
162
176
  doc: tr.doc,
163
177
  from: change.fromB,
164
178
  to: change.toB,
165
179
  colorScheme: colorScheme
166
180
  }, (0, _expValEquals.expValEquals)('platform_editor_diff_plugin_extended', 'isEnabled', true) && {
167
181
  isInserted: isInserted
182
+ }), {}, {
183
+ activeIndexPos: activeIndexPos,
184
+ intl: intl
168
185
  }))));
169
186
  }
170
187
  if (change.deleted.length > 0) {
171
- var _isActive = activeIndexPos && change.fromB >= activeIndexPos.from && change.toB <= activeIndexPos.to;
188
+ var _isActive = activeIndexPos && change.fromB === activeIndexPos.from && change.fromB === activeIndexPos.to;
172
189
  var decoration = (0, _createNodeChangedDecorationWidget.createNodeChangedDecorationWidget)(_objectSpread({
173
190
  change: change,
174
191
  doc: originalDoc,
@@ -186,7 +203,7 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref2
186
203
  }
187
204
  });
188
205
  (0, _getMarkChangeRanges.getMarkChangeRanges)(steps).forEach(function (change) {
189
- var isActive = activeIndexPos && change.fromB >= activeIndexPos.from && change.toB <= activeIndexPos.to;
206
+ var isActive = activeIndexPos && change.fromB === activeIndexPos.from && change.toB === activeIndexPos.to;
190
207
  decorations.push((0, _createInlineChangedDecoration.createInlineChangedDecoration)({
191
208
  change: change,
192
209
  colorScheme: colorScheme,
@@ -200,7 +217,9 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref2
200
217
  from: change.fromB,
201
218
  to: change.toB,
202
219
  colorScheme: colorScheme,
203
- isInserted: true
220
+ isInserted: true,
221
+ activeIndexPos: activeIndexPos,
222
+ intl: intl
204
223
  })));
205
224
  });
206
225
  return _view.DecorationSet.empty.add(tr.doc, decorations);
@@ -13,7 +13,7 @@ var editingStyle = exports.editingStyle = (0, _lazyNodeView.convertToInlineCss)(
13
13
  textDecorationColor: "var(--ds-border-accent-purple, #AF59E1)"
14
14
  });
15
15
  var editingStyleActive = exports.editingStyleActive = (0, _lazyNodeView.convertToInlineCss)({
16
- background: "var(--ds-background-accent-purple-subtler, #EED7FC)",
16
+ background: "var(--ds-background-accent-purple-subtler-pressed, #D8A0F7)",
17
17
  textDecoration: 'underline',
18
18
  textDecorationStyle: 'dotted',
19
19
  textDecorationThickness: "var(--ds-space-025, 2px)",
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.traditionalStyleRuleNode = exports.traditionalStyleQuoteNode = exports.traditionalStyleNode = exports.traditionalStyleCardBlockNode = exports.traditionalInsertStyleActive = exports.traditionalInsertStyle = exports.traditionalDecorationMarkerVariable = exports.traditionalAddedCellOverlayStyle = exports.deletedTraditionalStyleQuoteNode = exports.deletedTraditionalRowStyle = exports.deletedTraditionalContentStyleUnbounded = exports.deletedTraditionalContentStyle = exports.deletedTraditionalCellOverlayStyle = exports.deletedTraditionalBlockOutlineRounded = exports.deletedTraditionalBlockOutline = void 0;
6
+ exports.traditionalStyleRuleNodeActive = exports.traditionalStyleRuleNode = exports.traditionalStyleQuoteNodeActive = exports.traditionalStyleQuoteNode = exports.traditionalStyleNodeActive = exports.traditionalStyleNode = exports.traditionalStyleCardBlockNodeActive = exports.traditionalStyleCardBlockNode = exports.traditionalInsertStyleActive = exports.traditionalInsertStyle = exports.traditionalDecorationMarkerVariableActive = exports.traditionalDecorationMarkerVariable = exports.traditionalAddedCellOverlayStyle = exports.deletedTraditionalStyleQuoteNode = exports.deletedTraditionalRowStyle = exports.deletedTraditionalContentStyleUnboundedActive = exports.deletedTraditionalContentStyleUnbounded = exports.deletedTraditionalContentStyleActive = exports.deletedTraditionalContentStyle = exports.deletedTraditionalCellOverlayStyle = exports.deletedTraditionalBlockOutlineRounded = exports.deletedTraditionalBlockOutline = void 0;
7
7
  var _lazyNodeView = require("@atlaskit/editor-common/lazy-node-view");
8
8
  var traditionalInsertStyle = exports.traditionalInsertStyle = (0, _lazyNodeView.convertToInlineCss)({
9
9
  background: "var(--ds-background-accent-green-subtlest, #DCFFF1)",
@@ -13,7 +13,7 @@ var traditionalInsertStyle = exports.traditionalInsertStyle = (0, _lazyNodeView.
13
13
  textDecorationColor: "var(--ds-border-accent-green, #22A06B)"
14
14
  });
15
15
  var traditionalInsertStyleActive = exports.traditionalInsertStyleActive = (0, _lazyNodeView.convertToInlineCss)({
16
- background: "var(--ds-background-accent-green-subtler, #BAF3DB)",
16
+ background: "var(--ds-background-accent-green-subtler-pressed, #7EE2B8)",
17
17
  textDecoration: 'underline',
18
18
  textDecorationStyle: 'solid',
19
19
  textDecorationThickness: "var(--ds-space-025, 2px)",
@@ -25,6 +25,15 @@ var deletedTraditionalContentStyle = exports.deletedTraditionalContentStyle = (0
25
25
  position: 'relative',
26
26
  opacity: 1
27
27
  });
28
+
29
+ /** Emphasised (pressed) strikethrough for traditional removed text when active */
30
+ var deletedTraditionalContentStyleActive = exports.deletedTraditionalContentStyleActive = (0, _lazyNodeView.convertToInlineCss)({
31
+ textDecorationColor: "var(--ds-text-accent-red, #AE2E24)",
32
+ textDecoration: 'line-through',
33
+ backgroundColor: "var(--ds-background-accent-red-subtlest-pressed, #FFB8B2)",
34
+ position: 'relative',
35
+ opacity: 1
36
+ });
28
37
  var deletedTraditionalContentStyleUnbounded = exports.deletedTraditionalContentStyleUnbounded = (0, _lazyNodeView.convertToInlineCss)({
29
38
  position: 'absolute',
30
39
  top: '50%',
@@ -34,6 +43,17 @@ var deletedTraditionalContentStyleUnbounded = exports.deletedTraditionalContentS
34
43
  pointerEvents: 'none',
35
44
  zIndex: 1
36
45
  });
46
+
47
+ /** Emphasised (pressed) strikethrough line for traditional when active */
48
+ var deletedTraditionalContentStyleUnboundedActive = exports.deletedTraditionalContentStyleUnboundedActive = (0, _lazyNodeView.convertToInlineCss)({
49
+ position: 'absolute',
50
+ top: '50%',
51
+ width: '100%',
52
+ display: 'inline-block',
53
+ borderTop: "1px solid ".concat("var(--ds-text-accent-red-bolder, #5D1F1A)"),
54
+ pointerEvents: 'none',
55
+ zIndex: 1
56
+ });
37
57
  var deletedTraditionalStyleQuoteNode = exports.deletedTraditionalStyleQuoteNode = (0, _lazyNodeView.convertToInlineCss)({
38
58
  marginTop: "var(--ds-space-150, 12px)",
39
59
  paddingTop: "var(--ds-space-025, 2px)",
@@ -59,20 +79,37 @@ var deletedTraditionalRowStyle = exports.deletedTraditionalRowStyle = (0, _lazyN
59
79
  var traditionalStyleQuoteNode = exports.traditionalStyleQuoteNode = (0, _lazyNodeView.convertToInlineCss)({
60
80
  borderLeft: "2px solid ".concat("var(--ds-border-accent-green, #22A06B)")
61
81
  });
82
+ var traditionalStyleQuoteNodeActive = exports.traditionalStyleQuoteNodeActive = (0, _lazyNodeView.convertToInlineCss)({
83
+ borderLeft: "2px solid ".concat("var(--ds-background-accent-green-subtler-pressed, #7EE2B8)")
84
+ });
62
85
  var traditionalStyleRuleNode = exports.traditionalStyleRuleNode = (0, _lazyNodeView.convertToInlineCss)({
63
86
  backgroundColor: "var(--ds-border-accent-green, #22A06B)"
64
87
  });
88
+ var traditionalStyleRuleNodeActive = exports.traditionalStyleRuleNodeActive = (0, _lazyNodeView.convertToInlineCss)({
89
+ backgroundColor: "var(--ds-background-accent-green-subtler-pressed, #7EE2B8)"
90
+ });
65
91
  var traditionalStyleNode = exports.traditionalStyleNode = (0, _lazyNodeView.convertToInlineCss)({
66
92
  boxShadow: "0 0 0 1px ".concat("var(--ds-border-accent-green, #22A06B)"),
67
93
  borderRadius: "var(--ds-radius-small, 4px)"
68
94
  });
95
+ var traditionalStyleNodeActive = exports.traditionalStyleNodeActive = (0, _lazyNodeView.convertToInlineCss)({
96
+ boxShadow: "0 0 0 2px ".concat("var(--ds-background-accent-green-subtler-pressed, #7EE2B8)"),
97
+ borderRadius: "var(--ds-radius-small, 4px)"
98
+ });
69
99
  var traditionalStyleCardBlockNode = exports.traditionalStyleCardBlockNode = (0, _lazyNodeView.convertToInlineCss)({
70
100
  boxShadow: "0 0 0 1px ".concat("var(--ds-border-accent-green, #22A06B)"),
71
101
  borderRadius: "var(--ds-radius-medium, 6px)"
72
102
  });
103
+ var traditionalStyleCardBlockNodeActive = exports.traditionalStyleCardBlockNodeActive = (0, _lazyNodeView.convertToInlineCss)({
104
+ boxShadow: "0 0 0 1px ".concat("var(--ds-background-accent-green-subtler-pressed, #7EE2B8)"),
105
+ borderRadius: "var(--ds-radius-medium, 6px)"
106
+ });
73
107
  var traditionalDecorationMarkerVariable = exports.traditionalDecorationMarkerVariable = (0, _lazyNodeView.convertToInlineCss)({
74
108
  '--diff-decoration-marker-color': "var(--ds-border-accent-green, #22A06B)"
75
109
  });
110
+ var traditionalDecorationMarkerVariableActive = exports.traditionalDecorationMarkerVariableActive = (0, _lazyNodeView.convertToInlineCss)({
111
+ '--diff-decoration-marker-color': "var(--ds-text-accent-green, #216E4E)"
112
+ });
76
113
  var traditionalAddedCellOverlayStyle = exports.traditionalAddedCellOverlayStyle = (0, _lazyNodeView.convertToInlineCss)({
77
114
  position: 'absolute',
78
115
  top: 0,
@@ -21,7 +21,9 @@ var getBlockNodeStyle = function getBlockNodeStyle(_ref) {
21
21
  var nodeName = _ref.nodeName,
22
22
  colorScheme = _ref.colorScheme,
23
23
  _ref$isInserted = _ref.isInserted,
24
- isInserted = _ref$isInserted === void 0 ? true : _ref$isInserted;
24
+ isInserted = _ref$isInserted === void 0 ? true : _ref$isInserted,
25
+ _ref$isActive = _ref.isActive,
26
+ isActive = _ref$isActive === void 0 ? false : _ref$isActive;
25
27
  var isTraditional = colorScheme === 'traditional';
26
28
  if (['mediaSingle', 'mediaGroup', 'table',
27
29
  // Handle table separately to avoid border issues
@@ -34,73 +36,79 @@ var getBlockNodeStyle = function getBlockNodeStyle(_ref) {
34
36
  if (['extension', 'embedCard', 'listItem'].includes(nodeName)) {
35
37
  if ((0, _expValEquals.expValEquals)('platform_editor_diff_plugin_extended', 'isEnabled', true)) {
36
38
  if (isInserted) {
37
- return isTraditional ? _traditional.traditionalDecorationMarkerVariable : _standard.standardDecorationMarkerVariable;
39
+ return isTraditional && isActive ? _traditional.traditionalDecorationMarkerVariableActive : isTraditional ? _traditional.traditionalDecorationMarkerVariable : _standard.standardDecorationMarkerVariable;
38
40
  } else {
39
41
  return isTraditional ? _traditional.deletedTraditionalContentStyle : _standard.deletedContentStyleNew;
40
42
  }
41
43
  }
42
- return isTraditional ? _traditional.traditionalDecorationMarkerVariable : _standard.standardDecorationMarkerVariable;
44
+ return isTraditional && isActive ? _traditional.traditionalDecorationMarkerVariableActive : isTraditional ? _traditional.traditionalDecorationMarkerVariable : _standard.standardDecorationMarkerVariable;
43
45
  }
44
46
  if (nodeName === 'blockquote') {
45
47
  if ((0, _expValEquals.expValEquals)('platform_editor_diff_plugin_extended', 'isEnabled', true)) {
46
48
  if (isInserted) {
47
- return isTraditional ? _traditional.traditionalStyleQuoteNode : _standard.editingStyleQuoteNode;
49
+ return isTraditional ? isActive ? _traditional.traditionalStyleQuoteNodeActive : _traditional.traditionalStyleQuoteNode : _standard.editingStyleQuoteNode;
48
50
  } else {
49
51
  return isTraditional ? _traditional.deletedTraditionalStyleQuoteNode : _standard.deletedStyleQuoteNode;
50
52
  }
51
53
  }
52
- return isTraditional ? _traditional.traditionalStyleQuoteNode : _standard.editingStyleQuoteNode;
54
+ return isTraditional ? isActive ? _traditional.traditionalStyleQuoteNodeActive : _traditional.traditionalStyleQuoteNode : _standard.editingStyleQuoteNode;
53
55
  }
54
56
  if (nodeName === 'rule') {
55
57
  if ((0, _expValEquals.expValEquals)('platform_editor_diff_plugin_extended', 'isEnabled', true)) {
56
58
  if (isInserted) {
57
- return isTraditional ? _traditional.traditionalStyleRuleNode : _standard.editingStyleRuleNode;
59
+ return isTraditional ? isActive ? _traditional.traditionalStyleRuleNodeActive : _traditional.traditionalStyleRuleNode : _standard.editingStyleRuleNode;
58
60
  } else {
59
61
  return isTraditional ? _traditional.deletedTraditionalContentStyle : _standard.deletedContentStyleNew;
60
62
  }
61
63
  }
62
- return isTraditional ? _traditional.traditionalStyleRuleNode : _standard.editingStyleRuleNode;
64
+ return isTraditional ? isActive ? _traditional.traditionalStyleRuleNodeActive : _traditional.traditionalStyleRuleNode : _standard.editingStyleRuleNode;
63
65
  }
64
66
  if (nodeName === 'blockCard') {
65
67
  if ((0, _expValEquals.expValEquals)('platform_editor_diff_plugin_extended', 'isEnabled', true)) {
66
68
  if (isInserted) {
67
- return isTraditional ? _traditional.traditionalStyleCardBlockNode : _standard.editingStyleCardBlockNode;
69
+ return isTraditional ? isActive ? _traditional.traditionalStyleCardBlockNodeActive : _traditional.traditionalStyleCardBlockNode : _standard.editingStyleCardBlockNode;
68
70
  } else {
69
71
  return isTraditional ? _traditional.deletedTraditionalContentStyle : _standard.deletedContentStyleNew;
70
72
  }
71
73
  }
72
- return isTraditional ? _traditional.traditionalStyleCardBlockNode : _standard.editingStyleCardBlockNode;
74
+ return isTraditional ? isActive ? _traditional.traditionalStyleCardBlockNodeActive : _traditional.traditionalStyleCardBlockNode : _standard.editingStyleCardBlockNode;
73
75
  }
74
76
  if ((0, _expValEquals.expValEquals)('platform_editor_diff_plugin_extended', 'isEnabled', true)) {
75
77
  if (isInserted) {
76
- return isTraditional ? _traditional.traditionalStyleNode : _standard.editingStyleNode;
78
+ return isTraditional ? isActive ? _traditional.traditionalStyleNodeActive : _traditional.traditionalStyleNode : _standard.editingStyleNode;
77
79
  } else {
78
80
  return isTraditional ? _traditional.deletedTraditionalContentStyle : _standard.deletedContentStyleNew;
79
81
  }
80
82
  }
81
- return isTraditional ? _traditional.traditionalStyleNode : _standard.editingStyleNode;
83
+ return isTraditional ? isActive ? _traditional.traditionalStyleNodeActive : _traditional.traditionalStyleNode : _standard.editingStyleNode;
82
84
  };
83
85
 
84
86
  /**
85
- * Inline decoration used for insertions as the content already exists in the document
87
+ * Node decoration used for block-level insertions. When isActive, uses emphasised (pressed) styling.
86
88
  *
87
- * @param change Changeset "change" containing information about the change content + range
88
- * @returns Prosemirror inline decoration
89
+ * @param change Node range and name
90
+ * @param colorScheme Optional color scheme
91
+ * @param isActive Whether this node is part of the currently active/focused change
92
+ * @returns Prosemirror node decoration or undefined
89
93
  */
90
94
  var createBlockChangedDecoration = exports.createBlockChangedDecoration = function createBlockChangedDecoration(_ref2) {
91
95
  var change = _ref2.change,
92
96
  colorScheme = _ref2.colorScheme,
93
97
  _ref2$isInserted = _ref2.isInserted,
94
- isInserted = _ref2$isInserted === void 0 ? true : _ref2$isInserted;
98
+ isInserted = _ref2$isInserted === void 0 ? true : _ref2$isInserted,
99
+ _ref2$isActive = _ref2.isActive,
100
+ isActive = _ref2$isActive === void 0 ? false : _ref2$isActive;
95
101
  var style = getBlockNodeStyle({
96
102
  nodeName: change.name,
97
- colorScheme: colorScheme
103
+ colorScheme: colorScheme,
104
+ isActive: isActive
98
105
  });
99
106
  if ((0, _expValEquals.expValEquals)('platform_editor_diff_plugin_extended', 'isEnabled', true)) {
100
107
  style = getBlockNodeStyle({
101
108
  nodeName: change.name,
102
109
  colorScheme: colorScheme,
103
- isInserted: isInserted
110
+ isInserted: isInserted,
111
+ isActive: isActive
104
112
  });
105
113
  }
106
114
  var className = getNodeClass(change.name);
@@ -111,17 +119,19 @@ var createBlockChangedDecoration = exports.createBlockChangedDecoration = functi
111
119
  'data-testid': 'show-diff-changed-decoration-node',
112
120
  class: className
113
121
  }, {
114
- key: 'diff-block'
122
+ key: 'diff-block',
123
+ nodeName: change.name
115
124
  });
125
+ } else {
126
+ return undefined;
116
127
  }
117
- return undefined;
118
- } else {
119
- return _view.Decoration.node(change.from, change.to, {
120
- style: style,
121
- 'data-testid': 'show-diff-changed-decoration-node',
122
- class: className
123
- }, {
124
- key: 'diff-block'
125
- });
126
128
  }
129
+ return _view.Decoration.node(change.from, change.to, {
130
+ style: style,
131
+ 'data-testid': 'show-diff-changed-decoration-node',
132
+ class: className
133
+ }, {
134
+ key: 'diff-block',
135
+ nodeName: change.name
136
+ });
127
137
  };
@@ -15,6 +15,10 @@ var _createChangedRowDecorationWidgets = require("./createChangedRowDecorationWi
15
15
  var _findSafeInsertPos = require("./utils/findSafeInsertPos");
16
16
  var _wrapBlockNodeView = require("./utils/wrapBlockNodeView");
17
17
  var getDeletedContentStyleUnbounded = function getDeletedContentStyleUnbounded(colorScheme) {
18
+ var isActive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
19
+ if (colorScheme === 'traditional' && isActive) {
20
+ return _traditional.deletedTraditionalContentStyleUnboundedActive;
21
+ }
18
22
  return colorScheme === 'traditional' ? _traditional.deletedTraditionalContentStyleUnbounded : _standard.deletedContentStyleUnbounded;
19
23
  };
20
24
  var getInsertedContentStyle = function getInsertedContentStyle(colorScheme) {
@@ -33,7 +37,7 @@ var getInsertedContentStyle = function getInsertedContentStyle(colorScheme) {
33
37
  var getDeletedContentStyle = function getDeletedContentStyle(colorScheme) {
34
38
  var isActive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
35
39
  if (colorScheme === 'traditional') {
36
- return _traditional.deletedTraditionalContentStyle;
40
+ return isActive ? _traditional.deletedTraditionalContentStyleActive : _traditional.deletedTraditionalContentStyle;
37
41
  }
38
42
  if (isActive) {
39
43
  return (0, _expValEquals.expValEquals)('platform_editor_enghealth_a11y_jan_fixes', 'isEnabled', true) ? _standard.deletedContentStyleNewActive : _standard.deletedContentStyleActive;
@@ -254,7 +258,9 @@ var createNodeChangedDecorationWidget = exports.createNodeChangedDecorationWidge
254
258
  // Widget decoration used for deletions as the content is not in the document
255
259
  // and we want to display the deleted content with a style.
256
260
  var safeInsertPos = (0, _findSafeInsertPos.findSafeInsertPos)(newDoc, change.fromB, slice);
257
- return [_view.Decoration.widget(safeInsertPos, dom, {
258
- key: 'diff-widget'
259
- })];
261
+ var decorations = [];
262
+ decorations.push(_view.Decoration.widget(safeInsertPos, dom, {
263
+ key: "diff-widget-".concat(isActive ? 'active' : 'inactive')
264
+ }));
265
+ return decorations;
260
266
  };
@@ -21,9 +21,25 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
21
21
  var showDiffPluginKey = exports.showDiffPluginKey = new _state2.PluginKey('showDiffPlugin');
22
22
  var getScrollableDecorations = exports.getScrollableDecorations = function getScrollableDecorations(set) {
23
23
  var _set$find;
24
- return (_set$find = set === null || set === void 0 ? void 0 : set.find(undefined, undefined, function (spec) {
25
- return spec.key === 'diff-inline' || spec.key === 'diff-widget' || spec.key === 'diff-block';
26
- })) !== null && _set$find !== void 0 ? _set$find : [];
24
+ var seenBlockKeys = new Set();
25
+ return ((_set$find = set === null || set === void 0 ? void 0 : set.find(undefined, undefined, function (spec) {
26
+ var _spec$key;
27
+ return spec.key === 'diff-inline' || ((_spec$key = spec.key) === null || _spec$key === void 0 ? void 0 : _spec$key.startsWith('diff-widget')) || spec.key === 'diff-block';
28
+ })) !== null && _set$find !== void 0 ? _set$find : []).filter(function (dec) {
29
+ var _dec$spec;
30
+ if (((_dec$spec = dec.spec) === null || _dec$spec === void 0 ? void 0 : _dec$spec.key) === 'diff-block') {
31
+ var _dec$spec2, _dec$spec$nodeName, _dec$spec3;
32
+ // Skip listItem blocks as they are not scrollable
33
+ if (((_dec$spec2 = dec.spec) === null || _dec$spec2 === void 0 ? void 0 : _dec$spec2.nodeName) === 'listItem') return false;
34
+ var key = "".concat(dec.from, "-").concat(dec.to, "-").concat((_dec$spec$nodeName = (_dec$spec3 = dec.spec) === null || _dec$spec3 === void 0 ? void 0 : _dec$spec3.nodeName) !== null && _dec$spec$nodeName !== void 0 ? _dec$spec$nodeName : '');
35
+ // Skip blocks that have already been seen
36
+ if (seenBlockKeys.has(key)) return false;
37
+ seenBlockKeys.add(key);
38
+ }
39
+ return true;
40
+ }).sort(function (a, b) {
41
+ return a.from === b.from ? a.to - b.to : a.from - b.from;
42
+ });
27
43
  };
28
44
  var createPlugin = exports.createPlugin = function createPlugin(config, getIntl, api) {
29
45
  var nodeViewSerializer = new _NodeViewSerializer.NodeViewSerializer({});
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Returns true if both nodes have the same tree structure (type and child count at every level).
3
+ */
4
+ function isBlockStructureEqual(node1, node2) {
5
+ if (node1.type !== node2.type || node1.childCount !== node2.childCount) {
6
+ return false;
7
+ }
8
+ for (let i = 0; i < node1.childCount; i++) {
9
+ if (!isBlockStructureEqual(node1.child(i), node2.child(i))) {
10
+ return false;
11
+ }
12
+ }
13
+ return true;
14
+ }
15
+
16
+ /**
17
+ * Looser equality for "safe diff" cases: same full text content and same block structure
18
+ * (e.g. text moved across text-node boundaries). Used when strict areNodesEqualIgnoreAttrs fails.
19
+ * This is safe because we ensure decorations get applied to valid positions.
20
+ */
21
+ export function areDocsEqualByBlockStructureAndText(doc1, doc2) {
22
+ return doc1.textContent === doc2.textContent && doc1.nodeSize === doc2.nodeSize && isBlockStructureEqual(doc1, doc2);
23
+ }
@@ -4,7 +4,9 @@ import memoizeOne from 'memoize-one';
4
4
  import { ChangeSet, simplifyChanges } from 'prosemirror-changeset';
5
5
  import { areNodesEqualIgnoreAttrs } from '@atlaskit/editor-common/utils/document';
6
6
  import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
7
+ import { fg } from '@atlaskit/platform-feature-flags';
7
8
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
9
+ import { areDocsEqualByBlockStructureAndText } from './areDocsEqualByBlockStructureAndText';
8
10
  import { createBlockChangedDecoration } from './decorations/createBlockChangedDecoration';
9
11
  import { createInlineChangedDecoration } from './decorations/createInlineChangedDecoration';
10
12
  import { createNodeChangedDecorationWidget } from './decorations/createNodeChangedDecorationWidget';
@@ -16,20 +18,24 @@ const calculateNodesForBlockDecoration = ({
16
18
  from,
17
19
  to,
18
20
  colorScheme,
19
- isInserted = true
21
+ isInserted = true,
22
+ activeIndexPos
20
23
  }) => {
21
24
  const decorations = [];
22
25
  // Iterate over the document nodes within the range
23
26
  doc.nodesBetween(from, to, (node, pos) => {
24
27
  if (node.isBlock && (!expValEquals('platform_editor_diff_plugin_extended', 'isEnabled', true) || pos + node.nodeSize <= to)) {
28
+ const nodeEnd = pos + node.nodeSize;
29
+ const isActive = activeIndexPos && pos === activeIndexPos.from && nodeEnd === activeIndexPos.to;
25
30
  const decoration = createBlockChangedDecoration({
26
31
  change: {
27
32
  from: pos,
28
- to: pos + node.nodeSize,
33
+ to: nodeEnd,
29
34
  name: node.type.name
30
35
  },
31
36
  colorScheme,
32
- isInserted
37
+ isInserted,
38
+ isActive
33
39
  });
34
40
  if (decoration) {
35
41
  decorations.push(decoration);
@@ -113,6 +119,7 @@ const calculateDiffDecorationsInner = ({
113
119
  // Rather than using .eq() we use a custom function that only checks for structural
114
120
  // changes and ignores differences in attributes which don't affect decoration positions
115
121
  if (!areNodesEqualIgnoreAttrs(steppedDoc, tr.doc)) {
122
+ const recoveredViaContentEquality = fg('platform_editor_show_diff_equality_fallback') ? areDocsEqualByBlockStructureAndText(steppedDoc, tr.doc) : undefined;
116
123
  if (expValEquals('platform_editor_are_nodes_equal_ignore_mark_order', 'isEnabled', true)) {
117
124
  var _api$analytics;
118
125
  api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions.fireAnalyticsEvent({
@@ -121,18 +128,25 @@ const calculateDiffDecorationsInner = ({
121
128
  actionSubject: 'showDiff',
122
129
  attributes: {
123
130
  docSizeEqual: steppedDoc.nodeSize === tr.doc.nodeSize,
124
- colorScheme
131
+ colorScheme,
132
+ recoveredViaContentEquality
125
133
  }
126
134
  });
127
135
  }
128
- return DecorationSet.empty;
136
+ if (fg('platform_editor_show_diff_equality_fallback')) {
137
+ if (!recoveredViaContentEquality) {
138
+ return DecorationSet.empty;
139
+ }
140
+ } else {
141
+ return DecorationSet.empty;
142
+ }
129
143
  }
130
144
  const changeset = ChangeSet.create(originalDoc).addSteps(steppedDoc, stepMaps, tr.doc);
131
145
  const changes = simplifyChanges(changeset.changes, tr.doc);
132
146
  const optimizedChanges = optimizeChanges(changes);
133
147
  const decorations = [];
134
148
  optimizedChanges.forEach(change => {
135
- const isActive = activeIndexPos && change.fromB >= activeIndexPos.from && change.toB <= activeIndexPos.to;
149
+ const isActive = activeIndexPos && change.fromB === activeIndexPos.from && change.toB === activeIndexPos.to;
136
150
  // Our default operations are insertions, so it should match the opposite of isInverted.
137
151
  const isInserted = !isInverted;
138
152
  if (change.inserted.length > 0) {
@@ -151,11 +165,13 @@ const calculateDiffDecorationsInner = ({
151
165
  colorScheme,
152
166
  ...(expValEquals('platform_editor_diff_plugin_extended', 'isEnabled', true) && {
153
167
  isInserted
154
- })
168
+ }),
169
+ activeIndexPos,
170
+ intl
155
171
  }));
156
172
  }
157
173
  if (change.deleted.length > 0) {
158
- const isActive = activeIndexPos && change.fromB >= activeIndexPos.from && change.toB <= activeIndexPos.to;
174
+ const isActive = activeIndexPos && change.fromB === activeIndexPos.from && change.fromB === activeIndexPos.to;
159
175
  const decoration = createNodeChangedDecorationWidget({
160
176
  change,
161
177
  doc: originalDoc,
@@ -174,7 +190,7 @@ const calculateDiffDecorationsInner = ({
174
190
  }
175
191
  });
176
192
  getMarkChangeRanges(steps).forEach(change => {
177
- const isActive = activeIndexPos && change.fromB >= activeIndexPos.from && change.toB <= activeIndexPos.to;
193
+ const isActive = activeIndexPos && change.fromB === activeIndexPos.from && change.toB === activeIndexPos.to;
178
194
  decorations.push(createInlineChangedDecoration({
179
195
  change,
180
196
  colorScheme,
@@ -188,7 +204,9 @@ const calculateDiffDecorationsInner = ({
188
204
  from: change.fromB,
189
205
  to: change.toB,
190
206
  colorScheme,
191
- isInserted: true
207
+ isInserted: true,
208
+ activeIndexPos,
209
+ intl
192
210
  }));
193
211
  });
194
212
  return DecorationSet.empty.add(tr.doc, decorations);
@@ -7,7 +7,7 @@ export const editingStyle = convertToInlineCss({
7
7
  textDecorationColor: "var(--ds-border-accent-purple, #AF59E1)"
8
8
  });
9
9
  export const editingStyleActive = convertToInlineCss({
10
- background: "var(--ds-background-accent-purple-subtler, #EED7FC)",
10
+ background: "var(--ds-background-accent-purple-subtler-pressed, #D8A0F7)",
11
11
  textDecoration: 'underline',
12
12
  textDecorationStyle: 'dotted',
13
13
  textDecorationThickness: "var(--ds-space-025, 2px)",