Suggestions as Decorations

Hi Marijn,

We (Kevin from Y.js and Nick from BlockNote) are considering going back on our previous approach of suggested content as marks and are now reevaluating to represent suggestions as decorations.

The reason that we’ve gone back on this is that there can be cases where showing a deleted node can actually inject content into a node at a position which does not actually abide by the parent nodes content declaration. So, in such cases the prosemirror node cannot be created since it is not valid to the schema.

We’ve explored an alternative approach where we inject only “suggested” nodes which we’ve crafted to be valid in any position within the parent nodes content declaration. This did work in some capacity but would prove to be difficult to implement in an editor, since it breaks several assumptions about the schema of a document (e.g. injecting nodes into a table will break a lot of the assumptions that prosemirror-tables makes about its structure).

So, I’m now advocating for what you had originally suggested, to use decorations to insert the deleted content (which may be invalid to the schema, but since it is in a decoration it does not count as part of the document). The question that we are running into though, is how to be able to edit this content. I know that you have a demo for footnotes that embeds an editor view just for the footnotes content, would you suggest a similar approach for this? I guess that we are essentially trying to make a decoration act as an editor and will run into some issues with that, keyboard shortcuts, copy/paste etc. Do you have any other directions that we could look into?

I’m not really clear on your use case. If you’re displaying suggested content, wouldn’t that generally fit the schema? (It’s not a very good suggestion if it doesn’t.) And isn’t the flow for that to first accept it and then edit it?

Sorry, I definitely could have been clearer.

Take this schema, for example:

new Schema({

nodes: {
  doc: {
    content: 'block*',
  },

  paragraph: {
    content: 'inline*',
    group: 'block',
  },

  heading: {
    content: 'inline*',
    group: 'block',
  },

  container: {
    content: 'block',
    group: 'block',
  },
},
marks: {
  suggestion: {
     attrs: { userId: { default: null } }
  }
}
})

What we are running into is that given a document like:

doc(container(heading(‘text’))) and a suggestion like

doc(container(paragraph(‘text’))) a diff of these two documents would say replace heading with paragraph and attempt to generate something like doc(container(heading(‘text’), paragraph(‘text’))) but the container block really only allows a single child via it’s content declaration.

So, what I’ve proposed is that all deleted content is shown instead as a decoration, so that the suggestion document only ever has a valid document given the constraints of the ProseMirror schema.

Now, since decorations are not part of the document they are not editable. I too would argue that it is a good thing and that the user should have to accept/reject the suggestion, and only then can they modify the content of that deleted text; but, apparently some users are used to this from Google Docs where it is possible to continue editing. Like in the example below, I was able to add “ABC” and the deletion range extended over that inserted content. I don’t personally believe this to be correct, but let’s say for the sake of argument that we should allow it.

Now, I’m trying to figure out whether it is even feasible to try to insert these decorations with EditorViews attached to them to try to simulate this.

We looked into what it would take to simply extend the schema to allow multiple nodes like this, but it has too many implications on our editor for it to be completed in a reasonable amount of time. We are also trying to build something which, ideally, would be compatible with other prosemirror editors, rather than one which had it’s whole schema overhauled just to support this feature.

I appreciate your response, and sorry again for not being more clear earlier, I’ve been banging my head against this problem for months now.

Oh I see, this is suggestions as in modifications made as suggested edits. It does sound like you’ve backed yourself into a bit of a problematic corner with this design. Nested editors should be possible to make work, but making the editing across the inner and outer editors seamless is going to be quite a bit of work, and if there’s a ton of suggestions this approach might be a bit heavyweight.

Fair enough, was worth a try to ask you about it.

Thanks for your help anyway