@atlaskit/editor-plugin-show-diff 16.0.1 → 16.0.3

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 (53) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/afm-products/tsconfig.json +3 -0
  3. package/dist/cjs/pm-plugins/calculateDiff/calculateDiffDecorations.js +91 -51
  4. package/dist/cjs/pm-plugins/decorations/createContributorTagWidget.js +20 -1
  5. package/dist/cjs/pm-plugins/decorations/extractContributorTags.js +121 -21
  6. package/dist/cjs/pm-plugins/decorations/utils/getAttrChangeRanges.js +19 -8
  7. package/dist/cjs/pm-plugins/decorations/utils/getMarkChangeRanges.js +18 -4
  8. package/dist/cjs/pm-plugins/decorations/utils/mapStepRangeToFinal.js +34 -0
  9. package/dist/cjs/pm-plugins/main.js +18 -0
  10. package/dist/cjs/ui/ContributorTag/buildContributorTagDom.js +51 -5
  11. package/dist/cjs/ui/ContributorTag/contributorLabel.js +55 -0
  12. package/dist/cjs/ui/ContributorTag/contributorTagController.js +40 -43
  13. package/dist/cjs/ui/ContributorTag/messages.js +5 -0
  14. package/dist/cjs/ui/DiffNavigation/announceActiveDiff.js +54 -0
  15. package/dist/cjs/ui/DiffNavigation/messages.js +19 -0
  16. package/dist/es2019/pm-plugins/calculateDiff/calculateDiffDecorations.js +48 -13
  17. package/dist/es2019/pm-plugins/decorations/createContributorTagWidget.js +18 -1
  18. package/dist/es2019/pm-plugins/decorations/extractContributorTags.js +70 -10
  19. package/dist/es2019/pm-plugins/decorations/utils/getAttrChangeRanges.js +16 -0
  20. package/dist/es2019/pm-plugins/decorations/utils/getMarkChangeRanges.js +12 -4
  21. package/dist/es2019/pm-plugins/decorations/utils/mapStepRangeToFinal.js +28 -0
  22. package/dist/es2019/pm-plugins/main.js +18 -0
  23. package/dist/es2019/ui/ContributorTag/buildContributorTagDom.js +48 -4
  24. package/dist/es2019/ui/ContributorTag/contributorLabel.js +49 -0
  25. package/dist/es2019/ui/ContributorTag/contributorTagController.js +39 -44
  26. package/dist/es2019/ui/ContributorTag/messages.js +5 -0
  27. package/dist/es2019/ui/DiffNavigation/announceActiveDiff.js +49 -0
  28. package/dist/es2019/ui/DiffNavigation/messages.js +13 -0
  29. package/dist/esm/pm-plugins/calculateDiff/calculateDiffDecorations.js +91 -51
  30. package/dist/esm/pm-plugins/decorations/createContributorTagWidget.js +20 -1
  31. package/dist/esm/pm-plugins/decorations/extractContributorTags.js +121 -21
  32. package/dist/esm/pm-plugins/decorations/utils/getAttrChangeRanges.js +19 -8
  33. package/dist/esm/pm-plugins/decorations/utils/getMarkChangeRanges.js +17 -4
  34. package/dist/esm/pm-plugins/decorations/utils/mapStepRangeToFinal.js +28 -0
  35. package/dist/esm/pm-plugins/main.js +18 -0
  36. package/dist/esm/ui/ContributorTag/buildContributorTagDom.js +50 -4
  37. package/dist/esm/ui/ContributorTag/contributorLabel.js +49 -0
  38. package/dist/esm/ui/ContributorTag/contributorTagController.js +41 -44
  39. package/dist/esm/ui/ContributorTag/messages.js +5 -0
  40. package/dist/esm/ui/DiffNavigation/announceActiveDiff.js +48 -0
  41. package/dist/esm/ui/DiffNavigation/messages.js +13 -0
  42. package/dist/types/pm-plugins/decorations/extractContributorTags.d.ts +14 -1
  43. package/dist/types/pm-plugins/decorations/utils/getAttrChangeRanges.d.ts +3 -0
  44. package/dist/types/pm-plugins/decorations/utils/getMarkChangeRanges.d.ts +4 -1
  45. package/dist/types/pm-plugins/decorations/utils/mapStepRangeToFinal.d.ts +8 -0
  46. package/dist/types/showDiffPluginType.d.ts +7 -1
  47. package/dist/types/ui/ContributorTag/buildContributorTagDom.d.ts +12 -2
  48. package/dist/types/ui/ContributorTag/contributorLabel.d.ts +13 -0
  49. package/dist/types/ui/ContributorTag/contributorTagController.d.ts +11 -0
  50. package/dist/types/ui/ContributorTag/messages.d.ts +1 -0
  51. package/dist/types/ui/DiffNavigation/announceActiveDiff.d.ts +18 -0
  52. package/dist/types/ui/DiffNavigation/messages.d.ts +5 -0
  53. package/package.json +5 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,50 @@
1
1
  # @atlaskit/editor-plugin-show-diff
2
2
 
3
+ ## 16.0.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [`0265ca1688db1`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/0265ca1688db1) -
8
+ [EDITOR-8971] `VanillaTooltip` takes an optional container to append its tooltip to, instead of
9
+ appending it inside the trigger. Opt-in per caller, and used by the diff contributor tag; every
10
+ other tooltip is unchanged.
11
+
12
+ Diff contributor tag fixes, all behind `confluence_ncs_step_diffing_version_history`:
13
+ - The tag's full label no longer renders off screen. Its tooltip is hoisted out of the tag, so
14
+ Popper and the browser measure a top-layer popover from the same origin — inside the trigger
15
+ they disagreed whenever an ancestor was transformed, such as a wide image.
16
+ - Stepping to a change reveals only that change's tag, not every tag the active range touches.
17
+ - A contributor no longer gets two tags inside one navigation stop. Two of their changes that
18
+ merely touched each kept a tag, and the trailing one could be hovered but never stepped to; it
19
+ now folds into the leading tag and stays a hover target. Tags for different contributors sharing
20
+ a stop are still kept apart.
21
+ - A tag on deleted content no longer disappears when the document changes. Any change remaps the
22
+ decoration, which rebuilds its widget and fired the teardown — but the deleted-content widget's
23
+ DOM is reused as-is and runs no mount callback, so the tag was faded out of a change that was
24
+ still the active one. The tag is now kept whenever its host is still in a live editor.
25
+
26
+ - Updated dependencies
27
+
28
+ ## 16.0.2
29
+
30
+ ### Patch Changes
31
+
32
+ - [`44acf8971ef0e`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/44acf8971ef0e) -
33
+ Preserve contributor attribution for attribute-only diff decorations so they use the correct
34
+ colour and contributor tags.
35
+ - [`683c1a024bcb3`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/683c1a024bcb3) -
36
+ Improve the accessibility of contributor diff tags, behind the
37
+ `confluence_ncs_step_diffing_version_history` gate. A tag now announces its contributor once
38
+ rather than three times over, names itself through `aria-labelledby` so it is no longer a focus
39
+ stop without an accessible name, says in its label when the contributor is an AI agent, and draws
40
+ an inset focus ring that reads against every accent fill.
41
+
42
+ Stepping to the next or previous change now announces the reader's position in the diff and who
43
+ made the change, through the editor's shared live region. Behind the
44
+ `platform_editor_diff_plugin_extended` experiment.
45
+
46
+ - Updated dependencies
47
+
3
48
  ## 16.0.1
4
49
 
5
50
  ### Patch Changes
@@ -26,6 +26,9 @@
26
26
  {
27
27
  "path": "../../custom-steps/afm-products/tsconfig.json"
28
28
  },
29
+ {
30
+ "path": "../../editor-plugin-accessibility-utils/afm-products/tsconfig.json"
31
+ },
29
32
  {
30
33
  "path": "../../editor-plugin-analytics/afm-products/tsconfig.json"
31
34
  },
@@ -27,6 +27,7 @@ var _decorationKeys = require("../decorations/decorationKeys");
27
27
  var _extractContributorTags = require("../decorations/extractContributorTags");
28
28
  var _getAttrChangeRanges = require("../decorations/utils/getAttrChangeRanges");
29
29
  var _getMarkChangeRanges = require("../decorations/utils/getMarkChangeRanges");
30
+ var _getScrollableDecorations = require("../getScrollableDecorations");
30
31
  var _isExtendedEnabled = require("../isExtendedEnabled");
31
32
  var _diffBySteps = require("./diffBySteps");
32
33
  var _groupChangesByBlock = require("./groupChangesByBlock");
@@ -344,15 +345,18 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref8
344
345
  }
345
346
  var pendingAttrSteps = [];
346
347
  var stepMaps = [];
347
- var _iterator = _createForOfIteratorHelper(simplifiedSteps),
348
+ var _iterator = _createForOfIteratorHelper(simplifiedSteps.entries()),
348
349
  _step;
349
350
  try {
350
351
  for (_iterator.s(); !(_step = _iterator.n()).done;) {
351
- var step = _step.value;
352
+ var _step$value = (0, _slicedToArray2.default)(_step.value, 2),
353
+ stepIndex = _step$value[0],
354
+ step = _step$value[1];
352
355
  var result = step.apply(steppedDoc);
353
356
  if (result.failed === null && result.doc) {
354
357
  if ((0, _getAttrChangeRanges.stepIsValidAttrChange)(step, steppedDoc, result.doc)) {
355
358
  pendingAttrSteps.push({
359
+ attributionKey: (0, _attributions.getAttributionKey)(simplifiedStepAttributions[stepIndex]),
356
360
  afterNode: result.doc.nodeAt(step.pos),
357
361
  beforeNode: steppedDoc.nodeAt(step.pos),
358
362
  mapIndex: stepMaps.length,
@@ -372,6 +376,7 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref8
372
376
  }
373
377
  var attrStepContexts = (0, _fg.fg)('platform_editor_reduce_diff_attr_sensitivity') ? pendingAttrSteps.flatMap(function (_ref1) {
374
378
  var afterNode = _ref1.afterNode,
379
+ attributionKey = _ref1.attributionKey,
375
380
  beforeNode = _ref1.beforeNode,
376
381
  mapIndex = _ref1.mapIndex,
377
382
  step = _ref1.step;
@@ -381,6 +386,7 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref8
381
386
  }
382
387
  var originalPosition = new _transform.Mapping(stepMaps.slice(0, mapIndex)).invert().mapResult(step.pos);
383
388
  return [_objectSpread(_objectSpread({
389
+ attributionKey: attributionKey,
384
390
  afterNode: afterNode,
385
391
  beforeNode: beforeNode,
386
392
  finalPos: finalPosition.pos
@@ -390,8 +396,10 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref8
390
396
  step: step
391
397
  })];
392
398
  }) : pendingAttrSteps.map(function (_ref10) {
393
- var step = _ref10.step;
399
+ var attributionKey = _ref10.attributionKey,
400
+ step = _ref10.step;
394
401
  return {
402
+ attributionKey: attributionKey,
395
403
  afterNode: tr.doc.nodeAt(step.pos),
396
404
  beforeNode: originalDoc.nodeAt(step.pos),
397
405
  finalPos: step.pos,
@@ -656,34 +664,54 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref8
656
664
  // smart path. Only add the legacy step-range decoration when no equivalent changeset range was
657
665
  // produced; otherwise the same content receives two inline decorations (and two navigation
658
666
  // changes), usually one attribution colour and one default purple decoration.
659
- (0, _getMarkChangeRanges.getMarkChangeRanges)(steps).filter(function (_ref11) {
667
+ (0, _getMarkChangeRanges.getMarkChangeRanges)(simplifiedSteps, simplifiedStepAttributions, (0, _fg.fg)('confluence_ncs_step_diffing_version_history') ? stepMaps : undefined).filter(function (_ref11) {
660
668
  var fromB = _ref11.fromB,
661
669
  toB = _ref11.toB;
662
670
  return !(0, _fg.fg)('confluence_ncs_step_diffing_version_history') || !changes.some(function (change) {
663
671
  return change.fromB === fromB && change.toB === toB;
664
672
  });
665
673
  }).forEach(function (change) {
674
+ var _attributionColors$ge, _attributionColors;
675
+ var changeColorScheme = change.attributionKey ? (_attributionColors$ge = (_attributionColors = attributionColors) === null || _attributionColors === void 0 ? void 0 : _attributionColors.get(change.attributionKey)) !== null && _attributionColors$ge !== void 0 ? _attributionColors$ge : colorScheme : colorScheme;
676
+ var attributionKey = showContributorTags ? change.attributionKey : undefined;
666
677
  var isActive = isRangeActive(activeIndexPos, change.fromB, change.toB);
667
678
  decorations.push.apply(decorations, (0, _toConsumableArray2.default)((0, _createInlineChangedDecoration.createInlineChangedDecoration)({
679
+ attributionKey: attributionKey,
668
680
  change: change,
669
- colorScheme: colorScheme,
681
+ colorScheme: changeColorScheme,
682
+ doc: tr.doc,
670
683
  diffType: diffType,
671
684
  isActive: isActive,
672
685
  isInserted: true,
673
- reveal: reveal
686
+ reveal: reveal,
687
+ showContributorTags: showContributorTags,
688
+ tagMountContext: tagMountContext
674
689
  })));
675
690
  });
676
- (0, _getAttrChangeRanges.getAttrChangeRanges)(tr.doc, attrStepContexts, originalDoc).forEach(function (change) {
691
+ (0, _getAttrChangeRanges.getAttrChangeRanges)(tr.doc, attrStepContexts, originalDoc).filter(function (_ref12) {
692
+ var fromB = _ref12.fromB,
693
+ toB = _ref12.toB;
694
+ return !(0, _fg.fg)('confluence_ncs_step_diffing_version_history') || !changes.some(function (change) {
695
+ return change.fromB === fromB && change.toB === toB;
696
+ });
697
+ }).forEach(function (change) {
698
+ var _attributionColors$ge2, _attributionColors2;
699
+ var changeColorScheme = change.attributionKey ? (_attributionColors$ge2 = (_attributionColors2 = attributionColors) === null || _attributionColors2 === void 0 ? void 0 : _attributionColors2.get(change.attributionKey)) !== null && _attributionColors$ge2 !== void 0 ? _attributionColors$ge2 : colorScheme : colorScheme;
700
+ var attributionKey = showContributorTags ? change.attributionKey : undefined;
677
701
  if (change.isInline) {
678
702
  // Inline nodes (e.g. date, emoji, mention, status) need an inline decoration rather than a block decoration
679
703
  var isActive = isRangeActive(activeIndexPos, change.fromB, change.toB);
680
704
  decorations.push.apply(decorations, (0, _toConsumableArray2.default)((0, _createInlineChangedDecoration.createInlineChangedDecoration)({
705
+ attributionKey: attributionKey,
681
706
  change: change,
682
- colorScheme: colorScheme,
707
+ colorScheme: changeColorScheme,
708
+ doc: tr.doc,
683
709
  isActive: isActive,
684
710
  isInserted: true,
685
711
  isAtomicInlineNode: true,
686
712
  inlineNodeName: change.inlineNodeName,
713
+ showContributorTags: showContributorTags,
714
+ tagMountContext: tagMountContext,
687
715
  // Suppress the border-bottom underline for atomic inline nodeviews —
688
716
  // it doesn't render on custom nodeview DOM elements and is unnecessary noise.
689
717
  hideAddedDiffsUnderline: true,
@@ -701,12 +729,15 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref8
701
729
  deleted: []
702
730
  },
703
731
  doc: originalDoc,
732
+ attributionKey: attributionKey,
704
733
  nodeViewSerializer: nodeViewSerializer,
705
- colorScheme: colorScheme,
734
+ colorScheme: changeColorScheme,
706
735
  newDoc: tr.doc,
707
736
  intl: intl,
708
737
  activeIndexPos: activeIndexPos,
709
- isInserted: false
738
+ isInserted: false,
739
+ showContributorTags: showContributorTags,
740
+ tagMountContext: tagMountContext
710
741
  })));
711
742
  }
712
743
  } else {
@@ -714,11 +745,14 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref8
714
745
  doc: tr.doc,
715
746
  from: change.fromB,
716
747
  to: change.toB,
717
- colorScheme: colorScheme,
748
+ attributionKey: attributionKey,
749
+ colorScheme: changeColorScheme,
718
750
  isInserted: true,
719
751
  activeIndexPos: activeIndexPos,
720
752
  intl: intl,
721
- showIndicators: showIndicators
753
+ showContributorTags: showContributorTags,
754
+ showIndicators: showIndicators,
755
+ tagMountContext: tagMountContext
722
756
  })));
723
757
  // If the original node position is known (e.g. a panel type change), also render
724
758
  // the old block node as a "deleted" widget so the reviewer sees the before/after.
@@ -735,7 +769,8 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref8
735
769
  },
736
770
  doc: originalDoc,
737
771
  nodeViewSerializer: nodeViewSerializer,
738
- colorScheme: colorScheme,
772
+ attributionKey: attributionKey,
773
+ colorScheme: changeColorScheme,
739
774
  newDoc: tr.doc,
740
775
  intl: intl,
741
776
  activeIndexPos: activeIndexPos,
@@ -745,14 +780,19 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref8
745
780
  hideAddedDiffsUnderline: hideAddedDiffsUnderline,
746
781
  placeBelow: placeBelow
747
782
  }), {}, {
748
- showIndicators: showIndicators
783
+ showIndicators: showIndicators,
784
+ showContributorTags: showContributorTags,
785
+ tagMountContext: tagMountContext
749
786
  }))));
750
787
  }
751
788
  }
752
789
  });
753
790
  var decorationSet = _view.DecorationSet.empty.add(tr.doc, decorations);
754
791
  return {
755
- contributorTags: showContributorTags ? (0, _extractContributorTags.extractContributorTags)(decorationSet, contributors) : [],
792
+ contributorTags: showContributorTags ? (0, _extractContributorTags.extractContributorTags)(decorationSet, contributors, activeIndexPos,
793
+ // The stops the step buttons walk, so a stop cannot hold a second tag for one
794
+ // contributor that navigation can never reach.
795
+ (0, _getScrollableDecorations.getScrollableDecorations)(decorationSet, tr.doc, diffType)) : [],
756
796
  decorations: decorationSet,
757
797
  diffDescriptors: (0, _decorationKeys.extractDiffDescriptors)(decorationSet)
758
798
  };
@@ -760,49 +800,49 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref8
760
800
  var calculateDiffDecorations = exports.calculateDiffDecorations = (0, _memoizeOne.default)(calculateDiffDecorationsInner,
761
801
  // Cache results unless relevant inputs change. `tagMountContext` is deliberately absent: it is
762
802
  // built once per plugin instance, so it can never be the reason a diff needs recalculating.
763
- function (_ref12, _ref13) {
764
- var _ref17;
765
- var _ref14 = (0, _slicedToArray2.default)(_ref12, 1),
766
- _ref14$ = _ref14[0],
767
- pluginState = _ref14$.pluginState,
768
- state = _ref14$.state,
769
- colorScheme = _ref14$.colorScheme,
770
- intl = _ref14$.intl,
771
- activeIndexPos = _ref14$.activeIndexPos,
772
- isInverted = _ref14$.isInverted,
773
- diffType = _ref14$.diffType,
774
- hideDeletedDiffs = _ref14$.hideDeletedDiffs,
775
- hideAddedDiffsUnderline = _ref14$.hideAddedDiffsUnderline,
776
- showIndicators = _ref14$.showIndicators,
777
- smartThresholds = _ref14$.smartThresholds,
778
- deletedDiffPlacement = _ref14$.deletedDiffPlacement,
779
- inlineDeletedDiffPlacement = _ref14$.inlineDeletedDiffPlacement,
780
- reveal = _ref14$.reveal;
803
+ function (_ref13, _ref14) {
804
+ var _ref18;
781
805
  var _ref15 = (0, _slicedToArray2.default)(_ref13, 1),
782
806
  _ref15$ = _ref15[0],
783
- lastPluginState = _ref15$.pluginState,
784
- lastState = _ref15$.state,
785
- lastColorScheme = _ref15$.colorScheme,
786
- lastIntl = _ref15$.intl,
787
- lastActiveIndexPos = _ref15$.activeIndexPos,
788
- lastIsInverted = _ref15$.isInverted,
789
- lastDiffType = _ref15$.diffType,
790
- lastHideDeletedDiffs = _ref15$.hideDeletedDiffs,
791
- lastHideAddedDiffsUnderline = _ref15$.hideAddedDiffsUnderline,
792
- lastShowIndicators = _ref15$.showIndicators,
793
- lastSmartThresholds = _ref15$.smartThresholds,
794
- lastDeletedDiffPlacement = _ref15$.deletedDiffPlacement,
795
- lastInlineDeletedDiffPlacement = _ref15$.inlineDeletedDiffPlacement,
796
- lastReveal = _ref15$.reveal;
807
+ pluginState = _ref15$.pluginState,
808
+ state = _ref15$.state,
809
+ colorScheme = _ref15$.colorScheme,
810
+ intl = _ref15$.intl,
811
+ activeIndexPos = _ref15$.activeIndexPos,
812
+ isInverted = _ref15$.isInverted,
813
+ diffType = _ref15$.diffType,
814
+ hideDeletedDiffs = _ref15$.hideDeletedDiffs,
815
+ hideAddedDiffsUnderline = _ref15$.hideAddedDiffsUnderline,
816
+ showIndicators = _ref15$.showIndicators,
817
+ smartThresholds = _ref15$.smartThresholds,
818
+ deletedDiffPlacement = _ref15$.deletedDiffPlacement,
819
+ inlineDeletedDiffPlacement = _ref15$.inlineDeletedDiffPlacement,
820
+ reveal = _ref15$.reveal;
821
+ var _ref16 = (0, _slicedToArray2.default)(_ref14, 1),
822
+ _ref16$ = _ref16[0],
823
+ lastPluginState = _ref16$.pluginState,
824
+ lastState = _ref16$.state,
825
+ lastColorScheme = _ref16$.colorScheme,
826
+ lastIntl = _ref16$.intl,
827
+ lastActiveIndexPos = _ref16$.activeIndexPos,
828
+ lastIsInverted = _ref16$.isInverted,
829
+ lastDiffType = _ref16$.diffType,
830
+ lastHideDeletedDiffs = _ref16$.hideDeletedDiffs,
831
+ lastHideAddedDiffsUnderline = _ref16$.hideAddedDiffsUnderline,
832
+ lastShowIndicators = _ref16$.showIndicators,
833
+ lastSmartThresholds = _ref16$.smartThresholds,
834
+ lastDeletedDiffPlacement = _ref16$.deletedDiffPlacement,
835
+ lastInlineDeletedDiffPlacement = _ref16$.inlineDeletedDiffPlacement,
836
+ lastReveal = _ref16$.reveal;
797
837
  var originalDocIsSame = lastPluginState.originalDoc && pluginState.originalDoc && pluginState.originalDoc.eq(lastPluginState.originalDoc);
798
838
  if ((0, _isExtendedEnabled.isExtendedEnabled)(diffType)) {
799
- var _ref16;
800
- return (_ref16 = colorScheme === lastColorScheme && intl.locale === lastIntl.locale && isInverted === lastIsInverted && diffType === lastDiffType && (0, _isEqual.default)(activeIndexPos, lastActiveIndexPos) && originalDocIsSame && (0, _isEqual.default)(pluginState.steps, lastPluginState.steps) && (0, _isEqual.default)(pluginState.stepAttributions, lastPluginState.stepAttributions) &&
839
+ var _ref17;
840
+ return (_ref17 = colorScheme === lastColorScheme && intl.locale === lastIntl.locale && isInverted === lastIsInverted && diffType === lastDiffType && (0, _isEqual.default)(activeIndexPos, lastActiveIndexPos) && originalDocIsSame && (0, _isEqual.default)(pluginState.steps, lastPluginState.steps) && (0, _isEqual.default)(pluginState.stepAttributions, lastPluginState.stepAttributions) &&
801
841
  // Contributors can arrive after the first calculation; without this, tags never appear.
802
842
  (0, _isEqual.default)(pluginState.contributors, lastPluginState.contributors) && state.doc.eq(lastState.doc) && hideDeletedDiffs === lastHideDeletedDiffs && hideAddedDiffsUnderline === lastHideAddedDiffsUnderline && showIndicators === lastShowIndicators && (0, _isEqual.default)(smartThresholds, lastSmartThresholds) && deletedDiffPlacement === lastDeletedDiffPlacement && inlineDeletedDiffPlacement === lastInlineDeletedDiffPlacement &&
803
843
  // Turning the reveal on or off changes the emitted styles, so a cached result from the
804
844
  // other setting would leave the diff painted in the wrong resting state.
805
- (0, _isEqual.default)(reveal, lastReveal)) !== null && _ref16 !== void 0 ? _ref16 : false;
845
+ (0, _isEqual.default)(reveal, lastReveal)) !== null && _ref17 !== void 0 ? _ref17 : false;
806
846
  }
807
- return (_ref17 = originalDocIsSame && (0, _isEqual.default)(pluginState.steps, lastPluginState.steps) && (0, _isEqual.default)(pluginState.stepAttributions, lastPluginState.stepAttributions) && (0, _isEqual.default)(pluginState.contributors, lastPluginState.contributors) && state.doc.eq(lastState.doc) && colorScheme === lastColorScheme && intl.locale === lastIntl.locale && (0, _isEqual.default)(activeIndexPos, lastActiveIndexPos) && hideDeletedDiffs === lastHideDeletedDiffs) !== null && _ref17 !== void 0 ? _ref17 : false;
847
+ return (_ref18 = originalDocIsSame && (0, _isEqual.default)(pluginState.steps, lastPluginState.steps) && (0, _isEqual.default)(pluginState.stepAttributions, lastPluginState.stepAttributions) && (0, _isEqual.default)(pluginState.contributors, lastPluginState.contributors) && state.doc.eq(lastState.doc) && colorScheme === lastColorScheme && intl.locale === lastIntl.locale && (0, _isEqual.default)(activeIndexPos, lastActiveIndexPos) && hideDeletedDiffs === lastHideDeletedDiffs) !== null && _ref18 !== void 0 ? _ref18 : false;
808
848
  });
@@ -48,7 +48,26 @@ var mountContributorTag = exports.mountContributorTag = function mountContributo
48
48
  diffId: diffId
49
49
  }));
50
50
  controller.mount(host);
51
- return controller;
51
+
52
+ /**
53
+ * Kept alive when ProseMirror only rebuilt the widget desc around this same host: a document
54
+ * change remaps the decoration and fires `destroy`, but an element `toDOM` is reused verbatim
55
+ * and runs no mount callback, so tearing down here left an active change with no tag
56
+ * (EDITOR-8971).
57
+ *
58
+ * Deferred, because the host is still attached while that update is in flight. A host outside a
59
+ * live editor root is a real removal — including the view being destroyed, which drops the root.
60
+ */
61
+ return {
62
+ destroy: function destroy() {
63
+ return queueMicrotask(function () {
64
+ var _mountContext$getEdit;
65
+ if (!host.isConnected || !((_mountContext$getEdit = mountContext.getEditorRoot()) !== null && _mountContext$getEdit !== void 0 && _mountContext$getEdit.contains(host))) {
66
+ controller.destroy();
67
+ }
68
+ });
69
+ }
70
+ };
52
71
  };
53
72
  var unmountContributorTag = exports.unmountContributorTag = function unmountContributorTag(mount) {
54
73
  mount === null || mount === void 0 || mount.destroy();
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
7
  exports.extractContributorTags = void 0;
8
+ var _toArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toArray"));
8
9
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
10
  var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
10
11
  var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
@@ -56,12 +57,48 @@ var isSameBlockChange = function isSameBlockChange(inner, block) {
56
57
  return inner.spec.attributionKey === block.spec.attributionKey && (block.from <= inner.from && inner.to <= block.to || inner.from <= block.from && block.to <= inner.to);
57
58
  };
58
59
 
60
+ /**
61
+ * Which of two changes in the same range leads, and so is the one a tag captions. Position first,
62
+ * then `side`, since deleted content shares its `from` with the content that replaced it and paints
63
+ * above; then the narrower range, so a change nested in another captions itself.
64
+ */
65
+ var byLeadingPosition = function byLeadingPosition(a, b) {
66
+ var _a$decoration$spec$si, _b$decoration$spec$si;
67
+ return a.decoration.from - b.decoration.from || ((_a$decoration$spec$si = a.decoration.spec.side) !== null && _a$decoration$spec$si !== void 0 ? _a$decoration$spec$si : 0) - ((_b$decoration$spec$si = b.decoration.spec.side) !== null && _b$decoration$spec$si !== void 0 ? _b$decoration$spec$si : 0) || a.decoration.to - a.decoration.from - (b.decoration.to - b.decoration.from);
68
+ };
69
+
70
+ /** The targets a navigation range wholly covers, leader first. */
71
+ var containedBy = function containedBy(targets, _ref2) {
72
+ var from = _ref2.from,
73
+ to = _ref2.to;
74
+ return targets.filter(function (_ref3) {
75
+ var decoration = _ref3.decoration;
76
+ return from <= decoration.from && decoration.to <= to;
77
+ }).sort(byLeadingPosition);
78
+ };
79
+
80
+ /**
81
+ * The one tag a navigation step reveals. `spec.isActive` is no use here: it covers everything the
82
+ * group's union range touches, so several tags revealed over each other (EDITOR-8971). Hence
83
+ * containment, and the leading change of what it covers.
84
+ */
85
+ var resolveActiveTarget = function resolveActiveTarget(surviving, activeIndexPos) {
86
+ return containedBy(surviving, activeIndexPos)[0];
87
+ };
88
+
59
89
  /**
60
90
  * One model per diff decoration whose attribution resolves to a supplied contributor; anything
61
91
  * unattributed, untaggable or unresolved is skipped. A replacement's two decorations are collapsed
62
92
  * into a single tag, on whichever half renders first — see `isSameChange` and `leadsReplacement`.
93
+ *
94
+ * `activeIndexPos`, when given, reveals exactly one of the tags — see `resolveActiveTarget`.
95
+ * Absent, each tag keeps the active state its own decoration was drawn with.
96
+ *
97
+ * `stops`, when given, is the navigation stop list the step buttons walk
98
+ * (`getScrollableDecorations`). One contributor cannot hold two tags in one stop, since only the
99
+ * leading one would ever be reachable. Absent, every decoration keeps its own tag.
63
100
  */
64
- var extractContributorTags = exports.extractContributorTags = function extractContributorTags(decorations, contributors) {
101
+ var extractContributorTags = exports.extractContributorTags = function extractContributorTags(decorations, contributors, activeIndexPos, stops) {
65
102
  if (!contributors) {
66
103
  return [];
67
104
  }
@@ -94,25 +131,30 @@ var extractContributorTags = exports.extractContributorTags = function extractCo
94
131
  } finally {
95
132
  _iterator.f();
96
133
  }
97
- var inlineTargets = targets.filter(function (_ref2) {
98
- var decoration = _ref2.decoration;
134
+ var inlineTargets = targets.filter(function (_ref4) {
135
+ var decoration = _ref4.decoration;
99
136
  return decoration.spec.decorationType === 'inline';
100
137
  });
101
- var blockTargets = targets.filter(function (_ref3) {
102
- var decoration = _ref3.decoration;
138
+ var blockTargets = targets.filter(function (_ref5) {
139
+ var decoration = _ref5.decoration;
103
140
  return decoration.spec.decorationType === 'block';
104
141
  });
105
- var widgetTargets = targets.filter(function (_ref4) {
106
- var decoration = _ref4.decoration;
142
+ var widgetTargets = targets.filter(function (_ref6) {
143
+ var decoration = _ref6.decoration;
107
144
  return decoration.spec.decorationType === 'widget';
108
145
  });
109
146
  var linkedDiffIds = new Map();
110
147
  var folded = new Set();
111
148
  var fold = function fold(host, target) {
112
- var _linkedDiffIds$get;
149
+ var _linkedDiffIds$get, _linkedDiffIds$get2;
113
150
  folded.add(target);
114
151
  var hostDiffId = host.decoration.spec.diffId;
115
- linkedDiffIds.set(hostDiffId, [].concat((0, _toConsumableArray2.default)((_linkedDiffIds$get = linkedDiffIds.get(hostDiffId)) !== null && _linkedDiffIds$get !== void 0 ? _linkedDiffIds$get : []), [target.decoration.spec.diffId]));
152
+ var targetDiffId = target.decoration.spec.diffId;
153
+ // A target that already hosts folded tags hands them up, so no hover target is orphaned when
154
+ // one host folds into another.
155
+ var inherited = (_linkedDiffIds$get = linkedDiffIds.get(targetDiffId)) !== null && _linkedDiffIds$get !== void 0 ? _linkedDiffIds$get : [];
156
+ linkedDiffIds.delete(targetDiffId);
157
+ linkedDiffIds.set(hostDiffId, [].concat((0, _toConsumableArray2.default)((_linkedDiffIds$get2 = linkedDiffIds.get(hostDiffId)) !== null && _linkedDiffIds$get2 !== void 0 ? _linkedDiffIds$get2 : []), [targetDiffId], (0, _toConsumableArray2.default)(inherited)));
116
158
  };
117
159
  var _loop = function _loop() {
118
160
  var target = _targets[_i];
@@ -122,8 +164,8 @@ var extractContributorTags = exports.extractContributorTags = function extractCo
122
164
  }
123
165
 
124
166
  // A block outranks both other kinds, so it is tried first.
125
- var block = blockTargets.find(function (_ref5) {
126
- var decoration = _ref5.decoration;
167
+ var block = blockTargets.find(function (_ref7) {
168
+ var decoration = _ref7.decoration;
127
169
  return isSameBlockChange(target.decoration, decoration);
128
170
  });
129
171
  if (block) {
@@ -132,8 +174,8 @@ var extractContributorTags = exports.extractContributorTags = function extractCo
132
174
  }
133
175
  if (decorationType === 'inline') {
134
176
  // The deleted half renders in front of this one, so that half captions the change.
135
- var leadingWidget = widgetTargets.find(function (_ref6) {
136
- var decoration = _ref6.decoration;
177
+ var leadingWidget = widgetTargets.find(function (_ref8) {
178
+ var decoration = _ref8.decoration;
137
179
  return leadsReplacement(decoration) && isSameChange(decoration, target.decoration);
138
180
  });
139
181
  if (leadingWidget) {
@@ -146,8 +188,8 @@ var extractContributorTags = exports.extractContributorTags = function extractCo
146
188
  if (leadsReplacement(target.decoration)) {
147
189
  return 0; // continue
148
190
  }
149
- var host = inlineTargets.find(function (_ref7) {
150
- var decoration = _ref7.decoration;
191
+ var host = inlineTargets.find(function (_ref9) {
192
+ var decoration = _ref9.decoration;
151
193
  return isSameChange(target.decoration, decoration);
152
194
  });
153
195
  if (host) {
@@ -159,14 +201,72 @@ var extractContributorTags = exports.extractContributorTags = function extractCo
159
201
  _ret = _loop();
160
202
  if (_ret === 0) continue;
161
203
  }
162
- return targets.filter(function (target) {
204
+
205
+ // One tag per contributor per navigation stop. The folds above only catch a replacement's two
206
+ // halves and a block's own highlights; two of one contributor's changes that merely touch are a
207
+ // single stop (`groupTouchingDecorations`) yet kept a tag each, so the stop's trailing tag was
208
+ // drawn but could never be stepped to (EDITOR-8971). It folds into the leading tag of its
209
+ // contributor, staying a hover target. Contributors are kept apart: a stop spanning two of them
210
+ // still captions each, rather than crediting one for the other's change.
211
+ var _iterator2 = _createForOfIteratorHelper(stops !== null && stops !== void 0 ? stops : []),
212
+ _step2;
213
+ try {
214
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
215
+ var stop = _step2.value;
216
+ var byContributor = new Map();
217
+ var _iterator3 = _createForOfIteratorHelper(containedBy(targets.filter(function (target) {
218
+ return !folded.has(target);
219
+ }), stop)),
220
+ _step3;
221
+ try {
222
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
223
+ var _target$decoration$sp, _byContributor$get;
224
+ var target = _step3.value;
225
+ var key = (_target$decoration$sp = target.decoration.spec.attributionKey) !== null && _target$decoration$sp !== void 0 ? _target$decoration$sp : '';
226
+ byContributor.set(key, [].concat((0, _toConsumableArray2.default)((_byContributor$get = byContributor.get(key)) !== null && _byContributor$get !== void 0 ? _byContributor$get : []), [target]));
227
+ }
228
+ } catch (err) {
229
+ _iterator3.e(err);
230
+ } finally {
231
+ _iterator3.f();
232
+ }
233
+ var _iterator4 = _createForOfIteratorHelper(byContributor.values()),
234
+ _step4;
235
+ try {
236
+ var _loop2 = function _loop2() {
237
+ var _step4$value = (0, _toArray2.default)(_step4.value),
238
+ leader = _step4$value[0],
239
+ trailing = _arrayLikeToArray(_step4$value).slice(1);
240
+ trailing.forEach(function (target) {
241
+ return fold(leader, target);
242
+ });
243
+ };
244
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
245
+ _loop2();
246
+ }
247
+ } catch (err) {
248
+ _iterator4.e(err);
249
+ } finally {
250
+ _iterator4.f();
251
+ }
252
+ }
253
+ } catch (err) {
254
+ _iterator2.e(err);
255
+ } finally {
256
+ _iterator2.f();
257
+ }
258
+ var surviving = targets.filter(function (target) {
163
259
  return !folded.has(target);
164
- }).map(function (_ref8) {
165
- var contributor = _ref8.contributor,
166
- spec = _ref8.decoration.spec;
260
+ });
261
+ var activeTarget = activeIndexPos === undefined ? undefined : resolveActiveTarget(surviving, activeIndexPos);
262
+ return surviving.map(function (target) {
263
+ var contributor = target.contributor,
264
+ spec = target.decoration.spec;
167
265
  var connected = contributor.connectedToKey ? contributors[contributor.connectedToKey] : undefined;
168
266
  var connectedContributor = connected ? toTagContributor(connected) : undefined;
169
267
  var linked = linkedDiffIds.get(spec.diffId);
268
+ // Only the navigated tag reveals; with no active range, the decoration's own state stands.
269
+ var isActive = activeIndexPos === undefined ? spec.isActive : target === activeTarget;
170
270
  return _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
171
271
  contributor: toTagContributor(contributor),
172
272
  diffId: spec.diffId
@@ -174,8 +274,8 @@ var extractContributorTags = exports.extractContributorTags = function extractCo
174
274
  connectedContributor: connectedContributor
175
275
  } : {}), spec.colorScheme ? {
176
276
  colorScheme: spec.colorScheme
177
- } : {}), spec.isActive !== undefined ? {
178
- isActive: spec.isActive
277
+ } : {}), isActive !== undefined ? {
278
+ isActive: isActive
179
279
  } : {}), spec.isInserted !== undefined ? {
180
280
  isInserted: spec.isInserted
181
281
  } : {}), linked ? {
@@ -66,6 +66,7 @@ var getStepAttrs = function getStepAttrs(step) {
66
66
  var getAttrChangeRanges = exports.getAttrChangeRanges = function getAttrChangeRanges(doc, attrStepContexts, originalDoc) {
67
67
  return attrStepContexts.map(function (attrStepContext) {
68
68
  var afterNode = attrStepContext.afterNode,
69
+ attributionKey = attrStepContext.attributionKey,
69
70
  beforeNode = attrStepContext.beforeNode,
70
71
  finalPos = attrStepContext.finalPos,
71
72
  originalPos = attrStepContext.originalPos,
@@ -93,7 +94,9 @@ var getAttrChangeRanges = exports.getAttrChangeRanges = function getAttrChangeRa
93
94
  if (attrsToCheck.some(function (v) {
94
95
  return watchedAttrs.includes(v);
95
96
  })) {
96
- return _objectSpread({
97
+ return _objectSpread(_objectSpread({}, attributionKey ? {
98
+ attributionKey: attributionKey
99
+ } : {}), {}, {
97
100
  fromB: finalPos,
98
101
  toB: finalPos + nodeAtPos.nodeSize,
99
102
  isInline: true,
@@ -110,10 +113,12 @@ var getAttrChangeRanges = exports.getAttrChangeRanges = function getAttrChangeRa
110
113
  if (attrsToCheck.some(function (v) {
111
114
  return taskItemAttrs.includes(v);
112
115
  }) && (nodeAtPos === null || nodeAtPos === void 0 ? void 0 : nodeAtPos.type.name) === 'taskItem') {
113
- return {
116
+ return _objectSpread(_objectSpread({}, attributionKey ? {
117
+ attributionKey: attributionKey
118
+ } : {}), {}, {
114
119
  fromB: finalPos,
115
120
  toB: finalPos + nodeAtPos.nodeSize
116
- };
121
+ });
117
122
  }
118
123
 
119
124
  // panel node (incl. variants like panel_c1): type/colour/icon attribute change
@@ -123,7 +128,9 @@ var getAttrChangeRanges = exports.getAttrChangeRanges = function getAttrChangeRa
123
128
  if (attrsToCheck.some(function (v) {
124
129
  return panelAttrs.includes(v);
125
130
  }) && nodeAtPos && (0, _nodeTypeUtils.getBaseNodeTypeName)(nodeAtPos.type) === 'panel') {
126
- return _objectSpread({
131
+ return _objectSpread(_objectSpread({}, attributionKey ? {
132
+ attributionKey: attributionKey
133
+ } : {}), {}, {
127
134
  fromB: finalPos,
128
135
  toB: finalPos + nodeAtPos.nodeSize
129
136
  }, originalPos !== undefined && originalNodeAtPos && {
@@ -141,11 +148,13 @@ var getAttrChangeRanges = exports.getAttrChangeRanges = function getAttrChangeRa
141
148
  return undefined;
142
149
  }
143
150
  var isInline = nodeAtPos.type.name === 'inlineExtension';
144
- return {
151
+ return _objectSpread(_objectSpread({}, attributionKey ? {
152
+ attributionKey: attributionKey
153
+ } : {}), {}, {
145
154
  fromB: finalPos,
146
155
  toB: finalPos + nodeAtPos.nodeSize,
147
156
  isInline: isInline
148
- };
157
+ });
149
158
  }
150
159
 
151
160
  // media node: id/collection/url attribute change — highlight the mediaSingle parent
@@ -153,10 +162,12 @@ var getAttrChangeRanges = exports.getAttrChangeRanges = function getAttrChangeRa
153
162
  return mediaAttrs.includes(v);
154
163
  }) && $pos.parent.type === doc.type.schema.nodes.mediaSingle) {
155
164
  var startPos = $pos.pos + $pos.parentOffset;
156
- return {
165
+ return _objectSpread(_objectSpread({}, attributionKey ? {
166
+ attributionKey: attributionKey
167
+ } : {}), {}, {
157
168
  fromB: startPos,
158
169
  toB: startPos + $pos.parent.nodeSize - 1
159
- };
170
+ });
160
171
  }
161
172
  return undefined;
162
173
  }).filter(filterUndefined)