@atlaskit/editor-plugin-show-diff 16.0.14 → 16.0.17

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 (47) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/cjs/pm-plugins/calculateDiff/calculateDiffDecorations.js +1 -1
  3. package/dist/cjs/pm-plugins/decorations/createAnchorDecorationWidgets.js +19 -13
  4. package/dist/cjs/pm-plugins/decorations/createBlockChangedDecoration.js +2 -1
  5. package/dist/cjs/pm-plugins/decorations/createChangedRowDecorationWidgets.js +94 -28
  6. package/dist/cjs/pm-plugins/decorations/createInlineChangedDecoration.js +2 -1
  7. package/dist/cjs/pm-plugins/decorations/createNodeChangedDecorationWidget.js +14 -1
  8. package/dist/cjs/pm-plugins/decorations/decorationKeys.js +12 -2
  9. package/dist/cjs/pm-plugins/main.js +2 -2
  10. package/dist/cjs/pm-plugins/scrollToDiff.js +20 -0
  11. package/dist/cjs/ui/ContributorTag/buildContributorTagDom.js +5 -4
  12. package/dist/cjs/ui/IndicatorBar/IndicatorBar.js +1 -1
  13. package/dist/cjs/ui/IndicatorBar/IndicatorBarContentComponent.js +1 -1
  14. package/dist/es2019/pm-plugins/calculateDiff/calculateDiffDecorations.js +1 -1
  15. package/dist/es2019/pm-plugins/decorations/createAnchorDecorationWidgets.js +7 -3
  16. package/dist/es2019/pm-plugins/decorations/createBlockChangedDecoration.js +4 -3
  17. package/dist/es2019/pm-plugins/decorations/createChangedRowDecorationWidgets.js +73 -13
  18. package/dist/es2019/pm-plugins/decorations/createInlineChangedDecoration.js +3 -2
  19. package/dist/es2019/pm-plugins/decorations/createNodeChangedDecorationWidget.js +15 -2
  20. package/dist/es2019/pm-plugins/decorations/decorationKeys.js +10 -0
  21. package/dist/es2019/pm-plugins/main.js +2 -2
  22. package/dist/es2019/pm-plugins/scrollToDiff.js +21 -3
  23. package/dist/es2019/ui/ContributorTag/buildContributorTagDom.js +5 -4
  24. package/dist/es2019/ui/IndicatorBar/IndicatorBar.js +1 -1
  25. package/dist/es2019/ui/IndicatorBar/IndicatorBarContentComponent.js +1 -1
  26. package/dist/esm/pm-plugins/calculateDiff/calculateDiffDecorations.js +1 -1
  27. package/dist/esm/pm-plugins/decorations/createAnchorDecorationWidgets.js +19 -13
  28. package/dist/esm/pm-plugins/decorations/createBlockChangedDecoration.js +3 -2
  29. package/dist/esm/pm-plugins/decorations/createChangedRowDecorationWidgets.js +95 -29
  30. package/dist/esm/pm-plugins/decorations/createInlineChangedDecoration.js +3 -2
  31. package/dist/esm/pm-plugins/decorations/createNodeChangedDecorationWidget.js +15 -2
  32. package/dist/esm/pm-plugins/decorations/decorationKeys.js +10 -0
  33. package/dist/esm/pm-plugins/main.js +2 -2
  34. package/dist/esm/pm-plugins/scrollToDiff.js +21 -2
  35. package/dist/esm/ui/ContributorTag/buildContributorTagDom.js +5 -4
  36. package/dist/esm/ui/IndicatorBar/IndicatorBar.js +1 -1
  37. package/dist/esm/ui/IndicatorBar/IndicatorBarContentComponent.js +1 -1
  38. package/dist/types/pm-plugins/decorations/createChangedRowDecorationWidgets.d.ts +6 -1
  39. package/dist/types/pm-plugins/decorations/decorationKeys.d.ts +9 -0
  40. package/dist/types/pm-plugins/scrollToDiff.d.ts +5 -1
  41. package/dist/types/showDiffPluginType.d.ts +2 -0
  42. package/dist/types/ui/ContributorTag/buildContributorTagDom.d.ts +4 -4
  43. package/package.json +4 -3
  44. package/dist/cjs/pm-plugins/areDocsEqualByBlockStructureAndText.js +0 -55
  45. package/dist/es2019/pm-plugins/areDocsEqualByBlockStructureAndText.js +0 -50
  46. package/dist/esm/pm-plugins/areDocsEqualByBlockStructureAndText.js +0 -50
  47. package/dist/types/pm-plugins/areDocsEqualByBlockStructureAndText.d.ts +0 -12
@@ -17,7 +17,8 @@ import { buildAddedCellOverlayRoundedStyle, buildAddedCellOverlayStyle, buildDel
17
17
  import { colorSchemeRegistry, getLegacyColorScheme } from './colorSchemes/schemes';
18
18
  import { createLeftAnchorWidget } from './createAnchorDecorationWidgets';
19
19
  import { resolveCellOverlayStyleLegacy, resolveDeletedRowStyleLegacy } from './createChangedRowDecorationWidgets.styles.legacy';
20
- import { buildAnchorDecorationKey, buildDiffDecorationSpec } from './decorationKeys';
20
+ import { createContributorTagWidget, isContributorTagWidgetEnabled } from './createContributorTagWidget';
21
+ import { AnchorTypeKey, buildAnchorDecorationKey, buildDiffDecorationSpec, scrollMarginTopValue } from './decorationKeys';
21
22
  import { findSafeInsertPos } from './utils/findSafeInsertPos';
22
23
  import { applyCellEdgeAttrs, getRowCellEdgeAttrs, getTableTopAndBottomCellEdgeAttrs } from './utils/tableCellEdgeAttrs';
23
24
  /**
@@ -98,20 +99,40 @@ var extractChangedRows = function extractChangedRows(_ref) {
98
99
  }
99
100
  });
100
101
 
101
- // Filter changes that never truly got deleted
102
+ // Filter changes that never truly got deleted. Compare the number of equivalent rows rather
103
+ // than only checking whether one still exists: deleting two of three identical empty rows should
104
+ // retain two changed rows even though the third remains in the new table.
105
+ var equivalentRowDeletionCounts = [];
102
106
  return changedRows.filter(function (changedRow) {
103
107
  // A replacement leaves every sibling row in place, so asking "does this row still exist
104
108
  // ANYWHERE in the new table?" can drop a genuinely rewritten row that happens to match a
105
- // sibling. Compare it against the row at the same index instead. Deletions must keep the
106
- // whole-table `some()`: their indices shift, so an index comparison would let every
107
- // surviving row through and draw a widget for each one.
109
+ // sibling. Compare it against the row at the same index instead.
108
110
  if (handleRowReplacement) {
109
111
  var counterpart = tableNew.node.maybeChild(changedRow.rowIndex);
110
112
  return !counterpart || !areNodesEqualIgnoreAttrs(counterpart, changedRow.rowNode);
111
113
  }
112
- return !tableNew.node.children.some(function (newRow) {
113
- return areNodesEqualIgnoreAttrs(newRow, changedRow.rowNode);
114
+ var deletionCount = equivalentRowDeletionCounts.find(function (_ref2) {
115
+ var rowNode = _ref2.rowNode;
116
+ return areNodesEqualIgnoreAttrs(rowNode, changedRow.rowNode);
114
117
  });
118
+ if (!deletionCount) {
119
+ var oldRowCount = tableOld.node.children.filter(function (oldRow) {
120
+ return areNodesEqualIgnoreAttrs(oldRow, changedRow.rowNode);
121
+ }).length;
122
+ var newRowCount = tableNew.node.children.filter(function (newRow) {
123
+ return areNodesEqualIgnoreAttrs(newRow, changedRow.rowNode);
124
+ }).length;
125
+ deletionCount = {
126
+ remaining: Math.max(0, oldRowCount - newRowCount),
127
+ rowNode: changedRow.rowNode
128
+ };
129
+ equivalentRowDeletionCounts.push(deletionCount);
130
+ }
131
+ if (deletionCount.remaining === 0) {
132
+ return false;
133
+ }
134
+ deletionCount.remaining--;
135
+ return true;
115
136
  });
116
137
  };
117
138
 
@@ -156,6 +177,9 @@ var createChangedRowDOM = function createChangedRowDOM(rowNode, cellEdgeAttrs, n
156
177
  // is ADDED content, so it must not claim the "deleted" testid — page models match that as
157
178
  // removed content (same reasoning as `createTableCellContentWidgets`).
158
179
  tr.setAttribute('data-testid', isExtendedEnabled(diffType) && isInserted && fg('platform_editor_ai_show_diff_patch_1') ? 'show-diff-changed-row' : 'show-diff-deleted-row');
180
+ if (fg('platform_editor_ai_show_diff_patch_1')) {
181
+ tr.style.setProperty('scroll-margin-top', scrollMarginTopValue);
182
+ }
159
183
 
160
184
  // Serialize each cell in the row
161
185
  var cellIndex = 0;
@@ -194,11 +218,11 @@ var createChangedRowDOM = function createChangedRowDOM(rowNode, cellEdgeAttrs, n
194
218
  /**
195
219
  * Expands a diff to include whole changed rows when table rows are affected
196
220
  */
197
- var expandDiffForChangedRows = function expandDiffForChangedRows(_ref2) {
198
- var changes = _ref2.changes,
199
- originalDoc = _ref2.originalDoc,
200
- newDoc = _ref2.newDoc,
201
- diffType = _ref2.diffType;
221
+ var expandDiffForChangedRows = function expandDiffForChangedRows(_ref3) {
222
+ var changes = _ref3.changes,
223
+ originalDoc = _ref3.originalDoc,
224
+ newDoc = _ref3.newDoc,
225
+ diffType = _ref3.diffType;
202
226
  var rowInfo = [];
203
227
  var _iterator = _createForOfIteratorHelper(changes),
204
228
  _step;
@@ -227,17 +251,22 @@ var expandDiffForChangedRows = function expandDiffForChangedRows(_ref2) {
227
251
  /**
228
252
  * Main function to handle deleted rows - computes diff and creates decorations
229
253
  */
230
- export var createChangedRowDecorationWidgets = function createChangedRowDecorationWidgets(_ref3) {
231
- var changes = _ref3.changes,
232
- originalDoc = _ref3.originalDoc,
233
- newDoc = _ref3.newDoc,
234
- nodeViewSerializer = _ref3.nodeViewSerializer,
235
- colorScheme = _ref3.colorScheme,
236
- _ref3$isInserted = _ref3.isInserted,
237
- isInserted = _ref3$isInserted === void 0 ? false : _ref3$isInserted,
238
- diffType = _ref3.diffType,
239
- _ref3$showIndicators = _ref3.showIndicators,
240
- showIndicators = _ref3$showIndicators === void 0 ? false : _ref3$showIndicators;
254
+ export var createChangedRowDecorationWidgets = function createChangedRowDecorationWidgets(_ref4) {
255
+ var attributionKey = _ref4.attributionKey,
256
+ changes = _ref4.changes,
257
+ originalDoc = _ref4.originalDoc,
258
+ newDoc = _ref4.newDoc,
259
+ nodeViewSerializer = _ref4.nodeViewSerializer,
260
+ colorScheme = _ref4.colorScheme,
261
+ isActive = _ref4.isActive,
262
+ _ref4$isInserted = _ref4.isInserted,
263
+ isInserted = _ref4$isInserted === void 0 ? false : _ref4$isInserted,
264
+ diffType = _ref4.diffType,
265
+ _ref4$showIndicators = _ref4.showIndicators,
266
+ showIndicators = _ref4$showIndicators === void 0 ? false : _ref4$showIndicators,
267
+ _ref4$showContributor = _ref4.showContributorTags,
268
+ showContributorTags = _ref4$showContributor === void 0 ? false : _ref4$showContributor,
269
+ tagMountContext = _ref4.tagMountContext;
241
270
  // First, expand the changes to include complete deleted rows
242
271
  var changedRows = expandDiffForChangedRows({
243
272
  changes: changes.filter(function (change) {
@@ -254,8 +283,12 @@ export var createChangedRowDecorationWidgets = function createChangedRowDecorati
254
283
  var safeInsertPos = findSafeInsertPos(newDoc, changedRow.fromB - 1,
255
284
  // -1 to find the first safe position from the table
256
285
  originalDoc.slice(changedRow.fromA, changedRow.toA));
257
- var diffId = crypto.randomUUID();
286
+
287
+ // Stable while contributor tags are enabled so a decoration recalculation preserves the tag's
288
+ // identity and controller state.
289
+ var diffId = showContributorTags ? "widget-row-".concat(changedRow.fromA, "-").concat(changedRow.toA) : crypto.randomUUID();
258
290
  var decorations = [];
291
+ var rowAnchorNames = [];
259
292
 
260
293
  // `IndicatorBarContentComponent` renders a bar for every widget descriptor and anchors its
261
294
  // top and bottom to `anchor-<diffId>`. Without an element carrying that anchor name the bar
@@ -263,9 +296,9 @@ export var createChangedRowDecorationWidgets = function createChangedRowDecorati
263
296
  // bar covers only the row being changed. `createNodeChangedDecorationWidget` sets the same
264
297
  // property on its own widget DOM for non-table content; this path returns before reaching it.
265
298
  if (showIndicators && isExtendedEnabled(diffType) && fg('platform_editor_ai_show_diff_patch_1')) {
266
- rowDOM.style.setProperty('anchor-name', "--".concat(buildAnchorDecorationKey({
299
+ rowAnchorNames.push(buildAnchorDecorationKey({
267
300
  diffId: diffId
268
- })));
301
+ }));
269
302
 
270
303
  // A table's content can extend past the doc margin, so the bar also needs a left anchor
271
304
  // measured against the table itself or it is clipped once the table is resized.
@@ -278,14 +311,47 @@ export var createChangedRowDecorationWidgets = function createChangedRowDecorati
278
311
  decorations.push(leftAnchor);
279
312
  }
280
313
  }
281
- decorations.push(Decoration.widget(safeInsertPos, rowDOM, _objectSpread({}, buildDiffDecorationSpec({
314
+ var tagAnchorName = showContributorTags && isContributorTagWidgetEnabled() ? buildAnchorDecorationKey({
315
+ diffId: diffId,
316
+ anchorType: AnchorTypeKey.tag
317
+ }) : undefined;
318
+ var tagWidget = tagAnchorName ? createContributorTagWidget({
319
+ anchorAtRangeStart: true,
320
+ anchorName: tagAnchorName,
321
+ diffId: diffId,
322
+ doc: newDoc,
323
+ from: safeInsertPos,
324
+ mountContext: tagMountContext,
325
+ to: safeInsertPos
326
+ }) : undefined;
327
+ if (tagAnchorName) {
328
+ // The tag host is a separate, table-safe widget. CSS anchor positioning aligns it to this
329
+ // synthetic row without placing non-cell DOM inside the `<tr>` or inheriting its deletion
330
+ // opacity and strikethrough.
331
+ rowAnchorNames.push(tagAnchorName);
332
+ }
333
+ if (rowAnchorNames.length > 0) {
334
+ rowDOM.style.setProperty('anchor-name', rowAnchorNames.map(function (anchorName) {
335
+ return "--".concat(anchorName);
336
+ }).join(', '));
337
+ }
338
+ if (tagWidget) {
339
+ // Lets the contributor tag reveal when any part of the deleted row is hovered.
340
+ rowDOM.setAttribute('data-diff-id', diffId);
341
+ }
342
+ var rowWidget = Decoration.widget(safeInsertPos, rowDOM, _objectSpread({}, buildDiffDecorationSpec({
343
+ attributionKey: tagWidget ? attributionKey : undefined,
282
344
  colorScheme: colorScheme,
283
345
  decorationType: 'widget',
284
346
  diffId: diffId,
285
- isActive: false,
347
+ isActive: isActive,
286
348
  isInserted: isInserted,
287
349
  diffType: diffType
288
- }))));
350
+ })));
351
+ decorations.push(rowWidget);
352
+ if (tagWidget) {
353
+ decorations.push(tagWidget);
354
+ }
289
355
  return decorations;
290
356
  });
291
357
  };
@@ -5,6 +5,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
5
5
  import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
6
6
  import { Decoration } from '@atlaskit/editor-prosemirror/view';
7
7
  import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
8
+ import { fg } from '@atlaskit/platform-feature-flags/fg';
8
9
  import { CONTRIBUTOR_TAG_Z_INDEX } from '../../ui/ContributorTag/buildContributorTagDom';
9
10
  import { isExtendedEnabled } from '../isExtendedEnabled';
10
11
  import { isEmptyParagraphSlice } from '../utils/isEmptyParagraphSlice';
@@ -13,7 +14,7 @@ import { colorSchemeRegistry, getLegacyColorScheme } from './colorSchemes/scheme
13
14
  import { createInlineIndicatorAnchorWidgets } from './createAnchorDecorationWidgets';
14
15
  import { createContributorTagWidget, isContributorTagWidgetEnabled } from './createContributorTagWidget';
15
16
  import { getAtomicInlineNodeClassNameLegacy, resolveInlineChangedStyleLegacy } from './createInlineChangedDecoration.styles.legacy';
16
- import { buildDiffDecorationSpec } from './decorationKeys';
17
+ import { buildDiffDecorationSpec, scrollMarginTopStyle } from './decorationKeys';
17
18
  import { REVEAL_ATTR, resolveRevealStyle } from './revealStyles';
18
19
  var displayNoneStyle = convertToInlineCss({
19
20
  display: 'none'
@@ -208,7 +209,7 @@ export var createInlineChangedDecoration = function createInlineChangedDecoratio
208
209
  diffId: diffId,
209
210
  mountContext: tagMountContext
210
211
  }) : undefined;
211
- var inlineStyle = [style, atomicInlineAttrs === null || atomicInlineAttrs === void 0 ? void 0 : atomicInlineAttrs.styleSuffix, tagWidget ? stackBelowContributorTagStyle : undefined].filter(Boolean).join('');
212
+ var inlineStyle = [style, atomicInlineAttrs === null || atomicInlineAttrs === void 0 ? void 0 : atomicInlineAttrs.styleSuffix, tagWidget ? stackBelowContributorTagStyle : undefined, fg('platform_editor_ai_show_diff_patch_1') ? scrollMarginTopStyle : undefined].filter(Boolean).join('');
212
213
  var decorations = [Decoration.inline(change.fromB, change.toB, _objectSpread(_objectSpread(_objectSpread({
213
214
  style: inlineStyle
214
215
  }, atomicInlineAttrs && {
@@ -8,7 +8,7 @@ import { isEmptyParagraphSlice } from '../utils/isEmptyParagraphSlice';
8
8
  import { createLeftAnchorWidget } from './createAnchorDecorationWidgets';
9
9
  import { createChangedRowDecorationWidgets } from './createChangedRowDecorationWidgets';
10
10
  import { createContributorTagHost, unmountContributorTag } from './createContributorTagWidget';
11
- import { buildDiffDecorationSpec, buildAnchorDecorationKey } from './decorationKeys';
11
+ import { buildDiffDecorationSpec, buildAnchorDecorationKey, scrollMarginTopValue } from './decorationKeys';
12
12
  import { findSafeInsertPos } from './utils/findSafeInsertPos';
13
13
  import { wrapBlockNodeView, injectInnerWrapper, createContentWrapper } from './utils/wrapBlockNodeView';
14
14
  var isHeadingLevel = function isHeadingLevel(level) {
@@ -73,6 +73,9 @@ var createTableCellContentWidgets = function createTableCellContentWidgets(_ref)
73
73
  // This helper only runs for added content, so use the "changed" testid — not
74
74
  // "deleted", which page models match as removed content.
75
75
  dom.setAttribute('data-testid', 'show-diff-changed-decoration');
76
+ if (fg('platform_editor_ai_show_diff_patch_1')) {
77
+ dom.style.setProperty('scroll-margin-top', scrollMarginTopValue);
78
+ }
76
79
 
77
80
  // Skip findSafeInsertPos: it walks forward to a schema-valid cell-insert point
78
81
  // and pushes the widget into the next cell. `targetPos` is the correct spot.
@@ -159,16 +162,20 @@ export var createNodeChangedDecorationWidget = function createNodeChangedDecorat
159
162
  }
160
163
  if (isTableRowContent) {
161
164
  return createChangedRowDecorationWidgets({
165
+ attributionKey: attributionKey,
162
166
  changes: [change],
163
167
  originalDoc: doc,
164
168
  newDoc: newDoc,
165
169
  nodeViewSerializer: nodeViewSerializer,
166
170
  colorScheme: colorScheme,
171
+ isActive: isActive,
167
172
  isInserted: isInserted,
168
173
  diffType: diffType,
169
174
  // Needed for the row's own indicator anchor; this path returns before the
170
175
  // `anchor-name` assignment further down.
171
- showIndicators: showIndicators
176
+ showIndicators: showIndicators,
177
+ showContributorTags: showContributorTags,
178
+ tagMountContext: tagMountContext
172
179
  });
173
180
  }
174
181
  var serializer = nodeViewSerializer;
@@ -345,6 +352,9 @@ export var createNodeChangedDecorationWidget = function createNodeChangedDecorat
345
352
  }
346
353
  });
347
354
  dom.setAttribute('data-testid', 'show-diff-deleted-decoration');
355
+ if (fg('platform_editor_ai_show_diff_patch_1')) {
356
+ dom.style.setProperty('scroll-margin-top', scrollMarginTopValue);
357
+ }
348
358
 
349
359
  // Needed even when the indicator bar is off, because a contributor tag also anchors against the
350
360
  // widget.
@@ -424,6 +434,9 @@ export var createNodeChangedDecorationWidget = function createNodeChangedDecorat
424
434
  defaultSpacer.dataset.testid = 'show-diff-default-margin-spacer';
425
435
  defaultSpacer.style.display = 'block';
426
436
  defaultSpacer.style.marginTop = "var(--ds-space-100, 8px)";
437
+ if (fg('platform_editor_ai_show_diff_patch_1')) {
438
+ defaultSpacer.style.setProperty('scroll-margin-top', scrollMarginTopValue);
439
+ }
427
440
  decorations.push(Decoration.widget(safeInsertPos, defaultSpacer, _objectSpread({}, buildDiffDecorationSpec({
428
441
  colorScheme: colorScheme,
429
442
  decorationType: 'widget',
@@ -12,6 +12,16 @@ export var DecorationFamily = {
12
12
  anchor: 'anchor',
13
13
  contributorTag: 'contributor-tag'
14
14
  };
15
+
16
+ /**
17
+ * Navigation measures the target table header and writes this variable on the
18
+ * editor root immediately before scrolling. Diff decorations inherit it, so
19
+ * native scrolling leaves room for the header without DOM mutation on the
20
+ * ProseMirror-rendered suggestion.
21
+ */
22
+ export var SCROLL_TARGET_MARGIN_CSS_PROPERTY = '--ak-editor-diff-additional-margin';
23
+ export var scrollMarginTopValue = "calc(".concat("var(--ds-space-400, 32px)", " + var(", SCROLL_TARGET_MARGIN_CSS_PROPERTY, ", 0px))");
24
+ export var scrollMarginTopStyle = "scroll-margin-top: ".concat(scrollMarginTopValue, ";");
15
25
  export var AnchorTypeKey = {
16
26
  from: 'from',
17
27
  to: 'to',
@@ -251,7 +251,7 @@ export var createPlugin = function createPlugin(config, getIntl, api, onEditorVi
251
251
  if (pluginState !== null && pluginState !== void 0 && pluginState.scrollIntoView && isExtendedEnabled(pluginState === null || pluginState === void 0 ? void 0 : pluginState.diffType)) {
252
252
  var _cancelPendingScrollT;
253
253
  (_cancelPendingScrollT = cancelPendingScrollToDecoration) === null || _cancelPendingScrollT === void 0 || _cancelPendingScrollT();
254
- cancelPendingScrollToDecoration = scrollToDecoration(view, getScrollableDecorations(pluginState.decorations, view.state.doc, pluginState === null || pluginState === void 0 ? void 0 : pluginState.diffType));
254
+ cancelPendingScrollToDecoration = scrollToDecoration(view, getScrollableDecorations(pluginState.decorations, view.state.doc, pluginState === null || pluginState === void 0 ? void 0 : pluginState.diffType), undefined, api);
255
255
 
256
256
  // Reset the flag so we don't scroll again on subsequent updates
257
257
  view.dispatch(view.state.tr.setMeta(showDiffPluginKey, {
@@ -272,7 +272,7 @@ export var createPlugin = function createPlugin(config, getIntl, api, onEditorVi
272
272
  // avoid a circular dependency; expand picks up the meta if loaded (no-op if not).
273
273
  api === null || api === void 0 || api.core.actions.execute(toggleExpandRange(activeDecoration.from, activeDecoration.to, true));
274
274
  }
275
- cancelPendingScrollToDecoration = scrollToDecoration(view, scrollableDecorations, pluginState.activeIndex);
275
+ cancelPendingScrollToDecoration = scrollToDecoration(view, scrollableDecorations, pluginState.activeIndex, api);
276
276
 
277
277
  // Stepping only scrolls — no focus moves and no content changes — so without this a
278
278
  // screen-reader user gets silence. Announced through the live region rather than by
@@ -1,5 +1,7 @@
1
- import { isDiffDecoration } from './decorations/decorationKeys';
2
-
1
+ import { tableMarginTop } from '@atlaskit/editor-common/styles';
2
+ import { getStickyHeaderHeight } from '@atlaskit/editor-common/table/get-sticky-header-height';
3
+ import { fg } from '@atlaskit/platform-feature-flags/fg';
4
+ import { isDiffDecoration, SCROLL_TARGET_MARGIN_CSS_PROPERTY } from './decorations/decorationKeys';
3
5
  /**
4
6
  * Extra space above the scrolled-to element so it does not sit flush under the
5
7
  * viewport edge (helps with sticky table headers, toolbars, etc.).
@@ -10,6 +12,12 @@ import { isDiffDecoration } from './decorations/decorationKeys';
10
12
  * outer scroll or mis-identifies the active scroll container.
11
13
  */
12
14
  var SCROLL_TOP_MARGIN_PX = 100;
15
+ function updateScrollTargetMargin(view, targetPos, api) {
16
+ var _api$limitedMode;
17
+ var isLimitedModeEnabled = Boolean(api === null || api === void 0 || (_api$limitedMode = api.limitedMode) === null || _api$limitedMode === void 0 || (_api$limitedMode = _api$limitedMode.sharedState.currentState()) === null || _api$limitedMode === void 0 ? void 0 : _api$limitedMode.enabled);
18
+ var tableHeaderHeight = isLimitedModeEnabled ? undefined : getStickyHeaderHeight(view, targetPos);
19
+ view.dom.style.setProperty(SCROLL_TARGET_MARGIN_CSS_PROPERTY, "".concat(tableHeaderHeight ? tableHeaderHeight + tableMarginTop : 0, "px"));
20
+ }
13
21
 
14
22
  /**
15
23
  * Returns the resolved HTMLElement for a given DOM node, walking up to the
@@ -20,6 +28,13 @@ function scrollToSelection(node) {
20
28
  if (!(element instanceof HTMLElement)) {
21
29
  return;
22
30
  }
31
+ if (fg('platform_editor_ai_show_diff_patch_1')) {
32
+ element.scrollIntoView({
33
+ behavior: 'smooth',
34
+ block: 'start'
35
+ });
36
+ return;
37
+ }
23
38
 
24
39
  // scroll-margin is included in scroll-into-view math; it does not change layout.
25
40
  var previousScrollMarginTop = element.style.scrollMarginTop;
@@ -42,6 +57,7 @@ function scrollToSelection(node) {
42
57
  */
43
58
  export var scrollToDecoration = function scrollToDecoration(view, decorations) {
44
59
  var activeIndex = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
60
+ var api = arguments.length > 3 ? arguments[3] : undefined;
45
61
  var decoration = decorations[activeIndex];
46
62
  if (!decoration) {
47
63
  return function () {};
@@ -53,6 +69,9 @@ export var scrollToDecoration = function scrollToDecoration(view, decorations) {
53
69
  var target = isDiffDecoration(decoration) && decoration.spec.scrollTarget || decoration;
54
70
  var rafId = requestAnimationFrame(function () {
55
71
  rafId = null;
72
+ if (fg('platform_editor_ai_show_diff_patch_1')) {
73
+ updateScrollTargetMargin(view, target.from, api);
74
+ }
56
75
  if (isDiffDecoration(target) && target.spec.decorationType === 'widget') {
57
76
  var _target$type;
58
77
  // @ts-expect-error - decoration.type is not typed public API
@@ -1,5 +1,6 @@
1
1
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
2
  import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
3
+ import { akEditorSmallZIndex } from '@atlaskit/editor-shared-styles/constants';
3
4
  export var CONTRIBUTOR_TAG_TESTID = 'diff-contributor-tag';
4
5
  export var CONTRIBUTOR_TAG_NAME_TESTID = 'diff-contributor-tag-name';
5
6
 
@@ -13,15 +14,15 @@ export var MAX_TAG_WIDTH = '200px';
13
14
  /**
14
15
  * The tag sits on the line above the change, so it has to paint over that line to be readable —
15
16
  * including any diff highlight already on it, which would otherwise slice straight through the tag.
16
- * Hence one level above `akEditorUnitZIndex`, where the highlights sit; exported because the
17
- * change's own highlight is stacked one level below it — see `stackBelowContributorTagStyle` in
18
- * `createInlineChangedDecoration`.
17
+ * It also has to paint above table interaction overlays and sticky-capable header rows, which use
18
+ * `akEditorSmallZIndex`. The change's own highlight is stacked one level below it — see
19
+ * `stackBelowContributorTagStyle` in `createInlineChangedDecoration`.
19
20
  *
20
21
  * Painting above its own highlight is only safe because the tag can never reach it: `bottom: 100%`
21
22
  * puts the root's bottom edge exactly on the highlight's top edge, and the root's `overflow: clip`
22
23
  * keeps every pixel the tag paints inside it.
23
24
  */
24
- export var CONTRIBUTOR_TAG_Z_INDEX = 2;
25
+ export var CONTRIBUTOR_TAG_Z_INDEX = akEditorSmallZIndex + 1;
25
26
 
26
27
  /**
27
28
  * The plugin's whole side of the tag's motion: the fade and the hidden state are
@@ -1,4 +1,4 @@
1
- /* IndicatorBar.tsx generated by @compiled/babel-plugin v3.0.1 */
1
+ /* IndicatorBar.tsx generated by @compiled/babel-plugin v3.0.2 */
2
2
  import "./IndicatorBar.compiled.css";
3
3
  import * as React from 'react';
4
4
  import { ax, ix } from "@compiled/react/runtime";
@@ -1,4 +1,4 @@
1
- /* IndicatorBarContentComponent.tsx generated by @compiled/babel-plugin v3.0.1 */
1
+ /* IndicatorBarContentComponent.tsx generated by @compiled/babel-plugin v3.0.2 */
2
2
  import { ax, ix } from "@compiled/react/runtime";
3
3
  import React from 'react';
4
4
  import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
@@ -4,18 +4,23 @@ import { Decoration } from '@atlaskit/editor-prosemirror/view';
4
4
  import type { DiffType } from '../../showDiffPluginType';
5
5
  import type { NodeViewSerializer } from '../NodeViewSerializer';
6
6
  import type { ColorScheme } from './colorSchemes/types';
7
+ import { type ContributorTagMountContext } from './createContributorTagWidget';
7
8
  type SimpleChange = Pick<Change, 'fromA' | 'toA' | 'fromB' | 'deleted'>;
8
9
  /**
9
10
  * Main function to handle deleted rows - computes diff and creates decorations
10
11
  */
11
- export declare const createChangedRowDecorationWidgets: ({ changes, originalDoc, newDoc, nodeViewSerializer, colorScheme, isInserted, diffType, showIndicators, }: {
12
+ export declare const createChangedRowDecorationWidgets: ({ attributionKey, changes, originalDoc, newDoc, nodeViewSerializer, colorScheme, isActive, isInserted, diffType, showIndicators, showContributorTags, tagMountContext, }: {
13
+ attributionKey?: string;
12
14
  changes: SimpleChange[];
13
15
  colorScheme?: ColorScheme;
14
16
  diffType?: DiffType;
17
+ isActive?: boolean;
15
18
  isInserted?: boolean;
16
19
  newDoc: PMNode;
17
20
  nodeViewSerializer: NodeViewSerializer;
18
21
  originalDoc: PMNode;
22
+ showContributorTags?: boolean;
19
23
  showIndicators?: boolean;
24
+ tagMountContext?: ContributorTagMountContext;
20
25
  }) => Decoration[];
21
26
  export {};
@@ -10,6 +10,15 @@ export declare const DecorationFamily: {
10
10
  readonly anchor: 'anchor';
11
11
  readonly contributorTag: 'contributor-tag';
12
12
  };
13
+ /**
14
+ * Navigation measures the target table header and writes this variable on the
15
+ * editor root immediately before scrolling. Diff decorations inherit it, so
16
+ * native scrolling leaves room for the header without DOM mutation on the
17
+ * ProseMirror-rendered suggestion.
18
+ */
19
+ export declare const SCROLL_TARGET_MARGIN_CSS_PROPERTY = "--ak-editor-diff-additional-margin";
20
+ export declare const scrollMarginTopValue: string;
21
+ export declare const scrollMarginTopStyle: string;
13
22
  type DecorationFamilyValue = (typeof DecorationFamily)[keyof typeof DecorationFamily];
14
23
  type BaseDecorationSpec<TFamily extends DecorationFamilyValue> = {
15
24
  decorationFamily: TFamily;
@@ -1,8 +1,12 @@
1
+ import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
1
2
  import type { EditorView, Decoration } from '@atlaskit/editor-prosemirror/view';
3
+ import type { ShowDiffPlugin } from '../showDiffPluginType';
4
+ type PluginInjectionAPI = ExtractInjectionAPI<ShowDiffPlugin>;
2
5
  /**
3
6
  * Schedules scrolling to the decoration at the given index after the next frame. Defaults to the
4
7
  * first decoration when no index is provided.
5
8
  *
6
9
  * @returns A function that cancels the scheduled `requestAnimationFrame` if it has not run yet.
7
10
  */
8
- export declare const scrollToDecoration: (view: EditorView, decorations: Decoration[], activeIndex?: number) => (() => void);
11
+ export declare const scrollToDecoration: (view: EditorView, decorations: Decoration[], activeIndex?: number, api?: PluginInjectionAPI) => (() => void);
12
+ export {};
@@ -3,6 +3,7 @@ import type { NextEditorPlugin, EditorCommand, OptionalPlugin } from '@atlaskit/
3
3
  import type { JSONDocNode } from '@atlaskit/editor-json-transformer/types';
4
4
  import type { AccessibilityUtilsPlugin } from '@atlaskit/editor-plugin-accessibility-utils';
5
5
  import type { AnalyticsPlugin } from '@atlaskit/editor-plugin-analytics';
6
+ import type { LimitedModePlugin } from '@atlaskit/editor-plugin-limited-mode/limited-mode-plugin-type';
6
7
  import type { UserIntentPlugin } from '@atlaskit/editor-plugin-user-intent';
7
8
  import type { Node } from '@atlaskit/editor-prosemirror/model';
8
9
  import type { Step } from '@atlaskit/editor-prosemirror/transform-override';
@@ -232,6 +233,7 @@ export type ShowDiffPlugin = NextEditorPlugin<'showDiff', {
232
233
  dependencies: [
233
234
  OptionalPlugin<AnalyticsPlugin>,
234
235
  OptionalPlugin<UserIntentPlugin>,
236
+ OptionalPlugin<LimitedModePlugin>,
235
237
  /** Carries the live-region announcement made when stepping between changes. */
236
238
  OptionalPlugin<AccessibilityUtilsPlugin>
237
239
  ];
@@ -9,15 +9,15 @@ export declare const MAX_TAG_WIDTH = "200px";
9
9
  /**
10
10
  * The tag sits on the line above the change, so it has to paint over that line to be readable —
11
11
  * including any diff highlight already on it, which would otherwise slice straight through the tag.
12
- * Hence one level above `akEditorUnitZIndex`, where the highlights sit; exported because the
13
- * change's own highlight is stacked one level below it — see `stackBelowContributorTagStyle` in
14
- * `createInlineChangedDecoration`.
12
+ * It also has to paint above table interaction overlays and sticky-capable header rows, which use
13
+ * `akEditorSmallZIndex`. The change's own highlight is stacked one level below it — see
14
+ * `stackBelowContributorTagStyle` in `createInlineChangedDecoration`.
15
15
  *
16
16
  * Painting above its own highlight is only safe because the tag can never reach it: `bottom: 100%`
17
17
  * puts the root's bottom edge exactly on the highlight's top edge, and the root's `overflow: clip`
18
18
  * keeps every pixel the tag paints inside it.
19
19
  */
20
- export declare const CONTRIBUTOR_TAG_Z_INDEX = 2;
20
+ export declare const CONTRIBUTOR_TAG_Z_INDEX: number;
21
21
  /**
22
22
  * The plugin's whole side of the tag's motion: the fade and the hidden state are
23
23
  * `contributorTagStyles` in both EditorContentContainer stylesheets, keyed on this literal and the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-show-diff",
3
- "version": "16.0.14",
3
+ "version": "16.0.17",
4
4
  "description": "ShowDiff plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -25,6 +25,7 @@
25
25
  "@atlaskit/custom-steps": "^1.1.0",
26
26
  "@atlaskit/editor-plugin-accessibility-utils": "^18.0.0",
27
27
  "@atlaskit/editor-plugin-analytics": "^18.0.0",
28
+ "@atlaskit/editor-plugin-limited-mode": "^15.0.0",
28
29
  "@atlaskit/editor-plugin-user-intent": "^16.0.0",
29
30
  "@atlaskit/editor-prosemirror": "^8.0.0",
30
31
  "@atlaskit/editor-shared-styles": "^4.3.0",
@@ -32,7 +33,7 @@
32
33
  "@atlaskit/platform-feature-experiments": "^0.3.0",
33
34
  "@atlaskit/platform-feature-flags": "^2.2.0",
34
35
  "@atlaskit/primitives": "^22.5.0",
35
- "@atlaskit/tmp-editor-statsig": "^196.0.0",
36
+ "@atlaskit/tmp-editor-statsig": "^197.0.0",
36
37
  "@atlaskit/tokens": "^17.0.0",
37
38
  "@babel/runtime": "^7.0.0",
38
39
  "@compiled/react": "^1.0.2",
@@ -64,7 +65,7 @@
64
65
  "react-intl": "^7.0.0"
65
66
  },
66
67
  "peerDependencies": {
67
- "@atlaskit/editor-common": "^122.8.0",
68
+ "@atlaskit/editor-common": "^122.9.0",
68
69
  "react": "^18.2.0 || ^19.2.0",
69
70
  "react-dom": "^18.2.0 || ^19.2.0",
70
71
  "react-intl": "^5.25.1 || ^6.0.0 || ^7.0.0"
@@ -1,55 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.areDocsEqualByBlockStructureAndText = areDocsEqualByBlockStructureAndText;
7
- var _transform = require("@atlaskit/editor-prosemirror/transform");
8
- /**
9
- * Returns a copy of the document with all marks removed from all text.
10
- * This normalises mark fragmentation — e.g. annotation marks reordering can split
11
- * a single text run into many text nodes, making structural comparison unreliable.
12
- * After stripping, ProseMirror will merge adjacent text nodes so childCounts are stable.
13
- */
14
- function stripMarks(doc) {
15
- var tr = new _transform.Transform(doc);
16
- tr.removeMark(0, doc.content.size);
17
- return tr.doc;
18
- }
19
-
20
- /**
21
- * Returns true if both (mark-stripped) nodes have the same block tree structure (node type and child count at every level)
22
- */
23
- function isBlockStructureEqual(node1, node2) {
24
- if (node1.type !== node2.type || node1.childCount !== node2.childCount) {
25
- return false;
26
- }
27
- for (var i = 0; i < node1.childCount; i++) {
28
- if (!isBlockStructureEqual(node1.child(i), node2.child(i))) {
29
- return false;
30
- }
31
- }
32
- return true;
33
- }
34
-
35
- /**
36
- * Looser equality for "safe diff" cases: same full text content and same block structure
37
- * (e.g. text moved across text-node boundaries). Used when strict areNodesEqualIgnoreAttrs fails.
38
- * This is safe because we ensure decorations get applied to valid positions.
39
- *
40
- * Marks are intentionally ignored — two documents that differ only in mark application
41
- * (e.g. bold/italic boundaries or annotation mark ordering) are considered equal here.
42
- * Both documents are mark-stripped before comparison so that mark-driven text fragmentation
43
- * does not produce false inequalities.
44
- */
45
- function areDocsEqualByBlockStructureAndText(doc1, doc2) {
46
- if (doc1.textContent !== doc2.textContent) {
47
- return false;
48
- }
49
- // Strip marks before comparing so that mark-driven text fragmentation
50
- // (e.g. annotation mark reordering producing different childCounts) does not
51
- // cause false inequalities.
52
- var stripped1 = stripMarks(doc1);
53
- var stripped2 = stripMarks(doc2);
54
- return doc1.nodeSize === doc2.nodeSize && isBlockStructureEqual(stripped1, stripped2);
55
- }