How can I handle an overflow view when inserting a character in draft js?

Using react, draftjs editor, and an outer div styled (with a styled-component) to look like a bootstrap input, I made an inline input intended for a calculator (there will be more to it).

I set up onChange so that practically any change results in the editor’s selection moving to the end, and I added a button that when pressed adds a "+" to the editor’s text. When I type input with my keyboard, everything works as expected.

When I press the plus button, however, the "+" is added to the text, but the overflow view doesn’t move. So when I press the plus button, if the focus is at the edge of the input shell, the "+" is added, but it’s out of view, and the view doesn’t fix itself until I enter subsequent character with the keyboard.

When "+" is entered with keyboard:

enter image description here

When "+" is entered with plus button:

enter image description here

Here is the pertinent code:

const InputShell = styled.div.attrs(() => ({
  className: "form-control form-control-sm mb-1",
}))`
  width: 75px;
  overflow: hidden;

  .inlineBlock {
    white-space: nowrap;
  }
  :focus-within {
    color: #495057;
    background-color: #fff;
    border-color: #80bdff;
    outline: 0;
    box-shadow: 0 0 0 0.2rem rgb(0 123 255 / 25%);
  }
`;

const CalculatorInput = () => {
  const editor = React.useRef<Editor>(null);
  const [editorState, setEditorState] = React.useState<EditorState>(
    EditorState.createEmpty()
  );

  const focusEditor = React.useCallback(() => {
    if (editor.current) {
      editor.current.focus();
    }
  }, [editor]);

  const insertChars = (chars: string) => {
    console.log("chars", chars);
    let contentState = editorState.getCurrentContent();
    const selectionState = editorState.getSelection();
    contentState = Modifier.insertText(contentState, selectionState, chars);
    setEditorState(
      EditorState.push(editorState, contentState, "insert-characters")
    );
  };

  const selectionToEnd = (editorState: EditorState) => {
    const selectionState = editorState.getSelection();
    if (selectionState.getHasFocus())
      editorState = EditorState.moveSelectionToEnd(editorState);
    editorState = EditorState.forceSelection(
      editorState,
      editorState.getSelection()
    );
    setEditorState(editorState);
  };

  return (
    <div>
      <div>
        <InputShell onClick={focusEditor}>
          <EditorContext.Provider value={editorState}>
            <Editor
              ref={editor}
              editorState={editorState}
              onChange={selectionToEnd}
              onFocus={() => {
                selectionToEnd(editorState);
                return "handled";
              }}
              blockStyleFn={() => "inlineBlock"}
              handleReturn={() => "handled"}
              handlePastedText={() => "handled"}
              handlePastedFiles={() => "handled"}
              handleDroppedFiles={() => "handled"}
              handleDrop={() => "handled"}
            />
          </EditorContext.Provider>
        </InputShell>
        <button
          type="button"
          className="btn btn-primary"
          onClick={() => {
            console.log("click");
            insertChars("+");
          }}
        >
          +
        </button>
      </div>
      <div>
        <pre>
          {JSON.stringify(
            convertToRaw(editorState.getCurrentContent()),
            null,
            2
          )}
        </pre>
      </div>
    </div>
  );
};

Any solutions or workarounds are appreciated.

Source: Ask Javascript Questions

LEAVE A COMMENT