How to add different precedences for decorations within the same Plugin Extension

I want to create an extensions with different precedences for different decorations, I have a use case where I would like to create a mark decoration, which wraps another mark decoration, but I would like to do this within the same extension. This is possible as stated in the mark decoration reference, but I am not sure how should I go about doing this.

My extension for example:

export const Plugin = ViewPlugin.fromClass(class {
    constructor(view) {
        this.higher_prec_decorations = return_high_prec_decoration(view)
        this.lower_prec_decorations = return_low_prec_decoration(view)
    }

    update(update) {
    if (update.docChanged || update.viewportChanged)
        this.higher_prec_decorations = return_high_prec_decoration(update.view)
        this.lower_prec_decorations = return_low_prec_decoration(update.view)
    }
}, {
    decorations: v => v.?, // How do I return different prec decorations here?
})

Thanks.

You’ll want to use provide, not decorations, and return an array holding two instances of EditorView.decorations, accessing those fields in your plugin.

1 Like

After upgrading to 6.0.0 I’d like to migrate from PluginField.decorations to EditorView.decorations.

Tried modifying this:

ViewPlugin.define(view => (
{
    myDecorations: myDecorator.createDeco(view),
    moreDecorations: anotherDecorator.createDeco(view),

    update(u)
    {
        this.myDecorations = myDecorator.updateDeco(u, this.myDecorations)
        this.moreDecorations = anotherDecorator.updateDeco(u, this.moreDecorations)
    }
}), {
    provide: [
        PluginField.decorations.from(v => v.myDecorations),
        PluginField.decorations.from(v => v.moreDecorations),
    ]
})

to this:

ViewPlugin.define(view => (
{
    myDecorations: myDecorator.createDeco(view),
    moreDecorations: anotherDecorator.createDeco(view),

    update(u)
    {
        this.myDecorations = myDecorator.updateDeco(u, this.myDecorations)
        this.moreDecorations = anotherDecorator.updateDeco(u, this.moreDecorations)
    }
}), {
    provide: () => [
        EditorView.decorations.from(v => v.myDecorations),
        EditorView.decorations.from(v => v.moreDecorations),
    ]
})

This, however, results in a RangeError: Field is not present in this state

What kind of mistake did I make?

I’m not sure where the field not present error is coming from, but your decoration providers are reading the myDecorations/moreDecorations properties from the view object, which doesn’t have such properties. Something like this should work:

  provide: plugin => [
    EditorView.decorations.of(v => v.plugin(plugin)?.myDecorations || Decoration.none),
    EditorView.decorations.of(v => v.plugin(plugin)?.moreDecorations || Decoration.none)
  ]

Facet.from takes a field as first argument. EditorView.decorations.of takes a function from a view to a decoration set. (TypeScript can help catch type errors like this.)

1 Like

Awesome, thanks! Using your approach, fixes the problem!