@atlaskit/editor-plugin-annotation 2.8.2 → 2.9.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.
Files changed (36) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/cjs/editor-commands/index.js +50 -1
  3. package/dist/cjs/pm-plugins/annotation-manager-hooks.js +166 -4
  4. package/dist/cjs/pm-plugins/inline-comment.js +169 -30
  5. package/dist/cjs/pm-plugins/plugin-factory.js +51 -1
  6. package/dist/cjs/pm-plugins/reducer.js +18 -1
  7. package/dist/cjs/pm-plugins/toolbar.js +10 -7
  8. package/dist/cjs/pm-plugins/types.js +2 -0
  9. package/dist/cjs/ui/InlineCommentView.js +14 -1
  10. package/dist/es2019/editor-commands/index.js +42 -0
  11. package/dist/es2019/pm-plugins/annotation-manager-hooks.js +160 -5
  12. package/dist/es2019/pm-plugins/inline-comment.js +146 -9
  13. package/dist/es2019/pm-plugins/plugin-factory.js +51 -1
  14. package/dist/es2019/pm-plugins/reducer.js +22 -1
  15. package/dist/es2019/pm-plugins/toolbar.js +10 -8
  16. package/dist/es2019/pm-plugins/types.js +2 -0
  17. package/dist/es2019/ui/InlineCommentView.js +11 -1
  18. package/dist/esm/editor-commands/index.js +49 -0
  19. package/dist/esm/pm-plugins/annotation-manager-hooks.js +167 -5
  20. package/dist/esm/pm-plugins/inline-comment.js +159 -20
  21. package/dist/esm/pm-plugins/plugin-factory.js +51 -1
  22. package/dist/esm/pm-plugins/reducer.js +18 -1
  23. package/dist/esm/pm-plugins/toolbar.js +10 -7
  24. package/dist/esm/pm-plugins/types.js +2 -0
  25. package/dist/esm/ui/InlineCommentView.js +11 -1
  26. package/dist/types/editor-commands/index.d.ts +5 -0
  27. package/dist/types/pm-plugins/annotation-manager-hooks.d.ts +4 -1
  28. package/dist/types/pm-plugins/plugin-factory.d.ts +4 -0
  29. package/dist/types/pm-plugins/types.d.ts +26 -1
  30. package/dist/types/types/index.d.ts +1 -0
  31. package/dist/types-ts4.5/editor-commands/index.d.ts +5 -0
  32. package/dist/types-ts4.5/pm-plugins/annotation-manager-hooks.d.ts +4 -1
  33. package/dist/types-ts4.5/pm-plugins/plugin-factory.d.ts +4 -0
  34. package/dist/types-ts4.5/pm-plugins/types.d.ts +26 -1
  35. package/dist/types-ts4.5/types/index.d.ts +1 -0
  36. package/package.json +7 -4
@@ -1,13 +1,15 @@
1
1
  import { AnnotationTypes } from '@atlaskit/adf-schema';
2
- import { getRangeInlineNodeNames } from '@atlaskit/editor-common/utils';
2
+ import { getAnnotationInlineNodeTypes, getRangeInlineNodeNames } from '@atlaskit/editor-common/utils';
3
3
  import { findDomRefAtPos } from '@atlaskit/editor-prosemirror/utils';
4
- import { setInlineCommentDraftState, createAnnotation } from '../editor-commands';
4
+ import { fg } from '@atlaskit/platform-feature-flags';
5
+ import { setInlineCommentDraftState, createAnnotation, setSelectedAnnotation, closeComponent, setHoveredAnnotation, removeInlineCommentFromDoc } from '../editor-commands';
5
6
  import { AnnotationSelectionType } from '../types';
6
7
  import { inlineCommentPluginKey, isSelectionValid } from './utils';
7
8
  var ERROR_REASON_DRAFT_NOT_STARTED = 'draft-not-started';
8
9
  var ERROR_REASON_DRAFT_IN_PROGRESS = 'draft-in-progress';
9
10
  var ERROR_REASON_RANGE_MISSING = 'range-no-longer-exists';
10
11
  var ERROR_REASON_RANGE_INVALID = 'invalid-range';
12
+ var ERROR_REASON_ID_INVALID = 'id-not-valid';
11
13
  var domRefFromPos = function domRefFromPos(view, position) {
12
14
  var dom;
13
15
  try {
@@ -40,15 +42,34 @@ export var allowAnnotation = function allowAnnotation(editorView, options) {
40
42
  };
41
43
  export var startDraft = function startDraft(editorView, options) {
42
44
  return function () {
43
- var _getRangeInlineNodeNa, _options$annotationMa;
45
+ var _getRangeInlineNodeNa, _options$annotationMa2;
44
46
  var _ref2 = inlineCommentPluginKey.getState(editorView.state) || {},
45
- isDrafting = _ref2.isDrafting;
47
+ isDrafting = _ref2.isDrafting,
48
+ selectedAnnotations = _ref2.selectedAnnotations;
46
49
  if (isDrafting) {
47
50
  return {
48
51
  success: false,
49
52
  reason: ERROR_REASON_DRAFT_IN_PROGRESS
50
53
  };
51
54
  }
55
+ if (!!(selectedAnnotations !== null && selectedAnnotations !== void 0 && selectedAnnotations.length) && fg('platform_editor_comments_api_manager_select')) {
56
+ // if there are selected annotations when starting a draft, we need to clear the selected annotations
57
+ // before we start the draft.
58
+ closeComponent()(editorView.state, editorView.dispatch);
59
+
60
+ // not only that but we need to also deselect any other annotations that are currently selected.
61
+ selectedAnnotations === null || selectedAnnotations === void 0 || selectedAnnotations.forEach(function (annotation) {
62
+ var _options$annotationMa, _getAnnotationInlineN;
63
+ (_options$annotationMa = options.annotationManager) === null || _options$annotationMa === void 0 || _options$annotationMa.emit({
64
+ name: 'annotationSelectionChanged',
65
+ data: {
66
+ annotationId: annotation.id,
67
+ isSelected: false,
68
+ inlineNodeTypes: (_getAnnotationInlineN = getAnnotationInlineNodeTypes(editorView.state, annotation.id)) !== null && _getAnnotationInlineN !== void 0 ? _getAnnotationInlineN : []
69
+ }
70
+ });
71
+ });
72
+ }
52
73
  setInlineCommentDraftState(options.editorAnalyticsAPI)(true)(editorView.state, editorView.dispatch);
53
74
  var _ref3 = inlineCommentPluginKey.getState(editorView.state) || {},
54
75
  draftDecorationSet = _ref3.draftDecorationSet;
@@ -70,7 +91,7 @@ export var startDraft = function startDraft(editorView, options) {
70
91
  to: decorations[decorations.length - 1].to
71
92
  }
72
93
  })) !== null && _getRangeInlineNodeNa !== void 0 ? _getRangeInlineNodeNa : [];
73
- (_options$annotationMa = options.annotationManager) === null || _options$annotationMa === void 0 || _options$annotationMa.emit({
94
+ (_options$annotationMa2 = options.annotationManager) === null || _options$annotationMa2 === void 0 || _options$annotationMa2.emit({
74
95
  name: 'draftAnnotationStarted',
75
96
  data: {
76
97
  targetElement: targetElement,
@@ -114,6 +135,7 @@ export var clearDraft = function clearDraft(editorView, options) {
114
135
  };
115
136
  export var applyDraft = function applyDraft(editorView, options) {
116
137
  return function (id) {
138
+ var _options$annotationMa3, _getAnnotationInlineN2;
117
139
  var _ref5 = inlineCommentPluginKey.getState(editorView.state) || {},
118
140
  isDrafting = _ref5.isDrafting,
119
141
  draftDecorationSet = _ref5.draftDecorationSet,
@@ -138,6 +160,17 @@ export var applyDraft = function applyDraft(editorView, options) {
138
160
  // Using the original decoration from position we should be able to locate the new target element.
139
161
  // This is because the new annotation will be created at the same position as the draft decoration.
140
162
  var targetElement = domRefFromPos(editorView, from);
163
+
164
+ // When a draft is applied it is automatically selected, so we need to set the selected annotation.
165
+ // emit the event for the selected annotation.
166
+ (_options$annotationMa3 = options.annotationManager) === null || _options$annotationMa3 === void 0 || _options$annotationMa3.emit({
167
+ name: 'annotationSelectionChanged',
168
+ data: {
169
+ annotationId: id,
170
+ isSelected: true,
171
+ inlineNodeTypes: (_getAnnotationInlineN2 = getAnnotationInlineNodeTypes(editorView.state, id)) !== null && _getAnnotationInlineN2 !== void 0 ? _getAnnotationInlineN2 : []
172
+ }
173
+ });
141
174
  return {
142
175
  success: true,
143
176
  // Get the dom element from the newly created annotation and return it here.
@@ -182,4 +215,133 @@ export var getDraft = function getDraft(editorView, options) {
182
215
  actionResult: undefined
183
216
  };
184
217
  };
218
+ };
219
+ export var setIsAnnotationSelected = function setIsAnnotationSelected(editorView, options) {
220
+ return function (id, isSelected) {
221
+ var _selectedAnnotations$;
222
+ var _ref7 = inlineCommentPluginKey.getState(editorView.state) || {},
223
+ annotations = _ref7.annotations,
224
+ isDrafting = _ref7.isDrafting,
225
+ selectedAnnotations = _ref7.selectedAnnotations;
226
+ if (isDrafting) {
227
+ return {
228
+ success: false,
229
+ reason: ERROR_REASON_DRAFT_IN_PROGRESS
230
+ };
231
+ }
232
+
233
+ // If there is no annotation state with this id then we can assume the annotation is invalid.
234
+ if (!(annotations !== null && annotations !== void 0 && annotations.hasOwnProperty(id))) {
235
+ return {
236
+ success: false,
237
+ reason: ERROR_REASON_ID_INVALID
238
+ };
239
+ }
240
+ var isCurrentlySelectedIndex = (_selectedAnnotations$ = selectedAnnotations === null || selectedAnnotations === void 0 ? void 0 : selectedAnnotations.findIndex(function (annotation) {
241
+ return annotation.id === id;
242
+ })) !== null && _selectedAnnotations$ !== void 0 ? _selectedAnnotations$ : -1;
243
+ var isCurrentlySelected = isCurrentlySelectedIndex !== -1;
244
+ if (isSelected !== isCurrentlySelected) {
245
+ // the annotation is selection is changing.
246
+ if (isCurrentlySelected && !isSelected) {
247
+ var _options$annotationMa4, _getAnnotationInlineN3;
248
+ // the selected annotaion is being unselected, so we need to close the view.
249
+ closeComponent()(editorView.state, editorView.dispatch);
250
+ (_options$annotationMa4 = options.annotationManager) === null || _options$annotationMa4 === void 0 || _options$annotationMa4.emit({
251
+ name: 'annotationSelectionChanged',
252
+ data: {
253
+ annotationId: id,
254
+ isSelected: false,
255
+ inlineNodeTypes: (_getAnnotationInlineN3 = getAnnotationInlineNodeTypes(editorView.state, id)) !== null && _getAnnotationInlineN3 !== void 0 ? _getAnnotationInlineN3 : []
256
+ }
257
+ });
258
+ } else if (!isCurrentlySelected && isSelected) {
259
+ var _options$annotationMa6, _getAnnotationInlineN5;
260
+ // the annotation is currently not selected and is being selected, so we need to open the view.
261
+ setSelectedAnnotation(id)(editorView.state, editorView.dispatch);
262
+
263
+ // the current annotations are going to be unselected. So we need to notify listeners of this change also.
264
+ selectedAnnotations === null || selectedAnnotations === void 0 || selectedAnnotations.forEach(function (annotation) {
265
+ if (annotation.id !== id) {
266
+ var _options$annotationMa5, _getAnnotationInlineN4;
267
+ (_options$annotationMa5 = options.annotationManager) === null || _options$annotationMa5 === void 0 || _options$annotationMa5.emit({
268
+ name: 'annotationSelectionChanged',
269
+ data: {
270
+ annotationId: annotation.id,
271
+ isSelected: false,
272
+ inlineNodeTypes: (_getAnnotationInlineN4 = getAnnotationInlineNodeTypes(editorView.state, annotation.id)) !== null && _getAnnotationInlineN4 !== void 0 ? _getAnnotationInlineN4 : []
273
+ }
274
+ });
275
+ }
276
+ });
277
+
278
+ // Lastly we need to emit the event for the selected annotation.
279
+ (_options$annotationMa6 = options.annotationManager) === null || _options$annotationMa6 === void 0 || _options$annotationMa6.emit({
280
+ name: 'annotationSelectionChanged',
281
+ data: {
282
+ annotationId: id,
283
+ isSelected: true,
284
+ inlineNodeTypes: (_getAnnotationInlineN5 = getAnnotationInlineNodeTypes(editorView.state, id)) !== null && _getAnnotationInlineN5 !== void 0 ? _getAnnotationInlineN5 : []
285
+ }
286
+ });
287
+ }
288
+ }
289
+ return {
290
+ success: true,
291
+ isSelected: isSelected
292
+ };
293
+ };
294
+ };
295
+ export var setIsAnnotationHovered = function setIsAnnotationHovered(editorView, options) {
296
+ return function (id, isHovered) {
297
+ var _hoveredAnnotations$f;
298
+ var _ref8 = inlineCommentPluginKey.getState(editorView.state) || {},
299
+ annotations = _ref8.annotations,
300
+ hoveredAnnotations = _ref8.hoveredAnnotations;
301
+
302
+ // If there is no annotation state with this id then we can assume the annotation is invalid.
303
+ if (!(annotations !== null && annotations !== void 0 && annotations.hasOwnProperty(id))) {
304
+ return {
305
+ success: false,
306
+ reason: ERROR_REASON_ID_INVALID
307
+ };
308
+ }
309
+ var isCurrentlyHoveredIndex = (_hoveredAnnotations$f = hoveredAnnotations === null || hoveredAnnotations === void 0 ? void 0 : hoveredAnnotations.findIndex(function (annotation) {
310
+ return annotation.id === id;
311
+ })) !== null && _hoveredAnnotations$f !== void 0 ? _hoveredAnnotations$f : -1;
312
+ var isCurrentlyHovered = isCurrentlyHoveredIndex !== -1;
313
+ if (isHovered !== isCurrentlyHovered) {
314
+ // the annotation in hovered is changing.
315
+ if (isCurrentlyHovered && !isHovered) {
316
+ // the hovered annotaion is being unhovered, so we should remove the hover state.
317
+ setHoveredAnnotation('')(editorView.state, editorView.dispatch);
318
+ } else if (!isCurrentlyHovered && isHovered) {
319
+ // the annotation is currently not hovered and is being hovered.
320
+ setHoveredAnnotation(id)(editorView.state, editorView.dispatch);
321
+ }
322
+ }
323
+ return {
324
+ success: true,
325
+ isHovered: isHovered
326
+ };
327
+ };
328
+ };
329
+ export var clearAnnotation = function clearAnnotation(editorView, options) {
330
+ return function (id) {
331
+ var _ref9 = inlineCommentPluginKey.getState(editorView.state) || {},
332
+ annotations = _ref9.annotations;
333
+
334
+ // If there is no annotation state with this id then we can assume the annotation is invalid.
335
+ if (!(annotations !== null && annotations !== void 0 && annotations.hasOwnProperty(id))) {
336
+ return {
337
+ success: false,
338
+ reason: ERROR_REASON_ID_INVALID
339
+ };
340
+ }
341
+ removeInlineCommentFromDoc(id, options.provider.supportedBlockNodes)(editorView.state, editorView.dispatch);
342
+ return {
343
+ success: true,
344
+ actionResult: undefined
345
+ };
346
+ };
185
347
  };
@@ -4,11 +4,12 @@ import _regeneratorRuntime from "@babel/runtime/regenerator";
4
4
  import { AnnotationTypes } from '@atlaskit/adf-schema';
5
5
  import { RESOLVE_METHOD } from '@atlaskit/editor-common/analytics';
6
6
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
7
+ import { getAnnotationInlineNodeTypes } from '@atlaskit/editor-common/utils';
7
8
  import { Decoration, DecorationSet } from '@atlaskit/editor-prosemirror/view';
8
9
  import { fg } from '@atlaskit/platform-feature-flags';
9
- import { clearDirtyMark, closeComponent, setHoveredAnnotation, setInlineCommentsVisibility, setSelectedAnnotation, updateInlineCommentResolvedState, updateMouseState } from '../editor-commands';
10
+ import { clearDirtyMark, closeComponent, setHoveredAnnotation, setInlineCommentsVisibility, setSelectedAnnotation, flushPendingSelections, updateInlineCommentResolvedState, updateMouseState, setPendingSelectedAnnotation, setInlineCommentDraftState } from '../editor-commands';
10
11
  import { getAnnotationViewClassname, getBlockAnnotationViewClassname } from '../nodeviews';
11
- import { allowAnnotation, applyDraft, clearDraft, getDraft, startDraft } from './annotation-manager-hooks';
12
+ import { allowAnnotation, applyDraft, clearDraft, clearAnnotation, getDraft, setIsAnnotationHovered, setIsAnnotationSelected, startDraft } from './annotation-manager-hooks';
12
13
  import { createPluginState } from './plugin-factory';
13
14
  import { decorationKey, getAllAnnotations, getPluginState, inlineCommentPluginKey } from './utils';
14
15
  var fetchProviderStates = /*#__PURE__*/function () {
@@ -97,7 +98,9 @@ var initialState = function initialState() {
97
98
  isVisible: true,
98
99
  skipSelectionHandling: false,
99
100
  featureFlagsPluginState: featureFlagsPluginState,
100
- isDrafting: false
101
+ isDrafting: false,
102
+ pendingSelectedAnnotations: [],
103
+ pendingSelectedAnnotationsUpdateCount: 0
101
104
  };
102
105
  };
103
106
  var hideToolbar = function hideToolbar(state, dispatch) {
@@ -156,12 +159,33 @@ export var inlineCommentPlugin = function inlineCommentPlugin(options) {
156
159
  key: inlineCommentPluginKey,
157
160
  state: createPluginState(options.dispatch, initialState(provider.disallowOnWhitespace, featureFlagsPluginState)),
158
161
  view: function view(editorView) {
162
+ var allowAnnotationFn;
163
+ var startDraftFn;
164
+ var clearDraftFn;
165
+ var applyDraftFn;
166
+ var getDraftFn;
167
+ var setIsAnnotationSelectedFn;
168
+ var setIsAnnotationHoveredFn;
169
+ var clearAnnotationFn;
159
170
  if (annotationManager && fg('platform_editor_comments_api_manager')) {
160
- annotationManager.hook('allowAnnotation', allowAnnotation(editorView, options));
161
- annotationManager.hook('startDraft', startDraft(editorView, options));
162
- annotationManager.hook('clearDraft', clearDraft(editorView, options));
163
- annotationManager.hook('applyDraft', applyDraft(editorView, options));
164
- annotationManager.hook('getDraft', getDraft(editorView, options));
171
+ allowAnnotationFn = allowAnnotation(editorView, options);
172
+ startDraftFn = startDraft(editorView, options);
173
+ clearDraftFn = clearDraft(editorView, options);
174
+ applyDraftFn = applyDraft(editorView, options);
175
+ getDraftFn = getDraft(editorView, options);
176
+ annotationManager.hook('allowAnnotation', allowAnnotationFn);
177
+ annotationManager.hook('startDraft', startDraftFn);
178
+ annotationManager.hook('clearDraft', clearDraftFn);
179
+ annotationManager.hook('applyDraft', applyDraftFn);
180
+ annotationManager.hook('getDraft', getDraftFn);
181
+ if (fg('platform_editor_comments_api_manager_select')) {
182
+ setIsAnnotationSelectedFn = setIsAnnotationSelected(editorView, options);
183
+ setIsAnnotationHoveredFn = setIsAnnotationHovered(editorView, options);
184
+ clearAnnotationFn = clearAnnotation(editorView, options);
185
+ annotationManager.hook('setIsAnnotationSelected', setIsAnnotationSelectedFn);
186
+ annotationManager.hook('setIsAnnotationHovered', setIsAnnotationHoveredFn);
187
+ annotationManager.hook('clearAnnotation', clearAnnotationFn);
188
+ }
165
189
  }
166
190
  // Get initial state
167
191
  // Need to pass `editorView` to mitigate editor state going stale
@@ -219,6 +243,13 @@ export var inlineCommentPlugin = function inlineCommentPlugin(options) {
219
243
 
220
244
  // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
221
245
  editorView.root.addEventListener('mouseup', mouseUp);
246
+
247
+ /**
248
+ * This flag is used to prevent the preemptive gate from being called multiple times while a check is in-flight.
249
+ * If a check is still pending then it's most likely because the product is busy and trying to block the
250
+ * selection of an annotation.
251
+ */
252
+ var isPreemptiveGateActive = false;
222
253
  return {
223
254
  update: function update(view, _prevState) {
224
255
  var _prevSelectedAnnotati;
@@ -239,8 +270,85 @@ export var inlineCommentPlugin = function inlineCommentPlugin(options) {
239
270
  // The selectComponentExperience is using a simplified object, which is why it's type asserted.
240
271
  (_options$selectCommen = options.selectCommentExperience) === null || _options$selectCommen === void 0 || _options$selectCommen.selectAnnotation.complete(selectedAnnotationId);
241
272
  }
242
- var _ref6 = getPluginState(view.state) || {},
243
- dirtyAnnotations = _ref6.dirtyAnnotations;
273
+ if (fg('platform_editor_comments_api_manager_select')) {
274
+ // In the Editor, Annotations can be selected in three ways:
275
+ // 1. By clicking on the annotation in the editor
276
+ // 2. By using the annotation manager to select the annotation
277
+ // 3. By moving the cursor to the annotation and using the keyboard to select it
278
+ // Item 1 & 3 need to be protected by the preemptive gate. This is because these actions could be performed by a user
279
+ // at a time when changing the selection could cause data loss.
280
+ // The following preemptive check is designed to cover these items.
281
+
282
+ var _ref6 = getPluginState(view.state) || {},
283
+ pendingSelectedAnnotations = _ref6.pendingSelectedAnnotations,
284
+ pendingSelectedAnnotationsUpdateCount = _ref6.pendingSelectedAnnotationsUpdateCount;
285
+ var _ref7 = getPluginState(_prevState) || {},
286
+ prevPendingSelectedAnnotationsUpdateCount = _ref7.pendingSelectedAnnotationsUpdateCount;
287
+ if (!isPreemptiveGateActive && pendingSelectedAnnotationsUpdateCount !== prevPendingSelectedAnnotationsUpdateCount && !!(pendingSelectedAnnotations !== null && pendingSelectedAnnotations !== void 0 && pendingSelectedAnnotations.length)) {
288
+ // Need to set a lock to avoid calling gate multiple times. The lock will be released
289
+ // when the preemptive gate is complete.
290
+ isPreemptiveGateActive = true;
291
+ annotationManager === null || annotationManager === void 0 || annotationManager.checkPreemptiveGate().then(function (canSelectAnnotation) {
292
+ var _ref8 = getPluginState(view.state) || {},
293
+ isDrafting = _ref8.isDrafting,
294
+ latestPendingSelectedAnnotations = _ref8.pendingSelectedAnnotations,
295
+ latestSelectedAnnotations = _ref8.selectedAnnotations;
296
+ if (canSelectAnnotation) {
297
+ if (isDrafting) {
298
+ // The user must have chosen to discard there draft. So before we flush the pending selections
299
+ // we need to clear the draft if there is one.
300
+ setInlineCommentDraftState(options.editorAnalyticsAPI)(false)(view.state, view.dispatch);
301
+ }
302
+
303
+ // Flush the pending selections into the selected annotations list.
304
+ flushPendingSelections(true)(view.state, view.dispatch);
305
+ latestSelectedAnnotations === null || latestSelectedAnnotations === void 0 || latestSelectedAnnotations.filter(function (annotation) {
306
+ return (latestPendingSelectedAnnotations === null || latestPendingSelectedAnnotations === void 0 ? void 0 : latestPendingSelectedAnnotations.findIndex(function (pendingAnnotation) {
307
+ return pendingAnnotation.id === annotation.id;
308
+ })) === -1;
309
+ }).forEach(function (annotation) {
310
+ var _options$annotationMa, _getAnnotationInlineN;
311
+ (_options$annotationMa = options.annotationManager) === null || _options$annotationMa === void 0 || _options$annotationMa.emit({
312
+ name: 'annotationSelectionChanged',
313
+ data: {
314
+ annotationId: annotation.id,
315
+ isSelected: false,
316
+ inlineNodeTypes: (_getAnnotationInlineN = getAnnotationInlineNodeTypes(editorView.state, annotation.id)) !== null && _getAnnotationInlineN !== void 0 ? _getAnnotationInlineN : []
317
+ }
318
+ });
319
+ });
320
+
321
+ // Notify the annotation manager that the pending selection has changed.
322
+ latestPendingSelectedAnnotations === null || latestPendingSelectedAnnotations === void 0 || latestPendingSelectedAnnotations.forEach(function (_ref9) {
323
+ var _options$annotationMa2, _getAnnotationInlineN2;
324
+ var id = _ref9.id;
325
+ (_options$annotationMa2 = options.annotationManager) === null || _options$annotationMa2 === void 0 || _options$annotationMa2.emit({
326
+ name: 'annotationSelectionChanged',
327
+ data: {
328
+ annotationId: id,
329
+ isSelected: true,
330
+ inlineNodeTypes: (_getAnnotationInlineN2 = getAnnotationInlineNodeTypes(view.state, id)) !== null && _getAnnotationInlineN2 !== void 0 ? _getAnnotationInlineN2 : []
331
+ }
332
+ });
333
+ });
334
+ } else {
335
+ // Clears the pending selections if the preemptive gate returns false.
336
+ // We should need to worry about dispatching change events here because the pending selections
337
+ // are being aborted and the selections will remain unchanged.
338
+ flushPendingSelections(false)(view.state, view.dispatch);
339
+ }
340
+ }).catch(function (error) {
341
+ // TODO: EDITOR-595 - Ensure and anlytic is fired to indicate which reports on the error.
342
+
343
+ // If an error has occured we will clear any pending selections to avoid accidentally setting the wrong thing.
344
+ flushPendingSelections(false)(view.state, view.dispatch);
345
+ }).finally(function () {
346
+ isPreemptiveGateActive = false;
347
+ });
348
+ }
349
+ }
350
+ var _ref10 = getPluginState(view.state) || {},
351
+ dirtyAnnotations = _ref10.dirtyAnnotations;
244
352
  if (!dirtyAnnotations) {
245
353
  return;
246
354
  }
@@ -253,6 +361,16 @@ export var inlineCommentPlugin = function inlineCommentPlugin(options) {
253
361
  if (updateSubscriber) {
254
362
  updateSubscriber.off('resolve', resolve).off('delete', resolve).off('unresolve', unResolve).off('create', unResolve).off('setvisibility', setVisibility).off('setselectedannotation', setSelectedAnnotationFn).off('sethoveredannotation', setHoveredAnnotationFn).off('removehoveredannotation', removeHoveredannotationFn).off('closeinlinecomment', closeInlineCommentFn);
255
363
  }
364
+ if (annotationManager && fg('platform_editor_comments_api_manager')) {
365
+ annotationManager.unhook('allowAnnotation', allowAnnotationFn);
366
+ annotationManager.unhook('startDraft', startDraftFn);
367
+ annotationManager.unhook('clearDraft', clearDraftFn);
368
+ annotationManager.unhook('applyDraft', applyDraftFn);
369
+ annotationManager.unhook('getDraft', getDraftFn);
370
+ annotationManager.unhook('setIsAnnotationSelected', setIsAnnotationSelectedFn);
371
+ annotationManager.unhook('setIsAnnotationHovered', setIsAnnotationHoveredFn);
372
+ annotationManager.unhook('clearAnnotation', clearAnnotationFn);
373
+ }
256
374
  }
257
375
  };
258
376
  },
@@ -293,27 +411,48 @@ export var inlineCommentPlugin = function inlineCommentPlugin(options) {
293
411
  if (isSelected && !(pluginState !== null && pluginState !== void 0 && pluginState.isInlineCommentViewClosed)) {
294
412
  return false;
295
413
  }
296
- var _ref7 = pluginState || {},
297
- annotations = _ref7.annotations;
414
+ var _ref11 = pluginState || {},
415
+ annotations = _ref11.annotations;
298
416
  var isUnresolved = annotations && annotations[annotationId] === false;
299
417
  if (!isUnresolved) {
300
418
  return false;
301
419
  }
302
- setSelectedAnnotation(annotationId)(view.state, view.dispatch);
420
+ if (fg('platform_editor_comments_api_manager_select')) {
421
+ var _pluginState$pendingS;
422
+ // The manager disable setting the selected annotation on click because in the editor this is already
423
+ // handled by the selection update handler. When the manager is enabled, and a selection changes it's pushed into
424
+ // the pendingSelectedAnnotations array. This is then used to update the selection when the preemptive gate
425
+ // is released.
426
+ var isPendingSelection = pluginState === null || pluginState === void 0 || (_pluginState$pendingS = pluginState.pendingSelectedAnnotations) === null || _pluginState$pendingS === void 0 ? void 0 : _pluginState$pendingS.some(function (selectedAnnotation) {
427
+ return selectedAnnotation.id === annotationId;
428
+ });
429
+ // If the annotation is selected and the inline comment view is open, do nothing
430
+ // as the user is already in the comment view.
431
+ if (isPendingSelection) {
432
+ return false;
433
+ }
434
+ setPendingSelectedAnnotation(annotationId)(view.state, view.dispatch);
435
+ } else {
436
+ setSelectedAnnotation(annotationId)(view.state, view.dispatch);
437
+ }
303
438
  return true;
304
439
  }
305
440
  },
306
441
  decorations: function decorations(state) {
307
442
  // highlight comments, depending on state
308
- var _ref8 = getPluginState(state) || {},
309
- draftDecorationSet = _ref8.draftDecorationSet,
310
- annotations = _ref8.annotations,
311
- selectedAnnotations = _ref8.selectedAnnotations,
312
- isVisible = _ref8.isVisible,
313
- isInlineCommentViewClosed = _ref8.isInlineCommentViewClosed,
314
- hoveredAnnotations = _ref8.hoveredAnnotations;
443
+ var _ref12 = getPluginState(state) || {},
444
+ draftDecorationSet = _ref12.draftDecorationSet,
445
+ annotations = _ref12.annotations,
446
+ selectedAnnotations = _ref12.selectedAnnotations,
447
+ isVisible = _ref12.isVisible,
448
+ isInlineCommentViewClosed = _ref12.isInlineCommentViewClosed,
449
+ hoveredAnnotations = _ref12.hoveredAnnotations;
315
450
  var decorations = draftDecorationSet !== null && draftDecorationSet !== void 0 ? draftDecorationSet : DecorationSet.empty;
316
451
  var focusDecorations = [];
452
+
453
+ // TODO: EDITOR-760 - This needs to be optimised, it's not a good idea to scan the entire document
454
+ // everytime we need to update the decorations. This handler will be called alot. We should be caching
455
+ // the decorations in plugin state and only updating them when required.
317
456
  state.doc.descendants(function (node, pos) {
318
457
  var _provider$supportedBl;
319
458
  // Inline comment on mediaInline is not supported as part of comments on media project
@@ -4,6 +4,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
4
4
  import { pluginFactory } from '@atlaskit/editor-common/utils';
5
5
  import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
6
6
  import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
7
+ import { fg } from '@atlaskit/platform-feature-flags';
7
8
  import reducer from './reducer';
8
9
  import { decorationKey, findAnnotationsInSelection, inlineCommentPluginKey, isBlockNodeAnnotationsSelected, isSelectedAnnotationsChanged } from './utils';
9
10
  var handleDocChanged = function handleDocChanged(tr, prevPluginState) {
@@ -19,6 +20,10 @@ var handleDocChanged = function handleDocChanged(tr, prevPluginState) {
19
20
  * We clear bookmark on the following conditions:
20
21
  * 1. if current selection is an empty selection, or
21
22
  * 2. if the current selection and bookmark selection are different
23
+ * @param tr
24
+ * @param editorState
25
+ * @param bookmark
26
+ * @example
22
27
  */
23
28
  export var shouldClearBookMarkCheck = function shouldClearBookMarkCheck(tr, editorState, bookmark) {
24
29
  if (editorState.selection.empty || !bookmark) {
@@ -46,7 +51,7 @@ export var shouldClearBookMarkCheck = function shouldClearBookMarkCheck(tr, edit
46
51
  // by default we discard bookmark
47
52
  return true;
48
53
  };
49
- var getSelectionChangedHandler = function getSelectionChangedHandler(reopenCommentView) {
54
+ var getSelectionChangeHandlerOld = function getSelectionChangeHandlerOld(reopenCommentView) {
50
55
  return function (tr, pluginState) {
51
56
  if (pluginState.skipSelectionHandling) {
52
57
  return _objectSpread(_objectSpread({}, pluginState), {}, {
@@ -86,6 +91,51 @@ var getSelectionChangedHandler = function getSelectionChangedHandler(reopenComme
86
91
  });
87
92
  };
88
93
  };
94
+ var getSelectionChangeHandlerNew = function getSelectionChangeHandlerNew(reopenCommentView) {
95
+ return function (tr, pluginState) {
96
+ if (pluginState.skipSelectionHandling) {
97
+ return _objectSpread(_objectSpread({}, pluginState), {}, {
98
+ skipSelectionHandling: false
99
+ }, reopenCommentView && {
100
+ isInlineCommentViewClosed: false
101
+ });
102
+ }
103
+ var selectedAnnotations = findAnnotationsInSelection(tr.selection, tr.doc);
104
+
105
+ // NOTE: I've left this commented code here as a reference that the previous old code would reset the selected annotations
106
+ // if the selection is empty. If this is no longer needed, we can remove this code.
107
+ // clean up with platform_editor_comments_api_manager_select
108
+ // if (selectedAnnotations.length === 0) {
109
+ // return {
110
+ // ...pluginState,
111
+ // pendingSelectedAnnotations: selectedAnnotations,
112
+ // pendingSelectedAnnotationsUpdateCount:
113
+ // pluginState.pendingSelectedAnnotationsUpdateCount + 1,
114
+ // isInlineCommentViewClosed: true,
115
+ // selectAnnotationMethod: undefined,
116
+ // };
117
+ // }
118
+
119
+ if (isSelectedAnnotationsChanged(selectedAnnotations, pluginState.pendingSelectedAnnotations)) {
120
+ return _objectSpread(_objectSpread({}, pluginState), {}, {
121
+ pendingSelectedAnnotations: selectedAnnotations,
122
+ pendingSelectedAnnotationsUpdateCount: pluginState.pendingSelectedAnnotationsUpdateCount + 1
123
+ }, reopenCommentView && {
124
+ isInlineCommentViewClosed: false
125
+ });
126
+ }
127
+ return _objectSpread(_objectSpread(_objectSpread({}, pluginState), reopenCommentView && {
128
+ isInlineCommentViewClosed: false
129
+ }), {}, {
130
+ selectAnnotationMethod: undefined
131
+ });
132
+ };
133
+ };
134
+ var getSelectionChangedHandler = function getSelectionChangedHandler(reopenCommentView) {
135
+ return function (tr, pluginState) {
136
+ return fg('platform_editor_comments_api_manager_select') ? getSelectionChangeHandlerNew(reopenCommentView)(tr, pluginState) : getSelectionChangeHandlerOld(reopenCommentView)(tr, pluginState);
137
+ };
138
+ };
89
139
  var _pluginFactory = pluginFactory(inlineCommentPluginKey, reducer, {
90
140
  onSelectionChanged: getSelectionChangedHandler(true),
91
141
  onDocChanged: handleDocChanged,
@@ -25,12 +25,14 @@ export default (function (pluginState, action) {
25
25
  annotations: {}
26
26
  });
27
27
  case ACTIONS.CLOSE_COMPONENT:
28
- return _objectSpread(_objectSpread({}, pluginState), {}, {
28
+ return _objectSpread(_objectSpread(_objectSpread({}, pluginState), {}, {
29
29
  isInlineCommentViewClosed: true,
30
30
  isDrafting: false,
31
31
  isOpeningMediaCommentFromToolbar: false
32
32
  }, fg('platform_editor_annotation_selected_annotation') && {
33
33
  selectedAnnotations: []
34
+ }), fg('platform_editor_comments_api_manager_select') && {
35
+ selectedAnnotations: []
34
36
  });
35
37
  case ACTIONS.ADD_INLINE_COMMENT:
36
38
  var updatedPluginState = getNewDraftState(pluginState, action.data.drafting, action.data.editorState);
@@ -39,6 +41,8 @@ export default (function (pluginState, action) {
39
41
  annotations: _objectSpread(_objectSpread({}, pluginState.annotations), action.data.inlineComments),
40
42
  isInlineCommentViewClosed: false,
41
43
  selectAnnotationMethod: undefined
44
+ }, fg('platform_editor_comments_api_manager_select') && {
45
+ skipSelectionHandling: true
42
46
  });
43
47
  case ACTIONS.INLINE_COMMENT_SET_VISIBLE:
44
48
  var isVisible = action.data.isVisible;
@@ -62,6 +66,19 @@ export default (function (pluginState, action) {
62
66
  skipSelectionHandling: true,
63
67
  isInlineCommentViewClosed: false
64
68
  });
69
+ case ACTIONS.FLUSH_PENDING_SELECTIONS:
70
+ return _objectSpread(_objectSpread({}, pluginState), {}, {
71
+ selectedAnnotations: action.data.canSetAsSelectedAnnotations ? _toConsumableArray(pluginState.pendingSelectedAnnotations) : pluginState.selectedAnnotations,
72
+ pendingSelectedAnnotations: [],
73
+ isInlineCommentViewClosed: false
74
+ });
75
+ case ACTIONS.SET_PENDING_SELECTIONS:
76
+ return _objectSpread(_objectSpread({}, pluginState), {}, {
77
+ pendingSelectedAnnotations: _toConsumableArray(action.data.selectedAnnotations),
78
+ pendingSelectedAnnotationsUpdateCount: pluginState.pendingSelectedAnnotationsUpdateCount + 1,
79
+ skipSelectionHandling: true,
80
+ isInlineCommentViewClosed: false
81
+ });
65
82
  default:
66
83
  return pluginState;
67
84
  }
@@ -130,7 +130,7 @@ export var buildToolbar = function buildToolbar(editorAnalyticsAPI) {
130
130
  }
131
131
  if (fg('platform_editor_comments_api_manager')) {
132
132
  if (!annotationManager) {
133
- // TODO: EDITOR-188 - If we've reached here and the manager is not initialized, we should
133
+ // TODO: EDITOR-595 - If we've reached here and the manager is not initialized, we should
134
134
  // dispatch an analytics event to indicate that the user has clicked the button but
135
135
  // the action was not completed.
136
136
  return false;
@@ -144,16 +144,19 @@ export var buildToolbar = function buildToolbar(editorAnalyticsAPI) {
144
144
  }
145
145
  });
146
146
  createCommentExperience === null || createCommentExperience === void 0 || createCommentExperience.initExperience.start();
147
- var _annotationManager$st = annotationManager.startDraft(),
148
- success = _annotationManager$st.success;
149
- if (!success) {
150
- // TODO: EDITOR-188 - Report start draft attempt failed.
147
+ var result = annotationManager.startDraft();
148
+ if (result.success) {
149
+ // TODO: EDITOR-595 - Ensure and anlytic is fired to indicate that the user has started a draft.
150
+ } else {
151
+ // TODO: EDITOR-595 - Fire an analytics event to indicate that the user has clicked the button
152
+ // but the action was not completed, the result should contain a reason.
151
153
  }
152
154
  } else {
153
- // TODO: EDITOR-188 - Dispatch analytics event
155
+ // TODO: EDITOR-595 - Track the toolbar comment button was clicked but the preemptive gate
156
+ // check returned false and the draft cannot be started.
154
157
  }
155
158
  }).catch(function () {
156
- // TODO: EDITOR-188 - Handle preemptive gate check error and dispatch analytics event
159
+ // TODO: EDITOR-595 - Handle preemptive gate check error. Something went very wrong in the gate.
157
160
  });
158
161
  return true;
159
162
  } else {
@@ -8,5 +8,7 @@ export var ACTIONS = /*#__PURE__*/function (ACTIONS) {
8
8
  ACTIONS[ACTIONS["CLOSE_COMPONENT"] = 6] = "CLOSE_COMPONENT";
9
9
  ACTIONS[ACTIONS["SET_SELECTED_ANNOTATION"] = 7] = "SET_SELECTED_ANNOTATION";
10
10
  ACTIONS[ACTIONS["SET_HOVERED_ANNOTATION"] = 8] = "SET_HOVERED_ANNOTATION";
11
+ ACTIONS[ACTIONS["FLUSH_PENDING_SELECTIONS"] = 9] = "FLUSH_PENDING_SELECTIONS";
12
+ ACTIONS[ACTIONS["SET_PENDING_SELECTIONS"] = 10] = "SET_PENDING_SELECTIONS";
11
13
  return ACTIONS;
12
14
  }({});