Merge branch 'main' of github.com:ueberdosis/tiptap-next into main
This commit is contained in:
@@ -47,10 +47,10 @@ export default {
|
|||||||
isActive: () => this.editor.isActive('code'),
|
isActive: () => this.editor.isActive('code'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'paragraph',
|
icon: 'mark-pen-line',
|
||||||
title: 'Paragraph',
|
title: 'Highlight',
|
||||||
action: () => this.editor.chain().focus().setParagraph().run(),
|
action: () => this.editor.chain().focus().toggleHighlight().run(),
|
||||||
isActive: () => this.editor.isActive('paragraph'),
|
isActive: () => this.editor.isActive('highlight'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'h-1',
|
icon: 'h-1',
|
||||||
@@ -65,28 +65,10 @@ export default {
|
|||||||
isActive: () => this.editor.isActive('heading', { level: 2 }),
|
isActive: () => this.editor.isActive('heading', { level: 2 }),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'h-3',
|
icon: 'paragraph',
|
||||||
title: 'Heading 3',
|
title: 'Paragraph',
|
||||||
action: () => this.editor.chain().focus().toggleHeading({ level: 3 }).run(),
|
action: () => this.editor.chain().focus().setParagraph().run(),
|
||||||
isActive: () => this.editor.isActive('heading', { level: 3 }),
|
isActive: () => this.editor.isActive('paragraph'),
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'h-4',
|
|
||||||
title: 'Heading 4',
|
|
||||||
action: () => this.editor.chain().focus().toggleHeading({ level: 4 }).run(),
|
|
||||||
isActive: () => this.editor.isActive('heading', { level: 4 }),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'h-5',
|
|
||||||
title: 'Heading 5',
|
|
||||||
action: () => this.editor.chain().focus().toggleHeading({ level: 5 }).run(),
|
|
||||||
isActive: () => this.editor.isActive('heading', { level: 5 }),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'h-6',
|
|
||||||
title: 'Heading 6',
|
|
||||||
action: () => this.editor.chain().focus().toggleHeading({ level: 6 }).run(),
|
|
||||||
isActive: () => this.editor.isActive('heading', { level: 6 }),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'list-unordered',
|
icon: 'list-unordered',
|
||||||
@@ -100,6 +82,12 @@ export default {
|
|||||||
action: () => this.editor.chain().focus().toggleOrderedList().run(),
|
action: () => this.editor.chain().focus().toggleOrderedList().run(),
|
||||||
isActive: () => this.editor.isActive('orderedList'),
|
isActive: () => this.editor.isActive('orderedList'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
icon: 'list-check-2',
|
||||||
|
title: 'Task List',
|
||||||
|
action: () => this.editor.chain().focus().toggleTaskList().run(),
|
||||||
|
isActive: () => this.editor.isActive('taskList'),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
icon: 'code-box-line',
|
icon: 'code-box-line',
|
||||||
title: 'Code Block',
|
title: 'Code Block',
|
||||||
|
|||||||
@@ -41,6 +41,9 @@
|
|||||||
import { Editor, EditorContent, defaultExtensions } from '@tiptap/vue-starter-kit'
|
import { Editor, EditorContent, defaultExtensions } from '@tiptap/vue-starter-kit'
|
||||||
import Collaboration from '@tiptap/extension-collaboration'
|
import Collaboration from '@tiptap/extension-collaboration'
|
||||||
import CollaborationCursor from '@tiptap/extension-collaboration-cursor'
|
import CollaborationCursor from '@tiptap/extension-collaboration-cursor'
|
||||||
|
import TaskList from '@tiptap/extension-task-list'
|
||||||
|
import TaskItem from '@tiptap/extension-task-item'
|
||||||
|
import Highlight from '@tiptap/extension-highlight'
|
||||||
import * as Y from 'yjs'
|
import * as Y from 'yjs'
|
||||||
import { WebsocketProvider } from 'y-websocket'
|
import { WebsocketProvider } from 'y-websocket'
|
||||||
import { IndexeddbPersistence } from 'y-indexeddb'
|
import { IndexeddbPersistence } from 'y-indexeddb'
|
||||||
@@ -81,6 +84,9 @@ export default {
|
|||||||
this.editor = new Editor({
|
this.editor = new Editor({
|
||||||
extensions: [
|
extensions: [
|
||||||
...defaultExtensions().filter(extension => extension.config.name !== 'history'),
|
...defaultExtensions().filter(extension => extension.config.name !== 'history'),
|
||||||
|
Highlight,
|
||||||
|
TaskList,
|
||||||
|
TaskItem,
|
||||||
Collaboration.configure({
|
Collaboration.configure({
|
||||||
provider,
|
provider,
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -205,17 +205,55 @@ Yes, it’s magic. As already mentioned, that is all based on the fantastic Y.js
|
|||||||
## Store the content
|
## Store the content
|
||||||
Our collaborative editing backend is ready to handle advanced use cases, like authorization, persistence and scaling. Let’s go through a few common use cases here!
|
Our collaborative editing backend is ready to handle advanced use cases, like authorization, persistence and scaling. Let’s go through a few common use cases here!
|
||||||
|
|
||||||
|
### Authentication
|
||||||
|
With the `onConnect` hook you can write a custom Promise to check if a client is authenticated. That can be a request to an API, to a microservice, a database query, or whatever is needed, as long as it’s executing `resolve()` at some point. You can also pass contextual data to the `resolve()` method which will be accessible in other hooks.
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { Server } from '@hocuspocus/server'
|
||||||
|
|
||||||
|
const server = Server.configure({
|
||||||
|
onConnect(data, resolve, reject) {
|
||||||
|
const { requestHeaders } = data
|
||||||
|
// Your code here, for example a request to an API
|
||||||
|
|
||||||
|
// If the user is not authorized …
|
||||||
|
if (requestHeaders.access_token !== 'super-secret-token') {
|
||||||
|
return reject()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set contextual data
|
||||||
|
const context = {
|
||||||
|
user_id: 1234,
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the user is authorized …
|
||||||
|
resolve(context)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
server.listen()
|
||||||
|
```
|
||||||
|
|
||||||
### Authorization
|
### Authorization
|
||||||
With the `onJoinDocument` hook you can write a custom Promise to check if a client is authorized. That can be a request to an API, to a microservice, a database query, or whatever is needed, as long as it’s executing `resolve()` at some point.
|
With the `onJoinDocument` hook you can check if a user is authorized to edit the current document. This works in the same way the [Authentication](#authentication) works.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import { Server } from '@hocuspocus/server'
|
import { Server } from '@hocuspocus/server'
|
||||||
|
|
||||||
const server = Server.configure({
|
const server = Server.configure({
|
||||||
onJoinDocument(data, resolve, reject) {
|
onJoinDocument(data, resolve, reject) {
|
||||||
const { documentName, clientID, requestHeaders, clientsCount, document } = data
|
const {
|
||||||
|
clientsCount,
|
||||||
|
context,
|
||||||
|
document,
|
||||||
|
documentName,
|
||||||
|
requestHeaders,
|
||||||
|
} = data
|
||||||
// Your code here, for example a request to an API
|
// Your code here, for example a request to an API
|
||||||
|
|
||||||
|
// Access the contextual data from the onConnect hook, in this example this will print { user_id: 1234 }
|
||||||
|
console.log(context)
|
||||||
|
|
||||||
// If the user is authorized …
|
// If the user is authorized …
|
||||||
resolve()
|
resolve()
|
||||||
|
|
||||||
@@ -258,8 +296,14 @@ const server = Server.configure({
|
|||||||
|
|
||||||
// executed when the document is changed
|
// executed when the document is changed
|
||||||
onChange(data) {
|
onChange(data) {
|
||||||
const { documentName, clientID, requestHeaders, clientsCount, document } = data
|
const {
|
||||||
|
clientsCount,
|
||||||
|
document,
|
||||||
|
documentName,
|
||||||
|
requestHeaders,
|
||||||
|
} = data
|
||||||
|
|
||||||
|
// Your code here, for example a request to an API
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export default function isMarkActive(
|
|||||||
let markRanges: MarkRange[] = []
|
let markRanges: MarkRange[] = []
|
||||||
|
|
||||||
state.doc.nodesBetween(from, to, (node, pos) => {
|
state.doc.nodesBetween(from, to, (node, pos) => {
|
||||||
if (node.isInline) {
|
if (node.isText) {
|
||||||
const relativeFrom = Math.max(from, pos)
|
const relativeFrom = Math.max(from, pos)
|
||||||
const relativeTo = Math.min(to, pos + node.nodeSize)
|
const relativeTo = Math.min(to, pos + node.nodeSize)
|
||||||
const range = relativeTo - relativeFrom
|
const range = relativeTo - relativeFrom
|
||||||
@@ -51,6 +51,10 @@ export default function isMarkActive(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (selectionRange === 0) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
const range = markRanges
|
const range = markRanges
|
||||||
.filter(markRange => {
|
.filter(markRange => {
|
||||||
if (!type) {
|
if (!type) {
|
||||||
|
|||||||
Reference in New Issue
Block a user