tiptap/packages/extension-collaboration-cursor/src/collaboration-cursor.ts

96 lines
2.7 KiB
TypeScript
Raw Normal View History

2020-11-16 06:25:25 +08:00
import { Extension, Command } from '@tiptap/core'
2020-09-26 17:03:17 +08:00
import { yCursorPlugin } from 'y-prosemirror'
export interface CollaborationCursorOptions {
provider: any,
2020-11-30 20:35:49 +08:00
user: { [key: string]: any },
render (user: { [key: string]: any }): HTMLElement,
onUpdate: (users: { clientId: string, [key: string]: any }[]) => null,
}
const awarenessStatesToArray = (states: Map<number, { [key: string]: any }>) => {
return Array.from(states.entries()).map(([key, value]) => {
return {
clientId: key,
...value.user,
}
})
2020-09-26 17:03:17 +08:00
}
2020-12-08 04:32:50 +08:00
export const CollaborationCursor = Extension.create({
2020-12-02 16:44:46 +08:00
name: 'collaborationCursor',
2020-10-22 18:34:49 +08:00
defaultOptions: <CollaborationCursorOptions>{
2020-09-26 17:03:17 +08:00
provider: null,
2020-11-30 20:35:49 +08:00
user: {
name: null,
color: null,
},
render: user => {
const cursor = document.createElement('span')
2020-09-27 16:37:48 +08:00
cursor.classList.add('collaboration-cursor__caret')
cursor.setAttribute('style', `border-color: ${user.color}`)
const label = document.createElement('div')
2020-09-27 16:37:48 +08:00
label.classList.add('collaboration-cursor__label')
label.setAttribute('style', `background-color: ${user.color}`)
label.insertBefore(document.createTextNode(user.name), null)
cursor.insertBefore(label, null)
return cursor
},
2020-11-30 20:35:49 +08:00
onUpdate: () => null,
2020-10-22 18:34:49 +08:00
},
addCommands() {
return {
2020-11-13 22:08:30 +08:00
/**
* Update details of the current user
*/
2020-11-30 20:35:49 +08:00
user: (attributes: { [key: string]: any }): Command => () => {
2020-11-30 21:12:19 +08:00
this.options.user = attributes
2020-11-30 21:12:19 +08:00
this.options.provider.awareness.setLocalStateField('user', this.options.user)
2020-10-22 18:34:49 +08:00
return true
},
}
},
addProseMirrorPlugins() {
return [
yCursorPlugin((() => {
2020-11-30 20:35:49 +08:00
this.options.provider.awareness.setLocalStateField('user', this.options.user)
this.options.provider.awareness.on('change', () => {
this.options.onUpdate(awarenessStatesToArray(this.options.provider.awareness.states))
2020-10-22 18:34:49 +08:00
})
this.options.provider.awareness.on('update', () => {
this.options.onUpdate(awarenessStatesToArray(this.options.provider.awareness.states))
})
this.options.provider.on('status', (event: { status: string }) => {
if (event.status === 'connected') {
this.options.provider.awareness.setLocalStateField('user', this.options.user)
}
})
2020-11-30 20:35:49 +08:00
this.options.onUpdate(awarenessStatesToArray(this.options.provider.awareness.states))
2020-10-22 18:34:49 +08:00
return this.options.provider.awareness
})(),
// @ts-ignore
{
cursorBuilder: this.options.render,
}),
]
},
})
2020-10-23 04:40:40 +08:00
declare module '@tiptap/core' {
interface AllExtensions {
CollaborationCursor: typeof CollaborationCursor,
2020-10-23 04:40:40 +08:00
}
}