@lexical/yjs 0.7.7 → 0.7.9

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.
Files changed (2) hide show
  1. package/LexicalYjs.dev.js +50 -326
  2. package/package.json +3 -3
package/LexicalYjs.dev.js CHANGED
@@ -25,42 +25,34 @@ class CollabLineBreakNode {
25
25
  this._parent = parent;
26
26
  this._type = 'linebreak';
27
27
  }
28
-
29
28
  getNode() {
30
29
  const node = lexical.$getNodeByKey(this._key);
31
30
  return lexical.$isLineBreakNode(node) ? node : null;
32
31
  }
33
-
34
32
  getKey() {
35
33
  return this._key;
36
34
  }
37
-
38
35
  getSharedType() {
39
36
  return this._map;
40
37
  }
41
-
42
38
  getType() {
43
39
  return this._type;
44
40
  }
45
-
46
41
  getSize() {
47
42
  return 1;
48
43
  }
49
-
50
44
  getOffset() {
51
45
  const collabElementNode = this._parent;
52
46
  return collabElementNode.getChildOffset(this);
53
47
  }
54
-
55
48
  destroy(binding) {
56
49
  const collabNodeMap = binding.collabNodeMap;
57
50
  collabNodeMap.delete(this._key);
58
51
  }
59
-
60
52
  }
61
53
  function $createCollabLineBreakNode(map, parent) {
62
- const collabNode = new CollabLineBreakNode(map, parent); // @ts-expect-error: internal field
63
-
54
+ const collabNode = new CollabLineBreakNode(map, parent);
55
+ // @ts-expect-error: internal field
64
56
  map._collabNode = collabNode;
65
57
  return collabNode;
66
58
  }
@@ -72,29 +64,25 @@ function $createCollabLineBreakNode(map, parent) {
72
64
  * LICENSE file in the root directory of this source tree.
73
65
  *
74
66
  */
67
+
75
68
  function simpleDiffWithCursor(a, b, cursor) {
76
69
  const aLength = a.length;
77
70
  const bLength = b.length;
78
71
  let left = 0; // number of same characters counting from left
79
-
80
72
  let right = 0; // number of same characters counting from right
81
73
  // Iterate left to the right until we find a changed character
82
74
  // First iteration considers the current cursor position
83
-
84
75
  while (left < aLength && left < bLength && a[left] === b[left] && left < cursor) {
85
76
  left++;
86
- } // Iterate right to the left until we find a changed character
87
-
88
-
77
+ }
78
+ // Iterate right to the left until we find a changed character
89
79
  while (right + left < aLength && right + left < bLength && a[aLength - right - 1] === b[bLength - right - 1]) {
90
80
  right++;
91
- } // Try to iterate left further to the right without caring about the current cursor position
92
-
93
-
81
+ }
82
+ // Try to iterate left further to the right without caring about the current cursor position
94
83
  while (right + left < aLength && right + left < bLength && a[left] === b[left]) {
95
84
  left++;
96
85
  }
97
-
98
86
  return {
99
87
  index: left,
100
88
  insert: b.slice(left, bLength - right),
@@ -109,23 +97,18 @@ function simpleDiffWithCursor(a, b, cursor) {
109
97
  * LICENSE file in the root directory of this source tree.
110
98
  *
111
99
  */
112
-
113
100
  function diffTextContentAndApplyDelta(collabNode, key, prevText, nextText) {
114
101
  const selection = lexical.$getSelection();
115
102
  let cursorOffset = nextText.length;
116
-
117
103
  if (lexical.$isRangeSelection(selection) && selection.isCollapsed()) {
118
104
  const anchor = selection.anchor;
119
-
120
105
  if (anchor.key === key) {
121
106
  cursorOffset = anchor.offset;
122
107
  }
123
108
  }
124
-
125
109
  const diff = simpleDiffWithCursor(prevText, nextText, cursorOffset);
126
110
  collabNode.spliceText(diff.index, diff.remove, diff.insert);
127
111
  }
128
-
129
112
  class CollabTextNode {
130
113
  constructor(map, text, parent, type) {
131
114
  this._key = '';
@@ -135,64 +118,50 @@ class CollabTextNode {
135
118
  this._type = type;
136
119
  this._normalized = false;
137
120
  }
138
-
139
121
  getPrevNode(nodeMap) {
140
122
  if (nodeMap === null) {
141
123
  return null;
142
124
  }
143
-
144
125
  const node = nodeMap.get(this._key);
145
126
  return lexical.$isTextNode(node) ? node : null;
146
127
  }
147
-
148
128
  getNode() {
149
129
  const node = lexical.$getNodeByKey(this._key);
150
130
  return lexical.$isTextNode(node) ? node : null;
151
131
  }
152
-
153
132
  getSharedType() {
154
133
  return this._map;
155
134
  }
156
-
157
135
  getType() {
158
136
  return this._type;
159
137
  }
160
-
161
138
  getKey() {
162
139
  return this._key;
163
140
  }
164
-
165
141
  getSize() {
166
142
  return this._text.length + (this._normalized ? 0 : 1);
167
143
  }
168
-
169
144
  getOffset() {
170
145
  const collabElementNode = this._parent;
171
146
  return collabElementNode.getChildOffset(this);
172
147
  }
173
-
174
148
  spliceText(index, delCount, newText) {
175
149
  const collabElementNode = this._parent;
176
150
  const xmlText = collabElementNode._xmlText;
177
151
  const offset = this.getOffset() + 1 + index;
178
-
179
152
  if (delCount !== 0) {
180
153
  xmlText.delete(offset, delCount);
181
154
  }
182
-
183
155
  if (newText !== '') {
184
156
  xmlText.insert(offset, newText);
185
157
  }
186
158
  }
187
-
188
159
  syncPropertiesAndTextFromLexical(binding, nextLexicalNode, prevNodeMap) {
189
160
  const prevLexicalNode = this.getPrevNode(prevNodeMap);
190
161
  const nextText = nextLexicalNode.__text;
191
162
  syncPropertiesFromLexical(binding, this._map, prevLexicalNode, nextLexicalNode);
192
-
193
163
  if (prevLexicalNode !== null) {
194
164
  const prevText = prevLexicalNode.__text;
195
-
196
165
  if (prevText !== nextText) {
197
166
  const key = nextLexicalNode.__key;
198
167
  diffTextContentAndApplyDelta(this, key, prevText, nextText);
@@ -200,32 +169,26 @@ class CollabTextNode {
200
169
  }
201
170
  }
202
171
  }
203
-
204
172
  syncPropertiesAndTextFromYjs(binding, keysChanged) {
205
173
  const lexicalNode = this.getNode();
206
-
207
174
  if (!(lexicalNode !== null)) {
208
175
  throw Error(`syncPropertiesAndTextFromYjs: cound not find decorator node`);
209
176
  }
210
-
211
177
  syncPropertiesFromYjs(binding, this._map, lexicalNode, keysChanged);
212
178
  const collabText = this._text;
213
-
214
179
  if (lexicalNode.__text !== collabText) {
215
180
  const writable = lexicalNode.getWritable();
216
181
  writable.__text = collabText;
217
182
  }
218
183
  }
219
-
220
184
  destroy(binding) {
221
185
  const collabNodeMap = binding.collabNodeMap;
222
186
  collabNodeMap.delete(this._key);
223
187
  }
224
-
225
188
  }
226
189
  function $createCollabTextNode(map, text, parent, type) {
227
- const collabNode = new CollabTextNode(map, text, parent, type); // @ts-expect-error: internal field
228
-
190
+ const collabNode = new CollabTextNode(map, text, parent, type);
191
+ // @ts-expect-error: internal field
229
192
  map._collabNode = collabNode;
230
193
  return collabNode;
231
194
  }
@@ -240,17 +203,14 @@ function $createCollabTextNode(map, text, parent, type) {
240
203
  const excludedProperties = new Set(['__key', '__parent', '__cachedText', '__text', '__size', '__next', '__prev', '__first', '__last']);
241
204
  function $getNodeByKeyOrThrow(key) {
242
205
  const node = lexical.$getNodeByKey(key);
243
-
244
206
  if (!(node !== null)) {
245
207
  throw Error(`could not find node by key`);
246
208
  }
247
-
248
209
  return node;
249
210
  }
250
211
  function $createCollabNodeFromLexicalNode(binding, lexicalNode, parent) {
251
212
  const nodeType = lexicalNode.__type;
252
213
  let collabNode;
253
-
254
214
  if (lexical.$isElementNode(lexicalNode)) {
255
215
  const xmlText = new yjs.XmlText();
256
216
  collabNode = $createCollabElementNode(xmlText, parent, nodeType);
@@ -274,69 +234,54 @@ function $createCollabNodeFromLexicalNode(binding, lexicalNode, parent) {
274
234
  throw Error(`Expected text, element, decorator, or linebreak node`);
275
235
  }
276
236
  }
277
-
278
237
  collabNode._key = lexicalNode.__key;
279
238
  return collabNode;
280
239
  }
281
-
282
240
  function getNodeTypeFromSharedType(sharedType) {
283
241
  const type = sharedType instanceof yjs.Map ? sharedType.get('__type') : sharedType.getAttribute('__type');
284
-
285
242
  if (!(type != null)) {
286
243
  throw Error(`Expected shared type to include type attribute`);
287
244
  }
288
-
289
245
  return type;
290
246
  }
291
-
292
247
  function getOrInitCollabNodeFromSharedType(binding, sharedType, parent) {
293
248
  // @ts-expect-error: internal field
294
249
  const collabNode = sharedType._collabNode;
295
-
296
250
  if (collabNode === undefined) {
297
251
  const registeredNodes = binding.editor._nodes;
298
252
  const type = getNodeTypeFromSharedType(sharedType);
299
253
  const nodeInfo = registeredNodes.get(type);
300
-
301
254
  if (!(nodeInfo !== undefined)) {
302
255
  throw Error(`Node ${type} is not registered`);
303
256
  }
304
-
305
257
  const sharedParent = sharedType.parent;
306
258
  const targetParent = parent === undefined && sharedParent !== null ? getOrInitCollabNodeFromSharedType(binding, sharedParent) : parent || null;
307
-
308
259
  if (!(targetParent instanceof CollabElementNode)) {
309
260
  throw Error(`Expected parent to be a collab element node`);
310
261
  }
311
-
312
262
  if (sharedType instanceof yjs.XmlText) {
313
263
  return $createCollabElementNode(sharedType, targetParent, type);
314
264
  } else if (sharedType instanceof yjs.Map) {
315
265
  if (type === 'linebreak') {
316
266
  return $createCollabLineBreakNode(sharedType, targetParent);
317
267
  }
318
-
319
268
  return $createCollabTextNode(sharedType, '', targetParent, type);
320
269
  } else if (sharedType instanceof yjs.XmlElement) {
321
270
  return $createCollabDecoratorNode(sharedType, targetParent, type);
322
271
  }
323
272
  }
324
-
325
273
  return collabNode;
326
274
  }
327
275
  function createLexicalNodeFromCollabNode(binding, collabNode, parentKey) {
328
276
  const type = collabNode.getType();
329
277
  const registeredNodes = binding.editor._nodes;
330
278
  const nodeInfo = registeredNodes.get(type);
331
-
332
279
  if (!(nodeInfo !== undefined)) {
333
280
  throw Error(`Node ${type} is not registered`);
334
281
  }
335
-
336
282
  const lexicalNode = new nodeInfo.klass();
337
283
  lexicalNode.__parent = parentKey;
338
284
  collabNode._key = lexicalNode.__key;
339
-
340
285
  if (collabNode instanceof CollabElementNode) {
341
286
  const xmlText = collabNode._xmlText;
342
287
  collabNode.syncPropertiesFromYjs(binding, null);
@@ -347,43 +292,34 @@ function createLexicalNodeFromCollabNode(binding, collabNode, parentKey) {
347
292
  } else if (collabNode instanceof CollabDecoratorNode) {
348
293
  collabNode.syncPropertiesFromYjs(binding, null);
349
294
  }
350
-
351
295
  binding.collabNodeMap.set(lexicalNode.__key, collabNode);
352
296
  return lexicalNode;
353
297
  }
354
298
  function syncPropertiesFromYjs(binding, sharedType, lexicalNode, keysChanged) {
355
299
  const properties = keysChanged === null ? sharedType instanceof yjs.Map ? Array.from(sharedType.keys()) : Object.keys(sharedType.getAttributes()) : Array.from(keysChanged);
356
300
  let writableNode;
357
-
358
301
  for (let i = 0; i < properties.length; i++) {
359
302
  const property = properties[i];
360
-
361
303
  if (excludedProperties.has(property)) {
362
304
  continue;
363
305
  }
364
-
365
306
  const prevValue = lexicalNode[property];
366
307
  let nextValue = sharedType instanceof yjs.Map ? sharedType.get(property) : sharedType.getAttribute(property);
367
-
368
308
  if (prevValue !== nextValue) {
369
309
  if (nextValue instanceof yjs.Doc) {
370
310
  const yjsDocMap = binding.docMap;
371
-
372
311
  if (prevValue instanceof yjs.Doc) {
373
312
  yjsDocMap.delete(prevValue.guid);
374
313
  }
375
-
376
314
  const nestedEditor = lexical.createEditor();
377
315
  const key = nextValue.guid;
378
316
  nestedEditor._key = key;
379
317
  yjsDocMap.set(key, nextValue);
380
318
  nextValue = nestedEditor;
381
319
  }
382
-
383
320
  if (writableNode === undefined) {
384
321
  writableNode = lexicalNode.getWritable();
385
322
  }
386
-
387
323
  writableNode[property] = nextValue;
388
324
  }
389
325
  }
@@ -392,46 +328,40 @@ function syncPropertiesFromLexical(binding, sharedType, prevLexicalNode, nextLex
392
328
  const type = nextLexicalNode.__type;
393
329
  const nodeProperties = binding.nodeProperties;
394
330
  let properties = nodeProperties.get(type);
395
-
396
331
  if (properties === undefined) {
397
332
  properties = Object.keys(nextLexicalNode).filter(property => {
398
333
  return !excludedProperties.has(property);
399
334
  });
400
335
  nodeProperties.set(type, properties);
401
336
  }
402
-
403
337
  const EditorClass = binding.editor.constructor;
404
-
405
338
  for (let i = 0; i < properties.length; i++) {
406
339
  const property = properties[i];
407
340
  const prevValue = prevLexicalNode === null ? undefined : prevLexicalNode[property];
408
341
  let nextValue = nextLexicalNode[property];
409
-
410
342
  if (prevValue !== nextValue) {
411
343
  if (nextValue instanceof EditorClass) {
412
344
  const yjsDocMap = binding.docMap;
413
345
  let prevDoc;
414
-
415
346
  if (prevValue instanceof EditorClass) {
416
347
  // @ts-expect-error Lexical node
417
348
  const prevKey = prevValue._key;
418
349
  prevDoc = yjsDocMap.get(prevKey);
419
350
  yjsDocMap.delete(prevKey);
420
- } // If we already have a document, use it.
421
-
351
+ }
422
352
 
353
+ // If we already have a document, use it.
423
354
  const doc = prevDoc || new yjs.Doc();
424
- const key = doc.guid; // @ts-expect-error Lexical node
425
-
355
+ const key = doc.guid;
356
+ // @ts-expect-error Lexical node
426
357
  nextValue._key = key;
427
358
  yjsDocMap.set(key, doc);
428
- nextValue = doc; // Mark the node dirty as we've assigned a new key to it
429
-
359
+ nextValue = doc;
360
+ // Mark the node dirty as we've assigned a new key to it
430
361
  binding.editor.update(() => {
431
362
  nextLexicalNode.markDirty();
432
363
  });
433
364
  }
434
-
435
365
  if (sharedType instanceof yjs.Map) {
436
366
  sharedType.set(property, nextValue);
437
367
  } else {
@@ -448,21 +378,17 @@ function getPositionFromElementAndOffset(node, offset, boundaryIsEdge) {
448
378
  let i = 0;
449
379
  const children = node._children;
450
380
  const childrenLength = children.length;
451
-
452
381
  for (; i < childrenLength; i++) {
453
382
  const child = children[i];
454
383
  const childOffset = index;
455
384
  const size = child.getSize();
456
385
  index += size;
457
386
  const exceedsBoundary = boundaryIsEdge ? index >= offset : index > offset;
458
-
459
387
  if (exceedsBoundary && child instanceof CollabTextNode) {
460
388
  let textOffset = offset - childOffset - 1;
461
-
462
389
  if (textOffset < 0) {
463
390
  textOffset = 0;
464
391
  }
465
-
466
392
  const diffLength = index - offset;
467
393
  return {
468
394
  length: diffLength,
@@ -471,7 +397,6 @@ function getPositionFromElementAndOffset(node, offset, boundaryIsEdge) {
471
397
  offset: textOffset
472
398
  };
473
399
  }
474
-
475
400
  if (index > offset) {
476
401
  return {
477
402
  length: 0,
@@ -488,7 +413,6 @@ function getPositionFromElementAndOffset(node, offset, boundaryIsEdge) {
488
413
  };
489
414
  }
490
415
  }
491
-
492
416
  return {
493
417
  length: 0,
494
418
  node: null,
@@ -500,13 +424,13 @@ function doesSelectionNeedRecovering(selection) {
500
424
  const anchor = selection.anchor;
501
425
  const focus = selection.focus;
502
426
  let recoveryNeeded = false;
503
-
504
427
  try {
505
428
  const anchorNode = anchor.getNode();
506
429
  const focusNode = focus.getNode();
507
-
508
- if ( // We might have removed a node that no longer exists
509
- !anchorNode.isAttached() || !focusNode.isAttached() || // If we've split a node, then the offset might not be right
430
+ if (
431
+ // We might have removed a node that no longer exists
432
+ !anchorNode.isAttached() || !focusNode.isAttached() ||
433
+ // If we've split a node, then the offset might not be right
510
434
  lexical.$isTextNode(anchorNode) && anchor.offset > anchorNode.getTextContentSize() || lexical.$isTextNode(focusNode) && focus.offset > focusNode.getTextContentSize()) {
511
435
  recoveryNeeded = true;
512
436
  }
@@ -515,7 +439,6 @@ function doesSelectionNeedRecovering(selection) {
515
439
  // an error, so we need recovery then too.
516
440
  recoveryNeeded = true;
517
441
  }
518
-
519
442
  return recoveryNeeded;
520
443
  }
521
444
  function syncWithTransaction(binding, fn) {
@@ -524,31 +447,26 @@ function syncWithTransaction(binding, fn) {
524
447
  function createChildrenArray(element, nodeMap) {
525
448
  const children = [];
526
449
  let nodeKey = element.__first;
527
-
528
450
  while (nodeKey !== null) {
529
451
  const node = nodeMap === null ? lexical.$getNodeByKey(nodeKey) : nodeMap.get(nodeKey);
530
-
531
452
  if (node === null || node === undefined) {
532
453
  {
533
454
  throw Error(`createChildrenArray: node does not exist in nodeMap`);
534
455
  }
535
456
  }
536
-
537
457
  children.push(nodeKey);
538
458
  nodeKey = node.__next;
539
459
  }
540
-
541
460
  return children;
542
461
  }
543
462
  function removeFromParent(node) {
544
463
  const oldParent = node.getParent();
545
-
546
464
  if (oldParent !== null) {
547
465
  const writableNode = node.getWritable();
548
466
  const writableParent = oldParent.getWritable();
549
467
  const prevSibling = node.getPreviousSibling();
550
- const nextSibling = node.getNextSibling(); // TODO: this function duplicates a bunch of operations, can be simplified.
551
-
468
+ const nextSibling = node.getNextSibling();
469
+ // TODO: this function duplicates a bunch of operations, can be simplified.
552
470
  if (prevSibling === null) {
553
471
  if (nextSibling !== null) {
554
472
  const writableNextSibling = nextSibling.getWritable();
@@ -559,7 +477,6 @@ function removeFromParent(node) {
559
477
  }
560
478
  } else {
561
479
  const writablePrevSibling = prevSibling.getWritable();
562
-
563
480
  if (nextSibling !== null) {
564
481
  const writableNextSibling = nextSibling.getWritable();
565
482
  writableNextSibling.__prev = writablePrevSibling.__key;
@@ -567,10 +484,8 @@ function removeFromParent(node) {
567
484
  } else {
568
485
  writablePrevSibling.__next = null;
569
486
  }
570
-
571
487
  writableNode.__prev = null;
572
488
  }
573
-
574
489
  if (nextSibling === null) {
575
490
  if (prevSibling !== null) {
576
491
  const writablePrevSibling = prevSibling.getWritable();
@@ -581,7 +496,6 @@ function removeFromParent(node) {
581
496
  }
582
497
  } else {
583
498
  const writableNextSibling = nextSibling.getWritable();
584
-
585
499
  if (prevSibling !== null) {
586
500
  const writablePrevSibling = prevSibling.getWritable();
587
501
  writablePrevSibling.__next = writableNextSibling.__key;
@@ -589,10 +503,8 @@ function removeFromParent(node) {
589
503
  } else {
590
504
  writableNextSibling.__prev = null;
591
505
  }
592
-
593
506
  writableNode.__next = null;
594
507
  }
595
-
596
508
  writableParent.__size--;
597
509
  writableNode.__parent = null;
598
510
  }
@@ -613,72 +525,56 @@ class CollabDecoratorNode {
613
525
  this._type = type;
614
526
  this._unobservers = new Set();
615
527
  }
616
-
617
528
  getPrevNode(nodeMap) {
618
529
  if (nodeMap === null) {
619
530
  return null;
620
531
  }
621
-
622
532
  const node = nodeMap.get(this._key);
623
533
  return lexical.$isDecoratorNode(node) ? node : null;
624
534
  }
625
-
626
535
  getNode() {
627
536
  const node = lexical.$getNodeByKey(this._key);
628
537
  return lexical.$isDecoratorNode(node) ? node : null;
629
538
  }
630
-
631
539
  getSharedType() {
632
540
  return this._xmlElem;
633
541
  }
634
-
635
542
  getType() {
636
543
  return this._type;
637
544
  }
638
-
639
545
  getKey() {
640
546
  return this._key;
641
547
  }
642
-
643
548
  getSize() {
644
549
  return 1;
645
550
  }
646
-
647
551
  getOffset() {
648
552
  const collabElementNode = this._parent;
649
553
  return collabElementNode.getChildOffset(this);
650
554
  }
651
-
652
555
  syncPropertiesFromLexical(binding, nextLexicalNode, prevNodeMap) {
653
556
  const prevLexicalNode = this.getPrevNode(prevNodeMap);
654
557
  const xmlElem = this._xmlElem;
655
558
  syncPropertiesFromLexical(binding, xmlElem, prevLexicalNode, nextLexicalNode);
656
559
  }
657
-
658
560
  syncPropertiesFromYjs(binding, keysChanged) {
659
561
  const lexicalNode = this.getNode();
660
-
661
562
  if (!(lexicalNode !== null)) {
662
563
  throw Error(`syncPropertiesFromYjs: cound not find decorator node`);
663
564
  }
664
-
665
565
  const xmlElem = this._xmlElem;
666
566
  syncPropertiesFromYjs(binding, xmlElem, lexicalNode, keysChanged);
667
567
  }
668
-
669
568
  destroy(binding) {
670
569
  const collabNodeMap = binding.collabNodeMap;
671
570
  collabNodeMap.delete(this._key);
672
-
673
571
  this._unobservers.forEach(unobserver => unobserver());
674
-
675
572
  this._unobservers.clear();
676
573
  }
677
-
678
574
  }
679
575
  function $createCollabDecoratorNode(xmlElem, parent, type) {
680
- const collabNode = new CollabDecoratorNode(xmlElem, parent, type); // @ts-expect-error: internal field
681
-
576
+ const collabNode = new CollabDecoratorNode(xmlElem, parent, type);
577
+ // @ts-expect-error: internal field
682
578
  xmlElem._collabNode = collabNode;
683
579
  return collabNode;
684
580
  }
@@ -698,75 +594,57 @@ class CollabElementNode {
698
594
  this._type = type;
699
595
  this._parent = parent;
700
596
  }
701
-
702
597
  getPrevNode(nodeMap) {
703
598
  if (nodeMap === null) {
704
599
  return null;
705
600
  }
706
-
707
601
  const node = nodeMap.get(this._key);
708
602
  return lexical.$isElementNode(node) ? node : null;
709
603
  }
710
-
711
604
  getNode() {
712
605
  const node = lexical.$getNodeByKey(this._key);
713
606
  return lexical.$isElementNode(node) ? node : null;
714
607
  }
715
-
716
608
  getSharedType() {
717
609
  return this._xmlText;
718
610
  }
719
-
720
611
  getType() {
721
612
  return this._type;
722
613
  }
723
-
724
614
  getKey() {
725
615
  return this._key;
726
616
  }
727
-
728
617
  isEmpty() {
729
618
  return this._children.length === 0;
730
619
  }
731
-
732
620
  getSize() {
733
621
  return 1;
734
622
  }
735
-
736
623
  getOffset() {
737
624
  const collabElementNode = this._parent;
738
-
739
625
  if (!(collabElementNode !== null)) {
740
626
  throw Error(`getOffset: cound not find collab element node`);
741
627
  }
742
-
743
628
  return collabElementNode.getChildOffset(this);
744
629
  }
745
-
746
630
  syncPropertiesFromYjs(binding, keysChanged) {
747
631
  const lexicalNode = this.getNode();
748
-
749
632
  if (!(lexicalNode !== null)) {
750
633
  throw Error(`syncPropertiesFromYjs: cound not find element node`);
751
634
  }
752
-
753
635
  syncPropertiesFromYjs(binding, this._xmlText, lexicalNode, keysChanged);
754
636
  }
755
-
756
637
  applyChildrenYjsDelta(binding, deltas) {
757
638
  const children = this._children;
758
639
  let currIndex = 0;
759
-
760
640
  for (let i = 0; i < deltas.length; i++) {
761
641
  const delta = deltas[i];
762
642
  const insertDelta = delta.insert;
763
643
  const deleteDelta = delta.delete;
764
-
765
644
  if (delta.retain != null) {
766
645
  currIndex += delta.retain;
767
646
  } else if (typeof deleteDelta === 'number') {
768
647
  let deletionSize = deleteDelta;
769
-
770
648
  while (deletionSize > 0) {
771
649
  const {
772
650
  node,
@@ -774,7 +652,6 @@ class CollabElementNode {
774
652
  offset,
775
653
  length
776
654
  } = getPositionFromElementAndOffset(this, currIndex, false);
777
-
778
655
  if (node instanceof CollabElementNode || node instanceof CollabLineBreakNode || node instanceof CollabDecoratorNode) {
779
656
  children.splice(nodeIndex, 1);
780
657
  deletionSize -= 1;
@@ -782,8 +659,8 @@ class CollabElementNode {
782
659
  const delCount = Math.min(deletionSize, length);
783
660
  const prevCollabNode = nodeIndex !== 0 ? children[nodeIndex - 1] : null;
784
661
  const nodeSize = node.getSize();
785
-
786
- if (offset === 0 && delCount === 1 && nodeIndex > 0 && prevCollabNode instanceof CollabTextNode && length === nodeSize && // If the node has no keys, it's been deleted
662
+ if (offset === 0 && delCount === 1 && nodeIndex > 0 && prevCollabNode instanceof CollabTextNode && length === nodeSize &&
663
+ // If the node has no keys, it's been deleted
787
664
  Array.from(node._map.keys()).length === 0) {
788
665
  // Merge the text node with previous.
789
666
  prevCollabNode._text += node._text;
@@ -794,7 +671,6 @@ class CollabElementNode {
794
671
  } else {
795
672
  node._text = spliceString(node._text, offset, delCount, '');
796
673
  }
797
-
798
674
  deletionSize -= delCount;
799
675
  } else {
800
676
  // Can occur due to the deletion from the dangling text heuristic below.
@@ -807,20 +683,19 @@ class CollabElementNode {
807
683
  node,
808
684
  offset
809
685
  } = getPositionFromElementAndOffset(this, currIndex, true);
810
-
811
686
  if (node instanceof CollabTextNode) {
812
687
  node._text = spliceString(node._text, offset, 0, insertDelta);
813
688
  } else {
814
689
  // TODO: maybe we can improve this by keeping around a redundant
815
690
  // text node map, rather than removing all the text nodes, so there
816
691
  // never can be dangling text.
692
+
817
693
  // We have a conflict where there was likely a CollabTextNode and
818
694
  // an Lexical TextNode too, but they were removed in a merge. So
819
695
  // let's just ignore the text and trigger a removal for it from our
820
696
  // shared type.
821
697
  this._xmlText.delete(offset, insertDelta.length);
822
698
  }
823
-
824
699
  currIndex += insertDelta.length;
825
700
  } else {
826
701
  const sharedType = insertDelta;
@@ -836,15 +711,12 @@ class CollabElementNode {
836
711
  }
837
712
  }
838
713
  }
839
-
840
714
  syncChildrenFromYjs(binding) {
841
715
  // Now diff the children of the collab node with that of our existing Lexical node.
842
716
  const lexicalNode = this.getNode();
843
-
844
717
  if (!(lexicalNode !== null)) {
845
718
  throw Error(`syncChildrenFromYjs: cound not find element node`);
846
719
  }
847
-
848
720
  const key = lexicalNode.__key;
849
721
  const prevLexicalChildrenKeys = createChildrenArray(lexicalNode, null);
850
722
  const lexicalChildrenKeysLength = prevLexicalChildrenKeys.length;
@@ -856,25 +728,20 @@ class CollabElementNode {
856
728
  let writableLexicalNode;
857
729
  let prevIndex = 0;
858
730
  let prevChildNode = null;
859
-
860
731
  if (collabChildrenLength !== lexicalChildrenKeysLength) {
861
732
  writableLexicalNode = lexicalNode.getWritable();
862
733
  }
863
-
864
734
  for (let i = 0; i < collabChildrenLength; i++) {
865
735
  const lexicalChildKey = prevLexicalChildrenKeys[prevIndex];
866
736
  const childCollabNode = collabChildren[i];
867
737
  const collabLexicalChildNode = childCollabNode.getNode();
868
738
  const collabKey = childCollabNode._key;
869
-
870
739
  if (collabLexicalChildNode !== null && lexicalChildKey === collabKey) {
871
- const childNeedsUpdating = lexical.$isTextNode(collabLexicalChildNode); // Update
872
-
740
+ const childNeedsUpdating = lexical.$isTextNode(collabLexicalChildNode);
741
+ // Update
873
742
  visitedKeys.add(lexicalChildKey);
874
-
875
743
  if (childNeedsUpdating) {
876
744
  childCollabNode._key = lexicalChildKey;
877
-
878
745
  if (childCollabNode instanceof CollabElementNode) {
879
746
  const xmlText = childCollabNode._xmlText;
880
747
  childCollabNode.syncPropertiesFromYjs(binding, null);
@@ -895,17 +762,14 @@ class CollabElementNode {
895
762
  } else {
896
763
  if (collabKeys === undefined) {
897
764
  collabKeys = new Set();
898
-
899
765
  for (let s = 0; s < collabChildrenLength; s++) {
900
766
  const child = collabChildren[s];
901
767
  const childKey = child._key;
902
-
903
768
  if (childKey !== '') {
904
769
  collabKeys.add(childKey);
905
770
  }
906
771
  }
907
772
  }
908
-
909
773
  if (collabLexicalChildNode !== null && lexicalChildKey !== undefined && !collabKeys.has(lexicalChildKey)) {
910
774
  const nodeToRemove = $getNodeByKeyOrThrow(lexicalChildKey);
911
775
  removeFromParent(nodeToRemove);
@@ -913,17 +777,14 @@ class CollabElementNode {
913
777
  prevIndex++;
914
778
  continue;
915
779
  }
916
-
917
- writableLexicalNode = lexicalNode.getWritable(); // Create/Replace
918
-
780
+ writableLexicalNode = lexicalNode.getWritable();
781
+ // Create/Replace
919
782
  const lexicalChildNode = createLexicalNodeFromCollabNode(binding, childCollabNode, key);
920
783
  const childKey = lexicalChildNode.__key;
921
784
  collabNodeMap.set(childKey, childCollabNode);
922
-
923
785
  if (prevChildNode === null) {
924
786
  const nextSibling = writableLexicalNode.getFirstChild();
925
787
  writableLexicalNode.__first = childKey;
926
-
927
788
  if (nextSibling !== null) {
928
789
  const writableNextSibling = nextSibling.getWritable();
929
790
  writableNextSibling.__prev = childKey;
@@ -934,49 +795,39 @@ class CollabElementNode {
934
795
  const nextSibling = prevChildNode.getNextSibling();
935
796
  writablePrevChildNode.__next = childKey;
936
797
  lexicalChildNode.__prev = prevChildNode.__key;
937
-
938
798
  if (nextSibling !== null) {
939
799
  const writableNextSibling = nextSibling.getWritable();
940
800
  writableNextSibling.__prev = childKey;
941
801
  lexicalChildNode.__next = writableNextSibling.__key;
942
802
  }
943
803
  }
944
-
945
804
  if (i === collabChildrenLength - 1) {
946
805
  writableLexicalNode.__last = childKey;
947
806
  }
948
-
949
807
  writableLexicalNode.__size++;
950
808
  prevChildNode = lexicalChildNode;
951
809
  }
952
810
  }
953
-
954
811
  for (let i = 0; i < lexicalChildrenKeysLength; i++) {
955
812
  const lexicalChildKey = prevLexicalChildrenKeys[i];
956
-
957
813
  if (!visitedKeys.has(lexicalChildKey)) {
958
814
  // Remove
959
815
  const lexicalChildNode = $getNodeByKeyOrThrow(lexicalChildKey);
960
816
  const collabNode = binding.collabNodeMap.get(lexicalChildKey);
961
-
962
817
  if (collabNode !== undefined) {
963
818
  collabNode.destroy(binding);
964
819
  }
965
-
966
820
  removeFromParent(lexicalChildNode);
967
821
  }
968
822
  }
969
823
  }
970
-
971
824
  syncPropertiesFromLexical(binding, nextLexicalNode, prevNodeMap) {
972
825
  syncPropertiesFromLexical(binding, this._xmlText, this.getPrevNode(prevNodeMap), nextLexicalNode);
973
826
  }
974
-
975
827
  _syncChildFromLexical(binding, index, key, prevNodeMap, dirtyElements, dirtyLeaves) {
976
- const childCollabNode = this._children[index]; // Update
977
-
828
+ const childCollabNode = this._children[index];
829
+ // Update
978
830
  const nextChildNode = $getNodeByKeyOrThrow(key);
979
-
980
831
  if (childCollabNode instanceof CollabElementNode && lexical.$isElementNode(nextChildNode)) {
981
832
  childCollabNode.syncPropertiesFromLexical(binding, nextChildNode, prevNodeMap);
982
833
  childCollabNode.syncChildrenFromLexical(binding, nextChildNode, prevNodeMap, dirtyElements, dirtyLeaves);
@@ -986,7 +837,6 @@ class CollabElementNode {
986
837
  childCollabNode.syncPropertiesFromLexical(binding, nextChildNode, prevNodeMap);
987
838
  }
988
839
  }
989
-
990
840
  syncChildrenFromLexical(binding, nextLexicalNode, prevNodeMap, dirtyElements, dirtyLeaves) {
991
841
  const prevLexicalNode = this.getPrevNode(prevNodeMap);
992
842
  const prevChildren = prevLexicalNode === null ? [] : createChildrenArray(prevLexicalNode, prevNodeMap);
@@ -998,29 +848,23 @@ class CollabElementNode {
998
848
  let nextChildrenSet;
999
849
  let prevIndex = 0;
1000
850
  let nextIndex = 0;
1001
-
1002
851
  while (prevIndex <= prevEndIndex && nextIndex <= nextEndIndex) {
1003
852
  const prevKey = prevChildren[prevIndex];
1004
853
  const nextKey = nextChildren[nextIndex];
1005
-
1006
854
  if (prevKey === nextKey) {
1007
855
  // Nove move, create or remove
1008
856
  this._syncChildFromLexical(binding, nextIndex, nextKey, prevNodeMap, dirtyElements, dirtyLeaves);
1009
-
1010
857
  prevIndex++;
1011
858
  nextIndex++;
1012
859
  } else {
1013
860
  if (prevChildrenSet === undefined) {
1014
861
  prevChildrenSet = new Set(prevChildren);
1015
862
  }
1016
-
1017
863
  if (nextChildrenSet === undefined) {
1018
864
  nextChildrenSet = new Set(nextChildren);
1019
865
  }
1020
-
1021
866
  const nextHasPrevKey = nextChildrenSet.has(prevKey);
1022
867
  const prevHasNextKey = prevChildrenSet.has(nextKey);
1023
-
1024
868
  if (!nextHasPrevKey) {
1025
869
  // Remove
1026
870
  this.splice(binding, nextIndex, 1);
@@ -1030,7 +874,6 @@ class CollabElementNode {
1030
874
  const nextChildNode = $getNodeByKeyOrThrow(nextKey);
1031
875
  const collabNode = $createCollabNodeFromLexicalNode(binding, nextChildNode, this);
1032
876
  collabNodeMap.set(nextKey, collabNode);
1033
-
1034
877
  if (prevHasNextKey) {
1035
878
  this.splice(binding, nextIndex, 1, collabNode);
1036
879
  prevIndex++;
@@ -1042,10 +885,8 @@ class CollabElementNode {
1042
885
  }
1043
886
  }
1044
887
  }
1045
-
1046
888
  const appendNewChildren = prevIndex > prevEndIndex;
1047
889
  const removeOldChildren = nextIndex > nextEndIndex;
1048
-
1049
890
  if (appendNewChildren && !removeOldChildren) {
1050
891
  for (; nextIndex <= nextEndIndex; ++nextIndex) {
1051
892
  const key = nextChildren[nextIndex];
@@ -1060,122 +901,95 @@ class CollabElementNode {
1060
901
  }
1061
902
  }
1062
903
  }
1063
-
1064
904
  append(collabNode) {
1065
905
  const xmlText = this._xmlText;
1066
906
  const children = this._children;
1067
907
  const lastChild = children[children.length - 1];
1068
908
  const offset = lastChild !== undefined ? lastChild.getOffset() + lastChild.getSize() : 0;
1069
-
1070
909
  if (collabNode instanceof CollabElementNode) {
1071
910
  xmlText.insertEmbed(offset, collabNode._xmlText);
1072
911
  } else if (collabNode instanceof CollabTextNode) {
1073
912
  const map = collabNode._map;
1074
-
1075
913
  if (map.parent === null) {
1076
914
  xmlText.insertEmbed(offset, map);
1077
915
  }
1078
-
1079
916
  xmlText.insert(offset + 1, collabNode._text);
1080
917
  } else if (collabNode instanceof CollabLineBreakNode) {
1081
918
  xmlText.insertEmbed(offset, collabNode._map);
1082
919
  } else if (collabNode instanceof CollabDecoratorNode) {
1083
920
  xmlText.insertEmbed(offset, collabNode._xmlElem);
1084
921
  }
1085
-
1086
922
  this._children.push(collabNode);
1087
923
  }
1088
-
1089
924
  splice(binding, index, delCount, collabNode) {
1090
925
  const children = this._children;
1091
926
  const child = children[index];
1092
-
1093
927
  if (child === undefined) {
1094
928
  if (!(collabNode !== undefined)) {
1095
929
  throw Error(`splice: could not find collab element node`);
1096
930
  }
1097
-
1098
931
  this.append(collabNode);
1099
932
  return;
1100
933
  }
1101
-
1102
934
  const offset = child.getOffset();
1103
-
1104
935
  if (!(offset !== -1)) {
1105
936
  throw Error(`splice: expected offset to be greater than zero`);
1106
937
  }
1107
-
1108
938
  const xmlText = this._xmlText;
1109
-
1110
939
  if (delCount !== 0) {
1111
940
  // What if we delete many nodes, don't we need to get all their
1112
941
  // sizes?
1113
942
  xmlText.delete(offset, child.getSize());
1114
943
  }
1115
-
1116
944
  if (collabNode instanceof CollabElementNode) {
1117
945
  xmlText.insertEmbed(offset, collabNode._xmlText);
1118
946
  } else if (collabNode instanceof CollabTextNode) {
1119
947
  const map = collabNode._map;
1120
-
1121
948
  if (map.parent === null) {
1122
949
  xmlText.insertEmbed(offset, map);
1123
950
  }
1124
-
1125
951
  xmlText.insert(offset + 1, collabNode._text);
1126
952
  } else if (collabNode instanceof CollabLineBreakNode) {
1127
953
  xmlText.insertEmbed(offset, collabNode._map);
1128
954
  } else if (collabNode instanceof CollabDecoratorNode) {
1129
955
  xmlText.insertEmbed(offset, collabNode._xmlElem);
1130
956
  }
1131
-
1132
957
  if (delCount !== 0) {
1133
958
  const childrenToDelete = children.slice(index, index + delCount);
1134
-
1135
959
  for (let i = 0; i < childrenToDelete.length; i++) {
1136
960
  childrenToDelete[i].destroy(binding);
1137
961
  }
1138
962
  }
1139
-
1140
963
  if (collabNode !== undefined) {
1141
964
  children.splice(index, delCount, collabNode);
1142
965
  } else {
1143
966
  children.splice(index, delCount);
1144
967
  }
1145
968
  }
1146
-
1147
969
  getChildOffset(collabNode) {
1148
970
  let offset = 0;
1149
971
  const children = this._children;
1150
-
1151
972
  for (let i = 0; i < children.length; i++) {
1152
973
  const child = children[i];
1153
-
1154
974
  if (child === collabNode) {
1155
975
  return offset;
1156
976
  }
1157
-
1158
977
  offset += child.getSize();
1159
978
  }
1160
-
1161
979
  return -1;
1162
980
  }
1163
-
1164
981
  destroy(binding) {
1165
982
  const collabNodeMap = binding.collabNodeMap;
1166
983
  const children = this._children;
1167
-
1168
984
  for (let i = 0; i < children.length; i++) {
1169
985
  children[i].destroy(binding);
1170
986
  }
1171
-
1172
987
  collabNodeMap.delete(this._key);
1173
988
  }
1174
-
1175
989
  }
1176
990
  function $createCollabElementNode(xmlText, parent, type) {
1177
- const collabNode = new CollabElementNode(xmlText, parent, type); // @ts-expect-error: internal field
1178
-
991
+ const collabNode = new CollabElementNode(xmlText, parent, type);
992
+ // @ts-expect-error: internal field
1179
993
  xmlText._collabNode = collabNode;
1180
994
  return collabNode;
1181
995
  }
@@ -1191,7 +1005,6 @@ function createBinding(editor, provider, id, doc, docMap) {
1191
1005
  if (!(doc !== undefined && doc !== null)) {
1192
1006
  throw Error(`createBinding: doc is null or undefined`);
1193
1007
  }
1194
-
1195
1008
  const rootXmlText = doc.get('root', yjs.XmlText);
1196
1009
  const root = $createCollabElementNode(rootXmlText, null, 'root');
1197
1010
  root._key = 'root';
@@ -1216,53 +1029,41 @@ function createBinding(editor, provider, id, doc, docMap) {
1216
1029
  * LICENSE file in the root directory of this source tree.
1217
1030
  *
1218
1031
  */
1219
-
1220
1032
  function createRelativePosition(point, binding) {
1221
1033
  const collabNodeMap = binding.collabNodeMap;
1222
1034
  const collabNode = collabNodeMap.get(point.key);
1223
-
1224
1035
  if (collabNode === undefined) {
1225
1036
  return null;
1226
1037
  }
1227
-
1228
1038
  let offset = point.offset;
1229
1039
  let sharedType = collabNode.getSharedType();
1230
-
1231
1040
  if (collabNode instanceof CollabTextNode) {
1232
1041
  sharedType = collabNode._parent._xmlText;
1233
1042
  const currentOffset = collabNode.getOffset();
1234
-
1235
1043
  if (currentOffset === -1) {
1236
1044
  return null;
1237
1045
  }
1238
-
1239
1046
  offset = currentOffset + 1 + offset;
1240
1047
  } else if (collabNode instanceof CollabElementNode && point.type === 'element') {
1241
1048
  const parent = point.getNode();
1242
1049
  let accumulatedOffset = 0;
1243
1050
  let i = 0;
1244
1051
  let node = parent.getFirstChild();
1245
-
1246
1052
  while (node !== null && i++ < offset) {
1247
1053
  if (lexical.$isTextNode(node)) {
1248
1054
  accumulatedOffset += node.getTextContentSize() + 1;
1249
1055
  } else {
1250
1056
  accumulatedOffset++;
1251
1057
  }
1252
-
1253
1058
  node = node.getNextSibling();
1254
1059
  }
1255
-
1256
1060
  offset = accumulatedOffset;
1257
1061
  }
1258
-
1259
1062
  return yjs.createRelativePositionFromTypeIndex(sharedType, offset);
1260
1063
  }
1261
-
1262
1064
  function createAbsolutePosition(relativePosition, binding) {
1263
1065
  return yjs.createAbsolutePositionFromRelativePosition(relativePosition, binding.doc);
1264
1066
  }
1265
-
1266
1067
  function shouldUpdatePosition(currentPos, pos) {
1267
1068
  if (currentPos == null) {
1268
1069
  if (pos != null) {
@@ -1271,10 +1072,8 @@ function shouldUpdatePosition(currentPos, pos) {
1271
1072
  } else if (pos == null || !yjs.compareRelativePositions(currentPos, pos)) {
1272
1073
  return true;
1273
1074
  }
1274
-
1275
1075
  return false;
1276
1076
  }
1277
-
1278
1077
  function createCursor(name, color) {
1279
1078
  return {
1280
1079
  color: color,
@@ -1282,28 +1081,22 @@ function createCursor(name, color) {
1282
1081
  selection: null
1283
1082
  };
1284
1083
  }
1285
-
1286
1084
  function destroySelection(binding, selection) {
1287
1085
  const cursorsContainer = binding.cursorsContainer;
1288
-
1289
1086
  if (cursorsContainer !== null) {
1290
1087
  const selections = selection.selections;
1291
1088
  const selectionsLength = selections.length;
1292
-
1293
1089
  for (let i = 0; i < selectionsLength; i++) {
1294
1090
  cursorsContainer.removeChild(selections[i]);
1295
1091
  }
1296
1092
  }
1297
1093
  }
1298
-
1299
1094
  function destroyCursor(binding, cursor) {
1300
1095
  const selection = cursor.selection;
1301
-
1302
1096
  if (selection !== null) {
1303
1097
  destroySelection(binding, selection);
1304
1098
  }
1305
1099
  }
1306
-
1307
1100
  function createCursorSelection(cursor, anchorKey, anchorOffset, focusKey, focusOffset) {
1308
1101
  const color = cursor.color;
1309
1102
  const caret = document.createElement('span');
@@ -1327,25 +1120,19 @@ function createCursorSelection(cursor, anchorKey, anchorOffset, focusKey, focusO
1327
1120
  selections: []
1328
1121
  };
1329
1122
  }
1330
-
1331
1123
  function updateCursor(binding, cursor, nextSelection, nodeMap) {
1332
1124
  const editor = binding.editor;
1333
1125
  const rootElement = editor.getRootElement();
1334
1126
  const cursorsContainer = binding.cursorsContainer;
1335
-
1336
1127
  if (cursorsContainer === null || rootElement === null) {
1337
1128
  return;
1338
1129
  }
1339
-
1340
1130
  const cursorsContainerOffsetParent = cursorsContainer.offsetParent;
1341
-
1342
1131
  if (cursorsContainerOffsetParent === null) {
1343
1132
  return;
1344
1133
  }
1345
-
1346
1134
  const containerRect = cursorsContainerOffsetParent.getBoundingClientRect();
1347
1135
  const prevSelection = cursor.selection;
1348
-
1349
1136
  if (nextSelection === null) {
1350
1137
  if (prevSelection === null) {
1351
1138
  return;
@@ -1357,7 +1144,6 @@ function updateCursor(binding, cursor, nextSelection, nodeMap) {
1357
1144
  } else {
1358
1145
  cursor.selection = nextSelection;
1359
1146
  }
1360
-
1361
1147
  const caret = nextSelection.caret;
1362
1148
  const color = nextSelection.color;
1363
1149
  const selections = nextSelection.selections;
@@ -1367,37 +1153,31 @@ function updateCursor(binding, cursor, nextSelection, nodeMap) {
1367
1153
  const focusKey = focus.key;
1368
1154
  const anchorNode = nodeMap.get(anchorKey);
1369
1155
  const focusNode = nodeMap.get(focusKey);
1370
-
1371
1156
  if (anchorNode == null || focusNode == null) {
1372
1157
  return;
1373
1158
  }
1159
+ let selectionRects;
1374
1160
 
1375
- let selectionRects; // In the case of a collapsed selection on a linebreak, we need
1161
+ // In the case of a collapsed selection on a linebreak, we need
1376
1162
  // to improvise as the browser will return nothing here as <br>
1377
1163
  // apparantly take up no visual space :/
1378
1164
  // This won't work in all cases, but it's better than just showing
1379
1165
  // nothing all the time.
1380
-
1381
1166
  if (anchorNode === focusNode && lexical.$isLineBreakNode(anchorNode)) {
1382
1167
  const brRect = editor.getElementByKey(anchorKey).getBoundingClientRect();
1383
1168
  selectionRects = [brRect];
1384
1169
  } else {
1385
1170
  const range = selection.createDOMRange(editor, anchorNode, anchor.offset, focusNode, focus.offset);
1386
-
1387
1171
  if (range === null) {
1388
1172
  return;
1389
1173
  }
1390
-
1391
1174
  selectionRects = selection.createRectsFromDOMRange(editor, range);
1392
1175
  }
1393
-
1394
1176
  const selectionsLength = selections.length;
1395
1177
  const selectionRectsLength = selectionRects.length;
1396
-
1397
1178
  for (let i = 0; i < selectionRectsLength; i++) {
1398
1179
  const selectionRect = selectionRects[i];
1399
1180
  let selection = selections[i];
1400
-
1401
1181
  if (selection === undefined) {
1402
1182
  selection = document.createElement('span');
1403
1183
  selections[i] = selection;
@@ -1405,55 +1185,44 @@ function updateCursor(binding, cursor, nextSelection, nodeMap) {
1405
1185
  selection.appendChild(selectionBg);
1406
1186
  cursorsContainer.appendChild(selection);
1407
1187
  }
1408
-
1409
1188
  const top = selectionRect.top - containerRect.top;
1410
1189
  const left = selectionRect.left - containerRect.left;
1411
1190
  const style = `position:absolute;top:${top}px;left:${left}px;height:${selectionRect.height}px;width:${selectionRect.width}px;pointer-events:none;z-index:5;`;
1412
1191
  selection.style.cssText = style;
1413
1192
  selection.firstChild.style.cssText = `${style}left:0;top:0;background-color:${color};opacity:0.3;`;
1414
-
1415
1193
  if (i === selectionRectsLength - 1) {
1416
1194
  if (caret.parentNode !== selection) {
1417
1195
  selection.appendChild(caret);
1418
1196
  }
1419
1197
  }
1420
1198
  }
1421
-
1422
1199
  for (let i = selectionsLength - 1; i >= selectionRectsLength; i--) {
1423
1200
  const selection = selections[i];
1424
1201
  cursorsContainer.removeChild(selection);
1425
1202
  selections.pop();
1426
1203
  }
1427
1204
  }
1428
-
1429
1205
  function syncLocalCursorPosition(binding, provider) {
1430
1206
  const awareness = provider.awareness;
1431
1207
  const localState = awareness.getLocalState();
1432
-
1433
1208
  if (localState === null) {
1434
1209
  return;
1435
1210
  }
1436
-
1437
1211
  const anchorPos = localState.anchorPos;
1438
1212
  const focusPos = localState.focusPos;
1439
-
1440
1213
  if (anchorPos !== null && focusPos !== null) {
1441
1214
  const anchorAbsPos = createAbsolutePosition(anchorPos, binding);
1442
1215
  const focusAbsPos = createAbsolutePosition(focusPos, binding);
1443
-
1444
1216
  if (anchorAbsPos !== null && focusAbsPos !== null) {
1445
1217
  const [anchorCollabNode, anchorOffset] = getCollabNodeAndOffset(anchorAbsPos.type, anchorAbsPos.index);
1446
1218
  const [focusCollabNode, focusOffset] = getCollabNodeAndOffset(focusAbsPos.type, focusAbsPos.index);
1447
-
1448
1219
  if (anchorCollabNode !== null && focusCollabNode !== null) {
1449
1220
  const anchorKey = anchorCollabNode.getKey();
1450
1221
  const focusKey = focusCollabNode.getKey();
1451
1222
  const selection = lexical.$getSelection();
1452
-
1453
1223
  if (!lexical.$isRangeSelection(selection)) {
1454
1224
  return;
1455
1225
  }
1456
-
1457
1226
  const anchor = selection.anchor;
1458
1227
  const focus = selection.focus;
1459
1228
  setPoint(anchor, anchorKey, anchorOffset);
@@ -1462,46 +1231,38 @@ function syncLocalCursorPosition(binding, provider) {
1462
1231
  }
1463
1232
  }
1464
1233
  }
1465
-
1466
1234
  function setPoint(point, key, offset) {
1467
1235
  if (point.key !== key || point.offset !== offset) {
1468
1236
  let anchorNode = lexical.$getNodeByKey(key);
1469
-
1470
1237
  if (anchorNode !== null && !lexical.$isElementNode(anchorNode) && !lexical.$isTextNode(anchorNode)) {
1471
1238
  const parent = anchorNode.getParentOrThrow();
1472
1239
  key = parent.getKey();
1473
1240
  offset = anchorNode.getIndexWithinParent();
1474
1241
  anchorNode = parent;
1475
1242
  }
1476
-
1477
1243
  point.set(key, offset, lexical.$isElementNode(anchorNode) ? 'element' : 'text');
1478
1244
  }
1479
1245
  }
1480
-
1481
- function getCollabNodeAndOffset( // eslint-disable-next-line @typescript-eslint/no-explicit-any
1246
+ function getCollabNodeAndOffset(
1247
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1482
1248
  sharedType, offset) {
1483
1249
  const collabNode = sharedType._collabNode;
1484
-
1485
1250
  if (collabNode === undefined) {
1486
1251
  return [null, 0];
1487
1252
  }
1488
-
1489
1253
  if (collabNode instanceof CollabElementNode) {
1490
1254
  const {
1491
1255
  node,
1492
1256
  offset: collabNodeOffset
1493
1257
  } = getPositionFromElementAndOffset(collabNode, offset, true);
1494
-
1495
1258
  if (node === null) {
1496
1259
  return [collabNode, 0];
1497
1260
  } else {
1498
1261
  return [node, collabNodeOffset];
1499
1262
  }
1500
1263
  }
1501
-
1502
1264
  return [null, 0];
1503
1265
  }
1504
-
1505
1266
  function syncCursorPositions(binding, provider) {
1506
1267
  const awarenessStates = Array.from(provider.awareness.getStates());
1507
1268
  const localClientID = binding.clientID;
@@ -1509,11 +1270,9 @@ function syncCursorPositions(binding, provider) {
1509
1270
  const editor = binding.editor;
1510
1271
  const nodeMap = editor._editorState._nodeMap;
1511
1272
  const visitedClientIDs = new Set();
1512
-
1513
1273
  for (let i = 0; i < awarenessStates.length; i++) {
1514
1274
  const awarenessState = awarenessStates[i];
1515
1275
  const [clientID, awareness] = awarenessState;
1516
-
1517
1276
  if (clientID !== localClientID) {
1518
1277
  visitedClientIDs.add(clientID);
1519
1278
  const {
@@ -1525,25 +1284,20 @@ function syncCursorPositions(binding, provider) {
1525
1284
  } = awareness;
1526
1285
  let selection = null;
1527
1286
  let cursor = cursors.get(clientID);
1528
-
1529
1287
  if (cursor === undefined) {
1530
1288
  cursor = createCursor(name, color);
1531
1289
  cursors.set(clientID, cursor);
1532
1290
  }
1533
-
1534
1291
  if (anchorPos !== null && focusPos !== null && focusing) {
1535
1292
  const anchorAbsPos = createAbsolutePosition(anchorPos, binding);
1536
1293
  const focusAbsPos = createAbsolutePosition(focusPos, binding);
1537
-
1538
1294
  if (anchorAbsPos !== null && focusAbsPos !== null) {
1539
1295
  const [anchorCollabNode, anchorOffset] = getCollabNodeAndOffset(anchorAbsPos.type, anchorAbsPos.index);
1540
1296
  const [focusCollabNode, focusOffset] = getCollabNodeAndOffset(focusAbsPos.type, focusAbsPos.index);
1541
-
1542
1297
  if (anchorCollabNode !== null && focusCollabNode !== null) {
1543
1298
  const anchorKey = anchorCollabNode.getKey();
1544
1299
  const focusKey = focusCollabNode.getKey();
1545
1300
  selection = cursor.selection;
1546
-
1547
1301
  if (selection === null) {
1548
1302
  selection = createCursorSelection(cursor, anchorKey, anchorOffset, focusKey, focusOffset);
1549
1303
  } else {
@@ -1557,19 +1311,14 @@ function syncCursorPositions(binding, provider) {
1557
1311
  }
1558
1312
  }
1559
1313
  }
1560
-
1561
1314
  updateCursor(binding, cursor, selection, nodeMap);
1562
1315
  }
1563
1316
  }
1564
-
1565
1317
  const allClientIDs = Array.from(cursors.keys());
1566
-
1567
1318
  for (let i = 0; i < allClientIDs.length; i++) {
1568
1319
  const clientID = allClientIDs[i];
1569
-
1570
1320
  if (!visitedClientIDs.has(clientID)) {
1571
1321
  const cursor = cursors.get(clientID);
1572
-
1573
1322
  if (cursor !== undefined) {
1574
1323
  destroyCursor(binding, cursor);
1575
1324
  cursors.delete(clientID);
@@ -1580,11 +1329,9 @@ function syncCursorPositions(binding, provider) {
1580
1329
  function syncLexicalSelectionToYjs(binding, provider, prevSelection, nextSelection) {
1581
1330
  const awareness = provider.awareness;
1582
1331
  const localState = awareness.getLocalState();
1583
-
1584
1332
  if (localState === null) {
1585
1333
  return;
1586
1334
  }
1587
-
1588
1335
  const {
1589
1336
  anchorPos: currentAnchorPos,
1590
1337
  focusPos: currentFocusPos,
@@ -1594,18 +1341,15 @@ function syncLexicalSelectionToYjs(binding, provider, prevSelection, nextSelecti
1594
1341
  } = localState;
1595
1342
  let anchorPos = null;
1596
1343
  let focusPos = null;
1597
-
1598
1344
  if (nextSelection === null || currentAnchorPos !== null && !nextSelection.is(prevSelection)) {
1599
1345
  if (prevSelection === null) {
1600
1346
  return;
1601
1347
  }
1602
1348
  }
1603
-
1604
1349
  if (lexical.$isRangeSelection(nextSelection)) {
1605
1350
  anchorPos = createRelativePosition(nextSelection.anchor, binding);
1606
1351
  focusPos = createRelativePosition(nextSelection.focus, binding);
1607
1352
  }
1608
-
1609
1353
  if (shouldUpdatePosition(currentAnchorPos, anchorPos) || shouldUpdatePosition(currentFocusPos, focusPos)) {
1610
1354
  awareness.setLocalState({
1611
1355
  anchorPos,
@@ -1625,24 +1369,24 @@ function syncLexicalSelectionToYjs(binding, provider, prevSelection, nextSelecti
1625
1369
  *
1626
1370
  */
1627
1371
 
1372
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1628
1373
  function syncEvent(binding, event) {
1629
1374
  const {
1630
1375
  target
1631
1376
  } = event;
1632
1377
  const collabNode = getOrInitCollabNodeFromSharedType(binding, target);
1633
-
1634
1378
  if (collabNode instanceof CollabElementNode && event instanceof yjs.YTextEvent) {
1635
1379
  // @ts-expect-error We need to access the private property of the class
1636
1380
  const {
1637
1381
  keysChanged,
1638
1382
  childListChanged,
1639
1383
  delta
1640
- } = event; // Update
1384
+ } = event;
1641
1385
 
1386
+ // Update
1642
1387
  if (keysChanged.size > 0) {
1643
1388
  collabNode.syncPropertiesFromYjs(binding, keysChanged);
1644
1389
  }
1645
-
1646
1390
  if (childListChanged) {
1647
1391
  collabNode.applyChildrenYjsDelta(binding, delta);
1648
1392
  collabNode.syncChildrenFromYjs(binding);
@@ -1650,16 +1394,18 @@ function syncEvent(binding, event) {
1650
1394
  } else if (collabNode instanceof CollabTextNode && event instanceof yjs.YMapEvent) {
1651
1395
  const {
1652
1396
  keysChanged
1653
- } = event; // Update
1397
+ } = event;
1654
1398
 
1399
+ // Update
1655
1400
  if (keysChanged.size > 0) {
1656
1401
  collabNode.syncPropertiesAndTextFromYjs(binding, keysChanged);
1657
1402
  }
1658
1403
  } else if (collabNode instanceof CollabDecoratorNode && event instanceof yjs.YXmlEvent) {
1659
1404
  const {
1660
1405
  attributesChanged
1661
- } = event; // Update
1406
+ } = event;
1662
1407
 
1408
+ // Update
1663
1409
  if (attributesChanged.size > 0) {
1664
1410
  collabNode.syncPropertiesFromYjs(binding, attributesChanged);
1665
1411
  }
@@ -1669,53 +1415,46 @@ function syncEvent(binding, event) {
1669
1415
  }
1670
1416
  }
1671
1417
  }
1672
-
1673
1418
  function syncYjsChangesToLexical(binding, provider, events) {
1674
1419
  const editor = binding.editor;
1675
1420
  const currentEditorState = editor._editorState;
1676
1421
  editor.update(() => {
1677
1422
  const pendingEditorState = editor._pendingEditorState;
1678
-
1679
1423
  for (let i = 0; i < events.length; i++) {
1680
1424
  const event = events[i];
1681
1425
  syncEvent(binding, event);
1682
1426
  }
1683
-
1684
1427
  const selection = lexical.$getSelection();
1685
-
1686
1428
  if (lexical.$isRangeSelection(selection)) {
1687
1429
  // We can't use Yjs's cursor position here, as it doesn't always
1688
1430
  // handle selection recovery correctly – especially on elements that
1689
1431
  // get moved around or split. So instead, we roll our own solution.
1690
1432
  if (doesSelectionNeedRecovering(selection)) {
1691
1433
  const prevSelection = currentEditorState._selection;
1692
-
1693
1434
  if (lexical.$isRangeSelection(prevSelection)) {
1694
1435
  const prevOffsetView = offset.$createOffsetView(editor, 0, currentEditorState);
1695
1436
  const nextOffsetView = offset.$createOffsetView(editor, 0, pendingEditorState);
1696
1437
  const [start, end] = prevOffsetView.getOffsetsFromSelection(prevSelection);
1697
1438
  const nextSelection = nextOffsetView.createSelectionFromOffsets(start, end, prevOffsetView);
1698
-
1699
1439
  if (nextSelection !== null) {
1700
1440
  lexical.$setSelection(nextSelection);
1701
1441
  } else {
1702
1442
  // Fallback is to use the Yjs cursor position
1703
1443
  syncLocalCursorPosition(binding, provider);
1704
-
1705
1444
  if (doesSelectionNeedRecovering(selection)) {
1706
- const root = lexical.$getRoot(); // If there was a collision on the top level paragraph
1707
- // we need to re-add a paragraph
1445
+ const root = lexical.$getRoot();
1708
1446
 
1447
+ // If there was a collision on the top level paragraph
1448
+ // we need to re-add a paragraph
1709
1449
  if (root.getChildrenSize() === 0) {
1710
1450
  root.append(lexical.$createParagraphNode());
1711
- } // Fallback
1712
-
1451
+ }
1713
1452
 
1453
+ // Fallback
1714
1454
  lexical.$getRoot().selectEnd();
1715
1455
  }
1716
1456
  }
1717
1457
  }
1718
-
1719
1458
  syncLexicalSelectionToYjs(binding, provider, prevSelection, lexical.$getSelection());
1720
1459
  } else {
1721
1460
  syncLocalCursorPosition(binding, provider);
@@ -1729,18 +1468,15 @@ function syncYjsChangesToLexical(binding, provider, events) {
1729
1468
  tag: 'collaboration'
1730
1469
  });
1731
1470
  }
1732
-
1733
1471
  function handleNormalizationMergeConflicts(binding, normalizedNodes) {
1734
1472
  // We handle the merge operations here
1735
1473
  const normalizedNodesKeys = Array.from(normalizedNodes);
1736
1474
  const collabNodeMap = binding.collabNodeMap;
1737
1475
  const mergedNodes = [];
1738
-
1739
1476
  for (let i = 0; i < normalizedNodesKeys.length; i++) {
1740
1477
  const nodeKey = normalizedNodesKeys[i];
1741
1478
  const lexicalNode = lexical.$getNodeByKey(nodeKey);
1742
1479
  const collabNode = collabNodeMap.get(nodeKey);
1743
-
1744
1480
  if (collabNode instanceof CollabTextNode) {
1745
1481
  if (lexical.$isTextNode(lexicalNode)) {
1746
1482
  // We mutate the text collab nodes after removing
@@ -1748,16 +1484,12 @@ function handleNormalizationMergeConflicts(binding, normalizedNodes) {
1748
1484
  mergedNodes.push([collabNode, lexicalNode.__text]);
1749
1485
  } else {
1750
1486
  const offset = collabNode.getOffset();
1751
-
1752
1487
  if (offset === -1) {
1753
1488
  continue;
1754
1489
  }
1755
-
1756
1490
  const parent = collabNode._parent;
1757
1491
  collabNode._normalized = true;
1758
-
1759
1492
  parent._xmlText.delete(offset, 1);
1760
-
1761
1493
  collabNodeMap.delete(nodeKey);
1762
1494
  const parentChildren = parent._children;
1763
1495
  const index = parentChildren.indexOf(collabNode);
@@ -1765,16 +1497,13 @@ function handleNormalizationMergeConflicts(binding, normalizedNodes) {
1765
1497
  }
1766
1498
  }
1767
1499
  }
1768
-
1769
1500
  for (let i = 0; i < mergedNodes.length; i++) {
1770
1501
  const [collabNode, text] = mergedNodes[i];
1771
-
1772
1502
  if (collabNode instanceof CollabTextNode && typeof text === 'string') {
1773
1503
  collabNode._text = text;
1774
1504
  }
1775
1505
  }
1776
1506
  }
1777
-
1778
1507
  function syncLexicalUpdateToYjs(binding, provider, prevEditorState, currEditorState, dirtyElements, dirtyLeaves, normalizedNodes, tags) {
1779
1508
  syncWithTransaction(binding, () => {
1780
1509
  currEditorState.read(() => {
@@ -1789,10 +1518,8 @@ function syncLexicalUpdateToYjs(binding, provider, prevEditorState, currEditorSt
1789
1518
  if (normalizedNodes.size > 0) {
1790
1519
  handleNormalizationMergeConflicts(binding, normalizedNodes);
1791
1520
  }
1792
-
1793
1521
  return;
1794
1522
  }
1795
-
1796
1523
  if (dirtyElements.has('root')) {
1797
1524
  const prevNodeMap = prevEditorState._nodeMap;
1798
1525
  const nextLexicalRoot = lexical.$getRoot();
@@ -1800,7 +1527,6 @@ function syncLexicalUpdateToYjs(binding, provider, prevEditorState, currEditorSt
1800
1527
  collabRoot.syncPropertiesFromLexical(binding, nextLexicalRoot, prevNodeMap);
1801
1528
  collabRoot.syncChildrenFromLexical(binding, nextLexicalRoot, prevNodeMap, dirtyElements, dirtyLeaves);
1802
1529
  }
1803
-
1804
1530
  const selection = lexical.$getSelection();
1805
1531
  const prevSelection = prevEditorState._selection;
1806
1532
  syncLexicalSelectionToYjs(binding, provider, prevSelection, selection);
@@ -1830,7 +1556,6 @@ function setLocalStateFocus(provider, name, color, focusing) {
1830
1556
  awareness
1831
1557
  } = provider;
1832
1558
  let localState = awareness.getLocalState();
1833
-
1834
1559
  if (localState === null) {
1835
1560
  localState = {
1836
1561
  anchorPos: null,
@@ -1840,7 +1565,6 @@ function setLocalStateFocus(provider, name, color, focusing) {
1840
1565
  name
1841
1566
  };
1842
1567
  }
1843
-
1844
1568
  localState.focusing = focusing;
1845
1569
  awareness.setLocalState(localState);
1846
1570
  }