consider reducing verbosity of commands
See original GitHub issueIn the newest version of Slate, there is now a separation between Commands and Transforms…
-
Commands are user-level actions that are taken on the editor. They correspond directly to user input, and always operate on the current selection. They are overridable because this allows plugins to define complex behaviors (eg. auto-markdown).
-
Transforms are slightly lower level (but not as low as Operations), and are designed to make it easy to perform many types of changes to a Slate editor’s content. They’re not overridable, they’re just functional helpers. And they do not always act directly on the current selection, they can act on any location. They’re what you’d build commands from.
This distinction is very helpful.
But… the downside is that implementing every type of action a user can perform as commands is very verbose. You end up having to thread every custom command through the exec
function.
It feels like using Redux, and that’s not a compliment IMO.
I think there’s a good argument for trying to simplify this.
And it comes down to the question of whether userland commands need to be overridable by plugins. I’m not sure there are great use cases for this. This “requirement” is a vestige of the old Slate architecture.
The only ones that come to mind for me are Redux-like use cases like a global logger, but those are honestly pretty weak. (Even the examples Redux gives in its documentation for what you’d use middleware for are very contrived.) And we already have operations for global undo/redo.
If we need non-core commands to be overridable we’ve got to stick with the current state of things. But if we don’t…
Instead of modeling commands as objects that pass through exec
, we could promote the core commands to live directly on the Editor
object. For example:
editor.insertText('string')
editor.deleteForward({ unit: 'word' })
editor.undo()
And these are still available to be overridden by plugins, the same way that exec
or isVoid
are already overridden.
Combine that with moving the existing transforms to a separate object to make it clear these are not user-level actions:
Transforms.insertText(editor, 'string', { at: range })
Transforms.unwrapNodes(editor, { match: ... })
And then finally, (this one will confuse you if you’re still thinking in the current terms), create default helpers for the core commands on the Editor
:
Editor.insertText(editor, 'string')
Editor.deleteForward(editor, { unit: 'word' })
Editor.undo(editor)
I know that last step sounds confusing given the current API. But what it actually does it is allows the Editor
helper namespace to be properly customized by end-users the way they’d expect it to be. Instead of having to thread commands objects through exec
like you’re building a Redux app.
For example, you can now define your own helpers which blend in:
Editor.insertParagraph(editor)
Editor.formatLink(editor, 'https://example.com')
All depending on your schema.
I’m fairly sure this is a good idea.
If you have use cases where you need userland commands to be overridden by a plugin, please let me know! That’s the only real tradeoff that this makes.
Issue Analytics
- State:
- Created 4 years ago
- Reactions:2
- Comments:9 (5 by maintainers)
Top GitHub Comments
(And actually, you can still override them. You just have to be aware of the specific type of the
Editor
you are dealing with. Which actually seems like a net positive.)Hi Ian, thanks for the clarification.