Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@lexical/yjs

Package Overview
Dependencies
Maintainers
6
Versions
620
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@lexical/yjs - npm Package Compare versions

Comparing version
0.44.1-nightly.20260519.0
to
0.45.0
+48
dist/Bindings.d.ts
/**
* 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.
*
*/
import type { CollabDecoratorNode } from './CollabDecoratorNode';
import type { CollabElementNode } from './CollabElementNode';
import type { CollabLineBreakNode } from './CollabLineBreakNode';
import type { CollabTextNode } from './CollabTextNode';
import type { Cursor } from './SyncCursors';
import type { LexicalEditor, NodeKey } from 'lexical';
import { Klass, LexicalNode } from 'lexical';
import { Doc, XmlElement } from 'yjs';
import { Provider } from '.';
import { CollabV2Mapping } from './CollabV2Mapping';
export type ClientID = number;
export interface BaseBinding {
clientID: number;
cursors: Map<ClientID, Cursor>;
cursorsContainer: null | HTMLElement;
doc: Doc;
docMap: Map<string, Doc>;
editor: LexicalEditor;
id: string;
nodeProperties: Map<string, {
[property: string]: unknown;
}>;
excludedProperties: ExcludedProperties;
}
export interface Binding extends BaseBinding {
collabNodeMap: Map<NodeKey, CollabElementNode | CollabTextNode | CollabDecoratorNode | CollabLineBreakNode>;
root: CollabElementNode;
}
export interface BindingV2 extends BaseBinding {
mapping: CollabV2Mapping;
root: XmlElement;
}
export type AnyBinding = Binding | BindingV2;
export type ExcludedProperties = Map<Klass<LexicalNode>, Set<string>>;
export declare function createBinding(editor: LexicalEditor, provider: Provider, id: string, doc: Doc | null | undefined, docMap: Map<string, Doc>, excludedProperties?: ExcludedProperties): Binding;
export declare function createBindingV2__EXPERIMENTAL(editor: LexicalEditor, id: string, doc: Doc | null | undefined, docMap: Map<string, Doc>, options?: {
excludedProperties?: ExcludedProperties;
rootName?: string;
}): BindingV2;
export declare function isBindingV1(binding: BaseBinding): binding is Binding;
export declare function isBindingV2(binding: BaseBinding): binding is BindingV2;
/**
* 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.
*
*/
import type { Binding } from '.';
import type { CollabElementNode } from './CollabElementNode';
import type { DecoratorNode, NodeKey, NodeMap } from 'lexical';
import type { XmlElement } from 'yjs';
export declare class CollabDecoratorNode {
_xmlElem: XmlElement;
_key: NodeKey;
_parent: CollabElementNode;
_type: string;
constructor(xmlElem: XmlElement, parent: CollabElementNode, type: string);
getPrevNode(nodeMap: null | NodeMap): null | DecoratorNode<unknown>;
getNode(): null | DecoratorNode<unknown>;
getSharedType(): XmlElement;
getType(): string;
getKey(): NodeKey;
getSize(): number;
getOffset(): number;
syncPropertiesFromLexical(binding: Binding, nextLexicalNode: DecoratorNode<unknown>, prevNodeMap: null | NodeMap): void;
syncPropertiesFromYjs(binding: Binding, keysChanged: null | Set<string>): void;
destroy(binding: Binding): void;
}
export declare function $createCollabDecoratorNode(xmlElem: XmlElement, parent: CollabElementNode, type: string): CollabDecoratorNode;
/**
* 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.
*
*/
import type { Binding } from '.';
import type { ElementNode, NodeKey, NodeMap } from 'lexical';
import type { AbstractType, XmlText } from 'yjs';
import { CollabDecoratorNode } from './CollabDecoratorNode';
import { CollabLineBreakNode } from './CollabLineBreakNode';
import { CollabTextNode } from './CollabTextNode';
type IntentionallyMarkedAsDirtyElement = boolean;
export declare class CollabElementNode {
_key: NodeKey;
_children: Array<CollabElementNode | CollabTextNode | CollabDecoratorNode | CollabLineBreakNode>;
_xmlText: XmlText;
_type: string;
_parent: null | CollabElementNode;
constructor(xmlText: XmlText, parent: null | CollabElementNode, type: string);
getPrevNode(nodeMap: null | NodeMap): null | ElementNode;
getNode(): null | ElementNode;
getSharedType(): XmlText;
getType(): string;
getKey(): NodeKey;
isEmpty(): boolean;
getSize(): number;
getOffset(): number;
syncPropertiesFromYjs(binding: Binding, keysChanged: null | Set<string>): void;
applyChildrenYjsDelta(binding: Binding, deltas: Array<{
insert?: string | object | AbstractType<unknown>;
delete?: number;
retain?: number;
attributes?: {
[x: string]: unknown;
};
}>): void;
syncChildrenFromYjs(binding: Binding): void;
syncPropertiesFromLexical(binding: Binding, nextLexicalNode: ElementNode, prevNodeMap: null | NodeMap): void;
_syncChildFromLexical(binding: Binding, index: number, key: NodeKey, prevNodeMap: null | NodeMap, dirtyElements: null | Map<NodeKey, IntentionallyMarkedAsDirtyElement>, dirtyLeaves: null | Set<NodeKey>): void;
syncChildrenFromLexical(binding: Binding, nextLexicalNode: ElementNode, prevNodeMap: null | NodeMap, dirtyElements: null | Map<NodeKey, IntentionallyMarkedAsDirtyElement>, dirtyLeaves: null | Set<NodeKey>): void;
append(collabNode: CollabElementNode | CollabDecoratorNode | CollabTextNode | CollabLineBreakNode): void;
splice(binding: Binding, index: number, delCount: number, collabNode?: CollabElementNode | CollabDecoratorNode | CollabTextNode | CollabLineBreakNode): void;
getChildOffset(collabNode: CollabElementNode | CollabTextNode | CollabDecoratorNode | CollabLineBreakNode): number;
destroy(binding: Binding): void;
}
export declare function $createCollabElementNode(xmlText: XmlText, parent: null | CollabElementNode, type: string): CollabElementNode;
export {};
/**
* 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.
*
*/
import type { Binding } from '.';
import type { CollabElementNode } from './CollabElementNode';
import type { LineBreakNode, NodeKey } from 'lexical';
import type { Map as YMap } from 'yjs';
export declare class CollabLineBreakNode {
_map: YMap<unknown>;
_key: NodeKey;
_parent: CollabElementNode;
_type: 'linebreak';
constructor(map: YMap<unknown>, parent: CollabElementNode);
getNode(): null | LineBreakNode;
getKey(): NodeKey;
getSharedType(): YMap<unknown>;
getType(): string;
getSize(): number;
getOffset(): number;
destroy(binding: Binding): void;
}
export declare function $createCollabLineBreakNode(map: YMap<unknown>, parent: CollabElementNode): CollabLineBreakNode;
/**
* 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.
*
*/
import type { Binding } from '.';
import type { CollabElementNode } from './CollabElementNode';
import type { NodeKey, NodeMap, TextNode } from 'lexical';
import type { Map as YMap } from 'yjs';
export declare class CollabTextNode {
_map: YMap<unknown>;
_key: NodeKey;
_parent: CollabElementNode;
_text: string;
_type: string;
_normalized: boolean;
constructor(map: YMap<unknown>, text: string, parent: CollabElementNode, type: string);
getPrevNode(nodeMap: null | NodeMap): null | TextNode;
getNode(): null | TextNode;
getSharedType(): YMap<unknown>;
getType(): string;
getKey(): NodeKey;
getSize(): number;
getOffset(): number;
spliceText(index: number, delCount: number, newText: string): void;
syncPropertiesAndTextFromLexical(binding: Binding, nextLexicalNode: TextNode, prevNodeMap: null | NodeMap): void;
syncPropertiesAndTextFromYjs(binding: Binding, keysChanged: null | Set<string>): void;
destroy(binding: Binding): void;
}
export declare function $createCollabTextNode(map: YMap<unknown>, text: string, parent: CollabElementNode, type: string): CollabTextNode;
/**
* 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.
*
*/
import { type LexicalNode, NodeKey, type TextNode } from 'lexical';
import { XmlElement, XmlText } from 'yjs';
type SharedType = XmlElement | XmlText;
export declare class CollabV2Mapping {
private _nodeMap;
private _sharedTypeToNodeKeys;
private _nodeKeyToSharedType;
set(sharedType: SharedType, node: LexicalNode | TextNode[]): void;
get(sharedType: XmlElement): LexicalNode | undefined;
get(sharedType: XmlText): TextNode[] | undefined;
get(sharedType: SharedType): LexicalNode | Array<TextNode> | undefined;
getSharedType(node: LexicalNode): SharedType | undefined;
delete(sharedType: SharedType): void;
deleteNode(nodeKey: NodeKey): void;
has(sharedType: SharedType): boolean;
clear(): void;
}
export {};
/**
* 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.
*
*/
import type { BaseBinding } from './Bindings';
import type { LexicalCommand } from 'lexical';
import type { Doc, RelativePosition, Snapshot, UndoManager, XmlElement, XmlText } from 'yjs';
import './types';
export type UserState = {
anchorPos: null | RelativePosition;
color: string;
focusing: boolean;
focusPos: null | RelativePosition;
name: string;
awarenessData: object;
[key: string]: unknown;
};
export declare const CONNECTED_COMMAND: LexicalCommand<boolean>;
export declare const TOGGLE_CONNECT_COMMAND: LexicalCommand<boolean>;
export declare const DIFF_VERSIONS_COMMAND__EXPERIMENTAL: LexicalCommand<{
prevSnapshot?: Snapshot;
snapshot?: Snapshot;
}>;
export declare const CLEAR_DIFF_VERSIONS_COMMAND__EXPERIMENTAL: LexicalCommand<void>;
export { $getYChangeState, renderSnapshot__EXPERIMENTAL } from './RenderSnapshot';
export type ProviderAwareness = {
getLocalState: () => UserState | null;
getStates: () => Map<number, UserState>;
off: (type: 'update', cb: () => void) => void;
on: (type: 'update', cb: () => void) => void;
setLocalState: (arg0: UserState | null) => void;
setLocalStateField: (field: string, value: unknown) => void;
};
declare interface Provider {
awareness: ProviderAwareness;
connect(): void | Promise<void>;
disconnect(): void;
off(type: 'sync', cb: (isSynced: boolean) => void): void;
off(type: 'update', cb: (arg0: unknown) => void): void;
off(type: 'status', cb: (arg0: {
status: string;
}) => void): void;
off(type: 'reload', cb: (doc: Doc) => void): void;
on(type: 'sync', cb: (isSynced: boolean) => void): void;
on(type: 'status', cb: (arg0: {
status: string;
}) => void): void;
on(type: 'update', cb: (arg0: unknown) => void): void;
on(type: 'reload', cb: (doc: Doc) => void): void;
}
export type Operation = {
attributes: {
__type: string;
};
insert: string | Record<string, unknown>;
};
export type Delta = Array<Operation>;
export type YjsNode = Record<string, unknown>;
export type YjsEvent = Record<string, unknown>;
export type { Provider };
export type { BaseBinding, Binding, BindingV2, ClientID, ExcludedProperties, } from './Bindings';
export { createBinding, createBindingV2__EXPERIMENTAL } from './Bindings';
export declare function createUndoManager(binding: BaseBinding, root: XmlText | XmlElement): UndoManager;
export declare function initLocalState(provider: Provider, name: string, color: string, focusing: boolean, awarenessData: object): void;
export declare function setLocalStateFocus(provider: Provider, name: string, color: string, focusing: boolean, awarenessData: object): void;
export { getAnchorAndFocusCollabNodesForUserState, syncCursorPositions, type SyncCursorPositionsFn, } from './SyncCursors';
export { syncLexicalUpdateToYjs, syncLexicalUpdateToYjsV2__EXPERIMENTAL, syncYjsChangesToLexical, syncYjsChangesToLexicalV2__EXPERIMENTAL, syncYjsStateToLexicalV2__EXPERIMENTAL, } from './SyncEditorStates';

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

/**
* 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'
const LexicalYjs = process.env.NODE_ENV !== 'production' ? require('./LexicalYjs.dev.js') : require('./LexicalYjs.prod.js');
module.exports = LexicalYjs;

Sorry, the diff of this file is not supported yet

/**
* 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.
*
*/
import * as modDev from './LexicalYjs.dev.mjs';
import * as modProd from './LexicalYjs.prod.mjs';
const mod = process.env.NODE_ENV !== 'production' ? modDev : modProd;
export const $getYChangeState = mod.$getYChangeState;
export const CLEAR_DIFF_VERSIONS_COMMAND__EXPERIMENTAL = mod.CLEAR_DIFF_VERSIONS_COMMAND__EXPERIMENTAL;
export const CONNECTED_COMMAND = mod.CONNECTED_COMMAND;
export const DIFF_VERSIONS_COMMAND__EXPERIMENTAL = mod.DIFF_VERSIONS_COMMAND__EXPERIMENTAL;
export const TOGGLE_CONNECT_COMMAND = mod.TOGGLE_CONNECT_COMMAND;
export const createBinding = mod.createBinding;
export const createBindingV2__EXPERIMENTAL = mod.createBindingV2__EXPERIMENTAL;
export const createUndoManager = mod.createUndoManager;
export const getAnchorAndFocusCollabNodesForUserState = mod.getAnchorAndFocusCollabNodesForUserState;
export const initLocalState = mod.initLocalState;
export const renderSnapshot__EXPERIMENTAL = mod.renderSnapshot__EXPERIMENTAL;
export const setLocalStateFocus = mod.setLocalStateFocus;
export const syncCursorPositions = mod.syncCursorPositions;
export const syncLexicalUpdateToYjs = mod.syncLexicalUpdateToYjs;
export const syncLexicalUpdateToYjsV2__EXPERIMENTAL = mod.syncLexicalUpdateToYjsV2__EXPERIMENTAL;
export const syncYjsChangesToLexical = mod.syncYjsChangesToLexical;
export const syncYjsChangesToLexicalV2__EXPERIMENTAL = mod.syncYjsChangesToLexicalV2__EXPERIMENTAL;
export const syncYjsStateToLexicalV2__EXPERIMENTAL = mod.syncYjsStateToLexicalV2__EXPERIMENTAL;
/**
* 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.
*
*/
const mod = await (process.env.NODE_ENV !== 'production' ? import('./LexicalYjs.dev.mjs') : import('./LexicalYjs.prod.mjs'));
export const $getYChangeState = mod.$getYChangeState;
export const CLEAR_DIFF_VERSIONS_COMMAND__EXPERIMENTAL = mod.CLEAR_DIFF_VERSIONS_COMMAND__EXPERIMENTAL;
export const CONNECTED_COMMAND = mod.CONNECTED_COMMAND;
export const DIFF_VERSIONS_COMMAND__EXPERIMENTAL = mod.DIFF_VERSIONS_COMMAND__EXPERIMENTAL;
export const TOGGLE_CONNECT_COMMAND = mod.TOGGLE_CONNECT_COMMAND;
export const createBinding = mod.createBinding;
export const createBindingV2__EXPERIMENTAL = mod.createBindingV2__EXPERIMENTAL;
export const createUndoManager = mod.createUndoManager;
export const getAnchorAndFocusCollabNodesForUserState = mod.getAnchorAndFocusCollabNodesForUserState;
export const initLocalState = mod.initLocalState;
export const renderSnapshot__EXPERIMENTAL = mod.renderSnapshot__EXPERIMENTAL;
export const setLocalStateFocus = mod.setLocalStateFocus;
export const syncCursorPositions = mod.syncCursorPositions;
export const syncLexicalUpdateToYjs = mod.syncLexicalUpdateToYjs;
export const syncLexicalUpdateToYjsV2__EXPERIMENTAL = mod.syncLexicalUpdateToYjsV2__EXPERIMENTAL;
export const syncYjsChangesToLexical = mod.syncYjsChangesToLexical;
export const syncYjsChangesToLexicalV2__EXPERIMENTAL = mod.syncYjsChangesToLexicalV2__EXPERIMENTAL;
export const syncYjsStateToLexicalV2__EXPERIMENTAL = mod.syncYjsStateToLexicalV2__EXPERIMENTAL;
/**
* 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 e=require("lexical"),t=require("yjs"),n=require("@lexical/selection");function o(e,...t){const n=new URL("https://lexical.dev/docs/error"),o=new URLSearchParams;o.append("code",e);for(const e of t)o.append("v",e);throw n.search=o.toString(),Error(`Minified Lexical error #${e}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}function s(e,t,n){const o=e.length,s=t.length;let i=0,r=0;for(;i<o&&i<s&&e[i]===t[i]&&i<n;)i++;for(;r+i<o&&r+i<s&&e[o-r-1]===t[s-r-1];)r++;for(;r+i<o&&r+i<s&&e[i]===t[i];)i++;return{index:i,insert:t.slice(i,s-r),remove:o-i-r}}class i{_xmlElem;_key;_parent;_type;constructor(e,t,n){this._key="",this._xmlElem=e,this._parent=t,this._type=n}getPrevNode(t){if(null===t)return null;const n=t.get(this._key);return e.$isDecoratorNode(n)?n:null}getNode(){const t=e.$getNodeByKey(this._key);return e.$isDecoratorNode(t)?t:null}getSharedType(){return this._xmlElem}getType(){return this._type}getKey(){return this._key}getSize(){return 1}getOffset(){return this._parent.getChildOffset(this)}syncPropertiesFromLexical(e,t,n){const o=this.getPrevNode(n);M(e,this._xmlElem,o,t)}syncPropertiesFromYjs(e,t){const n=this.getNode();null===n&&o(83);C(e,this._xmlElem,n,t)}destroy(e){const t=e.collabNodeMap;t.get(this._key)===this&&t.delete(this._key)}}function r(e,t,n){const o=new i(e,t,n);return e._collabNode=o,o}class l{_map;_key;_parent;_type;constructor(e,t){this._key="",this._map=e,this._parent=t,this._type="linebreak"}getNode(){const t=e.$getNodeByKey(this._key);return e.$isLineBreakNode(t)?t:null}getKey(){return this._key}getSharedType(){return this._map}getType(){return this._type}getSize(){return 1}getOffset(){return this._parent.getChildOffset(this)}destroy(e){const t=e.collabNodeMap;t.get(this._key)===this&&t.delete(this._key)}}function c(e,t){const n=new l(e,t);return e._collabNode=n,n}class a{_map;_key;_parent;_text;_type;_normalized;constructor(e,t,n,o){this._key="",this._map=e,this._parent=n,this._text=t,this._type=o,this._normalized=!1}getPrevNode(t){if(null===t)return null;const n=t.get(this._key);return e.$isTextNode(n)?n:null}getNode(){const t=e.$getNodeByKey(this._key);return e.$isTextNode(t)?t: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(e,t,n){const o=this._parent._xmlText,s=this.getOffset()+1+e;0!==t&&o.delete(s,t),""!==n&&o.insert(s,n)}syncPropertiesAndTextFromLexical(t,n,o){const i=this.getPrevNode(o),r=n.__text;if(M(t,this._map,i,n),null!==i){const t=i.__text;if(t!==r){!function(t,n,o,i){const r=e.$getSelection();let l=i.length;if(e.$isRangeSelection(r)&&r.isCollapsed()){const e=r.anchor;e.key===n&&(l=e.offset)}const c=s(o,i,l);t.spliceText(c.index,c.remove,c.insert)}(this,n.__key,t,r),this._text=r}}}syncPropertiesAndTextFromYjs(e,t){const n=this.getNode();null===n&&o(84),C(e,this._map,n,t);const s=this._text;n.__text!==s&&n.setTextContent(s)}destroy(e){const t=e.collabNodeMap;t.get(this._key)===this&&t.delete(this._key)}}function d(e,t,n,o){const s=new a(e,t,n,o);return e._collabNode=s,s}class f{_key;_children;_xmlText;_type;_parent;constructor(e,t,n){this._key="",this._children=[],this._xmlText=e,this._type=n,this._parent=t}getPrevNode(t){if(null===t)return null;const n=t.get(this._key);return e.$isElementNode(n)?n:null}getNode(){const t=e.$getNodeByKey(this._key);return e.$isElementNode(t)?t:null}getSharedType(){return this._xmlText}getType(){return this._type}getKey(){return this._key}isEmpty(){return 0===this._children.length}getSize(){return 1}getOffset(){const e=this._parent;return null===e&&o(90),e.getChildOffset(this)}syncPropertiesFromYjs(e,t){const n=this.getNode();null===n&&o(91),C(e,this._xmlText,n,t)}applyChildrenYjsDelta(e,t){const n=this._children;let o=0,s=null;for(let r=0;r<t.length;r++){const c=t[r],d=c.insert,u=c.delete;if(null!=c.retain)o+=c.retain;else if("number"==typeof u){let e=u;for(;e>0;){const{node:t,nodeIndex:s,offset:r,length:c}=w(this,o,!1);if(t instanceof f||t instanceof l||t instanceof i)n.splice(s,1),e-=1;else{if(!(t instanceof a))break;{const o=Math.min(e,c),i=0!==s?n[s-1]:null,l=t.getSize();if(0===r&&c===l){n.splice(s,1);const e=A(t._text,r,o-1,"");e.length>0&&(i instanceof a?i._text+=e:this._xmlText.delete(r,e.length))}else t._text=A(t._text,r,o,"");e-=o}}}}else{if(null==d)throw new Error("Unexpected delta format");if("string"==typeof d){const{node:e,offset:t}=w(this,o,!0);e instanceof a?e._text=A(e._text,t,0,d):this._xmlText.delete(t,d.length),o+=d.length}else{const t=d,{node:i,nodeIndex:r,length:l}=w(this,o,!1),c=E(e,t,this);if(i instanceof a&&l>0&&l<i._text.length){const e=i._text,t=e.length-l;i._text=A(e,t,l,""),n.splice(r+1,0,c),s=A(e,0,t,"")}else n.splice(r,0,c);null!==s&&c instanceof a&&(c._text=s+c._text,s=null),o+=1}}}}syncChildrenFromYjs(t){const n=this.getNode();null===n&&o(92);const s=n.__key,r=e.$createChildrenArray(n,null),c=r.length,d=this._children,u=d.length,h=t.collabNodeMap,p=new Set;let g,y,_=0,m=null;u!==c&&(y=n.getWritable());for(let c=0;c<u;c++){const x=r[_],T=d[c],N=T.getNode(),S=T._key;if(null!==N&&x===S){const n=e.$isTextNode(N);if(p.add(x),n)if(T._key=x,T instanceof f){const e=T._xmlText;T.syncPropertiesFromYjs(t,null),T.applyChildrenYjsDelta(t,e.toDelta()),T.syncChildrenFromYjs(t)}else T instanceof a?T.syncPropertiesAndTextFromYjs(t,null):T instanceof i?T.syncPropertiesFromYjs(t,null):T instanceof l||o(93);m=N,_++}else{if(void 0===g){g=new Set;for(let e=0;e<u;e++){const t=d[e]._key;""!==t&&g.add(t)}}if(null!==N&&void 0!==x&&!g.has(x)){const t=e.$getNodeByKeyOrThrow(x);e.removeFromParent(t),c--,_++;continue}y=n.getWritable();const o=O(t,T,s),i=o.__key;if(h.set(i,T),null===m){const e=y.getFirstChild();if(y.__first=i,null!==e){const t=e.getWritable();t.__prev=i,o.__next=t.__key}}else{const e=m.getWritable(),t=m.getNextSibling();if(e.__next=i,o.__prev=m.__key,null!==t){const e=t.getWritable();e.__prev=i,o.__next=e.__key}}c===u-1&&(y.__last=i),y.__size++,m=o}}for(let n=0;n<c;n++){const o=r[n];if(!p.has(o)){const n=e.$getNodeByKeyOrThrow(o),s=t.collabNodeMap.get(o);void 0!==s&&s.destroy(t),e.removeFromParent(n)}}}syncPropertiesFromLexical(e,t,n){M(e,this._xmlText,this.getPrevNode(n),t)}_syncChildFromLexical(t,n,o,s,r,l){const c=this._children[n],d=e.$getNodeByKeyOrThrow(o);c instanceof f&&e.$isElementNode(d)?(c.syncPropertiesFromLexical(t,d,s),c.syncChildrenFromLexical(t,d,s,r,l)):c instanceof a&&e.$isTextNode(d)?c.syncPropertiesAndTextFromLexical(t,d,s):c instanceof i&&e.$isDecoratorNode(d)&&c.syncPropertiesFromLexical(t,d,s)}syncChildrenFromLexical(t,n,o,s,i){const r=this.getPrevNode(o),l=null===r?[]:e.$createChildrenArray(r,o),c=e.$createChildrenArray(n,null),a=l.length-1,d=c.length-1,f=t.collabNodeMap;let u,h,p=0,g=0;for(;p<=a&&g<=d;){const n=l[p],r=c[g];if(n===r)this._syncChildFromLexical(t,g,r,o,s,i),p++,g++;else{void 0===u&&(u=new Set(l)),void 0===h&&(h=new Set(c));const o=h.has(n),s=u.has(r);if(o){const n=S(t,e.$getNodeByKeyOrThrow(r),this);f.set(r,n),s?(this.splice(t,g,1,n),p++,g++):(this.splice(t,g,0,n),g++)}else this.splice(t,g,1),p++}}const y=p>a,_=g>d;if(y&&!_)for(;g<=d;++g){const n=c[g],o=S(t,e.$getNodeByKeyOrThrow(n),this);this.append(o),f.set(n,o)}else if(_&&!y)for(let e=this._children.length-1;e>=g;e--)this.splice(t,e,1)}append(e){const t=this._xmlText,n=this._children,o=n[n.length-1],s=void 0!==o?o.getOffset()+o.getSize():0;if(e instanceof f)t.insertEmbed(s,e._xmlText);else if(e instanceof a){const n=e._map;null===n.parent&&t.insertEmbed(s,n),t.insert(s+1,e._text)}else e instanceof l?t.insertEmbed(s,e._map):e instanceof i&&t.insertEmbed(s,e._xmlElem);this._children.push(e)}splice(e,t,n,s){const r=this._children,c=r[t];if(void 0===c)return void 0===s&&o(94),void this.append(s);const d=c.getOffset();-1===d&&o(95);const u=this._xmlText;if(0!==n&&u.delete(d,c.getSize()),s instanceof f)u.insertEmbed(d,s._xmlText);else if(s instanceof a){const e=s._map;null===e.parent&&u.insertEmbed(d,e),u.insert(d+1,s._text)}else s instanceof l?u.insertEmbed(d,s._map):s instanceof i&&u.insertEmbed(d,s._xmlElem);if(0!==n){const o=r.slice(t,t+n);for(let t=0;t<o.length;t++)o[t].destroy(e)}void 0!==s?r.splice(t,n,s):r.splice(t,n)}getChildOffset(e){let t=0;const n=this._children;for(let o=0;o<n.length;o++){const s=n[o];if(s===e)return t;t+=s.getSize()}return-1}destroy(e){const t=e.collabNodeMap,n=this._children;for(let t=0;t<n.length;t++)n[t].destroy(e);t.get(this._key)===this&&t.delete(this._key)}}function u(e,t,n){const o=new f(e,t,n);return e._collabNode=o,o}class h{_nodeMap=new Map;_sharedTypeToNodeKeys=new Map;_nodeKeyToSharedType=new Map;set(n,s){const i=s instanceof Array;this.delete(n);const r=i?s:[s];for(const e of r){const t=e.getKey();if(this._nodeKeyToSharedType.has(t)){const e=this._nodeKeyToSharedType.get(t),n=this._sharedTypeToNodeKeys.get(e).indexOf(t);-1!==n&&this._sharedTypeToNodeKeys.get(e).splice(n,1),this._nodeKeyToSharedType.delete(t),this._nodeMap.delete(t)}}if(n instanceof t.XmlText){if(i||o(331),0===s.length)return;this._sharedTypeToNodeKeys.set(n,s.map(e=>e.getKey()));for(const e of s)this._nodeMap.set(e.getKey(),e),this._nodeKeyToSharedType.set(e.getKey(),n)}else i&&o(332),e.$isTextNode(s)&&o(333),this._sharedTypeToNodeKeys.set(n,[s.getKey()]),this._nodeMap.set(s.getKey(),s),this._nodeKeyToSharedType.set(s.getKey(),n)}get(e){const n=this._sharedTypeToNodeKeys.get(e);if(void 0!==n){if(e instanceof t.XmlText){const e=Array.from(n.map(e=>this._nodeMap.get(e)));return e.length>0?e:void 0}return this._nodeMap.get(n[0])}}getSharedType(e){return this._nodeKeyToSharedType.get(e.getKey())}delete(e){const t=this._sharedTypeToNodeKeys.get(e);if(void 0!==t){for(const e of t)this._nodeMap.delete(e),this._nodeKeyToSharedType.delete(e);this._sharedTypeToNodeKeys.delete(e)}}deleteNode(e){const t=this._nodeKeyToSharedType.get(e);t&&this.delete(t),this._nodeMap.delete(e)}has(e){return this._sharedTypeToNodeKeys.has(e)}clear(){this._nodeMap.clear(),this._sharedTypeToNodeKeys.clear(),this._nodeKeyToSharedType.clear()}}function p(e,t,n,s,i){null==n&&o(81);const r={clientID:n.clientID,cursors:new Map,cursorsContainer:null,doc:n,docMap:s,editor:e,excludedProperties:i||new Map,id:t,nodeProperties:new Map};return function(e){const{editor:t,nodeProperties:n}=e;t.update(()=>{t._nodes.forEach(t=>{const o=new t.klass,s={};for(const[t,n]of Object.entries(o))T(t,o,e)||(s[t]=n);n.set(o.__type,Object.freeze(s))})})}(r),r}function g(e){return Object.prototype.hasOwnProperty.call(e,"collabNodeMap")}const y=new Set(["__key","__parent","__next","__prev","__state"]),_=new Set(["__first","__last","__size"]),m=new Set(["__cachedText"]),x=new Set(["__text"]);function T(t,n,o){if(y.has(t)||"function"==typeof n[t])return!0;if(e.$isTextNode(n)){if(x.has(t))return!0}else if(e.$isElementNode(n)&&(_.has(t)||e.$isRootNode(n)&&m.has(t)))return!0;const s=n.constructor,i=o.excludedProperties.get(s);return null!=i&&i.has(t)}function N(e,t){const n=e.__type,{nodeProperties:s}=t,i=s.get(n);return void 0===i&&o(330,n),i}function S(n,s,i){const l=s.__type;let a;if(e.$isElementNode(s)){a=u(new t.XmlText,i,l),a.syncPropertiesFromLexical(n,s,null),a.syncChildrenFromLexical(n,s,null,null,null)}else if(e.$isTextNode(s)){a=d(new t.Map,s.__text,i,l),a.syncPropertiesAndTextFromLexical(n,s,null)}else if(e.$isLineBreakNode(s)){const e=new t.Map;e.set("__type","linebreak"),a=c(e,i)}else if(e.$isDecoratorNode(s)){a=r(new t.XmlElement,i,l),a.syncPropertiesFromLexical(n,s,null)}else o(86);return a._key=s.__key,a}function b(e){const t=k(e,"__type");return"string"!=typeof t&&void 0!==t&&o(87),t}function E(e,n,s){const i=n._collabNode;if(void 0===i){const i=e.editor._nodes,l=b(n);"string"!=typeof l&&o(87);void 0===i.get(l)&&o(88,l);const a=n.parent,h=void 0===s&&null!==a?E(e,a):s||null;if(h instanceof f||o(89),n instanceof t.XmlText)return u(n,h,l);if(n instanceof t.Map)return"linebreak"===l?c(n,h):d(n,"",h,l);if(n instanceof t.XmlElement)return r(n,h,l)}return i}function O(e,t,n){const s=t.getType(),r=e.editor._nodes.get(s);void 0===r&&o(88,s);const l=new r.klass;if(l.__parent=n,t._key=l.__key,t instanceof f){const n=t._xmlText;t.syncPropertiesFromYjs(e,null),t.applyChildrenYjsDelta(e,n.toDelta()),t.syncChildrenFromYjs(e)}else t instanceof a?t.syncPropertiesAndTextFromYjs(e,null):t instanceof i&&t.syncPropertiesFromYjs(e,null);return e.collabNodeMap.set(l.__key,t),l}function C(n,o,s,i){const r=null===i?o instanceof t.Map?Array.from(o.keys()):o instanceof t.XmlText||o instanceof t.XmlElement?Object.keys(o.getAttributes()):Object.keys(o):Array.from(i);let l;for(let i=0;i<r.length;i++){const c=r[i];if(T(c,s,n)){"__state"===c&&g(n)&&(l||(l=s.getWritable()),v(o,l));continue}const a=s[c];let d=k(o,c);if(a!==d){if(d instanceof t.Doc){const o=n.docMap;a instanceof t.Doc&&o.delete(a.guid);const s=d.guid;if(o.set(s,d),e.isLexicalEditor(a))a._key=s,d=a;else{const t=e.createEditor();t._key=s,d=t}}void 0===l&&(l=s.getWritable()),l[c]=d}}}function k(e,n){return e instanceof t.Map?e.get(n):e instanceof t.XmlText||e instanceof t.XmlElement?e.getAttribute(n):e[n]}function $(e,n,o){e instanceof t.Map?e.set(n,o):e.setAttribute(n,o)}function v(n,o){const s=k(n,"__state");s instanceof t.Map&&e.$getWritableNodeState(o).updateFromJSON(s.toJSON())}function M(e,n,o,s){const i=Object.keys(N(s,e)),r=e.editor.constructor;!function(e,n,o,s){const i=s.__state,r=null===n.doc?void 0:k(n,"__state");if(!i)return;const[l,c]=i.getInternalState(),a=o&&o.__state,d=r instanceof t.Map?r:new t.Map;if(a===i)return;const[f,u]=a&&d.doc?a.getInternalState():[void 0,new Map];if(l)for(const[e,t]of Object.entries(l))f&&t!==f[e]&&d.set(e,t);for(const[e,t]of c)u.get(e)!==t&&d.set(e.key,e.unparse(t));r||$(n,"__state",d)}(0,n,o,s);for(let l=0;l<i.length;l++){const c=i[l],a=null===o?void 0:o[c];let d=s[c];if(a!==d){if(d instanceof r){const n=e.docMap;let o;if(a instanceof r){const e=a._key;o=n.get(e),n.delete(e)}const i=o||new t.Doc,l=i.guid;d._key=l,n.set(l,i),d=i,e.editor.update(()=>{s.markDirty()})}$(n,c,d)}}}function A(e,t,n,o){return e.slice(0,t)+o+e.slice(t+n)}function w(e,t,n){let o=0,s=0;const i=e._children,r=i.length;for(;s<r;s++){const e=i[s],l=o;o+=e.getSize();if((n?o>=t:o>t)&&e instanceof a){let n=t-l-1;n<0&&(n=0);return{length:o-t,node:e,nodeIndex:s,offset:n}}if(o>t)return{length:0,node:e,nodeIndex:s,offset:l};if(s===r-1)return{length:0,node:null,nodeIndex:s+1,offset:l+1}}return{length:0,node:null,nodeIndex:0,offset:0}}function P(t){const n=t.anchor,o=t.focus;let s=!1;try{const t=n.getNode(),i=o.getNode();(!t.isAttached()||!i.isAttached()||e.$isTextNode(t)&&n.offset>t.getTextContentSize()||e.$isTextNode(i)&&o.offset>i.getTextContentSize())&&(s=!0)}catch(e){s=!0}return s}function K(e,t){e.doc.transact(t,e)}function L(t,n){const o=n._nodeMap.get(t);if(!o)return void e.$getRoot().selectStart();const s=o.__prev;let i=null;s&&(i=e.$getNodeByKey(s)),null===i&&null!==o.__parent&&(i=e.$getNodeByKey(o.__parent)),null!==i?null!==i&&i.isAttached()?i.selectEnd():L(i.__key,n):e.$getRoot().selectStart()}const F=e=>"UNDEFINED"===e.nodeName,I=(n,s,i,r,l,c,a)=>{let d=s.mapping.get(n);if(d&&i&&0===i.size&&!r)return d;const f=F(n)?e.RootNode.getType():n.nodeName,u=s.editor._nodes.get(f);if(void 0===u)throw new Error(`$createOrUpdateNodeFromYElement: Node ${f} is not registered`);if(d||(d=new u.klass,i=null,r=!0),r&&d instanceof e.ElementNode){const e=[],i=n=>{if(n instanceof t.XmlElement){const t=I(n,s,new Set,!1,l,c,a);null!==t&&e.push(t)}else if(n instanceof t.XmlText){const t=j(n,s,l,c,a);null!==t&&t.forEach(t=>{null!==t&&e.push(t)})}else o(329)};void 0===l||void 0===c?n.toArray().forEach(i):t.typeListToArraySnapshot(n,new t.Snapshot(c.ds,l.sv)).filter(e=>!e._item.deleted||D(e._item,l)||D(e._item,c)).forEach(i),R(d,e)}const h=n.getAttributes(l);F(n)||void 0===l||(D(n._item,l)?D(n._item,c)||(h[Z("ychange")]=a?a("added",n._item.id):{type:"added"}):h[Z("ychange")]=a?a("removed",n._item.id):{type:"removed"});const p={...N(d,s)},g={};for(const e in h)e.startsWith(Q)?g[ee(e)]=h[e]:p[e]=h[e];if(C(s,p,d,i),i){if(i.size>0){const t=e.$getWritableNodeState(d);for(const e of i)if(e.startsWith(Q)){const n=ee(e);t.updateFromUnknown(n,g[n])}}}else e.$getWritableNodeState(d).updateFromJSON(g);const y=d.getLatest();return s.mapping.set(n,y),y},R=(e,t)=>{const n=e.getChildren(),o=new Set(n.map(e=>e.getKey())),s=new Set(t.map(e=>e.getKey())),i=n.length-1,r=t.length-1;let l=0,c=0;for(;l<=i&&c<=r;){const i=n[l].getKey(),r=t[c].getKey();if(i===r){l++,c++;continue}const a=s.has(i),d=o.has(r);if(!a){if(0===c&&1===e.getChildrenSize())return void e.splice(c,1,t.slice(c));e.splice(c,1,[]),l++;continue}const f=t[c];d?(e.splice(c,1,[f]),l++,c++):(e.splice(c,0,[f]),c++)}const a=l>i,d=c>r;a&&!d?e.append(...t.slice(c)):d&&!a&&e.splice(t.length,e.getChildrenSize()-t.length,[])},D=(e,n)=>void 0===n?!e.deleted:n.sv.has(e.id.client)&&n.sv.get(e.id.client)>e.id.clock&&!t.isDeleted(n.ds,e.id),j=(t,n,o,s,i)=>{const r=q(t,o,s,i);let l=n.mapping.get(t)??[];const c=r.map(t=>t.attributes.t??e.TextNode.getType());if(!(l.length===c.length&&l.every((e,t)=>e.getType()===c[t]))){const t=n.editor._nodes;l=c.map(n=>{const o=t.get(n);if(void 0===o)throw new Error(`$createTextNodesFromYText: Node ${n} is not registered`);const s=new o.klass;if(!e.$isTextNode(s))throw new Error(`$createTextNodesFromYText: Node ${n} is not a TextNode`);return s})}for(let t=0;t<r.length;t++){const o=l[t],s=r[t],{attributes:i,insert:c}=s;o.__text!==c&&o.setTextContent(c);const a={...N(o,n),...i.p},d=Object.fromEntries(Object.entries(i).filter(([e])=>e.startsWith(Q)).map(([e,t])=>[ee(e),t]));C(n,a,o,null),e.$getWritableNodeState(o).updateFromJSON(d)}const a=l.map(e=>e.getLatest());return n.mapping.set(t,a),a},X=(n,o)=>n instanceof Array?((e,n)=>{const o=new t.XmlText;return H(o,e,n),o})(n,o):((n,o)=>{const s=new t.XmlElement(n.getType()),i={...J(n,o),...te(n)};for(const e in i){const t=i[e];null!==t&&s.setAttribute(e,t)}return n instanceof e.ElementNode?(s.insert(0,B(n).map(e=>X(e,o))),o.mapping.set(s,n),s):s})(n,o),z=e=>"object"==typeof e&&null!=e,Y=(e,t)=>{const n=Object.keys(e).filter(t=>null!==e[t]);if(null==t)return 0===n.length;let o=n.length===Object.keys(t).filter(e=>null!==t[e]).length;for(let s=0;s<n.length&&o;s++){const i=n[s],r=e[i],l=t[i];o="ychange"===i||r===l||z(r)&&z(l)&&Y(r,l)}return o},B=t=>{if(!(t instanceof e.ElementNode))return[];const n=t.getChildren(),o=[];for(let t=0;t<n.length;t++){const s=n[t];if(e.$isTextNode(s)){const s=[];for(let o=n[t];t<n.length&&e.$isTextNode(o);o=n[++t])s.push(o);t--,o.push(s)}else o.push(s)}return o},U=(t,n,o)=>{const s=q(t);return s.length===n.length&&s.every((t,s)=>{const i=n[s],r=t.attributes.t??e.TextNode.getType(),l=t.attributes.p??{},c=Object.fromEntries(Object.entries(t.attributes).filter(([e])=>e.startsWith(Q)));return t.insert===i.getTextContent()&&r===i.getType()&&Y(l,J(i,o))&&Y(c,te(i))})},W=(e,n,o)=>{if(e instanceof t.XmlElement&&!(n instanceof Array)&&oe(e,n)){const t=B(n);return e._length===t.length&&Y(e.getAttributes(),{...J(n,o),...te(n)})&&e.toArray().every((e,n)=>W(e,t[n],o))}return e instanceof t.XmlText&&n instanceof Array&&U(e,n,o)},G=(e,t)=>e===t||e instanceof Array&&t instanceof Array&&e.length===t.length&&e.every((e,n)=>t[n]===e),V=(e,n,o)=>{const s=e.toArray(),i=B(n),r=i.length,l=s.length,c=Math.min(l,r);let a=0,d=0,f=!1;for(;a<c;a++){const e=s[a],n=i[a];if(e instanceof t.XmlHook)break;if(G(o.mapping.get(e),n))f=!0;else if(!W(e,n,o))break}for(;a+d<c;d++){const e=s[l-d-1],n=i[r-d-1];if(e instanceof t.XmlHook)break;if(G(o.mapping.get(e),n))f=!0;else if(!W(e,n,o))break}return{equalityFactor:a+d,foundMappedChild:f}},H=(n,o,i)=>{i.mapping.set(n,o);const{nAttrs:r,str:l}=(e=>{let n="",o=e._start;const s={};for(;null!==o;)o.deleted||(o.countable&&o.content instanceof t.ContentString?n+=o.content.str:o.content instanceof t.ContentFormat&&(s[o.content.key]=null)),o=o.right;return{nAttrs:s,str:n}})(n),c=o.map((t,n)=>{const o=t.getType();let s=J(t,i);return 0===Object.keys(s).length&&(s=null),{attributes:Object.assign({},r,{...o!==e.TextNode.getType()&&{t:o},p:s,...te(t),...n>0&&{i:n}}),insert:t.getTextContent(),nodeKey:t.getKey()}}),a=c.map(e=>e.insert).join(""),d=e.$getSelection();let f;if(e.$isRangeSelection(d)&&d.isCollapsed()){f=0;for(const e of c){if(e.nodeKey===d.anchor.key){f+=d.anchor.offset;break}f+=e.insert.length}}else f=a.length;const{insert:u,remove:h,index:p}=s(l,a,f);n.delete(p,h),n.insert(p,u),n.applyDelta(c.map(e=>({attributes:e.attributes,retain:e.insert.length})))},q=(e,t,n,o)=>e.toDelta(t,n,o).map(e=>{const t=e.attributes??{};return"ychange"in t&&(t[Z("ychange")]=t.ychange,delete t.ychange),{...e,attributes:t}}),J=(e,t)=>{const n=N(e,t),o={};return Object.entries(n).forEach(([t,n])=>{const s=e[t];s!==n&&(o[t]=s)}),o},Q="s_",Z=e=>`s_${e}`,ee=e=>{if(!e.startsWith(Q))throw new Error(`Invalid state key: ${e}`);return e.slice(Q.length)},te=e=>{const t=e.__state;if(!t)return{};const[n={},o]=t.getInternalState(),s={};for(const[e,t]of Object.entries(n))s[Z(e)]=t;for(const[e,t]of o)s[Z(e.key)]=e.unparse(t);return s},ne=(n,o,s,i,r)=>{if(o instanceof t.XmlElement&&o.nodeName!==s.getType()&&(!F(o)||s.getType()!==e.RootNode.getType()))throw new Error("node name mismatch!");if(i.mapping.set(o,s),o instanceof t.XmlElement){const e=o.getAttributes(),t={...J(s,i),...te(s)};for(const n in t)if(null!=t[n]){e[n]===t[n]||z(e[n])&&z(t[n])&&Y(e[n],t[n])||"ychange"===n||o.setAttribute(n,t[n])}else o.removeAttribute(n);for(const n in e)void 0===t[n]&&o.removeAttribute(n)}const l=B(s),c=l.length,a=o.toArray(),d=a.length,f=Math.min(c,d);let u=0,h=0;for(;u<f;u++){const o=a[u],s=l[u];if(o instanceof t.XmlHook)break;if(G(i.mapping.get(o),s))s instanceof e.ElementNode&&r.has(s.getKey())&&ne(n,o,s,i,r);else{if(!W(o,s,i))break;i.mapping.set(o,s)}}for(;h+u<f;h++){const o=a[d-h-1],s=l[c-h-1];if(o instanceof t.XmlHook)break;if(G(i.mapping.get(o),s))s instanceof e.ElementNode&&r.has(s.getKey())&&ne(n,o,s,i,r);else{if(!W(o,s,i))break;i.mapping.set(o,s)}}for(;d-u-h>0&&c-u-h>0;){const e=a[u],s=l[u],f=a[d-h-1],p=l[c-h-1];if(e instanceof t.XmlText&&s instanceof Array)U(e,s,i)||H(e,s,i),u+=1;else{let l=e instanceof t.XmlElement&&oe(e,s),c=f instanceof t.XmlElement&&oe(f,p);if(l&&c){const t=V(e,s,i),n=V(f,p,i);t.foundMappedChild&&!n.foundMappedChild?c=!1:!t.foundMappedChild&&n.foundMappedChild||t.equalityFactor<n.equalityFactor?l=!1:c=!1}l?(ne(n,e,s,i,r),u+=1):c?(ne(n,f,p,i,r),h+=1):(i.mapping.delete(o.get(u)),o.delete(u,1),o.insert(u,[X(s,i)]),u+=1)}}const p=d-u-h;if(1===d&&0===c&&a[0]instanceof t.XmlText?(i.mapping.delete(a[0]),a[0].delete(0,a[0].length)):p>0&&(o.slice(u,u+p).forEach(e=>i.mapping.delete(e)),o.delete(u,p)),u+h<c){const e=[];for(let t=u;t<c-h;t++)e.push(X(l[t],i));o.insert(u,e)}},oe=(e,t)=>!(t instanceof Array)&&e.nodeName===t.getType(),se=e.createState("ychange",{isEqual:(e,t)=>e===t,parse:e=>e??null});function ie(n,s){const i=s.collabNodeMap.get(n.key);if(void 0===i)return null;let r=n.offset,l=i.getSharedType();if(i instanceof a){l=i._parent._xmlText;const e=i.getOffset();if(-1===e)return null;r=e+1+r}else if(i instanceof f&&"element"===n.type){const t=n.getNode();e.$isElementNode(t)||o(184);let s=0,i=0,l=t.getFirstChild();for(;null!==l&&i++<r;)e.$isTextNode(l)?s+=l.getTextContentSize()+1:s++,l=l.getNextSibling();r=s}return t.createRelativePositionFromTypeIndex(l,r)}function re(n,s){const{mapping:i}=s,{offset:r}=n,l=n.getNode(),c=i.getSharedType(l);if(void 0===c)return null;if("text"===n.type){e.$isTextNode(l)||o(326);let n=l.getPreviousSibling(),s=r;for(;e.$isTextNode(n);)s+=n.getTextContentSize(),n=n.getPreviousSibling();return t.createRelativePositionFromTypeIndex(c,s)}if("element"===n.type){e.$isElementNode(l)||o(184);let n=0,s=l.getFirstChild();for(;null!==s&&n<r;){if(e.$isTextNode(s)){let t=s.getNextSibling();for(;e.$isTextNode(t);)t=t.getNextSibling()}n++,s=s.getNextSibling()}return t.createRelativePositionFromTypeIndex(c,n)}return null}function le(e,n){return t.createAbsolutePositionFromRelativePosition(e,n.doc)}function ce(e,n){if(null==e){if(null!=n)return!0}else if(null==n||!t.compareRelativePositions(e,n))return!0;return!1}function ae(e,t){return{color:t,name:e,selection:null}}function de(e,t){const n=e.cursorsContainer;if(null!==n){const e=t.selections,o=e.length;for(let t=0;t<o;t++)n.removeChild(e[t])}}function fe(e,t){const n=t.selection;null!==n&&de(e,n)}function ue(t,n,o,s,i,r={}){const l=t.color,c=document.createElement("span");r.cursor?(c.className=r.cursor,e.setDOMStyleObject(c.style,{"--lexical-cursor-color":l,bottom:"0",position:"absolute",right:"-1px",top:"0"})):e.setDOMStyleObject(c.style,{"background-color":l,bottom:"0",position:"absolute",right:"-1px",top:"0",width:"1px","z-index":"10"});const a=document.createElement("span");return a.textContent=t.name,r.cursorName?a.className=r.cursorName:e.setDOMStyleObject(a.style,{"background-color":l,color:"#fff","font-family":"Arial","font-size":"12px","font-weight":"bold",left:"-2px","line-height":"12px",padding:"2px",position:"absolute",top:"-16px","white-space":"nowrap"}),c.appendChild(a),{anchor:{key:n,offset:o},caret:c,color:l,focus:{key:s,offset:i},name:a,selections:[]}}function he(t,o,s,i,r={}){const l=t.editor,c=l.getRootElement(),a=t.cursorsContainer;if(null===a||null===c)return;const d=a.offsetParent;if(null===d)return;const f=d.getBoundingClientRect(),u=o.selection;if(null===s)return null===u?void 0:(o.selection=null,void de(t,u));o.selection=s;const h=s.caret,p=s.color,g=s.selections,y=s.anchor,_=s.focus,m=y.key,x=_.key,T=i.get(m),N=i.get(x);if(null==T||null==N)return;let S;if(T===N&&e.$isLineBreakNode(T)){S=[l.getElementByKey(m).getBoundingClientRect()]}else{const e=n.createDOMRange(l,T,y.offset,N,_.offset);if(null===e)return;S=n.createRectsFromDOMRange(l,e)}const b=g.length,E=S.length;for(let t=0;t<E;t++){const n=S[t];let o=g[t];if(void 0===o){o=document.createElement("span"),g[t]=o;const e=document.createElement("span");r.selectionBg&&(e.className=r.selectionBg),o.appendChild(e),a.appendChild(o)}const s=n.top-f.top,i=n.left-f.left,l={height:`${n.height}px`,left:`${i}px`,"pointer-events":"none",position:"absolute",top:`${s}px`,width:`${n.width}px`};r.selection?(o.className=r.selection,e.setDOMStyleObject(o.style,{...l,"--lexical-cursor-color":p}),e.setDOMStyleObject(o.firstChild.style,{height:"100%",left:"0",position:"absolute",top:"0",width:"100%"})):(e.setDOMStyleObject(o.style,l),e.setDOMStyleObject(o.firstChild.style,{...l,"background-color":p,left:"0",opacity:"0.3",top:"0","z-index":"5"})),t===E-1&&h.parentNode!==o&&o.appendChild(h)}for(let e=b-1;e>=E;e--){const t=g[e];a.removeChild(t),g.pop()}}function pe(t,n){const{anchorPos:o,focusPos:s}=n,i=o?le(o,t):null,r=s?le(s,t):null;if(null===i||null===r)return{anchorKey:null,anchorOffset:0,focusKey:null,focusOffset:0};if(g(t)){const[e,t]=_e(i.type,i.index),[n,o]=_e(r.type,r.index);return{anchorKey:null!==e?e.getKey():null,anchorOffset:t,focusKey:null!==n?n.getKey():null,focusOffset:o}}let[l,c]=me(t.mapping,i),[a,d]=me(t.mapping,r);if(a&&l&&(a!==l||d!==c)){const t=a.isBefore(l),n=t?a:l,o=t?d:c;e.$isTextNode(n)&&e.$isTextNode(n.getNextSibling())&&o===n.getTextContentSize()&&(t?(a=n.getNextSibling(),d=0):(l=n.getNextSibling(),c=0))}return{anchorKey:null!==l?l.getKey():null,anchorOffset:c,focusKey:null!==a?a.getKey():null,focusOffset:d}}function ge(t,n){const o=n.awareness.getLocalState();if(null===o)return;const{anchorKey:s,anchorOffset:i,focusKey:r,focusOffset:l}=pe(t,o);if(null!==s&&null!==r){const t=e.$getSelection();if(!e.$isRangeSelection(t))return;ye(t.anchor,s,i),ye(t.focus,r,l)}}function ye(t,n,o){if(t.key!==n||t.offset!==o){let s=e.$getNodeByKey(n);if(null!==s&&!e.$isElementNode(s)&&!e.$isTextNode(s)){const e=s.getParentOrThrow();n=e.getKey(),o=s.getIndexWithinParent(),s=e}t.set(n,o,e.$isElementNode(s)?"element":"text")}}function _e(e,t){const n=e._collabNode;if(void 0===n)return[null,0];if(n instanceof f){const{node:e,offset:o}=w(n,t,!0);return null===e?[n,0]:[e,o]}return[null,0]}function me(n,o){const s=o.type,i=o.index;if(s instanceof t.XmlElement){const t=n.get(s);if(void 0===t)return[null,0];if(!e.$isElementNode(t))return[t,i];let o=i,r=0;const l=t.getChildren();for(;o>0&&r<l.length;){const t=l[r];if(o-=1,r+=1,e.$isTextNode(t))for(;r<l.length&&e.$isTextNode(l[r]);)r+=1}return[t,r]}{const e=n.get(s);if(void 0===e)return[null,0];let t=0,o=i;for(;o>e[t].getTextContentSize()&&t+1<e.length;)o-=e[t].getTextContentSize(),t++;const r=e[t];return[r,Math.min(o,r.getTextContentSize())]}}function xe(e,t){return t.awareness.getStates()}function Te(e,t,n){const{getAwarenessStates:o=xe}=n??{},s=Array.from(o(e,t)),i=e.clientID,r=e.cursors,l=e.editor,c=l._config.theme.collaboration,a=l._editorState._nodeMap,d=new Set;for(let t=0;t<s.length;t++){const n=s[t],[o,f]=n;if(0!==o&&o!==i){d.add(o);const{name:t,color:n,focusing:s}=f;let i=null,u=r.get(o);if(void 0===u&&(u=ae(t,n),r.set(o,u)),s){const{anchorKey:t,anchorOffset:n,focusKey:o,focusOffset:s}=l.read(()=>pe(e,f));if(null!==t&&null!==o)if(i=u.selection,null===i)i=ue(u,t,n,o,s,c);else{const e=i.anchor,r=i.focus;e.key=t,e.offset=n,r.key=o,r.offset=s}}he(e,u,i,a,c)}}const f=Array.from(r.keys());for(let t=0;t<f.length;t++){const n=f[t];if(!d.has(n)){const t=r.get(n);void 0!==t&&(fe(e,t),r.delete(n))}}}function Ne(t,n,o,s){const i=n.awareness,r=i.getLocalState();if(null===r)return;const{anchorPos:l,focusPos:c,name:a,color:d,focusing:f,awarenessData:u}=r;let h=null,p=null;(null!==s&&(null===l||s.is(o))||null!==o)&&(e.$isRangeSelection(s)&&(g(t)?(h=ie(s.anchor,t),p=ie(s.focus,t)):(h=re(s.anchor,t),p=re(s.focus,t))),(ce(l,h)||ce(c,p))&&i.setLocalState({...r,anchorPos:h,awarenessData:u,color:d,focusPos:p,focusing:f,name:a}))}function Se(n,s){if(s instanceof t.YMapEvent&&function(n,o){const{target:s}=o;if(!s._item||"__state"!==s._item.parentSub||void 0!==b(s)||!(s.parent instanceof t.XmlText||s.parent instanceof t.XmlElement||s.parent instanceof t.Map))return!1;const i=E(n,s.parent).getNode();if(i){const t=e.$getWritableNodeState(i.getWritable());for(const e of o.keysChanged)t.updateFromUnknown(e,s.get(e))}return!0}(n,s))return;const{target:r}=s,l=E(n,r);if(l instanceof f&&s instanceof t.YTextEvent){const{keysChanged:e,childListChanged:t,delta:o}=s;e.size>0&&l.syncPropertiesFromYjs(n,e),t&&(l.applyChildrenYjsDelta(n,o),l.syncChildrenFromYjs(n))}else if(l instanceof a&&s instanceof t.YMapEvent){const{keysChanged:e}=s;e.size>0&&l.syncPropertiesAndTextFromYjs(n,e)}else if(l instanceof i&&s instanceof t.YXmlEvent){const{attributesChanged:e}=s;e.size>0&&l.syncPropertiesFromYjs(n,e)}else o(82)}function be(t,n,o){const s=e.$getSelection();if(e.$isRangeSelection(s))if(P(s)){const i=t._selection;if(e.$isRangeSelection(i)&&(ge(n,o),P(s))){L(s.anchor.key,t)}Ne(n,o,i,e.$getSelection())}else ge(n,o)}function Ee(){0===e.$getRoot().getChildrenSize()&&e.$getRoot().append(e.$createParagraphNode())}function Oe(e,n){const{target:s}=n;if(s instanceof t.XmlElement&&n instanceof t.YXmlEvent)I(s,e,n.attributesChanged,n.childListChanged);else if(s instanceof t.XmlText&&n instanceof t.YTextEvent){const n=s.parent;n instanceof t.XmlElement?I(n,e,new Set,!0):o(327)}else o(328)}const Ce=e.createCommand("CONNECTED_COMMAND"),ke=e.createCommand("TOGGLE_CONNECT_COMMAND"),$e=e.createCommand("DIFF_VERSIONS_COMMAND"),ve=e.createCommand("CLEAR_DIFF_VERSIONS_COMMAND");exports.$getYChangeState=function(t){return e.$getState(t,se)},exports.CLEAR_DIFF_VERSIONS_COMMAND__EXPERIMENTAL=ve,exports.CONNECTED_COMMAND=Ce,exports.DIFF_VERSIONS_COMMAND__EXPERIMENTAL=$e,exports.TOGGLE_CONNECT_COMMAND=ke,exports.createBinding=function(e,n,s,i,r,l){null==i&&o(81);const c=u(i.get("root",t.XmlText),null,"root");return c._key="root",{...p(e,s,i,r,l),collabNodeMap:new Map,root:c}},exports.createBindingV2__EXPERIMENTAL=function(e,n,s,i,r={}){null==s&&o(81);const{excludedProperties:l,rootName:c="root-v2"}=r;return{...p(e,n,s,i,l),mapping:new h,root:s.get(c,t.XmlElement)}},exports.createUndoManager=function(e,n){return new t.UndoManager(n,{trackedOrigins:new Set([e,null])})},exports.getAnchorAndFocusCollabNodesForUserState=function(e,t){const{anchorPos:n,focusPos:o}=t;let s=null,i=0,r=null,l=0;if(null!==n&&null!==o){const t=le(n,e),c=le(o,e);null!==t&&null!==c&&([s,i]=_e(t.type,t.index),[r,l]=_e(c.type,c.index))}return{anchorCollabNode:s,anchorOffset:i,focusCollabNode:r,focusOffset:l}},exports.initLocalState=function(e,t,n,o,s){e.awareness.setLocalState({anchorPos:null,awarenessData:s,color:n,focusPos:null,focusing:o,name:t})},exports.renderSnapshot__EXPERIMENTAL=(n,s=t.snapshot(n.doc),i=t.emptySnapshot)=>{const{doc:r}=n;r.gc&&o(325),r.transact(o=>{const l=new t.PermanentUserData(r);l&&l.dss.forEach(e=>{t.iterateDeletedStructs(o,e,e=>{})});const c=(e,t)=>({id:t,type:e,user:("added"===e?l.getUserByClientId(t.client):l.getUserByDeletedId(t))??null});n.mapping.clear(),n.editor.update(()=>{e.$getRoot().clear(),I(n.root,n,null,!0,s,i,c)})},n)},exports.setLocalStateFocus=function(e,t,n,o,s){const{awareness:i}=e;let r=i.getLocalState();null===r&&(r={anchorPos:null,awarenessData:s,color:n,focusPos:null,focusing:o,name:t}),r.focusing=o,i.setLocalState(r)},exports.syncCursorPositions=Te,exports.syncLexicalUpdateToYjs=function(t,n,o,s,i,r,l,c){K(t,()=>{s.read(()=>{if(c.has(e.COLLABORATION_TAG)||c.has(e.HISTORIC_TAG))return void(l.size>0&&function(t,n){const o=Array.from(n),s=t.collabNodeMap,i=[],r=[];for(let t=0;t<o.length;t++){const n=o[t],l=e.$getNodeByKey(n),c=s.get(n);if(c instanceof a)if(e.$isTextNode(l))i.push([c,l.__text]);else{const e=c.getOffset();if(-1===e)continue;const t=c._parent;c._normalized=!0,t._xmlText.delete(e,1),r.push(c)}}for(let e=0;e<r.length;e++){const t=r[e],n=t.getKey();s.delete(n);const o=t._parent._children,i=o.indexOf(t);o.splice(i,1)}for(let e=0;e<i.length;e++){const[t,n]=i[e];t._text=n}}(t,l));if(i.has("root")){const n=o._nodeMap,s=e.$getRoot(),l=t.root;l.syncPropertiesFromLexical(t,s,n),l.syncChildrenFromLexical(t,s,n,i,r)}const s=e.$getSelection(),d=o._selection;Ne(t,n,d,s)})})},exports.syncLexicalUpdateToYjsV2__EXPERIMENTAL=function(t,n,o,s,i,r,l){(l.has(e.COLLABORATION_TAG)||l.has(e.HISTORIC_TAG))&&0===r.size||(r.forEach(e=>{t.mapping.deleteNode(e)}),K(t,()=>{s.read(()=>{i.has("root")&&ne(t.doc,t.root,e.$getRoot(),t,new Set(i.keys()));const s=e.$getSelection(),r=o._selection;Ne(t,n,r,s)})}))},exports.syncYjsChangesToLexical=function(t,n,o,s,i=Te){const r=t.editor,l=r._editorState;o.forEach(e=>e.delta),r.update(()=>{for(let e=0;e<o.length;e++){const n=o[e];Se(t,n)}be(l,t,n),s||e.$addUpdateTag(e.SKIP_SCROLL_INTO_VIEW_TAG)},{onUpdate:()=>{i(t,n),r.update(()=>Ee())},skipTransforms:!0,tag:s?e.HISTORIC_TAG:e.COLLABORATION_TAG})},exports.syncYjsChangesToLexicalV2__EXPERIMENTAL=function(n,o,s,i,r){const l=n.editor,c=l._editorState;t.iterateDeletedStructs(i,i.deleteSet,e=>{if(e.constructor===t.Item){const t=e.content.type;t&&n.mapping.delete(t)}}),s.forEach(e=>e.delta),l.update(()=>{for(let e=0;e<s.length;e++){const t=s[e];Oe(n,t)}be(c,n,o),r||e.$addUpdateTag(e.SKIP_SCROLL_INTO_VIEW_TAG)},{discrete:!0,onUpdate:()=>{Te(n,o),l.update(()=>Ee())},skipTransforms:!0,tag:r?e.HISTORIC_TAG:e.COLLABORATION_TAG})},exports.syncYjsStateToLexicalV2__EXPERIMENTAL=function(t,n){t.mapping.clear();const o=t.editor;o.update(()=>{e.$getRoot().clear(),I(t.root,t,null,!0),e.$addUpdateTag(e.COLLABORATION_TAG)},{discrete:!0,onUpdate:()=>{Te(t,n),o.update(()=>Ee())},skipTransforms:!0,tag:e.COLLABORATION_TAG})};
/**
* 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.
*
*/
import{$isDecoratorNode as e,$getNodeByKey as t,$isLineBreakNode as n,$isTextNode as o,$getSelection as s,$isRangeSelection as i,$isElementNode as r,$createChildrenArray as l,$getNodeByKeyOrThrow as c,removeFromParent as a,isLexicalEditor as f,createEditor as d,$isRootNode as u,$getWritableNodeState as h,$getRoot as p,RootNode as g,ElementNode as _,TextNode as y,$getState as m,createState as x,setDOMStyleObject as b,COLLABORATION_TAG as T,HISTORIC_TAG as k,$addUpdateTag as N,SKIP_SCROLL_INTO_VIEW_TAG as S,$createParagraphNode as v,createCommand as w}from"lexical";import{XmlText as C,XmlElement as O,Map as K,Doc as M,typeListToArraySnapshot as P,Snapshot as E,isDeleted as F,XmlHook as A,ContentString as j,ContentFormat as z,emptySnapshot as L,PermanentUserData as D,iterateDeletedStructs as Y,snapshot as I,createAbsolutePositionFromRelativePosition as W,createRelativePositionFromTypeIndex as $,compareRelativePositions as U,Item as B,YMapEvent as R,YTextEvent as q,YXmlEvent as J,UndoManager as G}from"yjs";import{createDOMRange as V,createRectsFromDOMRange as H}from"@lexical/selection";function Q(e,...t){const n=new URL("https://lexical.dev/docs/error"),o=new URLSearchParams;o.append("code",e);for(const e of t)o.append("v",e);throw n.search=o.toString(),Error(`Minified Lexical error #${e}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}function X(e,t,n){const o=e.length,s=t.length;let i=0,r=0;for(;i<o&&i<s&&e[i]===t[i]&&i<n;)i++;for(;r+i<o&&r+i<s&&e[o-r-1]===t[s-r-1];)r++;for(;r+i<o&&r+i<s&&e[i]===t[i];)i++;return{index:i,insert:t.slice(i,s-r),remove:o-i-r}}class Z{_xmlElem;_key;_parent;_type;constructor(e,t,n){this._key="",this._xmlElem=e,this._parent=t,this._type=n}getPrevNode(t){if(null===t)return null;const n=t.get(this._key);return e(n)?n:null}getNode(){const n=t(this._key);return e(n)?n:null}getSharedType(){return this._xmlElem}getType(){return this._type}getKey(){return this._key}getSize(){return 1}getOffset(){return this._parent.getChildOffset(this)}syncPropertiesFromLexical(e,t,n){const o=this.getPrevNode(n);we(e,this._xmlElem,o,t)}syncPropertiesFromYjs(e,t){const n=this.getNode();null===n&&Q(83);ke(e,this._xmlElem,n,t)}destroy(e){const t=e.collabNodeMap;t.get(this._key)===this&&t.delete(this._key)}}function ee(e,t,n){const o=new Z(e,t,n);return e._collabNode=o,o}class te{_map;_key;_parent;_type;constructor(e,t){this._key="",this._map=e,this._parent=t,this._type="linebreak"}getNode(){const e=t(this._key);return n(e)?e:null}getKey(){return this._key}getSharedType(){return this._map}getType(){return this._type}getSize(){return 1}getOffset(){return this._parent.getChildOffset(this)}destroy(e){const t=e.collabNodeMap;t.get(this._key)===this&&t.delete(this._key)}}function ne(e,t){const n=new te(e,t);return e._collabNode=n,n}class oe{_map;_key;_parent;_text;_type;_normalized;constructor(e,t,n,o){this._key="",this._map=e,this._parent=n,this._text=t,this._type=o,this._normalized=!1}getPrevNode(e){if(null===e)return null;const t=e.get(this._key);return o(t)?t:null}getNode(){const e=t(this._key);return o(e)?e: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(e,t,n){const o=this._parent._xmlText,s=this.getOffset()+1+e;0!==t&&o.delete(s,t),""!==n&&o.insert(s,n)}syncPropertiesAndTextFromLexical(e,t,n){const o=this.getPrevNode(n),r=t.__text;if(we(e,this._map,o,t),null!==o){const e=o.__text;if(e!==r){!function(e,t,n,o){const r=s();let l=o.length;if(i(r)&&r.isCollapsed()){const e=r.anchor;e.key===t&&(l=e.offset)}const c=X(n,o,l);e.spliceText(c.index,c.remove,c.insert)}(this,t.__key,e,r),this._text=r}}}syncPropertiesAndTextFromYjs(e,t){const n=this.getNode();null===n&&Q(84),ke(e,this._map,n,t);const o=this._text;n.__text!==o&&n.setTextContent(o)}destroy(e){const t=e.collabNodeMap;t.get(this._key)===this&&t.delete(this._key)}}function se(e,t,n,o){const s=new oe(e,t,n,o);return e._collabNode=s,s}class ie{_key;_children;_xmlText;_type;_parent;constructor(e,t,n){this._key="",this._children=[],this._xmlText=e,this._type=n,this._parent=t}getPrevNode(e){if(null===e)return null;const t=e.get(this._key);return r(t)?t:null}getNode(){const e=t(this._key);return r(e)?e:null}getSharedType(){return this._xmlText}getType(){return this._type}getKey(){return this._key}isEmpty(){return 0===this._children.length}getSize(){return 1}getOffset(){const e=this._parent;return null===e&&Q(90),e.getChildOffset(this)}syncPropertiesFromYjs(e,t){const n=this.getNode();null===n&&Q(91),ke(e,this._xmlText,n,t)}applyChildrenYjsDelta(e,t){const n=this._children;let o=0,s=null;for(let i=0;i<t.length;i++){const r=t[i],l=r.insert,c=r.delete;if(null!=r.retain)o+=r.retain;else if("number"==typeof c){let e=c;for(;e>0;){const{node:t,nodeIndex:s,offset:i,length:r}=Oe(this,o,!1);if(t instanceof ie||t instanceof te||t instanceof Z)n.splice(s,1),e-=1;else{if(!(t instanceof oe))break;{const o=Math.min(e,r),l=0!==s?n[s-1]:null,c=t.getSize();if(0===i&&r===c){n.splice(s,1);const e=Ce(t._text,i,o-1,"");e.length>0&&(l instanceof oe?l._text+=e:this._xmlText.delete(i,e.length))}else t._text=Ce(t._text,i,o,"");e-=o}}}}else{if(null==l)throw new Error("Unexpected delta format");if("string"==typeof l){const{node:e,offset:t}=Oe(this,o,!0);e instanceof oe?e._text=Ce(e._text,t,0,l):this._xmlText.delete(t,l.length),o+=l.length}else{const t=l,{node:i,nodeIndex:r,length:c}=Oe(this,o,!1),a=be(e,t,this);if(i instanceof oe&&c>0&&c<i._text.length){const e=i._text,t=e.length-c;i._text=Ce(e,t,c,""),n.splice(r+1,0,a),s=Ce(e,0,t,"")}else n.splice(r,0,a);null!==s&&a instanceof oe&&(a._text=s+a._text,s=null),o+=1}}}}syncChildrenFromYjs(e){const t=this.getNode();null===t&&Q(92);const n=t.__key,s=l(t,null),i=s.length,r=this._children,f=r.length,d=e.collabNodeMap,u=new Set;let h,p,g=0,_=null;f!==i&&(p=t.getWritable());for(let i=0;i<f;i++){const l=s[g],y=r[i],m=y.getNode(),x=y._key;if(null!==m&&l===x){const t=o(m);if(u.add(l),t)if(y._key=l,y instanceof ie){const t=y._xmlText;y.syncPropertiesFromYjs(e,null),y.applyChildrenYjsDelta(e,t.toDelta()),y.syncChildrenFromYjs(e)}else y instanceof oe?y.syncPropertiesAndTextFromYjs(e,null):y instanceof Z?y.syncPropertiesFromYjs(e,null):y instanceof te||Q(93);_=m,g++}else{if(void 0===h){h=new Set;for(let e=0;e<f;e++){const t=r[e]._key;""!==t&&h.add(t)}}if(null!==m&&void 0!==l&&!h.has(l)){const e=c(l);a(e),i--,g++;continue}p=t.getWritable();const o=Te(e,y,n),s=o.__key;if(d.set(s,y),null===_){const e=p.getFirstChild();if(p.__first=s,null!==e){const t=e.getWritable();t.__prev=s,o.__next=t.__key}}else{const e=_.getWritable(),t=_.getNextSibling();if(e.__next=s,o.__prev=_.__key,null!==t){const e=t.getWritable();e.__prev=s,o.__next=e.__key}}i===f-1&&(p.__last=s),p.__size++,_=o}}for(let t=0;t<i;t++){const n=s[t];if(!u.has(n)){const t=c(n),o=e.collabNodeMap.get(n);void 0!==o&&o.destroy(e),a(t)}}}syncPropertiesFromLexical(e,t,n){we(e,this._xmlText,this.getPrevNode(n),t)}_syncChildFromLexical(t,n,s,i,l,a){const f=this._children[n],d=c(s);f instanceof ie&&r(d)?(f.syncPropertiesFromLexical(t,d,i),f.syncChildrenFromLexical(t,d,i,l,a)):f instanceof oe&&o(d)?f.syncPropertiesAndTextFromLexical(t,d,i):f instanceof Z&&e(d)&&f.syncPropertiesFromLexical(t,d,i)}syncChildrenFromLexical(e,t,n,o,s){const i=this.getPrevNode(n),r=null===i?[]:l(i,n),a=l(t,null),f=r.length-1,d=a.length-1,u=e.collabNodeMap;let h,p,g=0,_=0;for(;g<=f&&_<=d;){const t=r[g],i=a[_];if(t===i)this._syncChildFromLexical(e,_,i,n,o,s),g++,_++;else{void 0===h&&(h=new Set(r)),void 0===p&&(p=new Set(a));const n=p.has(t),o=h.has(i);if(n){const t=me(e,c(i),this);u.set(i,t),o?(this.splice(e,_,1,t),g++,_++):(this.splice(e,_,0,t),_++)}else this.splice(e,_,1),g++}}const y=g>f,m=_>d;if(y&&!m)for(;_<=d;++_){const t=a[_],n=me(e,c(t),this);this.append(n),u.set(t,n)}else if(m&&!y)for(let t=this._children.length-1;t>=_;t--)this.splice(e,t,1)}append(e){const t=this._xmlText,n=this._children,o=n[n.length-1],s=void 0!==o?o.getOffset()+o.getSize():0;if(e instanceof ie)t.insertEmbed(s,e._xmlText);else if(e instanceof oe){const n=e._map;null===n.parent&&t.insertEmbed(s,n),t.insert(s+1,e._text)}else e instanceof te?t.insertEmbed(s,e._map):e instanceof Z&&t.insertEmbed(s,e._xmlElem);this._children.push(e)}splice(e,t,n,o){const s=this._children,i=s[t];if(void 0===i)return void 0===o&&Q(94),void this.append(o);const r=i.getOffset();-1===r&&Q(95);const l=this._xmlText;if(0!==n&&l.delete(r,i.getSize()),o instanceof ie)l.insertEmbed(r,o._xmlText);else if(o instanceof oe){const e=o._map;null===e.parent&&l.insertEmbed(r,e),l.insert(r+1,o._text)}else o instanceof te?l.insertEmbed(r,o._map):o instanceof Z&&l.insertEmbed(r,o._xmlElem);if(0!==n){const o=s.slice(t,t+n);for(let t=0;t<o.length;t++)o[t].destroy(e)}void 0!==o?s.splice(t,n,o):s.splice(t,n)}getChildOffset(e){let t=0;const n=this._children;for(let o=0;o<n.length;o++){const s=n[o];if(s===e)return t;t+=s.getSize()}return-1}destroy(e){const t=e.collabNodeMap,n=this._children;for(let t=0;t<n.length;t++)n[t].destroy(e);t.get(this._key)===this&&t.delete(this._key)}}function re(e,t,n){const o=new ie(e,t,n);return e._collabNode=o,o}class le{_nodeMap=new Map;_sharedTypeToNodeKeys=new Map;_nodeKeyToSharedType=new Map;set(e,t){const n=t instanceof Array;this.delete(e);const s=n?t:[t];for(const e of s){const t=e.getKey();if(this._nodeKeyToSharedType.has(t)){const e=this._nodeKeyToSharedType.get(t),n=this._sharedTypeToNodeKeys.get(e).indexOf(t);-1!==n&&this._sharedTypeToNodeKeys.get(e).splice(n,1),this._nodeKeyToSharedType.delete(t),this._nodeMap.delete(t)}}if(e instanceof C){if(n||Q(331),0===t.length)return;this._sharedTypeToNodeKeys.set(e,t.map(e=>e.getKey()));for(const n of t)this._nodeMap.set(n.getKey(),n),this._nodeKeyToSharedType.set(n.getKey(),e)}else n&&Q(332),o(t)&&Q(333),this._sharedTypeToNodeKeys.set(e,[t.getKey()]),this._nodeMap.set(t.getKey(),t),this._nodeKeyToSharedType.set(t.getKey(),e)}get(e){const t=this._sharedTypeToNodeKeys.get(e);if(void 0!==t){if(e instanceof C){const e=Array.from(t.map(e=>this._nodeMap.get(e)));return e.length>0?e:void 0}return this._nodeMap.get(t[0])}}getSharedType(e){return this._nodeKeyToSharedType.get(e.getKey())}delete(e){const t=this._sharedTypeToNodeKeys.get(e);if(void 0!==t){for(const e of t)this._nodeMap.delete(e),this._nodeKeyToSharedType.delete(e);this._sharedTypeToNodeKeys.delete(e)}}deleteNode(e){const t=this._nodeKeyToSharedType.get(e);t&&this.delete(t),this._nodeMap.delete(e)}has(e){return this._sharedTypeToNodeKeys.has(e)}clear(){this._nodeMap.clear(),this._sharedTypeToNodeKeys.clear(),this._nodeKeyToSharedType.clear()}}function ce(e,t,n,o,s){null==n&&Q(81);const i={clientID:n.clientID,cursors:new Map,cursorsContainer:null,doc:n,docMap:o,editor:e,excludedProperties:s||new Map,id:t,nodeProperties:new Map};return function(e){const{editor:t,nodeProperties:n}=e;t.update(()=>{t._nodes.forEach(t=>{const o=new t.klass,s={};for(const[t,n]of Object.entries(o))_e(t,o,e)||(s[t]=n);n.set(o.__type,Object.freeze(s))})})}(i),i}function ae(e,t,n,o,s,i){null==o&&Q(81);const r=re(o.get("root",C),null,"root");return r._key="root",{...ce(e,n,o,s,i),collabNodeMap:new Map,root:r}}function fe(e,t,n,o,s={}){null==n&&Q(81);const{excludedProperties:i,rootName:r="root-v2"}=s;return{...ce(e,t,n,o,i),mapping:new le,root:n.get(r,O)}}function de(e){return Object.prototype.hasOwnProperty.call(e,"collabNodeMap")}const ue=new Set(["__key","__parent","__next","__prev","__state"]),he=new Set(["__first","__last","__size"]),pe=new Set(["__cachedText"]),ge=new Set(["__text"]);function _e(e,t,n){if(ue.has(e)||"function"==typeof t[e])return!0;if(o(t)){if(ge.has(e))return!0}else if(r(t)&&(he.has(e)||u(t)&&pe.has(e)))return!0;const s=t.constructor,i=n.excludedProperties.get(s);return null!=i&&i.has(e)}function ye(e,t){const n=e.__type,{nodeProperties:o}=t,s=o.get(n);return void 0===s&&Q(330,n),s}function me(t,s,i){const l=s.__type;let c;if(r(s)){c=re(new C,i,l),c.syncPropertiesFromLexical(t,s,null),c.syncChildrenFromLexical(t,s,null,null,null)}else if(o(s)){c=se(new K,s.__text,i,l),c.syncPropertiesAndTextFromLexical(t,s,null)}else if(n(s)){const e=new K;e.set("__type","linebreak"),c=ne(e,i)}else if(e(s)){c=ee(new O,i,l),c.syncPropertiesFromLexical(t,s,null)}else Q(86);return c._key=s.__key,c}function xe(e){const t=Ne(e,"__type");return"string"!=typeof t&&void 0!==t&&Q(87),t}function be(e,t,n){const o=t._collabNode;if(void 0===o){const o=e.editor._nodes,s=xe(t);"string"!=typeof s&&Q(87);void 0===o.get(s)&&Q(88,s);const i=t.parent,r=void 0===n&&null!==i?be(e,i):n||null;if(r instanceof ie||Q(89),t instanceof C)return re(t,r,s);if(t instanceof K)return"linebreak"===s?ne(t,r):se(t,"",r,s);if(t instanceof O)return ee(t,r,s)}return o}function Te(e,t,n){const o=t.getType(),s=e.editor._nodes.get(o);void 0===s&&Q(88,o);const i=new s.klass;if(i.__parent=n,t._key=i.__key,t instanceof ie){const n=t._xmlText;t.syncPropertiesFromYjs(e,null),t.applyChildrenYjsDelta(e,n.toDelta()),t.syncChildrenFromYjs(e)}else t instanceof oe?t.syncPropertiesAndTextFromYjs(e,null):t instanceof Z&&t.syncPropertiesFromYjs(e,null);return e.collabNodeMap.set(i.__key,t),i}function ke(e,t,n,o){const s=null===o?t instanceof K?Array.from(t.keys()):t instanceof C||t instanceof O?Object.keys(t.getAttributes()):Object.keys(t):Array.from(o);let i;for(let o=0;o<s.length;o++){const r=s[o];if(_e(r,n,e)){"__state"===r&&de(e)&&(i||(i=n.getWritable()),ve(t,i));continue}const l=n[r];let c=Ne(t,r);if(l!==c){if(c instanceof M){const t=e.docMap;l instanceof M&&t.delete(l.guid);const n=c.guid;if(t.set(n,c),f(l))l._key=n,c=l;else{const e=d();e._key=n,c=e}}void 0===i&&(i=n.getWritable()),i[r]=c}}}function Ne(e,t){return e instanceof K?e.get(t):e instanceof C||e instanceof O?e.getAttribute(t):e[t]}function Se(e,t,n){e instanceof K?e.set(t,n):e.setAttribute(t,n)}function ve(e,t){const n=Ne(e,"__state");n instanceof K&&h(t).updateFromJSON(n.toJSON())}function we(e,t,n,o){const s=Object.keys(ye(o,e)),i=e.editor.constructor;!function(e,t,n,o){const s=o.__state,i=null===t.doc?void 0:Ne(t,"__state");if(!s)return;const[r,l]=s.getInternalState(),c=n&&n.__state,a=i instanceof K?i:new K;if(c===s)return;const[f,d]=c&&a.doc?c.getInternalState():[void 0,new Map];if(r)for(const[e,t]of Object.entries(r))f&&t!==f[e]&&a.set(e,t);for(const[e,t]of l)d.get(e)!==t&&a.set(e.key,e.unparse(t));i||Se(t,"__state",a)}(0,t,n,o);for(let r=0;r<s.length;r++){const l=s[r],c=null===n?void 0:n[l];let a=o[l];if(c!==a){if(a instanceof i){const t=e.docMap;let n;if(c instanceof i){const e=c._key;n=t.get(e),t.delete(e)}const s=n||new M,r=s.guid;a._key=r,t.set(r,s),a=s,e.editor.update(()=>{o.markDirty()})}Se(t,l,a)}}}function Ce(e,t,n,o){return e.slice(0,t)+o+e.slice(t+n)}function Oe(e,t,n){let o=0,s=0;const i=e._children,r=i.length;for(;s<r;s++){const e=i[s],l=o;o+=e.getSize();if((n?o>=t:o>t)&&e instanceof oe){let n=t-l-1;n<0&&(n=0);return{length:o-t,node:e,nodeIndex:s,offset:n}}if(o>t)return{length:0,node:e,nodeIndex:s,offset:l};if(s===r-1)return{length:0,node:null,nodeIndex:s+1,offset:l+1}}return{length:0,node:null,nodeIndex:0,offset:0}}function Ke(e){const t=e.anchor,n=e.focus;let s=!1;try{const e=t.getNode(),i=n.getNode();(!e.isAttached()||!i.isAttached()||o(e)&&t.offset>e.getTextContentSize()||o(i)&&n.offset>i.getTextContentSize())&&(s=!0)}catch(e){s=!0}return s}function Me(e,t){e.doc.transact(t,e)}function Pe(e,n){const o=n._nodeMap.get(e);if(!o)return void p().selectStart();const s=o.__prev;let i=null;s&&(i=t(s)),null===i&&null!==o.__parent&&(i=t(o.__parent)),null!==i?null!==i&&i.isAttached()?i.selectEnd():Pe(i.__key,n):p().selectStart()}const Ee=e=>"UNDEFINED"===e.nodeName,Fe=(e,t,n,o,s,i,r)=>{let l=t.mapping.get(e);if(l&&n&&0===n.size&&!o)return l;const c=Ee(e)?g.getType():e.nodeName,a=t.editor._nodes.get(c);if(void 0===a)throw new Error(`$createOrUpdateNodeFromYElement: Node ${c} is not registered`);if(l||(l=new a.klass,n=null,o=!0),o&&l instanceof _){const n=[],o=e=>{if(e instanceof O){const o=Fe(e,t,new Set,!1,s,i,r);null!==o&&n.push(o)}else if(e instanceof C){const o=ze(e,t,s,i,r);null!==o&&o.forEach(e=>{null!==e&&n.push(e)})}else Q(329)};void 0===s||void 0===i?e.toArray().forEach(o):P(e,new E(i.ds,s.sv)).filter(e=>!e._item.deleted||je(e._item,s)||je(e._item,i)).forEach(o),Ae(l,n)}const f=e.getAttributes(s);Ee(e)||void 0===s||(je(e._item,s)?je(e._item,i)||(f[Ve("ychange")]=r?r("added",e._item.id):{type:"added"}):f[Ve("ychange")]=r?r("removed",e._item.id):{type:"removed"});const d={...ye(l,t)},u={};for(const e in f)e.startsWith(Ge)?u[He(e)]=f[e]:d[e]=f[e];if(ke(t,d,l,n),n){if(n.size>0){const e=h(l);for(const t of n)if(t.startsWith(Ge)){const n=He(t);e.updateFromUnknown(n,u[n])}}}else h(l).updateFromJSON(u);const p=l.getLatest();return t.mapping.set(e,p),p},Ae=(e,t)=>{const n=e.getChildren(),o=new Set(n.map(e=>e.getKey())),s=new Set(t.map(e=>e.getKey())),i=n.length-1,r=t.length-1;let l=0,c=0;for(;l<=i&&c<=r;){const i=n[l].getKey(),r=t[c].getKey();if(i===r){l++,c++;continue}const a=s.has(i),f=o.has(r);if(!a){if(0===c&&1===e.getChildrenSize())return void e.splice(c,1,t.slice(c));e.splice(c,1,[]),l++;continue}const d=t[c];f?(e.splice(c,1,[d]),l++,c++):(e.splice(c,0,[d]),c++)}const a=l>i,f=c>r;a&&!f?e.append(...t.slice(c)):f&&!a&&e.splice(t.length,e.getChildrenSize()-t.length,[])},je=(e,t)=>void 0===t?!e.deleted:t.sv.has(e.id.client)&&t.sv.get(e.id.client)>e.id.clock&&!F(t.ds,e.id),ze=(e,t,n,s,i)=>{const r=qe(e,n,s,i);let l=t.mapping.get(e)??[];const c=r.map(e=>e.attributes.t??y.getType());if(!(l.length===c.length&&l.every((e,t)=>e.getType()===c[t]))){const e=t.editor._nodes;l=c.map(t=>{const n=e.get(t);if(void 0===n)throw new Error(`$createTextNodesFromYText: Node ${t} is not registered`);const s=new n.klass;if(!o(s))throw new Error(`$createTextNodesFromYText: Node ${t} is not a TextNode`);return s})}for(let e=0;e<r.length;e++){const n=l[e],o=r[e],{attributes:s,insert:i}=o;n.__text!==i&&n.setTextContent(i);const c={...ye(n,t),...s.p},a=Object.fromEntries(Object.entries(s).filter(([e])=>e.startsWith(Ge)).map(([e,t])=>[He(e),t]));ke(t,c,n,null),h(n).updateFromJSON(a)}const a=l.map(e=>e.getLatest());return t.mapping.set(e,a),a},Le=(e,t)=>e instanceof Array?((e,t)=>{const n=new C;return Re(n,e,t),n})(e,t):((e,t)=>{const n=new O(e.getType()),o={...Je(e,t),...Qe(e)};for(const e in o){const t=o[e];null!==t&&n.setAttribute(e,t)}return e instanceof _?(n.insert(0,Ie(e).map(e=>Le(e,t))),t.mapping.set(n,e),n):n})(e,t),De=e=>"object"==typeof e&&null!=e,Ye=(e,t)=>{const n=Object.keys(e).filter(t=>null!==e[t]);if(null==t)return 0===n.length;let o=n.length===Object.keys(t).filter(e=>null!==t[e]).length;for(let s=0;s<n.length&&o;s++){const i=n[s],r=e[i],l=t[i];o="ychange"===i||r===l||De(r)&&De(l)&&Ye(r,l)}return o},Ie=e=>{if(!(e instanceof _))return[];const t=e.getChildren(),n=[];for(let e=0;e<t.length;e++){const s=t[e];if(o(s)){const s=[];for(let n=t[e];e<t.length&&o(n);n=t[++e])s.push(n);e--,n.push(s)}else n.push(s)}return n},We=(e,t,n)=>{const o=qe(e);return o.length===t.length&&o.every((e,o)=>{const s=t[o],i=e.attributes.t??y.getType(),r=e.attributes.p??{},l=Object.fromEntries(Object.entries(e.attributes).filter(([e])=>e.startsWith(Ge)));return e.insert===s.getTextContent()&&i===s.getType()&&Ye(r,Je(s,n))&&Ye(l,Qe(s))})},$e=(e,t,n)=>{if(e instanceof O&&!(t instanceof Array)&&Ze(e,t)){const o=Ie(t);return e._length===o.length&&Ye(e.getAttributes(),{...Je(t,n),...Qe(t)})&&e.toArray().every((e,t)=>$e(e,o[t],n))}return e instanceof C&&t instanceof Array&&We(e,t,n)},Ue=(e,t)=>e===t||e instanceof Array&&t instanceof Array&&e.length===t.length&&e.every((e,n)=>t[n]===e),Be=(e,t,n)=>{const o=e.toArray(),s=Ie(t),i=s.length,r=o.length,l=Math.min(r,i);let c=0,a=0,f=!1;for(;c<l;c++){const e=o[c],t=s[c];if(e instanceof A)break;if(Ue(n.mapping.get(e),t))f=!0;else if(!$e(e,t,n))break}for(;c+a<l;a++){const e=o[r-a-1],t=s[i-a-1];if(e instanceof A)break;if(Ue(n.mapping.get(e),t))f=!0;else if(!$e(e,t,n))break}return{equalityFactor:c+a,foundMappedChild:f}},Re=(e,t,n)=>{n.mapping.set(e,t);const{nAttrs:o,str:r}=(e=>{let t="",n=e._start;const o={};for(;null!==n;)n.deleted||(n.countable&&n.content instanceof j?t+=n.content.str:n.content instanceof z&&(o[n.content.key]=null)),n=n.right;return{nAttrs:o,str:t}})(e),l=t.map((e,t)=>{const s=e.getType();let i=Je(e,n);return 0===Object.keys(i).length&&(i=null),{attributes:Object.assign({},o,{...s!==y.getType()&&{t:s},p:i,...Qe(e),...t>0&&{i:t}}),insert:e.getTextContent(),nodeKey:e.getKey()}}),c=l.map(e=>e.insert).join(""),a=s();let f;if(i(a)&&a.isCollapsed()){f=0;for(const e of l){if(e.nodeKey===a.anchor.key){f+=a.anchor.offset;break}f+=e.insert.length}}else f=c.length;const{insert:d,remove:u,index:h}=X(r,c,f);e.delete(h,u),e.insert(h,d),e.applyDelta(l.map(e=>({attributes:e.attributes,retain:e.insert.length})))},qe=(e,t,n,o)=>e.toDelta(t,n,o).map(e=>{const t=e.attributes??{};return"ychange"in t&&(t[Ve("ychange")]=t.ychange,delete t.ychange),{...e,attributes:t}}),Je=(e,t)=>{const n=ye(e,t),o={};return Object.entries(n).forEach(([t,n])=>{const s=e[t];s!==n&&(o[t]=s)}),o},Ge="s_",Ve=e=>`s_${e}`,He=e=>{if(!e.startsWith(Ge))throw new Error(`Invalid state key: ${e}`);return e.slice(Ge.length)},Qe=e=>{const t=e.__state;if(!t)return{};const[n={},o]=t.getInternalState(),s={};for(const[e,t]of Object.entries(n))s[Ve(e)]=t;for(const[e,t]of o)s[Ve(e.key)]=e.unparse(t);return s},Xe=(e,t,n,o,s)=>{if(t instanceof O&&t.nodeName!==n.getType()&&(!Ee(t)||n.getType()!==g.getType()))throw new Error("node name mismatch!");if(o.mapping.set(t,n),t instanceof O){const e=t.getAttributes(),s={...Je(n,o),...Qe(n)};for(const n in s)if(null!=s[n]){e[n]===s[n]||De(e[n])&&De(s[n])&&Ye(e[n],s[n])||"ychange"===n||t.setAttribute(n,s[n])}else t.removeAttribute(n);for(const n in e)void 0===s[n]&&t.removeAttribute(n)}const i=Ie(n),r=i.length,l=t.toArray(),c=l.length,a=Math.min(r,c);let f=0,d=0;for(;f<a;f++){const t=l[f],n=i[f];if(t instanceof A)break;if(Ue(o.mapping.get(t),n))n instanceof _&&s.has(n.getKey())&&Xe(e,t,n,o,s);else{if(!$e(t,n,o))break;o.mapping.set(t,n)}}for(;d+f<a;d++){const t=l[c-d-1],n=i[r-d-1];if(t instanceof A)break;if(Ue(o.mapping.get(t),n))n instanceof _&&s.has(n.getKey())&&Xe(e,t,n,o,s);else{if(!$e(t,n,o))break;o.mapping.set(t,n)}}for(;c-f-d>0&&r-f-d>0;){const n=l[f],a=i[f],u=l[c-d-1],h=i[r-d-1];if(n instanceof C&&a instanceof Array)We(n,a,o)||Re(n,a,o),f+=1;else{let i=n instanceof O&&Ze(n,a),r=u instanceof O&&Ze(u,h);if(i&&r){const e=Be(n,a,o),t=Be(u,h,o);e.foundMappedChild&&!t.foundMappedChild?r=!1:!e.foundMappedChild&&t.foundMappedChild||e.equalityFactor<t.equalityFactor?i=!1:r=!1}i?(Xe(e,n,a,o,s),f+=1):r?(Xe(e,u,h,o,s),d+=1):(o.mapping.delete(t.get(f)),t.delete(f,1),t.insert(f,[Le(a,o)]),f+=1)}}const u=c-f-d;if(1===c&&0===r&&l[0]instanceof C?(o.mapping.delete(l[0]),l[0].delete(0,l[0].length)):u>0&&(t.slice(f,f+u).forEach(e=>o.mapping.delete(e)),t.delete(f,u)),f+d<r){const e=[];for(let t=f;t<r-d;t++)e.push(Le(i[t],o));t.insert(f,e)}},Ze=(e,t)=>!(t instanceof Array)&&e.nodeName===t.getType(),et=x("ychange",{isEqual:(e,t)=>e===t,parse:e=>e??null});function tt(e){return m(e,et)}const nt=(e,t=I(e.doc),n=L)=>{const{doc:o}=e;o.gc&&Q(325),o.transact(s=>{const i=new D(o);i&&i.dss.forEach(e=>{Y(s,e,e=>{})});const r=(e,t)=>({id:t,type:e,user:("added"===e?i.getUserByClientId(t.client):i.getUserByDeletedId(t))??null});e.mapping.clear(),e.editor.update(()=>{p().clear(),Fe(e.root,e,null,!0,t,n,r)})},e)};function ot(e,t){const n=t.collabNodeMap.get(e.key);if(void 0===n)return null;let s=e.offset,i=n.getSharedType();if(n instanceof oe){i=n._parent._xmlText;const e=n.getOffset();if(-1===e)return null;s=e+1+s}else if(n instanceof ie&&"element"===e.type){const t=e.getNode();r(t)||Q(184);let n=0,i=0,l=t.getFirstChild();for(;null!==l&&i++<s;)o(l)?n+=l.getTextContentSize()+1:n++,l=l.getNextSibling();s=n}return $(i,s)}function st(e,t){const{mapping:n}=t,{offset:s}=e,i=e.getNode(),l=n.getSharedType(i);if(void 0===l)return null;if("text"===e.type){o(i)||Q(326);let e=i.getPreviousSibling(),t=s;for(;o(e);)t+=e.getTextContentSize(),e=e.getPreviousSibling();return $(l,t)}if("element"===e.type){r(i)||Q(184);let e=0,t=i.getFirstChild();for(;null!==t&&e<s;){if(o(t)){let e=t.getNextSibling();for(;o(e);)e=e.getNextSibling()}e++,t=t.getNextSibling()}return $(l,e)}return null}function it(e,t){return W(e,t.doc)}function rt(e,t){if(null==e){if(null!=t)return!0}else if(null==t||!U(e,t))return!0;return!1}function lt(e,t){return{color:t,name:e,selection:null}}function ct(e,t){const n=e.cursorsContainer;if(null!==n){const e=t.selections,o=e.length;for(let t=0;t<o;t++)n.removeChild(e[t])}}function at(e,t){const n=t.selection;null!==n&&ct(e,n)}function ft(e,t,n,o,s,i={}){const r=e.color,l=document.createElement("span");i.cursor?(l.className=i.cursor,b(l.style,{"--lexical-cursor-color":r,bottom:"0",position:"absolute",right:"-1px",top:"0"})):b(l.style,{"background-color":r,bottom:"0",position:"absolute",right:"-1px",top:"0",width:"1px","z-index":"10"});const c=document.createElement("span");return c.textContent=e.name,i.cursorName?c.className=i.cursorName:b(c.style,{"background-color":r,color:"#fff","font-family":"Arial","font-size":"12px","font-weight":"bold",left:"-2px","line-height":"12px",padding:"2px",position:"absolute",top:"-16px","white-space":"nowrap"}),l.appendChild(c),{anchor:{key:t,offset:n},caret:l,color:r,focus:{key:o,offset:s},name:c,selections:[]}}function dt(e,t,o,s,i={}){const r=e.editor,l=r.getRootElement(),c=e.cursorsContainer;if(null===c||null===l)return;const a=c.offsetParent;if(null===a)return;const f=a.getBoundingClientRect(),d=t.selection;if(null===o)return null===d?void 0:(t.selection=null,void ct(e,d));t.selection=o;const u=o.caret,h=o.color,p=o.selections,g=o.anchor,_=o.focus,y=g.key,m=_.key,x=s.get(y),T=s.get(m);if(null==x||null==T)return;let k;if(x===T&&n(x)){k=[r.getElementByKey(y).getBoundingClientRect()]}else{const e=V(r,x,g.offset,T,_.offset);if(null===e)return;k=H(r,e)}const N=p.length,S=k.length;for(let e=0;e<S;e++){const t=k[e];let n=p[e];if(void 0===n){n=document.createElement("span"),p[e]=n;const t=document.createElement("span");i.selectionBg&&(t.className=i.selectionBg),n.appendChild(t),c.appendChild(n)}const o=t.top-f.top,s=t.left-f.left,r={height:`${t.height}px`,left:`${s}px`,"pointer-events":"none",position:"absolute",top:`${o}px`,width:`${t.width}px`};i.selection?(n.className=i.selection,b(n.style,{...r,"--lexical-cursor-color":h}),b(n.firstChild.style,{height:"100%",left:"0",position:"absolute",top:"0",width:"100%"})):(b(n.style,r),b(n.firstChild.style,{...r,"background-color":h,left:"0",opacity:"0.3",top:"0","z-index":"5"})),e===S-1&&u.parentNode!==n&&n.appendChild(u)}for(let e=N-1;e>=S;e--){const t=p[e];c.removeChild(t),p.pop()}}function ut(e,t){const{anchorPos:n,focusPos:o}=t;let s=null,i=0,r=null,l=0;if(null!==n&&null!==o){const t=it(n,e),c=it(o,e);null!==t&&null!==c&&([s,i]=_t(t.type,t.index),[r,l]=_t(c.type,c.index))}return{anchorCollabNode:s,anchorOffset:i,focusCollabNode:r,focusOffset:l}}function ht(e,t){const{anchorPos:n,focusPos:s}=t,i=n?it(n,e):null,r=s?it(s,e):null;if(null===i||null===r)return{anchorKey:null,anchorOffset:0,focusKey:null,focusOffset:0};if(de(e)){const[e,t]=_t(i.type,i.index),[n,o]=_t(r.type,r.index);return{anchorKey:null!==e?e.getKey():null,anchorOffset:t,focusKey:null!==n?n.getKey():null,focusOffset:o}}let[l,c]=yt(e.mapping,i),[a,f]=yt(e.mapping,r);if(a&&l&&(a!==l||f!==c)){const e=a.isBefore(l),t=e?a:l,n=e?f:c;o(t)&&o(t.getNextSibling())&&n===t.getTextContentSize()&&(e?(a=t.getNextSibling(),f=0):(l=t.getNextSibling(),c=0))}return{anchorKey:null!==l?l.getKey():null,anchorOffset:c,focusKey:null!==a?a.getKey():null,focusOffset:f}}function pt(e,t){const n=t.awareness.getLocalState();if(null===n)return;const{anchorKey:o,anchorOffset:r,focusKey:l,focusOffset:c}=ht(e,n);if(null!==o&&null!==l){const e=s();if(!i(e))return;gt(e.anchor,o,r),gt(e.focus,l,c)}}function gt(e,n,s){if(e.key!==n||e.offset!==s){let i=t(n);if(null!==i&&!r(i)&&!o(i)){const e=i.getParentOrThrow();n=e.getKey(),s=i.getIndexWithinParent(),i=e}e.set(n,s,r(i)?"element":"text")}}function _t(e,t){const n=e._collabNode;if(void 0===n)return[null,0];if(n instanceof ie){const{node:e,offset:o}=Oe(n,t,!0);return null===e?[n,0]:[e,o]}return[null,0]}function yt(e,t){const n=t.type,s=t.index;if(n instanceof O){const t=e.get(n);if(void 0===t)return[null,0];if(!r(t))return[t,s];let i=s,l=0;const c=t.getChildren();for(;i>0&&l<c.length;){const e=c[l];if(i-=1,l+=1,o(e))for(;l<c.length&&o(c[l]);)l+=1}return[t,l]}{const t=e.get(n);if(void 0===t)return[null,0];let o=0,i=s;for(;i>t[o].getTextContentSize()&&o+1<t.length;)i-=t[o].getTextContentSize(),o++;const r=t[o];return[r,Math.min(i,r.getTextContentSize())]}}function mt(e,t){return t.awareness.getStates()}function xt(e,t,n){const{getAwarenessStates:o=mt}=n??{},s=Array.from(o(e,t)),i=e.clientID,r=e.cursors,l=e.editor,c=l._config.theme.collaboration,a=l._editorState._nodeMap,f=new Set;for(let t=0;t<s.length;t++){const n=s[t],[o,d]=n;if(0!==o&&o!==i){f.add(o);const{name:t,color:n,focusing:s}=d;let i=null,u=r.get(o);if(void 0===u&&(u=lt(t,n),r.set(o,u)),s){const{anchorKey:t,anchorOffset:n,focusKey:o,focusOffset:s}=l.read(()=>ht(e,d));if(null!==t&&null!==o)if(i=u.selection,null===i)i=ft(u,t,n,o,s,c);else{const e=i.anchor,r=i.focus;e.key=t,e.offset=n,r.key=o,r.offset=s}}dt(e,u,i,a,c)}}const d=Array.from(r.keys());for(let t=0;t<d.length;t++){const n=d[t];if(!f.has(n)){const t=r.get(n);void 0!==t&&(at(e,t),r.delete(n))}}}function bt(e,t,n,o){const s=t.awareness,r=s.getLocalState();if(null===r)return;const{anchorPos:l,focusPos:c,name:a,color:f,focusing:d,awarenessData:u}=r;let h=null,p=null;(null!==o&&(null===l||o.is(n))||null!==n)&&(i(o)&&(de(e)?(h=ot(o.anchor,e),p=ot(o.focus,e)):(h=st(o.anchor,e),p=st(o.focus,e))),(rt(l,h)||rt(c,p))&&s.setLocalState({...r,anchorPos:h,awarenessData:u,color:f,focusPos:p,focusing:d,name:a}))}function Tt(e,t){if(t instanceof R&&function(e,t){const{target:n}=t;if(!n._item||"__state"!==n._item.parentSub||void 0!==xe(n)||!(n.parent instanceof C||n.parent instanceof O||n.parent instanceof K))return!1;const o=be(e,n.parent).getNode();if(o){const e=h(o.getWritable());for(const o of t.keysChanged)e.updateFromUnknown(o,n.get(o))}return!0}(e,t))return;const{target:n}=t,o=be(e,n);if(o instanceof ie&&t instanceof q){const{keysChanged:n,childListChanged:s,delta:i}=t;n.size>0&&o.syncPropertiesFromYjs(e,n),s&&(o.applyChildrenYjsDelta(e,i),o.syncChildrenFromYjs(e))}else if(o instanceof oe&&t instanceof R){const{keysChanged:n}=t;n.size>0&&o.syncPropertiesAndTextFromYjs(e,n)}else if(o instanceof Z&&t instanceof J){const{attributesChanged:n}=t;n.size>0&&o.syncPropertiesFromYjs(e,n)}else Q(82)}function kt(e,t,n,o,s=xt){const i=e.editor,r=i._editorState;n.forEach(e=>e.delta),i.update(()=>{for(let t=0;t<n.length;t++){const o=n[t];Tt(e,o)}Nt(r,e,t),o||N(S)},{onUpdate:()=>{s(e,t),i.update(()=>St())},skipTransforms:!0,tag:o?k:T})}function Nt(e,t,n){const o=s();if(i(o))if(Ke(o)){const r=e._selection;if(i(r)&&(pt(t,n),Ke(o))){Pe(o.anchor.key,e)}bt(t,n,r,s())}else pt(t,n)}function St(){0===p().getChildrenSize()&&p().append(v())}function vt(e,n,i,r,l,c,a,f){Me(e,()=>{r.read(()=>{if(f.has(T)||f.has(k))return void(a.size>0&&function(e,n){const s=Array.from(n),i=e.collabNodeMap,r=[],l=[];for(let e=0;e<s.length;e++){const n=s[e],c=t(n),a=i.get(n);if(a instanceof oe)if(o(c))r.push([a,c.__text]);else{const e=a.getOffset();if(-1===e)continue;const t=a._parent;a._normalized=!0,t._xmlText.delete(e,1),l.push(a)}}for(let e=0;e<l.length;e++){const t=l[e],n=t.getKey();i.delete(n);const o=t._parent._children,s=o.indexOf(t);o.splice(s,1)}for(let e=0;e<r.length;e++){const[t,n]=r[e];t._text=n}}(e,a));if(l.has("root")){const t=i._nodeMap,n=p(),o=e.root;o.syncPropertiesFromLexical(e,n,t),o.syncChildrenFromLexical(e,n,t,l,c)}const r=s(),d=i._selection;bt(e,n,d,r)})})}function wt(e,t){const{target:n}=t;if(n instanceof O&&t instanceof J)Fe(n,e,t.attributesChanged,t.childListChanged);else if(n instanceof C&&t instanceof q){const t=n.parent;t instanceof O?Fe(t,e,new Set,!0):Q(327)}else Q(328)}function Ct(e,t,n,o,s){const i=e.editor,r=i._editorState;Y(o,o.deleteSet,t=>{if(t.constructor===B){const n=t.content.type;n&&e.mapping.delete(n)}}),n.forEach(e=>e.delta),i.update(()=>{for(let t=0;t<n.length;t++){const o=n[t];wt(e,o)}Nt(r,e,t),s||N(S)},{discrete:!0,onUpdate:()=>{xt(e,t),i.update(()=>St())},skipTransforms:!0,tag:s?k:T})}function Ot(e,t){e.mapping.clear();const n=e.editor;n.update(()=>{p().clear(),Fe(e.root,e,null,!0),N(T)},{discrete:!0,onUpdate:()=>{xt(e,t),n.update(()=>St())},skipTransforms:!0,tag:T})}function Kt(e,t,n,o,i,r,l){(l.has(T)||l.has(k))&&0===r.size||(r.forEach(t=>{e.mapping.deleteNode(t)}),Me(e,()=>{o.read(()=>{i.has("root")&&Xe(e.doc,e.root,p(),e,new Set(i.keys()));const o=s(),r=n._selection;bt(e,t,r,o)})}))}const Mt=w("CONNECTED_COMMAND"),Pt=w("TOGGLE_CONNECT_COMMAND"),Et=w("DIFF_VERSIONS_COMMAND"),Ft=w("CLEAR_DIFF_VERSIONS_COMMAND");function At(e,t){return new G(t,{trackedOrigins:new Set([e,null])})}function jt(e,t,n,o,s){e.awareness.setLocalState({anchorPos:null,awarenessData:s,color:n,focusPos:null,focusing:o,name:t})}function zt(e,t,n,o,s){const{awareness:i}=e;let r=i.getLocalState();null===r&&(r={anchorPos:null,awarenessData:s,color:n,focusPos:null,focusing:o,name:t}),r.focusing=o,i.setLocalState(r)}export{tt as $getYChangeState,Ft as CLEAR_DIFF_VERSIONS_COMMAND__EXPERIMENTAL,Mt as CONNECTED_COMMAND,Et as DIFF_VERSIONS_COMMAND__EXPERIMENTAL,Pt as TOGGLE_CONNECT_COMMAND,ae as createBinding,fe as createBindingV2__EXPERIMENTAL,At as createUndoManager,ut as getAnchorAndFocusCollabNodesForUserState,jt as initLocalState,nt as renderSnapshot__EXPERIMENTAL,zt as setLocalStateFocus,xt as syncCursorPositions,vt as syncLexicalUpdateToYjs,Kt as syncLexicalUpdateToYjsV2__EXPERIMENTAL,kt as syncYjsChangesToLexical,Ct as syncYjsChangesToLexicalV2__EXPERIMENTAL,Ot as syncYjsStateToLexicalV2__EXPERIMENTAL};
import { LexicalNode } from 'lexical';
import { ID, Snapshot } from 'yjs';
import { BindingV2 } from './Bindings';
export type YChange<UserT = any> = {
id: ID;
type: 'removed' | 'added';
user: UserT | null;
};
export declare function $getYChangeState<UserT = unknown>(node: LexicalNode): YChange<UserT> | null;
/**
* Replaces the editor content with a view that compares the state between two given snapshots.
* Any added or removed nodes between the two snapshots will have {@link YChange} attached to them.
*
* @param binding Yjs binding
* @param snapshot Ending snapshot state (default: current state of the Yjs document)
* @param prevSnapshot Starting snapshot state (default: empty snapshot)
*/
export declare const renderSnapshot__EXPERIMENTAL: (binding: BindingV2, snapshot?: Snapshot, prevSnapshot?: Snapshot) => void;
/**
* 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.
*
*/
export default function simpleDiffWithCursor(a: string, b: string, cursor: number): {
index: number;
insert: string;
remove: number;
};
/**
* 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.
*
*/
import type { BaseSelection, NodeKey } from 'lexical';
import { Provider, UserState } from '.';
import { AnyBinding, type BaseBinding, type Binding } from './Bindings';
import { CollabDecoratorNode } from './CollabDecoratorNode';
import { CollabElementNode } from './CollabElementNode';
import { CollabLineBreakNode } from './CollabLineBreakNode';
import { CollabTextNode } from './CollabTextNode';
export type CursorSelection = {
anchor: {
key: NodeKey;
offset: number;
};
caret: HTMLElement;
color: string;
focus: {
key: NodeKey;
offset: number;
};
name: HTMLSpanElement;
selections: Array<HTMLElement>;
};
export type Cursor = {
color: string;
name: string;
selection: null | CursorSelection;
};
type AnyCollabNode = CollabDecoratorNode | CollabElementNode | CollabTextNode | CollabLineBreakNode;
/**
* @deprecated Use `$getAnchorAndFocusForUserState` instead.
*/
export declare function getAnchorAndFocusCollabNodesForUserState(binding: Binding, userState: UserState): {
anchorCollabNode: AnyCollabNode | null;
anchorOffset: number;
focusCollabNode: AnyCollabNode | null;
focusOffset: number;
};
export declare function $getAnchorAndFocusForUserState(binding: AnyBinding, userState: UserState): {
anchorKey: NodeKey | null;
anchorOffset: number;
focusKey: NodeKey | null;
focusOffset: number;
};
export declare function $syncLocalCursorPosition(binding: AnyBinding, provider: Provider): void;
export type SyncCursorPositionsFn = (binding: AnyBinding, provider: Provider, options?: SyncCursorPositionsOptions) => void;
export type SyncCursorPositionsOptions = {
getAwarenessStates?: (binding: BaseBinding, provider: Provider) => Map<number, UserState>;
};
export declare function syncCursorPositions(binding: AnyBinding, provider: Provider, options?: SyncCursorPositionsOptions): void;
export declare function syncLexicalSelectionToYjs(binding: AnyBinding, provider: Provider, prevSelection: null | BaseSelection, nextSelection: null | BaseSelection): void;
export {};
/**
* 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.
*
*/
import type { EditorState, NodeKey } from 'lexical';
import type { Transaction as YTransaction } from 'yjs';
import { Text as YText, XmlElement, XmlText, YEvent } from 'yjs';
import { Binding, BindingV2, Provider } from '.';
import { SyncCursorPositionsFn } from './SyncCursors';
export declare function syncYjsChangesToLexical(binding: Binding, provider: Provider, events: Array<YEvent<YText>>, isFromUndoManger: boolean, syncCursorPositionsFn?: SyncCursorPositionsFn): void;
type IntentionallyMarkedAsDirtyElement = boolean;
export declare function syncLexicalUpdateToYjs(binding: Binding, provider: Provider, prevEditorState: EditorState, currEditorState: EditorState, dirtyElements: Map<NodeKey, IntentionallyMarkedAsDirtyElement>, dirtyLeaves: Set<NodeKey>, normalizedNodes: Set<NodeKey>, tags: Set<string>): void;
export declare function syncYjsChangesToLexicalV2__EXPERIMENTAL(binding: BindingV2, provider: Provider, events: Array<YEvent<XmlElement | XmlText>>, transaction: YTransaction, isFromUndoManger: boolean): void;
export declare function syncYjsStateToLexicalV2__EXPERIMENTAL(binding: BindingV2, provider: Provider): void;
export declare function syncLexicalUpdateToYjsV2__EXPERIMENTAL(binding: BindingV2, provider: Provider, prevEditorState: EditorState, currEditorState: EditorState, dirtyElements: Map<NodeKey, IntentionallyMarkedAsDirtyElement>, normalizedNodes: Set<NodeKey>, tags: Set<string>): void;
export {};
/**
* 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.
*
*/
import { LexicalNode, NodeKey } from 'lexical';
import { Doc as YDoc, ID, Snapshot, XmlElement } from 'yjs';
import { BindingV2 } from './Bindings';
type ComputeYChange = (event: 'removed' | 'added', id: ID) => Record<string, unknown>;
export declare const $createOrUpdateNodeFromYElement: (el: XmlElement, binding: BindingV2, keysChanged: Set<string> | null, childListChanged: boolean, snapshot?: Snapshot, prevSnapshot?: Snapshot, computeYChange?: ComputeYChange) => LexicalNode | null;
export declare const $updateYFragment: (y: YDoc, yDomFragment: XmlElement, node: LexicalNode, binding: BindingV2, dirtyElements: Set<NodeKey>) => void;
export {};
/**
* 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.
*
*/
import { CollabDecoratorNode } from './CollabDecoratorNode';
import { CollabElementNode } from './CollabElementNode';
import { CollabLineBreakNode } from './CollabLineBreakNode';
import { CollabTextNode } from './CollabTextNode';
declare module 'yjs' {
interface XmlElement {
_collabNode: CollabDecoratorNode;
}
interface XmlText {
_collabNode: CollabElementNode;
}
interface Map<MapType> {
_collabNode: CollabLineBreakNode | CollabTextNode;
}
}
/**
* 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.
*
*/
import type { BaseBinding, Binding, YjsNode } from '.';
import { EditorState, LexicalNode, NodeKey, RangeSelection } from 'lexical';
import { Map as YMap, XmlElement, XmlText } from 'yjs';
import { CollabDecoratorNode } from './CollabDecoratorNode';
import { CollabElementNode } from './CollabElementNode';
import { CollabLineBreakNode } from './CollabLineBreakNode';
import { CollabTextNode } from './CollabTextNode';
export declare function initializeNodeProperties(binding: BaseBinding): void;
export declare function getDefaultNodeProperties(node: LexicalNode, binding: BaseBinding): {
[property: string]: unknown;
};
export declare function getIndexOfYjsNode(yjsParentNode: YjsNode, yjsNode: YjsNode): number;
export declare function $createCollabNodeFromLexicalNode(binding: Binding, lexicalNode: LexicalNode, parent: CollabElementNode): CollabElementNode | CollabTextNode | CollabLineBreakNode | CollabDecoratorNode;
export declare function getNodeTypeFromSharedType(sharedType: XmlText | YMap<unknown> | XmlElement): string | undefined;
export declare function $getOrInitCollabNodeFromSharedType(binding: Binding, sharedType: XmlText | YMap<unknown> | XmlElement, parent?: CollabElementNode): CollabElementNode | CollabTextNode | CollabLineBreakNode | CollabDecoratorNode;
export declare function createLexicalNodeFromCollabNode(binding: Binding, collabNode: CollabElementNode | CollabTextNode | CollabDecoratorNode | CollabLineBreakNode, parentKey: NodeKey): LexicalNode;
export declare function $syncPropertiesFromYjs(binding: BaseBinding, sharedType: XmlText | YMap<unknown> | XmlElement | Record<string, unknown>, lexicalNode: LexicalNode, keysChanged: null | Set<string>): void;
export declare function syncPropertiesFromLexical(binding: Binding, sharedType: XmlText | YMap<unknown> | XmlElement, prevLexicalNode: null | LexicalNode, nextLexicalNode: LexicalNode): void;
export declare function spliceString(str: string, index: number, delCount: number, newText: string): string;
export declare function getPositionFromElementAndOffset(node: CollabElementNode, offset: number, boundaryIsEdge: boolean): {
length: number;
node: CollabElementNode | CollabTextNode | CollabDecoratorNode | CollabLineBreakNode | null;
nodeIndex: number;
offset: number;
};
export declare function doesSelectionNeedRecovering(selection: RangeSelection): boolean;
export declare function syncWithTransaction(binding: BaseBinding, fn: () => void): void;
export declare function $moveSelectionToPreviousNode(anchorNodeKey: string, currentEditorState: EditorState): void;
/**
* 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.
*
*/
import type {CollabDecoratorNode} from './CollabDecoratorNode';
import type {CollabElementNode} from './CollabElementNode';
import type {CollabLineBreakNode} from './CollabLineBreakNode';
import type {CollabTextNode} from './CollabTextNode';
import type {Cursor} from './SyncCursors';
import type {LexicalEditor, NodeKey} from 'lexical';
import invariant from '@lexical/internal/invariant';
import {Klass, LexicalNode} from 'lexical';
import {Doc, XmlElement, XmlText} from 'yjs';
import {Provider} from '.';
import {$createCollabElementNode} from './CollabElementNode';
import {CollabV2Mapping} from './CollabV2Mapping';
import {initializeNodeProperties} from './Utils';
export type ClientID = number;
export interface BaseBinding {
clientID: number;
cursors: Map<ClientID, Cursor>;
cursorsContainer: null | HTMLElement;
doc: Doc;
docMap: Map<string, Doc>;
editor: LexicalEditor;
id: string;
nodeProperties: Map<string, {[property: string]: unknown}>; // node type to property to default value
excludedProperties: ExcludedProperties;
}
export interface Binding extends BaseBinding {
collabNodeMap: Map<
NodeKey,
| CollabElementNode
| CollabTextNode
| CollabDecoratorNode
| CollabLineBreakNode
>;
root: CollabElementNode;
}
export interface BindingV2 extends BaseBinding {
mapping: CollabV2Mapping;
root: XmlElement;
}
export type AnyBinding = Binding | BindingV2;
export type ExcludedProperties = Map<Klass<LexicalNode>, Set<string>>;
function createBaseBinding(
editor: LexicalEditor,
id: string,
doc: Doc | null | undefined,
docMap: Map<string, Doc>,
excludedProperties?: ExcludedProperties,
): BaseBinding {
invariant(
doc !== undefined && doc !== null,
'createBinding: doc is null or undefined',
);
const binding = {
clientID: doc.clientID,
cursors: new Map(),
cursorsContainer: null,
doc,
docMap,
editor,
excludedProperties: excludedProperties || new Map(),
id,
nodeProperties: new Map(),
};
initializeNodeProperties(binding);
return binding;
}
export function createBinding(
editor: LexicalEditor,
provider: Provider,
id: string,
doc: Doc | null | undefined,
docMap: Map<string, Doc>,
excludedProperties?: ExcludedProperties,
): Binding {
invariant(
doc !== undefined && doc !== null,
'createBinding: doc is null or undefined',
);
const rootXmlText = doc.get('root', XmlText) as XmlText;
const root: CollabElementNode = $createCollabElementNode(
rootXmlText,
null,
'root',
);
root._key = 'root';
return {
...createBaseBinding(editor, id, doc, docMap, excludedProperties),
collabNodeMap: new Map(),
root,
};
}
export function createBindingV2__EXPERIMENTAL(
editor: LexicalEditor,
id: string,
doc: Doc | null | undefined,
docMap: Map<string, Doc>,
options: {excludedProperties?: ExcludedProperties; rootName?: string} = {},
): BindingV2 {
invariant(
doc !== undefined && doc !== null,
'createBinding: doc is null or undefined',
);
const {excludedProperties, rootName = 'root-v2'} = options;
return {
...createBaseBinding(editor, id, doc, docMap, excludedProperties),
mapping: new CollabV2Mapping(),
root: doc.get(rootName, XmlElement) as XmlElement,
};
}
export function isBindingV1(binding: BaseBinding): binding is Binding {
return Object.prototype.hasOwnProperty.call(binding, 'collabNodeMap');
}
export function isBindingV2(binding: BaseBinding): binding is BindingV2 {
return Object.prototype.hasOwnProperty.call(binding, 'mapping');
}
/**
* 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.
*
*/
import type {Binding} from '.';
import type {CollabElementNode} from './CollabElementNode';
import type {DecoratorNode, NodeKey, NodeMap} from 'lexical';
import type {XmlElement} from 'yjs';
import invariant from '@lexical/internal/invariant';
import {$getNodeByKey, $isDecoratorNode} from 'lexical';
import {$syncPropertiesFromYjs, syncPropertiesFromLexical} from './Utils';
export class CollabDecoratorNode {
_xmlElem: XmlElement;
_key: NodeKey;
_parent: CollabElementNode;
_type: string;
constructor(xmlElem: XmlElement, parent: CollabElementNode, type: string) {
this._key = '';
this._xmlElem = xmlElem;
this._parent = parent;
this._type = type;
}
getPrevNode(nodeMap: null | NodeMap): null | DecoratorNode<unknown> {
if (nodeMap === null) {
return null;
}
const node = nodeMap.get(this._key);
return $isDecoratorNode(node) ? node : null;
}
getNode(): null | DecoratorNode<unknown> {
const node = $getNodeByKey(this._key);
return $isDecoratorNode(node) ? node : null;
}
getSharedType(): XmlElement {
return this._xmlElem;
}
getType(): string {
return this._type;
}
getKey(): NodeKey {
return this._key;
}
getSize(): number {
return 1;
}
getOffset(): number {
const collabElementNode = this._parent;
return collabElementNode.getChildOffset(this);
}
syncPropertiesFromLexical(
binding: Binding,
nextLexicalNode: DecoratorNode<unknown>,
prevNodeMap: null | NodeMap,
): void {
const prevLexicalNode = this.getPrevNode(prevNodeMap);
const xmlElem = this._xmlElem;
syncPropertiesFromLexical(
binding,
xmlElem,
prevLexicalNode,
nextLexicalNode,
);
}
syncPropertiesFromYjs(
binding: Binding,
keysChanged: null | Set<string>,
): void {
const lexicalNode = this.getNode();
invariant(
lexicalNode !== null,
'syncPropertiesFromYjs: could not find decorator node',
);
const xmlElem = this._xmlElem;
$syncPropertiesFromYjs(binding, xmlElem, lexicalNode, keysChanged);
}
destroy(binding: Binding): void {
const collabNodeMap = binding.collabNodeMap;
if (collabNodeMap.get(this._key) === this) {
collabNodeMap.delete(this._key);
}
}
}
export function $createCollabDecoratorNode(
xmlElem: XmlElement,
parent: CollabElementNode,
type: string,
): CollabDecoratorNode {
const collabNode = new CollabDecoratorNode(xmlElem, parent, type);
xmlElem._collabNode = collabNode;
return collabNode;
}
/**
* 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.
*
*/
import type {Binding} from '.';
import type {ElementNode, NodeKey, NodeMap} from 'lexical';
import type {AbstractType, Map as YMap, XmlElement, XmlText} from 'yjs';
import invariant from '@lexical/internal/invariant';
import {
$createChildrenArray,
$getNodeByKey,
$getNodeByKeyOrThrow,
$isDecoratorNode,
$isElementNode,
$isTextNode,
removeFromParent,
} from 'lexical';
import {CollabDecoratorNode} from './CollabDecoratorNode';
import {CollabLineBreakNode} from './CollabLineBreakNode';
import {CollabTextNode} from './CollabTextNode';
import {
$createCollabNodeFromLexicalNode,
$getOrInitCollabNodeFromSharedType,
$syncPropertiesFromYjs,
createLexicalNodeFromCollabNode,
getPositionFromElementAndOffset,
spliceString,
syncPropertiesFromLexical,
} from './Utils';
type IntentionallyMarkedAsDirtyElement = boolean;
export class CollabElementNode {
_key: NodeKey;
_children: Array<
| CollabElementNode
| CollabTextNode
| CollabDecoratorNode
| CollabLineBreakNode
>;
_xmlText: XmlText;
_type: string;
_parent: null | CollabElementNode;
constructor(
xmlText: XmlText,
parent: null | CollabElementNode,
type: string,
) {
this._key = '';
this._children = [];
this._xmlText = xmlText;
this._type = type;
this._parent = parent;
}
getPrevNode(nodeMap: null | NodeMap): null | ElementNode {
if (nodeMap === null) {
return null;
}
const node = nodeMap.get(this._key);
return $isElementNode(node) ? node : null;
}
getNode(): null | ElementNode {
const node = $getNodeByKey(this._key);
return $isElementNode(node) ? node : null;
}
getSharedType(): XmlText {
return this._xmlText;
}
getType(): string {
return this._type;
}
getKey(): NodeKey {
return this._key;
}
isEmpty(): boolean {
return this._children.length === 0;
}
getSize(): number {
return 1;
}
getOffset(): number {
const collabElementNode = this._parent;
invariant(
collabElementNode !== null,
'getOffset: could not find collab element node',
);
return collabElementNode.getChildOffset(this);
}
syncPropertiesFromYjs(
binding: Binding,
keysChanged: null | Set<string>,
): void {
const lexicalNode = this.getNode();
invariant(
lexicalNode !== null,
'syncPropertiesFromYjs: could not find element node',
);
$syncPropertiesFromYjs(binding, this._xmlText, lexicalNode, keysChanged);
}
applyChildrenYjsDelta(
binding: Binding,
deltas: Array<{
insert?: string | object | AbstractType<unknown>;
delete?: number;
retain?: number;
attributes?: {
[x: string]: unknown;
};
}>,
): void {
const children = this._children;
let currIndex = 0;
let pendingSplitText = null;
for (let i = 0; i < deltas.length; i++) {
const delta = deltas[i];
const insertDelta = delta.insert;
const deleteDelta = delta.delete;
if (delta.retain != null) {
currIndex += delta.retain;
} else if (typeof deleteDelta === 'number') {
let deletionSize = deleteDelta;
while (deletionSize > 0) {
const {node, nodeIndex, offset, length} =
getPositionFromElementAndOffset(this, currIndex, false);
if (
node instanceof CollabElementNode ||
node instanceof CollabLineBreakNode ||
node instanceof CollabDecoratorNode
) {
children.splice(nodeIndex, 1);
deletionSize -= 1;
} else if (node instanceof CollabTextNode) {
const delCount = Math.min(deletionSize, length);
const prevCollabNode =
nodeIndex !== 0 ? children[nodeIndex - 1] : null;
const nodeSize = node.getSize();
if (offset === 0 && length === nodeSize) {
// Text node has been deleted.
children.splice(nodeIndex, 1);
// If this was caused by an undo from YJS, there could be dangling text.
const danglingText = spliceString(
node._text,
offset,
delCount - 1,
'',
);
if (danglingText.length > 0) {
if (prevCollabNode instanceof CollabTextNode) {
// Merge the text node with previous.
prevCollabNode._text += danglingText;
} else {
// No previous text node to merge into, just delete the text.
this._xmlText.delete(offset, danglingText.length);
}
}
} else {
node._text = spliceString(node._text, offset, delCount, '');
}
deletionSize -= delCount;
} else {
// Can occur due to the deletion from the dangling text heuristic below.
break;
}
}
} else if (insertDelta != null) {
if (typeof insertDelta === 'string') {
const {node, offset} = getPositionFromElementAndOffset(
this,
currIndex,
true,
);
if (node instanceof CollabTextNode) {
node._text = spliceString(node._text, offset, 0, insertDelta);
} else {
// TODO: maybe we can improve this by keeping around a redundant
// text node map, rather than removing all the text nodes, so there
// never can be dangling text.
// We have a conflict where there was likely a CollabTextNode and
// an Lexical TextNode too, but they were removed in a merge. So
// let's just ignore the text and trigger a removal for it from our
// shared type.
this._xmlText.delete(offset, insertDelta.length);
}
currIndex += insertDelta.length;
} else {
const sharedType = insertDelta;
const {node, nodeIndex, length} = getPositionFromElementAndOffset(
this,
currIndex,
false,
);
const collabNode = $getOrInitCollabNodeFromSharedType(
binding,
sharedType as XmlText | YMap<unknown> | XmlElement,
this,
);
if (
node instanceof CollabTextNode &&
length > 0 &&
length < node._text.length
) {
// Trying to insert in the middle of a text node; split the text.
const text = node._text;
const splitIdx = text.length - length;
node._text = spliceString(text, splitIdx, length, '');
children.splice(nodeIndex + 1, 0, collabNode);
// The insert that triggers the text split might not be a text node. Need to keep a
// reference to the remaining text so that it can be added when we do create one.
pendingSplitText = spliceString(text, 0, splitIdx, '');
} else {
children.splice(nodeIndex, 0, collabNode);
}
if (
pendingSplitText !== null &&
collabNode instanceof CollabTextNode
) {
// Found a text node to insert the pending text into.
collabNode._text = pendingSplitText + collabNode._text;
pendingSplitText = null;
}
currIndex += 1;
}
} else {
throw new Error('Unexpected delta format');
}
}
}
syncChildrenFromYjs(binding: Binding): void {
// Now diff the children of the collab node with that of our existing Lexical node.
const lexicalNode = this.getNode();
invariant(
lexicalNode !== null,
'syncChildrenFromYjs: could not find element node',
);
const key = lexicalNode.__key;
const prevLexicalChildrenKeys = $createChildrenArray(lexicalNode, null);
const nextLexicalChildrenKeys: Array<NodeKey> = [];
const lexicalChildrenKeysLength = prevLexicalChildrenKeys.length;
const collabChildren = this._children;
const collabChildrenLength = collabChildren.length;
const collabNodeMap = binding.collabNodeMap;
const visitedKeys = new Set();
let collabKeys;
let writableLexicalNode;
let prevIndex = 0;
let prevChildNode = null;
if (collabChildrenLength !== lexicalChildrenKeysLength) {
writableLexicalNode = lexicalNode.getWritable();
}
for (let i = 0; i < collabChildrenLength; i++) {
const lexicalChildKey = prevLexicalChildrenKeys[prevIndex];
const childCollabNode = collabChildren[i];
const collabLexicalChildNode = childCollabNode.getNode();
const collabKey = childCollabNode._key;
if (collabLexicalChildNode !== null && lexicalChildKey === collabKey) {
const childNeedsUpdating = $isTextNode(collabLexicalChildNode);
// Update
visitedKeys.add(lexicalChildKey);
if (childNeedsUpdating) {
childCollabNode._key = lexicalChildKey;
if (childCollabNode instanceof CollabElementNode) {
const xmlText = childCollabNode._xmlText;
childCollabNode.syncPropertiesFromYjs(binding, null);
childCollabNode.applyChildrenYjsDelta(binding, xmlText.toDelta());
childCollabNode.syncChildrenFromYjs(binding);
} else if (childCollabNode instanceof CollabTextNode) {
childCollabNode.syncPropertiesAndTextFromYjs(binding, null);
} else if (childCollabNode instanceof CollabDecoratorNode) {
childCollabNode.syncPropertiesFromYjs(binding, null);
} else if (!(childCollabNode instanceof CollabLineBreakNode)) {
invariant(
false,
'syncChildrenFromYjs: expected text, element, decorator, or linebreak collab node',
);
}
}
nextLexicalChildrenKeys[i] = lexicalChildKey;
prevChildNode = collabLexicalChildNode;
prevIndex++;
} else {
if (collabKeys === undefined) {
collabKeys = new Set();
for (let s = 0; s < collabChildrenLength; s++) {
const child = collabChildren[s];
const childKey = child._key;
if (childKey !== '') {
collabKeys.add(childKey);
}
}
}
if (
collabLexicalChildNode !== null &&
lexicalChildKey !== undefined &&
!collabKeys.has(lexicalChildKey)
) {
const nodeToRemove = $getNodeByKeyOrThrow(lexicalChildKey);
removeFromParent(nodeToRemove);
i--;
prevIndex++;
continue;
}
writableLexicalNode = lexicalNode.getWritable();
// Create/Replace
const lexicalChildNode = createLexicalNodeFromCollabNode(
binding,
childCollabNode,
key,
);
const childKey = lexicalChildNode.__key;
collabNodeMap.set(childKey, childCollabNode);
nextLexicalChildrenKeys[i] = childKey;
if (prevChildNode === null) {
const nextSibling = writableLexicalNode.getFirstChild();
writableLexicalNode.__first = childKey;
if (nextSibling !== null) {
const writableNextSibling = nextSibling.getWritable();
writableNextSibling.__prev = childKey;
lexicalChildNode.__next = writableNextSibling.__key;
}
} else {
const writablePrevChildNode = prevChildNode.getWritable();
const nextSibling = prevChildNode.getNextSibling();
writablePrevChildNode.__next = childKey;
lexicalChildNode.__prev = prevChildNode.__key;
if (nextSibling !== null) {
const writableNextSibling = nextSibling.getWritable();
writableNextSibling.__prev = childKey;
lexicalChildNode.__next = writableNextSibling.__key;
}
}
if (i === collabChildrenLength - 1) {
writableLexicalNode.__last = childKey;
}
writableLexicalNode.__size++;
prevChildNode = lexicalChildNode;
}
}
for (let i = 0; i < lexicalChildrenKeysLength; i++) {
const lexicalChildKey = prevLexicalChildrenKeys[i];
if (!visitedKeys.has(lexicalChildKey)) {
// Remove
const lexicalChildNode = $getNodeByKeyOrThrow(lexicalChildKey);
const collabNode = binding.collabNodeMap.get(lexicalChildKey);
if (collabNode !== undefined) {
collabNode.destroy(binding);
}
removeFromParent(lexicalChildNode);
}
}
}
syncPropertiesFromLexical(
binding: Binding,
nextLexicalNode: ElementNode,
prevNodeMap: null | NodeMap,
): void {
syncPropertiesFromLexical(
binding,
this._xmlText,
this.getPrevNode(prevNodeMap),
nextLexicalNode,
);
}
_syncChildFromLexical(
binding: Binding,
index: number,
key: NodeKey,
prevNodeMap: null | NodeMap,
dirtyElements: null | Map<NodeKey, IntentionallyMarkedAsDirtyElement>,
dirtyLeaves: null | Set<NodeKey>,
): void {
const childCollabNode = this._children[index];
// Update
const nextChildNode = $getNodeByKeyOrThrow(key);
if (
childCollabNode instanceof CollabElementNode &&
$isElementNode(nextChildNode)
) {
childCollabNode.syncPropertiesFromLexical(
binding,
nextChildNode,
prevNodeMap,
);
childCollabNode.syncChildrenFromLexical(
binding,
nextChildNode,
prevNodeMap,
dirtyElements,
dirtyLeaves,
);
} else if (
childCollabNode instanceof CollabTextNode &&
$isTextNode(nextChildNode)
) {
childCollabNode.syncPropertiesAndTextFromLexical(
binding,
nextChildNode,
prevNodeMap,
);
} else if (
childCollabNode instanceof CollabDecoratorNode &&
$isDecoratorNode(nextChildNode)
) {
childCollabNode.syncPropertiesFromLexical(
binding,
nextChildNode,
prevNodeMap,
);
}
}
syncChildrenFromLexical(
binding: Binding,
nextLexicalNode: ElementNode,
prevNodeMap: null | NodeMap,
dirtyElements: null | Map<NodeKey, IntentionallyMarkedAsDirtyElement>,
dirtyLeaves: null | Set<NodeKey>,
): void {
const prevLexicalNode = this.getPrevNode(prevNodeMap);
const prevChildren =
prevLexicalNode === null
? []
: $createChildrenArray(prevLexicalNode, prevNodeMap);
const nextChildren = $createChildrenArray(nextLexicalNode, null);
const prevEndIndex = prevChildren.length - 1;
const nextEndIndex = nextChildren.length - 1;
const collabNodeMap = binding.collabNodeMap;
let prevChildrenSet: Set<NodeKey> | undefined;
let nextChildrenSet: Set<NodeKey> | undefined;
let prevIndex = 0;
let nextIndex = 0;
while (prevIndex <= prevEndIndex && nextIndex <= nextEndIndex) {
const prevKey = prevChildren[prevIndex];
const nextKey = nextChildren[nextIndex];
if (prevKey === nextKey) {
// Nove move, create or remove
this._syncChildFromLexical(
binding,
nextIndex,
nextKey,
prevNodeMap,
dirtyElements,
dirtyLeaves,
);
prevIndex++;
nextIndex++;
} else {
if (prevChildrenSet === undefined) {
prevChildrenSet = new Set(prevChildren);
}
if (nextChildrenSet === undefined) {
nextChildrenSet = new Set(nextChildren);
}
const nextHasPrevKey = nextChildrenSet.has(prevKey);
const prevHasNextKey = prevChildrenSet.has(nextKey);
if (!nextHasPrevKey) {
// Remove
this.splice(binding, nextIndex, 1);
prevIndex++;
} else {
// Create or replace
const nextChildNode = $getNodeByKeyOrThrow(nextKey);
const collabNode = $createCollabNodeFromLexicalNode(
binding,
nextChildNode,
this,
);
collabNodeMap.set(nextKey, collabNode);
if (prevHasNextKey) {
this.splice(binding, nextIndex, 1, collabNode);
prevIndex++;
nextIndex++;
} else {
this.splice(binding, nextIndex, 0, collabNode);
nextIndex++;
}
}
}
}
const appendNewChildren = prevIndex > prevEndIndex;
const removeOldChildren = nextIndex > nextEndIndex;
if (appendNewChildren && !removeOldChildren) {
for (; nextIndex <= nextEndIndex; ++nextIndex) {
const key = nextChildren[nextIndex];
const nextChildNode = $getNodeByKeyOrThrow(key);
const collabNode = $createCollabNodeFromLexicalNode(
binding,
nextChildNode,
this,
);
this.append(collabNode);
collabNodeMap.set(key, collabNode);
}
} else if (removeOldChildren && !appendNewChildren) {
for (let i = this._children.length - 1; i >= nextIndex; i--) {
this.splice(binding, i, 1);
}
}
}
append(
collabNode:
| CollabElementNode
| CollabDecoratorNode
| CollabTextNode
| CollabLineBreakNode,
): void {
const xmlText = this._xmlText;
const children = this._children;
const lastChild = children[children.length - 1];
const offset =
lastChild !== undefined ? lastChild.getOffset() + lastChild.getSize() : 0;
if (collabNode instanceof CollabElementNode) {
xmlText.insertEmbed(offset, collabNode._xmlText);
} else if (collabNode instanceof CollabTextNode) {
const map = collabNode._map;
if (map.parent === null) {
xmlText.insertEmbed(offset, map);
}
xmlText.insert(offset + 1, collabNode._text);
} else if (collabNode instanceof CollabLineBreakNode) {
xmlText.insertEmbed(offset, collabNode._map);
} else if (collabNode instanceof CollabDecoratorNode) {
xmlText.insertEmbed(offset, collabNode._xmlElem);
}
this._children.push(collabNode);
}
splice(
binding: Binding,
index: number,
delCount: number,
collabNode?:
| CollabElementNode
| CollabDecoratorNode
| CollabTextNode
| CollabLineBreakNode,
): void {
const children = this._children;
const child = children[index];
if (child === undefined) {
invariant(
collabNode !== undefined,
'splice: could not find collab element node',
);
this.append(collabNode);
return;
}
const offset = child.getOffset();
invariant(offset !== -1, 'splice: expected offset to be greater than zero');
const xmlText = this._xmlText;
if (delCount !== 0) {
// What if we delete many nodes, don't we need to get all their
// sizes?
xmlText.delete(offset, child.getSize());
}
if (collabNode instanceof CollabElementNode) {
xmlText.insertEmbed(offset, collabNode._xmlText);
} else if (collabNode instanceof CollabTextNode) {
const map = collabNode._map;
if (map.parent === null) {
xmlText.insertEmbed(offset, map);
}
xmlText.insert(offset + 1, collabNode._text);
} else if (collabNode instanceof CollabLineBreakNode) {
xmlText.insertEmbed(offset, collabNode._map);
} else if (collabNode instanceof CollabDecoratorNode) {
xmlText.insertEmbed(offset, collabNode._xmlElem);
}
if (delCount !== 0) {
const childrenToDelete = children.slice(index, index + delCount);
for (let i = 0; i < childrenToDelete.length; i++) {
childrenToDelete[i].destroy(binding);
}
}
if (collabNode !== undefined) {
children.splice(index, delCount, collabNode);
} else {
children.splice(index, delCount);
}
}
getChildOffset(
collabNode:
| CollabElementNode
| CollabTextNode
| CollabDecoratorNode
| CollabLineBreakNode,
): number {
let offset = 0;
const children = this._children;
for (let i = 0; i < children.length; i++) {
const child = children[i];
if (child === collabNode) {
return offset;
}
offset += child.getSize();
}
return -1;
}
destroy(binding: Binding): void {
const collabNodeMap = binding.collabNodeMap;
const children = this._children;
for (let i = 0; i < children.length; i++) {
children[i].destroy(binding);
}
if (collabNodeMap.get(this._key) === this) {
collabNodeMap.delete(this._key);
}
}
}
export function $createCollabElementNode(
xmlText: XmlText,
parent: null | CollabElementNode,
type: string,
): CollabElementNode {
const collabNode = new CollabElementNode(xmlText, parent, type);
xmlText._collabNode = collabNode;
return collabNode;
}
/**
* 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.
*
*/
import type {Binding} from '.';
import type {CollabElementNode} from './CollabElementNode';
import type {LineBreakNode, NodeKey} from 'lexical';
import type {Map as YMap} from 'yjs';
import {$getNodeByKey, $isLineBreakNode} from 'lexical';
export class CollabLineBreakNode {
_map: YMap<unknown>;
_key: NodeKey;
_parent: CollabElementNode;
_type: 'linebreak';
constructor(map: YMap<unknown>, parent: CollabElementNode) {
this._key = '';
this._map = map;
this._parent = parent;
this._type = 'linebreak';
}
getNode(): null | LineBreakNode {
const node = $getNodeByKey(this._key);
return $isLineBreakNode(node) ? node : null;
}
getKey(): NodeKey {
return this._key;
}
getSharedType(): YMap<unknown> {
return this._map;
}
getType(): string {
return this._type;
}
getSize(): number {
return 1;
}
getOffset(): number {
const collabElementNode = this._parent;
return collabElementNode.getChildOffset(this);
}
destroy(binding: Binding): void {
const collabNodeMap = binding.collabNodeMap;
if (collabNodeMap.get(this._key) === this) {
collabNodeMap.delete(this._key);
}
}
}
export function $createCollabLineBreakNode(
map: YMap<unknown>,
parent: CollabElementNode,
): CollabLineBreakNode {
const collabNode = new CollabLineBreakNode(map, parent);
map._collabNode = collabNode;
return collabNode;
}
/**
* 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.
*
*/
import type {Binding} from '.';
import type {CollabElementNode} from './CollabElementNode';
import type {NodeKey, NodeMap, TextNode} from 'lexical';
import type {Map as YMap} from 'yjs';
import invariant from '@lexical/internal/invariant';
import {
$getNodeByKey,
$getSelection,
$isRangeSelection,
$isTextNode,
} from 'lexical';
import simpleDiffWithCursor from './simpleDiffWithCursor';
import {$syncPropertiesFromYjs, syncPropertiesFromLexical} from './Utils';
function $diffTextContentAndApplyDelta(
collabNode: CollabTextNode,
key: NodeKey,
prevText: string,
nextText: string,
): void {
const selection = $getSelection();
let cursorOffset = nextText.length;
if ($isRangeSelection(selection) && selection.isCollapsed()) {
const anchor = selection.anchor;
if (anchor.key === key) {
cursorOffset = anchor.offset;
}
}
const diff = simpleDiffWithCursor(prevText, nextText, cursorOffset);
collabNode.spliceText(diff.index, diff.remove, diff.insert);
}
export class CollabTextNode {
_map: YMap<unknown>;
_key: NodeKey;
_parent: CollabElementNode;
_text: string;
_type: string;
_normalized: boolean;
constructor(
map: YMap<unknown>,
text: string,
parent: CollabElementNode,
type: string,
) {
this._key = '';
this._map = map;
this._parent = parent;
this._text = text;
this._type = type;
this._normalized = false;
}
getPrevNode(nodeMap: null | NodeMap): null | TextNode {
if (nodeMap === null) {
return null;
}
const node = nodeMap.get(this._key);
return $isTextNode(node) ? node : null;
}
getNode(): null | TextNode {
const node = $getNodeByKey(this._key);
return $isTextNode(node) ? node : null;
}
getSharedType(): YMap<unknown> {
return this._map;
}
getType(): string {
return this._type;
}
getKey(): NodeKey {
return this._key;
}
getSize(): number {
return this._text.length + (this._normalized ? 0 : 1);
}
getOffset(): number {
const collabElementNode = this._parent;
return collabElementNode.getChildOffset(this);
}
spliceText(index: number, delCount: number, newText: string): void {
const collabElementNode = this._parent;
const xmlText = collabElementNode._xmlText;
const offset = this.getOffset() + 1 + index;
if (delCount !== 0) {
xmlText.delete(offset, delCount);
}
if (newText !== '') {
xmlText.insert(offset, newText);
}
}
syncPropertiesAndTextFromLexical(
binding: Binding,
nextLexicalNode: TextNode,
prevNodeMap: null | NodeMap,
): void {
const prevLexicalNode = this.getPrevNode(prevNodeMap);
const nextText = nextLexicalNode.__text;
syncPropertiesFromLexical(
binding,
this._map,
prevLexicalNode,
nextLexicalNode,
);
if (prevLexicalNode !== null) {
const prevText = prevLexicalNode.__text;
if (prevText !== nextText) {
const key = nextLexicalNode.__key;
$diffTextContentAndApplyDelta(this, key, prevText, nextText);
this._text = nextText;
}
}
}
syncPropertiesAndTextFromYjs(
binding: Binding,
keysChanged: null | Set<string>,
): void {
const lexicalNode = this.getNode();
invariant(
lexicalNode !== null,
'syncPropertiesAndTextFromYjs: could not find decorator node',
);
$syncPropertiesFromYjs(binding, this._map, lexicalNode, keysChanged);
const collabText = this._text;
if (lexicalNode.__text !== collabText) {
lexicalNode.setTextContent(collabText);
}
}
destroy(binding: Binding): void {
const collabNodeMap = binding.collabNodeMap;
if (collabNodeMap.get(this._key) === this) {
collabNodeMap.delete(this._key);
}
}
}
export function $createCollabTextNode(
map: YMap<unknown>,
text: string,
parent: CollabElementNode,
type: string,
): CollabTextNode {
const collabNode = new CollabTextNode(map, text, parent, type);
map._collabNode = collabNode;
return collabNode;
}
/**
* 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.
*
*/
import invariant from '@lexical/internal/invariant';
import {$isTextNode, type LexicalNode, NodeKey, type TextNode} from 'lexical';
import {XmlElement, XmlText} from 'yjs';
type SharedType = XmlElement | XmlText;
// Stores mappings between Yjs shared types and the Lexical nodes they were last associated with.
export class CollabV2Mapping {
private _nodeMap: Map<NodeKey, LexicalNode> = new Map();
private _sharedTypeToNodeKeys: Map<SharedType, NodeKey[]> = new Map();
private _nodeKeyToSharedType: Map<NodeKey, SharedType> = new Map();
set(sharedType: SharedType, node: LexicalNode | TextNode[]): void {
const isArray = node instanceof Array;
// Clear all existing associations for this key.
this.delete(sharedType);
// If nodes were associated with other shared types, remove those associations.
const nodes = isArray ? node : [node];
for (const n of nodes) {
const key = n.getKey();
if (this._nodeKeyToSharedType.has(key)) {
const otherSharedType = this._nodeKeyToSharedType.get(key)!;
const keyIndex = this._sharedTypeToNodeKeys
.get(otherSharedType)!
.indexOf(key);
if (keyIndex !== -1) {
this._sharedTypeToNodeKeys.get(otherSharedType)!.splice(keyIndex, 1);
}
this._nodeKeyToSharedType.delete(key);
this._nodeMap.delete(key);
}
}
if (sharedType instanceof XmlText) {
invariant(isArray, 'Text nodes must be mapped as an array');
if (node.length === 0) {
return;
}
this._sharedTypeToNodeKeys.set(
sharedType,
node.map(n => n.getKey()),
);
for (const n of node) {
this._nodeMap.set(n.getKey(), n);
this._nodeKeyToSharedType.set(n.getKey(), sharedType);
}
} else {
invariant(!isArray, 'Element nodes must be mapped as a single node');
invariant(!$isTextNode(node), 'Text nodes must be mapped to XmlText');
this._sharedTypeToNodeKeys.set(sharedType, [node.getKey()]);
this._nodeMap.set(node.getKey(), node);
this._nodeKeyToSharedType.set(node.getKey(), sharedType);
}
}
get(sharedType: XmlElement): LexicalNode | undefined;
get(sharedType: XmlText): TextNode[] | undefined;
get(sharedType: SharedType): LexicalNode | Array<TextNode> | undefined;
get(sharedType: SharedType): LexicalNode | Array<TextNode> | undefined {
const nodes = this._sharedTypeToNodeKeys.get(sharedType);
if (nodes === undefined) {
return undefined;
}
if (sharedType instanceof XmlText) {
const arr = Array.from(
nodes.map(nodeKey => this._nodeMap.get(nodeKey)!),
) as Array<TextNode>;
return arr.length > 0 ? arr : undefined;
}
return this._nodeMap.get(nodes[0])!;
}
getSharedType(node: LexicalNode): SharedType | undefined {
return this._nodeKeyToSharedType.get(node.getKey());
}
delete(sharedType: SharedType): void {
const nodeKeys = this._sharedTypeToNodeKeys.get(sharedType);
if (nodeKeys === undefined) {
return;
}
for (const nodeKey of nodeKeys) {
this._nodeMap.delete(nodeKey);
this._nodeKeyToSharedType.delete(nodeKey);
}
this._sharedTypeToNodeKeys.delete(sharedType);
}
deleteNode(nodeKey: NodeKey): void {
const sharedType = this._nodeKeyToSharedType.get(nodeKey);
if (sharedType) {
this.delete(sharedType);
}
this._nodeMap.delete(nodeKey);
}
has(sharedType: SharedType): boolean {
return this._sharedTypeToNodeKeys.has(sharedType);
}
clear(): void {
this._nodeMap.clear();
this._sharedTypeToNodeKeys.clear();
this._nodeKeyToSharedType.clear();
}
}
/**
* 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.
*
*/
import type {BaseBinding} from './Bindings';
import type {LexicalCommand} from 'lexical';
import type {
Doc,
RelativePosition,
Snapshot,
UndoManager,
XmlElement,
XmlText,
} from 'yjs';
import './types';
import {createCommand} from 'lexical';
import {UndoManager as YjsUndoManager} from 'yjs';
export type UserState = {
anchorPos: null | RelativePosition;
color: string;
focusing: boolean;
focusPos: null | RelativePosition;
name: string;
awarenessData: object;
[key: string]: unknown;
};
export const CONNECTED_COMMAND: LexicalCommand<boolean> =
createCommand('CONNECTED_COMMAND');
export const TOGGLE_CONNECT_COMMAND: LexicalCommand<boolean> = createCommand(
'TOGGLE_CONNECT_COMMAND',
);
export const DIFF_VERSIONS_COMMAND__EXPERIMENTAL: LexicalCommand<{
// Starting snapshot if defined, otherwise compare since start of time.
prevSnapshot?: Snapshot;
// Ending snapshot if defined, otherwise compare against current state of the Yjs document.
snapshot?: Snapshot;
}> = createCommand('DIFF_VERSIONS_COMMAND');
export const CLEAR_DIFF_VERSIONS_COMMAND__EXPERIMENTAL: LexicalCommand<void> =
createCommand('CLEAR_DIFF_VERSIONS_COMMAND');
export {$getYChangeState, renderSnapshot__EXPERIMENTAL} from './RenderSnapshot';
export type ProviderAwareness = {
getLocalState: () => UserState | null;
getStates: () => Map<number, UserState>;
off: (type: 'update', cb: () => void) => void;
on: (type: 'update', cb: () => void) => void;
setLocalState: (arg0: UserState | null) => void;
setLocalStateField: (field: string, value: unknown) => void;
};
declare interface Provider {
awareness: ProviderAwareness;
connect(): void | Promise<void>;
disconnect(): void;
off(type: 'sync', cb: (isSynced: boolean) => void): void;
off(type: 'update', cb: (arg0: unknown) => void): void;
off(type: 'status', cb: (arg0: {status: string}) => void): void;
off(type: 'reload', cb: (doc: Doc) => void): void;
on(type: 'sync', cb: (isSynced: boolean) => void): void;
on(type: 'status', cb: (arg0: {status: string}) => void): void;
on(type: 'update', cb: (arg0: unknown) => void): void;
on(type: 'reload', cb: (doc: Doc) => void): void;
}
export type Operation = {
attributes: {
__type: string;
};
insert: string | Record<string, unknown>;
};
export type Delta = Array<Operation>;
export type YjsNode = Record<string, unknown>;
export type YjsEvent = Record<string, unknown>;
export type {Provider};
export type {
BaseBinding,
Binding,
BindingV2,
ClientID,
ExcludedProperties,
} from './Bindings';
export {createBinding, createBindingV2__EXPERIMENTAL} from './Bindings';
export function createUndoManager(
binding: BaseBinding,
root: XmlText | XmlElement,
): UndoManager {
return new YjsUndoManager(root, {
trackedOrigins: new Set([binding, null]),
});
}
export function initLocalState(
provider: Provider,
name: string,
color: string,
focusing: boolean,
awarenessData: object,
): void {
provider.awareness.setLocalState({
anchorPos: null,
awarenessData,
color,
focusPos: null,
focusing: focusing,
name,
});
}
export function setLocalStateFocus(
provider: Provider,
name: string,
color: string,
focusing: boolean,
awarenessData: object,
): void {
const {awareness} = provider;
let localState = awareness.getLocalState();
if (localState === null) {
localState = {
anchorPos: null,
awarenessData,
color,
focusPos: null,
focusing: focusing,
name,
};
}
localState.focusing = focusing;
awareness.setLocalState(localState);
}
export {
getAnchorAndFocusCollabNodesForUserState,
syncCursorPositions,
type SyncCursorPositionsFn,
} from './SyncCursors';
export {
syncLexicalUpdateToYjs,
syncLexicalUpdateToYjsV2__EXPERIMENTAL,
syncYjsChangesToLexical,
syncYjsChangesToLexicalV2__EXPERIMENTAL,
syncYjsStateToLexicalV2__EXPERIMENTAL,
} from './SyncEditorStates';
/**
* 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.
*
*/
import invariant from '@lexical/internal/invariant';
import {$getRoot, $getState, createState, LexicalNode} from 'lexical';
import {
emptySnapshot,
ID,
iterateDeletedStructs,
PermanentUserData,
Snapshot,
snapshot as createSnapshot,
} from 'yjs';
import {BindingV2} from './Bindings';
import {$createOrUpdateNodeFromYElement} from './SyncV2';
const STATE_KEY = 'ychange';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type YChange<UserT = any> = {
id: ID;
type: 'removed' | 'added';
user: UserT | null;
};
const ychangeState = createState<typeof STATE_KEY, YChange | null>(STATE_KEY, {
isEqual: (a, b) => a === b,
parse: value => (value as YChange) ?? null,
});
export function $getYChangeState<UserT = unknown>(
node: LexicalNode,
): YChange<UserT> | null {
return $getState(node, ychangeState);
}
// Not exposing $setState because it should only be created by SyncV2.ts.
/**
* Replaces the editor content with a view that compares the state between two given snapshots.
* Any added or removed nodes between the two snapshots will have {@link YChange} attached to them.
*
* @param binding Yjs binding
* @param snapshot Ending snapshot state (default: current state of the Yjs document)
* @param prevSnapshot Starting snapshot state (default: empty snapshot)
*/
export const renderSnapshot__EXPERIMENTAL = (
binding: BindingV2,
snapshot: Snapshot = createSnapshot(binding.doc),
prevSnapshot: Snapshot = emptySnapshot,
) => {
// The document that contains the full history of this document.
const {doc} = binding;
invariant(!doc.gc, 'GC must be disabled to render snapshot');
doc.transact(transaction => {
// Before rendering, we are going to sanitize ops and split deleted ops
// if they were deleted by separate users.
const pud = new PermanentUserData(doc);
if (pud) {
pud.dss.forEach(ds => {
iterateDeletedStructs(transaction, ds, _item => {});
});
}
const computeYChange = (type: 'removed' | 'added', id: ID): YChange => {
const user =
type === 'added'
? pud.getUserByClientId(id.client)
: pud.getUserByDeletedId(id);
return {
id,
type,
user: user ?? null,
};
};
binding.mapping.clear();
binding.editor.update(() => {
$getRoot().clear();
$createOrUpdateNodeFromYElement(
binding.root,
binding,
null,
true,
snapshot,
prevSnapshot,
computeYChange,
);
});
}, binding);
};
/**
* 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.
*
*/
export default function simpleDiffWithCursor(
a: string,
b: string,
cursor: number,
): {index: number; insert: string; remove: number} {
const aLength = a.length;
const bLength = b.length;
let left = 0; // number of same characters counting from left
let right = 0; // number of same characters counting from right
// Iterate left to the right until we find a changed character
// First iteration considers the current cursor position
while (
left < aLength &&
left < bLength &&
a[left] === b[left] &&
left < cursor
) {
left++;
}
// Iterate right to the left until we find a changed character
while (
right + left < aLength &&
right + left < bLength &&
a[aLength - right - 1] === b[bLength - right - 1]
) {
right++;
}
// Try to iterate left further to the right without caring about the current cursor position
while (
right + left < aLength &&
right + left < bLength &&
a[left] === b[left]
) {
left++;
}
return {
index: left,
insert: b.slice(left, bLength - right),
remove: aLength - left - right,
};
}
/**
* 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.
*
*/
import type {
BaseSelection,
LexicalNode,
NodeKey,
NodeMap,
Point,
} from 'lexical';
import invariant from '@lexical/internal/invariant';
import {createDOMRange, createRectsFromDOMRange} from '@lexical/selection';
import {
$getNodeByKey,
$getSelection,
$isElementNode,
$isLineBreakNode,
$isRangeSelection,
$isTextNode,
setDOMStyleObject,
} from 'lexical';
import {
AbsolutePosition,
compareRelativePositions,
createAbsolutePositionFromRelativePosition,
createRelativePositionFromTypeIndex,
RelativePosition,
XmlElement,
XmlText,
} from 'yjs';
import {Provider, UserState} from '.';
import {
AnyBinding,
type BaseBinding,
type Binding,
type BindingV2,
isBindingV1,
} from './Bindings';
import {CollabDecoratorNode} from './CollabDecoratorNode';
import {CollabElementNode} from './CollabElementNode';
import {CollabLineBreakNode} from './CollabLineBreakNode';
import {CollabTextNode} from './CollabTextNode';
import {CollabV2Mapping} from './CollabV2Mapping';
import {getPositionFromElementAndOffset} from './Utils';
export type CursorSelection = {
anchor: {
key: NodeKey;
offset: number;
};
caret: HTMLElement;
color: string;
focus: {
key: NodeKey;
offset: number;
};
name: HTMLSpanElement;
selections: Array<HTMLElement>;
};
export type Cursor = {
color: string;
name: string;
selection: null | CursorSelection;
};
function createRelativePosition(
point: Point,
binding: Binding,
): null | RelativePosition {
const collabNodeMap = binding.collabNodeMap;
const collabNode = collabNodeMap.get(point.key);
if (collabNode === undefined) {
return null;
}
let offset = point.offset;
let sharedType = collabNode.getSharedType();
if (collabNode instanceof CollabTextNode) {
sharedType = collabNode._parent._xmlText;
const currentOffset = collabNode.getOffset();
if (currentOffset === -1) {
return null;
}
offset = currentOffset + 1 + offset;
} else if (
collabNode instanceof CollabElementNode &&
point.type === 'element'
) {
const parent = point.getNode();
invariant($isElementNode(parent), 'Element point must be an element node');
let accumulatedOffset = 0;
let i = 0;
let node = parent.getFirstChild();
while (node !== null && i++ < offset) {
if ($isTextNode(node)) {
accumulatedOffset += node.getTextContentSize() + 1;
} else {
accumulatedOffset++;
}
node = node.getNextSibling();
}
offset = accumulatedOffset;
}
return createRelativePositionFromTypeIndex(sharedType, offset);
}
function createRelativePositionV2(
point: Point,
binding: BindingV2,
): null | RelativePosition {
const {mapping} = binding;
const {offset} = point;
const node = point.getNode();
const yType = mapping.getSharedType(node);
if (yType === undefined) {
return null;
}
if (point.type === 'text') {
invariant($isTextNode(node), 'Text point must be a text node');
let prevSibling = node.getPreviousSibling();
let adjustedOffset = offset;
while ($isTextNode(prevSibling)) {
adjustedOffset += prevSibling.getTextContentSize();
prevSibling = prevSibling.getPreviousSibling();
}
return createRelativePositionFromTypeIndex(yType, adjustedOffset);
} else if (point.type === 'element') {
invariant($isElementNode(node), 'Element point must be an element node');
let i = 0;
let child = node.getFirstChild();
while (child !== null && i < offset) {
if ($isTextNode(child)) {
let nextSibling = child.getNextSibling();
while ($isTextNode(nextSibling)) {
nextSibling = nextSibling.getNextSibling();
}
}
i++;
child = child.getNextSibling();
}
return createRelativePositionFromTypeIndex(yType, i);
}
return null;
}
function createAbsolutePosition(
relativePosition: RelativePosition,
binding: BaseBinding,
): AbsolutePosition | null {
return createAbsolutePositionFromRelativePosition(
relativePosition,
binding.doc,
);
}
function shouldUpdatePosition(
currentPos: RelativePosition | null | undefined,
pos: RelativePosition | null | undefined,
): boolean {
if (currentPos == null) {
if (pos != null) {
return true;
}
} else if (pos == null || !compareRelativePositions(currentPos, pos)) {
return true;
}
return false;
}
function createCursor(name: string, color: string): Cursor {
return {
color: color,
name: name,
selection: null,
};
}
function destroySelection(binding: BaseBinding, selection: CursorSelection) {
const cursorsContainer = binding.cursorsContainer;
if (cursorsContainer !== null) {
const selections = selection.selections;
const selectionsLength = selections.length;
for (let i = 0; i < selectionsLength; i++) {
cursorsContainer.removeChild(selections[i]);
}
}
}
function destroyCursor(binding: BaseBinding, cursor: Cursor) {
const selection = cursor.selection;
if (selection !== null) {
destroySelection(binding, selection);
}
}
function createCursorSelection(
cursor: Cursor,
anchorKey: NodeKey,
anchorOffset: number,
focusKey: NodeKey,
focusOffset: number,
theme: {cursor?: string; cursorName?: string} = {},
): CursorSelection {
const color = cursor.color;
const caret = document.createElement('span');
if (theme.cursor) {
caret.className = theme.cursor;
setDOMStyleObject(caret.style, {
'--lexical-cursor-color': color,
bottom: '0',
position: 'absolute',
right: '-1px',
top: '0',
});
} else {
setDOMStyleObject(caret.style, {
'background-color': color,
bottom: '0',
position: 'absolute',
right: '-1px',
top: '0',
width: '1px',
'z-index': '10',
});
}
const name = document.createElement('span');
name.textContent = cursor.name;
if (theme.cursorName) {
name.className = theme.cursorName;
} else {
setDOMStyleObject(name.style, {
'background-color': color,
color: '#fff',
'font-family': 'Arial',
'font-size': '12px',
'font-weight': 'bold',
left: '-2px',
'line-height': '12px',
padding: '2px',
position: 'absolute',
top: '-16px',
'white-space': 'nowrap',
});
}
caret.appendChild(name);
return {
anchor: {
key: anchorKey,
offset: anchorOffset,
},
caret,
color,
focus: {
key: focusKey,
offset: focusOffset,
},
name,
selections: [],
};
}
function updateCursor(
binding: BaseBinding,
cursor: Cursor,
nextSelection: null | CursorSelection,
nodeMap: NodeMap,
theme: {selection?: string; selectionBg?: string} = {},
): void {
const editor = binding.editor;
const rootElement = editor.getRootElement();
const cursorsContainer = binding.cursorsContainer;
if (cursorsContainer === null || rootElement === null) {
return;
}
const cursorsContainerOffsetParent = cursorsContainer.offsetParent;
if (cursorsContainerOffsetParent === null) {
return;
}
const containerRect = cursorsContainerOffsetParent.getBoundingClientRect();
const prevSelection = cursor.selection;
if (nextSelection === null) {
if (prevSelection === null) {
return;
} else {
cursor.selection = null;
destroySelection(binding, prevSelection);
return;
}
} else {
cursor.selection = nextSelection;
}
const caret = nextSelection.caret;
const color = nextSelection.color;
const selections = nextSelection.selections;
const anchor = nextSelection.anchor;
const focus = nextSelection.focus;
const anchorKey = anchor.key;
const focusKey = focus.key;
const anchorNode = nodeMap.get(anchorKey);
const focusNode = nodeMap.get(focusKey);
if (anchorNode == null || focusNode == null) {
return;
}
let selectionRects: Array<DOMRect>;
// In the case of a collapsed selection on a linebreak, we need
// to improvise as the browser will return nothing here as <br>
// apparently take up no visual space :/
// This won't work in all cases, but it's better than just showing
// nothing all the time.
if (anchorNode === focusNode && $isLineBreakNode(anchorNode)) {
const brRect = (
editor.getElementByKey(anchorKey) as HTMLElement
).getBoundingClientRect();
selectionRects = [brRect];
} else {
const range = createDOMRange(
editor,
anchorNode,
anchor.offset,
focusNode,
focus.offset,
);
if (range === null) {
return;
}
selectionRects = createRectsFromDOMRange(editor, range);
}
const selectionsLength = selections.length;
const selectionRectsLength = selectionRects.length;
for (let i = 0; i < selectionRectsLength; i++) {
const selectionRect = selectionRects[i];
let selection = selections[i];
if (selection === undefined) {
selection = document.createElement('span');
selections[i] = selection;
const selectionBg = document.createElement('span');
if (theme.selectionBg) {
selectionBg.className = theme.selectionBg;
}
selection.appendChild(selectionBg);
cursorsContainer.appendChild(selection);
}
const top = selectionRect.top - containerRect.top;
const left = selectionRect.left - containerRect.left;
const positionStyle = {
height: `${selectionRect.height}px`,
left: `${left}px`,
'pointer-events': 'none',
position: 'absolute',
top: `${top}px`,
width: `${selectionRect.width}px`,
};
if (theme.selection) {
selection.className = theme.selection;
setDOMStyleObject(selection.style, {
...positionStyle,
'--lexical-cursor-color': color,
});
setDOMStyleObject((selection.firstChild as HTMLSpanElement).style, {
height: '100%',
left: '0',
position: 'absolute',
top: '0',
width: '100%',
});
} else {
setDOMStyleObject(selection.style, positionStyle);
setDOMStyleObject((selection.firstChild as HTMLSpanElement).style, {
...positionStyle,
'background-color': color,
left: '0',
opacity: '0.3',
top: '0',
'z-index': '5',
});
}
if (i === selectionRectsLength - 1) {
if (caret.parentNode !== selection) {
selection.appendChild(caret);
}
}
}
for (let i = selectionsLength - 1; i >= selectionRectsLength; i--) {
const selection = selections[i];
cursorsContainer.removeChild(selection);
selections.pop();
}
}
type AnyCollabNode =
| CollabDecoratorNode
| CollabElementNode
| CollabTextNode
| CollabLineBreakNode;
/**
* @deprecated Use `$getAnchorAndFocusForUserState` instead.
*/
export function getAnchorAndFocusCollabNodesForUserState(
binding: Binding,
userState: UserState,
) {
const {anchorPos, focusPos} = userState;
let anchorCollabNode: AnyCollabNode | null = null;
let anchorOffset = 0;
let focusCollabNode: AnyCollabNode | null = null;
let focusOffset = 0;
if (anchorPos !== null && focusPos !== null) {
const anchorAbsPos = createAbsolutePosition(anchorPos, binding);
const focusAbsPos = createAbsolutePosition(focusPos, binding);
if (anchorAbsPos !== null && focusAbsPos !== null) {
[anchorCollabNode, anchorOffset] = getCollabNodeAndOffset(
anchorAbsPos.type,
anchorAbsPos.index,
);
[focusCollabNode, focusOffset] = getCollabNodeAndOffset(
focusAbsPos.type,
focusAbsPos.index,
);
}
}
return {
anchorCollabNode,
anchorOffset,
focusCollabNode,
focusOffset,
};
}
export function $getAnchorAndFocusForUserState(
binding: AnyBinding,
userState: UserState,
): {
anchorKey: NodeKey | null;
anchorOffset: number;
focusKey: NodeKey | null;
focusOffset: number;
} {
const {anchorPos, focusPos} = userState;
const anchorAbsPos = anchorPos
? createAbsolutePosition(anchorPos, binding)
: null;
const focusAbsPos = focusPos
? createAbsolutePosition(focusPos, binding)
: null;
if (anchorAbsPos === null || focusAbsPos === null) {
return {
anchorKey: null,
anchorOffset: 0,
focusKey: null,
focusOffset: 0,
};
}
if (isBindingV1(binding)) {
const [anchorCollabNode, anchorOffset] = getCollabNodeAndOffset(
anchorAbsPos.type,
anchorAbsPos.index,
);
const [focusCollabNode, focusOffset] = getCollabNodeAndOffset(
focusAbsPos.type,
focusAbsPos.index,
);
return {
anchorKey: anchorCollabNode !== null ? anchorCollabNode.getKey() : null,
anchorOffset,
focusKey: focusCollabNode !== null ? focusCollabNode.getKey() : null,
focusOffset,
};
}
let [anchorNode, anchorOffset] = $getNodeAndOffsetV2(
binding.mapping,
anchorAbsPos,
);
let [focusNode, focusOffset] = $getNodeAndOffsetV2(
binding.mapping,
focusAbsPos,
);
// For a non-collapsed selection, if the start of the selection is as the end of a text node,
// move it to the beginning of the next text node (if one exists).
if (
focusNode &&
anchorNode &&
(focusNode !== anchorNode || focusOffset !== anchorOffset)
) {
const isBackwards = focusNode.isBefore(anchorNode);
const startNode = isBackwards ? focusNode : anchorNode;
const startOffset = isBackwards ? focusOffset : anchorOffset;
if (
$isTextNode(startNode) &&
$isTextNode(startNode.getNextSibling()) &&
startOffset === startNode.getTextContentSize()
) {
if (isBackwards) {
focusNode = startNode.getNextSibling();
focusOffset = 0;
} else {
anchorNode = startNode.getNextSibling();
anchorOffset = 0;
}
}
}
return {
anchorKey: anchorNode !== null ? anchorNode.getKey() : null,
anchorOffset,
focusKey: focusNode !== null ? focusNode.getKey() : null,
focusOffset,
};
}
export function $syncLocalCursorPosition(
binding: AnyBinding,
provider: Provider,
): void {
const awareness = provider.awareness;
const localState = awareness.getLocalState();
if (localState === null) {
return;
}
const {anchorKey, anchorOffset, focusKey, focusOffset} =
$getAnchorAndFocusForUserState(binding, localState);
if (anchorKey !== null && focusKey !== null) {
const selection = $getSelection();
if (!$isRangeSelection(selection)) {
return;
}
$setPoint(selection.anchor, anchorKey, anchorOffset);
$setPoint(selection.focus, focusKey, focusOffset);
}
}
function $setPoint(point: Point, key: NodeKey, offset: number): void {
if (point.key !== key || point.offset !== offset) {
let anchorNode = $getNodeByKey(key);
if (
anchorNode !== null &&
!$isElementNode(anchorNode) &&
!$isTextNode(anchorNode)
) {
const parent = anchorNode.getParentOrThrow();
key = parent.getKey();
offset = anchorNode.getIndexWithinParent();
anchorNode = parent;
}
point.set(key, offset, $isElementNode(anchorNode) ? 'element' : 'text');
}
}
function getCollabNodeAndOffset(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
sharedType: any,
offset: number,
): [null | AnyCollabNode, number] {
const collabNode = sharedType._collabNode;
if (collabNode === undefined) {
return [null, 0];
}
if (collabNode instanceof CollabElementNode) {
const {node, offset: collabNodeOffset} = getPositionFromElementAndOffset(
collabNode,
offset,
true,
);
if (node === null) {
return [collabNode, 0];
} else {
return [node, collabNodeOffset];
}
}
return [null, 0];
}
function $getNodeAndOffsetV2(
mapping: CollabV2Mapping,
absolutePosition: AbsolutePosition,
): [null | LexicalNode, number] {
const yType = absolutePosition.type as XmlElement | XmlText;
const yOffset = absolutePosition.index;
if (yType instanceof XmlElement) {
const node = mapping.get(yType);
if (node === undefined) {
return [null, 0];
}
if (!$isElementNode(node)) {
return [node, yOffset];
}
let remainingYOffset = yOffset;
let lexicalOffset = 0;
const children = node.getChildren();
while (remainingYOffset > 0 && lexicalOffset < children.length) {
const child = children[lexicalOffset];
remainingYOffset -= 1;
lexicalOffset += 1;
if ($isTextNode(child)) {
while (
lexicalOffset < children.length &&
$isTextNode(children[lexicalOffset])
) {
lexicalOffset += 1;
}
}
}
return [node, lexicalOffset];
} else {
const nodes = mapping.get(yType);
if (nodes === undefined) {
return [null, 0];
}
let i = 0;
let adjustedOffset = yOffset;
while (
adjustedOffset > nodes[i].getTextContentSize() &&
i + 1 < nodes.length
) {
adjustedOffset -= nodes[i].getTextContentSize();
i++;
}
const textNode = nodes[i];
return [textNode, Math.min(adjustedOffset, textNode.getTextContentSize())];
}
}
export type SyncCursorPositionsFn = (
binding: AnyBinding,
provider: Provider,
options?: SyncCursorPositionsOptions,
) => void;
export type SyncCursorPositionsOptions = {
getAwarenessStates?: (
binding: BaseBinding,
provider: Provider,
) => Map<number, UserState>;
};
function getAwarenessStatesDefault(
_binding: BaseBinding,
provider: Provider,
): Map<number, UserState> {
return provider.awareness.getStates();
}
export function syncCursorPositions(
binding: AnyBinding,
provider: Provider,
options?: SyncCursorPositionsOptions,
): void {
const {getAwarenessStates = getAwarenessStatesDefault} = options ?? {};
const awarenessStates = Array.from(getAwarenessStates(binding, provider));
const localClientID = binding.clientID;
const cursors = binding.cursors;
const editor = binding.editor;
const collabTheme = editor._config.theme.collaboration;
const nodeMap = editor._editorState._nodeMap;
const visitedClientIDs = new Set();
for (let i = 0; i < awarenessStates.length; i++) {
const awarenessState = awarenessStates[i];
const [clientID, awareness] = awarenessState;
if (clientID !== 0 && clientID !== localClientID) {
visitedClientIDs.add(clientID);
const {name, color, focusing} = awareness;
let selection = null;
let cursor = cursors.get(clientID);
if (cursor === undefined) {
cursor = createCursor(name, color);
cursors.set(clientID, cursor);
}
if (focusing) {
const {anchorKey, anchorOffset, focusKey, focusOffset} = editor.read(
() => $getAnchorAndFocusForUserState(binding, awareness),
);
if (anchorKey !== null && focusKey !== null) {
selection = cursor.selection;
if (selection === null) {
selection = createCursorSelection(
cursor,
anchorKey,
anchorOffset,
focusKey,
focusOffset,
collabTheme,
);
} else {
const anchor = selection.anchor;
const focus = selection.focus;
anchor.key = anchorKey;
anchor.offset = anchorOffset;
focus.key = focusKey;
focus.offset = focusOffset;
}
}
}
updateCursor(binding, cursor, selection, nodeMap, collabTheme);
}
}
const allClientIDs = Array.from(cursors.keys());
for (let i = 0; i < allClientIDs.length; i++) {
const clientID = allClientIDs[i];
if (!visitedClientIDs.has(clientID)) {
const cursor = cursors.get(clientID);
if (cursor !== undefined) {
destroyCursor(binding, cursor);
cursors.delete(clientID);
}
}
}
}
export function syncLexicalSelectionToYjs(
binding: AnyBinding,
provider: Provider,
prevSelection: null | BaseSelection,
nextSelection: null | BaseSelection,
): void {
const awareness = provider.awareness;
const localState = awareness.getLocalState();
if (localState === null) {
return;
}
const {
anchorPos: currentAnchorPos,
focusPos: currentFocusPos,
name,
color,
focusing,
awarenessData,
} = localState;
let anchorPos = null;
let focusPos = null;
if (
nextSelection === null ||
(currentAnchorPos !== null && !nextSelection.is(prevSelection))
) {
if (prevSelection === null) {
return;
}
}
if ($isRangeSelection(nextSelection)) {
if (isBindingV1(binding)) {
anchorPos = createRelativePosition(nextSelection.anchor, binding);
focusPos = createRelativePosition(nextSelection.focus, binding);
} else {
anchorPos = createRelativePositionV2(nextSelection.anchor, binding);
focusPos = createRelativePositionV2(nextSelection.focus, binding);
}
}
if (
shouldUpdatePosition(currentAnchorPos, anchorPos) ||
shouldUpdatePosition(currentFocusPos, focusPos)
) {
awareness.setLocalState({
...localState,
anchorPos,
awarenessData,
color,
focusPos,
focusing,
name,
});
}
}
/**
* 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.
*
*/
import type {EditorState, NodeKey} from 'lexical';
import type {ContentType, Transaction as YTransaction} from 'yjs';
import invariant from '@lexical/internal/invariant';
import {
$addUpdateTag,
$createParagraphNode,
$getNodeByKey,
$getRoot,
$getSelection,
$getWritableNodeState,
$isRangeSelection,
$isTextNode,
COLLABORATION_TAG,
HISTORIC_TAG,
SKIP_SCROLL_INTO_VIEW_TAG,
} from 'lexical';
import {
Item,
iterateDeletedStructs,
Map as YMap,
Text as YText,
XmlElement,
XmlText,
YEvent,
YMapEvent,
YTextEvent,
YXmlEvent,
} from 'yjs';
import {Binding, BindingV2, Provider} from '.';
import {AnyBinding} from './Bindings';
import {CollabDecoratorNode} from './CollabDecoratorNode';
import {CollabElementNode} from './CollabElementNode';
import {CollabTextNode} from './CollabTextNode';
import {
$syncLocalCursorPosition,
syncCursorPositions,
SyncCursorPositionsFn,
syncLexicalSelectionToYjs,
} from './SyncCursors';
import {$createOrUpdateNodeFromYElement, $updateYFragment} from './SyncV2';
import {
$getOrInitCollabNodeFromSharedType,
$moveSelectionToPreviousNode,
doesSelectionNeedRecovering,
getNodeTypeFromSharedType,
syncWithTransaction,
} from './Utils';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function $syncStateEvent(binding: Binding, event: YMapEvent<any>): boolean {
const {target} = event;
if (
!(
target._item &&
target._item.parentSub === '__state' &&
getNodeTypeFromSharedType(target) === undefined &&
(target.parent instanceof XmlText ||
target.parent instanceof XmlElement ||
target.parent instanceof YMap)
)
) {
// TODO there might be a case to handle in here when a YMap
// is used as a value of __state? It would probably be desirable
// to mark the node as dirty when that happens.
return false;
}
const collabNode = $getOrInitCollabNodeFromSharedType(binding, target.parent);
const node = collabNode.getNode();
if (node) {
const state = $getWritableNodeState(node.getWritable());
for (const k of event.keysChanged) {
state.updateFromUnknown(k, target.get(k));
}
}
return true;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function $syncEvent(binding: Binding, event: any): void {
if (event instanceof YMapEvent && $syncStateEvent(binding, event)) {
return;
}
const {target} = event;
const collabNode = $getOrInitCollabNodeFromSharedType(binding, target);
if (collabNode instanceof CollabElementNode && event instanceof YTextEvent) {
// @ts-expect-error We need to access the private childListChanged property of the class
const {keysChanged, childListChanged, delta} = event;
// Update
if (keysChanged.size > 0) {
collabNode.syncPropertiesFromYjs(binding, keysChanged);
}
if (childListChanged) {
collabNode.applyChildrenYjsDelta(binding, delta);
collabNode.syncChildrenFromYjs(binding);
}
} else if (
collabNode instanceof CollabTextNode &&
event instanceof YMapEvent
) {
const {keysChanged} = event;
// Update
if (keysChanged.size > 0) {
collabNode.syncPropertiesAndTextFromYjs(binding, keysChanged);
}
} else if (
collabNode instanceof CollabDecoratorNode &&
event instanceof YXmlEvent
) {
const {attributesChanged} = event;
// Update
if (attributesChanged.size > 0) {
collabNode.syncPropertiesFromYjs(binding, attributesChanged);
}
} else {
invariant(false, 'Expected text, element, or decorator event');
}
}
export function syncYjsChangesToLexical(
binding: Binding,
provider: Provider,
events: Array<YEvent<YText>>,
isFromUndoManger: boolean,
syncCursorPositionsFn: SyncCursorPositionsFn = syncCursorPositions,
): void {
const editor = binding.editor;
const currentEditorState = editor._editorState;
// This line precompute the delta before editor update. The reason is
// delta is computed when it is accessed. Note that this can only be
// safely computed during the event call. If it is accessed after event
// call it might result in unexpected behavior.
// https://github.com/yjs/yjs/blob/00ef472d68545cb260abd35c2de4b3b78719c9e4/src/utils/YEvent.js#L132
events.forEach(event => event.delta);
editor.update(
() => {
for (let i = 0; i < events.length; i++) {
const event = events[i];
$syncEvent(binding, event);
}
$syncCursorFromYjs(currentEditorState, binding, provider);
if (!isFromUndoManger) {
// If it is an external change, we don't want the current scroll position to get changed
// since the user might've intentionally scrolled somewhere else in the document.
$addUpdateTag(SKIP_SCROLL_INTO_VIEW_TAG);
}
},
{
onUpdate: () => {
syncCursorPositionsFn(binding, provider);
editor.update(() => $ensureEditorNotEmpty());
},
skipTransforms: true,
tag: isFromUndoManger ? HISTORIC_TAG : COLLABORATION_TAG,
},
);
}
function $syncCursorFromYjs(
editorState: EditorState,
binding: AnyBinding,
provider: Provider,
) {
const selection = $getSelection();
if ($isRangeSelection(selection)) {
if (doesSelectionNeedRecovering(selection)) {
const prevSelection = editorState._selection;
if ($isRangeSelection(prevSelection)) {
$syncLocalCursorPosition(binding, provider);
if (doesSelectionNeedRecovering(selection)) {
// If the selected node is deleted, move the selection to the previous or parent node.
const anchorNodeKey = selection.anchor.key;
$moveSelectionToPreviousNode(anchorNodeKey, editorState);
}
}
syncLexicalSelectionToYjs(
binding,
provider,
prevSelection,
$getSelection(),
);
} else {
$syncLocalCursorPosition(binding, provider);
}
}
}
function $handleNormalizationMergeConflicts(
binding: Binding,
normalizedNodes: Set<NodeKey>,
): void {
// We handle the merge operations here
const normalizedNodesKeys = Array.from(normalizedNodes);
const collabNodeMap = binding.collabNodeMap;
const mergedNodes: [CollabTextNode, string][] = [];
const removedNodes: CollabTextNode[] = [];
for (let i = 0; i < normalizedNodesKeys.length; i++) {
const nodeKey = normalizedNodesKeys[i];
const lexicalNode = $getNodeByKey(nodeKey);
const collabNode = collabNodeMap.get(nodeKey);
if (collabNode instanceof CollabTextNode) {
if ($isTextNode(lexicalNode)) {
// We mutate the text collab nodes after removing
// all the dead nodes first, otherwise offsets break.
mergedNodes.push([collabNode, lexicalNode.__text]);
} else {
const offset = collabNode.getOffset();
if (offset === -1) {
continue;
}
const parent = collabNode._parent;
collabNode._normalized = true;
parent._xmlText.delete(offset, 1);
removedNodes.push(collabNode);
}
}
}
for (let i = 0; i < removedNodes.length; i++) {
const collabNode = removedNodes[i];
const nodeKey = collabNode.getKey();
collabNodeMap.delete(nodeKey);
const parentChildren = collabNode._parent._children;
const index = parentChildren.indexOf(collabNode);
parentChildren.splice(index, 1);
}
for (let i = 0; i < mergedNodes.length; i++) {
const [collabNode, text] = mergedNodes[i];
collabNode._text = text;
}
}
// 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'.
function $ensureEditorNotEmpty() {
if ($getRoot().getChildrenSize() === 0) {
$getRoot().append($createParagraphNode());
}
}
type IntentionallyMarkedAsDirtyElement = boolean;
export function syncLexicalUpdateToYjs(
binding: Binding,
provider: Provider,
prevEditorState: EditorState,
currEditorState: EditorState,
dirtyElements: Map<NodeKey, IntentionallyMarkedAsDirtyElement>,
dirtyLeaves: Set<NodeKey>,
normalizedNodes: Set<NodeKey>,
tags: Set<string>,
): void {
syncWithTransaction(binding, () => {
currEditorState.read(() => {
// We check if the update has come from a origin where the origin
// was the collaboration binding previously. This can help us
// prevent unnecessarily re-diffing and possible re-applying
// the same change editor state again. For example, if a user
// types a character and we get it, we don't want to then insert
// the same character again. The exception to this heuristic is
// when we need to handle normalization merge conflicts.
if (tags.has(COLLABORATION_TAG) || tags.has(HISTORIC_TAG)) {
if (normalizedNodes.size > 0) {
$handleNormalizationMergeConflicts(binding, normalizedNodes);
}
return;
}
if (dirtyElements.has('root')) {
const prevNodeMap = prevEditorState._nodeMap;
const nextLexicalRoot = $getRoot();
const collabRoot = binding.root;
collabRoot.syncPropertiesFromLexical(
binding,
nextLexicalRoot,
prevNodeMap,
);
collabRoot.syncChildrenFromLexical(
binding,
nextLexicalRoot,
prevNodeMap,
dirtyElements,
dirtyLeaves,
);
}
const selection = $getSelection();
const prevSelection = prevEditorState._selection;
syncLexicalSelectionToYjs(binding, provider, prevSelection, selection);
});
});
}
function $syncEventV2(
binding: BindingV2,
event: YEvent<XmlElement | XmlText>,
): void {
const {target} = event;
if (target instanceof XmlElement && event instanceof YXmlEvent) {
$createOrUpdateNodeFromYElement(
target,
binding,
event.attributesChanged,
// @ts-expect-error childListChanged is private
event.childListChanged,
);
} else if (target instanceof XmlText && event instanceof YTextEvent) {
const parent = target.parent;
if (parent instanceof XmlElement) {
// Need to sync via parent element in order to attach new next nodes.
$createOrUpdateNodeFromYElement(parent, binding, new Set(), true);
} else {
invariant(false, 'Expected XmlElement parent for XmlText');
}
} else {
invariant(false, 'Expected xml or text event');
}
}
export function syncYjsChangesToLexicalV2__EXPERIMENTAL(
binding: BindingV2,
provider: Provider,
events: Array<YEvent<XmlElement | XmlText>>,
transaction: YTransaction,
isFromUndoManger: boolean,
): void {
const editor = binding.editor;
const editorState = editor._editorState;
// Remove deleted nodes from the mapping
iterateDeletedStructs(transaction, transaction.deleteSet, struct => {
if (struct.constructor === Item) {
const content = struct.content as ContentType;
const type = content.type;
if (type) {
binding.mapping.delete(type as XmlElement | XmlText);
}
}
});
// This line precompute the delta before editor update. The reason is
// delta is computed when it is accessed. Note that this can only be
// safely computed during the event call. If it is accessed after event
// call it might result in unexpected behavior.
// https://github.com/yjs/yjs/blob/00ef472d68545cb260abd35c2de4b3b78719c9e4/src/utils/YEvent.js#L132
events.forEach(event => event.delta);
editor.update(
() => {
for (let i = 0; i < events.length; i++) {
const event = events[i];
$syncEventV2(binding, event);
}
$syncCursorFromYjs(editorState, binding, provider);
if (!isFromUndoManger) {
// If it is an external change, we don't want the current scroll position to get changed
// since the user might've intentionally scrolled somewhere else in the document.
$addUpdateTag(SKIP_SCROLL_INTO_VIEW_TAG);
}
},
{
// Need any text node normalization to be synchronously updated back to Yjs, otherwise the
// binding.mapping will get out of sync.
discrete: true,
onUpdate: () => {
syncCursorPositions(binding, provider);
editor.update(() => $ensureEditorNotEmpty());
},
skipTransforms: true,
tag: isFromUndoManger ? HISTORIC_TAG : COLLABORATION_TAG,
},
);
}
export function syncYjsStateToLexicalV2__EXPERIMENTAL(
binding: BindingV2,
provider: Provider,
) {
binding.mapping.clear();
const editor = binding.editor;
editor.update(
() => {
$getRoot().clear();
$createOrUpdateNodeFromYElement(binding.root, binding, null, true);
$addUpdateTag(COLLABORATION_TAG);
},
{
// Need any text node normalization to be synchronously updated back to Yjs, otherwise the
// binding.mapping will get out of sync.
discrete: true,
onUpdate: () => {
syncCursorPositions(binding, provider);
editor.update(() => $ensureEditorNotEmpty());
},
skipTransforms: true,
tag: COLLABORATION_TAG,
},
);
}
export function syncLexicalUpdateToYjsV2__EXPERIMENTAL(
binding: BindingV2,
provider: Provider,
prevEditorState: EditorState,
currEditorState: EditorState,
dirtyElements: Map<NodeKey, IntentionallyMarkedAsDirtyElement>,
normalizedNodes: Set<NodeKey>,
tags: Set<string>,
): void {
const isFromYjs = tags.has(COLLABORATION_TAG) || tags.has(HISTORIC_TAG);
if (isFromYjs && normalizedNodes.size === 0) {
return;
}
// Nodes are normalized synchronously (`discrete: true` above), so the mapping may now be
// incorrect for these nodes, as they point to `getLatest` which is mutable within an update.
normalizedNodes.forEach(nodeKey => {
binding.mapping.deleteNode(nodeKey);
});
syncWithTransaction(binding, () => {
currEditorState.read(() => {
if (dirtyElements.has('root')) {
$updateYFragment(
binding.doc,
binding.root,
$getRoot(),
binding,
new Set(dirtyElements.keys()),
);
}
const selection = $getSelection();
const prevSelection = prevEditorState._selection;
syncLexicalSelectionToYjs(binding, provider, prevSelection, selection);
});
});
}
/**
* 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.
*
*/
/*
* Implementation notes, in no particular order.
*
* Sibling text nodes are synced to a single XmlText type. All non-text nodes are synced one-to-one
* with an XmlElement.
*
* To be space-efficient, only property values that differ from their defaults are synced. Default
* values are determined by creating an instance of the node with no constructor arguments and
* enumerating over its properties.
*
* For a given text node, we make use of XmlText.applyDelta() to sync properties and state to
* specific ranges of text. Refer to TextAttributes below for the structure of the attributes.
*
* For non-text nodes, we use the XmlElement's attributes (YMap under the hood) to sync properties
* and state. The former are stored using their names as keys, and the latter are stored with a
* prefix. (NB: '$' couldn't be used as the prefix because it breaks XmlElement.toDOM().)
*/
import invariant from '@lexical/internal/invariant';
import {
$getSelection,
$getWritableNodeState,
$isRangeSelection,
$isTextNode,
ElementNode,
LexicalNode,
NodeKey,
RootNode,
TextNode,
} from 'lexical';
import {
ContentFormat,
ContentString,
Doc as YDoc,
ID,
isDeleted,
Item,
Snapshot,
Text as YText,
typeListToArraySnapshot,
XmlElement,
XmlHook,
XmlText,
} from 'yjs';
import {BindingV2} from './Bindings';
import simpleDiffWithCursor from './simpleDiffWithCursor';
import {$syncPropertiesFromYjs, getDefaultNodeProperties} from './Utils';
type ComputeYChange = (
event: 'removed' | 'added',
id: ID,
) => Record<string, unknown>;
type TextAttributes = {
t?: string; // type if not TextNode
p?: Record<string, unknown>; // properties
[key: `s_${string}`]: unknown; // state
i?: number; // used to prevent Yjs from merging text nodes itself
ychange?: Record<string, unknown>;
};
// https://docs.yjs.dev/api/shared-types/y.xmlelement
// "Define a top-level type; Note that the nodeName is always "undefined""
const isRootElement = (el: XmlElement): boolean => el.nodeName === 'UNDEFINED';
export const $createOrUpdateNodeFromYElement = (
el: XmlElement,
binding: BindingV2,
keysChanged: Set<string> | null,
childListChanged: boolean,
snapshot?: Snapshot,
prevSnapshot?: Snapshot,
computeYChange?: ComputeYChange,
): LexicalNode | null => {
let node = binding.mapping.get(el);
if (node && keysChanged && keysChanged.size === 0 && !childListChanged) {
return node;
}
const type = isRootElement(el) ? RootNode.getType() : el.nodeName;
const registeredNodes = binding.editor._nodes;
const nodeInfo = registeredNodes.get(type);
if (nodeInfo === undefined) {
throw new Error(
`$createOrUpdateNodeFromYElement: Node ${type} is not registered`,
);
}
if (!node) {
node = new nodeInfo.klass();
keysChanged = null;
childListChanged = true;
}
if (childListChanged && node instanceof ElementNode) {
const children: LexicalNode[] = [];
const $createChildren = (childType: XmlElement | XmlText | XmlHook) => {
if (childType instanceof XmlElement) {
const n = $createOrUpdateNodeFromYElement(
childType,
binding,
new Set(),
false,
snapshot,
prevSnapshot,
computeYChange,
);
if (n !== null) {
children.push(n);
}
} else if (childType instanceof XmlText) {
const ns = $createOrUpdateTextNodesFromYText(
childType,
binding,
snapshot,
prevSnapshot,
computeYChange,
);
if (ns !== null) {
ns.forEach(textchild => {
if (textchild !== null) {
children.push(textchild);
}
});
}
} else {
invariant(false, 'XmlHook is not supported');
}
};
if (snapshot === undefined || prevSnapshot === undefined) {
el.toArray().forEach($createChildren);
} else {
typeListToArraySnapshot(el, new Snapshot(prevSnapshot.ds, snapshot.sv))
.filter(
childType =>
!childType._item.deleted ||
isItemVisible(childType._item, snapshot) ||
isItemVisible(childType._item, prevSnapshot),
)
.forEach($createChildren);
}
$spliceChildren(node, children);
}
// TODO(collab-v2): typing for XmlElement generic
const attrs = el.getAttributes(snapshot) as Record<string, unknown>;
if (!isRootElement(el) && snapshot !== undefined) {
if (!isItemVisible(el._item!, snapshot)) {
attrs[stateKeyToAttrKey('ychange')] = computeYChange
? computeYChange('removed', el._item!.id)
: {type: 'removed'};
} else if (!isItemVisible(el._item!, prevSnapshot)) {
attrs[stateKeyToAttrKey('ychange')] = computeYChange
? computeYChange('added', el._item!.id)
: {type: 'added'};
}
}
const properties: Record<string, unknown> = {
...getDefaultNodeProperties(node, binding),
};
const state: Record<string, unknown> = {};
for (const k in attrs) {
if (k.startsWith(STATE_KEY_PREFIX)) {
state[attrKeyToStateKey(k)] = attrs[k];
} else {
properties[k] = attrs[k];
}
}
$syncPropertiesFromYjs(binding, properties, node, keysChanged);
if (!keysChanged) {
$getWritableNodeState(node).updateFromJSON(state);
} else if (keysChanged.size > 0) {
const writableState = $getWritableNodeState(node);
for (const changedKey of keysChanged) {
if (changedKey.startsWith(STATE_KEY_PREFIX)) {
const stateKey = attrKeyToStateKey(changedKey);
writableState.updateFromUnknown(stateKey, state[stateKey]);
}
}
}
const latestNode = node.getLatest();
binding.mapping.set(el, latestNode);
return latestNode;
};
const $spliceChildren = (node: ElementNode, nextChildren: LexicalNode[]) => {
const prevChildren = node.getChildren();
const prevChildrenKeySet = new Set(prevChildren.map(child => child.getKey()));
const nextChildrenKeySet = new Set(nextChildren.map(child => child.getKey()));
const prevEndIndex = prevChildren.length - 1;
const nextEndIndex = nextChildren.length - 1;
let prevIndex = 0;
let nextIndex = 0;
while (prevIndex <= prevEndIndex && nextIndex <= nextEndIndex) {
const prevKey = prevChildren[prevIndex].getKey();
const nextKey = nextChildren[nextIndex].getKey();
if (prevKey === nextKey) {
prevIndex++;
nextIndex++;
continue;
}
const nextHasPrevKey = nextChildrenKeySet.has(prevKey);
const prevHasNextKey = prevChildrenKeySet.has(nextKey);
if (!nextHasPrevKey) {
// If removing the last node, insert remaining new nodes immediately, otherwise if the node
// cannot be empty, it will remove itself from its parent.
if (nextIndex === 0 && node.getChildrenSize() === 1) {
node.splice(nextIndex, 1, nextChildren.slice(nextIndex));
return;
}
// Remove
node.splice(nextIndex, 1, []);
prevIndex++;
continue;
}
// Create or replace
const nextChildNode = nextChildren[nextIndex];
if (prevHasNextKey) {
node.splice(nextIndex, 1, [nextChildNode]);
prevIndex++;
nextIndex++;
} else {
node.splice(nextIndex, 0, [nextChildNode]);
nextIndex++;
}
}
const appendNewChildren = prevIndex > prevEndIndex;
const removeOldChildren = nextIndex > nextEndIndex;
if (appendNewChildren && !removeOldChildren) {
node.append(...nextChildren.slice(nextIndex));
} else if (removeOldChildren && !appendNewChildren) {
node.splice(
nextChildren.length,
node.getChildrenSize() - nextChildren.length,
[],
);
}
};
const isItemVisible = (item: Item, snapshot?: Snapshot): boolean =>
snapshot === undefined
? !item.deleted
: snapshot.sv.has(item.id.client) &&
snapshot.sv.get(item.id.client)! > item.id.clock &&
!isDeleted(snapshot.ds, item.id);
const $createOrUpdateTextNodesFromYText = (
text: XmlText,
binding: BindingV2,
snapshot?: Snapshot,
prevSnapshot?: Snapshot,
computeYChange?: ComputeYChange,
): Array<TextNode> | null => {
const deltas = toDelta(text, snapshot, prevSnapshot, computeYChange);
// Use existing text nodes if the count and types all align, otherwise throw out the existing
// nodes and create new ones.
let nodes: TextNode[] = binding.mapping.get(text) ?? [];
const nodeTypes: string[] = deltas.map(
delta => delta.attributes.t ?? TextNode.getType(),
);
const canReuseNodes =
nodes.length === nodeTypes.length &&
nodes.every((node, i) => node.getType() === nodeTypes[i]);
if (!canReuseNodes) {
const registeredNodes = binding.editor._nodes;
nodes = nodeTypes.map(type => {
const nodeInfo = registeredNodes.get(type);
if (nodeInfo === undefined) {
throw new Error(
`$createTextNodesFromYText: Node ${type} is not registered`,
);
}
const node = new nodeInfo.klass();
if (!$isTextNode(node)) {
throw new Error(
`$createTextNodesFromYText: Node ${type} is not a TextNode`,
);
}
return node;
});
}
// Sync text, properties and state to the text nodes.
for (let i = 0; i < deltas.length; i++) {
const node = nodes[i];
const delta = deltas[i];
const {attributes, insert} = delta;
if (node.__text !== insert) {
node.setTextContent(insert);
}
const properties = {
...getDefaultNodeProperties(node, binding),
...attributes.p,
};
const state = Object.fromEntries(
Object.entries(attributes)
.filter(([k]) => k.startsWith(STATE_KEY_PREFIX))
.map(([k, v]) => [attrKeyToStateKey(k), v]),
);
$syncPropertiesFromYjs(binding, properties, node, null);
$getWritableNodeState(node).updateFromJSON(state);
}
const latestNodes = nodes.map(node => node.getLatest());
binding.mapping.set(text, latestNodes);
return latestNodes;
};
const $createTypeFromTextNodes = (
nodes: TextNode[],
binding: BindingV2,
): XmlText => {
const type = new XmlText();
$updateYText(type, nodes, binding);
return type;
};
const createTypeFromElementNode = (
node: LexicalNode,
binding: BindingV2,
): XmlElement => {
const type = new XmlElement(node.getType());
const attrs = {
...propertiesToAttributes(node, binding),
...stateToAttributes(node),
};
for (const key in attrs) {
const val = attrs[key];
if (val !== null) {
// TODO(collab-v2): typing for XmlElement generic
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type.setAttribute(key, val as any);
}
}
if (!(node instanceof ElementNode)) {
return type;
}
type.insert(
0,
normalizeNodeContent(node).map(n =>
$createTypeFromTextOrElementNode(n, binding),
),
);
binding.mapping.set(type, node);
return type;
};
const $createTypeFromTextOrElementNode = (
node: LexicalNode | TextNode[],
meta: BindingV2,
): XmlElement | XmlText =>
node instanceof Array
? $createTypeFromTextNodes(node, meta)
: createTypeFromElementNode(node, meta);
const isObject = (
val: unknown,
): val is Record<string | number | symbol, unknown> =>
typeof val === 'object' && val != null;
const equalAttrs = (
pattrs: Record<string | number | symbol, unknown>,
yattrs: Record<string | number | symbol, unknown> | null,
) => {
const keys = Object.keys(pattrs).filter(key => pattrs[key] !== null);
if (yattrs == null) {
return keys.length === 0;
}
let eq =
keys.length ===
Object.keys(yattrs).filter(key => yattrs[key] !== null).length;
for (let i = 0; i < keys.length && eq; i++) {
const key = keys[i];
const l = pattrs[key];
const r = yattrs[key];
eq =
key === 'ychange' ||
l === r ||
(isObject(l) && isObject(r) && equalAttrs(l, r));
}
return eq;
};
type NormalizedPNodeContent = Array<Array<TextNode> | LexicalNode>;
const normalizeNodeContent = (node: LexicalNode): NormalizedPNodeContent => {
if (!(node instanceof ElementNode)) {
return [];
}
const c = node.getChildren();
const res: NormalizedPNodeContent = [];
for (let i = 0; i < c.length; i++) {
const n = c[i];
if ($isTextNode(n)) {
const textNodes: TextNode[] = [];
for (
let maybeTextNode = c[i];
i < c.length && $isTextNode(maybeTextNode);
maybeTextNode = c[++i]
) {
textNodes.push(maybeTextNode);
}
i--;
res.push(textNodes);
} else {
res.push(n);
}
}
return res;
};
const equalYTextLText = (
ytext: XmlText,
ltexts: TextNode[],
binding: BindingV2,
) => {
const deltas = toDelta(ytext);
return (
deltas.length === ltexts.length &&
deltas.every((d, i) => {
const ltext = ltexts[i];
const type = d.attributes.t ?? TextNode.getType();
const propertyAttrs = d.attributes.p ?? {};
const stateAttrs = Object.fromEntries(
Object.entries(d.attributes).filter(([k]) =>
k.startsWith(STATE_KEY_PREFIX),
),
);
return (
d.insert === ltext.getTextContent() &&
type === ltext.getType() &&
equalAttrs(propertyAttrs, propertiesToAttributes(ltext, binding)) &&
equalAttrs(stateAttrs, stateToAttributes(ltext))
);
})
);
};
const equalYTypePNode = (
ytype: XmlElement | XmlText | XmlHook,
lnode: LexicalNode | TextNode[],
binding: BindingV2,
): ytype is XmlElement | XmlText => {
if (
ytype instanceof XmlElement &&
!(lnode instanceof Array) &&
matchNodeName(ytype, lnode)
) {
const normalizedContent = normalizeNodeContent(lnode);
return (
ytype._length === normalizedContent.length &&
equalAttrs(ytype.getAttributes(), {
...propertiesToAttributes(lnode, binding),
...stateToAttributes(lnode),
}) &&
ytype
.toArray()
.every((ychild, i) =>
equalYTypePNode(ychild, normalizedContent[i], binding),
)
);
}
return (
ytype instanceof XmlText &&
lnode instanceof Array &&
equalYTextLText(ytype, lnode, binding)
);
};
const mappedIdentity = (
mapped: LexicalNode | TextNode[] | undefined,
lcontent: LexicalNode | TextNode[],
) =>
mapped === lcontent ||
(mapped instanceof Array &&
lcontent instanceof Array &&
mapped.length === lcontent.length &&
mapped.every((a, i) => lcontent[i] === a));
type EqualityFactor = {
foundMappedChild: boolean;
equalityFactor: number;
};
const computeChildEqualityFactor = (
ytype: XmlElement,
lnode: LexicalNode,
binding: BindingV2,
): EqualityFactor => {
const yChildren = ytype.toArray();
const pChildren = normalizeNodeContent(lnode);
const pChildCnt = pChildren.length;
const yChildCnt = yChildren.length;
const minCnt = Math.min(yChildCnt, pChildCnt);
let left = 0;
let right = 0;
let foundMappedChild = false;
for (; left < minCnt; left++) {
const leftY = yChildren[left];
const leftP = pChildren[left];
if (leftY instanceof XmlHook) {
break;
} else if (mappedIdentity(binding.mapping.get(leftY), leftP)) {
foundMappedChild = true; // definite (good) match!
} else if (!equalYTypePNode(leftY, leftP, binding)) {
break;
}
}
for (; left + right < minCnt; right++) {
const rightY = yChildren[yChildCnt - right - 1];
const rightP = pChildren[pChildCnt - right - 1];
if (rightY instanceof XmlHook) {
break;
} else if (mappedIdentity(binding.mapping.get(rightY), rightP)) {
foundMappedChild = true;
} else if (!equalYTypePNode(rightY, rightP, binding)) {
break;
}
}
return {
equalityFactor: left + right,
foundMappedChild,
};
};
const ytextTrans = (
ytext: YText,
): {nAttrs: Record<string, null>; str: string} => {
let str = '';
let n = ytext._start;
const nAttrs: Record<string, null> = {};
while (n !== null) {
if (!n.deleted) {
if (n.countable && n.content instanceof ContentString) {
str += n.content.str;
} else if (n.content instanceof ContentFormat) {
nAttrs[n.content.key] = null;
}
}
n = n.right;
}
return {
nAttrs,
str,
};
};
const $updateYText = (
ytext: XmlText,
ltexts: TextNode[],
binding: BindingV2,
) => {
binding.mapping.set(ytext, ltexts);
const {nAttrs, str} = ytextTrans(ytext);
const content = ltexts.map((node, i) => {
const nodeType = node.getType();
let p: TextAttributes['p'] | null = propertiesToAttributes(node, binding);
if (Object.keys(p).length === 0) {
p = null;
}
return {
attributes: Object.assign({}, nAttrs, {
...(nodeType !== TextNode.getType() && {t: nodeType}),
p,
...stateToAttributes(node),
...(i > 0 && {i}), // Prevent Yjs from merging text nodes itself.
}),
insert: node.getTextContent(),
nodeKey: node.getKey(),
};
});
const nextText = content.map(c => c.insert).join('');
const selection = $getSelection();
let cursorOffset: number;
if ($isRangeSelection(selection) && selection.isCollapsed()) {
cursorOffset = 0;
for (const c of content) {
if (c.nodeKey === selection.anchor.key) {
cursorOffset += selection.anchor.offset;
break;
}
cursorOffset += c.insert.length;
}
} else {
cursorOffset = nextText.length;
}
const {insert, remove, index} = simpleDiffWithCursor(
str,
nextText,
cursorOffset,
);
ytext.delete(index, remove);
ytext.insert(index, insert);
ytext.applyDelta(
content.map(c => ({attributes: c.attributes, retain: c.insert.length})),
);
};
const toDelta = (
ytext: YText,
snapshot?: Snapshot,
prevSnapshot?: Snapshot,
computeYChange?: ComputeYChange,
): Array<{insert: string; attributes: TextAttributes}> => {
return ytext
.toDelta(snapshot, prevSnapshot, computeYChange)
.map((delta: {insert: string; attributes?: TextAttributes}) => {
const attributes = delta.attributes ?? {};
if ('ychange' in attributes) {
attributes[stateKeyToAttrKey('ychange')] = attributes.ychange;
delete attributes.ychange;
}
return {...delta, attributes};
});
};
const propertiesToAttributes = (node: LexicalNode, meta: BindingV2) => {
const defaultProperties = getDefaultNodeProperties(node, meta);
const attrs: Record<string, unknown> = {};
Object.entries(defaultProperties).forEach(([property, defaultValue]) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const value = (node as any)[property];
if (value !== defaultValue) {
attrs[property] = value;
}
});
return attrs;
};
const STATE_KEY_PREFIX = 's_';
const stateKeyToAttrKey = (key: string): `s_${string}` => `s_${key}`;
const attrKeyToStateKey = (key: string) => {
if (!key.startsWith(STATE_KEY_PREFIX)) {
throw new Error(`Invalid state key: ${key}`);
}
return key.slice(STATE_KEY_PREFIX.length);
};
const stateToAttributes = (node: LexicalNode) => {
const state = node.__state;
if (!state) {
return {};
}
const [unknown = {}, known] = state.getInternalState();
const attrs: Record<string, unknown> = {};
for (const [k, v] of Object.entries(unknown)) {
attrs[stateKeyToAttrKey(k)] = v;
}
for (const [stateConfig, v] of known) {
attrs[stateKeyToAttrKey(stateConfig.key)] = stateConfig.unparse(v);
}
return attrs;
};
export const $updateYFragment = (
y: YDoc,
yDomFragment: XmlElement,
node: LexicalNode,
binding: BindingV2,
dirtyElements: Set<NodeKey>,
) => {
if (
yDomFragment instanceof XmlElement &&
yDomFragment.nodeName !== node.getType() &&
!(isRootElement(yDomFragment) && node.getType() === RootNode.getType())
) {
throw new Error('node name mismatch!');
}
binding.mapping.set(yDomFragment, node);
// update attributes
if (yDomFragment instanceof XmlElement) {
const yDomAttrs = yDomFragment.getAttributes();
const lexicalAttrs = {
...propertiesToAttributes(node, binding),
...stateToAttributes(node),
};
for (const key in lexicalAttrs) {
if (lexicalAttrs[key] != null) {
const isEqual =
yDomAttrs[key] === lexicalAttrs[key] ||
// deep equality check so we don't sync properties/state with object values every update
(isObject(yDomAttrs[key]) &&
isObject(lexicalAttrs[key]) &&
equalAttrs(yDomAttrs[key], lexicalAttrs[key]));
if (!isEqual && key !== 'ychange') {
// TODO(collab-v2): typing for XmlElement generic
// eslint-disable-next-line @typescript-eslint/no-explicit-any
yDomFragment.setAttribute(key, lexicalAttrs[key] as any);
}
} else {
yDomFragment.removeAttribute(key);
}
}
// remove all keys that are no longer in pAttrs
for (const key in yDomAttrs) {
if (lexicalAttrs[key] === undefined) {
yDomFragment.removeAttribute(key);
}
}
}
// update children
const lChildren = normalizeNodeContent(node);
const lChildCnt = lChildren.length;
const yChildren = yDomFragment.toArray();
const yChildCnt = yChildren.length;
const minCnt = Math.min(lChildCnt, yChildCnt);
let left = 0;
let right = 0;
// find number of matching elements from left
for (; left < minCnt; left++) {
const leftY = yChildren[left];
const leftL = lChildren[left];
if (leftY instanceof XmlHook) {
break;
} else if (mappedIdentity(binding.mapping.get(leftY), leftL)) {
if (leftL instanceof ElementNode && dirtyElements.has(leftL.getKey())) {
$updateYFragment(
y,
leftY as XmlElement,
leftL as LexicalNode,
binding,
dirtyElements,
);
}
} else if (equalYTypePNode(leftY, leftL, binding)) {
// update mapping
binding.mapping.set(leftY, leftL);
} else {
break;
}
}
// find number of matching elements from right
for (; right + left < minCnt; right++) {
const rightY = yChildren[yChildCnt - right - 1];
const rightL = lChildren[lChildCnt - right - 1];
if (rightY instanceof XmlHook) {
break;
} else if (mappedIdentity(binding.mapping.get(rightY), rightL)) {
if (rightL instanceof ElementNode && dirtyElements.has(rightL.getKey())) {
$updateYFragment(
y,
rightY as XmlElement,
rightL as LexicalNode,
binding,
dirtyElements,
);
}
} else if (equalYTypePNode(rightY, rightL, binding)) {
// update mapping
binding.mapping.set(rightY, rightL);
} else {
break;
}
}
// try to compare and update
while (yChildCnt - left - right > 0 && lChildCnt - left - right > 0) {
const leftY = yChildren[left];
const leftL = lChildren[left];
const rightY = yChildren[yChildCnt - right - 1];
const rightL = lChildren[lChildCnt - right - 1];
if (leftY instanceof XmlText && leftL instanceof Array) {
if (!equalYTextLText(leftY, leftL, binding)) {
$updateYText(leftY, leftL, binding);
}
left += 1;
} else {
let updateLeft =
leftY instanceof XmlElement && matchNodeName(leftY, leftL);
let updateRight =
rightY instanceof XmlElement && matchNodeName(rightY, rightL);
if (updateLeft && updateRight) {
// decide which which element to update
const equalityLeft = computeChildEqualityFactor(
leftY as XmlElement,
leftL as LexicalNode,
binding,
);
const equalityRight = computeChildEqualityFactor(
rightY as XmlElement,
rightL as LexicalNode,
binding,
);
if (equalityLeft.foundMappedChild && !equalityRight.foundMappedChild) {
updateRight = false;
} else if (
!equalityLeft.foundMappedChild &&
equalityRight.foundMappedChild
) {
updateLeft = false;
} else if (equalityLeft.equalityFactor < equalityRight.equalityFactor) {
updateLeft = false;
} else {
updateRight = false;
}
}
if (updateLeft) {
$updateYFragment(
y,
leftY as XmlElement,
leftL as LexicalNode,
binding,
dirtyElements,
);
left += 1;
} else if (updateRight) {
$updateYFragment(
y,
rightY as XmlElement,
rightL as LexicalNode,
binding,
dirtyElements,
);
right += 1;
} else {
binding.mapping.delete(yDomFragment.get(left));
yDomFragment.delete(left, 1);
yDomFragment.insert(left, [
$createTypeFromTextOrElementNode(leftL, binding),
]);
left += 1;
}
}
}
const yDelLen = yChildCnt - left - right;
if (yChildCnt === 1 && lChildCnt === 0 && yChildren[0] instanceof XmlText) {
binding.mapping.delete(yChildren[0]);
// Edge case handling https://github.com/yjs/y-prosemirror/issues/108
// Only delete the content of the Y.Text to retain remote changes on the same Y.Text object
yChildren[0].delete(0, yChildren[0].length);
} else if (yDelLen > 0) {
yDomFragment
.slice(left, left + yDelLen)
.forEach(type => binding.mapping.delete(type));
yDomFragment.delete(left, yDelLen);
}
if (left + right < lChildCnt) {
const ins = [];
for (let i = left; i < lChildCnt - right; i++) {
ins.push($createTypeFromTextOrElementNode(lChildren[i], binding));
}
yDomFragment.insert(left, ins);
}
};
const matchNodeName = (yElement: XmlElement, lnode: LexicalNode | TextNode[]) =>
!(lnode instanceof Array) && yElement.nodeName === lnode.getType();
/**
* 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.
*
*/
import {CollabDecoratorNode} from './CollabDecoratorNode';
import {CollabElementNode} from './CollabElementNode';
import {CollabLineBreakNode} from './CollabLineBreakNode';
import {CollabTextNode} from './CollabTextNode';
declare module 'yjs' {
interface XmlElement {
_collabNode: CollabDecoratorNode;
}
interface XmlText {
_collabNode: CollabElementNode;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface Map<MapType> {
_collabNode: CollabLineBreakNode | CollabTextNode;
}
}
/**
* 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.
*
*/
import type {BaseBinding, Binding, YjsNode} from '.';
import invariant from '@lexical/internal/invariant';
import {
$getNodeByKey,
$getRoot,
$getWritableNodeState,
$isDecoratorNode,
$isElementNode,
$isLineBreakNode,
$isRootNode,
$isTextNode,
createEditor,
DecoratorNode,
EditorState,
ElementNode,
isLexicalEditor,
LexicalNode,
NodeKey,
RangeSelection,
TextNode,
} from 'lexical';
import {Doc, Map as YMap, XmlElement, XmlText} from 'yjs';
import {isBindingV1} from './Bindings';
import {
$createCollabDecoratorNode,
CollabDecoratorNode,
} from './CollabDecoratorNode';
import {$createCollabElementNode, CollabElementNode} from './CollabElementNode';
import {
$createCollabLineBreakNode,
CollabLineBreakNode,
} from './CollabLineBreakNode';
import {$createCollabTextNode, CollabTextNode} from './CollabTextNode';
const baseExcludedProperties = new Set<string>([
'__key',
'__parent',
'__next',
'__prev',
'__state',
]);
const elementExcludedProperties = new Set<string>([
'__first',
'__last',
'__size',
]);
const rootExcludedProperties = new Set<string>(['__cachedText']);
const textExcludedProperties = new Set<string>(['__text']);
function isExcludedProperty(
name: string,
node: LexicalNode,
binding: BaseBinding,
): boolean {
if (
baseExcludedProperties.has(name) ||
typeof (node as unknown as Record<string, unknown>)[name] === 'function'
) {
return true;
}
if ($isTextNode(node)) {
if (textExcludedProperties.has(name)) {
return true;
}
} else if ($isElementNode(node)) {
if (
elementExcludedProperties.has(name) ||
($isRootNode(node) && rootExcludedProperties.has(name))
) {
return true;
}
}
const nodeKlass = node.constructor;
const excludedProperties = binding.excludedProperties.get(nodeKlass);
return excludedProperties != null && excludedProperties.has(name);
}
export function initializeNodeProperties(binding: BaseBinding): void {
const {editor, nodeProperties} = binding;
editor.update(() => {
editor._nodes.forEach(nodeInfo => {
const node = new nodeInfo.klass();
const defaultProperties: {[property: string]: unknown} = {};
for (const [property, value] of Object.entries(node)) {
if (!isExcludedProperty(property, node, binding)) {
defaultProperties[property] = value;
}
}
nodeProperties.set(node.__type, Object.freeze(defaultProperties));
});
});
}
export function getDefaultNodeProperties(
node: LexicalNode,
binding: BaseBinding,
): {[property: string]: unknown} {
const type = node.__type;
const {nodeProperties} = binding;
const properties = nodeProperties.get(type);
invariant(
properties !== undefined,
'Node properties for %s not initialized for sync',
type,
);
return properties;
}
export function getIndexOfYjsNode(
yjsParentNode: YjsNode,
yjsNode: YjsNode,
): number {
let node = yjsParentNode.firstChild;
let i = -1;
if (node === null) {
return -1;
}
do {
i++;
if (node === yjsNode) {
return i;
}
// @ts-expect-error Sibling exists but type is not available from YJS.
node = node.nextSibling;
if (node === null) {
return -1;
}
} while (node !== null);
return i;
}
export function $createCollabNodeFromLexicalNode(
binding: Binding,
lexicalNode: LexicalNode,
parent: CollabElementNode,
):
| CollabElementNode
| CollabTextNode
| CollabLineBreakNode
| CollabDecoratorNode {
const nodeType = lexicalNode.__type;
let collabNode;
if ($isElementNode(lexicalNode)) {
const xmlText = new XmlText();
collabNode = $createCollabElementNode(xmlText, parent, nodeType);
collabNode.syncPropertiesFromLexical(binding, lexicalNode, null);
collabNode.syncChildrenFromLexical(binding, lexicalNode, null, null, null);
} else if ($isTextNode(lexicalNode)) {
// TODO create a token text node for token, segmented nodes.
const map = new YMap();
collabNode = $createCollabTextNode(
map,
lexicalNode.__text,
parent,
nodeType,
);
collabNode.syncPropertiesAndTextFromLexical(binding, lexicalNode, null);
} else if ($isLineBreakNode(lexicalNode)) {
const map = new YMap();
map.set('__type', 'linebreak');
collabNode = $createCollabLineBreakNode(map, parent);
} else if ($isDecoratorNode(lexicalNode)) {
const xmlElem = new XmlElement();
collabNode = $createCollabDecoratorNode(xmlElem, parent, nodeType);
collabNode.syncPropertiesFromLexical(binding, lexicalNode, null);
} else {
invariant(false, 'Expected text, element, decorator, or linebreak node');
}
collabNode._key = lexicalNode.__key;
return collabNode;
}
export function getNodeTypeFromSharedType(
sharedType: XmlText | YMap<unknown> | XmlElement,
): string | undefined {
const type = sharedTypeGet(sharedType, '__type');
invariant(
typeof type === 'string' || typeof type === 'undefined',
'Expected shared type to include type attribute',
);
return type;
}
export function $getOrInitCollabNodeFromSharedType(
binding: Binding,
sharedType: XmlText | YMap<unknown> | XmlElement,
parent?: CollabElementNode,
):
| CollabElementNode
| CollabTextNode
| CollabLineBreakNode
| CollabDecoratorNode {
const collabNode = sharedType._collabNode;
if (collabNode === undefined) {
const registeredNodes = binding.editor._nodes;
const type = getNodeTypeFromSharedType(sharedType);
invariant(
typeof type === 'string',
'Expected shared type to include type attribute',
);
const nodeInfo = registeredNodes.get(type);
invariant(nodeInfo !== undefined, 'Node %s is not registered', type);
const sharedParent = sharedType.parent;
const targetParent =
parent === undefined && sharedParent !== null
? $getOrInitCollabNodeFromSharedType(
binding,
sharedParent as XmlText | YMap<unknown> | XmlElement,
)
: parent || null;
invariant(
targetParent instanceof CollabElementNode,
'Expected parent to be a collab element node',
);
if (sharedType instanceof XmlText) {
return $createCollabElementNode(sharedType, targetParent, type);
} else if (sharedType instanceof YMap) {
if (type === 'linebreak') {
return $createCollabLineBreakNode(sharedType, targetParent);
}
return $createCollabTextNode(sharedType, '', targetParent, type);
} else if (sharedType instanceof XmlElement) {
return $createCollabDecoratorNode(sharedType, targetParent, type);
}
}
return collabNode;
}
export function createLexicalNodeFromCollabNode(
binding: Binding,
collabNode:
| CollabElementNode
| CollabTextNode
| CollabDecoratorNode
| CollabLineBreakNode,
parentKey: NodeKey,
): LexicalNode {
const type = collabNode.getType();
const registeredNodes = binding.editor._nodes;
const nodeInfo = registeredNodes.get(type);
invariant(nodeInfo !== undefined, 'Node %s is not registered', type);
const lexicalNode:
| DecoratorNode<unknown>
| TextNode
| ElementNode
| LexicalNode = new nodeInfo.klass();
lexicalNode.__parent = parentKey;
collabNode._key = lexicalNode.__key;
if (collabNode instanceof CollabElementNode) {
const xmlText = collabNode._xmlText;
collabNode.syncPropertiesFromYjs(binding, null);
collabNode.applyChildrenYjsDelta(binding, xmlText.toDelta());
collabNode.syncChildrenFromYjs(binding);
} else if (collabNode instanceof CollabTextNode) {
collabNode.syncPropertiesAndTextFromYjs(binding, null);
} else if (collabNode instanceof CollabDecoratorNode) {
collabNode.syncPropertiesFromYjs(binding, null);
}
binding.collabNodeMap.set(lexicalNode.__key, collabNode);
return lexicalNode;
}
export function $syncPropertiesFromYjs(
binding: BaseBinding,
sharedType:
| XmlText
| YMap<unknown>
| XmlElement
// v2
| Record<string, unknown>,
lexicalNode: LexicalNode,
keysChanged: null | Set<string>,
): void {
const properties =
keysChanged === null
? sharedType instanceof YMap
? Array.from(sharedType.keys())
: sharedType instanceof XmlText || sharedType instanceof XmlElement
? Object.keys(sharedType.getAttributes())
: Object.keys(sharedType)
: Array.from(keysChanged);
let writableNode: LexicalNode | undefined;
for (let i = 0; i < properties.length; i++) {
const property = properties[i];
if (isExcludedProperty(property, lexicalNode, binding)) {
if (property === '__state' && isBindingV1(binding)) {
if (!writableNode) {
writableNode = lexicalNode.getWritable();
}
$syncNodeStateToLexical(sharedType, writableNode);
}
continue;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const prevValue = (lexicalNode as any)[property];
let nextValue = sharedTypeGet(sharedType, property);
if (prevValue !== nextValue) {
if (nextValue instanceof Doc) {
const yjsDocMap = binding.docMap;
if (prevValue instanceof Doc) {
yjsDocMap.delete(prevValue.guid);
}
const key = nextValue.guid;
yjsDocMap.set(key, nextValue);
// If the node already constructed a nested editor (e.g. via
// buildEditorFromExtensions in its constructor), reuse it so its
// extensions and LexicalBuilder registration survive the sync.
// Otherwise, fall back to a bare editor.
if (isLexicalEditor(prevValue)) {
prevValue._key = key;
nextValue = prevValue;
} else {
const nestedEditor = createEditor();
nestedEditor._key = key;
nextValue = nestedEditor;
}
}
if (writableNode === undefined) {
writableNode = lexicalNode.getWritable();
}
writableNode[property as string & keyof typeof writableNode] =
// eslint-disable-next-line @typescript-eslint/no-explicit-any
nextValue as any;
}
}
}
function sharedTypeGet(
sharedType: XmlText | YMap<unknown> | XmlElement | Record<string, unknown>,
property: string,
): unknown {
if (sharedType instanceof YMap) {
return sharedType.get(property);
} else if (
sharedType instanceof XmlText ||
sharedType instanceof XmlElement
) {
return sharedType.getAttribute(property);
} else {
return sharedType[property];
}
}
function sharedTypeSet(
sharedType: XmlText | YMap<unknown> | XmlElement,
property: string,
nextValue: unknown,
): void {
if (sharedType instanceof YMap) {
sharedType.set(property, nextValue);
} else {
sharedType.setAttribute(property, nextValue as string);
}
}
function $syncNodeStateToLexical(
sharedType: XmlText | YMap<unknown> | XmlElement | Record<string, unknown>,
lexicalNode: LexicalNode,
): void {
const existingState = sharedTypeGet(sharedType, '__state');
if (!(existingState instanceof YMap)) {
return;
}
// This should only called when creating the node initially,
// incremental updates to state come in through YMapEvent
// with the __state as the target.
$getWritableNodeState(lexicalNode).updateFromJSON(existingState.toJSON());
}
function syncNodeStateFromLexical(
binding: Binding,
sharedType: XmlText | YMap<unknown> | XmlElement,
prevLexicalNode: null | LexicalNode,
nextLexicalNode: LexicalNode,
): void {
const nextState = nextLexicalNode.__state;
// Reading from a shared type that hasn't been integrated into a doc yet
// logs a "premature access" warning in yjs >= 13.6.10. When the shared
// type is detached we know there cannot be any existing state.
const existingState =
sharedType.doc === null ? undefined : sharedTypeGet(sharedType, '__state');
if (!nextState) {
return;
}
const [unknown, known] = nextState.getInternalState();
const prevState = prevLexicalNode && prevLexicalNode.__state;
const stateMap: YMap<unknown> =
existingState instanceof YMap ? existingState : new YMap();
if (prevState === nextState) {
return;
}
const [prevUnknown, prevKnown] =
prevState && stateMap.doc
? prevState.getInternalState()
: [undefined, new Map()];
if (unknown) {
for (const [k, v] of Object.entries(unknown)) {
if (prevUnknown && v !== prevUnknown[k]) {
stateMap.set(k, v);
}
}
}
for (const [stateConfig, v] of known) {
if (prevKnown.get(stateConfig) !== v) {
stateMap.set(stateConfig.key, stateConfig.unparse(v));
}
}
if (!existingState) {
sharedTypeSet(sharedType, '__state', stateMap);
}
}
export function syncPropertiesFromLexical(
binding: Binding,
sharedType: XmlText | YMap<unknown> | XmlElement,
prevLexicalNode: null | LexicalNode,
nextLexicalNode: LexicalNode,
): void {
const properties = Object.keys(
getDefaultNodeProperties(nextLexicalNode, binding),
);
const EditorClass = binding.editor.constructor;
syncNodeStateFromLexical(
binding,
sharedType,
prevLexicalNode,
nextLexicalNode,
);
for (let i = 0; i < properties.length; i++) {
const property = properties[i];
const prevValue =
// eslint-disable-next-line @typescript-eslint/no-explicit-any
prevLexicalNode === null ? undefined : (prevLexicalNode as any)[property];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let nextValue = (nextLexicalNode as any)[property];
if (prevValue !== nextValue) {
if (nextValue instanceof EditorClass) {
const yjsDocMap = binding.docMap;
let prevDoc;
if (prevValue instanceof EditorClass) {
const prevKey = prevValue._key;
prevDoc = yjsDocMap.get(prevKey);
yjsDocMap.delete(prevKey);
}
// If we already have a document, use it.
const doc = prevDoc || new Doc();
const key = doc.guid;
nextValue._key = key;
yjsDocMap.set(key, doc);
nextValue = doc;
// Mark the node dirty as we've assigned a new key to it
binding.editor.update(() => {
nextLexicalNode.markDirty();
});
}
sharedTypeSet(sharedType, property, nextValue);
}
}
}
export function spliceString(
str: string,
index: number,
delCount: number,
newText: string,
): string {
return str.slice(0, index) + newText + str.slice(index + delCount);
}
export function getPositionFromElementAndOffset(
node: CollabElementNode,
offset: number,
boundaryIsEdge: boolean,
): {
length: number;
node:
| CollabElementNode
| CollabTextNode
| CollabDecoratorNode
| CollabLineBreakNode
| null;
nodeIndex: number;
offset: number;
} {
let index = 0;
let i = 0;
const children = node._children;
const childrenLength = children.length;
for (; i < childrenLength; i++) {
const child = children[i];
const childOffset = index;
const size = child.getSize();
index += size;
const exceedsBoundary = boundaryIsEdge ? index >= offset : index > offset;
if (exceedsBoundary && child instanceof CollabTextNode) {
let textOffset = offset - childOffset - 1;
if (textOffset < 0) {
textOffset = 0;
}
const diffLength = index - offset;
return {
length: diffLength,
node: child,
nodeIndex: i,
offset: textOffset,
};
}
if (index > offset) {
return {
length: 0,
node: child,
nodeIndex: i,
offset: childOffset,
};
} else if (i === childrenLength - 1) {
return {
length: 0,
node: null,
nodeIndex: i + 1,
offset: childOffset + 1,
};
}
}
return {
length: 0,
node: null,
nodeIndex: 0,
offset: 0,
};
}
export function doesSelectionNeedRecovering(
selection: RangeSelection,
): boolean {
const anchor = selection.anchor;
const focus = selection.focus;
let recoveryNeeded = false;
try {
const anchorNode = anchor.getNode();
const focusNode = focus.getNode();
if (
// We might have removed a node that no longer exists
!anchorNode.isAttached() ||
!focusNode.isAttached() ||
// If we've split a node, then the offset might not be right
($isTextNode(anchorNode) &&
anchor.offset > anchorNode.getTextContentSize()) ||
($isTextNode(focusNode) && focus.offset > focusNode.getTextContentSize())
) {
recoveryNeeded = true;
}
} catch (_e) {
// Sometimes checking nor a node via getNode might trigger
// an error, so we need recovery then too.
recoveryNeeded = true;
}
return recoveryNeeded;
}
export function syncWithTransaction(
binding: BaseBinding,
fn: () => void,
): void {
binding.doc.transact(fn, binding);
}
export function $moveSelectionToPreviousNode(
anchorNodeKey: string,
currentEditorState: EditorState,
) {
const anchorNode = currentEditorState._nodeMap.get(anchorNodeKey);
if (!anchorNode) {
$getRoot().selectStart();
return;
}
// Get previous node
const prevNodeKey = anchorNode.__prev;
let prevNode: ElementNode | null = null;
if (prevNodeKey) {
prevNode = $getNodeByKey(prevNodeKey);
}
// If previous node not found, get parent node
if (prevNode === null && anchorNode.__parent !== null) {
prevNode = $getNodeByKey(anchorNode.__parent);
}
if (prevNode === null) {
$getRoot().selectStart();
return;
}
if (prevNode !== null && prevNode.isAttached()) {
prevNode.selectEnd();
return;
} else {
// If the found node is also deleted, select the next one
$moveSelectionToPreviousNode(prevNode.__key, currentEditorState);
}
}
+31
-16

@@ -14,8 +14,9 @@ {

"license": "MIT",
"version": "0.44.1-nightly.20260519.0",
"main": "LexicalYjs.js",
"types": "index.d.ts",
"version": "0.45.0",
"main": "./dist/LexicalYjs.js",
"types": "./dist/index.d.ts",
"dependencies": {
"@lexical/selection": "0.44.1-nightly.20260519.0",
"lexical": "0.44.1-nightly.20260519.0"
"@lexical/internal": "0.45.0",
"@lexical/selection": "0.45.0",
"lexical": "0.45.0"
},

@@ -33,21 +34,35 @@ "devDependencies": {

},
"module": "LexicalYjs.mjs",
"module": "./dist/LexicalYjs.mjs",
"sideEffects": false,
"exports": {
".": {
"source": "./src/index.ts",
"import": {
"types": "./index.d.ts",
"development": "./LexicalYjs.dev.mjs",
"production": "./LexicalYjs.prod.mjs",
"node": "./LexicalYjs.node.mjs",
"default": "./LexicalYjs.mjs"
"types": "./dist/index.d.ts",
"development": "./dist/LexicalYjs.dev.mjs",
"production": "./dist/LexicalYjs.prod.mjs",
"node": "./dist/LexicalYjs.node.mjs",
"default": "./dist/LexicalYjs.mjs"
},
"require": {
"types": "./index.d.ts",
"development": "./LexicalYjs.dev.js",
"production": "./LexicalYjs.prod.js",
"default": "./LexicalYjs.js"
"types": "./dist/index.d.ts",
"development": "./dist/LexicalYjs.dev.js",
"production": "./dist/LexicalYjs.prod.js",
"default": "./dist/LexicalYjs.js"
}
}
}
},
"files": [
"dist",
"src",
"!src/__tests__",
"!src/__bench__",
"!src/__mocks__",
"!src/**/*.test.ts",
"!src/**/*.test.tsx",
"!src/**/*.bench.ts",
"!src/**/*.bench.tsx",
"README.md",
"LICENSE"
]
}
/**
* 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.
*
*/
import type { CollabDecoratorNode } from './CollabDecoratorNode';
import type { CollabElementNode } from './CollabElementNode';
import type { CollabLineBreakNode } from './CollabLineBreakNode';
import type { CollabTextNode } from './CollabTextNode';
import type { Cursor } from './SyncCursors';
import type { LexicalEditor, NodeKey } from 'lexical';
import { Klass, LexicalNode } from 'lexical';
import { Doc, XmlElement } from 'yjs';
import { Provider } from '.';
import { CollabV2Mapping } from './CollabV2Mapping';
export type ClientID = number;
export interface BaseBinding {
clientID: number;
cursors: Map<ClientID, Cursor>;
cursorsContainer: null | HTMLElement;
doc: Doc;
docMap: Map<string, Doc>;
editor: LexicalEditor;
id: string;
nodeProperties: Map<string, {
[property: string]: unknown;
}>;
excludedProperties: ExcludedProperties;
}
export interface Binding extends BaseBinding {
collabNodeMap: Map<NodeKey, CollabElementNode | CollabTextNode | CollabDecoratorNode | CollabLineBreakNode>;
root: CollabElementNode;
}
export interface BindingV2 extends BaseBinding {
mapping: CollabV2Mapping;
root: XmlElement;
}
export type AnyBinding = Binding | BindingV2;
export type ExcludedProperties = Map<Klass<LexicalNode>, Set<string>>;
export declare function createBinding(editor: LexicalEditor, provider: Provider, id: string, doc: Doc | null | undefined, docMap: Map<string, Doc>, excludedProperties?: ExcludedProperties): Binding;
export declare function createBindingV2__EXPERIMENTAL(editor: LexicalEditor, id: string, doc: Doc | null | undefined, docMap: Map<string, Doc>, options?: {
excludedProperties?: ExcludedProperties;
rootName?: string;
}): BindingV2;
export declare function isBindingV1(binding: BaseBinding): binding is Binding;
export declare function isBindingV2(binding: BaseBinding): binding is BindingV2;
/**
* 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.
*
*/
import type { Binding } from '.';
import type { CollabElementNode } from './CollabElementNode';
import type { DecoratorNode, NodeKey, NodeMap } from 'lexical';
import type { XmlElement } from 'yjs';
export declare class CollabDecoratorNode {
_xmlElem: XmlElement;
_key: NodeKey;
_parent: CollabElementNode;
_type: string;
constructor(xmlElem: XmlElement, parent: CollabElementNode, type: string);
getPrevNode(nodeMap: null | NodeMap): null | DecoratorNode<unknown>;
getNode(): null | DecoratorNode<unknown>;
getSharedType(): XmlElement;
getType(): string;
getKey(): NodeKey;
getSize(): number;
getOffset(): number;
syncPropertiesFromLexical(binding: Binding, nextLexicalNode: DecoratorNode<unknown>, prevNodeMap: null | NodeMap): void;
syncPropertiesFromYjs(binding: Binding, keysChanged: null | Set<string>): void;
destroy(binding: Binding): void;
}
export declare function $createCollabDecoratorNode(xmlElem: XmlElement, parent: CollabElementNode, type: string): CollabDecoratorNode;
/**
* 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.
*
*/
import type { Binding } from '.';
import type { ElementNode, NodeKey, NodeMap } from 'lexical';
import type { AbstractType, XmlText } from 'yjs';
import { CollabDecoratorNode } from './CollabDecoratorNode';
import { CollabLineBreakNode } from './CollabLineBreakNode';
import { CollabTextNode } from './CollabTextNode';
type IntentionallyMarkedAsDirtyElement = boolean;
export declare class CollabElementNode {
_key: NodeKey;
_children: Array<CollabElementNode | CollabTextNode | CollabDecoratorNode | CollabLineBreakNode>;
_xmlText: XmlText;
_type: string;
_parent: null | CollabElementNode;
constructor(xmlText: XmlText, parent: null | CollabElementNode, type: string);
getPrevNode(nodeMap: null | NodeMap): null | ElementNode;
getNode(): null | ElementNode;
getSharedType(): XmlText;
getType(): string;
getKey(): NodeKey;
isEmpty(): boolean;
getSize(): number;
getOffset(): number;
syncPropertiesFromYjs(binding: Binding, keysChanged: null | Set<string>): void;
applyChildrenYjsDelta(binding: Binding, deltas: Array<{
insert?: string | object | AbstractType<unknown>;
delete?: number;
retain?: number;
attributes?: {
[x: string]: unknown;
};
}>): void;
syncChildrenFromYjs(binding: Binding): void;
syncPropertiesFromLexical(binding: Binding, nextLexicalNode: ElementNode, prevNodeMap: null | NodeMap): void;
_syncChildFromLexical(binding: Binding, index: number, key: NodeKey, prevNodeMap: null | NodeMap, dirtyElements: null | Map<NodeKey, IntentionallyMarkedAsDirtyElement>, dirtyLeaves: null | Set<NodeKey>): void;
syncChildrenFromLexical(binding: Binding, nextLexicalNode: ElementNode, prevNodeMap: null | NodeMap, dirtyElements: null | Map<NodeKey, IntentionallyMarkedAsDirtyElement>, dirtyLeaves: null | Set<NodeKey>): void;
append(collabNode: CollabElementNode | CollabDecoratorNode | CollabTextNode | CollabLineBreakNode): void;
splice(binding: Binding, index: number, delCount: number, collabNode?: CollabElementNode | CollabDecoratorNode | CollabTextNode | CollabLineBreakNode): void;
getChildOffset(collabNode: CollabElementNode | CollabTextNode | CollabDecoratorNode | CollabLineBreakNode): number;
destroy(binding: Binding): void;
}
export declare function $createCollabElementNode(xmlText: XmlText, parent: null | CollabElementNode, type: string): CollabElementNode;
export {};
/**
* 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.
*
*/
import type { Binding } from '.';
import type { CollabElementNode } from './CollabElementNode';
import type { LineBreakNode, NodeKey } from 'lexical';
import type { Map as YMap } from 'yjs';
export declare class CollabLineBreakNode {
_map: YMap<unknown>;
_key: NodeKey;
_parent: CollabElementNode;
_type: 'linebreak';
constructor(map: YMap<unknown>, parent: CollabElementNode);
getNode(): null | LineBreakNode;
getKey(): NodeKey;
getSharedType(): YMap<unknown>;
getType(): string;
getSize(): number;
getOffset(): number;
destroy(binding: Binding): void;
}
export declare function $createCollabLineBreakNode(map: YMap<unknown>, parent: CollabElementNode): CollabLineBreakNode;
/**
* 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.
*
*/
import type { Binding } from '.';
import type { CollabElementNode } from './CollabElementNode';
import type { NodeKey, NodeMap, TextNode } from 'lexical';
import type { Map as YMap } from 'yjs';
export declare class CollabTextNode {
_map: YMap<unknown>;
_key: NodeKey;
_parent: CollabElementNode;
_text: string;
_type: string;
_normalized: boolean;
constructor(map: YMap<unknown>, text: string, parent: CollabElementNode, type: string);
getPrevNode(nodeMap: null | NodeMap): null | TextNode;
getNode(): null | TextNode;
getSharedType(): YMap<unknown>;
getType(): string;
getKey(): NodeKey;
getSize(): number;
getOffset(): number;
spliceText(index: number, delCount: number, newText: string): void;
syncPropertiesAndTextFromLexical(binding: Binding, nextLexicalNode: TextNode, prevNodeMap: null | NodeMap): void;
syncPropertiesAndTextFromYjs(binding: Binding, keysChanged: null | Set<string>): void;
destroy(binding: Binding): void;
}
export declare function $createCollabTextNode(map: YMap<unknown>, text: string, parent: CollabElementNode, type: string): CollabTextNode;
/**
* 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.
*
*/
import { type LexicalNode, NodeKey, type TextNode } from 'lexical';
import { XmlElement, XmlText } from 'yjs';
type SharedType = XmlElement | XmlText;
export declare class CollabV2Mapping {
private _nodeMap;
private _sharedTypeToNodeKeys;
private _nodeKeyToSharedType;
set(sharedType: SharedType, node: LexicalNode | TextNode[]): void;
get(sharedType: XmlElement): LexicalNode | undefined;
get(sharedType: XmlText): TextNode[] | undefined;
get(sharedType: SharedType): LexicalNode | Array<TextNode> | undefined;
getSharedType(node: LexicalNode): SharedType | undefined;
delete(sharedType: SharedType): void;
deleteNode(nodeKey: NodeKey): void;
has(sharedType: SharedType): boolean;
clear(): void;
}
export {};
/**
* 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.
*
*/
import type { BaseBinding } from './Bindings';
import type { LexicalCommand } from 'lexical';
import type { Doc, RelativePosition, Snapshot, UndoManager, XmlElement, XmlText } from 'yjs';
import './types';
export type UserState = {
anchorPos: null | RelativePosition;
color: string;
focusing: boolean;
focusPos: null | RelativePosition;
name: string;
awarenessData: object;
[key: string]: unknown;
};
export declare const CONNECTED_COMMAND: LexicalCommand<boolean>;
export declare const TOGGLE_CONNECT_COMMAND: LexicalCommand<boolean>;
export declare const DIFF_VERSIONS_COMMAND__EXPERIMENTAL: LexicalCommand<{
prevSnapshot?: Snapshot;
snapshot?: Snapshot;
}>;
export declare const CLEAR_DIFF_VERSIONS_COMMAND__EXPERIMENTAL: LexicalCommand<void>;
export { $getYChangeState, renderSnapshot__EXPERIMENTAL } from './RenderSnapshot';
export type ProviderAwareness = {
getLocalState: () => UserState | null;
getStates: () => Map<number, UserState>;
off: (type: 'update', cb: () => void) => void;
on: (type: 'update', cb: () => void) => void;
setLocalState: (arg0: UserState | null) => void;
setLocalStateField: (field: string, value: unknown) => void;
};
declare interface Provider {
awareness: ProviderAwareness;
connect(): void | Promise<void>;
disconnect(): void;
off(type: 'sync', cb: (isSynced: boolean) => void): void;
off(type: 'update', cb: (arg0: unknown) => void): void;
off(type: 'status', cb: (arg0: {
status: string;
}) => void): void;
off(type: 'reload', cb: (doc: Doc) => void): void;
on(type: 'sync', cb: (isSynced: boolean) => void): void;
on(type: 'status', cb: (arg0: {
status: string;
}) => void): void;
on(type: 'update', cb: (arg0: unknown) => void): void;
on(type: 'reload', cb: (doc: Doc) => void): void;
}
export type Operation = {
attributes: {
__type: string;
};
insert: string | Record<string, unknown>;
};
export type Delta = Array<Operation>;
export type YjsNode = Record<string, unknown>;
export type YjsEvent = Record<string, unknown>;
export type { Provider };
export type { BaseBinding, Binding, BindingV2, ClientID, ExcludedProperties, } from './Bindings';
export { createBinding, createBindingV2__EXPERIMENTAL } from './Bindings';
export declare function createUndoManager(binding: BaseBinding, root: XmlText | XmlElement): UndoManager;
export declare function initLocalState(provider: Provider, name: string, color: string, focusing: boolean, awarenessData: object): void;
export declare function setLocalStateFocus(provider: Provider, name: string, color: string, focusing: boolean, awarenessData: object): void;
export { getAnchorAndFocusCollabNodesForUserState, syncCursorPositions, type SyncCursorPositionsFn, } from './SyncCursors';
export { syncLexicalUpdateToYjs, syncLexicalUpdateToYjsV2__EXPERIMENTAL, syncYjsChangesToLexical, syncYjsChangesToLexicalV2__EXPERIMENTAL, syncYjsStateToLexicalV2__EXPERIMENTAL, } from './SyncEditorStates';

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

/**
* 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'
const LexicalYjs = process.env.NODE_ENV !== 'production' ? require('./LexicalYjs.dev.js') : require('./LexicalYjs.prod.js');
module.exports = LexicalYjs;

Sorry, the diff of this file is not supported yet

/**
* 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.
*
*/
import * as modDev from './LexicalYjs.dev.mjs';
import * as modProd from './LexicalYjs.prod.mjs';
const mod = process.env.NODE_ENV !== 'production' ? modDev : modProd;
export const $getYChangeState = mod.$getYChangeState;
export const CLEAR_DIFF_VERSIONS_COMMAND__EXPERIMENTAL = mod.CLEAR_DIFF_VERSIONS_COMMAND__EXPERIMENTAL;
export const CONNECTED_COMMAND = mod.CONNECTED_COMMAND;
export const DIFF_VERSIONS_COMMAND__EXPERIMENTAL = mod.DIFF_VERSIONS_COMMAND__EXPERIMENTAL;
export const TOGGLE_CONNECT_COMMAND = mod.TOGGLE_CONNECT_COMMAND;
export const createBinding = mod.createBinding;
export const createBindingV2__EXPERIMENTAL = mod.createBindingV2__EXPERIMENTAL;
export const createUndoManager = mod.createUndoManager;
export const getAnchorAndFocusCollabNodesForUserState = mod.getAnchorAndFocusCollabNodesForUserState;
export const initLocalState = mod.initLocalState;
export const renderSnapshot__EXPERIMENTAL = mod.renderSnapshot__EXPERIMENTAL;
export const setLocalStateFocus = mod.setLocalStateFocus;
export const syncCursorPositions = mod.syncCursorPositions;
export const syncLexicalUpdateToYjs = mod.syncLexicalUpdateToYjs;
export const syncLexicalUpdateToYjsV2__EXPERIMENTAL = mod.syncLexicalUpdateToYjsV2__EXPERIMENTAL;
export const syncYjsChangesToLexical = mod.syncYjsChangesToLexical;
export const syncYjsChangesToLexicalV2__EXPERIMENTAL = mod.syncYjsChangesToLexicalV2__EXPERIMENTAL;
export const syncYjsStateToLexicalV2__EXPERIMENTAL = mod.syncYjsStateToLexicalV2__EXPERIMENTAL;
/**
* 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.
*
*/
const mod = await (process.env.NODE_ENV !== 'production' ? import('./LexicalYjs.dev.mjs') : import('./LexicalYjs.prod.mjs'));
export const $getYChangeState = mod.$getYChangeState;
export const CLEAR_DIFF_VERSIONS_COMMAND__EXPERIMENTAL = mod.CLEAR_DIFF_VERSIONS_COMMAND__EXPERIMENTAL;
export const CONNECTED_COMMAND = mod.CONNECTED_COMMAND;
export const DIFF_VERSIONS_COMMAND__EXPERIMENTAL = mod.DIFF_VERSIONS_COMMAND__EXPERIMENTAL;
export const TOGGLE_CONNECT_COMMAND = mod.TOGGLE_CONNECT_COMMAND;
export const createBinding = mod.createBinding;
export const createBindingV2__EXPERIMENTAL = mod.createBindingV2__EXPERIMENTAL;
export const createUndoManager = mod.createUndoManager;
export const getAnchorAndFocusCollabNodesForUserState = mod.getAnchorAndFocusCollabNodesForUserState;
export const initLocalState = mod.initLocalState;
export const renderSnapshot__EXPERIMENTAL = mod.renderSnapshot__EXPERIMENTAL;
export const setLocalStateFocus = mod.setLocalStateFocus;
export const syncCursorPositions = mod.syncCursorPositions;
export const syncLexicalUpdateToYjs = mod.syncLexicalUpdateToYjs;
export const syncLexicalUpdateToYjsV2__EXPERIMENTAL = mod.syncLexicalUpdateToYjsV2__EXPERIMENTAL;
export const syncYjsChangesToLexical = mod.syncYjsChangesToLexical;
export const syncYjsChangesToLexicalV2__EXPERIMENTAL = mod.syncYjsChangesToLexicalV2__EXPERIMENTAL;
export const syncYjsStateToLexicalV2__EXPERIMENTAL = mod.syncYjsStateToLexicalV2__EXPERIMENTAL;
/**
* 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 e=require("lexical"),t=require("yjs"),n=require("@lexical/selection");function o(e,...t){const n=new URL("https://lexical.dev/docs/error"),o=new URLSearchParams;o.append("code",e);for(const e of t)o.append("v",e);throw n.search=o.toString(),Error(`Minified Lexical error #${e}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}function s(e,t,n){const o=e.length,s=t.length;let i=0,r=0;for(;i<o&&i<s&&e[i]===t[i]&&i<n;)i++;for(;r+i<o&&r+i<s&&e[o-r-1]===t[s-r-1];)r++;for(;r+i<o&&r+i<s&&e[i]===t[i];)i++;return{index:i,insert:t.slice(i,s-r),remove:o-i-r}}class i{_xmlElem;_key;_parent;_type;constructor(e,t,n){this._key="",this._xmlElem=e,this._parent=t,this._type=n}getPrevNode(t){if(null===t)return null;const n=t.get(this._key);return e.$isDecoratorNode(n)?n:null}getNode(){const t=e.$getNodeByKey(this._key);return e.$isDecoratorNode(t)?t:null}getSharedType(){return this._xmlElem}getType(){return this._type}getKey(){return this._key}getSize(){return 1}getOffset(){return this._parent.getChildOffset(this)}syncPropertiesFromLexical(e,t,n){const o=this.getPrevNode(n);M(e,this._xmlElem,o,t)}syncPropertiesFromYjs(e,t){const n=this.getNode();null===n&&o(83);C(e,this._xmlElem,n,t)}destroy(e){const t=e.collabNodeMap;t.get(this._key)===this&&t.delete(this._key)}}function r(e,t,n){const o=new i(e,t,n);return e._collabNode=o,o}class l{_map;_key;_parent;_type;constructor(e,t){this._key="",this._map=e,this._parent=t,this._type="linebreak"}getNode(){const t=e.$getNodeByKey(this._key);return e.$isLineBreakNode(t)?t:null}getKey(){return this._key}getSharedType(){return this._map}getType(){return this._type}getSize(){return 1}getOffset(){return this._parent.getChildOffset(this)}destroy(e){const t=e.collabNodeMap;t.get(this._key)===this&&t.delete(this._key)}}function c(e,t){const n=new l(e,t);return e._collabNode=n,n}class a{_map;_key;_parent;_text;_type;_normalized;constructor(e,t,n,o){this._key="",this._map=e,this._parent=n,this._text=t,this._type=o,this._normalized=!1}getPrevNode(t){if(null===t)return null;const n=t.get(this._key);return e.$isTextNode(n)?n:null}getNode(){const t=e.$getNodeByKey(this._key);return e.$isTextNode(t)?t: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(e,t,n){const o=this._parent._xmlText,s=this.getOffset()+1+e;0!==t&&o.delete(s,t),""!==n&&o.insert(s,n)}syncPropertiesAndTextFromLexical(t,n,o){const i=this.getPrevNode(o),r=n.__text;if(M(t,this._map,i,n),null!==i){const t=i.__text;if(t!==r){!function(t,n,o,i){const r=e.$getSelection();let l=i.length;if(e.$isRangeSelection(r)&&r.isCollapsed()){const e=r.anchor;e.key===n&&(l=e.offset)}const c=s(o,i,l);t.spliceText(c.index,c.remove,c.insert)}(this,n.__key,t,r),this._text=r}}}syncPropertiesAndTextFromYjs(e,t){const n=this.getNode();null===n&&o(84),C(e,this._map,n,t);const s=this._text;n.__text!==s&&n.setTextContent(s)}destroy(e){const t=e.collabNodeMap;t.get(this._key)===this&&t.delete(this._key)}}function d(e,t,n,o){const s=new a(e,t,n,o);return e._collabNode=s,s}class f{_key;_children;_xmlText;_type;_parent;constructor(e,t,n){this._key="",this._children=[],this._xmlText=e,this._type=n,this._parent=t}getPrevNode(t){if(null===t)return null;const n=t.get(this._key);return e.$isElementNode(n)?n:null}getNode(){const t=e.$getNodeByKey(this._key);return e.$isElementNode(t)?t:null}getSharedType(){return this._xmlText}getType(){return this._type}getKey(){return this._key}isEmpty(){return 0===this._children.length}getSize(){return 1}getOffset(){const e=this._parent;return null===e&&o(90),e.getChildOffset(this)}syncPropertiesFromYjs(e,t){const n=this.getNode();null===n&&o(91),C(e,this._xmlText,n,t)}applyChildrenYjsDelta(e,t){const n=this._children;let o=0,s=null;for(let r=0;r<t.length;r++){const c=t[r],d=c.insert,u=c.delete;if(null!=c.retain)o+=c.retain;else if("number"==typeof u){let e=u;for(;e>0;){const{node:t,nodeIndex:s,offset:r,length:c}=w(this,o,!1);if(t instanceof f||t instanceof l||t instanceof i)n.splice(s,1),e-=1;else{if(!(t instanceof a))break;{const o=Math.min(e,c),i=0!==s?n[s-1]:null,l=t.getSize();if(0===r&&c===l){n.splice(s,1);const e=A(t._text,r,o-1,"");e.length>0&&(i instanceof a?i._text+=e:this._xmlText.delete(r,e.length))}else t._text=A(t._text,r,o,"");e-=o}}}}else{if(null==d)throw new Error("Unexpected delta format");if("string"==typeof d){const{node:e,offset:t}=w(this,o,!0);e instanceof a?e._text=A(e._text,t,0,d):this._xmlText.delete(t,d.length),o+=d.length}else{const t=d,{node:i,nodeIndex:r,length:l}=w(this,o,!1),c=E(e,t,this);if(i instanceof a&&l>0&&l<i._text.length){const e=i._text,t=e.length-l;i._text=A(e,t,l,""),n.splice(r+1,0,c),s=A(e,0,t,"")}else n.splice(r,0,c);null!==s&&c instanceof a&&(c._text=s+c._text,s=null),o+=1}}}}syncChildrenFromYjs(t){const n=this.getNode();null===n&&o(92);const s=n.__key,r=e.$createChildrenArray(n,null),c=r.length,d=this._children,u=d.length,h=t.collabNodeMap,p=new Set;let g,y,_=0,m=null;u!==c&&(y=n.getWritable());for(let c=0;c<u;c++){const x=r[_],T=d[c],N=T.getNode(),S=T._key;if(null!==N&&x===S){const n=e.$isTextNode(N);if(p.add(x),n)if(T._key=x,T instanceof f){const e=T._xmlText;T.syncPropertiesFromYjs(t,null),T.applyChildrenYjsDelta(t,e.toDelta()),T.syncChildrenFromYjs(t)}else T instanceof a?T.syncPropertiesAndTextFromYjs(t,null):T instanceof i?T.syncPropertiesFromYjs(t,null):T instanceof l||o(93);m=N,_++}else{if(void 0===g){g=new Set;for(let e=0;e<u;e++){const t=d[e]._key;""!==t&&g.add(t)}}if(null!==N&&void 0!==x&&!g.has(x)){const t=e.$getNodeByKeyOrThrow(x);e.removeFromParent(t),c--,_++;continue}y=n.getWritable();const o=O(t,T,s),i=o.__key;if(h.set(i,T),null===m){const e=y.getFirstChild();if(y.__first=i,null!==e){const t=e.getWritable();t.__prev=i,o.__next=t.__key}}else{const e=m.getWritable(),t=m.getNextSibling();if(e.__next=i,o.__prev=m.__key,null!==t){const e=t.getWritable();e.__prev=i,o.__next=e.__key}}c===u-1&&(y.__last=i),y.__size++,m=o}}for(let n=0;n<c;n++){const o=r[n];if(!p.has(o)){const n=e.$getNodeByKeyOrThrow(o),s=t.collabNodeMap.get(o);void 0!==s&&s.destroy(t),e.removeFromParent(n)}}}syncPropertiesFromLexical(e,t,n){M(e,this._xmlText,this.getPrevNode(n),t)}_syncChildFromLexical(t,n,o,s,r,l){const c=this._children[n],d=e.$getNodeByKeyOrThrow(o);c instanceof f&&e.$isElementNode(d)?(c.syncPropertiesFromLexical(t,d,s),c.syncChildrenFromLexical(t,d,s,r,l)):c instanceof a&&e.$isTextNode(d)?c.syncPropertiesAndTextFromLexical(t,d,s):c instanceof i&&e.$isDecoratorNode(d)&&c.syncPropertiesFromLexical(t,d,s)}syncChildrenFromLexical(t,n,o,s,i){const r=this.getPrevNode(o),l=null===r?[]:e.$createChildrenArray(r,o),c=e.$createChildrenArray(n,null),a=l.length-1,d=c.length-1,f=t.collabNodeMap;let u,h,p=0,g=0;for(;p<=a&&g<=d;){const n=l[p],r=c[g];if(n===r)this._syncChildFromLexical(t,g,r,o,s,i),p++,g++;else{void 0===u&&(u=new Set(l)),void 0===h&&(h=new Set(c));const o=h.has(n),s=u.has(r);if(o){const n=S(t,e.$getNodeByKeyOrThrow(r),this);f.set(r,n),s?(this.splice(t,g,1,n),p++,g++):(this.splice(t,g,0,n),g++)}else this.splice(t,g,1),p++}}const y=p>a,_=g>d;if(y&&!_)for(;g<=d;++g){const n=c[g],o=S(t,e.$getNodeByKeyOrThrow(n),this);this.append(o),f.set(n,o)}else if(_&&!y)for(let e=this._children.length-1;e>=g;e--)this.splice(t,e,1)}append(e){const t=this._xmlText,n=this._children,o=n[n.length-1],s=void 0!==o?o.getOffset()+o.getSize():0;if(e instanceof f)t.insertEmbed(s,e._xmlText);else if(e instanceof a){const n=e._map;null===n.parent&&t.insertEmbed(s,n),t.insert(s+1,e._text)}else e instanceof l?t.insertEmbed(s,e._map):e instanceof i&&t.insertEmbed(s,e._xmlElem);this._children.push(e)}splice(e,t,n,s){const r=this._children,c=r[t];if(void 0===c)return void 0===s&&o(94),void this.append(s);const d=c.getOffset();-1===d&&o(95);const u=this._xmlText;if(0!==n&&u.delete(d,c.getSize()),s instanceof f)u.insertEmbed(d,s._xmlText);else if(s instanceof a){const e=s._map;null===e.parent&&u.insertEmbed(d,e),u.insert(d+1,s._text)}else s instanceof l?u.insertEmbed(d,s._map):s instanceof i&&u.insertEmbed(d,s._xmlElem);if(0!==n){const o=r.slice(t,t+n);for(let t=0;t<o.length;t++)o[t].destroy(e)}void 0!==s?r.splice(t,n,s):r.splice(t,n)}getChildOffset(e){let t=0;const n=this._children;for(let o=0;o<n.length;o++){const s=n[o];if(s===e)return t;t+=s.getSize()}return-1}destroy(e){const t=e.collabNodeMap,n=this._children;for(let t=0;t<n.length;t++)n[t].destroy(e);t.get(this._key)===this&&t.delete(this._key)}}function u(e,t,n){const o=new f(e,t,n);return e._collabNode=o,o}class h{_nodeMap=new Map;_sharedTypeToNodeKeys=new Map;_nodeKeyToSharedType=new Map;set(n,s){const i=s instanceof Array;this.delete(n);const r=i?s:[s];for(const e of r){const t=e.getKey();if(this._nodeKeyToSharedType.has(t)){const e=this._nodeKeyToSharedType.get(t),n=this._sharedTypeToNodeKeys.get(e).indexOf(t);-1!==n&&this._sharedTypeToNodeKeys.get(e).splice(n,1),this._nodeKeyToSharedType.delete(t),this._nodeMap.delete(t)}}if(n instanceof t.XmlText){if(i||o(331),0===s.length)return;this._sharedTypeToNodeKeys.set(n,s.map(e=>e.getKey()));for(const e of s)this._nodeMap.set(e.getKey(),e),this._nodeKeyToSharedType.set(e.getKey(),n)}else i&&o(332),e.$isTextNode(s)&&o(333),this._sharedTypeToNodeKeys.set(n,[s.getKey()]),this._nodeMap.set(s.getKey(),s),this._nodeKeyToSharedType.set(s.getKey(),n)}get(e){const n=this._sharedTypeToNodeKeys.get(e);if(void 0!==n){if(e instanceof t.XmlText){const e=Array.from(n.map(e=>this._nodeMap.get(e)));return e.length>0?e:void 0}return this._nodeMap.get(n[0])}}getSharedType(e){return this._nodeKeyToSharedType.get(e.getKey())}delete(e){const t=this._sharedTypeToNodeKeys.get(e);if(void 0!==t){for(const e of t)this._nodeMap.delete(e),this._nodeKeyToSharedType.delete(e);this._sharedTypeToNodeKeys.delete(e)}}deleteNode(e){const t=this._nodeKeyToSharedType.get(e);t&&this.delete(t),this._nodeMap.delete(e)}has(e){return this._sharedTypeToNodeKeys.has(e)}clear(){this._nodeMap.clear(),this._sharedTypeToNodeKeys.clear(),this._nodeKeyToSharedType.clear()}}function p(e,t,n,s,i){null==n&&o(81);const r={clientID:n.clientID,cursors:new Map,cursorsContainer:null,doc:n,docMap:s,editor:e,excludedProperties:i||new Map,id:t,nodeProperties:new Map};return function(e){const{editor:t,nodeProperties:n}=e;t.update(()=>{t._nodes.forEach(t=>{const o=new t.klass,s={};for(const[t,n]of Object.entries(o))T(t,o,e)||(s[t]=n);n.set(o.__type,Object.freeze(s))})})}(r),r}function g(e){return Object.prototype.hasOwnProperty.call(e,"collabNodeMap")}const y=new Set(["__key","__parent","__next","__prev","__state"]),_=new Set(["__first","__last","__size"]),m=new Set(["__cachedText"]),x=new Set(["__text"]);function T(t,n,o){if(y.has(t)||"function"==typeof n[t])return!0;if(e.$isTextNode(n)){if(x.has(t))return!0}else if(e.$isElementNode(n)&&(_.has(t)||e.$isRootNode(n)&&m.has(t)))return!0;const s=n.constructor,i=o.excludedProperties.get(s);return null!=i&&i.has(t)}function N(e,t){const n=e.__type,{nodeProperties:s}=t,i=s.get(n);return void 0===i&&o(330,n),i}function S(n,s,i){const l=s.__type;let a;if(e.$isElementNode(s)){a=u(new t.XmlText,i,l),a.syncPropertiesFromLexical(n,s,null),a.syncChildrenFromLexical(n,s,null,null,null)}else if(e.$isTextNode(s)){a=d(new t.Map,s.__text,i,l),a.syncPropertiesAndTextFromLexical(n,s,null)}else if(e.$isLineBreakNode(s)){const e=new t.Map;e.set("__type","linebreak"),a=c(e,i)}else if(e.$isDecoratorNode(s)){a=r(new t.XmlElement,i,l),a.syncPropertiesFromLexical(n,s,null)}else o(86);return a._key=s.__key,a}function b(e){const t=k(e,"__type");return"string"!=typeof t&&void 0!==t&&o(87),t}function E(e,n,s){const i=n._collabNode;if(void 0===i){const i=e.editor._nodes,l=b(n);"string"!=typeof l&&o(87);void 0===i.get(l)&&o(88,l);const a=n.parent,h=void 0===s&&null!==a?E(e,a):s||null;if(h instanceof f||o(89),n instanceof t.XmlText)return u(n,h,l);if(n instanceof t.Map)return"linebreak"===l?c(n,h):d(n,"",h,l);if(n instanceof t.XmlElement)return r(n,h,l)}return i}function O(e,t,n){const s=t.getType(),r=e.editor._nodes.get(s);void 0===r&&o(88,s);const l=new r.klass;if(l.__parent=n,t._key=l.__key,t instanceof f){const n=t._xmlText;t.syncPropertiesFromYjs(e,null),t.applyChildrenYjsDelta(e,n.toDelta()),t.syncChildrenFromYjs(e)}else t instanceof a?t.syncPropertiesAndTextFromYjs(e,null):t instanceof i&&t.syncPropertiesFromYjs(e,null);return e.collabNodeMap.set(l.__key,t),l}function C(n,o,s,i){const r=null===i?o instanceof t.Map?Array.from(o.keys()):o instanceof t.XmlText||o instanceof t.XmlElement?Object.keys(o.getAttributes()):Object.keys(o):Array.from(i);let l;for(let i=0;i<r.length;i++){const c=r[i];if(T(c,s,n)){"__state"===c&&g(n)&&(l||(l=s.getWritable()),v(o,l));continue}const a=s[c];let d=k(o,c);if(a!==d){if(d instanceof t.Doc){const o=n.docMap;a instanceof t.Doc&&o.delete(a.guid);const s=d.guid;if(o.set(s,d),e.isLexicalEditor(a))a._key=s,d=a;else{const t=e.createEditor();t._key=s,d=t}}void 0===l&&(l=s.getWritable()),l[c]=d}}}function k(e,n){return e instanceof t.Map?e.get(n):e instanceof t.XmlText||e instanceof t.XmlElement?e.getAttribute(n):e[n]}function $(e,n,o){e instanceof t.Map?e.set(n,o):e.setAttribute(n,o)}function v(n,o){const s=k(n,"__state");s instanceof t.Map&&e.$getWritableNodeState(o).updateFromJSON(s.toJSON())}function M(e,n,o,s){const i=Object.keys(N(s,e)),r=e.editor.constructor;!function(e,n,o,s){const i=s.__state,r=null===n.doc?void 0:k(n,"__state");if(!i)return;const[l,c]=i.getInternalState(),a=o&&o.__state,d=r instanceof t.Map?r:new t.Map;if(a===i)return;const[f,u]=a&&d.doc?a.getInternalState():[void 0,new Map];if(l)for(const[e,t]of Object.entries(l))f&&t!==f[e]&&d.set(e,t);for(const[e,t]of c)u.get(e)!==t&&d.set(e.key,e.unparse(t));r||$(n,"__state",d)}(0,n,o,s);for(let l=0;l<i.length;l++){const c=i[l],a=null===o?void 0:o[c];let d=s[c];if(a!==d){if(d instanceof r){const n=e.docMap;let o;if(a instanceof r){const e=a._key;o=n.get(e),n.delete(e)}const i=o||new t.Doc,l=i.guid;d._key=l,n.set(l,i),d=i,e.editor.update(()=>{s.markDirty()})}$(n,c,d)}}}function A(e,t,n,o){return e.slice(0,t)+o+e.slice(t+n)}function w(e,t,n){let o=0,s=0;const i=e._children,r=i.length;for(;s<r;s++){const e=i[s],l=o;o+=e.getSize();if((n?o>=t:o>t)&&e instanceof a){let n=t-l-1;n<0&&(n=0);return{length:o-t,node:e,nodeIndex:s,offset:n}}if(o>t)return{length:0,node:e,nodeIndex:s,offset:l};if(s===r-1)return{length:0,node:null,nodeIndex:s+1,offset:l+1}}return{length:0,node:null,nodeIndex:0,offset:0}}function P(t){const n=t.anchor,o=t.focus;let s=!1;try{const t=n.getNode(),i=o.getNode();(!t.isAttached()||!i.isAttached()||e.$isTextNode(t)&&n.offset>t.getTextContentSize()||e.$isTextNode(i)&&o.offset>i.getTextContentSize())&&(s=!0)}catch(e){s=!0}return s}function K(e,t){e.doc.transact(t,e)}function L(t,n){const o=n._nodeMap.get(t);if(!o)return void e.$getRoot().selectStart();const s=o.__prev;let i=null;s&&(i=e.$getNodeByKey(s)),null===i&&null!==o.__parent&&(i=e.$getNodeByKey(o.__parent)),null!==i?null!==i&&i.isAttached()?i.selectEnd():L(i.__key,n):e.$getRoot().selectStart()}const F=e=>"UNDEFINED"===e.nodeName,I=(n,s,i,r,l,c,a)=>{let d=s.mapping.get(n);if(d&&i&&0===i.size&&!r)return d;const f=F(n)?e.RootNode.getType():n.nodeName,u=s.editor._nodes.get(f);if(void 0===u)throw new Error(`$createOrUpdateNodeFromYElement: Node ${f} is not registered`);if(d||(d=new u.klass,i=null,r=!0),r&&d instanceof e.ElementNode){const e=[],i=n=>{if(n instanceof t.XmlElement){const t=I(n,s,new Set,!1,l,c,a);null!==t&&e.push(t)}else if(n instanceof t.XmlText){const t=j(n,s,l,c,a);null!==t&&t.forEach(t=>{null!==t&&e.push(t)})}else o(329)};void 0===l||void 0===c?n.toArray().forEach(i):t.typeListToArraySnapshot(n,new t.Snapshot(c.ds,l.sv)).filter(e=>!e._item.deleted||D(e._item,l)||D(e._item,c)).forEach(i),R(d,e)}const h=n.getAttributes(l);F(n)||void 0===l||(D(n._item,l)?D(n._item,c)||(h[Z("ychange")]=a?a("added",n._item.id):{type:"added"}):h[Z("ychange")]=a?a("removed",n._item.id):{type:"removed"});const p={...N(d,s)},g={};for(const e in h)e.startsWith(Q)?g[ee(e)]=h[e]:p[e]=h[e];if(C(s,p,d,i),i){if(i.size>0){const t=e.$getWritableNodeState(d);for(const e of i)if(e.startsWith(Q)){const n=ee(e);t.updateFromUnknown(n,g[n])}}}else e.$getWritableNodeState(d).updateFromJSON(g);const y=d.getLatest();return s.mapping.set(n,y),y},R=(e,t)=>{const n=e.getChildren(),o=new Set(n.map(e=>e.getKey())),s=new Set(t.map(e=>e.getKey())),i=n.length-1,r=t.length-1;let l=0,c=0;for(;l<=i&&c<=r;){const i=n[l].getKey(),r=t[c].getKey();if(i===r){l++,c++;continue}const a=s.has(i),d=o.has(r);if(!a){if(0===c&&1===e.getChildrenSize())return void e.splice(c,1,t.slice(c));e.splice(c,1,[]),l++;continue}const f=t[c];d?(e.splice(c,1,[f]),l++,c++):(e.splice(c,0,[f]),c++)}const a=l>i,d=c>r;a&&!d?e.append(...t.slice(c)):d&&!a&&e.splice(t.length,e.getChildrenSize()-t.length,[])},D=(e,n)=>void 0===n?!e.deleted:n.sv.has(e.id.client)&&n.sv.get(e.id.client)>e.id.clock&&!t.isDeleted(n.ds,e.id),j=(t,n,o,s,i)=>{const r=q(t,o,s,i);let l=n.mapping.get(t)??[];const c=r.map(t=>t.attributes.t??e.TextNode.getType());if(!(l.length===c.length&&l.every((e,t)=>e.getType()===c[t]))){const t=n.editor._nodes;l=c.map(n=>{const o=t.get(n);if(void 0===o)throw new Error(`$createTextNodesFromYText: Node ${n} is not registered`);const s=new o.klass;if(!e.$isTextNode(s))throw new Error(`$createTextNodesFromYText: Node ${n} is not a TextNode`);return s})}for(let t=0;t<r.length;t++){const o=l[t],s=r[t],{attributes:i,insert:c}=s;o.__text!==c&&o.setTextContent(c);const a={...N(o,n),...i.p},d=Object.fromEntries(Object.entries(i).filter(([e])=>e.startsWith(Q)).map(([e,t])=>[ee(e),t]));C(n,a,o,null),e.$getWritableNodeState(o).updateFromJSON(d)}const a=l.map(e=>e.getLatest());return n.mapping.set(t,a),a},X=(n,o)=>n instanceof Array?((e,n)=>{const o=new t.XmlText;return H(o,e,n),o})(n,o):((n,o)=>{const s=new t.XmlElement(n.getType()),i={...J(n,o),...te(n)};for(const e in i){const t=i[e];null!==t&&s.setAttribute(e,t)}return n instanceof e.ElementNode?(s.insert(0,B(n).map(e=>X(e,o))),o.mapping.set(s,n),s):s})(n,o),z=e=>"object"==typeof e&&null!=e,Y=(e,t)=>{const n=Object.keys(e).filter(t=>null!==e[t]);if(null==t)return 0===n.length;let o=n.length===Object.keys(t).filter(e=>null!==t[e]).length;for(let s=0;s<n.length&&o;s++){const i=n[s],r=e[i],l=t[i];o="ychange"===i||r===l||z(r)&&z(l)&&Y(r,l)}return o},B=t=>{if(!(t instanceof e.ElementNode))return[];const n=t.getChildren(),o=[];for(let t=0;t<n.length;t++){const s=n[t];if(e.$isTextNode(s)){const s=[];for(let o=n[t];t<n.length&&e.$isTextNode(o);o=n[++t])s.push(o);t--,o.push(s)}else o.push(s)}return o},U=(t,n,o)=>{const s=q(t);return s.length===n.length&&s.every((t,s)=>{const i=n[s],r=t.attributes.t??e.TextNode.getType(),l=t.attributes.p??{},c=Object.fromEntries(Object.entries(t.attributes).filter(([e])=>e.startsWith(Q)));return t.insert===i.getTextContent()&&r===i.getType()&&Y(l,J(i,o))&&Y(c,te(i))})},W=(e,n,o)=>{if(e instanceof t.XmlElement&&!(n instanceof Array)&&oe(e,n)){const t=B(n);return e._length===t.length&&Y(e.getAttributes(),{...J(n,o),...te(n)})&&e.toArray().every((e,n)=>W(e,t[n],o))}return e instanceof t.XmlText&&n instanceof Array&&U(e,n,o)},G=(e,t)=>e===t||e instanceof Array&&t instanceof Array&&e.length===t.length&&e.every((e,n)=>t[n]===e),V=(e,n,o)=>{const s=e.toArray(),i=B(n),r=i.length,l=s.length,c=Math.min(l,r);let a=0,d=0,f=!1;for(;a<c;a++){const e=s[a],n=i[a];if(e instanceof t.XmlHook)break;if(G(o.mapping.get(e),n))f=!0;else if(!W(e,n,o))break}for(;a+d<c;d++){const e=s[l-d-1],n=i[r-d-1];if(e instanceof t.XmlHook)break;if(G(o.mapping.get(e),n))f=!0;else if(!W(e,n,o))break}return{equalityFactor:a+d,foundMappedChild:f}},H=(n,o,i)=>{i.mapping.set(n,o);const{nAttrs:r,str:l}=(e=>{let n="",o=e._start;const s={};for(;null!==o;)o.deleted||(o.countable&&o.content instanceof t.ContentString?n+=o.content.str:o.content instanceof t.ContentFormat&&(s[o.content.key]=null)),o=o.right;return{nAttrs:s,str:n}})(n),c=o.map((t,n)=>{const o=t.getType();let s=J(t,i);return 0===Object.keys(s).length&&(s=null),{attributes:Object.assign({},r,{...o!==e.TextNode.getType()&&{t:o},p:s,...te(t),...n>0&&{i:n}}),insert:t.getTextContent(),nodeKey:t.getKey()}}),a=c.map(e=>e.insert).join(""),d=e.$getSelection();let f;if(e.$isRangeSelection(d)&&d.isCollapsed()){f=0;for(const e of c){if(e.nodeKey===d.anchor.key){f+=d.anchor.offset;break}f+=e.insert.length}}else f=a.length;const{insert:u,remove:h,index:p}=s(l,a,f);n.delete(p,h),n.insert(p,u),n.applyDelta(c.map(e=>({attributes:e.attributes,retain:e.insert.length})))},q=(e,t,n,o)=>e.toDelta(t,n,o).map(e=>{const t=e.attributes??{};return"ychange"in t&&(t[Z("ychange")]=t.ychange,delete t.ychange),{...e,attributes:t}}),J=(e,t)=>{const n=N(e,t),o={};return Object.entries(n).forEach(([t,n])=>{const s=e[t];s!==n&&(o[t]=s)}),o},Q="s_",Z=e=>`s_${e}`,ee=e=>{if(!e.startsWith(Q))throw new Error(`Invalid state key: ${e}`);return e.slice(Q.length)},te=e=>{const t=e.__state;if(!t)return{};const[n={},o]=t.getInternalState(),s={};for(const[e,t]of Object.entries(n))s[Z(e)]=t;for(const[e,t]of o)s[Z(e.key)]=e.unparse(t);return s},ne=(n,o,s,i,r)=>{if(o instanceof t.XmlElement&&o.nodeName!==s.getType()&&(!F(o)||s.getType()!==e.RootNode.getType()))throw new Error("node name mismatch!");if(i.mapping.set(o,s),o instanceof t.XmlElement){const e=o.getAttributes(),t={...J(s,i),...te(s)};for(const n in t)if(null!=t[n]){e[n]===t[n]||z(e[n])&&z(t[n])&&Y(e[n],t[n])||"ychange"===n||o.setAttribute(n,t[n])}else o.removeAttribute(n);for(const n in e)void 0===t[n]&&o.removeAttribute(n)}const l=B(s),c=l.length,a=o.toArray(),d=a.length,f=Math.min(c,d);let u=0,h=0;for(;u<f;u++){const o=a[u],s=l[u];if(o instanceof t.XmlHook)break;if(G(i.mapping.get(o),s))s instanceof e.ElementNode&&r.has(s.getKey())&&ne(n,o,s,i,r);else{if(!W(o,s,i))break;i.mapping.set(o,s)}}for(;h+u<f;h++){const o=a[d-h-1],s=l[c-h-1];if(o instanceof t.XmlHook)break;if(G(i.mapping.get(o),s))s instanceof e.ElementNode&&r.has(s.getKey())&&ne(n,o,s,i,r);else{if(!W(o,s,i))break;i.mapping.set(o,s)}}for(;d-u-h>0&&c-u-h>0;){const e=a[u],s=l[u],f=a[d-h-1],p=l[c-h-1];if(e instanceof t.XmlText&&s instanceof Array)U(e,s,i)||H(e,s,i),u+=1;else{let l=e instanceof t.XmlElement&&oe(e,s),c=f instanceof t.XmlElement&&oe(f,p);if(l&&c){const t=V(e,s,i),n=V(f,p,i);t.foundMappedChild&&!n.foundMappedChild?c=!1:!t.foundMappedChild&&n.foundMappedChild||t.equalityFactor<n.equalityFactor?l=!1:c=!1}l?(ne(n,e,s,i,r),u+=1):c?(ne(n,f,p,i,r),h+=1):(i.mapping.delete(o.get(u)),o.delete(u,1),o.insert(u,[X(s,i)]),u+=1)}}const p=d-u-h;if(1===d&&0===c&&a[0]instanceof t.XmlText?(i.mapping.delete(a[0]),a[0].delete(0,a[0].length)):p>0&&(o.slice(u,u+p).forEach(e=>i.mapping.delete(e)),o.delete(u,p)),u+h<c){const e=[];for(let t=u;t<c-h;t++)e.push(X(l[t],i));o.insert(u,e)}},oe=(e,t)=>!(t instanceof Array)&&e.nodeName===t.getType(),se=e.createState("ychange",{isEqual:(e,t)=>e===t,parse:e=>e??null});function ie(n,s){const i=s.collabNodeMap.get(n.key);if(void 0===i)return null;let r=n.offset,l=i.getSharedType();if(i instanceof a){l=i._parent._xmlText;const e=i.getOffset();if(-1===e)return null;r=e+1+r}else if(i instanceof f&&"element"===n.type){const t=n.getNode();e.$isElementNode(t)||o(184);let s=0,i=0,l=t.getFirstChild();for(;null!==l&&i++<r;)e.$isTextNode(l)?s+=l.getTextContentSize()+1:s++,l=l.getNextSibling();r=s}return t.createRelativePositionFromTypeIndex(l,r)}function re(n,s){const{mapping:i}=s,{offset:r}=n,l=n.getNode(),c=i.getSharedType(l);if(void 0===c)return null;if("text"===n.type){e.$isTextNode(l)||o(326);let n=l.getPreviousSibling(),s=r;for(;e.$isTextNode(n);)s+=n.getTextContentSize(),n=n.getPreviousSibling();return t.createRelativePositionFromTypeIndex(c,s)}if("element"===n.type){e.$isElementNode(l)||o(184);let n=0,s=l.getFirstChild();for(;null!==s&&n<r;){if(e.$isTextNode(s)){let t=s.getNextSibling();for(;e.$isTextNode(t);)t=t.getNextSibling()}n++,s=s.getNextSibling()}return t.createRelativePositionFromTypeIndex(c,n)}return null}function le(e,n){return t.createAbsolutePositionFromRelativePosition(e,n.doc)}function ce(e,n){if(null==e){if(null!=n)return!0}else if(null==n||!t.compareRelativePositions(e,n))return!0;return!1}function ae(e,t){return{color:t,name:e,selection:null}}function de(e,t){const n=e.cursorsContainer;if(null!==n){const e=t.selections,o=e.length;for(let t=0;t<o;t++)n.removeChild(e[t])}}function fe(e,t){const n=t.selection;null!==n&&de(e,n)}function ue(t,n,o,s,i,r={}){const l=t.color,c=document.createElement("span");r.cursor?(c.className=r.cursor,e.setDOMStyleObject(c.style,{"--lexical-cursor-color":l,bottom:"0",position:"absolute",right:"-1px",top:"0"})):e.setDOMStyleObject(c.style,{"background-color":l,bottom:"0",position:"absolute",right:"-1px",top:"0",width:"1px","z-index":"10"});const a=document.createElement("span");return a.textContent=t.name,r.cursorName?a.className=r.cursorName:e.setDOMStyleObject(a.style,{"background-color":l,color:"#fff","font-family":"Arial","font-size":"12px","font-weight":"bold",left:"-2px","line-height":"12px",padding:"2px",position:"absolute",top:"-16px","white-space":"nowrap"}),c.appendChild(a),{anchor:{key:n,offset:o},caret:c,color:l,focus:{key:s,offset:i},name:a,selections:[]}}function he(t,o,s,i,r={}){const l=t.editor,c=l.getRootElement(),a=t.cursorsContainer;if(null===a||null===c)return;const d=a.offsetParent;if(null===d)return;const f=d.getBoundingClientRect(),u=o.selection;if(null===s)return null===u?void 0:(o.selection=null,void de(t,u));o.selection=s;const h=s.caret,p=s.color,g=s.selections,y=s.anchor,_=s.focus,m=y.key,x=_.key,T=i.get(m),N=i.get(x);if(null==T||null==N)return;let S;if(T===N&&e.$isLineBreakNode(T)){S=[l.getElementByKey(m).getBoundingClientRect()]}else{const e=n.createDOMRange(l,T,y.offset,N,_.offset);if(null===e)return;S=n.createRectsFromDOMRange(l,e)}const b=g.length,E=S.length;for(let t=0;t<E;t++){const n=S[t];let o=g[t];if(void 0===o){o=document.createElement("span"),g[t]=o;const e=document.createElement("span");r.selectionBg&&(e.className=r.selectionBg),o.appendChild(e),a.appendChild(o)}const s=n.top-f.top,i=n.left-f.left,l={height:`${n.height}px`,left:`${i}px`,"pointer-events":"none",position:"absolute",top:`${s}px`,width:`${n.width}px`};r.selection?(o.className=r.selection,e.setDOMStyleObject(o.style,{...l,"--lexical-cursor-color":p}),e.setDOMStyleObject(o.firstChild.style,{height:"100%",left:"0",position:"absolute",top:"0",width:"100%"})):(e.setDOMStyleObject(o.style,l),e.setDOMStyleObject(o.firstChild.style,{...l,"background-color":p,left:"0",opacity:"0.3",top:"0","z-index":"5"})),t===E-1&&h.parentNode!==o&&o.appendChild(h)}for(let e=b-1;e>=E;e--){const t=g[e];a.removeChild(t),g.pop()}}function pe(t,n){const{anchorPos:o,focusPos:s}=n,i=o?le(o,t):null,r=s?le(s,t):null;if(null===i||null===r)return{anchorKey:null,anchorOffset:0,focusKey:null,focusOffset:0};if(g(t)){const[e,t]=_e(i.type,i.index),[n,o]=_e(r.type,r.index);return{anchorKey:null!==e?e.getKey():null,anchorOffset:t,focusKey:null!==n?n.getKey():null,focusOffset:o}}let[l,c]=me(t.mapping,i),[a,d]=me(t.mapping,r);if(a&&l&&(a!==l||d!==c)){const t=a.isBefore(l),n=t?a:l,o=t?d:c;e.$isTextNode(n)&&e.$isTextNode(n.getNextSibling())&&o===n.getTextContentSize()&&(t?(a=n.getNextSibling(),d=0):(l=n.getNextSibling(),c=0))}return{anchorKey:null!==l?l.getKey():null,anchorOffset:c,focusKey:null!==a?a.getKey():null,focusOffset:d}}function ge(t,n){const o=n.awareness.getLocalState();if(null===o)return;const{anchorKey:s,anchorOffset:i,focusKey:r,focusOffset:l}=pe(t,o);if(null!==s&&null!==r){const t=e.$getSelection();if(!e.$isRangeSelection(t))return;ye(t.anchor,s,i),ye(t.focus,r,l)}}function ye(t,n,o){if(t.key!==n||t.offset!==o){let s=e.$getNodeByKey(n);if(null!==s&&!e.$isElementNode(s)&&!e.$isTextNode(s)){const e=s.getParentOrThrow();n=e.getKey(),o=s.getIndexWithinParent(),s=e}t.set(n,o,e.$isElementNode(s)?"element":"text")}}function _e(e,t){const n=e._collabNode;if(void 0===n)return[null,0];if(n instanceof f){const{node:e,offset:o}=w(n,t,!0);return null===e?[n,0]:[e,o]}return[null,0]}function me(n,o){const s=o.type,i=o.index;if(s instanceof t.XmlElement){const t=n.get(s);if(void 0===t)return[null,0];if(!e.$isElementNode(t))return[t,i];let o=i,r=0;const l=t.getChildren();for(;o>0&&r<l.length;){const t=l[r];if(o-=1,r+=1,e.$isTextNode(t))for(;r<l.length&&e.$isTextNode(l[r]);)r+=1}return[t,r]}{const e=n.get(s);if(void 0===e)return[null,0];let t=0,o=i;for(;o>e[t].getTextContentSize()&&t+1<e.length;)o-=e[t].getTextContentSize(),t++;const r=e[t];return[r,Math.min(o,r.getTextContentSize())]}}function xe(e,t){return t.awareness.getStates()}function Te(e,t,n){const{getAwarenessStates:o=xe}=n??{},s=Array.from(o(e,t)),i=e.clientID,r=e.cursors,l=e.editor,c=l._config.theme.collaboration,a=l._editorState._nodeMap,d=new Set;for(let t=0;t<s.length;t++){const n=s[t],[o,f]=n;if(0!==o&&o!==i){d.add(o);const{name:t,color:n,focusing:s}=f;let i=null,u=r.get(o);if(void 0===u&&(u=ae(t,n),r.set(o,u)),s){const{anchorKey:t,anchorOffset:n,focusKey:o,focusOffset:s}=l.read(()=>pe(e,f));if(null!==t&&null!==o)if(i=u.selection,null===i)i=ue(u,t,n,o,s,c);else{const e=i.anchor,r=i.focus;e.key=t,e.offset=n,r.key=o,r.offset=s}}he(e,u,i,a,c)}}const f=Array.from(r.keys());for(let t=0;t<f.length;t++){const n=f[t];if(!d.has(n)){const t=r.get(n);void 0!==t&&(fe(e,t),r.delete(n))}}}function Ne(t,n,o,s){const i=n.awareness,r=i.getLocalState();if(null===r)return;const{anchorPos:l,focusPos:c,name:a,color:d,focusing:f,awarenessData:u}=r;let h=null,p=null;(null!==s&&(null===l||s.is(o))||null!==o)&&(e.$isRangeSelection(s)&&(g(t)?(h=ie(s.anchor,t),p=ie(s.focus,t)):(h=re(s.anchor,t),p=re(s.focus,t))),(ce(l,h)||ce(c,p))&&i.setLocalState({...r,anchorPos:h,awarenessData:u,color:d,focusPos:p,focusing:f,name:a}))}function Se(n,s){if(s instanceof t.YMapEvent&&function(n,o){const{target:s}=o;if(!s._item||"__state"!==s._item.parentSub||void 0!==b(s)||!(s.parent instanceof t.XmlText||s.parent instanceof t.XmlElement||s.parent instanceof t.Map))return!1;const i=E(n,s.parent).getNode();if(i){const t=e.$getWritableNodeState(i.getWritable());for(const e of o.keysChanged)t.updateFromUnknown(e,s.get(e))}return!0}(n,s))return;const{target:r}=s,l=E(n,r);if(l instanceof f&&s instanceof t.YTextEvent){const{keysChanged:e,childListChanged:t,delta:o}=s;e.size>0&&l.syncPropertiesFromYjs(n,e),t&&(l.applyChildrenYjsDelta(n,o),l.syncChildrenFromYjs(n))}else if(l instanceof a&&s instanceof t.YMapEvent){const{keysChanged:e}=s;e.size>0&&l.syncPropertiesAndTextFromYjs(n,e)}else if(l instanceof i&&s instanceof t.YXmlEvent){const{attributesChanged:e}=s;e.size>0&&l.syncPropertiesFromYjs(n,e)}else o(82)}function be(t,n,o){const s=e.$getSelection();if(e.$isRangeSelection(s))if(P(s)){const i=t._selection;if(e.$isRangeSelection(i)&&(ge(n,o),P(s))){L(s.anchor.key,t)}Ne(n,o,i,e.$getSelection())}else ge(n,o)}function Ee(){0===e.$getRoot().getChildrenSize()&&e.$getRoot().append(e.$createParagraphNode())}function Oe(e,n){const{target:s}=n;if(s instanceof t.XmlElement&&n instanceof t.YXmlEvent)I(s,e,n.attributesChanged,n.childListChanged);else if(s instanceof t.XmlText&&n instanceof t.YTextEvent){const n=s.parent;n instanceof t.XmlElement?I(n,e,new Set,!0):o(327)}else o(328)}const Ce=e.createCommand("CONNECTED_COMMAND"),ke=e.createCommand("TOGGLE_CONNECT_COMMAND"),$e=e.createCommand("DIFF_VERSIONS_COMMAND"),ve=e.createCommand("CLEAR_DIFF_VERSIONS_COMMAND");exports.$getYChangeState=function(t){return e.$getState(t,se)},exports.CLEAR_DIFF_VERSIONS_COMMAND__EXPERIMENTAL=ve,exports.CONNECTED_COMMAND=Ce,exports.DIFF_VERSIONS_COMMAND__EXPERIMENTAL=$e,exports.TOGGLE_CONNECT_COMMAND=ke,exports.createBinding=function(e,n,s,i,r,l){null==i&&o(81);const c=u(i.get("root",t.XmlText),null,"root");return c._key="root",{...p(e,s,i,r,l),collabNodeMap:new Map,root:c}},exports.createBindingV2__EXPERIMENTAL=function(e,n,s,i,r={}){null==s&&o(81);const{excludedProperties:l,rootName:c="root-v2"}=r;return{...p(e,n,s,i,l),mapping:new h,root:s.get(c,t.XmlElement)}},exports.createUndoManager=function(e,n){return new t.UndoManager(n,{trackedOrigins:new Set([e,null])})},exports.getAnchorAndFocusCollabNodesForUserState=function(e,t){const{anchorPos:n,focusPos:o}=t;let s=null,i=0,r=null,l=0;if(null!==n&&null!==o){const t=le(n,e),c=le(o,e);null!==t&&null!==c&&([s,i]=_e(t.type,t.index),[r,l]=_e(c.type,c.index))}return{anchorCollabNode:s,anchorOffset:i,focusCollabNode:r,focusOffset:l}},exports.initLocalState=function(e,t,n,o,s){e.awareness.setLocalState({anchorPos:null,awarenessData:s,color:n,focusPos:null,focusing:o,name:t})},exports.renderSnapshot__EXPERIMENTAL=(n,s=t.snapshot(n.doc),i=t.emptySnapshot)=>{const{doc:r}=n;r.gc&&o(325),r.transact(o=>{const l=new t.PermanentUserData(r);l&&l.dss.forEach(e=>{t.iterateDeletedStructs(o,e,e=>{})});const c=(e,t)=>({id:t,type:e,user:("added"===e?l.getUserByClientId(t.client):l.getUserByDeletedId(t))??null});n.mapping.clear(),n.editor.update(()=>{e.$getRoot().clear(),I(n.root,n,null,!0,s,i,c)})},n)},exports.setLocalStateFocus=function(e,t,n,o,s){const{awareness:i}=e;let r=i.getLocalState();null===r&&(r={anchorPos:null,awarenessData:s,color:n,focusPos:null,focusing:o,name:t}),r.focusing=o,i.setLocalState(r)},exports.syncCursorPositions=Te,exports.syncLexicalUpdateToYjs=function(t,n,o,s,i,r,l,c){K(t,()=>{s.read(()=>{if(c.has(e.COLLABORATION_TAG)||c.has(e.HISTORIC_TAG))return void(l.size>0&&function(t,n){const o=Array.from(n),s=t.collabNodeMap,i=[],r=[];for(let t=0;t<o.length;t++){const n=o[t],l=e.$getNodeByKey(n),c=s.get(n);if(c instanceof a)if(e.$isTextNode(l))i.push([c,l.__text]);else{const e=c.getOffset();if(-1===e)continue;const t=c._parent;c._normalized=!0,t._xmlText.delete(e,1),r.push(c)}}for(let e=0;e<r.length;e++){const t=r[e],n=t.getKey();s.delete(n);const o=t._parent._children,i=o.indexOf(t);o.splice(i,1)}for(let e=0;e<i.length;e++){const[t,n]=i[e];t._text=n}}(t,l));if(i.has("root")){const n=o._nodeMap,s=e.$getRoot(),l=t.root;l.syncPropertiesFromLexical(t,s,n),l.syncChildrenFromLexical(t,s,n,i,r)}const s=e.$getSelection(),d=o._selection;Ne(t,n,d,s)})})},exports.syncLexicalUpdateToYjsV2__EXPERIMENTAL=function(t,n,o,s,i,r,l){(l.has(e.COLLABORATION_TAG)||l.has(e.HISTORIC_TAG))&&0===r.size||(r.forEach(e=>{t.mapping.deleteNode(e)}),K(t,()=>{s.read(()=>{i.has("root")&&ne(t.doc,t.root,e.$getRoot(),t,new Set(i.keys()));const s=e.$getSelection(),r=o._selection;Ne(t,n,r,s)})}))},exports.syncYjsChangesToLexical=function(t,n,o,s,i=Te){const r=t.editor,l=r._editorState;o.forEach(e=>e.delta),r.update(()=>{for(let e=0;e<o.length;e++){const n=o[e];Se(t,n)}be(l,t,n),s||e.$addUpdateTag(e.SKIP_SCROLL_INTO_VIEW_TAG)},{onUpdate:()=>{i(t,n),r.update(()=>Ee())},skipTransforms:!0,tag:s?e.HISTORIC_TAG:e.COLLABORATION_TAG})},exports.syncYjsChangesToLexicalV2__EXPERIMENTAL=function(n,o,s,i,r){const l=n.editor,c=l._editorState;t.iterateDeletedStructs(i,i.deleteSet,e=>{if(e.constructor===t.Item){const t=e.content.type;t&&n.mapping.delete(t)}}),s.forEach(e=>e.delta),l.update(()=>{for(let e=0;e<s.length;e++){const t=s[e];Oe(n,t)}be(c,n,o),r||e.$addUpdateTag(e.SKIP_SCROLL_INTO_VIEW_TAG)},{discrete:!0,onUpdate:()=>{Te(n,o),l.update(()=>Ee())},skipTransforms:!0,tag:r?e.HISTORIC_TAG:e.COLLABORATION_TAG})},exports.syncYjsStateToLexicalV2__EXPERIMENTAL=function(t,n){t.mapping.clear();const o=t.editor;o.update(()=>{e.$getRoot().clear(),I(t.root,t,null,!0),e.$addUpdateTag(e.COLLABORATION_TAG)},{discrete:!0,onUpdate:()=>{Te(t,n),o.update(()=>Ee())},skipTransforms:!0,tag:e.COLLABORATION_TAG})};
/**
* 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.
*
*/
import{$isDecoratorNode as e,$getNodeByKey as t,$isLineBreakNode as n,$isTextNode as o,$getSelection as s,$isRangeSelection as i,$isElementNode as r,$createChildrenArray as l,$getNodeByKeyOrThrow as c,removeFromParent as a,isLexicalEditor as f,createEditor as d,$isRootNode as u,$getWritableNodeState as h,$getRoot as p,RootNode as g,ElementNode as _,TextNode as y,$getState as m,createState as x,setDOMStyleObject as b,COLLABORATION_TAG as T,HISTORIC_TAG as k,$addUpdateTag as N,SKIP_SCROLL_INTO_VIEW_TAG as S,$createParagraphNode as v,createCommand as w}from"lexical";import{XmlText as C,XmlElement as O,Map as K,Doc as M,typeListToArraySnapshot as P,Snapshot as E,isDeleted as F,XmlHook as A,ContentString as j,ContentFormat as z,emptySnapshot as L,PermanentUserData as D,iterateDeletedStructs as Y,snapshot as I,createAbsolutePositionFromRelativePosition as W,createRelativePositionFromTypeIndex as $,compareRelativePositions as U,Item as B,YMapEvent as R,YTextEvent as q,YXmlEvent as J,UndoManager as G}from"yjs";import{createDOMRange as V,createRectsFromDOMRange as H}from"@lexical/selection";function Q(e,...t){const n=new URL("https://lexical.dev/docs/error"),o=new URLSearchParams;o.append("code",e);for(const e of t)o.append("v",e);throw n.search=o.toString(),Error(`Minified Lexical error #${e}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}function X(e,t,n){const o=e.length,s=t.length;let i=0,r=0;for(;i<o&&i<s&&e[i]===t[i]&&i<n;)i++;for(;r+i<o&&r+i<s&&e[o-r-1]===t[s-r-1];)r++;for(;r+i<o&&r+i<s&&e[i]===t[i];)i++;return{index:i,insert:t.slice(i,s-r),remove:o-i-r}}class Z{_xmlElem;_key;_parent;_type;constructor(e,t,n){this._key="",this._xmlElem=e,this._parent=t,this._type=n}getPrevNode(t){if(null===t)return null;const n=t.get(this._key);return e(n)?n:null}getNode(){const n=t(this._key);return e(n)?n:null}getSharedType(){return this._xmlElem}getType(){return this._type}getKey(){return this._key}getSize(){return 1}getOffset(){return this._parent.getChildOffset(this)}syncPropertiesFromLexical(e,t,n){const o=this.getPrevNode(n);we(e,this._xmlElem,o,t)}syncPropertiesFromYjs(e,t){const n=this.getNode();null===n&&Q(83);ke(e,this._xmlElem,n,t)}destroy(e){const t=e.collabNodeMap;t.get(this._key)===this&&t.delete(this._key)}}function ee(e,t,n){const o=new Z(e,t,n);return e._collabNode=o,o}class te{_map;_key;_parent;_type;constructor(e,t){this._key="",this._map=e,this._parent=t,this._type="linebreak"}getNode(){const e=t(this._key);return n(e)?e:null}getKey(){return this._key}getSharedType(){return this._map}getType(){return this._type}getSize(){return 1}getOffset(){return this._parent.getChildOffset(this)}destroy(e){const t=e.collabNodeMap;t.get(this._key)===this&&t.delete(this._key)}}function ne(e,t){const n=new te(e,t);return e._collabNode=n,n}class oe{_map;_key;_parent;_text;_type;_normalized;constructor(e,t,n,o){this._key="",this._map=e,this._parent=n,this._text=t,this._type=o,this._normalized=!1}getPrevNode(e){if(null===e)return null;const t=e.get(this._key);return o(t)?t:null}getNode(){const e=t(this._key);return o(e)?e: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(e,t,n){const o=this._parent._xmlText,s=this.getOffset()+1+e;0!==t&&o.delete(s,t),""!==n&&o.insert(s,n)}syncPropertiesAndTextFromLexical(e,t,n){const o=this.getPrevNode(n),r=t.__text;if(we(e,this._map,o,t),null!==o){const e=o.__text;if(e!==r){!function(e,t,n,o){const r=s();let l=o.length;if(i(r)&&r.isCollapsed()){const e=r.anchor;e.key===t&&(l=e.offset)}const c=X(n,o,l);e.spliceText(c.index,c.remove,c.insert)}(this,t.__key,e,r),this._text=r}}}syncPropertiesAndTextFromYjs(e,t){const n=this.getNode();null===n&&Q(84),ke(e,this._map,n,t);const o=this._text;n.__text!==o&&n.setTextContent(o)}destroy(e){const t=e.collabNodeMap;t.get(this._key)===this&&t.delete(this._key)}}function se(e,t,n,o){const s=new oe(e,t,n,o);return e._collabNode=s,s}class ie{_key;_children;_xmlText;_type;_parent;constructor(e,t,n){this._key="",this._children=[],this._xmlText=e,this._type=n,this._parent=t}getPrevNode(e){if(null===e)return null;const t=e.get(this._key);return r(t)?t:null}getNode(){const e=t(this._key);return r(e)?e:null}getSharedType(){return this._xmlText}getType(){return this._type}getKey(){return this._key}isEmpty(){return 0===this._children.length}getSize(){return 1}getOffset(){const e=this._parent;return null===e&&Q(90),e.getChildOffset(this)}syncPropertiesFromYjs(e,t){const n=this.getNode();null===n&&Q(91),ke(e,this._xmlText,n,t)}applyChildrenYjsDelta(e,t){const n=this._children;let o=0,s=null;for(let i=0;i<t.length;i++){const r=t[i],l=r.insert,c=r.delete;if(null!=r.retain)o+=r.retain;else if("number"==typeof c){let e=c;for(;e>0;){const{node:t,nodeIndex:s,offset:i,length:r}=Oe(this,o,!1);if(t instanceof ie||t instanceof te||t instanceof Z)n.splice(s,1),e-=1;else{if(!(t instanceof oe))break;{const o=Math.min(e,r),l=0!==s?n[s-1]:null,c=t.getSize();if(0===i&&r===c){n.splice(s,1);const e=Ce(t._text,i,o-1,"");e.length>0&&(l instanceof oe?l._text+=e:this._xmlText.delete(i,e.length))}else t._text=Ce(t._text,i,o,"");e-=o}}}}else{if(null==l)throw new Error("Unexpected delta format");if("string"==typeof l){const{node:e,offset:t}=Oe(this,o,!0);e instanceof oe?e._text=Ce(e._text,t,0,l):this._xmlText.delete(t,l.length),o+=l.length}else{const t=l,{node:i,nodeIndex:r,length:c}=Oe(this,o,!1),a=be(e,t,this);if(i instanceof oe&&c>0&&c<i._text.length){const e=i._text,t=e.length-c;i._text=Ce(e,t,c,""),n.splice(r+1,0,a),s=Ce(e,0,t,"")}else n.splice(r,0,a);null!==s&&a instanceof oe&&(a._text=s+a._text,s=null),o+=1}}}}syncChildrenFromYjs(e){const t=this.getNode();null===t&&Q(92);const n=t.__key,s=l(t,null),i=s.length,r=this._children,f=r.length,d=e.collabNodeMap,u=new Set;let h,p,g=0,_=null;f!==i&&(p=t.getWritable());for(let i=0;i<f;i++){const l=s[g],y=r[i],m=y.getNode(),x=y._key;if(null!==m&&l===x){const t=o(m);if(u.add(l),t)if(y._key=l,y instanceof ie){const t=y._xmlText;y.syncPropertiesFromYjs(e,null),y.applyChildrenYjsDelta(e,t.toDelta()),y.syncChildrenFromYjs(e)}else y instanceof oe?y.syncPropertiesAndTextFromYjs(e,null):y instanceof Z?y.syncPropertiesFromYjs(e,null):y instanceof te||Q(93);_=m,g++}else{if(void 0===h){h=new Set;for(let e=0;e<f;e++){const t=r[e]._key;""!==t&&h.add(t)}}if(null!==m&&void 0!==l&&!h.has(l)){const e=c(l);a(e),i--,g++;continue}p=t.getWritable();const o=Te(e,y,n),s=o.__key;if(d.set(s,y),null===_){const e=p.getFirstChild();if(p.__first=s,null!==e){const t=e.getWritable();t.__prev=s,o.__next=t.__key}}else{const e=_.getWritable(),t=_.getNextSibling();if(e.__next=s,o.__prev=_.__key,null!==t){const e=t.getWritable();e.__prev=s,o.__next=e.__key}}i===f-1&&(p.__last=s),p.__size++,_=o}}for(let t=0;t<i;t++){const n=s[t];if(!u.has(n)){const t=c(n),o=e.collabNodeMap.get(n);void 0!==o&&o.destroy(e),a(t)}}}syncPropertiesFromLexical(e,t,n){we(e,this._xmlText,this.getPrevNode(n),t)}_syncChildFromLexical(t,n,s,i,l,a){const f=this._children[n],d=c(s);f instanceof ie&&r(d)?(f.syncPropertiesFromLexical(t,d,i),f.syncChildrenFromLexical(t,d,i,l,a)):f instanceof oe&&o(d)?f.syncPropertiesAndTextFromLexical(t,d,i):f instanceof Z&&e(d)&&f.syncPropertiesFromLexical(t,d,i)}syncChildrenFromLexical(e,t,n,o,s){const i=this.getPrevNode(n),r=null===i?[]:l(i,n),a=l(t,null),f=r.length-1,d=a.length-1,u=e.collabNodeMap;let h,p,g=0,_=0;for(;g<=f&&_<=d;){const t=r[g],i=a[_];if(t===i)this._syncChildFromLexical(e,_,i,n,o,s),g++,_++;else{void 0===h&&(h=new Set(r)),void 0===p&&(p=new Set(a));const n=p.has(t),o=h.has(i);if(n){const t=me(e,c(i),this);u.set(i,t),o?(this.splice(e,_,1,t),g++,_++):(this.splice(e,_,0,t),_++)}else this.splice(e,_,1),g++}}const y=g>f,m=_>d;if(y&&!m)for(;_<=d;++_){const t=a[_],n=me(e,c(t),this);this.append(n),u.set(t,n)}else if(m&&!y)for(let t=this._children.length-1;t>=_;t--)this.splice(e,t,1)}append(e){const t=this._xmlText,n=this._children,o=n[n.length-1],s=void 0!==o?o.getOffset()+o.getSize():0;if(e instanceof ie)t.insertEmbed(s,e._xmlText);else if(e instanceof oe){const n=e._map;null===n.parent&&t.insertEmbed(s,n),t.insert(s+1,e._text)}else e instanceof te?t.insertEmbed(s,e._map):e instanceof Z&&t.insertEmbed(s,e._xmlElem);this._children.push(e)}splice(e,t,n,o){const s=this._children,i=s[t];if(void 0===i)return void 0===o&&Q(94),void this.append(o);const r=i.getOffset();-1===r&&Q(95);const l=this._xmlText;if(0!==n&&l.delete(r,i.getSize()),o instanceof ie)l.insertEmbed(r,o._xmlText);else if(o instanceof oe){const e=o._map;null===e.parent&&l.insertEmbed(r,e),l.insert(r+1,o._text)}else o instanceof te?l.insertEmbed(r,o._map):o instanceof Z&&l.insertEmbed(r,o._xmlElem);if(0!==n){const o=s.slice(t,t+n);for(let t=0;t<o.length;t++)o[t].destroy(e)}void 0!==o?s.splice(t,n,o):s.splice(t,n)}getChildOffset(e){let t=0;const n=this._children;for(let o=0;o<n.length;o++){const s=n[o];if(s===e)return t;t+=s.getSize()}return-1}destroy(e){const t=e.collabNodeMap,n=this._children;for(let t=0;t<n.length;t++)n[t].destroy(e);t.get(this._key)===this&&t.delete(this._key)}}function re(e,t,n){const o=new ie(e,t,n);return e._collabNode=o,o}class le{_nodeMap=new Map;_sharedTypeToNodeKeys=new Map;_nodeKeyToSharedType=new Map;set(e,t){const n=t instanceof Array;this.delete(e);const s=n?t:[t];for(const e of s){const t=e.getKey();if(this._nodeKeyToSharedType.has(t)){const e=this._nodeKeyToSharedType.get(t),n=this._sharedTypeToNodeKeys.get(e).indexOf(t);-1!==n&&this._sharedTypeToNodeKeys.get(e).splice(n,1),this._nodeKeyToSharedType.delete(t),this._nodeMap.delete(t)}}if(e instanceof C){if(n||Q(331),0===t.length)return;this._sharedTypeToNodeKeys.set(e,t.map(e=>e.getKey()));for(const n of t)this._nodeMap.set(n.getKey(),n),this._nodeKeyToSharedType.set(n.getKey(),e)}else n&&Q(332),o(t)&&Q(333),this._sharedTypeToNodeKeys.set(e,[t.getKey()]),this._nodeMap.set(t.getKey(),t),this._nodeKeyToSharedType.set(t.getKey(),e)}get(e){const t=this._sharedTypeToNodeKeys.get(e);if(void 0!==t){if(e instanceof C){const e=Array.from(t.map(e=>this._nodeMap.get(e)));return e.length>0?e:void 0}return this._nodeMap.get(t[0])}}getSharedType(e){return this._nodeKeyToSharedType.get(e.getKey())}delete(e){const t=this._sharedTypeToNodeKeys.get(e);if(void 0!==t){for(const e of t)this._nodeMap.delete(e),this._nodeKeyToSharedType.delete(e);this._sharedTypeToNodeKeys.delete(e)}}deleteNode(e){const t=this._nodeKeyToSharedType.get(e);t&&this.delete(t),this._nodeMap.delete(e)}has(e){return this._sharedTypeToNodeKeys.has(e)}clear(){this._nodeMap.clear(),this._sharedTypeToNodeKeys.clear(),this._nodeKeyToSharedType.clear()}}function ce(e,t,n,o,s){null==n&&Q(81);const i={clientID:n.clientID,cursors:new Map,cursorsContainer:null,doc:n,docMap:o,editor:e,excludedProperties:s||new Map,id:t,nodeProperties:new Map};return function(e){const{editor:t,nodeProperties:n}=e;t.update(()=>{t._nodes.forEach(t=>{const o=new t.klass,s={};for(const[t,n]of Object.entries(o))_e(t,o,e)||(s[t]=n);n.set(o.__type,Object.freeze(s))})})}(i),i}function ae(e,t,n,o,s,i){null==o&&Q(81);const r=re(o.get("root",C),null,"root");return r._key="root",{...ce(e,n,o,s,i),collabNodeMap:new Map,root:r}}function fe(e,t,n,o,s={}){null==n&&Q(81);const{excludedProperties:i,rootName:r="root-v2"}=s;return{...ce(e,t,n,o,i),mapping:new le,root:n.get(r,O)}}function de(e){return Object.prototype.hasOwnProperty.call(e,"collabNodeMap")}const ue=new Set(["__key","__parent","__next","__prev","__state"]),he=new Set(["__first","__last","__size"]),pe=new Set(["__cachedText"]),ge=new Set(["__text"]);function _e(e,t,n){if(ue.has(e)||"function"==typeof t[e])return!0;if(o(t)){if(ge.has(e))return!0}else if(r(t)&&(he.has(e)||u(t)&&pe.has(e)))return!0;const s=t.constructor,i=n.excludedProperties.get(s);return null!=i&&i.has(e)}function ye(e,t){const n=e.__type,{nodeProperties:o}=t,s=o.get(n);return void 0===s&&Q(330,n),s}function me(t,s,i){const l=s.__type;let c;if(r(s)){c=re(new C,i,l),c.syncPropertiesFromLexical(t,s,null),c.syncChildrenFromLexical(t,s,null,null,null)}else if(o(s)){c=se(new K,s.__text,i,l),c.syncPropertiesAndTextFromLexical(t,s,null)}else if(n(s)){const e=new K;e.set("__type","linebreak"),c=ne(e,i)}else if(e(s)){c=ee(new O,i,l),c.syncPropertiesFromLexical(t,s,null)}else Q(86);return c._key=s.__key,c}function xe(e){const t=Ne(e,"__type");return"string"!=typeof t&&void 0!==t&&Q(87),t}function be(e,t,n){const o=t._collabNode;if(void 0===o){const o=e.editor._nodes,s=xe(t);"string"!=typeof s&&Q(87);void 0===o.get(s)&&Q(88,s);const i=t.parent,r=void 0===n&&null!==i?be(e,i):n||null;if(r instanceof ie||Q(89),t instanceof C)return re(t,r,s);if(t instanceof K)return"linebreak"===s?ne(t,r):se(t,"",r,s);if(t instanceof O)return ee(t,r,s)}return o}function Te(e,t,n){const o=t.getType(),s=e.editor._nodes.get(o);void 0===s&&Q(88,o);const i=new s.klass;if(i.__parent=n,t._key=i.__key,t instanceof ie){const n=t._xmlText;t.syncPropertiesFromYjs(e,null),t.applyChildrenYjsDelta(e,n.toDelta()),t.syncChildrenFromYjs(e)}else t instanceof oe?t.syncPropertiesAndTextFromYjs(e,null):t instanceof Z&&t.syncPropertiesFromYjs(e,null);return e.collabNodeMap.set(i.__key,t),i}function ke(e,t,n,o){const s=null===o?t instanceof K?Array.from(t.keys()):t instanceof C||t instanceof O?Object.keys(t.getAttributes()):Object.keys(t):Array.from(o);let i;for(let o=0;o<s.length;o++){const r=s[o];if(_e(r,n,e)){"__state"===r&&de(e)&&(i||(i=n.getWritable()),ve(t,i));continue}const l=n[r];let c=Ne(t,r);if(l!==c){if(c instanceof M){const t=e.docMap;l instanceof M&&t.delete(l.guid);const n=c.guid;if(t.set(n,c),f(l))l._key=n,c=l;else{const e=d();e._key=n,c=e}}void 0===i&&(i=n.getWritable()),i[r]=c}}}function Ne(e,t){return e instanceof K?e.get(t):e instanceof C||e instanceof O?e.getAttribute(t):e[t]}function Se(e,t,n){e instanceof K?e.set(t,n):e.setAttribute(t,n)}function ve(e,t){const n=Ne(e,"__state");n instanceof K&&h(t).updateFromJSON(n.toJSON())}function we(e,t,n,o){const s=Object.keys(ye(o,e)),i=e.editor.constructor;!function(e,t,n,o){const s=o.__state,i=null===t.doc?void 0:Ne(t,"__state");if(!s)return;const[r,l]=s.getInternalState(),c=n&&n.__state,a=i instanceof K?i:new K;if(c===s)return;const[f,d]=c&&a.doc?c.getInternalState():[void 0,new Map];if(r)for(const[e,t]of Object.entries(r))f&&t!==f[e]&&a.set(e,t);for(const[e,t]of l)d.get(e)!==t&&a.set(e.key,e.unparse(t));i||Se(t,"__state",a)}(0,t,n,o);for(let r=0;r<s.length;r++){const l=s[r],c=null===n?void 0:n[l];let a=o[l];if(c!==a){if(a instanceof i){const t=e.docMap;let n;if(c instanceof i){const e=c._key;n=t.get(e),t.delete(e)}const s=n||new M,r=s.guid;a._key=r,t.set(r,s),a=s,e.editor.update(()=>{o.markDirty()})}Se(t,l,a)}}}function Ce(e,t,n,o){return e.slice(0,t)+o+e.slice(t+n)}function Oe(e,t,n){let o=0,s=0;const i=e._children,r=i.length;for(;s<r;s++){const e=i[s],l=o;o+=e.getSize();if((n?o>=t:o>t)&&e instanceof oe){let n=t-l-1;n<0&&(n=0);return{length:o-t,node:e,nodeIndex:s,offset:n}}if(o>t)return{length:0,node:e,nodeIndex:s,offset:l};if(s===r-1)return{length:0,node:null,nodeIndex:s+1,offset:l+1}}return{length:0,node:null,nodeIndex:0,offset:0}}function Ke(e){const t=e.anchor,n=e.focus;let s=!1;try{const e=t.getNode(),i=n.getNode();(!e.isAttached()||!i.isAttached()||o(e)&&t.offset>e.getTextContentSize()||o(i)&&n.offset>i.getTextContentSize())&&(s=!0)}catch(e){s=!0}return s}function Me(e,t){e.doc.transact(t,e)}function Pe(e,n){const o=n._nodeMap.get(e);if(!o)return void p().selectStart();const s=o.__prev;let i=null;s&&(i=t(s)),null===i&&null!==o.__parent&&(i=t(o.__parent)),null!==i?null!==i&&i.isAttached()?i.selectEnd():Pe(i.__key,n):p().selectStart()}const Ee=e=>"UNDEFINED"===e.nodeName,Fe=(e,t,n,o,s,i,r)=>{let l=t.mapping.get(e);if(l&&n&&0===n.size&&!o)return l;const c=Ee(e)?g.getType():e.nodeName,a=t.editor._nodes.get(c);if(void 0===a)throw new Error(`$createOrUpdateNodeFromYElement: Node ${c} is not registered`);if(l||(l=new a.klass,n=null,o=!0),o&&l instanceof _){const n=[],o=e=>{if(e instanceof O){const o=Fe(e,t,new Set,!1,s,i,r);null!==o&&n.push(o)}else if(e instanceof C){const o=ze(e,t,s,i,r);null!==o&&o.forEach(e=>{null!==e&&n.push(e)})}else Q(329)};void 0===s||void 0===i?e.toArray().forEach(o):P(e,new E(i.ds,s.sv)).filter(e=>!e._item.deleted||je(e._item,s)||je(e._item,i)).forEach(o),Ae(l,n)}const f=e.getAttributes(s);Ee(e)||void 0===s||(je(e._item,s)?je(e._item,i)||(f[Ve("ychange")]=r?r("added",e._item.id):{type:"added"}):f[Ve("ychange")]=r?r("removed",e._item.id):{type:"removed"});const d={...ye(l,t)},u={};for(const e in f)e.startsWith(Ge)?u[He(e)]=f[e]:d[e]=f[e];if(ke(t,d,l,n),n){if(n.size>0){const e=h(l);for(const t of n)if(t.startsWith(Ge)){const n=He(t);e.updateFromUnknown(n,u[n])}}}else h(l).updateFromJSON(u);const p=l.getLatest();return t.mapping.set(e,p),p},Ae=(e,t)=>{const n=e.getChildren(),o=new Set(n.map(e=>e.getKey())),s=new Set(t.map(e=>e.getKey())),i=n.length-1,r=t.length-1;let l=0,c=0;for(;l<=i&&c<=r;){const i=n[l].getKey(),r=t[c].getKey();if(i===r){l++,c++;continue}const a=s.has(i),f=o.has(r);if(!a){if(0===c&&1===e.getChildrenSize())return void e.splice(c,1,t.slice(c));e.splice(c,1,[]),l++;continue}const d=t[c];f?(e.splice(c,1,[d]),l++,c++):(e.splice(c,0,[d]),c++)}const a=l>i,f=c>r;a&&!f?e.append(...t.slice(c)):f&&!a&&e.splice(t.length,e.getChildrenSize()-t.length,[])},je=(e,t)=>void 0===t?!e.deleted:t.sv.has(e.id.client)&&t.sv.get(e.id.client)>e.id.clock&&!F(t.ds,e.id),ze=(e,t,n,s,i)=>{const r=qe(e,n,s,i);let l=t.mapping.get(e)??[];const c=r.map(e=>e.attributes.t??y.getType());if(!(l.length===c.length&&l.every((e,t)=>e.getType()===c[t]))){const e=t.editor._nodes;l=c.map(t=>{const n=e.get(t);if(void 0===n)throw new Error(`$createTextNodesFromYText: Node ${t} is not registered`);const s=new n.klass;if(!o(s))throw new Error(`$createTextNodesFromYText: Node ${t} is not a TextNode`);return s})}for(let e=0;e<r.length;e++){const n=l[e],o=r[e],{attributes:s,insert:i}=o;n.__text!==i&&n.setTextContent(i);const c={...ye(n,t),...s.p},a=Object.fromEntries(Object.entries(s).filter(([e])=>e.startsWith(Ge)).map(([e,t])=>[He(e),t]));ke(t,c,n,null),h(n).updateFromJSON(a)}const a=l.map(e=>e.getLatest());return t.mapping.set(e,a),a},Le=(e,t)=>e instanceof Array?((e,t)=>{const n=new C;return Re(n,e,t),n})(e,t):((e,t)=>{const n=new O(e.getType()),o={...Je(e,t),...Qe(e)};for(const e in o){const t=o[e];null!==t&&n.setAttribute(e,t)}return e instanceof _?(n.insert(0,Ie(e).map(e=>Le(e,t))),t.mapping.set(n,e),n):n})(e,t),De=e=>"object"==typeof e&&null!=e,Ye=(e,t)=>{const n=Object.keys(e).filter(t=>null!==e[t]);if(null==t)return 0===n.length;let o=n.length===Object.keys(t).filter(e=>null!==t[e]).length;for(let s=0;s<n.length&&o;s++){const i=n[s],r=e[i],l=t[i];o="ychange"===i||r===l||De(r)&&De(l)&&Ye(r,l)}return o},Ie=e=>{if(!(e instanceof _))return[];const t=e.getChildren(),n=[];for(let e=0;e<t.length;e++){const s=t[e];if(o(s)){const s=[];for(let n=t[e];e<t.length&&o(n);n=t[++e])s.push(n);e--,n.push(s)}else n.push(s)}return n},We=(e,t,n)=>{const o=qe(e);return o.length===t.length&&o.every((e,o)=>{const s=t[o],i=e.attributes.t??y.getType(),r=e.attributes.p??{},l=Object.fromEntries(Object.entries(e.attributes).filter(([e])=>e.startsWith(Ge)));return e.insert===s.getTextContent()&&i===s.getType()&&Ye(r,Je(s,n))&&Ye(l,Qe(s))})},$e=(e,t,n)=>{if(e instanceof O&&!(t instanceof Array)&&Ze(e,t)){const o=Ie(t);return e._length===o.length&&Ye(e.getAttributes(),{...Je(t,n),...Qe(t)})&&e.toArray().every((e,t)=>$e(e,o[t],n))}return e instanceof C&&t instanceof Array&&We(e,t,n)},Ue=(e,t)=>e===t||e instanceof Array&&t instanceof Array&&e.length===t.length&&e.every((e,n)=>t[n]===e),Be=(e,t,n)=>{const o=e.toArray(),s=Ie(t),i=s.length,r=o.length,l=Math.min(r,i);let c=0,a=0,f=!1;for(;c<l;c++){const e=o[c],t=s[c];if(e instanceof A)break;if(Ue(n.mapping.get(e),t))f=!0;else if(!$e(e,t,n))break}for(;c+a<l;a++){const e=o[r-a-1],t=s[i-a-1];if(e instanceof A)break;if(Ue(n.mapping.get(e),t))f=!0;else if(!$e(e,t,n))break}return{equalityFactor:c+a,foundMappedChild:f}},Re=(e,t,n)=>{n.mapping.set(e,t);const{nAttrs:o,str:r}=(e=>{let t="",n=e._start;const o={};for(;null!==n;)n.deleted||(n.countable&&n.content instanceof j?t+=n.content.str:n.content instanceof z&&(o[n.content.key]=null)),n=n.right;return{nAttrs:o,str:t}})(e),l=t.map((e,t)=>{const s=e.getType();let i=Je(e,n);return 0===Object.keys(i).length&&(i=null),{attributes:Object.assign({},o,{...s!==y.getType()&&{t:s},p:i,...Qe(e),...t>0&&{i:t}}),insert:e.getTextContent(),nodeKey:e.getKey()}}),c=l.map(e=>e.insert).join(""),a=s();let f;if(i(a)&&a.isCollapsed()){f=0;for(const e of l){if(e.nodeKey===a.anchor.key){f+=a.anchor.offset;break}f+=e.insert.length}}else f=c.length;const{insert:d,remove:u,index:h}=X(r,c,f);e.delete(h,u),e.insert(h,d),e.applyDelta(l.map(e=>({attributes:e.attributes,retain:e.insert.length})))},qe=(e,t,n,o)=>e.toDelta(t,n,o).map(e=>{const t=e.attributes??{};return"ychange"in t&&(t[Ve("ychange")]=t.ychange,delete t.ychange),{...e,attributes:t}}),Je=(e,t)=>{const n=ye(e,t),o={};return Object.entries(n).forEach(([t,n])=>{const s=e[t];s!==n&&(o[t]=s)}),o},Ge="s_",Ve=e=>`s_${e}`,He=e=>{if(!e.startsWith(Ge))throw new Error(`Invalid state key: ${e}`);return e.slice(Ge.length)},Qe=e=>{const t=e.__state;if(!t)return{};const[n={},o]=t.getInternalState(),s={};for(const[e,t]of Object.entries(n))s[Ve(e)]=t;for(const[e,t]of o)s[Ve(e.key)]=e.unparse(t);return s},Xe=(e,t,n,o,s)=>{if(t instanceof O&&t.nodeName!==n.getType()&&(!Ee(t)||n.getType()!==g.getType()))throw new Error("node name mismatch!");if(o.mapping.set(t,n),t instanceof O){const e=t.getAttributes(),s={...Je(n,o),...Qe(n)};for(const n in s)if(null!=s[n]){e[n]===s[n]||De(e[n])&&De(s[n])&&Ye(e[n],s[n])||"ychange"===n||t.setAttribute(n,s[n])}else t.removeAttribute(n);for(const n in e)void 0===s[n]&&t.removeAttribute(n)}const i=Ie(n),r=i.length,l=t.toArray(),c=l.length,a=Math.min(r,c);let f=0,d=0;for(;f<a;f++){const t=l[f],n=i[f];if(t instanceof A)break;if(Ue(o.mapping.get(t),n))n instanceof _&&s.has(n.getKey())&&Xe(e,t,n,o,s);else{if(!$e(t,n,o))break;o.mapping.set(t,n)}}for(;d+f<a;d++){const t=l[c-d-1],n=i[r-d-1];if(t instanceof A)break;if(Ue(o.mapping.get(t),n))n instanceof _&&s.has(n.getKey())&&Xe(e,t,n,o,s);else{if(!$e(t,n,o))break;o.mapping.set(t,n)}}for(;c-f-d>0&&r-f-d>0;){const n=l[f],a=i[f],u=l[c-d-1],h=i[r-d-1];if(n instanceof C&&a instanceof Array)We(n,a,o)||Re(n,a,o),f+=1;else{let i=n instanceof O&&Ze(n,a),r=u instanceof O&&Ze(u,h);if(i&&r){const e=Be(n,a,o),t=Be(u,h,o);e.foundMappedChild&&!t.foundMappedChild?r=!1:!e.foundMappedChild&&t.foundMappedChild||e.equalityFactor<t.equalityFactor?i=!1:r=!1}i?(Xe(e,n,a,o,s),f+=1):r?(Xe(e,u,h,o,s),d+=1):(o.mapping.delete(t.get(f)),t.delete(f,1),t.insert(f,[Le(a,o)]),f+=1)}}const u=c-f-d;if(1===c&&0===r&&l[0]instanceof C?(o.mapping.delete(l[0]),l[0].delete(0,l[0].length)):u>0&&(t.slice(f,f+u).forEach(e=>o.mapping.delete(e)),t.delete(f,u)),f+d<r){const e=[];for(let t=f;t<r-d;t++)e.push(Le(i[t],o));t.insert(f,e)}},Ze=(e,t)=>!(t instanceof Array)&&e.nodeName===t.getType(),et=x("ychange",{isEqual:(e,t)=>e===t,parse:e=>e??null});function tt(e){return m(e,et)}const nt=(e,t=I(e.doc),n=L)=>{const{doc:o}=e;o.gc&&Q(325),o.transact(s=>{const i=new D(o);i&&i.dss.forEach(e=>{Y(s,e,e=>{})});const r=(e,t)=>({id:t,type:e,user:("added"===e?i.getUserByClientId(t.client):i.getUserByDeletedId(t))??null});e.mapping.clear(),e.editor.update(()=>{p().clear(),Fe(e.root,e,null,!0,t,n,r)})},e)};function ot(e,t){const n=t.collabNodeMap.get(e.key);if(void 0===n)return null;let s=e.offset,i=n.getSharedType();if(n instanceof oe){i=n._parent._xmlText;const e=n.getOffset();if(-1===e)return null;s=e+1+s}else if(n instanceof ie&&"element"===e.type){const t=e.getNode();r(t)||Q(184);let n=0,i=0,l=t.getFirstChild();for(;null!==l&&i++<s;)o(l)?n+=l.getTextContentSize()+1:n++,l=l.getNextSibling();s=n}return $(i,s)}function st(e,t){const{mapping:n}=t,{offset:s}=e,i=e.getNode(),l=n.getSharedType(i);if(void 0===l)return null;if("text"===e.type){o(i)||Q(326);let e=i.getPreviousSibling(),t=s;for(;o(e);)t+=e.getTextContentSize(),e=e.getPreviousSibling();return $(l,t)}if("element"===e.type){r(i)||Q(184);let e=0,t=i.getFirstChild();for(;null!==t&&e<s;){if(o(t)){let e=t.getNextSibling();for(;o(e);)e=e.getNextSibling()}e++,t=t.getNextSibling()}return $(l,e)}return null}function it(e,t){return W(e,t.doc)}function rt(e,t){if(null==e){if(null!=t)return!0}else if(null==t||!U(e,t))return!0;return!1}function lt(e,t){return{color:t,name:e,selection:null}}function ct(e,t){const n=e.cursorsContainer;if(null!==n){const e=t.selections,o=e.length;for(let t=0;t<o;t++)n.removeChild(e[t])}}function at(e,t){const n=t.selection;null!==n&&ct(e,n)}function ft(e,t,n,o,s,i={}){const r=e.color,l=document.createElement("span");i.cursor?(l.className=i.cursor,b(l.style,{"--lexical-cursor-color":r,bottom:"0",position:"absolute",right:"-1px",top:"0"})):b(l.style,{"background-color":r,bottom:"0",position:"absolute",right:"-1px",top:"0",width:"1px","z-index":"10"});const c=document.createElement("span");return c.textContent=e.name,i.cursorName?c.className=i.cursorName:b(c.style,{"background-color":r,color:"#fff","font-family":"Arial","font-size":"12px","font-weight":"bold",left:"-2px","line-height":"12px",padding:"2px",position:"absolute",top:"-16px","white-space":"nowrap"}),l.appendChild(c),{anchor:{key:t,offset:n},caret:l,color:r,focus:{key:o,offset:s},name:c,selections:[]}}function dt(e,t,o,s,i={}){const r=e.editor,l=r.getRootElement(),c=e.cursorsContainer;if(null===c||null===l)return;const a=c.offsetParent;if(null===a)return;const f=a.getBoundingClientRect(),d=t.selection;if(null===o)return null===d?void 0:(t.selection=null,void ct(e,d));t.selection=o;const u=o.caret,h=o.color,p=o.selections,g=o.anchor,_=o.focus,y=g.key,m=_.key,x=s.get(y),T=s.get(m);if(null==x||null==T)return;let k;if(x===T&&n(x)){k=[r.getElementByKey(y).getBoundingClientRect()]}else{const e=V(r,x,g.offset,T,_.offset);if(null===e)return;k=H(r,e)}const N=p.length,S=k.length;for(let e=0;e<S;e++){const t=k[e];let n=p[e];if(void 0===n){n=document.createElement("span"),p[e]=n;const t=document.createElement("span");i.selectionBg&&(t.className=i.selectionBg),n.appendChild(t),c.appendChild(n)}const o=t.top-f.top,s=t.left-f.left,r={height:`${t.height}px`,left:`${s}px`,"pointer-events":"none",position:"absolute",top:`${o}px`,width:`${t.width}px`};i.selection?(n.className=i.selection,b(n.style,{...r,"--lexical-cursor-color":h}),b(n.firstChild.style,{height:"100%",left:"0",position:"absolute",top:"0",width:"100%"})):(b(n.style,r),b(n.firstChild.style,{...r,"background-color":h,left:"0",opacity:"0.3",top:"0","z-index":"5"})),e===S-1&&u.parentNode!==n&&n.appendChild(u)}for(let e=N-1;e>=S;e--){const t=p[e];c.removeChild(t),p.pop()}}function ut(e,t){const{anchorPos:n,focusPos:o}=t;let s=null,i=0,r=null,l=0;if(null!==n&&null!==o){const t=it(n,e),c=it(o,e);null!==t&&null!==c&&([s,i]=_t(t.type,t.index),[r,l]=_t(c.type,c.index))}return{anchorCollabNode:s,anchorOffset:i,focusCollabNode:r,focusOffset:l}}function ht(e,t){const{anchorPos:n,focusPos:s}=t,i=n?it(n,e):null,r=s?it(s,e):null;if(null===i||null===r)return{anchorKey:null,anchorOffset:0,focusKey:null,focusOffset:0};if(de(e)){const[e,t]=_t(i.type,i.index),[n,o]=_t(r.type,r.index);return{anchorKey:null!==e?e.getKey():null,anchorOffset:t,focusKey:null!==n?n.getKey():null,focusOffset:o}}let[l,c]=yt(e.mapping,i),[a,f]=yt(e.mapping,r);if(a&&l&&(a!==l||f!==c)){const e=a.isBefore(l),t=e?a:l,n=e?f:c;o(t)&&o(t.getNextSibling())&&n===t.getTextContentSize()&&(e?(a=t.getNextSibling(),f=0):(l=t.getNextSibling(),c=0))}return{anchorKey:null!==l?l.getKey():null,anchorOffset:c,focusKey:null!==a?a.getKey():null,focusOffset:f}}function pt(e,t){const n=t.awareness.getLocalState();if(null===n)return;const{anchorKey:o,anchorOffset:r,focusKey:l,focusOffset:c}=ht(e,n);if(null!==o&&null!==l){const e=s();if(!i(e))return;gt(e.anchor,o,r),gt(e.focus,l,c)}}function gt(e,n,s){if(e.key!==n||e.offset!==s){let i=t(n);if(null!==i&&!r(i)&&!o(i)){const e=i.getParentOrThrow();n=e.getKey(),s=i.getIndexWithinParent(),i=e}e.set(n,s,r(i)?"element":"text")}}function _t(e,t){const n=e._collabNode;if(void 0===n)return[null,0];if(n instanceof ie){const{node:e,offset:o}=Oe(n,t,!0);return null===e?[n,0]:[e,o]}return[null,0]}function yt(e,t){const n=t.type,s=t.index;if(n instanceof O){const t=e.get(n);if(void 0===t)return[null,0];if(!r(t))return[t,s];let i=s,l=0;const c=t.getChildren();for(;i>0&&l<c.length;){const e=c[l];if(i-=1,l+=1,o(e))for(;l<c.length&&o(c[l]);)l+=1}return[t,l]}{const t=e.get(n);if(void 0===t)return[null,0];let o=0,i=s;for(;i>t[o].getTextContentSize()&&o+1<t.length;)i-=t[o].getTextContentSize(),o++;const r=t[o];return[r,Math.min(i,r.getTextContentSize())]}}function mt(e,t){return t.awareness.getStates()}function xt(e,t,n){const{getAwarenessStates:o=mt}=n??{},s=Array.from(o(e,t)),i=e.clientID,r=e.cursors,l=e.editor,c=l._config.theme.collaboration,a=l._editorState._nodeMap,f=new Set;for(let t=0;t<s.length;t++){const n=s[t],[o,d]=n;if(0!==o&&o!==i){f.add(o);const{name:t,color:n,focusing:s}=d;let i=null,u=r.get(o);if(void 0===u&&(u=lt(t,n),r.set(o,u)),s){const{anchorKey:t,anchorOffset:n,focusKey:o,focusOffset:s}=l.read(()=>ht(e,d));if(null!==t&&null!==o)if(i=u.selection,null===i)i=ft(u,t,n,o,s,c);else{const e=i.anchor,r=i.focus;e.key=t,e.offset=n,r.key=o,r.offset=s}}dt(e,u,i,a,c)}}const d=Array.from(r.keys());for(let t=0;t<d.length;t++){const n=d[t];if(!f.has(n)){const t=r.get(n);void 0!==t&&(at(e,t),r.delete(n))}}}function bt(e,t,n,o){const s=t.awareness,r=s.getLocalState();if(null===r)return;const{anchorPos:l,focusPos:c,name:a,color:f,focusing:d,awarenessData:u}=r;let h=null,p=null;(null!==o&&(null===l||o.is(n))||null!==n)&&(i(o)&&(de(e)?(h=ot(o.anchor,e),p=ot(o.focus,e)):(h=st(o.anchor,e),p=st(o.focus,e))),(rt(l,h)||rt(c,p))&&s.setLocalState({...r,anchorPos:h,awarenessData:u,color:f,focusPos:p,focusing:d,name:a}))}function Tt(e,t){if(t instanceof R&&function(e,t){const{target:n}=t;if(!n._item||"__state"!==n._item.parentSub||void 0!==xe(n)||!(n.parent instanceof C||n.parent instanceof O||n.parent instanceof K))return!1;const o=be(e,n.parent).getNode();if(o){const e=h(o.getWritable());for(const o of t.keysChanged)e.updateFromUnknown(o,n.get(o))}return!0}(e,t))return;const{target:n}=t,o=be(e,n);if(o instanceof ie&&t instanceof q){const{keysChanged:n,childListChanged:s,delta:i}=t;n.size>0&&o.syncPropertiesFromYjs(e,n),s&&(o.applyChildrenYjsDelta(e,i),o.syncChildrenFromYjs(e))}else if(o instanceof oe&&t instanceof R){const{keysChanged:n}=t;n.size>0&&o.syncPropertiesAndTextFromYjs(e,n)}else if(o instanceof Z&&t instanceof J){const{attributesChanged:n}=t;n.size>0&&o.syncPropertiesFromYjs(e,n)}else Q(82)}function kt(e,t,n,o,s=xt){const i=e.editor,r=i._editorState;n.forEach(e=>e.delta),i.update(()=>{for(let t=0;t<n.length;t++){const o=n[t];Tt(e,o)}Nt(r,e,t),o||N(S)},{onUpdate:()=>{s(e,t),i.update(()=>St())},skipTransforms:!0,tag:o?k:T})}function Nt(e,t,n){const o=s();if(i(o))if(Ke(o)){const r=e._selection;if(i(r)&&(pt(t,n),Ke(o))){Pe(o.anchor.key,e)}bt(t,n,r,s())}else pt(t,n)}function St(){0===p().getChildrenSize()&&p().append(v())}function vt(e,n,i,r,l,c,a,f){Me(e,()=>{r.read(()=>{if(f.has(T)||f.has(k))return void(a.size>0&&function(e,n){const s=Array.from(n),i=e.collabNodeMap,r=[],l=[];for(let e=0;e<s.length;e++){const n=s[e],c=t(n),a=i.get(n);if(a instanceof oe)if(o(c))r.push([a,c.__text]);else{const e=a.getOffset();if(-1===e)continue;const t=a._parent;a._normalized=!0,t._xmlText.delete(e,1),l.push(a)}}for(let e=0;e<l.length;e++){const t=l[e],n=t.getKey();i.delete(n);const o=t._parent._children,s=o.indexOf(t);o.splice(s,1)}for(let e=0;e<r.length;e++){const[t,n]=r[e];t._text=n}}(e,a));if(l.has("root")){const t=i._nodeMap,n=p(),o=e.root;o.syncPropertiesFromLexical(e,n,t),o.syncChildrenFromLexical(e,n,t,l,c)}const r=s(),d=i._selection;bt(e,n,d,r)})})}function wt(e,t){const{target:n}=t;if(n instanceof O&&t instanceof J)Fe(n,e,t.attributesChanged,t.childListChanged);else if(n instanceof C&&t instanceof q){const t=n.parent;t instanceof O?Fe(t,e,new Set,!0):Q(327)}else Q(328)}function Ct(e,t,n,o,s){const i=e.editor,r=i._editorState;Y(o,o.deleteSet,t=>{if(t.constructor===B){const n=t.content.type;n&&e.mapping.delete(n)}}),n.forEach(e=>e.delta),i.update(()=>{for(let t=0;t<n.length;t++){const o=n[t];wt(e,o)}Nt(r,e,t),s||N(S)},{discrete:!0,onUpdate:()=>{xt(e,t),i.update(()=>St())},skipTransforms:!0,tag:s?k:T})}function Ot(e,t){e.mapping.clear();const n=e.editor;n.update(()=>{p().clear(),Fe(e.root,e,null,!0),N(T)},{discrete:!0,onUpdate:()=>{xt(e,t),n.update(()=>St())},skipTransforms:!0,tag:T})}function Kt(e,t,n,o,i,r,l){(l.has(T)||l.has(k))&&0===r.size||(r.forEach(t=>{e.mapping.deleteNode(t)}),Me(e,()=>{o.read(()=>{i.has("root")&&Xe(e.doc,e.root,p(),e,new Set(i.keys()));const o=s(),r=n._selection;bt(e,t,r,o)})}))}const Mt=w("CONNECTED_COMMAND"),Pt=w("TOGGLE_CONNECT_COMMAND"),Et=w("DIFF_VERSIONS_COMMAND"),Ft=w("CLEAR_DIFF_VERSIONS_COMMAND");function At(e,t){return new G(t,{trackedOrigins:new Set([e,null])})}function jt(e,t,n,o,s){e.awareness.setLocalState({anchorPos:null,awarenessData:s,color:n,focusPos:null,focusing:o,name:t})}function zt(e,t,n,o,s){const{awareness:i}=e;let r=i.getLocalState();null===r&&(r={anchorPos:null,awarenessData:s,color:n,focusPos:null,focusing:o,name:t}),r.focusing=o,i.setLocalState(r)}export{tt as $getYChangeState,Ft as CLEAR_DIFF_VERSIONS_COMMAND__EXPERIMENTAL,Mt as CONNECTED_COMMAND,Et as DIFF_VERSIONS_COMMAND__EXPERIMENTAL,Pt as TOGGLE_CONNECT_COMMAND,ae as createBinding,fe as createBindingV2__EXPERIMENTAL,At as createUndoManager,ut as getAnchorAndFocusCollabNodesForUserState,jt as initLocalState,nt as renderSnapshot__EXPERIMENTAL,zt as setLocalStateFocus,xt as syncCursorPositions,vt as syncLexicalUpdateToYjs,Kt as syncLexicalUpdateToYjsV2__EXPERIMENTAL,kt as syncYjsChangesToLexical,Ct as syncYjsChangesToLexicalV2__EXPERIMENTAL,Ot as syncYjsStateToLexicalV2__EXPERIMENTAL};
/**
* 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.
*
*/
import { LexicalNode } from 'lexical';
import { ID, Snapshot } from 'yjs';
import { BindingV2 } from './Bindings';
export type YChange<UserT = any> = {
id: ID;
type: 'removed' | 'added';
user: UserT | null;
};
export declare function $getYChangeState<UserT = unknown>(node: LexicalNode): YChange<UserT> | null;
/**
* Replaces the editor content with a view that compares the state between two given snapshots.
* Any added or removed nodes between the two snapshots will have {@link YChange} attached to them.
*
* @param binding Yjs binding
* @param snapshot Ending snapshot state (default: current state of the Yjs document)
* @param prevSnapshot Starting snapshot state (default: empty snapshot)
*/
export declare const renderSnapshot__EXPERIMENTAL: (binding: BindingV2, snapshot?: Snapshot, prevSnapshot?: Snapshot) => void;
/**
* 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.
*
*/
import type { BaseSelection, NodeKey } from 'lexical';
import { Provider, UserState } from '.';
import { AnyBinding, type BaseBinding, type Binding } from './Bindings';
import { CollabDecoratorNode } from './CollabDecoratorNode';
import { CollabElementNode } from './CollabElementNode';
import { CollabLineBreakNode } from './CollabLineBreakNode';
import { CollabTextNode } from './CollabTextNode';
export type CursorSelection = {
anchor: {
key: NodeKey;
offset: number;
};
caret: HTMLElement;
color: string;
focus: {
key: NodeKey;
offset: number;
};
name: HTMLSpanElement;
selections: Array<HTMLElement>;
};
export type Cursor = {
color: string;
name: string;
selection: null | CursorSelection;
};
type AnyCollabNode = CollabDecoratorNode | CollabElementNode | CollabTextNode | CollabLineBreakNode;
/**
* @deprecated Use `$getAnchorAndFocusForUserState` instead.
*/
export declare function getAnchorAndFocusCollabNodesForUserState(binding: Binding, userState: UserState): {
anchorCollabNode: AnyCollabNode | null;
anchorOffset: number;
focusCollabNode: AnyCollabNode | null;
focusOffset: number;
};
export declare function $getAnchorAndFocusForUserState(binding: AnyBinding, userState: UserState): {
anchorKey: NodeKey | null;
anchorOffset: number;
focusKey: NodeKey | null;
focusOffset: number;
};
export declare function $syncLocalCursorPosition(binding: AnyBinding, provider: Provider): void;
export type SyncCursorPositionsFn = (binding: AnyBinding, provider: Provider, options?: SyncCursorPositionsOptions) => void;
export type SyncCursorPositionsOptions = {
getAwarenessStates?: (binding: BaseBinding, provider: Provider) => Map<number, UserState>;
};
export declare function syncCursorPositions(binding: AnyBinding, provider: Provider, options?: SyncCursorPositionsOptions): void;
export declare function syncLexicalSelectionToYjs(binding: AnyBinding, provider: Provider, prevSelection: null | BaseSelection, nextSelection: null | BaseSelection): void;
export {};
/**
* 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.
*
*/
import type { EditorState, NodeKey } from 'lexical';
import type { Transaction as YTransaction } from 'yjs';
import { Text as YText, XmlElement, XmlText, YEvent } from 'yjs';
import { Binding, BindingV2, Provider } from '.';
import { SyncCursorPositionsFn } from './SyncCursors';
export declare function syncYjsChangesToLexical(binding: Binding, provider: Provider, events: Array<YEvent<YText>>, isFromUndoManger: boolean, syncCursorPositionsFn?: SyncCursorPositionsFn): void;
type IntentionallyMarkedAsDirtyElement = boolean;
export declare function syncLexicalUpdateToYjs(binding: Binding, provider: Provider, prevEditorState: EditorState, currEditorState: EditorState, dirtyElements: Map<NodeKey, IntentionallyMarkedAsDirtyElement>, dirtyLeaves: Set<NodeKey>, normalizedNodes: Set<NodeKey>, tags: Set<string>): void;
export declare function syncYjsChangesToLexicalV2__EXPERIMENTAL(binding: BindingV2, provider: Provider, events: Array<YEvent<XmlElement | XmlText>>, transaction: YTransaction, isFromUndoManger: boolean): void;
export declare function syncYjsStateToLexicalV2__EXPERIMENTAL(binding: BindingV2, provider: Provider): void;
export declare function syncLexicalUpdateToYjsV2__EXPERIMENTAL(binding: BindingV2, provider: Provider, prevEditorState: EditorState, currEditorState: EditorState, dirtyElements: Map<NodeKey, IntentionallyMarkedAsDirtyElement>, normalizedNodes: Set<NodeKey>, tags: Set<string>): void;
export {};
/**
* 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.
*
*/
import { LexicalNode, NodeKey } from 'lexical';
import { Doc as YDoc, ID, Snapshot, XmlElement } from 'yjs';
import { BindingV2 } from './Bindings';
type ComputeYChange = (event: 'removed' | 'added', id: ID) => Record<string, unknown>;
export declare const $createOrUpdateNodeFromYElement: (el: XmlElement, binding: BindingV2, keysChanged: Set<string> | null, childListChanged: boolean, snapshot?: Snapshot, prevSnapshot?: Snapshot, computeYChange?: ComputeYChange) => LexicalNode | null;
export declare const $updateYFragment: (y: YDoc, yDomFragment: XmlElement, node: LexicalNode, binding: BindingV2, dirtyElements: Set<NodeKey>) => void;
export {};
/**
* 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.
*
*/
import { CollabDecoratorNode } from './CollabDecoratorNode';
import { CollabElementNode } from './CollabElementNode';
import { CollabLineBreakNode } from './CollabLineBreakNode';
import { CollabTextNode } from './CollabTextNode';
declare module 'yjs' {
interface XmlElement {
_collabNode: CollabDecoratorNode;
}
interface XmlText {
_collabNode: CollabElementNode;
}
interface Map<MapType> {
_collabNode: CollabLineBreakNode | CollabTextNode;
}
}
/**
* 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.
*
*/
import type { BaseBinding, Binding, YjsNode } from '.';
import { EditorState, LexicalNode, NodeKey, RangeSelection } from 'lexical';
import { Map as YMap, XmlElement, XmlText } from 'yjs';
import { CollabDecoratorNode } from './CollabDecoratorNode';
import { CollabElementNode } from './CollabElementNode';
import { CollabLineBreakNode } from './CollabLineBreakNode';
import { CollabTextNode } from './CollabTextNode';
export declare function initializeNodeProperties(binding: BaseBinding): void;
export declare function getDefaultNodeProperties(node: LexicalNode, binding: BaseBinding): {
[property: string]: unknown;
};
export declare function getIndexOfYjsNode(yjsParentNode: YjsNode, yjsNode: YjsNode): number;
export declare function $createCollabNodeFromLexicalNode(binding: Binding, lexicalNode: LexicalNode, parent: CollabElementNode): CollabElementNode | CollabTextNode | CollabLineBreakNode | CollabDecoratorNode;
export declare function getNodeTypeFromSharedType(sharedType: XmlText | YMap<unknown> | XmlElement): string | undefined;
export declare function $getOrInitCollabNodeFromSharedType(binding: Binding, sharedType: XmlText | YMap<unknown> | XmlElement, parent?: CollabElementNode): CollabElementNode | CollabTextNode | CollabLineBreakNode | CollabDecoratorNode;
export declare function createLexicalNodeFromCollabNode(binding: Binding, collabNode: CollabElementNode | CollabTextNode | CollabDecoratorNode | CollabLineBreakNode, parentKey: NodeKey): LexicalNode;
export declare function $syncPropertiesFromYjs(binding: BaseBinding, sharedType: XmlText | YMap<unknown> | XmlElement | Record<string, unknown>, lexicalNode: LexicalNode, keysChanged: null | Set<string>): void;
export declare function syncPropertiesFromLexical(binding: Binding, sharedType: XmlText | YMap<unknown> | XmlElement, prevLexicalNode: null | LexicalNode, nextLexicalNode: LexicalNode): void;
export declare function spliceString(str: string, index: number, delCount: number, newText: string): string;
export declare function getPositionFromElementAndOffset(node: CollabElementNode, offset: number, boundaryIsEdge: boolean): {
length: number;
node: CollabElementNode | CollabTextNode | CollabDecoratorNode | CollabLineBreakNode | null;
nodeIndex: number;
offset: number;
};
export declare function doesSelectionNeedRecovering(selection: RangeSelection): boolean;
export declare function syncWithTransaction(binding: BaseBinding, fn: () => void): void;
export declare function $moveSelectionToPreviousNode(anchorNodeKey: string, currentEditorState: EditorState): void;