Extensions

comment

Mark 0.33 kB gzipped

Threaded comments, anchored to ranges.

The thread itself — author, body, replies, resolution — belongs to the host application, not the document. All that lives here is the anchor: a mark carrying a thread id. That separation is deliberate. Comment bodies in the document would travel with every copy, paste and export of the text, and would need migrating whenever the comment schema changed.

Because the anchor is a mark, position mapping keeps it correct for free: edit the paragraph around a comment and the highlight follows the words.

1 · Install

One package for every extension · there is no @matrajs/comment to install.

npm i @matrajs/core

2 · Add it to the editor

Import it and put it in the extensions array. That array is the whole feature list: what is not in it is not in your bundle and not in the document's schema.

import { createEditor, document, paragraph, text, comment } from '@matrajs/core'

const editor = createEditor({
  extensions: [document, paragraph, text, comment],
  element: document.querySelector('#editor'),
})

3 · Use it

Run a command, and give focus back · a click on a button takes it away.

editor.commands.addComment('block-1')
editor.focus()

Wired to a button, with the pressed state kept in step:

const button = document.querySelector('#addComment')

button.addEventListener('click', () => {
  editor.commands.addComment('block-1')
  editor.focus()
})

const read = () => button.setAttribute('aria-pressed', String(editor.isActive('comment')))
editor.on('selectionChange', read)
editor.on('change', read)
read()

Both events, not one. selectionChange covers the caret moving into it; change covers the command that changed it without moving anything. A toolbar wired to only the first goes stale the moment someone uses the keyboard.

Commands

Every one returns true if it changed the document and false if it could not · a command that does not apply where the caret is says so rather than throwing.

Command Call
addComment editor.commands.addComment(threadId: string)
removeComment editor.commands.removeComment(threadId: string)

Styling

This one needs CSS to look right, and ships the minimum as a string rather than a file · nothing loads unless you load it, and you can ignore it and write your own.

import { commentCSS } from '@matrajs/core'

const style = document.createElement('style')
style.textContent = commentCSS
document.head.append(style)

In the document

Attribute Default
threadId none

← All 83 extensions

Edit this page on GitHub