draft.js: making editor content multipage

Viewed 561

I have a difficult problem to solve.

Here is my sample project

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: enter image description here


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?

1 Answers

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.

Listen

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); // <---
  }}
/>

Handle the change and focus

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 :)

https://codesandbox.io/s/young-shape-t6kcc?file=/src/App.js

Related