@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
|
@@ -16,9 +16,6 @@ var _schemes = require("../../pm-plugins/decorations/colorSchemes/schemes");
|
|
|
16
16
|
var _buildContributorTagDom = require("./buildContributorTagDom");
|
|
17
17
|
var _contributorAvatarRenderer = require("./contributorAvatarRenderer");
|
|
18
18
|
var _messages = require("./messages");
|
|
19
|
-
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
20
|
-
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; } }
|
|
21
|
-
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; }
|
|
22
19
|
var getContributorName = function getContributorName(contributor, formatMessage) {
|
|
23
20
|
var _contributor$name, _contributor$agentKin;
|
|
24
21
|
var name = (_contributor$name = contributor.name) === null || _contributor$name === void 0 ? void 0 : _contributor$name.trim();
|
|
@@ -35,8 +32,8 @@ var getContributorName = function getContributorName(contributor, formatMessage)
|
|
|
35
32
|
};
|
|
36
33
|
|
|
37
34
|
/**
|
|
38
|
-
* Resolves the tag's accent from the same scheme value
|
|
39
|
-
* two can never drift.
|
|
35
|
+
* Resolves the tag's accent from the same scheme value the highlight was drawn from, so the colour
|
|
36
|
+
* the two carry can never drift — only the tone does, which is `getAccentTokens`'s to pick.
|
|
40
37
|
*/
|
|
41
38
|
var getTagAccent = function getTagAccent(_ref) {
|
|
42
39
|
var colorScheme = _ref.colorScheme,
|
|
@@ -47,35 +44,70 @@ var getTagAccent = function getTagAccent(_ref) {
|
|
|
47
44
|
return (0, _factory.getAccentTokens)(accent);
|
|
48
45
|
};
|
|
49
46
|
|
|
50
|
-
/**
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Keyboard focus, as a member of `revealSources` alongside the elements the pointer can be over. It
|
|
49
|
+
* has no element of its own to key on — the tag is already in the set under its own hover.
|
|
50
|
+
*/
|
|
51
|
+
var FOCUS_SOURCE = Symbol('contributor-tag-focus');
|
|
52
|
+
|
|
53
|
+
/** Moves the tag between the two ends of the fade `contributorTagStyles` declares. */
|
|
54
|
+
var setRevealed = function setRevealed(tag, isVisible) {
|
|
55
|
+
tag.toggleAttribute(_buildContributorTagDom.CONTRIBUTOR_TAG_REVEALED_ATTRIBUTE, isVisible);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Whether flipping the tag's state will actually run a transition on it.
|
|
60
|
+
*
|
|
61
|
+
* Asked of the element rather than of `matchMedia`, because reduced motion and a missing stylesheet
|
|
62
|
+
* both compute to a zero duration — and a transition that never starts fires no `transitionend`, so
|
|
63
|
+
* a tag waiting for one would sit on screen until the backstop timeout.
|
|
64
|
+
*
|
|
65
|
+
* Read only when a tag is being taken down: it resolves style.
|
|
66
|
+
*/
|
|
67
|
+
var willTransition = function willTransition(tag) {
|
|
68
|
+
return window.getComputedStyle(tag).transitionDuration.split(',').some(function (duration) {
|
|
69
|
+
return parseFloat(duration) > 0;
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Fades a tag that is still on screen out, and releases it once the fade has finished.
|
|
75
|
+
*
|
|
76
|
+
* No controller owns the element by the time this runs — it is released up front so a republished
|
|
77
|
+
* model's tag can fade in over the top — so everything the removal needs is captured here.
|
|
78
|
+
*/
|
|
79
|
+
var fadeTagOut = function fadeTagOut(tag, release) {
|
|
80
|
+
setRevealed(tag, false);
|
|
81
|
+
|
|
82
|
+
// Nothing to wait for: reduced motion, or no stylesheet to fade it with.
|
|
83
|
+
if (!willTransition(tag)) {
|
|
84
|
+
release();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
var unbind;
|
|
88
|
+
var isFinished = false;
|
|
89
|
+
var finish = function finish() {
|
|
90
|
+
var _unbind;
|
|
91
|
+
// Whichever of the two signals arrives first wins; the other must not release twice.
|
|
92
|
+
if (isFinished) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
isFinished = true;
|
|
96
|
+
(_unbind = unbind) === null || _unbind === void 0 || _unbind();
|
|
97
|
+
unbind = undefined;
|
|
98
|
+
clearTimeout(fallbackId);
|
|
99
|
+
release();
|
|
100
|
+
};
|
|
101
|
+
unbind = (0, _bindEventListener.bind)(tag, {
|
|
102
|
+
type: 'transitionend',
|
|
103
|
+
// `transitionend` bubbles, and opacity is not the only property that could ever carry one.
|
|
104
|
+
listener: function listener(event) {
|
|
105
|
+
if (event.target === tag && event.propertyName === 'opacity') {
|
|
106
|
+
finish();
|
|
71
107
|
}
|
|
72
108
|
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
} finally {
|
|
76
|
-
_iterator.f();
|
|
77
|
-
}
|
|
78
|
-
return start;
|
|
109
|
+
});
|
|
110
|
+
var fallbackId = setTimeout(finish, _buildContributorTagDom.TAG_EXIT_FALLBACK_MS);
|
|
79
111
|
};
|
|
80
112
|
|
|
81
113
|
/** The contributors a tag draws, keyed so a republished model can be recognised as the same pair. */
|
|
@@ -104,8 +136,18 @@ var ContributorTagController = exports.ContributorTagController = /*#__PURE__*/f
|
|
|
104
136
|
(0, _defineProperty2.default)(this, "bindToken", 0);
|
|
105
137
|
(0, _defineProperty2.default)(this, "fullLabel", '');
|
|
106
138
|
(0, _defineProperty2.default)(this, "isDestroyed", false);
|
|
107
|
-
|
|
108
|
-
(0, _defineProperty2.default)(this, "
|
|
139
|
+
/** Last visibility written, so a teardown knows whether there is anything on screen to fade. */
|
|
140
|
+
(0, _defineProperty2.default)(this, "isVisible", false);
|
|
141
|
+
/**
|
|
142
|
+
* Everything currently asking for the tag to be up, other than the model: each hovered highlight,
|
|
143
|
+
* the tag itself while the pointer is on it, and `FOCUS_SOURCE` while it holds focus.
|
|
144
|
+
*
|
|
145
|
+
* One set rather than independent booleans, which is what let the exit's trailing delay go: a
|
|
146
|
+
* pointer crossing from the highlight onto the tag removes one member and adds another in the same
|
|
147
|
+
* dispatch, so no style is resolved in between and the browser never starts the exit. Booleans
|
|
148
|
+
* could not see each other, so the crossing wrote the tag out and straight back in.
|
|
149
|
+
*/
|
|
150
|
+
(0, _defineProperty2.default)(this, "revealSources", new Set());
|
|
109
151
|
(0, _defineProperty2.default)(this, "unbindHighlights", []);
|
|
110
152
|
this.options = options;
|
|
111
153
|
}
|
|
@@ -167,65 +209,101 @@ var ContributorTagController = exports.ContributorTagController = /*#__PURE__*/f
|
|
|
167
209
|
this.renderLabels(next);
|
|
168
210
|
this.applyAccent(next);
|
|
169
211
|
this.syncHighlightBindings(next);
|
|
170
|
-
this.
|
|
212
|
+
this.applyVisibility();
|
|
171
213
|
this.syncTooltip();
|
|
172
214
|
}
|
|
173
215
|
|
|
174
|
-
/**
|
|
216
|
+
/**
|
|
217
|
+
* Takes the tag's DOM down, keeping the subscription so a republished model redraws it.
|
|
218
|
+
*
|
|
219
|
+
* A tag that is still on screen is released here and fades out on its own, so a republished
|
|
220
|
+
* model's tag fades in over the top of the outgoing one — see `fadeTagOut`.
|
|
221
|
+
*/
|
|
175
222
|
}, {
|
|
176
223
|
key: "teardownTag",
|
|
177
224
|
value: function teardownTag() {
|
|
178
|
-
var _this$unbindTag, _this$tooltip
|
|
225
|
+
var _this$unbindTag, _this$tooltip;
|
|
226
|
+
// Unbound synchronously, ahead of any fade: a tag on its way out must not be revealed again by
|
|
227
|
+
// the pointer, and these listeners are what hold this controller.
|
|
179
228
|
this.unbindHighlightState();
|
|
180
229
|
this.boundSelector = undefined;
|
|
181
230
|
(_this$unbindTag = this.unbindTag) === null || _this$unbindTag === void 0 || _this$unbindTag.call(this);
|
|
182
231
|
this.unbindTag = undefined;
|
|
232
|
+
// Destroyed rather than carried through the fade: it is a popover in the top layer.
|
|
183
233
|
(_this$tooltip = this.tooltip) === null || _this$tooltip === void 0 || _this$tooltip.destroy();
|
|
184
234
|
this.tooltip = undefined;
|
|
185
235
|
this.tooltipContent = undefined;
|
|
186
|
-
this.
|
|
187
|
-
|
|
188
|
-
|
|
236
|
+
var dom = this.dom,
|
|
237
|
+
isVisible = this.isVisible;
|
|
238
|
+
// Destroying an avatar removes its element, so the avatars go with whoever removes the tag —
|
|
239
|
+
// destroyed here and it would fade out empty.
|
|
240
|
+
var avatars = this.avatars;
|
|
189
241
|
this.avatars = [];
|
|
190
|
-
(_this$dom = this.dom) === null || _this$dom === void 0 || _this$dom.root.remove();
|
|
191
242
|
this.dom = undefined;
|
|
192
|
-
this.
|
|
193
|
-
|
|
194
|
-
//
|
|
195
|
-
|
|
196
|
-
|
|
243
|
+
this.isVisible = false;
|
|
244
|
+
// The set belongs to the listeners just unbound: a stale member would draw the tag as visible
|
|
245
|
+
// with the pointer nowhere near it.
|
|
246
|
+
this.revealSources.clear();
|
|
247
|
+
if (!dom) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
var release = function release() {
|
|
251
|
+
avatars.forEach(function (avatar) {
|
|
252
|
+
return avatar.destroy();
|
|
253
|
+
});
|
|
254
|
+
dom.root.remove();
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
// Nothing on screen to fade. `isConnected` covers ProseMirror destroying the widget: a fade on
|
|
258
|
+
// a detached element never starts.
|
|
259
|
+
if (!isVisible || !dom.tag.isConnected) {
|
|
260
|
+
release();
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
fadeTagOut(dom.tag, release);
|
|
197
264
|
}
|
|
198
265
|
}, {
|
|
199
266
|
key: "bindTag",
|
|
200
267
|
value: function bindTag(_ref4) {
|
|
201
|
-
var _this3 = this;
|
|
202
268
|
var tag = _ref4.tag;
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
_this3.applyStyles();
|
|
207
|
-
};
|
|
208
|
-
};
|
|
269
|
+
// `mouseover`/`mouseout` rather than the enter/leave pair, because they are what fire as the
|
|
270
|
+
// pointer moves between the tag's own children. Both are keyed on the tag, so those moves add
|
|
271
|
+
// and remove the same member and the set never empties.
|
|
209
272
|
this.unbindTag = (0, _bindEventListener.bindAll)(tag, [{
|
|
210
273
|
type: 'mouseover',
|
|
211
|
-
listener:
|
|
274
|
+
listener: this.trackRevealSource(tag, true)
|
|
212
275
|
}, {
|
|
213
276
|
type: 'mouseout',
|
|
214
|
-
listener:
|
|
277
|
+
listener: this.trackRevealSource(tag, false)
|
|
215
278
|
}, {
|
|
216
279
|
type: 'focus',
|
|
217
|
-
listener:
|
|
280
|
+
listener: this.trackRevealSource(FOCUS_SOURCE, true)
|
|
218
281
|
}, {
|
|
219
282
|
type: 'blur',
|
|
220
|
-
listener:
|
|
283
|
+
listener: this.trackRevealSource(FOCUS_SOURCE, false)
|
|
221
284
|
}]);
|
|
222
285
|
}
|
|
286
|
+
|
|
287
|
+
/** One listener shape for every reveal source, so all of them land in the same set. */
|
|
288
|
+
}, {
|
|
289
|
+
key: "trackRevealSource",
|
|
290
|
+
value: function trackRevealSource(source, isRevealing) {
|
|
291
|
+
var _this3 = this;
|
|
292
|
+
return function () {
|
|
293
|
+
if (isRevealing) {
|
|
294
|
+
_this3.revealSources.add(source);
|
|
295
|
+
} else {
|
|
296
|
+
_this3.revealSources.delete(source);
|
|
297
|
+
}
|
|
298
|
+
_this3.applyVisibility();
|
|
299
|
+
};
|
|
300
|
+
}
|
|
223
301
|
}, {
|
|
224
302
|
key: "renderAvatars",
|
|
225
303
|
value: function renderAvatars(model) {
|
|
226
|
-
var _this$
|
|
304
|
+
var _this$dom,
|
|
227
305
|
_this4 = this;
|
|
228
|
-
var _ref5 = (_this$
|
|
306
|
+
var _ref5 = (_this$dom = this.dom) !== null && _this$dom !== void 0 ? _this$dom : {},
|
|
229
307
|
container = _ref5.avatars;
|
|
230
308
|
if (!container) {
|
|
231
309
|
return;
|
|
@@ -285,8 +363,8 @@ var ContributorTagController = exports.ContributorTagController = /*#__PURE__*/f
|
|
|
285
363
|
var agentName = isPrimaryAgent ? primaryName : secondaryName;
|
|
286
364
|
var userName = isPrimaryAgent ? secondaryName : primaryName;
|
|
287
365
|
|
|
288
|
-
// A connected pair only ever shows the agent; the pair is spelled out in the label, because
|
|
289
|
-
//
|
|
366
|
+
// A connected pair only ever shows the agent; the pair is spelled out in the label, because the
|
|
367
|
+
// tag is capped at `MAX_TAG_WIDTH` and two names rarely fit inside it.
|
|
290
368
|
this.dom.name.textContent = model.connectedContributor ? agentName || primaryName : primaryName;
|
|
291
369
|
this.fullLabel = model.connectedContributor ? formatMessage(_messages.contributorTagMessages.changedByConnected, {
|
|
292
370
|
agentName: agentName,
|
|
@@ -314,34 +392,34 @@ var ContributorTagController = exports.ContributorTagController = /*#__PURE__*/f
|
|
|
314
392
|
}
|
|
315
393
|
var accent = this.accentOf(model);
|
|
316
394
|
this.dom.tag.style.setProperty('background-color', accent.background);
|
|
317
|
-
this.dom.tag.style.setProperty('border-bottom-color', accent.border);
|
|
318
395
|
this.dom.name.style.setProperty('color', accent.text);
|
|
319
396
|
this.avatars.forEach(function (avatar) {
|
|
320
397
|
return avatar.setRingColor(accent.background);
|
|
321
398
|
});
|
|
322
399
|
}
|
|
323
400
|
|
|
324
|
-
/**
|
|
401
|
+
/**
|
|
402
|
+
* Visibility — the one thing the model does not carry on its own, because hover is not in it.
|
|
403
|
+
*
|
|
404
|
+
* One idempotent attribute write, with nothing to guard: whether the flip is a real one, whether
|
|
405
|
+
* the tag is attached yet, and whether motion is wanted at all are all the stylesheet's to answer.
|
|
406
|
+
*/
|
|
325
407
|
}, {
|
|
326
|
-
key: "
|
|
327
|
-
value: function
|
|
408
|
+
key: "applyVisibility",
|
|
409
|
+
value: function applyVisibility() {
|
|
328
410
|
var _this$model;
|
|
329
411
|
if (!this.dom) {
|
|
330
412
|
return;
|
|
331
413
|
}
|
|
332
|
-
this.
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
this.maxWidthPx === undefined ? '' : "max(".concat(Math.round(this.maxWidthPx), "px, ").concat(_buildContributorTagDom.MIN_TAG_WIDTH, ")"));
|
|
336
|
-
var isVisible = Boolean((_this$model = this.model) === null || _this$model === void 0 ? void 0 : _this$model.isActive) || this.isHighlightHovered || this.isHoveredOrFocused;
|
|
337
|
-
this.dom.tag.style.setProperty('opacity', isVisible ? '1' : '0');
|
|
338
|
-
this.dom.tag.style.setProperty('pointer-events', isVisible ? 'auto' : 'none');
|
|
414
|
+
var isVisible = Boolean((_this$model = this.model) === null || _this$model === void 0 ? void 0 : _this$model.isActive) || this.revealSources.size > 0;
|
|
415
|
+
this.isVisible = isVisible;
|
|
416
|
+
setRevealed(this.dom.tag, isVisible);
|
|
339
417
|
}
|
|
340
418
|
|
|
341
419
|
/**
|
|
342
|
-
* The full label is always the tooltip, whether or not the name it draws is clipped:
|
|
343
|
-
*
|
|
344
|
-
*
|
|
420
|
+
* The full label is always the tooltip, whether or not the name it draws is clipped: a name longer
|
|
421
|
+
* than `MAX_TAG_WIDTH` is ellipsised, and a connected pair spells out a contributor the tag does
|
|
422
|
+
* not show at any width.
|
|
345
423
|
*
|
|
346
424
|
* `VanillaTooltip` has no "set new content" call, so it is rebuilt when the label changes — the
|
|
347
425
|
* shape of `syncVanillaDisabledTooltip` in `mentionNodeView`.
|
|
@@ -372,9 +450,9 @@ var ContributorTagController = exports.ContributorTagController = /*#__PURE__*/f
|
|
|
372
450
|
}
|
|
373
451
|
|
|
374
452
|
/**
|
|
375
|
-
* Observes the highlight this tag describes, for what CSS here cannot see: its hover state
|
|
453
|
+
* Observes the highlight this tag describes, for what CSS here cannot see: its hover state. The
|
|
376
454
|
* highlight is a ProseMirror decoration in a different DOM subtree, so listeners are bound
|
|
377
|
-
* imperatively via `data-diff-id
|
|
455
|
+
* imperatively via `data-diff-id`.
|
|
378
456
|
*
|
|
379
457
|
* Deliberately not routed through plugin state: a transaction per pointer move would re-run the
|
|
380
458
|
* memoised decoration calculation.
|
|
@@ -394,8 +472,8 @@ var ContributorTagController = exports.ContributorTagController = /*#__PURE__*/f
|
|
|
394
472
|
this.boundSelector = selector;
|
|
395
473
|
this.unbindHighlightState();
|
|
396
474
|
|
|
397
|
-
// ProseMirror draws the tag's host in the same pass as the highlights
|
|
398
|
-
//
|
|
475
|
+
// ProseMirror draws the tag's host in the same pass as the highlights it binds to, so those may
|
|
476
|
+
// not be in the document yet. A microtask lands once that pass has finished.
|
|
399
477
|
var pendingBind = ++this.bindToken;
|
|
400
478
|
queueMicrotask(function () {
|
|
401
479
|
if (!_this5.isDestroyed && pendingBind === _this5.bindToken) {
|
|
@@ -406,91 +484,32 @@ var ContributorTagController = exports.ContributorTagController = /*#__PURE__*/f
|
|
|
406
484
|
}, {
|
|
407
485
|
key: "bindHighlightState",
|
|
408
486
|
value: function bindHighlightState(selector) {
|
|
409
|
-
var
|
|
410
|
-
|
|
411
|
-
//
|
|
412
|
-
// inside this one, cannot
|
|
413
|
-
|
|
414
|
-
var highlights =
|
|
415
|
-
if (!
|
|
487
|
+
var _this$options$getEdit,
|
|
488
|
+
_this6 = this;
|
|
489
|
+
// Scoped to this editor's content root, so a tag can only ever bind to the decorations its own
|
|
490
|
+
// plugin instance rendered — another editor on the page, or one nested inside this one, cannot
|
|
491
|
+
// reveal this tag.
|
|
492
|
+
var highlights = (_this$options$getEdit = this.options.getEditorRoot()) === null || _this$options$getEdit === void 0 ? void 0 : _this$options$getEdit.querySelectorAll(selector);
|
|
493
|
+
if (!(highlights !== null && highlights !== void 0 && highlights.length)) {
|
|
416
494
|
return;
|
|
417
495
|
}
|
|
418
496
|
|
|
419
|
-
//
|
|
420
|
-
//
|
|
421
|
-
|
|
422
|
-
var measure = function measure() {
|
|
423
|
-
var _findChangeStartLine;
|
|
424
|
-
// Counted by distinct line box, not by client rect: an inline node inside the change (a
|
|
425
|
-
// mention, emoji, date) splits the highlight into several rects on the same line, and
|
|
426
|
-
// treating that as a wrap would drop the width clamp on changes that never wrapped.
|
|
427
|
-
var lineTops = new Set();
|
|
428
|
-
for (var _i = 0, _ownElements = ownElements; _i < _ownElements.length; _i++) {
|
|
429
|
-
var highlight = _ownElements[_i];
|
|
430
|
-
var _iterator3 = _createForOfIteratorHelper(highlight.getClientRects()),
|
|
431
|
-
_step3;
|
|
432
|
-
try {
|
|
433
|
-
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
434
|
-
var rect = _step3.value;
|
|
435
|
-
lineTops.add(Math.round(rect.top));
|
|
436
|
-
}
|
|
437
|
-
} catch (err) {
|
|
438
|
-
_iterator3.e(err);
|
|
439
|
-
} finally {
|
|
440
|
-
_iterator3.f();
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
// A wrapped change's first line says nothing useful about how wide the tag may be.
|
|
445
|
-
_this6.maxWidthPx = lineTops.size > 1 ? undefined : (_findChangeStartLine = findChangeStartLine(ownElements)) === null || _findChangeStartLine === void 0 ? void 0 : _findChangeStartLine.width;
|
|
446
|
-
_this6.applyStyles();
|
|
447
|
-
};
|
|
448
|
-
measure();
|
|
449
|
-
|
|
450
|
-
// An inline element cannot be observed itself (ResizeObserver skips boxes with no principal
|
|
451
|
-
// box), so the block it sits in is observed instead.
|
|
452
|
-
this.resizeObserver = new ResizeObserver(measure);
|
|
453
|
-
var _iterator4 = _createForOfIteratorHelper(new Set(ownElements.map(function (_ref7) {
|
|
454
|
-
var parentElement = _ref7.parentElement;
|
|
455
|
-
return parentElement;
|
|
456
|
-
}))),
|
|
457
|
-
_step4;
|
|
458
|
-
try {
|
|
459
|
-
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
460
|
-
var parent = _step4.value;
|
|
461
|
-
if (parent) {
|
|
462
|
-
this.resizeObserver.observe(parent);
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
// `bindAll` takes a single target, and a change can render more than one highlight.
|
|
467
|
-
} catch (err) {
|
|
468
|
-
_iterator4.e(err);
|
|
469
|
-
} finally {
|
|
470
|
-
_iterator4.f();
|
|
471
|
-
}
|
|
497
|
+
// `bindAll` takes a single target, and a change can render more than one highlight. Each is its
|
|
498
|
+
// own member of `revealSources`, so the pointer can cross between them without the set
|
|
499
|
+
// emptying.
|
|
472
500
|
this.unbindHighlights = Array.from(highlights).map(function (highlight) {
|
|
473
501
|
return (0, _bindEventListener.bindAll)(highlight, [{
|
|
474
502
|
type: 'mouseenter',
|
|
475
|
-
listener:
|
|
476
|
-
_this6.isHighlightHovered = true;
|
|
477
|
-
_this6.applyStyles();
|
|
478
|
-
}
|
|
503
|
+
listener: _this6.trackRevealSource(highlight, true)
|
|
479
504
|
}, {
|
|
480
505
|
type: 'mouseleave',
|
|
481
|
-
listener:
|
|
482
|
-
_this6.isHighlightHovered = false;
|
|
483
|
-
_this6.applyStyles();
|
|
484
|
-
}
|
|
506
|
+
listener: _this6.trackRevealSource(highlight, false)
|
|
485
507
|
}]);
|
|
486
508
|
});
|
|
487
509
|
}
|
|
488
510
|
}, {
|
|
489
511
|
key: "unbindHighlightState",
|
|
490
512
|
value: function unbindHighlightState() {
|
|
491
|
-
var _this$resizeObserver;
|
|
492
|
-
(_this$resizeObserver = this.resizeObserver) === null || _this$resizeObserver === void 0 || _this$resizeObserver.disconnect();
|
|
493
|
-
this.resizeObserver = undefined;
|
|
494
513
|
this.unbindHighlights.forEach(function (unbind) {
|
|
495
514
|
return unbind();
|
|
496
515
|
});
|
|
@@ -6,7 +6,7 @@ import { Mapping } from '@atlaskit/editor-prosemirror/transform';
|
|
|
6
6
|
import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
7
7
|
import { UNSAFE_expValNoExposure } from '@atlaskit/platform-feature-experiments/unsafe-exp-val-no-exposure';
|
|
8
8
|
import { fg } from '@atlaskit/platform-feature-flags/fg';
|
|
9
|
-
import {
|
|
9
|
+
import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
|
|
10
10
|
import { areDocsEqualByBlockStructureAndText } from '../areDocsEqualByBlockStructureAndText';
|
|
11
11
|
import { createDocMarginAnchorWidget } from '../decorations/createAnchorDecorationWidgets';
|
|
12
12
|
import { createBlockChangedDecoration } from '../decorations/createBlockChangedDecoration';
|
|
@@ -482,8 +482,9 @@ const calculateDiffDecorationsInner = ({
|
|
|
482
482
|
// gets highlighted, and structural gaps never do.
|
|
483
483
|
const isSmartNodeLevel = diffType === 'smart' && fg('platform_editor_ai_smart_diff') && smartChangeLevel(change) === 'node';
|
|
484
484
|
// For a large inserted table, skip the per-cell inline decorations that
|
|
485
|
-
// freeze the browser on re-render. Only active
|
|
486
|
-
|
|
485
|
+
// freeze the browser on re-render. Only active when Review moment is
|
|
486
|
+
// eligible (xstate + M1).
|
|
487
|
+
const useCoarseTableDecoration = isSmartNodeLevel && expValEqualsNoExposure('platform_editor_ai_xstate_migration', 'isEnabled', true) && UNSAFE_expValNoExposure('platform_editor_ai_streaming_ux_experience_m1', 'isEnabled', false) === true && isLargeInsertedTableRange(tr.doc, change.fromB, change.toB);
|
|
487
488
|
// Whether the deleted-content widget will actually be rendered for this
|
|
488
489
|
// change. Used to decide if indicator anchor positions should be adjusted
|
|
489
490
|
// inward — when the widget is present the anchor must stay at the block
|
|
@@ -670,7 +671,7 @@ const calculateDiffDecorationsInner = ({
|
|
|
670
671
|
}));
|
|
671
672
|
// If the original node position is known (e.g. a panel type change), also render
|
|
672
673
|
// the old block node as a "deleted" widget so the reviewer sees the before/after.
|
|
673
|
-
const isSmartNodeLevelAttrChange = diffType === 'smart' && fg('platform_editor_ai_smart_diff') &&
|
|
674
|
+
const isSmartNodeLevelAttrChange = diffType === 'smart' && fg('platform_editor_ai_smart_diff') && expValEqualsNoExposure('platform_editor_ai_xstate_migration', 'isEnabled', true) && UNSAFE_expValNoExposure('platform_editor_ai_streaming_ux_experience_m1', 'isEnabled', false) === true;
|
|
674
675
|
if (isSmartNodeLevelAttrChange && change.fromA !== undefined && change.toA !== undefined) {
|
|
675
676
|
const placeBelow = deletedDiffPlacement === 'bottom';
|
|
676
677
|
decorations.push(...createNodeChangedDecorationWidget({
|
|
@@ -62,6 +62,18 @@ const bgSubtlerPressedMap = {
|
|
|
62
62
|
gray: "var(--ds-background-accent-gray-subtler-pressed, #8C8F97)",
|
|
63
63
|
lime: "var(--ds-background-accent-lime-subtler-pressed, #B3DF72)"
|
|
64
64
|
};
|
|
65
|
+
const bgBolderMap = {
|
|
66
|
+
green: "var(--ds-background-accent-green-bolder, #1F845A)",
|
|
67
|
+
teal: "var(--ds-background-accent-teal-bolder, #227D9B)",
|
|
68
|
+
blue: "var(--ds-background-accent-blue-bolder, #1868DB)",
|
|
69
|
+
purple: "var(--ds-background-accent-purple-bolder, #964AC0)",
|
|
70
|
+
red: "var(--ds-background-accent-red-bolder, #C9372C)",
|
|
71
|
+
orange: "var(--ds-background-accent-orange-bolder, #BD5B00)",
|
|
72
|
+
yellow: "var(--ds-background-accent-yellow-bolder, #946F00)",
|
|
73
|
+
magenta: "var(--ds-background-accent-magenta-bolder, #AE4787)",
|
|
74
|
+
gray: "var(--ds-background-accent-gray-bolder, #6B6E76)",
|
|
75
|
+
lime: "var(--ds-background-accent-lime-bolder, #5B7F24)"
|
|
76
|
+
};
|
|
65
77
|
const borderAccentMap = {
|
|
66
78
|
green: "var(--ds-border-accent-green, #22A06B)",
|
|
67
79
|
teal: "var(--ds-border-accent-teal, #2898BD)",
|
|
@@ -95,6 +107,9 @@ function bgSubtlestPressed(color) {
|
|
|
95
107
|
function bgSubtler(color) {
|
|
96
108
|
return bgSubtlerMap[color];
|
|
97
109
|
}
|
|
110
|
+
function bgBolder(color) {
|
|
111
|
+
return bgBolderMap[color];
|
|
112
|
+
}
|
|
98
113
|
function bgSubtlerPressed(color) {
|
|
99
114
|
return bgSubtlerPressedMap[color];
|
|
100
115
|
}
|
|
@@ -105,12 +120,18 @@ function textAccent(color) {
|
|
|
105
120
|
return textAccentMap[color];
|
|
106
121
|
}
|
|
107
122
|
|
|
108
|
-
/**
|
|
123
|
+
/**
|
|
124
|
+
* Presentation tokens for a contributor tag in one diff colour.
|
|
125
|
+
*
|
|
126
|
+
* A `bolder` fill rather than the `subtlest` tint the highlight uses: the tag is a label on the
|
|
127
|
+
* change, and at tag size a tint reads as a second, weaker highlight sitting above the real one.
|
|
128
|
+
* `inverse` is the only text tone that reads on a bolder fill, and it needs no per-colour map —
|
|
129
|
+
* which is also why the tag carries no border: the fill alone bounds it.
|
|
130
|
+
*/
|
|
109
131
|
export function getAccentTokens(color) {
|
|
110
132
|
return {
|
|
111
|
-
background:
|
|
112
|
-
|
|
113
|
-
text: textAccent(color)
|
|
133
|
+
background: bgBolder(color),
|
|
134
|
+
text: "var(--ds-text-inverse, #FFFFFF)"
|
|
114
135
|
};
|
|
115
136
|
}
|
|
116
137
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
|
|
2
2
|
import { Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
3
3
|
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
|
|
4
|
+
import { CONTRIBUTOR_TAG_Z_INDEX } from '../../ui/ContributorTag/buildContributorTagDom';
|
|
4
5
|
import { isExtendedEnabled } from '../isExtendedEnabled';
|
|
5
6
|
import { hasVisibleContent } from '../utils/hasVisibleContent';
|
|
6
7
|
import { buildAtomicInlineChangedCSSVariables, buildDeletedInlineContentStyleExtended, buildDeletedInlineStyle, buildDeletedInlineStyleStandard, buildInsertStyle, buildInsertStyleActive, buildInsertStyleExtended, buildInsertStyleExtendedActive, buildInsertStyleExtendedNoUnderline, buildInsertStyleExtendedNoUnderlineActive } from './colorSchemes/factory';
|
|
@@ -13,6 +14,25 @@ import { REVEAL_ATTR, resolveRevealStyle } from './revealStyles';
|
|
|
13
14
|
const displayNoneStyle = convertToInlineCss({
|
|
14
15
|
display: 'none'
|
|
15
16
|
});
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Stacks the change's highlight below its contributor tag, so no highlight can slice through a tag:
|
|
20
|
+
* a tag overlays the line *above* its own change, and a highlight already on that line — the tail of
|
|
21
|
+
* this change, or another change entirely — would otherwise paint straight over it.
|
|
22
|
+
*
|
|
23
|
+
* The tag still reads as attached to the change rather than laid on top of it, because it cannot
|
|
24
|
+
* paint over this highlight at all: its bottom edge is pinned to the highlight's top edge and
|
|
25
|
+
* clipped there. See `CONTRIBUTOR_TAG_Z_INDEX`.
|
|
26
|
+
*
|
|
27
|
+
* prosemirror-view places the tag's host widget as a *sibling* of this decoration's span, so
|
|
28
|
+
* painting order is decided by stacking level — and the host is absolutely positioned at
|
|
29
|
+
* `CONTRIBUTOR_TAG_Z_INDEX`. `position: relative` is what makes `z-index` apply to an otherwise
|
|
30
|
+
* static inline box; it adds no offset.
|
|
31
|
+
*/
|
|
32
|
+
const stackBelowContributorTagStyle = convertToInlineCss({
|
|
33
|
+
position: 'relative',
|
|
34
|
+
zIndex: CONTRIBUTOR_TAG_Z_INDEX - 1
|
|
35
|
+
});
|
|
16
36
|
const getColorScheme = colorScheme => colorSchemeRegistry[colorScheme !== null && colorScheme !== void 0 ? colorScheme : 'standard'];
|
|
17
37
|
|
|
18
38
|
/**
|
|
@@ -158,8 +178,23 @@ export const createInlineChangedDecoration = ({
|
|
|
158
178
|
});
|
|
159
179
|
const isAtomicInlineInsertion = isAtomicInlineNode && isInserted;
|
|
160
180
|
const atomicInlineAttrs = isAtomicInlineInsertion ? resolveAtomicInlineAttrs(inlineNodeName, colorScheme, colors) : undefined;
|
|
181
|
+
|
|
182
|
+
// Built from the raw change range, not the indicator anchors resolved below: a tag lines up with
|
|
183
|
+
// the changed text, while the bar's anchors are held on a block boundary when a deleted widget
|
|
184
|
+
// renders beside them.
|
|
185
|
+
//
|
|
186
|
+
// Built up here, ahead of where it is pushed, so the highlight's stacking below keys off whether a
|
|
187
|
+
// tag exists rather than re-deriving the condition and risking disagreement.
|
|
188
|
+
const tagWidget = canTagChange && doc ? createContributorTagWidget({
|
|
189
|
+
doc,
|
|
190
|
+
from: change.fromB,
|
|
191
|
+
to: change.toB,
|
|
192
|
+
diffId,
|
|
193
|
+
mountContext: tagMountContext
|
|
194
|
+
}) : undefined;
|
|
195
|
+
const inlineStyle = [style, atomicInlineAttrs === null || atomicInlineAttrs === void 0 ? void 0 : atomicInlineAttrs.styleSuffix, tagWidget ? stackBelowContributorTagStyle : undefined].filter(Boolean).join('');
|
|
161
196
|
const decorations = [Decoration.inline(change.fromB, change.toB, {
|
|
162
|
-
style:
|
|
197
|
+
style: inlineStyle,
|
|
163
198
|
...(atomicInlineAttrs && {
|
|
164
199
|
class: atomicInlineAttrs.className
|
|
165
200
|
}),
|
|
@@ -215,19 +250,10 @@ export const createInlineChangedDecoration = ({
|
|
|
215
250
|
}));
|
|
216
251
|
}
|
|
217
252
|
|
|
218
|
-
//
|
|
219
|
-
//
|
|
220
|
-
if (
|
|
221
|
-
|
|
222
|
-
doc,
|
|
223
|
-
from: change.fromB,
|
|
224
|
-
to: change.toB,
|
|
225
|
-
diffId,
|
|
226
|
-
mountContext: tagMountContext
|
|
227
|
-
});
|
|
228
|
-
if (tagWidget) {
|
|
229
|
-
decorations.push(tagWidget);
|
|
230
|
-
}
|
|
253
|
+
// Pushed after the indicator anchors so the decoration order is unchanged — see `tagWidget` above
|
|
254
|
+
// for why it is built before them.
|
|
255
|
+
if (tagWidget) {
|
|
256
|
+
decorations.push(tagWidget);
|
|
231
257
|
}
|
|
232
258
|
return decorations;
|
|
233
259
|
};
|
|
@@ -2,6 +2,7 @@ import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
|
|
|
2
2
|
import { trackChangesMessages } from '@atlaskit/editor-common/messages';
|
|
3
3
|
import { getBaseNodeTypeName } from '@atlaskit/editor-common/utils/node-type-utils';
|
|
4
4
|
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
|
|
5
|
+
import { fg } from '@atlaskit/platform-feature-flags/fg';
|
|
5
6
|
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
6
7
|
import { isExtendedEnabled } from '../../isExtendedEnabled';
|
|
7
8
|
import { applyRevealToElement } from '../revealStyles';
|
|
@@ -276,6 +277,16 @@ const applyInlineLeafNodeStyles = ({
|
|
|
276
277
|
});
|
|
277
278
|
});
|
|
278
279
|
};
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Editor CSS makes `blockquote` `inline-block` for its block formatting context. Inside a widget
|
|
283
|
+
* that collapses the indicator bar: the container is an inline `span`, so its anchor rect comes from
|
|
284
|
+
* font metrics, not from an inline-level child. `flow-root` keeps the formatting context but is
|
|
285
|
+
* block-level — unlike `block`, which lets the child paragraph's top margin collapse out.
|
|
286
|
+
*/
|
|
287
|
+
const quoteBlockLevelStyle = convertToInlineCss({
|
|
288
|
+
display: 'flow-root'
|
|
289
|
+
});
|
|
279
290
|
const applyTextLikeBlockNodeStyles = ({
|
|
280
291
|
element,
|
|
281
292
|
targetNode,
|
|
@@ -533,6 +544,9 @@ export const wrapBlockNodeView = ({
|
|
|
533
544
|
hideAddedDiffsUnderline,
|
|
534
545
|
highlightInlineLeafNodes
|
|
535
546
|
});
|
|
547
|
+
if (targetNode.type.name === 'blockquote' && fg('platform_editor_ai_show_diff_patch_1')) {
|
|
548
|
+
appendStyleToElement(nodeView, quoteBlockLevelStyle);
|
|
549
|
+
}
|
|
536
550
|
dom.append(nodeView);
|
|
537
551
|
return;
|
|
538
552
|
}
|