@lexical/react
Version:
This package provides Lexical components and hooks for React applications.
10 lines (8 loc) • 5.24 kB
JavaScript
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
;var e=require("@lexical/react/LexicalCollaborationContext"),t=require("@lexical/react/LexicalComposerContext"),o=require("@lexical/yjs"),r=require("react"),n=require("@lexical/utils"),s=require("lexical"),a=require("react-dom"),c=require("yjs"),i=require("react/jsx-runtime");function u(e){var t=Object.create(null);if(e)for(var o in e)t[o]=e[o];return t.default=e,t}var l=u(r);function d(e,t,n,u,l,d,f,C,m,g,p,E,R=o.syncCursorPositions){const O=r.useRef(!1),M=r.useCallback((()=>n.connect()),[n]),_=r.useCallback((()=>{try{n.disconnect()}catch(e){}}),[n]);r.useEffect((()=>{const{root:r}=C,{awareness:a}=n,i=({status:t})=>{e.dispatchCommand(o.CONNECTED_COMMAND,"connected"===t)},g=t=>{f&&t&&r.isEmpty()&&0===r._xmlText._length&&!1===O.current&&function(e,t){e.update((()=>{const o=s.$getRoot();if(o.isEmpty())if(t)switch(typeof t){case"string":{const o=e.parseEditorState(t);e.setEditorState(o,{tag:s.HISTORY_MERGE_TAG});break}case"object":e.setEditorState(t,{tag:s.HISTORY_MERGE_TAG});break;case"function":e.update((()=>{s.$getRoot().isEmpty()&&t(e)}),{tag:s.HISTORY_MERGE_TAG})}else{const t=s.$createParagraphNode();o.append(t);const{activeElement:r}=document;(null!==s.$getSelection()||null!==r&&r===e.getRootElement())&&t.select()}}),{tag:s.HISTORY_MERGE_TAG})}(e,p),O.current=!1},D=()=>{R(C,n)},T=(e,t)=>{const r=t.origin;if(r!==C){const t=r instanceof c.UndoManager;o.syncYjsChangesToLexical(C,n,e,t,R)}};o.initLocalState(n,l,d,document.activeElement===e.getRootElement(),E||{});const y=o=>{!function(e,t){if(e.update((()=>{const e=s.$getRoot();e.clear(),e.select()}),{tag:s.SKIP_COLLAB_TAG}),null==t.cursors)return;const o=t.cursors;if(null==o)return;const r=t.cursorsContainer;if(null==r)return;const n=Array.from(o.values());for(let e=0;e<n.length;e++){const t=n[e].selection;if(t&&null!=t.selections){const o=t.selections;for(let t=0;t<o.length;t++)r.removeChild(o[e])}}}(e,C),m(o),u.set(t,o),O.current=!0};n.on("reload",y),n.on("status",i),n.on("sync",g),a.on("update",D),r.getSharedType().observeDeep(T);const S=e.registerUpdateListener((({prevEditorState:e,editorState:t,dirtyLeaves:r,dirtyElements:a,normalizedNodes:c,tags:i})=>{!1===i.has(s.SKIP_COLLAB_TAG)&&o.syncLexicalUpdateToYjs(C,n,e,t,a,r,c,i)})),A=M();return()=>{!1===O.current&&(A?A.then(_):_()),n.off("sync",g),n.off("status",i),n.off("reload",y),a.off("update",D),r.getSharedType().unobserveDeep(T),u.delete(t),S()}}),[C,d,M,_,u,e,t,p,l,n,f,E,m,R]);const D=r.useMemo((()=>a.createPortal(i.jsx("div",{ref:e=>{C.cursorsContainer=e}}),g&&g.current||document.body)),[C,g]);return r.useEffect((()=>e.registerCommand(o.TOGGLE_CONNECT_COMMAND,(e=>(e?(console.log("Collaboration connected!"),M()):(console.log("Collaboration disconnected!"),_()),!0)),s.COMMAND_PRIORITY_EDITOR)),[M,_,e]),D}function f(e,t){const a=r.useMemo((()=>o.createUndoManager(t,t.root.getSharedType())),[t]);r.useEffect((()=>n.mergeRegister(e.registerCommand(s.UNDO_COMMAND,(()=>(a.undo(),!0)),s.COMMAND_PRIORITY_EDITOR),e.registerCommand(s.REDO_COMMAND,(()=>(a.redo(),!0)),s.COMMAND_PRIORITY_EDITOR))));const c=r.useCallback((()=>{a.clear()}),[a]);return l.useEffect((()=>{const t=()=>{e.dispatchCommand(s.CAN_UNDO_COMMAND,a.undoStack.length>0),e.dispatchCommand(s.CAN_REDO_COMMAND,a.redoStack.length>0)};return a.on("stack-item-added",t),a.on("stack-item-popped",t),a.on("stack-cleared",t),()=>{a.off("stack-item-added",t),a.off("stack-item-popped",t),a.off("stack-cleared",t)}}),[e,a]),c}function C({editor:e,id:t,provider:a,yjsDocMap:c,name:i,color:u,shouldBootstrap:l,cursorsContainerRef:C,initialEditorState:m,awarenessData:g,collabContext:p,binding:E,setDoc:R,syncCursorPositionsFn:O}){const M=d(e,t,a,c,i,u,l,E,R,C,m,g,O);return p.clientID=E.clientID,f(e,E),function(e,t,a,c,i){r.useEffect((()=>n.mergeRegister(e.registerCommand(s.FOCUS_COMMAND,(()=>(o.setLocalStateFocus(t,a,c,!0,i||{}),!1)),s.COMMAND_PRIORITY_EDITOR),e.registerCommand(s.BLUR_COMMAND,(()=>(o.setLocalStateFocus(t,a,c,!1,i||{}),!1)),s.COMMAND_PRIORITY_EDITOR))),[c,e,a,t,i])}(e,a,i,u,g),M}exports.CollaborationPlugin=function({id:n,providerFactory:s,shouldBootstrap:a,username:c,cursorColor:u,cursorsContainerRef:l,initialEditorState:d,excludedProperties:f,awarenessData:m,syncCursorPositionsFn:g}){const p=r.useRef(!1),E=r.useRef(!1),R=e.useCollaborationContext(c,u),{yjsDocMap:O,name:M,color:_}=R,[D]=t.useLexicalComposerContext();r.useEffect((()=>(R.isCollabActive=!0,()=>{null==D._parentEditor&&(R.isCollabActive=!1)})),[R,D]);const[T,y]=r.useState(),[S,A]=r.useState();r.useEffect((()=>{if(E.current)return;E.current=!0;const e=s(n,O);return y(e),A(O.get(n)),()=>{e.disconnect()}}),[n,s,O]);const[x,I]=r.useState();return r.useEffect((()=>{if(!T)return;if(p.current)return;p.current=!0;const e=o.createBinding(D,T,n,S||O.get(n),O,f);return I(e),()=>{e.root.destroy(e)}}),[D,T,n,O,S,f]),T&&x?i.jsx(C,{awarenessData:m,binding:x,collabContext:R,color:_,cursorsContainerRef:l,editor:D,id:n,initialEditorState:d,name:M,provider:T,setDoc:A,shouldBootstrap:a,yjsDocMap:O,syncCursorPositionsFn:g}):i.jsx(i.Fragment,{})};