Making Decoration.node play nice with node views

Hello again. I’m using node decorations to track view-related metadata about my document. In addition to the concern I’d posted earlier about setNodeMarkup breaking DecorationSet.map, another challenge I’ve experienced is the interaction between my node view and my node decorations.

Its common for our views will define the class name for the dom, a la

    let className = `list-item indent-${ indent }`;
    if (isExpanded) className += " expanded";

    this.dom.className = className;

Which works fine unto itself. I can subsequently apply a node decoration to this node to add a class to the dom element:

Decoration.node(from, from + parentNode.nodeSize, { class: "has-children" });

Which continues working great – now the node rendered by node view, at pos from, will have a class that combines the view and the node decoration like list-item indent-0 has-children.

The problem arises the next time that node is updated. At that point, the view is re-rendered, which removes the class applied by the node decoration. Since I would like the node decoration to be outside the concern of the list item view, it would be ideal if the mechanism that added the node decoration’s class was re-applied after each node view. Does anyone have ideas for how best to allow a DOM node to derive its class from a mix of its own attrs (which are the concern of the node view) and external plugins that control decorations that should be persistently applied to the node?

So far, my best idea is to adapt the view so that it can run a regex on the existing class name and allow externally applied (from the node decoration) class names to “pass through” by being applied after all the attr-related class naming is complete. It feels pretty hacky to have the view need to know about the decorations maintained by an external plugin which makes me think there must be a better way to approach this goal.

PS: I’ve confirmed that the node decorations continue to exist in the correct index in a DecorationSet known to the plugin. Those decorations just stop being drawn after the node view renders an update.

1 Like

After your node view’s update method runs, the library will apply any changes caused by changes to its outer decorations. In principle, node views don’t need to concern themselves with those, and should only manage the class names they themselves (possibly via .classList.toggle). If something specific is broken about that, please provide an example.