@atlaskit/editor-plugin-collab-edit 3.9.5 → 3.10.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 +13 -0
- package/dist/cjs/pm-plugins/main/plugin-state.js +10 -2
- package/dist/cjs/pm-plugins/utils.js +22 -2
- package/dist/es2019/pm-plugins/main/plugin-state.js +12 -5
- package/dist/es2019/pm-plugins/utils.js +22 -2
- package/dist/esm/pm-plugins/main/plugin-state.js +12 -4
- package/dist/esm/pm-plugins/utils.js +22 -2
- package/dist/types/pm-plugins/main/plugin-state.d.ts +3 -1
- package/dist/types/pm-plugins/utils.d.ts +3 -1
- package/dist/types-ts4.5/pm-plugins/main/plugin-state.d.ts +3 -1
- package/dist/types-ts4.5/pm-plugins/utils.d.ts +3 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-collab-edit
|
|
2
2
|
|
|
3
|
+
## 3.10.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#171561](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/171561)
|
|
8
|
+
[`d0c41c462c511`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/d0c41c462c511) -
|
|
9
|
+
[ux] Telepointers now stay expanded even if there are other transactions received which will
|
|
10
|
+
re-create their DOM elements.
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- Updated dependencies
|
|
15
|
+
|
|
3
16
|
## 3.9.5
|
|
4
17
|
|
|
5
18
|
### Patch Changes
|
|
@@ -33,6 +33,7 @@ var PluginState = exports.PluginState = /*#__PURE__*/function () {
|
|
|
33
33
|
function PluginState(decorations, participants, sessionId) {
|
|
34
34
|
var collabInitalised = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
35
35
|
var onError = arguments.length > 4 ? arguments[4] : undefined;
|
|
36
|
+
var nudgeAnimations = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : new Map();
|
|
36
37
|
(0, _classCallCheck2.default)(this, PluginState);
|
|
37
38
|
// eslint-disable-next-line no-console
|
|
38
39
|
(0, _defineProperty2.default)(this, "onError", function (error) {
|
|
@@ -43,6 +44,7 @@ var PluginState = exports.PluginState = /*#__PURE__*/function () {
|
|
|
43
44
|
this.sid = sessionId;
|
|
44
45
|
this.isReady = collabInitalised;
|
|
45
46
|
this.onError = onError || this.onError;
|
|
47
|
+
this.nudgeAnimations = nudgeAnimations;
|
|
46
48
|
}
|
|
47
49
|
return (0, _createClass2.default)(PluginState, [{
|
|
48
50
|
key: "decorations",
|
|
@@ -158,7 +160,7 @@ var PluginState = exports.PluginState = /*#__PURE__*/function () {
|
|
|
158
160
|
} catch (err) {
|
|
159
161
|
this.onError(err);
|
|
160
162
|
}
|
|
161
|
-
add = add.concat((0, _utils.createTelepointers)(from, to, sessionId, isSelection, this.getInitial(sessionId), this.getPresenceId(sessionId), this.getFullName(sessionId)));
|
|
163
|
+
add = add.concat((0, _utils.createTelepointers)(from, to, sessionId, isSelection, this.getInitial(sessionId), this.getPresenceId(sessionId), this.getFullName(sessionId), (0, _platformFeatureFlags.fg)('confluence_team_presence_scroll_to_pointer') ? (0, _utils.hasExistingNudge)(sessionId, this.nudgeAnimations) : false));
|
|
162
164
|
}
|
|
163
165
|
}
|
|
164
166
|
if (tr.docChanged) {
|
|
@@ -177,7 +179,7 @@ var PluginState = exports.PluginState = /*#__PURE__*/function () {
|
|
|
177
179
|
size = _ref.slice.content.size,
|
|
178
180
|
_from = _ref.from;
|
|
179
181
|
var pos = getValidPos(tr, size ? Math.min(_from + size, tr.doc.nodeSize - 3) : Math.max(_from, 1));
|
|
180
|
-
add = add.concat((0, _utils.createTelepointers)(pos, pos, _sessionId, false, _this.getInitial(_sessionId), presenceId, _this.getFullName(_sessionId)));
|
|
182
|
+
add = add.concat((0, _utils.createTelepointers)(pos, pos, _sessionId, false, _this.getInitial(_sessionId), presenceId, _this.getFullName(_sessionId), (0, _platformFeatureFlags.fg)('confluence_team_presence_scroll_to_pointer') ? (0, _utils.hasExistingNudge)(_sessionId, _this.nudgeAnimations) : false));
|
|
181
183
|
}
|
|
182
184
|
}
|
|
183
185
|
}
|
|
@@ -239,9 +241,11 @@ var PluginState = exports.PluginState = /*#__PURE__*/function () {
|
|
|
239
241
|
var _deco$spec, _deco$spec2;
|
|
240
242
|
if (deco.type.toDOM && participants.get(nudgeSessionId) && ((_deco$spec = deco.spec) === null || _deco$spec === void 0 || (_deco$spec = _deco$spec.pointer) === null || _deco$spec === void 0 ? void 0 : _deco$spec.sessionId) === nudgeSessionId && ((_deco$spec2 = deco.spec) === null || _deco$spec2 === void 0 ? void 0 : _deco$spec2.key) === "telepointer-".concat(nudgeSessionId)) {
|
|
241
243
|
// Restart animation by removing and re-adding the class
|
|
244
|
+
deco.type.toDOM.classList.remove(_collab.TELEPOINTER_PULSE_DURING_TR_CLASS);
|
|
242
245
|
deco.type.toDOM.classList.remove(_collab.TELEPOINTER_PULSE_CLASS);
|
|
243
246
|
void deco.type.toDOM.offsetWidth; // Force reflow
|
|
244
247
|
deco.type.toDOM.classList.add(_collab.TELEPOINTER_PULSE_CLASS);
|
|
248
|
+
_this.nudgeAnimations.set(nudgeSessionId, Date.now());
|
|
245
249
|
}
|
|
246
250
|
});
|
|
247
251
|
}
|
|
@@ -263,6 +267,10 @@ var PluginState = exports.PluginState = /*#__PURE__*/function () {
|
|
|
263
267
|
}
|
|
264
268
|
}
|
|
265
269
|
}
|
|
270
|
+
if ((0, _platformFeatureFlags.fg)('confluence_team_presence_scroll_to_pointer')) {
|
|
271
|
+
var _nextState = new PluginState(this.decorationSet, participants, sid, collabInitialised, this.onError, this.nudgeAnimations);
|
|
272
|
+
return PluginState.eq(_nextState, this) ? this : _nextState;
|
|
273
|
+
}
|
|
266
274
|
var nextState = new PluginState(this.decorationSet, participants, sid, collabInitialised);
|
|
267
275
|
return PluginState.eq(nextState, this) ? this : nextState;
|
|
268
276
|
}
|
|
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
});
|
|
7
7
|
exports.findPointers = exports.createTelepointers = exports._findPointers = void 0;
|
|
8
8
|
exports.getAvatarColor = getAvatarColor;
|
|
9
|
-
exports.scrollToCollabCursor = exports.replaceDocument = exports.originalTransactionHasMeta = exports.isReplaceStep = exports.isOrganicChange = exports.getPositionOfTelepointer = void 0;
|
|
9
|
+
exports.scrollToCollabCursor = exports.replaceDocument = exports.originalTransactionHasMeta = exports.isReplaceStep = exports.isOrganicChange = exports.hasExistingNudge = exports.getPositionOfTelepointer = void 0;
|
|
10
10
|
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
|
|
11
11
|
var _steps = require("@atlaskit/adf-schema/steps");
|
|
12
12
|
var _analytics = require("@atlaskit/editor-common/analytics");
|
|
@@ -46,7 +46,7 @@ function getAvatarColor(str) {
|
|
|
46
46
|
textColor: participantColor.color.textColor
|
|
47
47
|
};
|
|
48
48
|
}
|
|
49
|
-
var createTelepointers = exports.createTelepointers = function createTelepointers(from, to, sessionId, isSelection, initial, presenceId, fullName) {
|
|
49
|
+
var createTelepointers = exports.createTelepointers = function createTelepointers(from, to, sessionId, isSelection, initial, presenceId, fullName, isNudged) {
|
|
50
50
|
var decorations = [];
|
|
51
51
|
var avatarColor = getAvatarColor(presenceId);
|
|
52
52
|
var color = avatarColor.index.toString();
|
|
@@ -78,6 +78,12 @@ var createTelepointers = exports.createTelepointers = function createTelepointer
|
|
|
78
78
|
cursor.setAttribute('data-initial', initial);
|
|
79
79
|
if ((0, _platformFeatureFlags.fg)('confluence_team_presence_scroll_to_pointer')) {
|
|
80
80
|
cursor.setAttribute(_collab.TELEPOINTER_DATA_SESSION_ID_ATTR, sessionId);
|
|
81
|
+
// If there is an ongoing expand animation, we'll keep the telepointer expanded
|
|
82
|
+
// until the keyframe animation is complete. Please note that this will restart the anim timer
|
|
83
|
+
// from 0 everytime it's re-added.
|
|
84
|
+
if (isNudged) {
|
|
85
|
+
cursor.classList.add(_collab.TELEPOINTER_PULSE_DURING_TR_CLASS);
|
|
86
|
+
}
|
|
81
87
|
var fullNameEl = document.createElement('span');
|
|
82
88
|
fullNameEl.textContent = fullName;
|
|
83
89
|
fullNameEl.className = 'telepointer-fullname';
|
|
@@ -239,4 +245,18 @@ var isOrganicChange = exports.isOrganicChange = function isOrganicChange(tr) {
|
|
|
239
245
|
}
|
|
240
246
|
}) && !tr.doc.eq(tr.before);
|
|
241
247
|
});
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
// If we receive a transaction while there is an ongoing CSS expand animation in the telepointer,
|
|
251
|
+
// it will be cut off due to the removal of the element. We'll persist the animation state in the plugin,
|
|
252
|
+
// so we can keep the expanded version showing even when the telepointer element is recreated.
|
|
253
|
+
|
|
254
|
+
var hasExistingNudge = exports.hasExistingNudge = function hasExistingNudge(sessionId, nudgeAnimations) {
|
|
255
|
+
var nudgeAnimStartTime = nudgeAnimations.get(sessionId);
|
|
256
|
+
var hasExistingNudge = false;
|
|
257
|
+
if (nudgeAnimStartTime) {
|
|
258
|
+
var timeElapsed = Date.now() - nudgeAnimStartTime;
|
|
259
|
+
hasExistingNudge = timeElapsed < _collab.TELEPOINTER_PULSE_DURING_TR_DURATION_MS;
|
|
260
|
+
}
|
|
261
|
+
return hasExistingNudge;
|
|
242
262
|
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
2
|
import { browser } from '@atlaskit/editor-common/browser';
|
|
3
|
-
import { TELEPOINTER_DIM_CLASS, TELEPOINTER_PULSE_CLASS } from '@atlaskit/editor-common/collab';
|
|
3
|
+
import { TELEPOINTER_DIM_CLASS, TELEPOINTER_PULSE_CLASS, TELEPOINTER_PULSE_DURING_TR_CLASS } from '@atlaskit/editor-common/collab';
|
|
4
4
|
import { Selection } from '@atlaskit/editor-prosemirror/state';
|
|
5
5
|
import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
6
6
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
7
7
|
import { Participants } from '../participants';
|
|
8
|
-
import { createTelepointers, _findPointers, findPointers, getPositionOfTelepointer, isReplaceStep } from '../utils';
|
|
8
|
+
import { createTelepointers, _findPointers, findPointers, getPositionOfTelepointer, isReplaceStep, hasExistingNudge } from '../utils';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Returns position where it's possible to place a decoration.
|
|
@@ -31,7 +31,7 @@ export class PluginState {
|
|
|
31
31
|
get sessionId() {
|
|
32
32
|
return this.sid;
|
|
33
33
|
}
|
|
34
|
-
constructor(decorations, participants, sessionId, collabInitalised = false, onError) {
|
|
34
|
+
constructor(decorations, participants, sessionId, collabInitalised = false, onError, nudgeAnimations = new Map()) {
|
|
35
35
|
// eslint-disable-next-line no-console
|
|
36
36
|
_defineProperty(this, "onError", error => console.error(error));
|
|
37
37
|
this.decorationSet = decorations;
|
|
@@ -39,6 +39,7 @@ export class PluginState {
|
|
|
39
39
|
this.sid = sessionId;
|
|
40
40
|
this.isReady = collabInitalised;
|
|
41
41
|
this.onError = onError || this.onError;
|
|
42
|
+
this.nudgeAnimations = nudgeAnimations;
|
|
42
43
|
}
|
|
43
44
|
getFullName(sessionId) {
|
|
44
45
|
const participant = this.participants.get(sessionId);
|
|
@@ -132,7 +133,7 @@ export class PluginState {
|
|
|
132
133
|
} catch (err) {
|
|
133
134
|
this.onError(err);
|
|
134
135
|
}
|
|
135
|
-
add = add.concat(createTelepointers(from, to, sessionId, isSelection, this.getInitial(sessionId), this.getPresenceId(sessionId), this.getFullName(sessionId)));
|
|
136
|
+
add = add.concat(createTelepointers(from, to, sessionId, isSelection, this.getInitial(sessionId), this.getPresenceId(sessionId), this.getFullName(sessionId), fg('confluence_team_presence_scroll_to_pointer') ? hasExistingNudge(sessionId, this.nudgeAnimations) : false));
|
|
136
137
|
}
|
|
137
138
|
}
|
|
138
139
|
if (tr.docChanged) {
|
|
@@ -159,7 +160,7 @@ export class PluginState {
|
|
|
159
160
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
160
161
|
} = step;
|
|
161
162
|
const pos = getValidPos(tr, size ? Math.min(from + size, tr.doc.nodeSize - 3) : Math.max(from, 1));
|
|
162
|
-
add = add.concat(createTelepointers(pos, pos, sessionId, false, this.getInitial(sessionId), presenceId, this.getFullName(sessionId)));
|
|
163
|
+
add = add.concat(createTelepointers(pos, pos, sessionId, false, this.getInitial(sessionId), presenceId, this.getFullName(sessionId), fg('confluence_team_presence_scroll_to_pointer') ? hasExistingNudge(sessionId, this.nudgeAnimations) : false));
|
|
163
164
|
}
|
|
164
165
|
}
|
|
165
166
|
}
|
|
@@ -224,9 +225,11 @@ export class PluginState {
|
|
|
224
225
|
var _deco$spec, _deco$spec$pointer, _deco$spec2;
|
|
225
226
|
if (deco.type.toDOM && participants.get(nudgeSessionId) && ((_deco$spec = deco.spec) === null || _deco$spec === void 0 ? void 0 : (_deco$spec$pointer = _deco$spec.pointer) === null || _deco$spec$pointer === void 0 ? void 0 : _deco$spec$pointer.sessionId) === nudgeSessionId && ((_deco$spec2 = deco.spec) === null || _deco$spec2 === void 0 ? void 0 : _deco$spec2.key) === `telepointer-${nudgeSessionId}`) {
|
|
226
227
|
// Restart animation by removing and re-adding the class
|
|
228
|
+
deco.type.toDOM.classList.remove(TELEPOINTER_PULSE_DURING_TR_CLASS);
|
|
227
229
|
deco.type.toDOM.classList.remove(TELEPOINTER_PULSE_CLASS);
|
|
228
230
|
void deco.type.toDOM.offsetWidth; // Force reflow
|
|
229
231
|
deco.type.toDOM.classList.add(TELEPOINTER_PULSE_CLASS);
|
|
232
|
+
this.nudgeAnimations.set(nudgeSessionId, Date.now());
|
|
230
233
|
}
|
|
231
234
|
});
|
|
232
235
|
}
|
|
@@ -250,6 +253,10 @@ export class PluginState {
|
|
|
250
253
|
}
|
|
251
254
|
}
|
|
252
255
|
}
|
|
256
|
+
if (fg('confluence_team_presence_scroll_to_pointer')) {
|
|
257
|
+
const nextState = new PluginState(this.decorationSet, participants, sid, collabInitialised, this.onError, this.nudgeAnimations);
|
|
258
|
+
return PluginState.eq(nextState, this) ? this : nextState;
|
|
259
|
+
}
|
|
253
260
|
const nextState = new PluginState(this.decorationSet, participants, sid, collabInitialised);
|
|
254
261
|
return PluginState.eq(nextState, this) ? this : nextState;
|
|
255
262
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AnalyticsStep, SetAttrsStep } from '@atlaskit/adf-schema/steps';
|
|
2
2
|
import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
|
|
3
|
-
import { TELEPOINTER_DATA_SESSION_ID_ATTR } from '@atlaskit/editor-common/collab';
|
|
3
|
+
import { TELEPOINTER_DATA_SESSION_ID_ATTR, TELEPOINTER_PULSE_DURING_TR_CLASS, TELEPOINTER_PULSE_DURING_TR_DURATION_MS } from '@atlaskit/editor-common/collab';
|
|
4
4
|
import { processRawValueWithoutValidation } from '@atlaskit/editor-common/process-raw-value';
|
|
5
5
|
import { ZERO_WIDTH_JOINER } from '@atlaskit/editor-common/whitespace';
|
|
6
6
|
import { Transaction, Selection, TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
@@ -28,7 +28,7 @@ export function getAvatarColor(str) {
|
|
|
28
28
|
textColor: participantColor.color.textColor
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
|
-
export const createTelepointers = (from, to, sessionId, isSelection, initial, presenceId, fullName) => {
|
|
31
|
+
export const createTelepointers = (from, to, sessionId, isSelection, initial, presenceId, fullName, isNudged) => {
|
|
32
32
|
const decorations = [];
|
|
33
33
|
const avatarColor = getAvatarColor(presenceId);
|
|
34
34
|
const color = avatarColor.index.toString();
|
|
@@ -60,6 +60,12 @@ export const createTelepointers = (from, to, sessionId, isSelection, initial, pr
|
|
|
60
60
|
cursor.setAttribute('data-initial', initial);
|
|
61
61
|
if (fg('confluence_team_presence_scroll_to_pointer')) {
|
|
62
62
|
cursor.setAttribute(TELEPOINTER_DATA_SESSION_ID_ATTR, sessionId);
|
|
63
|
+
// If there is an ongoing expand animation, we'll keep the telepointer expanded
|
|
64
|
+
// until the keyframe animation is complete. Please note that this will restart the anim timer
|
|
65
|
+
// from 0 everytime it's re-added.
|
|
66
|
+
if (isNudged) {
|
|
67
|
+
cursor.classList.add(TELEPOINTER_PULSE_DURING_TR_CLASS);
|
|
68
|
+
}
|
|
63
69
|
const fullNameEl = document.createElement('span');
|
|
64
70
|
fullNameEl.textContent = fullName;
|
|
65
71
|
fullNameEl.className = 'telepointer-fullname';
|
|
@@ -223,4 +229,18 @@ export const isOrganicChange = tr => {
|
|
|
223
229
|
}
|
|
224
230
|
}) && !tr.doc.eq(tr.before);
|
|
225
231
|
});
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
// If we receive a transaction while there is an ongoing CSS expand animation in the telepointer,
|
|
235
|
+
// it will be cut off due to the removal of the element. We'll persist the animation state in the plugin,
|
|
236
|
+
// so we can keep the expanded version showing even when the telepointer element is recreated.
|
|
237
|
+
|
|
238
|
+
export const hasExistingNudge = (sessionId, nudgeAnimations) => {
|
|
239
|
+
const nudgeAnimStartTime = nudgeAnimations.get(sessionId);
|
|
240
|
+
let hasExistingNudge = false;
|
|
241
|
+
if (nudgeAnimStartTime) {
|
|
242
|
+
const timeElapsed = Date.now() - nudgeAnimStartTime;
|
|
243
|
+
hasExistingNudge = timeElapsed < TELEPOINTER_PULSE_DURING_TR_DURATION_MS;
|
|
244
|
+
}
|
|
245
|
+
return hasExistingNudge;
|
|
226
246
|
};
|
|
@@ -2,12 +2,12 @@ import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
|
2
2
|
import _createClass from "@babel/runtime/helpers/createClass";
|
|
3
3
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
4
4
|
import { browser } from '@atlaskit/editor-common/browser';
|
|
5
|
-
import { TELEPOINTER_DIM_CLASS, TELEPOINTER_PULSE_CLASS } from '@atlaskit/editor-common/collab';
|
|
5
|
+
import { TELEPOINTER_DIM_CLASS, TELEPOINTER_PULSE_CLASS, TELEPOINTER_PULSE_DURING_TR_CLASS } from '@atlaskit/editor-common/collab';
|
|
6
6
|
import { Selection } from '@atlaskit/editor-prosemirror/state';
|
|
7
7
|
import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
8
8
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
9
9
|
import { Participants } from '../participants';
|
|
10
|
-
import { createTelepointers, _findPointers, findPointers, getPositionOfTelepointer, isReplaceStep } from '../utils';
|
|
10
|
+
import { createTelepointers, _findPointers, findPointers, getPositionOfTelepointer, isReplaceStep, hasExistingNudge } from '../utils';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Returns position where it's possible to place a decoration.
|
|
@@ -27,6 +27,7 @@ export var PluginState = /*#__PURE__*/function () {
|
|
|
27
27
|
function PluginState(decorations, participants, sessionId) {
|
|
28
28
|
var collabInitalised = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
29
29
|
var onError = arguments.length > 4 ? arguments[4] : undefined;
|
|
30
|
+
var nudgeAnimations = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : new Map();
|
|
30
31
|
_classCallCheck(this, PluginState);
|
|
31
32
|
// eslint-disable-next-line no-console
|
|
32
33
|
_defineProperty(this, "onError", function (error) {
|
|
@@ -37,6 +38,7 @@ export var PluginState = /*#__PURE__*/function () {
|
|
|
37
38
|
this.sid = sessionId;
|
|
38
39
|
this.isReady = collabInitalised;
|
|
39
40
|
this.onError = onError || this.onError;
|
|
41
|
+
this.nudgeAnimations = nudgeAnimations;
|
|
40
42
|
}
|
|
41
43
|
return _createClass(PluginState, [{
|
|
42
44
|
key: "decorations",
|
|
@@ -152,7 +154,7 @@ export var PluginState = /*#__PURE__*/function () {
|
|
|
152
154
|
} catch (err) {
|
|
153
155
|
this.onError(err);
|
|
154
156
|
}
|
|
155
|
-
add = add.concat(createTelepointers(from, to, sessionId, isSelection, this.getInitial(sessionId), this.getPresenceId(sessionId), this.getFullName(sessionId)));
|
|
157
|
+
add = add.concat(createTelepointers(from, to, sessionId, isSelection, this.getInitial(sessionId), this.getPresenceId(sessionId), this.getFullName(sessionId), fg('confluence_team_presence_scroll_to_pointer') ? hasExistingNudge(sessionId, this.nudgeAnimations) : false));
|
|
156
158
|
}
|
|
157
159
|
}
|
|
158
160
|
if (tr.docChanged) {
|
|
@@ -171,7 +173,7 @@ export var PluginState = /*#__PURE__*/function () {
|
|
|
171
173
|
size = _ref.slice.content.size,
|
|
172
174
|
_from = _ref.from;
|
|
173
175
|
var pos = getValidPos(tr, size ? Math.min(_from + size, tr.doc.nodeSize - 3) : Math.max(_from, 1));
|
|
174
|
-
add = add.concat(createTelepointers(pos, pos, _sessionId, false, _this.getInitial(_sessionId), presenceId, _this.getFullName(_sessionId)));
|
|
176
|
+
add = add.concat(createTelepointers(pos, pos, _sessionId, false, _this.getInitial(_sessionId), presenceId, _this.getFullName(_sessionId), fg('confluence_team_presence_scroll_to_pointer') ? hasExistingNudge(_sessionId, _this.nudgeAnimations) : false));
|
|
175
177
|
}
|
|
176
178
|
}
|
|
177
179
|
}
|
|
@@ -233,9 +235,11 @@ export var PluginState = /*#__PURE__*/function () {
|
|
|
233
235
|
var _deco$spec, _deco$spec2;
|
|
234
236
|
if (deco.type.toDOM && participants.get(nudgeSessionId) && ((_deco$spec = deco.spec) === null || _deco$spec === void 0 || (_deco$spec = _deco$spec.pointer) === null || _deco$spec === void 0 ? void 0 : _deco$spec.sessionId) === nudgeSessionId && ((_deco$spec2 = deco.spec) === null || _deco$spec2 === void 0 ? void 0 : _deco$spec2.key) === "telepointer-".concat(nudgeSessionId)) {
|
|
235
237
|
// Restart animation by removing and re-adding the class
|
|
238
|
+
deco.type.toDOM.classList.remove(TELEPOINTER_PULSE_DURING_TR_CLASS);
|
|
236
239
|
deco.type.toDOM.classList.remove(TELEPOINTER_PULSE_CLASS);
|
|
237
240
|
void deco.type.toDOM.offsetWidth; // Force reflow
|
|
238
241
|
deco.type.toDOM.classList.add(TELEPOINTER_PULSE_CLASS);
|
|
242
|
+
_this.nudgeAnimations.set(nudgeSessionId, Date.now());
|
|
239
243
|
}
|
|
240
244
|
});
|
|
241
245
|
}
|
|
@@ -257,6 +261,10 @@ export var PluginState = /*#__PURE__*/function () {
|
|
|
257
261
|
}
|
|
258
262
|
}
|
|
259
263
|
}
|
|
264
|
+
if (fg('confluence_team_presence_scroll_to_pointer')) {
|
|
265
|
+
var _nextState = new PluginState(this.decorationSet, participants, sid, collabInitialised, this.onError, this.nudgeAnimations);
|
|
266
|
+
return PluginState.eq(_nextState, this) ? this : _nextState;
|
|
267
|
+
}
|
|
260
268
|
var nextState = new PluginState(this.decorationSet, participants, sid, collabInitialised);
|
|
261
269
|
return PluginState.eq(nextState, this) ? this : nextState;
|
|
262
270
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import _typeof from "@babel/runtime/helpers/typeof";
|
|
2
2
|
import { AnalyticsStep, SetAttrsStep } from '@atlaskit/adf-schema/steps';
|
|
3
3
|
import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
|
|
4
|
-
import { TELEPOINTER_DATA_SESSION_ID_ATTR } from '@atlaskit/editor-common/collab';
|
|
4
|
+
import { TELEPOINTER_DATA_SESSION_ID_ATTR, TELEPOINTER_PULSE_DURING_TR_CLASS, TELEPOINTER_PULSE_DURING_TR_DURATION_MS } from '@atlaskit/editor-common/collab';
|
|
5
5
|
import { processRawValueWithoutValidation } from '@atlaskit/editor-common/process-raw-value';
|
|
6
6
|
import { ZERO_WIDTH_JOINER } from '@atlaskit/editor-common/whitespace';
|
|
7
7
|
import { Transaction, Selection, TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
@@ -37,7 +37,7 @@ export function getAvatarColor(str) {
|
|
|
37
37
|
textColor: participantColor.color.textColor
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
|
-
export var createTelepointers = function createTelepointers(from, to, sessionId, isSelection, initial, presenceId, fullName) {
|
|
40
|
+
export var createTelepointers = function createTelepointers(from, to, sessionId, isSelection, initial, presenceId, fullName, isNudged) {
|
|
41
41
|
var decorations = [];
|
|
42
42
|
var avatarColor = getAvatarColor(presenceId);
|
|
43
43
|
var color = avatarColor.index.toString();
|
|
@@ -69,6 +69,12 @@ export var createTelepointers = function createTelepointers(from, to, sessionId,
|
|
|
69
69
|
cursor.setAttribute('data-initial', initial);
|
|
70
70
|
if (fg('confluence_team_presence_scroll_to_pointer')) {
|
|
71
71
|
cursor.setAttribute(TELEPOINTER_DATA_SESSION_ID_ATTR, sessionId);
|
|
72
|
+
// If there is an ongoing expand animation, we'll keep the telepointer expanded
|
|
73
|
+
// until the keyframe animation is complete. Please note that this will restart the anim timer
|
|
74
|
+
// from 0 everytime it's re-added.
|
|
75
|
+
if (isNudged) {
|
|
76
|
+
cursor.classList.add(TELEPOINTER_PULSE_DURING_TR_CLASS);
|
|
77
|
+
}
|
|
72
78
|
var fullNameEl = document.createElement('span');
|
|
73
79
|
fullNameEl.textContent = fullName;
|
|
74
80
|
fullNameEl.className = 'telepointer-fullname';
|
|
@@ -231,4 +237,18 @@ export var isOrganicChange = function isOrganicChange(tr) {
|
|
|
231
237
|
}
|
|
232
238
|
}) && !tr.doc.eq(tr.before);
|
|
233
239
|
});
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
// If we receive a transaction while there is an ongoing CSS expand animation in the telepointer,
|
|
243
|
+
// it will be cut off due to the removal of the element. We'll persist the animation state in the plugin,
|
|
244
|
+
// so we can keep the expanded version showing even when the telepointer element is recreated.
|
|
245
|
+
|
|
246
|
+
export var hasExistingNudge = function hasExistingNudge(sessionId, nudgeAnimations) {
|
|
247
|
+
var nudgeAnimStartTime = nudgeAnimations.get(sessionId);
|
|
248
|
+
var hasExistingNudge = false;
|
|
249
|
+
if (nudgeAnimStartTime) {
|
|
250
|
+
var timeElapsed = Date.now() - nudgeAnimStartTime;
|
|
251
|
+
hasExistingNudge = timeElapsed < TELEPOINTER_PULSE_DURING_TR_DURATION_MS;
|
|
252
|
+
}
|
|
253
|
+
return hasExistingNudge;
|
|
234
254
|
};
|
|
@@ -2,6 +2,7 @@ import type { ReadonlyTransaction } from '@atlaskit/editor-prosemirror/state';
|
|
|
2
2
|
import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
3
3
|
import type { ReadOnlyParticipants } from '../../types';
|
|
4
4
|
import { Participants } from '../participants';
|
|
5
|
+
import { type NudgeAnimationsMap } from '../utils';
|
|
5
6
|
/**
|
|
6
7
|
* Returns position where it's possible to place a decoration.
|
|
7
8
|
*/
|
|
@@ -9,13 +10,14 @@ export declare const getValidPos: (tr: ReadonlyTransaction, pos: number) => numb
|
|
|
9
10
|
export declare class PluginState {
|
|
10
11
|
private decorationSet;
|
|
11
12
|
private participants;
|
|
13
|
+
private nudgeAnimations;
|
|
12
14
|
private onError;
|
|
13
15
|
private sid?;
|
|
14
16
|
isReady: boolean;
|
|
15
17
|
get decorations(): DecorationSet;
|
|
16
18
|
get activeParticipants(): ReadOnlyParticipants;
|
|
17
19
|
get sessionId(): string | undefined;
|
|
18
|
-
constructor(decorations: DecorationSet, participants: Participants, sessionId?: string, collabInitalised?: boolean, onError?: (err: Error) => void);
|
|
20
|
+
constructor(decorations: DecorationSet, participants: Participants, sessionId?: string, collabInitalised?: boolean, onError?: (err: Error) => void, nudgeAnimations?: NudgeAnimationsMap);
|
|
19
21
|
getFullName(sessionId: string): string;
|
|
20
22
|
getInitial(sessionId: string): string;
|
|
21
23
|
getPresenceId(sessionId: string): string;
|
|
@@ -11,7 +11,7 @@ export declare function getAvatarColor(str: string): {
|
|
|
11
11
|
backgroundColor: string;
|
|
12
12
|
textColor: string;
|
|
13
13
|
};
|
|
14
|
-
export declare const createTelepointers: (from: number, to: number, sessionId: string, isSelection: boolean, initial: string, presenceId: string, fullName: string) => Decoration[];
|
|
14
|
+
export declare const createTelepointers: (from: number, to: number, sessionId: string, isSelection: boolean, initial: string, presenceId: string, fullName: string, isNudged: boolean) => Decoration[];
|
|
15
15
|
export declare const replaceDocument: (doc: any, state: EditorState, version?: number, options?: CollabEditOptions, reserveCursor?: boolean, editorAnalyticsAPI?: EditorAnalyticsAPI) => Transaction;
|
|
16
16
|
export declare const scrollToCollabCursor: (editorView: EditorView, participants: CollabParticipant[], sessionId: string | undefined, index: number, editorAnalyticsAPI: EditorAnalyticsAPI | undefined) => void;
|
|
17
17
|
export declare const getPositionOfTelepointer: (sessionId: string, decorationSet: DecorationSet) => undefined | number;
|
|
@@ -23,3 +23,5 @@ export declare const originalTransactionHasMeta: (transaction: Transaction | Rea
|
|
|
23
23
|
* @returns boolean
|
|
24
24
|
*/
|
|
25
25
|
export declare const isOrganicChange: (tr: ReadonlyTransaction) => boolean;
|
|
26
|
+
export type NudgeAnimationsMap = Map<string, number>;
|
|
27
|
+
export declare const hasExistingNudge: (sessionId: string, nudgeAnimations: NudgeAnimationsMap) => boolean;
|
|
@@ -2,6 +2,7 @@ import type { ReadonlyTransaction } from '@atlaskit/editor-prosemirror/state';
|
|
|
2
2
|
import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
3
3
|
import type { ReadOnlyParticipants } from '../../types';
|
|
4
4
|
import { Participants } from '../participants';
|
|
5
|
+
import { type NudgeAnimationsMap } from '../utils';
|
|
5
6
|
/**
|
|
6
7
|
* Returns position where it's possible to place a decoration.
|
|
7
8
|
*/
|
|
@@ -9,13 +10,14 @@ export declare const getValidPos: (tr: ReadonlyTransaction, pos: number) => numb
|
|
|
9
10
|
export declare class PluginState {
|
|
10
11
|
private decorationSet;
|
|
11
12
|
private participants;
|
|
13
|
+
private nudgeAnimations;
|
|
12
14
|
private onError;
|
|
13
15
|
private sid?;
|
|
14
16
|
isReady: boolean;
|
|
15
17
|
get decorations(): DecorationSet;
|
|
16
18
|
get activeParticipants(): ReadOnlyParticipants;
|
|
17
19
|
get sessionId(): string | undefined;
|
|
18
|
-
constructor(decorations: DecorationSet, participants: Participants, sessionId?: string, collabInitalised?: boolean, onError?: (err: Error) => void);
|
|
20
|
+
constructor(decorations: DecorationSet, participants: Participants, sessionId?: string, collabInitalised?: boolean, onError?: (err: Error) => void, nudgeAnimations?: NudgeAnimationsMap);
|
|
19
21
|
getFullName(sessionId: string): string;
|
|
20
22
|
getInitial(sessionId: string): string;
|
|
21
23
|
getPresenceId(sessionId: string): string;
|
|
@@ -11,7 +11,7 @@ export declare function getAvatarColor(str: string): {
|
|
|
11
11
|
backgroundColor: string;
|
|
12
12
|
textColor: string;
|
|
13
13
|
};
|
|
14
|
-
export declare const createTelepointers: (from: number, to: number, sessionId: string, isSelection: boolean, initial: string, presenceId: string, fullName: string) => Decoration[];
|
|
14
|
+
export declare const createTelepointers: (from: number, to: number, sessionId: string, isSelection: boolean, initial: string, presenceId: string, fullName: string, isNudged: boolean) => Decoration[];
|
|
15
15
|
export declare const replaceDocument: (doc: any, state: EditorState, version?: number, options?: CollabEditOptions, reserveCursor?: boolean, editorAnalyticsAPI?: EditorAnalyticsAPI) => Transaction;
|
|
16
16
|
export declare const scrollToCollabCursor: (editorView: EditorView, participants: CollabParticipant[], sessionId: string | undefined, index: number, editorAnalyticsAPI: EditorAnalyticsAPI | undefined) => void;
|
|
17
17
|
export declare const getPositionOfTelepointer: (sessionId: string, decorationSet: DecorationSet) => undefined | number;
|
|
@@ -23,3 +23,5 @@ export declare const originalTransactionHasMeta: (transaction: Transaction | Rea
|
|
|
23
23
|
* @returns boolean
|
|
24
24
|
*/
|
|
25
25
|
export declare const isOrganicChange: (tr: ReadonlyTransaction) => boolean;
|
|
26
|
+
export type NudgeAnimationsMap = Map<string, number>;
|
|
27
|
+
export declare const hasExistingNudge: (sessionId: string, nudgeAnimations: NudgeAnimationsMap) => boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-collab-edit",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.10.0",
|
|
4
4
|
"description": "Collab Edit plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@atlaskit/adf-schema": "^47.6.0",
|
|
35
35
|
"@atlaskit/custom-steps": "^0.11.0",
|
|
36
|
-
"@atlaskit/editor-common": "^106.
|
|
36
|
+
"@atlaskit/editor-common": "^106.8.0",
|
|
37
37
|
"@atlaskit/editor-json-transformer": "^8.24.0",
|
|
38
38
|
"@atlaskit/editor-plugin-analytics": "^2.3.0",
|
|
39
39
|
"@atlaskit/editor-plugin-connectivity": "^2.0.0",
|