Skip to content

Can't call blocksToHTMLLossy on document with React custom blocks without instantiating a BlockNoteView #720

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
1 task
blx opened this issue May 3, 2024 · 1 comment · Fixed by #451
Closed
1 task
Assignees
Labels
bug Something isn't working prio:high High priority server

Comments

@blx
Copy link

blx commented May 3, 2024

Describe the bug
<what's going wrong!?>

I want to render a document of blocks to HTML, "headlessly" ie. without showing the editor. But when some of my custom blocks are React-rendered (defined via createReactBlockSpec), an error is thrown when exporting to HTML without having instantiated a BlockNoteView.

blocksToHTMLLossy(), somewhere down the stack, depends on contentComponent being set on the inner editor._tiptapEditor (here), which is done by a useEffect in EditorContent that mutates the editor passed in , and EditorContent doesn't come into play without having a BlockNoteView.

I think this specific state of affairs was introduced in #641, but I haven't checked whether this would have worked before that.

For now, I'm just rendering a BlockNoteView on a throwaway React root, in order to get the mutation from EditorContent applied, which is fine, but a bit clunky.

I appreciate this is probably not a common use case 🙃

To Reproduce

const toHTML = async (blocks, schema=null) => BlockNoteEditor.create({
  initialContent: blocks,
  ...(schema ? { schema } : {})
}).blocksToHTMLLossy();

// Default schema block works fine:
console.log(await toHTML([{ type: 'paragraph', content: 'heya' }]));

// React-based custom element doesn't work...
const somethingBlock = createReactBlockSpec(
  { type: 'something', content: 'none', propSchema: {} },
  { render() { return <i>A constant something</i> } }
)
const customSchema = BlockNoteSchema.create({ blockSpecs: { something: somethingBlock } })

// ...Throws error:
console.log(await toHTML([{type: 'something'}], customSchema))

// But this works:
const editor = BlockNoteEditor.create({ initialContent: [{type: 'something'}], schema: customSchema });
await new Promise((resolve, reject) => {
  const tmpRoot = ReactDOMClient.createRoot(document.createElement('div'));
  tmpRoot.render(React.createElement(() => {
    useEffect(() => { resolve(); }, []);
    return React.createElement(BlockNoteView, { editor });
  }));
});
console.log(await editor.blocksToHTMLLossy());

The error thrown is:

Uncaught (in promise) TypeError: t._tiptapEditor.contentComponent is undefined
    Ce ReactRenderUtil.ts:13
    toExternalHTML ReactBlockSpec.tsx:213
    Kt sharedHTMLConversion.ts:70
    serializeNodeInner externalHTMLExporter.ts:66
    serializeFragment index.js:3273
    forEach index.js:250
    serializeFragment index.js:3247
    Kt sharedHTMLConversion.ts:109
    serializeNodeInner externalHTMLExporter.ts:66
    serializeFragment index.js:3273
    forEach index.js:250
    serializeFragment index.js:3247
    Jt sharedHTMLConversion.ts:124
    exportProseMirrorFragment externalHTMLExporter.ts:79
    exportBlocks externalHTMLExporter.ts:90
    blocksToHTMLLossy BlockNoteEditor.ts:907

<clear steps to reproduce are super helpful! Best is to provide an online sandbox, click to create one>

Misc

  • Node version:
  • Package manager:
  • Browser:
  • I'm a sponsor and would appreciate if you could look into this sooner than later 💖
@blx blx added the bug Something isn't working label May 3, 2024
@YousefED YousefED self-assigned this May 28, 2024
@YousefED
Copy link
Collaborator

Thanks for reporting this! Although your workaround should work we definitely need to fix this. When implementing #451, we should take this into account. I think the ideal solution would:

a) Make sure that for simple React blocks, setting up the React Root is not required. blocksToHTMLLossy should just work in this case. I think ReactRenderUtil should already cover this, so I'm not sure why this error is actually thrown (might also be recently fixed in #788 )

b) Make it still possible to call blocksToHTMLLossy (and related functions like blocksToMarkdown) in a React tree. This is because custom react blocks might depend on a React Context, so if the consumer wants it should be possible to make these available

@matthewlipski matthewlipski added the prio:high High priority label Jun 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working prio:high High priority server
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants