From 136a56558695b0506269b4584bacc330961f5fc7 Mon Sep 17 00:00:00 2001 From: Aman Harwara Date: Thu, 16 Jan 2025 04:48:32 +0530 Subject: [PATCH] [lexical-yjs] Feature: Allow passing in custom `syncCursorPositions` function to collab hook (#7053) --- .../src/shared/useYjsCollaboration.tsx | 14 +++++++++++--- packages/lexical-yjs/src/SyncCursors.ts | 5 +++++ packages/lexical-yjs/src/SyncEditorStates.ts | 4 +++- packages/lexical-yjs/src/index.ts | 1 + 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/packages/lexical-react/src/shared/useYjsCollaboration.tsx b/packages/lexical-react/src/shared/useYjsCollaboration.tsx index a8f4e49da17..457827756ee 100644 --- a/packages/lexical-react/src/shared/useYjsCollaboration.tsx +++ b/packages/lexical-react/src/shared/useYjsCollaboration.tsx @@ -6,7 +6,7 @@ * */ -import type {Binding, Provider} from '@lexical/yjs'; +import type {Binding, Provider, SyncCursorPositionsFn} from '@lexical/yjs'; import type {LexicalEditor} from 'lexical'; import {mergeRegister} from '@lexical/utils'; @@ -54,6 +54,7 @@ export function useYjsCollaboration( cursorsContainerRef?: CursorsContainerRef, initialEditorState?: InitialEditorStateType, awarenessData?: object, + syncCursorPositionsFn: SyncCursorPositionsFn = syncCursorPositions, ): JSX.Element { const isReloadingDoc = useRef(false); @@ -90,7 +91,7 @@ export function useYjsCollaboration( }; const onAwarenessUpdate = () => { - syncCursorPositions(binding, provider); + syncCursorPositionsFn(binding, provider); }; const onYjsTreeChanges = ( @@ -102,7 +103,13 @@ export function useYjsCollaboration( const origin = transaction.origin; if (origin !== binding) { const isFromUndoManger = origin instanceof UndoManager; - syncYjsChangesToLexical(binding, provider, events, isFromUndoManger); + syncYjsChangesToLexical( + binding, + provider, + events, + isFromUndoManger, + syncCursorPositionsFn, + ); } }; @@ -191,6 +198,7 @@ export function useYjsCollaboration( shouldBootstrap, awarenessData, setDoc, + syncCursorPositionsFn, ]); const cursorsContainer = useMemo(() => { const ref = (element: null | HTMLElement) => { diff --git a/packages/lexical-yjs/src/SyncCursors.ts b/packages/lexical-yjs/src/SyncCursors.ts index 5d21b42c0b2..31cf7010c6d 100644 --- a/packages/lexical-yjs/src/SyncCursors.ts +++ b/packages/lexical-yjs/src/SyncCursors.ts @@ -410,6 +410,11 @@ function getCollabNodeAndOffset( return [null, 0]; } +export type SyncCursorPositionsFn = ( + binding: Binding, + provider: Provider, +) => void; + export function syncCursorPositions( binding: Binding, provider: Provider, diff --git a/packages/lexical-yjs/src/SyncEditorStates.ts b/packages/lexical-yjs/src/SyncEditorStates.ts index beca7904176..c5f87d0c954 100644 --- a/packages/lexical-yjs/src/SyncEditorStates.ts +++ b/packages/lexical-yjs/src/SyncEditorStates.ts @@ -26,6 +26,7 @@ import {CollabTextNode} from './CollabTextNode'; import { $syncLocalCursorPosition, syncCursorPositions, + SyncCursorPositionsFn, syncLexicalSelectionToYjs, } from './SyncCursors'; import { @@ -83,6 +84,7 @@ export function syncYjsChangesToLexical( provider: Provider, events: Array>, isFromUndoManger: boolean, + syncCursorPositionsFn: SyncCursorPositionsFn = syncCursorPositions, ): void { const editor = binding.editor; const currentEditorState = editor._editorState; @@ -129,7 +131,7 @@ export function syncYjsChangesToLexical( }, { onUpdate: () => { - syncCursorPositions(binding, provider); + syncCursorPositionsFn(binding, provider); // If there was a collision on the top level paragraph // we need to re-add a paragraph. To ensure this insertion properly syncs with other clients, // it must be placed outside of the update block above that has tags 'collaboration' or 'historic'. diff --git a/packages/lexical-yjs/src/index.ts b/packages/lexical-yjs/src/index.ts index bed89d65e6a..21ace2cb1bb 100644 --- a/packages/lexical-yjs/src/index.ts +++ b/packages/lexical-yjs/src/index.ts @@ -114,6 +114,7 @@ export function setLocalStateFocus( export { getAnchorAndFocusCollabNodesForUserState, syncCursorPositions, + type SyncCursorPositionsFn, } from './SyncCursors'; export { syncLexicalUpdateToYjs,