react docs

This commit is contained in:
Jan Thurau 2023-06-02 18:26:24 +02:00
parent 89bce5e650
commit 4ad21341f2
No known key found for this signature in database
GPG Key ID: 60B3EB3A1C49AC04
15 changed files with 184 additions and 13 deletions

View File

@ -0,0 +1,52 @@
import './styles.css'
import { TiptapCollabProvider } from '@hocuspocus/provider'
import { CollaborationPlugin } from '@lexical/react/LexicalCollaborationPlugin'
import { InitialConfigType, LexicalComposer } from '@lexical/react/LexicalComposer'
import { ContentEditable } from '@lexical/react/LexicalContentEditable'
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary'
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin'
import React from 'react'
import * as Y from 'yjs'
import { TNote } from './types'
export default ({ note }: { note: TNote }) => {
const initialConfig: InitialConfigType = {
onError(error: Error): void {
throw error
},
namespace: 'myeditor',
editable: true,
}
return (
<LexicalComposer initialConfig={initialConfig}>
<RichTextPlugin
contentEditable={<ContentEditable/>}
placeholder={<p>{note.defaultContent}</p>}
ErrorBoundary={LexicalErrorBoundary}
/>
<CollaborationPlugin
id={note.id}
key={note.id}
// @ts-ignore
providerFactory={(id, yjsDocMap) => {
const doc = new Y.Doc()
yjsDocMap.set(id, doc)
const provider = new TiptapCollabProvider({
name: note.id, // any identifier - all connections sharing the same identifier will be synced
appId: '7j9y6m10', // replace with YOUR_APP_ID
token: 'notoken', // replace with your JWT
document: doc,
})
return provider
}}
shouldBootstrap={true}
/>
</LexicalComposer>
)
}

View File

@ -0,0 +1,26 @@
import './styles.css'
import React from 'react'
import Note from './Note'
import { TNote } from './types'
const notes: TNote[] = [
{
id: 'note-1',
defaultContent: 'some random note text',
},
{
id: 'note-2',
defaultContent: 'some really random note text',
},
]
export default () => {
return (
<div>
{notes.map(note => <Note note={note} key={note.id}/>)}
</div>
)
}

View File

@ -0,0 +1,3 @@
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";

View File

@ -0,0 +1,4 @@
export type TNote = {
id: string;
defaultContent: string;
};

View File

@ -23,7 +23,7 @@ export default ({ note }: { note: TNote }) => {
return () => {
provider.destroy()
}
}, [])
}, [note.id])
const editor = useEditor({
// make sure that you don't use `content` property anymore!

View File

@ -17,6 +17,11 @@ import { defineConfig } from 'vite'
const getPackageDependencies = () => {
const paths: Array<{ find: string, replacement: any }> = []
paths.push({
find: 'yjs',
replacement: resolve('../node_modules/yjs/src/index.js'),
})
fg.sync('../packages/*', { onlyDirectories: true })
.map(name => name.replace('../packages/', ''))
.forEach(name => {

View File

@ -2,12 +2,101 @@
tableOfContents: true
---
"Embed real-time collaboration into your app in under one minute, and everything is in sync." ([Live-Demo](/collab))- If that sounds interesting to you, we might have something :)
# Tiptap Collab
Tiptap Collab is our hosted solution of Hocuspocus for those who don't want to maintain their own deployment.
TODO: Maybe remove Cloud from hocuspocus docs, or keep the link but redirect to tiptap.dev/cloud?
Tiptap Collab is our hosted solution of Hocuspocus (The plugnplay collaborative editing backend) making it a blast to add real-time collaboration to any app.
:::warning Pro Feature
To get started, you need a Tiptap Pro account ([sign up / login here](https://tiptap.dev/pro)).
:::
[![Cloud Dashboard](https://tiptap.dev/images/docs/server/cloud/dashboard.png)](https://tiptap.dev/images/docs/server/cloud/dashboard.png)
Note that you need `@hocuspocus/provider` [~v2.0.0](https://github.com/ueberdosis/hocuspocus/releases/tag/v2.0.0)
## Getting started
Tiptap Collab makes your app collaborative by syncing your Y.Doc across users using websockets. If you are already using yjs in your app, getting started is as simple as shown below.
If you are not, you might want to start in our [Tutorials](/tutorials) section.
```typescript
import { TiptapCollabProvider } from '@hocuspocus/provider'
import * as Y from 'yjs'
const provider = new TiptapCollabProvider({
appId: 'your_app_id', // get this at collab.tiptap.dev
name: 'your_document_name', // e.g. a uuid uuidv4();
token: 'your_JWT', // see "Authentication" below
doc: new Y.Doc() // pass your existing doc, or leave this out and use provider.document
});
// That's it! Your Y.Doc will now be synced to any other user currently connected
```
### Upgrade from self-hosted deployments
If you are upgrading from a self-hosted deployment, on the frontend you just need to replace `HocuspocusProvider` with the new `TiptapCollabProvider`. The API is the same, it's just a wrapper that handles hostnames / auth.
## Examples
##### replit / Sandbox: Fully functional prototype
[![Cloud Documents](https://tiptap.dev/images/docs/server/cloud/tiptapcollab-demo.png)](https://tiptap.dev/images/docs/server/cloud/tiptapcollab-demo.png)
We have created a simple client / server setup using replit, which you can review and fork here:
[Github](https://github.com/janthurau/TiptapCollab) or [Replit (Live-Demo)](https://replit.com/@ueberdosis/TiptapCollab?v=1)
The example load multiple documents over the same websocket (multiplexing), and shows how to realize per-document authentication using JWT.
##### Authentication
Authentication is done using JWT. You can see your secret in the admin interface and use it to generate tokens for your clients. If you want to generate a JWT and add some attributes for testing, you can use http://jwtbuilder.jamiekurtz.com/ . You can leave all fields default, just replace the "key" with the secret from your settings.
In Node.js, you can generate a JWT like this:
```typescript
import jsonwebtoken from 'jsonwebtoken'
const data = {
// use this list to limit the number of documents that can be accessed by this client.
// empty array means no access at all
// not sending this property means access to all documents
// we are supporting a wildcard at the end of the string (only there)
allowedDocumentNames: ['document-1', 'document-2', 'my-user-uuid/*', 'my-organization-uuid/*']
}
const jwt = jsonwebtoken.sign(data, 'your_secret')
// this JWT should be sent in the `token` field of the provider. Never expose 'your_secret' to a frontend!
```
#### Getting the JSON document
If you want to access the JSON representation (we're currently exporting the `default` fragment of the YDoc), you can add a webhook in the admin interface. We are calling it when storing to our database, so it's debounced by 2 seconds (max 10 seconds).
All requests contain a header `X-Hocuspocus-Signature-256` which signs the entire message using 'your_secret' (find it in the settings). The payload looks like this:
```json
{
"appName": '', // name of your app
"name": '', // name of the document
"time": // current time as ISOString (new Date()).toISOString())
"tiptapData": {}, // JSON output from Tiptap (see https://tiptap.dev/guide/output#option-1-json): TiptapTransformer.fromYdoc()
"ydocState"?: {}, // optionally contains the entire yDoc as base64. Contact us to enable this property!
"clientsCount": 100 // number of currently connected clients
}
```
### Screenshots
[![Cloud Documents](https://tiptap.dev/images/docs/server/cloud/documents.png)](https://tiptap.dev/images/docs/server/cloud/documents.png)
[![Cloud Settings](https://tiptap.dev/images/docs/server/cloud/settings.png)](https://tiptap.dev/images/docs/server/cloud/settings.png)
### Need anything else?
Contact us on [Discord](https://tiptap.dev/discord) or send an email to [humans@tiptap.dev](mailto:humans@tiptap.dev).

View File

@ -2,4 +2,4 @@
tableOfContents: true
---
# Introduction
# Tutorials

View File

@ -4,8 +4,6 @@
**Welcome** to the first of a series of tutorials about collaboration in Tiptap (or Lexical, Quill, Slate, and others that have a [Yjs editor binding](https://docs.yjs.dev/ecosystem/editor-bindings)) using Tiptap Collab. This series will start covering the basics, and expand to more specific use cases in the next posts. For today, well start moving from a simple textarea box to a fully collaborative editor instance.
_For simplicity, I'm always referring to Tiptap from here, but you can switch each code sample to Lexical, Quill or Slate._
Imagine that you are building a simple sticky note app, where a user can create notes.
So let's say you have a few textareas. Depending on your framework (Vue, React, ..), the code probably looks similar to this:
@ -21,9 +19,6 @@ You begin by importing the necessary Tiptap components and creating a new editor
```bash
npm install @tiptap/vue-3 @tiptap/pm @tiptap/starter-kit
# for React: npm install @tiptap/react @tiptap/pm @tiptap/starter-kit
# for Lexical: npm install lexical @lexical/react
# for Quill: npm install quill
# for Slate: npm install slate slate-react react react-dom
```
<tiptap-demo name="Tutorials/1-2-tiptap"></tiptap-demo>
@ -39,9 +34,6 @@ To add the Collaboration extension to your editor instance, you first need to in
```bash
npm install @tiptap/extension-collaboration yjs
# for Lexical: npm install yjs
# for Quill: npm install y-quill yjs
# for Slate: npm install @slate-yjs/react yjs
```
Then, you can import the `Collaboration` extension and add it to your editor extensions: