@atlaskit/editor-plugin-show-diff 16.0.16 → 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 (35) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/cjs/pm-plugins/decorations/createAnchorDecorationWidgets.js +19 -13
  3. package/dist/cjs/pm-plugins/decorations/createBlockChangedDecoration.js +2 -1
  4. package/dist/cjs/pm-plugins/decorations/createChangedRowDecorationWidgets.js +3 -0
  5. package/dist/cjs/pm-plugins/decorations/createInlineChangedDecoration.js +2 -1
  6. package/dist/cjs/pm-plugins/decorations/createNodeChangedDecorationWidget.js +9 -0
  7. package/dist/cjs/pm-plugins/decorations/decorationKeys.js +12 -2
  8. package/dist/cjs/pm-plugins/main.js +2 -2
  9. package/dist/cjs/pm-plugins/scrollToDiff.js +20 -0
  10. package/dist/cjs/ui/IndicatorBar/IndicatorBar.js +1 -1
  11. package/dist/cjs/ui/IndicatorBar/IndicatorBarContentComponent.js +1 -1
  12. package/dist/es2019/pm-plugins/decorations/createAnchorDecorationWidgets.js +7 -3
  13. package/dist/es2019/pm-plugins/decorations/createBlockChangedDecoration.js +4 -3
  14. package/dist/es2019/pm-plugins/decorations/createChangedRowDecorationWidgets.js +4 -1
  15. package/dist/es2019/pm-plugins/decorations/createInlineChangedDecoration.js +3 -2
  16. package/dist/es2019/pm-plugins/decorations/createNodeChangedDecorationWidget.js +10 -1
  17. package/dist/es2019/pm-plugins/decorations/decorationKeys.js +10 -0
  18. package/dist/es2019/pm-plugins/main.js +2 -2
  19. package/dist/es2019/pm-plugins/scrollToDiff.js +21 -3
  20. package/dist/es2019/ui/IndicatorBar/IndicatorBar.js +1 -1
  21. package/dist/es2019/ui/IndicatorBar/IndicatorBarContentComponent.js +1 -1
  22. package/dist/esm/pm-plugins/decorations/createAnchorDecorationWidgets.js +19 -13
  23. package/dist/esm/pm-plugins/decorations/createBlockChangedDecoration.js +3 -2
  24. package/dist/esm/pm-plugins/decorations/createChangedRowDecorationWidgets.js +4 -1
  25. package/dist/esm/pm-plugins/decorations/createInlineChangedDecoration.js +3 -2
  26. package/dist/esm/pm-plugins/decorations/createNodeChangedDecorationWidget.js +10 -1
  27. package/dist/esm/pm-plugins/decorations/decorationKeys.js +10 -0
  28. package/dist/esm/pm-plugins/main.js +2 -2
  29. package/dist/esm/pm-plugins/scrollToDiff.js +21 -2
  30. package/dist/esm/ui/IndicatorBar/IndicatorBar.js +1 -1
  31. package/dist/esm/ui/IndicatorBar/IndicatorBarContentComponent.js +1 -1
  32. package/dist/types/pm-plugins/decorations/decorationKeys.d.ts +9 -0
  33. package/dist/types/pm-plugins/scrollToDiff.d.ts +5 -1
  34. package/dist/types/showDiffPluginType.d.ts +2 -0
  35. package/package.json +3 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # @atlaskit/editor-plugin-show-diff
2
2
 
3
+ ## 16.0.17
4
+
5
+ ### Patch Changes
6
+
7
+ - [`bac902441a512`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/bac902441a512) -
8
+ Keep layout column diff indicators aligned with their content instead of appearing beside the
9
+ comments footer, behind `platform_editor_ai_show_diff_patch_1`.
10
+ - [`20d41af8d6f4c`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/20d41af8d6f4c) -
11
+ EDITOR-9000 Fixes scroll to suggestion when it is in table with sticky header
12
+ - Updated dependencies
13
+
3
14
  ## 16.0.16
4
15
 
5
16
  ### Patch Changes
@@ -220,6 +220,7 @@ var createLeftAnchorWidget = exports.createLeftAnchorWidget = function createLef
220
220
  *
221
221
  */
222
222
  var createBlockIndicatorAnchorWidgets = exports.createBlockIndicatorAnchorWidgets = function createBlockIndicatorAnchorWidgets(_ref2) {
223
+ var _ref3, _parentTable$pos;
223
224
  var doc = _ref2.doc,
224
225
  from = _ref2.from,
225
226
  to = _ref2.to,
@@ -259,9 +260,14 @@ var createBlockIndicatorAnchorWidgets = exports.createBlockIndicatorAnchorWidget
259
260
  var parentCellOrRow = (0, _utils.findParentNodeClosestToPos)($from, function (ancestor) {
260
261
  return ['tableCell', 'tableHeader', 'tableRow'].includes(ancestor.type.name);
261
262
  });
262
-
263
- // Render outside the table when inside one; otherwise keep the original pos.
264
- var widgetPos = parentTable ? parentTable.pos : from;
263
+ var parentLayout = (0, _fg.fg)('platform_editor_ai_show_diff_patch_1') ? (0, _utils.findParentNodeClosestToPos)($from, function (ancestor) {
264
+ return ancestor.type.name === 'layoutSection';
265
+ }) : undefined;
266
+ // Layouts flatten direct widget children with display: contents. Such a wrapper has no
267
+ // bounding box or positioning context, so measuring its top produces an offset from the
268
+ // viewport origin and displaces the indicator into content below the editor. Keep the
269
+ // wrapper outside the layout, just as we do for tables, but still measure the target node.
270
+ 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;
265
271
  // Measure the actual cell/row DOM when inside one; otherwise measure the
266
272
  // widget's own position.
267
273
  var measurePos = parentCellOrRow ? parentCellOrRow.pos : from;
@@ -360,11 +366,11 @@ var createAnchorNameSpan = exports.createAnchorNameSpan = function createAnchorN
360
366
  span.style.setProperty('anchor-name', "--".concat(anchorKey));
361
367
  return span;
362
368
  };
363
- var createAnchorSpanWidget = function createAnchorSpanWidget(_ref3) {
364
- var pos = _ref3.pos,
365
- diffId = _ref3.diffId,
366
- anchorType = _ref3.anchorType,
367
- side = _ref3.side;
369
+ var createAnchorSpanWidget = function createAnchorSpanWidget(_ref4) {
370
+ var pos = _ref4.pos,
371
+ diffId = _ref4.diffId,
372
+ anchorType = _ref4.anchorType,
373
+ side = _ref4.side;
368
374
  return _view.Decoration.widget(pos, function () {
369
375
  return createAnchorNameSpan((0, _decorationKeys.buildAnchorDecorationKey)({
370
376
  diffId: diffId,
@@ -381,11 +387,11 @@ var createAnchorSpanWidget = function createAnchorSpanWidget(_ref3) {
381
387
  * Invisible `from`/`to` (and optional `left`) anchor widgets for one inline diff
382
388
  * range, so the `IndicatorBar` can align itself via CSS anchor positioning.
383
389
  */
384
- var createInlineIndicatorAnchorWidgets = exports.createInlineIndicatorAnchorWidgets = function createInlineIndicatorAnchorWidgets(_ref4) {
385
- var doc = _ref4.doc,
386
- from = _ref4.from,
387
- to = _ref4.to,
388
- diffId = _ref4.diffId;
390
+ var createInlineIndicatorAnchorWidgets = exports.createInlineIndicatorAnchorWidgets = function createInlineIndicatorAnchorWidgets(_ref5) {
391
+ var doc = _ref5.doc,
392
+ from = _ref5.from,
393
+ to = _ref5.to,
394
+ diffId = _ref5.diffId;
389
395
  var leftAnchor = createLeftAnchorWidget({
390
396
  doc: doc,
391
397
  from: from,
@@ -11,6 +11,7 @@ var _lazyNodeView = require("@atlaskit/editor-common/lazy-node-view");
11
11
  var _utils = require("@atlaskit/editor-prosemirror/utils");
12
12
  var _view = require("@atlaskit/editor-prosemirror/view");
13
13
  var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-experiment-enabled");
14
+ var _fg = require("@atlaskit/platform-feature-flags/fg");
14
15
  var _isExtendedEnabled = require("../isExtendedEnabled");
15
16
  var _factory = require("./colorSchemes/factory");
16
17
  var _schemes = require("./colorSchemes/schemes");
@@ -250,7 +251,7 @@ var createBlockChangedDecoration = exports.createBlockChangedDecoration = functi
250
251
  });
251
252
  var style = tagAnchorName ? [nodeStyle, (0, _lazyNodeView.convertToInlineCss)({
252
253
  anchorName: "--".concat(tagAnchorName)
253
- })].filter(Boolean).join(' ') : nodeStyle;
254
+ }), (0, _fg.fg)('platform_editor_ai_show_diff_patch_1') ? _decorationKeys.scrollMarginTopStyle : undefined].filter(Boolean).join(' ') : nodeStyle;
254
255
  var className = getNodeClass(change.name);
255
256
  if (style || className) {
256
257
  decorations.push(_view.Decoration.node(change.from, change.to, _objectSpread({
@@ -184,6 +184,9 @@ var createChangedRowDOM = function createChangedRowDOM(rowNode, cellEdgeAttrs, n
184
184
  // is ADDED content, so it must not claim the "deleted" testid — page models match that as
185
185
  // removed content (same reasoning as `createTableCellContentWidgets`).
186
186
  tr.setAttribute('data-testid', (0, _isExtendedEnabled.isExtendedEnabled)(diffType) && isInserted && (0, _fg.fg)('platform_editor_ai_show_diff_patch_1') ? 'show-diff-changed-row' : 'show-diff-deleted-row');
187
+ if ((0, _fg.fg)('platform_editor_ai_show_diff_patch_1')) {
188
+ tr.style.setProperty('scroll-margin-top', _decorationKeys.scrollMarginTopValue);
189
+ }
187
190
 
188
191
  // Serialize each cell in the row
189
192
  var cellIndex = 0;
@@ -10,6 +10,7 @@ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/de
10
10
  var _lazyNodeView = require("@atlaskit/editor-common/lazy-node-view");
11
11
  var _view = require("@atlaskit/editor-prosemirror/view");
12
12
  var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-experiment-enabled");
13
+ var _fg = require("@atlaskit/platform-feature-flags/fg");
13
14
  var _buildContributorTagDom = require("../../ui/ContributorTag/buildContributorTagDom");
14
15
  var _isExtendedEnabled = require("../isExtendedEnabled");
15
16
  var _isEmptyParagraphSlice = require("../utils/isEmptyParagraphSlice");
@@ -215,7 +216,7 @@ var createInlineChangedDecoration = exports.createInlineChangedDecoration = func
215
216
  diffId: diffId,
216
217
  mountContext: tagMountContext
217
218
  }) : undefined;
218
- var inlineStyle = [style, atomicInlineAttrs === null || atomicInlineAttrs === void 0 ? void 0 : atomicInlineAttrs.styleSuffix, tagWidget ? stackBelowContributorTagStyle : undefined].filter(Boolean).join('');
219
+ var inlineStyle = [style, atomicInlineAttrs === null || atomicInlineAttrs === void 0 ? void 0 : atomicInlineAttrs.styleSuffix, tagWidget ? stackBelowContributorTagStyle : undefined, (0, _fg.fg)('platform_editor_ai_show_diff_patch_1') ? _decorationKeys.scrollMarginTopStyle : undefined].filter(Boolean).join('');
219
220
  var decorations = [_view.Decoration.inline(change.fromB, change.toB, _objectSpread(_objectSpread(_objectSpread({
220
221
  style: inlineStyle
221
222
  }, atomicInlineAttrs && {
@@ -80,6 +80,9 @@ var createTableCellContentWidgets = function createTableCellContentWidgets(_ref)
80
80
  // This helper only runs for added content, so use the "changed" testid — not
81
81
  // "deleted", which page models match as removed content.
82
82
  dom.setAttribute('data-testid', 'show-diff-changed-decoration');
83
+ if ((0, _fg.fg)('platform_editor_ai_show_diff_patch_1')) {
84
+ dom.style.setProperty('scroll-margin-top', _decorationKeys.scrollMarginTopValue);
85
+ }
83
86
 
84
87
  // Skip findSafeInsertPos: it walks forward to a schema-valid cell-insert point
85
88
  // and pushes the widget into the next cell. `targetPos` is the correct spot.
@@ -356,6 +359,9 @@ var createNodeChangedDecorationWidget = exports.createNodeChangedDecorationWidge
356
359
  }
357
360
  });
358
361
  dom.setAttribute('data-testid', 'show-diff-deleted-decoration');
362
+ if ((0, _fg.fg)('platform_editor_ai_show_diff_patch_1')) {
363
+ dom.style.setProperty('scroll-margin-top', _decorationKeys.scrollMarginTopValue);
364
+ }
359
365
 
360
366
  // Needed even when the indicator bar is off, because a contributor tag also anchors against the
361
367
  // widget.
@@ -435,6 +441,9 @@ var createNodeChangedDecorationWidget = exports.createNodeChangedDecorationWidge
435
441
  defaultSpacer.dataset.testid = 'show-diff-default-margin-spacer';
436
442
  defaultSpacer.style.display = 'block';
437
443
  defaultSpacer.style.marginTop = "var(--ds-space-100, 8px)";
444
+ if ((0, _fg.fg)('platform_editor_ai_show_diff_patch_1')) {
445
+ defaultSpacer.style.setProperty('scroll-margin-top', _decorationKeys.scrollMarginTopValue);
446
+ }
438
447
  decorations.push(_view.Decoration.widget(safeInsertPos, defaultSpacer, _objectSpread({}, (0, _decorationKeys.buildDiffDecorationSpec)({
439
448
  colorScheme: colorScheme,
440
449
  decorationType: 'widget',
@@ -4,9 +4,9 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.buildAnchorDecorationKey = exports.DiffDecorationKey = exports.DecorationFamily = exports.AnchorTypeKey = exports.AnchorDocMarginKey = void 0;
7
+ exports.buildAnchorDecorationKey = exports.SCROLL_TARGET_MARGIN_CSS_PROPERTY = exports.DiffDecorationKey = exports.DecorationFamily = exports.AnchorTypeKey = exports.AnchorDocMarginKey = void 0;
8
8
  exports.buildAnchorDecorationSpec = buildAnchorDecorationSpec;
9
- exports.isDiffDecorationSpec = exports.isDiffDecoration = exports.isAnchorDecorationSpec = exports.extractDiffDescriptors = exports.buildDiffDecorationSpec = exports.buildDiffDecorationKey = exports.buildContributorTagDecorationSpec = void 0;
9
+ exports.scrollMarginTopValue = exports.scrollMarginTopStyle = exports.isDiffDecorationSpec = exports.isDiffDecoration = exports.isAnchorDecorationSpec = exports.extractDiffDescriptors = exports.buildDiffDecorationSpec = exports.buildDiffDecorationKey = exports.buildContributorTagDecorationSpec = void 0;
10
10
  var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
11
11
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
12
12
  var _isExtendedEnabled = require("../isExtendedEnabled");
@@ -21,6 +21,16 @@ var DecorationFamily = exports.DecorationFamily = {
21
21
  anchor: 'anchor',
22
22
  contributorTag: 'contributor-tag'
23
23
  };
24
+
25
+ /**
26
+ * Navigation measures the target table header and writes this variable on the
27
+ * editor root immediately before scrolling. Diff decorations inherit it, so
28
+ * native scrolling leaves room for the header without DOM mutation on the
29
+ * ProseMirror-rendered suggestion.
30
+ */
31
+ var SCROLL_TARGET_MARGIN_CSS_PROPERTY = exports.SCROLL_TARGET_MARGIN_CSS_PROPERTY = '--ak-editor-diff-additional-margin';
32
+ var scrollMarginTopValue = exports.scrollMarginTopValue = "calc(".concat("var(--ds-space-400, 32px)", " + var(", SCROLL_TARGET_MARGIN_CSS_PROPERTY, ", 0px))");
33
+ var scrollMarginTopStyle = exports.scrollMarginTopStyle = "scroll-margin-top: ".concat(scrollMarginTopValue, ";");
24
34
  var AnchorTypeKey = exports.AnchorTypeKey = {
25
35
  from: 'from',
26
36
  to: 'to',
@@ -258,7 +258,7 @@ var createPlugin = exports.createPlugin = function createPlugin(config, getIntl,
258
258
  if (pluginState !== null && pluginState !== void 0 && pluginState.scrollIntoView && (0, _isExtendedEnabled.isExtendedEnabled)(pluginState === null || pluginState === void 0 ? void 0 : pluginState.diffType)) {
259
259
  var _cancelPendingScrollT;
260
260
  (_cancelPendingScrollT = cancelPendingScrollToDecoration) === null || _cancelPendingScrollT === void 0 || _cancelPendingScrollT();
261
- cancelPendingScrollToDecoration = (0, _scrollToDiff.scrollToDecoration)(view, (0, _getScrollableDecorations.getScrollableDecorations)(pluginState.decorations, view.state.doc, pluginState === null || pluginState === void 0 ? void 0 : pluginState.diffType));
261
+ cancelPendingScrollToDecoration = (0, _scrollToDiff.scrollToDecoration)(view, (0, _getScrollableDecorations.getScrollableDecorations)(pluginState.decorations, view.state.doc, pluginState === null || pluginState === void 0 ? void 0 : pluginState.diffType), undefined, api);
262
262
 
263
263
  // Reset the flag so we don't scroll again on subsequent updates
264
264
  view.dispatch(view.state.tr.setMeta(showDiffPluginKey, {
@@ -279,7 +279,7 @@ var createPlugin = exports.createPlugin = function createPlugin(config, getIntl,
279
279
  // avoid a circular dependency; expand picks up the meta if loaded (no-op if not).
280
280
  api === null || api === void 0 || api.core.actions.execute((0, _expand.toggleExpandRange)(activeDecoration.from, activeDecoration.to, true));
281
281
  }
282
- cancelPendingScrollToDecoration = (0, _scrollToDiff.scrollToDecoration)(view, scrollableDecorations, pluginState.activeIndex);
282
+ cancelPendingScrollToDecoration = (0, _scrollToDiff.scrollToDecoration)(view, scrollableDecorations, pluginState.activeIndex, api);
283
283
 
284
284
  // Stepping only scrolls — no focus moves and no content changes — so without this a
285
285
  // screen-reader user gets silence. Announced through the live region rather than by
@@ -4,6 +4,9 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.scrollToDecoration = void 0;
7
+ var _styles = require("@atlaskit/editor-common/styles");
8
+ var _getStickyHeaderHeight = require("@atlaskit/editor-common/table/get-sticky-header-height");
9
+ var _fg = require("@atlaskit/platform-feature-flags/fg");
7
10
  var _decorationKeys = require("./decorations/decorationKeys");
8
11
  /**
9
12
  * Extra space above the scrolled-to element so it does not sit flush under the
@@ -15,6 +18,12 @@ var _decorationKeys = require("./decorations/decorationKeys");
15
18
  * outer scroll or mis-identifies the active scroll container.
16
19
  */
17
20
  var SCROLL_TOP_MARGIN_PX = 100;
21
+ function updateScrollTargetMargin(view, targetPos, api) {
22
+ var _api$limitedMode;
23
+ 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);
24
+ var tableHeaderHeight = isLimitedModeEnabled ? undefined : (0, _getStickyHeaderHeight.getStickyHeaderHeight)(view, targetPos);
25
+ view.dom.style.setProperty(_decorationKeys.SCROLL_TARGET_MARGIN_CSS_PROPERTY, "".concat(tableHeaderHeight ? tableHeaderHeight + _styles.tableMarginTop : 0, "px"));
26
+ }
18
27
 
19
28
  /**
20
29
  * Returns the resolved HTMLElement for a given DOM node, walking up to the
@@ -25,6 +34,13 @@ function scrollToSelection(node) {
25
34
  if (!(element instanceof HTMLElement)) {
26
35
  return;
27
36
  }
37
+ if ((0, _fg.fg)('platform_editor_ai_show_diff_patch_1')) {
38
+ element.scrollIntoView({
39
+ behavior: 'smooth',
40
+ block: 'start'
41
+ });
42
+ return;
43
+ }
28
44
 
29
45
  // scroll-margin is included in scroll-into-view math; it does not change layout.
30
46
  var previousScrollMarginTop = element.style.scrollMarginTop;
@@ -47,6 +63,7 @@ function scrollToSelection(node) {
47
63
  */
48
64
  var scrollToDecoration = exports.scrollToDecoration = function scrollToDecoration(view, decorations) {
49
65
  var activeIndex = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
66
+ var api = arguments.length > 3 ? arguments[3] : undefined;
50
67
  var decoration = decorations[activeIndex];
51
68
  if (!decoration) {
52
69
  return function () {};
@@ -58,6 +75,9 @@ var scrollToDecoration = exports.scrollToDecoration = function scrollToDecoratio
58
75
  var target = (0, _decorationKeys.isDiffDecoration)(decoration) && decoration.spec.scrollTarget || decoration;
59
76
  var rafId = requestAnimationFrame(function () {
60
77
  rafId = null;
78
+ if ((0, _fg.fg)('platform_editor_ai_show_diff_patch_1')) {
79
+ updateScrollTargetMargin(view, target.from, api);
80
+ }
61
81
  if ((0, _decorationKeys.isDiffDecoration)(target) && target.spec.decorationType === 'widget') {
62
82
  var _target$type;
63
83
  // @ts-expect-error - decoration.type is not typed public API
@@ -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
  "use strict";
3
3
 
4
4
  var _typeof = require("@babel/runtime/helpers/typeof");
@@ -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
  "use strict";
3
3
 
4
4
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
@@ -220,6 +220,7 @@ export const createBlockIndicatorAnchorWidgets = ({
220
220
  to,
221
221
  diffId
222
222
  }) => {
223
+ var _ref, _parentTable$pos;
223
224
  const leftAnchor = createLeftAnchorWidget({
224
225
  doc,
225
226
  from,
@@ -251,9 +252,12 @@ export const createBlockIndicatorAnchorWidgets = ({
251
252
  const $from = doc.resolve(from);
252
253
  const parentTable = findParentNodeClosestToPos($from, ancestor => ancestor.type.name === 'table');
253
254
  const parentCellOrRow = findParentNodeClosestToPos($from, ancestor => ['tableCell', 'tableHeader', 'tableRow'].includes(ancestor.type.name));
254
-
255
- // Render outside the table when inside one; otherwise keep the original pos.
256
- const widgetPos = parentTable ? parentTable.pos : from;
255
+ const parentLayout = fg('platform_editor_ai_show_diff_patch_1') ? findParentNodeClosestToPos($from, ancestor => ancestor.type.name === 'layoutSection') : undefined;
256
+ // Layouts flatten direct widget children with display: contents. Such a wrapper has no
257
+ // bounding box or positioning context, so measuring its top produces an offset from the
258
+ // viewport origin and displaces the indicator into content below the editor. Keep the
259
+ // wrapper outside the layout, just as we do for tables, but still measure the target node.
260
+ const widgetPos = (_ref = (_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 && _ref !== void 0 ? _ref : from;
257
261
  // Measure the actual cell/row DOM when inside one; otherwise measure the
258
262
  // widget's own position.
259
263
  const measurePos = parentCellOrRow ? parentCellOrRow.pos : from;
@@ -2,12 +2,13 @@ import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
2
2
  import { findParentNodeClosestToPos } from '@atlaskit/editor-prosemirror/utils';
3
3
  import { Decoration } from '@atlaskit/editor-prosemirror/view';
4
4
  import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
5
+ import { fg } from '@atlaskit/platform-feature-flags/fg';
5
6
  import { isExtendedEnabled } from '../isExtendedEnabled';
6
7
  import { buildAddedCellOverlayRoundedStyle, buildAddedCellOverlayStyle, buildDeletedBlockNodeStyle, buildDeletedCellOverlayRoundedStyle, buildDeletedCellOverlayStyle, buildInsertedBlockNodeStyle } from './colorSchemes/factory';
7
8
  import { colorSchemeRegistry, getLegacyColorScheme } from './colorSchemes/schemes';
8
9
  import { createBlockIndicatorAnchorWidgets } from './createAnchorDecorationWidgets';
9
10
  import { createContributorTagWidget, isContributorTagWidgetEnabled } from './createContributorTagWidget';
10
- import { AnchorTypeKey, buildAnchorDecorationKey, buildDiffDecorationSpec } from './decorationKeys';
11
+ import { AnchorTypeKey, buildDiffDecorationSpec, buildAnchorDecorationKey, scrollMarginTopStyle } from './decorationKeys';
11
12
  import { getBlockNodeStyleLegacy, resolveCellOverlayStyleLegacy } from './createBlockChangedDecoration.styles.legacy';
12
13
  const displayNoneStyle = convertToInlineCss({
13
14
  display: 'none'
@@ -230,11 +231,11 @@ export const createBlockChangedDecoration = ({
230
231
  });
231
232
  const style = tagAnchorName ? [nodeStyle, convertToInlineCss({
232
233
  anchorName: `--${tagAnchorName}`
233
- })].filter(Boolean).join(' ') : nodeStyle;
234
+ }), fg('platform_editor_ai_show_diff_patch_1') ? scrollMarginTopStyle : undefined].filter(Boolean).join(' ') : nodeStyle;
234
235
  const className = getNodeClass(change.name);
235
236
  if (style || className) {
236
237
  decorations.push(Decoration.node(change.from, change.to, {
237
- style: style,
238
+ style,
238
239
  'data-testid': 'show-diff-changed-decoration-node',
239
240
  class: className,
240
241
  // Lets the contributor tag find the block it captions on hover.
@@ -11,7 +11,7 @@ import { colorSchemeRegistry, getLegacyColorScheme } from './colorSchemes/scheme
11
11
  import { createLeftAnchorWidget } from './createAnchorDecorationWidgets';
12
12
  import { resolveCellOverlayStyleLegacy, resolveDeletedRowStyleLegacy } from './createChangedRowDecorationWidgets.styles.legacy';
13
13
  import { createContributorTagWidget, isContributorTagWidgetEnabled } from './createContributorTagWidget';
14
- import { AnchorTypeKey, buildAnchorDecorationKey, buildDiffDecorationSpec } from './decorationKeys';
14
+ import { AnchorTypeKey, buildAnchorDecorationKey, buildDiffDecorationSpec, scrollMarginTopValue } from './decorationKeys';
15
15
  import { findSafeInsertPos } from './utils/findSafeInsertPos';
16
16
  import { applyCellEdgeAttrs, getRowCellEdgeAttrs, getTableTopAndBottomCellEdgeAttrs } from './utils/tableCellEdgeAttrs';
17
17
  /**
@@ -160,6 +160,9 @@ const createChangedRowDOM = (rowNode, cellEdgeAttrs, nodeViewSerializer, colorSc
160
160
  // is ADDED content, so it must not claim the "deleted" testid — page models match that as
161
161
  // removed content (same reasoning as `createTableCellContentWidgets`).
162
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
+ }
163
166
 
164
167
  // Serialize each cell in the row
165
168
  let cellIndex = 0;
@@ -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.
@@ -334,6 +337,9 @@ export const createNodeChangedDecorationWidget = ({
334
337
  }
335
338
  });
336
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
+ }
337
343
 
338
344
  // Needed even when the indicator bar is off, because a contributor tag also anchors against the
339
345
  // widget.
@@ -420,6 +426,9 @@ export const createNodeChangedDecorationWidget = ({
420
426
  defaultSpacer.dataset.testid = 'show-diff-default-margin-spacer';
421
427
  defaultSpacer.style.display = 'block';
422
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
+ }
423
432
  decorations.push(Decoration.widget(safeInsertPos, defaultSpacer, {
424
433
  ...buildDiffDecorationSpec({
425
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,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';
@@ -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({
@@ -18,7 +18,7 @@ import { colorSchemeRegistry, getLegacyColorScheme } from './colorSchemes/scheme
18
18
  import { createLeftAnchorWidget } from './createAnchorDecorationWidgets';
19
19
  import { resolveCellOverlayStyleLegacy, resolveDeletedRowStyleLegacy } from './createChangedRowDecorationWidgets.styles.legacy';
20
20
  import { createContributorTagWidget, isContributorTagWidgetEnabled } from './createContributorTagWidget';
21
- import { AnchorTypeKey, buildAnchorDecorationKey, buildDiffDecorationSpec } from './decorationKeys';
21
+ import { AnchorTypeKey, buildAnchorDecorationKey, buildDiffDecorationSpec, scrollMarginTopValue } from './decorationKeys';
22
22
  import { findSafeInsertPos } from './utils/findSafeInsertPos';
23
23
  import { applyCellEdgeAttrs, getRowCellEdgeAttrs, getTableTopAndBottomCellEdgeAttrs } from './utils/tableCellEdgeAttrs';
24
24
  /**
@@ -177,6 +177,9 @@ var createChangedRowDOM = function createChangedRowDOM(rowNode, cellEdgeAttrs, n
177
177
  // is ADDED content, so it must not claim the "deleted" testid — page models match that as
178
178
  // removed content (same reasoning as `createTableCellContentWidgets`).
179
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
+ }
180
183
 
181
184
  // Serialize each cell in the row
182
185
  var cellIndex = 0;
@@ -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.
@@ -349,6 +352,9 @@ export var createNodeChangedDecorationWidget = function createNodeChangedDecorat
349
352
  }
350
353
  });
351
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
+ }
352
358
 
353
359
  // Needed even when the indicator bar is off, because a contributor tag also anchors against the
354
360
  // widget.
@@ -428,6 +434,9 @@ export var createNodeChangedDecorationWidget = function createNodeChangedDecorat
428
434
  defaultSpacer.dataset.testid = 'show-diff-default-margin-spacer';
429
435
  defaultSpacer.style.display = 'block';
430
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
+ }
431
440
  decorations.push(Decoration.widget(safeInsertPos, defaultSpacer, _objectSpread({}, buildDiffDecorationSpec({
432
441
  colorScheme: colorScheme,
433
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,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';
@@ -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
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-show-diff",
3
- "version": "16.0.16",
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",
@@ -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"