mirror of
https://github.com/ueberdosis/tiptap.git
synced 2024-11-28 15:49:23 +08:00
235 lines
8.0 KiB
Markdown
235 lines
8.0 KiB
Markdown
---
|
||
tableOfContents: true
|
||
---
|
||
|
||
|
||
# Install Collaboration
|
||
This guide will get you started with collaborative editing in the Tiptap Editor. If you're already using Tiptap Editor, feel free to skip ahead to the "Adding Collaboration" section.
|
||
|
||
### Installing Tiptap Editor
|
||
|
||
If Tiptap Editor isn't installed yet, run the following command in your CLI for either React or Vue to install the basic editor and necessary extensions for this example:
|
||
|
||
```bash
|
||
npm install @tiptap/extension-document @tiptap/extension-paragraph @tiptap/extension-text @tiptap/react
|
||
```
|
||
|
||
Once installed, you can get your Tiptap Editor up and running with this basic setup. Just add the following code snippets to your project:
|
||
https://embed.tiptap.dev/preview/Examples/Minimal
|
||
|
||
## Adding Collaboration
|
||
|
||
To introduce team collaboration features into your Tiptap Editor, integrate the Yjs library and Editor Collaboration extension into your frontend. This setup uses Y.Doc, a shared document model, rather than just handling plain text.
|
||
Afterwards we will connect Y.Doc to the TiptapCollabProvider to synchronize user interactions.
|
||
|
||
### Integrating Yjs and the Collaboration Extension
|
||
|
||
Add the Editor Collaboration extension and Yjs library to your frontend:
|
||
|
||
```bash
|
||
npm install @tiptap/extension-collaboration yjs
|
||
```
|
||
|
||
Then, update your index.jsx to include these new imports:
|
||
|
||
```typescript
|
||
import './styles.scss'
|
||
|
||
import Document from '@tiptap/extension-document'
|
||
import Paragraph from '@tiptap/extension-paragraph'
|
||
import Text from '@tiptap/extension-text'
|
||
import { EditorContent, useEditor } from '@tiptap/react'
|
||
import React from 'react'
|
||
|
||
import Collaboration from '@tiptap/extension-collaboration'
|
||
import * as Y from 'yjs'
|
||
|
||
export default () => {
|
||
const doc = new Y.Doc() // Initialize Y.Doc for shared editing
|
||
|
||
const editor = useEditor({
|
||
extensions: [
|
||
Document,
|
||
Paragraph,
|
||
Text,
|
||
Collaboration.configure({
|
||
document: doc // Configure Y.Doc for collaboration
|
||
})
|
||
],
|
||
content: `
|
||
<p>
|
||
This is a radically reduced version of tiptap. It has support for a document, with paragraphs and text. That’s it. It’s probably too much for real minimalists though.
|
||
</p>
|
||
<p>
|
||
The paragraph extension is not really required, but you need at least one node. Sure, that node can be something different.
|
||
</p>
|
||
`,
|
||
})
|
||
|
||
return (
|
||
<EditorContent editor={editor} />
|
||
)
|
||
}
|
||
```
|
||
|
||
Your editor is now prepared for collaborative editing!
|
||
|
||
### Connecting to the Collaboration Server
|
||
|
||
For collaborative functionality, install the `@hocuspocus/provider` package:
|
||
|
||
```bash
|
||
npm install @hocuspocus/provider
|
||
```
|
||
|
||
Next, configure the Hocuspocus provider in your index.jsx file with your server details:
|
||
|
||
- **name**: Serves as the document identifier for synchronization.
|
||
- **appID**: Found in your [Cloud account](https://cloud.tiptap.dev/apps) after you started your app. For on-premises setups replace `appID` with `baseUrl`.
|
||
- **token**: Use the JWT from your [Cloud interface](https://cloud.tiptap.dev/apps/settings) for testing, but generate your own JWT for production.
|
||
|
||
Incorporate the following code to complete the setup:
|
||
|
||
```typescript
|
||
import './styles.scss'
|
||
|
||
import Document from '@tiptap/extension-document'
|
||
import Paragraph from '@tiptap/extension-paragraph'
|
||
import Text from '@tiptap/extension-text'
|
||
import { EditorContent, useEditor } from '@tiptap/react'
|
||
import React from 'react'
|
||
|
||
import Collaboration from '@tiptap/extension-collaboration'
|
||
import * as Y from 'yjs'
|
||
|
||
// Importing the provider and useEffect
|
||
import {useEffect} from 'react'
|
||
import { TiptapCollabProvider } from '@hocuspocus/provider'
|
||
|
||
export default () => {
|
||
const doc = new Y.Doc()
|
||
|
||
const editor = useEditor({
|
||
extensions: [
|
||
Document,
|
||
Paragraph,
|
||
Text,
|
||
Collaboration.configure({
|
||
document: doc,
|
||
}),
|
||
],
|
||
content: `
|
||
<p>
|
||
This is a radically reduced version of tiptap. It has support for a document, with paragraphs and text. That’s it. It’s probably too much for real minimalists though.
|
||
</p>
|
||
<p>
|
||
The paragraph extension is not really required, but you need at least one node. Sure, that node can be something different.
|
||
</p>
|
||
`,
|
||
})
|
||
|
||
// Connect to your Collaboration server
|
||
useEffect(() => {
|
||
const provider = new TiptapCollabProvider({
|
||
name: "document.name", // Unique document identifier for syncing. This is your document name.
|
||
appId: '7j9y6m10', // Your Cloud Dashboard AppID or `baseURL` for on-premises
|
||
token: 'notoken', // Your JWT token
|
||
document: doc,
|
||
})
|
||
})
|
||
|
||
return (
|
||
<EditorContent editor={editor} />
|
||
)
|
||
}
|
||
```
|
||
|
||
After following these steps, you should be able to open two different browsers and connect to the same document simultaneously through separate WebSocket connections.
|
||
|
||
For a clear test of the collaboration features, using two different browsers is recommended to guarantee unique websocket connections.
|
||
|
||
### Initializing Content Properly
|
||
|
||
Upon implementing collaboration in your Tiptap Editor, you might notice that the initial content is repeatedly added each time the editor loads. To prevent this, use the `.setContent()` method to set the initial content only once.
|
||
|
||
```typescript
|
||
import './styles.scss'
|
||
|
||
import Document from '@tiptap/extension-document'
|
||
import Paragraph from '@tiptap/extension-paragraph'
|
||
import Text from '@tiptap/extension-text'
|
||
import { EditorContent, useEditor } from '@tiptap/react'
|
||
import React from 'react'
|
||
|
||
import * as Y from 'yjs'
|
||
import Collaboration from '@tiptap/extension-collaboration'
|
||
import {useEffect} from 'react'
|
||
|
||
import { TiptapCollabProvider } from '@hocuspocus/provider'
|
||
|
||
export default () => {
|
||
const doc = new Y.Doc()
|
||
|
||
const editor = useEditor({
|
||
extensions: [
|
||
Document,
|
||
Paragraph,
|
||
Text,
|
||
Collaboration.configure({
|
||
document: doc
|
||
})
|
||
],
|
||
// Remove the automatic content addition on editor initialization.
|
||
})
|
||
|
||
useEffect(() => {
|
||
const provider = new TiptapCollabProvider({
|
||
name: "document.name", // Unique document identifier for syncing. This is your document name.
|
||
appId: '7j9y6m10', // Your Cloud Dashboard AppID or `baseURL` for on-premises
|
||
token: 'notoken', // Your JWT token
|
||
document: doc,
|
||
|
||
// The onSynced callback ensures initial content is set only once using editor.setContent(), preventing repetitive content loading on editor syncs.
|
||
onSynced() {
|
||
|
||
if( !doc.getMap('config').get('initialContentLoaded') && editor ){
|
||
doc.getMap('config').set('initialContentLoaded', true);
|
||
|
||
editor.commands.setContent(`
|
||
<p>
|
||
This is a radically reduced version of tiptap. It has support for a document, with paragraphs and text. That’s it. It’s probably too much for real minimalists though.
|
||
</p>
|
||
<p>
|
||
The paragraph extension is not really required, but you need at least one node. Sure, that node can be something different.
|
||
</p>
|
||
`)
|
||
}
|
||
|
||
}
|
||
})
|
||
})
|
||
|
||
return (
|
||
<EditorContent editor={editor} />
|
||
)
|
||
}
|
||
```
|
||
|
||
This ensures the initial content is set only once. To test with new initial content, create a new document by changing the `name` parameter (e.g., from `document.name` to `document.name2`).
|
||
|
||
## Disabling Default Undo/Redo
|
||
If you're integrating collaboration into an editor **other than the one provided in this demo**, you may need to disable the default history function of your Editor. This is necessary to avoid conflicts with the collaborative history management: You wouldn't want to revert someone else's changes.
|
||
|
||
This action is only required if your project includes the Tiptap [StarterKit](https://tiptap.dev/docs/editor/api/extensions/starter-kit) or [History](https://tiptap.dev/docs/editor/api/extensions/history) extension.
|
||
|
||
```typescript
|
||
const editor = useEditor({
|
||
extensions: [
|
||
StarterKit.configure({
|
||
history: false, // Disables default history to use Collaboration's history management
|
||
}),
|
||
…
|
||
```
|
||
|
||
Following this guide will set up a basic, yet functional collaborative Tiptap Editor, synchronized through either the Collaboration Cloud or an on-premises backend.
|