This is the first in an ongoing series of posts.
- draft-js pieces
- draft-js EditorState
- draft-js ContentState
- draft-js ContentBlock
- draft-js SelectionState
- draft-js highlight text
- draft-js styling a ContentBlock
Draft-js is a highly programmatic rich text editor created by facebook. But it’s not what you might expect.Draft-js is just the underpinnings, leaving everything, and I mean everything, else up to you. When you render an Editor you get a textbox. This is because facebook wanted rich text in a number of different contexts, like all that commenting crap they do. I don’t know.
There are several wrappers that provide some structure and basic stuff like a toolbar. The one I use, and am extending for my purposes is react-rte. It’s pretty good and will get you started.
This post is about the api and the pieces you will interact with when using Draft-js or a wrapper for it.
There is, of course, the Editor Component. This is your window into the api. Or maybe your blender where you put all your margarita ingredients. But the meat and potatoes is in an object that is called EditorState. The EditorState is the complete representation of your document. It is wildly … large? bloated? If you look at it in a console.log it’s just huge, but that is not a problem, because most of it is empty arrays and they rely heavily on immutable.js for reuse and performance. I just mention it because you’re not going to want to persist that.
EditorState provides a convertToRaw() and a convertFromRaw() function that will distill it down to just what you need. This is what you are going to want to persist. It’s still pretty complex but it’s the minimum representation of your document.
Draft-js uses immutable.js heavily, so pretty much all collections are immutable.js maps. EditorState is made up of a map of ( generally ) 7 things. The first and most important is CurrentState. It’s actually called CurrentContent but it an object called CurrentState. The other elements are things such as undoStack, redoStack, decorators, selections etc. All very cool stuff which hopefully I’ll go into in subsequent posts.
CurrentState is essentially a map of three things, the blockmap which is a collection of ContentBlocks and the before and after state of the current selection. And now we are getting somewhere. The ContentBlocks represent line break delineated string. Generally this is a paragraph in your document. This (besides the selection) is the main building block of a document. ContentBlocks are generally of a type “unstyled”. You can of course style a block. This consists of, essentially, adding css styles the containing element. You can do this on the fly, meaning just a one off or you can create custom bocktypes that you can reuse such as a codeBlock that will be styled in a nice way for displaying code. Then you can start or apply that CodeBlock for specific a result.
Because a ContentBlocks is basically a string, you can reference any part of it by the number of characters. Remember how above I’ve mentioned Selections a couple times? Well this is where selections come in. If for instance you highlight some text, an onchange will fire and by calling EditorState.getSelection() You’ll get a SelectionState. I wont explain all the pieces the docs do a great job of that, but basically you get a startOffset and an endOffset. More importantly you get the SelectionState object which you can use to apply inline styles to.Draft-js will wrap the content in a span ( actually two spans ) and you can apply a previously defined style set to the wrapping span. Again I will go into detail later, but this is super powerful and what makes it even more powerful is that you can wrap a selection in a different tag, or even your own react component that you have complete control over.
That’s enough for this post but to reiterate, we have
- Editor ( the react component ) that take a
- EditorState which represents the entire document and has a
- CurrentState which has a selection and a
- ContentBlock map which represent paragraphs that you can get a
- SelectionState for, for more granular control