Skip to content

RangeError: Empty text nodes are not allowed (on editor.blocksToMarkdown) #184

@empiriker

Description

@empiriker

Hi there!

Great project! I really like the UI and the direction you're going.

I played a bit around in a NextJS project and found a couple of quirky issues that might have gone unnoticed. I'll report them in separate issues but here is the first one.

Unhandled Runtime Error
RangeError: Empty text nodes are not allowed

Source
new TextNode
node_modules/prosemirror-model/dist/index.js (1533:0)
Schema.text
node_modules/prosemirror-model/dist/index.js (2415:0)
Qt
node_modules/@blocknote/core/dist/blocknote.js (245:0)
ut
node_modules/@blocknote/core/dist/blocknote.js (258:0)
ht
node_modules/@blocknote/core/dist/blocknote.js (267:0)
R
node_modules/@blocknote/core/dist/blocknote.js (286:0)
mt
node_modules/@blocknote/core/dist/blocknote.js (498:0)
ie
node_modules/@blocknote/core/dist/blocknote.js (515:76)
No.blocksToMarkdown
node_modules/@blocknote/core/dist/blocknote.js (2801:0)
components/md-editor.tsx (68:46) @ blocksToMarkdown

  66 | // saves them.
  67 | const saveBlocksAsMarkdown = async () => {
> 68 |   const markdown: string = await editor.blocksToMarkdown(
     |                                        ^
  69 |     editor.topLevelBlocks
  70 |   );
  71 |   setValue(markdown);

I followed the documentation on converting blocks to Markdown with this code snippet:

// Stores the editor's contents as Markdown.
  const [markdown, setMarkdown] = useState<string>("");

  // Creates a new editor instance.
  const editor: BlockNoteEditor | null = useBlockNote({
    // Listens for when the editor's contents change.
    onEditorContentChange: (editor: BlockNoteEditor) => {
      // Converts the editor's contents from Block objects to Markdown and 
      // saves them.
      const saveBlocksAsMarkdown = async () => {
        const markdown: string = 
          await editor.blocksToMarkdown(editor.topLevelBlocks);
        setMarkdown(markdown);
      };
      saveBlocksAsMarkdown();
    }
  });

At first everything seemed to work as intended, but when copying a couple of websites to the editor (which converted the HTML to blocks in the background (excellent!)) in some cases I got the above error message.

Indeed, when investigating the block structure after pasting, I found this content block:

  {
    "id": "70b1274a-c071-4311-b4f2-9a854190406b",
    "type": "paragraph",
    "props": {
      "textColor": "default",
      "backgroundColor": "default",
      "textAlignment": "left"
    },
    "content": [
      { "type": "text", "text": "sometext", "styles": { "bold": true } },
      { "type": "text", "text": "", "styles": { "bold": true } }
    ],
    "children": []
  },

I am not sure what the HTML structure looked like that caused this. However, this doesn't seem to be intended.

I could solve the issue with manually checking for empty content nodes like this:

const removeEmptyTextBlocks = (blocks: Block[]) => {
  // Visit all nodes
  for (let i = 0; i < blocks.length; i++) {
    const block = blocks[i];

    // Recursively remove empty text nodes from children
    if (block.children) {
      removeEmptyTextBlocks(block.children);
    }

    // Remove empty text nodes from content
    if (block.content) {
      const filteredContent = block.content.filter(
        (contentNode) =>
          !(contentNode.type === 'text' && contentNode.text === '')
      );
      block.content = filteredContent.length ? filteredContent : [];
    }
  }
};

    // Listens for when the editor's contents change.
    onEditorContentChange: (editor: BlockNoteEditor) => {
      // Converts the editor's contents from Block objects to Markdown and
      // saves them.
      const saveBlocksAsMarkdown = async () => {
        const blocks = editor.topLevelBlocks;
        removeEmptyTextBlocks(blocks);

        const markdown: string = await editor.blocksToMarkdown(blocks);
        setValue(markdown);
      };
      saveBlocksAsMarkdown();
    }

Probably though this problem should be fixed either in the editor.blocksToMarkdown function or whatever function is responsible for pasting HTML. Or even a check when creating new content blocks. I am not too familiar with your code base, so I am not creating a pull request myself.

Keep up the great work!

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions