@atlaskit/editor-plugin-show-diff 10.5.1 → 10.5.3
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 +16 -0
- package/dist/cjs/pm-plugins/calculateDiff/calculateDiffDecorations.js +30 -3
- package/dist/cjs/pm-plugins/decorations/colorSchemes/standard.js +13 -1
- package/dist/cjs/pm-plugins/decorations/colorSchemes/traditional.js +15 -2
- package/dist/cjs/pm-plugins/decorations/createChangedRowDecorationWidgets.js +83 -26
- package/dist/cjs/pm-plugins/decorations/createInlineChangedDecoration.js +23 -4
- package/dist/cjs/pm-plugins/decorations/utils/getAttrChangeRanges.js +64 -4
- package/dist/es2019/pm-plugins/calculateDiff/calculateDiffDecorations.js +30 -3
- package/dist/es2019/pm-plugins/decorations/colorSchemes/standard.js +12 -0
- package/dist/es2019/pm-plugins/decorations/colorSchemes/traditional.js +14 -1
- package/dist/es2019/pm-plugins/decorations/createChangedRowDecorationWidgets.js +67 -9
- package/dist/es2019/pm-plugins/decorations/createInlineChangedDecoration.js +16 -1
- package/dist/es2019/pm-plugins/decorations/utils/getAttrChangeRanges.js +53 -4
- package/dist/esm/pm-plugins/calculateDiff/calculateDiffDecorations.js +30 -3
- package/dist/esm/pm-plugins/decorations/colorSchemes/standard.js +12 -0
- package/dist/esm/pm-plugins/decorations/colorSchemes/traditional.js +14 -1
- package/dist/esm/pm-plugins/decorations/createChangedRowDecorationWidgets.js +85 -28
- package/dist/esm/pm-plugins/decorations/createInlineChangedDecoration.js +23 -4
- package/dist/esm/pm-plugins/decorations/utils/getAttrChangeRanges.js +63 -4
- package/dist/types/pm-plugins/decorations/colorSchemes/standard.d.ts +1 -0
- package/dist/types/pm-plugins/decorations/colorSchemes/traditional.d.ts +2 -1
- package/dist/types/pm-plugins/decorations/createInlineChangedDecoration.d.ts +4 -1
- package/dist/types/pm-plugins/decorations/utils/getAttrChangeRanges.d.ts +11 -1
- package/package.json +3 -3
|
@@ -2,11 +2,54 @@ import { areNodesEqualIgnoreAttrs } from '@atlaskit/editor-common/utils/document
|
|
|
2
2
|
import { findParentNodeClosestToPos } from '@atlaskit/editor-prosemirror/utils';
|
|
3
3
|
import { Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
4
4
|
import { TableMap } from '@atlaskit/editor-tables/table-map';
|
|
5
|
+
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
5
6
|
import { isExtendedEnabled } from '../isExtendedEnabled';
|
|
6
|
-
import { addedCellOverlayStyle, deletedRowStyle, deletedCellOverlayStyle } from './colorSchemes/standard';
|
|
7
|
-
import { deletedTraditionalRowStyle, deletedTraditionalCellOverlayStyle, traditionalAddedCellOverlayStyle } from './colorSchemes/traditional';
|
|
7
|
+
import { addedCellOverlayStyle, addedCellOverlayRoundedStyle, deletedRowStyle, deletedCellOverlayStyle } from './colorSchemes/standard';
|
|
8
|
+
import { deletedTraditionalRowStyle, deletedTraditionalCellOverlayStyle, traditionalAddedCellOverlayStyle, traditionalAddedCellOverlayRoundedStyle } from './colorSchemes/traditional';
|
|
8
9
|
import { buildDiffDecorationSpec } from './decorationKeys';
|
|
9
10
|
import { findSafeInsertPos } from './utils/findSafeInsertPos';
|
|
11
|
+
/**
|
|
12
|
+
* Inserted table rows are rendered as decoration widgets, so their cells do not get the
|
|
13
|
+
* `data-reaches-*` attrs normally applied by the table cell node view. Mirror that boundary
|
|
14
|
+
* metadata here so the existing rounded-table CSS can round widget cells like real table cells.
|
|
15
|
+
*/
|
|
16
|
+
const getChangedRowCellEdgeAttrs = ({
|
|
17
|
+
rowNode,
|
|
18
|
+
rowStart,
|
|
19
|
+
tableMap
|
|
20
|
+
}) => {
|
|
21
|
+
const cellEdgeAttrs = [];
|
|
22
|
+
rowNode.content.forEach((cellNode, cellOffset) => {
|
|
23
|
+
if (cellNode.type.name !== 'tableCell' && cellNode.type.name !== 'tableHeader') {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const cellRect = tableMap.findCell(rowStart + 1 + cellOffset);
|
|
27
|
+
cellEdgeAttrs.push({
|
|
28
|
+
reachesBottom: cellRect.bottom >= tableMap.height,
|
|
29
|
+
reachesLeft: cellRect.left === 0,
|
|
30
|
+
reachesRight: cellRect.right >= tableMap.width,
|
|
31
|
+
reachesTop: cellRect.top === 0
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
return cellEdgeAttrs;
|
|
35
|
+
};
|
|
36
|
+
const applyCellEdgeAttrs = (cell, edgeAttrs) => {
|
|
37
|
+
if (!edgeAttrs) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (edgeAttrs.reachesTop) {
|
|
41
|
+
cell.setAttribute('data-reaches-top', 'true');
|
|
42
|
+
}
|
|
43
|
+
if (edgeAttrs.reachesBottom) {
|
|
44
|
+
cell.setAttribute('data-reaches-bottom', 'true');
|
|
45
|
+
}
|
|
46
|
+
if (edgeAttrs.reachesLeft) {
|
|
47
|
+
cell.setAttribute('data-reaches-left', 'true');
|
|
48
|
+
}
|
|
49
|
+
if (edgeAttrs.reachesRight) {
|
|
50
|
+
cell.setAttribute('data-reaches-right', 'true');
|
|
51
|
+
}
|
|
52
|
+
};
|
|
10
53
|
/**
|
|
11
54
|
* Extracts information about deleted table rows from a change
|
|
12
55
|
*/
|
|
@@ -52,10 +95,16 @@ const extractChangedRows = ({
|
|
|
52
95
|
// Check if this row overlaps with the deletion range
|
|
53
96
|
const rowOverlapsChange = rowStart >= changeStartInTable && rowStart < changeEndInTable || rowEnd > changeStartInTable && rowEnd <= changeEndInTable || rowStart < changeStartInTable && rowEnd > changeEndInTable;
|
|
54
97
|
if (rowOverlapsChange && rowNode.type.name === 'tableRow' && (isExtendedEnabled(diffType) || !isEmptyRow(rowNode))) {
|
|
98
|
+
const cellEdgeAttrs = isExtendedEnabled(diffType) && expValEquals('platform_editor_table_diff_rounded_corners', 'isEnabled', true) ? getChangedRowCellEdgeAttrs({
|
|
99
|
+
rowNode,
|
|
100
|
+
rowStart,
|
|
101
|
+
tableMap: oldTableMap
|
|
102
|
+
}) : undefined;
|
|
55
103
|
const startOfRow = newTableMap.mapByRow.slice().reverse().find(row => row[0] + tableNew.pos < change.fromB && change.fromB < row[row.length - 1] + tableNew.pos);
|
|
56
104
|
changedRows.push({
|
|
57
105
|
rowIndex,
|
|
58
106
|
rowNode,
|
|
107
|
+
cellEdgeAttrs,
|
|
59
108
|
fromA: tableOld.pos + 1 + rowStart,
|
|
60
109
|
toA: tableOld.pos + 1 + rowEnd,
|
|
61
110
|
fromB: startOfRow ? startOfRow[0] + tableNew.start : change.fromB
|
|
@@ -102,7 +151,7 @@ const isEmptyRow = rowNode => {
|
|
|
102
151
|
/**
|
|
103
152
|
* Creates a DOM representation of a deleted table row
|
|
104
153
|
*/
|
|
105
|
-
const createChangedRowDOM = (rowNode, nodeViewSerializer, colorScheme, isInserted, diffType) => {
|
|
154
|
+
const createChangedRowDOM = (rowNode, cellEdgeAttrs, nodeViewSerializer, colorScheme, isInserted, diffType) => {
|
|
106
155
|
const tr = document.createElement('tr');
|
|
107
156
|
if (isExtendedEnabled(diffType)) {
|
|
108
157
|
if (!isInserted) {
|
|
@@ -114,15 +163,23 @@ const createChangedRowDOM = (rowNode, nodeViewSerializer, colorScheme, isInserte
|
|
|
114
163
|
tr.setAttribute('data-testid', 'show-diff-deleted-row');
|
|
115
164
|
|
|
116
165
|
// Serialize each cell in the row
|
|
166
|
+
let cellIndex = 0;
|
|
117
167
|
rowNode.content.forEach(cellNode => {
|
|
118
168
|
if (cellNode.type.name === 'tableCell' || cellNode.type.name === 'tableHeader') {
|
|
119
169
|
const nodeView = nodeViewSerializer.tryCreateNodeView(cellNode);
|
|
120
170
|
if (nodeView) {
|
|
121
|
-
if (nodeView instanceof HTMLElement
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
171
|
+
if (nodeView instanceof HTMLElement) {
|
|
172
|
+
applyCellEdgeAttrs(nodeView, cellEdgeAttrs === null || cellEdgeAttrs === void 0 ? void 0 : cellEdgeAttrs[cellIndex]);
|
|
173
|
+
if (isExtendedEnabled(diffType)) {
|
|
174
|
+
const overlay = document.createElement('span');
|
|
175
|
+
const isRoundedTable = expValEquals('platform_editor_table_diff_rounded_corners', 'isEnabled', true);
|
|
176
|
+
const isTraditional = colorScheme === 'traditional';
|
|
177
|
+
const deletedCellStyle = isTraditional ? deletedTraditionalCellOverlayStyle : deletedCellOverlayStyle;
|
|
178
|
+
const addedCellStyle = isTraditional ? isRoundedTable ? traditionalAddedCellOverlayRoundedStyle : traditionalAddedCellOverlayStyle : isRoundedTable ? addedCellOverlayRoundedStyle : addedCellOverlayStyle;
|
|
179
|
+
const overlayStyle = isInserted ? addedCellStyle : deletedCellStyle;
|
|
180
|
+
overlay.setAttribute('style', overlayStyle);
|
|
181
|
+
nodeView.appendChild(overlay);
|
|
182
|
+
}
|
|
126
183
|
}
|
|
127
184
|
tr.appendChild(nodeView);
|
|
128
185
|
} else {
|
|
@@ -132,6 +189,7 @@ const createChangedRowDOM = (rowNode, nodeViewSerializer, colorScheme, isInserte
|
|
|
132
189
|
tr.appendChild(serializedContent);
|
|
133
190
|
}
|
|
134
191
|
}
|
|
192
|
+
cellIndex++;
|
|
135
193
|
}
|
|
136
194
|
});
|
|
137
195
|
return tr;
|
|
@@ -182,7 +240,7 @@ export const createChangedRowDecorationWidgets = ({
|
|
|
182
240
|
diffType
|
|
183
241
|
});
|
|
184
242
|
return changedRows.map(changedRow => {
|
|
185
|
-
const rowDOM = createChangedRowDOM(changedRow.rowNode, nodeViewSerializer, colorScheme, isInserted, diffType);
|
|
243
|
+
const rowDOM = createChangedRowDOM(changedRow.rowNode, changedRow.cellEdgeAttrs, nodeViewSerializer, colorScheme, isInserted, diffType);
|
|
186
244
|
|
|
187
245
|
// Find safe insertion position for the deleted row
|
|
188
246
|
const safeInsertPos = findSafeInsertPos(newDoc, changedRow.fromB - 1,
|
|
@@ -8,6 +8,16 @@ import { buildDiffDecorationSpec } from './decorationKeys';
|
|
|
8
8
|
const displayNoneStyle = convertToInlineCss({
|
|
9
9
|
display: 'none'
|
|
10
10
|
});
|
|
11
|
+
const getAtomicInlineNodeClassName = (inlineNodeName, colorScheme) => {
|
|
12
|
+
const classNames = ['show-diff-atomic-inline-changed'];
|
|
13
|
+
if (inlineNodeName) {
|
|
14
|
+
classNames.push(`show-diff-atomic-inline-changed-${inlineNodeName}`);
|
|
15
|
+
}
|
|
16
|
+
if (colorScheme === 'traditional') {
|
|
17
|
+
classNames.push('show-diff-atomic-inline-changed-traditional');
|
|
18
|
+
}
|
|
19
|
+
return classNames.join(' ');
|
|
20
|
+
};
|
|
11
21
|
/**
|
|
12
22
|
* Inline decoration used for insertions as the content already exists in the document
|
|
13
23
|
*
|
|
@@ -20,11 +30,13 @@ export const createInlineChangedDecoration = ({
|
|
|
20
30
|
colorScheme,
|
|
21
31
|
isActive = false,
|
|
22
32
|
isInserted = true,
|
|
33
|
+
isAtomicInlineNode = false,
|
|
23
34
|
shouldHideDeleted = false,
|
|
24
35
|
showIndicators = false,
|
|
25
36
|
doc,
|
|
26
37
|
diffType,
|
|
27
|
-
hideAddedDiffsUnderline = false
|
|
38
|
+
hideAddedDiffsUnderline = false,
|
|
39
|
+
inlineNodeName
|
|
28
40
|
}) => {
|
|
29
41
|
const diffId = crypto.randomUUID();
|
|
30
42
|
if (shouldHideDeleted) {
|
|
@@ -66,6 +78,9 @@ export const createInlineChangedDecoration = ({
|
|
|
66
78
|
}
|
|
67
79
|
const decorations = [Decoration.inline(change.fromB, change.toB, {
|
|
68
80
|
style,
|
|
81
|
+
...(isAtomicInlineNode && isInserted && {
|
|
82
|
+
class: getAtomicInlineNodeClassName(inlineNodeName, colorScheme)
|
|
83
|
+
}),
|
|
69
84
|
'data-testid': 'show-diff-changed-decoration'
|
|
70
85
|
}, buildDiffDecorationSpec({
|
|
71
86
|
decorationType: 'inline',
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SetAttrsStep } from '@atlaskit/adf-schema/steps';
|
|
2
2
|
import { AttrStep } from '@atlaskit/editor-prosemirror/transform';
|
|
3
|
+
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
3
4
|
const filterUndefined = x => !!x;
|
|
4
5
|
|
|
5
6
|
// Attributes that indicate a change in media image
|
|
@@ -11,6 +12,24 @@ const dateAttrs = ['timestamp'];
|
|
|
11
12
|
// Attribute that indicates a task item state change
|
|
12
13
|
const taskItemAttrs = ['state'];
|
|
13
14
|
|
|
15
|
+
// Attributes that indicate an emoji change
|
|
16
|
+
const emojiAttrs = ['shortName', 'id', 'text'];
|
|
17
|
+
|
|
18
|
+
// Attributes that indicate a mention change (who is mentioned)
|
|
19
|
+
const mentionAttrs = ['id', 'text'];
|
|
20
|
+
|
|
21
|
+
// Attributes that indicate a status change (label or colour)
|
|
22
|
+
const statusAttrs = ['text', 'color'];
|
|
23
|
+
|
|
24
|
+
// Map of node type name → the attrs that represent a meaningful content change for that node
|
|
25
|
+
const inlineNodeAttrMap = {
|
|
26
|
+
date: dateAttrs,
|
|
27
|
+
emoji: emojiAttrs,
|
|
28
|
+
mention: mentionAttrs,
|
|
29
|
+
status: statusAttrs
|
|
30
|
+
};
|
|
31
|
+
const isInlineAttrChangeNodeName = nodeName => nodeName in inlineNodeAttrMap;
|
|
32
|
+
|
|
14
33
|
// Attributes excluded from extension change detection (not meaningful content changes)
|
|
15
34
|
const extensionExcludedAttrs = ['localId'];
|
|
16
35
|
|
|
@@ -25,7 +44,7 @@ const getStepAttrs = step => {
|
|
|
25
44
|
}
|
|
26
45
|
return [];
|
|
27
46
|
};
|
|
28
|
-
export const getAttrChangeRanges = (doc, steps) => {
|
|
47
|
+
export const getAttrChangeRanges = (doc, steps, originalDoc) => {
|
|
29
48
|
return steps.map(step => {
|
|
30
49
|
if (!(step instanceof AttrStep) && !(step instanceof SetAttrsStep)) {
|
|
31
50
|
return undefined;
|
|
@@ -35,14 +54,38 @@ export const getAttrChangeRanges = (doc, steps) => {
|
|
|
35
54
|
const nodeAtPos = doc.nodeAt(step.pos);
|
|
36
55
|
|
|
37
56
|
// date node: timestamp attribute change — highlight the date node itself (inline)
|
|
38
|
-
if (stepAttrs.some(v => dateAttrs.includes(v)) && (nodeAtPos === null || nodeAtPos === void 0 ? void 0 : nodeAtPos.type.name) === 'date') {
|
|
57
|
+
if (stepAttrs.some(v => dateAttrs.includes(v)) && (nodeAtPos === null || nodeAtPos === void 0 ? void 0 : nodeAtPos.type.name) === 'date' && !expValEquals('platform_editor_improve_inline_diffs', 'isEnabled', true)) {
|
|
39
58
|
return {
|
|
40
59
|
fromB: step.pos,
|
|
41
60
|
toB: step.pos + nodeAtPos.nodeSize,
|
|
42
|
-
isInline: true
|
|
61
|
+
isInline: true,
|
|
62
|
+
inlineNodeName: 'date'
|
|
43
63
|
};
|
|
44
64
|
}
|
|
45
65
|
|
|
66
|
+
// The following inline node attr changes are gated behind platform_editor_improve_inline_diffs.
|
|
67
|
+
// The changeset path (createDecorationsForChange) handles the deletion widget via
|
|
68
|
+
// prosemirror-changeset; we only need to add the inline insertion highlight here.
|
|
69
|
+
if (expValEquals('platform_editor_improve_inline_diffs', 'isEnabled', true) && nodeAtPos) {
|
|
70
|
+
const nodeName = nodeAtPos.type.name;
|
|
71
|
+
if (isInlineAttrChangeNodeName(nodeName)) {
|
|
72
|
+
const watchedAttrs = inlineNodeAttrMap[nodeName];
|
|
73
|
+
if (stepAttrs.some(v => watchedAttrs.includes(v))) {
|
|
74
|
+
const originalNodeAtPos = originalDoc === null || originalDoc === void 0 ? void 0 : originalDoc.nodeAt(step.pos);
|
|
75
|
+
return {
|
|
76
|
+
fromB: step.pos,
|
|
77
|
+
toB: step.pos + nodeAtPos.nodeSize,
|
|
78
|
+
isInline: true,
|
|
79
|
+
inlineNodeName: nodeName,
|
|
80
|
+
...(originalNodeAtPos && {
|
|
81
|
+
fromA: step.pos,
|
|
82
|
+
toA: step.pos + originalNodeAtPos.nodeSize
|
|
83
|
+
})
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
46
89
|
// taskItem node: state attribute change — highlight the taskItem node
|
|
47
90
|
if (stepAttrs.some(v => taskItemAttrs.includes(v)) && (nodeAtPos === null || nodeAtPos === void 0 ? void 0 : nodeAtPos.type.name) === 'taskItem') {
|
|
48
91
|
return {
|
|
@@ -70,7 +113,13 @@ export const getAttrChangeRanges = (doc, steps) => {
|
|
|
70
113
|
};
|
|
71
114
|
}
|
|
72
115
|
return undefined;
|
|
73
|
-
}).filter(filterUndefined)
|
|
116
|
+
}).filter(filterUndefined)
|
|
117
|
+
// Deduplicate by node position: multiple AttrSteps on the same node
|
|
118
|
+
// (e.g. setNodeAttribute(pos, 'text', ...) + setNodeAttribute(pos, 'color', ...))
|
|
119
|
+
// should produce only one decoration, not one per step.
|
|
120
|
+
// Gated behind the same experiment as the inline node attr changes that introduced
|
|
121
|
+
// the possibility of multiple ranges for the same node position.
|
|
122
|
+
.filter((range, i, arr) => !expValEquals('platform_editor_improve_inline_diffs', 'isEnabled', true) || arr.findIndex(r => r.fromB === range.fromB) === i);
|
|
74
123
|
};
|
|
75
124
|
|
|
76
125
|
/**
|
|
@@ -421,16 +421,43 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref3
|
|
|
421
421
|
isInserted: true
|
|
422
422
|
})));
|
|
423
423
|
});
|
|
424
|
-
getAttrChangeRanges(tr.doc, attrSteps).forEach(function (change) {
|
|
424
|
+
getAttrChangeRanges(tr.doc, attrSteps, originalDoc).forEach(function (change) {
|
|
425
425
|
if (change.isInline) {
|
|
426
|
-
// Inline nodes (e.g. date) need an inline decoration rather than a block decoration
|
|
426
|
+
// Inline nodes (e.g. date, emoji, mention, status) need an inline decoration rather than a block decoration
|
|
427
427
|
var isActive = activeIndexPos && change.fromB === activeIndexPos.from && change.toB === activeIndexPos.to;
|
|
428
|
+
var isAtomicInlineNodeFlag = expValEquals('platform_editor_improve_inline_diffs', 'isEnabled', true);
|
|
428
429
|
decorations.push.apply(decorations, _toConsumableArray(createInlineChangedDecoration({
|
|
429
430
|
change: change,
|
|
430
431
|
colorScheme: colorScheme,
|
|
431
432
|
isActive: isActive,
|
|
432
|
-
isInserted: true
|
|
433
|
+
isInserted: true,
|
|
434
|
+
isAtomicInlineNode: isAtomicInlineNodeFlag,
|
|
435
|
+
inlineNodeName: change.inlineNodeName,
|
|
436
|
+
// Suppress the border-bottom underline for atomic inline nodeviews —
|
|
437
|
+
// it doesn't render on custom nodeview DOM elements and is unnecessary noise.
|
|
438
|
+
hideAddedDiffsUnderline: isAtomicInlineNodeFlag,
|
|
439
|
+
diffType: diffType
|
|
433
440
|
})));
|
|
441
|
+
// If we have the original node position, also render the old node as a "deleted" widget
|
|
442
|
+
// so the user can see what it looked like before the change.
|
|
443
|
+
if (change.fromA !== undefined && change.toA !== undefined && expValEquals('platform_editor_improve_inline_diffs', 'isEnabled', true)) {
|
|
444
|
+
decorations.push.apply(decorations, _toConsumableArray(createNodeChangedDecorationWidget({
|
|
445
|
+
change: {
|
|
446
|
+
fromA: change.fromA,
|
|
447
|
+
toA: change.toA,
|
|
448
|
+
fromB: change.fromB,
|
|
449
|
+
toB: change.toB,
|
|
450
|
+
deleted: []
|
|
451
|
+
},
|
|
452
|
+
doc: originalDoc,
|
|
453
|
+
nodeViewSerializer: nodeViewSerializer,
|
|
454
|
+
colorScheme: colorScheme,
|
|
455
|
+
newDoc: tr.doc,
|
|
456
|
+
intl: intl,
|
|
457
|
+
activeIndexPos: activeIndexPos,
|
|
458
|
+
isInserted: false
|
|
459
|
+
})));
|
|
460
|
+
}
|
|
434
461
|
} else {
|
|
435
462
|
decorations.push.apply(decorations, _toConsumableArray(calculateNodesForBlockDecoration({
|
|
436
463
|
doc: tr.doc,
|
|
@@ -170,6 +170,18 @@ export var addedCellOverlayStyle = convertToInlineCss({
|
|
|
170
170
|
outline: "1px solid ".concat("var(--ds-border-accent-purple, #AF59E1)"),
|
|
171
171
|
pointerEvents: 'none'
|
|
172
172
|
});
|
|
173
|
+
export var addedCellOverlayRoundedStyle = convertToInlineCss({
|
|
174
|
+
position: 'absolute',
|
|
175
|
+
top: 0,
|
|
176
|
+
left: 0,
|
|
177
|
+
width: '100%',
|
|
178
|
+
height: '100%',
|
|
179
|
+
backgroundColor: "rgba(from ".concat("var(--ds-background-accent-purple-subtlest, #F8EEFE)", " r g b / 0.5)"),
|
|
180
|
+
zIndex: 2,
|
|
181
|
+
outline: "1px solid ".concat("var(--ds-border-accent-purple, #AF59E1)"),
|
|
182
|
+
pointerEvents: 'none',
|
|
183
|
+
borderRadius: 'inherit'
|
|
184
|
+
});
|
|
173
185
|
export var deletedCellOverlayStyle = convertToInlineCss({
|
|
174
186
|
position: 'absolute',
|
|
175
187
|
top: 0,
|
|
@@ -84,7 +84,7 @@ export var deletedTraditionalBlockOutlineRoundedActive = convertToInlineCss({
|
|
|
84
84
|
borderRadius: "calc(".concat("var(--ds-radius-xsmall, 2px)", " + 1px)")
|
|
85
85
|
});
|
|
86
86
|
|
|
87
|
-
/** Scroll-navigation “new” emphasis: 4px ring
|
|
87
|
+
/** Scroll-navigation “new” emphasis: 4px ring. */
|
|
88
88
|
export var deletedTraditionalBlockOutlineNew = convertToInlineCss({
|
|
89
89
|
boxShadow: "0 0 0 4px ".concat("var(--ds-background-accent-red-subtlest, #FFECEB)"),
|
|
90
90
|
borderRadius: "var(--ds-radius-small, 4px)"
|
|
@@ -184,6 +184,19 @@ export var traditionalAddedCellOverlayStyle = convertToInlineCss({
|
|
|
184
184
|
outline: "1px solid ".concat("var(--ds-border-accent-green, #22A06B)"),
|
|
185
185
|
pointerEvents: 'none'
|
|
186
186
|
});
|
|
187
|
+
export var traditionalAddedCellOverlayRoundedStyle = convertToInlineCss({
|
|
188
|
+
position: 'absolute',
|
|
189
|
+
top: 0,
|
|
190
|
+
left: 0,
|
|
191
|
+
width: '100%',
|
|
192
|
+
height: '100%',
|
|
193
|
+
backgroundColor: "rgba(from ".concat("var(--ds-background-accent-green-subtlest, #DCFFF1)", " r g b / 0.5)"),
|
|
194
|
+
zIndex: 2,
|
|
195
|
+
outline: "1px solid ".concat("var(--ds-border-accent-green, #22A06B)"),
|
|
196
|
+
pointerEvents: 'none',
|
|
197
|
+
border: 'inherit',
|
|
198
|
+
borderRadius: 'inherit'
|
|
199
|
+
});
|
|
187
200
|
export var traditionalAddedCellOverlayStyleNew = convertToInlineCss({
|
|
188
201
|
position: 'absolute',
|
|
189
202
|
top: 0,
|
|
@@ -9,19 +9,61 @@ import { areNodesEqualIgnoreAttrs } from '@atlaskit/editor-common/utils/document
|
|
|
9
9
|
import { findParentNodeClosestToPos } from '@atlaskit/editor-prosemirror/utils';
|
|
10
10
|
import { Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
11
11
|
import { TableMap } from '@atlaskit/editor-tables/table-map';
|
|
12
|
+
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
12
13
|
import { isExtendedEnabled } from '../isExtendedEnabled';
|
|
13
|
-
import { addedCellOverlayStyle, deletedRowStyle, deletedCellOverlayStyle } from './colorSchemes/standard';
|
|
14
|
-
import { deletedTraditionalRowStyle, deletedTraditionalCellOverlayStyle, traditionalAddedCellOverlayStyle } from './colorSchemes/traditional';
|
|
14
|
+
import { addedCellOverlayStyle, addedCellOverlayRoundedStyle, deletedRowStyle, deletedCellOverlayStyle } from './colorSchemes/standard';
|
|
15
|
+
import { deletedTraditionalRowStyle, deletedTraditionalCellOverlayStyle, traditionalAddedCellOverlayStyle, traditionalAddedCellOverlayRoundedStyle } from './colorSchemes/traditional';
|
|
15
16
|
import { buildDiffDecorationSpec } from './decorationKeys';
|
|
16
17
|
import { findSafeInsertPos } from './utils/findSafeInsertPos';
|
|
18
|
+
/**
|
|
19
|
+
* Inserted table rows are rendered as decoration widgets, so their cells do not get the
|
|
20
|
+
* `data-reaches-*` attrs normally applied by the table cell node view. Mirror that boundary
|
|
21
|
+
* metadata here so the existing rounded-table CSS can round widget cells like real table cells.
|
|
22
|
+
*/
|
|
23
|
+
var getChangedRowCellEdgeAttrs = function getChangedRowCellEdgeAttrs(_ref) {
|
|
24
|
+
var rowNode = _ref.rowNode,
|
|
25
|
+
rowStart = _ref.rowStart,
|
|
26
|
+
tableMap = _ref.tableMap;
|
|
27
|
+
var cellEdgeAttrs = [];
|
|
28
|
+
rowNode.content.forEach(function (cellNode, cellOffset) {
|
|
29
|
+
if (cellNode.type.name !== 'tableCell' && cellNode.type.name !== 'tableHeader') {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
var cellRect = tableMap.findCell(rowStart + 1 + cellOffset);
|
|
33
|
+
cellEdgeAttrs.push({
|
|
34
|
+
reachesBottom: cellRect.bottom >= tableMap.height,
|
|
35
|
+
reachesLeft: cellRect.left === 0,
|
|
36
|
+
reachesRight: cellRect.right >= tableMap.width,
|
|
37
|
+
reachesTop: cellRect.top === 0
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
return cellEdgeAttrs;
|
|
41
|
+
};
|
|
42
|
+
var applyCellEdgeAttrs = function applyCellEdgeAttrs(cell, edgeAttrs) {
|
|
43
|
+
if (!edgeAttrs) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (edgeAttrs.reachesTop) {
|
|
47
|
+
cell.setAttribute('data-reaches-top', 'true');
|
|
48
|
+
}
|
|
49
|
+
if (edgeAttrs.reachesBottom) {
|
|
50
|
+
cell.setAttribute('data-reaches-bottom', 'true');
|
|
51
|
+
}
|
|
52
|
+
if (edgeAttrs.reachesLeft) {
|
|
53
|
+
cell.setAttribute('data-reaches-left', 'true');
|
|
54
|
+
}
|
|
55
|
+
if (edgeAttrs.reachesRight) {
|
|
56
|
+
cell.setAttribute('data-reaches-right', 'true');
|
|
57
|
+
}
|
|
58
|
+
};
|
|
17
59
|
/**
|
|
18
60
|
* Extracts information about deleted table rows from a change
|
|
19
61
|
*/
|
|
20
|
-
var extractChangedRows = function extractChangedRows(
|
|
21
|
-
var change =
|
|
22
|
-
originalDoc =
|
|
23
|
-
newDoc =
|
|
24
|
-
diffType =
|
|
62
|
+
var extractChangedRows = function extractChangedRows(_ref2) {
|
|
63
|
+
var change = _ref2.change,
|
|
64
|
+
originalDoc = _ref2.originalDoc,
|
|
65
|
+
newDoc = _ref2.newDoc,
|
|
66
|
+
diffType = _ref2.diffType;
|
|
25
67
|
var changedRows = [];
|
|
26
68
|
|
|
27
69
|
// Find the table in the original document
|
|
@@ -62,12 +104,18 @@ var extractChangedRows = function extractChangedRows(_ref) {
|
|
|
62
104
|
// Check if this row overlaps with the deletion range
|
|
63
105
|
var rowOverlapsChange = rowStart >= changeStartInTable && rowStart < changeEndInTable || rowEnd > changeStartInTable && rowEnd <= changeEndInTable || rowStart < changeStartInTable && rowEnd > changeEndInTable;
|
|
64
106
|
if (rowOverlapsChange && rowNode.type.name === 'tableRow' && (isExtendedEnabled(diffType) || !isEmptyRow(rowNode))) {
|
|
107
|
+
var cellEdgeAttrs = isExtendedEnabled(diffType) && expValEquals('platform_editor_table_diff_rounded_corners', 'isEnabled', true) ? getChangedRowCellEdgeAttrs({
|
|
108
|
+
rowNode: rowNode,
|
|
109
|
+
rowStart: rowStart,
|
|
110
|
+
tableMap: oldTableMap
|
|
111
|
+
}) : undefined;
|
|
65
112
|
var startOfRow = newTableMap.mapByRow.slice().reverse().find(function (row) {
|
|
66
113
|
return row[0] + tableNew.pos < change.fromB && change.fromB < row[row.length - 1] + tableNew.pos;
|
|
67
114
|
});
|
|
68
115
|
changedRows.push({
|
|
69
116
|
rowIndex: rowIndex,
|
|
70
117
|
rowNode: rowNode,
|
|
118
|
+
cellEdgeAttrs: cellEdgeAttrs,
|
|
71
119
|
fromA: tableOld.pos + 1 + rowStart,
|
|
72
120
|
toA: tableOld.pos + 1 + rowEnd,
|
|
73
121
|
fromB: startOfRow ? startOfRow[0] + tableNew.start : change.fromB
|
|
@@ -116,7 +164,7 @@ var isEmptyRow = function isEmptyRow(rowNode) {
|
|
|
116
164
|
/**
|
|
117
165
|
* Creates a DOM representation of a deleted table row
|
|
118
166
|
*/
|
|
119
|
-
var createChangedRowDOM = function createChangedRowDOM(rowNode, nodeViewSerializer, colorScheme, isInserted, diffType) {
|
|
167
|
+
var createChangedRowDOM = function createChangedRowDOM(rowNode, cellEdgeAttrs, nodeViewSerializer, colorScheme, isInserted, diffType) {
|
|
120
168
|
var tr = document.createElement('tr');
|
|
121
169
|
if (isExtendedEnabled(diffType)) {
|
|
122
170
|
if (!isInserted) {
|
|
@@ -128,15 +176,23 @@ var createChangedRowDOM = function createChangedRowDOM(rowNode, nodeViewSerializ
|
|
|
128
176
|
tr.setAttribute('data-testid', 'show-diff-deleted-row');
|
|
129
177
|
|
|
130
178
|
// Serialize each cell in the row
|
|
179
|
+
var cellIndex = 0;
|
|
131
180
|
rowNode.content.forEach(function (cellNode) {
|
|
132
181
|
if (cellNode.type.name === 'tableCell' || cellNode.type.name === 'tableHeader') {
|
|
133
182
|
var nodeView = nodeViewSerializer.tryCreateNodeView(cellNode);
|
|
134
183
|
if (nodeView) {
|
|
135
|
-
if (nodeView instanceof HTMLElement
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
184
|
+
if (nodeView instanceof HTMLElement) {
|
|
185
|
+
applyCellEdgeAttrs(nodeView, cellEdgeAttrs === null || cellEdgeAttrs === void 0 ? void 0 : cellEdgeAttrs[cellIndex]);
|
|
186
|
+
if (isExtendedEnabled(diffType)) {
|
|
187
|
+
var overlay = document.createElement('span');
|
|
188
|
+
var isRoundedTable = expValEquals('platform_editor_table_diff_rounded_corners', 'isEnabled', true);
|
|
189
|
+
var isTraditional = colorScheme === 'traditional';
|
|
190
|
+
var deletedCellStyle = isTraditional ? deletedTraditionalCellOverlayStyle : deletedCellOverlayStyle;
|
|
191
|
+
var addedCellStyle = isTraditional ? isRoundedTable ? traditionalAddedCellOverlayRoundedStyle : traditionalAddedCellOverlayStyle : isRoundedTable ? addedCellOverlayRoundedStyle : addedCellOverlayStyle;
|
|
192
|
+
var overlayStyle = isInserted ? addedCellStyle : deletedCellStyle;
|
|
193
|
+
overlay.setAttribute('style', overlayStyle);
|
|
194
|
+
nodeView.appendChild(overlay);
|
|
195
|
+
}
|
|
140
196
|
}
|
|
141
197
|
tr.appendChild(nodeView);
|
|
142
198
|
} else {
|
|
@@ -146,6 +202,7 @@ var createChangedRowDOM = function createChangedRowDOM(rowNode, nodeViewSerializ
|
|
|
146
202
|
tr.appendChild(serializedContent);
|
|
147
203
|
}
|
|
148
204
|
}
|
|
205
|
+
cellIndex++;
|
|
149
206
|
}
|
|
150
207
|
});
|
|
151
208
|
return tr;
|
|
@@ -154,11 +211,11 @@ var createChangedRowDOM = function createChangedRowDOM(rowNode, nodeViewSerializ
|
|
|
154
211
|
/**
|
|
155
212
|
* Expands a diff to include whole changed rows when table rows are affected
|
|
156
213
|
*/
|
|
157
|
-
var expandDiffForChangedRows = function expandDiffForChangedRows(
|
|
158
|
-
var changes =
|
|
159
|
-
originalDoc =
|
|
160
|
-
newDoc =
|
|
161
|
-
diffType =
|
|
214
|
+
var expandDiffForChangedRows = function expandDiffForChangedRows(_ref3) {
|
|
215
|
+
var changes = _ref3.changes,
|
|
216
|
+
originalDoc = _ref3.originalDoc,
|
|
217
|
+
newDoc = _ref3.newDoc,
|
|
218
|
+
diffType = _ref3.diffType;
|
|
162
219
|
var rowInfo = [];
|
|
163
220
|
var _iterator = _createForOfIteratorHelper(changes),
|
|
164
221
|
_step;
|
|
@@ -187,15 +244,15 @@ var expandDiffForChangedRows = function expandDiffForChangedRows(_ref2) {
|
|
|
187
244
|
/**
|
|
188
245
|
* Main function to handle deleted rows - computes diff and creates decorations
|
|
189
246
|
*/
|
|
190
|
-
export var createChangedRowDecorationWidgets = function createChangedRowDecorationWidgets(
|
|
191
|
-
var changes =
|
|
192
|
-
originalDoc =
|
|
193
|
-
newDoc =
|
|
194
|
-
nodeViewSerializer =
|
|
195
|
-
colorScheme =
|
|
196
|
-
|
|
197
|
-
isInserted =
|
|
198
|
-
diffType =
|
|
247
|
+
export var createChangedRowDecorationWidgets = function createChangedRowDecorationWidgets(_ref4) {
|
|
248
|
+
var changes = _ref4.changes,
|
|
249
|
+
originalDoc = _ref4.originalDoc,
|
|
250
|
+
newDoc = _ref4.newDoc,
|
|
251
|
+
nodeViewSerializer = _ref4.nodeViewSerializer,
|
|
252
|
+
colorScheme = _ref4.colorScheme,
|
|
253
|
+
_ref4$isInserted = _ref4.isInserted,
|
|
254
|
+
isInserted = _ref4$isInserted === void 0 ? false : _ref4$isInserted,
|
|
255
|
+
diffType = _ref4.diffType;
|
|
199
256
|
// First, expand the changes to include complete deleted rows
|
|
200
257
|
var changedRows = expandDiffForChangedRows({
|
|
201
258
|
changes: changes.filter(function (change) {
|
|
@@ -206,7 +263,7 @@ export var createChangedRowDecorationWidgets = function createChangedRowDecorati
|
|
|
206
263
|
diffType: diffType
|
|
207
264
|
});
|
|
208
265
|
return changedRows.map(function (changedRow) {
|
|
209
|
-
var rowDOM = createChangedRowDOM(changedRow.rowNode, nodeViewSerializer, colorScheme, isInserted, diffType);
|
|
266
|
+
var rowDOM = createChangedRowDOM(changedRow.rowNode, changedRow.cellEdgeAttrs, nodeViewSerializer, colorScheme, isInserted, diffType);
|
|
210
267
|
|
|
211
268
|
// Find safe insertion position for the deleted row
|
|
212
269
|
var safeInsertPos = findSafeInsertPos(newDoc, changedRow.fromB - 1,
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
2
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
3
|
+
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; }
|
|
4
|
+
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; }
|
|
2
5
|
import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
|
|
3
6
|
import { Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
4
7
|
import { isExtendedEnabled } from '../isExtendedEnabled';
|
|
@@ -9,6 +12,16 @@ import { buildDiffDecorationSpec } from './decorationKeys';
|
|
|
9
12
|
var displayNoneStyle = convertToInlineCss({
|
|
10
13
|
display: 'none'
|
|
11
14
|
});
|
|
15
|
+
var getAtomicInlineNodeClassName = function getAtomicInlineNodeClassName(inlineNodeName, colorScheme) {
|
|
16
|
+
var classNames = ['show-diff-atomic-inline-changed'];
|
|
17
|
+
if (inlineNodeName) {
|
|
18
|
+
classNames.push("show-diff-atomic-inline-changed-".concat(inlineNodeName));
|
|
19
|
+
}
|
|
20
|
+
if (colorScheme === 'traditional') {
|
|
21
|
+
classNames.push('show-diff-atomic-inline-changed-traditional');
|
|
22
|
+
}
|
|
23
|
+
return classNames.join(' ');
|
|
24
|
+
};
|
|
12
25
|
/**
|
|
13
26
|
* Inline decoration used for insertions as the content already exists in the document
|
|
14
27
|
*
|
|
@@ -23,6 +36,8 @@ export var createInlineChangedDecoration = function createInlineChangedDecoratio
|
|
|
23
36
|
isActive = _ref$isActive === void 0 ? false : _ref$isActive,
|
|
24
37
|
_ref$isInserted = _ref.isInserted,
|
|
25
38
|
isInserted = _ref$isInserted === void 0 ? true : _ref$isInserted,
|
|
39
|
+
_ref$isAtomicInlineNo = _ref.isAtomicInlineNode,
|
|
40
|
+
isAtomicInlineNode = _ref$isAtomicInlineNo === void 0 ? false : _ref$isAtomicInlineNo,
|
|
26
41
|
_ref$shouldHideDelete = _ref.shouldHideDeleted,
|
|
27
42
|
shouldHideDeleted = _ref$shouldHideDelete === void 0 ? false : _ref$shouldHideDelete,
|
|
28
43
|
_ref$showIndicators = _ref.showIndicators,
|
|
@@ -30,7 +45,8 @@ export var createInlineChangedDecoration = function createInlineChangedDecoratio
|
|
|
30
45
|
doc = _ref.doc,
|
|
31
46
|
diffType = _ref.diffType,
|
|
32
47
|
_ref$hideAddedDiffsUn = _ref.hideAddedDiffsUnderline,
|
|
33
|
-
hideAddedDiffsUnderline = _ref$hideAddedDiffsUn === void 0 ? false : _ref$hideAddedDiffsUn
|
|
48
|
+
hideAddedDiffsUnderline = _ref$hideAddedDiffsUn === void 0 ? false : _ref$hideAddedDiffsUn,
|
|
49
|
+
inlineNodeName = _ref.inlineNodeName;
|
|
34
50
|
var diffId = crypto.randomUUID();
|
|
35
51
|
if (shouldHideDeleted) {
|
|
36
52
|
return [Decoration.inline(change.fromB, change.toB, {
|
|
@@ -69,10 +85,13 @@ export var createInlineChangedDecoration = function createInlineChangedDecoratio
|
|
|
69
85
|
style = isActive ? editingStyleActive : editingStyle;
|
|
70
86
|
}
|
|
71
87
|
}
|
|
72
|
-
var decorations = [Decoration.inline(change.fromB, change.toB, {
|
|
73
|
-
style: style
|
|
88
|
+
var decorations = [Decoration.inline(change.fromB, change.toB, _objectSpread(_objectSpread({
|
|
89
|
+
style: style
|
|
90
|
+
}, isAtomicInlineNode && isInserted && {
|
|
91
|
+
class: getAtomicInlineNodeClassName(inlineNodeName, colorScheme)
|
|
92
|
+
}), {}, {
|
|
74
93
|
'data-testid': 'show-diff-changed-decoration'
|
|
75
|
-
}, buildDiffDecorationSpec({
|
|
94
|
+
}), buildDiffDecorationSpec({
|
|
76
95
|
decorationType: 'inline',
|
|
77
96
|
diffId: diffId,
|
|
78
97
|
isActive: isActive
|