From d988934781bffced2c6614563530424d2eba9b8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=A1vio=20Carvalho?= Date: Wed, 31 Jul 2024 15:40:06 +0100 Subject: [PATCH 1/2] Allow custom yjs xml text --- .../src/LexicalCollaborationPlugin.tsx | 18 ++++++------ .../lexical-website/docs/collaboration/faq.md | 2 +- packages/lexical-yjs/flow/LexicalYjs.js.flow | 10 ++++--- packages/lexical-yjs/src/Bindings.ts | 28 ++++++++++++------- 4 files changed, 35 insertions(+), 23 deletions(-) diff --git a/packages/lexical-react/src/LexicalCollaborationPlugin.tsx b/packages/lexical-react/src/LexicalCollaborationPlugin.tsx index b3018c1af5f..3836046e762 100644 --- a/packages/lexical-react/src/LexicalCollaborationPlugin.tsx +++ b/packages/lexical-react/src/LexicalCollaborationPlugin.tsx @@ -6,7 +6,7 @@ * */ -import type {Doc} from 'yjs'; +import type {Doc, XmlText} from 'yjs'; import { type CollaborationContextType, @@ -45,6 +45,7 @@ type Props = { excludedProperties?: ExcludedProperties; // `awarenessData` parameter allows arbitrary data to be added to the awareness. awarenessData?: object; + getXmlText?: (doc: Doc) => XmlText; }; export function CollaborationPlugin({ @@ -57,6 +58,7 @@ export function CollaborationPlugin({ initialEditorState, excludedProperties, awarenessData, + getXmlText, }: Props): JSX.Element { const isBindingInitialized = useRef(false); const isProviderInitialized = useRef(false); @@ -110,20 +112,20 @@ export function CollaborationPlugin({ isBindingInitialized.current = true; - const newBinding = createBinding( + const newBinding = createBinding({ + doc: doc || yjsDocMap.get(id), + docMap: yjsDocMap, editor, - provider, - id, - doc || yjsDocMap.get(id), - yjsDocMap, excludedProperties, - ); + getXmlText, + id, + }); setBinding(newBinding); return () => { newBinding.root.destroy(newBinding); }; - }, [editor, provider, id, yjsDocMap, doc, excludedProperties]); + }, [editor, provider, id, yjsDocMap, doc, excludedProperties, getXmlText]); if (!provider || !binding) { return <>; diff --git a/packages/lexical-website/docs/collaboration/faq.md b/packages/lexical-website/docs/collaboration/faq.md index eaa36ff23cd..fe2ac039afb 100644 --- a/packages/lexical-website/docs/collaboration/faq.md +++ b/packages/lexical-website/docs/collaboration/faq.md @@ -83,7 +83,7 @@ It's achievable by leveraging headless Lexical and no-op provider for Yjs: const doc = new Doc(); const docMap = new Map([[id, doc]]); const provider = createNoOpProvider(); - const binding = createBinding(editor, provider, id, doc, docMap); + const binding = createBinding({ editor, id, doc, docMap }); const unsubscribe = registerCollaborationListeners(editor, provider, binding); diff --git a/packages/lexical-yjs/flow/LexicalYjs.js.flow b/packages/lexical-yjs/flow/LexicalYjs.js.flow index 6258a1fce70..843155f1600 100644 --- a/packages/lexical-yjs/flow/LexicalYjs.js.flow +++ b/packages/lexical-yjs/flow/LexicalYjs.js.flow @@ -339,13 +339,15 @@ declare export function setLocalStateFocus( focusing: boolean, ): void; -declare export function createBinding( +declare export type BindingOptions = { editor: LexicalEditor, - provider: Provider, id: string, + getXmlText: (ydoc: Doc) => XmlText, doc: ?Doc, - docMap: Map, -): Binding; + docMap: Map +} + +declare export function createBinding(options: BindingOptions): Binding; declare export function syncCursorPositions( binding: Binding, diff --git a/packages/lexical-yjs/src/Bindings.ts b/packages/lexical-yjs/src/Bindings.ts index 5c9bdb8f9e0..91146f18c9f 100644 --- a/packages/lexical-yjs/src/Bindings.ts +++ b/packages/lexical-yjs/src/Bindings.ts @@ -18,7 +18,6 @@ import {Klass, LexicalNode} from 'lexical'; import invariant from 'shared/invariant'; import {XmlText} from 'yjs'; -import {Provider} from '.'; import {$createCollabElementNode} from './CollabElementNode'; export type ClientID = number; @@ -43,19 +42,28 @@ export type Binding = { }; export type ExcludedProperties = Map, Set>; -export function createBinding( - editor: LexicalEditor, - provider: Provider, - id: string, - doc: Doc | null | undefined, - docMap: Map, - excludedProperties?: ExcludedProperties, -): Binding { +export type CreateBindingOptions = { + editor: LexicalEditor; + id: string; + getXmlText?: (ydoc: Doc) => XmlText; + doc: Doc | null | undefined; + docMap: Map; + excludedProperties?: ExcludedProperties; +}; + +export function createBinding({ + editor, + id, + getXmlText = (ydoc) => ydoc.get('root', XmlText) as XmlText, + doc, + docMap, + excludedProperties, +}: CreateBindingOptions): Binding { invariant( doc !== undefined && doc !== null, 'createBinding: doc is null or undefined', ); - const rootXmlText = doc.get('root', XmlText) as XmlText; + const rootXmlText = getXmlText(doc); const root: CollabElementNode = $createCollabElementNode( rootXmlText, null, From 0ffa46229f7b3a79758a5a7c4c4a3a462c679045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=A1vio=20Carvalho?= Date: Thu, 1 Aug 2024 09:19:16 +0100 Subject: [PATCH 2/2] Update api --- .../src/LexicalCollaborationPlugin.tsx | 11 ++++---- .../lexical-website/docs/collaboration/faq.md | 2 +- packages/lexical-yjs/flow/LexicalYjs.js.flow | 11 ++++---- packages/lexical-yjs/src/Bindings.ts | 27 +++++++------------ 4 files changed, 22 insertions(+), 29 deletions(-) diff --git a/packages/lexical-react/src/LexicalCollaborationPlugin.tsx b/packages/lexical-react/src/LexicalCollaborationPlugin.tsx index 3836046e762..e69efa7dea1 100644 --- a/packages/lexical-react/src/LexicalCollaborationPlugin.tsx +++ b/packages/lexical-react/src/LexicalCollaborationPlugin.tsx @@ -112,14 +112,15 @@ export function CollaborationPlugin({ isBindingInitialized.current = true; - const newBinding = createBinding({ - doc: doc || yjsDocMap.get(id), - docMap: yjsDocMap, + const newBinding = createBinding( editor, + provider, + id, + doc || yjsDocMap.get(id), + yjsDocMap, excludedProperties, getXmlText, - id, - }); + ); setBinding(newBinding); return () => { diff --git a/packages/lexical-website/docs/collaboration/faq.md b/packages/lexical-website/docs/collaboration/faq.md index fe2ac039afb..eaa36ff23cd 100644 --- a/packages/lexical-website/docs/collaboration/faq.md +++ b/packages/lexical-website/docs/collaboration/faq.md @@ -83,7 +83,7 @@ It's achievable by leveraging headless Lexical and no-op provider for Yjs: const doc = new Doc(); const docMap = new Map([[id, doc]]); const provider = createNoOpProvider(); - const binding = createBinding({ editor, id, doc, docMap }); + const binding = createBinding(editor, provider, id, doc, docMap); const unsubscribe = registerCollaborationListeners(editor, provider, binding); diff --git a/packages/lexical-yjs/flow/LexicalYjs.js.flow b/packages/lexical-yjs/flow/LexicalYjs.js.flow index 843155f1600..019218f3c1c 100644 --- a/packages/lexical-yjs/flow/LexicalYjs.js.flow +++ b/packages/lexical-yjs/flow/LexicalYjs.js.flow @@ -339,15 +339,14 @@ declare export function setLocalStateFocus( focusing: boolean, ): void; -declare export type BindingOptions = { +declare export function createBinding( editor: LexicalEditor, + provider: Provider, id: string, - getXmlText: (ydoc: Doc) => XmlText, doc: ?Doc, - docMap: Map -} - -declare export function createBinding(options: BindingOptions): Binding; + docMap: Map, + getXmlText: ?(ydoc: Doc) => XmlText +): Binding; declare export function syncCursorPositions( binding: Binding, diff --git a/packages/lexical-yjs/src/Bindings.ts b/packages/lexical-yjs/src/Bindings.ts index 91146f18c9f..3fb4f5cdae7 100644 --- a/packages/lexical-yjs/src/Bindings.ts +++ b/packages/lexical-yjs/src/Bindings.ts @@ -18,6 +18,7 @@ import {Klass, LexicalNode} from 'lexical'; import invariant from 'shared/invariant'; import {XmlText} from 'yjs'; +import {Provider} from '.'; import {$createCollabElementNode} from './CollabElementNode'; export type ClientID = number; @@ -42,23 +43,15 @@ export type Binding = { }; export type ExcludedProperties = Map, Set>; -export type CreateBindingOptions = { - editor: LexicalEditor; - id: string; - getXmlText?: (ydoc: Doc) => XmlText; - doc: Doc | null | undefined; - docMap: Map; - excludedProperties?: ExcludedProperties; -}; - -export function createBinding({ - editor, - id, - getXmlText = (ydoc) => ydoc.get('root', XmlText) as XmlText, - doc, - docMap, - excludedProperties, -}: CreateBindingOptions): Binding { +export function createBinding( + editor: LexicalEditor, + provider: Provider, + id: string, + doc: Doc | null | undefined, + docMap: Map, + excludedProperties?: ExcludedProperties, + getXmlText = (ydoc: Doc) => ydoc.get('root', XmlText) as XmlText, +): Binding { invariant( doc !== undefined && doc !== null, 'createBinding: doc is null or undefined',