Skip to content

Commit

Permalink
Fixed Live Cursors
Browse files Browse the repository at this point in the history
  • Loading branch information
R1c4rdCo5t4 committed Apr 20, 2024
1 parent 0696f9f commit e21a15c
Show file tree
Hide file tree
Showing 7 changed files with 44 additions and 41 deletions.
1 change: 0 additions & 1 deletion code/client/src/editor/domain/document/input/operations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ export default (fugue: Fugue, communication: Communication): InputDomainOperatio
}

function updateSelection(range: BaseSelection) {
if (!range) return;
communication.emit('cursorChange', range);
}

Expand Down
7 changes: 4 additions & 3 deletions code/client/src/editor/slate/SlateEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ import EditorTitle from '@editor/components/title/EditorTitle';
import useEditor from '@editor/slate/hooks/useEditor';
import useFugue from '@editor/hooks/useFugue';
import useHistory from '@editor/slate/hooks/useHistory';
import useDecorate from '@editor/slate/hooks/useDecorate';
import useCursors from '@editor/slate/hooks/useCursors';
import getEventHandlers from '@editor/slate/handlers/getEventHandlers';
import getFugueHandlers from '@editor/domain/document/fugue/operations';
import useCursors from '@editor/slate/hooks/useCursors';
import './SlateEditor.scss';

// for testing purposes, we need to be able to pass in an editor
type SlateEditorProps = {
communication: Communication;
};
Expand All @@ -27,8 +27,9 @@ function SlateEditor({ communication }: SlateEditorProps) {
const fugue = useFugue();
const editor = useEditor(withHistory, withReact, getMarkdownPlugin(fugue, communication));
const fugueHandlers = getFugueHandlers(fugue);
const { decorate } = useCursors(editor, communication);
const { cursors } = useCursors(communication);
const { renderElement, renderLeaf } = useRenderers();
const decorate = useDecorate(editor, cursors);
const { onInput, onShortcut, onCut, onPaste, onSelectionChange, onFormat } = getEventHandlers(
editor,
fugue,
Expand Down
2 changes: 1 addition & 1 deletion code/client/src/editor/slate/handlers/getEventHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import markdownHandlers from '@editor/slate/handlers/markdown/markdownHandlers';
* @param communication
*/
function getEventHandlers(editor: Editor, fugue: Fugue, communication: Communication) {
// operation handlers
// domain operations
const markdownOperations = markdownDomainOperations(fugue, communication);
const inputOperations = inputDomainOperations(fugue, communication);

Expand Down
3 changes: 1 addition & 2 deletions code/client/src/editor/slate/handlers/input/inputHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,7 @@ export default (editor: Editor, domainOperations: InputDomainOperations, onForma
* Handles cursor selection
*/
function onSelectionChange() {
const range = editor.selection;
domainOperations.updateSelection(range);
domainOperations.updateSelection(editor.selection);
}

return { onInput, onPaste, onCut, onSelectionChange, onShortcut };
Expand Down
36 changes: 3 additions & 33 deletions code/client/src/editor/slate/hooks/useCursors.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { BaseRange, Editor, NodeEntry, Path } from 'slate';
import { Range, Text } from 'slate';
import { Range } from 'slate';
import { useState } from 'react';
import useSocketListeners from '@socket/useSocketListeners';
import { Communication } from '@editor/domain/communication';
Expand All @@ -10,7 +9,7 @@ export type CursorData = {
color: string;
};

export function useCursors(editor: Editor, communication: Communication) {
export function useCursors(communication: Communication) {
const [cursors, setCursors] = useState<CursorData[]>([]);

const onCursorChange = (cursor: CursorData) => {
Expand All @@ -25,36 +24,7 @@ export function useCursors(editor: Editor, communication: Communication) {
cursorChange: onCursorChange,
});

const decorate = ([node, path]: NodeEntry) => {
if (!Text.isText(node)) return [];

const ranges: Range[] = [];
for (const cursor of cursors) {
if (!cursor.range) continue;
const editorPath = Editor.path(editor, path);
const [start, end] = Range.edges(cursor.range);

if (Range.includes(cursor.range, editorPath)) {
const newStart = {
path: start.path,
offset: Path.equals(start.path, editorPath) ? start.offset : 0,
};
const newEnd = {
path: end.path,
offset: Path.equals(end.path, editorPath) ? end.offset : node.text.length,
};
ranges.push({
anchor: newStart,
focus: newEnd,
cursor,
} as BaseRange & { cursor: CursorData });
}
}

return ranges;
};

return { decorate };
return { cursors };
}

export default useCursors;
34 changes: 34 additions & 0 deletions code/client/src/editor/slate/hooks/useDecorate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { CursorData } from '@editor/slate/hooks/useCursors';
import { BaseRange, Editor, NodeEntry, Path, Range, Text } from 'slate';

function useDecorate(editor: Editor, cursors: CursorData[]) {
return ([node, path]: NodeEntry) => {
if (!Text.isText(node)) return [];

const ranges: Range[] = [];
for (const cursor of cursors) {
if (!cursor.range) continue;
const editorPath = Editor.path(editor, path);
const [start, end] = Range.edges(cursor.range);

if (Range.includes(cursor.range, editorPath)) {
const newStart = {
path: start.path,
offset: Path.equals(start.path, editorPath) ? start.offset : 0,
};
const newEnd = {
path: end.path,
offset: Path.equals(end.path, editorPath) ? end.offset : node.text.length,
};
ranges.push({
anchor: newStart,
focus: newEnd,
cursor,
} as BaseRange & { cursor: CursorData });
}
}
return ranges;
};
}

export default useDecorate;
2 changes: 1 addition & 1 deletion code/client/src/editor/slate/hooks/useEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useMemo } from 'react';
import { buildEditor } from '@editor/slate/utils/slate';

function useEditor(...plugins: Array<(editor: Editor) => Editor>): Editor {
return useMemo(() => buildEditor(...plugins), [plugins]);
return useMemo(() => buildEditor(...plugins), []); // eslint-disable-line react-hooks/exhaustive-deps
}

export default useEditor;

0 comments on commit e21a15c

Please sign in to comment.