@atlaskit/editor-plugin-collab-edit 13.0.30 → 13.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/dist/cjs/pm-plugins/actions.js +39 -0
- package/dist/cjs/pm-plugins/main/agent-shimmer-decorations.js +126 -0
- package/dist/cjs/pm-plugins/main/agent-shimmer-ranges.js +169 -0
- package/dist/cjs/pm-plugins/main/plugin-state.js +54 -3
- package/dist/cjs/pm-plugins/utils.js +6 -2
- package/dist/es2019/pm-plugins/actions.js +40 -0
- package/dist/es2019/pm-plugins/main/agent-shimmer-decorations.js +115 -0
- package/dist/es2019/pm-plugins/main/agent-shimmer-ranges.js +151 -0
- package/dist/es2019/pm-plugins/main/plugin-state.js +52 -4
- package/dist/es2019/pm-plugins/utils.js +7 -1
- package/dist/esm/pm-plugins/actions.js +39 -0
- package/dist/esm/pm-plugins/main/agent-shimmer-decorations.js +120 -0
- package/dist/esm/pm-plugins/main/agent-shimmer-ranges.js +163 -0
- package/dist/esm/pm-plugins/main/plugin-state.js +55 -3
- package/dist/esm/pm-plugins/utils.js +6 -2
- package/dist/types/pm-plugins/main/agent-shimmer-decorations.d.ts +31 -0
- package/dist/types/pm-plugins/main/agent-shimmer-ranges.d.ts +22 -0
- package/dist/types/pm-plugins/main/plugin-state.d.ts +3 -1
- package/package.json +7 -4
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { getCollabState } from '@atlaskit/prosemirror-collab';
|
|
2
|
+
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
3
|
+
// When an agent step lands we cover the top-level block(s) it wrote with a skeleton-loader shimmer
|
|
4
|
+
// (plus a Rovo agent telepointer at the end of the range), then remove it on a timer to reveal the
|
|
5
|
+
// content. Gated behind the `platform_editor_agent_be_streaming` experiment; `durationMs` sets how
|
|
6
|
+
// long the shimmer stays and a 0 duration disables it.
|
|
7
|
+
var agentShimmerIdCounter = 0;
|
|
8
|
+
|
|
9
|
+
// A step is position-neutral when its StepMap changes no range's length — i.e. it shifts no
|
|
10
|
+
// positions. Attribute-only steps (e.g. `localId` assignment) produce an empty StepMap, and
|
|
11
|
+
// same-size replacements preserve lengths, so both are position-neutral. Used to decide whether a
|
|
12
|
+
// rebase over local unconfirmed steps could have invalidated our index-based range math.
|
|
13
|
+
export var isPositionNeutralStep = function isPositionNeutralStep(step) {
|
|
14
|
+
var neutral = true;
|
|
15
|
+
step.getMap().forEach(function (oldStart, oldEnd, newStart, newEnd) {
|
|
16
|
+
if (oldEnd - oldStart !== newEnd - newStart) {
|
|
17
|
+
neutral = false;
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
return neutral;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Derive the shimmer ranges for the agent-authored steps in a received batch, in final-doc
|
|
25
|
+
* coordinates. `agentType` present ⇒ agent-authored (per the NCS↔Editor steps contract). Each
|
|
26
|
+
* emitted range is expanded to the whole top-level block(s) the agent touched, which the plugin
|
|
27
|
+
* covers with the skeleton shimmer. Ranges with no new content (pure deletions) are dropped.
|
|
28
|
+
*
|
|
29
|
+
* Steps whose new content is in the same or directly-adjacent top-level block are coalesced into one
|
|
30
|
+
* range, so an edit that arrives as several steps in a region shimmers as a single unit. Edits
|
|
31
|
+
* separated by an untouched block stay independent.
|
|
32
|
+
*
|
|
33
|
+
* Correctness: the range math assumes `tr` is a linear 1:1 apply of `steps`. Under the native collab
|
|
34
|
+
* plugin, `receiveTransaction` rebases incoming steps over unconfirmed local steps when they exist;
|
|
35
|
+
* that only invalidates our positions if a local step shifted positions, so we skip solely when a
|
|
36
|
+
* rebased local step changed sizes (a rare, safe degrade). Any unexpected error also degrades to no
|
|
37
|
+
* shimmer, so this never throws into the shared remote-step handler.
|
|
38
|
+
*/
|
|
39
|
+
export var getAgentShimmerRanges = function getAgentShimmerRanges(json, steps, tr, view, durationMs, telepointerEnabled) {
|
|
40
|
+
var _json$find;
|
|
41
|
+
if (!expValEquals('platform_editor_agent_be_streaming', 'isEnabled', true)) {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
// Nothing to reveal if the shimmer is disabled.
|
|
45
|
+
if (durationMs <= 0) {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
// Telepointer label = the agent's type upper-cased (e.g. `mcp` → "MCP"), falling back to a generic
|
|
49
|
+
// "Agent"; `undefined` when the telepointer is disabled, so the plugin skips it. `agentType` is the
|
|
50
|
+
// same on every step of an agent batch, so read it from the first agent-authored step.
|
|
51
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
52
|
+
var agentType = (_json$find = json.find(function (step) {
|
|
53
|
+
return typeof (step === null || step === void 0 ? void 0 : step.agentType) === 'string';
|
|
54
|
+
})) === null || _json$find === void 0 ? void 0 : _json$find.agentType;
|
|
55
|
+
var telepointerLabel = telepointerEnabled ? (agentType === null || agentType === void 0 ? void 0 : agentType.toUpperCase()) || 'Agent' : undefined;
|
|
56
|
+
// When the batch was rebased over local unconfirmed steps, our index-based range math is only
|
|
57
|
+
// valid if those local steps shifted no positions. Attribute-only steps (e.g. `localId`) and
|
|
58
|
+
// same-size replacements are position-neutral, so the shimmer stays correct. Skip only when a
|
|
59
|
+
// local step actually changed sizes (a genuine concurrent content edit).
|
|
60
|
+
if (Number(tr.getMeta('rebased')) > 0) {
|
|
61
|
+
var _getCollabState$uncon, _getCollabState;
|
|
62
|
+
var unconfirmed = (_getCollabState$uncon = (_getCollabState = getCollabState(view.state)) === null || _getCollabState === void 0 ? void 0 : _getCollabState.unconfirmed) !== null && _getCollabState$uncon !== void 0 ? _getCollabState$uncon : [];
|
|
63
|
+
if (unconfirmed.some(function (entry) {
|
|
64
|
+
return !isPositionNeutralStep(entry.step);
|
|
65
|
+
})) {
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
// Map an inserted range in doc_{i+1} forward through the remaining steps to final-doc coords.
|
|
71
|
+
// (A later step's own inserted content starts at its `from`; only subsequent steps shift it.)
|
|
72
|
+
var mapToFinalDoc = function mapToFinalDoc(pos, stepIndex, bias) {
|
|
73
|
+
var p = pos;
|
|
74
|
+
for (var j = stepIndex + 1; j < steps.length; j++) {
|
|
75
|
+
p = steps[j].getMap().map(p, bias);
|
|
76
|
+
}
|
|
77
|
+
return p;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// Derive each agent step's changed ranges from its StepMap — the canonical, step-type-agnostic
|
|
81
|
+
// source of what a step wrote. We only need the NEW extent (the content now in the document), in
|
|
82
|
+
// final-doc coords, since the highlight decorates content that is already present.
|
|
83
|
+
|
|
84
|
+
var infos = [];
|
|
85
|
+
json.forEach(function (rawStep, index) {
|
|
86
|
+
if (typeof (rawStep === null || rawStep === void 0 ? void 0 : rawStep.agentType) !== 'string') {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
90
|
+
var pmStep = steps[index];
|
|
91
|
+
if (typeof (pmStep === null || pmStep === void 0 ? void 0 : pmStep.getMap) !== 'function') {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
pmStep.getMap().forEach(function (_oldStart, _oldEnd, newStart, newEnd) {
|
|
95
|
+
if (newEnd <= newStart) {
|
|
96
|
+
return; // pure deletion / attribute-only — no new content to highlight
|
|
97
|
+
}
|
|
98
|
+
infos.push({
|
|
99
|
+
from: mapToFinalDoc(newStart, index, -1),
|
|
100
|
+
to: mapToFinalDoc(newEnd, index, 1)
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
if (!infos.length) {
|
|
105
|
+
return [];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Group the changed ranges by the TOP-LEVEL block they landed in, then highlight each touched
|
|
109
|
+
// block IN FULL. NCS emits a single agent edit as many small replace fragments and often keeps a
|
|
110
|
+
// common prefix/suffix untouched, so the changed sub-ranges cover only part of a block (e.g. half
|
|
111
|
+
// a rewritten heading). Expanding to the whole block's content makes the entire heading/paragraph
|
|
112
|
+
// shimmer as one unit rather than leaving the unchanged half undecorated. Directly-adjacent
|
|
113
|
+
// touched blocks (index n and n+1) merge into one group so a multi-block rewrite reveals together;
|
|
114
|
+
// a genuinely untouched block in between (index gap > 1) splits the run, so far-apart edits stay
|
|
115
|
+
// independent.
|
|
116
|
+
var docSize = tr.doc.content.size;
|
|
117
|
+
var clampPos = function clampPos(pos) {
|
|
118
|
+
return Math.min(Math.max(pos, 1), docSize);
|
|
119
|
+
};
|
|
120
|
+
var blockIndexAt = function blockIndexAt(pos) {
|
|
121
|
+
return tr.doc.resolve(clampPos(pos)).index(0);
|
|
122
|
+
};
|
|
123
|
+
// Start/end of the content of the top-level block containing `pos`, so the whole block is covered.
|
|
124
|
+
var blockContentStart = function blockContentStart(pos) {
|
|
125
|
+
var $pos = tr.doc.resolve(clampPos(pos));
|
|
126
|
+
return $pos.depth >= 1 ? $pos.start(1) : pos;
|
|
127
|
+
};
|
|
128
|
+
var blockContentEnd = function blockContentEnd(pos) {
|
|
129
|
+
var $pos = tr.doc.resolve(clampPos(pos));
|
|
130
|
+
return $pos.depth >= 1 ? $pos.end(1) : pos;
|
|
131
|
+
};
|
|
132
|
+
var sorted = [].concat(infos).sort(function (a, b) {
|
|
133
|
+
return a.from - b.from || a.to - b.to;
|
|
134
|
+
});
|
|
135
|
+
var groups = [];
|
|
136
|
+
sorted.forEach(function (info) {
|
|
137
|
+
var block = blockIndexAt(info.from);
|
|
138
|
+
var current = groups[groups.length - 1];
|
|
139
|
+
if (current && block <= current.maxBlock + 1) {
|
|
140
|
+
current.to = Math.max(current.to, info.to);
|
|
141
|
+
current.maxBlock = Math.max(current.maxBlock, block);
|
|
142
|
+
} else {
|
|
143
|
+
groups.push({
|
|
144
|
+
from: info.from,
|
|
145
|
+
to: info.to,
|
|
146
|
+
maxBlock: block
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
return groups.map(function (group) {
|
|
151
|
+
return {
|
|
152
|
+
shimmerId: "agent-shimmer-".concat(agentShimmerIdCounter++),
|
|
153
|
+
from: blockContentStart(group.from),
|
|
154
|
+
to: blockContentEnd(group.to),
|
|
155
|
+
telepointerLabel: telepointerLabel
|
|
156
|
+
};
|
|
157
|
+
});
|
|
158
|
+
} catch (_unused) {
|
|
159
|
+
// Never let shimmer range derivation throw into the shared remote-step handler; degrade to no
|
|
160
|
+
// shimmer.
|
|
161
|
+
return [];
|
|
162
|
+
}
|
|
163
|
+
};
|
|
@@ -7,6 +7,8 @@ import { Selection } from '@atlaskit/editor-prosemirror/state';
|
|
|
7
7
|
import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
8
8
|
import { Participants } from '../participants';
|
|
9
9
|
import { createTelepointers, findPointers, getPositionOfTelepointer, isReplaceStep, hasExistingNudge } from '../utils';
|
|
10
|
+
import { ADD_AGENT_SHIMMER_META, buildAgentShimmerDecorations, reduceAgentShimmers, REMOVE_AGENT_SHIMMER_META } from './agent-shimmer-decorations';
|
|
11
|
+
|
|
10
12
|
/**
|
|
11
13
|
* Returns position where it's possible to place a decoration.
|
|
12
14
|
*/
|
|
@@ -26,7 +28,10 @@ export var PluginState = /*#__PURE__*/function () {
|
|
|
26
28
|
var collabInitalised = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
27
29
|
var onError = arguments.length > 4 ? arguments[4] : undefined;
|
|
28
30
|
var nudgeAnimations = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : new Map();
|
|
31
|
+
var agentShimmers = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : [];
|
|
29
32
|
_classCallCheck(this, PluginState);
|
|
33
|
+
// Active agent-edit shimmer ranges (pure data). Replaced with a fresh array of fresh
|
|
34
|
+
// objects whenever it changes — never mutated in place.
|
|
30
35
|
// eslint-disable-next-line no-console
|
|
31
36
|
_defineProperty(this, "onError", function (error) {
|
|
32
37
|
return console.error(error);
|
|
@@ -37,6 +42,7 @@ export var PluginState = /*#__PURE__*/function () {
|
|
|
37
42
|
this.isReady = collabInitalised;
|
|
38
43
|
this.onError = onError || this.onError;
|
|
39
44
|
this.nudgeAnimations = nudgeAnimations;
|
|
45
|
+
this.agentShimmers = agentShimmers;
|
|
40
46
|
}
|
|
41
47
|
return _createClass(PluginState, [{
|
|
42
48
|
key: "decorations",
|
|
@@ -83,6 +89,8 @@ export var PluginState = /*#__PURE__*/function () {
|
|
|
83
89
|
var presenceData = tr.getMeta('presence');
|
|
84
90
|
var telepointerData = tr.getMeta('telepointer');
|
|
85
91
|
var nudgeTelepointerData = tr.getMeta('nudgeTelepointer');
|
|
92
|
+
var agentShimmerData = tr.getMeta(ADD_AGENT_SHIMMER_META);
|
|
93
|
+
var removeAgentShimmerId = tr.getMeta(REMOVE_AGENT_SHIMMER_META);
|
|
86
94
|
var sessionIdData = tr.getMeta('sessionId');
|
|
87
95
|
var collabInitialised = tr.getMeta('collabInitialised');
|
|
88
96
|
if (typeof collabInitialised !== 'boolean') {
|
|
@@ -170,6 +178,11 @@ export var PluginState = /*#__PURE__*/function () {
|
|
|
170
178
|
// Ignored via go/ees005
|
|
171
179
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
172
180
|
this.decorationSet.find().forEach(function (deco) {
|
|
181
|
+
var _deco$spec;
|
|
182
|
+
// Never let telepointer dim/side logic touch agent-shimmer decorations.
|
|
183
|
+
if ((_deco$spec = deco.spec) !== null && _deco$spec !== void 0 && _deco$spec.isAgentShimmer) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
173
186
|
if (deco.type.toDOM) {
|
|
174
187
|
var hasTelepointerDimClass = deco.type.toDOM.classList.contains(TELEPOINTER_DIM_CLASS);
|
|
175
188
|
var browser = getBrowserInfo();
|
|
@@ -198,8 +211,12 @@ export var PluginState = /*#__PURE__*/function () {
|
|
|
198
211
|
// Ignored via go/ees005
|
|
199
212
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
200
213
|
this.decorationSet.find().forEach(function (deco) {
|
|
201
|
-
var _deco$
|
|
202
|
-
|
|
214
|
+
var _deco$spec2, _deco$spec3, _deco$spec4;
|
|
215
|
+
// Never let telepointer nudge logic touch agent-shimmer decorations.
|
|
216
|
+
if ((_deco$spec2 = deco.spec) !== null && _deco$spec2 !== void 0 && _deco$spec2.isAgentShimmer) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
if (deco.type.toDOM && participants.get(nudgeSessionId) && ((_deco$spec3 = deco.spec) === null || _deco$spec3 === void 0 || (_deco$spec3 = _deco$spec3.pointer) === null || _deco$spec3 === void 0 ? void 0 : _deco$spec3.sessionId) === nudgeSessionId && ((_deco$spec4 = deco.spec) === null || _deco$spec4 === void 0 ? void 0 : _deco$spec4.key) === "telepointer-".concat(nudgeSessionId)) {
|
|
203
220
|
// Restart animation by removing and re-adding the class
|
|
204
221
|
deco.type.toDOM.classList.remove(TELEPOINTER_PULSE_DURING_TR_CLASS);
|
|
205
222
|
deco.type.toDOM.classList.remove(TELEPOINTER_PULSE_CLASS);
|
|
@@ -209,6 +226,41 @@ export var PluginState = /*#__PURE__*/function () {
|
|
|
209
226
|
}
|
|
210
227
|
});
|
|
211
228
|
}
|
|
229
|
+
|
|
230
|
+
// Register / keep-aligned / remove the agent-edit purple highlight
|
|
231
|
+
// decorations. Fully fault-isolated — it works on local copies and only merges into the shared
|
|
232
|
+
// `add`/`remove` (and commits `this.agentShimmers`) after the whole block succeeds, so a fault
|
|
233
|
+
// here can never corrupt telepointer decorations or the shared decoration set. Never mutates
|
|
234
|
+
// shimmer entries in place: each change produces a fresh array of fresh objects.
|
|
235
|
+
try {
|
|
236
|
+
var _reduceAgentShimmers = reduceAgentShimmers(this.agentShimmers, tr, agentShimmerData, removeAgentShimmerId),
|
|
237
|
+
changed = _reduceAgentShimmers.changed,
|
|
238
|
+
next = _reduceAgentShimmers.next;
|
|
239
|
+
if (changed) {
|
|
240
|
+
// Build into local arrays; only merge into the shared add/remove once the block succeeds.
|
|
241
|
+
var agentRemove = this.decorationSet.find(undefined, undefined, function (spec) {
|
|
242
|
+
return spec.isAgentShimmer;
|
|
243
|
+
});
|
|
244
|
+
var agentAdd = buildAgentShimmerDecorations(tr, next, getValidPos, this.onError);
|
|
245
|
+
|
|
246
|
+
// Commit only after the whole block succeeded.
|
|
247
|
+
remove = remove.concat(agentRemove);
|
|
248
|
+
add = add.concat(agentAdd);
|
|
249
|
+
this.agentShimmers = next;
|
|
250
|
+
}
|
|
251
|
+
} catch (err) {
|
|
252
|
+
this.onError(err);
|
|
253
|
+
// Degrade to no shimmer without corrupting telepointer decorations: drop all agent
|
|
254
|
+
// decorations and clear agent state, leaving the telepointer `add`/`remove` untouched.
|
|
255
|
+
this.agentShimmers = [];
|
|
256
|
+
try {
|
|
257
|
+
remove = remove.concat(this.decorationSet.find(undefined, undefined, function (spec) {
|
|
258
|
+
return spec.isAgentShimmer;
|
|
259
|
+
}));
|
|
260
|
+
} catch (_unused) {
|
|
261
|
+
// Teardown must not re-throw.
|
|
262
|
+
}
|
|
263
|
+
}
|
|
212
264
|
if (remove.length) {
|
|
213
265
|
this.decorationSet = this.decorationSet.remove(remove);
|
|
214
266
|
}
|
|
@@ -227,7 +279,7 @@ export var PluginState = /*#__PURE__*/function () {
|
|
|
227
279
|
}
|
|
228
280
|
}
|
|
229
281
|
}
|
|
230
|
-
var nextState = new PluginState(this.decorationSet, participants, sid, collabInitialised, this.onError, this.nudgeAnimations);
|
|
282
|
+
var nextState = new PluginState(this.decorationSet, participants, sid, collabInitialised, this.onError, this.nudgeAnimations, this.agentShimmers);
|
|
231
283
|
return PluginState.eq(nextState, this) ? this : nextState;
|
|
232
284
|
}
|
|
233
285
|
}], [{
|
|
@@ -10,8 +10,12 @@ import { Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
|
10
10
|
import { getParticipantColor } from '@atlaskit/editor-shared-styles';
|
|
11
11
|
import { preserveNodeIdentity } from './preserve-node-identity';
|
|
12
12
|
export var findPointers = function findPointers(id, decorations) {
|
|
13
|
-
return decorations.find().reduce(
|
|
14
|
-
|
|
13
|
+
return decorations.find().reduce(
|
|
14
|
+
// `pointer` is absent on non-telepointer decorations (e.g. the agent-shimmer
|
|
15
|
+
// sweep decorations), so guard against it to avoid crashing this shared helper.
|
|
16
|
+
function (arr, deco) {
|
|
17
|
+
var _deco$spec$pointer;
|
|
18
|
+
return ((_deco$spec$pointer = deco.spec.pointer) === null || _deco$spec$pointer === void 0 ? void 0 : _deco$spec$pointer.presenceId) === id ? arr.concat(deco) : arr;
|
|
15
19
|
}, []);
|
|
16
20
|
};
|
|
17
21
|
function style(options) {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ReadonlyTransaction } from '@atlaskit/editor-prosemirror/state';
|
|
2
|
+
import { Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
3
|
+
/** Default time the skeleton shimmer stays on the agent-authored content (ms). */
|
|
4
|
+
export declare const AGENT_SHIMMER_DEFAULT_DURATION_MS = 3000;
|
|
5
|
+
export declare const AGENT_SHIMMER_CLASS = "collab-agent-shimmer";
|
|
6
|
+
export declare const ROVO_AGENT_TELEPOINTER_CLASS = "ai-in-editor-telepointer";
|
|
7
|
+
export declare const ROVO_AGENT_TELEPOINTER_LABEL_CLASS = "ai-in-editor-telepointer-label";
|
|
8
|
+
export declare const ADD_AGENT_SHIMMER_META = "addAgentShimmer";
|
|
9
|
+
export declare const REMOVE_AGENT_SHIMMER_META = "removeAgentShimmer";
|
|
10
|
+
export type AgentShimmerRange = {
|
|
11
|
+
from: number;
|
|
12
|
+
shimmerId: string;
|
|
13
|
+
telepointerLabel?: string;
|
|
14
|
+
to: number;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Pure reducer for the active shimmer ranges from a transaction's changes. Maps existing ranges
|
|
18
|
+
* forward as the doc changes, replaces them wholesale when a new agent batch lands (a new batch
|
|
19
|
+
* supersedes any still-in-flight shimmer), and drops a range when its removal timer fires. Returns a
|
|
20
|
+
* fresh array (never mutates in place) plus whether anything changed.
|
|
21
|
+
*/
|
|
22
|
+
export declare const reduceAgentShimmers: (current: AgentShimmerRange[], tr: ReadonlyTransaction, added: AgentShimmerRange[] | undefined, removedShimmerId: string | undefined) => {
|
|
23
|
+
changed: boolean;
|
|
24
|
+
next: AgentShimmerRange[];
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Builds the inline skeleton-bar + trailing telepointer decorations for the active shimmer ranges.
|
|
28
|
+
* `getValidPos` clamps a raw position to a valid decoration position (owned by `plugin-state`).
|
|
29
|
+
* One bad range is isolated via `onError` so it can't kill the others.
|
|
30
|
+
*/
|
|
31
|
+
export declare const buildAgentShimmerDecorations: (tr: ReadonlyTransaction, shimmers: AgentShimmerRange[], getValidPos: (tr: ReadonlyTransaction, pos: number) => number, onError: (err: Error) => void) => Decoration[];
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Transaction } from '@atlaskit/editor-prosemirror/state';
|
|
2
|
+
import type { Step } from '@atlaskit/editor-prosemirror/transform';
|
|
3
|
+
import type { EditorView } from '@atlaskit/editor-prosemirror/view';
|
|
4
|
+
import type { AgentShimmerRange } from './agent-shimmer-decorations';
|
|
5
|
+
export declare const isPositionNeutralStep: (step: Step) => boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Derive the shimmer ranges for the agent-authored steps in a received batch, in final-doc
|
|
8
|
+
* coordinates. `agentType` present ⇒ agent-authored (per the NCS↔Editor steps contract). Each
|
|
9
|
+
* emitted range is expanded to the whole top-level block(s) the agent touched, which the plugin
|
|
10
|
+
* covers with the skeleton shimmer. Ranges with no new content (pure deletions) are dropped.
|
|
11
|
+
*
|
|
12
|
+
* Steps whose new content is in the same or directly-adjacent top-level block are coalesced into one
|
|
13
|
+
* range, so an edit that arrives as several steps in a region shimmers as a single unit. Edits
|
|
14
|
+
* separated by an untouched block stay independent.
|
|
15
|
+
*
|
|
16
|
+
* Correctness: the range math assumes `tr` is a linear 1:1 apply of `steps`. Under the native collab
|
|
17
|
+
* plugin, `receiveTransaction` rebases incoming steps over unconfirmed local steps when they exist;
|
|
18
|
+
* that only invalidates our positions if a local step shifted positions, so we skip solely when a
|
|
19
|
+
* rebased local step changed sizes (a rare, safe degrade). Any unexpected error also degrades to no
|
|
20
|
+
* shimmer, so this never throws into the shared remote-step handler.
|
|
21
|
+
*/
|
|
22
|
+
export declare const getAgentShimmerRanges: (json: any[], steps: Step[], tr: Transaction, view: EditorView, durationMs: number, telepointerEnabled: boolean) => AgentShimmerRange[];
|
|
@@ -3,6 +3,7 @@ import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
|
3
3
|
import type { ReadOnlyParticipants } from '../../types';
|
|
4
4
|
import { Participants } from '../participants';
|
|
5
5
|
import type { NudgeAnimationsMap } from '../utils';
|
|
6
|
+
import { type AgentShimmerRange } from './agent-shimmer-decorations';
|
|
6
7
|
/**
|
|
7
8
|
* Returns position where it's possible to place a decoration.
|
|
8
9
|
*/
|
|
@@ -11,13 +12,14 @@ export declare class PluginState {
|
|
|
11
12
|
private decorationSet;
|
|
12
13
|
private participants;
|
|
13
14
|
private nudgeAnimations;
|
|
15
|
+
private agentShimmers;
|
|
14
16
|
private onError;
|
|
15
17
|
private sid?;
|
|
16
18
|
isReady: boolean;
|
|
17
19
|
get decorations(): DecorationSet;
|
|
18
20
|
get activeParticipants(): ReadOnlyParticipants;
|
|
19
21
|
get sessionId(): string | undefined;
|
|
20
|
-
constructor(decorations: DecorationSet, participants: Participants, sessionId?: string, collabInitalised?: boolean, onError?: (err: Error) => void, nudgeAnimations?: NudgeAnimationsMap);
|
|
22
|
+
constructor(decorations: DecorationSet, participants: Participants, sessionId?: string, collabInitalised?: boolean, onError?: (err: Error) => void, nudgeAnimations?: NudgeAnimationsMap, agentShimmers?: AgentShimmerRange[]);
|
|
21
23
|
getFullName(sessionId: string): string;
|
|
22
24
|
getInitial(sessionId: string): string;
|
|
23
25
|
getPresenceId(sessionId: string): string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-collab-edit",
|
|
3
|
-
"version": "13.0
|
|
3
|
+
"version": "13.1.0",
|
|
4
4
|
"description": "Collab Edit plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -31,13 +31,13 @@
|
|
|
31
31
|
"@atlaskit/frontend-utilities": "^4.1.0",
|
|
32
32
|
"@atlaskit/platform-feature-flags": "^2.1.0",
|
|
33
33
|
"@atlaskit/prosemirror-collab": "^1.0.0",
|
|
34
|
-
"@atlaskit/tmp-editor-statsig": "^132.
|
|
35
|
-
"@atlaskit/tokens": "^16.
|
|
34
|
+
"@atlaskit/tmp-editor-statsig": "^132.3.0",
|
|
35
|
+
"@atlaskit/tokens": "^16.3.0",
|
|
36
36
|
"@babel/runtime": "^7.0.0",
|
|
37
37
|
"memoize-one": "^6.0.0"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
|
-
"@atlaskit/editor-common": "^116.
|
|
40
|
+
"@atlaskit/editor-common": "^116.36.0",
|
|
41
41
|
"react": "^18.2.0",
|
|
42
42
|
"react-dom": "^18.2.0"
|
|
43
43
|
},
|
|
@@ -86,6 +86,9 @@
|
|
|
86
86
|
"platform-feature-flags": {
|
|
87
87
|
"platform_editor_collab_organic_change_reporting": {
|
|
88
88
|
"type": "boolean"
|
|
89
|
+
},
|
|
90
|
+
"platform_editor_agent_be_streaming": {
|
|
91
|
+
"type": "experiment"
|
|
89
92
|
}
|
|
90
93
|
}
|
|
91
94
|
}
|