@atlaskit/editor-plugin-show-diff 17.0.1 → 17.0.2
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 +15 -0
- package/dist/cjs/pm-plugins/calculateDiff/calculateDiffDecorations.js +126 -49
- package/dist/cjs/pm-plugins/calculateDiff/groupDeletedColumnChanges.js +265 -0
- package/dist/cjs/pm-plugins/decorations/createChangedRowDecorationWidgets.js +100 -34
- package/dist/cjs/pm-plugins/decorations/createContributorTagWidget.js +18 -13
- package/dist/cjs/pm-plugins/decorations/createNodeChangedDecorationWidget.js +82 -20
- package/dist/cjs/pm-plugins/decorations/utils/createDeletedLineBreakWidget.js +106 -0
- package/dist/cjs/pm-plugins/decorations/utils/tableDiffMode.js +36 -0
- package/dist/cjs/pm-plugins/decorations/utils/wrapBlockNodeView.js +17 -6
- package/dist/cjs/pm-plugins/utils/emptyTextBlocks.js +66 -0
- package/dist/es2019/pm-plugins/calculateDiff/calculateDiffDecorations.js +61 -1
- package/dist/es2019/pm-plugins/calculateDiff/groupDeletedColumnChanges.js +210 -0
- package/dist/es2019/pm-plugins/decorations/createChangedRowDecorationWidgets.js +79 -13
- package/dist/es2019/pm-plugins/decorations/createContributorTagWidget.js +8 -2
- package/dist/es2019/pm-plugins/decorations/createNodeChangedDecorationWidget.js +85 -15
- package/dist/es2019/pm-plugins/decorations/utils/createDeletedLineBreakWidget.js +100 -0
- package/dist/es2019/pm-plugins/decorations/utils/tableDiffMode.js +27 -0
- package/dist/es2019/pm-plugins/decorations/utils/wrapBlockNodeView.js +15 -5
- package/dist/es2019/pm-plugins/utils/emptyTextBlocks.js +58 -0
- package/dist/esm/pm-plugins/calculateDiff/calculateDiffDecorations.js +127 -50
- package/dist/esm/pm-plugins/calculateDiff/groupDeletedColumnChanges.js +258 -0
- package/dist/esm/pm-plugins/decorations/createChangedRowDecorationWidgets.js +100 -34
- package/dist/esm/pm-plugins/decorations/createContributorTagWidget.js +18 -13
- package/dist/esm/pm-plugins/decorations/createNodeChangedDecorationWidget.js +84 -22
- package/dist/esm/pm-plugins/decorations/utils/createDeletedLineBreakWidget.js +100 -0
- package/dist/esm/pm-plugins/decorations/utils/tableDiffMode.js +30 -0
- package/dist/esm/pm-plugins/decorations/utils/wrapBlockNodeView.js +16 -5
- package/dist/esm/pm-plugins/utils/emptyTextBlocks.js +60 -0
- package/dist/types/pm-plugins/calculateDiff/groupDeletedColumnChanges.d.ts +9 -0
- package/dist/types/pm-plugins/decorations/createChangedRowDecorationWidgets.d.ts +3 -1
- package/dist/types/pm-plugins/decorations/createContributorTagWidget.d.ts +5 -1
- package/dist/types/pm-plugins/decorations/createNodeChangedDecorationWidget.d.ts +2 -1
- package/dist/types/pm-plugins/decorations/utils/createDeletedLineBreakWidget.d.ts +50 -0
- package/dist/types/pm-plugins/decorations/utils/tableDiffMode.d.ts +26 -0
- package/dist/types/pm-plugins/decorations/utils/wrapBlockNodeView.d.ts +4 -0
- package/dist/types/pm-plugins/utils/emptyTextBlocks.d.ts +16 -0
- package/package.json +2 -2
|
@@ -20,6 +20,7 @@ import { resolveCellOverlayStyleLegacy, resolveDeletedRowStyleLegacy } from './c
|
|
|
20
20
|
import { createContributorTagWidget, isContributorTagWidgetEnabled } from './createContributorTagWidget';
|
|
21
21
|
import { AnchorTypeKey, buildAnchorDecorationKey, buildDiffDecorationSpec, scrollMarginTopValue } from './decorationKeys';
|
|
22
22
|
import { findSafeInsertPos } from './utils/findSafeInsertPos';
|
|
23
|
+
import { createRemovedLozenge } from './utils/wrapBlockNodeView';
|
|
23
24
|
import { applyCellEdgeAttrs, getRowCellEdgeAttrs, getTableTopAndBottomCellEdgeAttrs } from './utils/tableCellEdgeAttrs';
|
|
24
25
|
/**
|
|
25
26
|
* Extracts information about deleted table rows from a change
|
|
@@ -161,17 +162,27 @@ var isEmptyRow = function isEmptyRow(rowNode) {
|
|
|
161
162
|
});
|
|
162
163
|
return isEmpty;
|
|
163
164
|
};
|
|
164
|
-
|
|
165
165
|
/**
|
|
166
166
|
* Creates a DOM representation of a deleted table row
|
|
167
167
|
*/
|
|
168
|
-
var createChangedRowDOM = function createChangedRowDOM(
|
|
168
|
+
var createChangedRowDOM = function createChangedRowDOM(_ref3) {
|
|
169
|
+
var rowNode = _ref3.rowNode,
|
|
170
|
+
cellEdgeAttrs = _ref3.cellEdgeAttrs,
|
|
171
|
+
nodeViewSerializer = _ref3.nodeViewSerializer,
|
|
172
|
+
colorScheme = _ref3.colorScheme,
|
|
173
|
+
isInserted = _ref3.isInserted,
|
|
174
|
+
diffType = _ref3.diffType,
|
|
175
|
+
hasAnchoredRemovedLozenge = _ref3.hasAnchoredRemovedLozenge,
|
|
176
|
+
intl = _ref3.intl,
|
|
177
|
+
isActive = _ref3.isActive;
|
|
169
178
|
var tr = document.createElement('tr');
|
|
170
179
|
var colors = colorSchemeRegistry[colorScheme !== null && colorScheme !== void 0 ? colorScheme : 'standard'];
|
|
180
|
+
var deletedTreatment = isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? buildDeletedRowStyle(colors) : resolveDeletedRowStyleLegacy(getLegacyColorScheme(colorScheme));
|
|
181
|
+
var hostsRemovedLozenge = Boolean(intl) && isExtendedEnabled(diffType) && !isInserted && !hasAnchoredRemovedLozenge;
|
|
171
182
|
|
|
172
183
|
// Inserted rows keep their natural styling; the row strikethrough is deletions only.
|
|
173
184
|
if (!isExtendedEnabled(diffType) || !isInserted) {
|
|
174
|
-
tr.setAttribute('style',
|
|
185
|
+
tr.setAttribute('style', deletedTreatment);
|
|
175
186
|
}
|
|
176
187
|
// Mirrors the strikethrough condition above: under the extended experience an `isInserted` row
|
|
177
188
|
// is ADDED content, so it must not claim the "deleted" testid — page models match that as
|
|
@@ -212,17 +223,50 @@ var createChangedRowDOM = function createChangedRowDOM(rowNode, cellEdgeAttrs, n
|
|
|
212
223
|
cellIndex++;
|
|
213
224
|
}
|
|
214
225
|
});
|
|
226
|
+
|
|
227
|
+
// A "Removed" label on the row's last cell, so it reads at the row's top right corner. Deletions
|
|
228
|
+
// only: an inserted row is added content and carries no removal label.
|
|
229
|
+
if (intl && hostsRemovedLozenge) {
|
|
230
|
+
var lastCell = tr.lastElementChild;
|
|
231
|
+
if (lastCell instanceof HTMLElement) {
|
|
232
|
+
lastCell.style.position = 'relative';
|
|
233
|
+
// Append, never prepend. Editor CSS resets the top margin of a cell's first child, so a
|
|
234
|
+
// prepended label pushes the paragraph out of that reset and the row grows taller.
|
|
235
|
+
lastCell.append(createRemovedLozenge(intl, isActive, colorScheme, true));
|
|
236
|
+
}
|
|
237
|
+
}
|
|
215
238
|
return tr;
|
|
216
239
|
};
|
|
240
|
+
var supportsAnchorPositioning = function supportsAnchorPositioning() {
|
|
241
|
+
return typeof CSS !== 'undefined' && typeof CSS.supports === 'function' && CSS.supports('top', 'anchor(--a top)');
|
|
242
|
+
};
|
|
243
|
+
var createAnchoredRemovedLozengeWidget = function createAnchoredRemovedLozengeWidget(_ref4) {
|
|
244
|
+
var anchorName = _ref4.anchorName,
|
|
245
|
+
colorScheme = _ref4.colorScheme,
|
|
246
|
+
from = _ref4.from,
|
|
247
|
+
intl = _ref4.intl,
|
|
248
|
+
isActive = _ref4.isActive;
|
|
249
|
+
var lozenge = createRemovedLozenge(intl, isActive, colorScheme, true);
|
|
250
|
+
var inset = lozenge.style.top;
|
|
251
|
+
lozenge.style.setProperty('position', 'fixed');
|
|
252
|
+
lozenge.style.setProperty('top', "calc(anchor(--".concat(anchorName, " top) + ").concat(inset, ")"));
|
|
253
|
+
lozenge.style.setProperty('left', "calc(anchor(--".concat(anchorName, " right) - ").concat(inset, ")"));
|
|
254
|
+
lozenge.style.setProperty('right', 'auto');
|
|
255
|
+
lozenge.style.setProperty('transform', 'translateX(-100%)');
|
|
256
|
+
return Decoration.widget(from, lozenge, {
|
|
257
|
+
key: "removed-lozenge-".concat(anchorName),
|
|
258
|
+
side: -1
|
|
259
|
+
});
|
|
260
|
+
};
|
|
217
261
|
|
|
218
262
|
/**
|
|
219
263
|
* Expands a diff to include whole changed rows when table rows are affected
|
|
220
264
|
*/
|
|
221
|
-
var expandDiffForChangedRows = function expandDiffForChangedRows(
|
|
222
|
-
var changes =
|
|
223
|
-
originalDoc =
|
|
224
|
-
newDoc =
|
|
225
|
-
diffType =
|
|
265
|
+
var expandDiffForChangedRows = function expandDiffForChangedRows(_ref5) {
|
|
266
|
+
var changes = _ref5.changes,
|
|
267
|
+
originalDoc = _ref5.originalDoc,
|
|
268
|
+
newDoc = _ref5.newDoc,
|
|
269
|
+
diffType = _ref5.diffType;
|
|
226
270
|
var rowInfo = [];
|
|
227
271
|
var _iterator = _createForOfIteratorHelper(changes),
|
|
228
272
|
_step;
|
|
@@ -251,22 +295,23 @@ var expandDiffForChangedRows = function expandDiffForChangedRows(_ref3) {
|
|
|
251
295
|
/**
|
|
252
296
|
* Main function to handle deleted rows - computes diff and creates decorations
|
|
253
297
|
*/
|
|
254
|
-
export var createChangedRowDecorationWidgets = function createChangedRowDecorationWidgets(
|
|
255
|
-
var attributionKey =
|
|
256
|
-
changes =
|
|
257
|
-
originalDoc =
|
|
258
|
-
newDoc =
|
|
259
|
-
nodeViewSerializer =
|
|
260
|
-
colorScheme =
|
|
261
|
-
isActive =
|
|
262
|
-
|
|
263
|
-
isInserted =
|
|
264
|
-
diffType =
|
|
265
|
-
|
|
266
|
-
showIndicators =
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
298
|
+
export var createChangedRowDecorationWidgets = function createChangedRowDecorationWidgets(_ref6) {
|
|
299
|
+
var attributionKey = _ref6.attributionKey,
|
|
300
|
+
changes = _ref6.changes,
|
|
301
|
+
originalDoc = _ref6.originalDoc,
|
|
302
|
+
newDoc = _ref6.newDoc,
|
|
303
|
+
nodeViewSerializer = _ref6.nodeViewSerializer,
|
|
304
|
+
colorScheme = _ref6.colorScheme,
|
|
305
|
+
isActive = _ref6.isActive,
|
|
306
|
+
_ref6$isInserted = _ref6.isInserted,
|
|
307
|
+
isInserted = _ref6$isInserted === void 0 ? false : _ref6$isInserted,
|
|
308
|
+
diffType = _ref6.diffType,
|
|
309
|
+
intl = _ref6.intl,
|
|
310
|
+
_ref6$showIndicators = _ref6.showIndicators,
|
|
311
|
+
showIndicators = _ref6$showIndicators === void 0 ? false : _ref6$showIndicators,
|
|
312
|
+
_ref6$showContributor = _ref6.showContributorTags,
|
|
313
|
+
showContributorTags = _ref6$showContributor === void 0 ? false : _ref6$showContributor,
|
|
314
|
+
tagMountContext = _ref6.tagMountContext;
|
|
270
315
|
// First, expand the changes to include complete deleted rows
|
|
271
316
|
var changedRows = expandDiffForChangedRows({
|
|
272
317
|
changes: changes.filter(function (change) {
|
|
@@ -277,16 +322,25 @@ export var createChangedRowDecorationWidgets = function createChangedRowDecorati
|
|
|
277
322
|
diffType: diffType
|
|
278
323
|
});
|
|
279
324
|
return changedRows.flatMap(function (changedRow) {
|
|
280
|
-
|
|
325
|
+
// Keep the ID stable while contributor tags are enabled so recalculation preserves their state.
|
|
326
|
+
var diffId = showContributorTags ? "widget-row-".concat(changedRow.fromA, "-").concat(changedRow.toA) : crypto.randomUUID();
|
|
327
|
+
var hasAnchoredRemovedLozenge = Boolean(intl) && isExtendedEnabled(diffType) && !isInserted && supportsAnchorPositioning();
|
|
328
|
+
var rowDOM = createChangedRowDOM({
|
|
329
|
+
rowNode: changedRow.rowNode,
|
|
330
|
+
cellEdgeAttrs: changedRow.cellEdgeAttrs,
|
|
331
|
+
nodeViewSerializer: nodeViewSerializer,
|
|
332
|
+
colorScheme: colorScheme,
|
|
333
|
+
isInserted: isInserted,
|
|
334
|
+
diffType: diffType,
|
|
335
|
+
hasAnchoredRemovedLozenge: hasAnchoredRemovedLozenge,
|
|
336
|
+
intl: intl,
|
|
337
|
+
isActive: isActive
|
|
338
|
+
});
|
|
281
339
|
|
|
282
340
|
// Find safe insertion position for the deleted row
|
|
283
341
|
var safeInsertPos = findSafeInsertPos(newDoc, changedRow.fromB - 1,
|
|
284
342
|
// -1 to find the first safe position from the table
|
|
285
343
|
originalDoc.slice(changedRow.fromA, changedRow.toA));
|
|
286
|
-
|
|
287
|
-
// Stable while contributor tags are enabled so a decoration recalculation preserves the tag's
|
|
288
|
-
// identity and controller state.
|
|
289
|
-
var diffId = showContributorTags ? "widget-row-".concat(changedRow.fromA, "-").concat(changedRow.toA) : crypto.randomUUID();
|
|
290
344
|
var decorations = [];
|
|
291
345
|
var rowAnchorNames = [];
|
|
292
346
|
|
|
@@ -315,6 +369,11 @@ export var createChangedRowDecorationWidgets = function createChangedRowDecorati
|
|
|
315
369
|
diffId: diffId,
|
|
316
370
|
anchorType: AnchorTypeKey.tag
|
|
317
371
|
}) : undefined;
|
|
372
|
+
var removedLozengeAnchorName = hasAnchoredRemovedLozenge ? tagAnchorName !== null && tagAnchorName !== void 0 ? tagAnchorName : buildAnchorDecorationKey({
|
|
373
|
+
diffId: diffId,
|
|
374
|
+
anchorType: AnchorTypeKey.tag
|
|
375
|
+
}) : undefined;
|
|
376
|
+
var rowLabelAnchorName = tagAnchorName !== null && tagAnchorName !== void 0 ? tagAnchorName : removedLozengeAnchorName;
|
|
318
377
|
var tagWidget = tagAnchorName ? createContributorTagWidget({
|
|
319
378
|
anchorAtRangeStart: true,
|
|
320
379
|
anchorName: tagAnchorName,
|
|
@@ -324,11 +383,9 @@ export var createChangedRowDecorationWidgets = function createChangedRowDecorati
|
|
|
324
383
|
mountContext: tagMountContext,
|
|
325
384
|
to: safeInsertPos
|
|
326
385
|
}) : undefined;
|
|
327
|
-
if (
|
|
328
|
-
//
|
|
329
|
-
|
|
330
|
-
// opacity and strikethrough.
|
|
331
|
-
rowAnchorNames.push(tagAnchorName);
|
|
386
|
+
if (rowLabelAnchorName) {
|
|
387
|
+
// Labels stay outside the table row so they do not inherit its deletion treatment.
|
|
388
|
+
rowAnchorNames.push(rowLabelAnchorName);
|
|
332
389
|
}
|
|
333
390
|
if (rowAnchorNames.length > 0) {
|
|
334
391
|
rowDOM.style.setProperty('anchor-name', rowAnchorNames.map(function (anchorName) {
|
|
@@ -349,6 +406,15 @@ export var createChangedRowDecorationWidgets = function createChangedRowDecorati
|
|
|
349
406
|
diffType: diffType
|
|
350
407
|
})));
|
|
351
408
|
decorations.push(rowWidget);
|
|
409
|
+
if (intl && removedLozengeAnchorName) {
|
|
410
|
+
decorations.push(createAnchoredRemovedLozengeWidget({
|
|
411
|
+
anchorName: removedLozengeAnchorName,
|
|
412
|
+
colorScheme: colorScheme,
|
|
413
|
+
from: safeInsertPos,
|
|
414
|
+
intl: intl,
|
|
415
|
+
isActive: isActive
|
|
416
|
+
}));
|
|
417
|
+
}
|
|
352
418
|
if (tagWidget) {
|
|
353
419
|
decorations.push(tagWidget);
|
|
354
420
|
}
|
|
@@ -95,14 +95,19 @@ var supportsAnchorPositioning = function supportsAnchorPositioning() {
|
|
|
95
95
|
* The host for a tag on deleted content, which renders inside its own widget decoration rather than
|
|
96
96
|
* needing one of its own. Unmount with `unmountContributorTag` from that widget's `destroy`.
|
|
97
97
|
*/
|
|
98
|
-
export var createContributorTagHost = function createContributorTagHost(
|
|
98
|
+
export var createContributorTagHost = function createContributorTagHost(_ref2) {
|
|
99
|
+
var anchorName = _ref2.anchorName,
|
|
100
|
+
diffId = _ref2.diffId,
|
|
101
|
+
mountContext = _ref2.mountContext;
|
|
99
102
|
if (!isContributorTagWidgetEnabled()) {
|
|
100
103
|
return undefined;
|
|
101
104
|
}
|
|
102
|
-
var
|
|
105
|
+
var tagAnchorName = anchorName && supportsAnchorPositioning() ? anchorName : undefined;
|
|
106
|
+
var host = buildContributorTagHost(diffId, tagAnchorName);
|
|
103
107
|
return {
|
|
104
108
|
host: host,
|
|
105
109
|
mount: mountContributorTag({
|
|
110
|
+
anchorName: tagAnchorName,
|
|
106
111
|
diffId: diffId,
|
|
107
112
|
host: host,
|
|
108
113
|
mountContext: mountContext
|
|
@@ -126,7 +131,7 @@ export var createContributorTagHost = function createContributorTagHost(diffId,
|
|
|
126
131
|
* (see `hasVisibleContent`).
|
|
127
132
|
*/
|
|
128
133
|
var resolveTagAnchorPos = function resolveTagAnchorPos(doc, from, to) {
|
|
129
|
-
var
|
|
134
|
+
var _ref3;
|
|
130
135
|
var edge;
|
|
131
136
|
var visibleEdge;
|
|
132
137
|
doc.nodesBetween(from, to, function (node, nodePos) {
|
|
@@ -159,7 +164,7 @@ var resolveTagAnchorPos = function resolveTagAnchorPos(doc, from, to) {
|
|
|
159
164
|
// Textblocks have no block children to descend into.
|
|
160
165
|
return false;
|
|
161
166
|
});
|
|
162
|
-
return (
|
|
167
|
+
return (_ref3 = visibleEdge !== null && visibleEdge !== void 0 ? visibleEdge : edge) !== null && _ref3 !== void 0 ? _ref3 : from;
|
|
163
168
|
};
|
|
164
169
|
|
|
165
170
|
/**
|
|
@@ -187,15 +192,15 @@ var resolveCodeBlockStart = function resolveCodeBlockStart(doc, pos) {
|
|
|
187
192
|
* The tag is mounted in `toDOM` and taken down in `destroy`, so it lives exactly as long as the host
|
|
188
193
|
* element ProseMirror drew it into — see `mountContributorTag`.
|
|
189
194
|
*/
|
|
190
|
-
export var createContributorTagWidget = function createContributorTagWidget(
|
|
191
|
-
var
|
|
192
|
-
anchorAtRangeStart =
|
|
193
|
-
anchorName =
|
|
194
|
-
doc =
|
|
195
|
-
from =
|
|
196
|
-
to =
|
|
197
|
-
diffId =
|
|
198
|
-
mountContext =
|
|
195
|
+
export var createContributorTagWidget = function createContributorTagWidget(_ref4) {
|
|
196
|
+
var _ref4$anchorAtRangeSt = _ref4.anchorAtRangeStart,
|
|
197
|
+
anchorAtRangeStart = _ref4$anchorAtRangeSt === void 0 ? false : _ref4$anchorAtRangeSt,
|
|
198
|
+
anchorName = _ref4.anchorName,
|
|
199
|
+
doc = _ref4.doc,
|
|
200
|
+
from = _ref4.from,
|
|
201
|
+
to = _ref4.to,
|
|
202
|
+
diffId = _ref4.diffId,
|
|
203
|
+
mountContext = _ref4.mountContext;
|
|
199
204
|
if (!isContributorTagWidgetEnabled()) {
|
|
200
205
|
return undefined;
|
|
201
206
|
}
|
|
@@ -4,17 +4,20 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
|
|
|
4
4
|
import { Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
5
5
|
import { fg } from '@atlaskit/platform-feature-flags/fg';
|
|
6
6
|
import { isExtendedEnabled } from '../isExtendedEnabled';
|
|
7
|
+
import { countEmptyTextBlockOnlySlice } from '../utils/emptyTextBlocks';
|
|
7
8
|
import { isEmptyParagraphSlice } from '../utils/isEmptyParagraphSlice';
|
|
8
9
|
import { createLeftAnchorWidget } from './createAnchorDecorationWidgets';
|
|
9
10
|
import { createChangedRowDecorationWidgets } from './createChangedRowDecorationWidgets';
|
|
10
11
|
import { createContributorTagHost, unmountContributorTag } from './createContributorTagWidget';
|
|
11
|
-
import { buildDiffDecorationSpec, buildAnchorDecorationKey, scrollMarginTopValue } from './decorationKeys';
|
|
12
|
+
import { AnchorTypeKey, buildDiffDecorationSpec, buildAnchorDecorationKey, scrollMarginTopValue } from './decorationKeys';
|
|
12
13
|
import { absorbFirstChildMarginReset } from './utils/absorbFirstChildMarginReset';
|
|
14
|
+
import { createDeletedLineBreakDecoration } from './utils/createDeletedLineBreakWidget';
|
|
13
15
|
import { createMarginAbsorber } from './utils/createMarginAbsorber';
|
|
14
16
|
import { createNodeShapedMarginSpacer } from './utils/createNodeShapedMarginSpacer';
|
|
15
17
|
import { findSafeInsertPos } from './utils/findSafeInsertPos';
|
|
16
18
|
import { safeResolve } from './utils/safeResolve';
|
|
17
|
-
import {
|
|
19
|
+
import { getTableDiffMode } from './utils/tableDiffMode';
|
|
20
|
+
import { wrapBlockNodeView, createRemovedLozenge, injectInnerWrapper, createContentWrapper } from './utils/wrapBlockNodeView';
|
|
18
21
|
var isHeadingLevel = function isHeadingLevel(level) {
|
|
19
22
|
return typeof level === 'number' && level >= 1 && level <= 6;
|
|
20
23
|
};
|
|
@@ -122,9 +125,18 @@ export var createNodeChangedDecorationWidget = function createNodeChangedDecorat
|
|
|
122
125
|
_ref2$hideAddedDiffsU = _ref2.hideAddedDiffsUnderline,
|
|
123
126
|
hideAddedDiffsUnderline = _ref2$hideAddedDiffsU === void 0 ? false : _ref2$hideAddedDiffsU,
|
|
124
127
|
reveal = _ref2.reveal,
|
|
125
|
-
tagMountContext = _ref2.tagMountContext
|
|
128
|
+
tagMountContext = _ref2.tagMountContext,
|
|
129
|
+
deletedColumns = _ref2.deletedColumns;
|
|
126
130
|
var slice = doc.slice(change.fromA, change.toA);
|
|
127
131
|
var shouldSkipDeletedEmptyParagraphDecoration = !isInserted && isEmptyParagraphSlice(slice);
|
|
132
|
+
// How many blank lines the deletion took, when it took nothing else. Blank means an empty
|
|
133
|
+
// paragraph or heading — both are a line the author put there deliberately, and neither leaves
|
|
134
|
+
// the widget any content to serialize.
|
|
135
|
+
//
|
|
136
|
+
// Kept separate from `shouldSkipDeletedEmptyParagraphDecoration` and gated, so the ungated early
|
|
137
|
+
// return below still covers only the single-empty-paragraph case it always did. Everything else
|
|
138
|
+
// degrades to what it rendered before the gate: an empty block, serialized invisibly.
|
|
139
|
+
var deletedBlankLineCount = !isInserted && fg('platform_editor_ai_show_diff_patch_2') ? countEmptyTextBlockOnlySlice(slice) : 0;
|
|
128
140
|
// Widget decoration used for deletions as the content is not in the document
|
|
129
141
|
// and we want to display the deleted content with a style.
|
|
130
142
|
// For `placeBelow`, anchor at the END of the new content (change.toB) so the deleted
|
|
@@ -132,24 +144,33 @@ export var createNodeChangedDecorationWidget = function createNodeChangedDecorat
|
|
|
132
144
|
var anchorPos = placeBelow ? change.toB : change.fromB;
|
|
133
145
|
var safeInsertPos = findSafeInsertPos(newDoc, anchorPos, slice);
|
|
134
146
|
var isActive = activeIndexPos && (fg('confluence_ncs_step_diffing_version_history') ? safeInsertPos >= activeIndexPos.from && safeInsertPos <= activeIndexPos.to : safeInsertPos === activeIndexPos.from && safeInsertPos === activeIndexPos.to);
|
|
135
|
-
if (
|
|
147
|
+
if (deletedBlankLineCount > 0) {
|
|
148
|
+
// The blocks have no content to serialize, so the deletion is shown as one struck-through
|
|
149
|
+
// return glyph per line the author removed. A single widget, not one per line: the lines are
|
|
150
|
+
// gone from `newDoc`, so they all resolve to the same anchor and separate widgets would stack.
|
|
151
|
+
//
|
|
152
|
+
// No attribution: the glyph is not a tag host, matching `canTagWidget` below.
|
|
153
|
+
return [createDeletedLineBreakDecoration({
|
|
154
|
+
colorScheme: colorScheme,
|
|
155
|
+
count: deletedBlankLineCount,
|
|
156
|
+
diffType: diffType,
|
|
157
|
+
isActive: isActive,
|
|
158
|
+
pos: safeInsertPos,
|
|
159
|
+
reveal: reveal,
|
|
160
|
+
side: placeBelow ? 1 : -1
|
|
161
|
+
})];
|
|
162
|
+
}
|
|
163
|
+
if (shouldSkipDeletedEmptyParagraphDecoration) {
|
|
136
164
|
return [];
|
|
137
165
|
}
|
|
138
|
-
|
|
139
|
-
return
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
return slice.content.content.some(function (siblingNode) {
|
|
145
|
-
return ['tableRow'].includes(siblingNode.type.name);
|
|
146
|
-
});
|
|
166
|
+
if (slice.content.content.length === 0) {
|
|
167
|
+
return [];
|
|
168
|
+
}
|
|
169
|
+
var tableDiffMode = getTableDiffMode({
|
|
170
|
+
slice: slice,
|
|
171
|
+
isInserted: isInserted
|
|
147
172
|
});
|
|
148
|
-
|
|
149
|
-
// Added whole cells (e.g. "Add table headers"): render per-cell content widgets.
|
|
150
|
-
// Deleted whole cells (delete row/col) fall through — they don't exist in `newDoc`,
|
|
151
|
-
// so there's nowhere to anchor content and we keep the original "render nothing".
|
|
152
|
-
if (isTableCellContent && isInserted) {
|
|
173
|
+
if (tableDiffMode.kind === 'cells') {
|
|
153
174
|
return createTableCellContentWidgets({
|
|
154
175
|
slice: slice,
|
|
155
176
|
newDoc: newDoc,
|
|
@@ -160,11 +181,10 @@ export var createNodeChangedDecorationWidget = function createNodeChangedDecorat
|
|
|
160
181
|
diffType: diffType
|
|
161
182
|
});
|
|
162
183
|
}
|
|
163
|
-
if (
|
|
164
|
-
// Deleted whole cells: nothing to render (see note above).
|
|
184
|
+
if (tableDiffMode.kind === 'none') {
|
|
165
185
|
return [];
|
|
166
186
|
}
|
|
167
|
-
if (
|
|
187
|
+
if (tableDiffMode.kind === 'rows') {
|
|
168
188
|
return createChangedRowDecorationWidgets({
|
|
169
189
|
attributionKey: attributionKey,
|
|
170
190
|
changes: [change],
|
|
@@ -175,6 +195,7 @@ export var createNodeChangedDecorationWidget = function createNodeChangedDecorat
|
|
|
175
195
|
isActive: isActive,
|
|
176
196
|
isInserted: isInserted,
|
|
177
197
|
diffType: diffType,
|
|
198
|
+
intl: intl,
|
|
178
199
|
// Needed for the row's own indicator anchor; this path returns before the
|
|
179
200
|
// `anchor-name` assignment further down.
|
|
180
201
|
showIndicators: showIndicators,
|
|
@@ -182,6 +203,9 @@ export var createNodeChangedDecorationWidget = function createNodeChangedDecorat
|
|
|
182
203
|
tagMountContext: tagMountContext
|
|
183
204
|
});
|
|
184
205
|
}
|
|
206
|
+
// `wholeTable` and `generic` both continue into the generic block widget below. Splitting the
|
|
207
|
+
// whole-table case into its own renderer is the next step of this refactor.
|
|
208
|
+
|
|
185
209
|
var serializer = nodeViewSerializer;
|
|
186
210
|
|
|
187
211
|
// For non-table content, use the existing span wrapper approach
|
|
@@ -383,6 +407,40 @@ export var createNodeChangedDecorationWidget = function createNodeChangedDecorat
|
|
|
383
407
|
}
|
|
384
408
|
}
|
|
385
409
|
});
|
|
410
|
+
var contributorTagAnchorName;
|
|
411
|
+
if (!isInserted && deletedColumns !== null && deletedColumns !== void 0 && deletedColumns.length) {
|
|
412
|
+
var table = dom.querySelector('table');
|
|
413
|
+
var firstRow = table === null || table === void 0 ? void 0 : table.rows[0];
|
|
414
|
+
if (table && canTagWidget) {
|
|
415
|
+
contributorTagAnchorName = buildAnchorDecorationKey({
|
|
416
|
+
diffId: diffId,
|
|
417
|
+
anchorType: AnchorTypeKey.tag
|
|
418
|
+
});
|
|
419
|
+
// The widget host sits before the table's preserved block margin. Anchor the tag to the
|
|
420
|
+
// table itself so its bottom edge meets the table's top edge with no visual gap.
|
|
421
|
+
table.style.setProperty('anchor-name', "--".concat(contributorTagAnchorName));
|
|
422
|
+
}
|
|
423
|
+
deletedColumns.forEach(function (column) {
|
|
424
|
+
var _table$rows;
|
|
425
|
+
Array.from((_table$rows = table === null || table === void 0 ? void 0 : table.rows) !== null && _table$rows !== void 0 ? _table$rows : []).forEach(function (row) {
|
|
426
|
+
var _cell$children;
|
|
427
|
+
var cell = row.cells[column];
|
|
428
|
+
Array.from((_cell$children = cell === null || cell === void 0 ? void 0 : cell.children) !== null && _cell$children !== void 0 ? _cell$children : []).forEach(function (child) {
|
|
429
|
+
if (child instanceof HTMLElement) {
|
|
430
|
+
child.style.setProperty('text-decoration-line', 'line-through');
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
});
|
|
434
|
+
var headerCell = firstRow === null || firstRow === void 0 ? void 0 : firstRow.cells[column];
|
|
435
|
+
if (headerCell) {
|
|
436
|
+
headerCell.style.position = 'relative';
|
|
437
|
+
// Append, never prepend. Editor CSS resets the top margin of a cell's first child, so
|
|
438
|
+
// a prepended label pushes the paragraph out of that reset and the cell grows.
|
|
439
|
+
// The label is absolutely positioned, so DOM order does not move it.
|
|
440
|
+
headerCell.append(createRemovedLozenge(intl, isActive, colorScheme, true));
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
}
|
|
386
444
|
dom.setAttribute('data-testid', 'show-diff-deleted-decoration');
|
|
387
445
|
if (fg('platform_editor_ai_show_diff_patch_1')) {
|
|
388
446
|
dom.style.setProperty('scroll-margin-top', scrollMarginTopValue);
|
|
@@ -420,7 +478,11 @@ export var createNodeChangedDecorationWidget = function createNodeChangedDecorat
|
|
|
420
478
|
|
|
421
479
|
// Hosted at the start of the deleted run rather than on `dom` itself: `dom` is inline, so once
|
|
422
480
|
// the deleted content wraps its box is the union of its line fragments.
|
|
423
|
-
var tagHost = createContributorTagHost(
|
|
481
|
+
var tagHost = createContributorTagHost({
|
|
482
|
+
anchorName: contributorTagAnchorName,
|
|
483
|
+
diffId: diffId,
|
|
484
|
+
mountContext: tagMountContext
|
|
485
|
+
});
|
|
424
486
|
if (tagHost) {
|
|
425
487
|
dom.prepend(tagHost.host);
|
|
426
488
|
tagMount = tagHost.mount;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
3
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
4
|
+
import { Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
5
|
+
import { fg } from '@atlaskit/platform-feature-flags/fg';
|
|
6
|
+
import { isExtendedEnabled } from '../../isExtendedEnabled';
|
|
7
|
+
import { buildDiffDecorationSpec, scrollMarginTopValue } from '../decorationKeys';
|
|
8
|
+
import { createContentWrapper } from './wrapBlockNodeView';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* U+2936 ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS — the return-key glyph.
|
|
12
|
+
*
|
|
13
|
+
* Exported so tests assert against the glyph actually rendered rather than a copy of it.
|
|
14
|
+
*/
|
|
15
|
+
export var RETURN_GLYPH = '⤶';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The DOM for a removed blank line: the return glyph, struck through in the deleted colours.
|
|
19
|
+
*
|
|
20
|
+
* An empty paragraph or heading is a line the author deliberately added, but it has no content for
|
|
21
|
+
* the deleted-content widget to serialize, so a deletion of one used to render nothing at all — the
|
|
22
|
+
* reviewer saw the surrounding text close up with no sign of what was removed. Standing the glyph
|
|
23
|
+
* in for the absent content keeps the deletion visible without inventing content that was not there.
|
|
24
|
+
*
|
|
25
|
+
* `createContentWrapper` supplies the highlight and the strikethrough line, so the glyph is styled
|
|
26
|
+
* exactly like any other run of deleted inline content, including the active and reveal states.
|
|
27
|
+
*
|
|
28
|
+
* Hidden from assistive technology: the glyph is a picture of a key, and read out it is announced as
|
|
29
|
+
* its Unicode name rather than as a removed line.
|
|
30
|
+
*/
|
|
31
|
+
export var createDeletedLineBreakWidget = function createDeletedLineBreakWidget(_ref) {
|
|
32
|
+
var colorScheme = _ref.colorScheme,
|
|
33
|
+
_ref$count = _ref.count,
|
|
34
|
+
count = _ref$count === void 0 ? 1 : _ref$count,
|
|
35
|
+
diffType = _ref.diffType,
|
|
36
|
+
_ref$isActive = _ref.isActive,
|
|
37
|
+
isActive = _ref$isActive === void 0 ? false : _ref$isActive,
|
|
38
|
+
reveal = _ref.reveal;
|
|
39
|
+
var dom = document.createElement('span');
|
|
40
|
+
// The testid deleted content is matched by, so the glyph is found wherever deleted content is.
|
|
41
|
+
dom.setAttribute('data-testid', 'show-diff-deleted-decoration');
|
|
42
|
+
dom.setAttribute('aria-hidden', 'true');
|
|
43
|
+
dom.contentEditable = 'false';
|
|
44
|
+
// Scroll navigation aligns on the widget itself, as it does for every other deleted widget.
|
|
45
|
+
dom.style.setProperty('scroll-margin-top', scrollMarginTopValue);
|
|
46
|
+
for (var index = 0; index < Math.max(count, 1); index++) {
|
|
47
|
+
if (index > 0) {
|
|
48
|
+
// Each removed line gets its own line in the widget, so a run of blank lines reads as the
|
|
49
|
+
// number of lines it was. `br` rather than a block wrapper: the widget is inline, and the
|
|
50
|
+
// deleted-content wrapper is styled as an inline run.
|
|
51
|
+
dom.append(dom.ownerDocument.createElement('br'));
|
|
52
|
+
}
|
|
53
|
+
var wrapper = createContentWrapper(colorScheme, isActive, false, diffType, reveal);
|
|
54
|
+
wrapper.append(dom.ownerDocument.createTextNode(RETURN_GLYPH));
|
|
55
|
+
dom.append(wrapper);
|
|
56
|
+
}
|
|
57
|
+
return dom;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The glyph as a widget decoration anchored at `pos`.
|
|
62
|
+
*
|
|
63
|
+
* Shared by the two shapes a blank-line removal arrives in. On a forward diff the block is gone from
|
|
64
|
+
* the new document, so the change lands on the deleted side and the glyph is anchored where the
|
|
65
|
+
* block used to be. On an inverted diff — what AI suggested edits renders — the block is still in
|
|
66
|
+
* the displayed document and the change lands on the *inserted* side, so the glyph is anchored
|
|
67
|
+
* inside the surviving block, on the blank line itself.
|
|
68
|
+
*/
|
|
69
|
+
export var createDeletedLineBreakDecoration = function createDeletedLineBreakDecoration(_ref2) {
|
|
70
|
+
var attributionKey = _ref2.attributionKey,
|
|
71
|
+
colorScheme = _ref2.colorScheme,
|
|
72
|
+
count = _ref2.count,
|
|
73
|
+
diffType = _ref2.diffType,
|
|
74
|
+
_ref2$isActive = _ref2.isActive,
|
|
75
|
+
isActive = _ref2$isActive === void 0 ? false : _ref2$isActive,
|
|
76
|
+
pos = _ref2.pos,
|
|
77
|
+
reveal = _ref2.reveal,
|
|
78
|
+
side = _ref2.side;
|
|
79
|
+
return Decoration.widget(pos, createDeletedLineBreakWidget({
|
|
80
|
+
colorScheme: colorScheme,
|
|
81
|
+
count: count,
|
|
82
|
+
diffType: diffType,
|
|
83
|
+
isActive: isActive,
|
|
84
|
+
reveal: reveal
|
|
85
|
+
}), _objectSpread(_objectSpread({}, buildDiffDecorationSpec(_objectSpread({
|
|
86
|
+
attributionKey: attributionKey,
|
|
87
|
+
colorScheme: colorScheme,
|
|
88
|
+
decorationType: 'widget',
|
|
89
|
+
diffId: crypto.randomUUID(),
|
|
90
|
+
isActive: isActive,
|
|
91
|
+
// The glyph always stands in for removed content, whichever side of the changeset the
|
|
92
|
+
// change itself landed on.
|
|
93
|
+
isInserted: false,
|
|
94
|
+
diffType: diffType
|
|
95
|
+
}, isExtendedEnabled(diffType) && side !== undefined && {
|
|
96
|
+
side: side
|
|
97
|
+
}))), fg('platform_editor_diff_inline_mark_changes') && {
|
|
98
|
+
marks: []
|
|
99
|
+
}));
|
|
100
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
var CELL_TYPE_NAMES = ['tableCell', 'tableHeader'];
|
|
2
|
+
export var getTableDiffMode = function getTableDiffMode(_ref) {
|
|
3
|
+
var slice = _ref.slice,
|
|
4
|
+
isInserted = _ref.isInserted;
|
|
5
|
+
var topLevelNodes = slice.content.content;
|
|
6
|
+
if (topLevelNodes.some(function (node) {
|
|
7
|
+
return CELL_TYPE_NAMES.includes(node.type.name);
|
|
8
|
+
})) {
|
|
9
|
+
return isInserted ? {
|
|
10
|
+
kind: 'cells'
|
|
11
|
+
} : {
|
|
12
|
+
kind: 'none'
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
if (topLevelNodes.some(function (node) {
|
|
16
|
+
return node.type.name === 'tableRow';
|
|
17
|
+
})) {
|
|
18
|
+
return {
|
|
19
|
+
kind: 'rows'
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
if (topLevelNodes.length === 1 && topLevelNodes[0].type.name === 'table' && slice.openStart === 0 && slice.openEnd === 0) {
|
|
23
|
+
return {
|
|
24
|
+
kind: 'wholeTable'
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
kind: 'generic'
|
|
29
|
+
};
|
|
30
|
+
};
|
|
@@ -141,26 +141,37 @@ var applyCellOverlayStyles = function applyCellOverlayStyles(_ref4) {
|
|
|
141
141
|
/**
|
|
142
142
|
* Creates a "Removed" lozenge to be displayed at the top right corner of deleted block nodes
|
|
143
143
|
*/
|
|
144
|
-
var createRemovedLozenge = function createRemovedLozenge(intl) {
|
|
144
|
+
export var createRemovedLozenge = function createRemovedLozenge(intl) {
|
|
145
145
|
var isActive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
146
146
|
var colorScheme = arguments.length > 2 ? arguments[2] : undefined;
|
|
147
|
+
var inCell = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
147
148
|
var container = document.createElement('span');
|
|
148
149
|
var containerStyle = convertToInlineCss({
|
|
149
150
|
position: 'absolute',
|
|
150
151
|
top: "var(--ds-space-075, 6px)",
|
|
151
152
|
right: "var(--ds-space-075, 6px)",
|
|
152
|
-
|
|
153
|
+
// Rounded table-cell overlays use z-index 2 and are appended after the cell content.
|
|
154
|
+
// Keep the lozenge above them so the overlay cannot tint or obscure it.
|
|
155
|
+
zIndex: 3,
|
|
153
156
|
pointerEvents: 'none',
|
|
154
157
|
display: 'flex'
|
|
155
158
|
});
|
|
156
|
-
container.setAttribute('style', containerStyle);
|
|
157
|
-
container.setAttribute('data-testid', 'show-diff-removed-lozenge');
|
|
158
159
|
|
|
159
160
|
// Create vanilla HTML lozenge element with Atlaskit Lozenge styling (visual refresh)
|
|
160
161
|
var lozengeElement = document.createElement('span');
|
|
161
|
-
|
|
162
|
+
|
|
163
|
+
// A column label sits over an already-grey deleted cell, so use the red Removed treatment.
|
|
164
|
+
var lozengeInnerStyle = resolveRemovedLozengeStyle(colorScheme, inCell || isActive);
|
|
162
165
|
lozengeElement.setAttribute('style', lozengeInnerStyle);
|
|
163
166
|
lozengeElement.textContent = intl.formatMessage(trackChangesMessages.removed).toUpperCase();
|
|
167
|
+
if (inCell) {
|
|
168
|
+
lozengeElement.setAttribute('style', "".concat(lozengeInnerStyle, ";").concat(containerStyle));
|
|
169
|
+
lozengeElement.setAttribute('data-testid', 'show-diff-removed-lozenge');
|
|
170
|
+
lozengeElement.contentEditable = 'false';
|
|
171
|
+
return lozengeElement;
|
|
172
|
+
}
|
|
173
|
+
container.setAttribute('style', containerStyle);
|
|
174
|
+
container.setAttribute('data-testid', 'show-diff-removed-lozenge');
|
|
164
175
|
container.appendChild(lozengeElement);
|
|
165
176
|
return container;
|
|
166
177
|
};
|