@atlaskit/editor-plugin-show-diff 15.1.6 → 15.1.7
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 +35 -0
- package/dist/cjs/pm-plugins/calculateDiff/calculateDiffDecorations.js +5 -4
- package/dist/cjs/pm-plugins/decorations/colorSchemes/factory.js +25 -4
- package/dist/cjs/pm-plugins/decorations/createInlineChangedDecoration.js +40 -14
- package/dist/cjs/pm-plugins/decorations/utils/wrapBlockNodeView.js +14 -0
- package/dist/cjs/ui/ContributorTag/buildContributorTagDom.js +70 -14
- package/dist/cjs/ui/ContributorTag/contributorTagController.js +169 -150
- package/dist/es2019/pm-plugins/calculateDiff/calculateDiffDecorations.js +5 -4
- package/dist/es2019/pm-plugins/decorations/colorSchemes/factory.js +25 -4
- package/dist/es2019/pm-plugins/decorations/createInlineChangedDecoration.js +40 -14
- package/dist/es2019/pm-plugins/decorations/utils/wrapBlockNodeView.js +14 -0
- package/dist/es2019/ui/ContributorTag/buildContributorTagDom.js +69 -13
- package/dist/es2019/ui/ContributorTag/contributorTagController.js +164 -104
- package/dist/esm/pm-plugins/calculateDiff/calculateDiffDecorations.js +5 -4
- package/dist/esm/pm-plugins/decorations/colorSchemes/factory.js +25 -4
- package/dist/esm/pm-plugins/decorations/createInlineChangedDecoration.js +40 -14
- package/dist/esm/pm-plugins/decorations/utils/wrapBlockNodeView.js +14 -0
- package/dist/esm/ui/ContributorTag/buildContributorTagDom.js +69 -13
- package/dist/esm/ui/ContributorTag/contributorTagController.js +171 -152
- package/dist/types/pm-plugins/decorations/colorSchemes/factory.d.ts +8 -2
- package/dist/types/ui/ContributorTag/buildContributorTagDom.d.ts +32 -3
- package/dist/types/ui/ContributorTag/contributorTagController.d.ts +32 -12
- package/package.json +2 -2
|
@@ -2,14 +2,11 @@ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
|
2
2
|
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
3
3
|
import _createClass from "@babel/runtime/helpers/createClass";
|
|
4
4
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
5
|
-
|
|
6
|
-
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
7
|
-
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
8
|
-
import { bindAll } from 'bind-event-listener';
|
|
5
|
+
import { bind, bindAll } from 'bind-event-listener';
|
|
9
6
|
import { VanillaTooltip } from '@atlaskit/editor-common/vanilla-tooltip';
|
|
10
7
|
import { getAccentTokens } from '../../pm-plugins/decorations/colorSchemes/factory';
|
|
11
8
|
import { colorSchemeRegistry } from '../../pm-plugins/decorations/colorSchemes/schemes';
|
|
12
|
-
import { buildContributorTagDom,
|
|
9
|
+
import { buildContributorTagDom, CONTRIBUTOR_TAG_REVEALED_ATTRIBUTE, TAG_EXIT_FALLBACK_MS } from './buildContributorTagDom';
|
|
13
10
|
import { contributorAvatarRenderer } from './contributorAvatarRenderer';
|
|
14
11
|
import { contributorTagMessages } from './messages';
|
|
15
12
|
var getContributorName = function getContributorName(contributor, formatMessage) {
|
|
@@ -28,8 +25,8 @@ var getContributorName = function getContributorName(contributor, formatMessage)
|
|
|
28
25
|
};
|
|
29
26
|
|
|
30
27
|
/**
|
|
31
|
-
* Resolves the tag's accent from the same scheme value
|
|
32
|
-
* two can never drift.
|
|
28
|
+
* Resolves the tag's accent from the same scheme value the highlight was drawn from, so the colour
|
|
29
|
+
* the two carry can never drift — only the tone does, which is `getAccentTokens`'s to pick.
|
|
33
30
|
*/
|
|
34
31
|
var getTagAccent = function getTagAccent(_ref) {
|
|
35
32
|
var colorScheme = _ref.colorScheme,
|
|
@@ -40,35 +37,70 @@ var getTagAccent = function getTagAccent(_ref) {
|
|
|
40
37
|
return getAccentTokens(accent);
|
|
41
38
|
};
|
|
42
39
|
|
|
43
|
-
/**
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Keyboard focus, as a member of `revealSources` alongside the elements the pointer can be over. It
|
|
42
|
+
* has no element of its own to key on — the tag is already in the set under its own hover.
|
|
43
|
+
*/
|
|
44
|
+
var FOCUS_SOURCE = Symbol('contributor-tag-focus');
|
|
45
|
+
|
|
46
|
+
/** Moves the tag between the two ends of the fade `contributorTagStyles` declares. */
|
|
47
|
+
var setRevealed = function setRevealed(tag, isVisible) {
|
|
48
|
+
tag.toggleAttribute(CONTRIBUTOR_TAG_REVEALED_ATTRIBUTE, isVisible);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Whether flipping the tag's state will actually run a transition on it.
|
|
53
|
+
*
|
|
54
|
+
* Asked of the element rather than of `matchMedia`, because reduced motion and a missing stylesheet
|
|
55
|
+
* both compute to a zero duration — and a transition that never starts fires no `transitionend`, so
|
|
56
|
+
* a tag waiting for one would sit on screen until the backstop timeout.
|
|
57
|
+
*
|
|
58
|
+
* Read only when a tag is being taken down: it resolves style.
|
|
59
|
+
*/
|
|
60
|
+
var willTransition = function willTransition(tag) {
|
|
61
|
+
return window.getComputedStyle(tag).transitionDuration.split(',').some(function (duration) {
|
|
62
|
+
return parseFloat(duration) > 0;
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Fades a tag that is still on screen out, and releases it once the fade has finished.
|
|
68
|
+
*
|
|
69
|
+
* No controller owns the element by the time this runs — it is released up front so a republished
|
|
70
|
+
* model's tag can fade in over the top — so everything the removal needs is captured here.
|
|
71
|
+
*/
|
|
72
|
+
var fadeTagOut = function fadeTagOut(tag, release) {
|
|
73
|
+
setRevealed(tag, false);
|
|
74
|
+
|
|
75
|
+
// Nothing to wait for: reduced motion, or no stylesheet to fade it with.
|
|
76
|
+
if (!willTransition(tag)) {
|
|
77
|
+
release();
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
var unbind;
|
|
81
|
+
var isFinished = false;
|
|
82
|
+
var finish = function finish() {
|
|
83
|
+
var _unbind;
|
|
84
|
+
// Whichever of the two signals arrives first wins; the other must not release twice.
|
|
85
|
+
if (isFinished) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
isFinished = true;
|
|
89
|
+
(_unbind = unbind) === null || _unbind === void 0 || _unbind();
|
|
90
|
+
unbind = undefined;
|
|
91
|
+
clearTimeout(fallbackId);
|
|
92
|
+
release();
|
|
93
|
+
};
|
|
94
|
+
unbind = bind(tag, {
|
|
95
|
+
type: 'transitionend',
|
|
96
|
+
// `transitionend` bubbles, and opacity is not the only property that could ever carry one.
|
|
97
|
+
listener: function listener(event) {
|
|
98
|
+
if (event.target === tag && event.propertyName === 'opacity') {
|
|
99
|
+
finish();
|
|
64
100
|
}
|
|
65
101
|
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
} finally {
|
|
69
|
-
_iterator.f();
|
|
70
|
-
}
|
|
71
|
-
return start;
|
|
102
|
+
});
|
|
103
|
+
var fallbackId = setTimeout(finish, TAG_EXIT_FALLBACK_MS);
|
|
72
104
|
};
|
|
73
105
|
|
|
74
106
|
/** The contributors a tag draws, keyed so a republished model can be recognised as the same pair. */
|
|
@@ -97,8 +129,18 @@ export var ContributorTagController = /*#__PURE__*/function () {
|
|
|
97
129
|
_defineProperty(this, "bindToken", 0);
|
|
98
130
|
_defineProperty(this, "fullLabel", '');
|
|
99
131
|
_defineProperty(this, "isDestroyed", false);
|
|
100
|
-
|
|
101
|
-
_defineProperty(this, "
|
|
132
|
+
/** Last visibility written, so a teardown knows whether there is anything on screen to fade. */
|
|
133
|
+
_defineProperty(this, "isVisible", false);
|
|
134
|
+
/**
|
|
135
|
+
* Everything currently asking for the tag to be up, other than the model: each hovered highlight,
|
|
136
|
+
* the tag itself while the pointer is on it, and `FOCUS_SOURCE` while it holds focus.
|
|
137
|
+
*
|
|
138
|
+
* One set rather than independent booleans, which is what let the exit's trailing delay go: a
|
|
139
|
+
* pointer crossing from the highlight onto the tag removes one member and adds another in the same
|
|
140
|
+
* dispatch, so no style is resolved in between and the browser never starts the exit. Booleans
|
|
141
|
+
* could not see each other, so the crossing wrote the tag out and straight back in.
|
|
142
|
+
*/
|
|
143
|
+
_defineProperty(this, "revealSources", new Set());
|
|
102
144
|
_defineProperty(this, "unbindHighlights", []);
|
|
103
145
|
this.options = options;
|
|
104
146
|
}
|
|
@@ -160,65 +202,101 @@ export var ContributorTagController = /*#__PURE__*/function () {
|
|
|
160
202
|
this.renderLabels(next);
|
|
161
203
|
this.applyAccent(next);
|
|
162
204
|
this.syncHighlightBindings(next);
|
|
163
|
-
this.
|
|
205
|
+
this.applyVisibility();
|
|
164
206
|
this.syncTooltip();
|
|
165
207
|
}
|
|
166
208
|
|
|
167
|
-
/**
|
|
209
|
+
/**
|
|
210
|
+
* Takes the tag's DOM down, keeping the subscription so a republished model redraws it.
|
|
211
|
+
*
|
|
212
|
+
* A tag that is still on screen is released here and fades out on its own, so a republished
|
|
213
|
+
* model's tag fades in over the top of the outgoing one — see `fadeTagOut`.
|
|
214
|
+
*/
|
|
168
215
|
}, {
|
|
169
216
|
key: "teardownTag",
|
|
170
217
|
value: function teardownTag() {
|
|
171
|
-
var _this$unbindTag, _this$tooltip
|
|
218
|
+
var _this$unbindTag, _this$tooltip;
|
|
219
|
+
// Unbound synchronously, ahead of any fade: a tag on its way out must not be revealed again by
|
|
220
|
+
// the pointer, and these listeners are what hold this controller.
|
|
172
221
|
this.unbindHighlightState();
|
|
173
222
|
this.boundSelector = undefined;
|
|
174
223
|
(_this$unbindTag = this.unbindTag) === null || _this$unbindTag === void 0 || _this$unbindTag.call(this);
|
|
175
224
|
this.unbindTag = undefined;
|
|
225
|
+
// Destroyed rather than carried through the fade: it is a popover in the top layer.
|
|
176
226
|
(_this$tooltip = this.tooltip) === null || _this$tooltip === void 0 || _this$tooltip.destroy();
|
|
177
227
|
this.tooltip = undefined;
|
|
178
228
|
this.tooltipContent = undefined;
|
|
179
|
-
this.
|
|
180
|
-
|
|
181
|
-
|
|
229
|
+
var dom = this.dom,
|
|
230
|
+
isVisible = this.isVisible;
|
|
231
|
+
// Destroying an avatar removes its element, so the avatars go with whoever removes the tag —
|
|
232
|
+
// destroyed here and it would fade out empty.
|
|
233
|
+
var avatars = this.avatars;
|
|
182
234
|
this.avatars = [];
|
|
183
|
-
(_this$dom = this.dom) === null || _this$dom === void 0 || _this$dom.root.remove();
|
|
184
235
|
this.dom = undefined;
|
|
185
|
-
this.
|
|
186
|
-
|
|
187
|
-
//
|
|
188
|
-
|
|
189
|
-
|
|
236
|
+
this.isVisible = false;
|
|
237
|
+
// The set belongs to the listeners just unbound: a stale member would draw the tag as visible
|
|
238
|
+
// with the pointer nowhere near it.
|
|
239
|
+
this.revealSources.clear();
|
|
240
|
+
if (!dom) {
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
var release = function release() {
|
|
244
|
+
avatars.forEach(function (avatar) {
|
|
245
|
+
return avatar.destroy();
|
|
246
|
+
});
|
|
247
|
+
dom.root.remove();
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
// Nothing on screen to fade. `isConnected` covers ProseMirror destroying the widget: a fade on
|
|
251
|
+
// a detached element never starts.
|
|
252
|
+
if (!isVisible || !dom.tag.isConnected) {
|
|
253
|
+
release();
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
fadeTagOut(dom.tag, release);
|
|
190
257
|
}
|
|
191
258
|
}, {
|
|
192
259
|
key: "bindTag",
|
|
193
260
|
value: function bindTag(_ref4) {
|
|
194
|
-
var _this3 = this;
|
|
195
261
|
var tag = _ref4.tag;
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
_this3.applyStyles();
|
|
200
|
-
};
|
|
201
|
-
};
|
|
262
|
+
// `mouseover`/`mouseout` rather than the enter/leave pair, because they are what fire as the
|
|
263
|
+
// pointer moves between the tag's own children. Both are keyed on the tag, so those moves add
|
|
264
|
+
// and remove the same member and the set never empties.
|
|
202
265
|
this.unbindTag = bindAll(tag, [{
|
|
203
266
|
type: 'mouseover',
|
|
204
|
-
listener:
|
|
267
|
+
listener: this.trackRevealSource(tag, true)
|
|
205
268
|
}, {
|
|
206
269
|
type: 'mouseout',
|
|
207
|
-
listener:
|
|
270
|
+
listener: this.trackRevealSource(tag, false)
|
|
208
271
|
}, {
|
|
209
272
|
type: 'focus',
|
|
210
|
-
listener:
|
|
273
|
+
listener: this.trackRevealSource(FOCUS_SOURCE, true)
|
|
211
274
|
}, {
|
|
212
275
|
type: 'blur',
|
|
213
|
-
listener:
|
|
276
|
+
listener: this.trackRevealSource(FOCUS_SOURCE, false)
|
|
214
277
|
}]);
|
|
215
278
|
}
|
|
279
|
+
|
|
280
|
+
/** One listener shape for every reveal source, so all of them land in the same set. */
|
|
281
|
+
}, {
|
|
282
|
+
key: "trackRevealSource",
|
|
283
|
+
value: function trackRevealSource(source, isRevealing) {
|
|
284
|
+
var _this3 = this;
|
|
285
|
+
return function () {
|
|
286
|
+
if (isRevealing) {
|
|
287
|
+
_this3.revealSources.add(source);
|
|
288
|
+
} else {
|
|
289
|
+
_this3.revealSources.delete(source);
|
|
290
|
+
}
|
|
291
|
+
_this3.applyVisibility();
|
|
292
|
+
};
|
|
293
|
+
}
|
|
216
294
|
}, {
|
|
217
295
|
key: "renderAvatars",
|
|
218
296
|
value: function renderAvatars(model) {
|
|
219
|
-
var _this$
|
|
297
|
+
var _this$dom,
|
|
220
298
|
_this4 = this;
|
|
221
|
-
var _ref5 = (_this$
|
|
299
|
+
var _ref5 = (_this$dom = this.dom) !== null && _this$dom !== void 0 ? _this$dom : {},
|
|
222
300
|
container = _ref5.avatars;
|
|
223
301
|
if (!container) {
|
|
224
302
|
return;
|
|
@@ -278,8 +356,8 @@ export var ContributorTagController = /*#__PURE__*/function () {
|
|
|
278
356
|
var agentName = isPrimaryAgent ? primaryName : secondaryName;
|
|
279
357
|
var userName = isPrimaryAgent ? secondaryName : primaryName;
|
|
280
358
|
|
|
281
|
-
// A connected pair only ever shows the agent; the pair is spelled out in the label, because
|
|
282
|
-
//
|
|
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.
|
|
283
361
|
this.dom.name.textContent = model.connectedContributor ? agentName || primaryName : primaryName;
|
|
284
362
|
this.fullLabel = model.connectedContributor ? formatMessage(contributorTagMessages.changedByConnected, {
|
|
285
363
|
agentName: agentName,
|
|
@@ -307,34 +385,34 @@ export var ContributorTagController = /*#__PURE__*/function () {
|
|
|
307
385
|
}
|
|
308
386
|
var accent = this.accentOf(model);
|
|
309
387
|
this.dom.tag.style.setProperty('background-color', accent.background);
|
|
310
|
-
this.dom.tag.style.setProperty('border-bottom-color', accent.border);
|
|
311
388
|
this.dom.name.style.setProperty('color', accent.text);
|
|
312
389
|
this.avatars.forEach(function (avatar) {
|
|
313
390
|
return avatar.setRingColor(accent.background);
|
|
314
391
|
});
|
|
315
392
|
}
|
|
316
393
|
|
|
317
|
-
/**
|
|
394
|
+
/**
|
|
395
|
+
* Visibility — the one thing the model does not carry on its own, because hover is not in it.
|
|
396
|
+
*
|
|
397
|
+
* One idempotent attribute write, with nothing to guard: whether the flip is a real one, whether
|
|
398
|
+
* the tag is attached yet, and whether motion is wanted at all are all the stylesheet's to answer.
|
|
399
|
+
*/
|
|
318
400
|
}, {
|
|
319
|
-
key: "
|
|
320
|
-
value: function
|
|
401
|
+
key: "applyVisibility",
|
|
402
|
+
value: function applyVisibility() {
|
|
321
403
|
var _this$model;
|
|
322
404
|
if (!this.dom) {
|
|
323
405
|
return;
|
|
324
406
|
}
|
|
325
|
-
this.
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
this.maxWidthPx === undefined ? '' : "max(".concat(Math.round(this.maxWidthPx), "px, ").concat(MIN_TAG_WIDTH, ")"));
|
|
329
|
-
var isVisible = Boolean((_this$model = this.model) === null || _this$model === void 0 ? void 0 : _this$model.isActive) || this.isHighlightHovered || this.isHoveredOrFocused;
|
|
330
|
-
this.dom.tag.style.setProperty('opacity', isVisible ? '1' : '0');
|
|
331
|
-
this.dom.tag.style.setProperty('pointer-events', isVisible ? 'auto' : 'none');
|
|
407
|
+
var isVisible = Boolean((_this$model = this.model) === null || _this$model === void 0 ? void 0 : _this$model.isActive) || this.revealSources.size > 0;
|
|
408
|
+
this.isVisible = isVisible;
|
|
409
|
+
setRevealed(this.dom.tag, isVisible);
|
|
332
410
|
}
|
|
333
411
|
|
|
334
412
|
/**
|
|
335
|
-
* The full label is always the tooltip, whether or not the name it draws is clipped:
|
|
336
|
-
*
|
|
337
|
-
*
|
|
413
|
+
* The full label is always the tooltip, whether or not the name it draws is clipped: a name longer
|
|
414
|
+
* than `MAX_TAG_WIDTH` is ellipsised, and a connected pair spells out a contributor the tag does
|
|
415
|
+
* not show at any width.
|
|
338
416
|
*
|
|
339
417
|
* `VanillaTooltip` has no "set new content" call, so it is rebuilt when the label changes — the
|
|
340
418
|
* shape of `syncVanillaDisabledTooltip` in `mentionNodeView`.
|
|
@@ -365,9 +443,9 @@ export var ContributorTagController = /*#__PURE__*/function () {
|
|
|
365
443
|
}
|
|
366
444
|
|
|
367
445
|
/**
|
|
368
|
-
* Observes the highlight this tag describes, for what CSS here cannot see: its hover state
|
|
446
|
+
* Observes the highlight this tag describes, for what CSS here cannot see: its hover state. The
|
|
369
447
|
* highlight is a ProseMirror decoration in a different DOM subtree, so listeners are bound
|
|
370
|
-
* imperatively via `data-diff-id
|
|
448
|
+
* imperatively via `data-diff-id`.
|
|
371
449
|
*
|
|
372
450
|
* Deliberately not routed through plugin state: a transaction per pointer move would re-run the
|
|
373
451
|
* memoised decoration calculation.
|
|
@@ -387,8 +465,8 @@ export var ContributorTagController = /*#__PURE__*/function () {
|
|
|
387
465
|
this.boundSelector = selector;
|
|
388
466
|
this.unbindHighlightState();
|
|
389
467
|
|
|
390
|
-
// ProseMirror draws the tag's host in the same pass as the highlights
|
|
391
|
-
//
|
|
468
|
+
// ProseMirror draws the tag's host in the same pass as the highlights it binds to, so those may
|
|
469
|
+
// not be in the document yet. A microtask lands once that pass has finished.
|
|
392
470
|
var pendingBind = ++this.bindToken;
|
|
393
471
|
queueMicrotask(function () {
|
|
394
472
|
if (!_this5.isDestroyed && pendingBind === _this5.bindToken) {
|
|
@@ -399,91 +477,32 @@ export var ContributorTagController = /*#__PURE__*/function () {
|
|
|
399
477
|
}, {
|
|
400
478
|
key: "bindHighlightState",
|
|
401
479
|
value: function bindHighlightState(selector) {
|
|
402
|
-
var
|
|
403
|
-
|
|
404
|
-
//
|
|
405
|
-
// inside this one, cannot
|
|
406
|
-
|
|
407
|
-
var highlights =
|
|
408
|
-
if (!
|
|
480
|
+
var _this$options$getEdit,
|
|
481
|
+
_this6 = this;
|
|
482
|
+
// Scoped to this editor's content root, so a tag can only ever bind to the decorations its own
|
|
483
|
+
// plugin instance rendered — another editor on the page, or one nested inside this one, cannot
|
|
484
|
+
// reveal this tag.
|
|
485
|
+
var highlights = (_this$options$getEdit = this.options.getEditorRoot()) === null || _this$options$getEdit === void 0 ? void 0 : _this$options$getEdit.querySelectorAll(selector);
|
|
486
|
+
if (!(highlights !== null && highlights !== void 0 && highlights.length)) {
|
|
409
487
|
return;
|
|
410
488
|
}
|
|
411
489
|
|
|
412
|
-
//
|
|
413
|
-
//
|
|
414
|
-
|
|
415
|
-
var measure = function measure() {
|
|
416
|
-
var _findChangeStartLine;
|
|
417
|
-
// Counted by distinct line box, not by client rect: an inline node inside the change (a
|
|
418
|
-
// mention, emoji, date) splits the highlight into several rects on the same line, and
|
|
419
|
-
// treating that as a wrap would drop the width clamp on changes that never wrapped.
|
|
420
|
-
var lineTops = new Set();
|
|
421
|
-
for (var _i = 0, _ownElements = ownElements; _i < _ownElements.length; _i++) {
|
|
422
|
-
var highlight = _ownElements[_i];
|
|
423
|
-
var _iterator3 = _createForOfIteratorHelper(highlight.getClientRects()),
|
|
424
|
-
_step3;
|
|
425
|
-
try {
|
|
426
|
-
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
427
|
-
var rect = _step3.value;
|
|
428
|
-
lineTops.add(Math.round(rect.top));
|
|
429
|
-
}
|
|
430
|
-
} catch (err) {
|
|
431
|
-
_iterator3.e(err);
|
|
432
|
-
} finally {
|
|
433
|
-
_iterator3.f();
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
// A wrapped change's first line says nothing useful about how wide the tag may be.
|
|
438
|
-
_this6.maxWidthPx = lineTops.size > 1 ? undefined : (_findChangeStartLine = findChangeStartLine(ownElements)) === null || _findChangeStartLine === void 0 ? void 0 : _findChangeStartLine.width;
|
|
439
|
-
_this6.applyStyles();
|
|
440
|
-
};
|
|
441
|
-
measure();
|
|
442
|
-
|
|
443
|
-
// An inline element cannot be observed itself (ResizeObserver skips boxes with no principal
|
|
444
|
-
// box), so the block it sits in is observed instead.
|
|
445
|
-
this.resizeObserver = new ResizeObserver(measure);
|
|
446
|
-
var _iterator4 = _createForOfIteratorHelper(new Set(ownElements.map(function (_ref7) {
|
|
447
|
-
var parentElement = _ref7.parentElement;
|
|
448
|
-
return parentElement;
|
|
449
|
-
}))),
|
|
450
|
-
_step4;
|
|
451
|
-
try {
|
|
452
|
-
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
453
|
-
var parent = _step4.value;
|
|
454
|
-
if (parent) {
|
|
455
|
-
this.resizeObserver.observe(parent);
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
// `bindAll` takes a single target, and a change can render more than one highlight.
|
|
460
|
-
} catch (err) {
|
|
461
|
-
_iterator4.e(err);
|
|
462
|
-
} finally {
|
|
463
|
-
_iterator4.f();
|
|
464
|
-
}
|
|
490
|
+
// `bindAll` takes a single target, and a change can render more than one highlight. Each is its
|
|
491
|
+
// own member of `revealSources`, so the pointer can cross between them without the set
|
|
492
|
+
// emptying.
|
|
465
493
|
this.unbindHighlights = Array.from(highlights).map(function (highlight) {
|
|
466
494
|
return bindAll(highlight, [{
|
|
467
495
|
type: 'mouseenter',
|
|
468
|
-
listener:
|
|
469
|
-
_this6.isHighlightHovered = true;
|
|
470
|
-
_this6.applyStyles();
|
|
471
|
-
}
|
|
496
|
+
listener: _this6.trackRevealSource(highlight, true)
|
|
472
497
|
}, {
|
|
473
498
|
type: 'mouseleave',
|
|
474
|
-
listener:
|
|
475
|
-
_this6.isHighlightHovered = false;
|
|
476
|
-
_this6.applyStyles();
|
|
477
|
-
}
|
|
499
|
+
listener: _this6.trackRevealSource(highlight, false)
|
|
478
500
|
}]);
|
|
479
501
|
});
|
|
480
502
|
}
|
|
481
503
|
}, {
|
|
482
504
|
key: "unbindHighlightState",
|
|
483
505
|
value: function unbindHighlightState() {
|
|
484
|
-
var _this$resizeObserver;
|
|
485
|
-
(_this$resizeObserver = this.resizeObserver) === null || _this$resizeObserver === void 0 || _this$resizeObserver.disconnect();
|
|
486
|
-
this.resizeObserver = undefined;
|
|
487
506
|
this.unbindHighlights.forEach(function (unbind) {
|
|
488
507
|
return unbind();
|
|
489
508
|
});
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import type { AdsAccentColor, DiffColorScheme } from './types';
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* Presentation tokens for a contributor tag in one diff colour.
|
|
4
|
+
*
|
|
5
|
+
* A `bolder` fill rather than the `subtlest` tint the highlight uses: the tag is a label on the
|
|
6
|
+
* change, and at tag size a tint reads as a second, weaker highlight sitting above the real one.
|
|
7
|
+
* `inverse` is the only text tone that reads on a bolder fill, and it needs no per-colour map —
|
|
8
|
+
* which is also why the tag carries no border: the fill alone bounds it.
|
|
9
|
+
*/
|
|
3
10
|
export declare function getAccentTokens(color: AdsAccentColor): {
|
|
4
11
|
background: string;
|
|
5
|
-
border: string;
|
|
6
12
|
text: string;
|
|
7
13
|
};
|
|
8
14
|
/** Inline inserted content — default state. */
|
|
@@ -1,10 +1,39 @@
|
|
|
1
1
|
export declare const CONTRIBUTOR_TAG_TESTID = "diff-contributor-tag";
|
|
2
2
|
export declare const CONTRIBUTOR_TAG_NAME_TESTID = "diff-contributor-tag-name";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Ceiling for the tag width. A constant rather than the width of the change: a change is routinely a
|
|
5
|
+
* word or two, and clamping to it ellipsised the contributor's name — the one thing the tag exists to
|
|
6
|
+
* show. Longer names are ellipsised into the tooltip.
|
|
6
7
|
*/
|
|
7
|
-
export declare const
|
|
8
|
+
export declare const MAX_TAG_WIDTH = "200px";
|
|
9
|
+
/**
|
|
10
|
+
* The tag sits on the line above the change, so it has to paint over that line to be readable —
|
|
11
|
+
* including any diff highlight already on it, which would otherwise slice straight through the tag.
|
|
12
|
+
* Hence one level above `akEditorUnitZIndex`, where the highlights sit; exported because the
|
|
13
|
+
* change's own highlight is stacked one level below it — see `stackBelowContributorTagStyle` in
|
|
14
|
+
* `createInlineChangedDecoration`.
|
|
15
|
+
*
|
|
16
|
+
* Painting above its own highlight is only safe because the tag can never reach it: `bottom: 100%`
|
|
17
|
+
* puts the root's bottom edge exactly on the highlight's top edge, and the root's `overflow: clip`
|
|
18
|
+
* keeps every pixel the tag paints inside it.
|
|
19
|
+
*/
|
|
20
|
+
export declare const CONTRIBUTOR_TAG_Z_INDEX = 2;
|
|
21
|
+
/**
|
|
22
|
+
* The plugin's whole side of the tag's motion: the fade and the hidden state are
|
|
23
|
+
* `contributorTagStyles` in both EditorContentContainer stylesheets, keyed on this literal and the
|
|
24
|
+
* one below — rename in step. This package cannot import `@atlaskit/editor-core` at runtime, so the
|
|
25
|
+
* plugin emits the hook and editor-core owns the rule, as `VanillaTooltip` does with
|
|
26
|
+
* `VANILLA_TOOLTIP_DEFAULT_CLASS`.
|
|
27
|
+
*/
|
|
28
|
+
export declare const CONTRIBUTOR_TAG_CLASS = "ak-editor-diff-contributor-tag";
|
|
29
|
+
/** Toggled by the controller to move the tag between the fade's two ends. */
|
|
30
|
+
export declare const CONTRIBUTOR_TAG_REVEALED_ATTRIBUTE = "data-revealed";
|
|
31
|
+
/**
|
|
32
|
+
* Backstop for removing a fading-out tag: a cancelled transition fires no `transitionend`. Must stay
|
|
33
|
+
* above the fade's 600ms, which lives in another package's stylesheet and cannot be read back as a
|
|
34
|
+
* number — hence the wide margin. Raise in step with that duration.
|
|
35
|
+
*/
|
|
36
|
+
export declare const TAG_EXIT_FALLBACK_MS = 1200;
|
|
8
37
|
export type ContributorTagDom = {
|
|
9
38
|
avatars: HTMLSpanElement;
|
|
10
39
|
name: HTMLSpanElement;
|
|
@@ -38,11 +38,19 @@ export declare class ContributorTagController {
|
|
|
38
38
|
private fullLabel;
|
|
39
39
|
private host;
|
|
40
40
|
private isDestroyed;
|
|
41
|
-
|
|
42
|
-
private
|
|
43
|
-
private maxWidthPx;
|
|
41
|
+
/** Last visibility written, so a teardown knows whether there is anything on screen to fade. */
|
|
42
|
+
private isVisible;
|
|
44
43
|
private model;
|
|
45
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Everything currently asking for the tag to be up, other than the model: each hovered highlight,
|
|
46
|
+
* the tag itself while the pointer is on it, and `FOCUS_SOURCE` while it holds focus.
|
|
47
|
+
*
|
|
48
|
+
* One set rather than independent booleans, which is what let the exit's trailing delay go: a
|
|
49
|
+
* pointer crossing from the highlight onto the tag removes one member and adds another in the same
|
|
50
|
+
* dispatch, so no style is resolved in between and the browser never starts the exit. Booleans
|
|
51
|
+
* could not see each other, so the crossing wrote the tag out and straight back in.
|
|
52
|
+
*/
|
|
53
|
+
private revealSources;
|
|
46
54
|
private tooltip;
|
|
47
55
|
private tooltipContent;
|
|
48
56
|
private unbindHighlights;
|
|
@@ -53,28 +61,40 @@ export declare class ContributorTagController {
|
|
|
53
61
|
destroy(): void;
|
|
54
62
|
private findModel;
|
|
55
63
|
private applyModel;
|
|
56
|
-
/**
|
|
64
|
+
/**
|
|
65
|
+
* Takes the tag's DOM down, keeping the subscription so a republished model redraws it.
|
|
66
|
+
*
|
|
67
|
+
* A tag that is still on screen is released here and fades out on its own, so a republished
|
|
68
|
+
* model's tag fades in over the top of the outgoing one — see `fadeTagOut`.
|
|
69
|
+
*/
|
|
57
70
|
private teardownTag;
|
|
58
71
|
private bindTag;
|
|
72
|
+
/** One listener shape for every reveal source, so all of them land in the same set. */
|
|
73
|
+
private trackRevealSource;
|
|
59
74
|
private renderAvatars;
|
|
60
75
|
private renderLabels;
|
|
61
76
|
private accentOf;
|
|
62
77
|
private applyAccent;
|
|
63
|
-
/** Width clamp and visibility — the two things that are not carried by the model alone. */
|
|
64
|
-
private applyStyles;
|
|
65
78
|
/**
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
79
|
+
* Visibility — the one thing the model does not carry on its own, because hover is not in it.
|
|
80
|
+
*
|
|
81
|
+
* One idempotent attribute write, with nothing to guard: whether the flip is a real one, whether
|
|
82
|
+
* the tag is attached yet, and whether motion is wanted at all are all the stylesheet's to answer.
|
|
83
|
+
*/
|
|
84
|
+
private applyVisibility;
|
|
85
|
+
/**
|
|
86
|
+
* The full label is always the tooltip, whether or not the name it draws is clipped: a name longer
|
|
87
|
+
* than `MAX_TAG_WIDTH` is ellipsised, and a connected pair spells out a contributor the tag does
|
|
88
|
+
* not show at any width.
|
|
69
89
|
*
|
|
70
90
|
* `VanillaTooltip` has no "set new content" call, so it is rebuilt when the label changes — the
|
|
71
91
|
* shape of `syncVanillaDisabledTooltip` in `mentionNodeView`.
|
|
72
92
|
*/
|
|
73
93
|
private syncTooltip;
|
|
74
94
|
/**
|
|
75
|
-
* Observes the highlight this tag describes, for what CSS here cannot see: its hover state
|
|
95
|
+
* Observes the highlight this tag describes, for what CSS here cannot see: its hover state. The
|
|
76
96
|
* highlight is a ProseMirror decoration in a different DOM subtree, so listeners are bound
|
|
77
|
-
* imperatively via `data-diff-id
|
|
97
|
+
* imperatively via `data-diff-id`.
|
|
78
98
|
*
|
|
79
99
|
* Deliberately not routed through plugin state: a transaction per pointer move would re-run the
|
|
80
100
|
* memoised decoration calculation.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-show-diff",
|
|
3
|
-
"version": "15.1.
|
|
3
|
+
"version": "15.1.7",
|
|
4
4
|
"description": "ShowDiff plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"react-intl": "^7.0.0"
|
|
64
64
|
},
|
|
65
65
|
"peerDependencies": {
|
|
66
|
-
"@atlaskit/editor-common": "^121.
|
|
66
|
+
"@atlaskit/editor-common": "^121.4.0",
|
|
67
67
|
"react": "^18.2.0 || ^19.2.0",
|
|
68
68
|
"react-dom": "^18.2.0 || ^19.2.0",
|
|
69
69
|
"react-intl": "^5.25.1 || ^6.0.0 || ^7.0.0"
|