Draft js plugins is great. But currently has a bunch of problems, some of which are entirely our own doing, building a plugin system that does more than it should.
- We have our own state management (sometimes more than 1 version of state management 😢. This causes a whole class of bugs
- Plugins have their own custom lifecycle, another class of bugs 😢
- Composing plugins really sucks 😕 (At some point we introduced a
decorator
“pattern” to remedy this, which is super confusing because it has nothing to do with draft js decorators) - The API for most of the plugins is too big and growing, making it exponentially hard to maintain and develop further.
- Plugins aren’t very
reacty
Having thought this over for almost a year now I think the best way forward would be to freeze draft js development (support yes, new features no) and start working on a successor with a different architecture: One that is component based.
- Components already have state 😒
- Components already have a lifecycle 😒
- Components provide great patterns for composition, and everyone who uses react is familiar with at least a handful of these patterns.
- Using component patterns over massive configuration objects, would make the API much smaller and easier to test, follow, maintain
Now some examples, if you have any questions ideas lmk!
The EditorContainer would be a container for the editorState, as well as all the properties a draft js Editor can hold.tt
<EditorStateContainer editorState={this.state.editorState} onChange={this.onChange}>
<Suggestions trigger="@" getSuggestions={this.fetchUsers}/>
<Editor />
</EditorStateContainer>
In this case we use a text selection popover for a medium style toolbar, but this could be anything
<EditorStateContainer editorState={this.state.editorState} onChange={this.onChange}>
<TextSelectionPopover>
<Bold />
<Italic />
<Underline />
<Strikethrough />
</TextSelectionPopover>
<Editor />
</EditorStateContainer>
<EditorContainer>
<Editor />
<AtomicBlock type="IMAGE">
{(props) => <Image {...props} />}
</AtomicBlock>
<AtomicBlock type="VIDEO">
{(props) => <Video {...props} />}
</AtomicBlock>
</EditorContainer>
<EditorContainer>
<Editor />
<Upload
onSelectFile={}
>
{() => (
<input type="file" />
)}
</Upload>
</EditorContainer>