I am running into problems with the interaction between a node decoration and a custom nodeView. When the node decoration is before the custom nodeview, and is then removed (i.e. replaced with an DecorationSet.empty
or a DecorationSet
that has no decorations), the entire document rerenders (and the node view is recreated).
In this case, my decoration adds a class to empty paragraphs (a prompt for users) (see github) and my node-view is an iframe (see github). The behaviour means the iframe gets rerendered on selection changes (causing flicking/loading, and other more complicated node views get recreated as well).
This seems to only happen when the prompt decoration is removed when it is before the iframe in the document, and when also involved in a selection change (it doesn’t happen when there are document changes). An example is below (also online here):
I was wondering if a quick look at the decoration code below highlights the problem? Or if maybe this is a bug? Or expected behaviour? I have also tried using the DecorationSet to map
/add
/remove
the decorations. When it gets down to an empty set, that always seems to trigger a full refresh and flicker in the IFrame/custom nodeView.
I also think this may have been introduced in the last four or so weeks, (this code did work before, but I am having trouble reproducing that and getting back to the right versions; our deployed app doesn’t do this). I can get a minimal example together to demonstrate this if it is helpful/worth it.
Decoration code
const promptPlugin = new Plugin({
key,
state: {
init: () => DecorationSet.empty,
apply(tr, value, oldState, newState) {
if (!isEditable(newState)) return DecorationSet.empty;
const paragraph = getParentIfParagraph(newState.selection);
const emptyParagraph = paragraph && paragraph.node.nodeSize === 2;
if (tr.selection.empty && emptyParagraph) {
const deco = Decoration.node(tr.selection.from - 1, tr.selection.to + 1, {
class: 'prompt',
});
return DecorationSet.create(tr.doc, [deco]);
}
return DecorationSet.empty;
},
},
props: {
decorations(state) {
return this.getState(state);
},
},
});