@atlaskit/editor-plugin-show-diff 15.0.1 → 15.1.2

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 (62) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/cjs/pm-plugins/calculateDiff/calculateDiffDecorations.js +131 -79
  3. package/dist/cjs/pm-plugins/decorations/colorSchemes/factory.js +32 -0
  4. package/dist/cjs/pm-plugins/decorations/createBlockChangedDecoration.js +87 -25
  5. package/dist/cjs/pm-plugins/decorations/createContributorTagWidget.js +27 -4
  6. package/dist/cjs/pm-plugins/decorations/createInlineChangedDecoration.js +17 -3
  7. package/dist/cjs/pm-plugins/decorations/createNodeChangedDecorationWidget.js +5 -3
  8. package/dist/cjs/pm-plugins/decorations/extractContributorTags.js +43 -14
  9. package/dist/cjs/pm-plugins/decorations/revealStyles.js +156 -0
  10. package/dist/cjs/pm-plugins/decorations/utils/wrapBlockNodeView.js +25 -5
  11. package/dist/cjs/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.js +4 -2
  12. package/dist/cjs/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.legacy.js +2 -1
  13. package/dist/cjs/pm-plugins/main.js +28 -10
  14. package/dist/cjs/pm-plugins/resolveDiffContributors.js +16 -9
  15. package/dist/cjs/pm-plugins/revealAnimation.js +524 -0
  16. package/dist/cjs/showDiffPlugin.js +42 -7
  17. package/dist/es2019/pm-plugins/calculateDiff/calculateDiffDecorations.js +59 -9
  18. package/dist/es2019/pm-plugins/decorations/colorSchemes/factory.js +30 -0
  19. package/dist/es2019/pm-plugins/decorations/createBlockChangedDecoration.js +62 -4
  20. package/dist/es2019/pm-plugins/decorations/createContributorTagWidget.js +25 -3
  21. package/dist/es2019/pm-plugins/decorations/createInlineChangedDecoration.js +18 -1
  22. package/dist/es2019/pm-plugins/decorations/createNodeChangedDecorationWidget.js +5 -3
  23. package/dist/es2019/pm-plugins/decorations/extractContributorTags.js +36 -9
  24. package/dist/es2019/pm-plugins/decorations/revealStyles.js +139 -0
  25. package/dist/es2019/pm-plugins/decorations/utils/wrapBlockNodeView.js +25 -6
  26. package/dist/es2019/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.js +6 -3
  27. package/dist/es2019/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.legacy.js +5 -2
  28. package/dist/es2019/pm-plugins/main.js +28 -9
  29. package/dist/es2019/pm-plugins/resolveDiffContributors.js +16 -8
  30. package/dist/es2019/pm-plugins/revealAnimation.js +495 -0
  31. package/dist/es2019/showDiffPlugin.js +37 -7
  32. package/dist/esm/pm-plugins/calculateDiff/calculateDiffDecorations.js +131 -79
  33. package/dist/esm/pm-plugins/decorations/colorSchemes/factory.js +30 -0
  34. package/dist/esm/pm-plugins/decorations/createBlockChangedDecoration.js +87 -25
  35. package/dist/esm/pm-plugins/decorations/createContributorTagWidget.js +27 -4
  36. package/dist/esm/pm-plugins/decorations/createInlineChangedDecoration.js +17 -3
  37. package/dist/esm/pm-plugins/decorations/createNodeChangedDecorationWidget.js +5 -3
  38. package/dist/esm/pm-plugins/decorations/extractContributorTags.js +43 -14
  39. package/dist/esm/pm-plugins/decorations/revealStyles.js +149 -0
  40. package/dist/esm/pm-plugins/decorations/utils/wrapBlockNodeView.js +25 -5
  41. package/dist/esm/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.js +4 -2
  42. package/dist/esm/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.legacy.js +2 -1
  43. package/dist/esm/pm-plugins/main.js +28 -10
  44. package/dist/esm/pm-plugins/resolveDiffContributors.js +16 -9
  45. package/dist/esm/pm-plugins/revealAnimation.js +518 -0
  46. package/dist/esm/showDiffPlugin.js +42 -7
  47. package/dist/types/entry-points/show-diff-plugin-type.d.ts +1 -1
  48. package/dist/types/pm-plugins/calculateDiff/calculateDiffDecorations.d.ts +2 -1
  49. package/dist/types/pm-plugins/decorations/colorSchemes/factory.d.ts +24 -0
  50. package/dist/types/pm-plugins/decorations/createBlockChangedDecoration.d.ts +5 -1
  51. package/dist/types/pm-plugins/decorations/createContributorTagWidget.d.ts +9 -3
  52. package/dist/types/pm-plugins/decorations/createInlineChangedDecoration.d.ts +3 -2
  53. package/dist/types/pm-plugins/decorations/createNodeChangedDecorationWidget.d.ts +3 -2
  54. package/dist/types/pm-plugins/decorations/revealStyles.d.ts +49 -0
  55. package/dist/types/pm-plugins/decorations/utils/wrapBlockNodeView.d.ts +4 -3
  56. package/dist/types/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.d.ts +1 -1
  57. package/dist/types/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.legacy.d.ts +1 -1
  58. package/dist/types/pm-plugins/main.d.ts +6 -1
  59. package/dist/types/pm-plugins/resolveDiffContributors.d.ts +3 -2
  60. package/dist/types/pm-plugins/revealAnimation.d.ts +33 -0
  61. package/dist/types/showDiffPluginType.d.ts +29 -1
  62. package/package.json +9 -3
@@ -12,6 +12,7 @@ import { createInlineIndicatorAnchorWidgets } from './createAnchorDecorationWidg
12
12
  import { createContributorTagWidget } from './createContributorTagWidget';
13
13
  import { getAtomicInlineNodeClassNameLegacy, resolveInlineChangedStyleLegacy } from './createInlineChangedDecoration.styles.legacy';
14
14
  import { buildDiffDecorationSpec } from './decorationKeys';
15
+ import { REVEAL_ATTR, resolveRevealStyle } from './revealStyles';
15
16
  var displayNoneStyle = convertToInlineCss({
16
17
  display: 'none'
17
18
  });
@@ -102,6 +103,7 @@ export var getAtomicInlineChangedAttrs = function getAtomicInlineChangedAttrs(in
102
103
  */
103
104
 
104
105
  export var createInlineChangedDecoration = function createInlineChangedDecoration(_ref2) {
106
+ var _revealed$style;
105
107
  var attributionKey = _ref2.attributionKey,
106
108
  change = _ref2.change,
107
109
  colorScheme = _ref2.colorScheme,
@@ -126,6 +128,7 @@ export var createInlineChangedDecoration = function createInlineChangedDecoratio
126
128
  hasDeletedWidget = _ref2$hasDeletedWidge === void 0 ? false : _ref2$hasDeletedWidge,
127
129
  _ref2$isDeletedWidget = _ref2.isDeletedWidgetBelow,
128
130
  isDeletedWidgetBelow = _ref2$isDeletedWidget === void 0 ? false : _ref2$isDeletedWidget,
131
+ reveal = _ref2.reveal,
129
132
  tagMountContext = _ref2.tagMountContext;
130
133
  // Derived from the range so it survives a recalculation: stepping to the next/previous change
131
134
  // rebuilds decorations without touching the doc, and a fresh id would change the React key and the
@@ -145,7 +148,18 @@ export var createInlineChangedDecoration = function createInlineChangedDecoratio
145
148
  }))];
146
149
  }
147
150
  var colors = getColorScheme(colorScheme);
148
- var style = resolveInlineChangedStyle({
151
+
152
+ // The reveal withholds the static highlight so the wipe has something to reveal, so it supplies
153
+ // the whole style rather than adding to the usual one. Extended pipeline only — the AI review
154
+ // surface is the only consumer, and the non-extended styles have no background to wipe.
155
+ var revealed = isExtendedEnabled(diffType) ? resolveRevealStyle({
156
+ colorScheme: colorScheme,
157
+ hideAddedDiffsUnderline: hideAddedDiffsUnderline,
158
+ isActive: isActive,
159
+ isInserted: isInserted,
160
+ reveal: reveal
161
+ }) : undefined;
162
+ var style = (_revealed$style = revealed === null || revealed === void 0 ? void 0 : revealed.style) !== null && _revealed$style !== void 0 ? _revealed$style : resolveInlineChangedStyle({
149
163
  colors: colors,
150
164
  colorScheme: colorScheme,
151
165
  diffType: diffType,
@@ -155,11 +169,11 @@ export var createInlineChangedDecoration = function createInlineChangedDecoratio
155
169
  });
156
170
  var isAtomicInlineInsertion = isAtomicInlineNode && isInserted;
157
171
  var atomicInlineAttrs = isAtomicInlineInsertion ? resolveAtomicInlineAttrs(inlineNodeName, colorScheme, colors) : undefined;
158
- var decorations = [Decoration.inline(change.fromB, change.toB, _objectSpread(_objectSpread({
172
+ var decorations = [Decoration.inline(change.fromB, change.toB, _objectSpread(_objectSpread(_objectSpread({
159
173
  style: atomicInlineAttrs ? "".concat(style).concat(atomicInlineAttrs.styleSuffix) : style
160
174
  }, atomicInlineAttrs && {
161
175
  class: atomicInlineAttrs.className
162
- }), {}, {
176
+ }), revealed && _defineProperty({}, REVEAL_ATTR, revealed.role)), {}, {
163
177
  'data-testid': 'show-diff-changed-decoration'
164
178
  }, showContributorTags && {
165
179
  'data-diff-id': diffId
@@ -111,6 +111,7 @@ export var createNodeChangedDecorationWidget = function createNodeChangedDecorat
111
111
  diffType = _ref2.diffType,
112
112
  _ref2$hideAddedDiffsU = _ref2.hideAddedDiffsUnderline,
113
113
  hideAddedDiffsUnderline = _ref2$hideAddedDiffsU === void 0 ? false : _ref2$hideAddedDiffsU,
114
+ reveal = _ref2.reveal,
114
115
  tagMountContext = _ref2.tagMountContext;
115
116
  var slice = doc.slice(change.fromA, change.toA);
116
117
  var shouldSkipDeletedEmptyParagraphDecoration = !isInserted && (slice === null || slice === void 0 || (_slice$content = slice.content) === null || _slice$content === void 0 ? void 0 : _slice$content.childCount) === 1 && (slice === null || slice === void 0 || (_slice$content2 = slice.content) === null || _slice$content2 === void 0 || (_slice$content2 = _slice$content2.firstChild) === null || _slice$content2 === void 0 ? void 0 : _slice$content2.type.name) === 'paragraph' && (slice === null || slice === void 0 || (_slice$content3 = slice.content) === null || _slice$content3 === void 0 || (_slice$content3 = _slice$content3.firstChild) === null || _slice$content3 === void 0 ? void 0 : _slice$content3.content.size) === 0;
@@ -292,7 +293,7 @@ export var createNodeChangedDecorationWidget = function createNodeChangedDecorat
292
293
  var nodeView = serializer.tryCreateNodeView(node);
293
294
  if (nodeView) {
294
295
  if (node.isInline) {
295
- var wrapper = createContentWrapper(colorScheme, isActive, isInserted, diffType);
296
+ var wrapper = createContentWrapper(colorScheme, isActive, isInserted, diffType, reveal);
296
297
  wrapper.append(nodeView);
297
298
  dom.append(wrapper);
298
299
  } else {
@@ -322,11 +323,12 @@ export var createNodeChangedDecorationWidget = function createNodeChangedDecorat
322
323
  colorScheme: colorScheme,
323
324
  isActive: isActive,
324
325
  isInserted: isInserted,
325
- diffType: diffType
326
+ diffType: diffType,
327
+ reveal: reveal
326
328
  });
327
329
  dom.append(injectedNode);
328
330
  } else {
329
- var _wrapper2 = createContentWrapper(colorScheme, isActive, isInserted, diffType);
331
+ var _wrapper2 = createContentWrapper(colorScheme, isActive, isInserted, diffType, reveal);
330
332
  _wrapper2.append(fallbackNode);
331
333
  dom.append(_wrapper2);
332
334
  }
@@ -11,9 +11,9 @@ import { isDiffDecoration, isDiffDecorationSpec } from './decorationKeys';
11
11
 
12
12
  /**
13
13
  * Diff kinds that expose an anchor a tag can be pinned to: `inline` is added/changed content,
14
- * `widget` is deleted content. Block diffs carry no attribution.
14
+ * `widget` is deleted content, `block` a whole changed block node.
15
15
  */
16
- var TAGGABLE_DECORATION_TYPES = new Set(['inline', 'widget']);
16
+ var TAGGABLE_DECORATION_TYPES = new Set(['block', 'inline', 'widget']);
17
17
 
18
18
  /** The connection is an internal key, so it is dropped on the way to the tag. */
19
19
  var toTagContributor = function toTagContributor(_ref) {
@@ -30,6 +30,15 @@ var isSameChange = function isSameChange(widget, inline) {
30
30
  return widget.spec.attributionKey === inline.spec.attributionKey && widget.from >= inline.from && widget.from <= inline.to;
31
31
  };
32
32
 
33
+ /**
34
+ * Whether `inner` captions the same change as the block decoration `block`, in which case only the
35
+ * block keeps the tag — one tag per block. Containment counts in either direction: a leaf block's
36
+ * highlight spans the wrapper the block sits in. Merely adjacent ranges keep a tag each.
37
+ */
38
+ var isSameBlockChange = function isSameBlockChange(inner, block) {
39
+ return inner.spec.attributionKey === block.spec.attributionKey && (block.from <= inner.from && inner.to <= block.to || inner.from <= block.from && block.to <= inner.to);
40
+ };
41
+
33
42
  /**
34
43
  * One model per diff decoration whose attribution resolves to a supplied contributor; anything
35
44
  * unattributed, untaggable or unresolved is skipped. A replacement's two decorations are collapsed
@@ -72,24 +81,44 @@ export var extractContributorTags = function extractContributorTags(decorations,
72
81
  var decoration = _ref2.decoration;
73
82
  return decoration.spec.decorationType === 'inline';
74
83
  });
84
+ var blockTargets = targets.filter(function (_ref3) {
85
+ var decoration = _ref3.decoration;
86
+ return decoration.spec.decorationType === 'block';
87
+ });
75
88
  var linkedDiffIds = new Map();
76
89
  var folded = new Set();
90
+ var fold = function fold(host, target) {
91
+ var _linkedDiffIds$get;
92
+ folded.add(target);
93
+ var hostDiffId = host.decoration.spec.diffId;
94
+ linkedDiffIds.set(hostDiffId, [].concat(_toConsumableArray((_linkedDiffIds$get = linkedDiffIds.get(hostDiffId)) !== null && _linkedDiffIds$get !== void 0 ? _linkedDiffIds$get : []), [target.decoration.spec.diffId]));
95
+ };
77
96
  var _loop = function _loop() {
78
- var _linkedDiffIds$get;
79
97
  var target = _targets[_i];
80
- if (target.decoration.spec.decorationType !== 'widget') {
98
+ var decorationType = target.decoration.spec.decorationType;
99
+ if (decorationType === 'block') {
81
100
  return 0; // continue
82
101
  }
83
- var host = inlineTargets.find(function (_ref3) {
84
- var decoration = _ref3.decoration;
85
- return isSameChange(target.decoration, decoration);
102
+
103
+ // A block outranks both other kinds, so it is tried first.
104
+ var block = blockTargets.find(function (_ref4) {
105
+ var decoration = _ref4.decoration;
106
+ return isSameBlockChange(target.decoration, decoration);
86
107
  });
87
- if (!host) {
108
+ if (block) {
109
+ fold(block, target);
110
+ return 0; // continue
111
+ }
112
+ if (decorationType !== 'widget') {
88
113
  return 0; // continue
89
114
  }
90
- folded.add(target);
91
- var hostDiffId = host.decoration.spec.diffId;
92
- linkedDiffIds.set(hostDiffId, [].concat(_toConsumableArray((_linkedDiffIds$get = linkedDiffIds.get(hostDiffId)) !== null && _linkedDiffIds$get !== void 0 ? _linkedDiffIds$get : []), [target.decoration.spec.diffId]));
115
+ var host = inlineTargets.find(function (_ref5) {
116
+ var decoration = _ref5.decoration;
117
+ return isSameChange(target.decoration, decoration);
118
+ });
119
+ if (host) {
120
+ fold(host, target);
121
+ }
93
122
  },
94
123
  _ret;
95
124
  for (var _i = 0, _targets = targets; _i < _targets.length; _i++) {
@@ -98,9 +127,9 @@ export var extractContributorTags = function extractContributorTags(decorations,
98
127
  }
99
128
  return targets.filter(function (target) {
100
129
  return !folded.has(target);
101
- }).map(function (_ref4) {
102
- var contributor = _ref4.contributor,
103
- spec = _ref4.decoration.spec;
130
+ }).map(function (_ref6) {
131
+ var contributor = _ref6.contributor,
132
+ spec = _ref6.decoration.spec;
104
133
  var connected = contributor.connectedToKey ? contributors[contributor.connectedToKey] : undefined;
105
134
  var connectedContributor = connected ? toTagContributor(connected) : undefined;
106
135
  var linked = linkedDiffIds.get(spec.diffId);
@@ -0,0 +1,149 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
3
+ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
4
+ import { buildDeletedInlineStyleStandard, getDeletedInlineRevealColors, getInsertedInlineRevealColors } from './colorSchemes/factory';
5
+ import { colorSchemeRegistry } from './colorSchemes/schemes';
6
+ import { deletedContentStyle, deletedContentStyleActive } from './colorSchemes/standard';
7
+ /**
8
+ * Painting strategy for reveal highlights. Highlights are `linear-gradient`s with animated
9
+ * `background-size` for the wipe effect. Colours live on elements as custom properties so the
10
+ * attribution palette works per-contributor.
11
+ */
12
+
13
+ /** Marks an element as taking part in the reveal, and says which side it represents. */
14
+ export var REVEAL_ATTR = 'data-show-diff-reveal';
15
+ /** Wipe colour, read by the animation as the gradient's colour stop. */
16
+ export var REVEAL_BG_VAR = '--show-diff-reveal-bg';
17
+
18
+ /** Underline colour, brought in on the same schedule as the highlight. */
19
+ export var REVEAL_BORDER_VAR = '--show-diff-reveal-border';
20
+
21
+ /** Only schemes with background highlights can be revealed; 'traditional' uses underline only. */
22
+ var schemeSupportsReveal = function schemeSupportsReveal(colorScheme) {
23
+ return colorScheme !== 'traditional';
24
+ };
25
+
26
+ /** Convert a flat background colour into a wipeable gradient (zero width initially). */
27
+ export var buildWipeableBackground = function buildWipeableBackground(color) {
28
+ return convertToInlineCss({
29
+ backgroundColor: 'transparent',
30
+ backgroundImage: "linear-gradient(".concat(color, ", ").concat(color, ")"),
31
+ backgroundRepeat: 'no-repeat',
32
+ backgroundSize: '0% 100%',
33
+ backgroundPosition: '0 0',
34
+ // Each line fragment of a wrapped highlight gets its own background box, so they wipe
35
+ // together rather than the gradient stretching across the whole wrapped run.
36
+ WebkitBoxDecorationBreak: 'clone',
37
+ boxDecorationBreak: 'clone'
38
+ });
39
+ };
40
+
41
+ /** Base padding and transparent underline placeholder (no layout shift on reveal). */
42
+ var revealBaseStyle = convertToInlineCss({
43
+ padding: "1px 0 2px",
44
+ borderBottom: "2px solid transparent"
45
+ });
46
+ var buildRevealVariables = function buildRevealVariables(_ref) {
47
+ var background = _ref.background,
48
+ border = _ref.border;
49
+ return convertToInlineCss(_defineProperty(_defineProperty({}, REVEAL_BG_VAR, background), REVEAL_BORDER_VAR, border));
50
+ };
51
+
52
+ /** Configuration that affects both resting state and reveal endpoint. */
53
+
54
+ /** Reveal colours from the refactored scheme registry (attribution palette ready). */
55
+ var revealColorsRefactored = function revealColorsRefactored(colors, _ref2) {
56
+ var hideAddedDiffsUnderline = _ref2.hideAddedDiffsUnderline,
57
+ isActive = _ref2.isActive,
58
+ isInserted = _ref2.isInserted;
59
+ return isInserted ? getInsertedInlineRevealColors(colors, isActive, hideAddedDiffsUnderline) : getDeletedInlineRevealColors(colors);
60
+ };
61
+
62
+ /**
63
+ * Legacy cohort reveal colours. Values MUST match `revealColorsRefactored()` output for
64
+ * `standard` scheme (test: `revealStyles.ts` in test package).
65
+ */
66
+ var revealColorsLegacy = function revealColorsLegacy(_ref3) {
67
+ var hideAddedDiffsUnderline = _ref3.hideAddedDiffsUnderline,
68
+ isActive = _ref3.isActive,
69
+ isInserted = _ref3.isInserted;
70
+ return isInserted ? {
71
+ // Mirrors `editingStyleExtended` / `editingStyleActiveExtended` and their
72
+ // `*NoUnderline` variants in `colorSchemes/standard.ts`.
73
+ background: isActive ? "var(--ds-background-accent-purple-subtler-pressed, #D8A0F7)" : "var(--ds-background-accent-purple-subtlest, #F8EEFE)",
74
+ border: hideAddedDiffsUnderline ? 'transparent' : "var(--ds-border-accent-purple, #AF59E1)"
75
+ } : {
76
+ // Mirrors `deletedInlineContentStyleExtended` in `colorSchemes/standard.ts`.
77
+ background: "var(--ds-background-accent-gray-subtlest, #F0F1F2)",
78
+ border: "var(--ds-border-accent-gray, #7D818A)"
79
+ };
80
+ };
81
+ var resolveRevealColors = function resolveRevealColors(colors, variant) {
82
+ return isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? revealColorsRefactored(colors, variant) : revealColorsLegacy(variant);
83
+ };
84
+ var getColorScheme = function getColorScheme(colorScheme) {
85
+ return colorSchemeRegistry[colorScheme !== null && colorScheme !== void 0 ? colorScheme : 'standard'];
86
+ };
87
+
88
+ /** Deleted text appearance (grey and strikethrough) without the highlight. */
89
+ var deletedTextOnlyStyle = function deletedTextOnlyStyle(colors, isActive) {
90
+ return isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? buildDeletedInlineStyleStandard(colors, isActive ? 'active' : 'default') : isActive ? deletedContentStyleActive : deletedContentStyle;
91
+ };
92
+
93
+ /**
94
+ * Resolve reveal attribute and style for a decoration. Returned style REPLACES the decoration's
95
+ * highlight (not an addition) so the animation has something to wipe. Gate resolved in showDiff
96
+ * command for single shared answer between decorations and animation.
97
+ */
98
+ export var resolveRevealStyle = function resolveRevealStyle(_ref4) {
99
+ var colorScheme = _ref4.colorScheme,
100
+ _ref4$hideAddedDiffsU = _ref4.hideAddedDiffsUnderline,
101
+ hideAddedDiffsUnderline = _ref4$hideAddedDiffsU === void 0 ? false : _ref4$hideAddedDiffsU,
102
+ _ref4$includeDeletedT = _ref4.includeDeletedTextStyle,
103
+ includeDeletedTextStyle = _ref4$includeDeletedT === void 0 ? true : _ref4$includeDeletedT,
104
+ isActive = _ref4.isActive,
105
+ isInserted = _ref4.isInserted,
106
+ reveal = _ref4.reveal;
107
+ if ((reveal === null || reveal === void 0 ? void 0 : reveal.mode) !== 'phased' || !schemeSupportsReveal(colorScheme)) {
108
+ return undefined;
109
+ }
110
+ var colors = getColorScheme(colorScheme);
111
+ var _resolveRevealColors = resolveRevealColors(colors, {
112
+ hideAddedDiffsUnderline: hideAddedDiffsUnderline,
113
+ isActive: isActive,
114
+ isInserted: isInserted
115
+ }),
116
+ background = _resolveRevealColors.background,
117
+ border = _resolveRevealColors.border;
118
+ return {
119
+ role: isInserted ? 'added' : 'deleted',
120
+ style: (isInserted || !includeDeletedTextStyle ? '' : deletedTextOnlyStyle(colors, isActive)) + revealBaseStyle + buildWipeableBackground(background) + buildRevealVariables({
121
+ background: background,
122
+ border: border
123
+ })
124
+ };
125
+ };
126
+
127
+ /** Reveal style for imperatively-built elements (deleted-content widget wrappers). */
128
+ export var applyRevealToElement = function applyRevealToElement(_ref5) {
129
+ var colorScheme = _ref5.colorScheme,
130
+ element = _ref5.element,
131
+ hideAddedDiffsUnderline = _ref5.hideAddedDiffsUnderline,
132
+ isActive = _ref5.isActive,
133
+ isInserted = _ref5.isInserted,
134
+ reveal = _ref5.reveal;
135
+ var resolved = resolveRevealStyle({
136
+ colorScheme: colorScheme,
137
+ hideAddedDiffsUnderline: hideAddedDiffsUnderline,
138
+ isActive: isActive,
139
+ isInserted: isInserted,
140
+ reveal: reveal,
141
+ // The widget supplies the deleted text's own grey/strikethrough styling already.
142
+ includeDeletedTextStyle: false
143
+ });
144
+ if (!resolved) {
145
+ return '';
146
+ }
147
+ element.setAttribute(REVEAL_ATTR, resolved.role);
148
+ return resolved.style;
149
+ };
@@ -5,6 +5,7 @@ import { getBaseNodeTypeName } from '@atlaskit/editor-common/utils/node-type-uti
5
5
  import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
6
6
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
7
7
  import { isExtendedEnabled } from '../../isExtendedEnabled';
8
+ import { applyRevealToElement } from '../revealStyles';
8
9
  import { getAtomicInlineChangedAttrs } from '../createInlineChangedDecoration';
9
10
  import { applyTableCellEdgeAttrs } from './tableCellEdgeAttrs';
10
11
  import { isInlineAttrChangeNodeName } from './getAttrChangeRanges';
@@ -607,9 +608,17 @@ export var injectInnerWrapper = function injectInnerWrapper(_ref13) {
607
608
  colorScheme = _ref13.colorScheme,
608
609
  isActive = _ref13.isActive,
609
610
  isInserted = _ref13.isInserted,
610
- diffType = _ref13.diffType;
611
+ diffType = _ref13.diffType,
612
+ reveal = _ref13.reveal;
611
613
  var wrapper = document.createElement('span');
612
- wrapper.setAttribute('style', isInserted ? getInsertedContentStyle(colorScheme, isActive) : getDeletedContentStyle(colorScheme, isActive, diffType));
614
+ var revealStyle = applyRevealToElement({
615
+ colorScheme: colorScheme,
616
+ element: wrapper,
617
+ isActive: isActive !== null && isActive !== void 0 ? isActive : false,
618
+ isInserted: isInserted !== null && isInserted !== void 0 ? isInserted : false,
619
+ reveal: reveal
620
+ });
621
+ wrapper.setAttribute('style', (isInserted ? getInsertedContentStyle(colorScheme, isActive) : getDeletedContentStyle(colorScheme, isActive, diffType, Boolean(revealStyle))) + revealStyle);
613
622
  _toConsumableArray(node.childNodes).forEach(function (child) {
614
623
  var removedChild = node.removeChild(child);
615
624
  wrapper.append(removedChild);
@@ -625,22 +634,33 @@ export var createContentWrapper = function createContentWrapper(colorScheme) {
625
634
  var isActive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
626
635
  var isInserted = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
627
636
  var diffType = arguments.length > 3 ? arguments[3] : undefined;
637
+ var reveal = arguments.length > 4 ? arguments[4] : undefined;
628
638
  var wrapper = document.createElement('span');
629
639
  var baseStyle = convertToInlineCss({
630
640
  position: 'relative',
631
641
  width: 'fit-content'
632
642
  });
643
+ // Empty unless the reveal is running, in which case the static highlight below is withheld so
644
+ // the animation can wipe it in instead.
645
+ var revealStyle = applyRevealToElement({
646
+ colorScheme: colorScheme,
647
+ element: wrapper,
648
+ isActive: isActive,
649
+ isInserted: isInserted,
650
+ reveal: reveal
651
+ });
652
+ var deletedStyle = getDeletedContentStyle(colorScheme, isActive, diffType, Boolean(revealStyle));
633
653
  if (isExtendedEnabled(diffType)) {
634
654
  if (isInserted) {
635
- wrapper.setAttribute('style', "".concat(baseStyle).concat(getInsertedContentStyle(colorScheme, isActive)));
655
+ wrapper.setAttribute('style', "".concat(baseStyle).concat(getInsertedContentStyle(colorScheme, isActive)).concat(revealStyle));
636
656
  } else {
637
- wrapper.setAttribute('style', "".concat(baseStyle).concat(getDeletedContentStyle(colorScheme, isActive, diffType)));
657
+ wrapper.setAttribute('style', "".concat(baseStyle).concat(deletedStyle).concat(revealStyle));
638
658
  var strikethrough = document.createElement('span');
639
659
  strikethrough.setAttribute('style', getDeletedContentStyleUnbounded(colorScheme, isActive));
640
660
  wrapper.append(strikethrough);
641
661
  }
642
662
  } else {
643
- wrapper.setAttribute('style', "".concat(baseStyle).concat(getDeletedContentStyle(colorScheme, isActive, diffType)));
663
+ wrapper.setAttribute('style', "".concat(baseStyle).concat(deletedStyle).concat(revealStyle));
644
664
  var _strikethrough = document.createElement('span');
645
665
  _strikethrough.setAttribute('style', getDeletedContentStyleUnbounded(colorScheme, isActive));
646
666
  wrapper.append(_strikethrough);
@@ -100,11 +100,12 @@ var getInsertedContentStyleNext = function getInsertedContentStyleNext(colorSche
100
100
  var getDeletedContentStyleNext = function getDeletedContentStyleNext(colorScheme) {
101
101
  var isActive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
102
102
  var diffType = arguments.length > 2 ? arguments[2] : undefined;
103
+ var omitHighlight = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
103
104
  var colors = getColorScheme(colorScheme);
104
105
  var base = buildDeletedInlineContentStyle(colors, isActive ? 'active' : 'new');
105
106
 
106
107
  // glyphTint adds a background highlight and border-bottom over the tint; strikethrough does not.
107
- var needsExtendedHighlight = colors.deletedInlineTreatment === 'glyphTint' && isExtendedEnabled(diffType);
108
+ var needsExtendedHighlight = colors.deletedInlineTreatment === 'glyphTint' && isExtendedEnabled(diffType) && !omitHighlight;
108
109
  return needsExtendedHighlight ? base + buildDeletedInlineContentStyleExtended(colors) : base;
109
110
  };
110
111
  var resolveCellOverlayStyleNext = function resolveCellOverlayStyleNext(_ref) {
@@ -166,7 +167,8 @@ export var getInsertedContentStyle = function getInsertedContentStyle(colorSchem
166
167
  export var getDeletedContentStyle = function getDeletedContentStyle(colorScheme) {
167
168
  var isActive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
168
169
  var diffType = arguments.length > 2 ? arguments[2] : undefined;
169
- return isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? getDeletedContentStyleNext(colorScheme, isActive, diffType) : getDeletedContentStyleLegacy(getLegacyColorScheme(colorScheme), isActive, diffType);
170
+ var omitHighlight = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
171
+ return isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? getDeletedContentStyleNext(colorScheme, isActive, diffType, omitHighlight) : getDeletedContentStyleLegacy(getLegacyColorScheme(colorScheme), isActive, diffType, omitHighlight);
170
172
  };
171
173
 
172
174
  /**
@@ -165,10 +165,11 @@ export var getInsertedContentStyleLegacy = function getInsertedContentStyleLegac
165
165
  export var getDeletedContentStyleLegacy = function getDeletedContentStyleLegacy(colorScheme) {
166
166
  var isActive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
167
167
  var diffType = arguments.length > 2 ? arguments[2] : undefined;
168
+ var omitHighlight = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
168
169
  if (colorScheme === 'traditional') {
169
170
  return getDeletedTraditionalInlineStyle(isActive);
170
171
  }
171
- if (isExtendedEnabled(diffType)) {
172
+ if (isExtendedEnabled(diffType) && !omitHighlight) {
172
173
  return (isActive ? deletedContentStyleActive : deletedContentStyleNew) + deletedInlineContentStyleExtended;
173
174
  }
174
175
  return isActive ? deletedContentStyleActive : deletedContentStyleNew;
@@ -13,6 +13,7 @@ import { enforceCustomStepRegisters } from './enforceCustomStepRegisters';
13
13
  import { getScrollableDecorations } from './getScrollableDecorations';
14
14
  import { getDefaultDiffType, isExtendedEnabled } from './isExtendedEnabled';
15
15
  import { NodeViewSerializer } from './NodeViewSerializer';
16
+ import { rebindReveal } from './revealAnimation';
16
17
  import { scrollToDecoration } from './scrollToDiff';
17
18
  export var showDiffPluginKey = new PluginKey('showDiffPlugin');
18
19
  /**
@@ -84,12 +85,21 @@ export var createPlugin = function createPlugin(config, getIntl, api, onEditorVi
84
85
  var meta = tr.getMeta(showDiffPluginKey);
85
86
  var newPluginState = currentPluginState;
86
87
  if (meta) {
87
- if ((meta === null || meta === void 0 ? void 0 : meta.action) === 'SHOW_DIFF') {
88
- var _newPluginState, _newPluginState2, _newPluginState3, _newPluginState4, _newPluginState5, _newPluginState6, _newPluginState7, _newPluginState8, _newPluginState9, _newPluginState0;
89
- // Update the plugin state with the new metadata
90
- newPluginState = _objectSpread(_objectSpread(_objectSpread({}, currentPluginState), meta), {}, {
88
+ if ((meta === null || meta === void 0 ? void 0 : meta.action) === 'SHOW_DIFF' || (meta === null || meta === void 0 ? void 0 : meta.action) === 'REVEAL_COMPLETE') {
89
+ var _newPluginState, _newPluginState2, _newPluginState3, _newPluginState4, _newPluginState5, _newPluginState6, _newPluginState7, _newPluginState8, _newPluginState9, _newPluginState0, _newPluginState1;
90
+ // REVEAL_COMPLETE repaints with the reveal dropped, so the decorations render their
91
+ // ordinary resting style. Without it the reveal stays in state indefinitely and the
92
+ // next unrelated repaint re-emits the hidden, zero-width highlight with no animation
93
+ // left to bring it in — the highlight simply vanishes.
94
+ newPluginState = meta.action === 'REVEAL_COMPLETE' ? _objectSpread(_objectSpread({}, currentPluginState), {}, {
95
+ reveal: undefined
96
+ }) : _objectSpread(_objectSpread(_objectSpread({}, currentPluginState), meta), {}, {
91
97
  isDisplayingChanges: true,
92
- activeIndex: undefined
98
+ activeIndex: undefined,
99
+ // Explicit rather than left to the spread: an absent key in `meta` would let
100
+ // the previous paint's choreography leak into this one, so closing the diff
101
+ // would animate too.
102
+ reveal: meta.reveal
93
103
  });
94
104
  // Calculate and store decorations in state
95
105
  var _calculateDiffDecorat = calculateDiffDecorations(_objectSpread({
@@ -109,7 +119,10 @@ export var createPlugin = function createPlugin(config, getIntl, api, onEditorVi
109
119
  showIndicators: (_newPluginState6 = newPluginState) === null || _newPluginState6 === void 0 ? void 0 : _newPluginState6.showIndicators,
110
120
  smartThresholds: (_newPluginState7 = newPluginState) === null || _newPluginState7 === void 0 ? void 0 : _newPluginState7.smartThresholds,
111
121
  deletedDiffPlacement: (_newPluginState8 = newPluginState) === null || _newPluginState8 === void 0 ? void 0 : _newPluginState8.deletedDiffPlacement,
112
- inlineDeletedDiffPlacement: (_newPluginState9 = newPluginState) === null || _newPluginState9 === void 0 ? void 0 : _newPluginState9.inlineDeletedDiffPlacement
122
+ inlineDeletedDiffPlacement: (_newPluginState9 = newPluginState) === null || _newPluginState9 === void 0 ? void 0 : _newPluginState9.inlineDeletedDiffPlacement,
123
+ // SHOW_DIFF only. The scroll-to-next recalculation further down deliberately
124
+ // omits this so stepping through changes cannot replay the choreography.
125
+ reveal: (_newPluginState0 = newPluginState) === null || _newPluginState0 === void 0 ? void 0 : _newPluginState0.reveal
113
126
  } : {})),
114
127
  contributorTags = _calculateDiffDecorat.contributorTags,
115
128
  decorations = _calculateDiffDecorat.decorations,
@@ -117,7 +130,7 @@ export var createPlugin = function createPlugin(config, getIntl, api, onEditorVi
117
130
  // Update the decorations and their ids
118
131
  newPluginState.decorations = decorations;
119
132
  newPluginState.contributorTags = contributorTags;
120
- if (isExtendedEnabled((_newPluginState0 = newPluginState) === null || _newPluginState0 === void 0 ? void 0 : _newPluginState0.diffType)) {
133
+ if (isExtendedEnabled((_newPluginState1 = newPluginState) === null || _newPluginState1 === void 0 ? void 0 : _newPluginState1.diffType)) {
121
134
  newPluginState.diffDescriptors = diffDescriptors;
122
135
  }
123
136
  } else if ((meta === null || meta === void 0 ? void 0 : meta.action) === 'HIDE_DIFF') {
@@ -125,7 +138,8 @@ export var createPlugin = function createPlugin(config, getIntl, api, onEditorVi
125
138
  decorations: DecorationSet.empty,
126
139
  isDisplayingChanges: false,
127
140
  activeIndex: undefined,
128
- contributorTags: []
141
+ contributorTags: [],
142
+ reveal: undefined
129
143
  }, isExtendedEnabled(currentPluginState.diffType) ? {
130
144
  isInverted: false,
131
145
  diffType: getDefaultDiffType(),
@@ -134,9 +148,9 @@ export var createPlugin = function createPlugin(config, getIntl, api, onEditorVi
134
148
  diffDescriptors: []
135
149
  } : {});
136
150
  } else if ((meta === null || meta === void 0 ? void 0 : meta.action) === 'SCROLL_TO_NEXT' || (meta === null || meta === void 0 ? void 0 : meta.action) === 'SCROLL_TO_PREVIOUS') {
137
- var _newPluginState1;
151
+ var _newPluginState10;
138
152
  // Update the active index in plugin state and recalculate decorations
139
- var _decorations = getScrollableDecorations(currentPluginState.decorations, newState.doc, (_newPluginState1 = newPluginState) === null || _newPluginState1 === void 0 ? void 0 : _newPluginState1.diffType);
153
+ var _decorations = getScrollableDecorations(currentPluginState.decorations, newState.doc, (_newPluginState10 = newPluginState) === null || _newPluginState10 === void 0 ? void 0 : _newPluginState10.diffType);
140
154
  if (_decorations.length > 0) {
141
155
  var _currentPluginState$a;
142
156
  // Initialize to -1 if undefined so that the first "next" scroll takes us to index 0 (first change).
@@ -226,6 +240,10 @@ export var createPlugin = function createPlugin(config, getIntl, api, onEditorVi
226
240
  }
227
241
  var pluginState = showDiffPluginKey.getState(view.state);
228
242
 
243
+ // A repaint rebuilds inline decorations, destroying any animation bound to them, so
244
+ // an in-flight reveal has to be re-attached to the new nodes. No-op when idle.
245
+ rebindReveal(view, view.dom);
246
+
229
247
  // Scroll to the first decoration when scrollIntoView was requested.
230
248
  // Use the same filtered/position-sorted list as the active-index path
231
249
  // so "first" reliably means the topmost scrollable diff in the document.
@@ -64,10 +64,15 @@ var resolveAgent = function resolveAgent(attribution, profilesByAccountId) {
64
64
 
65
65
  /**
66
66
  * One contributor per distinct actor behind the attributed steps, resolved against the identities
67
- * the consumer supplied. Returns `undefined` if any actor cannot be named: a half-credited diff
68
- * reads as "nobody touched this", so the whole list is dropped and the plain diff renders instead.
67
+ * the consumer supplied. An actor the consumer cannot name is skipped rather than dropping the whole
68
+ * list: tags are per change, so its changes keep their diff colour and simply carry no tag, while
69
+ * the actors that *are* named stay credited. Returns `undefined` only when nothing resolves at all.
69
70
  */
70
71
  export var resolveDiffContributors = function resolveDiffContributors(stepsWithAttribution, profiles) {
72
+ // Profiles opt callers into contributor tags; attribution alone still supplies diff colours.
73
+ if (profiles === undefined) {
74
+ return undefined;
75
+ }
71
76
  var profilesByAccountId = toProfilesByAccountId(profiles);
72
77
  var contributors = [];
73
78
  /** Keyed as the plugin keys changes, so no two entries can collapse onto one another. */
@@ -100,28 +105,30 @@ export var resolveDiffContributors = function resolveDiffContributors(stepsWithA
100
105
  userId: userId
101
106
  };
102
107
  var _user = resolveUser(userId, profilesByAccountId);
103
- if (!_user) {
104
- return undefined;
105
- }
106
108
 
107
109
  // Skipped if the invoking user's own step already credited them.
108
110
  var invokingUserActor = getAttributionKey(invokingUser);
109
- if (invokingUserActor && !creditedActors.has(invokingUserActor)) {
111
+ if (_user && invokingUserActor && !creditedActors.has(invokingUserActor)) {
110
112
  contributors.push(_objectSpread(_objectSpread({}, _user), {}, {
111
113
  attribution: invokingUser
112
114
  }));
113
115
  creditedActors.add(invokingUserActor);
114
116
  }
117
+
118
+ // The agent is always nameable, so it is credited even when its invoker is not — but
119
+ // without the connection, which would point at a contributor that was never created.
115
120
  contributors.push(_objectSpread(_objectSpread({}, agent), {}, {
116
- attribution: stepAttribution,
121
+ attribution: stepAttribution
122
+ }, _user ? {
117
123
  connectedTo: invokingUser
118
- }));
124
+ } : {}));
119
125
  creditedActors.add(actor);
120
126
  continue;
121
127
  }
122
128
  var user = userId ? resolveUser(userId, profilesByAccountId) : undefined;
123
129
  if (!user) {
124
- return undefined;
130
+ // Unnamed, and a user has no generic fallback label, so this actor's changes go untagged.
131
+ continue;
125
132
  }
126
133
  contributors.push(_objectSpread(_objectSpread({}, user), {}, {
127
134
  attribution: stepAttribution