I have a difficult problem to solve.
Basically I want to create a editable book-like container and since each book page is another container, I can't figure how to make an editor transition from one page to another, once the page is filled with text.
Here is what I'm trying to achieve:
My first thought was to use a shared state for multiple editor instances, but as you can see in the example code, it doesn't work as expected and same text appears in two pages.
How can I achieve a multi-container transition when using draft.js?
The logic in general is to listen to changes of the first editor, count characters / word / lines (or more advanced calculation, if the editor has scroll for example) and finally focus the second editor if needed.
This answer covers, listen, dummy calculation and focus on the next editor. This answer doesn't cover the calculation itself nor dynamic number of pages nor moving back from second editor when deleting content etc. But I believe that it's a direction to your final goal.
First of all, I moved the state creation and handling back to the Editor component itself. What "interests" the parent component ("App") is to get notified when its content changed.
But now, App needs to access the ("draft-js") editor in order to call focus
. This will solve by creating "ref" in App and propagate it using forwardRef
.
const editorRef = React.useRef();
const Editor = React.forwardRef((props, ref) => {
return <MyEditor name="editor-2" forwardRef={ref} />;
});
...
return (
...
<Editor ref={editorRef} />
)
and in Editor.js
function MyEditor({ onChange, forwardRef }) {
...
return (
<Editor
ref={forwardRef}
)
});
Next thing is to add onChange
to Editor so App get notified when the content has been changed.
<Editor
ref={forwardRef}
stripPastedStyles
editorState={editorState}
onChange={editorState => {
setEditorState(editorState);
onChange && onChange(editorState); // <---
}}
/>
The first editor is now
<MyEditor name="editor-1" onChange={onEditorChange} />
and onEditorChange
is
const onEditorChange = editorState => {
const text = editorState.getCurrentContent().getPlainText();
if (text.length >= 5) {
setTimeout(() => {
editorRef.current.focus();
});
}
};
Currently it checks if the content's length is 5
. You probably want to calculate it in a more sophisticated way.
The last question is, why setTimeout
? Well, the simple answer is that without it, "draft-js" throw an error. I believe that it's something with their implementation of release / delete / clear global variables or something.
And the most important part, the code and live demo :)