Skip to content

Commit

Permalink
React context implementation for Tiptap (#4192)
Browse files Browse the repository at this point in the history
* feat(react): add react context implementation

* chore(docs): updated react docs & demos for new context

* chore(docs): added slot docs

* chore(docs): fix typo

* chore(react): use correct editor package

* fix typo in react installation docs

* update react typings to latest version

* fix types

---------

Co-authored-by: bdbch <dominik@bdbch.com>
  • Loading branch information
bdbch and bdbch authored Jul 11, 2023
1 parent e661bbb commit d689e2d
Show file tree
Hide file tree
Showing 11 changed files with 251 additions and 138 deletions.
102 changes: 50 additions & 52 deletions demos/src/Examples/Default/React/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import './styles.scss'
import { Color } from '@tiptap/extension-color'
import ListItem from '@tiptap/extension-list-item'
import TextStyle from '@tiptap/extension-text-style'
import { EditorContent, useEditor } from '@tiptap/react'
import { EditorProvider, useCurrentEditor } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
import React from 'react'

const MenuBar = ({ editor }) => {
const MenuBar = () => {
const { editor } = useCurrentEditor()

if (!editor) {
return null
}
Expand Down Expand Up @@ -178,58 +180,54 @@ const MenuBar = ({ editor }) => {
)
}

export default () => {
const editor = useEditor({
extensions: [
Color.configure({ types: [TextStyle.name, ListItem.name] }),
TextStyle.configure({ types: [ListItem.name] }),
StarterKit.configure({
bulletList: {
keepMarks: true,
keepAttributes: false, // TODO : Making this as `false` becase marks are not preserved when I try to preserve attrs, awaiting a bit of help
},
orderedList: {
keepMarks: true,
keepAttributes: false, // TODO : Making this as `false` becase marks are not preserved when I try to preserve attrs, awaiting a bit of help
},
}),
],
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;
const extensions = [
Color.configure({ types: [TextStyle.name, ListItem.name] }),
TextStyle.configure({ types: [ListItem.name] }),
StarterKit.configure({
bulletList: {
keepMarks: true,
keepAttributes: false, // TODO : Making this as `false` becase marks are not preserved when I try to preserve attrs, awaiting a bit of help
},
orderedList: {
keepMarks: true,
keepAttributes: false, // TODO : Making this as `false` becase marks are not preserved when I try to preserve attrs, awaiting a bit of help
},
}),
]

const 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>
`,
})
<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>
`

export default () => {
return (
<div>
<MenuBar editor={editor} />
<EditorContent editor={editor} />
</div>
<EditorProvider slotBefore={<MenuBar />} extensions={extensions} content={content}></EditorProvider>
)
}
81 changes: 74 additions & 7 deletions docs/installation/react.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,54 @@ To actually start using Tiptap we need to create a new component. Let’s call i

```jsx
// src/Tiptap.jsx
import { useEditor, EditorContent } from '@tiptap/react'
import { EditorProvider, FloatingMenu, BubbleMenu } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'

// define your extension array
const extensions = [
StarterKit,
]

const content = '<p>Hello World!</p>'

const Tiptap = () => {
return (
<EditorProvider extensions={extensions} content={content}>
<FloatingMenu>This is the floating menu</FloatingMenu>
<BubbleMenu>This is the bubble menu</BubbleMenu>
</EditorProvider>
)
}

export default Tiptap
```

**Important Note**: You can always use the `useEditor` hook if you want to avoid using the Editor context.

```jsx
// src/Tiptap.jsx
import { useEditor, EditorContent FloatingMenu, BubbleMenu } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'

// define your extension array
const extensions = [
StarterKit,
]

const content = '<p>Hello World!</p>'

const Tiptap = () => {
const editor = useEditor({
extensions: [
StarterKit,
],
content: '<p>Hello World!</p>',
extensions,
content,
})

return (
<EditorContent editor={editor} />
<>
<EditorContent editor={editor} />
<FloatingMenu editor={editor}>This is the floating menu</FloatingMenu>
<BubbleMenu editor={editor}>This is the bubble menu</BubbleMenu>
</>
)
}

Expand All @@ -83,9 +118,41 @@ const App = () => {
export default App
```

#### 5. Consume the Editor context in child components

If you use the `EditorProvider` to setup your Tiptap editor, you can now easily access your editor instance from any child component using the `useCurrentEditor` hook.

```jsx
import { useCurrentEditor } from '@tiptap/react'

const EditorJSONPreview = () => {
const { editor } = useCurrentEditor()

return (
<pre>
{JSON.stringify(editor.getJSON(), null, 2)}
</pre>
)
}
```

**Important**: This won't work if you use the `useEditor` hook to setup your editor.

You should now see a pretty barebones example of Tiptap in your browser.

#### 5. The complete setup (optional)
#### 6. Add before or after slots
Since the EditorContent component is rendered by the `EditorProvider` component, we now can't directly define where to render before or after content of our editor. For that we can use the `slotBefore` & `slotAfter` props on the `EditorProvider` component.

```jsx
<EditorProvider
extensions={extensions}
content={content}
slotBefore={<MyEditorToolbar />}
slotAfter={<MyEditorFooter />}
/>
```

#### 7. The complete setup (optional)
Ready to add more? Below is a demo that shows how you could set up a basic toolbar. Feel free to take it and start customizing it to your needs:

https://embed.tiptap.dev/preview/Examples/Default
Loading

0 comments on commit d689e2d

Please sign in to comment.