@atlaskit/editor-plugin-annotation 1.2.1 → 1.3.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 (35) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cjs/commands/index.js +45 -4
  3. package/dist/cjs/nodeviews/index.js +1 -1
  4. package/dist/cjs/plugin.js +7 -3
  5. package/dist/cjs/pm-plugins/inline-comment.js +6 -3
  6. package/dist/cjs/pm-plugins/plugin-factory.js +21 -3
  7. package/dist/cjs/pm-plugins/reducer.js +6 -4
  8. package/dist/cjs/toolbar.js +0 -1
  9. package/dist/cjs/ui/AnnotationViewWrapper.js +1 -1
  10. package/dist/cjs/utils.js +50 -5
  11. package/dist/es2019/commands/index.js +47 -6
  12. package/dist/es2019/plugin.js +7 -3
  13. package/dist/es2019/pm-plugins/inline-comment.js +6 -4
  14. package/dist/es2019/pm-plugins/plugin-factory.js +21 -4
  15. package/dist/es2019/pm-plugins/reducer.js +8 -5
  16. package/dist/es2019/toolbar.js +0 -1
  17. package/dist/es2019/utils.js +52 -5
  18. package/dist/esm/commands/index.js +46 -5
  19. package/dist/esm/nodeviews/index.js +1 -1
  20. package/dist/esm/plugin.js +7 -3
  21. package/dist/esm/pm-plugins/inline-comment.js +6 -3
  22. package/dist/esm/pm-plugins/plugin-factory.js +22 -4
  23. package/dist/esm/pm-plugins/reducer.js +7 -5
  24. package/dist/esm/toolbar.js +0 -1
  25. package/dist/esm/ui/AnnotationViewWrapper.js +1 -1
  26. package/dist/esm/utils.js +50 -5
  27. package/dist/types/commands/index.d.ts +2 -2
  28. package/dist/types/pm-plugins/types.d.ts +5 -0
  29. package/dist/types/types.d.ts +5 -0
  30. package/dist/types/utils.d.ts +8 -2
  31. package/dist/types-ts4.5/commands/index.d.ts +2 -2
  32. package/dist/types-ts4.5/pm-plugins/types.d.ts +5 -0
  33. package/dist/types-ts4.5/types.d.ts +5 -0
  34. package/dist/types-ts4.5/utils.d.ts +8 -2
  35. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @atlaskit/editor-plugin-annotation
2
2
 
3
+ ## 1.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#80123](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/80123) [`8bb18b4d686c`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/8bb18b4d686c) - [ux] - Add decoration to media node when there is active draft comment associated, update plugin state mapping so that create view component is removed when there's node changes invalidating the decoration
8
+
9
+ - Save featureFlags plugin state as one of the annotation plugin state
10
+
11
+ ## 1.2.2
12
+
13
+ ### Patch Changes
14
+
15
+ - [#79658](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/79658) [`4b195011d7c1`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/4b195011d7c1) - ED-22112 support remove annotation from supported nodes
16
+
3
17
  ## 1.2.1
4
18
 
5
19
  ### Patch Changes
@@ -8,6 +8,7 @@ exports.updateMouseState = exports.updateInlineCommentResolvedState = exports.se
8
8
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
9
  var _adfSchema = require("@atlaskit/adf-schema");
10
10
  var _analytics = require("@atlaskit/editor-common/analytics");
11
+ var _state = require("@atlaskit/editor-prosemirror/state");
11
12
  var _pluginFactory = require("../pm-plugins/plugin-factory");
12
13
  var _types = require("../pm-plugins/types");
13
14
  var _types2 = require("../types");
@@ -38,11 +39,48 @@ var clearDirtyMark = exports.clearDirtyMark = function clearDirtyMark() {
38
39
  type: _types.ACTIONS.INLINE_COMMENT_CLEAR_DIRTY_MARK
39
40
  });
40
41
  };
42
+ var removeInlineCommentFromNode = function removeInlineCommentFromNode(id) {
43
+ var supportedBlockNodes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
44
+ var state = arguments.length > 2 ? arguments[2] : undefined;
45
+ var dispatch = arguments.length > 3 ? arguments[3] : undefined;
46
+ var tr = state.tr,
47
+ selection = state.selection;
48
+ if (selection instanceof _state.NodeSelection && (0, _utils.isSupportedBlockNode)(selection.node, supportedBlockNodes)) {
49
+ var $from = selection.$from;
50
+ var currNode = selection.node;
51
+ var from = $from.start();
52
+
53
+ // for media annotation, the selection is on media Single
54
+ if (currNode.type === state.schema.nodes.mediaSingle && currNode.firstChild) {
55
+ currNode = currNode.firstChild;
56
+ from = from + 1;
57
+ }
58
+ var annotationMarkType = state.schema.marks.annotation;
59
+ var hasAnnotation = currNode.marks.some(function (mark) {
60
+ return mark.type === annotationMarkType;
61
+ });
62
+ if (!hasAnnotation) {
63
+ return false;
64
+ }
65
+ tr.removeNodeMark(from, annotationMarkType.create({
66
+ id: id,
67
+ type: _adfSchema.AnnotationTypes.INLINE_COMMENT
68
+ }));
69
+ if (dispatch) {
70
+ dispatch(tr);
71
+ }
72
+ return true;
73
+ }
74
+ return false;
75
+ };
41
76
  var removeInlineCommentNearSelection = exports.removeInlineCommentNearSelection = function removeInlineCommentNearSelection(id) {
42
- var _supportedNodes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
77
+ var supportedNodes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
43
78
  return function (state, dispatch) {
44
79
  var tr = state.tr,
45
80
  $from = state.selection.$from;
81
+ if (removeInlineCommentFromNode(id, supportedNodes, state, dispatch)) {
82
+ return true;
83
+ }
46
84
  var annotationMarkType = state.schema.marks.annotation;
47
85
  var hasAnnotation = $from.marks().some(function (mark) {
48
86
  return mark.type === annotationMarkType;
@@ -62,7 +100,7 @@ var removeInlineCommentNearSelection = exports.removeInlineCommentNearSelection
62
100
  return true;
63
101
  };
64
102
  };
65
- var getDraftCommandAction = function getDraftCommandAction(drafting, targetType, isCommentOnMediaOn) {
103
+ var getDraftCommandAction = function getDraftCommandAction(drafting, targetType, isCommentOnMediaOn, supportedBlockNodes) {
66
104
  return function (editorState) {
67
105
  // validate selection only when entering draft mode
68
106
  if (drafting && (0, _utils.isSelectionValid)(editorState, isCommentOnMediaOn) !== _types2.AnnotationSelectionType.VALID) {
@@ -73,17 +111,20 @@ var getDraftCommandAction = function getDraftCommandAction(drafting, targetType,
73
111
  data: {
74
112
  drafting: drafting,
75
113
  editorState: editorState,
76
- targetType: targetType
114
+ targetType: targetType,
115
+ isCommentOnMediaOn: isCommentOnMediaOn,
116
+ supportedBlockNodes: supportedBlockNodes
77
117
  }
78
118
  };
79
119
  };
80
120
  };
81
121
  var setInlineCommentDraftState = exports.setInlineCommentDraftState = function setInlineCommentDraftState(editorAnalyticsAPI) {
122
+ var supportedBlockNodes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
82
123
  return function (drafting) {
83
124
  var inputMethod = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _analytics.INPUT_METHOD.TOOLBAR;
84
125
  var targetType = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'inline';
85
126
  var isCommentOnMediaOn = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
86
- var commandAction = getDraftCommandAction(drafting, targetType, isCommentOnMediaOn);
127
+ var commandAction = getDraftCommandAction(drafting, targetType, isCommentOnMediaOn, supportedBlockNodes);
87
128
  return (0, _pluginFactory.createCommand)(commandAction, _transform.default.addOpenCloseAnalytics(editorAnalyticsAPI)(drafting, inputMethod));
88
129
  };
89
130
  };
@@ -14,7 +14,7 @@ var _react = _interopRequireDefault(require("react"));
14
14
  var _reactNodeView = _interopRequireDefault(require("@atlaskit/editor-common/react-node-view"));
15
15
  var _styles = require("@atlaskit/editor-common/styles");
16
16
  function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2.default)(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2.default)(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2.default)(this, result); }; }
17
- function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
17
+ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
18
18
  var AnnotationNodeView = exports.AnnotationNodeView = /*#__PURE__*/function (_ReactNodeView) {
19
19
  (0, _inherits2.default)(AnnotationNodeView, _ReactNodeView);
20
20
  var _super = _createSuper(AnnotationNodeView);
@@ -37,13 +37,16 @@ var annotationPlugin = exports.annotationPlugin = function annotationPlugin(_ref
37
37
  },
38
38
  actions: {
39
39
  stripNonExistingAnnotations: _utils.stripNonExistingAnnotations,
40
- setInlineCommentDraftState: (0, _commands.setInlineCommentDraftState)(api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions)
40
+ setInlineCommentDraftState: (0, _commands.setInlineCommentDraftState)(api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions, annotationProviders === null || annotationProviders === void 0 ? void 0 : annotationProviders.inlineComment.supportedBlockNodes)
41
41
  },
42
42
  getSharedState: function getSharedState(editorState) {
43
43
  if (!editorState) {
44
44
  return undefined;
45
45
  }
46
- return (0, _utils.getPluginState)(editorState) || undefined;
46
+ var pluginState = (0, _utils.getPluginState)(editorState) || undefined;
47
+ var clonedPluginState = Object.assign({}, pluginState);
48
+ clonedPluginState === null || clonedPluginState === void 0 || delete clonedPluginState.featureFlagsPluginState;
49
+ return clonedPluginState;
47
50
  },
48
51
  pmPlugins: function pmPlugins() {
49
52
  return [{
@@ -59,7 +62,8 @@ var annotationPlugin = exports.annotationPlugin = function annotationPlugin(_ref
59
62
  portalProviderAPI: portalProviderAPI,
60
63
  eventDispatcher: eventDispatcher,
61
64
  provider: annotationProviders.inlineComment,
62
- editorAnalyticsAPI: api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions
65
+ editorAnalyticsAPI: api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions,
66
+ featureFlagsPluginState: featureFlags
63
67
  });
64
68
  }
65
69
  return;
@@ -77,6 +77,7 @@ var fetchState = /*#__PURE__*/function () {
77
77
  }();
78
78
  var initialState = function initialState() {
79
79
  var disallowOnWhitespace = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
80
+ var featureFlagsPluginState = arguments.length > 1 ? arguments[1] : undefined;
80
81
  return {
81
82
  annotations: {},
82
83
  selectedAnnotations: [],
@@ -86,7 +87,8 @@ var initialState = function initialState() {
86
87
  disallowOnWhitespace: disallowOnWhitespace,
87
88
  isInlineCommentViewClosed: false,
88
89
  isVisible: true,
89
- skipSelectionHandling: false
90
+ skipSelectionHandling: false,
91
+ featureFlagsPluginState: featureFlagsPluginState
90
92
  };
91
93
  };
92
94
  var hideToolbar = function hideToolbar(state, dispatch) {
@@ -140,10 +142,11 @@ var onSetVisibility = function onSetVisibility(view) {
140
142
  var inlineCommentPlugin = exports.inlineCommentPlugin = function inlineCommentPlugin(options) {
141
143
  var provider = options.provider,
142
144
  portalProviderAPI = options.portalProviderAPI,
143
- eventDispatcher = options.eventDispatcher;
145
+ eventDispatcher = options.eventDispatcher,
146
+ featureFlagsPluginState = options.featureFlagsPluginState;
144
147
  return new _safePlugin.SafePlugin({
145
148
  key: _utils.inlineCommentPluginKey,
146
- state: (0, _pluginFactory.createPluginState)(options.dispatch, initialState(provider.disallowOnWhitespace)),
149
+ state: (0, _pluginFactory.createPluginState)(options.dispatch, initialState(provider.disallowOnWhitespace, featureFlagsPluginState)),
147
150
  view: function view(editorView) {
148
151
  // Get initial state
149
152
  // Need to pass `editorView` to mitigate editor state going stale
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", {
7
7
  exports.createPluginState = exports.createCommand = void 0;
8
8
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
9
  var _utils = require("@atlaskit/editor-common/utils");
10
+ var _view = require("@atlaskit/editor-prosemirror/view");
10
11
  var _utils2 = require("../utils");
11
12
  var _reducer = _interopRequireDefault(require("./reducer"));
12
13
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
@@ -50,13 +51,30 @@ var getSelectionChangedHandler = function getSelectionChangedHandler(reopenComme
50
51
  var _pluginFactory = (0, _utils.pluginFactory)(_utils2.inlineCommentPluginKey, _reducer.default, {
51
52
  onSelectionChanged: getSelectionChangedHandler(true),
52
53
  onDocChanged: handleDocChanged,
53
- mapping: function mapping(tr, pluginState) {
54
+ mapping: function mapping(tr, pluginState, editorState) {
54
55
  var draftDecorationSet = pluginState.draftDecorationSet,
55
- bookmark = pluginState.bookmark;
56
- var mappedDecorationSet, mappedBookmark;
56
+ bookmark = pluginState.bookmark,
57
+ featureFlagsPluginState = pluginState.featureFlagsPluginState;
58
+ var mappedDecorationSet = _view.DecorationSet.empty,
59
+ mappedBookmark;
60
+ var hasMappedDecorations = false;
57
61
  if (draftDecorationSet) {
58
62
  mappedDecorationSet = draftDecorationSet.map(tr.mapping, tr.doc);
59
63
  }
64
+ if (featureFlagsPluginState !== null && featureFlagsPluginState !== void 0 && featureFlagsPluginState.commentsOnMedia) {
65
+ hasMappedDecorations = mappedDecorationSet.find(undefined, undefined, function (spec) {
66
+ return Object.values(_utils2.decorationKey).includes(spec.key);
67
+ }).length > 0;
68
+
69
+ // When changes to decoration target make decoration invalid (e.g. delete text, add mark to node),
70
+ // we need to reset bookmark to hide create component and to avoid invalid draft being published
71
+ if (!hasMappedDecorations) {
72
+ return _objectSpread(_objectSpread({}, pluginState), {}, {
73
+ draftDecorationSet: mappedDecorationSet,
74
+ bookmark: undefined
75
+ });
76
+ }
77
+ }
60
78
  if (bookmark) {
61
79
  mappedBookmark = bookmark.map(tr.mapping);
62
80
  }
@@ -24,7 +24,7 @@ var _default = exports.default = function _default(pluginState, action) {
24
24
  mouseData: mouseData
25
25
  });
26
26
  case _types.ACTIONS.SET_INLINE_COMMENT_DRAFT_STATE:
27
- return getNewDraftState(pluginState, action.data.drafting, action.data.editorState, action.data.targetType);
27
+ return getNewDraftState(pluginState, action.data.drafting, action.data.editorState, action.data.targetType, action.data.isCommentOnMediaOn, action.data.supportedBlockNodes);
28
28
  case _types.ACTIONS.INLINE_COMMENT_CLEAR_DIRTY_MARK:
29
29
  return _objectSpread(_objectSpread({}, pluginState), {}, {
30
30
  dirtyAnnotations: false,
@@ -59,7 +59,7 @@ var _default = exports.default = function _default(pluginState, action) {
59
59
  return pluginState;
60
60
  }
61
61
  };
62
- function getNewDraftState(pluginState, drafting, editorState, targetType) {
62
+ function getNewDraftState(pluginState, drafting, editorState, targetType, isCommentOnMediaOn, supportedBlockNodes) {
63
63
  var draftDecorationSet = pluginState.draftDecorationSet;
64
64
  if (!draftDecorationSet || !drafting) {
65
65
  draftDecorationSet = _view.DecorationSet.empty;
@@ -70,8 +70,10 @@ function getNewDraftState(pluginState, drafting, editorState, targetType) {
70
70
  newState.bookmark = undefined;
71
71
  if (drafting && editorState) {
72
72
  newState.bookmark = editorState.selection.getBookmark();
73
- var resolvedBookmark = newState.bookmark.resolve(editorState.doc);
74
- var draftDecoration = (0, _utils.addDraftDecoration)(resolvedBookmark.from, resolvedBookmark.to, targetType);
73
+ var _ref = isCommentOnMediaOn ? (0, _utils.resolveDraftBookmark)(editorState, newState.bookmark, supportedBlockNodes) : newState.bookmark.resolve(editorState.doc),
74
+ from = _ref.from,
75
+ to = _ref.to;
76
+ var draftDecoration = (0, _utils.addDraftDecoration)(from, to, targetType);
75
77
  newState.draftDecorationSet = draftDecorationSet.add(editorState.doc, [draftDecoration]);
76
78
  }
77
79
  return newState;
@@ -58,7 +58,6 @@ var buildToolbar = exports.buildToolbar = function buildToolbar(editorAnalyticsA
58
58
  },
59
59
  supportsViewMode: true // TODO: MODES-3950 Clean up this floating toolbar view mode logic
60
60
  };
61
-
62
61
  var annotation = schema.marks.annotation;
63
62
  var validNodes = Object.keys(schema.nodes).reduce(function (acc, current) {
64
63
  var type = schema.nodes[current];
@@ -12,7 +12,7 @@ var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime
12
12
  var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
13
13
  var _react = _interopRequireDefault(require("react"));
14
14
  function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2.default)(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2.default)(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2.default)(this, result); }; }
15
- function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
15
+ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
16
16
  // eslint-disable-next-line @repo/internal/react/no-class-components
17
17
  var AnnotationViewWrapper = exports.AnnotationViewWrapper = /*#__PURE__*/function (_React$PureComponent) {
18
18
  (0, _inherits2.default)(AnnotationViewWrapper, _React$PureComponent);
package/dist/cjs/utils.js CHANGED
@@ -11,7 +11,7 @@ Object.defineProperty(exports, "containsAnyAnnotations", {
11
11
  return _utils.containsAnyAnnotations;
12
12
  }
13
13
  });
14
- exports.getPluginState = exports.getDraftCommandAnalyticsPayload = exports.getAnnotationViewKey = exports.getAllAnnotations = exports.findAnnotationsInSelection = void 0;
14
+ exports.getPluginState = exports.getDraftCommandAnalyticsPayload = exports.getAnnotationViewKey = exports.getAllAnnotations = exports.findAnnotationsInSelection = exports.decorationKey = void 0;
15
15
  exports.getSelectionPositions = getSelectionPositions;
16
16
  Object.defineProperty(exports, "hasAnnotationMark", {
17
17
  enumerable: true,
@@ -23,7 +23,7 @@ exports.hasInvalidNodes = void 0;
23
23
  exports.hasInvalidWhitespaceNode = hasInvalidWhitespaceNode;
24
24
  exports.inlineCommentPluginKey = void 0;
25
25
  exports.isSelectedAnnotationsChanged = isSelectedAnnotationsChanged;
26
- exports.isSelectionValid = void 0;
26
+ exports.resolveDraftBookmark = exports.isSupportedBlockNode = exports.isSelectionValid = void 0;
27
27
  exports.stripNonExistingAnnotations = stripNonExistingAnnotations;
28
28
  exports.surroundingMarks = void 0;
29
29
  var _adfSchema = require("@atlaskit/adf-schema");
@@ -125,7 +125,10 @@ var validateAnnotationMark = function validateAnnotationMark(annotationMark) {
125
125
  return allowedTypes.includes(type);
126
126
  }
127
127
  };
128
-
128
+ var decorationKey = exports.decorationKey = {
129
+ block: 'blockCommentDecoration',
130
+ inline: 'inlineCommentDecoration'
131
+ };
129
132
  /*
130
133
  * add decoration for the comment selection in draft state
131
134
  * (when creating new comment)
@@ -134,11 +137,15 @@ var addDraftDecoration = exports.addDraftDecoration = function addDraftDecoratio
134
137
  var targetType = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'inline';
135
138
  if (targetType === 'block') {
136
139
  return _view.Decoration.node(start, end, {
137
- class: "".concat(_styles.AnnotationSharedClassNames.draft)
140
+ class: "".concat(_styles.BlockAnnotationSharedClassNames.draft)
141
+ }, {
142
+ key: decorationKey.block
138
143
  });
139
144
  }
140
145
  return _view.Decoration.inline(start, end, {
141
146
  class: "".concat(_styles.AnnotationSharedClassNames.draft)
147
+ }, {
148
+ key: decorationKey.inline
142
149
  });
143
150
  };
144
151
  var getAnnotationViewKey = exports.getAnnotationViewKey = function getAnnotationViewKey(annotations) {
@@ -179,7 +186,41 @@ var findAnnotationsInSelection = exports.findAnnotationsInSelection = function f
179
186
  reorderAnnotations(annotations, $anchor);
180
187
  return annotations;
181
188
  };
182
-
189
+ var resolveDraftBookmark = exports.resolveDraftBookmark = function resolveDraftBookmark(editorState, bookmark) {
190
+ var supportedBlockNodes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
191
+ var doc = editorState.doc;
192
+ var resolvedBookmark = bookmark.resolve(doc);
193
+ var from = resolvedBookmark.from,
194
+ to = resolvedBookmark.to,
195
+ head = resolvedBookmark.head;
196
+ var draftBookmark = {
197
+ from: from,
198
+ to: to,
199
+ head: head
200
+ };
201
+ if (resolvedBookmark instanceof _state.NodeSelection) {
202
+ // It's possible that annotation is only allowed in child node instead parent (e.g. mediaSingle vs media),
203
+ // thus, we traverse the node to find the first node that supports annotation and return its position
204
+ var nodeFound = false;
205
+ doc.nodesBetween(from, to, function (node, pos) {
206
+ // if we find the node, breakout the traversal to make sure we always record the first supported node
207
+ if (nodeFound) {
208
+ return false;
209
+ }
210
+ var nodeEndsAt = pos + node.nodeSize;
211
+ if (supportedBlockNodes.includes(node.type.name)) {
212
+ draftBookmark = {
213
+ from: pos,
214
+ to: nodeEndsAt,
215
+ head: nodeEndsAt
216
+ };
217
+ nodeFound = true;
218
+ return false;
219
+ }
220
+ });
221
+ }
222
+ return draftBookmark;
223
+ };
183
224
  /**
184
225
  * get selection from position to apply new comment for
185
226
  * @return bookmarked positions if they exists, otherwise current selection positions
@@ -299,6 +340,10 @@ function isEmptyTextSelection(selection, schema) {
299
340
  });
300
341
  return !hasContent;
301
342
  }
343
+ var isSupportedBlockNode = exports.isSupportedBlockNode = function isSupportedBlockNode(node) {
344
+ var supportedBlockNodes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
345
+ return supportedBlockNodes.indexOf(node.type.name) >= 0 || node.type.name === 'mediaSingle' && supportedBlockNodes.indexOf('media') >= 0;
346
+ };
302
347
 
303
348
  /**
304
349
  * Checks if any of the nodes in a given selection are completely whitespace
@@ -1,9 +1,10 @@
1
1
  import { AnnotationTypes } from '@atlaskit/adf-schema';
2
2
  import { INPUT_METHOD } from '@atlaskit/editor-common/analytics';
3
+ import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
3
4
  import { createCommand } from '../pm-plugins/plugin-factory';
4
5
  import { ACTIONS } from '../pm-plugins/types';
5
6
  import { AnnotationSelectionType } from '../types';
6
- import { getPluginState, isSelectionValid } from '../utils';
7
+ import { getPluginState, isSelectionValid, isSupportedBlockNode } from '../utils';
7
8
  import transform from './transform';
8
9
  export const updateInlineCommentResolvedState = editorAnalyticsAPI => (partialNewState, resolveMethod) => {
9
10
  const command = {
@@ -22,13 +23,51 @@ export const closeComponent = () => createCommand({
22
23
  export const clearDirtyMark = () => createCommand({
23
24
  type: ACTIONS.INLINE_COMMENT_CLEAR_DIRTY_MARK
24
25
  });
25
- export const removeInlineCommentNearSelection = (id, _supportedNodes = []) => (state, dispatch) => {
26
+ const removeInlineCommentFromNode = (id, supportedBlockNodes = [], state, dispatch) => {
27
+ const {
28
+ tr,
29
+ selection
30
+ } = state;
31
+ if (selection instanceof NodeSelection && isSupportedBlockNode(selection.node, supportedBlockNodes)) {
32
+ const {
33
+ $from
34
+ } = selection;
35
+ let currNode = selection.node;
36
+ let from = $from.start();
37
+
38
+ // for media annotation, the selection is on media Single
39
+ if (currNode.type === state.schema.nodes.mediaSingle && currNode.firstChild) {
40
+ currNode = currNode.firstChild;
41
+ from = from + 1;
42
+ }
43
+ const {
44
+ annotation: annotationMarkType
45
+ } = state.schema.marks;
46
+ const hasAnnotation = currNode.marks.some(mark => mark.type === annotationMarkType);
47
+ if (!hasAnnotation) {
48
+ return false;
49
+ }
50
+ tr.removeNodeMark(from, annotationMarkType.create({
51
+ id,
52
+ type: AnnotationTypes.INLINE_COMMENT
53
+ }));
54
+ if (dispatch) {
55
+ dispatch(tr);
56
+ }
57
+ return true;
58
+ }
59
+ return false;
60
+ };
61
+ export const removeInlineCommentNearSelection = (id, supportedNodes = []) => (state, dispatch) => {
26
62
  const {
27
63
  tr,
28
64
  selection: {
29
65
  $from
30
66
  }
31
67
  } = state;
68
+ if (removeInlineCommentFromNode(id, supportedNodes, state, dispatch)) {
69
+ return true;
70
+ }
32
71
  const {
33
72
  annotation: annotationMarkType
34
73
  } = state.schema.marks;
@@ -47,7 +86,7 @@ export const removeInlineCommentNearSelection = (id, _supportedNodes = []) => (s
47
86
  }
48
87
  return true;
49
88
  };
50
- const getDraftCommandAction = (drafting, targetType, isCommentOnMediaOn) => {
89
+ const getDraftCommandAction = (drafting, targetType, isCommentOnMediaOn, supportedBlockNodes) => {
51
90
  return editorState => {
52
91
  // validate selection only when entering draft mode
53
92
  if (drafting && isSelectionValid(editorState, isCommentOnMediaOn) !== AnnotationSelectionType.VALID) {
@@ -58,13 +97,15 @@ const getDraftCommandAction = (drafting, targetType, isCommentOnMediaOn) => {
58
97
  data: {
59
98
  drafting,
60
99
  editorState,
61
- targetType
100
+ targetType,
101
+ isCommentOnMediaOn,
102
+ supportedBlockNodes
62
103
  }
63
104
  };
64
105
  };
65
106
  };
66
- export const setInlineCommentDraftState = editorAnalyticsAPI => (drafting, inputMethod = INPUT_METHOD.TOOLBAR, targetType = 'inline', isCommentOnMediaOn = false) => {
67
- const commandAction = getDraftCommandAction(drafting, targetType, isCommentOnMediaOn);
107
+ export const setInlineCommentDraftState = (editorAnalyticsAPI, supportedBlockNodes = []) => (drafting, inputMethod = INPUT_METHOD.TOOLBAR, targetType = 'inline', isCommentOnMediaOn = false) => {
108
+ const commandAction = getDraftCommandAction(drafting, targetType, isCommentOnMediaOn, supportedBlockNodes);
68
109
  return createCommand(commandAction, transform.addOpenCloseAnalytics(editorAnalyticsAPI)(drafting, inputMethod));
69
110
  };
70
111
  export const addInlineComment = (editorAnalyticsAPI, editorAPI) => id => {
@@ -25,13 +25,16 @@ export const annotationPlugin = ({
25
25
  },
26
26
  actions: {
27
27
  stripNonExistingAnnotations,
28
- setInlineCommentDraftState: setInlineCommentDraftState(api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions)
28
+ setInlineCommentDraftState: setInlineCommentDraftState(api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions, annotationProviders === null || annotationProviders === void 0 ? void 0 : annotationProviders.inlineComment.supportedBlockNodes)
29
29
  },
30
30
  getSharedState(editorState) {
31
31
  if (!editorState) {
32
32
  return undefined;
33
33
  }
34
- return getPluginState(editorState) || undefined;
34
+ const pluginState = getPluginState(editorState) || undefined;
35
+ const clonedPluginState = Object.assign({}, pluginState);
36
+ clonedPluginState === null || clonedPluginState === void 0 ? true : delete clonedPluginState.featureFlagsPluginState;
37
+ return clonedPluginState;
35
38
  },
36
39
  pmPlugins: () => [{
37
40
  name: 'annotation',
@@ -47,7 +50,8 @@ export const annotationPlugin = ({
47
50
  portalProviderAPI,
48
51
  eventDispatcher,
49
52
  provider: annotationProviders.inlineComment,
50
- editorAnalyticsAPI: api === null || api === void 0 ? void 0 : (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions
53
+ editorAnalyticsAPI: api === null || api === void 0 ? void 0 : (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions,
54
+ featureFlagsPluginState: featureFlags
51
55
  });
52
56
  }
53
57
  return;
@@ -28,7 +28,7 @@ const fetchState = async (provider, annotationIds, editorView, editorAnalyticsAP
28
28
  updateInlineCommentResolvedState(editorAnalyticsAPI)(inlineCommentStates)(editorView.state, editorView.dispatch);
29
29
  }
30
30
  };
31
- const initialState = (disallowOnWhitespace = false) => {
31
+ const initialState = (disallowOnWhitespace = false, featureFlagsPluginState) => {
32
32
  return {
33
33
  annotations: {},
34
34
  selectedAnnotations: [],
@@ -38,7 +38,8 @@ const initialState = (disallowOnWhitespace = false) => {
38
38
  disallowOnWhitespace,
39
39
  isInlineCommentViewClosed: false,
40
40
  isVisible: true,
41
- skipSelectionHandling: false
41
+ skipSelectionHandling: false,
42
+ featureFlagsPluginState
42
43
  };
43
44
  };
44
45
  const hideToolbar = (state, dispatch) => () => {
@@ -86,11 +87,12 @@ export const inlineCommentPlugin = options => {
86
87
  const {
87
88
  provider,
88
89
  portalProviderAPI,
89
- eventDispatcher
90
+ eventDispatcher,
91
+ featureFlagsPluginState
90
92
  } = options;
91
93
  return new SafePlugin({
92
94
  key: inlineCommentPluginKey,
93
- state: createPluginState(options.dispatch, initialState(provider.disallowOnWhitespace)),
95
+ state: createPluginState(options.dispatch, initialState(provider.disallowOnWhitespace, featureFlagsPluginState)),
94
96
  view(editorView) {
95
97
  // Get initial state
96
98
  // Need to pass `editorView` to mitigate editor state going stale
@@ -1,5 +1,6 @@
1
1
  import { pluginFactory } from '@atlaskit/editor-common/utils';
2
- import { findAnnotationsInSelection, inlineCommentPluginKey, isSelectedAnnotationsChanged } from '../utils';
2
+ import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
3
+ import { decorationKey, findAnnotationsInSelection, inlineCommentPluginKey, isSelectedAnnotationsChanged } from '../utils';
3
4
  import reducer from './reducer';
4
5
  const handleDocChanged = (tr, prevPluginState) => {
5
6
  if (!tr.getMeta('replaceDocument')) {
@@ -50,15 +51,31 @@ export const {
50
51
  } = pluginFactory(inlineCommentPluginKey, reducer, {
51
52
  onSelectionChanged: getSelectionChangedHandler(true),
52
53
  onDocChanged: handleDocChanged,
53
- mapping: (tr, pluginState) => {
54
+ mapping: (tr, pluginState, editorState) => {
54
55
  let {
55
56
  draftDecorationSet,
56
- bookmark
57
+ bookmark,
58
+ featureFlagsPluginState
57
59
  } = pluginState;
58
- let mappedDecorationSet, mappedBookmark;
60
+ let mappedDecorationSet = DecorationSet.empty,
61
+ mappedBookmark;
62
+ let hasMappedDecorations = false;
59
63
  if (draftDecorationSet) {
60
64
  mappedDecorationSet = draftDecorationSet.map(tr.mapping, tr.doc);
61
65
  }
66
+ if (featureFlagsPluginState !== null && featureFlagsPluginState !== void 0 && featureFlagsPluginState.commentsOnMedia) {
67
+ hasMappedDecorations = mappedDecorationSet.find(undefined, undefined, spec => Object.values(decorationKey).includes(spec.key)).length > 0;
68
+
69
+ // When changes to decoration target make decoration invalid (e.g. delete text, add mark to node),
70
+ // we need to reset bookmark to hide create component and to avoid invalid draft being published
71
+ if (!hasMappedDecorations) {
72
+ return {
73
+ ...pluginState,
74
+ draftDecorationSet: mappedDecorationSet,
75
+ bookmark: undefined
76
+ };
77
+ }
78
+ }
62
79
  if (bookmark) {
63
80
  mappedBookmark = bookmark.map(tr.mapping);
64
81
  }
@@ -1,5 +1,5 @@
1
1
  import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
2
- import { addDraftDecoration } from '../utils';
2
+ import { addDraftDecoration, resolveDraftBookmark } from '../utils';
3
3
  import { ACTIONS } from './types';
4
4
  export default ((pluginState, action) => {
5
5
  switch (action.type) {
@@ -18,7 +18,7 @@ export default ((pluginState, action) => {
18
18
  mouseData
19
19
  };
20
20
  case ACTIONS.SET_INLINE_COMMENT_DRAFT_STATE:
21
- return getNewDraftState(pluginState, action.data.drafting, action.data.editorState, action.data.targetType);
21
+ return getNewDraftState(pluginState, action.data.drafting, action.data.editorState, action.data.targetType, action.data.isCommentOnMediaOn, action.data.supportedBlockNodes);
22
22
  case ACTIONS.INLINE_COMMENT_CLEAR_DIRTY_MARK:
23
23
  return {
24
24
  ...pluginState,
@@ -63,7 +63,7 @@ export default ((pluginState, action) => {
63
63
  return pluginState;
64
64
  }
65
65
  });
66
- function getNewDraftState(pluginState, drafting, editorState, targetType) {
66
+ function getNewDraftState(pluginState, drafting, editorState, targetType, isCommentOnMediaOn, supportedBlockNodes) {
67
67
  let {
68
68
  draftDecorationSet
69
69
  } = pluginState;
@@ -77,8 +77,11 @@ function getNewDraftState(pluginState, drafting, editorState, targetType) {
77
77
  newState.bookmark = undefined;
78
78
  if (drafting && editorState) {
79
79
  newState.bookmark = editorState.selection.getBookmark();
80
- const resolvedBookmark = newState.bookmark.resolve(editorState.doc);
81
- const draftDecoration = addDraftDecoration(resolvedBookmark.from, resolvedBookmark.to, targetType);
80
+ const {
81
+ from,
82
+ to
83
+ } = isCommentOnMediaOn ? resolveDraftBookmark(editorState, newState.bookmark, supportedBlockNodes) : newState.bookmark.resolve(editorState.doc);
84
+ const draftDecoration = addDraftDecoration(from, to, targetType);
82
85
  newState.draftDecorationSet = draftDecorationSet.add(editorState.doc, [draftDecoration]);
83
86
  }
84
87
  return newState;
@@ -49,7 +49,6 @@ export const buildToolbar = editorAnalyticsAPI => (state, intl, isToolbarAbove =
49
49
  },
50
50
  supportsViewMode: true // TODO: MODES-3950 Clean up this floating toolbar view mode logic
51
51
  };
52
-
53
52
  const {
54
53
  annotation
55
54
  } = schema.marks;