Editor core - Annotations
Annotations
Introduction
Annotations allow you to apply, well, annotations around sections of text.
Currently, there is only the inlineComment
type of annotation. In the future, other kinds of annotations like reactions, might be added.
Inline comments
These denote a comment thread about the given text, and are denoted by a yellow highlight. This is commonly seen within Confluence after selecting some text in View mode.
For Q1, our main areas of focus are:
Performance: Instrument key performance metrics and improve typing speed in the editor.
Insertion & nesting logic: Remove invisible barriers by enabling more content to be placed inside each other. E.g. allow users to paste an image inside a panel.
Example ADF
An annotation is defined in ADF like so;
{
"type": "text",
"text": "areas of focus are:",
"marks": [
{
"type": "annotation",
"attrs": {
"id": "b81e1de8-9df7-4210-861d-89e13512ce33",
"annotationType": "inlineComment"
}
}
]
}
Using annotations
You can do this with the annotationProvider
prop on the <Editor />
component. Passing a truthy value to this (e.g. the empty object {}
) will:
- enable support for working with the
annotation
ADF mark - will render highlights around any annotations, and
- allow copying and pasting of annotations within the same document, or between documents
Displaying and creating annotations
You can also optionally pass a React component to the component
, so you can render custom components on top of or around the editor when the user's text cursor is inside an annotation.
An annotation mark only describes an id
and a type
, so your component will probably want to fetch a remote resource based on these IDs and display the relevant information.
Example
The full page examples in the storybook use the ExampleViewInlineCommentComponent
within the @atlaskit/editor-core
package, like so:
import { Editor } from '@atlaskit/editor-core';
import { ExampleViewInlineCommentComponent } from '@atlaskit/editor-test-helpers/example-helpers';
class MyEditor extends React.Component {
render() {
return <Editor
// ... other providers and props here
annotationProvider={{
component: ExampleViewInlineCommentComponent,
}}
/>;
}
}
API and usage
The interface looks like:
export type AnnotationInfo = {
id: string;
type: AnnotationType;
};
export type AnnotationComponentProps = {
/**
* Existing annotations where the cursor is placed.
* These are provided in order, inner-most first.
*/
annotations: Array<AnnotationInfo>;
/**
* Selected text (can be used when creating a comment)
*/
textSelection?: string;
/**
* DOM element around selected text (for positioning)
*/
dom?: HTMLElement;
/**
* Deletes an annotation with the given ID around the selection.
*/
onDelete: (id: string) => void;
};
The Editor will render your component with the above props, given the lifecycle described below.
Multiple annotations
Note that the annotations
prop provides an array. This is because text can have multiple annotation marks.
This array is ordered so that the inner-most appears first. If you always want to display the outer one, for instance, just reverse the order. Here's an example of a document with multiple annotations. They are rendered slightly transparent.
This is a paragraph with a outer comment that also contains a nested comment, where the nested comment has two annotation marks applied.
Paragraph node's content:
[
{
"type": "text",
"marks": [
{
"type": "annotation",
"attrs": {
"id": "c7052cd7-5119-4837-85ce-45ba5207764c",
"annotationType": "inlineComment"
}
}
],
"text": "This is a paragraph with a outer comment "
},
{
"type": "text",
"marks": [
{
"type": "annotation",
"attrs": {
"id": "a5ee9b09-f302-4fa6-89cb-d5703cb6ccdd",
"annotationType": "inlineComment"
}
},
{
"type": "annotation",
"attrs": {
"id": "c7052cd7-5119-4837-85ce-45ba5207764c",
"annotationType": "inlineComment"
}
}
],
"text": "that also contains a nested comment"
},
{
"type": "text",
"text": ", where the nested comment has two annotation marks applied."
}
]
Annotation types
You are also provided the type of the annotation. You can use this to filter only to specific annotation types if you so choose.
You could also mix and match to render a combined component that applies multiple types of annotations at once (e.g. a combined inline comments + reaction annotation component).
If you just want to render the first annotation of a single type, you can do something like:
// only find inline comments
const comments = annotations.filter(
annotation => annotation.type === 'inlineComment',
);
to filter, and then just take the first one if the array contains any items.
Currently, only the inlineComment
annotation type is valid ADF.
Lifecycle
The component is mounted when entering a region of text containing an annotation.
It can be re-rendered if remaining in a region with annotations, possibly with different annotations or selections passed as props.
It is unmounted when exiting a region of text with an annotation.