You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
cudr_slate-collaborative/packages/client/src/useCursor.ts

69 lines
1.7 KiB

import { useState, useCallback, useEffect, useMemo } from 'react'
import { Text, Range, Path, NodeEntry } from 'slate'
import { toJS, Cursor, Cursors } from '@slate-collaborative/bridge'
import { AutomergeEditor } from './automerge-editor'
const useCursor = (
e: AutomergeEditor
): { decorate: (entry: NodeEntry) => Range[]; cursors: Cursor[] } => {
const [cursorData, setSursorData] = useState<Cursor[]>([])
useEffect(() => {
e.onCursor = (data: Cursors) => {
const ranges: Cursor[] = []
const cursors = toJS(data)
for (let cursor in cursors) {
if (cursor !== e.clientId && cursors[cursor]) {
ranges.push(JSON.parse(cursors[cursor]))
}
}
setSursorData(ranges)
}
}, [])
const cursors = useMemo<Cursor[]>(() => cursorData, [cursorData])
const decorate = useCallback(
([node, path]: NodeEntry) => {
const ranges: Range[] = []
if (Text.isText(node) && cursors?.length) {
cursors.forEach(cursor => {
if (Range.includes(cursor, path)) {
const { focus, anchor, isForward } = cursor
ranges.push({
...cursor,
isCaret: isForward
? Path.equals(focus.path, path)
: Path.equals(anchor.path, path),
anchor: Path.isBefore(anchor.path, path)
? { ...anchor, offset: 0 }
: anchor,
focus: Path.isAfter(focus.path, path)
? { ...focus, offset: node.text.length }
: focus
})
}
})
}
return ranges
},
[cursors]
)
return {
cursors,
decorate
}
}
export default useCursor