UNPKG

@lewiiiis/lexical-yjs

Version:

The library provides Yjs editor bindings for Lexical.

47 lines (46 loc) 17.5 kB
/** * 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. */ 'use strict';var r=require("@lewiiiis/lexical"),v=require("yjs"),y=require("@lewiiiis/lexical-selection"),A=require("@lewiiiis/lexical-offset"); class B{constructor(a,b){this._key="";this._map=a;this._parent=b;this._type="linebreak"}getNode(){let a=r.$getNodeByKey(this._key);return r.$isLineBreakNode(a)?a:null}getKey(){return this._key}getSharedType(){return this._map}getType(){return this._type}getSize(){return 1}getOffset(){return this._parent.getChildOffset(this)}destroy(a){a.collabNodeMap.delete(this._key)}}function C(a,b){b=new B(a,b);return a._collabNode=b} class D{constructor(a,b,c,d){this._key="";this._map=a;this._parent=c;this._text=b;this._type=d;this._normalized=!1}getPrevNode(a){if(null===a)return null;a=a.get(this._key);return r.$isTextNode(a)?a:null}getNode(){let a=r.$getNodeByKey(this._key);return r.$isTextNode(a)?a:null}getSharedType(){return this._map}getType(){return this._type}getKey(){return this._key}getSize(){return this._text.length+(this._normalized?0:1)}getOffset(){return this._parent.getChildOffset(this)}spliceText(a,b,c){let d=this._parent._xmlText; a=this.getOffset()+1+a;0!==b&&d.delete(a,b);""!==c&&d.insert(a,c)}syncPropertiesAndTextFromLexical(a,b,c){var d=this.getPrevNode(c);c=b.__text;E(a,this._map,d,b);if(null!==d&&(a=d.__text,a!==c)){d=b.__key;b=a;var e=r.$getSelection();a=c.length;r.$isRangeSelection(e)&&e.isCollapsed()&&(e=e.anchor,e.key===d&&(a=e.offset));d=b.length;let f=c.length,h=e=0;for(;e<d&&e<f&&b[e]===c[e]&&e<a;)e++;for(;h+e<d&&h+e<f&&b[d-h-1]===c[f-h-1];)h++;for(;h+e<d&&h+e<f&&b[e]===c[e];)e++;b=e;a=c.slice(e,f-h);d=d-e-h;this.spliceText(b, d,a);this._text=c}}syncPropertiesAndTextFromYjs(a,b){let c=this.getNode();if(null===c)throw Error("Should never happen");F(a,this._map,c,b);a=this._text;c.__text!==a&&(c.getWritable().__text=a)}destroy(a){a.collabNodeMap.delete(this._key)}}function G(a,b,c,d){b=new D(a,b,c,d);return a._collabNode=b}let H=new Set(["__key","__children","__parent","__cachedText","__text"]);function I(a){a=r.$getNodeByKey(a);if(null===a)throw Error("Should never happen");return a} function J(a,b,c){let d=b.__type;if(r.$isElementNode(b)){var e=new v.XmlText;c=K(e,c,d);c.syncPropertiesFromLexical(a,b,null);c.syncChildrenFromLexical(a,b,null,null,null)}else if(r.$isTextNode(b))e=new v.Map,c=G(e,b.__text,c,d),c.syncPropertiesAndTextFromLexical(a,b,null);else if(r.$isLineBreakNode(b))a=new v.Map,a.set("__type","linebreak"),c=C(a,c);else if(r.$isDecoratorNode(b))e=new v.XmlElement,c=L(e,c,d),c.syncPropertiesFromLexical(a,b,null);else throw Error("Should never happen");c._key=b.__key; return c} function M(a,b,c){let d=b._collabNode;if(void 0===d){var e=a.editor._nodes;let f=b instanceof v.Map?b.get("__type"):b.getAttribute("__type");if(null==f)throw Error("Should never happen");if(void 0===e.get(f))throw Error("Should never happen");e=b.parent;a=void 0===c&&null!==e?M(a,e):c||null;if(!(a instanceof N))throw Error("Should never happen");if(b instanceof v.XmlText)return K(b,a,f);if(b instanceof v.Map){if(null===a)throw Error("Should never happen");return"linebreak"===f?C(b,a):G(b,"",a,f)}if(b instanceof v.XmlElement)return L(b,a,f)}return d}function F(a,b,c,d){d=null===d?b instanceof v.Map?Array.from(b.keys()):Object.keys(b.getAttributes()):Array.from(d);let e;for(let h=0;h<d.length;h++){let g=d[h];if(H.has(g))continue;var f=c[g];let k=b instanceof v.Map?b.get(g):b.getAttribute(g);if(f!==k){if(k instanceof v.Doc){let l=a.docMap;f instanceof v.Doc&&l.delete(f.guid);f=r.createEditor();let n=k.guid;f._key=n;l.set(n,k);k=f}void 0===e&&(e=c.getWritable());e[g]=k}}} function E(a,b,c,d){var e=d.__type,f=a.nodeProperties;let h=f.get(e);void 0===h&&(h=Object.keys(d).filter(k=>!H.has(k)),f.set(e,h));e=a.editor.constructor;for(f=0;f<h.length;f++){let k=h[f];var g=null===c?void 0:c[k];let l=d[k];if(g!==l){if(l instanceof e){let n=a.docMap,q;g instanceof e&&(g=g._key,q=n.get(g),n.delete(g));g=q||new v.Doc;let t=g.guid;l._key=t;n.set(t,g);l=g;a.editor.update(()=>{d.markDirty()})}b instanceof v.Map?b.set(k,l):b.setAttribute(k,l)}}} function O(a,b,c){let d=0,e=0,f=a._children,h=f.length;for(;e<h;e++){a=f[e];let g=d,k=a.getSize();d+=k;if((c?d>=b:d>b)&&a instanceof D)return c=b-g-1,0>c&&(c=0),{length:d-b,node:a,nodeIndex:e,offset:c};if(d>b)return{length:0,node:a,nodeIndex:e,offset:g};if(e===h-1)return{length:0,node:null,nodeIndex:e+1,offset:g+1}}return{length:0,node:null,nodeIndex:0,offset:0}} function P(a){let b=a.anchor;a=a.focus;let c=!1;try{let d=b.getNode(),e=a.getNode();if(!d.isAttached()||!e.isAttached()||r.$isTextNode(d)&&b.offset>d.getTextContentSize()||r.$isTextNode(e)&&a.offset>e.getTextContentSize())c=!0}catch(d){c=!0}return c}function ea(a,b){a.doc.transact(b,a)} class Q{constructor(a,b,c){this._key="";this._xmlElem=a;this._parent=b;this._type=c;this._unobservers=new Set}getPrevNode(a){if(null===a)return null;a=a.get(this._key);return r.$isDecoratorNode(a)?a:null}getNode(){let a=r.$getNodeByKey(this._key);return r.$isDecoratorNode(a)?a:null}getSharedType(){return this._xmlElem}getType(){return this._type}getKey(){return this._key}getSize(){return 1}getOffset(){return this._parent.getChildOffset(this)}syncPropertiesFromLexical(a,b,c){c=this.getPrevNode(c); E(a,this._xmlElem,c,b)}syncPropertiesFromYjs(a,b){let c=this.getNode();if(null===c)throw Error("Should never happen");F(a,this._xmlElem,c,b)}destroy(a){a.collabNodeMap.delete(this._key);this._unobservers.forEach(b=>b());this._unobservers.clear()}}function L(a,b,c){b=new Q(a,b,c);return a._collabNode=b} class N{constructor(a,b,c){this._key="";this._children=[];this._xmlText=a;this._type=c;this._parent=b}getPrevNode(a){if(null===a)return null;a=a.get(this._key);return r.$isElementNode(a)?a:null}getNode(){let a=r.$getNodeByKey(this._key);return r.$isElementNode(a)?a:null}getSharedType(){return this._xmlText}getType(){return this._type}getKey(){return this._key}isEmpty(){return 0===this._children.length}getSize(){return 1}getOffset(){let a=this._parent;if(null===a)throw Error("Should never happen"); return a.getChildOffset(this)}syncPropertiesFromYjs(a,b){let c=this.getNode();if(null===c)throw this.getNode(),Error("Should never happen");F(a,this._xmlText,c,b)}applyChildrenYjsDelta(a,b){let c=this._children,d=0;for(let n=0;n<b.length;n++){var e=b[n],f=e.insert,h=e.delete;if(null!=e.retain)d+=e.retain;else if("number"===typeof h)for(f=h;0<f;){let {node:q,nodeIndex:t,offset:m,length:p}=O(this,d,!1);if(q instanceof N||q instanceof B||q instanceof Q)c.splice(t,1),--f;else if(q instanceof D){e=Math.min(f, p);h=0!==t?c[t-1]:null;var g=q.getSize();if(0===m&&1===e&&0<t&&h instanceof D&&p===g&&0===Array.from(q._map.keys()).length)h._text+=q._text,c.splice(t,1);else if(0===m&&e===g)c.splice(t,1);else{h=q;g=q._text;var k=m,l=e;g=g.slice(0,k)+""+g.slice(k+l);h._text=g}f-=e}else break}else if(null!=f)if("string"===typeof f){let {node:q,offset:t}=O(this,d,!0);q instanceof D?(e=q,h=q._text,g=t,k=f,h=h.slice(0,g)+k+h.slice(g+0),e._text=h):this._xmlText.delete(t,f.length);d+=f.length}else e=f,{nodeIndex:f}=O(this, d,!1),e=M(a,e,this),c.splice(f,0,e),d+=1;else throw Error("Unexpected delta format");}}syncChildrenFromYjs(a){var b=this.getNode();if(null===b)throw this.getNode(),Error("Should never happen");var c=b.__key;let d=b.__children;var e=[];let f=d.length,h=this._children,g=h.length,k=a.collabNodeMap,l=new Set,n,q;g!==f&&(q=R(b,q,e));let t=0;for(let z=0;z<g;z++){var m=d[t];let x=h[z];var p=x.getNode(),u=x._key;if(null!==p&&m===u){p=r.$isTextNode(p);l.add(m);if(p)if(x._key=m,x instanceof N)p=x._xmlText, x.syncPropertiesFromYjs(a,null),x.applyChildrenYjsDelta(a,p.toDelta()),x.syncChildrenFromYjs(a);else if(x instanceof D)x.syncPropertiesAndTextFromYjs(a,null);else if(x instanceof Q)x.syncPropertiesFromYjs(a,null);else if(!(x instanceof B))throw Error("Should never happen");e[z]=m;t++}else{if(void 0===n)for(n=new Set,u=0;u<g;u++){var w=h[u]._key;""!==w&&n.add(w)}if(null===p||void 0===m||n.has(m)){q=R(b,q,e);m=a;p=x;u=c;w=p.getType();w=m.editor._nodes.get(w);if(void 0===w)throw Error("createLexicalNode failed"); w=new w.klass;w.__parent=u;p._key=w.__key;p instanceof N?(u=p._xmlText,p.syncPropertiesFromYjs(m,null),p.applyChildrenYjsDelta(m,u.toDelta()),p.syncChildrenFromYjs(m)):p instanceof D?p.syncPropertiesAndTextFromYjs(m,null):p instanceof Q&&p.syncPropertiesFromYjs(m,null);m.collabNodeMap.set(w.__key,p);m=w.__key;k.set(m,x);e[z]=m}else z--,t++}}for(b=0;b<f;b++)e=d[b],l.has(e)||(c=I(e).getWritable(),e=a.collabNodeMap.get(e),void 0!==e&&e.destroy(a),c.__parent=null)}syncPropertiesFromLexical(a,b,c){E(a, this._xmlText,this.getPrevNode(c),b)}_syncChildFromLexical(a,b,c,d,e,f){b=this._children[b];c=I(c);b instanceof N&&r.$isElementNode(c)?(b.syncPropertiesFromLexical(a,c,d),b.syncChildrenFromLexical(a,c,d,e,f)):b instanceof D&&r.$isTextNode(c)?b.syncPropertiesAndTextFromLexical(a,c,d):b instanceof Q&&r.$isDecoratorNode(c)&&b.syncPropertiesFromLexical(a,c,d)}syncChildrenFromLexical(a,b,c,d,e){var f=this.getPrevNode(c);let h=null===f?[]:f.__children;f=b.__children;let g=h.length-1,k=f.length-1,l=a.collabNodeMap, n,q,t=0;for(b=0;t<=g&&b<=k;){var m=h[t];let u=f[b];if(m===u)this._syncChildFromLexical(a,b,u,c,d,e),t++,b++;else{void 0===n&&(n=new Set(h));void 0===q&&(q=new Set(f));var p=q.has(m);m=n.has(u);p?(p=I(u),p=J(a,p,this),l.set(u,p),m?(this.splice(a,b,1,p),t++):this.splice(a,b,0,p),b++):(this.splice(a,b,1),t++)}}c=t>g;d=b>k;if(c&&!d)for(;b<=k;++b)c=f[b],d=I(c),d=J(a,d,this),this.append(d),l.set(c,d);else if(d&&!c)for(f=this._children.length-1;f>=b;f--)this.splice(a,f,1)}append(a){let b=this._xmlText;var c= this._children;c=c[c.length-1];c=void 0!==c?c.getOffset()+c.getSize():0;if(a instanceof N)b.insertEmbed(c,a._xmlText);else if(a instanceof D){let d=a._map;null===d.parent&&b.insertEmbed(c,d);b.insert(c+1,a._text)}else a instanceof B?b.insertEmbed(c,a._map):a instanceof Q&&b.insertEmbed(c,a._xmlElem);this._children.push(a)}splice(a,b,c,d){let e=this._children;var f=e[b];if(void 0===f)if(void 0!==d)this.append(d);else throw Error("Should never happen");else{var h=f.getOffset();if(-1===h)throw Error("Should never happen"); var g=this._xmlText;0!==c&&g.delete(h,f.getSize());d instanceof N?g.insertEmbed(h,d._xmlText):d instanceof D?(f=d._map,null===f.parent&&g.insertEmbed(h,f),g.insert(h+1,d._text)):d instanceof B?g.insertEmbed(h,d._map):d instanceof Q&&g.insertEmbed(h,d._xmlElem);if(0!==c)for(h=e.slice(b,b+c),g=0;g<h.length;g++)h[g].destroy(a);void 0!==d?e.splice(b,c,d):e.splice(b,c)}}getChildOffset(a){let b=0,c=this._children;for(let d=0;d<c.length;d++){let e=c[d];if(e===a)return b;b+=e.getSize()}return-1}destroy(a){let b= a.collabNodeMap,c=this._children;for(let d=0;d<c.length;d++)c[d].destroy(a);b.delete(this._key)}}function R(a,b,c){return void 0===b?(a=a.getWritable(),a.__children=c,a):b}function K(a,b,c){b=new N(a,b,c);return a._collabNode=b}function S(a,b){b=b.collabNodeMap.get(a.key);if(void 0===b)return null;a=a.offset;let c=b.getSharedType();if(b instanceof D){c=b._parent._xmlText;b=b.getOffset();if(-1===b)return null;a=b+1+a}return v.createRelativePositionFromTypeIndex(c,a)} function T(a,b){if(null==a){if(null!=b)return!0}else if(null==b||!v.compareRelativePositions(a,b))return!0;return!1}function U(a,b){a=a.cursorsContainer;if(null!==a){b=b.selections;let c=b.length;for(let d=0;d<c;d++)a.removeChild(b[d])}} function V(a,b){var c=b.awareness.getLocalState();if(null!==c&&(b=c.anchorPos,c=c.focusPos,null!==b&&null!==c&&(b=v.createAbsolutePositionFromRelativePosition(b,a.doc),a=v.createAbsolutePositionFromRelativePosition(c,a.doc),null!==b&&null!==a))){let [e,f]=W(b.type,b.index),[h,g]=W(a.type,a.index);if(null!==e&&null!==h){let k=e.getKey();a=h.getKey();b=r.$getSelection();if(r.$isRangeSelection(b)){var d=b.anchor;c=b.focus;if(d.key!==k||d.offset!==f)d=r.$getNodeByKey(k),b.anchor.set(k,f,r.$isElementNode(d)? "element":"text");if(c.key!==a||c.offset!==g)c=r.$getNodeByKey(a),b.focus.set(a,g,r.$isElementNode(c)?"element":"text")}}}}function W(a,b){a=a._collabNode;if(void 0===a)return[null,0];if(a instanceof N){let {node:c,offset:d}=O(a,b,!0);return null===c?[a,0]:[c,d]}return[null,0]} function X(a,b){var c=Array.from(b.awareness.getStates()),d=a.clientID;b=a.cursors;var e=a.editor._editorState._nodeMap;let f=new Set;for(var h=0;h<c.length;h++){let [z,x]=c[h];if(z!==d){f.add(z);let {anchorPos:Y,focusPos:Z,name:ha,color:ia,focusing:ja}=x;var g=null,k=b.get(z);void 0===k&&(k={color:ia,name:ha,selection:null},b.set(z,k));if(null!==Y&&null!==Z&&ja){var l=v.createAbsolutePositionFromRelativePosition(Y,a.doc),n=v.createAbsolutePositionFromRelativePosition(Z,a.doc);if(null!==l&&null!== n){let [aa,ba]=W(l.type,l.index),[ca,da]=W(n.type,n.index);if(null!==aa&&null!==ca){n=aa.getKey();var q=ca.getKey();g=k.selection;if(null===g){l=k;g=n;n=ba;var t=da,m=l.color,p=document.createElement("span");p.style.cssText=`position:absolute;top:0;bottom:0;right:-1px;width:1px;background-color:rgb(${m});z-index:10;`;var u=document.createElement("span");u.textContent=l.name;u.style.cssText=`position:absolute;left:-2px;top:-16px;background-color:rgb(${m});color:#fff;line-height:12px;height:12px;font-size:12px;padding:2px;font-family:Arial;font-weight:bold;white-space:nowrap;`; p.appendChild(u);g={anchor:{key:g,offset:n},caret:p,color:m,focus:{key:q,offset:t},name:u,selections:[]}}else l=g.anchor,t=g.focus,l.key=n,l.offset=ba,t.key=q,t.offset=da}}}l=a;n=k;m=g;t=e;q=l.editor;g=q.getRootElement();k=l.cursorsContainer;if(null!==k&&null!==g)if(g=n.selection,null===m)null!==g&&(n.selection=null,U(l,g));else{n.selection=m;g=m.caret;n=m.color;l=m.selections;p=m.anchor;m=m.focus;var w=m.key;u=t.get(p.key);t=t.get(w);if(null!=u&&null!=t&&(m=y.createDOMRange(q,u,p.offset,t,m.offset), null!==m)){t=l.length;m=y.createRectsFromDOMRange(q,m);q=m.length;for(p=0;p<q;p++)u=m[p],w=l[p],void 0===w&&(w=document.createElement("span"),l[p]=w,k.appendChild(w)),w.style.cssText=`position:absolute;top:${u.top}px;left:${u.left}px;height:${u.height}px;width:${u.width}px;background-color:rgba(${n}, 0.3);pointer-events:none;z-index:5;`,p===q-1&&g.parentNode!==w&&w.appendChild(g);for(g=t-1;g>=q;g--)k.removeChild(l[g]),l.pop()}}}}c=Array.from(b.keys());for(d=0;d<c.length;d++)e=c[d],f.has(e)||(h=b.get(e), void 0!==h&&(h=h.selection,null!==h&&U(a,h),b.delete(e)))}function fa(a,b,c,d){b=b.awareness;var e=b.getLocalState();if(null!==e){var {anchorPos:f,focusPos:h,name:g,color:k,focusing:l}=e,n=e=null;if(null!==d&&(null===f||d.is(c))||null!==c)r.$isRangeSelection(d)&&(e=S(d.anchor,a),n=S(d.focus,a)),(T(f,e)||T(h,n))&&b.setLocalState({anchorPos:e,color:k,focusPos:n,focusing:l,name:g})}}let ka=r.createCommand(),la=r.createCommand();exports.CONNECTED_COMMAND=ka;exports.TOGGLE_CONNECT_COMMAND=la; exports.createBinding=function(a,b,c,d,e){if(void 0===d||null===d)throw Error("Should never happen");b=d.get("root",v.XmlText);b=K(b,null,"root");b._key="root";return{clientID:d.clientID,collabNodeMap:new Map,cursors:new Map,cursorsContainer:null,doc:d,docMap:e,editor:a,id:c,nodeProperties:new Map,root:b}};exports.createUndoManager=function(a,b){return new v.UndoManager(b,{trackedOrigins:new Set([a,null])})}; exports.initLocalState=function(a,b,c,d){a.awareness.setLocalState({anchorPos:null,color:c,focusPos:null,focusing:d,name:b})};exports.setLocalStateFocus=function(a,b,c,d){({awareness:a}=a);let e=a.getLocalState();null===e&&(e={anchorPos:null,color:c,focusPos:null,focusing:d,name:b});e.focusing=d;a.setLocalState(e)};exports.syncCursorPositions=X; exports.syncLexicalUpdateToYjs=function(a,b,c,d,e,f,h,g){ea(a,()=>{d.read(()=>{if(g.has("collaboration")){if(0<h.size){var k=Array.from(h),l=a.collabNodeMap,n=[];for(let p=0;p<k.length;p++){var q=k[p],t=r.$getNodeByKey(q),m=l.get(q);if(m instanceof D)if(r.$isTextNode(t))n.push([m,t.__text]);else{t=m.getOffset();if(-1===t)continue;let u=m._parent;m._normalized=!0;u._xmlText.delete(t,1);l.delete(q);q=u._children;m=q.indexOf(m);q.splice(m,1)}}for(k=0;k<n.length;k++){let [p,u]=n[k];p instanceof D&&"string"=== typeof u&&(p._text=u)}}}else e.has("root")&&(n=c._nodeMap,k=r.$getRoot(),l=a.root,l.syncPropertiesFromLexical(a,k,n),l.syncChildrenFromLexical(a,k,n,e,f)),n=r.$getSelection(),fa(a,b,c._selection,n)})})}; exports.syncYjsChangesToLexical=function(a,b,c){let d=a.editor,e=d._editorState;d.update(()=>{var f=d._pendingEditorState;for(var h=0;h<c.length;h++){var g=a,k=c[h],{target:l}=k;l=M(g,l);if(l instanceof N&&k instanceof v.YTextEvent){let {keysChanged:n,childListChanged:q,delta:t}=k;0<n.size&&l.syncPropertiesFromYjs(g,n);q&&(l.applyChildrenYjsDelta(g,t),l.syncChildrenFromYjs(g))}else if(l instanceof D&&k instanceof v.YMapEvent)({keysChanged:k}=k),0<k.size&&l.syncPropertiesAndTextFromYjs(g,k);else if(l instanceof Q&&k instanceof v.YXmlEvent)({attributesChanged:k}=k),0<k.size&&l.syncPropertiesFromYjs(g,k);else throw Error("Should never happen");}h=r.$getSelection();if(r.$isRangeSelection(h))if(P(h)){g=e._selection;if(r.$isRangeSelection(g)){l=A.$createOffsetView(d,0,e);f=A.$createOffsetView(d,0,f);let [n,q]=l.getOffsetsFromSelection(g);f=f.createSelectionFromOffsets(n,q,l);null!==f?r.$setSelection(f):(V(a,b),P(h)&&(f=r.$getRoot(),0===f.getChildrenSize()&&f.append(r.$createParagraphNode()),r.$getRoot().selectEnd()))}fa(a, b,g,r.$getSelection())}else V(a,b)},{onUpdate:()=>{X(a,b)},skipTransforms:!0,tag:"collaboration"})}