@atlaskit/editor-plugin-annotation
Version:
Annotation plugin for @atlaskit/editor-core
257 lines (247 loc) • 13 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.InlineCommentView = InlineCommentView;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = _interopRequireDefault(require("react"));
var _annotation = require("@atlaskit/adf-schema/annotation");
var _enums = require("@atlaskit/editor-common/analytics/types/enums");
var _inlineCommentEvents = require("@atlaskit/editor-common/analytics/types/inline-comment-events");
var _isOfflineMode = require("@atlaskit/editor-common/connectivity/isOfflineMode");
var _useSharedPluginStateSelector = require("@atlaskit/editor-common/useSharedPluginStateSelector");
var _useSharedPluginStateWithSelector = require("@atlaskit/editor-common/useSharedPluginStateWithSelector");
var _annotation2 = require("@atlaskit/editor-common/utils/annotation");
var _state = require("@atlaskit/editor-prosemirror/state");
var _utils = require("@atlaskit/editor-prosemirror/utils");
var _fg = require("@atlaskit/platform-feature-flags/fg");
var _editorCommands = require("../editor-commands");
var _utils2 = require("../pm-plugins/utils");
var _types = require("../types");
var _AnnotationViewWrapper = require("./AnnotationViewWrapper");
var findPosForDOM = function findPosForDOM(sel) {
var $from = sel.$from,
from = sel.from;
// Retrieve current TextNode
var index = $from.index();
var node = index < $from.parent.childCount && $from.parent.child(index);
// Right edge of a mark.
if (!node && $from.nodeBefore && $from.nodeBefore.isText && $from.nodeBefore.marks.find(function (mark) {
return mark.type.name === 'annotation';
})) {
return from - 1;
}
return from;
};
var selector = function selector(states) {
var _states$annotationSta, _states$annotationSta2, _states$annotationSta3, _states$annotationSta4, _states$annotationSta5, _states$annotationSta6, _states$annotationSta7;
return {
annotations: (_states$annotationSta = states.annotationState) === null || _states$annotationSta === void 0 ? void 0 : _states$annotationSta.annotations,
bookmark: (_states$annotationSta2 = states.annotationState) === null || _states$annotationSta2 === void 0 ? void 0 : _states$annotationSta2.bookmark,
isInlineCommentViewClosed: (_states$annotationSta3 = states.annotationState) === null || _states$annotationSta3 === void 0 ? void 0 : _states$annotationSta3.isInlineCommentViewClosed,
isOpeningMediaCommentFromToolbar: (_states$annotationSta4 = states.annotationState) === null || _states$annotationSta4 === void 0 ? void 0 : _states$annotationSta4.isOpeningMediaCommentFromToolbar,
selectAnnotationMethod: (_states$annotationSta5 = states.annotationState) === null || _states$annotationSta5 === void 0 ? void 0 : _states$annotationSta5.selectAnnotationMethod,
selectedAnnotations: (_states$annotationSta6 = states.annotationState) === null || _states$annotationSta6 === void 0 ? void 0 : _states$annotationSta6.selectedAnnotations,
isAnnotationManagerEnabled: (_states$annotationSta7 = states.annotationState) === null || _states$annotationSta7 === void 0 ? void 0 : _states$annotationSta7.isAnnotationManagerEnabled
};
};
function InlineCommentView(_ref) {
var providers = _ref.providers,
editorView = _ref.editorView,
editorAnalyticsAPI = _ref.editorAnalyticsAPI,
editorAPI = _ref.editorAPI,
dispatchAnalyticsEvent = _ref.dispatchAnalyticsEvent;
// As inlineComment is the only annotation present, this function is not generic
var inlineCommentProvider = providers.inlineComment;
var state = editorView.state,
dispatch = editorView.dispatch;
var CreateComponent = inlineCommentProvider.createComponent,
ViewComponent = inlineCommentProvider.viewComponent;
var _useSharedPluginState = (0, _useSharedPluginStateWithSelector.useSharedPluginStateWithSelector)(editorAPI, ['annotation'], selector),
annotations = _useSharedPluginState.annotations,
bookmark = _useSharedPluginState.bookmark,
isInlineCommentViewClosed = _useSharedPluginState.isInlineCommentViewClosed,
isOpeningMediaCommentFromToolbar = _useSharedPluginState.isOpeningMediaCommentFromToolbar,
selectAnnotationMethod = _useSharedPluginState.selectAnnotationMethod,
selectedAnnotations = _useSharedPluginState.selectedAnnotations,
isAnnotationManagerEnabled = _useSharedPluginState.isAnnotationManagerEnabled;
var annotationsList = (0, _utils2.getAllAnnotations)(editorView.state.doc);
var selection = (0, _utils2.getSelectionPositions)(state, bookmark);
var position = findPosForDOM(selection);
var isExtensionSelection = selection instanceof _state.NodeSelection && selection.node.type.name === 'extension';
var dom;
var domLookupError;
try {
var domRef = (0, _utils.findDomRefAtPos)(position, editorView.domAtPos.bind(editorView));
if ((0, _fg.fg)('cc_maui_annotations_on_extensions') && isExtensionSelection) {
if (domRef instanceof HTMLElement) {
dom = domRef;
}
} else {
// Preserve the existing text/media and gate-off anchor lookup.
// eslint-disable-next-line @atlaskit/editor/no-as-casting
dom = domRef;
}
} catch (error) {
domLookupError = error;
}
// Native embed extension nodes are rendered by a node view. Depending on
// the wrapper, domAtPos can return no element (or throw) even though
// EditorView.nodeDOM can. Use that direct lookup as a block-comment anchor.
if ((0, _fg.fg)('cc_maui_annotations_on_extensions') && !dom && isExtensionSelection) {
var nodeDom = editorView.nodeDOM(selection.from);
if (nodeDom instanceof HTMLElement) {
dom = nodeDom;
}
}
if (!dom && domLookupError) {
// eslint-disable-next-line no-console
console.warn(domLookupError);
if (dispatchAnalyticsEvent) {
var payload = {
action: _enums.ACTION.ERRORED,
actionSubject: _enums.ACTION_SUBJECT.CONTENT_COMPONENT,
eventType: _enums.EVENT_TYPE.OPERATIONAL,
attributes: {
component: _enums.CONTENT_COMPONENT.INLINE_COMMENT,
selection: selection.toJSON(),
position: position,
docSize: editorView.state.doc.nodeSize,
error: domLookupError.toString()
}
};
dispatchAnalyticsEvent(payload);
}
}
// Network Status
var networkStatusSelector = (0, _useSharedPluginStateSelector.useSharedPluginStateSelector)(editorAPI, 'connectivity.mode');
if (!dom) {
return null;
}
// Create Component
if (bookmark) {
if (!CreateComponent) {
return null;
}
var inlineNodeTypes = (0, _annotation2.getRangeInlineNodeNames)({
doc: state.doc,
pos: selection
});
//getting all text between bookmarked positions
var textSelection = state.doc.textBetween(selection.from, selection.to);
return /*#__PURE__*/_react.default.createElement("div", {
"data-testid": _types.AnnotationTestIds.floatingComponent,
"data-editor-popup": "true"
}, /*#__PURE__*/_react.default.createElement(CreateComponent, {
dom: dom,
textSelection: textSelection
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
,
onCreate: function onCreate(id) {
if (!isAnnotationManagerEnabled) {
var createAnnotationResult = (0, _editorCommands.createAnnotation)(editorAnalyticsAPI, editorAPI)(id, _annotation.AnnotationTypes.INLINE_COMMENT, inlineCommentProvider.supportedBlockNodes, inlineCommentProvider.isBlockNodeSupported)(editorView.state, editorView.dispatch);
!editorView.hasFocus() && editorView.focus();
if (!createAnnotationResult) {
throw new Error('Failed to create annotation');
}
}
}
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
,
onCreateError: function onCreateError(id) {
return (
// This is called when optimistic create inline comment encounters an error,
// in which case the optimistically added annotation must be removed.
(0, _editorCommands.removeInlineCommentNearSelection)(id, inlineCommentProvider.supportedBlockNodes, inlineCommentProvider.isBlockNodeSupported)(editorView.state, editorView.dispatch)
);
}
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
,
onClose: function onClose() {
if (!isAnnotationManagerEnabled) {
(0, _editorCommands.setInlineCommentDraftState)(editorAnalyticsAPI, undefined, editorAPI)(false)(editorView.state, editorView.dispatch);
!editorView.hasFocus() && editorView.focus();
}
},
inlineNodeTypes: inlineNodeTypes,
isOpeningMediaCommentFromToolbar: isOpeningMediaCommentFromToolbar,
isOffline: (0, _isOfflineMode.isOfflineMode)(networkStatusSelector)
}));
}
// View Component
var activeAnnotations =
// eslint-disable-next-line @atlassian/perf-linting/no-expensive-computations-in-render -- Ignored via go/ees017 (to be fixed)
(selectedAnnotations === null || selectedAnnotations === void 0 ? void 0 : selectedAnnotations.filter(function (mark) {
return annotations && annotations[mark.id] === false;
})) || [];
if (!ViewComponent || activeAnnotations.length === 0) {
return null;
}
var onAnnotationViewed = function onAnnotationViewed() {
if (!dispatchAnalyticsEvent) {
return;
}
// fire analytics
var targetNode = editorView.state.doc.nodeAt(position);
var targetNodeType = targetNode === null || targetNode === void 0 ? void 0 : targetNode.type.name;
var commentTargetType = targetNode ? 'other' : 'unknown';
if (targetNodeType === 'extension') {
commentTargetType = (targetNode === null || targetNode === void 0 ? void 0 : targetNode.attrs.extensionKey) === 'native-embed:maui' ? 'remixEmbed' : 'other';
} else if (['media', 'mediaSingle', 'mediaInline'].includes(targetNodeType !== null && targetNodeType !== void 0 ? targetNodeType : '')) {
commentTargetType = 'media';
} else if (targetNode !== null && targetNode !== void 0 && targetNode.isText) {
commentTargetType = 'text';
}
var payload = {
action: _enums.ACTION.VIEWED,
actionSubject: _enums.ACTION_SUBJECT.ANNOTATION,
actionSubjectId: _enums.ACTION_SUBJECT_ID.INLINE_COMMENT,
eventType: _enums.EVENT_TYPE.TRACK,
attributes: {
overlap: activeAnnotations.length ? activeAnnotations.length - 1 : 0,
targetNodeType: targetNodeType,
commentTargetType: commentTargetType,
method: selectAnnotationMethod
}
};
dispatchAnalyticsEvent(payload);
};
if (isInlineCommentViewClosed || !selectedAnnotations) {
return null;
}
// For view mode, the finding of inline node types is a bit more complex,
// that's why we will not provide it as a `inlineNodeTypes` props to the view component,
// to speed up the rendering process.
var getInlineNodeTypes = function getInlineNodeTypes(annotationId) {
return (0, _annotation2.getAnnotationInlineNodeTypes)(editorView.state, annotationId);
};
return /*#__PURE__*/_react.default.createElement(_AnnotationViewWrapper.AnnotationViewWrapper, {
"data-editor-popup": "true",
"data-testid": _types.AnnotationTestIds.floatingComponent,
key: (0, _utils2.getAnnotationViewKey)(activeAnnotations),
onViewed: onAnnotationViewed
}, /*#__PURE__*/_react.default.createElement(ViewComponent, {
annotationsList: annotationsList,
annotations: activeAnnotations,
getInlineNodeTypes: getInlineNodeTypes,
dom: dom
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
,
onDelete: function onDelete(id) {
return (0, _editorCommands.removeInlineCommentNearSelection)(id, inlineCommentProvider.supportedBlockNodes, inlineCommentProvider.isBlockNodeSupported)(editorView.state, dispatch);
}
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
,
onResolve: function onResolve(id) {
return (0, _editorCommands.updateInlineCommentResolvedState)(editorAnalyticsAPI)((0, _defineProperty2.default)({}, id, true), _inlineCommentEvents.RESOLVE_METHOD.COMPONENT)(editorView.state, editorView.dispatch);
}
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
,
onClose: function onClose() {
(0, _editorCommands.closeComponent)()(editorView.state, editorView.dispatch);
},
isOpeningMediaCommentFromToolbar: isOpeningMediaCommentFromToolbar,
isOffline: (0, _isOfflineMode.isOfflineMode)(networkStatusSelector)
}));
}