Whats the best way to keep decorations aka WidgetPlugins in sync with a StateFiled ?
I got a StateField that that is updated from the “outside” (my vue application) with some values lets say its an array. For this i simply dispatch an effect like:
view.dispatch({
effects: updateAdditionalState.of(vars),
})
where vars is an array of variables. After this I insert into my view a string representing that var “{{1}}” which is then styles by a match decorator and i “replace” the number value inside with the value in my state field
export const variableMatchingConfig = new MatchDecorator({
regexp: /\{{(.*?)}}/g,
decoration: (match, view) => {
// a function that gets the variable via view.state.field(<myStateField>)
const variable = getVariableFromStateByNumericLabel(view, parseInt(match[1]))
return Decoration.replace({
widget: new VariableWidget(variable?.name, variable?.uuid),
})
},
})
All of this works just fine but now - how am I’m able to recognise that a widget(its atomic) was removed from the doc (f.e. via the delete key) and sync that with my StateField ? How is it possible to keep StateField and WidgetPlugins kinda in sync?
You could do a check where you see if the range set’s size changed after mapping, and if so, do a scan through it to figure out which widget that you still have in your outside data was removed.
1 Like
Thanks for the fast answer!
And where do i get that RangeSet from i just got a extension for:
- the state - a StateField thats in sync with the outside state
- DecorationWidgets - that show the variable
I thought about to check the doc on every view update. And if my doc changes from
“Hey {{1}} whats up {{2}}” to “Hey {{1}} whats up” i would know that the second widget was removed and update the StateField regarding to this. But i thought there is a more convenient way to keep Decoration and State in sync…
Is there even a way to check if a widget is added between two other widgets ? Probably only by parsing the doc and some diffing right ?
Another solution could be to hack around that parsing stuff, i found out that the plugins internally are correctly listed as they are used within the doc
const plugin = view?.plugin(myPlugin)?.myPluginDeco
// that access is some kind of a hack, but we were not able
// to locate a proper way to access the currently used widgets and their values
return plugin?.chunk?.[0]?.value.map((deco) => {
return {
title: deco?.widget?.title, // identifiers i added on Widget creation
id: deco?.widget?.id, // identifiers i added on Widget creation
}
})
the order in that chunk value array does match the correct order as we display or added the widgets to the doc so I thought about using it to determine which widgets are available atm and in which order. But looks a bit odd to me
It would be nice to have a getter on accessing it in a more convenient way 
Okay we could ignore this, i was able to do it how you suggested, the Decoration as RangeSet got everything I needed… will leave the code part here for reference if anyone else is searching for a similar solution
export const getVariableVariableWidgets = (view: EditorView) => {
const decoSet = view?.plugin(myPlugin)?.myPluginDeco
const variableWidgets = []
const iterator = decoSet?.iter(0)
while (iterator?.value != null) {
variableWidgets.push({
// @ts-expect-error
id: iterator.value?.widget?.id, // identifier added to the widget class
// @ts-expect-error
title: iterator.value?.widget?.title, // identifier added to the widget class
})
iterator.next()
}
TY!
1 Like