@atlaskit/editor-plugin-show-diff 25.0.4 → 25.0.6

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,22 @@
1
1
  # @atlaskit/editor-plugin-show-diff
2
2
 
3
+ ## 25.0.6
4
+
5
+ ### Patch Changes
6
+
7
+ - [`8843fc489d5a6`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/8843fc489d5a6) -
8
+ EDITOR-9591 Behind platform_editor_ai_show_diff_patch_2, highlight inserted inline nodes as a
9
+ whole instead of the text inside them, and only outline an inserted atomic inline node (date,
10
+ emoji, mention, status) when its attributes are the only change
11
+ (platform_editor_show_diff_deleted_nodeview_content)
12
+ - Updated dependencies
13
+
14
+ ## 25.0.5
15
+
16
+ ### Patch Changes
17
+
18
+ - Updated dependencies
19
+
3
20
  ## 25.0.4
4
21
 
5
22
  ### Patch Changes
@@ -112,7 +112,8 @@ var NodeViewSerializer = exports.NodeViewSerializer = /*#__PURE__*/function () {
112
112
  if (childNode) {
113
113
  // Give inserted atomic children the same box-shadow
114
114
  // highlight an in-place attribute change already gets (`getAtomicInlineChangedAttrs`).
115
- if (isInserted && (0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_show_diff_deleted_nodeview_content') && (0, _getAttrChangeRanges.isInlineAttrChangeNodeName)(child.type.name) && childNode instanceof HTMLElement) {
115
+ // Disabled under patch_2: the outline also landed on atomic children inserted alongside text.
116
+ if (isInserted && !(0, _fg.fg)('platform_editor_ai_show_diff_patch_2') && (0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_show_diff_deleted_nodeview_content') && (0, _getAttrChangeRanges.isInlineAttrChangeNodeName)(child.type.name) && childNode instanceof HTMLElement) {
116
117
  var _getAtomicInlineChang = (0, _createInlineChangedDecoration.getAtomicInlineChangedAttrs)(child.type.name, colorScheme),
117
118
  className = _getAtomicInlineChang.className,
118
119
  styleSuffix = _getAtomicInlineChang.styleSuffix;
@@ -1164,11 +1164,16 @@ function buildDeletedWrappedBlockOutline(colors, _ref) {
1164
1164
  * decoration span and read by the `.show-diff-atomic-inline-changed-*` selectors in
1165
1165
  * EditorContentContainer, on the decorated element or a descendant, so it must inherit. Being
1166
1166
  * inline it beats the stylesheet's fallback, making the plugin the only source of the colour.
1167
+ *
1168
+ * Under patch_2 it also reserves the 2px ring either side, since the ring takes up no space and
1169
+ * otherwise paints over an adjacent inline diff.
1167
1170
  */
1168
1171
  function buildAtomicInlineChangedCSSVariables(colors) {
1169
- return (0, _cssHelper.convertToInlineCss)({
1172
+ return (0, _cssHelper.convertToInlineCss)(_objectSpread({
1170
1173
  '--show-diff-atomic-inline-changed-border-color': borderAccent(colors.insertColor)
1171
- });
1174
+ }, (0, _fg.fg)('platform_editor_ai_show_diff_patch_2') && {
1175
+ marginInline: "var(--ds-space-025, 2px)"
1176
+ }));
1172
1177
  }
1173
1178
 
1174
1179
  /** Hands editor-core the same strike line the widget path uses, via a custom property. */
@@ -7,19 +7,24 @@ Object.defineProperty(exports, "__esModule", {
7
7
  exports.createNodeChangedDecorationWidget = void 0;
8
8
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
9
  var _view = require("@atlaskit/editor-prosemirror/view");
10
+ var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-experiment-enabled");
10
11
  var _fg = require("@atlaskit/platform-feature-flags/fg");
11
12
  var _baseNodeName = require("../utils/baseNodeName");
12
13
  var _emptyTextBlocks = require("../utils/emptyTextBlocks");
13
14
  var _isEmptyParagraphSlice = require("../utils/isEmptyParagraphSlice");
15
+ var _factory = require("./colorSchemes/factory");
16
+ var _schemes = require("./colorSchemes/schemes");
14
17
  var _createAnchorDecorationWidgets = require("./createAnchorDecorationWidgets");
15
18
  var _createChangedRowDecorationWidgets = require("./createChangedRowDecorationWidgets");
16
19
  var _createContributorTagWidget = require("./createContributorTagWidget");
20
+ var _createInlineChangedDecoration = require("./createInlineChangedDecoration");
17
21
  var _decorationKeys = require("./decorationKeys");
18
22
  var _absorbFirstChildMarginReset = require("./utils/absorbFirstChildMarginReset");
19
23
  var _createDeletedLineBreakWidget = require("./utils/createDeletedLineBreakWidget");
20
24
  var _createMarginAbsorber = require("./utils/createMarginAbsorber");
21
25
  var _createNodeShapedMarginSpacer = require("./utils/createNodeShapedMarginSpacer");
22
26
  var _findSafeInsertPos = require("./utils/findSafeInsertPos");
27
+ var _getAttrChangeRanges = require("./utils/getAttrChangeRanges");
23
28
  var _safeResolve = require("./utils/safeResolve");
24
29
  var _tableDiffMode = require("./utils/tableDiffMode");
25
30
  var _wrapBlockNodeView = require("./utils/wrapBlockNodeView");
@@ -120,6 +125,32 @@ var createTableCellContentWidgets = function createTableCellContentWidgets(_ref)
120
125
  return decorations;
121
126
  };
122
127
 
128
+ /**
129
+ * The node name when `change` only swapped one atomic inline node (date, emoji, mention, status)
130
+ * for another of the same type, i.e. an attribute change rather than content added or removed
131
+ * around it.
132
+ */
133
+ var getAtomicInlineAttrOnlyNodeName = function getAtomicInlineAttrOnlyNodeName(change, doc, newDoc) {
134
+ var nodeA = doc.nodeAt(change.fromA);
135
+ var nodeB = newDoc.nodeAt(change.fromB);
136
+ if (!nodeA || !nodeB || nodeA.type !== nodeB.type || nodeA.nodeSize !== change.toA - change.fromA || nodeB.nodeSize !== change.toB - change.fromB) {
137
+ return undefined;
138
+ }
139
+ var nodeName = nodeA.type.name;
140
+ return (0, _getAttrChangeRanges.isInlineAttrChangeNodeName)(nodeName) ? nodeName : undefined;
141
+ };
142
+
143
+ /** Wraps an inserted atomic inline node view in the outline an in-place attribute change gets. */
144
+ var createAtomicInlineOutline = function createAtomicInlineOutline(nodeName, nodeView, colorScheme) {
145
+ var outlineWrapper = document.createElement('span');
146
+ outlineWrapper.className = (0, _createInlineChangedDecoration.getAtomicInlineChangedAttrs)(nodeName, colorScheme).className;
147
+ // Set in both cohorts of `platform_editor_show_diff_color_scheme_refactor`: being inline it beats
148
+ // the stylesheet's purple/green table, so editor-core's rings follow the change's scheme too.
149
+ outlineWrapper.setAttribute('style', (0, _factory.buildAtomicInlineChangedCSSVariables)(_schemes.colorSchemeRegistry[colorScheme !== null && colorScheme !== void 0 ? colorScheme : 'standard']));
150
+ outlineWrapper.append(nodeView);
151
+ return outlineWrapper;
152
+ };
153
+
123
154
  /**
124
155
  * This function is used to create a decoration widget to show content
125
156
  * that is not in the current document.
@@ -391,9 +422,17 @@ var createNodeChangedDecorationWidget = exports.createNodeChangedDecorationWidge
391
422
  nodeView.style.setProperty('anchor-name', "--".concat(contributorTagAnchorName));
392
423
  }
393
424
  if (node.isInline) {
394
- var wrapper = (0, _wrapBlockNodeView.createContentWrapper)(colorScheme, isActive, isInserted, reveal);
395
- wrapper.append(nodeView);
396
- dom.append(wrapper);
425
+ var attrOnlyNodeName = isInserted && (0, _fg.fg)('platform_editor_ai_show_diff_patch_2') && (0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_show_diff_deleted_nodeview_content') ? getAtomicInlineAttrOnlyNodeName(change, doc, newDoc) : undefined;
426
+ if (attrOnlyNodeName) {
427
+ // Only the node's attributes changed, so outline it as an in-place attribute change
428
+ // does, in place of the highlight. Its own wrapper keeps the outline clear of the node
429
+ // view's styles.
430
+ dom.append(createAtomicInlineOutline(attrOnlyNodeName, nodeView, colorScheme));
431
+ } else {
432
+ var wrapper = (0, _wrapBlockNodeView.createContentWrapper)(colorScheme, isActive, isInserted, reveal);
433
+ wrapper.append(nodeView);
434
+ dom.append(wrapper);
435
+ }
397
436
  } else {
398
437
  // Handle all block nodes with unified function
399
438
  (0, _wrapBlockNodeView.wrapBlockNodeView)({
@@ -294,7 +294,28 @@ var applyTextLikeBlockNodeStyles = function applyTextLikeBlockNodeStyles(_ref8)
294
294
  element.setAttribute('style', "".concat(currentStyle).concat(nodeSpecificStyle));
295
295
  }
296
296
  var contentStyle = (0, _wrapBlockNodeViewStyles.getChangedContentStyle)(colorScheme, isActive, isInserted, hideAddedDiffsUnderline);
297
- var walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT);
297
+
298
+ // Under patch_2, an inserted inline node view (a date, a status lozenge) is highlighted as a whole
299
+ // rather than the text inside it, so the highlight sits behind the node. Rejecting it skips its
300
+ // subtree, so this stays a single walk.
301
+ var highlightInlineNodesWhole = isInserted && (0, _fg.fg)('platform_editor_ai_show_diff_patch_2');
302
+ // `applyInlineLeafNodeStyles` styles the block's direct inline children itself.
303
+ var handlesDirectInlineChildren = highlightInlineLeafNodes && targetNode.type.inlineContent;
304
+ var inlineNodesToWrap = [];
305
+ var walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT, {
306
+ acceptNode: function acceptNode(node) {
307
+ if (node instanceof Text) {
308
+ return NodeFilter.FILTER_ACCEPT;
309
+ }
310
+ if (highlightInlineNodesWhole && node instanceof HTMLElement && node.dataset.prosemirrorNodeInline === 'true') {
311
+ if (!(handlesDirectInlineChildren && node.parentElement === element)) {
312
+ inlineNodesToWrap.push(node);
313
+ }
314
+ return NodeFilter.FILTER_REJECT;
315
+ }
316
+ return NodeFilter.FILTER_SKIP;
317
+ }
318
+ });
298
319
  var textNodesToWrap = [];
299
320
  var currentNode = walker.nextNode();
300
321
  while (currentNode) {
@@ -303,13 +324,13 @@ var applyTextLikeBlockNodeStyles = function applyTextLikeBlockNodeStyles(_ref8)
303
324
  }
304
325
  currentNode = walker.nextNode();
305
326
  }
306
- textNodesToWrap.forEach(function (textNode) {
327
+ [].concat(textNodesToWrap, inlineNodesToWrap).forEach(function (node) {
307
328
  var contentWrapper = document.createElement('span');
308
329
  contentWrapper.setAttribute('style', contentStyle);
309
- textNode.replaceWith(contentWrapper);
310
- contentWrapper.append(textNode);
330
+ node.replaceWith(contentWrapper);
331
+ contentWrapper.append(node);
311
332
  });
312
- if (highlightInlineLeafNodes && targetNode.type.inlineContent) {
333
+ if (handlesDirectInlineChildren) {
313
334
  applyInlineLeafNodeStyles({
314
335
  element: element,
315
336
  targetNode: targetNode,
@@ -95,7 +95,8 @@ export class NodeViewSerializer {
95
95
  if (childNode) {
96
96
  // Give inserted atomic children the same box-shadow
97
97
  // highlight an in-place attribute change already gets (`getAtomicInlineChangedAttrs`).
98
- if (isInserted && isExperimentEnabled('platform_editor_show_diff_deleted_nodeview_content') && isInlineAttrChangeNodeName(child.type.name) && childNode instanceof HTMLElement) {
98
+ // Disabled under patch_2: the outline also landed on atomic children inserted alongside text.
99
+ if (isInserted && !fg('platform_editor_ai_show_diff_patch_2') && isExperimentEnabled('platform_editor_show_diff_deleted_nodeview_content') && isInlineAttrChangeNodeName(child.type.name) && childNode instanceof HTMLElement) {
99
100
  const {
100
101
  className,
101
102
  styleSuffix
@@ -1085,10 +1085,16 @@ export function buildDeletedWrappedBlockOutline(colors, {
1085
1085
  * decoration span and read by the `.show-diff-atomic-inline-changed-*` selectors in
1086
1086
  * EditorContentContainer, on the decorated element or a descendant, so it must inherit. Being
1087
1087
  * inline it beats the stylesheet's fallback, making the plugin the only source of the colour.
1088
+ *
1089
+ * Under patch_2 it also reserves the 2px ring either side, since the ring takes up no space and
1090
+ * otherwise paints over an adjacent inline diff.
1088
1091
  */
1089
1092
  export function buildAtomicInlineChangedCSSVariables(colors) {
1090
1093
  return convertToInlineCss({
1091
- '--show-diff-atomic-inline-changed-border-color': borderAccent(colors.insertColor)
1094
+ '--show-diff-atomic-inline-changed-border-color': borderAccent(colors.insertColor),
1095
+ ...(fg('platform_editor_ai_show_diff_patch_2') && {
1096
+ marginInline: "var(--ds-space-025, 2px)"
1097
+ })
1092
1098
  });
1093
1099
  }
1094
1100
 
@@ -1,17 +1,22 @@
1
1
  import { Decoration } from '@atlaskit/editor-prosemirror/view';
2
+ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
2
3
  import { fg } from '@atlaskit/platform-feature-flags/fg';
3
4
  import { resolveBaseNodeName } from '../utils/baseNodeName';
4
5
  import { countEmptyTextBlockOnlySlice } from '../utils/emptyTextBlocks';
5
6
  import { isEmptyParagraphSlice } from '../utils/isEmptyParagraphSlice';
7
+ import { buildAtomicInlineChangedCSSVariables } from './colorSchemes/factory';
8
+ import { colorSchemeRegistry } from './colorSchemes/schemes';
6
9
  import { clampAnchorPosIntoCell, createAnchorNameSpan, createLeftAnchorWidget } from './createAnchorDecorationWidgets';
7
10
  import { createChangedRowDecorationWidgets } from './createChangedRowDecorationWidgets';
8
11
  import { createContributorTagHost, resolveHoistedCodeBlockAnchor, unmountContributorTag } from './createContributorTagWidget';
12
+ import { getAtomicInlineChangedAttrs } from './createInlineChangedDecoration';
9
13
  import { AnchorTypeKey, buildContributorTagDecorationSpec, buildDiffDecorationSpec, buildAnchorDecorationKey, scrollMarginTopValue } from './decorationKeys';
10
14
  import { absorbFirstChildMarginReset } from './utils/absorbFirstChildMarginReset';
11
15
  import { createDeletedLineBreakDecoration } from './utils/createDeletedLineBreakWidget';
12
16
  import { createMarginAbsorber } from './utils/createMarginAbsorber';
13
17
  import { createNodeShapedMarginSpacer } from './utils/createNodeShapedMarginSpacer';
14
18
  import { findSafeInsertPos } from './utils/findSafeInsertPos';
19
+ import { isInlineAttrChangeNodeName } from './utils/getAttrChangeRanges';
15
20
  import { safeResolve } from './utils/safeResolve';
16
21
  import { getTableDiffMode } from './utils/tableDiffMode';
17
22
  import { wrapBlockNodeView, createRemovedLozenge, injectInnerWrapper, createContentWrapper } from './utils/wrapBlockNodeView';
@@ -112,6 +117,32 @@ const createTableCellContentWidgets = ({
112
117
  return decorations;
113
118
  };
114
119
 
120
+ /**
121
+ * The node name when `change` only swapped one atomic inline node (date, emoji, mention, status)
122
+ * for another of the same type, i.e. an attribute change rather than content added or removed
123
+ * around it.
124
+ */
125
+ const getAtomicInlineAttrOnlyNodeName = (change, doc, newDoc) => {
126
+ const nodeA = doc.nodeAt(change.fromA);
127
+ const nodeB = newDoc.nodeAt(change.fromB);
128
+ if (!nodeA || !nodeB || nodeA.type !== nodeB.type || nodeA.nodeSize !== change.toA - change.fromA || nodeB.nodeSize !== change.toB - change.fromB) {
129
+ return undefined;
130
+ }
131
+ const nodeName = nodeA.type.name;
132
+ return isInlineAttrChangeNodeName(nodeName) ? nodeName : undefined;
133
+ };
134
+
135
+ /** Wraps an inserted atomic inline node view in the outline an in-place attribute change gets. */
136
+ const createAtomicInlineOutline = (nodeName, nodeView, colorScheme) => {
137
+ const outlineWrapper = document.createElement('span');
138
+ outlineWrapper.className = getAtomicInlineChangedAttrs(nodeName, colorScheme).className;
139
+ // Set in both cohorts of `platform_editor_show_diff_color_scheme_refactor`: being inline it beats
140
+ // the stylesheet's purple/green table, so editor-core's rings follow the change's scheme too.
141
+ outlineWrapper.setAttribute('style', buildAtomicInlineChangedCSSVariables(colorSchemeRegistry[colorScheme !== null && colorScheme !== void 0 ? colorScheme : 'standard']));
142
+ outlineWrapper.append(nodeView);
143
+ return outlineWrapper;
144
+ };
145
+
115
146
  /**
116
147
  * This function is used to create a decoration widget to show content
117
148
  * that is not in the current document.
@@ -377,9 +408,17 @@ export const createNodeChangedDecorationWidget = ({
377
408
  nodeView.style.setProperty('anchor-name', `--${contributorTagAnchorName}`);
378
409
  }
379
410
  if (node.isInline) {
380
- const wrapper = createContentWrapper(colorScheme, isActive, isInserted, reveal);
381
- wrapper.append(nodeView);
382
- dom.append(wrapper);
411
+ const attrOnlyNodeName = isInserted && fg('platform_editor_ai_show_diff_patch_2') && isExperimentEnabled('platform_editor_show_diff_deleted_nodeview_content') ? getAtomicInlineAttrOnlyNodeName(change, doc, newDoc) : undefined;
412
+ if (attrOnlyNodeName) {
413
+ // Only the node's attributes changed, so outline it as an in-place attribute change
414
+ // does, in place of the highlight. Its own wrapper keeps the outline clear of the node
415
+ // view's styles.
416
+ dom.append(createAtomicInlineOutline(attrOnlyNodeName, nodeView, colorScheme));
417
+ } else {
418
+ const wrapper = createContentWrapper(colorScheme, isActive, isInserted, reveal);
419
+ wrapper.append(nodeView);
420
+ dom.append(wrapper);
421
+ }
383
422
  } else {
384
423
  // Handle all block nodes with unified function
385
424
  wrapBlockNodeView({
@@ -284,7 +284,28 @@ const applyTextLikeBlockNodeStyles = ({
284
284
  element.setAttribute('style', `${currentStyle}${nodeSpecificStyle}`);
285
285
  }
286
286
  const contentStyle = getChangedContentStyle(colorScheme, isActive, isInserted, hideAddedDiffsUnderline);
287
- const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT);
287
+
288
+ // Under patch_2, an inserted inline node view (a date, a status lozenge) is highlighted as a whole
289
+ // rather than the text inside it, so the highlight sits behind the node. Rejecting it skips its
290
+ // subtree, so this stays a single walk.
291
+ const highlightInlineNodesWhole = isInserted && fg('platform_editor_ai_show_diff_patch_2');
292
+ // `applyInlineLeafNodeStyles` styles the block's direct inline children itself.
293
+ const handlesDirectInlineChildren = highlightInlineLeafNodes && targetNode.type.inlineContent;
294
+ const inlineNodesToWrap = [];
295
+ const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT, {
296
+ acceptNode: node => {
297
+ if (node instanceof Text) {
298
+ return NodeFilter.FILTER_ACCEPT;
299
+ }
300
+ if (highlightInlineNodesWhole && node instanceof HTMLElement && node.dataset.prosemirrorNodeInline === 'true') {
301
+ if (!(handlesDirectInlineChildren && node.parentElement === element)) {
302
+ inlineNodesToWrap.push(node);
303
+ }
304
+ return NodeFilter.FILTER_REJECT;
305
+ }
306
+ return NodeFilter.FILTER_SKIP;
307
+ }
308
+ });
288
309
  const textNodesToWrap = [];
289
310
  let currentNode = walker.nextNode();
290
311
  while (currentNode) {
@@ -293,13 +314,13 @@ const applyTextLikeBlockNodeStyles = ({
293
314
  }
294
315
  currentNode = walker.nextNode();
295
316
  }
296
- textNodesToWrap.forEach(textNode => {
317
+ [...textNodesToWrap, ...inlineNodesToWrap].forEach(node => {
297
318
  const contentWrapper = document.createElement('span');
298
319
  contentWrapper.setAttribute('style', contentStyle);
299
- textNode.replaceWith(contentWrapper);
300
- contentWrapper.append(textNode);
320
+ node.replaceWith(contentWrapper);
321
+ contentWrapper.append(node);
301
322
  });
302
- if (highlightInlineLeafNodes && targetNode.type.inlineContent) {
323
+ if (handlesDirectInlineChildren) {
303
324
  applyInlineLeafNodeStyles({
304
325
  element,
305
326
  targetNode,
@@ -105,7 +105,8 @@ export var NodeViewSerializer = /*#__PURE__*/function () {
105
105
  if (childNode) {
106
106
  // Give inserted atomic children the same box-shadow
107
107
  // highlight an in-place attribute change already gets (`getAtomicInlineChangedAttrs`).
108
- if (isInserted && isExperimentEnabled('platform_editor_show_diff_deleted_nodeview_content') && isInlineAttrChangeNodeName(child.type.name) && childNode instanceof HTMLElement) {
108
+ // Disabled under patch_2: the outline also landed on atomic children inserted alongside text.
109
+ if (isInserted && !fg('platform_editor_ai_show_diff_patch_2') && isExperimentEnabled('platform_editor_show_diff_deleted_nodeview_content') && isInlineAttrChangeNodeName(child.type.name) && childNode instanceof HTMLElement) {
109
110
  var _getAtomicInlineChang = getAtomicInlineChangedAttrs(child.type.name, colorScheme),
110
111
  className = _getAtomicInlineChang.className,
111
112
  styleSuffix = _getAtomicInlineChang.styleSuffix;
@@ -1088,11 +1088,16 @@ export function buildDeletedWrappedBlockOutline(colors, _ref) {
1088
1088
  * decoration span and read by the `.show-diff-atomic-inline-changed-*` selectors in
1089
1089
  * EditorContentContainer, on the decorated element or a descendant, so it must inherit. Being
1090
1090
  * inline it beats the stylesheet's fallback, making the plugin the only source of the colour.
1091
+ *
1092
+ * Under patch_2 it also reserves the 2px ring either side, since the ring takes up no space and
1093
+ * otherwise paints over an adjacent inline diff.
1091
1094
  */
1092
1095
  export function buildAtomicInlineChangedCSSVariables(colors) {
1093
- return convertToInlineCss({
1096
+ return convertToInlineCss(_objectSpread({
1094
1097
  '--show-diff-atomic-inline-changed-border-color': borderAccent(colors.insertColor)
1095
- });
1098
+ }, fg('platform_editor_ai_show_diff_patch_2') && {
1099
+ marginInline: "var(--ds-space-025, 2px)"
1100
+ }));
1096
1101
  }
1097
1102
 
1098
1103
  /** Hands editor-core the same strike line the widget path uses, via a custom property. */
@@ -2,19 +2,24 @@ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
2
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
3
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
4
  import { Decoration } from '@atlaskit/editor-prosemirror/view';
5
+ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
5
6
  import { fg } from '@atlaskit/platform-feature-flags/fg';
6
7
  import { resolveBaseNodeName } from '../utils/baseNodeName';
7
8
  import { countEmptyTextBlockOnlySlice } from '../utils/emptyTextBlocks';
8
9
  import { isEmptyParagraphSlice } from '../utils/isEmptyParagraphSlice';
10
+ import { buildAtomicInlineChangedCSSVariables } from './colorSchemes/factory';
11
+ import { colorSchemeRegistry } from './colorSchemes/schemes';
9
12
  import { clampAnchorPosIntoCell, createAnchorNameSpan, createLeftAnchorWidget } from './createAnchorDecorationWidgets';
10
13
  import { createChangedRowDecorationWidgets } from './createChangedRowDecorationWidgets';
11
14
  import { createContributorTagHost, resolveHoistedCodeBlockAnchor, unmountContributorTag } from './createContributorTagWidget';
15
+ import { getAtomicInlineChangedAttrs } from './createInlineChangedDecoration';
12
16
  import { AnchorTypeKey, buildContributorTagDecorationSpec, buildDiffDecorationSpec, buildAnchorDecorationKey, scrollMarginTopValue } from './decorationKeys';
13
17
  import { absorbFirstChildMarginReset } from './utils/absorbFirstChildMarginReset';
14
18
  import { createDeletedLineBreakDecoration } from './utils/createDeletedLineBreakWidget';
15
19
  import { createMarginAbsorber } from './utils/createMarginAbsorber';
16
20
  import { createNodeShapedMarginSpacer } from './utils/createNodeShapedMarginSpacer';
17
21
  import { findSafeInsertPos } from './utils/findSafeInsertPos';
22
+ import { isInlineAttrChangeNodeName } from './utils/getAttrChangeRanges';
18
23
  import { safeResolve } from './utils/safeResolve';
19
24
  import { getTableDiffMode } from './utils/tableDiffMode';
20
25
  import { wrapBlockNodeView, createRemovedLozenge, injectInnerWrapper, createContentWrapper } from './utils/wrapBlockNodeView';
@@ -114,6 +119,32 @@ var createTableCellContentWidgets = function createTableCellContentWidgets(_ref)
114
119
  return decorations;
115
120
  };
116
121
 
122
+ /**
123
+ * The node name when `change` only swapped one atomic inline node (date, emoji, mention, status)
124
+ * for another of the same type, i.e. an attribute change rather than content added or removed
125
+ * around it.
126
+ */
127
+ var getAtomicInlineAttrOnlyNodeName = function getAtomicInlineAttrOnlyNodeName(change, doc, newDoc) {
128
+ var nodeA = doc.nodeAt(change.fromA);
129
+ var nodeB = newDoc.nodeAt(change.fromB);
130
+ if (!nodeA || !nodeB || nodeA.type !== nodeB.type || nodeA.nodeSize !== change.toA - change.fromA || nodeB.nodeSize !== change.toB - change.fromB) {
131
+ return undefined;
132
+ }
133
+ var nodeName = nodeA.type.name;
134
+ return isInlineAttrChangeNodeName(nodeName) ? nodeName : undefined;
135
+ };
136
+
137
+ /** Wraps an inserted atomic inline node view in the outline an in-place attribute change gets. */
138
+ var createAtomicInlineOutline = function createAtomicInlineOutline(nodeName, nodeView, colorScheme) {
139
+ var outlineWrapper = document.createElement('span');
140
+ outlineWrapper.className = getAtomicInlineChangedAttrs(nodeName, colorScheme).className;
141
+ // Set in both cohorts of `platform_editor_show_diff_color_scheme_refactor`: being inline it beats
142
+ // the stylesheet's purple/green table, so editor-core's rings follow the change's scheme too.
143
+ outlineWrapper.setAttribute('style', buildAtomicInlineChangedCSSVariables(colorSchemeRegistry[colorScheme !== null && colorScheme !== void 0 ? colorScheme : 'standard']));
144
+ outlineWrapper.append(nodeView);
145
+ return outlineWrapper;
146
+ };
147
+
117
148
  /**
118
149
  * This function is used to create a decoration widget to show content
119
150
  * that is not in the current document.
@@ -385,9 +416,17 @@ export var createNodeChangedDecorationWidget = function createNodeChangedDecorat
385
416
  nodeView.style.setProperty('anchor-name', "--".concat(contributorTagAnchorName));
386
417
  }
387
418
  if (node.isInline) {
388
- var wrapper = createContentWrapper(colorScheme, isActive, isInserted, reveal);
389
- wrapper.append(nodeView);
390
- dom.append(wrapper);
419
+ var attrOnlyNodeName = isInserted && fg('platform_editor_ai_show_diff_patch_2') && isExperimentEnabled('platform_editor_show_diff_deleted_nodeview_content') ? getAtomicInlineAttrOnlyNodeName(change, doc, newDoc) : undefined;
420
+ if (attrOnlyNodeName) {
421
+ // Only the node's attributes changed, so outline it as an in-place attribute change
422
+ // does, in place of the highlight. Its own wrapper keeps the outline clear of the node
423
+ // view's styles.
424
+ dom.append(createAtomicInlineOutline(attrOnlyNodeName, nodeView, colorScheme));
425
+ } else {
426
+ var wrapper = createContentWrapper(colorScheme, isActive, isInserted, reveal);
427
+ wrapper.append(nodeView);
428
+ dom.append(wrapper);
429
+ }
391
430
  } else {
392
431
  // Handle all block nodes with unified function
393
432
  wrapBlockNodeView({
@@ -287,7 +287,28 @@ var applyTextLikeBlockNodeStyles = function applyTextLikeBlockNodeStyles(_ref8)
287
287
  element.setAttribute('style', "".concat(currentStyle).concat(nodeSpecificStyle));
288
288
  }
289
289
  var contentStyle = getChangedContentStyle(colorScheme, isActive, isInserted, hideAddedDiffsUnderline);
290
- var walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT);
290
+
291
+ // Under patch_2, an inserted inline node view (a date, a status lozenge) is highlighted as a whole
292
+ // rather than the text inside it, so the highlight sits behind the node. Rejecting it skips its
293
+ // subtree, so this stays a single walk.
294
+ var highlightInlineNodesWhole = isInserted && fg('platform_editor_ai_show_diff_patch_2');
295
+ // `applyInlineLeafNodeStyles` styles the block's direct inline children itself.
296
+ var handlesDirectInlineChildren = highlightInlineLeafNodes && targetNode.type.inlineContent;
297
+ var inlineNodesToWrap = [];
298
+ var walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT, {
299
+ acceptNode: function acceptNode(node) {
300
+ if (node instanceof Text) {
301
+ return NodeFilter.FILTER_ACCEPT;
302
+ }
303
+ if (highlightInlineNodesWhole && node instanceof HTMLElement && node.dataset.prosemirrorNodeInline === 'true') {
304
+ if (!(handlesDirectInlineChildren && node.parentElement === element)) {
305
+ inlineNodesToWrap.push(node);
306
+ }
307
+ return NodeFilter.FILTER_REJECT;
308
+ }
309
+ return NodeFilter.FILTER_SKIP;
310
+ }
311
+ });
291
312
  var textNodesToWrap = [];
292
313
  var currentNode = walker.nextNode();
293
314
  while (currentNode) {
@@ -296,13 +317,13 @@ var applyTextLikeBlockNodeStyles = function applyTextLikeBlockNodeStyles(_ref8)
296
317
  }
297
318
  currentNode = walker.nextNode();
298
319
  }
299
- textNodesToWrap.forEach(function (textNode) {
320
+ [].concat(textNodesToWrap, inlineNodesToWrap).forEach(function (node) {
300
321
  var contentWrapper = document.createElement('span');
301
322
  contentWrapper.setAttribute('style', contentStyle);
302
- textNode.replaceWith(contentWrapper);
303
- contentWrapper.append(textNode);
323
+ node.replaceWith(contentWrapper);
324
+ contentWrapper.append(node);
304
325
  });
305
- if (highlightInlineLeafNodes && targetNode.type.inlineContent) {
326
+ if (handlesDirectInlineChildren) {
306
327
  applyInlineLeafNodeStyles({
307
328
  element: element,
308
329
  targetNode: targetNode,
@@ -227,6 +227,9 @@ export declare function buildDeletedWrappedBlockOutline(colors: DiffColorScheme,
227
227
  * decoration span and read by the `.show-diff-atomic-inline-changed-*` selectors in
228
228
  * EditorContentContainer, on the decorated element or a descendant, so it must inherit. Being
229
229
  * inline it beats the stylesheet's fallback, making the plugin the only source of the colour.
230
+ *
231
+ * Under patch_2 it also reserves the 2px ring either side, since the ring takes up no space and
232
+ * otherwise paints over an adjacent inline diff.
230
233
  */
231
234
  export declare function buildAtomicInlineChangedCSSVariables(colors: DiffColorScheme): string;
232
235
  /** Hands editor-core the same strike line the widget path uses, via a custom property. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-show-diff",
3
- "version": "25.0.4",
3
+ "version": "25.0.6",
4
4
  "description": "ShowDiff plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -39,8 +39,8 @@
39
39
  "@atlaskit/platform-feature-experiments": "^0.3.0",
40
40
  "@atlaskit/platform-feature-flags": "^2.2.0",
41
41
  "@atlaskit/primitives": "^22.5.0",
42
- "@atlaskit/tmp-editor-statsig": "^239.0.0",
43
- "@atlaskit/tokens": "^20.5.0",
42
+ "@atlaskit/tmp-editor-statsig": "^240.0.0",
43
+ "@atlaskit/tokens": "^20.6.0",
44
44
  "@babel/runtime": "^7.0.0",
45
45
  "@compiled/react": "^1.0.2",
46
46
  "bind-event-listener": "^3.0.0",
@@ -64,7 +64,7 @@
64
64
  "@atlassian/confluence-presets": "workspace:^",
65
65
  "@atlassian/content-reconciliation": "^0.1.3506",
66
66
  "@atlassian/editor-ai-injected-editors": "^41.0.0",
67
- "@atlassian/editor-plugin-ai": "^81.0.0",
67
+ "@atlassian/editor-plugin-ai": "^81.2.0",
68
68
  "@atlassian/structured-docs-types": "workspace:^",
69
69
  "react": "^19.2.0",
70
70
  "react-dom": "^19.2.0",