Draft.js: List depth control
At Propeller it’s really important for us to make the interaction between our users and platform as smooth as possible. And one of the major points of this interaction is text editing. We’ve chosen DraftJS editor as the tool to provide RichText capabilities to our users. To achieve the best user experience we can we need to follow some commonly used patterns in the area of RichText editing, but DraftJS doesn’t follow these patterns out of the box. Instead, it provides you a wide range of possibilities to customise the editor as you need.
The problem
Imagine you have a nested list(ordered or unordered). When you have finished your work with current depth level, you need to go one level up. The common way to do it is to leave the item blank and hit Return
button. The depth level would be decreased and you can continue your work without even thinking about pressing specific key combo. And if the the cursor is on the first depth level the editor should close the list.
By default DraftJS implements different logics — when you hit Return
on a blank list item a new item is created.
To improve the UX of your app you can use this plugin or follow the steps below.
Solution
The algorithm is pretty simple: when user has pressed Return
we need to check if current list item is empty. If so — we need to check the depth level. If it is greater than 0 we need to decrease it. Otherwise we need to close the list. The depth level can’t be less than 0. As always, things start to get complicated when it goes down to DraftJS and it’s documentation.
Since we need to alter the behaviour of Return
key press, DraftJS method handleReturn
would be a great point to start! First of all, we need to get currently selected block(if there is any) to work with. To do it, we need to get current states of selection and content and select a block where the selection starts.
Once the block is selected we need to check if the block is a list item and if this item has no text. Let’s implement a function to do this.
Now we can detect the exact case when we need to alter the default behaviour. Let’s now combine everything we have so far.
So far so good! Now let’s implement handleReturnForListItem
method according to the described algorithm.
Changing block’s depth level turned out to be pretty simple. Since DraftJS uses Immutable.js internally, we can call set
method of the block to get a copy of the object with updated property. Then we need to update the state of the editor accordingly.
Note that EditorState
from DraftJS is used here — not a locally stored editorState
. Also note that adjust-depth
change type is used here. DraftJS uses change-types to determine if current change may be regarded as a boundary state for undo/redo behaviour.
We’re almost done now! The only part left to be written is the logics to close the list if depth level is 0.
Method tryToRemoveBlockStyle
from RichUtils
module allows us to safely change block type to unstyled
. This means that our list would be closed and the last item in this list would be the previous one.
If you’ve read this post till this moment you may also want to check my other post and apply this enhancement as well.