@lexical/yjs 0.12.2 → 0.12.4

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