@atlaskit/editor-plugin-show-diff 16.0.12 → 16.0.14
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 +30 -0
- package/dist/cjs/pm-plugins/decorations/colorSchemes/attributions.js +30 -4
- package/dist/cjs/pm-plugins/decorations/createChangedRowDecorationWidgets.js +52 -6
- package/dist/cjs/pm-plugins/decorations/createInlineChangedDecoration.js +4 -6
- package/dist/cjs/pm-plugins/decorations/createNodeChangedDecorationWidget.js +10 -8
- package/dist/cjs/pm-plugins/utils/isEmptyParagraphSlice.js +11 -0
- package/dist/cjs/ui/IndicatorBar/IndicatorBar.js +1 -1
- package/dist/cjs/ui/IndicatorBar/IndicatorBarContentComponent.js +1 -1
- package/dist/es2019/pm-plugins/decorations/colorSchemes/attributions.js +28 -4
- package/dist/es2019/pm-plugins/decorations/createChangedRowDecorationWidgets.js +52 -7
- package/dist/es2019/pm-plugins/decorations/createInlineChangedDecoration.js +4 -6
- package/dist/es2019/pm-plugins/decorations/createNodeChangedDecorationWidget.js +10 -8
- package/dist/es2019/pm-plugins/utils/isEmptyParagraphSlice.js +5 -0
- package/dist/es2019/ui/IndicatorBar/IndicatorBar.js +1 -1
- package/dist/es2019/ui/IndicatorBar/IndicatorBarContentComponent.js +1 -1
- package/dist/esm/pm-plugins/decorations/colorSchemes/attributions.js +30 -4
- package/dist/esm/pm-plugins/decorations/createChangedRowDecorationWidgets.js +53 -7
- package/dist/esm/pm-plugins/decorations/createInlineChangedDecoration.js +4 -6
- package/dist/esm/pm-plugins/decorations/createNodeChangedDecorationWidget.js +10 -8
- package/dist/esm/pm-plugins/utils/isEmptyParagraphSlice.js +5 -0
- package/dist/esm/ui/IndicatorBar/IndicatorBar.js +1 -1
- package/dist/esm/ui/IndicatorBar/IndicatorBarContentComponent.js +1 -1
- package/dist/types/pm-plugins/decorations/createChangedRowDecorationWidgets.d.ts +2 -1
- package/dist/types/pm-plugins/utils/isEmptyParagraphSlice.d.ts +3 -0
- package/package.json +2 -2
- package/dist/cjs/pm-plugins/utils/hasVisibleContent.js +0 -37
- package/dist/es2019/pm-plugins/utils/hasVisibleContent.js +0 -28
- package/dist/esm/pm-plugins/utils/hasVisibleContent.js +0 -32
- package/dist/types/pm-plugins/utils/hasVisibleContent.d.ts +0 -13
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-show-diff
|
|
2
2
|
|
|
3
|
+
## 16.0.14
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`6667b6ae8e77c`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/6667b6ae8e77c) -
|
|
8
|
+
Ensure contributor tags are rendered for shown attributed diff content, including whitespace-only
|
|
9
|
+
changes and deletion widgets, without tagging structurally empty paragraphs.
|
|
10
|
+
|
|
11
|
+
## 16.0.13
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- [`7d1a41f1575e5`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/7d1a41f1575e5) -
|
|
16
|
+
Reserve red for deletions in show-diff attribution: an actor hashing to a red palette slot now
|
|
17
|
+
takes the next colour instead. Gated on confluence_ncs_step_diffing_version_history and
|
|
18
|
+
platform_editor_show_diff_color_scheme_refactor.
|
|
19
|
+
- [`19e336d422584`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/19e336d422584) -
|
|
20
|
+
Fix whole-row table replacements rendering no diff for the new content.
|
|
21
|
+
`createChangedRowDecorationWidgets` only handled row deletions, so a `replaceNode` on a `tableRow`
|
|
22
|
+
(as AI suggested edits emits) left the reviewer with just the removed side — or an empty row in
|
|
23
|
+
the clean view.
|
|
24
|
+
|
|
25
|
+
Also give the changed-row widget an indicator anchor, so the indicator bar spans both the proposed
|
|
26
|
+
and replaced rows instead of only the row being changed. This affects row deletions too, whose
|
|
27
|
+
deleted-row bar previously had no anchor to resolve against.
|
|
28
|
+
|
|
29
|
+
Both behind `platform_editor_ai_show_diff_patch_1`.
|
|
30
|
+
|
|
31
|
+
- Updated dependencies
|
|
32
|
+
|
|
3
33
|
## 16.0.12
|
|
4
34
|
|
|
5
35
|
### Patch Changes
|
|
@@ -25,15 +25,40 @@ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length)
|
|
|
25
25
|
|
|
26
26
|
/** Maps the shared 18-slot telepointer palette onto the ten bolder diff colours. */
|
|
27
27
|
var HASHED_PARTICIPANT_COLOR_SCHEMES = [].concat((0, _toConsumableArray2.default)(_types.PARTICIPANT_COLOR_SCHEMES), ['blue', 'red', 'orange', 'yellow', 'green', 'teal', 'purple', 'magenta']);
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Red means "deleted" in both public schemes, so it never identifies an actor. Reserving it here
|
|
31
|
+
* covers every path into an attribution colour; `createAttributionColorMap` is the only caller, and
|
|
32
|
+
* it is gated on `confluence_ncs_step_diffing_version_history` plus
|
|
33
|
+
* `platform_editor_show_diff_color_scheme_refactor`.
|
|
34
|
+
*/
|
|
35
|
+
var RESERVED_ATTRIBUTION_COLORS = new Set(['red']);
|
|
36
|
+
var isAssignable = function isAssignable(color) {
|
|
37
|
+
return !RESERVED_ATTRIBUTION_COLORS.has(color);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/** Projects a telepointer slot onto its diff hue, advancing past a hue reserved for deletion. */
|
|
41
|
+
var getSlotColor = function getSlotColor(index) {
|
|
42
|
+
for (var offset = 0; offset < HASHED_PARTICIPANT_COLOR_SCHEMES.length; offset++) {
|
|
43
|
+
var color = HASHED_PARTICIPANT_COLOR_SCHEMES[(index + offset) % HASHED_PARTICIPANT_COLOR_SCHEMES.length];
|
|
44
|
+
if (color && isAssignable(color)) {
|
|
45
|
+
return color;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return undefined;
|
|
49
|
+
};
|
|
28
50
|
var getAvailableColor = function getAvailableColor(hashedColor, allocatedColors) {
|
|
51
|
+
var _PARTICIPANT_COLOR_SC;
|
|
29
52
|
var startIndex = _types.PARTICIPANT_COLOR_SCHEMES.indexOf(hashedColor);
|
|
30
53
|
for (var offset = 0; offset < _types.PARTICIPANT_COLOR_SCHEMES.length; offset++) {
|
|
31
54
|
var color = _types.PARTICIPANT_COLOR_SCHEMES[(startIndex + offset) % _types.PARTICIPANT_COLOR_SCHEMES.length];
|
|
32
|
-
if (color && !allocatedColors.has(color)) {
|
|
55
|
+
if (color && isAssignable(color) && !allocatedColors.has(color)) {
|
|
33
56
|
return color;
|
|
34
57
|
}
|
|
35
58
|
}
|
|
36
|
-
|
|
59
|
+
|
|
60
|
+
// Every assignable hue is taken, so a duplicate is unavoidable — but never the reserved hue.
|
|
61
|
+
return isAssignable(hashedColor) ? hashedColor : (_PARTICIPANT_COLOR_SC = _types.PARTICIPANT_COLOR_SCHEMES.find(isAssignable)) !== null && _PARTICIPANT_COLOR_SC !== void 0 ? _PARTICIPANT_COLOR_SC : hashedColor;
|
|
37
62
|
};
|
|
38
63
|
|
|
39
64
|
/**
|
|
@@ -133,7 +158,8 @@ var createAttributionColorMap = exports.createAttributionColorMap = function cre
|
|
|
133
158
|
var colors = new Map();
|
|
134
159
|
var allocatedColors = new Set();
|
|
135
160
|
|
|
136
|
-
// Reserve shared brand colours before hashing other actors, regardless of step order.
|
|
161
|
+
// Reserve shared brand colours before hashing other actors, regardless of step order. A brand
|
|
162
|
+
// slot is pinned deliberately, so it is taken verbatim rather than through `getSlotColor`.
|
|
137
163
|
var _iterator2 = _createForOfIteratorHelper(stepAttributions),
|
|
138
164
|
_step2;
|
|
139
165
|
try {
|
|
@@ -168,7 +194,7 @@ var createAttributionColorMap = exports.createAttributionColorMap = function cre
|
|
|
168
194
|
}
|
|
169
195
|
var _getParticipantColor2 = (0, _utils.getParticipantColor)(_identity.colorSeed, _attribution === null || _attribution === void 0 ? void 0 : _attribution.agentType),
|
|
170
196
|
_index = _getParticipantColor2.index;
|
|
171
|
-
var hashedColor =
|
|
197
|
+
var hashedColor = getSlotColor(_index);
|
|
172
198
|
if (!hashedColor) {
|
|
173
199
|
continue;
|
|
174
200
|
}
|
|
@@ -12,10 +12,12 @@ var _utils = require("@atlaskit/editor-prosemirror/utils");
|
|
|
12
12
|
var _view = require("@atlaskit/editor-prosemirror/view");
|
|
13
13
|
var _tableMap = require("@atlaskit/editor-tables/table-map");
|
|
14
14
|
var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-experiment-enabled");
|
|
15
|
+
var _fg = require("@atlaskit/platform-feature-flags/fg");
|
|
15
16
|
var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
|
|
16
17
|
var _isExtendedEnabled = require("../isExtendedEnabled");
|
|
17
18
|
var _factory = require("./colorSchemes/factory");
|
|
18
19
|
var _schemes = require("./colorSchemes/schemes");
|
|
20
|
+
var _createAnchorDecorationWidgets = require("./createAnchorDecorationWidgets");
|
|
19
21
|
var _createChangedRowDecorationWidgetsStyles = require("./createChangedRowDecorationWidgets.styles.legacy");
|
|
20
22
|
var _decorationKeys = require("./decorationKeys");
|
|
21
23
|
var _findSafeInsertPos = require("./utils/findSafeInsertPos");
|
|
@@ -54,8 +56,14 @@ var extractChangedRows = function extractChangedRows(_ref) {
|
|
|
54
56
|
return changedRows;
|
|
55
57
|
}
|
|
56
58
|
var newTableMap = _tableMap.TableMap.get(tableNew.node);
|
|
59
|
+
// A row DELETION makes the table shorter. An in-place whole-row REPLACEMENT (`replaceNode` on a
|
|
60
|
+
// `tableRow`, which AI suggested edits emits) leaves the row count untouched — and this helper
|
|
61
|
+
// was written for deletions only, so it used to discard every replacement and the changed row's
|
|
62
|
+
// content was never rendered anywhere. The reviewer was left with just the removed side.
|
|
63
|
+
var isRowDeletion = oldTableMap.height > newTableMap.height;
|
|
64
|
+
var handleRowReplacement = oldTableMap.height === newTableMap.height && (0, _fg.fg)('platform_editor_ai_show_diff_patch_1');
|
|
57
65
|
// If no rows were changed, return empty
|
|
58
|
-
if (
|
|
66
|
+
if (!(isRowDeletion || handleRowReplacement) ||
|
|
59
67
|
// For now ignore if there are column deletions as well
|
|
60
68
|
oldTableMap.width !== newTableMap.width) {
|
|
61
69
|
return changedRows;
|
|
@@ -99,6 +107,15 @@ var extractChangedRows = function extractChangedRows(_ref) {
|
|
|
99
107
|
|
|
100
108
|
// Filter changes that never truly got deleted
|
|
101
109
|
return changedRows.filter(function (changedRow) {
|
|
110
|
+
// A replacement leaves every sibling row in place, so asking "does this row still exist
|
|
111
|
+
// ANYWHERE in the new table?" can drop a genuinely rewritten row that happens to match a
|
|
112
|
+
// sibling. Compare it against the row at the same index instead. Deletions must keep the
|
|
113
|
+
// whole-table `some()`: their indices shift, so an index comparison would let every
|
|
114
|
+
// surviving row through and draw a widget for each one.
|
|
115
|
+
if (handleRowReplacement) {
|
|
116
|
+
var counterpart = tableNew.node.maybeChild(changedRow.rowIndex);
|
|
117
|
+
return !counterpart || !(0, _document.areNodesEqualIgnoreAttrs)(counterpart, changedRow.rowNode);
|
|
118
|
+
}
|
|
102
119
|
return !tableNew.node.children.some(function (newRow) {
|
|
103
120
|
return (0, _document.areNodesEqualIgnoreAttrs)(newRow, changedRow.rowNode);
|
|
104
121
|
});
|
|
@@ -142,7 +159,10 @@ var createChangedRowDOM = function createChangedRowDOM(rowNode, cellEdgeAttrs, n
|
|
|
142
159
|
if (!(0, _isExtendedEnabled.isExtendedEnabled)(diffType) || !isInserted) {
|
|
143
160
|
tr.setAttribute('style', (0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_show_diff_color_scheme_refactor') ? (0, _factory.buildDeletedRowStyle)(colors) : (0, _createChangedRowDecorationWidgetsStyles.resolveDeletedRowStyleLegacy)((0, _schemes.getLegacyColorScheme)(colorScheme)));
|
|
144
161
|
}
|
|
145
|
-
|
|
162
|
+
// Mirrors the strikethrough condition above: under the extended experience an `isInserted` row
|
|
163
|
+
// is ADDED content, so it must not claim the "deleted" testid — page models match that as
|
|
164
|
+
// removed content (same reasoning as `createTableCellContentWidgets`).
|
|
165
|
+
tr.setAttribute('data-testid', (0, _isExtendedEnabled.isExtendedEnabled)(diffType) && isInserted && (0, _fg.fg)('platform_editor_ai_show_diff_patch_1') ? 'show-diff-changed-row' : 'show-diff-deleted-row');
|
|
146
166
|
|
|
147
167
|
// Serialize each cell in the row
|
|
148
168
|
var cellIndex = 0;
|
|
@@ -222,7 +242,9 @@ var createChangedRowDecorationWidgets = exports.createChangedRowDecorationWidget
|
|
|
222
242
|
colorScheme = _ref3.colorScheme,
|
|
223
243
|
_ref3$isInserted = _ref3.isInserted,
|
|
224
244
|
isInserted = _ref3$isInserted === void 0 ? false : _ref3$isInserted,
|
|
225
|
-
diffType = _ref3.diffType
|
|
245
|
+
diffType = _ref3.diffType,
|
|
246
|
+
_ref3$showIndicators = _ref3.showIndicators,
|
|
247
|
+
showIndicators = _ref3$showIndicators === void 0 ? false : _ref3$showIndicators;
|
|
226
248
|
// First, expand the changes to include complete deleted rows
|
|
227
249
|
var changedRows = expandDiffForChangedRows({
|
|
228
250
|
changes: changes.filter(function (change) {
|
|
@@ -232,7 +254,7 @@ var createChangedRowDecorationWidgets = exports.createChangedRowDecorationWidget
|
|
|
232
254
|
newDoc: newDoc,
|
|
233
255
|
diffType: diffType
|
|
234
256
|
});
|
|
235
|
-
return changedRows.
|
|
257
|
+
return changedRows.flatMap(function (changedRow) {
|
|
236
258
|
var rowDOM = createChangedRowDOM(changedRow.rowNode, changedRow.cellEdgeAttrs, nodeViewSerializer, colorScheme, isInserted, diffType);
|
|
237
259
|
|
|
238
260
|
// Find safe insertion position for the deleted row
|
|
@@ -240,13 +262,37 @@ var createChangedRowDecorationWidgets = exports.createChangedRowDecorationWidget
|
|
|
240
262
|
// -1 to find the first safe position from the table
|
|
241
263
|
originalDoc.slice(changedRow.fromA, changedRow.toA));
|
|
242
264
|
var diffId = crypto.randomUUID();
|
|
243
|
-
|
|
265
|
+
var decorations = [];
|
|
266
|
+
|
|
267
|
+
// `IndicatorBarContentComponent` renders a bar for every widget descriptor and anchors its
|
|
268
|
+
// top and bottom to `anchor-<diffId>`. Without an element carrying that anchor name the bar
|
|
269
|
+
// is still created but can never resolve a position, so it silently does not render and the
|
|
270
|
+
// bar covers only the row being changed. `createNodeChangedDecorationWidget` sets the same
|
|
271
|
+
// property on its own widget DOM for non-table content; this path returns before reaching it.
|
|
272
|
+
if (showIndicators && (0, _isExtendedEnabled.isExtendedEnabled)(diffType) && (0, _fg.fg)('platform_editor_ai_show_diff_patch_1')) {
|
|
273
|
+
rowDOM.style.setProperty('anchor-name', "--".concat((0, _decorationKeys.buildAnchorDecorationKey)({
|
|
274
|
+
diffId: diffId
|
|
275
|
+
})));
|
|
276
|
+
|
|
277
|
+
// A table's content can extend past the doc margin, so the bar also needs a left anchor
|
|
278
|
+
// measured against the table itself or it is clipped once the table is resized.
|
|
279
|
+
var leftAnchor = (0, _createAnchorDecorationWidgets.createLeftAnchorWidget)({
|
|
280
|
+
doc: newDoc,
|
|
281
|
+
from: safeInsertPos,
|
|
282
|
+
diffId: diffId
|
|
283
|
+
});
|
|
284
|
+
if (leftAnchor) {
|
|
285
|
+
decorations.push(leftAnchor);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
decorations.push(_view.Decoration.widget(safeInsertPos, rowDOM, _objectSpread({}, (0, _decorationKeys.buildDiffDecorationSpec)({
|
|
244
289
|
colorScheme: colorScheme,
|
|
245
290
|
decorationType: 'widget',
|
|
246
291
|
diffId: diffId,
|
|
247
292
|
isActive: false,
|
|
248
293
|
isInserted: isInserted,
|
|
249
294
|
diffType: diffType
|
|
250
|
-
})));
|
|
295
|
+
}))));
|
|
296
|
+
return decorations;
|
|
251
297
|
});
|
|
252
298
|
};
|
|
@@ -12,7 +12,7 @@ var _view = require("@atlaskit/editor-prosemirror/view");
|
|
|
12
12
|
var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-experiment-enabled");
|
|
13
13
|
var _buildContributorTagDom = require("../../ui/ContributorTag/buildContributorTagDom");
|
|
14
14
|
var _isExtendedEnabled = require("../isExtendedEnabled");
|
|
15
|
-
var
|
|
15
|
+
var _isEmptyParagraphSlice = require("../utils/isEmptyParagraphSlice");
|
|
16
16
|
var _factory = require("./colorSchemes/factory");
|
|
17
17
|
var _schemes = require("./colorSchemes/schemes");
|
|
18
18
|
var _createAnchorDecorationWidgets = require("./createAnchorDecorationWidgets");
|
|
@@ -163,11 +163,9 @@ var createInlineChangedDecoration = exports.createInlineChangedDecoration = func
|
|
|
163
163
|
// tag host's key, remounting every tag mid-step. Random ids are kept when tags are off.
|
|
164
164
|
var diffId = showContributorTags ? "inline-".concat(change.fromB, "-").concat(change.toB) : crypto.randomUUID();
|
|
165
165
|
|
|
166
|
-
//
|
|
167
|
-
//
|
|
168
|
-
|
|
169
|
-
// a host that is never emitted (EDITOR-8855).
|
|
170
|
-
var canTagChange = showContributorTags && !!doc && (0, _isExtendedEnabled.isExtendedEnabled)(diffType) && (0, _createContributorTagWidget.isContributorTagWidgetEnabled)() && (0, _hasVisibleContent.hasVisibleContent)(doc.slice(change.fromB, change.toB).content);
|
|
166
|
+
// Match the rendered shape: whitespace text is eligible, while an empty paragraph is structural
|
|
167
|
+
// content with no tag host.
|
|
168
|
+
var canTagChange = showContributorTags && !!doc && (0, _isExtendedEnabled.isExtendedEnabled)(diffType) && (0, _createContributorTagWidget.isContributorTagWidgetEnabled)() && !(0, _isEmptyParagraphSlice.isEmptyParagraphSlice)(doc.slice(change.fromB, change.toB));
|
|
171
169
|
if (shouldHideDeleted) {
|
|
172
170
|
return [_view.Decoration.inline(change.fromB, change.toB, {
|
|
173
171
|
style: displayNoneStyle
|
|
@@ -9,7 +9,7 @@ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/de
|
|
|
9
9
|
var _view = require("@atlaskit/editor-prosemirror/view");
|
|
10
10
|
var _fg = require("@atlaskit/platform-feature-flags/fg");
|
|
11
11
|
var _isExtendedEnabled = require("../isExtendedEnabled");
|
|
12
|
-
var
|
|
12
|
+
var _isEmptyParagraphSlice = require("../utils/isEmptyParagraphSlice");
|
|
13
13
|
var _createAnchorDecorationWidgets = require("./createAnchorDecorationWidgets");
|
|
14
14
|
var _createChangedRowDecorationWidgets = require("./createChangedRowDecorationWidgets");
|
|
15
15
|
var _createContributorTagWidget = require("./createContributorTagWidget");
|
|
@@ -101,7 +101,7 @@ var createTableCellContentWidgets = function createTableCellContentWidgets(_ref)
|
|
|
101
101
|
* that is not in the current document.
|
|
102
102
|
*/
|
|
103
103
|
var createNodeChangedDecorationWidget = exports.createNodeChangedDecorationWidget = function createNodeChangedDecorationWidget(_ref2) {
|
|
104
|
-
var
|
|
104
|
+
var _$safeInsertPos$nodeB, _slice$content$firstC, _newDoc$firstChild, _slice$content$firstC2;
|
|
105
105
|
var attributionKey = _ref2.attributionKey,
|
|
106
106
|
change = _ref2.change,
|
|
107
107
|
doc = _ref2.doc,
|
|
@@ -124,7 +124,7 @@ var createNodeChangedDecorationWidget = exports.createNodeChangedDecorationWidge
|
|
|
124
124
|
reveal = _ref2.reveal,
|
|
125
125
|
tagMountContext = _ref2.tagMountContext;
|
|
126
126
|
var slice = doc.slice(change.fromA, change.toA);
|
|
127
|
-
var shouldSkipDeletedEmptyParagraphDecoration = !isInserted && (
|
|
127
|
+
var shouldSkipDeletedEmptyParagraphDecoration = !isInserted && (0, _isEmptyParagraphSlice.isEmptyParagraphSlice)(slice);
|
|
128
128
|
// Widget decoration used for deletions as the content is not in the document
|
|
129
129
|
// and we want to display the deleted content with a style.
|
|
130
130
|
// For `placeBelow`, anchor at the END of the new content (change.toB) so the deleted
|
|
@@ -172,7 +172,10 @@ var createNodeChangedDecorationWidget = exports.createNodeChangedDecorationWidge
|
|
|
172
172
|
nodeViewSerializer: nodeViewSerializer,
|
|
173
173
|
colorScheme: colorScheme,
|
|
174
174
|
isInserted: isInserted,
|
|
175
|
-
diffType: diffType
|
|
175
|
+
diffType: diffType,
|
|
176
|
+
// Needed for the row's own indicator anchor; this path returns before the
|
|
177
|
+
// `anchor-name` assignment further down.
|
|
178
|
+
showIndicators: showIndicators
|
|
176
179
|
});
|
|
177
180
|
}
|
|
178
181
|
var serializer = nodeViewSerializer;
|
|
@@ -223,10 +226,9 @@ var createNodeChangedDecorationWidget = exports.createNodeChangedDecorationWidge
|
|
|
223
226
|
// Derived from the deleted range so it survives a recalculation — see the same reasoning in
|
|
224
227
|
// `createInlineChangedDecoration`.
|
|
225
228
|
var diffId = showContributorTags ? "widget-".concat(change.fromA, "-").concat(change.toA) : crypto.randomUUID();
|
|
226
|
-
//
|
|
227
|
-
//
|
|
228
|
-
|
|
229
|
-
var canTagWidget = showContributorTags && (0, _hasVisibleContent.hasVisibleContent)(slice.content);
|
|
229
|
+
// Match the rendering predicate above: an empty paragraph has no widget to tag, while whitespace
|
|
230
|
+
// text in a rendered widget remains eligible.
|
|
231
|
+
var canTagWidget = showContributorTags && !shouldSkipDeletedEmptyParagraphDecoration;
|
|
230
232
|
var decorations = [];
|
|
231
233
|
var replacementNode = newDoc.nodeAt(change.fromB);
|
|
232
234
|
var firstReplacedNode = slice.content.firstChild;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.isEmptyParagraphSlice = void 0;
|
|
7
|
+
/** Whether a slice contains exactly one structurally empty paragraph. */
|
|
8
|
+
var isEmptyParagraphSlice = exports.isEmptyParagraphSlice = function isEmptyParagraphSlice(slice) {
|
|
9
|
+
var _slice$content$firstC;
|
|
10
|
+
return (slice === null || slice === void 0 ? void 0 : slice.content.childCount) === 1 && ((_slice$content$firstC = slice.content.firstChild) === null || _slice$content$firstC === void 0 ? void 0 : _slice$content$firstC.type.name) === 'paragraph' && slice.content.firstChild.content.size === 0;
|
|
11
|
+
};
|
|
@@ -9,15 +9,38 @@ import { PARTICIPANT_COLOR_SCHEMES } from './types';
|
|
|
9
9
|
|
|
10
10
|
/** Maps the shared 18-slot telepointer palette onto the ten bolder diff colours. */
|
|
11
11
|
const HASHED_PARTICIPANT_COLOR_SCHEMES = [...PARTICIPANT_COLOR_SCHEMES, 'blue', 'red', 'orange', 'yellow', 'green', 'teal', 'purple', 'magenta'];
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Red means "deleted" in both public schemes, so it never identifies an actor. Reserving it here
|
|
15
|
+
* covers every path into an attribution colour; `createAttributionColorMap` is the only caller, and
|
|
16
|
+
* it is gated on `confluence_ncs_step_diffing_version_history` plus
|
|
17
|
+
* `platform_editor_show_diff_color_scheme_refactor`.
|
|
18
|
+
*/
|
|
19
|
+
const RESERVED_ATTRIBUTION_COLORS = new Set(['red']);
|
|
20
|
+
const isAssignable = color => !RESERVED_ATTRIBUTION_COLORS.has(color);
|
|
21
|
+
|
|
22
|
+
/** Projects a telepointer slot onto its diff hue, advancing past a hue reserved for deletion. */
|
|
23
|
+
const getSlotColor = index => {
|
|
24
|
+
for (let offset = 0; offset < HASHED_PARTICIPANT_COLOR_SCHEMES.length; offset++) {
|
|
25
|
+
const color = HASHED_PARTICIPANT_COLOR_SCHEMES[(index + offset) % HASHED_PARTICIPANT_COLOR_SCHEMES.length];
|
|
26
|
+
if (color && isAssignable(color)) {
|
|
27
|
+
return color;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return undefined;
|
|
31
|
+
};
|
|
12
32
|
const getAvailableColor = (hashedColor, allocatedColors) => {
|
|
33
|
+
var _PARTICIPANT_COLOR_SC;
|
|
13
34
|
const startIndex = PARTICIPANT_COLOR_SCHEMES.indexOf(hashedColor);
|
|
14
35
|
for (let offset = 0; offset < PARTICIPANT_COLOR_SCHEMES.length; offset++) {
|
|
15
36
|
const color = PARTICIPANT_COLOR_SCHEMES[(startIndex + offset) % PARTICIPANT_COLOR_SCHEMES.length];
|
|
16
|
-
if (color && !allocatedColors.has(color)) {
|
|
37
|
+
if (color && isAssignable(color) && !allocatedColors.has(color)) {
|
|
17
38
|
return color;
|
|
18
39
|
}
|
|
19
40
|
}
|
|
20
|
-
|
|
41
|
+
|
|
42
|
+
// Every assignable hue is taken, so a duplicate is unavoidable — but never the reserved hue.
|
|
43
|
+
return isAssignable(hashedColor) ? hashedColor : (_PARTICIPANT_COLOR_SC = PARTICIPANT_COLOR_SCHEMES.find(isAssignable)) !== null && _PARTICIPANT_COLOR_SC !== void 0 ? _PARTICIPANT_COLOR_SC : hashedColor;
|
|
21
44
|
};
|
|
22
45
|
|
|
23
46
|
/**
|
|
@@ -104,7 +127,8 @@ export const createAttributionColorMap = stepAttributions => {
|
|
|
104
127
|
const colors = new Map();
|
|
105
128
|
const allocatedColors = new Set();
|
|
106
129
|
|
|
107
|
-
// Reserve shared brand colours before hashing other actors, regardless of step order.
|
|
130
|
+
// Reserve shared brand colours before hashing other actors, regardless of step order. A brand
|
|
131
|
+
// slot is pinned deliberately, so it is taken verbatim rather than through `getSlotColor`.
|
|
108
132
|
for (const attribution of stepAttributions) {
|
|
109
133
|
const identity = getAttributionIdentity(attribution);
|
|
110
134
|
if (!identity) {
|
|
@@ -128,7 +152,7 @@ export const createAttributionColorMap = stepAttributions => {
|
|
|
128
152
|
const {
|
|
129
153
|
index
|
|
130
154
|
} = getParticipantColor(identity.colorSeed, attribution === null || attribution === void 0 ? void 0 : attribution.agentType);
|
|
131
|
-
const hashedColor =
|
|
155
|
+
const hashedColor = getSlotColor(index);
|
|
132
156
|
if (!hashedColor) {
|
|
133
157
|
continue;
|
|
134
158
|
}
|
|
@@ -3,12 +3,14 @@ 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
5
|
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
|
|
6
|
+
import { fg } from '@atlaskit/platform-feature-flags/fg';
|
|
6
7
|
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
7
8
|
import { isExtendedEnabled } from '../isExtendedEnabled';
|
|
8
9
|
import { buildAddedCellOverlayRoundedStyle, buildAddedCellOverlayStyle, buildDeletedCellOverlayRoundedStyle, buildDeletedCellOverlayStyle, buildDeletedRowStyle } from './colorSchemes/factory';
|
|
9
10
|
import { colorSchemeRegistry, getLegacyColorScheme } from './colorSchemes/schemes';
|
|
11
|
+
import { createLeftAnchorWidget } from './createAnchorDecorationWidgets';
|
|
10
12
|
import { resolveCellOverlayStyleLegacy, resolveDeletedRowStyleLegacy } from './createChangedRowDecorationWidgets.styles.legacy';
|
|
11
|
-
import { buildDiffDecorationSpec } from './decorationKeys';
|
|
13
|
+
import { buildAnchorDecorationKey, buildDiffDecorationSpec } from './decorationKeys';
|
|
12
14
|
import { findSafeInsertPos } from './utils/findSafeInsertPos';
|
|
13
15
|
import { applyCellEdgeAttrs, getRowCellEdgeAttrs, getTableTopAndBottomCellEdgeAttrs } from './utils/tableCellEdgeAttrs';
|
|
14
16
|
/**
|
|
@@ -37,8 +39,14 @@ const extractChangedRows = ({
|
|
|
37
39
|
return changedRows;
|
|
38
40
|
}
|
|
39
41
|
const newTableMap = TableMap.get(tableNew.node);
|
|
42
|
+
// A row DELETION makes the table shorter. An in-place whole-row REPLACEMENT (`replaceNode` on a
|
|
43
|
+
// `tableRow`, which AI suggested edits emits) leaves the row count untouched — and this helper
|
|
44
|
+
// was written for deletions only, so it used to discard every replacement and the changed row's
|
|
45
|
+
// content was never rendered anywhere. The reviewer was left with just the removed side.
|
|
46
|
+
const isRowDeletion = oldTableMap.height > newTableMap.height;
|
|
47
|
+
const handleRowReplacement = oldTableMap.height === newTableMap.height && fg('platform_editor_ai_show_diff_patch_1');
|
|
40
48
|
// If no rows were changed, return empty
|
|
41
|
-
if (
|
|
49
|
+
if (!(isRowDeletion || handleRowReplacement) ||
|
|
42
50
|
// For now ignore if there are column deletions as well
|
|
43
51
|
oldTableMap.width !== newTableMap.width) {
|
|
44
52
|
return changedRows;
|
|
@@ -80,6 +88,15 @@ const extractChangedRows = ({
|
|
|
80
88
|
|
|
81
89
|
// Filter changes that never truly got deleted
|
|
82
90
|
return changedRows.filter(changedRow => {
|
|
91
|
+
// A replacement leaves every sibling row in place, so asking "does this row still exist
|
|
92
|
+
// ANYWHERE in the new table?" can drop a genuinely rewritten row that happens to match a
|
|
93
|
+
// sibling. Compare it against the row at the same index instead. Deletions must keep the
|
|
94
|
+
// whole-table `some()`: their indices shift, so an index comparison would let every
|
|
95
|
+
// surviving row through and draw a widget for each one.
|
|
96
|
+
if (handleRowReplacement) {
|
|
97
|
+
const counterpart = tableNew.node.maybeChild(changedRow.rowIndex);
|
|
98
|
+
return !counterpart || !areNodesEqualIgnoreAttrs(counterpart, changedRow.rowNode);
|
|
99
|
+
}
|
|
83
100
|
return !tableNew.node.children.some(newRow => areNodesEqualIgnoreAttrs(newRow, changedRow.rowNode));
|
|
84
101
|
});
|
|
85
102
|
};
|
|
@@ -121,7 +138,10 @@ const createChangedRowDOM = (rowNode, cellEdgeAttrs, nodeViewSerializer, colorSc
|
|
|
121
138
|
if (!isExtendedEnabled(diffType) || !isInserted) {
|
|
122
139
|
tr.setAttribute('style', isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? buildDeletedRowStyle(colors) : resolveDeletedRowStyleLegacy(getLegacyColorScheme(colorScheme)));
|
|
123
140
|
}
|
|
124
|
-
|
|
141
|
+
// Mirrors the strikethrough condition above: under the extended experience an `isInserted` row
|
|
142
|
+
// is ADDED content, so it must not claim the "deleted" testid — page models match that as
|
|
143
|
+
// removed content (same reasoning as `createTableCellContentWidgets`).
|
|
144
|
+
tr.setAttribute('data-testid', isExtendedEnabled(diffType) && isInserted && fg('platform_editor_ai_show_diff_patch_1') ? 'show-diff-changed-row' : 'show-diff-deleted-row');
|
|
125
145
|
|
|
126
146
|
// Serialize each cell in the row
|
|
127
147
|
let cellIndex = 0;
|
|
@@ -192,7 +212,8 @@ export const createChangedRowDecorationWidgets = ({
|
|
|
192
212
|
nodeViewSerializer,
|
|
193
213
|
colorScheme,
|
|
194
214
|
isInserted = false,
|
|
195
|
-
diffType
|
|
215
|
+
diffType,
|
|
216
|
+
showIndicators = false
|
|
196
217
|
}) => {
|
|
197
218
|
// First, expand the changes to include complete deleted rows
|
|
198
219
|
const changedRows = expandDiffForChangedRows({
|
|
@@ -201,7 +222,7 @@ export const createChangedRowDecorationWidgets = ({
|
|
|
201
222
|
newDoc,
|
|
202
223
|
diffType
|
|
203
224
|
});
|
|
204
|
-
return changedRows.
|
|
225
|
+
return changedRows.flatMap(changedRow => {
|
|
205
226
|
const rowDOM = createChangedRowDOM(changedRow.rowNode, changedRow.cellEdgeAttrs, nodeViewSerializer, colorScheme, isInserted, diffType);
|
|
206
227
|
|
|
207
228
|
// Find safe insertion position for the deleted row
|
|
@@ -209,7 +230,30 @@ export const createChangedRowDecorationWidgets = ({
|
|
|
209
230
|
// -1 to find the first safe position from the table
|
|
210
231
|
originalDoc.slice(changedRow.fromA, changedRow.toA));
|
|
211
232
|
const diffId = crypto.randomUUID();
|
|
212
|
-
|
|
233
|
+
const decorations = [];
|
|
234
|
+
|
|
235
|
+
// `IndicatorBarContentComponent` renders a bar for every widget descriptor and anchors its
|
|
236
|
+
// top and bottom to `anchor-<diffId>`. Without an element carrying that anchor name the bar
|
|
237
|
+
// is still created but can never resolve a position, so it silently does not render and the
|
|
238
|
+
// bar covers only the row being changed. `createNodeChangedDecorationWidget` sets the same
|
|
239
|
+
// property on its own widget DOM for non-table content; this path returns before reaching it.
|
|
240
|
+
if (showIndicators && isExtendedEnabled(diffType) && fg('platform_editor_ai_show_diff_patch_1')) {
|
|
241
|
+
rowDOM.style.setProperty('anchor-name', `--${buildAnchorDecorationKey({
|
|
242
|
+
diffId
|
|
243
|
+
})}`);
|
|
244
|
+
|
|
245
|
+
// A table's content can extend past the doc margin, so the bar also needs a left anchor
|
|
246
|
+
// measured against the table itself or it is clipped once the table is resized.
|
|
247
|
+
const leftAnchor = createLeftAnchorWidget({
|
|
248
|
+
doc: newDoc,
|
|
249
|
+
from: safeInsertPos,
|
|
250
|
+
diffId
|
|
251
|
+
});
|
|
252
|
+
if (leftAnchor) {
|
|
253
|
+
decorations.push(leftAnchor);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
decorations.push(Decoration.widget(safeInsertPos, rowDOM, {
|
|
213
257
|
...buildDiffDecorationSpec({
|
|
214
258
|
colorScheme,
|
|
215
259
|
decorationType: 'widget',
|
|
@@ -218,6 +262,7 @@ export const createChangedRowDecorationWidgets = ({
|
|
|
218
262
|
isInserted,
|
|
219
263
|
diffType
|
|
220
264
|
})
|
|
221
|
-
});
|
|
265
|
+
}));
|
|
266
|
+
return decorations;
|
|
222
267
|
});
|
|
223
268
|
};
|
|
@@ -3,7 +3,7 @@ import { Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
|
3
3
|
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
|
|
4
4
|
import { CONTRIBUTOR_TAG_Z_INDEX } from '../../ui/ContributorTag/buildContributorTagDom';
|
|
5
5
|
import { isExtendedEnabled } from '../isExtendedEnabled';
|
|
6
|
-
import {
|
|
6
|
+
import { isEmptyParagraphSlice } from '../utils/isEmptyParagraphSlice';
|
|
7
7
|
import { buildAtomicInlineChangedCSSVariables, buildDeletedInlineContentStyleExtended, buildDeletedInlineStyle, buildDeletedInlineStyleStandard, buildInsertStyle, buildInsertStyleActive, buildInsertStyleExtended, buildInsertStyleExtendedActive, buildInsertStyleExtendedNoUnderline, buildInsertStyleExtendedNoUnderlineActive } from './colorSchemes/factory';
|
|
8
8
|
import { colorSchemeRegistry, getLegacyColorScheme } from './colorSchemes/schemes';
|
|
9
9
|
import { createInlineIndicatorAnchorWidgets } from './createAnchorDecorationWidgets';
|
|
@@ -138,11 +138,9 @@ export const createInlineChangedDecoration = ({
|
|
|
138
138
|
// tag host's key, remounting every tag mid-step. Random ids are kept when tags are off.
|
|
139
139
|
const diffId = showContributorTags ? `inline-${change.fromB}-${change.toB}` : crypto.randomUUID();
|
|
140
140
|
|
|
141
|
-
//
|
|
142
|
-
//
|
|
143
|
-
|
|
144
|
-
// a host that is never emitted (EDITOR-8855).
|
|
145
|
-
const canTagChange = showContributorTags && !!doc && isExtendedEnabled(diffType) && isContributorTagWidgetEnabled() && hasVisibleContent(doc.slice(change.fromB, change.toB).content);
|
|
141
|
+
// Match the rendered shape: whitespace text is eligible, while an empty paragraph is structural
|
|
142
|
+
// content with no tag host.
|
|
143
|
+
const canTagChange = showContributorTags && !!doc && isExtendedEnabled(diffType) && isContributorTagWidgetEnabled() && !isEmptyParagraphSlice(doc.slice(change.fromB, change.toB));
|
|
146
144
|
if (shouldHideDeleted) {
|
|
147
145
|
return [Decoration.inline(change.fromB, change.toB, {
|
|
148
146
|
style: displayNoneStyle
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
2
2
|
import { fg } from '@atlaskit/platform-feature-flags/fg';
|
|
3
3
|
import { isExtendedEnabled } from '../isExtendedEnabled';
|
|
4
|
-
import {
|
|
4
|
+
import { isEmptyParagraphSlice } from '../utils/isEmptyParagraphSlice';
|
|
5
5
|
import { createLeftAnchorWidget } from './createAnchorDecorationWidgets';
|
|
6
6
|
import { createChangedRowDecorationWidgets } from './createChangedRowDecorationWidgets';
|
|
7
7
|
import { createContributorTagHost, unmountContributorTag } from './createContributorTagWidget';
|
|
@@ -114,9 +114,9 @@ export const createNodeChangedDecorationWidget = ({
|
|
|
114
114
|
reveal,
|
|
115
115
|
tagMountContext
|
|
116
116
|
}) => {
|
|
117
|
-
var
|
|
117
|
+
var _$safeInsertPos$nodeB, _slice$content$firstC, _newDoc$firstChild, _slice$content$firstC2;
|
|
118
118
|
const slice = doc.slice(change.fromA, change.toA);
|
|
119
|
-
const shouldSkipDeletedEmptyParagraphDecoration = !isInserted && (slice
|
|
119
|
+
const shouldSkipDeletedEmptyParagraphDecoration = !isInserted && isEmptyParagraphSlice(slice);
|
|
120
120
|
// Widget decoration used for deletions as the content is not in the document
|
|
121
121
|
// and we want to display the deleted content with a style.
|
|
122
122
|
// For `placeBelow`, anchor at the END of the new content (change.toB) so the deleted
|
|
@@ -156,7 +156,10 @@ export const createNodeChangedDecorationWidget = ({
|
|
|
156
156
|
nodeViewSerializer,
|
|
157
157
|
colorScheme,
|
|
158
158
|
isInserted,
|
|
159
|
-
diffType
|
|
159
|
+
diffType,
|
|
160
|
+
// Needed for the row's own indicator anchor; this path returns before the
|
|
161
|
+
// `anchor-name` assignment further down.
|
|
162
|
+
showIndicators
|
|
160
163
|
});
|
|
161
164
|
}
|
|
162
165
|
const serializer = nodeViewSerializer;
|
|
@@ -207,10 +210,9 @@ export const createNodeChangedDecorationWidget = ({
|
|
|
207
210
|
// Derived from the deleted range so it survives a recalculation — see the same reasoning in
|
|
208
211
|
// `createInlineChangedDecoration`.
|
|
209
212
|
const diffId = showContributorTags ? `widget-${change.fromA}-${change.toA}` : crypto.randomUUID();
|
|
210
|
-
//
|
|
211
|
-
//
|
|
212
|
-
|
|
213
|
-
const canTagWidget = showContributorTags && hasVisibleContent(slice.content);
|
|
213
|
+
// Match the rendering predicate above: an empty paragraph has no widget to tag, while whitespace
|
|
214
|
+
// text in a rendered widget remains eligible.
|
|
215
|
+
const canTagWidget = showContributorTags && !shouldSkipDeletedEmptyParagraphDecoration;
|
|
214
216
|
const decorations = [];
|
|
215
217
|
const replacementNode = newDoc.nodeAt(change.fromB);
|
|
216
218
|
const firstReplacedNode = slice.content.firstChild;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Whether a slice contains exactly one structurally empty paragraph. */
|
|
2
|
+
export const isEmptyParagraphSlice = slice => {
|
|
3
|
+
var _slice$content$firstC;
|
|
4
|
+
return (slice === null || slice === void 0 ? void 0 : slice.content.childCount) === 1 && ((_slice$content$firstC = slice.content.firstChild) === null || _slice$content$firstC === void 0 ? void 0 : _slice$content$firstC.type.name) === 'paragraph' && slice.content.firstChild.content.size === 0;
|
|
5
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* IndicatorBarContentComponent.tsx generated by @compiled/babel-plugin v3.0.
|
|
1
|
+
/* IndicatorBarContentComponent.tsx generated by @compiled/babel-plugin v3.0.1 */
|
|
2
2
|
import { ax, ix } from "@compiled/react/runtime";
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
|
|
@@ -19,15 +19,40 @@ import { PARTICIPANT_COLOR_SCHEMES } from './types';
|
|
|
19
19
|
|
|
20
20
|
/** Maps the shared 18-slot telepointer palette onto the ten bolder diff colours. */
|
|
21
21
|
var HASHED_PARTICIPANT_COLOR_SCHEMES = [].concat(_toConsumableArray(PARTICIPANT_COLOR_SCHEMES), ['blue', 'red', 'orange', 'yellow', 'green', 'teal', 'purple', 'magenta']);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Red means "deleted" in both public schemes, so it never identifies an actor. Reserving it here
|
|
25
|
+
* covers every path into an attribution colour; `createAttributionColorMap` is the only caller, and
|
|
26
|
+
* it is gated on `confluence_ncs_step_diffing_version_history` plus
|
|
27
|
+
* `platform_editor_show_diff_color_scheme_refactor`.
|
|
28
|
+
*/
|
|
29
|
+
var RESERVED_ATTRIBUTION_COLORS = new Set(['red']);
|
|
30
|
+
var isAssignable = function isAssignable(color) {
|
|
31
|
+
return !RESERVED_ATTRIBUTION_COLORS.has(color);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/** Projects a telepointer slot onto its diff hue, advancing past a hue reserved for deletion. */
|
|
35
|
+
var getSlotColor = function getSlotColor(index) {
|
|
36
|
+
for (var offset = 0; offset < HASHED_PARTICIPANT_COLOR_SCHEMES.length; offset++) {
|
|
37
|
+
var color = HASHED_PARTICIPANT_COLOR_SCHEMES[(index + offset) % HASHED_PARTICIPANT_COLOR_SCHEMES.length];
|
|
38
|
+
if (color && isAssignable(color)) {
|
|
39
|
+
return color;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
};
|
|
22
44
|
var getAvailableColor = function getAvailableColor(hashedColor, allocatedColors) {
|
|
45
|
+
var _PARTICIPANT_COLOR_SC;
|
|
23
46
|
var startIndex = PARTICIPANT_COLOR_SCHEMES.indexOf(hashedColor);
|
|
24
47
|
for (var offset = 0; offset < PARTICIPANT_COLOR_SCHEMES.length; offset++) {
|
|
25
48
|
var color = PARTICIPANT_COLOR_SCHEMES[(startIndex + offset) % PARTICIPANT_COLOR_SCHEMES.length];
|
|
26
|
-
if (color && !allocatedColors.has(color)) {
|
|
49
|
+
if (color && isAssignable(color) && !allocatedColors.has(color)) {
|
|
27
50
|
return color;
|
|
28
51
|
}
|
|
29
52
|
}
|
|
30
|
-
|
|
53
|
+
|
|
54
|
+
// Every assignable hue is taken, so a duplicate is unavoidable — but never the reserved hue.
|
|
55
|
+
return isAssignable(hashedColor) ? hashedColor : (_PARTICIPANT_COLOR_SC = PARTICIPANT_COLOR_SCHEMES.find(isAssignable)) !== null && _PARTICIPANT_COLOR_SC !== void 0 ? _PARTICIPANT_COLOR_SC : hashedColor;
|
|
31
56
|
};
|
|
32
57
|
|
|
33
58
|
/**
|
|
@@ -127,7 +152,8 @@ export var createAttributionColorMap = function createAttributionColorMap(stepAt
|
|
|
127
152
|
var colors = new Map();
|
|
128
153
|
var allocatedColors = new Set();
|
|
129
154
|
|
|
130
|
-
// Reserve shared brand colours before hashing other actors, regardless of step order.
|
|
155
|
+
// Reserve shared brand colours before hashing other actors, regardless of step order. A brand
|
|
156
|
+
// slot is pinned deliberately, so it is taken verbatim rather than through `getSlotColor`.
|
|
131
157
|
var _iterator2 = _createForOfIteratorHelper(stepAttributions),
|
|
132
158
|
_step2;
|
|
133
159
|
try {
|
|
@@ -162,7 +188,7 @@ export var createAttributionColorMap = function createAttributionColorMap(stepAt
|
|
|
162
188
|
}
|
|
163
189
|
var _getParticipantColor2 = getParticipantColor(_identity.colorSeed, _attribution === null || _attribution === void 0 ? void 0 : _attribution.agentType),
|
|
164
190
|
_index = _getParticipantColor2.index;
|
|
165
|
-
var hashedColor =
|
|
191
|
+
var hashedColor = getSlotColor(_index);
|
|
166
192
|
if (!hashedColor) {
|
|
167
193
|
continue;
|
|
168
194
|
}
|
|
@@ -10,12 +10,14 @@ 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
12
|
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
|
|
13
|
+
import { fg } from '@atlaskit/platform-feature-flags/fg';
|
|
13
14
|
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
14
15
|
import { isExtendedEnabled } from '../isExtendedEnabled';
|
|
15
16
|
import { buildAddedCellOverlayRoundedStyle, buildAddedCellOverlayStyle, buildDeletedCellOverlayRoundedStyle, buildDeletedCellOverlayStyle, buildDeletedRowStyle } from './colorSchemes/factory';
|
|
16
17
|
import { colorSchemeRegistry, getLegacyColorScheme } from './colorSchemes/schemes';
|
|
18
|
+
import { createLeftAnchorWidget } from './createAnchorDecorationWidgets';
|
|
17
19
|
import { resolveCellOverlayStyleLegacy, resolveDeletedRowStyleLegacy } from './createChangedRowDecorationWidgets.styles.legacy';
|
|
18
|
-
import { buildDiffDecorationSpec } from './decorationKeys';
|
|
20
|
+
import { buildAnchorDecorationKey, buildDiffDecorationSpec } from './decorationKeys';
|
|
19
21
|
import { findSafeInsertPos } from './utils/findSafeInsertPos';
|
|
20
22
|
import { applyCellEdgeAttrs, getRowCellEdgeAttrs, getTableTopAndBottomCellEdgeAttrs } from './utils/tableCellEdgeAttrs';
|
|
21
23
|
/**
|
|
@@ -47,8 +49,14 @@ var extractChangedRows = function extractChangedRows(_ref) {
|
|
|
47
49
|
return changedRows;
|
|
48
50
|
}
|
|
49
51
|
var newTableMap = TableMap.get(tableNew.node);
|
|
52
|
+
// A row DELETION makes the table shorter. An in-place whole-row REPLACEMENT (`replaceNode` on a
|
|
53
|
+
// `tableRow`, which AI suggested edits emits) leaves the row count untouched — and this helper
|
|
54
|
+
// was written for deletions only, so it used to discard every replacement and the changed row's
|
|
55
|
+
// content was never rendered anywhere. The reviewer was left with just the removed side.
|
|
56
|
+
var isRowDeletion = oldTableMap.height > newTableMap.height;
|
|
57
|
+
var handleRowReplacement = oldTableMap.height === newTableMap.height && fg('platform_editor_ai_show_diff_patch_1');
|
|
50
58
|
// If no rows were changed, return empty
|
|
51
|
-
if (
|
|
59
|
+
if (!(isRowDeletion || handleRowReplacement) ||
|
|
52
60
|
// For now ignore if there are column deletions as well
|
|
53
61
|
oldTableMap.width !== newTableMap.width) {
|
|
54
62
|
return changedRows;
|
|
@@ -92,6 +100,15 @@ var extractChangedRows = function extractChangedRows(_ref) {
|
|
|
92
100
|
|
|
93
101
|
// Filter changes that never truly got deleted
|
|
94
102
|
return changedRows.filter(function (changedRow) {
|
|
103
|
+
// A replacement leaves every sibling row in place, so asking "does this row still exist
|
|
104
|
+
// ANYWHERE in the new table?" can drop a genuinely rewritten row that happens to match a
|
|
105
|
+
// sibling. Compare it against the row at the same index instead. Deletions must keep the
|
|
106
|
+
// whole-table `some()`: their indices shift, so an index comparison would let every
|
|
107
|
+
// surviving row through and draw a widget for each one.
|
|
108
|
+
if (handleRowReplacement) {
|
|
109
|
+
var counterpart = tableNew.node.maybeChild(changedRow.rowIndex);
|
|
110
|
+
return !counterpart || !areNodesEqualIgnoreAttrs(counterpart, changedRow.rowNode);
|
|
111
|
+
}
|
|
95
112
|
return !tableNew.node.children.some(function (newRow) {
|
|
96
113
|
return areNodesEqualIgnoreAttrs(newRow, changedRow.rowNode);
|
|
97
114
|
});
|
|
@@ -135,7 +152,10 @@ var createChangedRowDOM = function createChangedRowDOM(rowNode, cellEdgeAttrs, n
|
|
|
135
152
|
if (!isExtendedEnabled(diffType) || !isInserted) {
|
|
136
153
|
tr.setAttribute('style', isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? buildDeletedRowStyle(colors) : resolveDeletedRowStyleLegacy(getLegacyColorScheme(colorScheme)));
|
|
137
154
|
}
|
|
138
|
-
|
|
155
|
+
// Mirrors the strikethrough condition above: under the extended experience an `isInserted` row
|
|
156
|
+
// is ADDED content, so it must not claim the "deleted" testid — page models match that as
|
|
157
|
+
// removed content (same reasoning as `createTableCellContentWidgets`).
|
|
158
|
+
tr.setAttribute('data-testid', isExtendedEnabled(diffType) && isInserted && fg('platform_editor_ai_show_diff_patch_1') ? 'show-diff-changed-row' : 'show-diff-deleted-row');
|
|
139
159
|
|
|
140
160
|
// Serialize each cell in the row
|
|
141
161
|
var cellIndex = 0;
|
|
@@ -215,7 +235,9 @@ export var createChangedRowDecorationWidgets = function createChangedRowDecorati
|
|
|
215
235
|
colorScheme = _ref3.colorScheme,
|
|
216
236
|
_ref3$isInserted = _ref3.isInserted,
|
|
217
237
|
isInserted = _ref3$isInserted === void 0 ? false : _ref3$isInserted,
|
|
218
|
-
diffType = _ref3.diffType
|
|
238
|
+
diffType = _ref3.diffType,
|
|
239
|
+
_ref3$showIndicators = _ref3.showIndicators,
|
|
240
|
+
showIndicators = _ref3$showIndicators === void 0 ? false : _ref3$showIndicators;
|
|
219
241
|
// First, expand the changes to include complete deleted rows
|
|
220
242
|
var changedRows = expandDiffForChangedRows({
|
|
221
243
|
changes: changes.filter(function (change) {
|
|
@@ -225,7 +247,7 @@ export var createChangedRowDecorationWidgets = function createChangedRowDecorati
|
|
|
225
247
|
newDoc: newDoc,
|
|
226
248
|
diffType: diffType
|
|
227
249
|
});
|
|
228
|
-
return changedRows.
|
|
250
|
+
return changedRows.flatMap(function (changedRow) {
|
|
229
251
|
var rowDOM = createChangedRowDOM(changedRow.rowNode, changedRow.cellEdgeAttrs, nodeViewSerializer, colorScheme, isInserted, diffType);
|
|
230
252
|
|
|
231
253
|
// Find safe insertion position for the deleted row
|
|
@@ -233,13 +255,37 @@ export var createChangedRowDecorationWidgets = function createChangedRowDecorati
|
|
|
233
255
|
// -1 to find the first safe position from the table
|
|
234
256
|
originalDoc.slice(changedRow.fromA, changedRow.toA));
|
|
235
257
|
var diffId = crypto.randomUUID();
|
|
236
|
-
|
|
258
|
+
var decorations = [];
|
|
259
|
+
|
|
260
|
+
// `IndicatorBarContentComponent` renders a bar for every widget descriptor and anchors its
|
|
261
|
+
// top and bottom to `anchor-<diffId>`. Without an element carrying that anchor name the bar
|
|
262
|
+
// is still created but can never resolve a position, so it silently does not render and the
|
|
263
|
+
// bar covers only the row being changed. `createNodeChangedDecorationWidget` sets the same
|
|
264
|
+
// property on its own widget DOM for non-table content; this path returns before reaching it.
|
|
265
|
+
if (showIndicators && isExtendedEnabled(diffType) && fg('platform_editor_ai_show_diff_patch_1')) {
|
|
266
|
+
rowDOM.style.setProperty('anchor-name', "--".concat(buildAnchorDecorationKey({
|
|
267
|
+
diffId: diffId
|
|
268
|
+
})));
|
|
269
|
+
|
|
270
|
+
// A table's content can extend past the doc margin, so the bar also needs a left anchor
|
|
271
|
+
// measured against the table itself or it is clipped once the table is resized.
|
|
272
|
+
var leftAnchor = createLeftAnchorWidget({
|
|
273
|
+
doc: newDoc,
|
|
274
|
+
from: safeInsertPos,
|
|
275
|
+
diffId: diffId
|
|
276
|
+
});
|
|
277
|
+
if (leftAnchor) {
|
|
278
|
+
decorations.push(leftAnchor);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
decorations.push(Decoration.widget(safeInsertPos, rowDOM, _objectSpread({}, buildDiffDecorationSpec({
|
|
237
282
|
colorScheme: colorScheme,
|
|
238
283
|
decorationType: 'widget',
|
|
239
284
|
diffId: diffId,
|
|
240
285
|
isActive: false,
|
|
241
286
|
isInserted: isInserted,
|
|
242
287
|
diffType: diffType
|
|
243
|
-
})));
|
|
288
|
+
}))));
|
|
289
|
+
return decorations;
|
|
244
290
|
});
|
|
245
291
|
};
|
|
@@ -7,7 +7,7 @@ import { Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
|
7
7
|
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
|
|
8
8
|
import { CONTRIBUTOR_TAG_Z_INDEX } from '../../ui/ContributorTag/buildContributorTagDom';
|
|
9
9
|
import { isExtendedEnabled } from '../isExtendedEnabled';
|
|
10
|
-
import {
|
|
10
|
+
import { isEmptyParagraphSlice } from '../utils/isEmptyParagraphSlice';
|
|
11
11
|
import { buildAtomicInlineChangedCSSVariables, buildDeletedInlineContentStyleExtended, buildDeletedInlineStyle, buildDeletedInlineStyleStandard, buildInsertStyle, buildInsertStyleActive, buildInsertStyleExtended, buildInsertStyleExtendedActive, buildInsertStyleExtendedNoUnderline, buildInsertStyleExtendedNoUnderlineActive } from './colorSchemes/factory';
|
|
12
12
|
import { colorSchemeRegistry, getLegacyColorScheme } from './colorSchemes/schemes';
|
|
13
13
|
import { createInlineIndicatorAnchorWidgets } from './createAnchorDecorationWidgets';
|
|
@@ -156,11 +156,9 @@ export var createInlineChangedDecoration = function createInlineChangedDecoratio
|
|
|
156
156
|
// tag host's key, remounting every tag mid-step. Random ids are kept when tags are off.
|
|
157
157
|
var diffId = showContributorTags ? "inline-".concat(change.fromB, "-").concat(change.toB) : crypto.randomUUID();
|
|
158
158
|
|
|
159
|
-
//
|
|
160
|
-
//
|
|
161
|
-
|
|
162
|
-
// a host that is never emitted (EDITOR-8855).
|
|
163
|
-
var canTagChange = showContributorTags && !!doc && isExtendedEnabled(diffType) && isContributorTagWidgetEnabled() && hasVisibleContent(doc.slice(change.fromB, change.toB).content);
|
|
159
|
+
// Match the rendered shape: whitespace text is eligible, while an empty paragraph is structural
|
|
160
|
+
// content with no tag host.
|
|
161
|
+
var canTagChange = showContributorTags && !!doc && isExtendedEnabled(diffType) && isContributorTagWidgetEnabled() && !isEmptyParagraphSlice(doc.slice(change.fromB, change.toB));
|
|
164
162
|
if (shouldHideDeleted) {
|
|
165
163
|
return [Decoration.inline(change.fromB, change.toB, {
|
|
166
164
|
style: displayNoneStyle
|
|
@@ -4,7 +4,7 @@ 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 {
|
|
7
|
+
import { isEmptyParagraphSlice } from '../utils/isEmptyParagraphSlice';
|
|
8
8
|
import { createLeftAnchorWidget } from './createAnchorDecorationWidgets';
|
|
9
9
|
import { createChangedRowDecorationWidgets } from './createChangedRowDecorationWidgets';
|
|
10
10
|
import { createContributorTagHost, unmountContributorTag } from './createContributorTagWidget';
|
|
@@ -94,7 +94,7 @@ var createTableCellContentWidgets = function createTableCellContentWidgets(_ref)
|
|
|
94
94
|
* that is not in the current document.
|
|
95
95
|
*/
|
|
96
96
|
export var createNodeChangedDecorationWidget = function createNodeChangedDecorationWidget(_ref2) {
|
|
97
|
-
var
|
|
97
|
+
var _$safeInsertPos$nodeB, _slice$content$firstC, _newDoc$firstChild, _slice$content$firstC2;
|
|
98
98
|
var attributionKey = _ref2.attributionKey,
|
|
99
99
|
change = _ref2.change,
|
|
100
100
|
doc = _ref2.doc,
|
|
@@ -117,7 +117,7 @@ export var createNodeChangedDecorationWidget = function createNodeChangedDecorat
|
|
|
117
117
|
reveal = _ref2.reveal,
|
|
118
118
|
tagMountContext = _ref2.tagMountContext;
|
|
119
119
|
var slice = doc.slice(change.fromA, change.toA);
|
|
120
|
-
var shouldSkipDeletedEmptyParagraphDecoration = !isInserted && (slice
|
|
120
|
+
var shouldSkipDeletedEmptyParagraphDecoration = !isInserted && isEmptyParagraphSlice(slice);
|
|
121
121
|
// Widget decoration used for deletions as the content is not in the document
|
|
122
122
|
// and we want to display the deleted content with a style.
|
|
123
123
|
// For `placeBelow`, anchor at the END of the new content (change.toB) so the deleted
|
|
@@ -165,7 +165,10 @@ export var createNodeChangedDecorationWidget = function createNodeChangedDecorat
|
|
|
165
165
|
nodeViewSerializer: nodeViewSerializer,
|
|
166
166
|
colorScheme: colorScheme,
|
|
167
167
|
isInserted: isInserted,
|
|
168
|
-
diffType: diffType
|
|
168
|
+
diffType: diffType,
|
|
169
|
+
// Needed for the row's own indicator anchor; this path returns before the
|
|
170
|
+
// `anchor-name` assignment further down.
|
|
171
|
+
showIndicators: showIndicators
|
|
169
172
|
});
|
|
170
173
|
}
|
|
171
174
|
var serializer = nodeViewSerializer;
|
|
@@ -216,10 +219,9 @@ export var createNodeChangedDecorationWidget = function createNodeChangedDecorat
|
|
|
216
219
|
// Derived from the deleted range so it survives a recalculation — see the same reasoning in
|
|
217
220
|
// `createInlineChangedDecoration`.
|
|
218
221
|
var diffId = showContributorTags ? "widget-".concat(change.fromA, "-").concat(change.toA) : crypto.randomUUID();
|
|
219
|
-
//
|
|
220
|
-
//
|
|
221
|
-
|
|
222
|
-
var canTagWidget = showContributorTags && hasVisibleContent(slice.content);
|
|
222
|
+
// Match the rendering predicate above: an empty paragraph has no widget to tag, while whitespace
|
|
223
|
+
// text in a rendered widget remains eligible.
|
|
224
|
+
var canTagWidget = showContributorTags && !shouldSkipDeletedEmptyParagraphDecoration;
|
|
223
225
|
var decorations = [];
|
|
224
226
|
var replacementNode = newDoc.nodeAt(change.fromB);
|
|
225
227
|
var firstReplacedNode = slice.content.firstChild;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Whether a slice contains exactly one structurally empty paragraph. */
|
|
2
|
+
export var isEmptyParagraphSlice = function isEmptyParagraphSlice(slice) {
|
|
3
|
+
var _slice$content$firstC;
|
|
4
|
+
return (slice === null || slice === void 0 ? void 0 : slice.content.childCount) === 1 && ((_slice$content$firstC = slice.content.firstChild) === null || _slice$content$firstC === void 0 ? void 0 : _slice$content$firstC.type.name) === 'paragraph' && slice.content.firstChild.content.size === 0;
|
|
5
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* IndicatorBarContentComponent.tsx generated by @compiled/babel-plugin v3.0.
|
|
1
|
+
/* IndicatorBarContentComponent.tsx generated by @compiled/babel-plugin v3.0.1 */
|
|
2
2
|
import { ax, ix } from "@compiled/react/runtime";
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
|
|
@@ -8,7 +8,7 @@ type SimpleChange = Pick<Change, 'fromA' | 'toA' | 'fromB' | 'deleted'>;
|
|
|
8
8
|
/**
|
|
9
9
|
* Main function to handle deleted rows - computes diff and creates decorations
|
|
10
10
|
*/
|
|
11
|
-
export declare const createChangedRowDecorationWidgets: ({ changes, originalDoc, newDoc, nodeViewSerializer, colorScheme, isInserted, diffType, }: {
|
|
11
|
+
export declare const createChangedRowDecorationWidgets: ({ changes, originalDoc, newDoc, nodeViewSerializer, colorScheme, isInserted, diffType, showIndicators, }: {
|
|
12
12
|
changes: SimpleChange[];
|
|
13
13
|
colorScheme?: ColorScheme;
|
|
14
14
|
diffType?: DiffType;
|
|
@@ -16,5 +16,6 @@ export declare const createChangedRowDecorationWidgets: ({ changes, originalDoc,
|
|
|
16
16
|
newDoc: PMNode;
|
|
17
17
|
nodeViewSerializer: NodeViewSerializer;
|
|
18
18
|
originalDoc: PMNode;
|
|
19
|
+
showIndicators?: boolean;
|
|
19
20
|
}) => Decoration[];
|
|
20
21
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-show-diff",
|
|
3
|
-
"version": "16.0.
|
|
3
|
+
"version": "16.0.14",
|
|
4
4
|
"description": "ShowDiff plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"react-intl": "^7.0.0"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
|
-
"@atlaskit/editor-common": "^122.
|
|
67
|
+
"@atlaskit/editor-common": "^122.8.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"
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
Object.defineProperty(exports, "__esModule", {
|
|
5
|
-
value: true
|
|
6
|
-
});
|
|
7
|
-
exports.hasVisibleContent = void 0;
|
|
8
|
-
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
9
|
-
var _charsByOffset = require("./charsByOffset");
|
|
10
|
-
/**
|
|
11
|
-
* Whether `fragment` holds anything a reader can see.
|
|
12
|
-
*
|
|
13
|
-
* Text counts once it carries a single non-whitespace character; a leaf node (mention, emoji, date,
|
|
14
|
-
* media, rule, hardBreak, …) counts in its own right, exactly as `resolveTagAnchorPos` treats one.
|
|
15
|
-
* Everything else is descended into, so a paragraph is visible when its content is.
|
|
16
|
-
*
|
|
17
|
-
* A change whose content is nothing but whitespace — a space typed between two words, a run of
|
|
18
|
-
* trailing spaces, an added blank paragraph — has no visible content for a contributor tag to
|
|
19
|
-
* caption, so it carries no tag (EDITOR-8855).
|
|
20
|
-
*/
|
|
21
|
-
var _hasVisibleContent = exports.hasVisibleContent = function hasVisibleContent(fragment) {
|
|
22
|
-
var visible = false;
|
|
23
|
-
fragment.forEach(function (node) {
|
|
24
|
-
if (visible) {
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
if (node.isText) {
|
|
28
|
-
var _node$text;
|
|
29
|
-
visible = (0, _toConsumableArray2.default)((_node$text = node.text) !== null && _node$text !== void 0 ? _node$text : '').some(function (char) {
|
|
30
|
-
return !(0, _charsByOffset.isWhitespaceChar)(char);
|
|
31
|
-
});
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
visible = node.isLeaf || _hasVisibleContent(node.content);
|
|
35
|
-
});
|
|
36
|
-
return visible;
|
|
37
|
-
};
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { isWhitespaceChar } from './charsByOffset';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Whether `fragment` holds anything a reader can see.
|
|
5
|
-
*
|
|
6
|
-
* Text counts once it carries a single non-whitespace character; a leaf node (mention, emoji, date,
|
|
7
|
-
* media, rule, hardBreak, …) counts in its own right, exactly as `resolveTagAnchorPos` treats one.
|
|
8
|
-
* Everything else is descended into, so a paragraph is visible when its content is.
|
|
9
|
-
*
|
|
10
|
-
* A change whose content is nothing but whitespace — a space typed between two words, a run of
|
|
11
|
-
* trailing spaces, an added blank paragraph — has no visible content for a contributor tag to
|
|
12
|
-
* caption, so it carries no tag (EDITOR-8855).
|
|
13
|
-
*/
|
|
14
|
-
export const hasVisibleContent = fragment => {
|
|
15
|
-
let visible = false;
|
|
16
|
-
fragment.forEach(node => {
|
|
17
|
-
if (visible) {
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
if (node.isText) {
|
|
21
|
-
var _node$text;
|
|
22
|
-
visible = [...((_node$text = node.text) !== null && _node$text !== void 0 ? _node$text : '')].some(char => !isWhitespaceChar(char));
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
visible = node.isLeaf || hasVisibleContent(node.content);
|
|
26
|
-
});
|
|
27
|
-
return visible;
|
|
28
|
-
};
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
2
|
-
import { isWhitespaceChar } from './charsByOffset';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Whether `fragment` holds anything a reader can see.
|
|
6
|
-
*
|
|
7
|
-
* Text counts once it carries a single non-whitespace character; a leaf node (mention, emoji, date,
|
|
8
|
-
* media, rule, hardBreak, …) counts in its own right, exactly as `resolveTagAnchorPos` treats one.
|
|
9
|
-
* Everything else is descended into, so a paragraph is visible when its content is.
|
|
10
|
-
*
|
|
11
|
-
* A change whose content is nothing but whitespace — a space typed between two words, a run of
|
|
12
|
-
* trailing spaces, an added blank paragraph — has no visible content for a contributor tag to
|
|
13
|
-
* caption, so it carries no tag (EDITOR-8855).
|
|
14
|
-
*/
|
|
15
|
-
var _hasVisibleContent = function hasVisibleContent(fragment) {
|
|
16
|
-
var visible = false;
|
|
17
|
-
fragment.forEach(function (node) {
|
|
18
|
-
if (visible) {
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
if (node.isText) {
|
|
22
|
-
var _node$text;
|
|
23
|
-
visible = _toConsumableArray((_node$text = node.text) !== null && _node$text !== void 0 ? _node$text : '').some(function (char) {
|
|
24
|
-
return !isWhitespaceChar(char);
|
|
25
|
-
});
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
visible = node.isLeaf || _hasVisibleContent(node.content);
|
|
29
|
-
});
|
|
30
|
-
return visible;
|
|
31
|
-
};
|
|
32
|
-
export { _hasVisibleContent as hasVisibleContent };
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
2
|
-
/**
|
|
3
|
-
* Whether `fragment` holds anything a reader can see.
|
|
4
|
-
*
|
|
5
|
-
* Text counts once it carries a single non-whitespace character; a leaf node (mention, emoji, date,
|
|
6
|
-
* media, rule, hardBreak, …) counts in its own right, exactly as `resolveTagAnchorPos` treats one.
|
|
7
|
-
* Everything else is descended into, so a paragraph is visible when its content is.
|
|
8
|
-
*
|
|
9
|
-
* A change whose content is nothing but whitespace — a space typed between two words, a run of
|
|
10
|
-
* trailing spaces, an added blank paragraph — has no visible content for a contributor tag to
|
|
11
|
-
* caption, so it carries no tag (EDITOR-8855).
|
|
12
|
-
*/
|
|
13
|
-
export declare const hasVisibleContent: (fragment: Fragment) => boolean;
|