@atlaskit/editor-plugin-show-diff 16.0.8 → 16.0.10

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # @atlaskit/editor-plugin-show-diff
2
2
 
3
+ ## 16.0.10
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+
9
+ ## 16.0.9
10
+
11
+ ### Patch Changes
12
+
13
+ - [`c00ea38023074`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/c00ea38023074) -
14
+ [ux] Contributor tags on changed block nodes now sit on the block's own top-left corner, instead
15
+ of drifting by that node type's margin. Behind `confluence_ncs_step_diffing_version_history`.
16
+ - Updated dependencies
17
+
3
18
  ## 16.0.8
4
19
 
5
20
  ### Patch Changes
@@ -198,6 +198,11 @@ var createBlockChangedDecoration = exports.createBlockChangedDecoration = functi
198
198
  from: change.from,
199
199
  name: change.name
200
200
  });
201
+ // Named so this block's own tag can position against it; see `createContributorTagWidget`.
202
+ var tagAnchorName = shouldTagBlock && (0, _createContributorTagWidget.isContributorTagWidgetEnabled)() ? (0, _decorationKeys.buildAnchorDecorationKey)({
203
+ diffId: diffId,
204
+ anchorType: _decorationKeys.AnchorTypeKey.tag
205
+ }) : undefined;
201
206
  if (shouldHideDeleted) {
202
207
  return [_view.Decoration.node(change.from, change.to, {
203
208
  style: displayNoneStyle
@@ -236,13 +241,16 @@ var createBlockChangedDecoration = exports.createBlockChangedDecoration = functi
236
241
  }));
237
242
  }
238
243
  // isInserted is only read under the extended experience, so pass it unconditionally.
239
- var style = getBlockNodeStyle({
244
+ var nodeStyle = getBlockNodeStyle({
240
245
  nodeName: change.name,
241
246
  colorScheme: colorScheme,
242
247
  isInserted: isInserted,
243
248
  isActive: isActive,
244
249
  diffType: diffType
245
250
  });
251
+ var style = tagAnchorName ? [nodeStyle, (0, _lazyNodeView.convertToInlineCss)({
252
+ anchorName: "--".concat(tagAnchorName)
253
+ })].filter(Boolean).join(' ') : nodeStyle;
246
254
  var className = getNodeClass(change.name);
247
255
  if (style || className) {
248
256
  decorations.push(_view.Decoration.node(change.from, change.to, _objectSpread({
@@ -280,6 +288,7 @@ var createBlockChangedDecoration = exports.createBlockChangedDecoration = functi
280
288
  if (shouldTagBlock && doc) {
281
289
  var tagWidget = (0, _createContributorTagWidget.createContributorTagWidget)({
282
290
  anchorAtRangeStart: true,
291
+ anchorName: tagAnchorName,
283
292
  doc: doc,
284
293
  from: change.from,
285
294
  to: change.to,
@@ -38,13 +38,15 @@ var isContributorTagWidgetEnabled = exports.isContributorTagWidgetEnabled = func
38
38
  * (EDITOR-8702).
39
39
  */
40
40
  var mountContributorTag = exports.mountContributorTag = function mountContributorTag(_ref) {
41
- var diffId = _ref.diffId,
41
+ var anchorName = _ref.anchorName,
42
+ diffId = _ref.diffId,
42
43
  host = _ref.host,
43
44
  mountContext = _ref.mountContext;
44
45
  if (!mountContext) {
45
46
  return undefined;
46
47
  }
47
48
  var controller = new _contributorTagController.ContributorTagController(_objectSpread(_objectSpread({}, mountContext), {}, {
49
+ anchorName: anchorName,
48
50
  diffId: diffId
49
51
  }));
50
52
  controller.mount(host);
@@ -76,14 +78,25 @@ var unmountContributorTag = exports.unmountContributorTag = function unmountCont
76
78
  /**
77
79
  * A zero-size inline host for one contributor tag. `position: relative` makes it the containing
78
80
  * block of the absolutely positioned tag, so the tag sits on the change with no measurement.
81
+ *
82
+ * An anchored tag takes a static host instead: an anchor is only acceptable when it sits inside the
83
+ * tag's containing block, and the block node is not inside this host. Measured in Chrome 153 — a
84
+ * relative host makes the `anchor()` insets resolve to `auto`.
79
85
  */
80
- var buildContributorTagHost = function buildContributorTagHost(diffId) {
86
+ var buildContributorTagHost = function buildContributorTagHost(diffId, anchorName) {
81
87
  var host = document.createElement('span');
82
88
  host.setAttribute(CONTRIBUTOR_TAG_HOST_ATTRIBUTE, diffId);
83
- host.style.setProperty('position', 'relative');
89
+ if (!anchorName) {
90
+ host.style.setProperty('position', 'relative');
91
+ }
84
92
  return host;
85
93
  };
86
94
 
95
+ /** Without anchor positioning the tag keeps its host-relative placement. */
96
+ var supportsAnchorPositioning = function supportsAnchorPositioning() {
97
+ return typeof CSS !== 'undefined' && typeof CSS.supports === 'function' && CSS.supports('bottom', 'anchor(--a top)');
98
+ };
99
+
87
100
  /**
88
101
  * The host for a tag on deleted content, which renders inside its own widget decoration rather than
89
102
  * needing one of its own. Unmount with `unmountContributorTag` from that widget's `destroy`.
@@ -183,6 +196,7 @@ var resolveCodeBlockStart = function resolveCodeBlockStart(doc, pos) {
183
196
  var createContributorTagWidget = exports.createContributorTagWidget = function createContributorTagWidget(_ref3) {
184
197
  var _ref3$anchorAtRangeSt = _ref3.anchorAtRangeStart,
185
198
  anchorAtRangeStart = _ref3$anchorAtRangeSt === void 0 ? false : _ref3$anchorAtRangeSt,
199
+ anchorName = _ref3.anchorName,
186
200
  doc = _ref3.doc,
187
201
  from = _ref3.from,
188
202
  to = _ref3.to,
@@ -191,6 +205,7 @@ var createContributorTagWidget = exports.createContributorTagWidget = function c
191
205
  if (!isContributorTagWidgetEnabled()) {
192
206
  return undefined;
193
207
  }
208
+ var tagAnchorName = anchorName && supportsAnchorPositioning() ? anchorName : undefined;
194
209
 
195
210
  // Reassigned when ProseMirror redraws this decoration, which it may do more than once for the
196
211
  // same `Decoration` instance.
@@ -201,8 +216,9 @@ var createContributorTagWidget = exports.createContributorTagWidget = function c
201
216
  return _view.Decoration.widget(
202
217
  // Keep the host out of the table row's grid (EDITOR-8442).
203
218
  (0, _createAnchorDecorationWidgets.clampAnchorPosIntoCell)(doc, codeBlockPos !== null && codeBlockPos !== void 0 ? codeBlockPos : anchorPos, 1), function () {
204
- var host = buildContributorTagHost(diffId);
219
+ var host = buildContributorTagHost(diffId, tagAnchorName);
205
220
  mount = mountContributorTag({
221
+ anchorName: tagAnchorName,
206
222
  diffId: diffId,
207
223
  host: host,
208
224
  mountContext: mountContext
@@ -25,7 +25,9 @@ var AnchorTypeKey = exports.AnchorTypeKey = {
25
25
  from: 'from',
26
26
  to: 'to',
27
27
  left: 'left',
28
- docMargin: 'doc-margin'
28
+ docMargin: 'doc-margin',
29
+ /** The decorated block itself, which its contributor tag positions against. */
30
+ tag: 'tag'
29
31
  };
30
32
 
31
33
  /**
@@ -186,10 +186,19 @@ var createSpan = function createSpan(doc, style) {
186
186
  *
187
187
  * Built element by element rather than through `DOMSerializer.renderSpec`, which returns `Node` and
188
188
  * would need a cast per reference below.
189
+ *
190
+ * `anchorName` is the `anchor-name` its block carries — see `createContributorTagWidget`.
189
191
  */
190
- var buildContributorTagDom = exports.buildContributorTagDom = function buildContributorTagDom(doc) {
192
+ var buildContributorTagDom = exports.buildContributorTagDom = function buildContributorTagDom(doc, anchorName) {
191
193
  var labelId = generateLabelId();
192
194
  var root = createSpan(doc, constraintStyle);
195
+ if (anchorName) {
196
+ // Anchored to the block's own box, so the tag clears whatever margin its node type has — the
197
+ // same `anchor()` insets the `IndicatorBar` uses. A browser without anchor positioning rejects
198
+ // these values and keeps the `bottom: 100%` fallback above.
199
+ root.style.setProperty('bottom', "anchor(--".concat(anchorName, " top)"));
200
+ root.style.setProperty('inset-inline-start', "anchor(--".concat(anchorName, " left)"));
201
+ }
193
202
  var tag = createSpan(doc, tagStyle, {
194
203
  class: CONTRIBUTOR_TAG_CLASS,
195
204
  'data-testid': CONTRIBUTOR_TAG_TESTID,
@@ -186,7 +186,7 @@ var ContributorTagController = exports.ContributorTagController = /*#__PURE__*/f
186
186
  return;
187
187
  }
188
188
  if (!this.dom) {
189
- this.dom = (0, _buildContributorTagDom.buildContributorTagDom)(host.ownerDocument);
189
+ this.dom = (0, _buildContributorTagDom.buildContributorTagDom)(host.ownerDocument, this.options.anchorName);
190
190
  this.bindTag(this.dom);
191
191
  host.appendChild(this.dom.root);
192
192
  }
@@ -6,8 +6,8 @@ import { isExtendedEnabled } from '../isExtendedEnabled';
6
6
  import { buildAddedCellOverlayRoundedStyle, buildAddedCellOverlayStyle, buildDeletedBlockNodeStyle, buildDeletedCellOverlayRoundedStyle, buildDeletedCellOverlayStyle, buildInsertedBlockNodeStyle } from './colorSchemes/factory';
7
7
  import { colorSchemeRegistry, getLegacyColorScheme } from './colorSchemes/schemes';
8
8
  import { createBlockIndicatorAnchorWidgets } from './createAnchorDecorationWidgets';
9
- import { createContributorTagWidget } from './createContributorTagWidget';
10
- import { buildDiffDecorationSpec } from './decorationKeys';
9
+ import { createContributorTagWidget, isContributorTagWidgetEnabled } from './createContributorTagWidget';
10
+ import { AnchorTypeKey, buildAnchorDecorationKey, buildDiffDecorationSpec } from './decorationKeys';
11
11
  import { getBlockNodeStyleLegacy, resolveCellOverlayStyleLegacy } from './createBlockChangedDecoration.styles.legacy';
12
12
  const displayNoneStyle = convertToInlineCss({
13
13
  display: 'none'
@@ -178,6 +178,11 @@ export const createBlockChangedDecoration = ({
178
178
  from: change.from,
179
179
  name: change.name
180
180
  });
181
+ // Named so this block's own tag can position against it; see `createContributorTagWidget`.
182
+ const tagAnchorName = shouldTagBlock && isContributorTagWidgetEnabled() ? buildAnchorDecorationKey({
183
+ diffId,
184
+ anchorType: AnchorTypeKey.tag
185
+ }) : undefined;
181
186
  if (shouldHideDeleted) {
182
187
  return [Decoration.node(change.from, change.to, {
183
188
  style: displayNoneStyle
@@ -216,13 +221,16 @@ export const createBlockChangedDecoration = ({
216
221
  }));
217
222
  }
218
223
  // isInserted is only read under the extended experience, so pass it unconditionally.
219
- const style = getBlockNodeStyle({
224
+ const nodeStyle = getBlockNodeStyle({
220
225
  nodeName: change.name,
221
226
  colorScheme,
222
227
  isInserted,
223
228
  isActive,
224
229
  diffType
225
230
  });
231
+ const style = tagAnchorName ? [nodeStyle, convertToInlineCss({
232
+ anchorName: `--${tagAnchorName}`
233
+ })].filter(Boolean).join(' ') : nodeStyle;
226
234
  const className = getNodeClass(change.name);
227
235
  if (style || className) {
228
236
  decorations.push(Decoration.node(change.from, change.to, {
@@ -262,6 +270,7 @@ export const createBlockChangedDecoration = ({
262
270
  if (shouldTagBlock && doc) {
263
271
  const tagWidget = createContributorTagWidget({
264
272
  anchorAtRangeStart: true,
273
+ anchorName: tagAnchorName,
265
274
  doc,
266
275
  from: change.from,
267
276
  to: change.to,
@@ -27,6 +27,7 @@ export const isContributorTagWidgetEnabled = () => fg('confluence_ncs_step_diffi
27
27
  * (EDITOR-8702).
28
28
  */
29
29
  export const mountContributorTag = ({
30
+ anchorName,
30
31
  diffId,
31
32
  host,
32
33
  mountContext
@@ -36,6 +37,7 @@ export const mountContributorTag = ({
36
37
  }
37
38
  const controller = new ContributorTagController({
38
39
  ...mountContext,
40
+ anchorName,
39
41
  diffId
40
42
  });
41
43
  controller.mount(host);
@@ -65,14 +67,23 @@ export const unmountContributorTag = mount => {
65
67
  /**
66
68
  * A zero-size inline host for one contributor tag. `position: relative` makes it the containing
67
69
  * block of the absolutely positioned tag, so the tag sits on the change with no measurement.
70
+ *
71
+ * An anchored tag takes a static host instead: an anchor is only acceptable when it sits inside the
72
+ * tag's containing block, and the block node is not inside this host. Measured in Chrome 153 — a
73
+ * relative host makes the `anchor()` insets resolve to `auto`.
68
74
  */
69
- const buildContributorTagHost = diffId => {
75
+ const buildContributorTagHost = (diffId, anchorName) => {
70
76
  const host = document.createElement('span');
71
77
  host.setAttribute(CONTRIBUTOR_TAG_HOST_ATTRIBUTE, diffId);
72
- host.style.setProperty('position', 'relative');
78
+ if (!anchorName) {
79
+ host.style.setProperty('position', 'relative');
80
+ }
73
81
  return host;
74
82
  };
75
83
 
84
+ /** Without anchor positioning the tag keeps its host-relative placement. */
85
+ const supportsAnchorPositioning = () => typeof CSS !== 'undefined' && typeof CSS.supports === 'function' && CSS.supports('bottom', 'anchor(--a top)');
86
+
76
87
  /**
77
88
  * The host for a tag on deleted content, which renders inside its own widget decoration rather than
78
89
  * needing one of its own. Unmount with `unmountContributorTag` from that widget's `destroy`.
@@ -171,6 +182,7 @@ const resolveCodeBlockStart = (doc, pos) => {
171
182
  */
172
183
  export const createContributorTagWidget = ({
173
184
  anchorAtRangeStart = false,
185
+ anchorName,
174
186
  doc,
175
187
  from,
176
188
  to,
@@ -180,6 +192,7 @@ export const createContributorTagWidget = ({
180
192
  if (!isContributorTagWidgetEnabled()) {
181
193
  return undefined;
182
194
  }
195
+ const tagAnchorName = anchorName && supportsAnchorPositioning() ? anchorName : undefined;
183
196
 
184
197
  // Reassigned when ProseMirror redraws this decoration, which it may do more than once for the
185
198
  // same `Decoration` instance.
@@ -190,8 +203,9 @@ export const createContributorTagWidget = ({
190
203
  return Decoration.widget(
191
204
  // Keep the host out of the table row's grid (EDITOR-8442).
192
205
  clampAnchorPosIntoCell(doc, codeBlockPos !== null && codeBlockPos !== void 0 ? codeBlockPos : anchorPos, 1), () => {
193
- const host = buildContributorTagHost(diffId);
206
+ const host = buildContributorTagHost(diffId, tagAnchorName);
194
207
  mount = mountContributorTag({
208
+ anchorName: tagAnchorName,
195
209
  diffId,
196
210
  host,
197
211
  mountContext
@@ -12,7 +12,9 @@ export const AnchorTypeKey = {
12
12
  from: 'from',
13
13
  to: 'to',
14
14
  left: 'left',
15
- docMargin: 'doc-margin'
15
+ docMargin: 'doc-margin',
16
+ /** The decorated block itself, which its contributor tag positions against. */
17
+ tag: 'tag'
16
18
  };
17
19
 
18
20
  /**
@@ -172,10 +172,19 @@ const createSpan = (doc, style, attributes = {}) => {
172
172
  *
173
173
  * Built element by element rather than through `DOMSerializer.renderSpec`, which returns `Node` and
174
174
  * would need a cast per reference below.
175
+ *
176
+ * `anchorName` is the `anchor-name` its block carries — see `createContributorTagWidget`.
175
177
  */
176
- export const buildContributorTagDom = doc => {
178
+ export const buildContributorTagDom = (doc, anchorName) => {
177
179
  const labelId = generateLabelId();
178
180
  const root = createSpan(doc, constraintStyle);
181
+ if (anchorName) {
182
+ // Anchored to the block's own box, so the tag clears whatever margin its node type has — the
183
+ // same `anchor()` insets the `IndicatorBar` uses. A browser without anchor positioning rejects
184
+ // these values and keeps the `bottom: 100%` fallback above.
185
+ root.style.setProperty('bottom', `anchor(--${anchorName} top)`);
186
+ root.style.setProperty('inset-inline-start', `anchor(--${anchorName} left)`);
187
+ }
179
188
  const tag = createSpan(doc, tagStyle, {
180
189
  class: CONTRIBUTOR_TAG_CLASS,
181
190
  'data-testid': CONTRIBUTOR_TAG_TESTID,
@@ -160,7 +160,7 @@ export class ContributorTagController {
160
160
  return;
161
161
  }
162
162
  if (!this.dom) {
163
- this.dom = buildContributorTagDom(host.ownerDocument);
163
+ this.dom = buildContributorTagDom(host.ownerDocument, this.options.anchorName);
164
164
  this.bindTag(this.dom);
165
165
  host.appendChild(this.dom.root);
166
166
  }
@@ -10,8 +10,8 @@ import { isExtendedEnabled } from '../isExtendedEnabled';
10
10
  import { buildAddedCellOverlayRoundedStyle, buildAddedCellOverlayStyle, buildDeletedBlockNodeStyle, buildDeletedCellOverlayRoundedStyle, buildDeletedCellOverlayStyle, buildInsertedBlockNodeStyle } from './colorSchemes/factory';
11
11
  import { colorSchemeRegistry, getLegacyColorScheme } from './colorSchemes/schemes';
12
12
  import { createBlockIndicatorAnchorWidgets } from './createAnchorDecorationWidgets';
13
- import { createContributorTagWidget } from './createContributorTagWidget';
14
- import { buildDiffDecorationSpec } from './decorationKeys';
13
+ import { createContributorTagWidget, isContributorTagWidgetEnabled } from './createContributorTagWidget';
14
+ import { AnchorTypeKey, buildAnchorDecorationKey, buildDiffDecorationSpec } from './decorationKeys';
15
15
  import { getBlockNodeStyleLegacy, resolveCellOverlayStyleLegacy } from './createBlockChangedDecoration.styles.legacy';
16
16
  var displayNoneStyle = convertToInlineCss({
17
17
  display: 'none'
@@ -191,6 +191,11 @@ export var createBlockChangedDecoration = function createBlockChangedDecoration(
191
191
  from: change.from,
192
192
  name: change.name
193
193
  });
194
+ // Named so this block's own tag can position against it; see `createContributorTagWidget`.
195
+ var tagAnchorName = shouldTagBlock && isContributorTagWidgetEnabled() ? buildAnchorDecorationKey({
196
+ diffId: diffId,
197
+ anchorType: AnchorTypeKey.tag
198
+ }) : undefined;
194
199
  if (shouldHideDeleted) {
195
200
  return [Decoration.node(change.from, change.to, {
196
201
  style: displayNoneStyle
@@ -229,13 +234,16 @@ export var createBlockChangedDecoration = function createBlockChangedDecoration(
229
234
  }));
230
235
  }
231
236
  // isInserted is only read under the extended experience, so pass it unconditionally.
232
- var style = getBlockNodeStyle({
237
+ var nodeStyle = getBlockNodeStyle({
233
238
  nodeName: change.name,
234
239
  colorScheme: colorScheme,
235
240
  isInserted: isInserted,
236
241
  isActive: isActive,
237
242
  diffType: diffType
238
243
  });
244
+ var style = tagAnchorName ? [nodeStyle, convertToInlineCss({
245
+ anchorName: "--".concat(tagAnchorName)
246
+ })].filter(Boolean).join(' ') : nodeStyle;
239
247
  var className = getNodeClass(change.name);
240
248
  if (style || className) {
241
249
  decorations.push(Decoration.node(change.from, change.to, _objectSpread({
@@ -273,6 +281,7 @@ export var createBlockChangedDecoration = function createBlockChangedDecoration(
273
281
  if (shouldTagBlock && doc) {
274
282
  var tagWidget = createContributorTagWidget({
275
283
  anchorAtRangeStart: true,
284
+ anchorName: tagAnchorName,
276
285
  doc: doc,
277
286
  from: change.from,
278
287
  to: change.to,
@@ -32,13 +32,15 @@ export var isContributorTagWidgetEnabled = function isContributorTagWidgetEnable
32
32
  * (EDITOR-8702).
33
33
  */
34
34
  export var mountContributorTag = function mountContributorTag(_ref) {
35
- var diffId = _ref.diffId,
35
+ var anchorName = _ref.anchorName,
36
+ diffId = _ref.diffId,
36
37
  host = _ref.host,
37
38
  mountContext = _ref.mountContext;
38
39
  if (!mountContext) {
39
40
  return undefined;
40
41
  }
41
42
  var controller = new ContributorTagController(_objectSpread(_objectSpread({}, mountContext), {}, {
43
+ anchorName: anchorName,
42
44
  diffId: diffId
43
45
  }));
44
46
  controller.mount(host);
@@ -70,14 +72,25 @@ export var unmountContributorTag = function unmountContributorTag(mount) {
70
72
  /**
71
73
  * A zero-size inline host for one contributor tag. `position: relative` makes it the containing
72
74
  * block of the absolutely positioned tag, so the tag sits on the change with no measurement.
75
+ *
76
+ * An anchored tag takes a static host instead: an anchor is only acceptable when it sits inside the
77
+ * tag's containing block, and the block node is not inside this host. Measured in Chrome 153 — a
78
+ * relative host makes the `anchor()` insets resolve to `auto`.
73
79
  */
74
- var buildContributorTagHost = function buildContributorTagHost(diffId) {
80
+ var buildContributorTagHost = function buildContributorTagHost(diffId, anchorName) {
75
81
  var host = document.createElement('span');
76
82
  host.setAttribute(CONTRIBUTOR_TAG_HOST_ATTRIBUTE, diffId);
77
- host.style.setProperty('position', 'relative');
83
+ if (!anchorName) {
84
+ host.style.setProperty('position', 'relative');
85
+ }
78
86
  return host;
79
87
  };
80
88
 
89
+ /** Without anchor positioning the tag keeps its host-relative placement. */
90
+ var supportsAnchorPositioning = function supportsAnchorPositioning() {
91
+ return typeof CSS !== 'undefined' && typeof CSS.supports === 'function' && CSS.supports('bottom', 'anchor(--a top)');
92
+ };
93
+
81
94
  /**
82
95
  * The host for a tag on deleted content, which renders inside its own widget decoration rather than
83
96
  * needing one of its own. Unmount with `unmountContributorTag` from that widget's `destroy`.
@@ -177,6 +190,7 @@ var resolveCodeBlockStart = function resolveCodeBlockStart(doc, pos) {
177
190
  export var createContributorTagWidget = function createContributorTagWidget(_ref3) {
178
191
  var _ref3$anchorAtRangeSt = _ref3.anchorAtRangeStart,
179
192
  anchorAtRangeStart = _ref3$anchorAtRangeSt === void 0 ? false : _ref3$anchorAtRangeSt,
193
+ anchorName = _ref3.anchorName,
180
194
  doc = _ref3.doc,
181
195
  from = _ref3.from,
182
196
  to = _ref3.to,
@@ -185,6 +199,7 @@ export var createContributorTagWidget = function createContributorTagWidget(_ref
185
199
  if (!isContributorTagWidgetEnabled()) {
186
200
  return undefined;
187
201
  }
202
+ var tagAnchorName = anchorName && supportsAnchorPositioning() ? anchorName : undefined;
188
203
 
189
204
  // Reassigned when ProseMirror redraws this decoration, which it may do more than once for the
190
205
  // same `Decoration` instance.
@@ -195,8 +210,9 @@ export var createContributorTagWidget = function createContributorTagWidget(_ref
195
210
  return Decoration.widget(
196
211
  // Keep the host out of the table row's grid (EDITOR-8442).
197
212
  clampAnchorPosIntoCell(doc, codeBlockPos !== null && codeBlockPos !== void 0 ? codeBlockPos : anchorPos, 1), function () {
198
- var host = buildContributorTagHost(diffId);
213
+ var host = buildContributorTagHost(diffId, tagAnchorName);
199
214
  mount = mountContributorTag({
215
+ anchorName: tagAnchorName,
200
216
  diffId: diffId,
201
217
  host: host,
202
218
  mountContext: mountContext
@@ -16,7 +16,9 @@ export var AnchorTypeKey = {
16
16
  from: 'from',
17
17
  to: 'to',
18
18
  left: 'left',
19
- docMargin: 'doc-margin'
19
+ docMargin: 'doc-margin',
20
+ /** The decorated block itself, which its contributor tag positions against. */
21
+ tag: 'tag'
20
22
  };
21
23
 
22
24
  /**
@@ -179,10 +179,19 @@ var createSpan = function createSpan(doc, style) {
179
179
  *
180
180
  * Built element by element rather than through `DOMSerializer.renderSpec`, which returns `Node` and
181
181
  * would need a cast per reference below.
182
+ *
183
+ * `anchorName` is the `anchor-name` its block carries — see `createContributorTagWidget`.
182
184
  */
183
- export var buildContributorTagDom = function buildContributorTagDom(doc) {
185
+ export var buildContributorTagDom = function buildContributorTagDom(doc, anchorName) {
184
186
  var labelId = generateLabelId();
185
187
  var root = createSpan(doc, constraintStyle);
188
+ if (anchorName) {
189
+ // Anchored to the block's own box, so the tag clears whatever margin its node type has — the
190
+ // same `anchor()` insets the `IndicatorBar` uses. A browser without anchor positioning rejects
191
+ // these values and keeps the `bottom: 100%` fallback above.
192
+ root.style.setProperty('bottom', "anchor(--".concat(anchorName, " top)"));
193
+ root.style.setProperty('inset-inline-start', "anchor(--".concat(anchorName, " left)"));
194
+ }
186
195
  var tag = createSpan(doc, tagStyle, {
187
196
  class: CONTRIBUTOR_TAG_CLASS,
188
197
  'data-testid': CONTRIBUTOR_TAG_TESTID,
@@ -179,7 +179,7 @@ export var ContributorTagController = /*#__PURE__*/function () {
179
179
  return;
180
180
  }
181
181
  if (!this.dom) {
182
- this.dom = buildContributorTagDom(host.ownerDocument);
182
+ this.dom = buildContributorTagDom(host.ownerDocument, this.options.anchorName);
183
183
  this.bindTag(this.dom);
184
184
  host.appendChild(this.dom.root);
185
185
  }
@@ -28,7 +28,8 @@ export type ContributorTagMount = {
28
28
  * destroying the one it replaces, the outgoing `destroy` cannot take the incoming tag down with it
29
29
  * (EDITOR-8702).
30
30
  */
31
- export declare const mountContributorTag: ({ diffId, host, mountContext, }: {
31
+ export declare const mountContributorTag: ({ anchorName, diffId, host, mountContext, }: {
32
+ anchorName?: string;
32
33
  diffId: string;
33
34
  host: HTMLElement;
34
35
  mountContext: ContributorTagMountContext | undefined;
@@ -50,12 +51,18 @@ export declare const createContributorTagHost: (diffId: string, mountContext?: C
50
51
  * The tag is mounted in `toDOM` and taken down in `destroy`, so it lives exactly as long as the host
51
52
  * element ProseMirror drew it into — see `mountContributorTag`.
52
53
  */
53
- export declare const createContributorTagWidget: ({ anchorAtRangeStart, doc, from, to, diffId, mountContext, }: {
54
+ export declare const createContributorTagWidget: ({ anchorAtRangeStart, anchorName, doc, from, to, diffId, mountContext, }: {
54
55
  /**
55
56
  * Anchor the host at `from` instead of the range's first inline content, so a block range hosts
56
57
  * its tag outside the node rather than inside its content DOM.
57
58
  */
58
59
  anchorAtRangeStart?: boolean;
60
+ /**
61
+ * The `anchor-name` the block's own decoration carries, so the tag positions against that box
62
+ * rather than against its host — the block's margin and padding are then the browser's to
63
+ * resolve, and the tag sits on the same corner for every node type (EDITOR-8933).
64
+ */
65
+ anchorName?: string;
59
66
  diffId: string;
60
67
  doc: PMNode;
61
68
  from: number;
@@ -46,6 +46,8 @@ export declare const AnchorTypeKey: {
46
46
  readonly to: 'to';
47
47
  readonly left: 'left';
48
48
  readonly docMargin: 'doc-margin';
49
+ /** The decorated block itself, which its contributor tag positions against. */
50
+ readonly tag: 'tag';
49
51
  };
50
52
  export type InlineAnchorType = Exclude<(typeof AnchorTypeKey)[keyof typeof AnchorTypeKey], typeof AnchorTypeKey.docMargin>;
51
53
  export type AnchorDecorationSpec = (BaseDecorationSpec<typeof DecorationFamily.anchor> & {
@@ -60,5 +60,7 @@ export type ContributorTagDom = {
60
60
  *
61
61
  * Built element by element rather than through `DOMSerializer.renderSpec`, which returns `Node` and
62
62
  * would need a cast per reference below.
63
+ *
64
+ * `anchorName` is the `anchor-name` its block carries — see `createContributorTagWidget`.
63
65
  */
64
- export declare const buildContributorTagDom: (doc: Document) => ContributorTagDom;
66
+ export declare const buildContributorTagDom: (doc: Document, anchorName?: string) => ContributorTagDom;
@@ -2,6 +2,8 @@ import type { IntlShape } from 'react-intl';
2
2
  import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
3
3
  import type { ShowDiffPlugin } from '../../showDiffPluginType';
4
4
  export type ContributorTagControllerOptions = {
5
+ /** The `anchor-name` of the block this tag captions, when it has one. */
6
+ anchorName?: string;
5
7
  api?: ExtractInjectionAPI<ShowDiffPlugin>;
6
8
  diffId: string;
7
9
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-show-diff",
3
- "version": "16.0.8",
3
+ "version": "16.0.10",
4
4
  "description": "ShowDiff plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -32,7 +32,7 @@
32
32
  "@atlaskit/platform-feature-experiments": "^0.3.0",
33
33
  "@atlaskit/platform-feature-flags": "^2.2.0",
34
34
  "@atlaskit/primitives": "^22.5.0",
35
- "@atlaskit/tmp-editor-statsig": "^193.0.0",
35
+ "@atlaskit/tmp-editor-statsig": "^194.0.0",
36
36
  "@atlaskit/tokens": "^16.12.0",
37
37
  "@babel/runtime": "^7.0.0",
38
38
  "@compiled/react": "^1.0.2",
@@ -57,14 +57,14 @@
57
57
  "@atlassian/confluence-presets": "workspace:^",
58
58
  "@atlassian/content-reconciliation": "^0.1.3506",
59
59
  "@atlassian/editor-ai-injected-editors": "^32.0.0",
60
- "@atlassian/editor-plugin-ai": "^72.1.0",
60
+ "@atlassian/editor-plugin-ai": "^72.2.0",
61
61
  "@atlassian/structured-docs-types": "workspace:^",
62
62
  "react": "^19.2.0",
63
63
  "react-dom": "^19.2.0",
64
64
  "react-intl": "^7.0.0"
65
65
  },
66
66
  "peerDependencies": {
67
- "@atlaskit/editor-common": "^122.4.0",
67
+ "@atlaskit/editor-common": "^122.6.0",
68
68
  "react": "^18.2.0 || ^19.2.0",
69
69
  "react-dom": "^18.2.0 || ^19.2.0",
70
70
  "react-intl": "^5.25.1 || ^6.0.0 || ^7.0.0"