@atlaskit/editor-plugin-show-diff 16.0.1 → 16.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -0
- package/afm-products/tsconfig.json +3 -0
- package/dist/cjs/pm-plugins/calculateDiff/calculateDiffDecorations.js +91 -51
- package/dist/cjs/pm-plugins/decorations/createContributorTagWidget.js +20 -1
- package/dist/cjs/pm-plugins/decorations/extractContributorTags.js +121 -21
- package/dist/cjs/pm-plugins/decorations/utils/getAttrChangeRanges.js +19 -8
- package/dist/cjs/pm-plugins/decorations/utils/getMarkChangeRanges.js +18 -4
- package/dist/cjs/pm-plugins/decorations/utils/mapStepRangeToFinal.js +34 -0
- package/dist/cjs/pm-plugins/main.js +18 -0
- package/dist/cjs/ui/ContributorTag/buildContributorTagDom.js +51 -5
- package/dist/cjs/ui/ContributorTag/contributorLabel.js +55 -0
- package/dist/cjs/ui/ContributorTag/contributorTagController.js +40 -43
- package/dist/cjs/ui/ContributorTag/messages.js +5 -0
- package/dist/cjs/ui/DiffNavigation/announceActiveDiff.js +54 -0
- package/dist/cjs/ui/DiffNavigation/messages.js +19 -0
- package/dist/es2019/pm-plugins/calculateDiff/calculateDiffDecorations.js +48 -13
- package/dist/es2019/pm-plugins/decorations/createContributorTagWidget.js +18 -1
- package/dist/es2019/pm-plugins/decorations/extractContributorTags.js +70 -10
- package/dist/es2019/pm-plugins/decorations/utils/getAttrChangeRanges.js +16 -0
- package/dist/es2019/pm-plugins/decorations/utils/getMarkChangeRanges.js +12 -4
- package/dist/es2019/pm-plugins/decorations/utils/mapStepRangeToFinal.js +28 -0
- package/dist/es2019/pm-plugins/main.js +18 -0
- package/dist/es2019/ui/ContributorTag/buildContributorTagDom.js +48 -4
- package/dist/es2019/ui/ContributorTag/contributorLabel.js +49 -0
- package/dist/es2019/ui/ContributorTag/contributorTagController.js +39 -44
- package/dist/es2019/ui/ContributorTag/messages.js +5 -0
- package/dist/es2019/ui/DiffNavigation/announceActiveDiff.js +49 -0
- package/dist/es2019/ui/DiffNavigation/messages.js +13 -0
- package/dist/esm/pm-plugins/calculateDiff/calculateDiffDecorations.js +91 -51
- package/dist/esm/pm-plugins/decorations/createContributorTagWidget.js +20 -1
- package/dist/esm/pm-plugins/decorations/extractContributorTags.js +121 -21
- package/dist/esm/pm-plugins/decorations/utils/getAttrChangeRanges.js +19 -8
- package/dist/esm/pm-plugins/decorations/utils/getMarkChangeRanges.js +17 -4
- package/dist/esm/pm-plugins/decorations/utils/mapStepRangeToFinal.js +28 -0
- package/dist/esm/pm-plugins/main.js +18 -0
- package/dist/esm/ui/ContributorTag/buildContributorTagDom.js +50 -4
- package/dist/esm/ui/ContributorTag/contributorLabel.js +49 -0
- package/dist/esm/ui/ContributorTag/contributorTagController.js +41 -44
- package/dist/esm/ui/ContributorTag/messages.js +5 -0
- package/dist/esm/ui/DiffNavigation/announceActiveDiff.js +48 -0
- package/dist/esm/ui/DiffNavigation/messages.js +13 -0
- package/dist/types/pm-plugins/decorations/extractContributorTags.d.ts +14 -1
- package/dist/types/pm-plugins/decorations/utils/getAttrChangeRanges.d.ts +3 -0
- package/dist/types/pm-plugins/decorations/utils/getMarkChangeRanges.d.ts +4 -1
- package/dist/types/pm-plugins/decorations/utils/mapStepRangeToFinal.d.ts +8 -0
- package/dist/types/showDiffPluginType.d.ts +7 -1
- package/dist/types/ui/ContributorTag/buildContributorTagDom.d.ts +12 -2
- package/dist/types/ui/ContributorTag/contributorLabel.d.ts +13 -0
- package/dist/types/ui/ContributorTag/contributorTagController.d.ts +11 -0
- package/dist/types/ui/ContributorTag/messages.d.ts +1 -0
- package/dist/types/ui/DiffNavigation/announceActiveDiff.d.ts +18 -0
- package/dist/types/ui/DiffNavigation/messages.d.ts +5 -0
- package/package.json +5 -4
|
@@ -7,6 +7,7 @@ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
|
7
7
|
import { PluginKey } from '@atlaskit/editor-prosemirror/state';
|
|
8
8
|
import { Step as ProseMirrorStep } from '@atlaskit/editor-prosemirror/transform-override';
|
|
9
9
|
import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
10
|
+
import { getActiveDiffAnnouncement } from '../ui/DiffNavigation/announceActiveDiff';
|
|
10
11
|
import { calculateDiffDecorations } from './calculateDiff/calculateDiffDecorations';
|
|
11
12
|
import { isDiffDecoration, isDiffDecorationSpec } from './decorations/decorationKeys';
|
|
12
13
|
import { enforceCustomStepRegisters } from './enforceCustomStepRegisters';
|
|
@@ -272,6 +273,23 @@ export var createPlugin = function createPlugin(config, getIntl, api, onEditorVi
|
|
|
272
273
|
api === null || api === void 0 || api.core.actions.execute(toggleExpandRange(activeDecoration.from, activeDecoration.to, true));
|
|
273
274
|
}
|
|
274
275
|
cancelPendingScrollToDecoration = scrollToDecoration(view, scrollableDecorations, pluginState.activeIndex);
|
|
276
|
+
|
|
277
|
+
// Stepping only scrolls — no focus moves and no content changes — so without this a
|
|
278
|
+
// screen-reader user gets silence. Announced through the live region rather than by
|
|
279
|
+
// focusing the change, since the "next change" control has to stay focused to be
|
|
280
|
+
// pressed again. After the scroll above, so the announcement never precedes it.
|
|
281
|
+
if (isExtendedEnabled(pluginState === null || pluginState === void 0 ? void 0 : pluginState.diffType)) {
|
|
282
|
+
var announcement = getActiveDiffAnnouncement({
|
|
283
|
+
activeIndex: pluginState.activeIndex,
|
|
284
|
+
contributorTags: pluginState.contributorTags,
|
|
285
|
+
decorations: scrollableDecorations,
|
|
286
|
+
intl: getIntl()
|
|
287
|
+
});
|
|
288
|
+
if (announcement) {
|
|
289
|
+
var _api$accessibilityUti;
|
|
290
|
+
api === null || api === void 0 || (_api$accessibilityUti = api.accessibilityUtils) === null || _api$accessibilityUti === void 0 || _api$accessibilityUti.actions.ariaNotify(announcement);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
275
293
|
}
|
|
276
294
|
},
|
|
277
295
|
destroy: function destroy() {
|
|
@@ -42,6 +42,30 @@ export var CONTRIBUTOR_TAG_REVEALED_ATTRIBUTE = 'data-revealed';
|
|
|
42
42
|
*/
|
|
43
43
|
export var TAG_EXIT_FALLBACK_MS = 1200;
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* The tooltip's look, inline rather than through `VANILLA_TOOLTIP_DEFAULT_CLASS`: this tooltip is
|
|
47
|
+
* hoisted out of the tag, and that class's rule is scoped under `.ProseMirror` — see
|
|
48
|
+
* `resolveTooltipContainer`. Otherwise `vanillaTooltipDefaultStyles` in editor-core, which is the
|
|
49
|
+
* look every other vanilla tooltip has; keep the two in step.
|
|
50
|
+
*/
|
|
51
|
+
export var CONTRIBUTOR_TAG_TOOLTIP_STYLES = {
|
|
52
|
+
boxSizing: 'border-box',
|
|
53
|
+
maxWidth: '240px',
|
|
54
|
+
backgroundColor: "var(--ds-background-neutral-bold, #292A2E)",
|
|
55
|
+
// A `popover` is given one by the UA stylesheet.
|
|
56
|
+
border: 'none',
|
|
57
|
+
borderRadius: "var(--ds-radius-small, 3px)",
|
|
58
|
+
color: "var(--ds-text-inverse, #FFFFFF)",
|
|
59
|
+
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)",
|
|
60
|
+
fontFamily: "var(--ds-font-family-body, \"Atlassian Sans\", ui-sans-serif, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Ubuntu, \"Helvetica Neue\", sans-serif)",
|
|
61
|
+
overflowWrap: 'break-word',
|
|
62
|
+
paddingBlock: "var(--ds-space-050, 4px)",
|
|
63
|
+
paddingInline: "var(--ds-space-075, 6px)",
|
|
64
|
+
whiteSpace: 'normal',
|
|
65
|
+
// A tooltip is never a hit target — it hangs over the document's own content.
|
|
66
|
+
pointerEvents: 'none'
|
|
67
|
+
};
|
|
68
|
+
|
|
45
69
|
// Positioned against the host widget its decoration renders on the change's first character:
|
|
46
70
|
// `bottom: 100%` lifts the tag onto the line above, `inset-inline-start` starts it on that
|
|
47
71
|
// character.
|
|
@@ -125,6 +149,19 @@ var srLabelStyle = convertToInlineCss({
|
|
|
125
149
|
userSelect: 'none',
|
|
126
150
|
whiteSpace: 'nowrap'
|
|
127
151
|
});
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Ids for the hidden label that the tag's `aria-labelledby` points at. Namespaced and random because
|
|
155
|
+
* the tag renders inside the document and shares the host page's id space — the same reason
|
|
156
|
+
* `VanillaTooltip` does it this way. The counter is a fallback for non-secure contexts, where
|
|
157
|
+
* `crypto.randomUUID` is unavailable.
|
|
158
|
+
*/
|
|
159
|
+
var generateLabelId = function () {
|
|
160
|
+
var count = 0;
|
|
161
|
+
return function () {
|
|
162
|
+
return typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function' ? "".concat(CONTRIBUTOR_TAG_CLASS, "-label-").concat(crypto.randomUUID()) : "".concat(CONTRIBUTOR_TAG_CLASS, "-label-").concat(count += 1);
|
|
163
|
+
};
|
|
164
|
+
}();
|
|
128
165
|
var createSpan = function createSpan(doc, style) {
|
|
129
166
|
var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
130
167
|
var span = doc.createElement('span');
|
|
@@ -144,21 +181,30 @@ var createSpan = function createSpan(doc, style) {
|
|
|
144
181
|
* would need a cast per reference below.
|
|
145
182
|
*/
|
|
146
183
|
export var buildContributorTagDom = function buildContributorTagDom(doc) {
|
|
184
|
+
var labelId = generateLabelId();
|
|
147
185
|
var root = createSpan(doc, constraintStyle);
|
|
148
186
|
var tag = createSpan(doc, tagStyle, {
|
|
149
187
|
class: CONTRIBUTOR_TAG_CLASS,
|
|
150
188
|
'data-testid': CONTRIBUTOR_TAG_TESTID,
|
|
151
|
-
//
|
|
152
|
-
//
|
|
189
|
+
// Named by the hidden label rather than `aria-label`, which would be a second copy of the same
|
|
190
|
+
// sentence. `role="note"` takes its name from the author, not its contents, so without this
|
|
191
|
+
// the tag is a focus stop with no accessible name.
|
|
192
|
+
'aria-labelledby': labelId,
|
|
153
193
|
role: 'note',
|
|
154
|
-
// Focusable so keyboard and screen-reader users can reach the tag and its tooltip.
|
|
194
|
+
// Focusable so keyboard and screen-reader users can reach the tag and its tooltip. Its focus
|
|
195
|
+
// ring is drawn inward — see `contributorTagStyles` in editor-core.
|
|
155
196
|
tabindex: '0'
|
|
156
197
|
});
|
|
157
198
|
var avatars = createSpan(doc, avatarsStyle);
|
|
199
|
+
// `aria-hidden`: the hidden label restates this name in a full sentence, so leaving it in the
|
|
200
|
+
// tree announced the contributor twice ("Priya Changed by Priya").
|
|
158
201
|
var name = createSpan(doc, nameStyle, {
|
|
202
|
+
'aria-hidden': 'true',
|
|
159
203
|
'data-testid': CONTRIBUTOR_TAG_NAME_TESTID
|
|
160
204
|
});
|
|
161
|
-
var srLabel = createSpan(doc, srLabelStyle
|
|
205
|
+
var srLabel = createSpan(doc, srLabelStyle, {
|
|
206
|
+
id: labelId
|
|
207
|
+
});
|
|
162
208
|
tag.append(avatars, name, srLabel);
|
|
163
209
|
root.appendChild(tag);
|
|
164
210
|
return {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { contributorTagMessages } from './messages';
|
|
2
|
+
var getContributorName = function getContributorName(contributor, formatMessage) {
|
|
3
|
+
var _contributor$name, _contributor$agentKin;
|
|
4
|
+
var name = (_contributor$name = contributor.name) === null || _contributor$name === void 0 ? void 0 : _contributor$name.trim();
|
|
5
|
+
if (name) {
|
|
6
|
+
return name;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// `agentKind` defaults to `'external'` per the plugin type contract; an unidentified external
|
|
10
|
+
// agent falls back to a generic label rather than rendering a nameless tag.
|
|
11
|
+
if (contributor.kind === 'agent' && ((_contributor$agentKin = contributor.agentKind) !== null && _contributor$agentKin !== void 0 ? _contributor$agentKin : 'external') === 'external') {
|
|
12
|
+
return formatMessage(contributorTagMessages.externalAgentName);
|
|
13
|
+
}
|
|
14
|
+
return '';
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Whether the label has to spell out that the contributor is an agent. A sighted user reads that off
|
|
19
|
+
* the `aria-hidden` avatar, so the label is the only other carrier.
|
|
20
|
+
*
|
|
21
|
+
* Excluded: a connected pair, which says it via `changedByConnected`, and an unnamed external agent,
|
|
22
|
+
* whose name `getContributorName` has already resolved to "External agent".
|
|
23
|
+
*/
|
|
24
|
+
var isUnaccompaniedNamedAgent = function isUnaccompaniedNamedAgent(model) {
|
|
25
|
+
var _model$contributor$na;
|
|
26
|
+
return !model.connectedContributor && model.contributor.kind === 'agent' && Boolean((_model$contributor$na = model.contributor.name) === null || _model$contributor$na === void 0 ? void 0 : _model$contributor$na.trim());
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* The two strings a tag's model resolves to. Shared with `getActiveDiffAnnouncement`, so stepping
|
|
30
|
+
* onto a change says the same sentence as the tag pinned to it rather than a copy free to drift.
|
|
31
|
+
*/
|
|
32
|
+
export var formatContributorLabel = function formatContributorLabel(model, formatMessage) {
|
|
33
|
+
var isPrimaryAgent = model.contributor.kind === 'agent';
|
|
34
|
+
var primaryName = getContributorName(model.contributor, formatMessage);
|
|
35
|
+
var secondaryName = model.connectedContributor ? getContributorName(model.connectedContributor, formatMessage) : '';
|
|
36
|
+
var agentName = isPrimaryAgent ? primaryName : secondaryName;
|
|
37
|
+
var userName = isPrimaryAgent ? secondaryName : primaryName;
|
|
38
|
+
return {
|
|
39
|
+
fullLabel: model.connectedContributor ? formatMessage(contributorTagMessages.changedByConnected, {
|
|
40
|
+
agentName: agentName,
|
|
41
|
+
userName: userName
|
|
42
|
+
}) : formatMessage(isUnaccompaniedNamedAgent(model) ? contributorTagMessages.changedByAgent : contributorTagMessages.changedBy, {
|
|
43
|
+
name: primaryName
|
|
44
|
+
}),
|
|
45
|
+
// A connected pair only ever shows the agent; the pair is spelled out in `fullLabel`, because
|
|
46
|
+
// the tag is capped at `MAX_TAG_WIDTH` and two names rarely fit inside it.
|
|
47
|
+
visibleName: model.connectedContributor ? agentName || primaryName : primaryName
|
|
48
|
+
};
|
|
49
|
+
};
|
|
@@ -6,24 +6,9 @@ import { bind, bindAll } from 'bind-event-listener';
|
|
|
6
6
|
import { VanillaTooltip } from '@atlaskit/editor-common/vanilla-tooltip';
|
|
7
7
|
import { getAccentTokens } from '../../pm-plugins/decorations/colorSchemes/factory';
|
|
8
8
|
import { colorSchemeRegistry } from '../../pm-plugins/decorations/colorSchemes/schemes';
|
|
9
|
-
import { buildContributorTagDom, CONTRIBUTOR_TAG_REVEALED_ATTRIBUTE, TAG_EXIT_FALLBACK_MS } from './buildContributorTagDom';
|
|
9
|
+
import { buildContributorTagDom, CONTRIBUTOR_TAG_REVEALED_ATTRIBUTE, CONTRIBUTOR_TAG_TOOLTIP_STYLES, TAG_EXIT_FALLBACK_MS } from './buildContributorTagDom';
|
|
10
10
|
import { contributorAvatarRenderer } from './contributorAvatarRenderer';
|
|
11
|
-
import {
|
|
12
|
-
var getContributorName = function getContributorName(contributor, formatMessage) {
|
|
13
|
-
var _contributor$name, _contributor$agentKin;
|
|
14
|
-
var name = (_contributor$name = contributor.name) === null || _contributor$name === void 0 ? void 0 : _contributor$name.trim();
|
|
15
|
-
if (name) {
|
|
16
|
-
return name;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// `agentKind` defaults to `'external'` per the plugin type contract; an unidentified external
|
|
20
|
-
// agent falls back to a generic label rather than rendering a nameless tag.
|
|
21
|
-
if (contributor.kind === 'agent' && ((_contributor$agentKin = contributor.agentKind) !== null && _contributor$agentKin !== void 0 ? _contributor$agentKin : 'external') === 'external') {
|
|
22
|
-
return formatMessage(contributorTagMessages.externalAgentName);
|
|
23
|
-
}
|
|
24
|
-
return '';
|
|
25
|
-
};
|
|
26
|
-
|
|
11
|
+
import { formatContributorLabel } from './contributorLabel';
|
|
27
12
|
/**
|
|
28
13
|
* Resolves the tag's accent from the same scheme value the highlight was drawn from, so the colour
|
|
29
14
|
* the two carry can never drift — only the tone does, which is `getAccentTokens`'s to pick.
|
|
@@ -106,8 +91,8 @@ var fadeTagOut = function fadeTagOut(tag, release) {
|
|
|
106
91
|
/** The contributors a tag draws, keyed so a republished model can be recognised as the same pair. */
|
|
107
92
|
var identityOf = function identityOf(model) {
|
|
108
93
|
return [model === null || model === void 0 ? void 0 : model.contributor, model === null || model === void 0 ? void 0 : model.connectedContributor].map(function (contributor) {
|
|
109
|
-
var _contributor$
|
|
110
|
-
return contributor ? "".concat(contributor.kind, ":").concat((_contributor$
|
|
94
|
+
var _contributor$agentKin, _contributor$avatarUr;
|
|
95
|
+
return contributor ? "".concat(contributor.kind, ":").concat((_contributor$agentKin = contributor.agentKind) !== null && _contributor$agentKin !== void 0 ? _contributor$agentKin : '', ":").concat(contributor.name, ":").concat((_contributor$avatarUr = contributor.avatarUrl) !== null && _contributor$avatarUr !== void 0 ? _contributor$avatarUr : '') : '';
|
|
111
96
|
}).join('|');
|
|
112
97
|
};
|
|
113
98
|
|
|
@@ -348,24 +333,12 @@ export var ContributorTagController = /*#__PURE__*/function () {
|
|
|
348
333
|
if (!this.dom) {
|
|
349
334
|
return;
|
|
350
335
|
}
|
|
351
|
-
var
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
var userName = isPrimaryAgent ? secondaryName : primaryName;
|
|
358
|
-
|
|
359
|
-
// A connected pair only ever shows the agent; the pair is spelled out in the label, because the
|
|
360
|
-
// tag is capped at `MAX_TAG_WIDTH` and two names rarely fit inside it.
|
|
361
|
-
this.dom.name.textContent = model.connectedContributor ? agentName || primaryName : primaryName;
|
|
362
|
-
this.fullLabel = model.connectedContributor ? formatMessage(contributorTagMessages.changedByConnected, {
|
|
363
|
-
agentName: agentName,
|
|
364
|
-
userName: userName
|
|
365
|
-
}) : formatMessage(contributorTagMessages.changedBy, {
|
|
366
|
-
name: primaryName
|
|
367
|
-
});
|
|
368
|
-
this.dom.srLabel.textContent = this.fullLabel;
|
|
336
|
+
var _formatContributorLab = formatContributorLabel(model, this.options.getIntl().formatMessage),
|
|
337
|
+
fullLabel = _formatContributorLab.fullLabel,
|
|
338
|
+
visibleName = _formatContributorLab.visibleName;
|
|
339
|
+
this.dom.name.textContent = visibleName;
|
|
340
|
+
this.fullLabel = fullLabel;
|
|
341
|
+
this.dom.srLabel.textContent = fullLabel;
|
|
369
342
|
}
|
|
370
343
|
}, {
|
|
371
344
|
key: "accentOf",
|
|
@@ -431,15 +404,39 @@ export var ContributorTagController = /*#__PURE__*/function () {
|
|
|
431
404
|
if (!content || !this.dom) {
|
|
432
405
|
return;
|
|
433
406
|
}
|
|
434
|
-
this.tooltip = new VanillaTooltip(this.dom.tag, content,
|
|
435
|
-
//
|
|
436
|
-
|
|
437
|
-
//
|
|
438
|
-
|
|
407
|
+
this.tooltip = new VanillaTooltip(this.dom.tag, content,
|
|
408
|
+
// Generated id.
|
|
409
|
+
undefined,
|
|
410
|
+
// No class: the look is inline, because a hoisted tooltip is outside the `.ProseMirror`
|
|
411
|
+
// scope `VANILLA_TOOLTIP_DEFAULT_CLASS` is keyed on — see `CONTRIBUTOR_TAG_TOOLTIP_STYLES`.
|
|
412
|
+
'',
|
|
413
|
+
// Default delay, no `onShow`, and the default `top` placement.
|
|
414
|
+
undefined, CONTRIBUTOR_TAG_TOOLTIP_STYLES, undefined, undefined, this.resolveTooltipContainer());
|
|
439
415
|
// `VanillaTooltip` sets `aria-describedby` on its trigger, which would announce the label a
|
|
440
|
-
// second time — the
|
|
441
|
-
// requires.
|
|
416
|
+
// second time — the hidden child already announces it, and names the tag with it.
|
|
442
417
|
this.dom.tag.removeAttribute('aria-describedby');
|
|
418
|
+
// Out of the tag but still in the document, so its text would otherwise be a third copy of the
|
|
419
|
+
// same sentence. It stays visible for sighted users, who need the part of the name the tag
|
|
420
|
+
// clipped.
|
|
421
|
+
this.tooltip.element.setAttribute('aria-hidden', 'true');
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Where the tooltip is appended, rather than inside the tag.
|
|
426
|
+
*
|
|
427
|
+
* Popper and the browser only agree on a top-layer popover's origin when nothing above it is
|
|
428
|
+
* transformed, and the tag hangs under the editor's own transformed nodes — inside a wide image
|
|
429
|
+
* that is `.rich-media-item`, whose `translateX(-50%)` threw the tooltip off screen
|
|
430
|
+
* (EDITOR-8971). The content area is the nearest ancestor with none of that above it, and keeps
|
|
431
|
+
* the tooltip inside the editor it belongs to; the document body covers an appearance that has
|
|
432
|
+
* no content area.
|
|
433
|
+
*/
|
|
434
|
+
}, {
|
|
435
|
+
key: "resolveTooltipContainer",
|
|
436
|
+
value: function resolveTooltipContainer() {
|
|
437
|
+
var _editorRoot$closest;
|
|
438
|
+
var editorRoot = this.options.getEditorRoot();
|
|
439
|
+
return (_editorRoot$closest = editorRoot === null || editorRoot === void 0 ? void 0 : editorRoot.closest('.ak-editor-content-area')) !== null && _editorRoot$closest !== void 0 ? _editorRoot$closest : editorRoot === null || editorRoot === void 0 ? void 0 : editorRoot.ownerDocument.body;
|
|
443
440
|
}
|
|
444
441
|
|
|
445
442
|
/**
|
|
@@ -5,6 +5,11 @@ export var contributorTagMessages = defineMessages({
|
|
|
5
5
|
defaultMessage: 'Changed by {name}',
|
|
6
6
|
description: 'Screen-reader label and tooltip for the tag pinned to a highlighted change in the version-history diff, naming the single person or agent that made the change. The name placeholder is the contributor display name.'
|
|
7
7
|
},
|
|
8
|
+
changedByAgent: {
|
|
9
|
+
id: 'editor-plugin-show-diff.ContributorTag.changedByAgent',
|
|
10
|
+
defaultMessage: 'Changed by {name}, an AI agent',
|
|
11
|
+
description: 'Screen-reader label and tooltip for the tag pinned to a highlighted change in the version-history diff, when a named AI agent made the change rather than a person. The name placeholder is the agent display name.'
|
|
12
|
+
},
|
|
8
13
|
changedByConnected: {
|
|
9
14
|
id: 'editor-plugin-show-diff.ContributorTag.changedByConnected',
|
|
10
15
|
defaultMessage: 'Changed by {agentName} with {userName}',
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
3
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
4
|
+
import { isDiffDecoration } from '../../pm-plugins/decorations/decorationKeys';
|
|
5
|
+
import { formatContributorLabel } from '../ContributorTag/contributorLabel';
|
|
6
|
+
import { diffNavigationMessages } from './messages';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The tag that captions the given decoration, if any. `linkedDiffIds` is checked as well as
|
|
10
|
+
* `diffId`, because a replacement's two decorations share one tag and navigation can land on either.
|
|
11
|
+
*/
|
|
12
|
+
var findTagFor = function findTagFor(decoration, contributorTags) {
|
|
13
|
+
if (!(contributorTags !== null && contributorTags !== void 0 && contributorTags.length) || !isDiffDecoration(decoration)) {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
var diffId = decoration.spec.diffId;
|
|
17
|
+
return contributorTags.find(function (tag) {
|
|
18
|
+
var _tag$linkedDiffIds;
|
|
19
|
+
return tag.diffId === diffId || ((_tag$linkedDiffIds = tag.linkedDiffIds) === null || _tag$linkedDiffIds === void 0 ? void 0 : _tag$linkedDiffIds.includes(diffId));
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* What a screen reader should say once the reader has stepped onto a change: where they are in the
|
|
25
|
+
* diff, and — when the plugin can credit the change — who made it. Stepping otherwise only scrolls,
|
|
26
|
+
* which is silent.
|
|
27
|
+
*
|
|
28
|
+
* Returns `undefined` for an index that resolves no change, so the caller says nothing at all
|
|
29
|
+
* rather than "Change 4 of 3".
|
|
30
|
+
*/
|
|
31
|
+
export var getActiveDiffAnnouncement = function getActiveDiffAnnouncement(_ref) {
|
|
32
|
+
var activeIndex = _ref.activeIndex,
|
|
33
|
+
contributorTags = _ref.contributorTags,
|
|
34
|
+
decorations = _ref.decorations,
|
|
35
|
+
intl = _ref.intl;
|
|
36
|
+
var activeDecoration = decorations[activeIndex];
|
|
37
|
+
if (!activeDecoration) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
var position = {
|
|
41
|
+
index: activeIndex + 1,
|
|
42
|
+
total: decorations.length
|
|
43
|
+
};
|
|
44
|
+
var tag = findTagFor(activeDecoration, contributorTags);
|
|
45
|
+
return tag ? intl.formatMessage(diffNavigationMessages.activeChangeWithContributor, _objectSpread(_objectSpread({}, position), {}, {
|
|
46
|
+
contributor: formatContributorLabel(tag, intl.formatMessage).fullLabel
|
|
47
|
+
})) : intl.formatMessage(diffNavigationMessages.activeChange, position);
|
|
48
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { defineMessages } from 'react-intl';
|
|
2
|
+
export var diffNavigationMessages = defineMessages({
|
|
3
|
+
activeChange: {
|
|
4
|
+
id: 'editor-plugin-show-diff.DiffNavigation.activeChange',
|
|
5
|
+
defaultMessage: 'Change {index} of {total}',
|
|
6
|
+
description: 'Announced to screen readers when the reader steps to the next or previous change in the version-history diff. The index placeholder is the position of the change stepped to, counting from 1; total is how many changes the diff has.'
|
|
7
|
+
},
|
|
8
|
+
activeChangeWithContributor: {
|
|
9
|
+
id: 'editor-plugin-show-diff.DiffNavigation.activeChangeWithContributor',
|
|
10
|
+
defaultMessage: 'Change {index} of {total}. {contributor}',
|
|
11
|
+
description: 'Announced to screen readers when the reader steps to the next or previous change in the version-history diff and that change is credited to someone. The index and total placeholders are as in activeChange. The contributor placeholder is an already-translated sentence (changedBy, changedByAgent or changedByConnected), so it must be kept whole and only repositioned.'
|
|
12
|
+
}
|
|
13
|
+
});
|
|
@@ -5,5 +5,18 @@ import type { ResolvedDiffContributors } from './colorSchemes/attributions';
|
|
|
5
5
|
* One model per diff decoration whose attribution resolves to a supplied contributor; anything
|
|
6
6
|
* unattributed, untaggable or unresolved is skipped. A replacement's two decorations are collapsed
|
|
7
7
|
* into a single tag, on whichever half renders first — see `isSameChange` and `leadsReplacement`.
|
|
8
|
+
*
|
|
9
|
+
* `activeIndexPos`, when given, reveals exactly one of the tags — see `resolveActiveTarget`.
|
|
10
|
+
* Absent, each tag keeps the active state its own decoration was drawn with.
|
|
11
|
+
*
|
|
12
|
+
* `stops`, when given, is the navigation stop list the step buttons walk
|
|
13
|
+
* (`getScrollableDecorations`). One contributor cannot hold two tags in one stop, since only the
|
|
14
|
+
* leading one would ever be reachable. Absent, every decoration keeps its own tag.
|
|
8
15
|
*/
|
|
9
|
-
export declare const extractContributorTags: (decorations: DecorationSet, contributors: ResolvedDiffContributors | undefined
|
|
16
|
+
export declare const extractContributorTags: (decorations: DecorationSet, contributors: ResolvedDiffContributors | undefined, activeIndexPos?: {
|
|
17
|
+
from: number;
|
|
18
|
+
to: number;
|
|
19
|
+
}, stops?: ReadonlyArray<{
|
|
20
|
+
from: number;
|
|
21
|
+
to: number;
|
|
22
|
+
}>) => ContributorTagModel[];
|
|
@@ -5,6 +5,7 @@ import { AttrStep } from '@atlaskit/editor-prosemirror/transform';
|
|
|
5
5
|
export type InlineAttrChangeNodeName = 'date' | 'emoji' | 'mention' | 'status';
|
|
6
6
|
type AttrChangeStep = AttrStep | SetAttrsStep;
|
|
7
7
|
export type AttrStepContext = {
|
|
8
|
+
attributionKey?: string;
|
|
8
9
|
afterNode: PMNode | null;
|
|
9
10
|
beforeNode: PMNode | null;
|
|
10
11
|
finalPos: number;
|
|
@@ -12,6 +13,8 @@ export type AttrStepContext = {
|
|
|
12
13
|
step: AttrChangeStep;
|
|
13
14
|
};
|
|
14
15
|
type StepRange = {
|
|
16
|
+
/** Attribution key for the step that produced this range. */
|
|
17
|
+
attributionKey?: string;
|
|
15
18
|
/**
|
|
16
19
|
* Position of the original (before) node in the original doc.
|
|
17
20
|
* Populated for inline attr changes (e.g. emoji, date) so the caller can
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { Step as ProseMirrorStep } from '@atlaskit/editor-prosemirror/transform-override';
|
|
2
|
+
import { type StepMap } from '@atlaskit/editor-prosemirror/transform';
|
|
3
|
+
import type { DiffStepAttribution } from '../../../showDiffPluginType';
|
|
2
4
|
type StepRange = {
|
|
5
|
+
attributionKey?: string;
|
|
3
6
|
fromB: number;
|
|
4
7
|
toB: number;
|
|
5
8
|
};
|
|
6
|
-
export declare const getMarkChangeRanges: (steps: ProseMirrorStep[]) => StepRange[];
|
|
9
|
+
export declare const getMarkChangeRanges: (steps: ProseMirrorStep[], stepAttributions?: Array<DiffStepAttribution | undefined>, stepMaps?: StepMap[]) => StepRange[];
|
|
7
10
|
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type StepMap } from '@atlaskit/editor-prosemirror/transform';
|
|
2
|
+
type StepRange = {
|
|
3
|
+
fromB: number;
|
|
4
|
+
toB: number;
|
|
5
|
+
};
|
|
6
|
+
/** Maps a step's range into final-document coordinates when the rollout path supplies step maps. */
|
|
7
|
+
export declare const mapStepRangeToFinal: (from: number, to: number, stepIndex: number, stepMaps?: StepMap[]) => StepRange | undefined;
|
|
8
|
+
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { StepJson } from '@atlaskit/editor-common/collab';
|
|
2
2
|
import type { NextEditorPlugin, EditorCommand, OptionalPlugin } from '@atlaskit/editor-common/types';
|
|
3
3
|
import type { JSONDocNode } from '@atlaskit/editor-json-transformer/types';
|
|
4
|
+
import type { AccessibilityUtilsPlugin } from '@atlaskit/editor-plugin-accessibility-utils';
|
|
4
5
|
import type { AnalyticsPlugin } from '@atlaskit/editor-plugin-analytics';
|
|
5
6
|
import type { UserIntentPlugin } from '@atlaskit/editor-plugin-user-intent';
|
|
6
7
|
import type { Node } from '@atlaskit/editor-prosemirror/model';
|
|
@@ -226,7 +227,12 @@ export type ShowDiffPlugin = NextEditorPlugin<'showDiff', {
|
|
|
226
227
|
scrollToPrevious: EditorCommand;
|
|
227
228
|
showDiff: (config: ShowDiffParams) => EditorCommand;
|
|
228
229
|
};
|
|
229
|
-
dependencies: [
|
|
230
|
+
dependencies: [
|
|
231
|
+
OptionalPlugin<AnalyticsPlugin>,
|
|
232
|
+
OptionalPlugin<UserIntentPlugin>,
|
|
233
|
+
/** Carries the live-region announcement made when stepping between changes. */
|
|
234
|
+
OptionalPlugin<AccessibilityUtilsPlugin>
|
|
235
|
+
];
|
|
230
236
|
pluginConfiguration: DiffParams | undefined;
|
|
231
237
|
sharedState: {
|
|
232
238
|
/**
|
|
@@ -34,13 +34,23 @@ export declare const CONTRIBUTOR_TAG_REVEALED_ATTRIBUTE = "data-revealed";
|
|
|
34
34
|
* number — hence the wide margin. Raise in step with that duration.
|
|
35
35
|
*/
|
|
36
36
|
export declare const TAG_EXIT_FALLBACK_MS = 1200;
|
|
37
|
+
/**
|
|
38
|
+
* The tooltip's look, inline rather than through `VANILLA_TOOLTIP_DEFAULT_CLASS`: this tooltip is
|
|
39
|
+
* hoisted out of the tag, and that class's rule is scoped under `.ProseMirror` — see
|
|
40
|
+
* `resolveTooltipContainer`. Otherwise `vanillaTooltipDefaultStyles` in editor-core, which is the
|
|
41
|
+
* look every other vanilla tooltip has; keep the two in step.
|
|
42
|
+
*/
|
|
43
|
+
export declare const CONTRIBUTOR_TAG_TOOLTIP_STYLES: Readonly<Record<string, string>>;
|
|
37
44
|
export type ContributorTagDom = {
|
|
38
45
|
avatars: HTMLSpanElement;
|
|
39
46
|
name: HTMLSpanElement;
|
|
40
47
|
root: HTMLSpanElement;
|
|
41
48
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
49
|
+
* The tag's single announcement: it names the tag via `aria-labelledby` and is the only child
|
|
50
|
+
* left in the accessibility tree.
|
|
51
|
+
*
|
|
52
|
+
* `VanillaTooltip` appends its popover to the tag as well, so this is the last *content* child
|
|
53
|
+
* rather than the last node.
|
|
44
54
|
*/
|
|
45
55
|
srLabel: HTMLSpanElement;
|
|
46
56
|
tag: HTMLSpanElement;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { IntlShape } from 'react-intl';
|
|
2
|
+
import type { ContributorTagModel } from '../../showDiffPluginType';
|
|
3
|
+
export type ContributorLabel = {
|
|
4
|
+
/** One sentence crediting everyone the change is attributed to — the tag's announcement. */
|
|
5
|
+
fullLabel: string;
|
|
6
|
+
/** The name the tag paints, which `MAX_TAG_WIDTH` may ellipsise. */
|
|
7
|
+
visibleName: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* The two strings a tag's model resolves to. Shared with `getActiveDiffAnnouncement`, so stepping
|
|
11
|
+
* onto a change says the same sentence as the tag pinned to it rather than a copy free to drift.
|
|
12
|
+
*/
|
|
13
|
+
export declare const formatContributorLabel: (model: ContributorTagModel, formatMessage: IntlShape['formatMessage']) => ContributorLabel;
|
|
@@ -91,6 +91,17 @@ export declare class ContributorTagController {
|
|
|
91
91
|
* shape of `syncVanillaDisabledTooltip` in `mentionNodeView`.
|
|
92
92
|
*/
|
|
93
93
|
private syncTooltip;
|
|
94
|
+
/**
|
|
95
|
+
* Where the tooltip is appended, rather than inside the tag.
|
|
96
|
+
*
|
|
97
|
+
* Popper and the browser only agree on a top-layer popover's origin when nothing above it is
|
|
98
|
+
* transformed, and the tag hangs under the editor's own transformed nodes — inside a wide image
|
|
99
|
+
* that is `.rich-media-item`, whose `translateX(-50%)` threw the tooltip off screen
|
|
100
|
+
* (EDITOR-8971). The content area is the nearest ancestor with none of that above it, and keeps
|
|
101
|
+
* the tooltip inside the editor it belongs to; the document body covers an appearance that has
|
|
102
|
+
* no content area.
|
|
103
|
+
*/
|
|
104
|
+
private resolveTooltipContainer;
|
|
94
105
|
/**
|
|
95
106
|
* Observes the highlight this tag describes, for what CSS here cannot see: its hover state. The
|
|
96
107
|
* highlight is a ProseMirror decoration in a different DOM subtree, so listeners are bound
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { IntlShape } from 'react-intl';
|
|
2
|
+
import type { Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
3
|
+
import type { ContributorTagModel } from '../../showDiffPluginType';
|
|
4
|
+
/**
|
|
5
|
+
* What a screen reader should say once the reader has stepped onto a change: where they are in the
|
|
6
|
+
* diff, and — when the plugin can credit the change — who made it. Stepping otherwise only scrolls,
|
|
7
|
+
* which is silent.
|
|
8
|
+
*
|
|
9
|
+
* Returns `undefined` for an index that resolves no change, so the caller says nothing at all
|
|
10
|
+
* rather than "Change 4 of 3".
|
|
11
|
+
*/
|
|
12
|
+
export declare const getActiveDiffAnnouncement: ({ activeIndex, contributorTags, decorations, intl, }: {
|
|
13
|
+
activeIndex: number;
|
|
14
|
+
contributorTags: ContributorTagModel[] | undefined;
|
|
15
|
+
/** The navigable changes, in document order — `getScrollableDecorations`'s result. */
|
|
16
|
+
decorations: Decoration[];
|
|
17
|
+
intl: IntlShape;
|
|
18
|
+
}) => string | undefined;
|
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.3",
|
|
4
4
|
"description": "ShowDiff plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"@atlaskit/adf-schema": "^57.4.0",
|
|
24
24
|
"@atlaskit/avatar": "^28.0.0",
|
|
25
25
|
"@atlaskit/custom-steps": "^1.1.0",
|
|
26
|
+
"@atlaskit/editor-plugin-accessibility-utils": "^18.0.0",
|
|
26
27
|
"@atlaskit/editor-plugin-analytics": "^18.0.0",
|
|
27
28
|
"@atlaskit/editor-plugin-user-intent": "^16.0.0",
|
|
28
29
|
"@atlaskit/editor-prosemirror": "^8.0.0",
|
|
@@ -31,7 +32,7 @@
|
|
|
31
32
|
"@atlaskit/platform-feature-experiments": "^0.3.0",
|
|
32
33
|
"@atlaskit/platform-feature-flags": "^2.2.0",
|
|
33
34
|
"@atlaskit/primitives": "^22.5.0",
|
|
34
|
-
"@atlaskit/tmp-editor-statsig": "^
|
|
35
|
+
"@atlaskit/tmp-editor-statsig": "^190.0.0",
|
|
35
36
|
"@atlaskit/tokens": "^16.12.0",
|
|
36
37
|
"@babel/runtime": "^7.0.0",
|
|
37
38
|
"@compiled/react": "^1.0.2",
|
|
@@ -45,7 +46,7 @@
|
|
|
45
46
|
"@atlaskit/button": "^25.3.0",
|
|
46
47
|
"@atlaskit/css": "^1.1.0",
|
|
47
48
|
"@atlaskit/dropdown-menu": "^18.3.0",
|
|
48
|
-
"@atlaskit/editor-core": "^228.
|
|
49
|
+
"@atlaskit/editor-core": "^228.1.0",
|
|
49
50
|
"@atlaskit/editor-json-transformer": "^9.8.0",
|
|
50
51
|
"@atlaskit/editor-plugins": "^16.1.0",
|
|
51
52
|
"@atlaskit/form": "^17.2.0",
|
|
@@ -63,7 +64,7 @@
|
|
|
63
64
|
"react-intl": "^7.0.0"
|
|
64
65
|
},
|
|
65
66
|
"peerDependencies": {
|
|
66
|
-
"@atlaskit/editor-common": "^122.
|
|
67
|
+
"@atlaskit/editor-common": "^122.3.0",
|
|
67
68
|
"react": "^18.2.0 || ^19.2.0",
|
|
68
69
|
"react-dom": "^18.2.0 || ^19.2.0",
|
|
69
70
|
"react-intl": "^5.25.1 || ^6.0.0 || ^7.0.0"
|