@atlaskit/editor-plugin-show-diff 14.5.1 → 15.0.0
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 +34 -6
- package/dist/cjs/pm-plugins/calculateDiff/calculateDiffDecorations.js +3 -9
- package/dist/cjs/pm-plugins/calculateDiff/smart/classifySmartChanges.js +1 -2
- package/dist/cjs/pm-plugins/decorations/colorSchemes/attributions.js +21 -4
- package/dist/cjs/pm-plugins/decorations/colorSchemes/factory.js +6 -56
- package/dist/cjs/pm-plugins/decorations/colorSchemes/schemes.js +6 -20
- package/dist/cjs/pm-plugins/decorations/colorSchemes/types.js +4 -6
- package/dist/cjs/pm-plugins/decorations/createChangedRowDecorationWidgets.js +1 -2
- package/dist/cjs/pm-plugins/decorations/createContributorTagWidget.js +14 -29
- package/dist/cjs/pm-plugins/decorations/createInlineChangedDecoration.js +1 -2
- package/dist/cjs/pm-plugins/decorations/utils/getAttrChangeRanges.js +2 -25
- package/dist/cjs/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.js +1 -2
- package/dist/cjs/pm-plugins/main.js +4 -4
- package/dist/cjs/showDiffPlugin.js +4 -5
- package/dist/cjs/ui/ContributorTag/buildContributorTagDom.js +122 -0
- package/dist/cjs/ui/ContributorTag/contributorAvatarRenderer.js +140 -0
- package/dist/cjs/ui/ContributorTag/contributorTagController.js +500 -0
- package/dist/cjs/ui/ContributorTag/contributorTagIcons.js +46 -0
- package/dist/es2019/pm-plugins/calculateDiff/calculateDiffDecorations.js +3 -5
- package/dist/es2019/pm-plugins/calculateDiff/smart/classifySmartChanges.js +1 -2
- package/dist/es2019/pm-plugins/decorations/colorSchemes/attributions.js +20 -3
- package/dist/es2019/pm-plugins/decorations/colorSchemes/factory.js +6 -55
- package/dist/es2019/pm-plugins/decorations/colorSchemes/schemes.js +14 -26
- package/dist/es2019/pm-plugins/decorations/colorSchemes/types.js +4 -6
- package/dist/es2019/pm-plugins/decorations/createChangedRowDecorationWidgets.js +1 -2
- package/dist/es2019/pm-plugins/decorations/createContributorTagWidget.js +16 -30
- package/dist/es2019/pm-plugins/decorations/createInlineChangedDecoration.js +1 -2
- package/dist/es2019/pm-plugins/decorations/utils/getAttrChangeRanges.js +2 -17
- package/dist/es2019/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.js +1 -2
- package/dist/es2019/pm-plugins/main.js +4 -4
- package/dist/es2019/showDiffPlugin.js +4 -5
- package/dist/es2019/ui/ContributorTag/buildContributorTagDom.js +110 -0
- package/dist/es2019/ui/ContributorTag/contributorAvatarRenderer.js +136 -0
- package/dist/es2019/ui/ContributorTag/contributorTagController.js +403 -0
- package/dist/es2019/ui/ContributorTag/contributorTagIcons.js +40 -0
- package/dist/esm/pm-plugins/calculateDiff/calculateDiffDecorations.js +3 -9
- package/dist/esm/pm-plugins/calculateDiff/smart/classifySmartChanges.js +1 -2
- package/dist/esm/pm-plugins/decorations/colorSchemes/attributions.js +21 -4
- package/dist/esm/pm-plugins/decorations/colorSchemes/factory.js +6 -57
- package/dist/esm/pm-plugins/decorations/colorSchemes/schemes.js +7 -20
- package/dist/esm/pm-plugins/decorations/colorSchemes/types.js +4 -6
- package/dist/esm/pm-plugins/decorations/createChangedRowDecorationWidgets.js +1 -2
- package/dist/esm/pm-plugins/decorations/createContributorTagWidget.js +15 -30
- package/dist/esm/pm-plugins/decorations/createInlineChangedDecoration.js +1 -2
- package/dist/esm/pm-plugins/decorations/utils/getAttrChangeRanges.js +2 -25
- package/dist/esm/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.js +1 -2
- package/dist/esm/pm-plugins/main.js +4 -4
- package/dist/esm/showDiffPlugin.js +4 -5
- package/dist/esm/ui/ContributorTag/buildContributorTagDom.js +115 -0
- package/dist/esm/ui/ContributorTag/contributorAvatarRenderer.js +135 -0
- package/dist/esm/ui/ContributorTag/contributorTagController.js +493 -0
- package/dist/esm/ui/ContributorTag/contributorTagIcons.js +40 -0
- package/dist/types/pm-plugins/decorations/colorSchemes/attributions.d.ts +3 -3
- package/dist/types/pm-plugins/decorations/colorSchemes/factory.d.ts +2 -2
- package/dist/types/pm-plugins/decorations/colorSchemes/schemes.d.ts +1 -1
- package/dist/types/pm-plugins/decorations/colorSchemes/types.d.ts +13 -16
- package/dist/types/pm-plugins/decorations/createContributorTagWidget.d.ts +11 -9
- package/dist/types/pm-plugins/main.d.ts +1 -2
- package/dist/types/ui/ContributorTag/buildContributorTagDom.d.ts +25 -0
- package/dist/types/ui/ContributorTag/contributorAvatarRenderer.d.ts +22 -0
- package/dist/types/ui/ContributorTag/contributorTagController.d.ts +85 -0
- package/dist/types/ui/ContributorTag/contributorTagIcons.d.ts +12 -0
- package/package.json +9 -13
- package/dist/cjs/ui/ContributorTag/ContributorTag.compiled.css +0 -29
- package/dist/cjs/ui/ContributorTag/ContributorTag.js +0 -383
- package/dist/cjs/ui/ContributorTag/ContributorTagWidget.js +0 -50
- package/dist/es2019/ui/ContributorTag/ContributorTag.compiled.css +0 -29
- package/dist/es2019/ui/ContributorTag/ContributorTag.js +0 -312
- package/dist/es2019/ui/ContributorTag/ContributorTagWidget.js +0 -43
- package/dist/esm/ui/ContributorTag/ContributorTag.compiled.css +0 -29
- package/dist/esm/ui/ContributorTag/ContributorTag.js +0 -375
- package/dist/esm/ui/ContributorTag/ContributorTagWidget.js +0 -43
- package/dist/types/ui/ContributorTag/ContributorTag.d.ts +0 -37
- package/dist/types/ui/ContributorTag/ContributorTagWidget.d.ts +0 -22
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
|
|
2
|
-
import { participantColors } from '@atlaskit/editor-shared-styles/constants';
|
|
3
|
-
import { PARTICIPANT_COLOR_SCHEMES } from './types';
|
|
4
|
-
|
|
5
2
|
// token() is a build-time transform needing static literals, so pre-compute every colour's
|
|
6
3
|
// tokens here and index by name at runtime.
|
|
7
4
|
|
|
@@ -77,69 +74,23 @@ const textAccentMap = {
|
|
|
77
74
|
gray: "var(--ds-text-accent-gray, #505258)",
|
|
78
75
|
lime: "var(--ds-text-accent-lime, #4C6B1F)"
|
|
79
76
|
};
|
|
80
|
-
|
|
81
|
-
/** Pressed counterpart of each participant's diff-safe SVG background tint. */
|
|
82
|
-
const participantPressedBackgroundMap = {
|
|
83
|
-
'red-bolder': bgSubtlerPressedMap.red,
|
|
84
|
-
'blue-bolder': bgSubtlerPressedMap.blue,
|
|
85
|
-
'green-bolder': bgSubtlerPressedMap.green,
|
|
86
|
-
'yellow-bolder': bgSubtlerPressedMap.yellow,
|
|
87
|
-
'purple-bolder': bgSubtlerPressedMap.purple,
|
|
88
|
-
'magenta-bolder': bgSubtlerPressedMap.magenta,
|
|
89
|
-
'teal-bolder': bgSubtlerPressedMap.teal,
|
|
90
|
-
'orange-bolder': bgSubtlerPressedMap.orange,
|
|
91
|
-
'lime-bolder': bgSubtlerPressedMap.lime,
|
|
92
|
-
'gray-bolder': bgSubtlerPressedMap.gray,
|
|
93
|
-
'blue-subtle': bgSubtlestPressedMap.blue,
|
|
94
|
-
'red-subtle': bgSubtlestPressedMap.red,
|
|
95
|
-
'orange-subtle': bgSubtlestPressedMap.orange,
|
|
96
|
-
'yellow-subtle': bgSubtlestPressedMap.yellow,
|
|
97
|
-
'green-subtle': bgSubtlestPressedMap.green,
|
|
98
|
-
'teal-subtle': bgSubtlestPressedMap.teal,
|
|
99
|
-
'purple-subtle': bgSubtlestPressedMap.purple,
|
|
100
|
-
'magenta-subtle': bgSubtlestPressedMap.magenta
|
|
101
|
-
};
|
|
102
|
-
/**
|
|
103
|
-
* Telepointers can put inverse text directly on their bolder colour. Diff colours sit behind
|
|
104
|
-
* arbitrary document content, so use the participant SVG tint and its matching pressed token for
|
|
105
|
-
* diff backgrounds. Borders and rings use the exact participant colour, preserving all 18
|
|
106
|
-
* bolder/subtle slots while keeping every value in the shared ADS participant palette.
|
|
107
|
-
*/
|
|
108
|
-
const participantColorTokenSets = Object.fromEntries(PARTICIPANT_COLOR_SCHEMES.map((scheme, index) => {
|
|
109
|
-
const participantColor = participantColors[index];
|
|
110
|
-
if (!participantColor) {
|
|
111
|
-
throw new Error(`Missing shared participant colour for show-diff slot ${index}`);
|
|
112
|
-
}
|
|
113
|
-
return [scheme, {
|
|
114
|
-
backgroundSubtlest: participantColor.svgBackgroundColor,
|
|
115
|
-
backgroundSubtlestPressed: participantPressedBackgroundMap[scheme],
|
|
116
|
-
backgroundSubtler: participantColor.svgBackgroundColor,
|
|
117
|
-
backgroundSubtlerPressed: participantPressedBackgroundMap[scheme],
|
|
118
|
-
borderAccent: participantColor.backgroundColor,
|
|
119
|
-
// The first ten bolder colours are safe as accents on the editor surface. The
|
|
120
|
-
// remaining subtle colours use their paired dark participant text colour.
|
|
121
|
-
textAccent: index < 10 ? participantColor.backgroundColor : participantColor.textColor
|
|
122
|
-
}];
|
|
123
|
-
}));
|
|
124
|
-
const participantColorSchemeSet = new Set(PARTICIPANT_COLOR_SCHEMES);
|
|
125
|
-
const isParticipantColorScheme = color => participantColorSchemeSet.has(color);
|
|
126
77
|
function bgSubtlest(color) {
|
|
127
|
-
return
|
|
78
|
+
return bgSubtlestMap[color];
|
|
128
79
|
}
|
|
129
80
|
function bgSubtlestPressed(color) {
|
|
130
|
-
return
|
|
81
|
+
return bgSubtlestPressedMap[color];
|
|
131
82
|
}
|
|
132
83
|
function bgSubtler(color) {
|
|
133
|
-
return
|
|
84
|
+
return bgSubtlerMap[color];
|
|
134
85
|
}
|
|
135
86
|
function bgSubtlerPressed(color) {
|
|
136
|
-
return
|
|
87
|
+
return bgSubtlerPressedMap[color];
|
|
137
88
|
}
|
|
138
89
|
function borderAccent(color) {
|
|
139
|
-
return
|
|
90
|
+
return borderAccentMap[color];
|
|
140
91
|
}
|
|
141
92
|
function textAccent(color) {
|
|
142
|
-
return
|
|
93
|
+
return textAccentMap[color];
|
|
143
94
|
}
|
|
144
95
|
|
|
145
96
|
/** Presentation tokens for one diff colour, shared by highlights and contributor tags. */
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { PARTICIPANT_COLOR_SCHEMES } from './types';
|
|
2
|
+
|
|
1
3
|
/** Green insertions, red deletions. */
|
|
2
4
|
export const traditionalScheme = {
|
|
3
5
|
insertColor: 'green',
|
|
@@ -52,35 +54,21 @@ export const standardScheme = {
|
|
|
52
54
|
deletedQuoteNodeActiveTone: 'borderAccent',
|
|
53
55
|
strikesDeletedEmbedCard: false
|
|
54
56
|
};
|
|
55
|
-
const createAttributionScheme = color =>
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
const createAttributionScheme = color => {
|
|
58
|
+
return {
|
|
59
|
+
...standardScheme,
|
|
60
|
+
insertColor: color,
|
|
61
|
+
insertActiveColor: color,
|
|
62
|
+
deleteColor: color,
|
|
63
|
+
deleteActiveColor: color,
|
|
64
|
+
deletedCellColor: color
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
const attributionColorSchemes = Object.fromEntries(PARTICIPANT_COLOR_SCHEMES.map(color => [color, createAttributionScheme(color)]));
|
|
63
68
|
|
|
64
69
|
/** Maps public schemes and attribution-only participant slots to their data objects. */
|
|
65
70
|
export const colorSchemeRegistry = {
|
|
66
|
-
|
|
67
|
-
'blue-bolder': createAttributionScheme('blue-bolder'),
|
|
68
|
-
'green-bolder': createAttributionScheme('green-bolder'),
|
|
69
|
-
'yellow-bolder': createAttributionScheme('yellow-bolder'),
|
|
70
|
-
'purple-bolder': createAttributionScheme('purple-bolder'),
|
|
71
|
-
'magenta-bolder': createAttributionScheme('magenta-bolder'),
|
|
72
|
-
'teal-bolder': createAttributionScheme('teal-bolder'),
|
|
73
|
-
'orange-bolder': createAttributionScheme('orange-bolder'),
|
|
74
|
-
'lime-bolder': createAttributionScheme('lime-bolder'),
|
|
75
|
-
'gray-bolder': createAttributionScheme('gray-bolder'),
|
|
76
|
-
'blue-subtle': createAttributionScheme('blue-subtle'),
|
|
77
|
-
'red-subtle': createAttributionScheme('red-subtle'),
|
|
78
|
-
'orange-subtle': createAttributionScheme('orange-subtle'),
|
|
79
|
-
'yellow-subtle': createAttributionScheme('yellow-subtle'),
|
|
80
|
-
'green-subtle': createAttributionScheme('green-subtle'),
|
|
81
|
-
'teal-subtle': createAttributionScheme('teal-subtle'),
|
|
82
|
-
'purple-subtle': createAttributionScheme('purple-subtle'),
|
|
83
|
-
'magenta-subtle': createAttributionScheme('magenta-subtle'),
|
|
71
|
+
...attributionColorSchemes,
|
|
84
72
|
traditional: traditionalScheme,
|
|
85
73
|
standard: standardScheme
|
|
86
74
|
};
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
/** Schemes consumers may explicitly request through the show-diff API. */
|
|
2
2
|
|
|
3
3
|
/** Attribution-only participant slots selected by the plugin, never by consumers. */
|
|
4
|
-
export const PARTICIPANT_COLOR_SCHEMES = ['red
|
|
4
|
+
export const PARTICIPANT_COLOR_SCHEMES = ['red', 'blue', 'green', 'yellow', 'purple', 'magenta', 'teal', 'orange', 'lime', 'gray'];
|
|
5
5
|
|
|
6
6
|
/** ADS accent hues used by the public and participant colour schemes. */
|
|
7
7
|
|
|
8
8
|
/** A public scheme or an attribution participant slot resolved internally for one change. */
|
|
9
9
|
|
|
10
|
-
/** A colour value that the factory expands into a complete set of diff-safe ADS tokens. */
|
|
11
|
-
|
|
12
10
|
/**
|
|
13
|
-
* A show-diff colour scheme. Colour fields are ADS hues
|
|
14
|
-
*
|
|
15
|
-
*
|
|
11
|
+
* A show-diff colour scheme. Colour fields are ADS hues that `factory.ts` expands into token paths;
|
|
12
|
+
* the rest encode structural differences no colour can express. Ring widths, padding, radius and
|
|
13
|
+
* pointer-events are fixed in the factory, not per scheme.
|
|
16
14
|
*/
|
|
@@ -11,7 +11,6 @@ import { resolveCellOverlayStyleLegacy, resolveDeletedRowStyleLegacy } from './c
|
|
|
11
11
|
import { buildDiffDecorationSpec } from './decorationKeys';
|
|
12
12
|
import { findSafeInsertPos } from './utils/findSafeInsertPos';
|
|
13
13
|
import { applyCellEdgeAttrs, getRowCellEdgeAttrs, getTableTopAndBottomCellEdgeAttrs } from './utils/tableCellEdgeAttrs';
|
|
14
|
-
const DEFAULT_COLOR_SCHEME = 'standard';
|
|
15
14
|
/**
|
|
16
15
|
* Extracts information about deleted table rows from a change
|
|
17
16
|
*/
|
|
@@ -116,7 +115,7 @@ const isEmptyRow = rowNode => {
|
|
|
116
115
|
*/
|
|
117
116
|
const createChangedRowDOM = (rowNode, cellEdgeAttrs, nodeViewSerializer, colorScheme, isInserted, diffType) => {
|
|
118
117
|
const tr = document.createElement('tr');
|
|
119
|
-
const colors = colorSchemeRegistry[colorScheme !== null && colorScheme !== void 0 ? colorScheme :
|
|
118
|
+
const colors = colorSchemeRegistry[colorScheme !== null && colorScheme !== void 0 ? colorScheme : 'standard'];
|
|
120
119
|
|
|
121
120
|
// Inserted rows keep their natural styling; the row strikethrough is deletions only.
|
|
122
121
|
if (!isExtendedEnabled(diffType) || !isInserted) {
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { createElement } from 'react';
|
|
2
1
|
import { Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
3
2
|
import { fg } from '@atlaskit/platform-feature-flags/fg';
|
|
4
|
-
import {
|
|
3
|
+
import { ContributorTagController } from '../../ui/ContributorTag/contributorTagController';
|
|
5
4
|
import { clampAnchorPosIntoCell } from './createAnchorDecorationWidgets';
|
|
6
|
-
import { buildContributorTagDecorationSpec
|
|
5
|
+
import { buildContributorTagDecorationSpec } from './decorationKeys';
|
|
7
6
|
|
|
8
7
|
/** Marks the host element of one tag, so a tag can be found in the document by its own diff. */
|
|
9
8
|
export const CONTRIBUTOR_TAG_HOST_ATTRIBUTE = 'data-contributor-tag-host';
|
|
@@ -12,23 +11,19 @@ export const CONTRIBUTOR_TAG_HOST_ATTRIBUTE = 'data-contributor-tag-host';
|
|
|
12
11
|
const isContributorTagWidgetEnabled = () => fg('confluence_ncs_step_diffing_version_history');
|
|
13
12
|
|
|
14
13
|
/**
|
|
15
|
-
* Everything a tag needs to
|
|
14
|
+
* Everything a tag needs to draw itself into the document, plumbed down from the plugin. Absent in
|
|
16
15
|
* unit tests that build decorations directly: the hosts are still emitted, they just stay empty.
|
|
17
16
|
*/
|
|
18
17
|
|
|
19
18
|
/** A mounted tag, so whoever emitted the host can take it down again. */
|
|
20
19
|
|
|
21
20
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Renders the tag into `host` through the editor's portal provider, the way the rest of the editor
|
|
30
|
-
* mounts React into decorations. The tag resolves its own model from plugin state, so a redraw of
|
|
31
|
-
* the host re-parents the tag instead of stranding it, and `isActive` changes arrive as a re-render.
|
|
21
|
+
* Draws the tag into `host`. The tag resolves its own model from plugin state, so a redraw of the
|
|
22
|
+
* host re-parents the tag instead of stranding it, and `isActive` changes arrive as an update.
|
|
23
|
+
*
|
|
24
|
+
* Each mount owns its own controller and DOM, so when ProseMirror draws a replacement widget before
|
|
25
|
+
* destroying the one it replaces, the outgoing `destroy` cannot take the incoming tag down with it
|
|
26
|
+
* (EDITOR-8702).
|
|
32
27
|
*/
|
|
33
28
|
export const mountContributorTag = ({
|
|
34
29
|
diffId,
|
|
@@ -38,24 +33,15 @@ export const mountContributorTag = ({
|
|
|
38
33
|
if (!mountContext) {
|
|
39
34
|
return undefined;
|
|
40
35
|
}
|
|
41
|
-
const {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
portalProviderAPI.render(() => /*#__PURE__*/createElement(ContributorTagWidget, {
|
|
48
|
-
api,
|
|
49
|
-
diffId,
|
|
50
|
-
getEditorRoot
|
|
51
|
-
}), host, key);
|
|
52
|
-
return {
|
|
53
|
-
key,
|
|
54
|
-
portalProviderAPI
|
|
55
|
-
};
|
|
36
|
+
const controller = new ContributorTagController({
|
|
37
|
+
...mountContext,
|
|
38
|
+
diffId
|
|
39
|
+
});
|
|
40
|
+
controller.mount(host);
|
|
41
|
+
return controller;
|
|
56
42
|
};
|
|
57
43
|
export const unmountContributorTag = mount => {
|
|
58
|
-
mount === null || mount === void 0 ? void 0 : mount.
|
|
44
|
+
mount === null || mount === void 0 ? void 0 : mount.destroy();
|
|
59
45
|
};
|
|
60
46
|
|
|
61
47
|
/**
|
|
@@ -11,8 +11,7 @@ import { buildDiffDecorationSpec } from './decorationKeys';
|
|
|
11
11
|
const displayNoneStyle = convertToInlineCss({
|
|
12
12
|
display: 'none'
|
|
13
13
|
});
|
|
14
|
-
const
|
|
15
|
-
const getColorScheme = colorScheme => colorSchemeRegistry[colorScheme !== null && colorScheme !== void 0 ? colorScheme : DEFAULT_COLOR_SCHEME];
|
|
14
|
+
const getColorScheme = colorScheme => colorSchemeRegistry[colorScheme !== null && colorScheme !== void 0 ? colorScheme : 'standard'];
|
|
16
15
|
|
|
17
16
|
/**
|
|
18
17
|
* Class names for an atomic inline node decoration (date, emoji, mention, status). Scheme-agnostic
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import isEqual from 'lodash/isEqual';
|
|
2
2
|
import omit from 'lodash/omit';
|
|
3
3
|
import { SetAttrsStep } from '@atlaskit/adf-schema/steps/set-attrs';
|
|
4
|
-
import { isExperimentEnabled } from '@atlaskit/editor-common/deprecated-platform-feature-experiments';
|
|
5
4
|
import { getBaseNodeTypeName } from '@atlaskit/editor-common/utils/node-type-utils';
|
|
6
5
|
import { AttrStep } from '@atlaskit/editor-prosemirror/transform';
|
|
7
6
|
import { fg } from '@atlaskit/platform-feature-flags/fg';
|
|
8
|
-
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
9
7
|
import { getRequiredIncludedDiffableAttrs, isDiffableAttr } from './diffableAttrs';
|
|
10
8
|
const filterUndefined = x => !!x;
|
|
11
9
|
|
|
@@ -68,20 +66,9 @@ export const getAttrChangeRanges = (doc, attrStepContexts, originalDoc) => {
|
|
|
68
66
|
const nodeAtPos = doc.nodeAt(finalPos);
|
|
69
67
|
const originalNodeAtPos = originalPos === undefined ? null : originalDoc.nodeAt(originalPos);
|
|
70
68
|
|
|
71
|
-
// date node: timestamp attribute change — highlight the date node itself (inline)
|
|
72
|
-
if (attrsToCheck.some(v => dateAttrs.includes(v)) && (nodeAtPos === null || nodeAtPos === void 0 ? void 0 : nodeAtPos.type.name) === 'date' && !isExperimentEnabled('platform_editor_improve_inline_diffs', () => expValEquals('platform_editor_improve_inline_diffs', 'isEnabled', true))) {
|
|
73
|
-
return {
|
|
74
|
-
fromB: finalPos,
|
|
75
|
-
toB: finalPos + nodeAtPos.nodeSize,
|
|
76
|
-
isInline: true,
|
|
77
|
-
inlineNodeName: 'date'
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// The following inline node attr changes are gated behind platform_editor_improve_inline_diffs.
|
|
82
69
|
// The changeset path (createDecorationsForChange) handles the deletion widget via
|
|
83
70
|
// prosemirror-changeset; we only need to add the inline insertion highlight here.
|
|
84
|
-
if (
|
|
71
|
+
if (nodeAtPos) {
|
|
85
72
|
const nodeName = nodeAtPos.type.name;
|
|
86
73
|
if (isInlineAttrChangeNodeName(nodeName)) {
|
|
87
74
|
const watchedAttrs = inlineNodeAttrMap[nodeName];
|
|
@@ -150,9 +137,7 @@ export const getAttrChangeRanges = (doc, attrStepContexts, originalDoc) => {
|
|
|
150
137
|
// Deduplicate by node position: multiple AttrSteps on the same node
|
|
151
138
|
// (e.g. setNodeAttribute(pos, 'text', ...) + setNodeAttribute(pos, 'color', ...))
|
|
152
139
|
// should produce only one decoration, not one per step.
|
|
153
|
-
|
|
154
|
-
// the possibility of multiple ranges for the same node position.
|
|
155
|
-
.filter((range, i, arr) => !isExperimentEnabled('platform_editor_improve_inline_diffs', () => expValEquals('platform_editor_improve_inline_diffs', 'isEnabled', true)) || arr.findIndex(r => r.fromB === range.fromB) === i);
|
|
140
|
+
.filter((range, i, arr) => arr.findIndex(r => r.fromB === range.fromB) === i);
|
|
156
141
|
};
|
|
157
142
|
|
|
158
143
|
/**
|
|
@@ -16,8 +16,7 @@ import { isExtendedEnabled } from '../../isExtendedEnabled';
|
|
|
16
16
|
import { buildAddedCellOverlayRoundedStyle, buildAddedCellOverlayStyle, buildAddedCellOverlayStyleNew, buildDeletedCellOverlayRoundedStyle, buildDeletedCellOverlayStyle, buildDeletedInlineContentStyle, buildDeletedInlineContentStyleExtended, buildDeletedLozengeActiveStyle, buildDeletedLozengeStyle, buildDeletedNodeCSSVariables, buildDeletedQuoteNodeWithLozengeStyle, buildDeletedStrikethroughLine, buildDeletedWrappedBlockOutline, buildInsertedBlockNodeStyle, buildInsertedInlineStyle, buildInsertStyleInBlockExtended, buildInsertStyleInBlockExtendedNoUnderline, buildInsertStyleNode } from '../colorSchemes/factory';
|
|
17
17
|
import { colorSchemeRegistry, getLegacyColorScheme, standardScheme } from '../colorSchemes/schemes';
|
|
18
18
|
import { getChangedContentStyleLegacy, getChangedNodeStyleLegacy, getDeletedContentStyleLegacy, getDeletedContentStyleUnboundedLegacy, getInsertedContentStyleLegacy, hasRestingDeletedRingLegacy, resolveCellOverlayStyleLegacy, resolveNestedInsertedNodeStyleLegacy, resolveRemovedLozengeStyleLegacy } from './wrapBlockNodeViewStyles.legacy';
|
|
19
|
-
const
|
|
20
|
-
const getColorScheme = colorScheme => colorSchemeRegistry[colorScheme !== null && colorScheme !== void 0 ? colorScheme : DEFAULT_COLOR_SCHEME];
|
|
19
|
+
const getColorScheme = colorScheme => colorSchemeRegistry[colorScheme !== null && colorScheme !== void 0 ? colorScheme : 'standard'];
|
|
21
20
|
|
|
22
21
|
/**
|
|
23
22
|
* Inserted content inside a multi-container or list node always uses the standard scheme, so a
|
|
@@ -29,7 +29,7 @@ const dropOrphanedContributorTags = (contributorTags, decorations) => {
|
|
|
29
29
|
}) => liveDiffIds.has(diffId));
|
|
30
30
|
return liveTags.length === contributorTags.length ? contributorTags : liveTags;
|
|
31
31
|
};
|
|
32
|
-
export const createPlugin = (config, getIntl, api,
|
|
32
|
+
export const createPlugin = (config, getIntl, api, onEditorView) => {
|
|
33
33
|
enforceCustomStepRegisters();
|
|
34
34
|
const nodeViewSerializer = new NodeViewSerializer({});
|
|
35
35
|
const setNodeViewSerializer = editorView => {
|
|
@@ -46,14 +46,14 @@ export const createPlugin = (config, getIntl, api, portalProviderAPI, onEditorVi
|
|
|
46
46
|
* lifecycle, which decorations are calculated independently of.
|
|
47
47
|
*/
|
|
48
48
|
let currentEditorView;
|
|
49
|
-
const tagMountContext =
|
|
49
|
+
const tagMountContext = {
|
|
50
50
|
api,
|
|
51
51
|
getEditorRoot: () => {
|
|
52
52
|
var _currentEditorView$do, _currentEditorView;
|
|
53
53
|
return (_currentEditorView$do = (_currentEditorView = currentEditorView) === null || _currentEditorView === void 0 ? void 0 : _currentEditorView.dom) !== null && _currentEditorView$do !== void 0 ? _currentEditorView$do : null;
|
|
54
54
|
},
|
|
55
|
-
|
|
56
|
-
}
|
|
55
|
+
getIntl
|
|
56
|
+
};
|
|
57
57
|
return new SafePlugin({
|
|
58
58
|
key: showDiffPluginKey,
|
|
59
59
|
state: {
|
|
@@ -97,12 +97,11 @@ export const showDiffPlugin = ({
|
|
|
97
97
|
pmPlugins() {
|
|
98
98
|
return [{
|
|
99
99
|
name: 'showDiffPlugin',
|
|
100
|
-
// Contributor tags
|
|
101
|
-
//
|
|
100
|
+
// Contributor tags draw themselves into their own decoration widgets — plain DOM, so
|
|
101
|
+
// no portal provider is needed here.
|
|
102
102
|
plugin: ({
|
|
103
|
-
getIntl
|
|
104
|
-
|
|
105
|
-
}) => createPlugin(config, getIntl, api, nodeViewPortalProviderAPI, setEditorView)
|
|
103
|
+
getIntl
|
|
104
|
+
}) => createPlugin(config, getIntl, api, setEditorView)
|
|
106
105
|
}];
|
|
107
106
|
},
|
|
108
107
|
contentComponent: () => {
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
|
|
2
|
+
export const CONTRIBUTOR_TAG_TESTID = 'diff-contributor-tag';
|
|
3
|
+
export const CONTRIBUTOR_TAG_NAME_TESTID = 'diff-contributor-tag-name';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Floor for the tag width (~one 16px avatar plus padding), so the highlight-width clamp cannot
|
|
7
|
+
* collapse the box on a very short highlight.
|
|
8
|
+
*/
|
|
9
|
+
export const MIN_TAG_WIDTH = '28px';
|
|
10
|
+
|
|
11
|
+
// Positioned against the host widget its decoration renders on the change's first character:
|
|
12
|
+
// `bottom: 100%` lifts the tag onto the line above, `inset-inline-start` starts it on that
|
|
13
|
+
// character.
|
|
14
|
+
const constraintStyle = convertToInlineCss({
|
|
15
|
+
display: 'block',
|
|
16
|
+
position: 'absolute',
|
|
17
|
+
bottom: '100%',
|
|
18
|
+
insetInlineStart: 0,
|
|
19
|
+
minWidth: 0,
|
|
20
|
+
// The tag may cover surrounding text, so it has to paint over it. Matches `akEditorUnitZIndex`.
|
|
21
|
+
zIndex: 1,
|
|
22
|
+
// It renders inside the document and it is not content: dragging a selection across the change
|
|
23
|
+
// must not select it.
|
|
24
|
+
userSelect: 'none'
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// `backgroundColor`, `borderBottomColor` and the visibility come from the model, and are set by the
|
|
28
|
+
// controller.
|
|
29
|
+
const tagStyle = convertToInlineCss({
|
|
30
|
+
display: 'inline-flex',
|
|
31
|
+
alignItems: 'center',
|
|
32
|
+
gap: "var(--ds-space-050, 4px)",
|
|
33
|
+
// Never wider than the highlight; overflow is ellipsised on the name below.
|
|
34
|
+
maxWidth: '100%',
|
|
35
|
+
minWidth: 0,
|
|
36
|
+
overflow: 'hidden',
|
|
37
|
+
paddingInline: "var(--ds-space-050, 4px)",
|
|
38
|
+
paddingBlock: "var(--ds-space-025, 2px)",
|
|
39
|
+
borderRadius: "var(--ds-radius-small, 4px)",
|
|
40
|
+
borderBottomStyle: 'solid',
|
|
41
|
+
borderBottomWidth: "var(--ds-border-width-selected, 2px)",
|
|
42
|
+
boxShadow: "var(--ds-shadow-overlay, 0px 8px 12px #1E1F2126, 0px 0px 1px #1E1F214f)",
|
|
43
|
+
font: "var(--ds-font-body-small, normal 400 12px/16px \"Atlassian Sans\", ui-sans-serif, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Ubuntu, \"Helvetica Neue\", sans-serif)",
|
|
44
|
+
whiteSpace: 'nowrap',
|
|
45
|
+
boxSizing: 'border-box'
|
|
46
|
+
});
|
|
47
|
+
const avatarsStyle = convertToInlineCss({
|
|
48
|
+
display: 'inline-flex',
|
|
49
|
+
alignItems: 'center',
|
|
50
|
+
flexShrink: 0
|
|
51
|
+
});
|
|
52
|
+
const nameStyle = convertToInlineCss({
|
|
53
|
+
display: 'block',
|
|
54
|
+
minWidth: 0,
|
|
55
|
+
overflow: 'hidden',
|
|
56
|
+
textOverflow: 'ellipsis',
|
|
57
|
+
whiteSpace: 'nowrap'
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
/** `@atlaskit/visually-hidden`, inlined. */
|
|
61
|
+
const srLabelStyle = convertToInlineCss({
|
|
62
|
+
width: '1px',
|
|
63
|
+
height: '1px',
|
|
64
|
+
padding: 0,
|
|
65
|
+
position: 'absolute',
|
|
66
|
+
border: 0,
|
|
67
|
+
clip: 'rect(1px, 1px, 1px, 1px)',
|
|
68
|
+
overflow: 'hidden',
|
|
69
|
+
userSelect: 'none',
|
|
70
|
+
whiteSpace: 'nowrap'
|
|
71
|
+
});
|
|
72
|
+
const createSpan = (doc, style, attributes = {}) => {
|
|
73
|
+
const span = doc.createElement('span');
|
|
74
|
+
span.setAttribute('style', style);
|
|
75
|
+
for (const [name, value] of Object.entries(attributes)) {
|
|
76
|
+
span.setAttribute(name, value);
|
|
77
|
+
}
|
|
78
|
+
return span;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* The tag's markup, with no model applied — see `ContributorTagController`.
|
|
82
|
+
*
|
|
83
|
+
* Built element by element rather than through `DOMSerializer.renderSpec`, which returns `Node` and
|
|
84
|
+
* would need a cast per reference below.
|
|
85
|
+
*/
|
|
86
|
+
export const buildContributorTagDom = doc => {
|
|
87
|
+
const root = createSpan(doc, constraintStyle);
|
|
88
|
+
const tag = createSpan(doc, tagStyle, {
|
|
89
|
+
'data-testid': CONTRIBUTOR_TAG_TESTID,
|
|
90
|
+
// Deliberately no `aria-label`: it would be announced ahead of the element's contents, but
|
|
91
|
+
// design requires the contributor *after* the change — hence the visually hidden label.
|
|
92
|
+
role: 'note',
|
|
93
|
+
// Focusable so keyboard and screen-reader users can reach the tag and its tooltip.
|
|
94
|
+
tabindex: '0'
|
|
95
|
+
});
|
|
96
|
+
const avatars = createSpan(doc, avatarsStyle);
|
|
97
|
+
const name = createSpan(doc, nameStyle, {
|
|
98
|
+
'data-testid': CONTRIBUTOR_TAG_NAME_TESTID
|
|
99
|
+
});
|
|
100
|
+
const srLabel = createSpan(doc, srLabelStyle);
|
|
101
|
+
tag.append(avatars, name, srLabel);
|
|
102
|
+
root.appendChild(tag);
|
|
103
|
+
return {
|
|
104
|
+
avatars,
|
|
105
|
+
name,
|
|
106
|
+
root,
|
|
107
|
+
srLabel,
|
|
108
|
+
tag
|
|
109
|
+
};
|
|
110
|
+
};
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { bind } from 'bind-event-listener';
|
|
2
|
+
import { AVATAR_SIZES } from '@atlaskit/avatar/avatar-sizes';
|
|
3
|
+
import { BORDER_WIDTH } from '@atlaskit/avatar/constants/default';
|
|
4
|
+
import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
|
|
5
|
+
import { getContributorTagIcon } from './contributorTagIcons';
|
|
6
|
+
|
|
7
|
+
/** The size `@atlaskit/avatar`'s `xxsmall` rendered at. */
|
|
8
|
+
const AVATAR_SIZE = AVATAR_SIZES.xxsmall;
|
|
9
|
+
/** `xxsmall` also carried a `space.025` margin — the same 2px — which is where the ring is painted. */
|
|
10
|
+
const AVATAR_RING_WIDTH = BORDER_WIDTH;
|
|
11
|
+
const AVATAR_BOX_SIZE = AVATAR_SIZE + AVATAR_RING_WIDTH * 2;
|
|
12
|
+
|
|
13
|
+
/** Reused from `@atlaskit/avatar`'s `avatar-content`, so the two shapes cannot drift. */
|
|
14
|
+
const HEXAGON_CLIP_PATH = 'polygon(45% 1.33975%, 46.5798% 0.60307%, 48.26352% 0.15192%, 50% 0%, 51.73648% 0.15192%, 53.4202% 0.60307%, 55% 1.33975%, 89.64102% 21.33975%, 91.06889% 22.33956%, 92.30146% 23.57212%, 93.30127% 25%, 94.03794% 26.5798%, 94.48909% 28.26352%, 94.64102% 30%, 94.64102% 70%, 94.48909% 71.73648%, 94.03794% 73.4202%, 93.30127% 75%, 92.30146% 76.42788%, 91.06889% 77.66044%, 89.64102% 78.66025%, 55% 98.66025%, 53.4202% 99.39693%, 51.73648% 99.84808%, 50% 100%, 48.26352% 99.84808%, 46.5798% 99.39693%, 45% 98.66025%, 10.35898% 78.66025%, 8.93111% 77.66044%, 7.69854% 76.42788%, 6.69873% 75%, 5.96206% 73.4202%, 5.51091% 71.73648%, 5.35898% 70%, 5.35898% 30%, 5.51091% 28.26352%, 5.96206% 26.5798%, 6.69873% 25%, 7.69854% 23.57212%, 8.93111% 22.33956%, 10.35898% 21.33975%)';
|
|
15
|
+
const boxStyle = convertToInlineCss({
|
|
16
|
+
display: 'inline-flex',
|
|
17
|
+
alignItems: 'center',
|
|
18
|
+
justifyContent: 'center',
|
|
19
|
+
flexShrink: 0,
|
|
20
|
+
boxSizing: 'border-box',
|
|
21
|
+
width: `${AVATAR_BOX_SIZE}px`,
|
|
22
|
+
height: `${AVATAR_BOX_SIZE}px`
|
|
23
|
+
});
|
|
24
|
+
const shapeStyle = convertToInlineCss({
|
|
25
|
+
display: 'inline-flex',
|
|
26
|
+
alignItems: 'center',
|
|
27
|
+
justifyContent: 'center',
|
|
28
|
+
boxSizing: 'border-box',
|
|
29
|
+
width: `${AVATAR_SIZE}px`,
|
|
30
|
+
height: `${AVATAR_SIZE}px`,
|
|
31
|
+
overflow: 'hidden'
|
|
32
|
+
});
|
|
33
|
+
const imageStyle = convertToInlineCss({
|
|
34
|
+
display: 'block',
|
|
35
|
+
width: '100%',
|
|
36
|
+
height: '100%',
|
|
37
|
+
objectFit: 'cover'
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
/** The `@atlaskit/avatar` image fallback: a subtle glyph on a tinted box. */
|
|
41
|
+
const personFallbackStyle = convertToInlineCss({
|
|
42
|
+
width: '100%',
|
|
43
|
+
height: '100%',
|
|
44
|
+
display: 'flex',
|
|
45
|
+
alignItems: 'center',
|
|
46
|
+
justifyContent: 'center',
|
|
47
|
+
backgroundColor: "var(--ds-background-accent-gray-subtler, #DDDEE1)",
|
|
48
|
+
color: "var(--ds-icon-subtle, #505258)"
|
|
49
|
+
});
|
|
50
|
+
/**
|
|
51
|
+
* One 16px avatar for a contributor: a circle for a person, a hexagon for an agent.
|
|
52
|
+
*
|
|
53
|
+
* Mirrors `mentionAvatarRenderer` — a bare `<img>` with a glyph fallback bound to `error`, and the
|
|
54
|
+
* hexagon cut with `clip-path`. The ring `@atlaskit/avatar` drew from `borderColor` is a
|
|
55
|
+
* `box-shadow` on the circle and a second clipped hexagon behind the agent, since `box-shadow` is
|
|
56
|
+
* cut away by `clip-path`.
|
|
57
|
+
*/
|
|
58
|
+
export const contributorAvatarRenderer = ({
|
|
59
|
+
contributor,
|
|
60
|
+
doc,
|
|
61
|
+
ringColor,
|
|
62
|
+
stackIndex
|
|
63
|
+
}) => {
|
|
64
|
+
const isAgent = contributor.kind === 'agent';
|
|
65
|
+
const element = doc.createElement('span');
|
|
66
|
+
element.setAttribute('style', boxStyle);
|
|
67
|
+
// Decorative: the tag names its contributors in the visually hidden label its screen-reader
|
|
68
|
+
// announcement comes from.
|
|
69
|
+
element.setAttribute('aria-hidden', 'true');
|
|
70
|
+
if (stackIndex !== undefined) {
|
|
71
|
+
element.style.setProperty('z-index', String(stackIndex));
|
|
72
|
+
}
|
|
73
|
+
const shape = doc.createElement('span');
|
|
74
|
+
shape.setAttribute('style', shapeStyle);
|
|
75
|
+
element.appendChild(shape);
|
|
76
|
+
if (isAgent) {
|
|
77
|
+
element.style.setProperty('clip-path', HEXAGON_CLIP_PATH);
|
|
78
|
+
shape.style.setProperty('clip-path', HEXAGON_CLIP_PATH);
|
|
79
|
+
} else {
|
|
80
|
+
shape.style.setProperty('border-radius', "var(--ds-radius-full, 9999px)");
|
|
81
|
+
}
|
|
82
|
+
let image;
|
|
83
|
+
let unbindImageError;
|
|
84
|
+
const showFallback = () => {
|
|
85
|
+
var _unbindImageError, _image;
|
|
86
|
+
(_unbindImageError = unbindImageError) === null || _unbindImageError === void 0 ? void 0 : _unbindImageError();
|
|
87
|
+
unbindImageError = undefined;
|
|
88
|
+
(_image = image) === null || _image === void 0 ? void 0 : _image.remove();
|
|
89
|
+
image = undefined;
|
|
90
|
+
if (!isAgent) {
|
|
91
|
+
const fallback = doc.createElement('span');
|
|
92
|
+
fallback.setAttribute('style', personFallbackStyle);
|
|
93
|
+
fallback.appendChild(getContributorTagIcon('person', doc));
|
|
94
|
+
shape.appendChild(fallback);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
shape.appendChild(getContributorTagIcon(contributor.agentKind === 'rovo' ? 'rovoHex' : 'aiBot', doc));
|
|
98
|
+
};
|
|
99
|
+
if (contributor.avatarUrl) {
|
|
100
|
+
image = doc.createElement('img');
|
|
101
|
+
image.alt = '';
|
|
102
|
+
image.decoding = 'async';
|
|
103
|
+
image.draggable = false;
|
|
104
|
+
image.loading = 'lazy';
|
|
105
|
+
image.setAttribute('style', imageStyle);
|
|
106
|
+
unbindImageError = bind(image, {
|
|
107
|
+
type: 'error',
|
|
108
|
+
listener: showFallback
|
|
109
|
+
});
|
|
110
|
+
shape.appendChild(image);
|
|
111
|
+
image.src = contributor.avatarUrl;
|
|
112
|
+
} else {
|
|
113
|
+
showFallback();
|
|
114
|
+
}
|
|
115
|
+
const setRingColor = nextRingColor => {
|
|
116
|
+
if (isAgent) {
|
|
117
|
+
element.style.setProperty('background', nextRingColor);
|
|
118
|
+
// Shows through wherever the artwork is transparent, as the avatar background did.
|
|
119
|
+
shape.style.setProperty('background', nextRingColor);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
shape.style.setProperty('box-shadow', `0 0 0 ${AVATAR_RING_WIDTH}px ${nextRingColor}`);
|
|
123
|
+
shape.style.setProperty('background', nextRingColor);
|
|
124
|
+
};
|
|
125
|
+
setRingColor(ringColor);
|
|
126
|
+
return {
|
|
127
|
+
destroy: () => {
|
|
128
|
+
var _unbindImageError2;
|
|
129
|
+
(_unbindImageError2 = unbindImageError) === null || _unbindImageError2 === void 0 ? void 0 : _unbindImageError2();
|
|
130
|
+
unbindImageError = undefined;
|
|
131
|
+
element.remove();
|
|
132
|
+
},
|
|
133
|
+
element,
|
|
134
|
+
setRingColor
|
|
135
|
+
};
|
|
136
|
+
};
|