@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
@@ -10,7 +10,8 @@ import { buildAddedCellOverlayRoundedStyle, buildAddedCellOverlayStyle, buildDel
10
10
  import { colorSchemeRegistry, getLegacyColorScheme } from './colorSchemes/schemes';
11
11
  import { createLeftAnchorWidget } from './createAnchorDecorationWidgets';
12
12
  import { resolveCellOverlayStyleLegacy, resolveDeletedRowStyleLegacy } from './createChangedRowDecorationWidgets.styles.legacy';
13
- import { buildAnchorDecorationKey, buildDiffDecorationSpec } from './decorationKeys';
13
+ import { createContributorTagWidget, isContributorTagWidgetEnabled } from './createContributorTagWidget';
14
+ import { AnchorTypeKey, buildAnchorDecorationKey, buildDiffDecorationSpec, scrollMarginTopValue } from './decorationKeys';
14
15
  import { findSafeInsertPos } from './utils/findSafeInsertPos';
15
16
  import { applyCellEdgeAttrs, getRowCellEdgeAttrs, getTableTopAndBottomCellEdgeAttrs } from './utils/tableCellEdgeAttrs';
16
17
  /**
@@ -86,18 +87,35 @@ const extractChangedRows = ({
86
87
  }
87
88
  });
88
89
 
89
- // Filter changes that never truly got deleted
90
+ // Filter changes that never truly got deleted. Compare the number of equivalent rows rather
91
+ // than only checking whether one still exists: deleting two of three identical empty rows should
92
+ // retain two changed rows even though the third remains in the new table.
93
+ const equivalentRowDeletionCounts = [];
90
94
  return changedRows.filter(changedRow => {
91
95
  // A replacement leaves every sibling row in place, so asking "does this row still exist
92
96
  // ANYWHERE in the new table?" can drop a genuinely rewritten row that happens to match a
93
- // sibling. Compare it against the row at the same index instead. Deletions must keep the
94
- // whole-table `some()`: their indices shift, so an index comparison would let every
95
- // surviving row through and draw a widget for each one.
97
+ // sibling. Compare it against the row at the same index instead.
96
98
  if (handleRowReplacement) {
97
99
  const counterpart = tableNew.node.maybeChild(changedRow.rowIndex);
98
100
  return !counterpart || !areNodesEqualIgnoreAttrs(counterpart, changedRow.rowNode);
99
101
  }
100
- return !tableNew.node.children.some(newRow => areNodesEqualIgnoreAttrs(newRow, changedRow.rowNode));
102
+ let deletionCount = equivalentRowDeletionCounts.find(({
103
+ rowNode
104
+ }) => areNodesEqualIgnoreAttrs(rowNode, changedRow.rowNode));
105
+ if (!deletionCount) {
106
+ const oldRowCount = tableOld.node.children.filter(oldRow => areNodesEqualIgnoreAttrs(oldRow, changedRow.rowNode)).length;
107
+ const newRowCount = tableNew.node.children.filter(newRow => areNodesEqualIgnoreAttrs(newRow, changedRow.rowNode)).length;
108
+ deletionCount = {
109
+ remaining: Math.max(0, oldRowCount - newRowCount),
110
+ rowNode: changedRow.rowNode
111
+ };
112
+ equivalentRowDeletionCounts.push(deletionCount);
113
+ }
114
+ if (deletionCount.remaining === 0) {
115
+ return false;
116
+ }
117
+ deletionCount.remaining--;
118
+ return true;
101
119
  });
102
120
  };
103
121
 
@@ -142,6 +160,9 @@ const createChangedRowDOM = (rowNode, cellEdgeAttrs, nodeViewSerializer, colorSc
142
160
  // is ADDED content, so it must not claim the "deleted" testid — page models match that as
143
161
  // removed content (same reasoning as `createTableCellContentWidgets`).
144
162
  tr.setAttribute('data-testid', isExtendedEnabled(diffType) && isInserted && fg('platform_editor_ai_show_diff_patch_1') ? 'show-diff-changed-row' : 'show-diff-deleted-row');
163
+ if (fg('platform_editor_ai_show_diff_patch_1')) {
164
+ tr.style.setProperty('scroll-margin-top', scrollMarginTopValue);
165
+ }
145
166
 
146
167
  // Serialize each cell in the row
147
168
  let cellIndex = 0;
@@ -206,14 +227,18 @@ const expandDiffForChangedRows = ({
206
227
  * Main function to handle deleted rows - computes diff and creates decorations
207
228
  */
208
229
  export const createChangedRowDecorationWidgets = ({
230
+ attributionKey,
209
231
  changes,
210
232
  originalDoc,
211
233
  newDoc,
212
234
  nodeViewSerializer,
213
235
  colorScheme,
236
+ isActive,
214
237
  isInserted = false,
215
238
  diffType,
216
- showIndicators = false
239
+ showIndicators = false,
240
+ showContributorTags = false,
241
+ tagMountContext
217
242
  }) => {
218
243
  // First, expand the changes to include complete deleted rows
219
244
  const changedRows = expandDiffForChangedRows({
@@ -229,8 +254,12 @@ export const createChangedRowDecorationWidgets = ({
229
254
  const safeInsertPos = findSafeInsertPos(newDoc, changedRow.fromB - 1,
230
255
  // -1 to find the first safe position from the table
231
256
  originalDoc.slice(changedRow.fromA, changedRow.toA));
232
- const diffId = crypto.randomUUID();
257
+
258
+ // Stable while contributor tags are enabled so a decoration recalculation preserves the tag's
259
+ // identity and controller state.
260
+ const diffId = showContributorTags ? `widget-row-${changedRow.fromA}-${changedRow.toA}` : crypto.randomUUID();
233
261
  const decorations = [];
262
+ const rowAnchorNames = [];
234
263
 
235
264
  // `IndicatorBarContentComponent` renders a bar for every widget descriptor and anchors its
236
265
  // top and bottom to `anchor-<diffId>`. Without an element carrying that anchor name the bar
@@ -238,9 +267,9 @@ export const createChangedRowDecorationWidgets = ({
238
267
  // bar covers only the row being changed. `createNodeChangedDecorationWidget` sets the same
239
268
  // property on its own widget DOM for non-table content; this path returns before reaching it.
240
269
  if (showIndicators && isExtendedEnabled(diffType) && fg('platform_editor_ai_show_diff_patch_1')) {
241
- rowDOM.style.setProperty('anchor-name', `--${buildAnchorDecorationKey({
270
+ rowAnchorNames.push(buildAnchorDecorationKey({
242
271
  diffId
243
- })}`);
272
+ }));
244
273
 
245
274
  // A table's content can extend past the doc margin, so the bar also needs a left anchor
246
275
  // measured against the table itself or it is clipped once the table is resized.
@@ -253,16 +282,47 @@ export const createChangedRowDecorationWidgets = ({
253
282
  decorations.push(leftAnchor);
254
283
  }
255
284
  }
256
- decorations.push(Decoration.widget(safeInsertPos, rowDOM, {
285
+ const tagAnchorName = showContributorTags && isContributorTagWidgetEnabled() ? buildAnchorDecorationKey({
286
+ diffId,
287
+ anchorType: AnchorTypeKey.tag
288
+ }) : undefined;
289
+ const tagWidget = tagAnchorName ? createContributorTagWidget({
290
+ anchorAtRangeStart: true,
291
+ anchorName: tagAnchorName,
292
+ diffId,
293
+ doc: newDoc,
294
+ from: safeInsertPos,
295
+ mountContext: tagMountContext,
296
+ to: safeInsertPos
297
+ }) : undefined;
298
+ if (tagAnchorName) {
299
+ // The tag host is a separate, table-safe widget. CSS anchor positioning aligns it to this
300
+ // synthetic row without placing non-cell DOM inside the `<tr>` or inheriting its deletion
301
+ // opacity and strikethrough.
302
+ rowAnchorNames.push(tagAnchorName);
303
+ }
304
+ if (rowAnchorNames.length > 0) {
305
+ rowDOM.style.setProperty('anchor-name', rowAnchorNames.map(anchorName => `--${anchorName}`).join(', '));
306
+ }
307
+ if (tagWidget) {
308
+ // Lets the contributor tag reveal when any part of the deleted row is hovered.
309
+ rowDOM.setAttribute('data-diff-id', diffId);
310
+ }
311
+ const rowWidget = Decoration.widget(safeInsertPos, rowDOM, {
257
312
  ...buildDiffDecorationSpec({
313
+ attributionKey: tagWidget ? attributionKey : undefined,
258
314
  colorScheme,
259
315
  decorationType: 'widget',
260
316
  diffId,
261
- isActive: false,
317
+ isActive,
262
318
  isInserted,
263
319
  diffType
264
320
  })
265
- }));
321
+ });
322
+ decorations.push(rowWidget);
323
+ if (tagWidget) {
324
+ decorations.push(tagWidget);
325
+ }
266
326
  return decorations;
267
327
  });
268
328
  };
@@ -1,6 +1,7 @@
1
1
  import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
2
2
  import { Decoration } from '@atlaskit/editor-prosemirror/view';
3
3
  import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
4
+ import { fg } from '@atlaskit/platform-feature-flags/fg';
4
5
  import { CONTRIBUTOR_TAG_Z_INDEX } from '../../ui/ContributorTag/buildContributorTagDom';
5
6
  import { isExtendedEnabled } from '../isExtendedEnabled';
6
7
  import { isEmptyParagraphSlice } from '../utils/isEmptyParagraphSlice';
@@ -9,7 +10,7 @@ import { colorSchemeRegistry, getLegacyColorScheme } from './colorSchemes/scheme
9
10
  import { createInlineIndicatorAnchorWidgets } from './createAnchorDecorationWidgets';
10
11
  import { createContributorTagWidget, isContributorTagWidgetEnabled } from './createContributorTagWidget';
11
12
  import { getAtomicInlineNodeClassNameLegacy, resolveInlineChangedStyleLegacy } from './createInlineChangedDecoration.styles.legacy';
12
- import { buildDiffDecorationSpec } from './decorationKeys';
13
+ import { buildDiffDecorationSpec, scrollMarginTopStyle } from './decorationKeys';
13
14
  import { REVEAL_ATTR, resolveRevealStyle } from './revealStyles';
14
15
  const displayNoneStyle = convertToInlineCss({
15
16
  display: 'none'
@@ -190,7 +191,7 @@ export const createInlineChangedDecoration = ({
190
191
  diffId,
191
192
  mountContext: tagMountContext
192
193
  }) : undefined;
193
- const inlineStyle = [style, atomicInlineAttrs === null || atomicInlineAttrs === void 0 ? void 0 : atomicInlineAttrs.styleSuffix, tagWidget ? stackBelowContributorTagStyle : undefined].filter(Boolean).join('');
194
+ const 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('');
194
195
  const decorations = [Decoration.inline(change.fromB, change.toB, {
195
196
  style: inlineStyle,
196
197
  ...(atomicInlineAttrs && {
@@ -5,7 +5,7 @@ import { isEmptyParagraphSlice } from '../utils/isEmptyParagraphSlice';
5
5
  import { createLeftAnchorWidget } from './createAnchorDecorationWidgets';
6
6
  import { createChangedRowDecorationWidgets } from './createChangedRowDecorationWidgets';
7
7
  import { createContributorTagHost, unmountContributorTag } from './createContributorTagWidget';
8
- import { buildDiffDecorationSpec, buildAnchorDecorationKey } from './decorationKeys';
8
+ import { buildDiffDecorationSpec, buildAnchorDecorationKey, scrollMarginTopValue } from './decorationKeys';
9
9
  import { findSafeInsertPos } from './utils/findSafeInsertPos';
10
10
  import { wrapBlockNodeView, injectInnerWrapper, createContentWrapper } from './utils/wrapBlockNodeView';
11
11
  const isHeadingLevel = level => typeof level === 'number' && level >= 1 && level <= 6;
@@ -69,6 +69,9 @@ const createTableCellContentWidgets = ({
69
69
  // This helper only runs for added content, so use the "changed" testid — not
70
70
  // "deleted", which page models match as removed content.
71
71
  dom.setAttribute('data-testid', 'show-diff-changed-decoration');
72
+ if (fg('platform_editor_ai_show_diff_patch_1')) {
73
+ dom.style.setProperty('scroll-margin-top', scrollMarginTopValue);
74
+ }
72
75
 
73
76
  // Skip findSafeInsertPos: it walks forward to a schema-valid cell-insert point
74
77
  // and pushes the widget into the next cell. `targetPos` is the correct spot.
@@ -150,16 +153,20 @@ export const createNodeChangedDecorationWidget = ({
150
153
  }
151
154
  if (isTableRowContent) {
152
155
  return createChangedRowDecorationWidgets({
156
+ attributionKey,
153
157
  changes: [change],
154
158
  originalDoc: doc,
155
159
  newDoc,
156
160
  nodeViewSerializer,
157
161
  colorScheme,
162
+ isActive,
158
163
  isInserted,
159
164
  diffType,
160
165
  // Needed for the row's own indicator anchor; this path returns before the
161
166
  // `anchor-name` assignment further down.
162
- showIndicators
167
+ showIndicators,
168
+ showContributorTags,
169
+ tagMountContext
163
170
  });
164
171
  }
165
172
  const serializer = nodeViewSerializer;
@@ -330,6 +337,9 @@ export const createNodeChangedDecorationWidget = ({
330
337
  }
331
338
  });
332
339
  dom.setAttribute('data-testid', 'show-diff-deleted-decoration');
340
+ if (fg('platform_editor_ai_show_diff_patch_1')) {
341
+ dom.style.setProperty('scroll-margin-top', scrollMarginTopValue);
342
+ }
333
343
 
334
344
  // Needed even when the indicator bar is off, because a contributor tag also anchors against the
335
345
  // widget.
@@ -416,6 +426,9 @@ export const createNodeChangedDecorationWidget = ({
416
426
  defaultSpacer.dataset.testid = 'show-diff-default-margin-spacer';
417
427
  defaultSpacer.style.display = 'block';
418
428
  defaultSpacer.style.marginTop = "var(--ds-space-100, 8px)";
429
+ if (fg('platform_editor_ai_show_diff_patch_1')) {
430
+ defaultSpacer.style.setProperty('scroll-margin-top', scrollMarginTopValue);
431
+ }
419
432
  decorations.push(Decoration.widget(safeInsertPos, defaultSpacer, {
420
433
  ...buildDiffDecorationSpec({
421
434
  colorScheme,
@@ -8,6 +8,16 @@ export const DecorationFamily = {
8
8
  anchor: 'anchor',
9
9
  contributorTag: 'contributor-tag'
10
10
  };
11
+
12
+ /**
13
+ * Navigation measures the target table header and writes this variable on the
14
+ * editor root immediately before scrolling. Diff decorations inherit it, so
15
+ * native scrolling leaves room for the header without DOM mutation on the
16
+ * ProseMirror-rendered suggestion.
17
+ */
18
+ export const SCROLL_TARGET_MARGIN_CSS_PROPERTY = '--ak-editor-diff-additional-margin';
19
+ export const scrollMarginTopValue = `calc(${"var(--ds-space-400, 32px)"} + var(${SCROLL_TARGET_MARGIN_CSS_PROPERTY}, 0px))`;
20
+ export const scrollMarginTopStyle = `scroll-margin-top: ${scrollMarginTopValue};`;
11
21
  export const AnchorTypeKey = {
12
22
  from: 'from',
13
23
  to: 'to',
@@ -264,7 +264,7 @@ export const createPlugin = (config, getIntl, api, onEditorView) => {
264
264
  if (pluginState !== null && pluginState !== void 0 && pluginState.scrollIntoView && isExtendedEnabled(pluginState === null || pluginState === void 0 ? void 0 : pluginState.diffType)) {
265
265
  var _cancelPendingScrollT;
266
266
  (_cancelPendingScrollT = cancelPendingScrollToDecoration) === null || _cancelPendingScrollT === void 0 ? void 0 : _cancelPendingScrollT();
267
- cancelPendingScrollToDecoration = scrollToDecoration(view, getScrollableDecorations(pluginState.decorations, view.state.doc, pluginState === null || pluginState === void 0 ? void 0 : pluginState.diffType));
267
+ cancelPendingScrollToDecoration = scrollToDecoration(view, getScrollableDecorations(pluginState.decorations, view.state.doc, pluginState === null || pluginState === void 0 ? void 0 : pluginState.diffType), undefined, api);
268
268
 
269
269
  // Reset the flag so we don't scroll again on subsequent updates
270
270
  view.dispatch(view.state.tr.setMeta(showDiffPluginKey, {
@@ -285,7 +285,7 @@ export const createPlugin = (config, getIntl, api, onEditorView) => {
285
285
  // avoid a circular dependency; expand picks up the meta if loaded (no-op if not).
286
286
  api === null || api === void 0 ? void 0 : api.core.actions.execute(toggleExpandRange(activeDecoration.from, activeDecoration.to, true));
287
287
  }
288
- cancelPendingScrollToDecoration = scrollToDecoration(view, scrollableDecorations, pluginState.activeIndex);
288
+ cancelPendingScrollToDecoration = scrollToDecoration(view, scrollableDecorations, pluginState.activeIndex, api);
289
289
 
290
290
  // Stepping only scrolls — no focus moves and no content changes — so without this a
291
291
  // 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
  const SCROLL_TOP_MARGIN_PX = 100;
15
+ function updateScrollTargetMargin(view, targetPos, api) {
16
+ var _api$limitedMode, _api$limitedMode$shar;
17
+ const isLimitedModeEnabled = Boolean(api === null || api === void 0 ? void 0 : (_api$limitedMode = api.limitedMode) === null || _api$limitedMode === void 0 ? void 0 : (_api$limitedMode$shar = _api$limitedMode.sharedState.currentState()) === null || _api$limitedMode$shar === void 0 ? void 0 : _api$limitedMode$shar.enabled);
18
+ const tableHeaderHeight = isLimitedModeEnabled ? undefined : getStickyHeaderHeight(view, targetPos);
19
+ view.dom.style.setProperty(SCROLL_TARGET_MARGIN_CSS_PROPERTY, `${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
  const previousScrollMarginTop = element.style.scrollMarginTop;
@@ -40,7 +55,7 @@ function scrollToSelection(node) {
40
55
  *
41
56
  * @returns A function that cancels the scheduled `requestAnimationFrame` if it has not run yet.
42
57
  */
43
- export const scrollToDecoration = (view, decorations, activeIndex = 0) => {
58
+ export const scrollToDecoration = (view, decorations, activeIndex = 0, api) => {
44
59
  const decoration = decorations[activeIndex];
45
60
  if (!decoration) {
46
61
  return () => {};
@@ -52,6 +67,9 @@ export const scrollToDecoration = (view, decorations, activeIndex = 0) => {
52
67
  const target = isDiffDecoration(decoration) && decoration.spec.scrollTarget || decoration;
53
68
  let rafId = requestAnimationFrame(() => {
54
69
  rafId = null;
70
+ if (fg('platform_editor_ai_show_diff_patch_1')) {
71
+ updateScrollTargetMargin(view, target.from, api);
72
+ }
55
73
  if (isDiffDecoration(target) && target.spec.decorationType === 'widget') {
56
74
  var _target$type;
57
75
  // @ts-expect-error - decoration.type is not typed public API
@@ -1,4 +1,5 @@
1
1
  import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
2
+ import { akEditorSmallZIndex } from '@atlaskit/editor-shared-styles/constants';
2
3
  export const CONTRIBUTOR_TAG_TESTID = 'diff-contributor-tag';
3
4
  export const CONTRIBUTOR_TAG_NAME_TESTID = 'diff-contributor-tag-name';
4
5
 
@@ -12,15 +13,15 @@ export const MAX_TAG_WIDTH = '200px';
12
13
  /**
13
14
  * The tag sits on the line above the change, so it has to paint over that line to be readable —
14
15
  * including any diff highlight already on it, which would otherwise slice straight through the tag.
15
- * Hence one level above `akEditorUnitZIndex`, where the highlights sit; exported because the
16
- * change's own highlight is stacked one level below it — see `stackBelowContributorTagStyle` in
17
- * `createInlineChangedDecoration`.
16
+ * It also has to paint above table interaction overlays and sticky-capable header rows, which use
17
+ * `akEditorSmallZIndex`. The change's own highlight is stacked one level below it — see
18
+ * `stackBelowContributorTagStyle` in `createInlineChangedDecoration`.
18
19
  *
19
20
  * Painting above its own highlight is only safe because the tag can never reach it: `bottom: 100%`
20
21
  * puts the root's bottom edge exactly on the highlight's top edge, and the root's `overflow: clip`
21
22
  * keeps every pixel the tag paints inside it.
22
23
  */
23
- export const CONTRIBUTOR_TAG_Z_INDEX = 2;
24
+ export const CONTRIBUTOR_TAG_Z_INDEX = akEditorSmallZIndex + 1;
24
25
 
25
26
  /**
26
27
  * 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';
@@ -9,13 +9,13 @@ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length)
9
9
  import isEqual from 'lodash/isEqual';
10
10
  import memoizeOne from 'memoize-one';
11
11
  import { ChangeSet, simplifyChanges } from 'prosemirror-changeset';
12
+ import { areDocsEqualByBlockStructureAndText } from '@atlaskit/editor-common/utils/areDocsEqualByBlockStructureAndText';
12
13
  import { areNodesEqualIgnoreAttrs } from '@atlaskit/editor-common/utils/document';
13
14
  import { Mapping } from '@atlaskit/editor-prosemirror/transform';
14
15
  import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
15
16
  import { UNSAFE_expValNoExposure } from '@atlaskit/platform-feature-experiments/unsafe-exp-val-no-exposure';
16
17
  import { fg } from '@atlaskit/platform-feature-flags/fg';
17
18
  import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
18
- import { areDocsEqualByBlockStructureAndText } from '../areDocsEqualByBlockStructureAndText';
19
19
  import { createDocMarginAnchorWidget } from '../decorations/createAnchorDecorationWidgets';
20
20
  import { createBlockChangedDecoration } from '../decorations/createBlockChangedDecoration';
21
21
  import { createInlineChangedDecoration } from '../decorations/createInlineChangedDecoration';
@@ -214,6 +214,7 @@ export var createLeftAnchorWidget = function createLeftAnchorWidget(_ref) {
214
214
  *
215
215
  */
216
216
  export var createBlockIndicatorAnchorWidgets = function createBlockIndicatorAnchorWidgets(_ref2) {
217
+ var _ref3, _parentTable$pos;
217
218
  var doc = _ref2.doc,
218
219
  from = _ref2.from,
219
220
  to = _ref2.to,
@@ -253,9 +254,14 @@ export var createBlockIndicatorAnchorWidgets = function createBlockIndicatorAnch
253
254
  var parentCellOrRow = findParentNodeClosestToPos($from, function (ancestor) {
254
255
  return ['tableCell', 'tableHeader', 'tableRow'].includes(ancestor.type.name);
255
256
  });
256
-
257
- // Render outside the table when inside one; otherwise keep the original pos.
258
- var widgetPos = parentTable ? parentTable.pos : from;
257
+ var parentLayout = fg('platform_editor_ai_show_diff_patch_1') ? findParentNodeClosestToPos($from, function (ancestor) {
258
+ return ancestor.type.name === 'layoutSection';
259
+ }) : undefined;
260
+ // Layouts flatten direct widget children with display: contents. Such a wrapper has no
261
+ // bounding box or positioning context, so measuring its top produces an offset from the
262
+ // viewport origin and displaces the indicator into content below the editor. Keep the
263
+ // wrapper outside the layout, just as we do for tables, but still measure the target node.
264
+ var widgetPos = (_ref3 = (_parentTable$pos = parentTable === null || parentTable === void 0 ? void 0 : parentTable.pos) !== null && _parentTable$pos !== void 0 ? _parentTable$pos : parentLayout === null || parentLayout === void 0 ? void 0 : parentLayout.pos) !== null && _ref3 !== void 0 ? _ref3 : from;
259
265
  // Measure the actual cell/row DOM when inside one; otherwise measure the
260
266
  // widget's own position.
261
267
  var measurePos = parentCellOrRow ? parentCellOrRow.pos : from;
@@ -354,11 +360,11 @@ export var createAnchorNameSpan = function createAnchorNameSpan(anchorKey) {
354
360
  span.style.setProperty('anchor-name', "--".concat(anchorKey));
355
361
  return span;
356
362
  };
357
- var createAnchorSpanWidget = function createAnchorSpanWidget(_ref3) {
358
- var pos = _ref3.pos,
359
- diffId = _ref3.diffId,
360
- anchorType = _ref3.anchorType,
361
- side = _ref3.side;
363
+ var createAnchorSpanWidget = function createAnchorSpanWidget(_ref4) {
364
+ var pos = _ref4.pos,
365
+ diffId = _ref4.diffId,
366
+ anchorType = _ref4.anchorType,
367
+ side = _ref4.side;
362
368
  return Decoration.widget(pos, function () {
363
369
  return createAnchorNameSpan(buildAnchorDecorationKey({
364
370
  diffId: diffId,
@@ -375,11 +381,11 @@ var createAnchorSpanWidget = function createAnchorSpanWidget(_ref3) {
375
381
  * Invisible `from`/`to` (and optional `left`) anchor widgets for one inline diff
376
382
  * range, so the `IndicatorBar` can align itself via CSS anchor positioning.
377
383
  */
378
- export var createInlineIndicatorAnchorWidgets = function createInlineIndicatorAnchorWidgets(_ref4) {
379
- var doc = _ref4.doc,
380
- from = _ref4.from,
381
- to = _ref4.to,
382
- diffId = _ref4.diffId;
384
+ export var createInlineIndicatorAnchorWidgets = function createInlineIndicatorAnchorWidgets(_ref5) {
385
+ var doc = _ref5.doc,
386
+ from = _ref5.from,
387
+ to = _ref5.to,
388
+ diffId = _ref5.diffId;
383
389
  var leftAnchor = createLeftAnchorWidget({
384
390
  doc: doc,
385
391
  from: from,
@@ -6,12 +6,13 @@ import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
6
6
  import { findParentNodeClosestToPos } from '@atlaskit/editor-prosemirror/utils';
7
7
  import { Decoration } from '@atlaskit/editor-prosemirror/view';
8
8
  import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
9
+ import { fg } from '@atlaskit/platform-feature-flags/fg';
9
10
  import { isExtendedEnabled } from '../isExtendedEnabled';
10
11
  import { buildAddedCellOverlayRoundedStyle, buildAddedCellOverlayStyle, buildDeletedBlockNodeStyle, buildDeletedCellOverlayRoundedStyle, buildDeletedCellOverlayStyle, buildInsertedBlockNodeStyle } from './colorSchemes/factory';
11
12
  import { colorSchemeRegistry, getLegacyColorScheme } from './colorSchemes/schemes';
12
13
  import { createBlockIndicatorAnchorWidgets } from './createAnchorDecorationWidgets';
13
14
  import { createContributorTagWidget, isContributorTagWidgetEnabled } from './createContributorTagWidget';
14
- import { AnchorTypeKey, buildAnchorDecorationKey, buildDiffDecorationSpec } from './decorationKeys';
15
+ import { AnchorTypeKey, buildDiffDecorationSpec, buildAnchorDecorationKey, scrollMarginTopStyle } from './decorationKeys';
15
16
  import { getBlockNodeStyleLegacy, resolveCellOverlayStyleLegacy } from './createBlockChangedDecoration.styles.legacy';
16
17
  var displayNoneStyle = convertToInlineCss({
17
18
  display: 'none'
@@ -243,7 +244,7 @@ export var createBlockChangedDecoration = function createBlockChangedDecoration(
243
244
  });
244
245
  var style = tagAnchorName ? [nodeStyle, convertToInlineCss({
245
246
  anchorName: "--".concat(tagAnchorName)
246
- })].filter(Boolean).join(' ') : nodeStyle;
247
+ }), fg('platform_editor_ai_show_diff_patch_1') ? scrollMarginTopStyle : undefined].filter(Boolean).join(' ') : nodeStyle;
247
248
  var className = getNodeClass(change.name);
248
249
  if (style || className) {
249
250
  decorations.push(Decoration.node(change.from, change.to, _objectSpread({