@lexical/yjs 0.2.4 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LexicalYjs.d.ts +274 -0
- package/LexicalYjs.dev.js +18 -89
- package/LexicalYjs.js.flow +364 -0
- package/LexicalYjs.prod.js +39 -41
- package/package.json +3 -3
package/LexicalYjs.d.ts
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
import type {
|
|
9
|
+
Doc,
|
|
10
|
+
RelativePosition,
|
|
11
|
+
TextOperation,
|
|
12
|
+
UndoManager,
|
|
13
|
+
XmlElement,
|
|
14
|
+
XmlText,
|
|
15
|
+
Map as YMap,
|
|
16
|
+
} from 'yjs';
|
|
17
|
+
import type {
|
|
18
|
+
DecoratorNode,
|
|
19
|
+
EditorState,
|
|
20
|
+
ElementNode,
|
|
21
|
+
LexicalCommand,
|
|
22
|
+
LexicalEditor,
|
|
23
|
+
LineBreakNode,
|
|
24
|
+
NodeMap,
|
|
25
|
+
NodeKey,
|
|
26
|
+
TextNode,
|
|
27
|
+
IntentionallyMarkedAsDirtyElement,
|
|
28
|
+
} from 'lexical';
|
|
29
|
+
// @ts-expect-error: todo
|
|
30
|
+
export type YjsEvent = Record<string, any>;
|
|
31
|
+
export type UserState = {
|
|
32
|
+
anchorPos: null | RelativePosition;
|
|
33
|
+
color: string;
|
|
34
|
+
focusing: boolean;
|
|
35
|
+
focusPos: null | RelativePosition;
|
|
36
|
+
name: string;
|
|
37
|
+
};
|
|
38
|
+
export type ProviderAwareness = {
|
|
39
|
+
getLocalState: () => UserState | null;
|
|
40
|
+
getStates: () => Map<number, UserState>;
|
|
41
|
+
off: (type: 'update', cb: () => void) => void;
|
|
42
|
+
on: (type: 'update', cb: () => void) => void;
|
|
43
|
+
setLocalState: (arg0: UserState) => void;
|
|
44
|
+
};
|
|
45
|
+
declare interface Provider {
|
|
46
|
+
awareness: ProviderAwareness;
|
|
47
|
+
connect(): void | Promise<void>;
|
|
48
|
+
disconnect(): void;
|
|
49
|
+
off(type: 'sync', cb: (isSynced: boolean) => void): void;
|
|
50
|
+
// $FlowFixMe: temp
|
|
51
|
+
off(type: 'update', cb: (arg0: any) => void): void;
|
|
52
|
+
off(type: 'status', cb: (arg0: {status: string}) => void): void;
|
|
53
|
+
off(type: 'reload', cb: (doc: Doc) => void): void;
|
|
54
|
+
on(type: 'sync', cb: (isSynced: boolean) => void): void;
|
|
55
|
+
on(type: 'status', cb: (arg0: {status: string}) => void): void;
|
|
56
|
+
// $FlowFixMe: temp
|
|
57
|
+
on(type: 'update', cb: (arg0: any) => void): void;
|
|
58
|
+
on(type: 'reload', cb: (doc: Doc) => void): void;
|
|
59
|
+
}
|
|
60
|
+
export type ClientID = number;
|
|
61
|
+
export type CursorSelection = {
|
|
62
|
+
anchor: {
|
|
63
|
+
key: NodeKey;
|
|
64
|
+
offset: number;
|
|
65
|
+
};
|
|
66
|
+
caret: HTMLElement;
|
|
67
|
+
color: string;
|
|
68
|
+
focus: {
|
|
69
|
+
key: NodeKey;
|
|
70
|
+
offset: number;
|
|
71
|
+
};
|
|
72
|
+
name: HTMLSpanElement;
|
|
73
|
+
selections: Array<HTMLElement>;
|
|
74
|
+
};
|
|
75
|
+
export type Cursor = {
|
|
76
|
+
color: string;
|
|
77
|
+
name: string;
|
|
78
|
+
selection: null | CursorSelection;
|
|
79
|
+
};
|
|
80
|
+
export type Binding = {
|
|
81
|
+
clientID: number;
|
|
82
|
+
collabNodeMap: Map<
|
|
83
|
+
NodeKey,
|
|
84
|
+
| CollabElementNode
|
|
85
|
+
| CollabTextNode
|
|
86
|
+
| CollabDecoratorNode
|
|
87
|
+
| CollabLineBreakNode
|
|
88
|
+
>;
|
|
89
|
+
cursors: Map<ClientID, Cursor>;
|
|
90
|
+
cursorsContainer: null | HTMLElement;
|
|
91
|
+
doc: Doc;
|
|
92
|
+
docMap: Map<string, Doc>;
|
|
93
|
+
editor: LexicalEditor;
|
|
94
|
+
id: string;
|
|
95
|
+
nodeProperties: Map<string, Array<string>>;
|
|
96
|
+
root: CollabElementNode;
|
|
97
|
+
};
|
|
98
|
+
export declare class CollabDecoratorNode {
|
|
99
|
+
_xmlElem: XmlElement;
|
|
100
|
+
_key: NodeKey;
|
|
101
|
+
_parent: CollabElementNode;
|
|
102
|
+
_type: string;
|
|
103
|
+
_unobservers: Set<() => void>;
|
|
104
|
+
constructor(xmlElem: XmlElement, parent: CollabElementNode, type: string);
|
|
105
|
+
getPrevNode(nodeMap: null | NodeMap): null | DecoratorNode<{}>;
|
|
106
|
+
getNode(): null | DecoratorNode<{}>;
|
|
107
|
+
getSharedType(): XmlElement;
|
|
108
|
+
getType(): string;
|
|
109
|
+
getKey(): NodeKey;
|
|
110
|
+
getSize(): number;
|
|
111
|
+
getOffset(): number;
|
|
112
|
+
syncPropertiesFromLexical(
|
|
113
|
+
binding: Binding,
|
|
114
|
+
nextLexicalNode: DecoratorNode<{}>,
|
|
115
|
+
prevNodeMap: null | NodeMap,
|
|
116
|
+
): void;
|
|
117
|
+
syncPropertiesFromYjs(
|
|
118
|
+
binding: Binding,
|
|
119
|
+
keysChanged: null | Set<string>,
|
|
120
|
+
): void;
|
|
121
|
+
destroy(binding: Binding): void;
|
|
122
|
+
}
|
|
123
|
+
export declare class CollabLineBreakNode {
|
|
124
|
+
_map: YMap;
|
|
125
|
+
_key: NodeKey;
|
|
126
|
+
_parent: CollabElementNode;
|
|
127
|
+
_type: 'linebreak';
|
|
128
|
+
constructor(map: YMap, parent: CollabElementNode);
|
|
129
|
+
getNode(): null | LineBreakNode;
|
|
130
|
+
getKey(): NodeKey;
|
|
131
|
+
getSharedType(): YMap;
|
|
132
|
+
getType(): string;
|
|
133
|
+
getSize(): number;
|
|
134
|
+
getOffset(): number;
|
|
135
|
+
destroy(binding: Binding): void;
|
|
136
|
+
}
|
|
137
|
+
export declare class CollabTextNode {
|
|
138
|
+
_map: YMap;
|
|
139
|
+
_key: NodeKey;
|
|
140
|
+
_parent: CollabElementNode;
|
|
141
|
+
_text: string;
|
|
142
|
+
_type: string;
|
|
143
|
+
_normalized: boolean;
|
|
144
|
+
constructor(map: YMap, text: string, parent: CollabElementNode, type: string);
|
|
145
|
+
getPrevNode(nodeMap: null | NodeMap): null | TextNode;
|
|
146
|
+
getNode(): null | TextNode;
|
|
147
|
+
getSharedType(): YMap;
|
|
148
|
+
getType(): string;
|
|
149
|
+
getKey(): NodeKey;
|
|
150
|
+
getSize(): number;
|
|
151
|
+
getOffset(): number;
|
|
152
|
+
spliceText(index: number, delCount: number, newText: string): void;
|
|
153
|
+
syncPropertiesAndTextFromLexical(
|
|
154
|
+
binding: Binding,
|
|
155
|
+
nextLexicalNode: TextNode,
|
|
156
|
+
prevNodeMap: null | NodeMap,
|
|
157
|
+
): void;
|
|
158
|
+
syncPropertiesAndTextFromYjs(
|
|
159
|
+
binding: Binding,
|
|
160
|
+
keysChanged: null | Set<string>,
|
|
161
|
+
): void;
|
|
162
|
+
destroy(binding: Binding): void;
|
|
163
|
+
}
|
|
164
|
+
export declare class CollabElementNode {
|
|
165
|
+
_key: NodeKey;
|
|
166
|
+
_children: Array<
|
|
167
|
+
| CollabElementNode
|
|
168
|
+
| CollabTextNode
|
|
169
|
+
| CollabDecoratorNode
|
|
170
|
+
| CollabLineBreakNode
|
|
171
|
+
>;
|
|
172
|
+
_xmlText: XmlText;
|
|
173
|
+
_type: string;
|
|
174
|
+
_parent: null | CollabElementNode;
|
|
175
|
+
constructor(xmlText: XmlText, parent: null | CollabElementNode, type: string);
|
|
176
|
+
getPrevNode(nodeMap: null | NodeMap): null | ElementNode;
|
|
177
|
+
getNode(): null | ElementNode;
|
|
178
|
+
getSharedType(): XmlText;
|
|
179
|
+
getType(): string;
|
|
180
|
+
getKey(): NodeKey;
|
|
181
|
+
isEmpty(): boolean;
|
|
182
|
+
getSize(): number;
|
|
183
|
+
getOffset(): number;
|
|
184
|
+
syncPropertiesFromYjs(
|
|
185
|
+
binding: Binding,
|
|
186
|
+
keysChanged: null | Set<string>,
|
|
187
|
+
): void;
|
|
188
|
+
applyChildrenYjsDelta(binding: Binding, deltas: Array<TextOperation>): void;
|
|
189
|
+
syncChildrenFromYjs(binding: Binding): void;
|
|
190
|
+
syncPropertiesFromLexical(
|
|
191
|
+
binding: Binding,
|
|
192
|
+
nextLexicalNode: ElementNode,
|
|
193
|
+
prevNodeMap: null | NodeMap,
|
|
194
|
+
): void;
|
|
195
|
+
_syncChildFromLexical(
|
|
196
|
+
binding: Binding,
|
|
197
|
+
index: number,
|
|
198
|
+
key: NodeKey,
|
|
199
|
+
prevNodeMap: null | NodeMap,
|
|
200
|
+
dirtyElements: null | Map<NodeKey, IntentionallyMarkedAsDirtyElement>,
|
|
201
|
+
dirtyLeaves: null | Set<NodeKey>,
|
|
202
|
+
): void;
|
|
203
|
+
syncChildrenFromLexical(
|
|
204
|
+
binding: Binding,
|
|
205
|
+
nextLexicalNode: ElementNode,
|
|
206
|
+
prevNodeMap: null | NodeMap,
|
|
207
|
+
dirtyElements: null | Map<NodeKey, IntentionallyMarkedAsDirtyElement>,
|
|
208
|
+
dirtyLeaves: null | Set<NodeKey>,
|
|
209
|
+
): void;
|
|
210
|
+
append(
|
|
211
|
+
collabNode:
|
|
212
|
+
| CollabElementNode
|
|
213
|
+
| CollabDecoratorNode
|
|
214
|
+
| CollabTextNode
|
|
215
|
+
| CollabLineBreakNode,
|
|
216
|
+
): void;
|
|
217
|
+
splice(
|
|
218
|
+
binding: Binding,
|
|
219
|
+
index: number,
|
|
220
|
+
delCount: number,
|
|
221
|
+
collabNode?:
|
|
222
|
+
| CollabElementNode
|
|
223
|
+
| CollabDecoratorNode
|
|
224
|
+
| CollabTextNode
|
|
225
|
+
| CollabLineBreakNode,
|
|
226
|
+
): void;
|
|
227
|
+
getChildOffset(
|
|
228
|
+
collabNode:
|
|
229
|
+
| CollabElementNode
|
|
230
|
+
| CollabTextNode
|
|
231
|
+
| CollabDecoratorNode
|
|
232
|
+
| CollabLineBreakNode,
|
|
233
|
+
): number;
|
|
234
|
+
destroy(binding: Binding): void;
|
|
235
|
+
}
|
|
236
|
+
export function createUndoManager(binding: Binding, root: XmlText): UndoManager;
|
|
237
|
+
export function initLocalState(
|
|
238
|
+
provider: Provider,
|
|
239
|
+
name: string,
|
|
240
|
+
color: string,
|
|
241
|
+
focusing: boolean,
|
|
242
|
+
): void;
|
|
243
|
+
export function setLocalStateFocus(
|
|
244
|
+
provider: Provider,
|
|
245
|
+
name: string,
|
|
246
|
+
color: string,
|
|
247
|
+
focusing: boolean,
|
|
248
|
+
): void;
|
|
249
|
+
export function createBinding(
|
|
250
|
+
editor: LexicalEditor,
|
|
251
|
+
provider: Provider,
|
|
252
|
+
id: string,
|
|
253
|
+
doc: Doc | null | undefined,
|
|
254
|
+
docMap: Map<string, Doc>,
|
|
255
|
+
): Binding;
|
|
256
|
+
export function syncCursorPositions(binding: Binding, provider: Provider): void;
|
|
257
|
+
export function syncLexicalUpdateToYjs(
|
|
258
|
+
binding: Binding,
|
|
259
|
+
provider: Provider,
|
|
260
|
+
prevEditorState: EditorState,
|
|
261
|
+
currEditorState: EditorState,
|
|
262
|
+
dirtyElements: Map<NodeKey, IntentionallyMarkedAsDirtyElement>,
|
|
263
|
+
dirtyLeaves: Set<NodeKey>,
|
|
264
|
+
normalizedNodes: Set<NodeKey>,
|
|
265
|
+
tags: Set<string>,
|
|
266
|
+
): void;
|
|
267
|
+
export function syncYjsChangesToLexical(
|
|
268
|
+
binding: Binding,
|
|
269
|
+
provider: Provider,
|
|
270
|
+
events: Array<YjsEvent>,
|
|
271
|
+
): void;
|
|
272
|
+
export declare var CONNECTED_COMMAND: LexicalCommand<boolean>;
|
|
273
|
+
export declare var TOGGLE_CONNECT_COMMAND: LexicalCommand<boolean>;
|
|
274
|
+
export type {Provider};
|
package/LexicalYjs.dev.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
var lexical = require('lexical');
|
|
10
10
|
var yjs = require('yjs');
|
|
11
|
+
var selection = require('@lexical/selection');
|
|
11
12
|
var offset = require('@lexical/offset');
|
|
12
13
|
|
|
13
14
|
/**
|
|
@@ -73,7 +74,6 @@ function $createCollabLineBreakNode(map, parent) {
|
|
|
73
74
|
*
|
|
74
75
|
*
|
|
75
76
|
*/
|
|
76
|
-
|
|
77
77
|
function simpleDiffWithCursor(a, b, cursor) {
|
|
78
78
|
const aLength = a.length;
|
|
79
79
|
const bLength = b.length;
|
|
@@ -104,6 +104,15 @@ function simpleDiffWithCursor(a, b, cursor) {
|
|
|
104
104
|
};
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
/**
|
|
108
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
109
|
+
*
|
|
110
|
+
* This source code is licensed under the MIT license found in the
|
|
111
|
+
* LICENSE file in the root directory of this source tree.
|
|
112
|
+
*
|
|
113
|
+
*
|
|
114
|
+
*/
|
|
115
|
+
|
|
107
116
|
function diffTextContentAndApplyDelta(collabNode, key, prevText, nextText) {
|
|
108
117
|
const selection = lexical.$getSelection();
|
|
109
118
|
let cursorOffset = nextText.length;
|
|
@@ -464,7 +473,7 @@ function getPositionFromElementAndOffset(node, offset, boundaryIsEdge) {
|
|
|
464
473
|
textOffset = 0;
|
|
465
474
|
}
|
|
466
475
|
|
|
467
|
-
const diffLength =
|
|
476
|
+
const diffLength = index - offset;
|
|
468
477
|
return {
|
|
469
478
|
length: diffLength,
|
|
470
479
|
node: child,
|
|
@@ -1203,21 +1212,6 @@ function destroyCursor(binding, cursor) {
|
|
|
1203
1212
|
}
|
|
1204
1213
|
}
|
|
1205
1214
|
|
|
1206
|
-
function getDOMTextNode(element) {
|
|
1207
|
-
let node = element;
|
|
1208
|
-
|
|
1209
|
-
while (node != null) {
|
|
1210
|
-
if (node.nodeType === 3) {
|
|
1211
|
-
// $FlowFixMe: this is a Text
|
|
1212
|
-
return node;
|
|
1213
|
-
}
|
|
1214
|
-
|
|
1215
|
-
node = node.firstChild;
|
|
1216
|
-
}
|
|
1217
|
-
|
|
1218
|
-
return null;
|
|
1219
|
-
}
|
|
1220
|
-
|
|
1221
1215
|
function createCursorSelection(cursor, anchorKey, anchorOffset, focusKey, focusOffset) {
|
|
1222
1216
|
const color = cursor.color;
|
|
1223
1217
|
const caret = document.createElement('span');
|
|
@@ -1238,21 +1232,10 @@ function createCursorSelection(cursor, anchorKey, anchorOffset, focusKey, focusO
|
|
|
1238
1232
|
offset: focusOffset
|
|
1239
1233
|
},
|
|
1240
1234
|
name,
|
|
1241
|
-
range: document.createRange(),
|
|
1242
1235
|
selections: []
|
|
1243
1236
|
};
|
|
1244
1237
|
}
|
|
1245
1238
|
|
|
1246
|
-
function getDOMIndexWithinParent(node) {
|
|
1247
|
-
const parent = node.parentNode;
|
|
1248
|
-
|
|
1249
|
-
if (parent == null) {
|
|
1250
|
-
throw new Error('Should never happen');
|
|
1251
|
-
}
|
|
1252
|
-
|
|
1253
|
-
return [parent, Array.from(parent.childNodes).indexOf(node)];
|
|
1254
|
-
}
|
|
1255
|
-
|
|
1256
1239
|
function updateCursor(binding, cursor, nextSelection, nodeMap) {
|
|
1257
1240
|
const editor = binding.editor;
|
|
1258
1241
|
const rootElement = editor.getRootElement();
|
|
@@ -1276,7 +1259,6 @@ function updateCursor(binding, cursor, nextSelection, nodeMap) {
|
|
|
1276
1259
|
cursor.selection = nextSelection;
|
|
1277
1260
|
}
|
|
1278
1261
|
|
|
1279
|
-
const range = nextSelection.range;
|
|
1280
1262
|
const caret = nextSelection.caret;
|
|
1281
1263
|
const color = nextSelection.color;
|
|
1282
1264
|
const selections = nextSelection.selections;
|
|
@@ -1286,76 +1268,23 @@ function updateCursor(binding, cursor, nextSelection, nodeMap) {
|
|
|
1286
1268
|
const focusKey = focus.key;
|
|
1287
1269
|
const anchorNode = nodeMap.get(anchorKey);
|
|
1288
1270
|
const focusNode = nodeMap.get(focusKey);
|
|
1289
|
-
let anchorDOM = editor.getElementByKey(anchorKey);
|
|
1290
|
-
let focusDOM = editor.getElementByKey(focusKey);
|
|
1291
|
-
let anchorOffset = anchor.offset;
|
|
1292
|
-
let focusOffset = focus.offset;
|
|
1293
|
-
|
|
1294
|
-
if (lexical.$isTextNode(anchorNode)) {
|
|
1295
|
-
anchorDOM = getDOMTextNode(anchorDOM);
|
|
1296
|
-
}
|
|
1297
1271
|
|
|
1298
|
-
if (
|
|
1299
|
-
focusDOM = getDOMTextNode(focusDOM);
|
|
1300
|
-
}
|
|
1301
|
-
|
|
1302
|
-
if (anchorNode === undefined || focusNode === undefined || anchorDOM === null || focusDOM === null) {
|
|
1272
|
+
if (anchorNode == null || focusNode == null) {
|
|
1303
1273
|
return;
|
|
1304
1274
|
}
|
|
1305
1275
|
|
|
1306
|
-
|
|
1307
|
-
[anchorDOM, anchorOffset] = getDOMIndexWithinParent(anchorDOM);
|
|
1308
|
-
}
|
|
1309
|
-
|
|
1310
|
-
if (focusDOM.nodeName === 'BR') {
|
|
1311
|
-
[focusDOM, focusOffset] = getDOMIndexWithinParent(focusDOM);
|
|
1312
|
-
}
|
|
1313
|
-
|
|
1314
|
-
const firstChild = anchorDOM.firstChild;
|
|
1315
|
-
|
|
1316
|
-
if (anchorDOM === focusDOM && firstChild != null && firstChild.nodeName === 'BR' && anchorOffset === 0 && focusOffset === 0) {
|
|
1317
|
-
focusOffset = 1;
|
|
1318
|
-
}
|
|
1276
|
+
const range = selection.createDOMRange(editor, anchorNode, anchor.offset, focusNode, focus.offset);
|
|
1319
1277
|
|
|
1320
|
-
|
|
1321
|
-
range.setStart(anchorDOM, anchorOffset);
|
|
1322
|
-
range.setEnd(focusDOM, focusOffset);
|
|
1323
|
-
} catch (e) {
|
|
1278
|
+
if (range === null) {
|
|
1324
1279
|
return;
|
|
1325
1280
|
}
|
|
1326
1281
|
|
|
1327
|
-
if (range.collapsed && (anchorOffset !== focusOffset || anchorKey !== focusKey)) {
|
|
1328
|
-
// Range is backwards, we need to reverse it
|
|
1329
|
-
range.setStart(focusDOM, focusOffset);
|
|
1330
|
-
range.setEnd(anchorDOM, anchorOffset);
|
|
1331
|
-
} // We need to
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
const rootRect = rootElement.getBoundingClientRect();
|
|
1335
|
-
const computedStyle = getComputedStyle(rootElement);
|
|
1336
|
-
const rootPadding = parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight);
|
|
1337
|
-
const selectionRects = Array.from(range.getClientRects());
|
|
1338
|
-
let selectionRectsLength = selectionRects.length;
|
|
1339
1282
|
const selectionsLength = selections.length;
|
|
1340
|
-
|
|
1283
|
+
const selectionRects = selection.createRectsFromDOMRange(editor, range);
|
|
1284
|
+
const selectionRectsLength = selectionRects.length;
|
|
1341
1285
|
|
|
1342
1286
|
for (let i = 0; i < selectionRectsLength; i++) {
|
|
1343
|
-
const selectionRect = selectionRects[i];
|
|
1344
|
-
// the same rect twice for some elements. A more sophisticated thing to do here is to
|
|
1345
|
-
// merge all the rects together into a set of rects that don't overlap, so we don't
|
|
1346
|
-
// generate backgrounds that are too dark.
|
|
1347
|
-
|
|
1348
|
-
const isDuplicateRect = prevRect && prevRect.top === selectionRect.top && prevRect.left === selectionRect.left && prevRect.width === selectionRect.width && prevRect.height === selectionRect.height; // Exclude selections that span the entire element
|
|
1349
|
-
|
|
1350
|
-
const selectionSpansElement = selectionRect.width + rootPadding === rootRect.width;
|
|
1351
|
-
|
|
1352
|
-
if (isDuplicateRect || selectionSpansElement) {
|
|
1353
|
-
selectionRects.splice(i--, 1);
|
|
1354
|
-
selectionRectsLength--;
|
|
1355
|
-
continue;
|
|
1356
|
-
}
|
|
1357
|
-
|
|
1358
|
-
prevRect = selectionRect;
|
|
1287
|
+
const selectionRect = selectionRects[i];
|
|
1359
1288
|
let selection = selections[i];
|
|
1360
1289
|
|
|
1361
1290
|
if (selection === undefined) {
|
|
@@ -1364,7 +1293,7 @@ function updateCursor(binding, cursor, nextSelection, nodeMap) {
|
|
|
1364
1293
|
cursorsContainer.appendChild(selection);
|
|
1365
1294
|
}
|
|
1366
1295
|
|
|
1367
|
-
const style = `position:absolute;top:${selectionRect.top}px;left:${selectionRect.left}px;height:${selectionRect.height}px;width:${selectionRect.width}px;background-color:rgba(${color}, 0.3);pointer-events:none;z-index:
|
|
1296
|
+
const style = `position:absolute;top:${selectionRect.top}px;left:${selectionRect.left}px;height:${selectionRect.height}px;width:${selectionRect.width}px;background-color:rgba(${color}, 0.3);pointer-events:none;z-index:5;`;
|
|
1368
1297
|
selection.style.cssText = style;
|
|
1369
1298
|
|
|
1370
1299
|
if (i === selectionRectsLength - 1) {
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @flow strict
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {Doc, RelativePosition, UndoManager, XmlText} from 'yjs';
|
|
11
|
+
import type {
|
|
12
|
+
DecoratorNode,
|
|
13
|
+
EditorState,
|
|
14
|
+
ElementNode,
|
|
15
|
+
LexicalCommand,
|
|
16
|
+
LexicalEditor,
|
|
17
|
+
LineBreakNode,
|
|
18
|
+
NodeMap,
|
|
19
|
+
NodeKey,
|
|
20
|
+
TextNode,
|
|
21
|
+
IntentionallyMarkedAsDirtyElement,
|
|
22
|
+
} from 'lexical';
|
|
23
|
+
|
|
24
|
+
// $FlowFixMe: todo
|
|
25
|
+
export type YjsEvent = Object;
|
|
26
|
+
|
|
27
|
+
export type UserState = {
|
|
28
|
+
anchorPos: null | RelativePosition,
|
|
29
|
+
color: string,
|
|
30
|
+
focusing: boolean,
|
|
31
|
+
focusPos: null | RelativePosition,
|
|
32
|
+
name: string,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export type ProviderAwareness = {
|
|
36
|
+
getLocalState: () => UserState | null,
|
|
37
|
+
getStates: () => Map<number, UserState>,
|
|
38
|
+
off: (type: 'update', cb: () => void) => void,
|
|
39
|
+
on: (type: 'update', cb: () => void) => void,
|
|
40
|
+
setLocalState: (UserState) => void,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
declare interface Provider {
|
|
44
|
+
awareness: ProviderAwareness;
|
|
45
|
+
connect(): void | Promise<void>;
|
|
46
|
+
disconnect(): void;
|
|
47
|
+
off(type: 'sync', cb: (isSynced: boolean) => void): void;
|
|
48
|
+
// $FlowFixMe: temp
|
|
49
|
+
off(type: 'update', cb: (any) => void): void;
|
|
50
|
+
off(type: 'status', cb: ({status: string}) => void): void;
|
|
51
|
+
off(type: 'reload', cb: (doc: Doc) => void): void;
|
|
52
|
+
on(type: 'sync', cb: (isSynced: boolean) => void): void;
|
|
53
|
+
on(type: 'status', cb: ({status: string}) => void): void;
|
|
54
|
+
// $FlowFixMe: temp
|
|
55
|
+
on(type: 'update', cb: (any) => void): void;
|
|
56
|
+
on(type: 'reload', cb: (doc: Doc) => void): void;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export type ClientID = number;
|
|
60
|
+
// $FlowFixMe: work around for internal
|
|
61
|
+
export type XmlElement = Object;
|
|
62
|
+
// $FlowFixMe: work around for internal
|
|
63
|
+
export type YMap = Object;
|
|
64
|
+
// $FlowFixMe: work around for internal
|
|
65
|
+
export type TextOperation = Object;
|
|
66
|
+
|
|
67
|
+
export type CursorSelection = {
|
|
68
|
+
anchor: {
|
|
69
|
+
key: NodeKey,
|
|
70
|
+
offset: number,
|
|
71
|
+
},
|
|
72
|
+
caret: HTMLElement,
|
|
73
|
+
color: string,
|
|
74
|
+
focus: {
|
|
75
|
+
key: NodeKey,
|
|
76
|
+
offset: number,
|
|
77
|
+
},
|
|
78
|
+
name: HTMLSpanElement,
|
|
79
|
+
selections: Array<HTMLElement>,
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export type Cursor = {
|
|
83
|
+
color: string,
|
|
84
|
+
name: string,
|
|
85
|
+
selection: null | CursorSelection,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export type Binding = {
|
|
89
|
+
clientID: number,
|
|
90
|
+
collabNodeMap: Map<
|
|
91
|
+
NodeKey,
|
|
92
|
+
| CollabElementNode
|
|
93
|
+
| CollabTextNode
|
|
94
|
+
| CollabDecoratorNode
|
|
95
|
+
| CollabLineBreakNode,
|
|
96
|
+
>,
|
|
97
|
+
cursors: Map<ClientID, Cursor>,
|
|
98
|
+
cursorsContainer: null | HTMLElement,
|
|
99
|
+
doc: Doc,
|
|
100
|
+
docMap: Map<string, Doc>,
|
|
101
|
+
editor: LexicalEditor,
|
|
102
|
+
id: string,
|
|
103
|
+
nodeProperties: Map<string, Array<string>>,
|
|
104
|
+
root: CollabElementNode,
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
declare export class CollabDecoratorNode {
|
|
108
|
+
_xmlElem: XmlElement;
|
|
109
|
+
_key: NodeKey;
|
|
110
|
+
_parent: CollabElementNode;
|
|
111
|
+
_type: string;
|
|
112
|
+
_unobservers: Set<() => void>;
|
|
113
|
+
|
|
114
|
+
constructor(
|
|
115
|
+
xmlElem: XmlElement,
|
|
116
|
+
parent: CollabElementNode,
|
|
117
|
+
type: string,
|
|
118
|
+
): void;
|
|
119
|
+
|
|
120
|
+
getPrevNode(nodeMap: null | NodeMap): null | DecoratorNode<{...}>;
|
|
121
|
+
|
|
122
|
+
getNode(): null | DecoratorNode<{...}>;
|
|
123
|
+
|
|
124
|
+
getSharedType(): XmlElement;
|
|
125
|
+
|
|
126
|
+
getType(): string;
|
|
127
|
+
|
|
128
|
+
getKey(): NodeKey;
|
|
129
|
+
|
|
130
|
+
getSize(): number;
|
|
131
|
+
|
|
132
|
+
getOffset(): number;
|
|
133
|
+
|
|
134
|
+
syncPropertiesFromLexical(
|
|
135
|
+
binding: Binding,
|
|
136
|
+
nextLexicalNode: DecoratorNode<{...}>,
|
|
137
|
+
prevNodeMap: null | NodeMap,
|
|
138
|
+
): void;
|
|
139
|
+
|
|
140
|
+
syncPropertiesFromYjs(
|
|
141
|
+
binding: Binding,
|
|
142
|
+
keysChanged: null | Set<string>,
|
|
143
|
+
): void;
|
|
144
|
+
|
|
145
|
+
destroy(binding: Binding): void;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
declare export class CollabLineBreakNode {
|
|
149
|
+
_map: YMap;
|
|
150
|
+
_key: NodeKey;
|
|
151
|
+
_parent: CollabElementNode;
|
|
152
|
+
_type: 'linebreak';
|
|
153
|
+
|
|
154
|
+
constructor(map: YMap, parent: CollabElementNode): void;
|
|
155
|
+
|
|
156
|
+
getNode(): null | LineBreakNode;
|
|
157
|
+
|
|
158
|
+
getKey(): NodeKey;
|
|
159
|
+
|
|
160
|
+
getSharedType(): YMap;
|
|
161
|
+
|
|
162
|
+
getType(): string;
|
|
163
|
+
|
|
164
|
+
getSize(): number;
|
|
165
|
+
|
|
166
|
+
getOffset(): number;
|
|
167
|
+
|
|
168
|
+
destroy(binding: Binding): void;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
declare export class CollabTextNode {
|
|
172
|
+
_map: YMap;
|
|
173
|
+
_key: NodeKey;
|
|
174
|
+
_parent: CollabElementNode;
|
|
175
|
+
_text: string;
|
|
176
|
+
_type: string;
|
|
177
|
+
_normalized: boolean;
|
|
178
|
+
|
|
179
|
+
constructor(
|
|
180
|
+
map: YMap,
|
|
181
|
+
text: string,
|
|
182
|
+
parent: CollabElementNode,
|
|
183
|
+
type: string,
|
|
184
|
+
): void;
|
|
185
|
+
|
|
186
|
+
getPrevNode(nodeMap: null | NodeMap): null | TextNode;
|
|
187
|
+
|
|
188
|
+
getNode(): null | TextNode;
|
|
189
|
+
|
|
190
|
+
getSharedType(): YMap;
|
|
191
|
+
|
|
192
|
+
getType(): string;
|
|
193
|
+
|
|
194
|
+
getKey(): NodeKey;
|
|
195
|
+
|
|
196
|
+
getSize(): number;
|
|
197
|
+
|
|
198
|
+
getOffset(): number;
|
|
199
|
+
|
|
200
|
+
spliceText(index: number, delCount: number, newText: string): void;
|
|
201
|
+
|
|
202
|
+
syncPropertiesAndTextFromLexical(
|
|
203
|
+
binding: Binding,
|
|
204
|
+
nextLexicalNode: TextNode,
|
|
205
|
+
prevNodeMap: null | NodeMap,
|
|
206
|
+
): void;
|
|
207
|
+
|
|
208
|
+
syncPropertiesAndTextFromYjs(
|
|
209
|
+
binding: Binding,
|
|
210
|
+
keysChanged: null | Set<string>,
|
|
211
|
+
): void;
|
|
212
|
+
|
|
213
|
+
destroy(binding: Binding): void;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
declare export class CollabElementNode {
|
|
217
|
+
_key: NodeKey;
|
|
218
|
+
_children: Array<
|
|
219
|
+
| CollabElementNode
|
|
220
|
+
| CollabTextNode
|
|
221
|
+
| CollabDecoratorNode
|
|
222
|
+
| CollabLineBreakNode,
|
|
223
|
+
>;
|
|
224
|
+
_xmlText: XmlText;
|
|
225
|
+
_type: string;
|
|
226
|
+
_parent: null | CollabElementNode;
|
|
227
|
+
|
|
228
|
+
constructor(
|
|
229
|
+
xmlText: XmlText,
|
|
230
|
+
parent: null | CollabElementNode,
|
|
231
|
+
type: string,
|
|
232
|
+
): void;
|
|
233
|
+
|
|
234
|
+
getPrevNode(nodeMap: null | NodeMap): null | ElementNode;
|
|
235
|
+
|
|
236
|
+
getNode(): null | ElementNode;
|
|
237
|
+
|
|
238
|
+
getSharedType(): XmlText;
|
|
239
|
+
|
|
240
|
+
getType(): string;
|
|
241
|
+
|
|
242
|
+
getKey(): NodeKey;
|
|
243
|
+
|
|
244
|
+
isEmpty(): boolean;
|
|
245
|
+
|
|
246
|
+
getSize(): number;
|
|
247
|
+
|
|
248
|
+
getOffset(): number;
|
|
249
|
+
|
|
250
|
+
syncPropertiesFromYjs(
|
|
251
|
+
binding: Binding,
|
|
252
|
+
keysChanged: null | Set<string>,
|
|
253
|
+
): void;
|
|
254
|
+
|
|
255
|
+
applyChildrenYjsDelta(binding: Binding, deltas: Array<TextOperation>): void;
|
|
256
|
+
|
|
257
|
+
syncChildrenFromYjs(binding: Binding): void;
|
|
258
|
+
|
|
259
|
+
syncPropertiesFromLexical(
|
|
260
|
+
binding: Binding,
|
|
261
|
+
nextLexicalNode: ElementNode,
|
|
262
|
+
prevNodeMap: null | NodeMap,
|
|
263
|
+
): void;
|
|
264
|
+
|
|
265
|
+
_syncChildFromLexical(
|
|
266
|
+
binding: Binding,
|
|
267
|
+
index: number,
|
|
268
|
+
key: NodeKey,
|
|
269
|
+
prevNodeMap: null | NodeMap,
|
|
270
|
+
dirtyElements: null | Map<NodeKey, IntentionallyMarkedAsDirtyElement>,
|
|
271
|
+
dirtyLeaves: null | Set<NodeKey>,
|
|
272
|
+
): void;
|
|
273
|
+
|
|
274
|
+
syncChildrenFromLexical(
|
|
275
|
+
binding: Binding,
|
|
276
|
+
nextLexicalNode: ElementNode,
|
|
277
|
+
prevNodeMap: null | NodeMap,
|
|
278
|
+
dirtyElements: null | Map<NodeKey, IntentionallyMarkedAsDirtyElement>,
|
|
279
|
+
dirtyLeaves: null | Set<NodeKey>,
|
|
280
|
+
): void;
|
|
281
|
+
|
|
282
|
+
append(
|
|
283
|
+
collabNode:
|
|
284
|
+
| CollabElementNode
|
|
285
|
+
| CollabDecoratorNode
|
|
286
|
+
| CollabTextNode
|
|
287
|
+
| CollabLineBreakNode,
|
|
288
|
+
): void;
|
|
289
|
+
|
|
290
|
+
splice(
|
|
291
|
+
binding: Binding,
|
|
292
|
+
index: number,
|
|
293
|
+
delCount: number,
|
|
294
|
+
collabNode?:
|
|
295
|
+
| CollabElementNode
|
|
296
|
+
| CollabDecoratorNode
|
|
297
|
+
| CollabTextNode
|
|
298
|
+
| CollabLineBreakNode,
|
|
299
|
+
): void;
|
|
300
|
+
|
|
301
|
+
getChildOffset(
|
|
302
|
+
collabNode:
|
|
303
|
+
| CollabElementNode
|
|
304
|
+
| CollabTextNode
|
|
305
|
+
| CollabDecoratorNode
|
|
306
|
+
| CollabLineBreakNode,
|
|
307
|
+
): number;
|
|
308
|
+
|
|
309
|
+
destroy(binding: Binding): void;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
declare export function createUndoManager(
|
|
313
|
+
binding: Binding,
|
|
314
|
+
root: XmlText,
|
|
315
|
+
): UndoManager;
|
|
316
|
+
|
|
317
|
+
declare export function initLocalState(
|
|
318
|
+
provider: Provider,
|
|
319
|
+
name: string,
|
|
320
|
+
color: string,
|
|
321
|
+
focusing: boolean,
|
|
322
|
+
): void;
|
|
323
|
+
|
|
324
|
+
declare export function setLocalStateFocus(
|
|
325
|
+
provider: Provider,
|
|
326
|
+
name: string,
|
|
327
|
+
color: string,
|
|
328
|
+
focusing: boolean,
|
|
329
|
+
): void;
|
|
330
|
+
|
|
331
|
+
declare export function createBinding(
|
|
332
|
+
editor: LexicalEditor,
|
|
333
|
+
provider: Provider,
|
|
334
|
+
id: string,
|
|
335
|
+
doc: ?Doc,
|
|
336
|
+
docMap: Map<string, Doc>,
|
|
337
|
+
): Binding;
|
|
338
|
+
|
|
339
|
+
declare export function syncCursorPositions(
|
|
340
|
+
binding: Binding,
|
|
341
|
+
provider: Provider,
|
|
342
|
+
): void;
|
|
343
|
+
|
|
344
|
+
declare export function syncLexicalUpdateToYjs(
|
|
345
|
+
binding: Binding,
|
|
346
|
+
provider: Provider,
|
|
347
|
+
prevEditorState: EditorState,
|
|
348
|
+
currEditorState: EditorState,
|
|
349
|
+
dirtyElements: Map<NodeKey, IntentionallyMarkedAsDirtyElement>,
|
|
350
|
+
dirtyLeaves: Set<NodeKey>,
|
|
351
|
+
normalizedNodes: Set<NodeKey>,
|
|
352
|
+
tags: Set<string>,
|
|
353
|
+
): void;
|
|
354
|
+
|
|
355
|
+
declare export function syncYjsChangesToLexical(
|
|
356
|
+
binding: Binding,
|
|
357
|
+
provider: Provider,
|
|
358
|
+
events: Array<YjsEvent>,
|
|
359
|
+
): void;
|
|
360
|
+
|
|
361
|
+
declare export var CONNECTED_COMMAND: LexicalCommand<boolean>;
|
|
362
|
+
declare export var TOGGLE_CONNECT_COMMAND: LexicalCommand<boolean>;
|
|
363
|
+
|
|
364
|
+
export type {Provider};
|
package/LexicalYjs.prod.js
CHANGED
|
@@ -4,46 +4,44 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
-
var q=require("lexical"),
|
|
7
|
+
var q=require("lexical"),v=require("yjs"),y=require("@lexical/selection"),A=require("@lexical/offset");class B{constructor(a,b){this._key="";this._map=a;this._parent=b;this._type="linebreak"}getNode(){const a=q.$getNodeByKey(this._key);return q.$isLineBreakNode(a)?a:null}getKey(){return this._key}getSharedType(){return this._map}getType(){return this._type}getSize(){return 1}getOffset(){return this._parent.getChildOffset(this)}destroy(a){a.collabNodeMap.delete(this._key)}}
|
|
8
|
+
function C(a,b){b=new B(a,b);return a._collabNode=b}
|
|
8
9
|
class D{constructor(a,b,c,d){this._key="";this._map=a;this._parent=c;this._text=b;this._type=d;this._normalized=!1}getPrevNode(a){if(null===a)return null;a=a.get(this._key);return q.$isTextNode(a)?a:null}getNode(){const a=q.$getNodeByKey(this._key);return q.$isTextNode(a)?a:null}getSharedType(){return this._map}getType(){return this._type}getKey(){return this._key}getSize(){return this._text.length+(this._normalized?0:1)}getOffset(){return this._parent.getChildOffset(this)}spliceText(a,b,c){const d=
|
|
9
|
-
this._parent._xmlText;a=this.getOffset()+1+a;0!==b&&d.delete(a,b);""!==c&&d.insert(a,c)}syncPropertiesAndTextFromLexical(a,b,c){var d=this.getPrevNode(c);c=b.__text;
|
|
10
|
-
e;a=c.slice(e,f-
|
|
11
|
-
function
|
|
12
|
-
function
|
|
10
|
+
this._parent._xmlText;a=this.getOffset()+1+a;0!==b&&d.delete(a,b);""!==c&&d.insert(a,c)}syncPropertiesAndTextFromLexical(a,b,c){var d=this.getPrevNode(c);c=b.__text;E(a,this._map,d,b);if(null!==d&&(a=d.__text,a!==c)){d=b.__key;b=a;var e=q.$getSelection();a=c.length;q.$isRangeSelection(e)&&e.isCollapsed()&&(e=e.anchor,e.key===d&&(a=e.offset));d=b.length;const f=c.length;let h=e=0;for(;e<d&&e<f&&b[e]===c[e]&&e<a;)e++;for(;h+e<d&&h+e<f&&b[d-h-1]===c[f-h-1];)h++;for(;h+e<d&&h+e<f&&b[e]===c[e];)e++;b=
|
|
11
|
+
e;a=c.slice(e,f-h);d=d-e-h;this.spliceText(b,d,a);this._text=c}}syncPropertiesAndTextFromYjs(a,b){const c=this.getNode();if(null===c)throw Error("Should never happen");F(a,this._map,c,b);a=this._text;c.__text!==a&&(c.getWritable().__text=a)}destroy(a){a.collabNodeMap.delete(this._key)}}function G(a,b,c,d){b=new D(a,b,c,d);return a._collabNode=b}const H=new Set(["__key","__children","__parent","__cachedText","__text"]);
|
|
12
|
+
function I(a){a=q.$getNodeByKey(a);if(null===a)throw Error("Should never happen");return a}
|
|
13
|
+
function J(a,b,c){const d=b.__type;if(q.$isElementNode(b)){var e=new v.XmlText;c=K(e,c,d);c.syncPropertiesFromLexical(a,b,null);c.syncChildrenFromLexical(a,b,null,null,null)}else if(q.$isTextNode(b))e=new v.Map,c=G(e,b.__text,c,d),c.syncPropertiesAndTextFromLexical(a,b,null);else if(q.$isLineBreakNode(b))a=new v.Map,a.set("__type","linebreak"),c=C(a,c);else if(q.$isDecoratorNode(b))e=new v.XmlElement,c=L(e,c,d),c.syncPropertiesFromLexical(a,b,null);else throw Error("Should never happen");c._key=b.__key;
|
|
13
14
|
return c}
|
|
14
|
-
function
|
|
15
|
-
f)}if(b instanceof
|
|
16
|
-
function
|
|
17
|
-
function
|
|
18
|
-
function
|
|
19
|
-
class
|
|
20
|
-
|
|
21
|
-
class
|
|
22
|
-
return a.getChildOffset(this)}syncPropertiesFromYjs(a,b){const c=this.getNode();if(null===c)throw this.getNode(),Error("Should never happen");
|
|
23
|
-
D){e=Math.min(f,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
this._xmlText,this.getPrevNode(c),b)}_syncChildFromLexical(a,b,c,d,e,f){b=this._children[b];c=
|
|
28
|
-
a.collabNodeMap;let l,t
|
|
29
|
-
this._xmlText;var c=this._children;c=c[c.length-1];c=void 0!==c?c.getOffset()+c.getSize():0;if(a instanceof
|
|
30
|
-
if(-1===
|
|
31
|
-
if(e===a)return b;b+=e.getSize()}return-1}destroy(a){const b=a.collabNodeMap,c=this._children;for(let d=0;d<c.length;d++)c[d].destroy(a);b.delete(this._key)}}function
|
|
32
|
-
function
|
|
33
|
-
function
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
n.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
function
|
|
43
|
-
|
|
44
|
-
exports.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
exports.syncYjsChangesToLexical=function(a,b,c){const d=a.editor,e=d._editorState;d.update(()=>{var f=d._pendingEditorState;for(var g=0;g<c.length;g++){var h=a,k=c[g],{target:m}=k;m=Q(h,m);if(m instanceof R&&k instanceof w.YTextEvent){const {keysChanged:l,childListChanged:t,delta:u}=k;0<l.size&&m.syncPropertiesFromYjs(h,l);t&&(m.applyChildrenYjsDelta(h,u),m.syncChildrenFromYjs(h))}else if(m instanceof D&&k instanceof w.YMapEvent)({keysChanged:k}=k),0<k.size&&m.syncPropertiesAndTextFromYjs(h,k);else if(m instanceof
|
|
48
|
-
U&&k instanceof w.YXmlEvent)({attributesChanged:k}=k),0<k.size&&m.syncPropertiesFromYjs(h,k);else throw Error("Should never happen");}g=q.$getSelection();if(q.$isRangeSelection(g))if(T(g)){h=e._selection;if(q.$isRangeSelection(h)){m=z.$createOffsetView(d,0,e);f=z.$createOffsetView(d,0,f);const [l,t]=m.getOffsetsFromSelection(h);f=f.createSelectionFromOffsets(l,t,m);null!==f?q.$setSelection(f):(da(a,b),T(g)&&(f=q.$getRoot(),0===f.getChildrenSize()&&f.append(q.$createParagraphNode()),q.$getRoot().selectEnd()))}ka(a,
|
|
49
|
-
b,h,q.$getSelection())}else da(a,b)},{onUpdate:()=>{ja(a,b)},skipTransforms:!0,tag:"collaboration"})};
|
|
15
|
+
function M(a,b,c){const d=b._collabNode;if(void 0===d){var e=a.editor._nodes;const f=b instanceof v.Map?b.get("__type"):b.getAttribute("__type");if(null==f)throw Error("Should never happen");if(void 0===e.get(f))throw Error("Should never happen");e=b.parent;a=void 0===c&&null!==e?M(a,e):c||null;if(!(a instanceof N))throw Error("Should never happen");if(b instanceof v.XmlText)return K(b,a,f);if(b instanceof v.Map){if(null===a)throw Error("Should never happen");return"linebreak"===f?C(b,a):G(b,"",a,
|
|
16
|
+
f)}if(b instanceof v.XmlElement)return L(b,a,f)}return d}function F(a,b,c,d){d=null===d?b instanceof v.Map?Array.from(b.keys()):Object.keys(b.getAttributes()):Array.from(d);let e;for(let h=0;h<d.length;h++){const g=d[h];if(H.has(g))continue;var f=c[g];let k=b instanceof v.Map?b.get(g):b.getAttribute(g);if(f!==k){if(k instanceof v.Doc){const m=a.docMap;f instanceof v.Doc&&m.delete(f.guid);f=q.createEditor();const l=k.guid;f._key=l;m.set(l,k);k=f}void 0===e&&(e=c.getWritable());e[g]=k}}}
|
|
17
|
+
function E(a,b,c,d){var e=d.__type,f=a.nodeProperties;let h=f.get(e);void 0===h&&(h=Object.keys(d).filter(k=>!H.has(k)),f.set(e,h));e=a.editor.constructor;for(f=0;f<h.length;f++){const k=h[f];var g=null===c?void 0:c[k];let m=d[k];if(g!==m){if(m instanceof e){const l=a.docMap;let r;g instanceof e&&(g=g._key,r=l.get(g),l.delete(g));g=r||new v.Doc;const t=g.guid;m._key=t;l.set(t,g);m=g;a.editor.update(()=>{d.markDirty()})}b instanceof v.Map?b.set(k,m):b.setAttribute(k,m)}}}
|
|
18
|
+
function O(a,b,c){let d=0,e=0;const f=a._children,h=f.length;for(;e<h;e++){a=f[e];const g=d,k=a.getSize();d+=k;if((c?d>=b:d>b)&&a instanceof D)return c=b-g-1,0>c&&(c=0),{length:d-b,node:a,nodeIndex:e,offset:c};if(d>b)return{length:0,node:a,nodeIndex:e,offset:g};if(e===h-1)return{length:0,node:null,nodeIndex:e+1,offset:g+1}}return{length:0,node:null,nodeIndex:0,offset:0}}
|
|
19
|
+
function P(a){const b=a.anchor;a=a.focus;let c=!1;try{const d=b.getNode(),e=a.getNode();if(!d.isAttached()||!e.isAttached()||q.$isTextNode(d)&&b.offset>d.getTextContentSize()||q.$isTextNode(e)&&a.offset>e.getTextContentSize())c=!0}catch(d){c=!0}return c}function ea(a,b){a.doc.transact(b,a)}
|
|
20
|
+
class Q{constructor(a,b,c){this._key="";this._xmlElem=a;this._parent=b;this._type=c;this._unobservers=new Set}getPrevNode(a){if(null===a)return null;a=a.get(this._key);return q.$isDecoratorNode(a)?a:null}getNode(){const a=q.$getNodeByKey(this._key);return q.$isDecoratorNode(a)?a:null}getSharedType(){return this._xmlElem}getType(){return this._type}getKey(){return this._key}getSize(){return 1}getOffset(){return this._parent.getChildOffset(this)}syncPropertiesFromLexical(a,b,c){c=this.getPrevNode(c);
|
|
21
|
+
E(a,this._xmlElem,c,b)}syncPropertiesFromYjs(a,b){const c=this.getNode();if(null===c)throw Error("Should never happen");F(a,this._xmlElem,c,b)}destroy(a){a.collabNodeMap.delete(this._key);this._unobservers.forEach(b=>b());this._unobservers.clear()}}function L(a,b,c){b=new Q(a,b,c);return a._collabNode=b}
|
|
22
|
+
class N{constructor(a,b,c){this._key="";this._children=[];this._xmlText=a;this._type=c;this._parent=b}getPrevNode(a){if(null===a)return null;a=a.get(this._key);return q.$isElementNode(a)?a:null}getNode(){const a=q.$getNodeByKey(this._key);return q.$isElementNode(a)?a:null}getSharedType(){return this._xmlText}getType(){return this._type}getKey(){return this._key}isEmpty(){return 0===this._children.length}getSize(){return 1}getOffset(){const a=this._parent;if(null===a)throw Error("Should never happen");
|
|
23
|
+
return a.getChildOffset(this)}syncPropertiesFromYjs(a,b){const c=this.getNode();if(null===c)throw this.getNode(),Error("Should never happen");F(a,this._xmlText,c,b)}applyChildrenYjsDelta(a,b){const c=this._children;let d=0;for(let m=0;m<b.length;m++){var e=b[m],f=e.insert,h=e.delete;if(null!=e.retain)d+=e.retain;else if("number"===typeof h)for(f=h;0<f;){const {node:l,nodeIndex:r,offset:t,length:n}=O(this,d,!1);if(l instanceof N||l instanceof B||l instanceof Q)c.splice(r,1),--f;else if(l instanceof
|
|
24
|
+
D){e=Math.min(f,n);h=0!==r?c[r-1]:null;var g=l.getSize();if(0===t&&1===e&&0<r&&h instanceof D&&n===g&&0===Array.from(l._map.keys()).length)h._text+=l._text,c.splice(r,1);else if(0===t&&e===g)c.splice(r,1);else{h=l._text;g=t;var k=e;h=h.slice(0,g)+""+h.slice(g+k);l._text=h}f-=e}else break}else if(null!=f)if("string"===typeof f){const {node:l,offset:r}=O(this,d,!0);l instanceof D?(e=l._text,h=r,g=f,e=e.slice(0,h)+g+e.slice(h+0),l._text=e):this._xmlText.delete(r,f.length);d+=f.length}else e=f,{nodeIndex:f}=
|
|
25
|
+
O(this,d,!1),e=M(a,e,this),c.splice(f,0,e),d+=1;else throw Error("Unexpected delta format");}}syncChildrenFromYjs(a){var b=this.getNode();if(null===b)throw this.getNode(),Error("Should never happen");var c=b.__key;const d=b.__children;var e=[];const f=d.length,h=this._children,g=h.length,k=a.collabNodeMap,m=new Set;let l,r;g!==f&&(r=R(b,r,e));let t=0;for(let z=0;z<g;z++){var n=d[t];const x=h[z];var p=x.getNode(),u=x._key;if(null!==p&&n===u){p=q.$isTextNode(p);m.add(n);if(p)if(x._key=n,x instanceof
|
|
26
|
+
N)p=x._xmlText,x.syncPropertiesFromYjs(a,null),x.applyChildrenYjsDelta(a,p.toDelta()),x.syncChildrenFromYjs(a);else if(x instanceof D)x.syncPropertiesAndTextFromYjs(a,null);else if(x instanceof Q)x.syncPropertiesFromYjs(a,null);else if(!(x instanceof B))throw Error("Should never happen");e[z]=n;t++}else{if(void 0===l)for(l=new Set,u=0;u<g;u++){var w=h[u]._key;""!==w&&l.add(w)}if(null===p||void 0===n||l.has(n)){r=R(b,r,e);n=a;p=x;u=c;w=p.getType();w=n.editor._nodes.get(w);if(void 0===w)throw Error("createLexicalNode failed");
|
|
27
|
+
w=new w.klass;w.__parent=u;p._key=w.__key;p instanceof N?(u=p._xmlText,p.syncPropertiesFromYjs(n,null),p.applyChildrenYjsDelta(n,u.toDelta()),p.syncChildrenFromYjs(n)):p instanceof D?p.syncPropertiesAndTextFromYjs(n,null):p instanceof Q&&p.syncPropertiesFromYjs(n,null);n.collabNodeMap.set(w.__key,p);n=w.__key;k.set(n,x);e[z]=n}else z--,t++}}for(b=0;b<f;b++)e=d[b],m.has(e)||(c=I(e).getWritable(),e=a.collabNodeMap.get(e),void 0!==e&&e.destroy(a),c.__parent=null)}syncPropertiesFromLexical(a,b,c){E(a,
|
|
28
|
+
this._xmlText,this.getPrevNode(c),b)}_syncChildFromLexical(a,b,c,d,e,f){b=this._children[b];c=I(c);b instanceof N&&q.$isElementNode(c)?(b.syncPropertiesFromLexical(a,c,d),b.syncChildrenFromLexical(a,c,d,e,f)):b instanceof D&&q.$isTextNode(c)?b.syncPropertiesAndTextFromLexical(a,c,d):b instanceof Q&&q.$isDecoratorNode(c)&&b.syncPropertiesFromLexical(a,c,d)}syncChildrenFromLexical(a,b,c,d,e){var f=this.getPrevNode(c);const h=null===f?[]:f.__children;f=b.__children;const g=h.length-1,k=f.length-1,m=
|
|
29
|
+
a.collabNodeMap;let l,r,t=0;for(b=0;t<=g&&b<=k;){var n=h[t];const u=f[b];if(n===u)this._syncChildFromLexical(a,b,u,c,d,e),t++,b++;else{void 0===l&&(l=new Set(h));void 0===r&&(r=new Set(f));var p=r.has(n);n=l.has(u);p?(p=I(u),p=J(a,p,this),m.set(u,p),n?(this.splice(a,b,1,p),t++):this.splice(a,b,0,p),b++):(this.splice(a,b,1),t++)}}c=t>g;d=b>k;if(c&&!d)for(;b<=k;++b)c=f[b],d=I(c),d=J(a,d,this),this.append(d),m.set(c,d);else if(d&&!c)for(f=this._children.length-1;f>=b;f--)this.splice(a,f,1)}append(a){const b=
|
|
30
|
+
this._xmlText;var c=this._children;c=c[c.length-1];c=void 0!==c?c.getOffset()+c.getSize():0;if(a instanceof N)b.insertEmbed(c,a._xmlText);else if(a instanceof D){const d=a._map;null===d.parent&&b.insertEmbed(c,d);b.insert(c+1,a._text)}else a instanceof B?b.insertEmbed(c,a._map):a instanceof Q&&b.insertEmbed(c,a._xmlElem);this._children.push(a)}splice(a,b,c,d){const e=this._children;var f=e[b];if(void 0===f)if(void 0!==d)this.append(d);else throw Error("Should never happen");else{var h=f.getOffset();
|
|
31
|
+
if(-1===h)throw Error("Should never happen");var g=this._xmlText;0!==c&&g.delete(h,f.getSize());d instanceof N?g.insertEmbed(h,d._xmlText):d instanceof D?(f=d._map,null===f.parent&&g.insertEmbed(h,f),g.insert(h+1,d._text)):d instanceof B?g.insertEmbed(h,d._map):d instanceof Q&&g.insertEmbed(h,d._xmlElem);if(0!==c)for(h=e.slice(b,b+c),g=0;g<h.length;g++)h[g].destroy(a);void 0!==d?e.splice(b,c,d):e.splice(b,c)}}getChildOffset(a){let b=0;const c=this._children;for(let d=0;d<c.length;d++){const e=c[d];
|
|
32
|
+
if(e===a)return b;b+=e.getSize()}return-1}destroy(a){const b=a.collabNodeMap,c=this._children;for(let d=0;d<c.length;d++)c[d].destroy(a);b.delete(this._key)}}function R(a,b,c){return void 0===b?(a=a.getWritable(),a.__children=c,a):b}function K(a,b,c){b=new N(a,b,c);return a._collabNode=b}
|
|
33
|
+
function S(a,b){b=b.collabNodeMap.get(a.key);if(void 0===b)return null;a=a.offset;let c=b.getSharedType();if(b instanceof D){c=b._parent._xmlText;b=b.getOffset();if(-1===b)return null;a=b+1+a}return v.createRelativePositionFromTypeIndex(c,a)}function T(a,b){if(null==a){if(null!=b)return!0}else if(null==b||!v.compareRelativePositions(a,b))return!0;return!1}function U(a,b){a=a.cursorsContainer;if(null!==a){b=b.selections;const c=b.length;for(let d=0;d<c;d++)a.removeChild(b[d])}}
|
|
34
|
+
function V(a,b){var c=b.awareness.getLocalState();if(null!==c&&(b=c.anchorPos,c=c.focusPos,null!==b&&null!==c&&(b=v.createAbsolutePositionFromRelativePosition(b,a.doc),a=v.createAbsolutePositionFromRelativePosition(c,a.doc),null!==b&&null!==a))){const [e,f]=W(b.type,b.index),[h,g]=W(a.type,a.index);if(null!==e&&null!==h){const k=e.getKey();a=h.getKey();b=q.$getSelection();if(q.$isRangeSelection(b)){var d=b.anchor;c=b.focus;if(d.key!==k||d.offset!==f)d=q.$getNodeByKey(k),b.anchor.set(k,f,q.$isElementNode(d)?
|
|
35
|
+
"element":"text");if(c.key!==a||c.offset!==g)c=q.$getNodeByKey(a),b.focus.set(a,g,q.$isElementNode(c)?"element":"text")}}}}function W(a,b){a=a._collabNode;if(void 0===a)return[null,0];if(a instanceof N){const {node:c,offset:d}=O(a,b,!0);return null===c?[a,0]:[c,d]}return[null,0]}
|
|
36
|
+
function X(a,b){var c=Array.from(b.awareness.getStates()),d=a.clientID;b=a.cursors;var e=a.editor._editorState._nodeMap;const f=new Set;for(var h=0;h<c.length;h++){const [z,x]=c[h];if(z!==d){f.add(z);const {anchorPos:Y,focusPos:Z,name:ha,color:ia,focusing:ja}=x;var g=null,k=b.get(z);void 0===k&&(k={color:ia,name:ha,selection:null},b.set(z,k));if(null!==Y&&null!==Z&&ja){var m=v.createAbsolutePositionFromRelativePosition(Y,a.doc),l=v.createAbsolutePositionFromRelativePosition(Z,a.doc);if(null!==m&&
|
|
37
|
+
null!==l){const [aa,ba]=W(m.type,m.index),[ca,da]=W(l.type,l.index);if(null!==aa&&null!==ca){l=aa.getKey();var r=ca.getKey();g=k.selection;if(null===g){m=k;g=l;l=ba;var t=da,n=m.color,p=document.createElement("span");p.style.cssText=`position:absolute;top:0;bottom:0;right:-1px;width:1px;background-color:rgb(${n});z-index:10;`;var u=document.createElement("span");u.textContent=m.name;u.style.cssText=`position:absolute;left:-2px;top:-16px;background-color:rgb(${n});color:#fff;line-height:12px;height:12px;font-size:12px;padding:2px;font-family:Arial;font-weight:bold;white-space:nowrap;`;
|
|
38
|
+
p.appendChild(u);g={anchor:{key:g,offset:l},caret:p,color:n,focus:{key:r,offset:t},name:u,selections:[]}}else m=g.anchor,t=g.focus,m.key=l,m.offset=ba,t.key=r,t.offset=da}}}m=a;l=k;n=g;t=e;r=m.editor;g=r.getRootElement();k=m.cursorsContainer;if(null!==k&&null!==g)if(g=l.selection,null===n)null!==g&&(l.selection=null,U(m,g));else{l.selection=n;g=n.caret;l=n.color;m=n.selections;p=n.anchor;n=n.focus;var w=n.key;u=t.get(p.key);t=t.get(w);if(null!=u&&null!=t&&(n=y.createDOMRange(r,u,p.offset,t,n.offset),
|
|
39
|
+
null!==n)){t=m.length;n=y.createRectsFromDOMRange(r,n);r=n.length;for(p=0;p<r;p++)u=n[p],w=m[p],void 0===w&&(w=document.createElement("span"),m[p]=w,k.appendChild(w)),w.style.cssText=`position:absolute;top:${u.top}px;left:${u.left}px;height:${u.height}px;width:${u.width}px;background-color:rgba(${l}, 0.3);pointer-events:none;z-index:5;`,p===r-1&&g.parentNode!==w&&w.appendChild(g);for(g=t-1;g>=r;g--)k.removeChild(m[g]),m.pop()}}}}c=Array.from(b.keys());for(d=0;d<c.length;d++)e=c[d],f.has(e)||(h=b.get(e),
|
|
40
|
+
void 0!==h&&(h=h.selection,null!==h&&U(a,h),b.delete(e)))}function fa(a,b,c,d){b=b.awareness;var e=b.getLocalState();if(null!==e){var {anchorPos:f,focusPos:h,name:g,color:k,focusing:m}=e,l=e=null;if(null!==d&&(null===f||d.is(c))||null!==c)q.$isRangeSelection(d)&&(e=S(d.anchor,a),l=S(d.focus,a)),(T(f,e)||T(h,l))&&b.setLocalState({anchorPos:e,color:k,focusPos:l,focusing:m,name:g})}}const ka=q.createCommand(),la=q.createCommand();exports.CONNECTED_COMMAND=ka;exports.TOGGLE_CONNECT_COMMAND=la;
|
|
41
|
+
exports.createBinding=function(a,b,c,d,e){if(void 0===d||null===d)throw Error("Should never happen");b=d.get("root",v.XmlText);b=K(b,null,"root");b._key="root";return{clientID:d.clientID,collabNodeMap:new Map,cursors:new Map,cursorsContainer:null,doc:d,docMap:e,editor:a,id:c,nodeProperties:new Map,root:b}};exports.createUndoManager=function(a,b){return new v.UndoManager(b,{trackedOrigins:new Set([a,null])})};
|
|
42
|
+
exports.initLocalState=function(a,b,c,d){a.awareness.setLocalState({anchorPos:null,color:c,focusPos:null,focusing:d,name:b})};exports.setLocalStateFocus=function(a,b,c,d){({awareness:a}=a);let e=a.getLocalState();null===e&&(e={anchorPos:null,color:c,focusPos:null,focusing:d,name:b});e.focusing=d;a.setLocalState(e)};exports.syncCursorPositions=X;
|
|
43
|
+
exports.syncLexicalUpdateToYjs=function(a,b,c,d,e,f,h,g){ea(a,()=>{d.read(()=>{if(g.has("collaboration")){if(0<h.size){var k=Array.from(h),m=a.collabNodeMap,l=[];for(let p=0;p<k.length;p++){var r=k[p],t=q.$getNodeByKey(r),n=m.get(r);if(n instanceof D)if(q.$isTextNode(t))l.push([n,t.__text]);else{t=n.getOffset();if(-1===t)continue;const u=n._parent;n._normalized=!0;u._xmlText.delete(t,1);m.delete(r);r=u._children;n=r.indexOf(n);r.splice(n,1)}}for(k=0;k<l.length;k++){const [p,u]=l[k];p._text=u}}}else e.has("root")&&
|
|
44
|
+
(l=c._nodeMap,k=q.$getRoot(),m=a.root,m.syncPropertiesFromLexical(a,k,l),m.syncChildrenFromLexical(a,k,l,e,f)),l=q.$getSelection(),fa(a,b,c._selection,l)})})};
|
|
45
|
+
exports.syncYjsChangesToLexical=function(a,b,c){const d=a.editor,e=d._editorState;d.update(()=>{var f=d._pendingEditorState;for(var h=0;h<c.length;h++){var g=a,k=c[h],{target:m}=k;m=M(g,m);if(m instanceof N&&k instanceof v.YTextEvent){const {keysChanged:l,childListChanged:r,delta:t}=k;0<l.size&&m.syncPropertiesFromYjs(g,l);r&&(m.applyChildrenYjsDelta(g,t),m.syncChildrenFromYjs(g))}else if(m instanceof D&&k instanceof v.YMapEvent)({keysChanged:k}=k),0<k.size&&m.syncPropertiesAndTextFromYjs(g,k);else if(m instanceof
|
|
46
|
+
Q&&k instanceof v.YXmlEvent)({attributesChanged:k}=k),0<k.size&&m.syncPropertiesFromYjs(g,k);else throw Error("Should never happen");}h=q.$getSelection();if(q.$isRangeSelection(h))if(P(h)){g=e._selection;if(q.$isRangeSelection(g)){m=A.$createOffsetView(d,0,e);f=A.$createOffsetView(d,0,f);const [l,r]=m.getOffsetsFromSelection(g);f=f.createSelectionFromOffsets(l,r,m);null!==f?q.$setSelection(f):(V(a,b),P(h)&&(f=q.$getRoot(),0===f.getChildrenSize()&&f.append(q.$createParagraphNode()),q.$getRoot().selectEnd()))}fa(a,
|
|
47
|
+
b,g,q.$getSelection())}else V(a,b)},{onUpdate:()=>{X(a,b)},skipTransforms:!0,tag:"collaboration"})};
|
package/package.json
CHANGED
|
@@ -11,13 +11,13 @@
|
|
|
11
11
|
"crdt"
|
|
12
12
|
],
|
|
13
13
|
"license": "MIT",
|
|
14
|
-
"version": "0.2.
|
|
14
|
+
"version": "0.2.7",
|
|
15
15
|
"main": "LexicalYjs.js",
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@lexical/offset": "0.2.
|
|
17
|
+
"@lexical/offset": "0.2.7"
|
|
18
18
|
},
|
|
19
19
|
"peerDependencies": {
|
|
20
|
-
"lexical": "0.2.
|
|
20
|
+
"lexical": "0.2.7",
|
|
21
21
|
"yjs": ">=13.5.22"
|
|
22
22
|
},
|
|
23
23
|
"repository": {
|