Reputation: 101
They offer great details on setContent and commands in general. But, I've been ctrl+F looking everywhere for where "commands" should be placed in code. I'm just hoping to load in HTML that I exported earlier with this Tiptap Editor.
https://tiptap.dev/api/commands/set-content
Here's some of my code for reference. Although, not sure if this has anything to do with where to put commands:
import "../../styles/tiptap.scss";
import { EditorContent, useEditor } from "@tiptap/react";
import StarterKit from "@tiptap/starter-kit";
import React, { useEffect } from "react";
const MenuBar = ({ editor }) => {
if (!editor) {
return null;
}
return (
<>
<button
onClick={() => editor.chain().focus().toggleBold().run()}
disabled={!editor.can().chain().focus().toggleBold().run()}
className={editor.isActive("bold") ? "is-active" : ""}
>
bold
</button>
<button
onClick={() => editor.chain().focus().toggleItalic().run()}
disabled={!editor.can().chain().focus().toggleItalic().run()}
className={editor.isActive("italic") ? "is-active" : ""}
>
italic
</button>
<button
onClick={() => editor.chain().focus().toggleStrike().run()}
disabled={!editor.can().chain().focus().toggleStrike().run()}
className={editor.isActive("strike") ? "is-active" : ""}
>
strike
</button>
<button
onClick={() => editor.chain().focus().toggleCode().run()}
disabled={!editor.can().chain().focus().toggleCode().run()}
className={editor.isActive("code") ? "is-active" : ""}
>
code
</button>
<button onClick={() => editor.chain().focus().unsetAllMarks().run()}>clear marks</button>
<button onClick={() => editor.chain().focus().clearNodes().run()}>clear nodes</button>
<button
onClick={() => editor.chain().focus().setParagraph().run()}
className={editor.isActive("paragraph") ? "is-active" : ""}
>
paragraph
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}
className={editor.isActive("heading", { level: 1 }) ? "is-active" : ""}
>
h1
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}
className={editor.isActive("heading", { level: 2 }) ? "is-active" : ""}
>
h2
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 3 }).run()}
className={editor.isActive("heading", { level: 3 }) ? "is-active" : ""}
>
h3
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 4 }).run()}
className={editor.isActive("heading", { level: 4 }) ? "is-active" : ""}
>
h4
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 5 }).run()}
className={editor.isActive("heading", { level: 5 }) ? "is-active" : ""}
>
h5
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 6 }).run()}
className={editor.isActive("heading", { level: 6 }) ? "is-active" : ""}
>
h6
</button>
<button
onClick={() => editor.chain().focus().toggleBulletList().run()}
className={editor.isActive("bulletList") ? "is-active" : ""}
>
bullet list
</button>
<button
onClick={() => editor.chain().focus().toggleOrderedList().run()}
className={editor.isActive("orderedList") ? "is-active" : ""}
>
ordered list
</button>
<button
onClick={() => editor.chain().focus().toggleCodeBlock().run()}
className={editor.isActive("codeBlock") ? "is-active" : ""}
>
code block
</button>
<button
onClick={() => editor.chain().focus().toggleBlockquote().run()}
className={editor.isActive("blockquote") ? "is-active" : ""}
>
blockquote
</button>
<button onClick={() => editor.chain().focus().setHorizontalRule().run()}>
horizontal rule
</button>
<button onClick={() => editor.chain().focus().setHardBreak().run()}>hard break</button>
<button
onClick={() => editor.chain().focus().undo().run()}
disabled={!editor.can().chain().focus().undo().run()}
>
undo
</button>
<button
onClick={() => editor.chain().focus().redo().run()}
disabled={!editor.can().chain().focus().redo().run()}
>
redo
</button>
</>
);
};
export default ({ newPostRichText, setNewPostRichText }) => {
const editor = useEditor({
extensions: [StarterKit],
content: `
<h2>
Hi there,
</h2>
<p>
this is a <em>basic</em> example of <strong>tiptap</strong>. Sure, there are all kind of basic text styles you’d probably expect from a text editor. But wait until you see the lists:
</p>
<ul>
<li>
That’s a bullet list with one …
</li>
<li>
… or two list items.
</li>
</ul>
<p>
Isn’t that great? And all of that is editable. But wait, there’s more. Let’s try a code block:
</p>
<pre><code class="language-css">body {
display: none;
}</code></pre>
<p>
I know, I know, this is impressive. It’s only the tip of the iceberg though. Give it a try and click a little bit around. Don’t forget to check the other examples too.
</p>
<blockquote>
Wow, that’s amazing. Good work, boy! 👏
<br />
— Mom
</blockquote>
`,
// triggered on every change
onUpdate: ({ editor }) => {
setNewPostRichText(editor?.getHTML());
//console.log(newPostRichText);
},
});
return (
<div>
<MenuBar editor={editor} />
<EditorContent editor={editor} />
</div>
);
};
I'm hoping to pass the HTML I exported from TipTap back in
Upvotes: 3
Views: 9495
Reputation: 33
React Hook "React.useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render react-hooks/rules-of-hook
useEditor...
useEffect..
Upvotes: 0
Reputation: 1634
Do I understand you correctly that the editor is inside the modal? Then I would recommend to make sure that the editor is not mounted if the modal is not shown. Since the tiptap editor does not work like other controlled inputs where we always feed back the value. We can only set the initial value in the useEditor hook. The the editor will keep its own state, however we can feed back the changes to the parent so we can do other stuff with the value.
const editor = useEditor({
extensions: [StarterKit],
content: newPostRichText,
// triggered on every change
onUpdate: ({ editor }) => {
setNewPostRichText(editor?.getHTML());
},
});
If you make sure to mount the editor when you show the modal, you should be able to set the content on mount every time
const [showModal, setShowModal] = useState(false);
return showModal ? (
<Modal>
<Editor
newPostRichText={"Initial content that you want to set when showing modal"}
setNewPostRichText={(html: string) => Do something with the content}
/>
</Modal>
) : null;
Let me know if this does not solve the problem, and I can try to elaborate a bit more.
Upvotes: 0
Reputation: 101
If you already have the content you want to load into the editor when the editor is initially shown you can easily just pass your content into the useEditor hook like this:
// make sure to have your content ready somewhere here?
const editorContent = '<p>Your content</p>'
const Tiptap = () => {
const editor = useEditor({
extensions: [
StarterKit,
],
content: editorContent,
})
return (
<EditorContent editor={editor} />
)
}
If you don't have the content already and you're fetching it from somewhere, you can do something like this:
const Tiptap = () => {
const editor = useEditor({
extensions: [
StarterKit,
],
content: '',
})
useEffect(() => {
// this is just an example. do whatever you want to do here
// to retrieve your editors content from somewhere
editor.commands.setContent(insertYourHTMLHere)
}, [editor])
return (
<EditorContent editor={editor} />
)
}
In this case you should probably save the content in state and don't show the when no content was loaded yet, as people could already start typing while the network request is still running.
Shoutout to https://github.com/bdbch for the help
Upvotes: 7