@atlaskit/editor-plugin-show-diff 14.0.4 → 14.1.0

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 (56) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/cjs/pm-plugins/calculateDiff/calculateDiffDecorations.js +172 -97
  3. package/dist/cjs/pm-plugins/calculateDiff/diffBySteps.js +20 -9
  4. package/dist/cjs/pm-plugins/calculateDiff/simplifyChangesWithAttribution.js +89 -0
  5. package/dist/cjs/pm-plugins/calculateDiff/simplifySteps.js +81 -4
  6. package/dist/cjs/pm-plugins/decorations/colorSchemes/attributions.js +68 -0
  7. package/dist/cjs/pm-plugins/decorations/colorSchemes/schemes.js +26 -2
  8. package/dist/cjs/pm-plugins/decorations/colorSchemes/types.js +5 -1
  9. package/dist/cjs/pm-plugins/decorations/createBlockChangedDecoration.js +7 -2
  10. package/dist/cjs/pm-plugins/decorations/createChangedRowDecorationWidgets.js +2 -2
  11. package/dist/cjs/pm-plugins/decorations/createInlineChangedDecoration.js +4 -2
  12. package/dist/cjs/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.js +14 -10
  13. package/dist/cjs/pm-plugins/main.js +1 -0
  14. package/dist/cjs/showDiffPlugin.js +36 -14
  15. package/dist/es2019/pm-plugins/calculateDiff/calculateDiffDecorations.js +90 -19
  16. package/dist/es2019/pm-plugins/calculateDiff/diffBySteps.js +17 -9
  17. package/dist/es2019/pm-plugins/calculateDiff/simplifyChangesWithAttribution.js +64 -0
  18. package/dist/es2019/pm-plugins/calculateDiff/simplifySteps.js +64 -1
  19. package/dist/es2019/pm-plugins/decorations/colorSchemes/attributions.js +37 -0
  20. package/dist/es2019/pm-plugins/decorations/colorSchemes/schemes.js +19 -2
  21. package/dist/es2019/pm-plugins/decorations/colorSchemes/types.js +1 -0
  22. package/dist/es2019/pm-plugins/decorations/createBlockChangedDecoration.js +6 -3
  23. package/dist/es2019/pm-plugins/decorations/createChangedRowDecorationWidgets.js +3 -3
  24. package/dist/es2019/pm-plugins/decorations/createInlineChangedDecoration.js +6 -3
  25. package/dist/es2019/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.js +12 -9
  26. package/dist/es2019/pm-plugins/main.js +1 -0
  27. package/dist/es2019/showDiffPlugin.js +23 -1
  28. package/dist/esm/pm-plugins/calculateDiff/calculateDiffDecorations.js +173 -98
  29. package/dist/esm/pm-plugins/calculateDiff/diffBySteps.js +20 -9
  30. package/dist/esm/pm-plugins/calculateDiff/simplifyChangesWithAttribution.js +82 -0
  31. package/dist/esm/pm-plugins/calculateDiff/simplifySteps.js +79 -5
  32. package/dist/esm/pm-plugins/decorations/colorSchemes/attributions.js +61 -0
  33. package/dist/esm/pm-plugins/decorations/colorSchemes/schemes.js +24 -1
  34. package/dist/esm/pm-plugins/decorations/colorSchemes/types.js +1 -0
  35. package/dist/esm/pm-plugins/decorations/createBlockChangedDecoration.js +8 -3
  36. package/dist/esm/pm-plugins/decorations/createChangedRowDecorationWidgets.js +3 -3
  37. package/dist/esm/pm-plugins/decorations/createInlineChangedDecoration.js +5 -3
  38. package/dist/esm/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.js +14 -9
  39. package/dist/esm/pm-plugins/main.js +1 -0
  40. package/dist/esm/showDiffPlugin.js +36 -14
  41. package/dist/types/entry-points/show-diff-plugin-type.d.ts +1 -1
  42. package/dist/types/pm-plugins/calculateDiff/diffBySteps.d.ts +2 -1
  43. package/dist/types/pm-plugins/calculateDiff/simplifyChangesWithAttribution.d.ts +7 -0
  44. package/dist/types/pm-plugins/calculateDiff/simplifySteps.d.ts +10 -0
  45. package/dist/types/pm-plugins/decorations/colorSchemes/attributions.d.ts +12 -0
  46. package/dist/types/pm-plugins/decorations/colorSchemes/schemes.d.ts +5 -3
  47. package/dist/types/pm-plugins/decorations/colorSchemes/types.d.ts +6 -1
  48. package/dist/types/pm-plugins/decorations/createBlockChangedDecoration.d.ts +2 -1
  49. package/dist/types/pm-plugins/decorations/createChangedRowDecorationWidgets.d.ts +2 -1
  50. package/dist/types/pm-plugins/decorations/createInlineChangedDecoration.d.ts +2 -1
  51. package/dist/types/pm-plugins/decorations/createNodeChangedDecorationWidget.d.ts +2 -1
  52. package/dist/types/pm-plugins/decorations/utils/wrapBlockNodeView.d.ts +2 -1
  53. package/dist/types/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.d.ts +2 -1
  54. package/dist/types/pm-plugins/main.d.ts +3 -1
  55. package/dist/types/showDiffPluginType.d.ts +29 -1
  56. package/package.json +3 -3
@@ -11,6 +11,7 @@ import { createDocMarginAnchorWidget } from '../decorations/createAnchorDecorati
11
11
  import { createBlockChangedDecoration } from '../decorations/createBlockChangedDecoration';
12
12
  import { createInlineChangedDecoration } from '../decorations/createInlineChangedDecoration';
13
13
  import { createNodeChangedDecorationWidget } from '../decorations/createNodeChangedDecorationWidget';
14
+ import { createAttributionColorMap, getAttributionKey, getColorSchemeForChange, isAttributionColoringEnabled } from '../decorations/colorSchemes/attributions';
14
15
  import { extractDiffDescriptors } from '../decorations/decorationKeys';
15
16
  import { getAttrChangeRanges, stepIsValidAttrChange } from '../decorations/utils/getAttrChangeRanges';
16
17
  import { getMarkChangeRanges } from '../decorations/utils/getMarkChangeRanges';
@@ -19,7 +20,8 @@ import { attrAwareTokenEncoder } from './attrAwareTokenEncoder';
19
20
  import { diffBySteps } from './diffBySteps';
20
21
  import { groupChangesByBlock } from './groupChangesByBlock';
21
22
  import { optimizeChanges } from './optimizeChanges';
22
- import { simplifySteps } from './simplifySteps';
23
+ import { simplifyChangesWithAttribution } from './simplifyChangesWithAttribution';
24
+ import { simplifySteps, simplifyStepsWithAttribution } from './simplifySteps';
23
25
  import { classifySmartChanges } from './smart/classifySmartChanges';
24
26
  import { smartChangeLevel } from './smart/helpers';
25
27
  const getChanges = ({
@@ -58,6 +60,35 @@ const getChanges = ({
58
60
  const changes = simplifyChanges(changeset.changes, tr.doc);
59
61
  return optimizeChanges(changes);
60
62
  };
63
+ const getAttributedChanges = ({
64
+ attributedChanges,
65
+ changeset,
66
+ originalDoc,
67
+ steppedDoc,
68
+ diffType,
69
+ tr,
70
+ intl,
71
+ smartThresholds
72
+ }) => {
73
+ if (isExtendedEnabled(diffType)) {
74
+ if (diffType === 'smart' && fg('platform_editor_ai_smart_diff')) {
75
+ return classifySmartChanges({
76
+ changes: simplifyChangesWithAttribution(attributedChanges, tr.doc),
77
+ originalDoc,
78
+ newDoc: tr.doc,
79
+ locale: intl.locale,
80
+ thresholds: smartThresholds
81
+ });
82
+ }
83
+ if (diffType === 'step') {
84
+ return attributedChanges;
85
+ }
86
+ if (diffType === 'block') {
87
+ return groupChangesByBlock(changeset.changes, originalDoc, steppedDoc);
88
+ }
89
+ }
90
+ return simplifyChangesWithAttribution(attributedChanges, tr.doc);
91
+ };
61
92
 
62
93
  /**
63
94
  * Collect the inline-content ranges of every leaf text-bearing block (paragraph, heading, …)
@@ -206,6 +237,7 @@ const calculateDiffDecorationsInner = ({
206
237
  const {
207
238
  originalDoc,
208
239
  steps,
240
+ stepAttributions,
209
241
  isDisplayingChanges
210
242
  } = pluginState;
211
243
  if (!originalDoc || !isDisplayingChanges) {
@@ -222,8 +254,21 @@ const calculateDiffDecorationsInner = ({
222
254
  tr
223
255
  } = state;
224
256
  let steppedDoc = originalDoc;
257
+ const attributionColoringEnabled = isAttributionColoringEnabled(stepAttributions);
258
+ let simplifiedSteps;
259
+ let simplifiedStepAttributions = [];
260
+ if (attributionColoringEnabled) {
261
+ const simplifiedStepsWithAttribution = simplifyStepsWithAttribution(steps, stepAttributions !== null && stepAttributions !== void 0 ? stepAttributions : [], originalDoc);
262
+ simplifiedSteps = simplifiedStepsWithAttribution.map(({
263
+ step
264
+ }) => step);
265
+ simplifiedStepAttributions = simplifiedStepsWithAttribution.map(({
266
+ stepAttribution
267
+ }) => stepAttribution);
268
+ } else {
269
+ simplifiedSteps = simplifySteps(steps, originalDoc);
270
+ }
225
271
  const attrSteps = [];
226
- const simplifiedSteps = simplifySteps(steps, originalDoc);
227
272
  const stepMaps = [];
228
273
  for (const step of simplifiedSteps) {
229
274
  const result = step.apply(steppedDoc);
@@ -262,17 +307,42 @@ const calculateDiffDecorationsInner = ({
262
307
  // gated with it; other diff types keep the library default so their output is
263
308
  // unchanged.
264
309
  const tokenEncoder = diffType === 'smart' && fg('platform_editor_ai_smart_diff') ? attrAwareTokenEncoder : undefined;
265
- const changeset = ChangeSet.create(originalDoc, undefined, tokenEncoder).addSteps(steppedDoc, stepMaps, tr.doc);
266
- const changes = getChanges({
267
- changeset,
268
- originalDoc,
269
- steppedDoc,
270
- diffType,
271
- tr,
272
- steps,
273
- intl,
274
- smartThresholds
275
- });
310
+ let changes;
311
+ let attributedChanges = [];
312
+ let attributionColors;
313
+ if (attributionColoringEnabled) {
314
+ const changeset = ChangeSet.create(originalDoc, (left, right) => getAttributionKey(left) === getAttributionKey(right) ? left.stepIndex > right.stepIndex ? left : right :
315
+ // `prosemirror-changeset` uses null as its incompatible-data sentinel even
316
+ // though its public combine callback is typed as returning Data.
317
+ null, tokenEncoder).addSteps(steppedDoc, stepMaps, simplifiedStepAttributions.map((attribution, stepIndex) => ({
318
+ ...attribution,
319
+ stepIndex
320
+ })));
321
+ attributedChanges = diffBySteps(originalDoc, simplifiedSteps, simplifiedStepAttributions);
322
+ changes = getAttributedChanges({
323
+ changeset,
324
+ originalDoc,
325
+ steppedDoc,
326
+ diffType,
327
+ tr,
328
+ attributedChanges,
329
+ intl,
330
+ smartThresholds
331
+ });
332
+ attributionColors = createAttributionColorMap(simplifiedStepAttributions);
333
+ } else {
334
+ const changeset = ChangeSet.create(originalDoc, undefined, tokenEncoder).addSteps(steppedDoc, stepMaps, tr.doc);
335
+ changes = getChanges({
336
+ changeset,
337
+ originalDoc,
338
+ steppedDoc,
339
+ diffType,
340
+ tr,
341
+ steps: simplifiedSteps,
342
+ intl,
343
+ smartThresholds
344
+ });
345
+ }
276
346
  const decorations = [];
277
347
 
278
348
  /**
@@ -285,6 +355,7 @@ const calculateDiffDecorationsInner = ({
285
355
  // Our default operations are insertions, so it should match the opposite of isInverted.
286
356
  const isInserted = !isInverted;
287
357
  const createDecorationsForChange = change => {
358
+ const changeColorScheme = attributionColors ? getColorSchemeForChange(change, attributedChanges, attributionColors, colorScheme) : colorScheme;
288
359
  const isActive = activeIndexPos && change.fromB === activeIndexPos.from && change.toB === activeIndexPos.to;
289
360
 
290
361
  // Hoisted because it decides BOTH where the deleted widget is anchored and — since the
@@ -333,7 +404,7 @@ const calculateDiffDecorationsInner = ({
333
404
  toB: to
334
405
  },
335
406
  doc: tr.doc,
336
- colorScheme,
407
+ colorScheme: changeColorScheme,
337
408
  isActive,
338
409
  diffType,
339
410
  ...(isExtendedEnabled(diffType) && {
@@ -350,7 +421,7 @@ const calculateDiffDecorationsInner = ({
350
421
  decorations.push(...createInlineChangedDecoration({
351
422
  change,
352
423
  doc: tr.doc,
353
- colorScheme,
424
+ colorScheme: changeColorScheme,
354
425
  isActive,
355
426
  diffType,
356
427
  ...(isExtendedEnabled(diffType) && {
@@ -367,7 +438,7 @@ const calculateDiffDecorationsInner = ({
367
438
  doc: tr.doc,
368
439
  from: change.fromB,
369
440
  to: change.toB,
370
- colorScheme,
441
+ colorScheme: changeColorScheme,
371
442
  ...(isExtendedEnabled(diffType) && {
372
443
  isInserted,
373
444
  shouldHideDeleted,
@@ -386,7 +457,7 @@ const calculateDiffDecorationsInner = ({
386
457
  change,
387
458
  doc: originalDoc,
388
459
  nodeViewSerializer,
389
- colorScheme,
460
+ colorScheme: changeColorScheme,
390
461
  newDoc: tr.doc,
391
462
  intl,
392
463
  activeIndexPos,
@@ -532,7 +603,7 @@ export const calculateDiffDecorations = memoizeOne(calculateDiffDecorationsInner
532
603
  const originalDocIsSame = lastPluginState.originalDoc && pluginState.originalDoc && pluginState.originalDoc.eq(lastPluginState.originalDoc);
533
604
  if (isExtendedEnabled(diffType)) {
534
605
  var _ref;
535
- return (_ref = colorScheme === lastColorScheme && intl.locale === lastIntl.locale && isInverted === lastIsInverted && diffType === lastDiffType && isEqual(activeIndexPos, lastActiveIndexPos) && originalDocIsSame && isEqual(pluginState.steps, lastPluginState.steps) && state.doc.eq(lastState.doc) && hideDeletedDiffs === lastHideDeletedDiffs && hideAddedDiffsUnderline === lastHideAddedDiffsUnderline && showIndicators === lastShowIndicators && isEqual(smartThresholds, lastSmartThresholds) && deletedDiffPlacement === lastDeletedDiffPlacement && inlineDeletedDiffPlacement === lastInlineDeletedDiffPlacement) !== null && _ref !== void 0 ? _ref : false;
606
+ return (_ref = colorScheme === lastColorScheme && intl.locale === lastIntl.locale && isInverted === lastIsInverted && diffType === lastDiffType && isEqual(activeIndexPos, lastActiveIndexPos) && originalDocIsSame && isEqual(pluginState.steps, lastPluginState.steps) && isEqual(pluginState.stepAttributions, lastPluginState.stepAttributions) && state.doc.eq(lastState.doc) && hideDeletedDiffs === lastHideDeletedDiffs && hideAddedDiffsUnderline === lastHideAddedDiffsUnderline && showIndicators === lastShowIndicators && isEqual(smartThresholds, lastSmartThresholds) && deletedDiffPlacement === lastDeletedDiffPlacement && inlineDeletedDiffPlacement === lastInlineDeletedDiffPlacement) !== null && _ref !== void 0 ? _ref : false;
536
607
  }
537
- return (_ref2 = originalDocIsSame && isEqual(pluginState.steps, lastPluginState.steps) && state.doc.eq(lastState.doc) && colorScheme === lastColorScheme && intl.locale === lastIntl.locale && isEqual(activeIndexPos, lastActiveIndexPos) && hideDeletedDiffs === lastHideDeletedDiffs) !== null && _ref2 !== void 0 ? _ref2 : false;
608
+ return (_ref2 = originalDocIsSame && isEqual(pluginState.steps, lastPluginState.steps) && isEqual(pluginState.stepAttributions, lastPluginState.stepAttributions) && state.doc.eq(lastState.doc) && colorScheme === lastColorScheme && intl.locale === lastIntl.locale && isEqual(activeIndexPos, lastActiveIndexPos) && hideDeletedDiffs === lastHideDeletedDiffs) !== null && _ref2 !== void 0 ? _ref2 : false;
538
609
  });
@@ -1,6 +1,7 @@
1
1
  import { simplifyChanges, ChangeSet } from 'prosemirror-changeset';
2
2
  import { Mark } from '@atlaskit/editor-prosemirror/model';
3
3
  import { Mapping, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
4
+ import { getAttributionKey } from '../decorations/colorSchemes/attributions';
4
5
  import { attrAwareTokenEncoder } from './attrAwareTokenEncoder';
5
6
  import { optimizeChanges } from './optimizeChanges';
6
7
  const WORD_CHAR_REGEX = /[\p{L}\p{N}_]/u;
@@ -177,9 +178,9 @@ const createMapping = maps => {
177
178
  }
178
179
  return mapping;
179
180
  };
180
- const createSpans = length => length > 0 ? [{
181
+ const createSpans = (length, data = null) => length > 0 ? [{
181
182
  length,
182
- data: null
183
+ data
183
184
  }] : [];
184
185
  const mergeOverlappingByNewDocRange = changes => {
185
186
  if (changes.length <= 1) {
@@ -191,8 +192,11 @@ const mergeOverlappingByNewDocRange = changes => {
191
192
  ...sortedChanges[0]
192
193
  };
193
194
  for (let i = 1; i < sortedChanges.length; i++) {
195
+ var _, _2;
194
196
  const next = sortedChanges[i];
195
- const isOverlapping = next.fromB <= current.toB;
197
+ const currentIdentity = getAttributionKey((_ = [...current.deleted, ...current.inserted][0]) === null || _ === void 0 ? void 0 : _.data);
198
+ const nextIdentity = getAttributionKey((_2 = [...next.deleted, ...next.inserted][0]) === null || _2 === void 0 ? void 0 : _2.data);
199
+ const isOverlapping = next.fromB <= current.toB && currentIdentity === nextIdentity;
196
200
  if (isOverlapping) {
197
201
  current = {
198
202
  fromA: Math.min(current.fromA, next.fromA),
@@ -248,12 +252,12 @@ const shouldCheckGranularDiff = (step, before, from, to) => {
248
252
  const isTextContentEqual = (replacedNode === null || replacedNode === void 0 ? void 0 : replacedNode.textContent) === (replacingNode === null || replacingNode === void 0 ? void 0 : replacingNode.textContent);
249
253
  return !isTextContentEqual || isTextContentEqual && hasSameChildMarks(replacedNode, replacingNode);
250
254
  };
251
- export const diffBySteps = (originalDoc, steps) => {
255
+ export const diffBySteps = (originalDoc, steps, stepAttributions) => {
252
256
  const changes = [];
253
257
  let currentDoc = originalDoc;
254
258
  const successfulStepMaps = [];
255
259
  const rangedSteps = [];
256
- for (const step of steps) {
260
+ for (const [stepIndex, step] of steps.entries()) {
257
261
  const before = currentDoc;
258
262
  const result = step.apply(currentDoc);
259
263
  if (result.failed !== null || !result.doc) {
@@ -268,6 +272,10 @@ export const diffBySteps = (originalDoc, steps) => {
268
272
  from: rangeStep.from,
269
273
  to: rangeStep.to,
270
274
  mapIndex: successfulStepMaps.length,
275
+ stepAttribution: stepAttributions !== null && stepAttributions !== void 0 && stepAttributions[stepIndex] ? {
276
+ ...stepAttributions[stepIndex],
277
+ stepIndex
278
+ } : null,
271
279
  step,
272
280
  stepMap
273
281
  });
@@ -343,8 +351,8 @@ export const diffBySteps = (originalDoc, steps) => {
343
351
  toA: granularToA,
344
352
  fromB: granularFromB,
345
353
  toB: granularToB,
346
- deleted: createSpans(Math.max(0, granularToA - granularFromA)),
347
- inserted: createSpans(Math.max(0, granularToB - granularFromB))
354
+ deleted: createSpans(Math.max(0, granularToA - granularFromA), rangedStep.stepAttribution),
355
+ inserted: createSpans(Math.max(0, granularToB - granularFromB), rangedStep.stepAttribution)
348
356
  });
349
357
  }
350
358
  continue;
@@ -354,8 +362,8 @@ export const diffBySteps = (originalDoc, steps) => {
354
362
  toA,
355
363
  fromB,
356
364
  toB,
357
- deleted: createSpans(Math.max(0, toA - fromA)),
358
- inserted: createSpans(Math.max(0, toB - fromB))
365
+ deleted: createSpans(Math.max(0, toA - fromA), rangedStep.stepAttribution),
366
+ inserted: createSpans(Math.max(0, toB - fromB), rangedStep.stepAttribution)
359
367
  });
360
368
  }
361
369
  return mergeOverlappingByNewDocRange(changes);
@@ -0,0 +1,64 @@
1
+ import { simplifyChanges } from 'prosemirror-changeset';
2
+ import { getAttributionKey } from '../decorations/colorSchemes/attributions';
3
+ import { optimizeChanges } from './optimizeChanges';
4
+ const getAttributionIdentity = change => {
5
+ const identities = new Set();
6
+ for (const span of [...change.deleted, ...change.inserted]) {
7
+ identities.add(getAttributionKey(span.data));
8
+ }
9
+ if (identities.size > 1) {
10
+ return {
11
+ key: undefined,
12
+ mergeable: false
13
+ };
14
+ }
15
+ return {
16
+ key: identities.values().next().value,
17
+ mergeable: true
18
+ };
19
+ };
20
+
21
+ /**
22
+ * Simplifies and optimizes consecutive changes without crossing an attribution boundary.
23
+ * A change which already contains more than one identity is deliberately kept isolated.
24
+ */
25
+ export const simplifyChangesWithAttribution = (changes, doc) => {
26
+ const result = [];
27
+ let run = [];
28
+ let runIdentity;
29
+ const flush = () => {
30
+ if (run.length > 0) {
31
+ // Some show-diff producers use structurally compatible Change objects rather than the
32
+ // library class. `simplifyChanges` reads runtime `lenA`/`lenB` getters even though they
33
+ // are intentionally omitted from its public declarations, so add equivalent getters
34
+ // without calling the library's internal constructor.
35
+ const normalizedRun = run.map(change => ({
36
+ ...change,
37
+ get lenA() {
38
+ return change.toA - change.fromA;
39
+ },
40
+ get lenB() {
41
+ return change.toB - change.fromB;
42
+ }
43
+ }));
44
+ result.push(...optimizeChanges(simplifyChanges(normalizedRun, doc)));
45
+ }
46
+ run = [];
47
+ runIdentity = undefined;
48
+ };
49
+ for (const change of changes) {
50
+ var _runIdentity;
51
+ const identity = getAttributionIdentity(change);
52
+ const canJoinRun = ((_runIdentity = runIdentity) === null || _runIdentity === void 0 ? void 0 : _runIdentity.mergeable) === true && identity.mergeable && runIdentity.key === identity.key;
53
+ if (run.length > 0 && !canJoinRun) {
54
+ flush();
55
+ }
56
+ run.push(change);
57
+ runIdentity = identity;
58
+ if (!identity.mergeable) {
59
+ flush();
60
+ }
61
+ }
62
+ flush();
63
+ return result;
64
+ };
@@ -1,7 +1,7 @@
1
1
  import { AnalyticsStep } from '@atlaskit/adf-schema/steps';
2
2
  import { areNodesEqualIgnoreAttrs } from '@atlaskit/editor-common/utils/document';
3
3
  import { ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
4
-
4
+ import { getAttributionKey } from '../decorations/colorSchemes/attributions';
5
5
  /**
6
6
  * Attempts to merge two consecutive ReplaceStep operations.
7
7
  * This merges steps where:
@@ -41,6 +41,69 @@ export function simplifySteps(steps, originalDoc) {
41
41
  return acc;
42
42
  }, []);
43
43
  }
44
+ const mergeAttributions = (first, second) => {
45
+ var _second$wasOffline;
46
+ if (!first) {
47
+ return second;
48
+ }
49
+ if (!second) {
50
+ return first;
51
+ }
52
+ return {
53
+ ...first,
54
+ ...second,
55
+ wasOffline: first.wasOffline === true || second.wasOffline === true ? true : (_second$wasOffline = second.wasOffline) !== null && _second$wasOffline !== void 0 ? _second$wasOffline : first.wasOffline
56
+ };
57
+ };
58
+
59
+ /**
60
+ * Attribution-preserving variant of `simplifySteps`.
61
+ *
62
+ * Steps may only merge when they have the same effective actor identity. Keeping the attribution
63
+ * coupled to the step also ensures filtering a no-op/analytics step cannot shift array indexes.
64
+ */
65
+ export function simplifyStepsWithAttribution(steps, stepAttributions, originalDoc) {
66
+ const stepsToFilter = removeUnusedAttributedSteps(steps.map((step, index) => ({
67
+ step,
68
+ stepAttribution: stepAttributions[index]
69
+ })), originalDoc);
70
+ return stepsToFilter.filter(({
71
+ step
72
+ }) => !(step instanceof AnalyticsStep)).reduce((acc, current) => {
73
+ var _previous$step$merge, _previous$step$merge2, _previous$step;
74
+ const previous = acc[acc.length - 1];
75
+ const isSameIdentity = previous && getAttributionKey(previous.stepAttribution) === getAttributionKey(current.stepAttribution);
76
+ const merged = isSameIdentity ? (_previous$step$merge = (_previous$step$merge2 = (_previous$step = previous.step).merge) === null || _previous$step$merge2 === void 0 ? void 0 : _previous$step$merge2.call(_previous$step, current.step)) !== null && _previous$step$merge !== void 0 ? _previous$step$merge : mergeReplaceSteps(previous.step, current.step) : null;
77
+ if (merged) {
78
+ acc[acc.length - 1] = {
79
+ step: merged,
80
+ stepAttribution: mergeAttributions(previous.stepAttribution, current.stepAttribution)
81
+ };
82
+ } else {
83
+ acc.push(current);
84
+ }
85
+ return acc;
86
+ }, []);
87
+ }
88
+
89
+ /**
90
+ * Does a first pass to remove steps that don't impact the document
91
+ */
92
+ function removeUnusedAttributedSteps(stepsWithAttribution, originalDoc) {
93
+ const finalSteps = [];
94
+ let firstPassDoc = originalDoc;
95
+ for (const stepWithAttribution of stepsWithAttribution) {
96
+ const {
97
+ step
98
+ } = stepWithAttribution;
99
+ const result = step.apply(firstPassDoc);
100
+ if (result.failed === null && result.doc && !areNodesEqualIgnoreAttrs(firstPassDoc, result.doc, ['localId'])) {
101
+ finalSteps.push(stepWithAttribution);
102
+ firstPassDoc = result.doc;
103
+ }
104
+ }
105
+ return finalSteps;
106
+ }
44
107
 
45
108
  /**
46
109
  * Does a first pass to remove steps that don't impact the document
@@ -0,0 +1,37 @@
1
+ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
2
+ import { fg } from '@atlaskit/platform-feature-flags/fg';
3
+ const ATTRIBUTION_COLOR_PALETTE = ['purple', 'blue', 'teal', 'magenta', 'orange', 'green'];
4
+
5
+ /** `userId` is primary; `agentId`, or `agentType` as its fallback, separates shared users. */
6
+ export const getAttributionKey = attribution => {
7
+ var _attribution$userId, _attribution$agentId, _attribution$agentTyp;
8
+ const userId = attribution === null || attribution === void 0 ? void 0 : (_attribution$userId = attribution.userId) === null || _attribution$userId === void 0 ? void 0 : _attribution$userId.trim();
9
+ const agentId = attribution === null || attribution === void 0 ? void 0 : (_attribution$agentId = attribution.agentId) === null || _attribution$agentId === void 0 ? void 0 : _attribution$agentId.trim();
10
+ const agentType = attribution === null || attribution === void 0 ? void 0 : (_attribution$agentTyp = attribution.agentType) === null || _attribution$agentTyp === void 0 ? void 0 : _attribution$agentTyp.trim();
11
+ if (!userId && !agentId && !agentType) {
12
+ return undefined;
13
+ }
14
+ const agentIdentity = agentId || (agentType ? `type:${agentType}` : '');
15
+ return `user:${userId !== null && userId !== void 0 ? userId : ''}|agent:${agentIdentity}`;
16
+ };
17
+ export const areAttributionColorGatesEnabled = () => fg('confluence_ncs_step_diffing_version_history') && isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor');
18
+ export const isAttributionColoringEnabled = stepAttributions => areAttributionColorGatesEnabled() && (stepAttributions === null || stepAttributions === void 0 ? void 0 : stepAttributions.some(attribution => getAttributionKey(attribution) !== undefined)) === true;
19
+ export const createAttributionColorMap = stepAttributions => {
20
+ const keys = Array.from(new Set(stepAttributions.map(getAttributionKey).filter(key => key !== undefined))).sort();
21
+ return new Map(keys.map((key, index) => [key, ATTRIBUTION_COLOR_PALETTE[index % ATTRIBUTION_COLOR_PALETTE.length]]));
22
+ };
23
+ const getLatestAttribution = changes => {
24
+ const data = changes.flatMap(change => [...change.deleted, ...change.inserted]).map(span => span.data).filter(value => typeof value === 'object' && value !== null && 'stepIndex' in value && typeof value.stepIndex === 'number');
25
+ return data.reduce((latest, attribution) => !latest || attribution.stepIndex > latest.stepIndex ? attribution : latest, undefined);
26
+ };
27
+ const rangesOverlap = (fromA, toA, fromB, toB) => fromA < toB && fromB < toA;
28
+ const changesOverlap = (change, attributedChange) => {
29
+ const insertedOverlap = change.inserted.length > 0 && attributedChange.inserted.length > 0 && rangesOverlap(change.fromB, change.toB, attributedChange.fromB, attributedChange.toB);
30
+ const deletedOverlap = change.deleted.length > 0 && attributedChange.deleted.length > 0 && rangesOverlap(change.fromA, change.toA, attributedChange.fromA, attributedChange.toA);
31
+ return insertedOverlap || deletedOverlap;
32
+ };
33
+ export const getColorSchemeForChange = (change, attributedChanges, attributionColors, fallback) => {
34
+ var _attributionColors$ge;
35
+ const key = getAttributionKey(getLatestAttribution(attributedChanges.filter(attributedChange => changesOverlap(change, attributedChange))));
36
+ return key ? (_attributionColors$ge = attributionColors.get(key)) !== null && _attributionColors$ge !== void 0 ? _attributionColors$ge : fallback : fallback;
37
+ };
@@ -52,9 +52,26 @@ export const standardScheme = {
52
52
  deletedQuoteNodeActiveTone: 'borderAccent',
53
53
  strikesDeletedEmbedCard: false
54
54
  };
55
+ const createAttributionScheme = color => ({
56
+ ...standardScheme,
57
+ insertColor: color,
58
+ insertActiveColor: color,
59
+ deleteColor: color,
60
+ deleteActiveColor: color,
61
+ deletedCellColor: color
62
+ });
55
63
 
56
- /** Maps the public ColorScheme string to its data object. Adding a scheme = one entry here. */
64
+ /** Maps public schemes and attribution-only accents to their data objects. */
57
65
  export const colorSchemeRegistry = {
66
+ blue: createAttributionScheme('blue'),
67
+ green: createAttributionScheme('green'),
68
+ magenta: createAttributionScheme('magenta'),
69
+ orange: createAttributionScheme('orange'),
70
+ purple: createAttributionScheme('purple'),
71
+ teal: createAttributionScheme('teal'),
58
72
  traditional: traditionalScheme,
59
73
  standard: standardScheme
60
- };
74
+ };
75
+
76
+ /** Attribution accents are impossible in the refactor-off cohort; fall back defensively. */
77
+ export const getLegacyColorScheme = colorScheme => colorScheme === 'standard' || colorScheme === 'traditional' ? colorScheme : undefined;
@@ -4,7 +4,7 @@ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-e
4
4
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
5
5
  import { isExtendedEnabled } from '../isExtendedEnabled';
6
6
  import { buildAddedCellOverlayRoundedStyle, buildAddedCellOverlayStyle, buildDeletedBlockNodeStyle, buildDeletedCellOverlayRoundedStyle, buildDeletedCellOverlayStyle, buildInsertedBlockNodeStyle } from './colorSchemes/factory';
7
- import { colorSchemeRegistry } from './colorSchemes/schemes';
7
+ import { colorSchemeRegistry, getLegacyColorScheme } from './colorSchemes/schemes';
8
8
  import { createBlockIndicatorAnchorWidgets } from './createAnchorDecorationWidgets';
9
9
  import { buildDiffDecorationSpec } from './decorationKeys';
10
10
  import { getBlockNodeStyleLegacy, resolveCellOverlayStyleLegacy } from './createBlockChangedDecoration.styles.legacy';
@@ -95,7 +95,10 @@ const getBlockNodeStyleNext = ({
95
95
  * OFF cohort of `platform_editor_show_diff_color_scheme_refactor`. Both are built to emit the
96
96
  * same style strings for both shipped schemes; see EDITOR-8281.
97
97
  */
98
- const getBlockNodeStyle = props => isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? getBlockNodeStyleNext(props) : getBlockNodeStyleLegacy(props);
98
+ const getBlockNodeStyle = props => isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? getBlockNodeStyleNext(props) : getBlockNodeStyleLegacy({
99
+ ...props,
100
+ colorScheme: getLegacyColorScheme(props.colorScheme)
101
+ });
99
102
 
100
103
  /**
101
104
  * A table cell is "empty" only when it has no content at all — no text AND no
@@ -165,7 +168,7 @@ export const createBlockChangedDecoration = ({
165
168
  const isEmptyCellBeingFilled = !isInserted && !!cellNode && isCellEmpty(cellNode);
166
169
  const useAddedStyle = isInserted || isEmptyCellBeingFilled;
167
170
  const cellOverlayStyle = isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? useAddedStyle ? isRoundedTable ? buildAddedCellOverlayRoundedStyle(colors) : buildAddedCellOverlayStyle(colors) : isRoundedTable ? buildDeletedCellOverlayRoundedStyle(colors) : buildDeletedCellOverlayStyle(colors) : resolveCellOverlayStyleLegacy({
168
- colorScheme,
171
+ colorScheme: getLegacyColorScheme(colorScheme),
169
172
  isRoundedTable,
170
173
  useAddedStyle
171
174
  });
@@ -6,7 +6,7 @@ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-e
6
6
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
7
7
  import { isExtendedEnabled } from '../isExtendedEnabled';
8
8
  import { buildAddedCellOverlayRoundedStyle, buildAddedCellOverlayStyle, buildDeletedCellOverlayRoundedStyle, buildDeletedCellOverlayStyle, buildDeletedRowStyle } from './colorSchemes/factory';
9
- import { colorSchemeRegistry } from './colorSchemes/schemes';
9
+ import { colorSchemeRegistry, getLegacyColorScheme } from './colorSchemes/schemes';
10
10
  import { resolveCellOverlayStyleLegacy, resolveDeletedRowStyleLegacy } from './createChangedRowDecorationWidgets.styles.legacy';
11
11
  import { buildDiffDecorationSpec } from './decorationKeys';
12
12
  import { findSafeInsertPos } from './utils/findSafeInsertPos';
@@ -120,7 +120,7 @@ const createChangedRowDOM = (rowNode, cellEdgeAttrs, nodeViewSerializer, colorSc
120
120
 
121
121
  // Inserted rows keep their natural styling; the row strikethrough is deletions only.
122
122
  if (!isExtendedEnabled(diffType) || !isInserted) {
123
- tr.setAttribute('style', isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? buildDeletedRowStyle(colors) : resolveDeletedRowStyleLegacy(colorScheme));
123
+ tr.setAttribute('style', isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? buildDeletedRowStyle(colors) : resolveDeletedRowStyleLegacy(getLegacyColorScheme(colorScheme)));
124
124
  }
125
125
  tr.setAttribute('data-testid', 'show-diff-deleted-row');
126
126
 
@@ -136,7 +136,7 @@ const createChangedRowDOM = (rowNode, cellEdgeAttrs, nodeViewSerializer, colorSc
136
136
  const overlay = document.createElement('span');
137
137
  const isRoundedTable = expValEquals('platform_editor_table_diff_rounded_corners', 'isEnabled', true);
138
138
  const overlayStyle = isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? isInserted ? isRoundedTable ? buildAddedCellOverlayRoundedStyle(colors) : buildAddedCellOverlayStyle(colors) : isRoundedTable ? buildDeletedCellOverlayRoundedStyle(colors) : buildDeletedCellOverlayStyle(colors) : resolveCellOverlayStyleLegacy({
139
- colorScheme,
139
+ colorScheme: getLegacyColorScheme(colorScheme),
140
140
  isInserted,
141
141
  isRoundedTable
142
142
  });
@@ -3,7 +3,7 @@ import { Decoration } from '@atlaskit/editor-prosemirror/view';
3
3
  import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
4
4
  import { isExtendedEnabled } from '../isExtendedEnabled';
5
5
  import { buildAtomicInlineChangedCSSVariables, buildDeletedInlineContentStyleExtended, buildDeletedInlineStyle, buildDeletedInlineStyleStandard, buildInsertStyle, buildInsertStyleActive, buildInsertStyleExtended, buildInsertStyleExtendedActive, buildInsertStyleExtendedNoUnderline, buildInsertStyleExtendedNoUnderlineActive } from './colorSchemes/factory';
6
- import { colorSchemeRegistry } from './colorSchemes/schemes';
6
+ import { colorSchemeRegistry, getLegacyColorScheme } from './colorSchemes/schemes';
7
7
  import { createInlineIndicatorAnchorWidgets } from './createAnchorDecorationWidgets';
8
8
  import { getAtomicInlineNodeClassNameLegacy, resolveInlineChangedStyleLegacy } from './createInlineChangedDecoration.styles.legacy';
9
9
  import { buildDiffDecorationSpec } from './decorationKeys';
@@ -64,7 +64,10 @@ const resolveInlineChangedStyleRefactored = ({
64
64
  * Single gate for the inline `style` string: registry + factory when the refactor is on, the
65
65
  * verbatim pre-refactor per-scheme constants when it is off.
66
66
  */
67
- const resolveInlineChangedStyle = args => isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? resolveInlineChangedStyleRefactored(args) : resolveInlineChangedStyleLegacy(args);
67
+ const resolveInlineChangedStyle = args => isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? resolveInlineChangedStyleRefactored(args) : resolveInlineChangedStyleLegacy({
68
+ ...args,
69
+ colorScheme: getLegacyColorScheme(args.colorScheme)
70
+ });
68
71
 
69
72
  /**
70
73
  * Single gate for the atomic-inline-node decoration attributes. The two cohorts differ in the DOM:
@@ -76,7 +79,7 @@ const resolveAtomicInlineAttrs = (inlineNodeName, colorScheme, colors) => isExpe
76
79
  className: getAtomicInlineNodeClassName(inlineNodeName),
77
80
  styleSuffix: buildAtomicInlineChangedCSSVariables(colors)
78
81
  } : {
79
- className: getAtomicInlineNodeClassNameLegacy(inlineNodeName, colorScheme),
82
+ className: getAtomicInlineNodeClassNameLegacy(inlineNodeName, getLegacyColorScheme(colorScheme)),
80
83
  styleSuffix: ''
81
84
  };
82
85
 
@@ -14,7 +14,7 @@ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-e
14
14
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
15
15
  import { isExtendedEnabled } from '../../isExtendedEnabled';
16
16
  import { buildAddedCellOverlayRoundedStyle, buildAddedCellOverlayStyle, buildAddedCellOverlayStyleNew, buildDeletedCellOverlayRoundedStyle, buildDeletedCellOverlayStyle, buildDeletedInlineContentStyle, buildDeletedInlineContentStyleExtended, buildDeletedLozengeActiveStyle, buildDeletedLozengeStyle, buildDeletedNodeCSSVariables, buildDeletedQuoteNodeWithLozengeStyle, buildDeletedStrikethroughLine, buildDeletedWrappedBlockOutline, buildInsertedBlockNodeStyle, buildInsertedInlineStyle, buildInsertStyleInBlockExtended, buildInsertStyleInBlockExtendedNoUnderline, buildInsertStyleNode } from '../colorSchemes/factory';
17
- import { colorSchemeRegistry, standardScheme } from '../colorSchemes/schemes';
17
+ import { colorSchemeRegistry, getLegacyColorScheme, standardScheme } from '../colorSchemes/schemes';
18
18
  import { getChangedContentStyleLegacy, getChangedNodeStyleLegacy, getDeletedContentStyleLegacy, getDeletedContentStyleUnboundedLegacy, getInsertedContentStyleLegacy, hasRestingDeletedRingLegacy, resolveCellOverlayStyleLegacy, resolveNestedInsertedNodeStyleLegacy, resolveRemovedLozengeStyleLegacy } from './wrapBlockNodeViewStyles.legacy';
19
19
  const DEFAULT_COLOR_SCHEME = 'standard';
20
20
  const getColorScheme = colorScheme => colorSchemeRegistry[colorScheme !== null && colorScheme !== void 0 ? colorScheme : DEFAULT_COLOR_SCHEME];
@@ -108,28 +108,31 @@ const resolveNestedInsertedNodeStyleNext = () => buildInsertStyleNode(nestedCont
108
108
  const hasRestingDeletedRingNext = colorScheme => getColorScheme(colorScheme).deletedNodeEmphasis === 'stateful';
109
109
 
110
110
  /** Inline content style for a changed (inserted or deleted) block node. */
111
- export const getChangedContentStyle = (colorScheme, isActive = false, isInserted = false, diffType, hideAddedDiffsUnderline = false) => isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? getChangedContentStyleNext(colorScheme, isActive, isInserted, diffType, hideAddedDiffsUnderline) : getChangedContentStyleLegacy(colorScheme, isActive, isInserted, diffType, hideAddedDiffsUnderline);
111
+ export const getChangedContentStyle = (colorScheme, isActive = false, isInserted = false, diffType, hideAddedDiffsUnderline = false) => isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? getChangedContentStyleNext(colorScheme, isActive, isInserted, diffType, hideAddedDiffsUnderline) : getChangedContentStyleLegacy(getLegacyColorScheme(colorScheme), isActive, isInserted, diffType, hideAddedDiffsUnderline);
112
112
 
113
113
  /** Node-specific style for a changed block node, or `undefined` when the node type has none. */
114
- export const getChangedNodeStyle = (nodeName, colorScheme, isInserted = false, isActive = false, diffType, hideAddedDiffsUnderline = false) => isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? getChangedNodeStyleNext(nodeName, colorScheme, isInserted, isActive, diffType, hideAddedDiffsUnderline) : getChangedNodeStyleLegacy(nodeName, colorScheme, isInserted, isActive, diffType, hideAddedDiffsUnderline);
114
+ export const getChangedNodeStyle = (nodeName, colorScheme, isInserted = false, isActive = false, diffType, hideAddedDiffsUnderline = false) => isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? getChangedNodeStyleNext(nodeName, colorScheme, isInserted, isActive, diffType, hideAddedDiffsUnderline) : getChangedNodeStyleLegacy(nodeName, getLegacyColorScheme(colorScheme), isInserted, isActive, diffType, hideAddedDiffsUnderline);
115
115
 
116
116
  /** The positioned line drawn across deleted content spanning an unbounded range. */
117
- export const getDeletedContentStyleUnbounded = (colorScheme, isActive = false) => isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? getDeletedContentStyleUnboundedNext(colorScheme, isActive) : getDeletedContentStyleUnboundedLegacy(colorScheme, isActive);
117
+ export const getDeletedContentStyleUnbounded = (colorScheme, isActive = false) => isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? getDeletedContentStyleUnboundedNext(colorScheme, isActive) : getDeletedContentStyleUnboundedLegacy(getLegacyColorScheme(colorScheme), isActive);
118
118
 
119
119
  /** Inline style for inserted content. */
120
- export const getInsertedContentStyle = (colorScheme, isActive = false, hideAddedDiffsUnderline = false) => isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? getInsertedContentStyleNext(colorScheme, isActive, hideAddedDiffsUnderline) : getInsertedContentStyleLegacy(colorScheme, isActive, hideAddedDiffsUnderline);
120
+ export const getInsertedContentStyle = (colorScheme, isActive = false, hideAddedDiffsUnderline = false) => isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? getInsertedContentStyleNext(colorScheme, isActive, hideAddedDiffsUnderline) : getInsertedContentStyleLegacy(getLegacyColorScheme(colorScheme), isActive, hideAddedDiffsUnderline);
121
121
 
122
122
  /** Inline style for deleted content. */
123
- export const getDeletedContentStyle = (colorScheme, isActive = false, diffType) => isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? getDeletedContentStyleNext(colorScheme, isActive, diffType) : getDeletedContentStyleLegacy(colorScheme, isActive, diffType);
123
+ export const getDeletedContentStyle = (colorScheme, isActive = false, diffType) => isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? getDeletedContentStyleNext(colorScheme, isActive, diffType) : getDeletedContentStyleLegacy(getLegacyColorScheme(colorScheme), isActive, diffType);
124
124
 
125
125
  /**
126
126
  * Overlay style for one added or deleted table cell. Invariant across the cells of a table, so the
127
127
  * `querySelectorAll('td, th')` loop in `wrapBlockNodeView.ts` resolves it once.
128
128
  */
129
- export const resolveCellOverlayStyle = args => isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? resolveCellOverlayStyleNext(args) : resolveCellOverlayStyleLegacy(args);
129
+ export const resolveCellOverlayStyle = args => isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? resolveCellOverlayStyleNext(args) : resolveCellOverlayStyleLegacy({
130
+ ...args,
131
+ colorScheme: getLegacyColorScheme(args.colorScheme)
132
+ });
130
133
 
131
134
  /** Inner style for the "Removed" lozenge on a deleted block node. */
132
- export const resolveRemovedLozengeStyle = (colorScheme, isActive) => isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? resolveRemovedLozengeStyleNext(colorScheme, isActive) : resolveRemovedLozengeStyleLegacy(colorScheme, isActive);
135
+ export const resolveRemovedLozengeStyle = (colorScheme, isActive) => isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? resolveRemovedLozengeStyleNext(colorScheme, isActive) : resolveRemovedLozengeStyleLegacy(getLegacyColorScheme(colorScheme), isActive);
133
136
 
134
137
  /**
135
138
  * Style for inserted content nested inside a multi-container or list node — the `decisionList` and
@@ -142,7 +145,7 @@ export const resolveNestedInsertedNodeStyle = () => isExperimentEnabled('platfor
142
145
  * Whether the colour scheme draws a resting (non-active) ring on a deleted media/embed node, which
143
146
  * is what the `show-diff-deleted-outline-new` class styles in editor-core's smartCardStyles.
144
147
  */
145
- export const hasRestingDeletedRing = colorScheme => isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? hasRestingDeletedRingNext(colorScheme) : hasRestingDeletedRingLegacy(colorScheme);
148
+ export const hasRestingDeletedRing = colorScheme => isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? hasRestingDeletedRingNext(colorScheme) : hasRestingDeletedRingLegacy(getLegacyColorScheme(colorScheme));
146
149
 
147
150
  /**
148
151
  * Custom properties consumed by the `show-diff-deleted-node-vars` selectors in editor-core.
@@ -27,6 +27,7 @@ export const createPlugin = (config, getIntl, api, onEditorView) => {
27
27
  const defaultDiffType = getDefaultDiffType();
28
28
  return {
29
29
  steps: [],
30
+ stepAttributions: [],
30
31
  originalDoc: undefined,
31
32
  decorations: DecorationSet.empty,
32
33
  isDisplayingChanges: false,