Does ProseMirror implement those features?

Hello, I have a project to implement and I was wondering if ProseMirror has any plugin that allows me to do the following:

  1. Tiered item lists (for example, 1 for chapter, 1.2 for subchapter etc.)
  2. Outline for the text of each selected/moused over item from the list (and only for the selected/moused over text)
  3. An indicator for each selected/moused over item from the list.

The image below describes it better. I just want to know if ProseMirror can help me implement this or if this is already implemented by someone else. Thanks.

Hi there,

I am not aware of a plugin that has the exact behavior - but what you describe seems reasonable if you write your own plugin.

We do similar numbering in our project by simply putting attributes with the counter value onto nodes and then reading them with CSS (keeps the logic outside of CSS). ProseMirror does support ordered lists out of the box (with indent/de-indent etc.) so that could be a good starting point.

If you use one ProseMirror instance for the entire document, you’ll probably have to create the lines around the currently edited node yourself. But that could also be handled within a plugin (ProseMirror gives you the active selection, so you’d listen to that and then apply a CSS class to the item).

Maybe someone else has more concrete examples where this was implemented already.

Best Frederik

1 Like

Can I have a code snippet or an example of active selection? I am struggling with prosemirror a lot. It’s extremely unfriendly.

Edit: I am trying to set decorations for the current selected node, but I don’t know how to do that. Can anyone ELI5 the decorations? I am getting the current node in the transaction with:

transaction.curSelection.$anchor.parent

How do I apply nodeViews to this?

Maybe have a look at the Linting Example on the website? The code is available as a Glitch so you can experiment with it.

I can also really recommend reading the Guide on the website. It explains step by step how to apply decorations as well as the more basic concepts needed.

This evening, I started playing with the Linting Example. The example makes sense to me; however, I’m making a mistake I don’t see. When I generate the inline decorations I create the first one, but the others are null.

What might cause a null result from a call to Decoration.inline(from, to, attrs) ?

TypeScript Snippet

function parseDocument(doc: ProsemirrorNode) {
    let decorations: Decoration[] = []

    doc.descendants((node: ProsemirrorNode, pos: number) => {
        if (node.isText && node.text) {
            parse(node.text, mockServices).tokens.forEach((t: Token) => {
                decorations.push(
                    Decoration.inline(
                        t.start,
                        t.start + t.text.length - 1,
                        { class: t.uiMark }
                    )
                )
            })
        }
    })

    return DecorationSet.create(doc, decorations)
}

Example of the Tokens I Parse:

[
  {
    "itemKind": "text",
    "start": 0,
    "text": "if ",
    "uiMark": "text"
  },
  {
    "itemKind": "user",
    "start": 3,
    "text": "@paula",
    "uiMark": "user",
    "data": {
      "id": 1980
    }
  },
  {
    "itemKind": "text",
    "start": 9,
    "text": " is ",
    "uiMark": "text"
  },
  {
    "itemKind": "hash",
    "start": 13,
    "text": "#hashtag",
    "uiMark": "hashInvalid",
    "data": {
      "id": -1
    }
  },
  {
    "itemKind": "text",
    "start": 21,
    "text": " cool",
    "uiMark": "text"
  }
]

Thanks for your time and help.

Where does start in the Token come from? Decoration.inline should take the absolute document position as the first arguments. Assuming that token.start is the relative start point within the text you just parsed, it should probably be Decoration.inline(pos + t.start, pos + t.start + t.text.length -1, …