I have written a plugin that is controlled by dispatching transactions with meta data. I can then respond to that meta data in the apply
method, and return new plugin state.
This worked well, as it allowed me to generate new plugin state programatically:
if (tr.getMeta('action') === CANCEL) {
// ...
}
Then I started to need to generate new plugin state by some inspecting the document state:
if (tr.getMeta('action') === CANCEL || autoCancel(state)) {
// ...
}
(Imagine that autoCancel
inspects some selection ranges).
And that’s when I ran into trouble.
Because the plugin also has a public interface like:
apply(tr) {
if (tr.getMeta('action') === CANCEL || autoCancel(state)) {
pluginConfig.onCancel(); // <-- this
return null;
}
}
Now if the consumer of the plugin wants to dispatch a transaction, they will run into timing issues, e.g.
myPlugin({
onCancel() {
insertText('foo')(state, dispatch)
}
})
Because the onCancel
method got fired whilst still inside the apply
method of the plugin, they will be unable to update the document.
A hacky fix being setTimeout(..., 0);
I know I need to refactor, but I’m unsure which direction to take.
My first idea was to try the update
method:
update(view) {
const pluginState = this.getState(view.state)
// `pluginState` now reflects the cancellation
// but how to know whether to call `pluginConfig.onCancel()` ?
}
Firing the public actions could potentially work here, because the pluginState
knows about the new state, but we do not know if it is an appropriate time to call them. I’d have to have another property like fireOnCancel: true
on the pluginState
, which I then set to false
after firing onCancel
. But that feels wrong, because I already have a nice way to control it with setMeta
.
Can anyone guide me here?